SpringBoot的Controller层常用注解

4,927 阅读19分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的30天,点击查看活动详情

👨‍🎓作者:Java学术趴

🏦仓库:GithubGitee

✏️博客:CSDN掘金InfoQ云+社区

💌公众号:Java学术趴

🚫特别声明:原创不易,未经授权不得转载或抄袭,如需转载可联系小编授权。

🙏版权声明:文章里的部分文字或者图片来自于互联网以及百度百科,如有侵权请尽快联系小编。微信搜索公众号Java学术趴联系小编。

☠️每日毒鸡汤:这个社会是存在不公平的,不要抱怨,因为没有用!人总是在反省中进步的!

👋大家好!我是你们的老朋友Java学术趴

3. SpringBoot中Controller层的注解

3.1 @Controller注解

@Controller : 加在类上面的注解,使得类里面的每个方法都返回一个视图页面。

但是在实际开发中,我们一般只是让后端的方法返回给前端是查询的数据,而不是一个新的视图页面。如果使用@Controller注解必须结合@ResponseBody,让这个方法返回给前端的不是一个视图,而只是给前端传递查询到的数据。

可以把@ResponseBody注解加到Controller类上或者是Controller层的方法上。

  • @ResponseBody添加到类上:代表这个类中国所有的方法都返回的数据,而不是视图。
  • @ResponseBody添加到方法上:代表只有这个方法返回的是数据,其他没有声明的返回的还是视图。

@Controller
public class HelloController {
​
@GetMapping(value="/hello")
@ResponseBody
public String say(){//返回json 数据  
    return "gril";
}
  
@GetMapping(value="/hello1")
public String say1(){//返回视图
    return "sys/index1";
}

为了解决这个麻烦的操作,SpringBoot中提供了@RestController注解解决这个问题,如下:

3.2 @RestController

@RestController :从Spring 4.0以后产生的,用来将json/xml数据发送到前台页面,而不是返回视图页面。它相当于@Controller和@ResponseBody。

@RestController加在类上面的注解,使得类里面的每个方法都将json/xml返回数据加返回到前台页面中。梭所以在实际开发中,我们一般都使用这个注解。

3.3 @RequestMapping("路径信息")

@RequestMapping("路径信息") :@RequestMapping 来映射请求,也就是通过它来指定控制器可以处理哪些URL请求。这个注解可以使用在Controller层的类或者方法上。

@RequestMapping中的参数:

  • path : 指定路径,和value没有区别,只是path不可以省略,value可以省略。

3.3.1 注解在Controller类上

  • 将 @RequestMapping 注解在 Controller 类上,这时类的注解是相对于 Web 根目录,而方法上的是相对于类上的路径。
  • 注意: @RequestMapping("/index") 等同于 @RequestMapping(value = "/index")

@RestController
@RequestMapping("/user")
// @RequestMapping(value = "/user")
public class UserController {
 
    @RequestMapping("/login")
    public String login() {
        return "success";
    }
}
// 此时请求的实际路径是:/user/login
// 在类上的@RequestMapping相当于声明一个根路径,在请求的时候他会把类和方上的路径进行拼接

3.3.2 注解在Controller类的方法上

method属性:

通过method属性来指定请求的类型:有GET(查)、POST(增)、PUT(改)、DELETE(删),由于浏览器表单无法发送 DELETE 和 PUT 请求,如果使用的话需要进行处理,所以我们在开发中一般使用 CET和POST请求方式完成请求任务。

  • 通过 @RequestMapping(value="/login",method=RequestMethod.GET) 来指定 login()方法 仅处理通过 GET 方式发来的请求

@RestController
@RequestMapping(path = "/user")
public class UserController {
    
    // 通过 method 属性来指定请求的类型,此时只能使用GET请求访问,使用POST会报错。
    @RequestMapping(path = "/login", method=RequestMethod.GET)
    public String login() {
        return "success";
    }
}
  • 通过 @RequestMapping(value="/login",method=RequestMethod.POST) 来指定 login()方法 仅处理通过 POST 方式发来的请求

@RestController
@RequestMapping(path = "/user")
public class UserController {
 
