SpringMVC对异常进行全局处理,并区分对待ajax和普通请求
异常信息应统一进行处理. 程序员开发过程中,应尽量少用try..catch.避免因为catch造成的业务歧义.
而在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 = ;
while(tmp.getCause()!=null){
if(tmp.equals(tmp.getCause())){
break;
}
tmp=tmp.getCause();
breakPoint++;
if(breakPoint>){
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")>-){ //这个判断是openjpa的代理类型,带$的不光是代理类型,内部类的名称同样有,所以编码上要约束
String[] ss = simpleName.split("\\$");
if(ss.length>){
simpleName = ss[ss.length-];
simpleName = simpleName.substring(,).toLowerCase()+simpleName.substring();
}
}
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=;
if(ex instanceof BaseRuntimeException){
responseCode=((BaseRuntimeException)ex).getResponseCode();
}
if(ex instanceof ConstraintViolationException){
responseCode=;
}
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和普通请求的更多相关文章
- springmvc处理局部异常和全局异常
springmvc通过HandlerExceptionResolver(是一个接口,在spring-webmvc依赖下)处理程序异常,包括处理器异常.数据绑定异常以及处理器执行时发生的异常.Handl ...
- SpringMVC 处理异常的4种方式
springmvc处理异常有三种方式: 1.在一个controller中定义一个方法,用@ExceptionHandler注解标注.(优先级最高) @ExceptionHandler public M ...
- springmvc全局异常处理ControllerAdvice区分返回响应类型是页面还是JSON
思路: 加一个拦截器,在preHandler中取得HandlerMethod,判断其方法的返回类型,以及方法的注解和类的注解. 如果返回是json,收到异常则返回默认的异常包装类型. 如果返回是页面, ...
- springmvc 通过异常增强返回给客户端统一格式
在springmvc开发中,我们经常遇到这样的问题:逻辑正常执行时返回客户端指定格式的数据,比如json,但是遇NullPointerException空指针异常,NoSuchMethodExcept ...
- springmvc、 springboot 项目全局异常处理
异常在项目中那是不可避免的,通常情况下,我们需要对全局异常进行处理,下面介绍两种比较常用的情况. 准备工作: 在捕获到异常的时候,我们通常需要返回给前端错误码,错误信息等,所以我们需要手动封装一个js ...
- Xamarin.Android-捕获未处理异常(全局异常)
一.前言 android中如果出现了未处理的异常,程序会闪退,这是非常不好的用户体验,很多用户会因此卸载APP,因此未处理的异常是应该尽力避免的. 有些很难避免的异常(如:IO.网络等),应在代码中进 ...
- SpringMVC学习--异常处理器
简介 springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑. 异常处理思路 系统中异常包括两类:预期异常和运行时异常RuntimeExc ...
- SpringMVC接口测试异常:Can not deserialize instance of int out of START_OBJECT token
之前使用springmvc搭建了restful风格的接口服务,在使用mockmvc进行集成测试的时候出现了异常:Can not deserialize instance of int out of S ...
- Struts局部异常与全局异常处理
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAowAAAG3CAIAAACxBJNyAAAgAElEQVR4nOy9z6tk15Ymdv4B0eRU8O
随机推荐
- 基础连接已经关闭: 未能为 SSL/TLS 安全通道建立信任关系。
(转自:http://blog.sina.com.cn/s/blog_5eca668b01018949.html)定义一个类,来对远程X.509证书的验证,进行处理,返回为true.我们要自己定义一个 ...
- Spring 事务处理
Spring 默认执行事务回滚:当开启事务的类中对数据库的操作的异常没有任何处理时,才会主动触发事务回滚. 而很多时候业务都需要对抛出的异常进行处理,所以如果try,catch了操作数据库的方法,事务 ...
- Linux Runlevel 启动 脚本
Linux 操作系统自从开始启动至启动完毕需要经历几个不同的阶段,这几个阶段就叫做 Runlevel,同样,当Linux操作系统关闭时也要经历另外几个不同的 Runlevel,下面详细介绍一下 Run ...
- ReactJS学习笔记(二)
1.Ajax: componentDidMount 方法设置 Ajax 请求,等到请求成功,再用 this.setState 方法重新渲染 UI. /*demo1*/ var Demo1Box=Rea ...
- java学习第14天(集合的框架和基本遍历)
今天主要是接触了集合的概念,集合简单意义上来说就是类对象的集合,我们一般用Collection 这个接口来表示,集合主要体系为: Collection |--List |--ArrayList |-- ...
- RabbitMQ学习: 介绍
1. 介绍 RabbitMQ是一个由erlang开发的基于AMQP(Advanced Message Queue )协议的开源实现.用于在分布式系统中存储转发消息,在易用性.扩展性.高可用性等方面都非 ...
- HTTP权威协议笔记-6.代理
6.1 Web的中间实体 Http的代理服务器即是客户端的服务器又是服务器的客户端. 它介于服务器与客户端之间,当客户端发送请求报文经过它时,它会像服务器一样正确的处理请求和返回响应,同时,代理服务器 ...
- 查询数据库最大id加1
SELECT ISNULL(MAX(id),0)+1 AS MaxId FROM TABLE ISNULL(MAX(id),0) 就是如果id为空 就返回0,然后再加1
- DataSnap 2009 系列之三 (生命周期篇)
DataSnap 2009 系列之三 (生命周期篇) DataSnap 2009的服务器对象的生命周期依赖于DSServerClass组件的设置 当DSServer启动时从DSServerClass组 ...
- UE3 ExampleGame Android版无法运行解决方案
首先将 UE3\UnrealEngine3\UDKGame\Build\Android 文件夹 拷贝到 ExampleGame\Build下面.里面有相应的android 配置文件.xml 若果此时 ...