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

> 原文：https://pjhubs.com/2018/04/13/%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%E5%9B%9B%EF%BC%89/
>
> 作者：PJHubs · 发布于 2018-04-13 · 标签：Spring MVC

😔终于最后一个实验了。。。

**1. 利用SpringMVC技术完成自己项目的前端界面以及控制层代码，包括增加、修改、删除、查询等功能。**

首先明确一点，是使用SPring MVC来完成增删改查的功能，首先引入相关需要的包，因为需要使用Annotation、ORM、log记录、mysql连接。

需要导入的jar包如下所示：
1. jstl
2. standard
3. mybatis
4. mysql
5. log4j

在intelliJ中创建Spring MVC工程，因为我们并不想像之前一样每次都手拼SQL和管理JDBC的相关内容，因此可以用上MyBatis去帮助减少工作量，先来写下对应的配置文件

```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.UserMapper">
    <select id="selectUserWithID" parameterType="int" resultType="com.pjhubs.Model.User">
    select * from user where id = #{id}
</select>
    <select id="selectAllUser" resultType="com.pjhubs.Model.User">
    select * from user
</select>
    <insert id="insertUser" parameterType="com.pjhubs.Model.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.Model.User">
    update user set nickname=#{nickname} where id=#{id}
</update>
</mapper>

```

随后再写下对MyBatis的配置文件,

```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 DB name?useSSL=false"/>
                <property name="username" value="your DB username"/>
                <property name="password" value="your DB passwd"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!-- 对应上面sql文件的路径 -->
        <mapper resource="com/pjhubs/User.xml"/>
    </mappers>
</configuration>
```

随后来定义`Usermodel`文件，该model需要根据自己的表结构进行改造，供参考

```java
package com.pjhubs.Model;

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;
    }
}

```

接着来定义`UserMapper`文件，因为MyBatis也提供简化了帮助我们减少写模板代码的步骤。注意，如果你并不想试用Mapper的做法，请在对应的SQL配置文件中的`<mapper namespace>`标签下修改对应的值为你的DAO层接口实现文件。

```java
package com.pjhubs.DAO;

import java.util.List;
import com.pjhubs.Model.User;

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;
}

```

以上就是我们的准备工作，接下来开始正式进入到编写SpringMVC的Controller层控制代码。此处的Controller层可以理解为是控制数据源的索取和给视图填入数据，返回视图的中心者。

对于这个中心者，遵循的可以是MVC、MVP、MVVM等架构设计中充当C、P、VM角色，我们从Spring MVC的名字上看也能看出了该框架遵循的MVC的架构设计，而对于MVC最重要的事情就是M和V都要分开，并且M和V都互相知道对方的存在，这可以说是MVC的好处也可以认为是MVC的坏处，以为内MVP达到的是V不知道M是谁，只管自己要的数据是什么，只需要在P中填充给V对应的数据即可，而在MVVM中，V和M双方都不知道对方的存在，V只知道自己需要哪些数据，M只知道自己能够获取到哪些数据，而负责对V和M进行数据绑定的则由ViewModel来做。

