配置 AOP 切面
代码语言:javascript复制添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
编写切面类
使用 @Component,@Aspect 标记到切面类上:
@Aspect
@Component
public class TimeAspect {
@Around("execution(* com.light.springboot.controller.FastJsonController..*(..))")
public Object method(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("=====Aspect处理=======");
Object[] args = pjp.getArgs();
for (Object arg : args) {
System.out.println("参数为:" arg);
}
long start = System.currentTimeMillis();
Object object = pjp.proceed();
System.out.println("Aspect 耗时:" (System.currentTimeMillis() - start));
return object;
}
}
请求 FastJsonController 控制器的方法,结果如下:
错误处理
代码语言:javascript复制友好页面
先演示非友好页面,修改 FastJsonController 类中的 test 方法:
@RestController
@RequestMapping("fastjson")
public class FastJsonController {
@RequestMapping("/test")
public User test() {
User user = new User();
user.setId(1);
user.setUsername("jack");
user.setPassword("jack123");
user.setBirthday(new Date());
// 模拟异常
int i = 1/0;
return user;
}
}
当系统报错时,返回到页面的内容通常是一些杂乱的代码段,这种显示对用户来说不友好,因此我们需要自定义一个友好的提示系统异常的页面。
在 src/main/resources 下创建 /public/error,在该目录下再创建一个名为 5xx.html 文件,该页面的内容就是当系统报错时返回给用户浏览的内容:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>系统错误</title>
<link href="/css/index.css" rel="stylesheet"/>
</head>
<body>
<div class="container">
<h2>系统内部错误</h2>
</div>
</body>
</html>
路径时固定的,Spring Boot 会在系统报错时将返回视图指向该目录下的文件。
上边处理的 5xx 状态码的问题,接下来解决 404 状态码的问题。
当出现 404 的情况时,用户浏览的页面也不够友好,因此我们也需要自定义一个友好的页面给用户展示。
在 /public/error 目录下再创建一个名为 404.html 的文件:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>访问异常</title>
<link href="/css/index.css" rel="stylesheet"/>
</head>
<body>
<div class="container">
<h2>找不到页面</h2>
</div>
</body>
</html>
全局异常捕获
如果项目前后端是通过 JSON 进行数据通信,则当出现异常时可以常用如下方式处理异常信息。
编写一个类充当全局异常的处理类,需要使用 @ControllerAdvice 和 @ExceptionHandler 注解:
@ControllerAdvice
public class GlobalDefaultExceptionHandler {
/**
* 处理 Exception 类型的异常
* @param e
* @return
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public Map<String,Object> defaultExceptionHandler(Exception e) {
Map<String,Object> map = new HashMap<String,Object>();
map.put("code", 500);
map.put("msg", e.getMessage());
return map;
}
}
其中,方法名为任意名,入参一般使用 Exception 异常类,方法返回值可自定义。
文件上传和下载
代码语言:javascript复制添加依赖
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
编写一个实体类,用于封装返回信息:
public class FileInfo {
private String path;
public FileInfo(String path) {
this.path = path;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}
编写 Controller,用于处理文件上传下载:
@RestController
@RequestMapping("/file")
public class FileController {
private String path = "d:\";
@PostMapping
public FileInfo upload(MultipartFile file) throws Exception {
System.out.println(file.getName());
System.out.println(file.getOriginalFilename());
System.out.println(file.getSize());
File localFile = new File(path, file.getOriginalFilename());
file.transferTo(localFile);
return new FileInfo(localFile.getAbsolutePath());
}
@GetMapping("/{id}")
public void download(@PathVariable String id, HttpServletRequest request, HttpServletResponse response) {
try (InputStream inputStream = new FileInputStream(new File(path, id ".jpg"));
OutputStream outputStream = response.getOutputStream();) {
response.setContentType("application/x-download");
response.addHeader("Content-Disposition", "attachment;filename=" id ".jpg");
IOUtils.copy(inputStream, outputStream);
} catch (Exception e) {
e.printStackTrace();
}
}
}
CORS 支持
代码语言:javascript复制前端页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>跨域测试</title>
</head>
<body>
<button id="test">测试</button>
<script type="text/javascript" src="jquery-1.12.3.min.js"></script>
<script type="text/javascript">
$(function() {
$("#test").on("click", function() {
$.ajax({
"url": "http://localhost:8080/fastjson/test",
"type": "get",
"dataType": "json",
"success": function(data) {
console.log(data);
}
})
});
});
</script>
</body>
</html>
前端服务器启动端口为 8088 与后端服务器 8080 不同源,因此出现跨域的问题。
现在开始解决跨域问题,可以两种维度控制客户端请求。
粗粒度控制:
方式一
@Configuration
public class WebConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/fastjson/**")
.allowedOrigins("http://localhost:8088");// 允许 8088 端口访问
}
};
}
}
方式二
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter{
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/fastjson/**")
.allowedOrigins("http://localhost:8088");// 允许 8088 端口访问
}
}
细粒度控制:
在 FastJsonController 类中的方法上添加 @CrossOrigin(origins="xx") 注解:
@RequestMapping("/test")
@CrossOrigin(origins="http://localhost:8088")
public User test() {
User user = new User();
user.setId(1);
user.setUsername("jack");
user.setPassword("jack123");
user.setBirthday(new Date());
return user;
}
在使用该注解时,需要注意 @RequestMapping 使用的请求方式类型,即 GET 或 POST。