MVC和三层架构在JavaWeb中的应用实例-CURD
一、MVC模式
MVC设计模式提供了一种按功能对软件进行模块划分的方法。该模式将软件程序分为三个核心模块:模型(Model)、视图(View)和控制器(Controller)。
**模型(Model)**负责管理应用程序的业务数据、定义访问控制以及修改这些数据的业务规则。
**视图(View)**负责与用户进行交互,它从模型中获取数据向用户展示,同时也能将用户请求传递给控制器进行处理。
**控制器(Controller)**负责应用程序中处理用户交互的部分,它从视图中读取数据,控制用户输入,并向模型发送数据。
控制器(serlvlet)用来接收浏览器发送过来的请求,控制器调用模型(Model)来获取数据,比如从数据库查询数据;控制器获取到数据后再交由视图(JSP)进行数据展示。
二、三层架构
三层架构是将我们的项目按照业务逻辑分成了三个层面,分别是业务逻辑层、表现层、数据访问层。三层又分别对应着SSM框架中的Spring、SpringMVC、Mybatis。
数据访问层-dao:完成数据库的访问,对数据库进行CURD操作。
**业务逻辑层-service:**对业务逻辑进行封装,调用数据访问层中基本功能,形成复杂的业务逻辑功能。以用户注册为例,当要注册新用户时,首先会调用数据访问层的selectByName()方法查看用户是否存在,如果不存在再调用数据访问层的insert()方法进行注册(即将用户数据添加到数据库中)。
**表现层-controller:**与用户进行交互,接受用户发起的请求,封装业务实体,调用业务逻辑,响应页面给用户。
三、三层架构与MVC的关系
三层架构主要是为了符合“高内聚,低耦合”思想,把各个功能模块划分为表示层(UI)、业务逻辑层(BLL)和数据访问层(DAL)三层。各层之间采用接口相互访问,并通过对象模型的实体类(Model)作为数据传递的载体。这种划分使得开发人员分工更明确,能够更专注于应用系统核心业务逻辑的分析、设计和开发,从而提高开发效率,有利于项目的更新和维护工作。
MVC模式,即模型(Model)、视图(View)和控制器(Controller),是一个广泛流行的软件设计模式。它的主要目的是实现Web系统的职能分工。Model层实现系统中的业务逻辑,View层负责将信息以图形用户界面的形式呈现给用户,而Controller层则负责确保Model和View的同步,处理用户输入并调用Model和View完成用户的需求。
三层架构主要是基于业务来分的,它关注于整个应用体系的层次结构,强调高内聚和低耦合,以提高开发效率和可维护性。
MVC模式则更多地关注于表现层,即如何更好地组织和展示用户界面和用户的交互,它并不直接涉及业务逻辑或数据访问,而是关注于如何将这两者有效地结合起来,提供一个良好的用户体验。
四、增删查改案例
需求:完成用户数据的增删改查。
1.项目搭建
在实际项目的开发中,用户信息是存放在数据库中的,管理员对用户信息进行管理的过程,无时无刻不涉及到增删改查操作。
- 创建一个javaWeb项目,添加响应的servlet,mysql、jstl的jar包。
<!--servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!--jstl-->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
-
创建一个包domain,在包中新建一个用户实体类User类来映射数据表中的用户的属性;
-
创建一个包utils,在包中新建JDBCUtils工具类用于封装数据库的连接信息;
-
创建一个包dao,在包中新建UserDao类,在该类中编写对数据库进行增删改查的方法。
-
创建一个包service,在包中新建UserService类,在该类中编写对数据进行增删改查的业务方法。
-
创建一个包controller,在包中新建AddServlet,用于接收用户请求和调用service业务逻辑方法,实现数据控制和中转。
2.实现原理
2.1添加数据
当用户点击useList.jsp页面的新增按钮时,会跳转到addUser.jsp页面。用户输入用户信息点击提交,浏览器就会发送一个请求到AddServlet,该请求会携带表单数据,在AddServlet中使用request.getParameter(“”)方法接受到表达数据,然后封装为用户对象,调用service层的添加方法,service层又调用dao层添加数据的方法,最后将数据存入数据库中。
2.2查询数据
2.3修改数据-数据回显
2.4修改数据-修改
修改数据和添加数据复用一个Servlet,在接收数据时判断用户id是否存在,如果存在就表示该请求时修改,就调用修改的方法;如果不存在就是添加数据,就调用添加添加束的方法。
3.实现步骤-后台
3.1准备数据
-- 创建用户表
DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user` (
`user_id` int(0) NOT NULL AUTO_INCREMENT COMMENT '编号',
`user_name` varchar(40) NOT NULL COMMENT '用户名',
`user_cardNo` varchar(18) NOT NULL COMMENT '身份证号',
`user_gender` int(0) NULL COMMENT '性别',
`user_birthday` date NULL DEFAULT NULL COMMENT '出生日期',
`user_phone` varchar(11) NOT NULL COMMENT '联系电话',
`user_pwd` varchar(30) NOT NULL COMMENT '密码',
PRIMARY KEY (`user_id`) ,
);
-- 添加数据
INSERT INTO `tb_user` VALUES (1, '肖遥', '5303000123', 1, '2024-03-27', '1383636437', '123');
INSERT INTO `tb_user` VALUES (2, '美杜莎', '5303000456', 0, '2024-03-20', '1383535468', '321');
INSERT INTO `tb_user` VALUES (3, '小医仙', '540400123', 0, '2024-03-13', '1388345670', '123');
INSERT INTO `tb_user` VALUES (4, '张三', '1233333', 1, '1970-01-01', '133333', '123');
3.2添加业务实体
public class User {
private Integer userId;
private String userName;
private String userPwd;
private String userPhone;
private String userCardNo;
private int userGender;
private Date userBirthday;
//省略getter、setter
}
3.3JDBCUtils
package com.kdf.utils;
import java.sql.*;
public class JDBCUtils {
private static final String DRIVER = "com.mysql.cj.jdbc.Driver";
private static final String URL = "jdbc:mysql://localhost:3306/kdftest";
private static final String NAME = "root";
private static final String PASSWORD = "root";
static {
try {
//加载驱动
Class.forName(DRIVER);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getCon(){
Connection connection = null;
try {
connection = DriverManager.getConnection(URL, NAME, PASSWORD);
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
//释放资源
public static void close(Connection con, PreparedStatement pst, ResultSet rs){
try {
if (con!=null){
con.close();
}
if(pst!=null){
pst.close();
}
if(rs!=null){
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
3.4编写dao层接口
public interface UserDao {
//添加
public int addUser(User user);
//删除
public int delUser(int userId);
//修改
public int updateUser(User user);
//查询
public List<User> queryAll();
//根据id查询
public User queryById(int userId);
}
3.5编写service层接口
public interface UserService {
//添加
public boolean addUser(User user);
//删除
public boolean delUser(int userId);
//修改
public boolean updateUser(User user);
//查询
public List<User> queryAll();
//根据id查询
public User queryById(int userId);
}
3.6实现dao层接口
package com.kdf.dao.impl;
import com.kdf.dao.UserDao;
import com.kdf.domain.User;
import com.kdf.utils.DateUtils;
import com.kdf.utils.JDBCUtils;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
//dao层实现类--访问数据库
public class UserDaoImpl implements UserDao {
//定义连接对象
private Connection con = null;
//定义结果集
private ResultSet rs = null;
//定义预编译对象
private PreparedStatement pst = null;
/**
*
* @param user 传入user对象
* @return 返回受影响的行,大于0表示添加成功
*/
@Override
public int addUser(User user) {
int row = 0;
//获取数据库连接
con = JDBCUtils.getCon();
//编写sql语句,主键自增长可以使用null填充,其余数据使用占位符填充
String sql = "insert into tb_user values(null,?,?,?,?,?,?)";
//预编译sql语句
try {
pst = con.prepareStatement(sql);
//给占位符赋值
pst.setString(1,user.getUserName());
pst.setString(2,user.getUserCardNo());
pst.setInt(3,user.getUserGender());
//数据类型转换
Date sqlDate = DateUtils.util2Sql(user.getUserBirthday());
pst.setDate(4,sqlDate);
pst.setString(5,user.getUserPhone());
pst.setString(6,user.getUserPwd());
//执行更新操作,返回受影响的行
row = pst.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//释放资源
JDBCUtils.close(con,pst,null);
}
//返回受影响的行
return row;
}
@Override
public int delUser(int userId) {
int row = 0;
//获取数据库连接
con = JDBCUtils.getCon();
//编写sql语句,主键自增长可以使用null填充,其余数据使用占位符填充
String sql = "delete from tb_user where user_id = ?";
//预编译sql语句
try {
pst = con.prepareStatement(sql);
//给占位符赋值
pst.setInt(1,userId);
//执行更新操作,返回受影响的行
row = pst.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//释放资源
JDBCUtils.close(con,pst,null);
}
//返回受影响的行
return row;
}
@Override
public int updateUser(User user) {
int row = 0;
//获取数据库连接
con = JDBCUtils.getCon();
//编写sql语句,主键自增长可以使用null填充,其余数据使用占位符填充
String sql = "update tb_user set user_name=?,user_cardno=?,user_gender=?,user_birthday=?,user_phone=? where user_id = ?";
//预编译sql语句
try {
pst = con.prepareStatement(sql);
//给占位符赋值
pst.setString(1,user.getUserName());
pst.setString(2,user.getUserCardNo());
pst.setInt(3,user.getUserGender());
//数据类型转换
Date sqlDate = DateUtils.util2Sql(user.getUserBirthday());
pst.setDate(4,sqlDate);
pst.setString(5,user.getUserPhone());
pst.setInt(6,user.getUserId());
//执行更新操作,返回受影响的行
row = pst.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//释放资源
JDBCUtils.close(con,pst,null);
}
//返回受影响的行
return row;
}
@Override
public List<User> queryAll() {
List<User> list = new ArrayList<>();
//获取数据库连接
con = JDBCUtils.getCon();
//编写sql语句,主键自增长可以使用null填充,其余数据使用占位符填充
String sql = "select * from tb_user";
//预编译sql语句
try {
pst = con.prepareStatement(sql);
//执行查询操作,返回结果集
ResultSet rs = pst.executeQuery();
while(rs.next()){
//将结果集中的记录取出
int user_id = rs.getInt("user_id");
String user_name = rs.getString("user_name");
String user_cardno = rs.getString("user_cardno");
int user_gender = rs.getInt("user_gender");
Date user_birthday = rs.getDate("user_birthday");
String user_phone = rs.getString("user_phone");
String user_pwd = rs.getString("user_pwd");
//创建对象
User user = new User();
user.setUserId(user_id);
user.setUserName(user_name);
user.setUserBirthday(user_birthday);
user.setUserCardNo(user_cardno);
user.setUserGender(user_gender);
user.setUserPwd(user_pwd);
user.setUserPhone(user_phone);
//将对象存入集合中
list.add(user);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
//释放资源
JDBCUtils.close(con,pst,rs);
}
//返回集合
return list;
}
@Override
public User queryById(int userId) {
//创建对象
User user = new User();
//获取数据库连接
con = JDBCUtils.getCon();
//编写sql语句,主键自增长可以使用null填充,其余数据使用占位符填充
String sql = "select * from tb_user where user_id=?";
//预编译sql语句
try {
pst = con.prepareStatement(sql);
pst.setInt(1,userId);
//执行查询操作,返回结果集
ResultSet rs = pst.executeQuery();
if (rs.next()){
//将结果集中的记录取出
int user_id = rs.getInt("user_id");
String user_name = rs.getString("user_name");
String user_cardno = rs.getString("user_cardno");
int user_gender = rs.getInt("user_gender");
Date user_birthday = rs.getDate("user_birthday");
String user_phone = rs.getString("user_phone");
String user_pwd = rs.getString("user_pwd");
user.setUserId(user_id);
user.setUserName(user_name);
user.setUserBirthday(user_birthday);
user.setUserCardNo(user_cardno);
user.setUserGender(user_gender);
user.setUserPwd(user_pwd);
user.setUserPhone(user_phone);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
//释放资源
JDBCUtils.close(con,pst,rs);
}
//返回集合
return user;
}
}
3.7实现service接口
package com.kdf.service.impl;
import com.kdf.dao.UserDao;
import com.kdf.dao.impl.UserDaoImpl;
import com.kdf.domain.User;
import com.kdf.service.UserService;
import java.util.List;
//service接口实现类,调用dao层方法
public class UserServiceImpl implements UserService {
//创建dao层对象 --多态
private UserDao userDao= new UserDaoImpl();
@Override
public boolean addUser(User user) {
return userDao.addUser(user)>0;
}
@Override
public boolean delUser(int userId) {
return userDao.delUser(userId)>0;
}
@Override
public boolean updateUser(User user) {
return userDao.updateUser(user)>0;
}
@Override
public List<User> queryAll() {
return userDao.queryAll();
}
@Override
public User queryById(int userId) {
return userDao.queryById(userId);
}
}
3.8查询所有数据
package com.kdf.controller;
import com.kdf.domain.User;
import com.kdf.service.UserService;
import com.kdf.service.impl.UserServiceImpl;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.util.List;
//查询所有数据
@WebServlet(name = "FindAllServlet", value = "/findAll")
public class FindAllServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//调用查询所有的方法
UserService userService = new UserServiceImpl();
List<User> users = userService.queryAll();
//将集合存入session会话中
request.getSession().setAttribute("users",users);
//重定向到数据展示页面 userList.jsp
response.sendRedirect("userList.jsp");
}
}
3.9添加|修改数据
添加和修改数据可以复用同一个servlet,判断用户id是否存在。
package com.kdf.controller;
import com.kdf.domain.User;
import com.kdf.service.UserService;
import com.kdf.service.impl.UserServiceImpl;
import com.kdf.utils.DateUtils;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.util.Date;
//添加和修改数据可使用同一个servlet
@WebServlet(name = "UpdateServlet", value = "/UpdateServlet")
public class UpdateServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.设置字符编码
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//2.接收表单数据
String user_name = request.getParameter("user_name");
String user_cardno = request.getParameter("user_cardno");
String user_gender = request.getParameter("user_gender");
String user_birthday = request.getParameter("user_birthday");
String user_phone = request.getParameter("user_phone");
String user_pwd = request.getParameter("user_pwd");
String user_id = request.getParameter("user_id");
//3.封装业务实体,传递数据
User user = new User();
user.setUserPhone(user_phone);
user.setUserPwd(user_pwd);
//将String类型转换为Int类型
Integer gender = Integer.valueOf(user_gender);
user.setUserGender(gender);
user.setUserCardNo(user_cardno);
user.setUserName(user_name);
//将String类型转换为Date类型
Date date = DateUtils.String2UtilDate(user_birthday);
user.setUserBirthday(date);
//调用业务层方法
UserService us = new UserServiceImpl();
boolean b = false;
//如果id不等于null,就表示做的是修改操作,
if(user_id!=null &&user_id!=""){
user.setUserId(Integer.valueOf(user_id));
b = us.updateUser(user);//修改
}else{
b = us.addUser(user);
}
if(b){
//修改成功转发到查询所有数据servlet
request.getRequestDispatcher("/findAll").forward(request,response);
}else {
//添加失败重定向到添加页面
response.getWriter().append("添加失败");
response.sendRedirect("addUser.jsp");
}
}
}
3.10删除数据
package com.kdf.controller;
import com.kdf.service.impl.UserServiceImpl;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
//删除数据
@WebServlet(name = "DelServlet", value = "/delServlet")
public class DelServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置字符编码
request.setCharacterEncoding("utf-8");
//接收页面传递的id
String id = request.getParameter("id");
//调用删除方法
UserServiceImpl userService = new UserServiceImpl();
boolean b = userService.delUser(Integer.valueOf(id));
if (b){
//删除成功调用查询所有的servlet
request.getRequestDispatcher("/findAll").forward(request,response);
}
}
}
3.11修改数据
修改数据时,先通过id查询到需要修改的对象,然后将对象传入修改页面显示,再进行修改,所以先调用findByIdServlet。
修改数据的Servlet参看3.9添加|修改数据
package com.kdf.controller;
import com.kdf.domain.User;
import com.kdf.service.impl.UserServiceImpl;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
//查询单个对象
@WebServlet(name = "FindByIdServlet", value = "/FindByIdServlet")
public class FindByIdServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置字符编码
request.setCharacterEncoding("utf-8");
//接收页面传递的id
String id = request.getParameter("id");
//调用删除方法
UserServiceImpl userService = new UserServiceImpl();
User user = userService.queryById(Integer.valueOf(id));
//对象存session
request.getSession().setAttribute("user",user);
//重定向到修改页面
response.sendRedirect("updateUser.jsp");
}
}
4.实现步骤-页面
4.1userList.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
<title>用户信息</title>
</head>
<body>
<input type="button" value="新增" id="add"><br>
<hr>
<table border="1" cellspacing="0" width="80%">
<tr>
<th>序号</th>
<th>姓名</th>
<th>省份证号</th>
<th>性别</th>
<th>生日</th>
<th>电话</th>
<th>操作</th>
</tr>
<c:forEach items="${users}" var="user" varStatus="status">
<tr align="center">
<td>${user.userId}</td>
<td>${user.userName}</td>
<td>${user.userCardNo}</td>
<%--判断性别--%>
<c:if test="${user.userGender == 1}">
<td>男</td>
</c:if>
<c:if test="${user.userGender == 0}">
<td>女</td>
</c:if>
<td>${user.userPhone}</td>
<td><fmt:formatDate value="${user.userBirthday}"/></td>
<td><a href="delServlet?id=${user.userId}">删除</a>
<a href="FindByIdServlet?id=${user.userId}">修改</a>
</td>
</tr>
</c:forEach>
</table>
<script>
//点击添加按钮,跳转到addUser.jsp页面
document.getElementById("add").οnclick=function (){
location.href="addUser.jsp";
}
</script>
</body>
</html>
4.2addUser.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加用户</title>
</head>
<body>
<h3>添加用户</h3>
<form action="UpdateServlet" method="post">
用户姓名:<input name="user_name" id="username"><br>
用户密码:<input type="password" name="user_pwd"><br>
身份证号:<input name="user_cardno"><br>
用户性别:
<input type="radio" name="user_gender" value="1"> 男
<input type="radio" name="user_gender" value="0"> 女<br>
用户生日:<input type="text" name="user_birthday"><br>
用户电话:<input type="text" name="user_phone"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
4.3updateUser.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>修改用户</title>
</head>
<body>
<h3>修改用户</h3>
<form action="UpdateServlet" method="post">
<%--隐藏域,提交id--%>
<input type="hidden" name="user_id" value="${user.userId}">
用户姓名:<input name="user_name" value="${user.userName}"><br>
用户密码:<input type="hidden" name="user_pwd"value="${user.userPwd}">
身份证号:<input name="user_cardno" value="${user.userCardNo}"><br>
用户性别:
<c:if test="${user.userGender==1}">
<input type="radio" name="user_gender" value="1" checked> 男<br>
<input type="radio" name="user_gender" value="0" > 女<br>
</c:if>
<c:if test="${user.userGender==0}">
<input type="radio" name="user_gender" value="1" > 男<br>
<input type="radio" name="user_gender" value="0" checked> 女<br>
</c:if>
用户生日:<input type="text" name="user_birthday" value="${user.userBirthday}">
用户电话:<input type="text" name="user_phone" value="${user.userPhone}">
<input type="submit" value="提交">
</form>
</body>
</html>
两岸猿声啼不住,轻舟已过万重山!