springboot2——5 请求映射

1 请求映射

1.1 restful风格

请求映射是通过编写一个controller并在每一个方法上加上requestmapping完成的。在没有使用restful风格之前,我们进行对用户的增删改查操作定义的请求路径往往是:获取用户/getUser、删除用户/deleteUser、增加用户/addUser、修改用户/updateUser等,由于请求路径太多,请求路径名起到最后往往不知道起什么,在引入restful风格后解决了这一问题。
restful风格是使用Http请求方式动词表示对资源的操作,GET——查找用户、DELETE——删除用户、PUT——更改用户、POST——添加用户,具体使用如下:

@RestController
public class HelloController {
    @RequestMapping(value = "/user",method = RequestMethod.GET)
    //等同于@GetMapping("/user")
    public String getUser() {
        return "get user";
    }
    @RequestMapping(value = "/user",method = RequestMethod.POST)
    //等同于@PostMapping("/user")
    public String postUser() {
        return "post user";
    }
    @RequestMapping(value = "/user",method = RequestMethod.DELETE)
    //等同于@DeleteMapping("/user")
    public String deleteUser() {
        return "delete user";
    }
    @RequestMapping(value = "/user",method = RequestMethod.PUT)
    //等同于@PutMapping("/user")
    public String putUser() {
        return "put user";
    }
}

这样写后两个方式delete和put并不支持,都被当成get方式处理,通过给springmvc中配置HiddenHttpMethodFilter解决。

<body>
<form action="/user" method="get">
    <input type="submit" value="get方式"/>
</form>
<form action="/user" method="post">
    <input type="submit" value="post方式"/>
</form>
<form action="/user" method="delete">
    <input type="submit" value="delete方式"/>
</form>
<form action="/user" method="put">
    <input type="submit" value="put方式"/>
</form>
</body>

通过查看源码,springboot中的自动配置类通过OrderedHiddenHttpMethodFilter方法向容器中注册了HiddenHttpMethodFilter组件,但需要手动在配置文件中修改spring.mvc.hiddenmethod.filter.enabled为true,另外要将form表单里的method设为POST并加入一个隐藏项name为_method,值为相应的PUT、DELETE最终实现表单的restful风格。

@Bean
@ConditionalOnMissingBean({HiddenHttpMethodFilter.class})

@ConditionalOnProperty(
    prefix = "spring.mvc.hiddenmethod.filter",
    name = {"enabled"}
    //默认是不开启的,通过prefix和name在配置文件将其配置为true,
    //使HiddenHttpMethodFilter组件生效
)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
    return new OrderedHiddenHttpMethodFilter();
}
<body>
<form action="/user" method="get">
    <input type="submit" value="get方式"/>
</form>
<form action="/user" method="post">
    <input type="submit" value="post方式"/>
</form>
<form action="/user" method="post">
    <input name="_method" value="DELETE" type="hidden">
    <input type="submit" value="delete方式"/>
</form>
<form action="/user" method="post">
    <input name="_method" value="PUT" type="hidden">
    <input type="submit" value="put方式"/>
</form>
</body>

restful原理:简而言之就是表单提交的请求会被HiddenHttpMethodFilter拦截,如果是post方式且没有错误,经过处理会根据请求携带的_method的值对post方式进行包装,将请求方式更改为对应的_method的值,如果是客户端工具,可以直接发送delete、put请求,无需HiddenHttpMethodFilter的处理。

1.2 请求映射原理

SpringMVC的功能分析都是从DispatcherServlet类的doDispatch方法入手,此方法调用getHandler(processedRequest)对获取到的所有请求使用for循环逐个匹配容器中的handlerMappings。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

				// 找到当前请求使用哪个Handler(Controller的方法)处理
				mappedHandler = getHandler(processedRequest);
                
                //HandlerMapping:处理器映射。/xxx->>xxxx

常见的HandlerMapping有:RequestMappingHandlerMapping——保存了所有@RequestMapping和handler的映射规则,WelcomePageHandlerMapping——欢迎页的映射规则。
总结下来,请求进来,挨个尝试所有的HandlerMapping看是否能匹配,如果能就找到这个请求对应的handler,如果不能就找下一个 HandlerMapping。
特别地,如果我们需要一些自定义的映射处理,也可以自己给容器中放HandlerMapping,即自定义 HandlerMapping

2 常用参数注解

2.1 @PathVariable

在Restful请求风格中,使用路径的方式进行参数的传递,@PathVariable注解是用来获取url路径中参数的值。
另外,如果参数的位置有一个map<String,String>,那么会将所有的路径变量的key和value放进map中。

    @GetMapping("/car/{carId}/owner/{username}")
    public Map<String,Object> car(@PathVariable("carId") String id,
                                  @PathVariable("username") String name,
                                  @PathVariable Map<String,String> pv) {
        Map<String,Object> map = new HashMap<>();
        map.put("id",id);
        map.put("name",name);
        map.put("pv",pv);
        return map;
    }

在这里插入图片描述

2.2 @RequestHeader

@RequestHeader注解用来获取请求头的值,另外,如果参数的位置有一个map<String,String>,那么会将所有的请求头的key和value放进map中。

    @GetMapping("/header")
    public Map<String,Object> header(@RequestHeader("user-agent") String useragent,
                                     @RequestHeader Map<String,String> headers) {
        Map<String,Object> map = new HashMap<>();
        map.put("useragent",useragent);
        map.put("headers",headers);
        return map;
    }

