Web层通用数据处理之统一异常处理@ExceptionHandler
实际开发过程中会遇到对dao层、service层和controller层抛出的异常统一处理,对每个模块的方法进行异常处理也能解决问题,但这样是不合理的,并且代码看起来也不雅观,这时就可以使用@ExceptionHandler对Web层进行统一异常处理,让异常由下往上(dao—>service—>controller)抛出。代码如下:
import com.sand.base.core.common.BaseCommon; import com.sand.base.core.entity.ResultEntity; import com.sand.base.enums.ResultEnum; import com.sand.base.exception.LsException; import com.sand.base.util.ResultUtil; import com.sand.base.util.editor.DateEditor; import com.sand.base.util.editor.StringEditor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.ModelAttribute; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.util.Date; import java.util.Objects; /** * 功能说明:Web层通用数据处理 * 开发人员:@author liusha * 开发日期:2019/8/26 21:43 * 功能描述:定义所有控制器的父控制器,进行属性绑定、数据转换、异常处理 */ @Slf4j public class BaseController extends BaseCommon { protected HttpSession session; protected HttpServletRequest request; protected HttpServletResponse response; /** * 属性访问器 * * @param session session * @param request request * @param response response */ @ModelAttribute public void modelAttribute(HttpSession session, HttpServletRequest request, HttpServletResponse response) { this.session = session; this.request = request; this.response = response; } /** * 属性编辑器 * * @param binder 数据绑定 */ @InitBinder public void initBinder(WebDataBinder binder) { // Date类型转换,几乎支持所有的日期类型 binder.registerCustomEditor(Date.class, new DateEditor()); // String类型转换,将所有传递进来的String进行HTML编码,防止XSS攻击 binder.registerCustomEditor(String.class, new StringEditor()); } /** * 顶级异常处理 * * @param e 异常 * @return 响应客户端 */ @ExceptionHandler(Exception.class) public ResultEntity handleException(Exception e) { errorLog(e); return ResultUtil.error(); } /** * 自定义异常处理 * * @param e 异常 * @return 响应客户端 */ @ExceptionHandler(LsException.class) public ResultEntity handleLsException(LsException e) { errorLog(e); return ResultUtil.info(e.getCode(), e.getMessage()); } /** * 参数缺失处理 * * @param e 异常 * @return 响应客户端 */ @ExceptionHandler(MissingServletRequestParameterException.class) public ResultEntity handleMissingParamException(MissingServletRequestParameterException e) { errorLog(e); return ResultUtil.error(ResultEnum.PARAM_MISSING_ERROR); } /** * 读取方法处理 * * @param e 异常 * @return 响应客户端 */ @ExceptionHandler(HttpMessageNotReadableException.class) public ResultEntity handleMessageNotReadableException(HttpMessageNotReadableException e) { errorLog(e); return ResultUtil.error(ResultEnum.READ_METHOD_ERROR); } /** * 打印出错log * * @param e 异常 */ private void errorLog(Exception e) { StackTraceElement element = e.getStackTrace()[0]; if (e instanceof LsException) { log.info("异常位置:{}.{},第{}行,原因:{}", element.getClassName(), element.getMethodName(), element.getLineNumber(), e.getMessage()); if (!Objects.isNull(e.getCause())) { StackTraceElement cause = e.getCause().getStackTrace()[0]; log.info("起因:{}.{},第{}行,原因:{}", cause.getClassName(), cause.getMethodName(), cause.getLineNumber(), e.getCause().getMessage()); } } else { log.error("错误位置:{}.{},第{}行,错误原因:{}", element.getClassName(), element.getMethodName(), element.getLineNumber(), e.getClass().getName()); } log.error("错误信息:" + e); } }
需要注意的是,这种处理方式只对当前controller有效,也就是只有当controller继承了BaseController才能捕获到异常。如果希望没有继承BaseController的controller也能进行异常捕获,就需要新建一个@ControllerAdvice切面类配合@ExceptionHandler进行全局异常处理(值得注意的是,其它所有的切面类需将异常抛出而不是捕获处理,异常处理流程由统一异常处理类去完成,方便排查问题)。
我这里只列出了其中几种异常,异常种类远远不止这些,可以参考API文档进行选择自己需要的异常http://tool.oschina.net/apidocs/apidoc?api=Spring-3.1.1
千万不要试图去研究 研究了很久都整不明白的东西,或许是层次不到,境界未到,也或许是从未在实际的应用场景接触过,这种情况下去研究,只会事倍功半,徒劳一番罢了。能做的就是不断的沉淀知识,保持一颗积极向上的学习心态,相信终有一天所有的困难都会迎刃而解。