JavaWeb统一异常处理

Wesley13
• 阅读 543

JavaWeb统一异常处理

[toc]

处理方案

1. xml文件配置方式

web.xml配置

<error-page>
    <error-code>404</error-code>
    <location>/404</location>
</error-page>
<error-page>
    <error-code>500</error-code>
    <location>/500</location>
</error-page>

<!-- 未捕获的错误,同样可指定其它异常类,或自定义异常类 -->
<error-page>
    <exception-type>java.lang.Exception</exception-type>
    <location>/uncaughtException</location>
</error-page>

springmvc(applicationContext.xml)配置

<mvc:view-controller path="/400" view-name="400"/>
<mvc:view-controller path="/404" view-name="404"/>
<mvc:view-controller path="/500" view-name="500"/>
<mvc:view-controller path="/uncaughtException" view-name="uncaughtException"/>

SimpleMappingExceptionResolver

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
   
    <property name="exceptionMappings">
        <props>
            <!-- 异常类名,可以是全路径,错误页面或Controller路径! -->
            <prop key="NullPointerException">NullPointerException</prop>
            <prop key="IOException">IOException</prop>
        </props>
    </property>
    
     <!-- 表示当抛出异常但没有在exceptionMappings里面找到对应的异常时 返回名叫exception的视图-->  
    <property name="defaultErrorView" value="exception"/>
    
    <!-- 定义在发生异常时视图跟返回码的对应关系 --> 
    <property name="statusCodes"> 
        <props>  
            <prop key="number">500</prop>
            <prop key="null">503</prop>  
        </props>  
    </property>  
    <property name="defaultStatusCode" value="404"/>  
</bean>

2.代码拦截

自定义异常。

作统一异常处理。

自定义非检测异常,继承RuntimeException类,直接中断处理,不需要显示的捕捉和处理。例如参数错误等等无需进一步处理和恢复。

自定义检测异常, 继承Exception类,需要显示的捕捉或抛出。

public class BaseRuntimeException extends RuntimeException {

    private String message; //异常信息
    private Object[] args;  //相关参数等

   
    public BaseRuntimeException(String message) {
        super(message);
        this.message = message;
    }

   
    public BaseRuntimeException(String message, Throwable cause) {
        super(message, cause);
        this.message = message;
    }

   
    public BaseRuntimeException(String message, Object ... args) {
        super(message);
        this.message = message;
        this.args = args;
    }


    public BaseRuntimeException(String message, Throwable cause, Object ... args) {
        super(message, cause);
        this.message = message;
        this.args = args;
    }

 
    public String getMessage() {
        return message;
    }

    public Object[] getArgs() {
        return args;
    }
}

自定义异常处理器。

1.基于spring mvc 实现HandlerExceptionResolver接口
public class GlobalHandlerExceptionResolver implements HandlerExceptionResolver {   
 private static final Logger LOG = LoggerFactory.getLogger(GlobalHandlerExceptionResolver.class);                 
     
   @Override    
   public ModelAndView resolveException(HttpServletRequest req,                                         HttpServletResponse resp, Object o, Exception ex) {   
       ex.printStackTrace();     
       if (ex instanceof BaseRuntimeException) {
           printWrite(ex.getMessage, resp); 
        } else {          
             
           printWrite("ERROR!", resp);   
        }
        
         return new ModelAndView(); 
   }  

   /**     
   * 将错误信息写入到response中  
   * @param messsage     
   * @param response     
   * @throws IOException     
   */   
    public static void printWrite(String messsage, HttpServletResponse response) {      
         try {           
             PrintWriter pw = response.getWriter();        
             pw.write(messsage);       
             pw.flush();       
             pw.close();      
          } catch (Exception e) {          
             e.printStackTrace();      
          }   
    }
}
2. 注册异常处理器
<bean class="com.iot.learnssm.firstssm.exception.CustomExceptionResolver"></bean>

自定义拦截器

由于HandlerExceptionResolver接口只实现返回值为ModelAndView,前后端分离的话,可以采用拦截器HandlerInterceptor或者Filter。(springmvc还可以采用@ExceptionHandler注解来处理局部异常(注解应用于方法上),此处不多谈)

1. 基于spring mvc 实现HandlerInterceptor接口
public interface HandlerInterceptor {

//处理前,返回ture 进入postHandle, 返回false 进入afterCompletion
    boolean preHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception; 

//进入控制器
    void postHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3, ModelAndView var4) throws Exception;

//执行完控制器后调用
    void afterCompletion(HttpServletRequest var1, HttpServletResponse var2, Object var3, Exception var4) throws Exception; 
}