在这里插入图片描述

2.3 @RequestParam

@RequestParam注解用来获取请求参数的值,另外,如果参数的位置有一个map<String,String>,那么会将所有的@RequestParam的key和value放进map中。如果方法参数名和路径变量名一样会自动匹配可以省略该注解。

@GetMapping("/param")
    public Map<String,Object> param(@RequestParam("age") Integer age,
                                     @RequestParam("interests") List<String> interests,
                                     @RequestParam Map<String,String> params) {
        Map<String,Object> map = new HashMap<>();
        map.put("age",age);
        map.put("interests",interests);
        map.put("params",params);
        return map;
    }

在这里插入图片描述

2.4 @RequestBody

@RequestBody注解用来获取请求体的值,post请求才有请求体

 @PostMapping("save")
    public Map<String,Object> save(@RequestBody String request) {
        Map<String, Object> map = new HashMap<>();
        map.put("request",request);
        return map;
    }

在这里插入图片描述

2.5 @RequestAttribute

@RequestAttribute用来获取request域的值,两种获取方式:①直接@RequestAttribute注解 ②HttpServletRequest对象的getAttribute方法。

@Controller
public class DemoController {
    @RequestMapping("/to1")
    public String to1(HttpServletRequest request) {
        request.setAttribute("msg","ok了");
        return "/to2";
    }
    @ResponseBody
    @RequestMapping("/to2")
    public String to2(@RequestAttribute("msg") String message,HttpServletRequest request) {
        String anno = "注解方式得到" + message;
        String normal = "普通方式得到" + request.getAttribute("msg");
        return anno + "|||" + normal;
    }
}

在这里插入图片描述
一般都是存到request域中,在页面用EL表达式取

2.6 @MatrixVariable

url重写解决页面开发中cookie禁用时获取session里面的内容的问题,是把cookie的值使用矩阵变量的方式进行传递
矩阵变量必须绑定在路径变量中,其使用步骤如下:
(1)springboot默认禁用矩阵变量,需要手动开启,有两种方法。
第一种是通过自定义配置类向容器注册WebMvcConfigurer组件替代默认的组件来开启矩阵变量

@Configuration
public class MyConfig {
    @Bean
    public WebMvcConfigurer webMvcConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void configurePathMatch(PathMatchConfigurer configurer) {
                UrlPathHelper urlPathHelper = new UrlPathHelper();
                urlPathHelper.setRemoveSemicolonContent(false);
                configurer.setUrlPathHelper(urlPathHelper);
            }
        };
    }

第二种是让配置类实现WebMvcConfigurer,重写configurePathMatch方法

@Configuration
public class MyConfig implements WebMvcConfigurer {
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        UrlPathHelper urlPathHelper = new UrlPathHelper();
        //不移除分号后面的内容,使矩阵变量功能生效
        urlPathHelper.setRemoveSemicolonContent(false);
        configurer.setUrlPathHelper(urlPathHelper);
    }
}

(2)使用,一定要把矩阵变量绑定在路径变量中!!

//访问路径/car;brand=bmw,byd/son;age=12;name=xp
//访问路径也可以写成/car;brand=bmw;brand=byd/son;age=12;name=xp
    @GetMapping("/{traffic}/{relation}")
    public Map<String,Object> boss(@PathVariable("traffic") String traffic,
                                   @PathVariable("relation") String relation,
                                   @MatrixVariable("brand") List<String> brands,
                                   @MatrixVariable("age") Integer age,
                                   @MatrixVariable("name") String name) {
        Map<String, Object> map = new HashMap<>();
        map.put("relation",relation);
        map.put("traffic",traffic);
        map.put("name",name);
        map.put("age",age);
        map.put("brands",brands);
        return map;
    }

在这里插入图片描述
如果矩阵变量的名字重复可以用下面这种方式解决
在这里插入图片描述

3 原理简析

springmvc除了在参数位置处标注注解的参数可以用参数解析器解析外,方法位置也允许传入servlet api(WebRequest、ServletRequest、MultipartRequest、 HttpSession、javax.servlet.http.PushBuilder、Principal、InputStream、Reader、HttpMethod、Locale、TimeZone、ZoneId)、复杂参数(Map、Model(给map、model放数据会被放在request的请求域,相当于调用了 request.setAttribute)、Errors/BindingResult、RedirectAttributes( 重定向携带数据)、ServletResponse(response)、SessionStatus、UriComponentsBuilder、ServletUriComponentsBuilder)、自定义对象参数,都可以用参数解析器解析。

页面提交的请求数据(GET、POST)会自动和自定义对象参数的属性(也就是POJO类的参数)进行绑定

 @RequestMapping("/user")
    public User user(User user) {
        return user;
    }
public class User {
    private String name;
    private int age;
    private Pet pet;
}
<body>
<form action="/user" method="post">
    用户名<input name="name"><br>
    年龄<input name="age"><br>
    宠物名<input name="pet.name"><br>
    <input type="submit" value="提交">
</form>
</body>

在这里插入图片描述
在这里插入图片描述
可以自定义转换器,通过向容器注册WebMvcConfigurer组件重写相应的方法即可

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值