    // 通过 method 属性来指定请求的类型,此时只能使用POST请求访问,使用GET会报错。
    @RequestMapping(path = "/login", method=RequestMethod.POST)
    public String login() {
        return "success";
    }
}
  • 由于在 RequestMapping 注解类中 method() 方法返回的是 RequestMethod 数组,所以可以给 method 同时指定多个请求方式,例如

@RestController
@RequestMapping(path = "/user")
public class UserController {
     // 该方法将同时接收通过GET和POST方式发来的请求
    @RequestMapping(path = "/login", method={RequestMethod.POST,RequestMethod.GET})
    public String login() {
        return "success";
    }
}

params属性:

  • @RequestMapping 的 params 属性,该属性表示请求参数,也就是追加在URL上的键值对,多个请求参数以&隔开,例如:

http://localhost/SpringMVC/user/login?username=kolbe&password=123456
  • 则这个请求的参数为username=kolbe以及password=123456,@RequestMapping 中可以使用 params 来限制请求参数,来实现进一步的过滤请求,举个例子:

@Controller
@RequestMapping(path = "/user")
public class UserController {
        
     // 该方法将接收 /user/login 发来的请求,且请求参数必须为 username=kolbe&password=123456
    @RequestMapping(path = "/login", params={"username=kolbe","password=123456"})
    public String login() {
        return "success";
    }
}
  • 该例中则表示 UserController 中的 login() 方法仅处理 /user/login 发来的请求,且必须带有 username=kolbe&password=123456 的请求参数,否则浏览器将返回HTTP 404的错误。

headers 属性:

  • @RequestMapping 的 headers 属性,该属性表示请求头。

  • 通过 @RequestMapping 中的 headers 属性,可以限制客户端发来的请求。

@Controller
@RequestMapping(path = "/user")
public class UserController {
     // 表示只接收 localhost:8080 发来的请求,不会处理其他请求
    @RequestMapping(path = "/login", headers="Host=localhost:8080")
    public String login() {
        return "success";
    }
}

带有占位符的URL

  • 带占位符的URL是Spring 3.0 新增的功能,可以通过 @PathVariable 将 URL 中的占位符绑定到控制器的处理方法的参数中,占位符使用{}括起来。

@Controller
@RequestMapping(path = "/user")
public class UserController {
     // 当只存在一个参数的时候,可以省略@PathVariable("id")注解,但是后边的参数名必须和{}中的占位符名字一致,否则找不到会报错。
    // 当给定 @PathVariable("id") 的时候括号中的参数名字必须和{}中占位符的名字一致。此时后边的参数可以随便定义其他的名字比如:@PathVariable("id") Integer param
    @RequestMapping(value="/{id}", method=RequestMethod.GET)
    public String show(@PathVariable("id") Integer id) {
        return "success";
    }
}

在这个控制器中 show() 方法将可以接收 user/1、user/2、user/3等等的路径请求,请求的方法必须为GET,使用 @PathVariable 为应用实现 REST 规范提供了具大的便利条件。

3.4 @PostMapping("路径信息")

  • 用于将Http Post 请求映射到特定处理程序方法的注释。具体来讲就是:@PostMapping是一个做为快捷方式的组合注释@RequestMapping(method = RequestMethod.POST)。
  • 这个注解相当于: @RequestMapping(value="/{id}", method=RequestMethod.POST)

3.5 @GetMapping("路径信息")

  • 用于将Http Get 请求映射到特定处理程序方法的注释。具体来讲就是:@GetMapping是一个做为快捷方式的组合注释 @RequestMapping(method = RequestMethod.GET)。
  • 这个注解相当于: @RequestMapping(value="/{id}", method=RequestMethod.GET)

相似组合注解还有:@PutMapping、@DeleteMapping、@PatchMapping分别对用method的PUT、Delete以及Patch

3.6 @Api(tags = "针对这个Controller类的描述")

@Api :这个注解是Swagger中的一个注解,专门用于在Controller类上,针对这个Controller接口类生成一个文档的描述,在之后生成的Swagger的Api文档中会对这个Controller进行介绍。

参数信息:

