1.MVC设计模式

1.1.分层架构模式

随着软件工程的规模越来越大,复杂度越来越高,工程中的组件也越来越多。而组件与组件之间的关联过于紧密,导致整个工程变得异常复杂,进而导致开发人员越来越难以掌控整个工程,造成工程开发失败。 这就是组件之间的 “紧耦合” 问题。为了解决这个问题,提出了 “高内聚低耦合” 的思想。也就是 “解耦”。

  1. 高内聚:每个模块尽可能独立完成自己的功能,不依赖于模块外部的代码。
  2. 低耦合:模块与模块之间使用接口尽量降低耦合度。

高内聚、低耦合目的:使得软件工程实现 “可重用、可扩展、可维护、灵活性好” 的目的。
分层架构也是解决 “解耦” 问题的一种设计模式。

1.1.1.model1 两层架构

在早期开发中,通常采用的都是model1。Model1就是两层架构:视图层和数据层。
p05_01.png

实际上,在我们的第一个JDBC项目中,使用的就是两层架构。

1.1.2.model2 三层架构

model1两层架构只适用于比较简单的软件工程,后来出现了model2三层架构。
05.MVC设计模式 - 图2

所谓三层体系结构,是在视图层与数据层之间加入了一个“中间层”。 三层架构使得视图层不在直接与数据层进行交互,而是经由中间层与数据层进行交互。

1.2.MVC设计模式

model2三层架构提供了一种思想,为了实现这种思想,人们提出了一些具体的设计模式。 MVC就三层架构思想的一种具体实现。
05.MVC设计模式 - 图3

  • MVC是 “Model-View-Controller” 的缩写。也就是 “模型-视图-控制器”。
  • MVC把工程的组成分解成模型、视图、控制器三种部件。
  • MVC架构的目的:用控制器将业务模型和视图分离,这就是MVC架构的目的。

1.3.在javaWeb工程中的MVC

p05_04.png

具体来说: 在javaWeb工程中,MVC部件与javaWeb工程中的组件的对应关系为:

  • View:前端html
  • Controller:Servlet
  • Model:javaBean(Service组件)

1.4.在前后端分离架构工程中的MVC

05.MVC设计模式 - 图5

在前后端分离的开发模式中,V层已经独立出来,成为一个独立的工程。

2.MVC实例:分页

下面使用MVC架构实现一个分页。工程目录结构为:
p05_06.png

2.1.服务器端代码

2.1.1.使用过滤器解决跨域和字符集问题

  1. package com.neusoft.emp.filter;
  2. import javax.servlet.*;
  3. import javax.servlet.annotation.WebFilter;
  4. import javax.servlet.http.HttpServletResponse;
  5. import java.io.IOException;
  6. @WebFilter("/*")
  7. public class SetCharFilter implements Filter{
  8. @Override
  9. public void init(FilterConfig filterConfig) throws ServletException { }
  10. @Override
  11. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
  12. FilterChain filterChain) throws IOException, ServletException {
  13. servletRequest.setCharacterEncoding("utf-8");
  14. servletResponse.setContentType("text/html;charset=utf-8");
  15. servletResponse.setCharacterEncoding("utf-8");
  16. filterChain.doFilter(servletRequest, servletResponse);
  17. }
  18. @Override
  19. public void destroy() { }
  20. }
  1. package filter;
  2. import java.io.IOException;
  3. import javax.servlet.Filter;
  4. import javax.servlet.FilterChain;
  5. import javax.servlet.FilterConfig;
  6. import javax.servlet.ServletException;
  7. import javax.servlet.ServletRequest;
  8. import javax.servlet.ServletResponse;
  9. import javax.servlet.annotation.WebFilter;
  10. import javax.servlet.http.HttpServletRequest;
  11. import javax.servlet.http.HttpServletResponse;
  12. @WebFilter("/*")
  13. public class CorsFilter implements Filter {
  14. @Override
  15. public void init(FilterConfig filterConfig) throws ServletException {}
  16. @Override
  17. public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
  18. throws IOException, ServletException {
  19. HttpServletRequest request = (HttpServletRequest)req;
  20. HttpServletResponse response = (HttpServletResponse)resp;
  21. //设置允许跨域
  22. response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
  23. //设置开启Cookie
  24. response.setHeader("Access-Control-Allow-Credentials", "true");
  25. chain.doFilter(req, resp);
  26. }
  27. @Override
  28. public void destroy() {}
  29. }

