前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringBoot的Controller层常用注解

SpringBoot的Controller层常用注解

原创
作者头像
Java学术趴
发布2022-06-29 23:20:26
2.4K0
发布2022-06-29 23:20:26
举报
文章被收录于专栏:Java全栈·Java全栈·

👨‍🎓作者:Java学术趴 🏦仓库:GithubGitee ✏️博客:CSDN掘金InfoQ云+社区 🚫特别声明:原创不易,未经授权不得转载或抄袭,如需转载可联系小编授权。 🙏版权声明:文章里的部分文字或者图片来自于互联网以及百度百科,如有侵权请尽快联系小编。

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

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

3. SpringBoot中Controller层的注解

3.1 @Controller注解

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

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

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

  • @ResponseBody添加到类上:代表这个类中国所有的方法都返回的数据,而不是视图。
  • @ResponseBody添加到方法上:代表只有这个方法返回的是数据,其他没有声明的返回的还是视图。
代码语言:javascript
复制
@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")
代码语言:javascript
复制
@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 方式发来的请求
代码语言:javascript
复制
@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 方式发来的请求
代码语言:javascript
复制
@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 同时指定多个请求方式,例如
代码语言:javascript
复制
@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上的键值对,多个请求参数以&隔开,例如:
代码语言:javascript
复制
http://localhost/SpringMVC/user/login?username=kolbe&password=123456
  • 则这个请求的参数为username=kolbe以及password=123456,@RequestMapping 中可以使用 params 来限制请求参数,来实现进一步的过滤请求,举个例子:
代码语言:javascript
复制
@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 属性,可以限制客户端发来的请求。
代码语言:javascript
复制
@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 中的占位符绑定到控制器的处理方法的参数中,占位符使用{}括起来。
代码语言:javascript
复制
@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都显示所有接口。
代码语言:javascript
复制
@Api(tags = "列表1")
@Api(tags = {"列表1","列表2"})
  • value : 它的作用和 tags 是一样的,只是不可以生成多个list,只能生成一个。
代码语言:javascript
复制
// 用于 Controller 类上
@Api(tags = "客户端通信服务端接口")

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

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

参数信息:

  • value: 对这个方法进行描述,value可以省略。
  • notes : 用于提示内容。
代码语言:javascript
复制
// 用于 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

代码语言:javascript
复制
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注解的正确用法。
代码语言:javascript
复制
private final CategoryMapper categoryMapper;
​
public CategoryServiceImpl(CategoryMapper categoryMapper) {
    this.categoryMapper = categoryMapper;
}

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

代码语言:javascript
复制
@Autowired
private CategoryMapper categoryMapper;

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

3.9 @Resource

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

  1. 我们先来定义一个Bean(通过注解的方式定义)
代码语言:javascript
复制
@Component(value = "renlei")
public class Person {
    String name;
 
    Integer age;
}
  1. 然后我们再来定义一个类House,并引用上面的Person,使容器对它自动装配

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

代码语言:javascript
复制
@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")
  • 给变量赋一个值。
代码语言:javascript
复制
@Value("张三")
private String name;
​
// 以上用法相当于
private String name = "张三";
3.10.1.2 @Value("${...}") -- 配置参数值注入

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

使用方式:

  1. application.yml配置文件
代码语言:javascript
复制
student:
    name:张三
    age:20
    room:java
  1. 在代码层获取这个变量值
代码语言:javascript
复制
@Value("${student.name}")
private String name;
​
// 此时的name等于张三

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

代码语言:javascript
复制
java.lang.IllegalArgumentException: 
Could not resolve placeholder 'server.error.path' in value "${server.error.path}"

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

代码语言:javascript
复制
@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}")
代码语言:javascript
复制
@Value("#{"张三"}")
private String name;
​
// 此时的name等于张三
  • 注入 bean student 属性name的值
  • 如果 student 不存在或者其属性 name 不存在,则抛出异常 SpelEvaluationException
代码语言:javascript
复制
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("#{...}")
代码语言:javascript
复制
@Value("#{student.name ?: '张三'}")
  • 注入 bean student 的属性name值
  • 如果student存在并且有属性name,但属性值为null,则注入值“张三”

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

3.11 @PathVariable

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

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

代码语言:javascript
复制
@RequestMapping("/user/{id}")
public String testPathVariable(@PathVariable("id") String id){
    System.out.println("路径上的占位符的值="+id);
    return "success";
}
  • 当URL中只存在一个一个占位符的时候,可以省略这个@PathVariable注解,此时后面参数名必须和占位符的名字一致。