  • tags: 生成的api文档会根据tags分类,直白的说就是这个controller中的所有接口生成的接口文档都会在tags这个list下;tags如果有多个值,会生成多个list,每个list都显示所有接口。

@Api(tags = "列表1")
@Api(tags = {"列表1","列表2"})
  • value : 它的作用和 tags 是一样的,只是不可以生成多个list,只能生成一个。

// 用于 Controller 类上
@Api(tags = "客户端通信服务端接口")

3.7 @ApiOperation("针对Controller类中某个方法的描述")

@ApiOperation : 这个也是Swagger中的一个注解,作用在Controller类中的方法上,针对这个接口进行描述,会在Swagger的Api文档中进行记录。

参数信息:

  • value: 对这个方法进行描述,value可以省略。
  • notes : 用于提示内容。

// 用于 Controller 类中的接口上
@ApiOperation(value = "客户端下载对应脚本", notes = "下载脚本")

这两个Swagger注解用于 Controller 类上,还有 @ApiModel()以及@ApiModelProperty()用于实体类上,注意区分

3.8 @Autowired

@Autowired : spring可以自动帮你把bean里面引用的对象的setter/getter方法省略,它会自动帮你set/get。他会帮你完成对该Bean对象的自动装配。

@Autowired这个注解是属于SpringBoot的

@Autowired自动创建和装配的原理: 默认加在IOC容器中的组件,容器会调用无参构造器创建对象,在进行初始化赋值等操作,如果只有有参构造,Spring会调用有参构造,有参构造函数会自动注入。

@Autowired使用的地方:

  • 构造器 : 如果组件只有一个有参构造器,这个有参构造器的@Autowrite可以省略,参数位置组件还是可以自动从容器中获取。
  • 方法:@Bean或者方法参数,参数从容器中获取;默认不写@Autowrite效果是一样的,都能自动装配。
  • 参数 :可以自动注入。
  • 属性 :可以自动注入。

注意:使用 @Autowrite声明的对象一般声明为 private


package com.sue.cache.service;
​
import org.springframework.stereotype.Service;
​
@Service
public class TestService1 {
    public void test1() {
    }
}
​
package com.sue.cache.service;
​
import org.springframework.stereotype.Service;
​
@Service
public class TestService2 {
​
    //自动装配一个 Service 层的实例对象
    @Autowired
    private TestService1 testService1;
​
    public void test2() {
    }
}

@Autowride的使用原理,他是在返回数据的时候使用DI技术实现的。DAO层不用使用@Autowited,因为这层不需要实体类

注意:

  • spring是按照类型装配的,也就是我们所说的byType方式。

  • 如果要修改为根据 byName进行自动装配,需要和 @Qualifier() 注解 配套使用

    
    @Autowired() 
    @Qualifier("baseDao")     
    private BaseDao baseDao;   
    

    byName : 会搜索整个配置文件中的bean,如果有相同名称的bean则自动装配,否则显示异常。(类名)
    byType : 会搜索整个配置文件中的bean,如果有相同类型的bean则自动装配,否则显示异常。(类的类别)
    
  • @Autowired注解的required参数默认是true,表示开启自动装配,有些时候我们不想使用自动装配功能,可以将该参数设置成false。

    required = true :开启自动装配(默认)
    required = false : 关闭自动装配(需手动开启)
    

在 IDEA 中 @Autowired 存在下划线,但是可以正常使用。这是为什么呢???

  • 因为 @Autowired 是基于构造函数的,正确的使用方式应该是使用构造函数的饿方式声明一个类对象。才是@Autowired注解的正确用法。

private final CategoryMapper categoryMapper;
​
public CategoryServiceImpl(CategoryMapper categoryMapper) {
    this.categoryMapper = categoryMapper;
}

但是在实际开发中,我们都直接使用 @Autowired 来简化开发的难度。


@Autowired
private CategoryMapper categoryMapper;

所以他会存在一个提醒的下画波浪线,但是不影响使用。

3.9 @Resource

@Resource :@Resource注解和@Autowired注解一样,都是为了装配Bean,但是两者在使用上又有少许区别。@Resource默认按照名字装配Bean,即会按照name属性的值来找到具有相同id的Bean Definition 并注入。如果@Resource没有指定name属性,则会根据这个将要被注入的属性的名字来进行Bean装配。

