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中调用方法传入参数时直接进行转换