Spring Mvc Annotations详解(上)

2020-04-01 · 树下魅狐 · · 本文共2,934个字,预计阅读需要14分钟。

序言

在上一节中,集中讲解了Spring框架中的构造型注解@Component,@Controller,@Service@Repository。在本章节中,将集中讲解Spring MVC中的注解进行讲解。对Spring MVC框架中所有注解的作用和用法进行解析。

1.@Controller

@Controller是一个类级别的注解,其表明当前类是Spring MVC中的视图控制器。当Spring应用程序开启了组件扫描后,Spring会根据类路径对那些带有@Controller注解的类进行扫描,并将其自动注入到Spring的容器中。该注解是Spring MVC框架中一个比较常见的注解,通常与@RequestMapping搭配使用。处理能在Spring MVC中使用外,@Controller注解也可以在Spring WebFlux中使用。下面是@Controller注解的简单示例:

@Controller
@RequestMapping("/demo")
public class DemoController{
    //省略其他
}

2. @RequestMapping

@RequestMapping可同时在类和方法上使用的注解。该注解用于将Web请求映射到具体的处理类和处理方法上。当该注解作用在类上是,你可以简单的理解为该注解定义了当前控制器所映射的Request请求地址的前缀,类中所有的处理方法都会加上在类上定义的URI地址。当该注解作用于方法上时,会将符合其URI规则的Request请求映射到当前的方法上。请看下面的例子:

@Controller
@RequestMapping("/users")
public class UserController{

    @RequestMapping("/")
    public String index(){
        return "/user/index";
    }

    @RequestMapping("/add")
    public String add(){
        return "/user/add"
    }
}

在上面的例子中,”/users/“会被映射到index()方法上,而”/users/add“会被映射到add()方法上。在默认情况下,@RequestMapping所处理的Web请求类型为”GET”类型。除了上述的方式之外,我们还可以取消在类上的注解,只在方法上进行定义,代码如下:

@Controller
public class UserController{

    @RequestMapping("/users/")
    public String index(){
        return "/user/index";
    }

    @RequestMapping("/users/add")
    public String add(){
        return "/user/add"
    }
}

为了代码的可读性和简洁性,推荐使用第一种方式定义请求的URI规则。

上述的书写方式是@RequestMapping的简写,“/users/”,”/users/add”其实是在给@RequestMapping的value属性进行赋值。value属性接受一个或多个String类型的变量,该变量可以是字符串,也可以是EL表达式。

2.1 @RequestMapping属性

@RequestMapping有六个属性值,它们分别是value,method,consumes,produces,params和headers。我们可以通过@RequestMapping注解详细了解一下:

RequestMapping.java

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
    String name() default "";

    @AliasFor("path")
    String[] value() default {};

    @AliasFor("value")
    String[] path() default {};

    RequestMethod[] method() default {};

    String[] params() default {};

    String[] headers() default {};

    String[] consumes() default {};

    String[] produces() default {};
}

接下来,将分别对@RequestMapping的属性进行介绍。

属性 说明
value 控制器映射的实际地址,设置value的值和path的值具有同等的作用
method 指定RequestMethod的类型,如GET,POST,PUT,DELETE等
consumes 指定处理方法所接受的数据格式(Content-Type),例如application/json,text/html等
produces 指定处理方法返回的数据格式,当且仅当Request请求头中的Accept类型中包含指定的数据格式,数据才会返回
params 指定Request中必须包含某些特定的参数,请求才会被映射到方法上,参数以键值对的方式加入到请求中
headers 指定Request中必须包含某些指定的header值,请求才会被映射到处理方法上。

在接下来的内容中,将分别演示如何使用这些属性。

2.2 处理多个URL

@RequestMapping的代码中可以看到,value属性接受一个String类型的数组。因此,我们可以通过value属性将多个URL请求映射到同一个方法上,例如:

@Controller
public class DemoController{

