JavaWeb统一异常处理
[toc]
处理方案
1. xml文件配置方式
web.xml配置
1<error-page> 2 <error-code>404</error-code> 3 <location>/404</location> 4</error-page> 5<error-page> 6 <error-code>500</error-code> 7 <location>/500</location> 8</error-page> 9 10<!-- 未捕获的错误,同样可指定其它异常类,或自定义异常类 --> 11<error-page> 12 <exception-type>java.lang.Exception</exception-type> 13 <location>/uncaughtException</location> 14</error-page> 15 16
springmvc(applicationContext.xml)配置
1<mvc:view-controller path="/400" view-name="400"/> 2<mvc:view-controller path="/404" view-name="404"/> 3<mvc:view-controller path="/500" view-name="500"/> 4<mvc:view-controller path="/uncaughtException" view-name="uncaughtException"/> 5
SimpleMappingExceptionResolver
1<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> 2 3 <property name="exceptionMappings"> 4 <props> 5 <!-- 异常类名,可以是全路径,错误页面或Controller路径! --> 6 <prop key="NullPointerException">NullPointerException</prop> 7 <prop key="IOException">IOException</prop> 8 </props> 9 </property> 10 11 <!-- 表示当抛出异常但没有在exceptionMappings里面找到对应的异常时 返回名叫exception的视图--> 12 <property name="defaultErrorView" value="exception"/> 13 14 <!-- 定义在发生异常时视图跟返回码的对应关系 --> 15 <property name="statusCodes"> 16 <props> 17 <prop key="number">500</prop> 18 <prop key="null">503</prop> 19 </props> 20 </property> 21 <property name="defaultStatusCode" value="404"/> 22</bean> 23
2.代码拦截
自定义异常。
作统一异常处理。
自定义非检测异常,继承RuntimeException类,直接中断处理,不需要显示的捕捉和处理。例如参数错误等等无需进一步处理和恢复。
自定义检测异常, 继承Exception类,需要显示的捕捉或抛出。
1public class BaseRuntimeException extends RuntimeException { 2 3 private String message; //异常信息 4 private Object[] args; //相关参数等 5 6 7 public BaseRuntimeException(String message) { 8 super(message); 9 this.message = message; 10 } 11 12 13 public BaseRuntimeException(String message, Throwable cause) { 14 super(message, cause); 15 this.message = message; 16 } 17 18 19 public BaseRuntimeException(String message, Object ... args) { 20 super(message); 21 this.message = message; 22 this.args = args; 23 } 24 25 26 public BaseRuntimeException(String message, Throwable cause, Object ... args) { 27 super(message, cause); 28 this.message = message; 29 this.args = args; 30 } 31 32 33 public String getMessage() { 34 return message; 35 } 36 37 public Object[] getArgs() { 38 return args; 39 } 40} 41 42
自定义异常处理器。
1.基于spring mvc 实现HandlerExceptionResolver接口
1public class GlobalHandlerExceptionResolver implements HandlerExceptionResolver { 2 private static final Logger LOG = LoggerFactory.getLogger(GlobalHandlerExceptionResolver.class); 3 4 @Override 5 public ModelAndView resolveException(HttpServletRequest req, HttpServletResponse resp, Object o, Exception ex) { 6 ex.printStackTrace(); 7 if (ex instanceof BaseRuntimeException) { 8 printWrite(ex.getMessage, resp); 9 } else { 10 11 printWrite("ERROR!", resp); 12 } 13 14 return new ModelAndView(); 15 } 16 17 /** 18 * 将错误信息写入到response中 19 * @param messsage 20 * @param response 21 * @throws IOException 22 */ 23 public static void printWrite(String messsage, HttpServletResponse response) { 24 try { 25 PrintWriter pw = response.getWriter(); 26 pw.write(messsage); 27 pw.flush(); 28 pw.close(); 29 } catch (Exception e) { 30 e.printStackTrace(); 31 } 32 } 33} 34 35
2. 注册异常处理器
<bean class="com.iot.learnssm.firstssm.exception.CustomExceptionResolver"></bean>
自定义拦截器
由于HandlerExceptionResolver接口只实现返回值为ModelAndView,前后端分离的话,可以采用拦截器HandlerInterceptor或者Filter。(springmvc还可以采用@ExceptionHandler注解来处理局部异常(注解应用于方法上),此处不多谈)
1. 基于spring mvc 实现HandlerInterceptor接口
1public interface HandlerInterceptor { 2 3//处理前,返回ture 进入postHandle, 返回false 进入afterCompletion 4 boolean preHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception; 5 6//进入控制器 7 void postHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3, ModelAndView var4) throws Exception; 8 9//执行完控制器后调用 10 void afterCompletion(HttpServletRequest var1, HttpServletResponse var2, Object var3, Exception var4) throws Exception; 11} 12 13 14 15public class MVCRequestInterceptor implements HandlerInterceptor { 16 17 @Override 18 public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { 19 return true; 20 } 21 22 @Override 23 public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { 24 25 httpServletResponse.setHeader("Access-Control-Allow-Methods","GET,POST,PUT,DELETE"); 26 httpServletResponse.setHeader("Access-Control-Allow-Credentials","true"); 27 28 29 try { 30 chain.doFilter(request, httpServletResponse); 31 } catch (BaseRuntimeException e) { 32 e1.printStackTrace(); 33 printMessage(httpServletResponse, e.getMessage); 34 35 } catch (Exception e){ 36 e1.printStackTrace(); 37 printMessage(httpServletResponse, ExceptionUtils.getStackTrace(e)); 38 } 39 40 41 } 42 43 @Override 44 public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { 45 46 47 } 48 49 50 private void printMessage(httpServletResponse response, String message){ 51 PrintWriter out = httpServletResponse.getWriter(); 52 Map<String,Object> map = new HashMap<String,Object>(); 53 map.put("success", false); 54 map.put("msg", message);//获取详细错误信息 55 out.println(JSONObject.toJSONString(map)); 56 } 57} 58 59 60 61
2. 注册拦截器
1<!-- 注册拦截器 --> 2 <mvc:interceptors> 3 <bean class="com.project.base.interceptor.ControlInterceptor" /> 4 </mvc:interceptors> 5 6
自定义Filter拦截器
1. 选择缘由
- 框架由Struts2 改为 spring mvc,原代码并未改动,为了兼容两种控制器,实现javax.servlet的Filter接口,进行错误统一处理。
2.实现Filter 接口
1@Component 2public class GlobeExceptionFilter extends GenericFilterBean { 3 4/*采用DelegatingFilterProxy代理管理自定义filter,可直接注入该service 5 @Autowired 6 private SysLoginLogService sysLoginLogService; 7 */ 8 9 10 @Override 11 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 12 HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse; 13 httpServletResponse.setHeader("Access-Control-Allow-Origin","*"); 14 httpServletResponse.setHeader("Access-Control-Allow-Methods","GET,POST,PUT,DELETE"); 15 httpServletResponse.setHeader("Access-Control-Allow-Credentials","true"); 16 17 18 try { 19 filterChain.doFilter(servletRequest, httpServletResponse); 20 21 int httpStatus = httpServletResponse.getStatus(); 22 if(httpStatus >=400){ //请求错误 23 HttpServletRequest request = (HttpServletRequest) servletRequest; 24 String requestURI = request.getRequestURI(); 25 String queryString = request.getQueryString(); 26 System.out.println("------>"+requestURI); 27 System.out.println("--------->"+queryString); 28 // throw new BaseRuntimeException("error", requestURI, queryString); //用于测试 29 } 30 31 32 } catch (BaseError e){ //内部自定义错误 33 System.out.println(e.getMessage()); 34 System.out.println(Arrays.toString(e.getArgs())); 35 } catch (BaseRuntimeException e){ //内部自定义异常 36 37 System.out.println("messsage--->" +e.getMessage()); 38 System.out.println("args--->" +Arrays.toString(e.getArgs())); 39 40 //追踪栈上信息 41 StackTraceElement[] st = e.getStackTrace(); 42 if(st.length > 0){ 43 String exclass = st[0].getClassName(); 44 String method = st[0].getMethodName(); 45 System.out.println("calss----->" + exclass); //发生异常类 46 System.out.println("method----->" + method); //方法 47 System.out.println("method----->" + lineNumber); //行数 48 } 49 printMessage(httpServletResponse, e.getMessage()); 50 51 } catch (Exception e){ //其他异常 52 e.printStackTrace(); 53 54 55 printMessage(httpServletResponse, e.getMessage()); 56 } 57 58 } 59 60 61 private void printMessage(HttpServletResponse httpServletResponse, String message){ 62 httpServletResponse.setContentType("application/json;charset=UTF-8"); 63 PrintWriter out = null; 64 try { 65 out = httpServletResponse.getWriter(); 66 Map<String,Object> map = new HashMap<String,Object>(); 67 map.put("success", false); 68 map.put("msg", message); 69 out.println(JSONObject.toJSONString(map)); 70 out.flush(); 71 } catch (IOException e) { 72 e.printStackTrace(); 73 } finally { 74 if(out != null){ 75 out.close(); 76 } 77 } 78 79 } 80} 81 82 83 84 85
3. xml配置
通过spring管理filter
采用DelegatingFilterProxy代理管理自定义filter ,filter内部可直接使用spring bean直接注入。
1 <filter> 2 <filter-name>globeExceptionFilter</filter-name> 3 <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> 4 <init-param> 5 <!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由servlet container管理 --> 6 <param-name>targetFilterLifecycle</param-name> 7 <param-value>true</param-value> 8 </init-param> 9 </filter> 10 11 <filter-mapping> 12 <filter-name>globeExceptionFilter</filter-name> 13 <url-pattern>/*</url-pattern> 14 </filter-mapping> 15 16
Spring中注册filter
1 <!-- 全局异常处理 --> 2 <bean id="globeExceptionFilter" class="com.project.base.filter.GlobeExceptionFilter" />