  1. 我们先来定义一个Bean(通过注解的方式定义)

@Component(value = "renlei")
public class Person {
    String name;
 
    Integer age;
}
  1. 然后我们再来定义一个类House,并引用上面的Person,使容器对它自动装配

使用 @Resource(name = "renlei") 中name属性值去对应@Component(value = "renlei") 中的value值


@Component
public class House {
    
    //@Resource的name属性的值与Person类的@Component的value值相对应【都是 renlei】,所以可以进行装配
    @Resource(name = "renlei")
    private Person p1;
    
 
    
    //@Resource的name属性的值与Person类的@Component的value值不对应,一个是relei,一个是person,所以装配失败
    @Resource(name = "person")
    private Person p1;
 
 
    //@Reource 没有指定name的值,所以容器会拿这个p1变量的名字去Bean池子中查找id为renlei的bean并装配到这个renlei变量中。装配成功
    @Reource
    private Person renlei;
 
    // @Reource 没有指定name的值,所以容器会拿这个p1变量的名字去Bean池子中查找id为p1的bean并装配到这个          p1变量中。如果找不到,就按照类型来进行装配,都是Person类,所以装配成功
    // 注意:这里存在一个先更具 byName方式匹配之后根据 byType方式匹配,都不成功的时候才会报错。
    @Reource
    private Person p1;
    
}

@Resource这个注解是属于 J2EE的。用于属性或者方法上,一般用于属性上。

@Resource注解使用的过程:

  1. 当启动spring容器的时候,spring容器加载了配置文件

  2. 在spring配置文件中,只要遇到bean的配置,就会为该bean创建对象

  3. 在纳入spring容器的范围内查找所有的bean,看哪些bean的属性或者方法上加有@Resource

  4. 找到@Resource注解以后,判断该注解name的属性是否为""(name没有写)

    • 如果没有写name属性,则会让属性的名称的值和spring中ID的值做匹配,如果匹配成功则赋值如果匹配不成功,则会按照类型进行匹配,如果匹配不成功,则报错。
    • 如果有name属性,则会按照name属性的值和spring的bean中ID进行匹配,匹配成功,则赋值,不成功则报错。

注意:@Resource先使用 byName 进行匹配,匹配不成功给则使用 byType 方式,如果还是匹配失败,则报错。在实际开发中,我们一般都给 @Service、@Controller以及@Repository 的value属性,所以在项目中使用的 @Resource 注解都是使用的 byType 类型匹配方式。

3.10 @Value

3.10.1 @Value("${...}") -- 配置参数值注入

3.10.1.1 @Value("1")
  • 给变量赋一个值。

@Value("张三")
private String name;
​
// 以上用法相当于
private String name = "张三";
3.10.1.2 @Value("${...}") -- 配置参数值注入

@Value :项目启动时,用于读取配置文件给静态文件赋值。读取SpringBoot的主配置文件中的属性值。

使用方式:

