优质项目源码推荐

  1. SpringBoot + Vue + MyBatis 音乐网站项目

  2. 【超高颜值】一款高颜值的 SpringBoot+JPA 博客项目

  3. 推荐一款 SpringBoot 私活脚手架,开发效率可提高 70%

  4. Java 私活神器,一套 SpringBoot+Vue 通用的后台管理系统

  5. SpringCloud 网上商城系统(附源码及教程)

大家好,我是路人,这是 SpringMVC 系列第 27 篇。

本文将介绍 SpringMVC 中的@RequestAttribute 注解。

1、预备知识

  1. 接口测试利器 HTTP Client

  2. 参数解析器 HandlerMethodArgumentResolver 解密

2、@RequestAttribute 注解

2.1、作用

用来标注在接口的参数上,参数的值来源于 request 作用域。

2.2、用法

如下代码,site 参数上使用了@RequestAttribute("site")注解,site 参数的值等于request.getAttribute("site")

@ResponseBody
public String test2(@RequestAttribute("site") String site) {
    return site;
}

这个注解的源码如下

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestAttribute {

 /**
  * 指定request作用域中属性的名称
  */
 @AliasFor("name")
 String value() default "";

 /**
  * 同value属性
  */
 @AliasFor("value")
 String name() default "";

 /**
  * 属性是不是必须的,如果是true,request中没有取到时,则会抛出异常
  * 此时可以将required设置为false,或者使用java8中的Option类型来修饰参数解决
  */
 boolean required() default true;

}

3、案例

下面代码中有 2 个接口方法

  • 第一个方法 test1 中向 request 域中丢了一个 site 属性,然后进行了跳转,跳转到第二个方法,最后将 site 作为响应体输出

  • 第二个方的 site 参数上标注了@RequestAttribute("site"),所以会拿到 request 中 site 的值,然后输出

package com.javacode2018.springmvc.chat18.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;

@Controller
public class RequestAttributeController {

    @RequestMapping("/requestattribute/test1")
    public String test1(HttpServletRequest request) {
        request.setAttribute("site",
                "<a href='http://www.itsoku.com'>路人博客,包含了所有系列文章,阅读更方便</a>");
        return "forward:/requestattribute/test2";
    }

    @RequestMapping(value = "/requestattribute/test2", produces = "text/html;charset=UTF-8")
    @ResponseBody
    public String test2(@RequestAttribute("site") String site) {
        return site;
    }
}

浏览器中访问第一个接口/requestattribute/test1,输出如下

b3552528289e886ba0d7f9ef0bc49dc2.png

若我们调整一下接口 1 中代码,将 site 的值置为空

request.setAttribute("site", null);

此时再次访问接口会报 400 错误,原因:request 域中没有找到 site 这个属性对应的值,即 request.getAttribute("site")为 null

1f120db8742324c417dea1c3a6e327a8.png

2 种解决方案

  • 方案 1:将@RequestAttribute 的 required 属性设置为 false,常用这种方式

  • 方案 2:将@RequestAttribute 标注的参数类型调整为 java8 中的 java.util.Optional 类型,上面的接口 2 的 site 参数类型可以调整为Optional<String>类型,即可解决问题

4、@RequestAttribute 注解原理

@RequestAttribute 注解标注的参数的值来源于org.springframework.web.servlet.mvc.method.annotation.RequestAttributeMethodArgumentResolver解析器,源码

public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {

 @Override
 public boolean supportsParameter(MethodParameter parameter) {
  return parameter.hasParameterAnnotation(RequestAttribute.class);
 }

 @Override
 protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
  RequestAttribute ann = parameter.getParameterAnnotation(RequestAttribute.class);
  Assert.state(ann != null, "No RequestAttribute annotation");
  return new NamedValueInfo(ann.name(), ann.required(), ValueConstants.DEFAULT_NONE);
 }

 @Override
 @Nullable
 protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request){
  return request.getAttribute(name, RequestAttributes.SCOPE_REQUEST);
 }

 @Override
 protected void handleMissingValue(String name, MethodParameter parameter) throws ServletException {
  throw new ServletRequestBindingException("Missing request attribute '" + name +
    "' of type " +  parameter.getNestedParameterType().getSimpleName());
 }

}

5、案例代码 git 地址

https://gitee.com/javacode2018/springmvc-series

所有系列文章的均在此仓库中。

6、SpringMVC 系列目录

  1. SpringMVC 系列第 1 篇:helloword

  2. SpringMVC 系列第 2 篇:@Controller、@RequestMapping

  3. SpringMVC 系列第 3 篇:异常高效的一款接口测试利器

  4. SpringMVC 系列第 4 篇:controller 常见的接收参数的方式

  5. SpringMVC 系列第 5 篇:@RequestBody 大解密,说点你不知道的

  6. SpringMVC 系列第 6 篇:上传文件的 4 种方式,你都会么?

  7. SpringMVC 系列第 7 篇:SpringMVC 返回视图常见的 5 种方式,你会几种?

  8. SpringMVC 系列第 8 篇:返回 json & 通用返回值设计

  9. SpringMVC 系列第 9 篇:SpringMVC 返回 null 是什么意思?

  10. SpringMVC 系列第 10 篇:异步处理

  11. SpringMVC 系列第 11 篇:集成静态资源

  12. SpringMVC 系列第 12 篇:拦截器

  13. SpringMVC 系列第 13 篇:统一异常处理

  14. SpringMVC 系列第 14 篇:实战篇:通用返回值 & 异常处理设计

  15. SpringMVC 系列第 15 篇:全注解的方式  &  原理解析

  16. SpringMVC 系列第 16 篇:通过源码解析 SpringMVC 处理请求的流程

  17. SpringMVC 系列第 17 篇:源码解析 SpringMVC 容器的启动过程

  18. SpringMVC 系列第 18 篇:强大的 RequestBodyAdvice 解密

  19. SpringMVC 系列第 19 篇:强大的 ResponseBodyAdvice 解密

  20. SpringMVC 系列第 20 篇:RestFull 详解

  21. SpringMVC 系列第 21 篇:接口调用过利器 RestTemplate

  22. SpringMVC 系列第 22 篇:参数解析器 HandlerMethodArgumentResolver 解密

  23. SpringMVC 系列第 23 篇:@RequestParam 用法及原理详解

  24. SpringMVC 系列第 24 篇:@RequestBody 用法及原理详解

  25. SpringMVC 系列第 25 篇:@RequestHeader 用法及原理详解

  26. SpringMVC 系列第 26 篇:@CookieValue 用法及原理详解

7、更多系列文章

  1. Spring 高手系列(共 56 篇)

  2. Java 高并发系列(共 34 篇)

  3. MySql 高手系列(共 27 篇)

  4. Maven 高手系列(共 10 篇)

  5. Mybatis 系列(共 12 篇)

  6. 聊聊 db 和缓存一致性常见的实现方式

  7. 接口幂等性这么重要,它是什么?怎么实现?

  8. 泛型,有点难度,会让很多人懵逼,那是因为你没有看这篇文章!

8、最新资料

  1. 尚硅谷 Java 学科全套教程(总 207.77GB)

  2. 2021 最新版 Java 微服务学习线路图 + 视频

  3. 阿里技术大佬整理的《Spring 学习笔记.pdf》

  4. 阿里大佬的《MySQL 学习笔记高清.pdf》

  5. 2021 版 java 高并发常见面试题汇总.pdf

  6. Idea 快捷键大全.pdf

Logo

前往低代码交流专区

更多推荐