Spring MVC 注解详解

 2022-08-06

一、常用基础注解

1. @Controller

作用:此注解用用于修饰表现层控制器的注解

2. @RequestMapping

作用:用于建立请求URL和处理请求方法之间的对应关系

    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Mapping
    public @interface RequestMapping {
    
        //给请求URL提供一个名称
        String name() default "";
    
        //用于指定请求的URL,在配置此属性时,写不写/都是可以的
        @AliasFor("path")
        String[] value() default {};
    
        //用于指定请求的URL,在配置此属性时,写不写/都是可以的
        @AliasFor("value")
        String[] path() default {};
    
        //method:用于指定请求的方式。
        //它支持RequestMethod枚举指定的:GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE这些类型
        RequestMethod[] method() default {};
    
        //用于指定限制请求参数的条件
        //例如:params = {"accountName"},表示请求参数必须有accountName
        String[] params() default {};
    
        //用于指定限制请求消息头的条件
        //例如:headers = "content-type=text/*"
        String[] headers() default {};
    
        //用于指定可以接收的请求正文类型
        //consumes = {"text/plain", "application/*"}
        String[] consumes() default {};
    
        //用于指定可以生成的响应正文类型
        //produces = {"text/plain", "application/*"}
        String[] produces() default {};
    
    }

常见的衍生注解,用于Rest风格开发。如下:
Ⅰ @GetMapping
Ⅱ @PostMapping
Ⅲ @PutMapping
Ⅳ @DeleteMapping
Ⅴ @PatchMapping

3. @RequestParam

作用:此注解是从请求正文中获取请求参数,给控制器方法形参赋值的

    @Target(ElementType.PARAMETER)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface RequestParam {
    
        @AliasFor("name")
        String value() default "";
    
        @AliasFor("value")
        String name() default "";
    
        //当为true时,参数没有值会报错;false则非必须
        boolean required() default true;
    
        //在参数没有值时的默认值
        String defaultValue() default ValueConstants.DEFAULT_NONE;
    
    }

4. @InitBinder

作用:用于初始化表单请求参数的数据转换器,用于参数映射

    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface InitBinder {
        //用于指定给哪些参数做数据绑定,如果没有指定,则对所有参数生效
        String[] value() default {};
    
    }

Ⅰ 使用案例

在对应的Controller类中添加如下代码:

    //初始化数据转换器
    @InitBinder(value = {"user", "product"})
    public void dateBinder(WebDataBinder dataBinder){
        dataBinder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
    }

注意:此种使用方式仅对该Controller类内的方法起到转换绑定作用。
如需对所有Controller类的方法进行增强,可以配和@ControllerAdvice注解一起使用。

4.1 补充:@DateTimeFormat

作用:日期类型数据转换器,用于日期类型参数绑定

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
    public @interface DateTimeFormat {
        //是国际标准的(short date, short time)格式
        //具体为:MM/dd/yyyy HH:mm 
        //如:5/15/2022 20:57
        String style() default "SS";
    
        //默认不指定,指定则覆盖style属性,默认提供了三种形式的ISO格式
        ISO iso() default ISO.NONE;
    
        //自定义日期属性
        String pattern() default "";
    
        //枚举指定ISO日期格式
        enum ISO {
    
            /**
             * The most common ISO Date Format {@code yyyy-MM-dd},
             * e.g. "2000-10-31".
             */
            DATE,
    
            /**
             * The most common ISO Time Format {@code HH:mm:ss.SSSXXX},
             * e.g. "01:30:00.000-05:00".
             */
            TIME,
    
            /**
             * The most common ISO DateTime Format {@code yyyy-MM-dd'T'HH:mm:ss.SSSXXX},
             * e.g. "2000-10-31T01:30:00.000-05:00".
             * <p>This is the default if no annotation value is specified.
             */
            DATE_TIME,
    
            /**
             * Indicates that no ISO-based format pattern should be applied.
             */
            NONE
        }
    
    }

