Spring MVC前后端数据传输项目实践
目录
任务:
列表页界面设计
编辑
新增操作的界面设计
编辑操作的界面设计
删除操作的界面设计
编辑
操作流程:
新增项目模块
导入相关依赖
配置Web.xml
配置spring-mvc.xml
Model分析
实体类User的实现
User的Vo类的实现
业务分析
业务类UserService的实现
Controller层分析
UserController的实现
控制器向视图传值的方式
使用参数reques和response进行数据分享和页面跳转
编辑
使用控制ModelAndView对象进行数据共享和页面的跳转
编辑
使用Model对象,使用返回的字符串控制页面的跳转,可使用试图解析器自动补充前后缀
编辑
新增与修改GET请求Action的实现
编辑
控制器接收参数的方式
新增、修改POST请求Action的实现
删除请求Action的实现
控制器完整代码:
View层:
列表页技术要点
编辑页技术要点
最后配置tomcat,至此项目就结束了
任务:
使用SpringMVC框架实现用户管理功能
列表页界面设计
新增操作的界面设计
编辑操作的界面设计
删除操作的界面设计
操作流程:
新增项目模块
导入相关依赖
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.flowerfog</groupId>
<artifactId>SpringMvcDemo</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>MvcDataInteraction</artifactId>
<packaging>war</packaging>
<name>MvcDataInteraction Maven Webapp</name>
<url>https://maven.apache.org</url>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<org.springframework.version>6.0.2</org.springframework.version>
<jakarta.servlet-api.version>5.0.0</jakarta.servlet-api.version>
<jakarta.servlet.jsp-api.version>3.0.0</jakarta.servlet.jsp-api.version>
<jakarta.servlet.jsp.jstl-api.version>3.0.1</jakarta.servlet.jsp.jstl-api.version>
<jakarta.servlet.jsp.jstl.version>3.0.1</jakarta.servlet.jsp.jstl.version>
<org.junit.jupiter.api.version>5.3.1</org.junit.jupiter.api.version>
<org.projectlombok.version>1.18.30</org.projectlombok.version>
<jackson-databind.version>2.17.1</jackson-databind.version>
</properties>
<dependencies>
<!--spring web依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!--spring-webmvc依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!--servlet-->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>${jakarta.servlet-api.version}</version>
</dependency>
<!--jsp-->
<dependency>
<groupId>jakarta.servlet.jsp</groupId>
<artifactId>jakarta.servlet.jsp-api</artifactId>
<version>${jakarta.servlet.jsp-api.version}</version>
</dependency>
<dependency>
<groupId>jakarta.servlet.jsp.jstl</groupId>
<artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
<version>${jakarta.servlet.jsp.jstl-api.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jakarta.servlet.jsp.jstl</artifactId>
<version>${jakarta.servlet.jsp.jstl.version}</version>
</dependency>
<!--Jackson依赖-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-databind.version}</version>
</dependency>
<!--junit5测试-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${org.junit.jupiter.api.version}</version>
</dependency>
<!--lombok插件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${org.projectlombok.version}</version>
</dependency>
</dependencies>
<build>
<finalName>MvcDataInteraction</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
配置Web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee">
<display-name>Archetype Created Web Application</display-name>
<!-- 配置DispatcherServlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 自动加载spring-mvc.xml -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<!--当值≥0时,启动时就加载;当值<0或不指定时,则表示第一次请求时加载-->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 配置DispatcherServlet接受所有URL请求 -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 编码过滤器,解决中文乱码问题 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
配置spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="org.flowerfog.service"/>
<context:component-scan base-package="org.flowerfog.controller"/>
<!-- 开启SpringMVC框架的注解驱动 -->
<mvc:annotation-driven/>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--静态资源访问映射路径-->
<mvc:resources location="/static/" mapping="/static/**"/>
</beans>
Model分析
需设计以下类:
①实体类
②Vo类:映射状态
实体类User的实现
package org.flowerfog.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 实体类:用户
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id;
private String name;
private String account;
private String password;
private Integer status;
}
User的Vo类的实现
package org.flowerfog.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.flowerfog.pojo.User;
@EqualsAndHashCode(callSuper = true)
@Data
public class UserVo extends User {
private String stateName;
}
业务分析
业务类UserService的实现
package org.flowerfog.service;
import org.flowerfog.pojo.User;
import org.flowerfog.vo.UserVo;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.util.*;
@Service
public class UserService {
//暂不连数据库,用内存数据演示
static Integer currentId=2;//Id最大值
static Map<Integer, User> users = new HashMap<>();
static{
users.put(1, new User(1, "管理员", "admin", "123456",0));
users.put(2, new User(2, "付祥明", "fxm", "123456",0));
}
public List<UserVo> findAll() {
List<UserVo> vos = new ArrayList<>();
List<User> mos = users.values().stream().toList();
for (User mo : mos) {
UserVo vo = new UserVo();
BeanUtils.copyProperties(mo, vo);
vo.setStatusName(mo.getStatus().equals(0) ? "正常" : "禁用");
vos.add(vo);
}
return vos;
}
public void save(User user){
if(user.getId() == null){
currentId=currentId+1;
user.setId(currentId);
}
users.put(user.getId(), user);
}
public User getById(Integer id){
return users.get(id);
}
public void deleteById(Integer id){
users.remove(id);
}
}
Controller层分析
调用业务层服务,需提供以下Action
列表GET
入参:查询分页条件;出参:vos;页面跳转:列表页
新增GET
入参:无;出参:mo;页面跳转:编辑页
编辑GET
入参:id;出参:mo;页面跳转:编辑页
新增和修改的数据保持POST
入参:User;出参:json;页面跳转:无
根据主键删除实体GET
入参:id;出参:json;页面跳转:无
UserController的实现
package org.flowerfog.controller;
import org.flowerfog.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
UserService userService;
}
控制器向视图传值的方式
控制器一般调用业务层接口获取业务数据
如何传值给视图
原生方式,使用方法的参数reques和response进行数据分享和页面跳转
使用控制ModelAndView对象进行数据共享和页面的跳转
使用Model对象,使用返回的字符串控制页面的跳转,可使用试图解析器自动补充前后缀
返回值为对象类型,一般返回JSON格式的对象字符串
使用参数reques和response进行数据分享和页面跳转
使用控制ModelAndView对象进行数据共享和页面的跳转
使用Model对象,使用返回的字符串控制页面的跳转,可使用试图解析器自动补充前后缀
新增与修改GET请求Action的实现
控制器接收参数的方式
SpringMVC框架中,Controller是用于处理HTTP请求的组件,在HTTP请求中,无论是get请求还是post请求,一般都会携带参数
Controller接收参数的方式有以下三种:
HttpServletRequest接收
方法形参接收
实体类型接收
新增、修改POST请求Action的实现
删除请求Action的实现
控制器完整代码:
package org.flowerfog.controller;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.flowerfog.pojo.User;
import org.flowerfog.service.UserService;
import org.flowerfog.vo.UserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
//1.向页面传值
//1.1.原生方式,使用方法的参数reques和response进行数据分享和页面跳转
@GetMapping("/list1")
public void list1(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
List<UserVo> users = userService.findAll();
request.setAttribute("userList", users);
request.getRequestDispatcher("/WEB-INF/views/user/list.jsp").forward(request, response);
}
@RequestMapping("/list12")
public String list12(HttpSession session){
List<UserVo> users = userService.findAll();
session.setAttribute("userList", users);
return "user/list";
}
@RequestMapping("/list13")
public String list13(HttpServletRequest request){
List<UserVo> users = userService.findAll();
ServletContext ctx = request.getServletContext();
ctx.setAttribute("userList", users);
return "user/list";
}
//1.2.使用控制ModelAndView对象进行数据共享和页面的跳转
@GetMapping("/list2")
public ModelAndView list2() {
ModelAndView mv = new ModelAndView();
List<UserVo> users = userService.findAll();
mv.addObject("userList", users);
mv.setViewName("user/list");
return mv;
}
//1.3.使用Model对象,使用返回的字符串控制页面的跳转,可使用试图解析器自动补充前后缀
@GetMapping("/list3")
public String list3(Model model){
List<UserVo> users = userService.findAll();
model.addAttribute("userList", users);
return "user/list";
}
@GetMapping("/list32")
public String list32(ModelMap model){
List<UserVo> users = userService.findAll();
model.addAttribute("userList", users);
return "user/list";
}
@GetMapping("/list33")
public String list33(Map<String,Object> map){
List<UserVo> users = userService.findAll();
map.put("userList", users);
return "user/list";
}
//1.4.返回值为对象类型,一般返回JSON格式的对象字符串(后续专题学习)
//新增Get
@GetMapping("/add")
public String add(Model model){
User user = new User();
user.setStatus(0);//设置默认值
model.addAttribute("user", user);
return "user/edit";
}
//修改Get
@GetMapping("/edit")
public String edit(Model model,Integer id){
User user = userService.getById(id);
model.addAttribute("user", user);
return "user/edit";
}
//新增与修改的Post
@PostMapping(value="/save")
@ResponseBody
public Object save(@RequestBody User user) {
HashMap<String,Object> ret = new HashMap<>();
try {
userService.save(user);
ret.put("code", 200);
ret.put("msg", "success");
} catch (Exception e) {
ret.put("code", -1);
ret.put("msg", e.getMessage());
}
return ret;
}
//删除Get
@GetMapping("/delete/{id}")
@ResponseBody
public Object delete(@PathVariable Integer id){
HashMap<String,Object> ret = new HashMap<>();
try {
userService.deleteById(id);
ret.put("code", 200);
ret.put("msg", "success");
} catch (Exception e) {
ret.put("code", -1);
ret.put("msg", e.getMessage());
}
return ret;
}
}
View层:
所需静态资源
jQuery
Bootstrap
Bootstrap-table
Layer
业务规划
列表页面
编辑页面
列表页技术要点
静态资源的引入
Bootstrap-table的使用
jQuery的使用
Layer的使用
Ajax的使用
<c:foreach />
弹窗子页面方法的访问
<%--
Created by IntelliJ IDEA.
User: flowerfog
Date: 2024/11/18
Time: 8:55
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
<!-- jquery -->
<script type="text/javascript" src="${pageContext.request.contextPath}/static/jquery-3.6.1.js"></script>
<!-- layer -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/layer/theme/default/layer.css"/>
<script type="text/javascript" src="${pageContext.request.contextPath}/static/layer/layer.js"></script>
<!-- 引入bootstrap -->
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/static/bootstrap/css/bootstrap.css">
<script type="text/javascript" src="${pageContext.request.contextPath}/static/bootstrap/js/bootstrap.js"></script>
<!-- 引入bootstrap-table -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/bootstrap-table/bootstrap-table.css"/>
<script type="text/javascript"
src="${pageContext.request.contextPath}/static/bootstrap-table/bootstrap-table.js"></script>
<script type="text/javascript"
src="${pageContext.request.contextPath}/static/bootstrap-table/locale/bootstrap-table-zh-CN.js"></script>
</head>
<body>
<div class="table-responsive">
<h5 class="text-center">系统用户列表</h5>
<div id="toolbar">
<div class="input-group col-xs-12">
<span class="input-group-btn">
<button class="btn btn-info" onclick="rowAdd()"><span
class="glyphicon glyphicon-plus-sign"></span>新增</button>
</span>
</div>
</div>
<table id="gridTable" class="table table-striped">
<tr>
<th>编号</th>
<th>用户名</th>
<th>登录账号</th>
<th>状态</th>
<th>操作</th>
</tr>
<c:forEach var="item" items="${userList}">
<tr>
<td>${item.id}</td>
<td>${item.name}</td>
<td>${item.account}</td>
<td>${item.statusName}</td>
<td>
<button class="btn btn-info btn-xs" onclick="rowEdit(${item.id})"><span
class="glyphicon glyphicon-edit"></span>编辑
</button>
<button class="btn btn-info btn-xs" onclick="rowDelete(${item.id},'${item.name}')"><span
class="glyphicon glyphicon-remove-circle"></span>删除
</button>
</td>
</tr>
</c:forEach>
</table>
</div>
</body>
<script type="text/javascript">
function rowDelete(id, name) {
let info = '您确定要删除用户:' + name + ' 吗?';
layer.confirm(info, {
title: '操作提示',
icon: 3,
btn: ['确定', '取消']
}, function (index) {
layer.close(index);
$.ajax({
type: "get",
url: "${pageContext.request.contextPath}/user/delete/" + id,
dataType: "json",
cache: false,
async: false,
success: function (rdata) {
if (rdata.code == 200) {
//刷新列表页
window.location.reload();
} else {
// 显示错误
layer.msg(data);
}
},
});
});
}
function rowAdd() {
layer.open({
type: 2,
area: ['550px', '430px'],
title: '新增用户',
content: ['${pageContext.request.contextPath}/user/add', 'no'],
btn: ['确定', '取消'],
yes: function (index, layero) {
//获取弹窗子页面的doSubmit方法并获取其返回值
var iframeWin = layero.find("iframe")[0];
var postData = iframeWin.contentWindow.doSubmit();
//ajax提交数据
$.ajax({
type: "post",
url: "${pageContext.request.contextPath}/user/save",
data: JSON.stringify(postData),
dataType: "json",
contentType: "application/json;charset=UTF-8",
success: function (rdata) {
if (rdata.code == 200) {
//关闭弹窗页
layer.close(index);
//刷新列表页
window.location.reload();
} else {
layer.msg(rdata.msg);
}
}
});
},
cancel: function (index) {
layer.close(index);//关闭弹窗页
}
});
}
function rowEdit(id) {
layer.open({
type: 2,
area: ['550px', '430px'],
title: '编辑用户',
content: ['${pageContext.request.contextPath}/user/edit?id=' + id, 'no'],
btn: ['确定', '取消'],
yes: function (index, layero) {
//获取弹窗子页面的doSubmit方法并获取其返回值
let iframeWin = layero.find("iframe")[0];
let postData = iframeWin.contentWindow.doSubmit();
//ajax提交数据
console.log("ajax提交数据");
$.ajax({
type: "post",
url: "${pageContext.request.contextPath}/user/save",
data: JSON.stringify(postData),
dataType: "json",
contentType: "application/json;charset=UTF-8",
success: function (rdata) {
if (rdata.code == 200) {
//关闭弹窗页
layer.close(index);
//刷新列表页
window.location.reload();
} else {
layer.msg(rdata.msg);
}
}
});
},
cancel: function (index) {
layer.close(index);//关闭弹窗页
}
});
}
</script>
</html>
编辑页技术要点
Bootstrap表单布局
表单项赋初值
<c:if/>的使用
form数据的序列化
<%--
Created by IntelliJ IDEA.
User: flowerfog
Date: 2024/11/18
Time: 8:57
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
<!-- jquery -->
<script type="text/javascript" src="${pageContext.request.contextPath}/static/jquery-3.6.1.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/static/jquery-ext.js"></script>
<!-- layer -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/layer/theme/default/layer.css"/>
<script type="text/javascript" src="${pageContext.request.contextPath}/static/layer/layer.js"></script>
<!-- 引入bootstrap -->
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/static/bootstrap/css/bootstrap.css">
<script type="text/javascript" src="${pageContext.request.contextPath}/static/bootstrap/js/bootstrap.js"></script>
</head>
<body style="margin-left: 10px;margin-right: 10px;">
<form id="form1">
<input type="hidden" name="id" value="${user.id}"/>
<div class="row">
<label class="col-sm-2 col-form-label">用户名 </label>
<div class="col-sm-10">
<input type="text" class="form-control" name="name" placeholder="请输入用户名" value="${user.name}">
</div>
</div>
<div class="row">
<label class="col-sm-2 col-form-label">登录账号</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="account" value="${user.account}">
</div>
</div>
<div class="row">
<label class="col-sm-2 col-form-label">登录密码</label>
<div class="col-sm-10">
<input type="password" class="form-control" name="password" value="${user.password}">
</div>
</div>
<fieldset class="row">
<legend class="col-form-label col-sm-2 pt-0">状态</legend>
<div class="col-sm-10">
<div class="form-check">
<c:if test="${status==0}">
<input class="form-check-input" type="radio" name="status" value="0" checked="checked">
</c:if>
<c:if test="${status!=0}">
<input class="form-check-input" type="radio" name="status" value="0">
</c:if>
<label class="form-check-label">正常</label>
</div>
<div class="form-check">
<c:if test="${status==1}">
<input class="form-check-input" type="radio" name="status" value="1" checked="checked">
</c:if>
<c:if test="${status!=1}">
<input class="form-check-input" type="radio" name="status" value="1">
</c:if>
<label class="form-check-label">禁用</label>
</div>
</div>
</fieldset>
</form>
</body>
<script type="text/javascript">
function doSubmit() {
return $("#form1").serializeObject();
}
</script>
</html>
最后配置tomcat,至此项目就结束了