SpringMVC对异常进行全局处理,并区分对待ajax和普通请求
2014-01-20 12:26
591 查看
异常信息应统一进行处理. 程序员开发过程中,应尽量少用try..catch.避免因为catch造成的业务歧义.
而在web开发中,普通的页面提交动作,和ajax提交动作,处理方式不一样,因为跳转后直接显示响应数据,而ajax是通过error回调函数进行处理.
这里的处理思路,适用springmvc和struts2. 只是叫法不一样,一个是HandlerExceptionResolver ,一个是exceptioninterceptor.
下面是部分摘要,体现一下思路
首先定义异常拦截器:
然后是 ExceptionHandlerFactory 主要是用于生成 异常处理的具体类型
最后书写一个用于验证异常的处理类型
而BaseExceptionHandler 只是对最后响应代码做一个判断
xml 配置
而在web开发中,普通的页面提交动作,和ajax提交动作,处理方式不一样,因为跳转后直接显示响应数据,而ajax是通过error回调函数进行处理.
这里的处理思路,适用springmvc和struts2. 只是叫法不一样,一个是HandlerExceptionResolver ,一个是exceptioninterceptor.
下面是部分摘要,体现一下思路
首先定义异常拦截器:
@Component public class MyExceptionHandler implements HandlerExceptionResolver { protected Log log = LogFactory.getLog(this.getClass()); @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { log.error("异常捕获", ex); String requestURI = request.getRequestURI(); String fileExtName = StringUtils.getFileExtName(requestURI); boolean isajax = "ajax".equals(fileExtName); Throwable parseException = parseException(ex); return ExceptionHandlerFactory.createExceptionhandler(parseException) .resolveException(request, response, handler, parseException, isajax); } //这里要获取到最内层的异常 private static Throwable parseException(Throwable e){ Throwable tmp = e; int breakPoint = 0; while(tmp.getCause()!=null){ if(tmp.equals(tmp.getCause())){ break; } tmp=tmp.getCause(); breakPoint++; if(breakPoint>1000){ break; } } return tmp; } }
然后是 ExceptionHandlerFactory 主要是用于生成 异常处理的具体类型
public class ExceptionHandlerFactory { /** * 外挂的自定义处理器,用于外部扩展 */ private static Map<String , ExceptionHandler> handlerList = null; public static ExceptionHandler createExceptionhandler(Throwable ex){ //这个是自定义的接口 ExceptionHandler exceptionHandler=null; String packageName=ExceptionHandlerFactory.class.getName().replace(ExceptionHandlerFactory.class.getSimpleName(), ""); String className = ex.getClass().getSimpleName(); String classFullName = ex.getClass().getName(); if(handlerList==null){ handlerList = new HashMap<String, ExceptionHandler>(); } if(handlerList.containsKey(classFullName)){ return handlerList.get(classFullName); } //能走到这边,说明自定义的没有生效,走过之后,下面会将他缓存,也就是说,自定义的优先级永远大过系统自带的 try { //这里查找系统自带的,按照捕获的异常名称+ Handler进行查找,算是简单约定,因为框架开发中的内置我可以约定,扩展的使用配置文件进行 exceptionHandler = (ExceptionHandler)Class.forName(packageName+ className+"Handler").newInstance(); } catch (Exception e) { e.printStackTrace(); } if(exceptionHandler==null){ exceptionHandler = new SimpleExceptionHandler(); } handlerList.put(classFullName, exceptionHandler); return exceptionHandler; } public Map<String, ExceptionHandler> getHandlerList() { return handlerList; } //这里有getset,用于spring注入 public void setHandlerList(Map<String, ExceptionHandler> handlerList) { ExceptionHandlerFactory.handlerList = handlerList; } }
最后书写一个用于验证异常的处理类型
public class ConstraintViolationExceptionHandler extends BaseExceptionHandler{ @Override public Object processException(HttpServletRequest request, HttpServletResponse response, Object handler, Throwable ex, boolean isajax) { ConstraintViolationException e=(ConstraintViolationException)ex; Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations(); //ValidateInfo包含当前出错的字段,错误信息,出错的字段所在的类型,等必要的信息 // 在ajax特别是ajaxForm的提交中,只要前端约定好了命名规则,就可以根据返回的信息,进行界面提示,比如可渲染成和validate一样的风格 // 也可以给出一个dialog提示,或者...... List<ValidateInfo> validateInfos =new ArrayList<ValidateInfo>(); if(constraintViolations!=null && !constraintViolations.isEmpty()){ for(ConstraintViolation<?> violation : constraintViolations){ ValidateInfo info = new ValidateInfo(); info.setField(violation.getPropertyPath().toString().replaceAll("\\.","_")); info.setMessage(violation.getMessage()); Class<? extends Object> class1 = violation.getRootBean().getClass(); String simpleName =StringUtils.getSpringName(class1); if(simpleName.indexOf("$pcsubclass")>-1){ //这个判断是openjpa的代理类型,带$的不光是代理类型,内部类的名称同样有,所以编码上要约束 String[] ss = simpleName.split("\\$"); if(ss.length>1){ simpleName = ss[ss.length-2]; simpleName = simpleName.substring(0,1).toLowerCase()+simpleName.substring(1); } } info.setClassName(simpleName); Object ov =violation.getInvalidValue(); if(ov==null){ info.setCurrentValue(""); }else{ info.setCurrentValue(ov.toString()); } validateInfos.add(info); } } return validateInfos; //返回经过封装的验证信息,用于jquery ajax error回调方法进行统一处理 } }
而BaseExceptionHandler 只是对最后响应代码做一个判断
public abstract class BaseExceptionHandler implements ExceptionHandler{ /** * 用于传递到页面的值 */ protected Map<String, Object> data = new HashMap<String, Object>(); /** * 写到输出流 */ protected ModelAndView write(HttpServletRequest request, HttpServletResponse response, Object handler, Throwable ex, boolean isajax,Object dt){ int responseCode=500; if(ex instanceof BaseRuntimeException){ responseCode=((BaseRuntimeException)ex).getResponseCode(); } if(ex instanceof ConstraintViolationException){ responseCode=5001; } response.setStatus(responseCode); if(!isajax){//非ajax,直接跳转的,这里的是否ajax很简单,我们约定,ajax请求全部使用.ajax扩展.当然通过httpheader也能,jquery还支持preFilter,可以在这里统一加参数 ModelAndView modelAndView = new ModelAndView("/error/error"); modelAndView.addObject("__exception__", ex); modelAndView.addAllObjects(data); if(dt!=null){ modelAndView.addObject(dt); } return modelAndView; } //这个是封装的标准返回值模版,包含相应code,错误信息和响应数据等字段 ResultTemplate createFailResult = ResultTemplate.createFailResult(ex.getMessage()); createFailResult.setData(dt); WebUtils.renderJson(createFailResult); return null; } public abstract Object processException(HttpServletRequest request, HttpServletResponse response, Object handler, Throwable ex, boolean isajax); @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Throwable ex, boolean isajax) { Object d = processException(request, response, handler, ex, isajax); return write(request, response, handler, ex, isajax,d); } }
xml 配置
<bean class="com.core.web.interceptor.exceptionhandler.ExceptionHandlerFactory"> <property name="handlerList"> <map> <entry key="javax.validation.ConstraintViolationException" > <!-- jpa验证异常,这里可以不配置,系统内置,也可以配置自己的,替换系统自带的 --> <bean class="com.core.web.interceptor.exceptionhandler.ConstraintViolationExceptionHandler"/> </entry> </map> </property> </bean>
相关文章推荐
- SpringMVC处理普通请求异常以及,ajax异常
- 全局的异常捕获过滤器 区分ajax请求 与浏览器导航请求
- ajax和普通请求使用spring mvc在controller中的异常统一处理
- spring mvc 第二天【注解实现springmvc Handler处理ajax简单请求 的配置】
- springMVC --全局异常处理(两种方式)
- SpringMVC 全局异常处理代码
- Springmvc的全局异常处理
- springmvc请求参数异常处理
- SpringMVC实现全局异常捕获处理
- 通过jquery进行ajax的一些“异常”请求的页面自提交到其它页面
- springmvc 通过异常增强返回给客户端统一格式 springmvc请求参数异常处理
- Ajax响应中文乱码 [SpringMVC使用@ResponseBody处理Ajax请求]
- springMVC-异常的全局处理 @ControllerAdvice , @ExceptionHandler(Exception.class)
- 利用HandlerExceptionResolver对SpringMVC进行统一异常处理
- ajax请求二进制流进行处理(ajax异步下载文件)
- springmvc拦截器区分ajax请求
- springMVC全局异常处理
- springMVC拦截器处理ajax请求及数据返回
- springMVC --全局异常处理(两种方式)
- springmvc全局异常处理