君子博学而日参省乎己 则知明而行无过矣

博客园 首页 新随笔 联系 订阅 管理

转载出处:http://fuliang.iteye.com/blog/947191  

Spring MVC的确很强大,在每一个你想的到和想不到的地方都会留下钩子,来插入自定义的实现,透明替换默认实现, 

拦截器堆栈结构设计的非常强大,多种试图的解析,url mapping的多种实现,Locale resolver、Theme resolver 
、multipart file resolver,Excepiton hanlder Resolver等等,能让Spring MVC从1.0到3.0经历巨大变化, 
仍能向后兼容,并支持很酷的RESTful风格和强大的简化xml配置的注解。 
这些功能我们在项目中经常用到,但是Excepiton hanlder Resolver可能是个生僻一点的东东,因为我们通常对错误 
的处理通常不是非常的复杂,很多情况下只是根据异常或者http error code跳转到错误页面,这个是JSP/servlet就可
以搞定,在web.xml配置一下即可。 

今天遇到一个事情,让我想用到HandlerExceptionResolver这个东东来处理异常。今天准备把自助系统进入上线状态, 
所以把log的级别从DEBUG调到INFO,结果没有catch的Runtime异常在log记录,后来跟踪了一下原来Spring把异常处理的log, 
直接使用的是debug,而不是error,所以log级别设置为INFO导致异常没有记录,看了一下spring的源代码: 
Java代码  收藏代码
  1. // Check registerer HandlerExceptionResolvers...  
  2. ModelAndView exMv = null;  
  3. for (Iterator it = this.handlerExceptionResolvers.iterator(); exMv == null && it.hasNext();) {  
  4. HandlerExceptionResolver resolver = (HandlerExceptionResolver) it.next();  
  5. exMv = resolver.resolveException(request, response, handler, ex);  
  6. }  
  7. if (exMv != null) {  
  8. if (logger.isDebugEnabled()) {  
  9. logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);  
  10. }  
  11. WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());  
  12. return exMv;  
  13. }  

可以看到可以插入自己的HandlerExceptionResover来搞定这个问题,我们可以在resolveException方法任意处理异常和log。也可以 
把错误信息个性化后传到view层显示。 
我们只有简单的需求,就是把没有catch的异常记入log,将异常的完整信息放在错误页面的一个隐藏的区域,方便查找出现错误的原因。 
首先我们实现HandlerExceptionResolver 
Java代码  收藏代码
  1. package com.qunar.advertisement.exception;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5.   
  6. import javax.servlet.http.HttpServletRequest;  
  7. import javax.servlet.http.HttpServletResponse;  
  8.   
  9. import org.apache.log4j.Logger;  
  10. import org.springframework.web.servlet.HandlerExceptionResolver;  
  11. import org.springframework.web.servlet.ModelAndView;  
  12.   
  13. import com.qunar.advertisement.utils.StringPrintWriter;  
  14.   
  15. public class QADHandlerExceptionResolver implements HandlerExceptionResolver{  
  16.     private static Logger logger = Logger.getLogger(QADHandlerExceptionResolver.class);  
  17.     @Override  
  18.     public ModelAndView resolveException(HttpServletRequest request,  
  19.             HttpServletResponse response, Object handler, Exception ex) {  
  20.         logger.error("Catch Exception: ",ex);//把漏网的异常信息记入日志  
  21.         Map<String,Object> map = new HashMap<String,Object>();  
  22.         StringPrintWriter strintPrintWriter = new StringPrintWriter();  
  23.         ex.printStackTrace(strintPrintWriter);  
  24.         map.put("errorMsg", strintPrintWriter.getString());//将错误信息传递给view  
  25.         return new ModelAndView("error",map);  
  26.     }  
  27.   
  28. }  

我们还需要一个辅助的类StringPrintWriter,因为ex.printStackTrace参数只有个PrintWriter类型的,java自带的StringWriter 
不可用,所以我们需要自己实现一个装饰器的StringPrintWriter。 
Java代码  收藏代码
  1. package com.qunar.advertisement.utils;  
  2.   
  3. import java.io.PrintWriter;  
  4. import java.io.StringWriter;  
  5.   
  6. public class StringPrintWriter extends PrintWriter{  
  7.   
  8.     public StringPrintWriter(){  
  9.         super(new StringWriter());  
  10.     }  
  11.      
  12.     public StringPrintWriter(int initialSize) {  
  13.           super(new StringWriter(initialSize));  
  14.     }  
  15.      
  16.     public String getString() {  
  17.           flush();  
  18.           return ((StringWriter) this.out).toString();  
  19.     }  
  20.      
  21.     @Override  
  22.     public String toString() {  
  23.         return getString();  
  24.     }  
  25. }  

我们只需要在xml中配置一下就可以了: 
Xml代码  收藏代码
  1. <bean class="com.qunar.advertisement.exception.QADHandlerExceptionResolver">  
  2. </bean>  

我们在错误页面隐藏区域显示错误信息: 
Html代码  收藏代码
  1. <div style="display:none;">  
  2.      <c:out value="${errorMsg}"></c:out>  
  3. </div>  
posted on 2012-04-08 00:40  刺猬的温驯  阅读(1763)  评论(0编辑  收藏  举报