MVC、三层架构
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方法@Overrideprotected 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=addString 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中的idString 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 {@Overridepublic 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;}@Overridepublic 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);}}@Overridepublic 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);}}@Overridepublic 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;}@Overridepublic 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();@Overridepublic List<Student> selectAll() {return studentDao.selectAll();}@Overridepublic void deleteById(Integer id) {studentDao.deleteById(id);}@Overridepublic void add(Student student) {studentDao.add(student);}@Overridepublic Student selectById(Integer id) {return studentDao.selectById(id);}@Overridepublic 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中调用方法传入参数时直接进行转换