统一的异常处理和自定义的全局异常处理器的配置使用

一、统一的异常处理

1、自定义异常处理类,继承了exception

package yycg.base.process.result;


/**
 * 自定义系统异常类
 */
public class ExceptionResultInfo extends Exception {

    // 系统统一使用的结果类,包括了 提示信息类型和信息内容
    private ResultInfo resultInfo;

    public ExceptionResultInfo(ResultInfo resultInfo) {
        super(resultInfo.getMessage());
        this.resultInfo = resultInfo;
    }

    public ResultInfo getResultInfo() {
        return resultInfo;
    }

    public void setResultInfo(ResultInfo resultInfo) {
        this.resultInfo = resultInfo;
    }

}

 

 2、统一的异常处理类,包括异常类型,异常信息

package yycg.base.process.result;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import yycg.util.ResourcesUtil;

/**
 * 系统提示信息封装类
 * @author mrt
 *
 */
public class ResultInfo
{
    public static final int TYPE_RESULT_FAIL = 0;//失败
    public static final int TYPE_RESULT_SUCCESS = 1;//成功
    public static final int TYPE_RESULT_WARN = 2;//警告
    public static final int TYPE_RESULT_INFO = 3;//提示信息
    
    public ResultInfo(){}

    /**
     * 消息提示类型
     */
    private int type;
        
    
    /**
     * 提示代码
     */
    private int messageCode;
    
       
    /**
     * 提示信息
     */
    private String message;
    
    
    /**
     * 提示信息明细列表
     */
    private List<ResultInfo> details;
    
    public List<ResultInfo> getDetails() {
        return details;
    }


    public void setDetails(List<ResultInfo> details) {
        this.details = details;
    } 
    
    /**
     * 提示消息对应操作的序号,方便用户查找问题,通常用于在批量提示信息中标识记录序号
     */
    private int index;
    
    
    /**
     * 提交后得到到业务数据信息从而返回给页面
     */
    private Map<String,Object> sysdata = new HashMap<String, Object>();
    
    /**
     * 构造函数,根据提交信息代码messageCode获取提示信息
     * @param MESSAGE
     */
    public ResultInfo(final int type,int messageCode,String message){
        this.type = type;
        this.messageCode = messageCode;
        this.message = message;
    }
    
   
    public int getMessageCode() {
        return messageCode;
    }




    public void setMessageCode(int messageCode) {
        this.messageCode = messageCode;
    }


    public String getMessage() {
        return message;
    }
    
    
    public void setMessage(String message) {
        this.message = message;
    }


    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public boolean isSuccess(){
        if(this.type == TYPE_RESULT_SUCCESS){
            return true;
        }
        return false;
    }

    public int getIndex() {
        return index;
    }
    public void setIndex(int index) {
        this.index = index;
    }
    
        
    


    public Map<String, Object> getSysdata() {
        return sysdata;
    }


    public void setSysdata(Map<String, Object> sysdata) {
        this.sysdata = sysdata;
    }



}

 

3、操作结果信息返回到页面进行提示的包装类

package yycg.base.process.result;


/**
 * 系统提交结果结果类型
 * @author Thinkpad
 *
 */
public class SubmitResultInfo {

    public SubmitResultInfo(ResultInfo resultInfo){
        this.resultInfo = resultInfo;
    }
    
    //操作结果信息
    private ResultInfo resultInfo;
    
    public ResultInfo getResultInfo() {
        return resultInfo;
    }

    public void setResultInfo(ResultInfo resultInfo) {
        this.resultInfo = resultInfo;
    }
        
}

 

使用说明:

【1】
ExceptionResultInfo 类继承了exception,同时添加了resultInfo属性
resultInfo用来标记异常出错类型(type)和记录异常信息(message)
例子:
resultInfo.setType(resultInfo.TYPE_RESULT_FAIL);//0错误 1成功 2警告3提示
resultInfo.setMessage("账号已存在,请重新输入!");
throw new ExceptionResultInfo(resultInfo);

【2】
在将json异常信息放回到页面时使用SubmitResultInfo类
return new SubmitResultInfo(resultInfo);

 

二、自定义全局异常处理器,springmvc 提供接口:HandlerExceptionResolver

1、自定义的异常处理器类,实现接口:handlerExceptionResolver

package yycg.base.process.exception;

import java.io.IOException;
import java.lang.reflect.Method;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import yycg.base.process.result.ExceptionResultInfo;
import yycg.base.process.result.ResultInfo;

/**
 * 
 * <p>
 * Title: ExceptionResolverCustom
 * </p>
 * <p>
 * Description:全局异常处理器
 * </p>
 * <p>
 * Company: www.itcast.com
 * </p>
 * 
 * @author
 * @date 
 * @version 1.0
 */
public class ExceptionResolverCustom implements HandlerExceptionResolver {

    // json转换器
    // 将异常信息转json
    private HttpMessageConverter<ExceptionResultInfo> jsonMessageConverter;

