Java程序中,异常处理对于程序来说是非常基础。但是真正能很好理解并且很好的统一处理,这样会使得代码逻辑更清晰,更高效。下面就是程序中需要处理并且注意的异常统一处理案例:
通用异常处理类:
package com.jd.ccc.sys.biz.yb.mall.common.exception; import com.jd.ccc.sys.biz.yb.mall.common.enums.CodeEnum; import lombok.ToString; /** * 商城通用异常 * * @create 2018-4-28 * @author zhangqiang200<https://blog.csdn.net/zhangqiang_accp> * */ @ToString public class YbMallException extends RuntimeException { private static final long serialVersionUID = 111820440373615072L; /** * 异常代码 */ private int code; /** * 异常消息 */ private String message; public YbMallException(CodeEnum codeEnum) { this.code = codeEnum.getCode(); this.message = codeEnum.getMessage(); } public YbMallException(int code, String message) { super(message); this.code = code; this.message = message; } public YbMallException(int code, String message, Throwable cause) { super(message, cause); this.code = code; this.message = message; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } 服务层异常处理类:
package com.jd.ccc.sys.biz.yb.mall.common.exception; import com.jd.ccc.sys.biz.yb.mall.common.enums.CodeEnum; import lombok.ToString; /** * 商城服务层异常 * * @create 2018-4-28 * @author zhangqiang200<https://blog.csdn.net/zhangqiang_accp> * */ @ToString public class YbMallServiceException extends YbMallException { private static final long serialVersionUID = -3140415845720194815L; public YbMallServiceException(CodeEnum codeEnum) { super(codeEnum); } public YbMallServiceException(int code, String message) { super(code, message); } public YbMallServiceException(int code, String message, Throwable cause) { super(code, message, cause); } } 异常处理枚举类:
package com.jd.ccc.sys.biz.yb.mall.common.enums; /** * 应答码枚举类 * * @create 2018-4-28 * @author zhangqiang200<https://blog.csdn.net/zhangqiang_accp> */ public enum CodeEnum { /** * 处理成功 */ SUCCESS(200, "处理成功"), /** * 入参异常 */ ERROR(401, "入参异常"), /** * 保存失败 */ SAVE_FAIL(402, "保存失败"), /** * 查询失败 */ QUERY_FAIL(403, "查询失败"), /** * 未知异常 */ UNKOWN_ERROR(404,"未知异常"), SERVER_ACCESS_FAIL(405, "服务器访问失败"); /** * 响应代码 */ private final int code; /** * 响应消息 */ private final String message; CodeEnum(int _code, String _message) { this.code = _code; this.message = _message; } public int getCode() { return code; } public String getMessage() { return message; } /** * 通过枚举code获取对应的message * * @return 取不到时返回null * @create 2018-4-28 * @author zhangqiang200<https://blog.csdn.net/zhangqiang_accp> */ public static String getMessageByCode(int code) { for (CodeEnum _enum : values()) { if (_enum.getCode() == code) { return _enum.getMessage(); } } return null; } /** * 通过枚举code获取枚举对象 * * @return 取不到时返回null * @create 2018-4-28 * @author zhangqiang200<https://blog.csdn.net/zhangqiang_accp> */ public static CodeEnum getByCode(int code) { for (CodeEnum _enum : values()) { if (_enum.getCode() == code) { return _enum; } } return null; } } 响应结果处理类:
package com.jd.ccc.sys.biz.yb.mall.common.res; import com.jd.ccc.sys.biz.yb.mall.common.enums.CodeEnum; import lombok.Data; import lombok.ToString; /** * 响应结果 * * @create 2018-4-28 * @author zhangqiang200<https://blog.csdn.net/zhangqiang_accp> */ @Data @ToString public class CommonResult { /** * 应答码 * * @see 默认值为操作成功 */ private int code = CodeEnum.SUCCESS.getCode(); /** * 应答码描述 * * @see 默认值为操作成功 */ private String message = CodeEnum.SUCCESS.getMessage(); /** * 应答数据体 * * @see 可以为空 */ private Object data; /** * 京东账号 * * @see 可以为空 */ private String jdPin; public CommonResult() { this(CodeEnum.SUCCESS.getCode(), CodeEnum.SUCCESS.getMessage(), null); } public CommonResult(CodeEnum codeEnum) { this(codeEnum.getCode(), codeEnum.getMessage(), null); } /** * 默认返回的code=CodeEnum.SUCCESS.getCode() */ public CommonResult(Object data) { this(CodeEnum.SUCCESS.getCode(), CodeEnum.SUCCESS.getMessage(), data); } /** * 默认返回的data=null */ public CommonResult(int code, String message) { this(code, message, null); } public CommonResult(int code, String message, Object data) { this.code = code; this.message = message; this.data = data; } }控制层异常拦截:
package com.jd.ccc.sys.biz.yb.mall.web.controller.error; import javax.servlet.http.HttpServletRequest; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import com.jd.ccc.sys.biz.yb.mall.common.res.CommonResult; import com.jd.ccc.sys.biz.yb.mall.common.enums.CodeEnum; import com.jd.ccc.sys.biz.yb.mall.common.exception.YbMallException; import com.jd.ccc.sys.biz.yb.mall.common.exception.YbMallServiceException; /** * * Controller异常统一处理,因为需要让已经在线上运行的接口不受影响,所以本 * 次异常处理只扫描“com.jd.ccc.sys.biz.yb.mall.web.controller.v1”包路径下的 * Controller进行统一的“com.jd.ccc.sys.biz.yb.mall.common.exception.YbMall * Exception”和“com.jd.ccc.sys.biz.yb.mall.common.exception.YbMallServiceE * xception”这两类自定义异常处理。 * * @create 2018-4-28 * @author zhangqiang200<https://blog.csdn.net/zhangqiang_accp> * */ @ControllerAdvice(basePackages = "com.jd.ccc.sys.biz.yb.mall.web.controller.v1") public class ExceptionAspect { /** * * 统一处理JSON响应结果的错误结果 例如:{"code":201,message:"入参异常",data:null} * * @param cause * {@link Throwable} 异常 * @param request * {@link HttpServletRequest} 请求 * @return {@link CommonResult} 响应结果 * * @create 2018-4-28 * @author zhangqiang200<https://blog.csdn.net/zhangqiang_accp> */ @ResponseBody @ExceptionHandler({YbMallException.class, YbMallServiceException.class }) public CommonResult process(Throwable cause, HttpServletRequest request) { CommonResult result = new CommonResult(); // 判断抛出异常是否为YbMallException if (cause instanceof YbMallException) { result.setMessage(cause.getMessage()); result.setCode(((YbMallException) cause).getCode()); } else { result.setCode(CodeEnum.ERROR.getCode()); result.setMessage(CodeEnum.ERROR.getMessage()); } return result; } }
说明:拦截控制层抛出的YbMallException和YbMallServiceException异常。
Controller前的通讯异常等处理:
package com.jd.ccc.sys.biz.yb.mall.web.controller.error; import org.springframework.boot.autoconfigure.web.ErrorController; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.jd.ccc.sys.biz.yb.mall.common.enums.CodeEnum; import com.jd.ccc.sys.biz.yb.mall.common.res.CommonResult; import javax.servlet.http.HttpServletRequest; /** * Created by wangtianhong1 on 2017/7/6. */ @Controller public class ExceptionController implements ErrorController { private static final String ERROR_PATH = "/error"; @RequestMapping(value=ERROR_PATH,produces = {"text/html"}) public String errorHtml(HttpServletRequest request){ HttpStatus statusVal = getStatus(request); String errorUrl="redirect:/"; switch (statusVal.value()) { case 401: return errorUrl;//重定向首页 case 404: return errorUrl; case 500: return "redirect:https://www.jd.com/error2.aspx"; default: return errorUrl; } } /** * * 针对JSON数据的异常处理 * * @param request * 请求 * @return {@link CommonResult} * @create 2018-5-15 * @author zhangqiang200<https://blog.csdn.net/zhangqiang_accp> */ @RequestMapping(value = ERROR_PATH) @ResponseBody public CommonResult errorJson(HttpServletRequest request) { return new CommonResult(CodeEnum.ERROR); } /** * 获取错误状态编码 * @param request */ private HttpStatus getStatus(HttpServletRequest request) { Integer statusCode = (Integer) request .getAttribute("javax.servlet.error.status_code"); if (statusCode == null) { return HttpStatus.INTERNAL_SERVER_ERROR; } try { return HttpStatus.valueOf(statusCode); } catch (Exception ex) { return HttpStatus.INTERNAL_SERVER_ERROR; } } @Override public String getErrorPath() { return ERROR_PATH; } }