MVC、三层架构

发布于:2025-09-02 ⋅ 阅读:(16) ⋅ 点赞:(0)

1、MVC

MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范。
用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。
最简单的、最经典就是JSP(view) +Servlet(controller) + JavaBean(model)
视图和逻辑隔离开来
单一职责

控制器是核心
M(Model) 模型 JavaBean
V(View) 视图 Html、JSP、Thymeleaf、Volicity、Freemaker
C(Control) 控制器 Servlet,Controller
1.当控制器收到来自用户的请求
2.控制器调用业务层完成JavaBean数据封装
3.完成业务后通过控制器跳转JSP页面的方式给用户反馈信息
4.JSP个用户做出响应。

什么是JavaBean
JavaBean:一种规范,表达实体和信息的规范,便于封装重用
1.所有属性为private
2.提供默认无参构造方法
3.提供getter和setter
undefined.实现serializable接口

2、三层架构

在这里插入图片描述
在这里插入图片描述
1.Controller:负责控制,拿到View传递过来的数据,封装之后交给Service处理,Service处理完了之后,Controller拿到结果之后,将结果交给界面。
2.Service:业务逻辑(分页,为了完成分页就要调用两次DAO层)
3.Dao:纯粹的JDBC的增删改查操作
上一层可以调用下一层所有代码,并不是StudentServlet只能调用IStudentService代码,也可以调用ITeacherService代码

@WebServlet("/student")
public class StudentServlet extends HttpServlet {
    private IStudentService studentService = new StudentServiceImpl();
    private ITeacherService teacherService = new TeacherServiceImpl();
    
}

@Service
public class StudentServiceImpl implements IStudentService {
    private IStudentDao studentDao = new StudentDaoImpl();
    private ITeacherDao teacherDao = new TeacherDaoImpl();
    
}

public class StudentDaoImpl implements IStudentDao {

}

先改为两层:
即控制层(controller或servlet)直接调用Dao层
该案例中逻辑层作用不明显,因为也是直接调用Dao
但是当存在复杂逻辑时(如分页),逻辑层必不可少

package com.easy.web.servlet;

import com.easy.web.dao.IStudentDao;
import com.easy.web.dao.impl.StudentDaoImpl;
import com.easy.web.pojo.Student;
import com.easy.web.util.JDBCUtil;

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.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;



//将list数据放入req中
//浏览器请求服务器,服务器查询数据库返回数据

//取名字用于访问
@WebServlet("/student")
//继承什么就是什么
public class StudentServlet extends HttpServlet {

    private IStudentDao studentDao = new StudentDaoImpl();

