SpringMVC 的请求映射处理

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情

一、@RequestMapping

@RequestMapping用来匹配客户端发送的请求,可以在方法上使用,也可以在类上使用。

方法:表示用来匹配要处理的请求

类上:表示为当前类的所有方法的请求地址添加一个前置路径,访问的时候必须要添加此路径

image.png 如上图,在类和方法上同时加上@RequestMapping,一般实际项目中习惯把加载类上的@RequestMapping作为模块,加在方法上的为实际执行方法。

注意:在整个项目的不同方法上不能包含相同的@RequestMapping值

除此以外,@RequestMapping注解还可以添加很多额外的属性值,用来精确匹配请求

1、通过method设置请求类型

@RequestMapping请求方式可以分为如下几种: 如果不写值,则所有请求都可以进来 image.png

2、通过指定的方式请求类型

除了使用method指定请求方式外,也可以设置指定的注解,确定方法的请求方式

@PostMapping
@GetMapping
@DeleteMapping
@PutMapping
复制代码

3、设置当前请求必须有/没有某些参数,参数必须等于/不等于某值

3-1、必须有某个参数

params={"username"}
设置必须有username这个参数,如果请求未添加这个参数,如下: image.png 加上必须要传的参数,如下:

image.png

3-2、必须没有某个参数

params={"!username"}
请求携带了username参数,如下: image.png

请求没有username参数如下:

image.png

3-3、请求参数必须等于某个值

设置请求参数必须是某个值 params={"username=123"}

错误参数值请求 image.png 正确参数值请求

image.png

3-4、请求参数必须不等于某个值

params={"username!=456"} 就不做演示了。

4、使用header设置请求头

headers={"Host=localhost:8080"}设置只有localhost:8080能请求

image.png

把8080改为9090

image.png

5、使用consumers指定请求类型

相当于指定Content‐Type,常见内容类型如下:
application/x-www-urlencoded:form表单默认提交类型
multipart/form-data:form表单提交文件流的内容类型
application/jspn:ajax提交的json内容类型
如设置当前请求必须为application/x-www-urlencoded类型:

consumers={"application/x-www-urlencoded"}

6、使用produces 指定返回内容类型

produces指定响应类型,相关文件响应类型,可以查看tomcat里面的web.xml。

如设置当前响应类型为application/json:

produces={"application/json"}

6、@RequestMapping通配符支持

?:一个?能替代任意一个字符
*: 一个 * 号能替代任意多个字符和一层路径
** :一个 ** 可以能代替多层路径

需要注意的是:如果映射存在包含关系会优先交给更精确的去处理,没有通配符就需要100%匹配、如果三个全部可以匹配到,优先处理顺序如下:

没有通配符 > ? > * > **

http://localhost:8080/mapping/test1
如果设置通配符 @RequestMapping("/test?")和@RequestMapping("/test*")则会由@RequestMapping("/test?")来处理,因为?代替一个字符,更加精确

http://localhost:8080/mapping/test1rewrew
这样则由@RequestMapping("/test*")进行处理

http://localhost:8080/mapping/3/4/5/6/test1rewrew
@RequestMapping("**/test*") 就可以进行处理。

二、@PathVariable

如果需要在请求路径中的参数像作为参数应该怎么使用呢?可以使用@PathVariable注解,此注解就是提供了对占位符URL的支持,就是将URL中占位符参数绑定到控制器处理方法的参数中。

2-1、使用相同的占位符接收参数

image.png

如上图,我们在请求url中用"/"进行参数分割,然后在Controller中的@requestMapping中使用{xxx}进行占位符,代表参数,然后在方法内使用@PathVariable 指定和{xxx} 一样的值即可。

2-2、使用@PathVariable的value属性接收参数

通过value的配置,后面的参数名就可以随便定义了。 image.png

2-3、接收javaBean对象

传入的参数如果是javaBean的属性值,那就可以不用@PathVeriable直接使用javaBean对象接收参数,如下:

image.png

三、REST

