springmvc 通篇学习
SpringMVC基础
- Spring web mvc
- 是Spring的一部分
- 基于MVC的开发模式,用来优化控制器,是Spring家族的一员
- 具备IOC和AOP
- MVC
- 一种开发模式
- 模型,视图,控制器的简称
- 所有的web应用都是基于MVC的开发
- M: 模型层 包含实体类 业务逻辑层 数据访问层的Model
- V: 视图层 包含html javaScript vue 等都是视图层,用来显示数据 (view)
- C: 控制器 用来接收用户的请求,并返回到客户端组件, Servlet就是组件 (controller)
- 框架总结:
- SSM
- Spring 是一种容器,整合其他框架的框架
- SpringMVC 基于MVC开发模式,优化控制器
- MyBatis 优化数据访问层的,JDBC,sql语句
- SSH(了解)
- Spring
- Struts2 (SpringMVC)
- Hibernate(MyBatis)
- SSM
- SpringMVC的优点
- 第一点: 轻量级的框架
- 第二点: 基于MVC的框架
- 第三点: 易上手,容易理解
- 第四点: 功能强大
- 第五点: 具备IOC和AOP
- 第六点: 完全基于注解式开发
基于SpringMVC的开发步骤
- 开发步骤:
- 第一步:新建项目,选择webapp的模板, 修改目录
- 第二步: 修改目录,添加缺失的test,java,resources(两套),并修改目录属性
- 第三步: 修改pom.xml文件,添加SpringMVC的依赖,添加Servlet的依赖
- 第四步: 添加SpringMVC.xml的配置文件,指定包扫描,添加视图解析器
- 第五步: 删除web.xml文件,新建web.xml
- 第六步: 在web.xml文件中注册SpringMVC框架(所有的web请求都是基于servlet的)
- 第七步: 在webapp文件下新建admin目录,在admin目录下新建main.jsp页面, 删除index.jsp页面,并新建,发送请求给服务器
- 第八步: 开发控制器(Servlet),它是一个普通的类
- 第九步: 添加Tomcat进行测试功能
pom.xml
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--添加SpringMVC的框架-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.9</version>
</dependency>
<!--添加Servlet的依赖-->
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
springmvc.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--添加包扫描-->
<context:component-scan base-package="org.example.controller"/>
<!--添加视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--配置前缀-->
<property name="prefix" value="/admin/"/>
<!--配置后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
web.xml DispatcherServlet需要在web.xml文件中注册才可以
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--注册SpringMVC的框架-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>
分析web请求
- web请求的执行流程
- index.jsp <----------------------------------->DispatcherServlet<---------------------------> servlet SpringMVC处理器是一个普通的类
- one.jsp <-------------------------------------->DispatcherServlet<---------------------------> servlet SpringMVC处理器是一个普通的类
DispatcherServlet需要在web.xml文件中注册才可以
@RequestMapping注解
此注解就是来映射服务器访问的路径
-
第一: 此注解可以加载在方法上,为此方法注册一个可以访问的名称(路径)
@RequestMapping("/demo.action") public String demo() { System.out.println("服务器被访问到了........."); return "main"; //可以直接跳到/admin/main.jsp目录下 } <a href="${pageContext.request.contextPath}/demo.action">访问服务器</a> -
第二: 此注解可以加载在类上,相当于包名( 虚拟路径 )
- 区分不同类中的action
@Controller //交给spring容器创建对象 @RequestMapping("/zar") public class DemoAction1 { /** * action中所有的功能实现都是由方法来完成的 * action方法的规范 * 1,访问权限是public * 2,方法的返回值是 任意 * 3,方法名称 任意 * 4,方法可以没有参数,如果没有则可以是任意类型 * 5,要使用@RequestMapping注解声明一个访问的路径(名称) */ @RequestMapping("/demo.action") public String demo() { System.out.println("服务器被访问到了........."); return "main"; //可以直接跳到/admin/main.jsp目录下 } } <a href="${pageContext.request.contextPath}/zar/demo.action">z访问服务器</a> -
第三: 此注解可以区分get请求和post请求
@Controller public class RequestAction { @RequestMapping(value = "/req.action", method = RequestMethod.GET) public String req() { System.out.println("我是处理get请求的......."); return "main"; } @RequestMapping(value = "/req.action", method = RequestMethod.POST) public String req1() { System.out.println("我是处理post请求的......."); return "main"; } }
SpringMVC请求处理
- action 所做之事
- Spring MVC中每个控制器中可以定义多个请求处理方法,我们把这种请求处理方法简称为Action,每个请求处理方法可以有多个不同的参数,以及一个多种类型的返回结果
action-5种数据的提交方式
-
第一种: 散提交数据
- 参数为基本数据类型,且名称与请求参数名称相同,则会进行自动映射
1,单个数据提交
@Controller
public class DataSubmitAction {
@RequestMapping("/one.action")
public String one(String myName,int age) {
System.out.println("myName = " + myName + "," + "age = " + (age + 100));
return "main";
}
}
- 第二种: 对象封装提交数据
- 在提交请求中,保证请求参数的名称与实体类中成员变量的名称一致,则可以自动创建对象,则可以自动提交数据,自动类型转换,自动封装数据到对象中
```java
<h2>2,对象封装提交</h2>
<form action="${pageContext.request.contextPath}/two.action">
姓名:<input name="name"/><br>
年龄:<input name="age"/><br>
<input type="submit" value="提交"/>
</form>
@RequestMapping("/two.action")
public String two(Users users) {
System.out.println(users);
return "main";
}
-
第三种: 动态占位符提交(用得少) Restful风格
-
仅限于超链接或者地址栏提交数据
-
它是一杠一值,一杠一大括号,使用注解@PathVariable解析
<br> <h2>3,动态占位符</h2> <a href="${pageContext.request.contextPath}/three/张三/22.action"> 动态提交 </a> @RequestMapping("/three/{uname}/{uage}.action") public String three( @PathVariable("uname") String name, @PathVariable("uage") int age ) { System.out.println("name = " + name + "," + "age = " + (age + 100)); return "main"; }
-
-
第四种: 映射名称不一致
-
提交请求参数与action方法的形参的名称不一致,使用注解@RequestParam来解析
<br> <h2>4,参数名称不一致解决方案</h2> <form action="${pageContext.request.contextPath}/four.action"> 姓名:<input name="name"/><br> 年龄:<input name="age"/><br> <input type="submit" value="提交"/> </form> /** * 姓名:<input name="name"/><br> * 年龄:<input name="age"/><br> * */ @RequestMapping("/four.action") public String four( @RequestParam("name") String uname, @RequestParam("age") int uage) { System.out.println("uname = " + uname + "," + "age = " + (uage + 100)); return "main"; }
-
-
第五种: 手工提取数据
<h2>5,手工提取数据</h2> <form action="${pageContext.request.contextPath}/five.action"> 姓名:<input name="name"/><br> 年龄:<input name="age"/><br> <input type="submit" value="提交"/> </form> @RequestMapping("/five.action") public String five(HttpServletRequest request) { String name = request.getParameter("name"); int age = Integer.parseInt(request.getParameter("age")); System.out.println("name = " + name + "," + "age = " + (age + 100)); return "main"; }
action-方法的返回值
-
第一种:
-
String
-
客户端资源的地址 ,自动拼接前缀和后缀
-
还可以屏蔽自动拼接字符串,可以指定返回的路径
-
-
第二种:
-
Object
-
返回json格式的对象,自动将对象或集合转为json,使用的jackson工具进行转换,必须要添加jackson的依赖
-
一般用于ajax请求
-
-
第三种:
-
void
-
无返回值
-
一般用于ajax请求
-
-
第四种:
-
基本数据类型
-
用于ajax请求
-
-
第五种:
- ModeAndView
- 返回数据和视图
- 用的很少了
完成ajax请求访问服务器
-
返回学生集合
-
步骤:
-
第一步: 添加jackson依赖
-
第二步: 在webapp的目录下,新建js目录,添加jQuery的函数库
-
第三步: 在index.jsp页面上导入函数库
-
第四步: 在action上添加注解@ResponseBody, 专门用来处理ajax请求
-
@RestController //如果本类中全部是ajax请求,则使用此注解在类上,方法上的@ResponseBody可以不写
-
-
第五步: 在springmvc.xml文件中添加注解驱动<mvc: annotationdriven> ,用来解析@ResponseBody注解
-
前端页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>欢迎界面</title>
<%--在页面上导入jQuery的函数库--%>
<script src="js/jquery-3.6.0.js"></script>
</head>
<body>
<br><br><br>
<a href="javascript:showStu()">访问服务器返回学生集合</a>
<div id="mydiv">等待服务器返回数据</div>
<script type="text/javascript">
function showStu() {
//使用jQuery封装的ajax请求发送数据
$.ajax({
url:"${pageContext.request.contextPath}/list.action",
type:"get",
dataType:"json",
success:function (stuList) {
var s = "";
$.each(stuList,function(i,stu){
s+=stu.name + "-----" + stu.age + "<br>";
});
//回显数据
$("#mydiv").html(s);
}
});
}
</script>
</body>
</html>
后端代码:
@Controller
public class StudentListAction {
@RequestMapping("/list.action")
@ResponseBody //解析ajax的请求,必须要在springmvc.xml文件中添加注解驱动
public List<Student> list() {
List<Student> list = new ArrayList<>();
Student stu1 = new Student("张三", 23);
Student stu2 = new Student("李四", 24);
Student stu3 = new Student("王五", 25);
list.add(stu1);
list.add(stu2);
list.add(stu3);
return list; //springmvc框架负责将集合转为json数组,自动转
}
}
配置文件:
<!--添加包扫描-->
<context:component-scan base-package="org.example.controller"/>
<!--不用添加视图解析器,因为处理的是ajax请求-->
<!--必须要添加注解驱动,专门用来处理ajax请求的-->
<mvc:annotation-driven/>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--添加中文乱码的解决方案-->
<filter>
<filter-name>encode</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>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encode</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--注册springmvc-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>
SpringMVC的四种跳转方式
-
请求转发
- 是基于服务器的跳转
@Controller
public class JumpAction {
@RequestMapping("/one.action")
public String one() {
System.out.println("这是请求转发页面跳转");
return "main"; //默认请求转发,,使用试图解析器拼接前缀,后缀进行页面的跳转
}
@RequestMapping("/two.action")
public String two() {
System.out.println("这是请求转发页面action");
return "forward:/other.action"; //默认请求转发,,使用试图解析器拼接前缀,后缀进行页面的跳转
// forward: 可以屏蔽前缀和后缀
}
- **重定向**
- 是基于客户端的跳转
```java
<a href="${pageContext.request.contextPath}/three.action">3,请求重定向页面</a><br>
<a href="${pageContext.request.contextPath}/four.action">4,请求重定向action</a><br>
<a href="${pageContext.request.contextPath}/five.action">5,随便跳页面</a><br>
@RequestMapping("/three.action")
public String three() {
System.out.println("这是重定向页面.......");
//redirect: 可以屏蔽前缀和后缀
//实现重定向跳转
return "redirect:/admin/main.jsp"; //默认请求转发,,使用试图解析器拼接前缀,后缀进行页面的跳转
}
@RequestMapping("/four.action")
public String four() {
System.out.println("这是重定向页面action.......");
//redirect: 可以屏蔽前缀和后缀
//实现重定向跳转
return "redirect:/other.action"; //默认请求转发,,使用试图解析器拼接前缀,后缀进行页面的跳转
}
@RequestMapping("/five.action")
public String five() {
System.out.println("这是随便跳页面.......");
//redirect: 可以屏蔽前缀和后缀
//实现重定向跳转
return "forward:/fore/login.jsp"; //默认请求转发,,使用试图解析器拼接前缀,后缀进行页面的跳转
}
请求转发和重定向的区别
转发: forward
重定向: redirect
1、请求次数
重定向是浏览器向服务器发送一个请求并收到响应(302 响应码)后再次向一个新地址发出请求,转发是服务器收到请求后为了完成响应跳转到一个新的地址;重定向至少请求两次,转发请求一次;
2、地址栏不同
重定向地址栏会发生变化,转发地址栏不会发生变化;
3、是否共享数据
重定向两次请求不共享数据,转发一次请求共享数据(在request级别使用信息共享,使用重定向必然出错);
4、跳转限制
重定向可以跳转到任意URL,转发只能跳转本站点资源;
5、发生行为不同
重定向是客户端行为,转发是服务器端行为;
SpringMVC的中文乱码解决方案
配置过滤器
force : 强转
<!--中文编码过滤器-->
<filter>
<filter-name>encode</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>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encode</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
默认参数类型
- SpringMVC的默认参数类型
- 常见的参数
- 不需要创建,直接拿来使用即可
- HttpServletRequet
- HttpServletResponse
- HttpSession
- Model
- Map
- ModelMap
注意:Map Model ModelMap 和request一样,都是使用请求作用域,所以服务端的跳转必须是请求转发
index.jsp
<br>
<a href="${pageContext.request.contextPath}/data.action?name=zar">访问服务器,进行数据携带跳转</a>
main.jsp
<h2>main.............显示数据</h2><br>
requestUsers:${requestUsers}<br>
session:${session}<br>
modelUsers:${modelUsers}<br>
mapUsers:${mapUsers}<br>
modelMapUsers:${modelMapUsers}<br>
从index.jsp页面来的数据${param.name}
DataAction
@Controller
public class DataAction {
@RequestMapping("/data.action")
public String data(HttpServletRequest request,
HttpServletResponse response,
HttpSession session,
Model model,
Map map,
ModelMap modelMap) {
//做一个数据,传到main.jsp页面上
Users users = new Users("张三", 34);
//传递数据
request.setAttribute("requestUsers",users);
session.setAttribute("session",users);
model.addAttribute("modelUsers", users);
map.put("mapUsers", users);
modelMap.addAttribute("modelMapUsers", users);
return "main"; //请求方式跳转
}
}
日期处理
第一: 日期的提交处理
-
A,单个日期处理
-
使用注解@DateTimeFormat,此注解必须搭配springmvc.xml中的<mvc: annotationdriven>标签
index.jsp
<br><br><br><br> <form action="${pageContext.request.contextPath}/mydate.action"> 日期:<input type="date" name="mydate"/><br> <input type="submit" value="提交"/> </form>MyDateAction
@Controller public class MyDateAction { SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd"); @RequestMapping("/mydate.action") public String mydate( @DateTimeFormat(pattern = "yyyy-MM-dd") Date mydate) { System.out.println(mydate); System.out.println(sf.format(mydate)); return "show"; } }
-
-
同样也可以在实体类的属性上添加或者setxxx方法上加注解
Student实体类
public class Student {
private String name;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthday;
-
json中的日期处理
-
同样也可以在实体类的属性上添加或者getxxx方法上加注解
@JsonFormat(pattern = "yyyy-MM-dd") public Date getBirthday() { return birthday; }
-
-
B,类中全局处理
-
注册一个注解,用来解析本类中的所有日期类型,自动转换
-
@InitBinder
//注册一个全局的日期处理注解 @InitBinder public void initBander(WebDataBinder dataBinder) { dataBinder.registerCustomEditor(Date.class,new CustomDateEditor(sf,true)); } @RequestMapping("/mydate.action") public String mydate(Date mydate) { System.out.println(mydate); System.out.println(sf.format(mydate)); return "show"; }
-
第二: 日期的显示处理
-
需求: 在页面上显示好看的日期,必须使用JSTL
- 步骤:
- 在页面上添加jstl依赖
- 在页面上导入标签库
- 使用标签显示数据
- 步骤:
-
如果是单个日期的对象,直接转为好看的格式化的字符串进行显示
@RequestMapping("/mydate.action") public String mydate(Date mydate, HttpServletRequest request) { System.out.println(mydate); System.out.println(sf.format(mydate)); request.setAttribute("mydate",sf.format(mydate)); return "show"; } -
如果是list中的实体类对象的成员变量是日期类型,则必须使用jstl进行显示
- 步骤:
- 在页面上添加jstl依赖
- 在页面上导入标签库
- 使用标签显示数据
show.jsp
<%--导入jstl的核心标签库--%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%--导入jstl的格式化标签库--%> <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <br> <%--显示学生集合--%> <table width="800px" border="1px"> <tr> <th>姓名</th> <th>生日</th> </tr> <c:forEach items="${list}" var="stu" > <tr> <td>${stu.name}</td> <td>${stu.birthday}------ <fmt:formatDate value="${stu.birthday}" pattern="yyyy-MM-dd" /></td> </tr> </c:forEach> </table>MyDateAction.java
@RequestMapping("/list.action") public String list(HttpServletRequest request) throws ParseException { Student student1 = new Student("张三", sf.parse("2021-3-11")); Student student2 = new Student("李四", sf.parse("2021-4-11")); Student student3 = new Student("王五", sf.parse("2021-5-11")); List<Student> list = new ArrayList<>(); list.add(student1); list.add(student2); list.add(student3); request.setAttribute("list",list); return "show"; } - 步骤:
<mvc: annotation-driven/>驱动
- <mvc: annotation-driven/>会自动注册两个bean
- HandlerMapping和HandlerAdapter
- 支持使用@DateTimeFormat, @NumberFormat
- 注解@DateTimeFormat,此注解必须搭配springmvc.xml中的<mvc: annotationdriven>标签(单个日期提交处理)
- 注解完成数据类型的格式化
- 支持使用@RequestBody 和 @ResponseBody注解
- @ResponseBody //解析ajax的请求,必须要在springmvc.xml文件中添加注解驱动
- 静态资源的分流也使用这个标签
资源放到WEB-INF目录下
- 此目录下的动态资源,不可以直接访问,只能通过请求转发的方式进行访问
SpringMVC拦截器
-
概念
- 针对请求和响应进行的额外的处理
- 在请求和响应的过程中添加预处理,后处理和最终处理
-
拦截器执行的时机
- preHandle(): 在请求被处理之前进行操作 预处理
- postHandle() : 在请求后处理之后,但结果还没有渲染前进行操作,可改变响应的结果 后处理
- afterCompletion: 所有的请求响应结束后执行善后工作,清理对象,关闭资源 最终处理
-
拦截器实现的两种方式
-
继承父类
- HandlerInterceptorAdapter父类
-
项目中使用的都是这种
-
实现接口<重要,推荐使用>
- HandlerInterceptor接口
-
拦截器实现步骤
-
第一步: 在session中存储用户信息,用于进行权限验证
//登录的业务判断 @RequestMapping("/login") public String login(String name, String pwd, HttpServletRequest request) { if ("zar".equalsIgnoreCase(name) && "123".equalsIgnoreCase(pwd)) { //在session中存储用户信息,用于进行权限验证 request.getSession().setAttribute("users",name); return "main"; }else{ request.setAttribute("msg","用户名或密码不正确"); return "login"; } } -
第二步: 开发拦截器的功能,实现HandlerInterceptor接口,重写preHandle()方法
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //是否登录过的判断 if (request.getSession().getAttribute("uses") == null) { //此时没有登录,打回到登录页面,并给出提示 request.setAttribute("msg","你还没有登录,请先登录"); request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response); return false; } return true; //放行请求 } -
第三步: 在springmvc.xml文件中注册拦截器
-
<!--注册拦截器--> <mvc:interceptors> <mvc:interceptor> <!--映射要拦截的请求--> <mvc:mapping path="/**"/> <!--设置放行的请求--> <mvc:exclude-mapping path="/showLogin"/> <mvc:exclude-mapping path="/login"/> <!--配置具体的拦截器,实现功能的类--> <bean class="org.example.interceptor.LoginInterceptor"/> </mvc:interceptor> </mvc:interceptors>
-
SSM整合
- SSM整合后台功能
- 整合的步骤
- 第零步: 新建表
- 第一步: 新建maven项目,选择webapp的模板
- 第二步: 修改目录
- 第三步: 修改pom文件
- 第四步: 添加jdbc.properties属性文件
- 第五步: 添加SqlMapConfig.xml(使用模板)
- 第六步: 添加applicationContext_mapper.xml文件( 数据访问层的核心配置文件)
- 第七步: 添加applicationContext_service.xml文件( 业务逻辑层的核心配置文件)
- 第八步: 添加springmvc.xml文件
- 第九步: 删除web.xml文件,新建,改名,设置中文编码 并注册springmvc框架,并注册Spring框架
- 第十步: 新建实体类user
- 第十一步: 新建UserMapper.java 接口
- 第十二步: 新建UserMapper.xml实现增删改查的所有功能
- 第十三步: 新建service接口和实现类
- 第十四步: 新建测试类,完成所有功能的测试
- 第十五步: 新建控制器,完成所有的功能
- 第十六步: 浏览器测试功能
浙公网安备 33010602011771号