以上就是对MVC、MVP、MVVM三大架构设计的一个简单讲解，如果你也做移动应用开发甚至是iOS开发，想要更加细的对架构设计有一个更加深入的了解，可以参考我的[这篇文章](http://pjhubs.com/2018/02/02/More-DesignPattern/)。

我们需要用到Spring MVC框架中提供的Controller功能，也可以先浅显的认为是路由中心（但很显然它不应该是中心），我们访问的所有资源，最终都会落入到Controller中（前提改了配置文件），在正式开始编写Controller中心者功能前，我们现在来配置框架的配置文件，如果你也是用intelliJ创建的工程，该配置文件的名称应为`applicationContext.xml`，千万注意相关文件的路径！！！

```xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.pjhubs.controller"/>
    <!-- 静态资源(js、image等)的访问 -->
    <mvc:default-servlet-handler/>
    <!-- 开启注解 -->
    <mvc:annotation-driven/>
    <!-- mapping后跟的为URL访问时的映射路径 -->
    <mvc:resources location="/WEB-INF/resource/scripts/js/" mapping="/js/**"></mvc:resources>

    <!--ViewResolver 视图解析器-->
    <!--用于支持Servlet、JSP视图解析-->
    <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/Views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>
```

为了降低实验的复杂度（我就是懒），谢绝考虑其他一切不相干问题，修改`dispatcher-servlet.xml`文件内容如下所示，
```xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <!-- 重点是它, 截取所有访问入Spring-->
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
```

现在我们就先来完成的Controller代码。

```java
package com.pjhubs.controller;

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 org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.annotation.Resource;
import java.io.InputStream;
import java.util.List;

import com.pjhubs.DAO.UserMapper;
import com.pjhubs.Model.User;

@Controller
public class thingsController {

    // 直接访问根地址定位到这
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String todoList(ModelMap modelMap) {
        modelMap.addAttribute("msg", "To-do List");
        return "todolist";
    }

    // 访问 /allThings定位到这
    @RequestMapping(value = "/allThings", method = RequestMethod.GET)
    public List<User> allThings(ModelMap modelMap) throws Exception {

        String resource = "com/pjhubs/SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        List<User> userList = mapper.selectAllUser();
        for (User user : userList) {
            System.out.println("id:" + user.getId() + " 昵称：" + user.getNickname());
        }
        session.close();

        return userList;
    }

    @RequestMapping(value = "/deleteThing/{id}", method = RequestMethod.POST)
    public String deleteThing(@PathVariable("id") int id) throws Exception {

        String resource = "com/pjhubs/SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();

        UserMapper mapper = session.getMapper(UserMapper.class);
        mapper.deleteUserWithID(id);
        session.commit();

        session.close();

        System.out.println(id);
        return "redirect:/allThings";
    }

    @RequestMapping(value = "/modify/{id}", method = RequestMethod.POST)
    public String modifyThing(@PathVariable("id") int id, ModelMap modelMap) throws Exception {

        String resource = "com/pjhubs/SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();

        UserMapper mapper = session.getMapper(UserMapper.class);
        User user = mapper.selectUserWithID(id);
        session.commit();

        session.close();

        modelMap.addAttribute("id", user.getId());
        modelMap.addAttribute("nickname", user.getNickname());

        return "modify";
    }

    @RequestMapping(value = "/updateStudent/{id}", method = RequestMethod.POST)
    public String updateStudent(int id, String nickname) throws Exception {

        String resource = "com/pjhubs/SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();

        User user = new User();
        user.setId(id);
        user.setNickname(nickname);

        UserMapper mapper = session.getMapper(UserMapper.class);
        mapper.updateUserWithNickname(user);
        session.commit();

        session.close();

        return "redirect:/allThings";
    }

    @RequestMapping(value = "/insertUser", method = RequestMethod.GET)
    public String insertUser(ModelMap modelMap) {
        return "insertUser";
    }

    @RequestMapping(value = "/insertNewuser", method = RequestMethod.POST)
    public String updateStudent(String nickname, String passwd) throws Exception {

        String resource = "com/pjhubs/SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        User newuser = new User();
        newuser.setNickname(nickname);
        newuser.setPasswd(passwd);

        UserMapper mapper = session.getMapper(UserMapper.class);
        mapper.insertUser(newuser);
        session.commit();
        session.close();

        return "redirect:/allThings";
    }

}

```

遵循了RESTful，没有session，没有用户判断，存粹的只完成了实验要求。

**2. 利用自定义Spring监听方式，将当前项目的内存情况每过5秒钟记录到数据库一次。完成业务模块和后台管理模块同时运行的效果。**

该题目继承实验一，之前只是把totalMemory记录下来，这回需要记录下maxMemory、totalMemory、freeMemory，拿到这三个值需要用到Runtime类相关方法，想要完成实验，需要做的事情如下，

在`dispatcher-servlet.xml`中的`xmlns`下添加
```xml
xmlns:task="http://www.springframework.org/schema/task"  
```

在`xsi:schemaLocation`填写，
```xml
http://www.springframework.org/schema/task  
http://www.springframework.org/schema/task/spring-task-3.2.xsd  
```

最后在该文件中写下task任务扫描注解，供后续文件中使用，
```xml
<task:annotation-driven/>  
<!-- base-package填写需要进行task任务扫描的包 -->
<context:component-scan base-package="com.pjhubs.controller"></context:component-scan>
```

接着再重复一遍之前UserMapper要做的事情即可写入，

```java
@Controller
// 新增
@Component
public class thingsController {
    // 新增
    @Scheduled(cron="0/5 * * * * ? ") //间隔5秒执行
    public void taskCycle() throws Exception {
        Runtime runtime = Runtime.getRuntime();
        System.out.println(runtime.maxMemory() / 1024 / 1024 + "," + runtime.totalMemory() / 1024 / 1024 + "," + runtime.freeMemory() / 1024 / 1024);


        String resource = "com/pjhubs/SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        Memory memory = new Memory();
        memory.setMax(runtime.maxMemory() / 1024 / 1024);
        memory.setTotal(runtime.totalMemory() / 1024 / 1024);
        memory.setFree(runtime.freeMemory() / 1024 / 1024);


        MemoryMapper mapper = session.getMapper(MemoryMapper.class);
        mapper.insertData(memory);
        session.commit();
        session.close();

    }
    ......
```
不想写讲解了，就这样吧。