public class MVCRequestInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        return true;
    }

   @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

        httpServletResponse.setHeader("Access-Control-Allow-Methods","GET,POST,PUT,DELETE");
        httpServletResponse.setHeader("Access-Control-Allow-Credentials","true");


        try {
            chain.doFilter(request, httpServletResponse);
        } catch (BaseRuntimeException e) {
            e1.printStackTrace();
            printMessage(httpServletResponse, e.getMessage);

        } catch (Exception e){
            e1.printStackTrace();
            printMessage(httpServletResponse, ExceptionUtils.getStackTrace(e));
        }


    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {


    }
    
    
    private void printMessage(httpServletResponse response, String message){
         PrintWriter out = httpServletResponse.getWriter();
            Map<String,Object> map = new HashMap<String,Object>();
            map.put("success", false);
            map.put("msg", message);//获取详细错误信息
            out.println(JSONObject.toJSONString(map));
    }
}
2. 注册拦截器
<!-- 注册拦截器 -->
    <mvc:interceptors>
        <bean class="com.project.base.interceptor.ControlInterceptor" />
    </mvc:interceptors>

自定义Filter拦截器

1. 选择缘由
  • 框架由Struts2 改为 spring mvc,原代码并未改动,为了兼容两种控制器,实现javax.servlet的Filter接口,进行错误统一处理。
2.实现Filter 接口
@Component
public class GlobeExceptionFilter extends GenericFilterBean {

/*采用DelegatingFilterProxy代理管理自定义filter,可直接注入该service
    @Autowired
    private SysLoginLogService sysLoginLogService;
    */


    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
        httpServletResponse.setHeader("Access-Control-Allow-Origin","*");
        httpServletResponse.setHeader("Access-Control-Allow-Methods","GET,POST,PUT,DELETE");
        httpServletResponse.setHeader("Access-Control-Allow-Credentials","true");


        try {
            filterChain.doFilter(servletRequest, httpServletResponse);

            int httpStatus = httpServletResponse.getStatus();
                if(httpStatus >=400){ //请求错误
                HttpServletRequest request = (HttpServletRequest) servletRequest;
                String requestURI = request.getRequestURI();
                String queryString = request.getQueryString();
                System.out.println("------>"+requestURI);
                System.out.println("--------->"+queryString);
                // throw new BaseRuntimeException("error", requestURI, queryString); //用于测试
            }


        } catch (BaseError e){ //内部自定义错误
            System.out.println(e.getMessage());
            System.out.println(Arrays.toString(e.getArgs()));
        } catch (BaseRuntimeException e){ //内部自定义异常

            System.out.println("messsage--->" +e.getMessage());
            System.out.println("args--->" +Arrays.toString(e.getArgs()));

           //追踪栈上信息
            StackTraceElement[] st = e.getStackTrace();
            if(st.length > 0){
                String exclass = st[0].getClassName();
                String method = st[0].getMethodName();
                System.out.println("calss----->" + exclass); //发生异常类
                System.out.println("method----->" + method); //方法
                System.out.println("method----->" + lineNumber); //行数 
            }
            printMessage(httpServletResponse, e.getMessage());

            } catch (Exception e){ //其他异常
            e.printStackTrace();

        
            printMessage(httpServletResponse, e.getMessage());
        }

    }
    
    
    private void printMessage(HttpServletResponse httpServletResponse, String message){
        httpServletResponse.setContentType("application/json;charset=UTF-8");
        PrintWriter out = null;
        try {
            out = httpServletResponse.getWriter();
            Map<String,Object> map = new HashMap<String,Object>();
            map.put("success", false);
            map.put("msg", message);
            out.println(JSONObject.toJSONString(map));
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(out != null){
                out.close();
            }
        }

    }
}
3. xml配置
通过spring管理filter

采用DelegatingFilterProxy代理管理自定义filter ,filter内部可直接使用spring bean直接注入。

    <filter>
        <filter-name>globeExceptionFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由servlet container管理 -->
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>globeExceptionFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
Spring中注册filter
    <!-- 全局异常处理 -->
    <bean id="globeExceptionFilter" class="com.project.base.filter.GlobeExceptionFilter" />
点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
Java日期时间API系列31
  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Stella981 Stella981
2年前
Python之time模块的时间戳、时间字符串格式化与转换
Python处理时间和时间戳的内置模块就有time,和datetime两个,本文先说time模块。关于时间戳的几个概念时间戳,根据1970年1月1日00:00:00开始按秒计算的偏移量。时间元组(struct_time),包含9个元素。 time.struct_time(tm_y
Wesley13 Wesley13
2年前
03.Android崩溃Crash库之ExceptionHandler分析
目录总结00.异常处理几个常用api01.UncaughtExceptionHandler02.Java线程处理异常分析03.Android中线程处理异常分析04.为何使用setDefaultUncaughtExceptionHandler前沿上一篇整体介绍了crash崩溃
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这