1 异常映射
1.1 目标
使用异常映射对项目的异常
和错误提示
进行统一管理。
1.2 思路
对于普通的页面请求,异常映射机制捕获到handler方法抛出的异常后会响应为一个错误页面,对于处理ajax请求的handler方法抛出的异常则响应一个json。
SpringMVC提供了基于xml和注解方式的异常映射机制,而且通过xml视图控制器<mvc:view-controller>进行的请求映射的异常只能通过xml的异常映射机制获取,而通过@requestMapping注解进行的请求映射的异常既能通过xml也能通过注解方式的异常映射机制获取。
1.3 代码
1.3.1 基于XML异常映射机制
classpath: spring-webmvc.xm
<!--基于XML的异常映射-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"
id="simpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<!-- key指定异常的全类名 -->
<!-- 标签指定对应视图,会经过视图解析器添加前后缀 -->
<prop key="java.lang.Exception">system-error</prop>
</property>
</bean>
1.3.2 基于注解的异常映射处理机制
首先写一个判断请求是否是ajax请求
/**
* 判断请求类型
* @param request
* @return true=json请求;false=普通页面请求
*/
public static boolean judgeRequestType(HttpServletRequest request){
String accept = request.getHeader("Accept");
String header = request.getHeader("X-Requested-With");
return (accept != null && accept.contains("application/json"))
||
(header != null && header.equals("XMLHttpRequest"));
}
编写基于注解的异常处理类
//注解标明该类是基于注解的异常处理器类
@ControllerAdvice
public class CrowdExceptionResolver {
/**
* 处理登录失败的异常
*
* @param exception
* @param request
* @param response
* @return
* @throws IOException
*/
@ExceptionHandler(value = {LoginFailedException.class})
public ModelAndView resolveloginFailedException(LoginFailedException exception, HttpServletRequest request, HttpServletResponse response) throws IOException {
// String viewName="admin-login";
String viewName = "admin-login";
return commonCode(exception, request, response, viewName);
}
//处理空指针异常
@ExceptionHandler(value = {NullPointerException.class})
public ModelAndView resolveNullPointerException(NullPointerException exception, HttpServletRequest request, HttpServletResponse response) throws IOException {
return commonCode(exception, request, response, "system-error");
}
//处理数学异常,这里如果内部操作相同,跳转页面也相同,其实可以放在上面一个方法中,此处只是为了演示
@ExceptionHandler(value = {ArithmeticException.class})
public ModelAndView resolveArithmeticException(ArithmeticException exception, HttpServletRequest request, HttpServletResponse response) throws IOException {
return commonCode(exception, request, response, "system-error");
}
//整理出的不同异常的可重用代码
private ModelAndView commonCode(
//触发的异常,此处借助多态
Exception exception,
//客户器端的请求
HttpServletRequest request,
//服务端的响应
HttpServletResponse response,
//指定普通页面请求时,去的错误页面
String viewName) throws IOException {
boolean judgeRequestType = CrowdUtil.judgeRequestType(request);
if (judgeRequestType) {
//if判断-是json请求
ResultEntity<Object> failed = ResultEntity.failed(exception.getMessage());
//创建Gson对象
Gson gson = new Gson();
//将ResultEntity对象转换成json格式
String json = gson.toJson(failed);
//通过原生servlet的response传回异常内容
response.getWriter().write(json);
//此时只需要返回null(因为是通过json格式返回数据)
return null;
} else {
//if判断-是普通页面请求
//创建ModelAndView对象
ModelAndView modelAndView = new ModelAndView();
//设置触发异常跳转的页面(会自动被视图解析器加上前后缀)
modelAndView.setViewName(viewName);
//将异常信息加入
modelAndView.addObject(CrowdConstant.ATTR_NAME_EXCEPTION, exception);
//返回设置完成的ModelAndView
return modelAndView;
}
}
}
1.3.3 创建自定义异常类
① 以登录为例,创建一个自定义异常LoginFailedException
/**
* 登录失败后抛出的异常
*/
public class LoginFailedException extends RuntimeException {
public LoginFailedException() {
super();
}
public LoginFailedException(String message) {
super(message);
}
public LoginFailedException(String message, Throwable cause) {
super(message, cause);
}
public LoginFailedException(Throwable cause) {
super(cause);
}
protected LoginFailedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
继承自RuntimeException或者CompilerException这里都可以
② 在登录业务service中抛出自定义异常
@Service
public class AdminServiceImpl implements AdminService {
@Autowired
AdminMapper adminMapper;
@Override
public Admin getAdminByLoginAcct(String loginAcct, String userPswd) {
// 1。 通过数据库查询是否存在该用户
// ①创建 AdminExample 对象
AdminExample adminExample = new AdminExample();
// ②创建 Criteria 对象
AdminExample.Criteria criteria = adminExample.createCriteria();
//③在 Criteria 对象中封装查询条件
// criteria.andCreateTimeEqualTo(loginAcct);
criteria.andLoginAcctEqualTo(loginAcct);
//④调用 AdminMapper 的方法执行查询
// 2。 判断admin是否存在
List<Admin> admins = adminMapper.selectByExample(adminExample);
if (admins == null || admins.size() == 0) {
throw new LoginFailedException(CrowdConstant.MESSAGE_LOGIN_FAILED);
}
if (admins.size() > 1) {
throw new LoginFailedException(CrowdConstant.MESSAGE_SYSTEM_ERROR_LOGIN_NOT_UNIQUE);
}
Admin admin = admins.get(0);
if (admin == null) {
throw new LoginFailedException(CrowdConstant.MESSAGE_LOGIN_FAILED);
}
// 3。 比对数据库中的用户密文密码
String userPswdDB = admin.getUserPswd();
String userPswdWeb = CrowdUtil.md5(userPswd);
// 4。密码比对失败 抛出异常
if (!Objects.equals(userPswdDB, userPswdWeb)) {
throw new LoginFailedException(CrowdConstant.MESSAGE_LOGIN_FAILED);
}
// 5。 返回Admin对象
return admin;
}
}
③ 在异常处理类中捕获controller处理请求产生的异常
//注解标明该类是基于注解的异常处理器类
@ControllerAdvice
public class CrowdExceptionResolver {
/**
* 处理登录失败的异常
*
* @param exception
* @param request
* @param response
* @return
* @throws IOException
*/
@ExceptionHandler(value = {LoginFailedException.class})
public ModelAndView resolveloginFailedException(LoginFailedException exception, HttpServletRequest request, HttpServletResponse response) throws IOException {
// String viewName="admin-login";
String viewName = "admin-login";
return commonCode(exception, request, response, viewName);
}
)