1. 全局异常处理机制
基于注解实现声明式异常处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
|
@RestControllerAdvice public class GlobalExceptionHandler {
@ExceptionHandler(HttpMessageNotReadableException.class) public Object handlerJsonDateException(HttpMessageNotReadableException e){ return null; }
@ExceptionHandler(NullPointerException.class) public Object handlerNullException(NullPointerException e){ return null; }
@ExceptionHandler(Exception.class) public Object handlerException(Exception e){ return null; } }
|
基于配置
SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口:HandlerExceptionResolver
HandlerExceptionResolver接口的实现类有:DefaultHandlerExceptionResolver和SimpleMappingExceptionResolver
SpringMVC提供了自定义的异常处理器SimpleMappingExceptionResolver,使用方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props>
<prop key="java.lang.ArithmeticException">error</prop> </props> </property>
<property name="exceptionAttribute" value="ex"></property> </bean>
|
2. 拦截器
2.1 创建拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class Process01Interceptor implements HandlerInterceptor {
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("request = " + request + ", response = " + response + ", handler = " + handler); System.out.println("Process01Interceptor.preHandle"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("request = " + request + ", response = " + response + ", handler = " + handler + ", modelAndView = " + modelAndView); System.out.println("Process01Interceptor.postHandle"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("request = " + request + ", response = " + response + ", handler = " + handler + ", ex = " + ex); System.out.println("Process01Interceptor.afterCompletion"); } }
|

2.2 拦截器的配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| @EnableWebMvc @Configuration @ComponentScan(basePackages = {"com.atguigu.controller","com.atguigu.exceptionhandler"}) public class SpringMvcConfig implements WebMvcConfigurer {
@Override public void configureViewResolvers(ViewResolverRegistry registry) { registry.jsp("/WEB-INF/views/",".jsp"); }
@Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); }
@Override public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new Process01Interceptor());
registry.addInterceptor(new Process01Interceptor()) .addPathPatterns("/common/request/one","/common/request/tow");
registry.addInterceptor(new Process01Interceptor()) .addPathPatterns("/common/request/one","/common/request/tow") .excludePathPatterns("/common/request/tow"); } }
|
3. 参数校验
3.1 校验概述
JSR 303 是 Java 为 Bean 数据合法性校验提供的标准框架,它已经包含在 JavaEE 6.0 标准中。JSR 303 通过在 Bean 属性上标注类似于 @NotNull、@Max 等标准的注解指定校验规则,并通过标准的验证接口对Bean进行验证。
注解 |
规则 |
@Null |
标注值必须为 null |
@NotNull |
标注值不可为 null |
@AssertTrue |
标注值必须为 true |
@AssertFalse |
标注值必须为 false |
@Min(value) |
标注值必须大于或等于 value |
@Max(value) |
标注值必须小于或等于 value |
@DecimalMin(value) |
标注值必须大于或等于 value |
@DecimalMax(value) |
标注值必须小于或等于 value |
@Size(max,min) |
标注值大小必须在 max 和 min 限定的范围内 |
@Digits(integer,fratction) |
标注值值必须是一个数字,且必须在可接受的范围内 |
@Past |
标注值只能用于日期型,且必须是过去的日期 |
@Future |
标注值只能用于日期型,且必须是将来的日期 |
@Pattern(value) |
标注值必须符合指定的正则表达式 |
JSR 303 只是一套标准,需要提供其实现才可以使用。Hibernate Validator 是 JSR 303 的一个参考实现,除支持所有标准的校验注解外,它还支持以下的扩展注解:
注解 |
规则 |
@Email |
标注值必须是格式正确的 Email 地址 |
@Length |
标注值字符串大小必须在指定的范围内 |
@NotEmpty |
标注值字符串不能是空字符串 |
@Range |
标注值必须在指定的范围内 |
Spring 4.0 版本已经拥有自己独立的数据校验框架,同时支持 JSR 303 标准的校验框架。Spring 在进行数据绑定时,可同时调用校验框架完成数据校验工作。在SpringMVC 中,可直接通过注解驱动 @EnableWebMvc 的方式进行数据校验。Spring 的 LocalValidatorFactoryBean 既实现了 Spring 的 Validator 接口,也实现了 JSR 303 的 Validator 接口。只要在Spring容器中定义了一个LocalValidatorFactoryBean,即可将其注入到需要数据校验的 Bean中。Spring本身并没有提供JSR 303的实现,所以必须将JSR 303的实现者的jar包放到类路径下。
配置 @EnableWebMvc后,SpringMVC 会默认装配好一个 LocalValidatorFactoryBean,通过在处理方法的入参上标注 @Validated 注解即可让 SpringMVC 在完成数据绑定后执行数据校验的工作。
3.2 示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <dependency> <groupId>jakarta.platform</groupId> <artifactId>jakarta.jakartaee-web-api</artifactId> <version>9.1.0</version> <scope>provided</scope> </dependency>
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>8.0.0.Final</version> </dependency>
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator-annotation-processor</artifactId> <version>8.0.0.Final</version> </dependency>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import jakarta.validation.constraints.Email; import jakarta.validation.constraints.Min; import org.hibernate.validator.constraints.Length;
@Data public class User { @Min(10) private int age;
@Length(min = 3,max = 10) private String name;
@Email private String email; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @RestController @RequestMapping("user") public class UserController {
@PostMapping("save") public Object save(@Validated @RequestBody User user, //在实体类参数和 BindingResult 之间不能有任何其他参数, BindingResult可以接受错误信息,避免信息抛出! BindingResult result){ if (result.hasErrors()){ System.out.println("错误"); String errorMsg = result.getFieldError().toString(); return errorMsg; } System.out.println("正常"); return user; } }
|
3.3 检查是否为空
@NotNull
、@NotEmpty
、@NotBlank
都是用于在数据校验中检查字段值是否为空的注解,但是它们的用法和校验规则有所不同。
@NotNull
(包装类型不为null)
@NotNull 注解是 JSR 303 规范中定义的注解,当被标注的字段值为 null 时,会认为校验失败而抛出异常。该注解不能用于字符串类型的校验,若要对字符串进行校验,应该使用 @NotBlank 或 @NotEmpty 注解。
@NotEmpty
(集合类型长度大于0)
@NotEmpty 注解同样是 JSR 303 规范中定义的注解,对于 CharSequence、Collection、Map 或者数组对象类型的属性进行校验,校验时会检查该属性是否为 null 或者 size()==0,如果是的话就会校验失败。但是对于其他类型的属性,该注解无效。需要注意的是只校验空格前后的字符串,如果该字符串中间只有空格,不会被认为是空字符串,校验不会失败。
@NotBlank
(字符串,不为null,且不为” “字符串)
@NotBlank 注解是 Hibernate Validator 附加的注解,对于字符串类型的属性进行校验,校验时会检查该属性是否为 null 或 “” 或者只包含空格,如果是的话就会校验失败。需要注意的是,@NotBlank 注解只能用于字符串类型的校验。
总之,这三种注解都是用于校验字段值是否为空的注解,但是其校验规则和用法有所不同。在进行数据校验时,需要根据具体情况选择合适的注解进行校验。
4. 文件上传和下载
4.1 文件下载
使用 ResponseEntity 实现下载文件的功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @RequestMapping("/testDown") public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException { ServletContext servletContext = session.getServletContext(); String realPath = servletContext.getRealPath("/static/img/1.jpg"); InputStream is = new FileInputStream(realPath); byte[] bytes = new byte[is.available()]; is.read(bytes); MultiValueMap<String, String> headers = new HttpHeaders(); headers.add("Content-Disposition", "attachment;filename=1.jpg"); HttpStatus statusCode = HttpStatus.OK; ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, statusCode); is.close(); return responseEntity; }
|
4.2 文件上传
文件上传要求form表单的请求方式必须为post,并且添加属性enctype=”multipart/form-data”
SpringMVC中将上传的文件封装到MultipartFile对象中,通过此对象可以获取文件相关信息
上传步骤:
a>添加依赖:
1 2 3 4 5 6
| <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency>
|
b>在SpringMVC的配置文件中添加配置:
1 2
| <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
|
c>控制器方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @RequestMapping("/testUp") public String testUp(MultipartFile photo, HttpSession session) throws IOException { String fileName = photo.getOriginalFilename(); String hzName = fileName.substring(fileName.lastIndexOf(".")); fileName = UUID.randomUUID().toString() + hzName; ServletContext servletContext = session.getServletContext(); String photoPath = servletContext.getRealPath("photo"); File file = new File(photoPath); if(!file.exists()){ file.mkdir(); } String finalPath = photoPath + File.separator + fileName; photo.transferTo(new File(finalPath)); return "success"; }
|