  1. application.yml配置文件

student:
    name:张三
    age:20
    room:java
  1. 在代码层获取这个变量值

@Value("${student.name}")
private String name;
​
// 此时的name等于张三

如果配置参数 student.name 在配置文件中未定义则注入失败,抛出异常IllegalArgumentException


java.lang.IllegalArgumentException: 
Could not resolve placeholder 'server.error.path' in value "${server.error.path}"

@Value("{...:{...}}") 嵌套使用


@Value("${student.name:${studnet.age:/student.room}}")
private String info;
  1. 注入配置参数 student.name 的值。
  2. student.name 值未定义,注入配置参数 studnet.age 的值。
  3. 如果 student.namestudnet.age 都没有定义,则使用 student.room 的值。
  4. 如果这三个值都未定义,则报以上的错误。

3.10.2 @Value("#{...}") -- SPEL表达式求值注入

3.10.2.1 @Value("#{1}")

@Value("#{"张三"}")
private String name;
​
// 此时的name等于张三
  • 注入 bean student 属性name的值
  • 如果 student 不存在或者其属性 name 不存在,则抛出异常 SpelEvaluationException

org.springframework.expression.spel.SpelEvaluationException: 
EL1008E: Property or field 'student' cannot be found on object of type 
'org.springframework.beans.factory.config.BeanExpressionContext' 
- maybe not public or not valid?
3.10.2.2 @Value("#{...}")

@Value("#{student.name ?: '张三'}")
  • 注入 bean student 的属性name值
  • 如果student存在并且有属性name,但属性值为null,则注入值“张三”

这个 @Value 注解可以使用在任何层

3.11 @PathVariable

@PathVariable : 映射URL绑定的占位符。

带占位符的URL是 Spring3.0 新增的功能,URL中的 {xxx} 占位符可以通过 @PathVariable("xxx") 绑定到操作方法的入参中。


@RequestMapping("/user/{id}")
public String testPathVariable(@PathVariable("id") String id){
    System.out.println("路径上的占位符的值="+id);
    return "success";
}
  • 当URL中只存在一个一个占位符的时候,可以省略这个@PathVariable注解,此时后面参数名必须和占位符的名字一致。

@RequestMapping("/user/{id}")
// 这个参数名必须是id,和占位符一致才可以识别到。
public String testPathVariable(String id){
    System.out.println("路径上的占位符的值="+id);
    return "success";
}
  • 当给定@PathVariable注解的时候,这个注解中的值必须和占位符名一致,此时后面的参数名可以自定义。

@RequestMapping("/user/{id}")
// @PathVariable("id") 中的参数名必须和占位符一致,此时后面的参数可以任意给定。
public String testPathVariable(@PathVariable("id") String myId){
    System.out.println("路径上的占位符的值="+myId);
    return "success";
}
  • 当存在多个占位符的时候,此时不可以省略 @PathVariable 注解,并且要把其中的参数和占位符相对应。

@RequestMapping("/user/{id}/{name}")
public String testPathVariable(@PathVariable("id") String myId, @PathVariable("name") String myName,){
    System.out.println("路径上的占位符的值="+id);
    return "success";
}

3.12 @RequestParam

@RequestParam : 这个注解是用于后端接收数据的。接收的参数是来自requestHeader中,即请求头。通常用于GET请求,像POST、DELETE等其它类型的请求也可以使用。比如常见的url:http://localhost:8081/spring-boot-study/novel/findByAuthorAndType?author=唐家三少&type=已完结


@RequestMapping(value = "add",method = RequestMethod.GRT)
public void addPeople(@RequestParam(value = "name", required = fasle,default = "Java学术趴") String name,@RequestParam(value = "age") Integer age){
  .....
}

3.13 @RequestBody

@RequestBody :这个注解也是用于后端接收数据的。接收的参数是来自requestBody中,即请求体。通常用于接收POST、DELETE等类型的请求数据,GET类型也可以适用。一般用于处理非 Content-Type: application/x-www-form-urlencoded编码格式的数据,比如:application/json、application/xml等类型的数据。

  • application/json类型的数据而言,使用注解@RequestBody可以将body里面所有的json数据传到后端,后端再进行解析。

@RequestMapping(value = "add",method = RequestMethod.GRT)
public void addPeople(@RequestBody People people){
  .....
}

在后端的同一个接收方法里,@RequestBody与@RequestParam()可以同时使用,@RequestBody最多只能有一个,而@RequestParam()可以有多个。

3.14 @ExceptionHandler

3.14.1 基本用法

