最后由中央处理器DispatchServlet交由全局异常处理器进行异常处理, 如下图所示
常用的Spring MVC异常处理方式主要有三种:
-
使用系统定义好的异常处理器SimpleMappingExceptionResolver
-
使用自定义异常处理器
-
使用异常注解
SimpleMappingExceptionResolver
只需要在配置文件中注册该异常处理器Bean即可, 无需显式调用, 当异常发生时会自动执行该类.
1 <bean class=“org.springframework.web.servlet.handler.SimpleMappingExceptionResolver”>
2 <property name=“defaultErrorView” value="/errors/error.jsp"/>
3 </bean>
(1) 声明一个自定义的异常类
1 public class NameException extends Exception {
2
3 public NameException() {
4 super();
5 }
6
7 public NameException(String message) {
8 super(message);
9 }
10
11 }
(2) 注册异常处理器
1 <bean class=“org.springframework.web.servlet.handler.SimpleMappingExceptionResolver”>
2 <property name=“defaultErrorView” value="/errors/error.jsp"/>
3 <property name=“exceptionAttribute” value=“ex”/>
4 <property name=“exceptionMappings”>
5 <props>
6 <prop key=“com.test.exceptions.NameException”>/errors/nameError.jsp</prop>
7 </props>
8 </property>
9 </bean>
exceptionMapping: Properties类型属性, 用于指定具体的不同类型异常对应的响应页面.
defaultErrorView: 默认的异常响应页面, 若发生的异常不是自定义的异常, 则使用默认响应页面.
exceptionAttribute: 捕获到的异常对象, 一般异常响应页面中使用.
自定义异常处理器
SimpleMappingExceptionResolver可以在发生异常的时候进行页面跳转, 但是如果想要在捕获到特定异常后,
执行一些操作, 则需要自定义异常. 自定义异常处理器需要实现HandlerExceptionResolver接口, 并且该类
需要在配置文件中进行注册.
(1) 定义异常处理器
当一个类实现了HandlerExceptionResolver接口后, 只要有异常发生, 都会执行resolveException方法.
1 public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
2
3 public ModelAndView resolveException(HttpServletRequest request,
4 HttpServletResponse response, Object handler, Exception ex) {
5
6 ModelAndView mv = new ModelAndView();
7 mv.addObject(“ex”, ex);
8 mv.setViewName("/errors/error.jsp");
9
10 if(ex instanceof NameException) {
11 // 执行一些操作
12 mv.setViewName("/errors/nameError.jsp");
13 }
14
15 return mv;
16 }
17
18 }
(2) 注册异常处理器
1
2 <bean class=“com.test.resolvers.MyHandlerExceptionResolver”/>
异常处理注解
使用注解@ExceptionHandler可以将一个方法指定为异常处理方法, 该注解有一个可选属性value,
可用于指定该注解方法所需要处理的异常类.
定义一个顶层Controller, 处理所有异常, 其他Controller继承该类即可实现异常集中管理.
1 @Controller
2 public class BaseController {
3
4 // 处理NameException异常
5 @ExceptionHandler(NameException.class)
6 public ModelAndView handlerNameException(Exception ex) {
7 ModelAndView mv = new ModelAndView();
8 mv.addObject(“ex”, ex);
9 // 执行一些操作
10 mv.setViewName("/errors/nameError.jsp");
11 return mv;
12 }
13
14 }
类型转换器
可以将用户web端提交的数据, 在后台转为需要的数据类型.
自定义类型转换器
若要定义类型转换器, 则需要实现Converter接口, 该Convert接口有两个泛型:
第一个为待转换类型, 第二个为目标类型, 该接口方法convert用于实现转换.
1 public class MyDateConverter implements Converter<String, Date> {
2
3 public Date convert(String source) {
4 SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd”);
5 try {
6 return sdf.parse(source);
7 } catch (ParseException e) {
8 e.printStackTrace();
9 }
10 return null;
11 }
12
13 }
类型转换器定义完毕后, 需要在配置文件中进行注册, 然后注册一个转换服务Bean, 将转换器注入给该Bean,
最后由处理器适配器来使用该转换服务器Bean. 该Bean由ConversionServiceFactory工厂创建, 工厂有Set集合属性,
可以提供多种转换功能的Bean来处理多种数据类型转换.
1
2 <bean id=“myDateConverter” class=“com.test.converters.MyDateConverter”/>
3
4
5 <bean id=“conversionService” class=“org.springframework.context.support.ConversionServiceFactoryBean”>
6 <property name=“converters” ref=“myDateConverter”/>
7 </bean>
8
9
10 <mvc:annotation-driven conversion-service=“conversionService”/>
数据验证
主要是校验客户端发来的数据是否合法, 例如不能为空, 或者长度不符合等等. Spring MVC没有校验功能,
但是支持JSR303-Bean Validation, 可以用实现该规范的Hibernate Validator校验框架.
(1) 配置验证器
1
2 <bean id=“myValidator” class=“org.springframework.validation.beanvalidation.LocalValidatorFactoryBean”>
3 <property name=“providerClass” value=“org.hibernate.validator.HibernateValidator”/>
4 </bean>
(2) 在Bean上添加验证注解
1 public class Student {
2
3 @NotNull(message=“姓名不能为空”)
4 @Size(min=3, max=6, message=“姓名长度应在{min}-{max}个字符”)
5 private String name;
6
【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
7 @Min(value=0, message=“成绩不能小于{value}”)
8 @Max(value=100, message=“成绩不能大于{value}”)
9 private double score;
10
11
12 @NotNull(message=“电话不能为空”)
13 @Pattern(regexp="^1[34578]\\d{9}$", message=“手机号格式不正确”)
14 private String mobile;
15
16 …
17 }
(3) 修改Controller
在需要校验的参数前面加上@Validated注解, 同时追加一个BindingResult参数, 用于获取验证异常信息.
1 @Controller
2 @RequestMapping("/test")
3 public class MyController {
4
5 @RequestMapping("/register.do")
6 public ModelAndView doRegister(@Validated Student student, BindingResult br) {
7
8 ModelAndView mv = new ModelAndView();
9 mv.addObject(“student”, student);
10 mv.setViewName("/WEB-INF/jsp/welcome.jsp");
11
12 int errorCount = br.getErrorCount();
13 if(errorCount > 0) {
14 FieldError nameError = br.getFieldError(“name”);
15
16 if (nameError != null) {
17 String nameErrorMSG = nameError.getDefaultMessage();
18 mv.addObject(“nameErrorMSG”, nameErrorMSG);
19 }
20 mv.setViewName("/index.jsp");
21 }
22
23 return mv;
24 }
25 }
文件上传与下载
上传
Spring MVC中文件上传需要添加Apache Commons FileUpload相关的jar包,
基于该jar, Spring中提供了MultipartResolver实现类: CommonsMultipartResolver.
注册该Bean到配置文件中
<bean id=“multipartResolver”
class=“org.springframework.web.multipart.commons.CommonsMultipartResolver”>
<property name=“maxUploadSize”>
<value>10485760</value>
</property>
<property name=“defaultEncoding”>
<value>UTF-8</value>
</property>
</bean>
Spring MVC会将上传的文件绑定到MultipartFile对象, 该对象提供获取内容, 文件名等方法.
通过transferTo方法可以将文件存储到磁盘.
1 //上传文件会自动绑定到MultipartFile中
2 @RequestMapping(value="/upload",method=RequestMethod.POST)
3 public String upload(HttpServletRequest request,
4 @RequestParam(“description”) String description,
5 @RequestParam(“file”) MultipartFile file) throws Exception {
6
7 System.out.println(description);
8 //如果文件不为空,写入上传路径
9 if(!file.isEmpty()) {
10 //上传文件路径
11 String path = request.getServletContext().getRealPath("/images/");
12 //上传文件名
13 String filename = file.getOriginalFilename();
14 File filepath = new File(path,filename);
15 //判断路径是否存在,如果不存在就创建一个
16 if (!filepath.getParentFile().exists()) {
17 filepath.getParentFile().mkdirs();
18 }
19 //将上传文件保存到一个目标文件当中
20 file.transferTo(new File(path + File.separator + filename));
21 return “success”;
22 } else {
1 String path = request.getServletContext().getRealPath("/images/");
12 //上传文件名
13 String filename = file.getOriginalFilename();
14 File filepath = new File(path,filename);
15 //判断路径是否存在,如果不存在就创建一个
16 if (!filepath.getParentFile().exists()) {
17 filepath.getParentFile().mkdirs();
18 }
19 //将上传文件保存到一个目标文件当中
20 file.transferTo(new File(path + File.separator + filename));
21 return “success”;
22 } else {