64MVC设计模式

MVC设计模式

MVC理解图

概念 - 代码的分层

字母 表示 理解
M Modle 模型层 业务的具体实现
V View 视图层 展示数据
C Controller 控制器层 控制业务流程

细化理解层数

View:视图层,用于存放前端页面

Controller:控制器层,用于存放Servlet

Modle-Biz:逻辑业务层,用于存放业务具体的实现

Modle-Dao:数据持久层,用于存放操作数据的实现

优缺点

缺点:使用MVC不能减少代码量, 增加系统结构和实现的复杂性

优点:整个项目结构清晰,业务逻辑清晰,降低了代码的耦合性,代码的重用性高

各层的命名规范

Controller控制器层:controller/servlet/action/web

Modle-Biz 逻辑业务层:service/biz

Modle-Dao 数据持久层:dao/persist/mapper

MVC学生管理系统

Mapper层

操作数据库

接口

CourseMapper

TeacherMapper

StudentMapper

java 复制代码
package com.ckl.mapper;

import com.ckl.pojo.Student;

import java.util.List;

public interface StudentMapper {

    public void add(String username,String password,String name,String sex,int age,String hobbies,String photo);

    public void delete(String username);

    public void update(String username,String newPassword);

    public void update(String username,String name,String sex,int age,String hobbies);

    public void update(String username,String name,String sex,int age,String hobbies,String photo);

    public Student getStudent(String username);

    public Student getStudent(String username,String password);

    public List<Student> getStudents(int offset,int count);

    public int getAllCount();
}
实现类

CourseMapperImpl

TeacherMapperImpl

StudentMapperImpl

java 复制代码
package com.ckl.mapper.impl;

import com.ckl.mapper.StudentMapper;
import com.ckl.pojo.Student;
import com.ckl.utils.DBUtils;

import java.sql.SQLException;
import java.util.List;

public class StudentMapperImpl implements StudentMapper {