  • Spring的@ExceptionHandler可以用来统一处理方法抛出的异常,比如这样:

@ExceptionHandler()
public String handleExeption2(Exception ex) {
    System.out.println("抛异常了:" + ex);
    ex.printStackTrace();
    String resultStr = "异常:默认";
    return resultStr;
}

比如上面的handleExeption2()方法,给这个方法加上@ExceptionHandler注解,这个方法就会处理类中其他方法(被@RequestMapping注解)抛出的异常。

3.1.4.2 注解的参数

@ExceptionHandler注解中可以添加参数,参数是某个异常类的class,代表这个方法专门处理该类异常,比如这样:


@ExceptionHandler(NumberFormatException.class)
public String handleExeption(Exception ex) {
    System.out.println("抛异常了:" + ex);
    ex.printStackTrace();
    String resultStr = "异常:NumberFormatException";
    return resultStr;
}

此时注解的参数是NumberFormatException.class,表示只有方法抛出NumberFormatException时,才会调用该方法。如果抛出其他的异常的时候,这个方法就不可以接收到这个异常。

3.1.4.3 就近原则

当异常发生时,Spring会选择最接近抛出异常的处理方法。

比如之前提到的NumberFormatException,这个异常有父类RuntimeException,RuntimeException还有父类Exception,如果我们分别定义异常处理方法,@ExceptionHandler分别使用这三个异常作为参数,比如这样:


@ExceptionHandler(NumberFormatException.class)
public String handleExeption(Exception ex) {
    System.out.println("抛异常了:" + ex);
    ex.printStackTrace();
    String resultStr = "异常:NumberFormatException";
    return resultStr;
}
 
@ExceptionHandler()
public String handleExeption2(Exception ex) {
    System.out.println("抛异常了:" + ex);
    ex.printStackTrace();
    String resultStr = "异常:默认";
    return resultStr;
}
 
@ExceptionHandler(RuntimeException.class)
public String handleExeption3(Exception ex) {
    System.out.println("抛异常了:" + ex);
    ex.printStackTrace();
    String resultStr = "异常:RuntimeException";
    return resultStr;
}

那么,当代码抛出NumberFormatException时,调用的方法将是注解参数NumberFormatException.class的方法,也就是handleExeption(),而当代码抛出IndexOutOfBoundsException时,调用的方法将是注解参数RuntimeException的方法,也就是handleExeption3()。

3.1.1.4 注解方法的返回值

标识了@ExceptionHandler注解的方法,返回值类型和标识了@RequestMapping的方法是统一的,可参见@RequestMapping的说明,比如默认返回Spring的ModelAndView对象,也可以返回String,这时的String是ModelAndView的路径,而不是字符串本身。

有些情况下我们会给标识了@RequestMapping的方法添加 @ResponseBody,比如使用Ajax的场景,直接返回字符串,异常处理类也可以如此操作,添加@ResponseBody注解后,可以直接返回字符串,比如这样:


@ExceptionHandler(NumberFormatException.class)
@ResponseBody
public String handleExeption(Exception ex) {
    System.out.println("抛异常了:" + ex);
    ex.printStackTrace();
    String resultStr = "异常:NumberFormatException";
    return resultStr;
}

这样的操作可以在执行完方法后直接返回字符串本身。

3.1.1.5 错误的操作

使用@ExceptionHandler时尽量不要使用相同的注解参数

如果我们定义两个处理相同异常的处理方法:


@ExceptionHandler(NumberFormatException.class)
@ResponseBody
public String handleExeption(Exception ex) {
    System.out.println("抛异常了:" + ex);
    ex.printStackTrace();
    String resultStr = "异常:NumberFormatException";
    return resultStr;
}
 
@ExceptionHandler(NumberFormatException.class)
@ResponseBody
public String handleExeption2(Exception ex) {
    System.out.println("抛异常了:" + ex);
    ex.printStackTrace();
    String resultStr = "异常:默认";
    return resultStr;
}

两个方法都处理NumberFormatException,这种定义方式编译可以通过,而当NumberFormatException真正被抛出时,Spring会给我们报错:


java.lang.IllegalStateException: Ambiguous @ExceptionHandler method mapped for [class java.lang.NumberFormatException]: {public java.lang.String TestController.handleExeption(java.lang.Exception), public java.lang.String TestController.handleExeption2(java.lang.Exception)}
    at org.springframework.web.method.annotation.ExceptionHandlerMethodResolver.addExceptionMapping(ExceptionHandlerMethodResolver.java:102) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.method.annotation.ExceptionHandlerMethodResolver.<init>(ExceptionHandlerMethodResolver.java:66) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]

3.18 @ModelAttribute

  • @ModelAttribute注解常用在Controller层的方法上,被@ModelAttribute声明的方法在Controller层每个方法执行之前都会执行,因此对于一个Controller层包含多个URL的时候,要谨慎使用。在开发中,我们一般都是把被@ModelAttribute声明的方法单独的提取出来。