使用方式

Ⅰ 首先添加@EnableWebMvc注解

    @Configuration
    @ComponentScan("com.stone.controller")
    @EnableWebMvc //开启Spring对注解MVC的支持
    public class SpringMvcConfiguration implements WebMvcConfigurer {...}

Ⅱ 在需要绑定参数的属性上添加注解

    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
    private Date updateTime;

5. @ControllerAdvice

作用:用于给控制器提供一个增强的通知,以保证可以在多个控制器之间实现增强共享。

可以配合以下三个注解来用:
@InitBinder
@ExceptionHandler
@ModelAttribute

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Component
    public @interface ControllerAdvice {
        
        //用于指定对哪些包下的控制器进行增强
        @AliasFor("basePackages")
        String[] value() default {};
    
        //用于指定对哪些包下的控制器进行增强
        @AliasFor("value")
        String[] basePackages() default {};
    
        //可以通过指定类的字节码的方式来指定增强作用范围
        Class<?>[] basePackageClasses() default {};
    
        //用于指定特定的类型提供增强
        Class<?>[] assignableTypes() default {};
    
        //用于指定给特定注解提供增强
        Class<? extends Annotation>[] annotations() default {};
    }

使用方式

@ControllerAdvice注解不写其属性,则表示对所有的Controller类进行通知增强

    @ControllerAdvice
    public class InitBinderAdvice {
        @InitBinder("user")
        public void dateBinder(WebDataBinder dataBinder){
            dataBinder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
        }
    }

6. @RequestHeader

作用:此注解是从请求消息头中获取消息头的值,并把值赋给控制器方法形参

    @Target(ElementType.PARAMETER)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface RequestHeader {
    
        //用于指定请求消息头的名称
        @AliasFor("name")
        String value() default "";
    
        //用于指定请求消息头的名称
        @AliasFor("value")
        String name() default "";
    
        //用于指定是否必须有此消息头。当取默认值时,没有此消息头会报错
        boolean required() default true;
    
        //用于指定消息头的默认值
        String defaultValue() default ValueConstants.DEFAULT_NONE;
    }

使用方法

    @RequestMapping("/useRequestHeader")
    public String useRequestHeader(@RequestHeader(value="Accept-Language", 
        required=false)String requestHeader){...}

7. @CookieValue

作用:此注解是从请求消息头中获取Cookie的值,并把值赋给控制器方法形参

    @Target(ElementType.PARAMETER)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface CookieValue {
    
        //用于指定cookie的名称
        @AliasFor("name")
        String value() default "";
    
        //用于指定cookie的名称
        @AliasFor("value")
        String name() default "";
    
        //用于指定是否必须有此消息头。当取默认值时,没有此消息头会报错
        boolean required() default true;
    
        //用于指定消息头的默认值
        String defaultValue() default ValueConstants.DEFAULT_NONE;
    }

使用方式

    @RequestMapping("/useCookieValue")
    public String
    useCookieValue(@CookieValue(value="JSESSIONID",
        required=false) String cookieValue){...}

8. @ModelAttribute