REST即表述性状态传递(英文:Representational State Transfer,简称REST)是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。它是一种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高系统的可伸缩性。

一种相较与之前URL所产生一种更优雅的URL风格

比如原来我们的请求方式为:
查询用户:http://localhost:8080/app/user.do?action=getUser&id=xxx GET

增加用户: http://localhost:8080/app/user_add.do POST

修改用户: http://localhost:8080/app/xiugaiuser.do POST

删除用户: http://localhost:8080/app/delete.do?id=1 GET/POST

按照此方式发送请求的时候比较麻烦,需要定义多种请求,而在HTTP协议中,有不同的发送请求的方式,分别是GET、POST、PUT、DELETE等,我们如果能让不同的请求方式表示不同的请求类型就可以简化我们的查询,改成名词:面向资源

看URL就知道要什么,, 看http method就知道干什么

查询用户: http://localhost:8080/xxx/user/1 GET ­­查询

查询多个用户: http://localhost:8080/xxx/users GET

新增用户: http://localhost:8080/xxx/user POST ­­­新增

修改用户: http://localhost:8080/xxx/user/1 PUT ­­修改

删除用户:http://localhost:8080/xxx/user/1 DELETE ­­删除

下面我们就使用以上方式来实现rest风格的CRUD

3-1、准备Controller

RestController.java

package com.jony.controller;

import com.jony.entity.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

@Controller
@RequestMapping("/rest")
public class RestController {
   // 查询
   @GetMapping("/user/{id}")
   public String get(@PathVariable("id") Integer id){
       System.out.println("查询用户:"+id);
       return "/index.jsp";
   }

   // 新增
   @PostMapping("/user")
   public String add(User user){
       System.out.println("新增用户:"+user);
       return "/index.jsp";
   }

   // 修改
   @PutMapping("/user/{id}")
   public String update(User user){
       System.out.println("修改用户:"+user);
       return "/index.jsp";
   }

   // 删除
   @DeleteMapping("/user/{id}")
   public String delete(@PathVariable("id") Integer id){
       System.out.println("删除用户:"+id);
       return "/index.jsp";
   }

}
复制代码

3-2、准备jsp实现CRUD的方法

3-2-1、设置get/post/put/delete请求方式

目前我们知道http协议支持get、post、post、delete,但是html/jsp仅支持get、post。

jsp中我们发送的请求只能是get或者post,没有办法发送put和delete请求,如果method写上put或者delete,method不认识,则会以默认的get方式发送请求。因此我们就需要想办法来处理一下。

我们可以先将请求方式设为post,然后在提交表单中添加一个参数,然后添加一个过滤器,只要监控到这个参数就知道是什么样的请求类型了。

3-2-1-1、处理的过滤器

上面提到将请求方式通过过滤器来处理,springmvc已经给我们提供了这样一个过滤器。

org.springframework.web.filter.HiddenHttpMethodFilter
复制代码

需要注意的是,一定要引用如下的包。 image.png 下面我们看一下HiddenHttpMethodFilter的源码。
1、查看源码 image.png 通过上面代码,我们可以看到首先需要是post请求才能进入方法,其次通过request.getParameter("_method")获得post过来的参数值。并且这个参数值在ALLOWED_METHODS中,下面我们看这个集合内容
2、查看过滤器中内置的请求方式 image.png 这个ALLOWED_METHODS集合中一共有三个值:PUT/DELETE/PATCH,我们需要的put和delete正好就在其中。

3、查看请求方式的赋值

image.png 如上图,如果我们页面传过来的_method的值是delete/put/patch中的,则执行下面的方法

image.png 这样就可以将我们的请求过来的post请求重新赋值为delete/put/patch了。

总结:因此如果我们页面需要调用delete/put/patch的请求方式是,只要向后台传递一个name为“_method”,并且值为delete/put/patch中的某一个即可(大小写均可,因为源代码中,已经帮我们转为大写了处理了)

3-2-1-2、在web.xml中添加过滤器的映射