    @Override
    public void add(String username, String password, String name, String sex, int age, String hobbies, String photo) {
        try {
            DBUtils.commonUpdate("insert into student(username,password,name,sex,age,hobbies,photo) values(?,?,?,?,?,?,?)",username,password,name,sex,age, hobbies,photo);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void delete(String username) {
        try {
            DBUtils.commonUpdate("delete from student where username = ?",username);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void update(String username, String newPassword) {
        try {
            DBUtils.commonUpdate("update student set password=? where username=?",newPassword,username);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void update(String username, String name, String sex, int age, String hobbies) {
        try {
            DBUtils.commonUpdate("update student set name=?,sex=?,age=?,hobbies=? where username=?",name,sex,age,hobbies,username);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void update(String username, String name, String sex, int age, String hobbies, String photo) {
        try {
            DBUtils.commonUpdate("update student set name=?,sex=?,age=?,hobbies=?,photo=? where username=?",name,sex,age,hobbies,photo,username);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Student getStudent(String username) {

        Student student = null;
        try {
            student = DBUtils.commonQueryObj(Student.class, "select * from student where username = ?", username);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        return student;
    }

    @Override
    public Student getStudent(String username, String password) {
        Student student = null;
        try {
            student = DBUtils.commonQueryObj(Student.class, "select * from student where username = ? and password = ?", username, password);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return student;
    }

    @Override
    public List<Student> getStudents(int offset, int count) {

        List<Student> students = null;
        try {
            students = DBUtils.commonQueryList(Student.class, "select * from student limit ?,?", offset, count);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        return students;
    }

    @Override
    public int getAllCount() {

        int allcount = 0;
        try {
            allcount = DBUtils.getAllCount("student");
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return allcount;
    }
}

Service层

业务功能实现

接口

对于后续管理员的功能,会用到的Service方法先在Service接口规范出来

CourseService

是否添加、添加、修改课程信息初始化、修改课程信息、查询课程、删除

UserService

验证码、登录、记住我【直接传需要的数据】、安全退出、修改密码

TeacherService

是否添加、添加、修改课程信息初始化、修改课程信息、查询课程、删除

StudentService

是否注册、注册、修改课程信息初始化、修改课程信息、查询课程、删除

java 复制代码
package com.ckl.service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface StudentService {

    public boolean isRegister(String username);

    public boolean register(HttpServletRequest request, HttpServletResponse response);

    public void initModify(HttpServletRequest request, HttpServletResponse response);

    public void modify(HttpServletRequest request, HttpServletResponse response);

    public void getStudents(HttpServletRequest request, HttpServletResponse response);

    public void delete(HttpServletRequest request, HttpServletResponse response);
}
实现类

【一般传请求和响应】

1.不做跳转

2.涉及数据库的操作都求助于mapper层,newmapperImpl层实现类对象,再使用多态向上转型mapper对象进行方法调用

  private StudentMapper studentMapper = new StudentMapperImpl();

3.对于学生老师在添加时,会利用到对象和输入输出流就会需要写一个解析请求数据包类使用泛型【新建一个core包】,解析请求的工具类【处理文本数据和二进制数据】,利用反射

public class ParseRequestData<T> {

    private T t;
    private InputStream in;
    private OutputStream out;

    ...
}

4.对于学生老师信息的修改,会出现不修改头像的情况,就需要在mapper层添加方法;在处理业务,工具类要注意判断输入流,有就改了没有就不改,注意流的关闭

public void update(String username,String name,String sex,int age,String hobbies);

public void update(String username,String name,String sex,int age,String hobbies,String photo);

存的头像路径就会在service层传路径,传入在工具类处理就会自定义新的路径,再存就可以

CourseServiceImpl

UserServiceImpl

对于角色判断登录使用多态获取user对象,直接调用Mapper层方法,记住我也是调用同类方法,登录成功失败都只是返回boolean值

TeacherServiceImpl

除了获取TeacherMapper对象,还要用到CourseService对象

private TeacherMapper teacherMapper = new TeacherMapperImpl();
private CourseService courseService = new CourseServiceImpl();

StudentServiceImpl

注意:查询涉及分页,就新新增工具类PageUtils,获取总页数;

java 复制代码
package com.ckl.service.impl;

import com.ckl.core.ParseRequestData;
import com.ckl.dto.StudentDto;
import com.ckl.mapper.StudentMapper;
import com.ckl.mapper.impl.StudentMapperImpl;
import com.ckl.pojo.Page;
import com.ckl.pojo.Student;
import com.ckl.service.StudentService;
import com.ckl.utils.*;
import org.apache.commons.io.IOUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

public class StudentServiceImpl implements StudentService {

    private StudentMapper studentMapper = new StudentMapperImpl();

    @Override
    public boolean isRegister(String username) {

        Student student = studentMapper.getStudent(username);
        if(student == null){
            return true;
        }
        return false;
    }

    @Override
    public boolean register(HttpServletRequest request, HttpServletResponse response) {

        ParseRequestData<Student> parseRequestData = ParseRequestDataUtils.parseRequest(request, Student.class, "upload\\student");

        Student stu = parseRequestData.getT();
        InputStream in = parseRequestData.getIn();
        OutputStream out = parseRequestData.getOut();

        boolean register = isRegister(stu.getUsername());
        if(register){
            //将数据插入到学生表中
            studentMapper.add(stu.getUsername(),stu.getPassword(),stu.getName(),stu.getSex(),stu.getAge(),stu.getHobbies(),stu.getPhoto());

            //将头像存储到本地磁盘
            try {
                IOUtils.copy(in,out);
                in.close();
                out.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            return true;
        }else{
            try {
                in.close();
                out.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            request.setAttribute("msg","注册失败 -- 账号已注册");
            return false;
        }
    }

    @Override
    public void initModify(HttpServletRequest request, HttpServletResponse response) {
        String username = request.getParameter("username");
        Student student = studentMapper.getStudent(username);
        request.setAttribute("student",student);
    }

    @Override
    public void modify(HttpServletRequest request, HttpServletResponse response) {

        ParseRequestData<Student> parseRequestData = ParseRequestDataUtils.parseRequest(request, Student.class, "upload\\student");
        Student stu = parseRequestData.getT();
        InputStream in = parseRequestData.getIn();
        OutputStream out = parseRequestData.getOut();

        try {
            if(stu.getPhoto() != null){//说明用户修改头像

                studentMapper.update(stu.getUsername(),stu.getName(), stu.getSex(), stu.getAge(),stu.getHobbies(),stu.getPhoto());
                IOUtils.copy(in,out);
            }else{
                studentMapper.update(stu.getUsername(),stu.getName(), stu.getSex(), stu.getAge(),stu.getHobbies());
            }
            if(in != null){
                in.close();
            }
            if(out != null){
                out.close();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        String role = (String) request.getSession().getAttribute("role");
        if("student".equals(role)){
            //更新Session里的数据
            request.getSession().setAttribute("name",stu.getName());
            //更新Cookie里的数据
            response.addCookie(CookieUtils.createCookie("name",stu.getName(),60*60*24*5));
            if(stu.getPhoto() != null){
                request.getSession().setAttribute("photo",stu.getPhoto());
                response.addCookie(CookieUtils.createCookie("photo",stu.getPhoto(),60*60*24*5));
            }

        }

    }

    @Override
    public void getStudents(HttpServletRequest request, HttpServletResponse response) {
        //获取当前页数
        int curPage = Integer.parseInt(request.getParameter("curPage"));

        //设置URL
        String url = "student?action=doGetStudents&curPage=";
        //设置当前页的数据条数
        int count = 15;
        //计算偏移量
        int offset = (curPage-1)*count;
        //计算总页数
        int allCount = studentMapper.getAllCount();
        int totalPage = PageUtils.getTotalPage(allCount,count);

        //从数据库获取学生的集合
        List<Student> students = studentMapper.getStudents(offset,count);

        //处理学生集合
        List<StudentDto> studentDtos = DtoUtils.studentDtoListHandler(students);

        //封装Page对象
        Page<StudentDto> page = new Page<>(url, curPage, totalPage, studentDtos);

        //将数据存入到请求对象中
        request.setAttribute("page",page);
    }

    @Override
    public void delete(HttpServletRequest request, HttpServletResponse response) {
        String username = request.getParameter("username");
        studentMapper.delete(username);
    }
}

Controller层

做跳转

前面的项目用的Servlet,一个功能一个Servlet会很多

现在分角色来写Servlet,不同角色里有对应的多个功能

减少了多个Servlet堆积

实现原理

客户端发送的请求都会找到对应角色的Controller层,但是角色中包含很多功能,需要判断功能,如何实现?

理解:表单提交不是用到action,同理我们判断对应功能,就在jsp对应功能写上角色名+对应功能的action

角色名即找到对应的ControllerServlet

Controller里,获取action,进行功能判断

ControllerServlet

CourseController

UserController

TeacherController

StudentController

@WebServlet("/student")
public class StudentController extends HttpServlet {

    private StudentService studentService = new StudentServiceImpl();

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String action = request.getParameter("action");

        if("doRegister".equals(action)){
            boolean register = studentService.register(request, response);
            if(register){
                response.sendRedirect("login.jsp");
            }else{
                request.getRequestDispatcher("register.jsp").forward(request,response);
            }

        }else if("doInitModify".equals(action)){
            studentService.initModify(request,response);
            request.getRequestDispatcher("stuInfo.jsp").forward(request,response);

        }else if("doModify".equals(action)){
            studentService.modify(request,response);
            String role = (String) request.getSession().getAttribute("role");

            if("student".equals(role)){
                response.sendRedirect("index.jsp");
            }else if("teacher".equals(role)){
                request.getRequestDispatcher("student?action=doGetStudents&curPage=1").forward(request,response);
            }

        }else if("doGetStudents".equals(action)){
            studentService.getStudents(request,response);
            request.getRequestDispatcher("stuList.jsp").forward(request,response);

        }else if("doDelete".equals(action)){
            studentService.delete(request,response);
            request.getRequestDispatcher("student?action=doGetStudents&curPage=1").forward(request,response);
        }
    }
}
功能判断处理方式

法一:extends HttpServlet,就会实现doGet()、doPost(),在doPost()里获取请求的action,进行if-else判断功能

法二:extends BaseServlet,写一个用来判断功能的BaseServlet,在BaseServlet也就是获取action,不同是利用反射进行获取调用对应功能方法,这样就不用if-else判断,而在ControllerServlet里就是一个个方法,可维护性更高

java 复制代码
package com.qf.servlet;

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 java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class BaseServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //url -- http://localhost:8080/Day24_MVC_war_exploded/user?action=doLogin
        String action = request.getParameter("action");//doLogin

        //获取Controller类的class对象
        Class<? extends BaseServlet> clazz = this.getClass();

        try {
            //根据action获取Controller类对应的方法对象
            Method method = clazz.getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
            //设置操作权限
            method.setAccessible(true);
            //调用方法
            method.invoke(this,request,response);

        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }


    }
}
java 复制代码
package com.ckl.controller;

import com.ckl.service.StudentService;
import com.ckl.service.impl.StudentServiceImpl;
import com.ckl.servlet.BaseServlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/student")
public class StudentController extends BaseServlet {

    private StudentService studentService = new StudentServiceImpl();

    public void doRegister(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
        boolean register = studentService.register(request, response);
        if(register){
            response.sendRedirect("login.jsp");
        }else{
            request.getRequestDispatcher("register.jsp").forward(request,response);
        }
    }

    public void doInitModify(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
        studentService.initModify(request,response);
        request.getRequestDispatcher("stuInfo.jsp").forward(request,response);
    }

    public void doModify(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
        studentService.modify(request,response);
        String role = (String) request.getSession().getAttribute("role");

        if("student".equals(role)){
            response.sendRedirect("index.jsp");
        }else if("teacher".equals(role)){
            request.getRequestDispatcher("student?action=doGetStudents&curPage=1").forward(request,response);
        }
    }

    public void doGetStudents(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
        studentService.getStudents(request,response);
        request.getRequestDispatcher("stuList.jsp").forward(request,response);
    }

    public void delete(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
        studentService.delete(request,response);
        request.getRequestDispatcher("student?action=doGetStudents&curPage=1").forward(request,response);
    }

}

View

页面数据展示,功能匹配ControllerServlet和其中的方法来陆续实现

jsp 复制代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

  <%@ include file="rememberMe.jsp"%>

  ${msg}

  <h1>登录页面</h1>

  <form action="user?action=doLogin" method="post">

    账号:<input type="text" name="username"/><br/>
    密码:<input type="password" name="password"/><br/>
    验证码:<input type="text" name="userCode"/><img src="user?action=doDrawCode" width="120px" height="30px" οnclick="refresh()"><a href="#" οnclick="refresh()">刷新</a><br/>
    记住我:<input type="checkbox" name="rememberMe"/><br/>
    角色:
    <select name="role">
      <option value="student">学生</option>
      <option value="teacher">老师</option>
    </select>
    <br/>
    <input type="submit" value="登录"/>
    <input type="button" value="返回" οnclick="goWelcome()"/>
  </form>

  <script type="text/javascript">
    function goWelcome(){
      window.location = "welcome.html";
    }

    img = document.getElementsByTagName("img")[0];
    function refresh(){
      img.src = "user?action=doDrawCode&" + new Date();
    }
  </script>
</body>
</html>
相关推荐
哪 吒1 小时前
最简单的设计模式,抽象工厂模式,是否属于过度设计?
设计模式·抽象工厂模式
Theodore_10221 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
转世成为计算机大神4 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式
小乖兽技术5 小时前
23种设计模式速记法
设计模式
小白不太白9507 小时前
设计模式之 外观模式
microsoft·设计模式·外观模式
小白不太白9507 小时前
设计模式之 原型模式
设计模式·原型模式
澄澈i7 小时前
设计模式学习[8]---原型模式
学习·设计模式·原型模式
小白不太白95014 小时前
设计模式之建造者模式
java·设计模式·建造者模式
菜菜-plus16 小时前
java 设计模式 模板方法模式
java·设计模式·模板方法模式
萨达大16 小时前
23种设计模式-模板方法(Template Method)设计模式
java·c++·设计模式·软考·模板方法模式·软件设计师·行为型设计模式