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;    
    }    
}    
​    

Creativity requires the courage to let go of certainties.