Spring MVC框架下一般会自定义全局异常,再通过Spring MVC下的全局异常拦截全部转化为自定义异常。但在controller层处理异常有很多的try{}catch{},影响性能。所以为了能够处理异常的同时返回相同的数据结构,定义一个全局异常统一响应以返回JSON格式数据结构(code:“”,message:“”,data:“”)。
1.自定义异常类(继承RuntimeException以保证事务可以回滚):
package exception;
/**
* 自定义异常
*/
public class MyException extends RuntimeException{
private static final long serialVersionUID = 2305653807231756702L;
//异常信息
private String message;
//构造器
public MyException(String message){
super(message);
this.message=message;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
2.自定义拦截全局异常处理器(以保证可以拦截框架下的所有异常)
package exception;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
MyException myException = null;
if (e instanceof MyException) {
myException = (MyException) e;
} else {//如果该异常类型不是系统自定义的异常,构造一个自定义的异常类型(信息为“未知错误”)
myException = new MyException("未知错误");
}
return null;
}
}
3.配置全局异常处理器(springmvc-servlet.xml)
<!--自定义的全局异常处理器-->
<bean id="myHandlerExceptionResolver" class="exception.MyHandlerExceptionResolver"/>
4.自定义全局异常响应(以保证controller层抛出的异常能够全局响应JSON)
package exception;
import model.ResponseData;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
/**
* @ControllerAdvice是一个@Component,用于定义@ExceptionHandler
*
*/
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = MyException.class)
@ResponseBody
public ResponseData jsonExceptionHandler(HttpServletRequest request, MyException e) {
return new ResponseData().fail(e.getMessage());
}
}
其中的ResponseData类如下:
package model;
import java.util.LinkedHashMap;
/**
* 用来返回controller层请求的结果
* 默认为三个返回项:code,message,data
* 如果有其他更多返回项,使用result方法拼接
*/
public class ResponseData extends LinkedHashMap<String, Object> {
private static final long serialVersionUID = -364546270975223015L;
public ResponseData result(String key, Object value) {
this.put(key, value);
return this;
}
public ResponseData success(){
return this.success("success");
}
public ResponseData success(Object message){
this.put("code",200);
this.put("message", message);
return this;
}
public ResponseData fail(){
return this.fail("fail");
}
public ResponseData fail(Object message) {
this.put("code",400);
this.put("message", message);
return this;
}
public ResponseData redirect(String message) {
this.put("code",300);
this.put("message", message);
return this;
}
public ResponseData unauthorized() {
return this.unauthorized("the current user is unauthorized");
}
public ResponseData unauthorized(Object message){
this.put("code",401);
this.put("message", message);
return this;
}
public ResponseData forbidden(Object message){
this.put("code",403);
this.put("message", message);
return this;
}
public ResponseData code(int code) {
return result("code",code);
}
public ResponseData message(String message) {
return result("message", message);
}
public ResponseData data(Object data) {
return result("data", data);
}
}
5.配置全局异常统一响应处理器
在springmvc-servlet.xml中:
<!--配置全局异常统一响应处理器-->
<context:component-scan base-package="exception" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
在web.xml中:
<!--2.配置 Spring MVC DispatcherServlet 前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置全局异常统一响应处理器,DispatcherServlet源码中对于throwExceptionIfNoHandlerFound 默认是 false -->
<init-param>
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
<!-- contextConfigLocation 是参数名称,该参数的值包含 Spring MVC 的配置文件路径 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:springmvc-servlet.xml</param-value>
</init-param>
<!-- 在 Web 应用启动时立即加载 Servlet -->
<load-on-startup>1</load-on-startup>
</servlet>
6.效果如下:
controller层不用再进行try{}catch{},直接抛出异常即可
返回示例:
至此就不用在controller层每次进行try{}catch{}了。