<!--设置delete put patch处理的过滤器-->
<filter>
    <filter-name>HiddenHttpMethod</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>HiddenHttpMethod</filter-name>
    <servlet-name>springmvc</servlet-name>
</filter-mapping>
复制代码

3-2-1-3、在jsp中添加隐藏域

我们就需要在form中添加一个隐藏域,然后设置put/delete,如下name设置为“_method”,然后value设置put/delete就可以了

<input type="hidden" value="put" name="_method">
复制代码

如果不设置,或者method就会默认用get请求方式

3-2-2、设置请求连接根目录

上节文章,我们在form的action中使用了如下方式来设置的,

<form action="${pageContext.request.contextPath}/saveUser">
复制代码

这样就需要在每个action中添加,一个简便的方法就是如下: 首先在jsp页头添加一个basepath

<% request.setAttribute("basepath",request.getContextPath()); %>
复制代码

然后form中action就可以这样写

<form action="${basepath}/rest/user/1" method="get">
复制代码

3-2-3、jsp的实现方式

rest.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<% request.setAttribute("basepath",request.getContextPath()); %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="${basepath}/rest/user/1" method="get">
    <input type="submit" value="查询">
</form>

<form action="${basepath}/rest/user" method="post">
    id:<input name="id" type="text"> <p></p>
    姓名:<input name="name" type="text"> <p></p>
    <input type="submit" value="新增">
</form>

<form action="${basepath}/rest/user/1" method="post">  <%--method默认是get--%>
    <input type="hidden" value="put" name="_method">
    id:<input name="id" type="text"> <p></p>
    姓名:<input name="name" type="text"> <p></p>
    <input type="submit" value="修改">
</form>

<form action="${basepath}/rest/user/1" method="post">
    <input type="hidden" value="delete" name="_method">
    <input type="submit" value="删除">
</form>
</body>
</html>
复制代码

3-2-4、测试

3-2-4-1、根据ID查询某个用户

image.png

3-2-4-2、新增用户

image.png

3-2-4-3、修改用户

image.png 可以看到虽然已经请求进入到Controller了,但是因为return "/index.jsp" 实际使用的是forward,之前已经将post请求改为put,这样到index.jsp就不识别put了,因此告诉我们需要使用get/post/head三种方式。这个错误处理,我们后面介绍解决方案

3-2-4-4、删除用户

image.png 虽然执行成功了,但是同样也报上面的错误

3-2-5、使用delete/put 405错误的解决

错误产生原因主要就是因为使用了tomcat8,tomcat8对请求方式要求的更加严格,只能使用get/post/head,因此报了405错误。解决方案有如下四种:

1.用tomcat7
2.不用转发,用重定向
3. 将jsp的page指定 isErrorPage属性改成true(不建议)\

第一种方式我们就不做测试了。我们试一下后面三种方法

3-2-5-1、使用重定向解决put/delete错误

image.png

3-2-5-2、修改目标jsp的isErrorPage属性

image.png

通过下图可以看到,我们依旧使用的是转发的方式跳转到了index.jsp image.png isErrorPage不建议使用,否则页面的报错信息就看不到了。

四、处理访问静态资源

我们在项目的web.xml中配置了DispatcherServlet的拦截设置

image.png 这样除了JSP页面其他所有请求都会到DispatcherServlet,比如我们设置的css/js/image等就无法完成请求了。我们下面来测试一下

4-1、将图片复制到项目中,然后在jsp中引入图片

image.png 浏览器访问如下:

image.png

4-2、通过添加配置,解决静态文件访问。

4-2-1、通过访问地址映射本地路径的方式(推荐使用)

我们在配置文件中添加如下:

image.png 然后通过浏览器访问地址:

image.png 发现图片还是没有显示成功,可以看到左侧out中我们刚刚假如的图片没有编译到其中,删除out,重新启动项目。

再次访问

image.png

4-2-2、设置如果springmvc无法处理则调用默认的servlet处理

我们在配置中添加如下:

image.png

猜你喜欢

转载自juejin.im/post/7082544941582254094