    // 前端控制器调用此方法执行异常处理
    // handler,执行的action类就包装了一个方法(对应url的方法)
    @Override
    public ModelAndView resolveException(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex) {

        // 输出 异常信息
        ex.printStackTrace();
        // 转成springmvc底层对象(就是对action方法的封装对象,只有一个方法)
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        // 取出方法
        Method method = handlerMethod.getMethod();

        // 判断方法是否返回json
        // 只要方法上有responsebody注解表示返回json
        // 查询method是否有responsebody注解
        ResponseBody responseBody = AnnotationUtils.findAnnotation(method,
                ResponseBody.class);
        if (responseBody != null) {
            // 将异常信息转json输出  
            return this.resolveJsonException(request, response, handlerMethod,
                    ex);

        }
        /**
         *1如果上面是可预知异常,type和message都已经设置有值,return ModelandView
          *直接将可预知异常返回到请求页面的回调函数,不再执行以下代码end
          *2如果是未知异常,则执行以下代码,构建未知异常,跳转到error页面显示
        */
        // 这里说明action返回的是jsp页面

        // 解析异常
        ExceptionResultInfo exceptionResultInfo = resolveExceptionCustom(ex);

        // 将异常信息在异常页面显示
        request.setAttribute("exceptionResultInfo",
                exceptionResultInfo.getResultInfo());

        // 转向错误页面
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("exceptionResultInfo",
                exceptionResultInfo.getResultInfo());
        modelAndView.setViewName("/base/error");// 逻辑视图名
        return modelAndView;
    }
//------------------------------------------------------------------------------------
    // 异常信息解析方法
    private ExceptionResultInfo resolveExceptionCustom(Exception ex) {
        ResultInfo resultInfo = null;
        if (ex instanceof ExceptionResultInfo) {
            // 抛出的是系统自定义异常
            resultInfo = ((ExceptionResultInfo) ex).getResultInfo();
        } else {
            // 重新构造“未知错误”异常
            resultInfo = new ResultInfo();
            resultInfo.setType(ResultInfo.TYPE_RESULT_FAIL);
            resultInfo.setMessage("未知错误!");
        }

        return new ExceptionResultInfo(resultInfo);

    }
//------------------------------------------------------------------------------------
    // 将异常信息转json输出
    private ModelAndView resolveJsonException(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex) {

        // 解析异常  (解析返回异常是自定义异常还是未知异常)
        ExceptionResultInfo exceptionResultInfo = resolveExceptionCustom(ex);
        
        HttpOutputMessage outputMessage = new ServletServerHttpResponse(response);
        
        try {
            //将exceptionResultInfo对象转成json输出
            jsonMessageConverter.write(exceptionResultInfo, MediaType.APPLICATION_JSON, outputMessage);
        } catch (HttpMessageNotWritableException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        

        return new ModelAndView();

    }

    public HttpMessageConverter<ExceptionResultInfo> getJsonMessageConverter() {
        return jsonMessageConverter;
    }

    public void setJsonMessageConverter(
            HttpMessageConverter<ExceptionResultInfo> jsonMessageConverter) {
        this.jsonMessageConverter = jsonMessageConverter;
    }

}

 

2、配置

  ①在springmvc.xml文件中配上json转换器(spring-web jar提供),并注入上面自定义的异常处理器类中,用于异常信息转换为json

 

 <!-- json转换器 -->
     <bean id="jsonMessageConverter"
        class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
    </bean>
     
    <!-- 统一异常处理类 -->
    <bean id="handlerExceptionResolver"
        class="yycg.base.process.exception.ExceptionResolverCustom">
        <!-- 注入一个json转换器 -->
        <property name="jsonMessageConverter" ref="jsonMessageConverter" />
    </bean>
    

 

 ②在web.xml中声明屏蔽默认的异常处理器,使自定义的异常处理器生效

<init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring/springmvc.xml</param-value>
        </init-param>
        <!-- 屏蔽springmvc自动注册的异常处理器 -->
        <init-param>
            <param-name>detectAllHandlerExceptionResolvers</param-name>
            <param-value>false</param-value>
        </init-param>

 

说明: 

1、自定义全局异常处理器,实现HandlerExceptionResolver接口

2、在springmvc.xml配置统一异常处理器。
<!-- json转换器 -->
<bean id="jsonMessageConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
</bean>

<!-- 统一异常处理类 -->
<bean id="handlerExceptionResolver"
class="yycg.base.process.exception.ExceptionResolverCustom">
<!-- 注入一个json转换器 -->
<property name="jsonMessageConverter" ref="jsonMessageConverter" />
</bean>


3、在web.xml中配置:
【前端控制器知道全局异常处理器id为handlerExceptionResolver
detectAllHandlerExceptionResolvers:
屏蔽自动注册异常处理器,固定使用bean的id为handlerExceptionResolver的异常处理器。】
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc.xml</param-value>
</init-param>
<init-param>
<param-name>detectAllHandlerExceptionResolvers</param-name>
<param-value>false</param-value>
</init-param>