文章目录
【Spring Boot】027-@ControllerAdvice 与 @RestControllerAdvice
一、@ControllerAdvice概述
1、简介
@ControllerAdvice 是 @Controller 的增强版,其主要用来处理全局数据,一般搭配 @ExceptionHandler 、@ModelAttribute 以及 @InitBinder 使用!
2、使用场景
- 全局异常处理;
- 添加全局数据;
- 请求参数预处理;
二、全局异常处理
1、概述
@ControllerAdvice 最常见的使用场景就是全局异常处理。在文件上传时,有时候文件超过最大限制,就会抛出异常,此时我们可以通过 @Controller 结合 @ExceptionHandler 定义全局异常捕捉机制!
2、代码演示
Thymeleaf几乎不用了,不再演示!
自定义异常处理类 CustomExceptionHandler
package com.zibo.api.common.handler;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@ControllerAdvice
public class CustomExceptionHandler {
@ExceptionHandler(MaxUploadSizeExceededException.class)
public void uploadException(MaxUploadSizeExceededException e, HttpServletResponse resp) throws IOException{
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.write("上传文件大小超出限制!");
out.flush();
out.close();
}
}
resources/static目录下的upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上传文件</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="uploadFile" value="请选择文件">
<input type="submit" value="上传">
</form>
</body>
</html>
文件上传处理接口FileUploadController
package com.zibo.api.controller.file;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
@RestController
public class FileUploadController {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
@PostMapping("upload")
public String upload(MultipartFile uploadFile, HttpServletRequest request){
String realPath = request.getSession().getServletContext().getRealPath("/uploadFile/");
String format = sdf.format(new Date());
File folder = new File(realPath + format);
if(!folder.isDirectory()){
folder.mkdirs();
}
String oldName = uploadFile.getOriginalFilename();
String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
try {
uploadFile.transferTo(new File(folder,newName));
return request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/uploadFile/" + format + "/" + newName;
}catch (IOException e){
e.printStackTrace();
}
return "上传失败!";
}
}
3、运行测试
上传正常大小的图片
上传较大的图片
三、添加全局数据
1、概述
@ControllerAdvice 是一个全局数据处理组件,因此也可以在其中配置全局数据,使用 @ModelAttribute 注解进行配置。
2、代码演示
全局数据配置 GlobalConfig
package com.zibo.api.config;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ModelAttribute;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice
public class GlobalConfig {
// info表示的是返回数据的key
@ModelAttribute(value = "info")
public Map<String,String> userInfo(){
Map<String,String> map = new HashMap<>();
map.put("username","刘备");
map.put("gender","男");
return map;
}
}
在Controller中使用全局数据
注意 @RestController 和 @Controller 两个注解的区别!@RestController = @Controller + @ResponseBody
这里就暂时使用 @Controller 吧!因为很少用,所以用一下吧,增强记忆!
package com.zibo.api.controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@Controller
public class HelloController {
@RequestMapping("hello")
@ResponseBody
public Object hello(Model model){
Map<String, Object> map = model.asMap();
return map.get("info");
}
}
3、运行结果
四、请求参数预处理
1、概述
@ControllerAdvice 结合 @InitBinder 实现对请求参数预处理!
2、代码示例
仅作写法展示,未进行实际测试!
实体类:Book
package com.zibo.api.entity;
import lombok.Data;
@Data
public class Book {
private String name;
private String author;
}
实体类:Author
package com.zibo.api.entity;
import lombok.Data;
@Data
public class Author {
private String name;
private Integer age;
}
Controller 接收实体类(错误写法)
这么写的问题:book 和 author 中都有 name 属性,会导致数据混淆错误!
@RequestMapping("hi")
public String hi(Book book, Author author){
return book.toString() + "==>" + author.toString();
}
Controller 接收实体类(正确写法)
@RequestMapping("hi")
public String hi(@ModelAttribute("b") Book book, @ModelAttribute("a") Author author){
return book.toString() + "==>" + author.toString();
}
GlobalConfig
package com.zibo.api.config;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice
public class GlobalConfig {
@InitBinder("b")
public void init(WebDataBinder binder){
binder.setFieldDefaultPrefix("b.");
}
@InitBinder("a")
public void init2(WebDataBinder binder){
binder.setFieldDefaultPrefix("a.");
}
}
五、@RestControllerAdvice
1、与 @ControllerAdvice 区别
代码演示省略!
简单地说,@RestControllerAdvice 与 @ControllerAdvice 的区别就和 @RestController 与 @Controller 的区别类似,@RestControllerAdvice 注解包含了 @ControllerAdvice 注解和 @ResponseBody 注解。
当自定义类加@ControllerAdvice注解时,方法需要返回json数据时,每个方法还需要添加@ResponseBody注解;
当自定义类加@RestControllerAdvice注解时,方法自动返回json数据,每个方法无需再添加@ResponseBody注解;
2、@RestController 与 @Controller 的区别
@RestController = @Controller + @ResponseBody
使用@Controller 注解
在对应的方法上,视图解析器可以解析 return 的 jsp,html 页面,并且跳转到相应页面
若返回 json 等内容到页面,则需要加 @ResponseBody 注解;
@RestController注解
相当于 @Controller + @ResponseBody 两个注解的结合,返回 json 数据不需要在方法前面加 @ResponseBody 注解了,但使用@RestController 这个注解,就不能返回 jsp,html 页面,视图解析器无法解析 jsp,html 页面;