    @RequestMapping(value={"/","/index","/index.html","/home/index","/home/index.html","/start","/start.html"})
    public String home(){
        return "/home";
    }
}

设定应用程序的端口号为8080,那么,下列的请求都将被映射到DemoController类的home()方法上。

  • localhost:8080/
  • localhost:8080/index
  • localhost:8080/index.html
  • localhost:8080/home/index
  • localhost:8080/home/index.html
  • localhost:8080/start
  • localhost:8080/start.html

2.3 限定请求类型

@RequestMapping注解能够处理多种类型的Web请求,通过指定method属性的值,可以让方法处理诸如GET,POST,PUT,DELETE,PATCH等类型的请求。在默认情况下,@RequestMapping注解处理请求的类型为GET。在@RequestMapping注解中,method属性值的类型为RequestMethod类型,RequestMethod是一个枚举类型的Java类,内容如下:

RequestMethod.java

public enum RequestMethod {
    GET,
    HEAD,
    POST,
    PUT,
    PATCH,
    DELETE,
    OPTIONS,
    TRACE;

    private RequestMethod() {
    }
}

接下来,通过一个简单的Demo代码,了解method属性的使用。

@RestController
@RequestMapping("/hello")
public class SayHelloController{

    @RequestMapping(method=RequestMethod.GET)
    public String get(){
        return "Hello World!";
    }

    @RequestMapping(method=RequestMethod.DELETE)
    public String delete(){
        return "Delete Handler.";
    }

    @RequestMapping(method=RequestMethod.POST)
    public String post(){
        return "POST Handler.";
    }

    @RequestMapping(method=RequestMethod.PUT)
    public String put(){
        return "PUT Handler.";
    }

    @RequestMapping(method=RequestMethod.PATCH)
    public String patch(){
        return "PATCH Handler.";
    }

}

说明

为了便于测试,在这里使用了@RestController注解,它是@Controller@ResponseBody两个注解的组合注解。你也可以理解为快捷方式。

在上述的例子中,方法上的@RequestMapping没有指定value属性的值,则所有方法的请求URL都为类上定义的“/hello”;Spring MVC会根据“/hello”请求类型的不同,将URL映射到各自的方法上。例如,当“/hello”是以GET的方式发送请求,则该请求会被映射到get()方法上,同时将“Hello World”字符串返回到客户端。最后,我们通过CURL命令来测试这些请求:

$ curl -X GET http://localhost:8080/hello
Hello World
$ curl -X DELETE http://localhost:8080/hello
Delete Handler.
$ curl -X POST http://localhost:8080/hello
POST Handler.
$ curl -X PUT http://localhost:8080/hello
PUT Handler.
$ curl -X PATCH http://localhost:8080/hello
PATCH Handler.

2.4 限定数据格式

在使用@RequestMapping注解时,可以通过consumes和produces两个属性来限定请求和响应的数据格式。如果某个处理方法只允许接收JSON格式的请求数据,则可以通过设置consumes属性进行限定,例如:

@RestController
@RequestMapping("/users")
public class UserController{

    @RequestMapping(value="/add",method=RequestMethod.POST,consumes="application/JSON")
    public String add(User user){
        //...
        return "Success!";
    }
}

如果你想限定方法返回值的数据类型,则可以通过produes属性进行指定,例如:

@RestController
@RequestMapping("/users")
public class UserController{

    @RequestMapping(value="/add",method=RequestMethod.POST,produces="application/JSON")
    public User add(User user){
        //...
        return user;
    }
}

2.5 headers属性

如果在使用@RequestMapping注解时,你想根据header中设置的参数来映射具体的处理方法,则可以通过headers属性进行指定,例如:

@RestController
@RequestMapping("/demo")
public class DemoController{

    @RequestMapping(headers={"content-type=text/plain"})
    public String header(){
        return "headers handler";
    }
}

在此示例中,只有当请求头中Content-Type=text/plain时,“http://localhost:8080/demo”请求才会被映射到header()方法上。下面是通过curl测试的结果:

$ curl -H "Content-Type:text/html" http://localhost:8080/demo
header handler
$ curl -H "Content-Type:application/json" http://localhost:8080/demo
{"timestamp":"2020-04-01T08:08:57.224+0000","status":415,"error":"Unsupported Media Type","message":"Content type 'application/json' not supported","path":"/demo"}

2.6 params属性

如果某个方法在处理Web请求时必须要求中携带指定的参数,则可以通过params指定,只有符合URL规则且有指定参数的请求才会映射到当前的方法上,例如:

@RestController
public class OtherController {
    @RequestMapping(value = "/demo/params",params = "token=123")
    public String params(){
        return "params handler";
    }
}

curl测试结果:

$ curl http://localhost:8080/demo/params?token=123
params handler
$ curl http://localhost:8080/demo/params
{"timestamp":"2020-04-01T08:26:18.492+0000","status":400,"error":"Bad Request","message":"Parameter conditions "token=123" not met for actual request parameters: ","path":"/demo/params"}

2.7 与@RequestParam注解配合使用

@RequestMapping@RequestParam注解一起使用,可以将Web请求参数绑定到处理方法的参数上。可以使用@RequestParam给方法属性指定默认值以及设定该参数是否是必须的。例如:

@RequestMapping("/demo/requestparam")
    public String requestMethod(@RequestParam("username")String username,@RequestParam(value = "id",defaultValue = "0")Integer id){
        return "username:"+username+", id:"+id;
    }

curl测试结果:

$ curl http://localhost:8080/demo/requestparam?username=ramostear&id=1000
username:ramostear, id:1000
$ curl http://localhost:8080/demo/requestparam?username=ramostear
username:ramostear, id:0

2.8 动态URL

@RequestMapping可以和@PathVariable注解配合处理动态的URI,在这种情况下,URI中动态参数可以和方法中的参数进行绑定,同时还可以使用正则表达式进行URI的匹配。下面是一个简单的示例:

@RequestMapping("/demo/{id}")
public String dynamicUri(@PathVariable Integer id){
    return "user`s id="+id;
}
$ curl http://localhost:8080/demo/5
user`s id=5
@RequestMapping("user/{id:\\d+}/{username:[a-z]+}")
public String dynamicUris(@PathVariable("id") Integer id,
                          @PathVariable("username") String username){
    return "user`s info id="+id+", username="+username;
}
$ curl http://localhost:8080/user/100/ramostear
user`s info id=100, username=ramostear
$ curl http://localhost:8080/user/100/RAMOSTEAR
{"timestamp":"2020-04-01T09:00:04.150+0000","status":404,"error":"Not Found","message":"No message available","path":"/user/100/RAMOSTEAR"}

在第二个方法中,我们使用了正则表达式,限定了id必须为数字,username必须是a到z26个小写字母组成的字符串。

提示:

@PathVariable注解的参数不允许有空值,也没有默认值,但你可以选择当前参数是否是必须的。

3 @RequestMapping的快捷方式

Spring框架从4.3版本开始引入@RequestMapping注解的简写方式,这些简写方式可以提高编码的效率和代码的可读性。简单来说,@RequestMapping注解快捷方式是@RequestMpping(method=RequestMethod.XX)的一种变体。下面通过一张表格来进行对比:

全写 简写
@RequestMapping(method=RequestMethod.GET) @GetMapping
@RequestMapping(method=RequestMethod.POST) @PostMapping
@RequestMapping(method=RequestMethod.PATCH) @PatchMapping
@RequestMapping(method=RequestMethod.DELETE) @DeleteMapping
@RequestMapping(method=RequestMethod.PUT) @PutMapping

以上就是本节的全部内容,在下一篇内容当中,将介绍更细粒度的Spring MVC注解,例如@ExceptionHandler@InitBinder,@RequestAttribute,@RequestBody等等。