    //访问servlet的时候默认访问service方法
    //需要重写父类中的service方法
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        System.out.println("StudentServlet.service");
        //像之前那样写的话一个类光增删改查就需要写四个servlet,如果有十个类就至少需要四十个servlet
        //所以我们用switch(method)在一个servlet中即可包含增删改查
        //http://localhost:8080/student?method=selectAll
        //http://localhost:8080/student?method=deleteById&id=
        //http://localhost:8080/student?method=add
        String method = req.getParameter("method");
        if (method == null || method.equals("")) {
            method = "selectAll";
        }
        switch (method) {
            case "selectAll":
                selectAll(req,resp);
                break;
            case "deleteById":
                deleteById(req,resp);
                break;
            case "add":
                add(req,resp);
                break;
            case "toUpdate":
                toUpdate(req,resp);
                break;
            case "update":
                update(req,resp);
                break;
        }



    }

    //完成update后台操作
    private void update(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        System.out.println("StudentServlet.update");

        String id = req.getParameter("id");
        String name = req.getParameter("name");
        String age = req.getParameter("age");
        String gender = req.getParameter("gender");

        Student student = new Student(Integer.parseInt(id),name, Integer.parseInt(age),gender);
        studentDao.update(student);

        resp.sendRedirect("/student");

    }

    //toUpdate是为了去后台拿数据,用于数据回显,是update的一个中间过程
    //实际上即为根据id来查找
    private void toUpdate(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //通过selectAll代码修改的
        System.out.println("StudentServlet.toUpdate");
        //拿出request中的id
        String id = req.getParameter("id");


        Student student = studentDao.selectById(Integer.parseInt(id));

        //(设置属性)
        req.setAttribute("student",student);
        //转发到student_update.jsp页面进行数据回显
        req.getRequestDispatcher("student_update.jsp").forward(req,resp);

    }

    private void add(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        System.out.println("StudentServlet.add");

        String name = req.getParameter("name");
        String age = req.getParameter("age");
        String gender = req.getParameter("gender");

        //这里为了好看,在Student类中多弄了一个专门的构造方法
        //实际上也可以直接用无参的构造方法,然后通过set方法设置
        Student student = new Student(name,Integer.parseInt(age),gender);
        studentDao.add(student);

        //更新类的操作,同样也需要重定向
        resp.sendRedirect("/student");
    }

    private void deleteById(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        //打印方法名,即使结果没有达到预期效果,你也可以知道是否进行了正常的访问
        System.out.println("StudentServlet.deleteById");
        //访问delteStudent之后,我们需要拿到id值才能去删除
        //拿任何参数都是到req中通过getParameter拿,返回值都是String类型
        String id = req.getParameter("id");

        //调用deleteById方法
        studentDao.deleteById(Integer.parseInt(id));

        //重定向 302请求
        //通过resp将重定向的地址告诉浏览器,浏览器自动发送请求
        //修改(添加、删除)完数据后重定向到“student”页面,将修改后的数据展示出来
        //即修改数据后,又会到StudentServlet,自动查找所有数据,转发到页面进行展示

        //resp.sendRedirect("/student");
        resp.sendRedirect("/student?method=selectAll");
    }

    private void selectAll(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("StudentServlet.selectAll");

        List<Student> list = studentDao.selectAll();


        //将list数据放入req
        //(设置属性)
        req.setAttribute("list",list);
        //转发到student_list.jsp页面进行展示
        //(把请求分发)
        req.getRequestDispatcher("student_list.jsp").forward(req,resp);
    }
}

package com.easy.web.dao.impl;

import com.easy.web.dao.IStudentDao;
import com.easy.web.pojo.Student;
import com.easy.web.util.JDBCUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

//impl即为实现类
//实现原本直接实现在servlet层中的逻辑代码,通过调用的方式实现业务逻辑,可实现复用,且可以简化servlet层代码
public class StudentDaoImpl implements IStudentDao {
    @Override
    public List<Student> selectAll() {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        //扩大作用域,下面要将list数据放到req中
        List<Student> list = new ArrayList<>();
        try {
            //利用工具类方法获取连接
            connection = JDBCUtil.getConnection();
            String sql = "SELECT id,name,age,gender FROM student";
            preparedStatement = connection.prepareStatement(sql);
            resultSet = preparedStatement.executeQuery();
            //因为在这里声明的list只能在try的大括号里面使用,下面拿不到,所以需要在try上面声明list,扩大作用域
            //List<Student> list = new ArrayList<>();
            while (resultSet.next()) {
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                int age = resultSet.getInt("age");
                String gender = resultSet.getString("gender");
                Student student = new Student(id, name, age, gender);
                list.add(student);
            }
            for (Student student : list) {
                System.out.println(student);
            }
        }
        //ClassNotFoundException在JDBCUtil静态代码块中已被捕获,所以不需要在这里再捕获了
        catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtil.close(connection, preparedStatement, resultSet);
        }