作用:它可以用于修饰方法,或者是参数;
当修饰方法时,表示【执行控制器方法之前】,被此注解修饰的方法都会执行;
当修饰参数时,用于获取指定的数据给参数赋值。

    @Target({ElementType.PARAMETER, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface ModelAttribute {
    
        //当注解写在方法上,则表示存入时的名称。(值是方法的返回值)
        //当注解写在参数上,可以从ModelMap、Model、Map中的获取数据。(前提是之前存入过)
        //指定的是存入时的key
        @AliasFor("name")
        String value() default "";
    
        //和value的作用是一样的
        @AliasFor("value")
        String name() default "";
    
        //用于指定是否支持数据绑定
        boolean binding() default true;
    
    }

使用方式

Model是spring提供的一个接口,该接口有一个实现类ExtendedModelMap。该类继承了ModelMap,而ModelMap就是LinkedHashMap子类。

    //方式一:使用Model对象存储数据
    @ModelAttribute
    public void showModel(String username, Model model) {
        username = "prefix_" + username;
        model.addAttribute("username", username);
    }
    
    //方式二:通过返回值存储,需手动指定key
    @ModelAttribute("username")
    public String showModel(String username, Model model) {
        username = "prefix_" + username;
        return username;
    }
    
    //获取数据
    @RequestMapping("/testModelAttribute")
    public String testModelAttribute(@ModelAttribute("username") String username) {...}

使用场景:
由于此方法会在所有Controller方法执行之前执行,所以可以提前对获取到的参数做处理。
但是,也是因为所有的方法执行之前执行,使用的时候要【选择性的使用】。

9. @SessionAttribute和@SessionAttributes

作用:此注解是用于让开发者和ServletAPI进行解耦,让开发者可以无需使用HttpSession的getAttribute方法即可从会话域中获取数据。

注意:
没有使用此注解时,当我们在控制器方法形参中加入Model或者ModelMap类型参数时,默认是存入【请求域】的。
但当控制器上使用了此注解,就会往【会话域】中添加数据,【请求域】中仍然会存储。

    @Target(ElementType.PARAMETER)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface SessionAttribute {
        //用于指定在会话域中数据的名称
        @AliasFor("name")
        String value() default "";
    
        //用于指定在会话域中数据的名称
        @AliasFor("value")
        String name() default "";
    
        //用于指定是否必须从会话域中获取到数据。默认值是true,表示如果指定名称不存在会报错。
        boolean required() default true;
    }
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    public @interface SessionAttributes {
        //指定可以存入会话域中的名称
        @AliasFor("names")
        String[] value() default {};
    
        //指定可以存入会话域中的名称
        @AliasFor("value")
        String[] names() default {};
    
        //指定可以存入会话域中的数据类型
        Class<?>[] types() default {};
    }

使用方式

注意:
没有使用此注解时,当我们在控制器方法形参中加入Model或者ModelMap类型参数时,默认是存入【请求域】的。
但当控制器上使用了此注解,就会往【会话域】中添加数据,【请求域】中仍然会存储。
web的知识点:【会话域】存储的内容是会话共享的,而【请求域】中的内容仅当前请求有效。

    @Controller
    @SessionAttributes(value = {"username"})
    public class SessionAttributesController{
    
        //把数据存入SessionAttribute
        @RequestMapping("/testPut")
        public void testPut(Model model){
            model.addAttribute("username", "泰斯特");
        }
    
        //获取数据
        @RequestMapping("/testGet")
        public void testGet(ModelMap model){
            model.get("username");
        }
    
        //清空 Spring MVC 的 Session ,同时清除对应键的 HttpSession 内容
        //但是通过request.getSession.setAttribute () 方式添加的内容不会被清除掉
        @RequestMapping("/testClean")
        public void complete(SessionStatus sessionStatus){
            //手动清除SessionAttributes
            sessionStatus.setComplete();
        }
    
        @RequestMapping("/testSessionAttribute")
        public void testSessionAttribute(@SessionAttribute("username")String username){
            ////已经被清除,无法获取username的值
            sout(username);
        }
    
    }

注意:@SessionAttributes注解作用在类上,@SessionAttribute作用在请求参数位置,两者一般是配合使用的。

10. @ExceptionHandler

作用:用于注释方法,表明当前方法是控制器执行产生异常后的处理方法

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface ExceptionHandler {
        //指定用于需要捕获的异常类型
        Class<? extends Throwable>[] value() default {};
    }

使用方法

通常配合@ControllerAdvice注解一起使用,表示对所有的Controller类生效。

    @Slf4j
    @ControllerAdvice(annotations = {RestController.class, Controller.class})
    @ResponseBody
    public class GlobalExceptionHandler {
        /**
         * 异常处理方法
         * @param e 异常对象
         * @return 结果信息
         */
        @ExceptionHandler(Exception.class)
        public R<String> exceptionHandler(Exception e){
            log.info(e.getMessage());
            return R.error(e.getMessage());
        }
    }

二、JSON数据交互相关注解

1. @RequestBody

作用:用于获取全部的请求体

    @Target(ElementType.PARAMETER)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface RequestBody {
        //用于指定是否必须有请求体
        boolean required() default true;
    
    }

使用方式

注意:默认接收到的JSON数据格式是字符串类型的,如果需要封装成指定类型需要用到第三方组件。

    @RequestMapping("/useRequestBody")
    public void useRequestBody(@RequestBody(required=false) String body){
        System.out.println(body);
    }

使用第三方组件封装JSON字符串成指定类型,导入如下依赖:
Ⅰ jackson-core
Ⅱ jackson-databind
Ⅲ jackson-annotations

2. @ResponseBody

作用:用于用流输出响应正文

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface ResponseBody {
    
    }

使用方式

    //方式一
    @RequestMapping("useResponseBody")
    public @ResponseBody String useResponseBody(String name){
        return "success";
    }
    
    //方式二
    @RequestMapping("useResponseBody")
    @ResponseBody
    public String useResponseBody(String name){
        return "success";
    }
    
    //方式三
    //直接写在Controller类上
    //@RestController = @Controller + @ResponseBody

补充:@RestControllerAdvice = @ControllerAdvice + @ResponseBody

三、Rest风格URL请求相关注解

1. @PathVariable

作用:是springmvc框架支持rest风格url的标识,可以用于获取请求url映射中占位符对应的值。

    @Target(ElementType.PARAMETER)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface PathVariable {
        //指定url映射中占位符的名称
        @AliasFor("name")
        String value() default "";
    
        //指定url映射中占位符的名称
        @AliasFor("value")
        String name() default "";
    
        //用于指定是否必须有此占位符。当取默认值时,没有会报错。
        boolean required() default true;
    }

使用方式

    @RequestMapping("/usePathVariable/{id}")
    public void usePathVariable(@PathVariable("id") Integer id){
        sout(id);
    }

四、跨域访问

1. @CrossOrigin

作用:此注解用于指定是否支持跨域访问

1.1 补充:跨域访问

发起请求的资源所在域不同于该请求所指向资源所在的域,包含:协议、主机、端口,此三个有任意一个不一致,则称为跨域访问。
但是,包括CSS、图片、JavaScript 脚本以及其它类资源,即使没有使用@CrossOrigin也能够被跨域访问加载。

    @Target({ ElementType.METHOD, ElementType.TYPE })
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface CrossOrigin {
    
        @Deprecated
        String[] DEFAULT_ORIGINS = { "*" };
    
        @Deprecated
        String[] DEFAULT_ALLOWED_HEADERS = { "*" };
    
        @Deprecated
        boolean DEFAULT_ALLOW_CREDENTIALS = false;
    
        @Deprecated
        long DEFAULT_MAX_AGE = 1800;
    
        //"*"代表所有域的请求都支持
        @AliasFor("origins")
        String[] value() default {};
    
        //"*"代表所有域的请求都支持
        @AliasFor("value")
        String[] origins() default {};
    
        //允许请求头中的header,默认都支持
        String[] allowedHeaders() default {};
    
        //响应头中允许访问的header,默认为空
        String[] exposedHeaders() default {};
    
        //用于指定支持的HTTP请求方式列表
        RequestMethod[] methods() default {};
    
        //是否允许cookie随请求发送,使用时必须指定具体的域
        String allowCredentials() default "";
    
        //预请求的结果的有效期,默认值是:1800秒 (30分钟)
        long maxAge() default -1;
    
    }

使用方式

    @RestController
    @CrossOrigin
    public class CrossOriginController {
        @RequestMapping("/useCrossOrigin")
        public String useCrossOrigin() {
            return "success";
        }
    }

五、结尾

以上即为Spring MVC-注解开发-注解介绍的基础内容,感谢阅读。