3.15 @ControllerAdvice

  • @ControllerAdvice是@Controller注解的一个增强,这个注解是Spring里面的东西,可以处理全局异常。当然在Spring Boot中也可以使用,但是Spring Boot中有它全自动化配置的异常处理,因为是全自动化的,因此也可以自己定制,比如定制它的异常页面,异常信息提示,异常视图。需要配合@ModelAttribute一起使用。

@ControllerAdvice
public class MyAdviceException {
     //MaxUploadSizeExceededException,这个是异常类,这里可以枚举多个异常
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public void myexcept(MaxUploadSizeExceededException e, HttpServletResponse response){
         response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = null;
        try {
            writer = response.getWriter();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        writer.write("文件太大,请重新选择");
        writer.flush();
        writer.close();
​
    }
}

3.16 @ResponseStatus

  • @ResponseStatus的作用就是为了改变HTTP响应的状态码。

3.17 @CrossOrigin

3.17.1 跨域介绍

  • @CrossOrigin注解:出于安全原因,浏览器禁止Ajax调用驻留在当前源点之外的资源。比如:当你在一个网页中查看你的银行账户,此时你在另一个页面中访问这个银行账户的时候,此时就禁止这个页面向当这个银行账户发送请求。这样就保证了账户的安全。
  • 跨源资源共享(CORS)是由大多数浏览器实现的W3C规范,允许您灵活地指定什么样的跨域请求被授权,而不是使用一些不太安全和不太强大的策略,如IFPAME或JSONP。

3.17.2 使用方式

1. 给controller中的某个方法配置CORS

controller方法的CORS配置,您可以向@RequestMapping注解处理程序方法添加一个@CrossOrigin注解,以便启用CORS(默认情况下,@CrossOrigin允许在@RequestMapping注解中指定的所有源和HTTP方法):

为单独的方法配置跨域请求


@RestController
@RequestMapping("/account") public class AccountController {
 
 @CrossOrigin
 @GetMapping("/{id}") 
 public Account retrieve(@PathVariable Long id) { // ...
   
 }
  
 @DeleteMapping("/{id}")
 public void remove(@PathVariable Long id) { // ...
   
 }
}

@CrossOrigin注解中的参数

  • origins : 允许可访问的域列表
  • maxAge:准备响应前的缓存持续的最大时间(以秒为单位)。

2.为整个controller启用@CrossOrigin

在这个例子中,对于retrieve()和remove()处理方法都启用了跨域支持,还可以看到如何使用@CrossOrigin属性定制CORS配置。


@CrossOrigin(origins = "http://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account") public class AccountController {
 
 @GetMapping("/{id}") public Account retrieve(@PathVariable Long id) { // ...
   
 }
 
 @DeleteMapping("/{id}") public void remove(@PathVariable Long id) { // ...
   
 }
}

3. 同时使用controller和方法级别的CORS配置,Spring将合并两个注释属性以创建合并的CORS配置。


@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account") public class AccountController {
 
 @CrossOrigin(origins = "http://domain2.com")
 @GetMapping("/{id}") 
 public Account retrieve(@PathVariable Long id) { 
   // ...
 }
 
 @DeleteMapping("/{id}") 
 public void remove(@PathVariable Long id) { 
   // ...
 }
}

3.18 @InitBinder

@InitBinder : 在实际操作中经常会碰到表单中的日期 字符串和Javabean中的日期类型的属性自动转换, 而springMVC默认不支持这个格式的转换,所以必须要手动配置, 自定义数据类型的绑定才能实现这个功能。

@InitBinder用于在@Controller中标注于方法,表示为当前控制器注册一个属性编辑器或者其他,只对当前的Controller有效。

@RequestMapping("test")
@Controller
public class TestController {
​
    @InitBinder
    public     void InitBinder(WebDataBinder binder){
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        CustomDateEditor dateEditor = new CustomDateEditor(df, true);
        binder.registerCustomEditor(Date.class,dateEditor);
    }
​
    @RequestMapping(value="/param",method=RequestMethod.GET)
    @ResponseBody
    public Map<String,Object> getFormatData(Date date) throws ParseException{
        Map<String,Object> map = new HashMap<String, Object>();
        map.put("name", "zhangsan");
        map.put("age", 22);
        map.put("date",date);
        return map;
    }
}
​