spring-mvc第二天笔记整理
文章目录
springmvc异步请求
页面准备
<a href="javascript:void(0);" id="testAjax">访问springmvc后台controller</a><br/>
<a href="javascript:void(0);" id="testAjaxPojo">访问springmvc后台controller,传递Json格式POJO</a><br/>
<a href="javascript:void(0);" id="testAjaxList">访问springmvc后台controller,传递Json格式List</a><br/>
<a href="javascript:void(0);" id="testAjaxReturnString">访问springmvc后台controller,返回字符串数据</a><br/>
<a href="javascript:void(0);" id="testAjaxReturnJson">访问springmvc后台controller,返回Json数据</a><br/>
<a href="javascript:void(0);" id="testAjaxReturnJsonList">访问springmvc后台controller,返回Json数组数据</a><br/>
<a href="javascript:void(0);" id="testCross">跨域访问</a><br/>
<%--引入jQuery--%>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.3.1.min.js"></script>
发送和接收异步请求参数
接收异步请求参数,需要在形参前添加**@RequestBody
**注解
1)发送并接收简单参数
- 页面发送请求代码
$("#testAjax").click(function(){
//发送异步调用
$.ajax({
//请求方式:POST请求
type:"POST",
//请求的地址
url:"ajaxController",
//请求参数(也就是请求内容)
data:'ajax message',
//响应正文类型
dataType:"text",
//请求正文的MIME类型
contentType:"text/plain",
});
});
- Controller方法
@RequestMapping("/ajaxController")
//使用@RequestBody注解,可以将请求体内容封装到指定参数中
public String ajaxController(@RequestBody String message) {
System.out.println("ajax request is running..." + message);
return "page.jsp";
}
注意:异步请求不会发送页面跳转
发送json对象接收并封装成pojo
- 页面发送请求代码
$("#testAjaxPojo").click(function(){
$.ajax({
t ype:"POST",
url:"ajaxPojoToController",
data:'{"name":"Jock","age":39}',
dataType:"text",
contentType:"application/json",
});
});
注意:必须通过contentType
指定请求数据的类型为json的mime类型application/json
- Controller方法
@RequestMapping("/ajaxPojoToController")
//如果处理参数是POJO,且页面发送的请求数据格式与POJO中的属性对应,@RequestBody注解可以自动映射对应请求数据到POJO中
//注意:POJO中的属性如果请求数据中没有,属性值为null,POJO中没有的属性如果请求数据中有,不进行映射
public String ajaxPojoToController(@RequestBody User user) {
System.out.println("controller pojo :" + user);
return "page.jsp";
}
异步请求响应数据
1)方法直接返回String并响应
- 页面发送请求代码
$("#testAjaxReturnString").click(function () {
//发送异步调用
$.ajax({
type: "POST",
url: "ajaxReturnString",
//回调函数
success: function (data) {
//打印返回结果
alert(data);
}
});
});
- Controller方法
@RequestMapping(value="/ajaxReturnString",produces = "text/plain;charset=UTF-8")
@ResponseBody
public String ajaxReturnString() {
System.out.println("controller return string ...");
return "page.jsp页面";
}
注意:直接返回字符串时,虽然添加了@ResponseBody
注解,但是如果响应的字符串中包含中文,会出现中文乱码。需要通过@RequestMapping
注解的produces
属性指定响应体的mime类型和编码
2)方法返回对象或集合,转成json字符串后响应
- 页面发送请求代码
//为id="testAjaxReturnJson"的组件绑定点击事件
$("#testAjaxReturnJson").click(function () {
//发送异步调用
$.ajax({
type: "POST",
url: "ajaxReturnJson",
//回调函数
success: function (data) {
// {"name":"Jockme","age":"39"}
alert(data);
alert(data.name + " , " + data['age']);
}
});
});
//为id="testAjaxReturnJsonList"的组件绑定点击事件
$("#testAjaxReturnJsonList").click(function () {
//发送异步调用
$.ajax({
type: "POST",
url: "ajaxReturnJsonList",
//回调函数
success: function (data) {
alert(data);
alert(data.length);
alert(data[0]["name"]);
alert(data[1].age);
}
});
});
- Controller方法
@RequestMapping("/ajaxReturnJson")
@ResponseBody
//基于jackon技术,使用@ResponseBody注解可以将返回的POJO对象转成json格式数据
public User ajaxReturnJson() {
System.out.println("controller return json pojo...");
User user = new User();
user.setName("Jockme");
user.setAge(39);
return user;//{"name":"Jockme","age":"39"}
}
@RequestMapping("/ajaxReturnJsonList")
@ResponseBody
//基于jackon技术,使用@ResponseBody注解可以将返回的保存POJO对象的集合转成json数组格式数据
public List ajaxReturnJsonList() {
System.out.println("controller return json list...");
User user1 = new User();
user1.setName("Tom");
user1.setAge(3);
User user2 = new User();
user2.setName("Jerry");
user2.setAge(5);
ArrayList al = new ArrayList();
al.add(user1);
al.add(user2); // [{"name":"Jockme","age":"39"},{"name":"Jockme","age":"39"}]
return al;
}
注意:如果是通过springmvc自动将对象或集合转成json字符串,不会出现中文乱码,因为在响应时springmvc会自动指定mime类型和编码
跨域访问
跨域的概念
解决方式
在愿意支持跨域访问的Controller方法上添加**@CrossOrigin
**注解,就可以支持跨域访问
@RequestMapping("/cross")
@ResponseBody
//使用@CrossOrigin开启跨域访问
@CrossOrigin
public User cross(HttpServletRequest request) {
System.out.println("controller cross..." + request.getRequestURL());
User user = new User();
user.setName("Jockme");
user.setAge(39);
return user;
}
注意:@CrossOrigin标注在处理器方法上方表示该方法支持跨域访问,标注在处理器类上表示该处理器类中的所有方法均支持跨域访问
springmvc拦截器
拦截器的概念
相关概念
springmvc中的拦截器
Interceptor
,类似于web开发中的Filter,一般用于对处理器的方法进行预处理和后处理
拦截器(Inteceptor)和过滤器(Filter)的区别
- Filter属于Servlet技术,只要是web工程均可以使用,Interceptor属于SpringMVC技术,必须有SpringMVC环境才可以使用
- Filter主要用于对所有请求过滤,拦截器只能拦截DispatcherServlet处理的请求
- Filter的执行时机早于Interceptor
拦截器使用入门
1)Controller环境准备
@Controller
public class InterceptorController {
@RequestMapping("/handleRun")
public String handleRun() {
System.out.println("业务处理器运行------------main");
return "/page.jsp";
}
}
2)自定义拦截器类,实现HandlerInterceptor
接口,可根据选择重写preHandle
,postHandle
,afterCompletion
方法
public class MyInterceptor1 implements HandlerInterceptor {
// 预处理方法,在控制器的方法执行之前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle1");
//return false;// 返回true代表放行,返回false代表不放行
return true;
}
// 后处理方法,在处理器执行之后,但是页面跳转之前执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle1");
}
// 视图跳转结束之后执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion1");
}
}
3)在spring-mvc.xml文件中配置拦截器
<!--配置拦截器-->
<mvc:interceptors>
<!--配置具体的拦截器-->
<mvc:interceptor>
<!--配置拦截的资源-->
<mvc:mapping path="/**"/>
<!--配置拦截器bean对象-->
<bean class="com.itheima.interceptor.MyInterceptor1"/>
</mvc:interceptor>
</mvc:interceptors>
拦截器方法详解
-
preHandle方法
作用:用于对拦截到的请求进行预处理,方法接收boolean类型的返回值,返回true代表放行,返回false代表不放行
执行时机:在处理器的方法执行之前执行
方法参数:
- request:请求对象
- response:响应对象
- handler:拦截到的处理器方法
-
postHandle方法
作用:用于对拦截到的请求进行后处理,可以在方法中对模型数据和视图进行修改
执行时机:在处理器的方法执行后,视图渲染之前
方法参数:
- request:请求对象
- response:响应对象
- handler:拦截到的处理器方法
- modelAndView:处理器方法返回的模型和视图对象,可以在方法中修改模型和视图
-
afterCompletion方法
作用:用于在整个流程完成之后进行最后处理,如果请求流程中有异常,可以在方法中获取异常对象
执行时机:视图渲染完成之后(整个流程结束之后)
方法参数:
- request:请求对象
- response:响应对象
- handler:拦截到的处理器方法
- ex:异常对象
各方法执行时机图
拦截器链(多拦截器)
拦截器链的概念
如果多个拦截器能够对相同的请求进行拦截,则多个拦截器会形成一个拦截器链。主要理解拦截器的执行顺序。
拦截器链中多个拦截器的执行顺序
拦截器链中的多个拦截器的执行顺序,跟拦截器的配置顺序有关,先配置的先执行。测试代码如下
MyInterceptor2.java
public class MyInterceptor2 implements HandlerInterceptor {
// 预处理方法,在控制器的方法执行之前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle2");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle2");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion2");
}
}
配置顺序如下:
<!--配置拦截器们-->
<mvc:interceptors>
<!--配置具体的拦截器-->
<mvc:interceptor>
<!--配置拦截的资源-->
<mvc:mapping path="/**"/>
<!--配置拦截器bean对象-->
<bean class="com.itheima.interceptor.MyInterceptor1"/>
</mvc:interceptor>
<mvc:interceptor>
<!--配置拦截的资源-->
<mvc:mapping path="/**"/>
<!--配置拦截器bean对象-->
<bean class="com.itheima.interceptor.MyInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
访问http://localhost/handleRun
控制台输出顺序如下:
preHandle1
preHandle2
业务处理器运行------------main
postHandle2
postHandle1
afterCompletion2
afterCompletion1
执行顺序图示
注意:只要preHandle方法返回true,对应拦截器的afterCompletion方法肯定会执行。如:仅修改MyInterceptor2的preHandle方法返回值为false,虽然整体没有放行,但是MyInterceptor1的afterCompletion方法还是会执行。
拦截器排除静态资源
默认情况下,如果DispatcherServlet的url-pattern配置为/,拦截器的拦截路径配置为/**
,那么拦截器会拦截静态资源。但是实际场景中,拦截器通常只负责拦截对于处理器Controller的访问,所以需要排除静态资源,配置方式有两种:
方式1:配置拦截器只拦截对指定前缀Controller方法的访问
<mvc:interceptor>
<!--配置拦截的资源,只拦截资源路径以/user开始的访问-->
<mvc:mapping path="/user/**"/>
<mvc:mapping path="/dept/**"/>
....
<!--配置拦截器bean对象-->
<bean class="com.itheima.interceptor.MyInterceptor1"/>
</mvc:interceptor>
这种方式的缺陷是,首先Controller必须配置一级访问目录。其次,一旦项目中的Controller过多,会出现大量的配置。
方式2:配置拦截器排除指定资源的拦截
<mvc:interceptor>
<!--配置拦截的资源-->
<mvc:mapping path="/**"/>
<!--配置拦截器不拦截的资源-->
<mvc:exclude-mapping path="/**/*.png"/>
<mvc:exclude-mapping path="/*/*.css"/>
<mvc:exclude-mapping path="/**/*.js"/>
<!--配置拦截器bean对象-->
<bean class="com.itheima.interceptor.MyInterceptor1"/>
</mvc:interceptor>
上述配置中/**/*.png
类似的配置,含义为,访问当前项目中任意层级的以.png结尾的资源拦截器都不拦截,如:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-isgeZVsT-1608297930845)(排除拦截.png)]
springmvc异常处理
异常处理思路
基于HandlerExceptionResolver接口实现
此方式了解即可
1)编写异常处理器,实现HandlerExceptionResolver
接口,并将该类对象存入spring容器
@Component
public class ExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
System.out.println("my exception is running ...."+ex);
ModelAndView modelAndView = new ModelAndView();
if( ex instanceof NullPointerException){
modelAndView.addObject("msg","空指针异常");
}else if ( ex instanceof ArithmeticException){
modelAndView.addObject("msg","算数运算异常");
}else{
modelAndView.addObject("msg","未知的异常");
}
modelAndView.setViewName("/error.jsp");
return modelAndView;
}
}
2)编写用于展示友好提示信息的页面error.jsp
<%--异常消息展示页面--%>
<%@page pageEncoding="UTF-8" language="java" contentType="text/html;UTF-8" %>
${msg}
基于@ControllerAdvice注解实现
重点掌握!
1)基础环境
- ajax.jsp
<%@page pageEncoding="UTF-8" language="java" contentType="text/html;UTF-8" %>
<a href="javascript:void(0);" id="testException">访问springmvc后台controller,传递Json格式POJO</a><br/>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.3.1.min.js"></script>
<script type="text/javascript">
$(function () {
$("#testException").click(function(){
$.ajax({
contentType:"application/json",
type:"POST",
url:"findAll",
data:'{"name":"Jock","age":"18"}',
dataType:"text",
//回调函数
success:function(data){
alert(data);
}
});
});
});
</script>
- User.java
public class User {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
- UserController
@Controller
public class UserController {
@RequestMapping("/findAll")
@ResponseBody
public Result findAll(@RequestBody User user){
User u1 = new User();
u1.setName("Tom");
u1.setAge(3);
User u2 = new User();
u2.setName("Jerry");
u2.setAge(5);
ArrayList<User> list = new ArrayList<User>();
list.add(u1);
list.add(u2);
return new Result(list,"查询成功", Code.GET_OK);
}
}
- 定义通用的封装响应结果的实体类
在基于异步请求的开发中,为了便于前后台处理,通常会统一返回的json数据的格式,因此通常会自定义封装响应结果的实体类。对于来自前台的一次请求来说,后台需要响应给前台的信息通常是固定的几部分数据:
-
是否成功的标识
-
成功之后的核心数据
-
提示消息(多用于失败之后的消息)
-
操作的状态码
对于操作的状态码通常不会临时随意编写,而是预先按照一定的设计规则以常量的形式定义在一个专门的类中
- 用于封装响应消息的实体类:Result.java
public class Result {
// 是否成功
private boolean flag;
// 成功之后响应的核心数据
private Object data;
// 提示消息
private String message;
// 操作状态码
private Integer code;
// 成功
public Result(Object data, String message, Integer code) {
this.flag = true;
this.data = data;
this.message = message;
this.code = code;
}
// 失败
public Result(String message, Integer code) {
this.flag = false;
this.message = message;
this.code = code;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
}
- 用于封装操作结果码的类:Code.java
public class Code {
// 操作结果编码
public static final Integer SAVE_OK = 20011;
public static final Integer UPDATE_OK = 20021;
public static final Integer DELETE_OK = 20031;
public static final Integer GET_OK = 20041;
public static final Integer SAVE_ERROR = 20010;
public static final Integer UPDATE_ERROR = 20020;
public static final Integer DELETE_ERROR = 20030;
public static final Integer GET_ERROR = 20040;
// 校验结果编码
public static final Integer DATA_LENGTH_ERROR = 30001;
public static final Integer DATA_VALUE_ERROR = 30002;
}
3)自定义异常类
需要自定义异常类的原因通常如下:
- jdk中默认提供的异常类型过多,不可能在异常处理器中对所有异常进行单独处理
- 相同类型的异常可能有不同的原因,因此应该给出不同的提示,而jdk中自带的异常类中并没有与业务相关的提示信息
- jdk中默认的异常类型中,没有相关的操作状态码(自定义的状态码)
在自定义异常时,通常选择继承RuntimeException
,因为运行时异常不会强制在代码中进行处理,自定义的异常类如下:
public class BusinessException extends RuntimeException {
// 用于封装错误的状态码
private Integer code;
public BusinessException(Integer code) {
this.code = code;
}
public BusinessException(String message, Integer code) {
super(message);
this.code = code;
}
public BusinessException(String message, Throwable cause, Integer code) {
super(message, cause);
this.code = code;
}
public BusinessException(Throwable cause, Integer code) {
super(cause);
this.code = code;
}
public BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Integer code) {
super(message, cause, enableSuppression, writableStackTrace);
this.code = code;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
}
4)编写同一个异常处理类
@Component
@ControllerAdvice
public class ProjectExceptionAdvice {
@ExceptionHandler(BusinessException.class)
@ResponseBody
public Result doBusinessException(BusinessException e){
// 获取异常的状态的码
Integer code = e.getCode();
// 获取异常的提示信息
String message = e.getMessage();
// 将其封装到Result对象
Result result = new Result(message, code);
return result;
}
}
5)修改代码进行测试
Controller代码
@RequestMapping("/findAll")
@ResponseBody
public Result findAll(@RequestBody User user){
if (user.getName().trim().length() < 4){
// 将其转换成自定义异常
throw new BusinessException("用户长度必须大于4位",Code.DATA_LENGTH_ERROR);
}
if (user.getAge() <= 0){
throw new BusinessException("年龄必须大于0",Code.DATA_VALUE_ERROR);
}
User u1 = new User();
u1.setName("Tom");
u1.setAge(3);
User u2 = new User();
u2.setName("Jerry");
u2.setAge(5);
ArrayList<User> list = new ArrayList<User>();
list.add(u1);
list.add(u2);
return new Result(list,"查询成功", Code.GET_OK);
}
修改页面参数
data:'{"name":"Jo","age":"0"}',
data:'{"name":"Jock","age":"0"}',
springmvc文件上传
单文件上传
实现步骤
1)导入fileupload坐标
<!--文件上传下载-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
2)配置文件上传解析器
<!--配置文件上传的解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--文件上传的总大小-->
<property name="maxUploadSize" value="20480000"/>
<!--单个文件的最大大小-->
<property name="maxUploadSizePerFile" value="2048000"/>
<!--解决中文文件名的乱码问题,如果web.xml中配置了中文乱码过滤器,可以不进行配置-->
<property name="defaultEncoding" value="UTF-8"/>
</bean>
注意事项:CommonsMultipartResolver
对象的id必须为multipartResolver
,因为DispatcherServlet
中已经将这个值写死:
3)编写文件上传页面
<form action="upload" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="imgFile"/><br>
<button type="submit">上传</button>
</form>
4)编写Controller中实现文件上传的方法
@Controller
public class FileUploadController {
@RequestMapping("/upload")
public String upload(MultipartFile imgFile, HttpServletRequest request) {
// 判断文件数据是否为空
if (!imgFile.isEmpty()) {
// 1获取文件名
String fileName = imgFile.getOriginalFilename();
String uuid = UUID.randomUUID().toString();
// 1.2 解决文件名重名
fileName = uuid + "_" + fileName;
// 2将文件数据保存到硬盘上
// 2.1 动态获取images目录的绝对路径
ServletContext context = request.getServletContext();
String realPath = context.getRealPath("/images");
// 2.2 创建File对象
File file = new File(realPath, fileName);
try {
imgFile.transferTo(file);
} catch (IOException e) {
e.printStackTrace();
}
}
return "/page.jsp";
}
}
多文件上传
1)修改表单,添加多个file类型的表单项
<form action="upload" method="post" enctype="multipart/form-data">
选择文件1:<input type="file" name="imgFiles"/><br>
选择文件1:<input type="file" name="imgFiles"/><br>
<button type="submit">上传</button>
</form>
注意:多个表单项的name属性值一致
2)修改Controller中的方法,修改参数类型为MultipartFile[]
数组
@Controller
public class FileUploadController {
@RequestMapping("/upload")
public String upload(MultipartFile[] imgFiles,HttpServletRequest request){
for (MultipartFile imgFile : imgFiles) {
// 判断文件数据是否为空
if(!imgFile.isEmpty()){
// 1获取文件名
String fileName = imgFile.getOriginalFilename();
String uuid = UUID.randomUUID().toString();
// 1.2 解决文件名重名
fileName=uuid+"_"+fileName;
// 2将文件数据保存到硬盘上
// 2.1 动态获取images目录的绝对路径
ServletContext context = request.getServletContext();
String realPath = context.getRealPath("/images");
// 2.2 创建File对象
File file = new File(realPath, fileName);
try {
imgFile.transferTo(file);
} catch (IOException e) {
e.printStackTrace();
}
}
}
return "/page.jsp";
}
}
核心对象:
-
MultipartFile
用于封装上传的文件相关数据
核心方法:
-
isEmpty()
判断文件数据是否为空,false代表不为空
-
getOriginalFilename()
获取文件名
-
transferTo()
将文件数据转移到一个file中(将文件数据写入到硬盘的某个文件中)
注意事项:
- MultipartFile类型的参数名必须和file类型的表单项的name属性值保持一致
springmvc之Restful风格
什么是Restful?
restful 是一套网络接口的设计风格,通过资源+请求方式描述对资源的不同操作
以用户模块的增删改查操作为例,传统风格和restful风格的设计方式分别如下:
同步请求使用Restful
- 过滤器配置
<!--配置拦截器,解析请求中的参数_method,否则无法发起PUT请求与DELETE请求,配合页面表单使用-->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2)页面代码
<h2>同步请求</h2>
<h3>查询单个用户</h3>
<a href="/user/1">查询用户</a>
<h3>保存用户</h3>
<form action="/user" method="post">
用户名:<input type="text" name="name"/><br>
年龄:<input type="number" name="age"></br>
<button type="submit">保存</button>
</form>
<h3>删除用户</h3>
<form action="/user/2" method="post">
<input type="hidden" name="_method" value="delete">
<button type="submit">删除</button>
</form>
<h3>更新用户</h3>
<form action="/user" method="post">
<input type="hidden" name="_method" value="PUT">
用户名:<input type="text" name="name"/><br>
年龄:<input type="number" name="age"></br>
<button type="submit">更新</button>
</form>
- Controller 方法
/*@Controller
@ResponseBody*/
@RestController
@RequestMapping("/user")
public class UserController {
//@RequestMapping(value = "/{id}",method = RequestMethod.GET )
@GetMapping("/{id}")
public String findUser(@PathVariable("id") int uid){
System.out.println("查询"+uid+"号用户");
return "findUser";
}
//@RequestMapping(method = RequestMethod.POST)
@PostMapping()
public String saveUser(String name,int age){
System.out.println("保存用户");
System.out.println(name+","+age);
return "saveUser";
}
// @RequestMapping(value = "/{id}",method = RequestMethod.DELETE)
@DeleteMapping("/{id}")
public String deleteUser(@PathVariable("id") int uid){
System.out.println("删除"+uid+"号用户");
return "deleteUser";
}
// @RequestMapping(method = RequestMethod.PUT)
@PutMapping()
public String updateUser(String name,int age){
System.out.println("更新用户");
System.out.println(name+","+age);
return "updateUser";
}
}
代码解释:
-
路径中的参数值不是固定的,所以通过
${变量名}
表示这是一个路径中的变量 -
@PathVariable
表示将指定名称的路径变量对应的值,赋值给方法形参
-
@RestController
相当于@Controller+@ResponseBody
-
@GetMapping
相当于
@RequestMapping(method = {RequestMethod.GET})
其它同理
异步请求使用Restful
异步请求可以直接发球PUT或DELETE请求,因此可以不配置HiddenHttpMethodFilter过滤器
1)页面发起请求代码
<script src="js/jquery-3.3.1.min.js"></script>
<script>
function deleteUser() {
$.ajax({
url: "${pageContext.request.contextPath}/user/10",
type: "DELETE"
})
}
function updateUser() {
$.ajax({
url: "${pageContext.request.contextPath}/user/3",
type: "PUT"
})
}
function saveUser() {
$.ajax({
url: "${pageContext.request.contextPath}/user",
type: "POST",
data:'name=zhangsan&age=10'
})
}
</script>
<h2>ajax异步请求</h2>
<hr>
<input type="button" value="删除账户" οnclick="deleteAccount();">
<input type="button" value="修改账户" οnclick="updateAccount();">
<input type="button" value="查询账户" οnclick="findAccount();">
<input type="button" value="添加账户" οnclick="saveAccount();">
需要添加一个新的updateUser方法
@PutMapping("/{id}")
public String updateUser(@PathVariable int id){
System.out.println("更新用户"+id);
return "updateUser";
}