        return list;
    }

    @Override
    public void deleteById(Integer id) {

        Connection connection = null;
        PreparedStatement preparedStatement = null;
        //不是查询类,没有结果集

        try {
            connection = JDBCUtil.getConnection();
            String sql = "DELETE FROM student WHERE id=?";
            //一个一个填补括号中的“?”
            preparedStatement = connection.prepareStatement(sql);
            //用Integer.parseInt(id)将id转为int类型
            preparedStatement.setInt(1,id);
            //打印出来,显示在执行什么语句(非必须)
            System.out.println(preparedStatement);

            //返回影响行数
            int count = preparedStatement.executeUpdate();
            System.out.println("count: " + count);

        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtil.close(connection,preparedStatement,null);
        }
    }

    @Override
    public void add(Student student) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        //不是查询类,没有结果集

        try {
            connection = JDBCUtil.getConnection();
            String sql = "INSERT INTO student(name,age,gender) VALUES(?,?,?)";
            //一个一个填补括号中的“?”
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,student.getName());
            preparedStatement.setInt(2,student.getAge());
            preparedStatement.setString(3,student.getGender());
            //打印出来,显示在执行什么语句(非必须)
            System.out.println(preparedStatement);

            //返回影响行数
            int count = preparedStatement.executeUpdate();
            System.out.println("count: " + count);

        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtil.close(connection,preparedStatement,null);
        }
    }

    @Override
    public Student selectById(Integer id) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        //在这里不再是封装成list集合,封装为一个student对象即可
        Student student = null;
        try {
            connection = JDBCUtil.getConnection();
            String sql = "SELECT id,name,age,gender FROM student WHERE id=?";
            preparedStatement = connection.prepareStatement(sql);
            //填补“?”
            preparedStatement.setInt(1,id);
            System.out.println(preparedStatement);

            resultSet = preparedStatement.executeQuery();
            while (resultSet.next()) {
                String name = resultSet.getString("name");
                int age = resultSet.getInt("age");
                String gender = resultSet.getString("gender");
                student = new Student(id, name, age, gender);
            }
        }         //ClassNotFoundException在JDBCUtil静态代码块中已被捕获,所以不需要在这里再捕获了
        catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtil.close(connection, preparedStatement, resultSet);
        }

        return student;
    }

    @Override
    public void update(Student student) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        //不是查询类,没有结果集

        try {
            connection = JDBCUtil.getConnection();
            String sql = "UPDATE student SET name=?,age=?,gender=? WHERE id=?";
            //一个一个填补括号中的“?”
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,student.getName());
            preparedStatement.setInt(2,student.getAge());
            preparedStatement.setString(3,student.getGender());
            preparedStatement.setInt(4,student.getId());
            //打印出来,显示在执行什么语句(非必须)
            System.out.println(preparedStatement);

            //返回影响行数
            int count = preparedStatement.executeUpdate();
            System.out.println("count: " + count);

        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtil.close(connection,preparedStatement,null);
        }
    }
}

package com.easy.web.dao;

import com.easy.web.pojo.Student;

import java.util.List;

//Dao数据访问层
//分离数据访问逻辑与业务逻辑,降低两者之间的耦合度。
//接口里面列出来的是能提供的所有功能的清单
public interface IStudentDao {
    //有关Student类的方法(增删改查)
    List<Student> selectAll();
    void deleteById(Integer id);
    void add(Student student);
    Student selectById(Integer id);
    void update(Student student);
}

改为三层:

package com.easy.web.service.impl;

import com.easy.web.dao.IStudentDao;
import com.easy.web.dao.impl.StudentDaoImpl;
import com.easy.web.pojo.Student;
import com.easy.web.service.IStudentService;

import java.util.List;

public class StudentServiceImpl implements IStudentService {
    //在逻辑层调用Dao层
    private IStudentDao studentDao = new StudentDaoImpl();

    @Override
    public List<Student> selectAll() {
        return studentDao.selectAll();
    }

    @Override
    public void deleteById(Integer id) {
        studentDao.deleteById(id);
    }

    @Override
    public void add(Student student) {
        studentDao.add(student);
    }

    @Override
    public Student selectById(Integer id) {
        return studentDao.selectById(id);
    }

    @Override
    public void update(Student student) {
        studentDao.update(student);
    }
}

package com.easy.web.service;

import com.easy.web.pojo.Student;

import java.util.List;

public interface IStudentService {
    //有关Student类的方法(增删改查)
    //与Dao层相同
    List<Student> selectAll();
    void deleteById(Integer id);
    void add(Student student);
    Student selectById(Integer id);
    void update(Student student);
}

控制层代码只是调用对象发生了改变

public class StudentServlet extends HttpServlet {

    //private IStudentDao studentDao = new StudentDaoImpl();
    //改为三层实现
    //在控制层调用逻辑层而不直接调用Dao层
    private IStudentService studentService = new StudentServiceImpl();

Dao代码没有改变

ps:
1、在接口定义中,查询类方法有返回值,修改类方法没有
2、关于id等参数的类型转换,需在控制层即servlet或者controller中调用方法传入参数时直接进行转换


网站公告

今日签到

点亮在社区的每一天
去签到