2.1.2.po代码

package com.neusoft.emp.po;
public class Emp {
    private Integer empno;
    private String ename;
    private String job;
    private Integer mgr;
    private String hiredate;
    private Double sal;
    private Double comm;
    private Integer deptno;
    //get/set方法...
}

2.1.3.dto代码

DTO:数据传输对象(Data Transfer Object); 这里专用于响应分页后的业务数据。

package com.neusoft.emp.dto;
import java.util.List;
public class PageDto {
    private int totalRow;        //总行数
    private int totalPageNum;    //总页数
    private int preNum;          //上一页
    private int nextNum;         //下一页
    private int pageNum;         //当前页
    private int maxPageNum;      //每页显示最大行数
    private int beginNum;        //开始记录数
    private List list;               //查询返回数据
    //get/set方法...
}

2.1.4.dao层代码

package com.neusoft.emp.dao;
import java.util.List;
import com.neusoft.emp.po.Emp;
public interface EmpDao {
    public int getEmpCount();
    public List<Emp> listEmp(int beginNum,int maxPageNum);
}
package com.neusoft.emp.dao.impl;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.neusoft.emp.dao.EmpDao;
import com.neusoft.emp.po.Emp;
import com.neusoft.emp.util.DBUtil;
public class EmpDaoImpl implements EmpDao{
    private Connection con = null;
    private PreparedStatement pst = null;
    private ResultSet rs = null;
    @Override
    public int getEmpCount() {
        int count = 0;
        String sql = "select count(*) from emp";
        try {
            con = DBUtil.getConnection();
            pst = con.prepareStatement(sql);
            rs = pst.executeQuery();
            if(rs.next()) {
                count = rs.getInt(1);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(rs, pst, con);
        }
        return count;
    }
    @Override
    public List<Emp> listEmp(int beginNum,int maxPageNum) {
        List<Emp> list = new ArrayList();
        String sql = "select * from emp order by empno desc limit ?,?";
        try {
            con = DBUtil.getConnection();
            pst = con.prepareStatement(sql);
            pst.setInt(1, beginNum);
            pst.setInt(2, maxPageNum);
            rs = pst.executeQuery();
            while(rs.next()) {
                Emp e = new Emp();
                e.setEmpno(rs.getInt("empno"));
                e.setEname(rs.getString("ename"));
                e.setJob(rs.getString("job"));
                e.setMgr(rs.getInt("mgr"));
                e.setHiredate(rs.getString("hiredate"));
                e.setSal(rs.getDouble("sal"));
                e.setComm(rs.getDouble("comm"));
                e.setDeptno(rs.getInt("deptno"));
                list.add(e);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(rs, pst, con);
        }
        return list;
    }
}

2.1.5.service层代码

package com.neusoft.emp.service;
import com.neusoft.emp.dto.PageDto;
public interface EmpService {
    public PageDto listEmp(int pageNum,int maxPageNum);
}
package com.neusoft.emp.service.impl;
import java.util.List;
import com.neusoft.emp.dao.EmpDao;
import com.neusoft.emp.dao.impl.EmpDaoImpl;
import com.neusoft.emp.dto.PageDto;
import com.neusoft.emp.po.Emp;
import com.neusoft.emp.service.EmpService;
public class EmpServiceImpl implements EmpService{
    @Override
    public PageDto listEmp(int pageNum,int maxPageNum) {
        int totalRow = 0;          //初始化总行数
        int totalPageNum = 0;      //初始化总页数
        int preNum = 0;            //初始化上一页
        int nextNum = 0;           //初始化下一页
        int beginNum = 0;          //初始化开始记录数
        //创建DAO
        EmpDao dao = new EmpDaoImpl();
        //创建返回值
        PageDto pageDto = new PageDto();
        //获取总行数
        totalRow = dao.getEmpCount();
        //如果查询行数为0,那么直接结束。
        if(totalRow == 0) {
            return pageDto;
        }
        //计算总页数
        //totalPageNum = totalRow/maxPageNum+1;
        if(totalRow%maxPageNum==0) {
            totalPageNum = totalRow/maxPageNum;
        }else {
            totalPageNum = totalRow/maxPageNum+1;
        }
        //当前页数验证
        if(pageNum<=0){
            pageNum = 1;
        }
        if(pageNum>totalPageNum){
            pageNum = totalPageNum;
        }
        //设置上一页和下一页
        preNum = pageNum;
        nextNum = pageNum;
        if(pageNum > 1) {
            preNum--;
        }
        if(pageNum < totalPageNum) {
            nextNum++;
        }
        //计算开始查询记录数
        beginNum = (pageNum - 1) * maxPageNum;
        //开始查询业务数据
        List<Emp> list = dao.listEmp(beginNum, maxPageNum);
        //封装返回数据
        pageDto.setTotalRow(totalRow);
        pageDto.setTotalPageNum(totalPageNum);
        pageDto.setPreNum(preNum);
        pageDto.setNextNum(nextNum);
        pageDto.setPageNum(pageNum);
        pageDto.setMaxPageNum(maxPageNum);
        pageDto.setBeginNum(beginNum);
        pageDto.setList(list);
        return pageDto;
    }
}

2.1.6.controller层代码

package com.neusoft.emp.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.neusoft.emp.dto.PageDto;
import com.neusoft.emp.po.Emp;
import com.neusoft.emp.service.EmpService;
import com.neusoft.emp.service.impl.EmpServiceImpl;
@WebServlet("/listEmp")
public class ListEmpServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
                         throws ServletException, IOException {
        Integer pageNum = Integer.valueOf(request.getParameter("pageNum"));
        Integer maxPageNum = Integer.valueOf(request.getParameter("maxPageNum"));
        EmpService service = new EmpServiceImpl();
        PageDto pageDto = service.listEmp(pageNum, maxPageNum);
        PrintWriter out = response.getWriter();
        ObjectMapper om = new ObjectMapper();
        out.print(om.writeValueAsString(pageDto));  
        out.close();
    }
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
                            throws ServletException, IOException {
        doGet(request, response);
    }
}

2.2.前端代码

<template>
    <div class="home">
        <table>
            <tr>
                <th>员工编号</th>
                <th>员工姓名</th>
                <th>员工职位</th>
                <th>入职日期</th>
                <th>员工工资</th>
                <th>所属部门</th>
            </tr>
            <tr v-for="emp in pageInfo.list">
                <td>{{emp.empno}}</td>
                <td>{{emp.ename}}</td>
                <td>{{emp.job}}</td>
                <td>{{emp.hiredate}}</td>
                <td>{{emp.sal}}</td>
                <td>{{emp.deptno}}</td>
            </tr>
        </table>
        <ul>
            <li><a @click="fenye(1)">首页</a></li>
            <li><a @click="fenye(pageInfo.preNum)">上一页</a></li>
            <li>第{{pageInfo.pageNum}}页</li>
            <li>总{{pageInfo.totalPageNum}}页</li>
            <li><a @click="fenye(pageInfo.nextNum)">下一页</a></li>
            <li><a @click="fenye(pageInfo.totalPageNum)">尾页</a></li>
            <li>
                <input type="text" v-model="toPage"><a @click="fenye(toPage)">GO</a>
            </li>
        </ul>
    </div>
</template>
<script>
    export default {
        name: 'Home',
        data(){
            return {
                pageInfo:{},
                maxPageNum:10,
                toPage:1
            }
        },
        created() {
            this.fenye(1);
        },
        methods:{
            fenye(pageNum){
                this.$axios.post('http://localhost:8080/emp/listEmp',this.$qs.stringify({
                    pageNum:pageNum,
                    maxPageNum:this.maxPageNum
                }))
                    .then(response=> {
                        this.pageInfo = response.data
                    })
                    .catch(error=> {
                        console.log(error);
                    });  
            }
        }
    }
</script>
<style scoped>
    table{
        width: 100%;
        border-collapse: collapse;
    }
    table tr,table td,table th{
        height: 36px;
        border-bottom: solid 1px #AAA;
    }
    ul{
        width: 100%;
        display: flex;
        justify-content: center;
    }
    ul li{
        width: 60px;
        display: flex;
        justify-content: center;
    }
    ul li input{
        width: 25px;
        margin-right: 4px;
    }
    ul li a{
        user-select: none;
        cursor: pointer;
    }
</style>