代码语言:javascript
复制
@RequestMapping("/user/{id}")
// 这个参数名必须是id,和占位符一致才可以识别到。
public String testPathVariable(String id){
    System.out.println("路径上的占位符的值="+id);
    return "success";
}
  • 当给定@PathVariable注解的时候,这个注解中的值必须和占位符名一致,此时后面的参数名可以自定义。
代码语言:javascript
复制
@RequestMapping("/user/{id}")
// @PathVariable("id") 中的参数名必须和占位符一致,此时后面的参数可以任意给定。
public String testPathVariable(@PathVariable("id") String myId){
    System.out.println("路径上的占位符的值="+myId);
    return "success";
}
  • 当存在多个占位符的时候,此时不可以省略 @PathVariable 注解,并且要把其中的参数和占位符相对应。
代码语言:javascript
复制
@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=已完结

代码语言:javascript
复制
@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数据传到后端,后端再进行解析。
代码语言:javascript
复制
@RequestMapping(value = "add",method = RequestMethod.GRT)
public void addPeople(@RequestBody People people){
  .....
}

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

3.14 @ExceptionHandler

3.14.1 基本用法
  • Spring的@ExceptionHandler可以用来统一处理方法抛出的异常,比如这样:
代码语言:javascript
复制
@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,代表这个方法专门处理该类异常,比如这样:

代码语言:javascript
复制
@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分别使用这三个异常作为参数,比如这样:

代码语言:javascript
复制
@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注解后,可以直接返回字符串,比如这样:

代码语言:javascript
复制
@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时尽量不要使用相同的注解参数

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

代码语言:javascript
复制
@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会给我们报错:

代码语言:javascript
复制
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一起使用。
代码语言:javascript
复制
@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方法):

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

代码语言:javascript
复制
@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配置。

代码语言:javascript
复制
@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配置。

代码语言:javascript
复制
@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有效。

代码语言:javascript
复制
@RequestMapping("👨‍🎓作者:Java学术趴
🏦仓库:Github、Gitee
✏️博客: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装配。

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


@Component(value = "renlei")
public class Person {
    String name;
 
    Integer age;
}


然后我们再来定义一个类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注解使用的过程:


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


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


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


找到@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的主配置文件中的属性值。
使用方式:

application.yml配置文件


student:
    name:张三
    age:20
    room:java


在代码层获取这个变量值


@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;


注入配置参数 student.name 的值。
当 student.name 值未定义,注入配置参数 studnet.age 的值。
如果 student.name 和 studnet.age 都没有定义,则使用 student.room 的值。
如果这三个值都未定义,则报以上的错误。

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

作者:Java学术趴
链接:https://juejin.cn/post/7114681674402627598/
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。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;
    }
}
​

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 3. SpringBoot中Controller层的注解
    • 3.1 @Controller注解
      • 3.2 @RestController
        • 3.3 @RequestMapping("路径信息")
          • 3.3.1 注解在Controller类上
          • 3.3.2 注解在Controller类的方法上
        • 3.4 @PostMapping("路径信息")
          • 3.5 @GetMapping("路径信息")
            • 3.6 @Api(tags = "针对这个Controller类的描述")
              • 3.7 @ApiOperation("针对Controller类中某个方法的描述")
                • 3.8 @Autowired
                  • 3.9 @Resource
                    • 3.10 @Value
                      • 3.10.1 @Value("${...}") -- 配置参数值注入
                      • 3.10.2 @Value("#{...}") -- SPEL表达式求值注入
                    • 3.11 @PathVariable
                      • 3.12 @RequestParam
                        • 3.13 @RequestBody
                          • 3.14 @ExceptionHandler
                            • 3.14.1 基本用法
                            • 3.1.4.2 注解的参数
                            • 3.1.4.3 就近原则
                            • 3.1.1.4 注解方法的返回值
                            • 3.1.1.5 错误的操作
                          • 3.18 @ModelAttribute
                            • 3.15 @ControllerAdvice
                              • 3.16 @ResponseStatus
                                • 3.17 @CrossOrigin
                                  • 3.17.1 跨域介绍
                                  • 3.17.2 使用方式
                                • 3.18 @InitBinder
                                相关产品与服务
                                容器服务
                                腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                                领券
                                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档