# 软件开发项目实践（二）

> 原文：https://pjhubs.com/2018/04/01/%E8%BD%AF%E4%BB%B6%E5%BC%80%E5%8F%91%E9%A1%B9%E7%9B%AE%E5%AE%9E%E8%B7%B5%EF%BC%88%E4%BA%8C%EF%BC%89/
>
> 作者：PJHubs · 发布于 2018-04-01 · 标签：后端、Java

**1. 利用MyBatis结合Junit、Log4j实现对数据库的增删改查。**
导入MyBatis、Junit、Log4j和mysql驱动包，IntelliJ导包操作：File -> Project Structure -> Modules(左侧栏) -> 找到"+"，选择JARs -> 选择对应包路径即可。

确定各个包做的事情：
1. MyBatis：主要解决了之前使用JDBC对数据库进行操作的繁杂步骤，是一种ORM。
2. Junit：java测试框架。
3. Log4j：主要用户log记录。
4. mysql驱动：为java连接mysql数据库提供驱动及操作承载。

实验步骤：
1. 安装mysql数据库，创建数据库，创建表。为方便进行实验，我创建的user表结构如下：
  ```SQL
  +------------+-------------+------+-----+-------------------+-----------------------------+
  | Field      | Type        | Null | Key | Default           | Extra                       |
  +------------+-------------+------+-----+-------------------+-----------------------------+
  | id         | int(11)     | NO   | PRI | NULL              | auto_increment              |
  | passwd     | varchar(16) | NO   |     | NULL              |                             |
  | nickname   | varchar(20) | NO   |     | NULL              |                             |
  | createTime | timestamp   | NO   |     | CURRENT_TIMESTAMP |                             |
  | updateTime | datetime    | YES  |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
  +------------+-------------+------+-----+-------------------+-----------------------------+
  ```

2. 创建java工程。导包。
3. 编写User实例。
```Java
public class User {

    private Integer id;
    private String passwd;
    private String nickname;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getPasswd() {
        return passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }
}
```
4. 编写User.xml mapper文件。该文件可以暂时认为是之前JDBC做的事情，在此配置好User实例中对应的方法要操作数据库的事情。
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- mapper标签要指定namespace属性，不然会报错，可看做包名-->
<mapper namespace="com.pjhubs.dao.intf.UserDAO">
    <select id="selectUserWithID" parameterType="int" resultType="com.pjhubs.instance.User">
        select * from user where id = #{id}
    </select>
    <select id="selectAllUser" resultType="com.pjhubs.instance.User">
        select * from user
    </select>
    <insert id="insertUser" parameterType="com.pjhubs.instance.User">
        insert into user(nickname,passwd) values(#{nickname},#{passwd})
    </insert>
    <delete id="deleteUserWithID" parameterType="int">
        delete from user where id=#{id}
    </delete>
    <update id="updateUserWithNickname" parameterType="com.pjhubs.instance.User">
        update user set nickname=#{nickname} where id=#{id}
    </update>
</mapper>

```
5. 编写MyBatis配置文件，SqlMapConfig.xml
  ```xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/your_database_name?useSSL=false"/>
                <property name="username" value="your_database_name"/>
                <property name="password" value="your_database_password"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="User.xml"/>
    </mappers>
</configuration>
  ```
6. 编写User接口及其实现。
  ```Java
// ---------- user interface ---------
import java.util.List;
import com.pjhubs.instance.User;

public interface UserDAO {

    public User selectUserWithID(int ID) throws Exception;
    public List<User> selectAllUser() throws Exception;
    public void insertUser(User user) throws Exception;
    public void deleteUserWithID(int ID) throws Exception;
    public void updateUserWithNickname(User user) throws Exception;

}

// ---------- user implements -----------
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import com.pjhubs.dao.intf.UserDAO;
import com.pjhubs.instance.User;

public class UserDAOImpl implements UserDAO {

    @Override
    public User selectUserWithID(int ID) throws  Exception {
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        User user = session.selectOne("user.selectUserWithID", ID);
        session.close();
        return user;
    }

    @Override
    public List<User> selectAllUser() {
        List<User> usersList = new ArrayList<User>();
        try {
            String resource = "SqlMapConfig.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
            SqlSession session = factory.openSession();
            usersList = session.selectList("user.selectAllUser");
            session.close();
        } catch (Exception e) {
            System.out.println(e);
        }
        return usersList;
    }

    @Override
    public void insertUser(User user) throws Exception {
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        session.insert("user.insertUser", user);
        // insert、Update、delete 加上 commit
        session.commit();  
        session.close();
    }

    @Override
    public void deleteUserWithID(int ID) throws Exception {
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        session.delete("user.deleteUserWithID", ID);
        // insert、Update、delete 加上 commit
        session.commit();   
        session.close();
    }

    @Override
    public void updateUserWithNickname(User user) throws Exception {
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        session.update("user.updateUserWithNickname", user);
        // insert、Update、delete 加上 commit
        session.commit();   
        session.close();
    }
}
  ```

7. 使用Junit进行测试。
```Java
import java.util.List;
import org.junit.jupiter.api.Test;

import com.pjhubs.instance.User;
import com.pjhubs.dao.intf.UserDAO;
import com.pjhubs.dao.impl.UserDAOImpl;

public class UserTest {

    @Test
    public void testSelectAllUser() throws Exception {
        UserDAO userDAO = new UserDAOImpl();
        List<User> userList = userDAO.selectAllUser();
        for (User user : userList) {
            System.out.println("id：" + user.getId() + "昵称：" + user.getNickname());
        }
    }

    @Test
    public void testSelectUserWithID() throws Exception {
        UserDAO userDAO = new UserDAOImpl();
        User user = userDAO.selectUserWithID(1);
        System.out.println("id:" + user.getId() + " 昵称:" + user.getNickname());
    }

    @Test
    public void testInsertUser() throws Exception {
        UserDAO userDAO = new UserDAOImpl();
        User user = new User();
        user.setNickname("PJHubs");
        user.setPasswd("woaiwoziji123");
        userDAO.insertUser(user);
    }

    @Test
    public void testDeleteUserByID() throws Exception {
        UserDAO userDAO = new UserDAOImpl();
        userDAO.deleteUserWithID(1);
    }

    @Test
    public void testUpdateUserNickname() throws Exception {
        UserDAO userDAO = new UserDAOImpl();
        User user = new User();
        user.setNickname("pjhubs");
        user.setId(1);
        user.setPasswd("woaiwoziji123");
        userDAO.updateUserWithNickname(user);
    }

}

```

8. 使用Junit编写测试类，
```Java
import java.util.List;
import org.junit.jupiter.api.Test;

import com.pjhubs.instance.User;
import com.pjhubs.dao.intf.UserDAO;
import com.pjhubs.dao.impl.UserDAOImpl;

public class UserTest {

    @Test
    public void testSelectAllUser() throws Exception {
        UserDAO userDAO = new UserDAOImpl();
        List<User> userList = userDAO.selectAllUser();
        for (User user : userList) {
            System.out.println("id：" + user.getId() + "昵称：" + user.getNickname());
        }
    }

    @Test
    public void testSelectUserWithID() throws Exception {
        UserDAO userDAO = new UserDAOImpl();
        User user = userDAO.selectUserWithID(1);
        System.out.println("id:" + user.getId() + " 昵称:" + user.getNickname());
    }

    @Test
    public void testInsertUser() throws Exception {
        UserDAO userDAO = new UserDAOImpl();
        User user = new User();
        user.setNickname("PJHubs");
        user.setPasswd("woaiwoziji123");
        userDAO.insertUser(user);
    }

    @Test
    public void testDeleteUserByID() throws Exception {
        UserDAO userDAO = new UserDAOImpl();
        userDAO.deleteUserWithID(1);
    }

    @Test
    public void testUpdateUserNickname() throws Exception {
        UserDAO userDAO = new UserDAOImpl();
        User user = new User();
        user.setNickname("pjhubs");
        user.setId(1);
        user.setPasswd("woaiwoziji123");
        userDAO.updateUserWithNickname(user);
    }

}
```

至此经过八个步骤，实验完成，但还有个可以优化的地方，会发现其实在给UserDAO写implements时出现了非常多的重复性代码，经过一番搜索，发现可以使用MyBatis提供的Mapper代理开发模式进行优化，这个模式的意思是说，coder只需要编写mapper接口，可以认为是之前写的UserDAO interface，而不用再写具有相当多的重复性代码的implements，因为MyBatis会自动为Mapper接口生成动态代理实现类，编写Mapper接口类需要注意一下事项：

1. mapper接口的全限定名（包名）要和mapper映射文件的namespace的值相同。
2. mapper接口的方法名称要和mapper映射文件中的statement的id相同。
3. mapper接口的方法参数只能有一个，且类型要和mapper映射文件中statement的parameterType的值保持一致。
4. mapper接口的返回值类型要和mapper映射文件中statement的resultType值或resultMap中的type值保持一致。

可见如果想要做一些简单的操作，用这种模式最方便不过了。

接下来，需要修改User.xml文件为：
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 修改了namespace -->
<mapper namespace="com.pjhubs.dao.intf.UserMapper">
    <select id="selectUserWithID" parameterType="int" resultType="com.pjhubs.instance.User">
        select * from user where id = #{id}
    </select>
    <select id="selectAllUser" resultType="com.pjhubs.instance.User">
        select * from user
    </select>
    <insert id="insertUser" parameterType="com.pjhubs.instance.User">
        insert into user(nickname,passwd) values(#{nickname},#{passwd})
    </insert>
    <delete id="deleteUserWithID" parameterType="int">
        delete from user where id=#{id}
    </delete>
    <update id="updateUserWithNickname" parameterType="com.pjhubs.instance.User">
        update user set nickname=#{nickname} where id=#{id}
    </update>
</mapper>
```

创建一个新的UserMapper接口类，
```Java
import com.pjhubs.instance.User;

import java.util.List;

public interface UserMapper {

    public User selectUserWithID(int ID) throws Exception;
    public List<User> selectAllUser() throws Exception;
    public void insertUser(User user) throws Exception;
    public void deleteUserWithID(int ID) throws Exception;
    public void updateUserWithNickname(User user) throws Exception;

}
```

创建一个新的测试类，
```Java
import java.util.List;
import org.junit.jupiter.api.Test;

import com.pjhubs.instance.User;
import com.pjhubs.dao.intf.UserDAO;
import com.pjhubs.dao.impl.UserDAOImpl;

public class UserTest {

    @Test
    public void testSelectAllUser() throws Exception {
        UserDAO userDAO = new UserDAOImpl();
        List<User> userList = userDAO.selectAllUser();
        for (User user : userList) {
            System.out.println("id：" + user.getId() + "昵称：" + user.getNickname());
        }
    }

    @Test
    public void testSelectUserWithID() throws Exception {
        UserDAO userDAO = new UserDAOImpl();
        User user = userDAO.selectUserWithID(1);
        System.out.println("id:" + user.getId() + " 昵称:" + user.getNickname());
    }

    @Test
    public void testInsertUser() throws Exception {
        UserDAO userDAO = new UserDAOImpl();
        User user = new User();
        user.setNickname("PJHubs");
        user.setPasswd("woaiwoziji123");
        userDAO.insertUser(user);
    }

    @Test
    public void testDeleteUserByID() throws Exception {
        UserDAO userDAO = new UserDAOImpl();
        userDAO.deleteUserWithID(1);
    }

    @Test
    public void testUpdateUserNickname() throws Exception {
        UserDAO userDAO = new UserDAOImpl();
        User user = new User();
        user.setNickname("pjhubs");
        user.setId(1);
        user.setPasswd("woaiwoziji123");
        userDAO.updateUserWithNickname(user);
    }

}
```


**2. 自己定义一个线程，每过5秒钟将当前系统的使用内存，用Log4j打印到磁盘和屏幕。**
创建一个线程类，
```Java
package pjhubs;

import org.apache.log4j.Logger;

public class ThreadClass implements Runnable {
    private Thread t;
    private String threadName;

    ThreadClass( String name) {
        threadName = name;
        System.out.println("Creating " +  threadName );
    }

    public void run() {
        System.out.println("Running " +  threadName );
        while(true) {
            try {
                Thread.sleep(2000);
                Logger logger = Logger.getLogger(Main.class);
                logger.info("当前JVM已经从操作系统拿到的内存大小:"
                        + Runtime.getRuntime().totalMemory() / 1024 / 1024 + "M");
            } catch (InterruptedException e) {
                System.out.println("Thread " +  threadName + " interrupted.");
            }
            System.out.println("Thread " +  threadName + " exiting.");
        }
    }

    public void start () {
        System.out.println("Starting " +  threadName );
        if (t == null) {
            t = new Thread (this, threadName);
            t.start ();
        }
    }
}
```

在Main方法中进行调用，
```Java
public class Main {

    public static void main(String[] args) throws Exception {
        ThreadClass t1 = new ThreadClass("pjThread");
        t1.start();
    }
}
```
