package com.stylefeng.guns.core.aop; import com.stylefeng.guns.core.common.exception.BizExceptionEnum; import com.stylefeng.guns.core.common.exception.InvalidKaptchaException; import com.stylefeng.guns.core.base.tips.ErrorTip; import com.stylefeng.guns.core.exception.GunsException; import com.stylefeng.guns.core.log.LogManager; import com.stylefeng.guns.core.log.factory.LogTaskFactory; import com.stylefeng.guns.core.shiro.ShiroKit; import com.stylefeng.guns.core.util.ToolUtil; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.CredentialsException; import org.apache.shiro.authc.DisabledAccountException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; import java.lang.reflect.UndeclaredThrowableException; import static com.stylefeng.guns.core.support.HttpKit.getIp; import static com.stylefeng.guns.core.support.HttpKit.getRequest; /** * 全局的的异常拦截器(拦截所有的控制器)(带有@RequestMapping注解的方法上都会拦截) * * @author fengshuonan * @date 2016年11月12日 下午3:19:56 */ @ControllerAdvice @Order(-1) public class GlobalExceptionHandler { private Logger log = LoggerFactory.getLogger(this.getClass()); private final static String BASE_PARAM_ERR_MSG = "参数校验不通过"; /** * 拦截业务异常 */ @ExceptionHandler(GunsException.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ResponseBody public ErrorTip notFount(GunsException e) { LogManager.me().executeLog(LogTaskFactory.exceptionLog(ShiroKit.getUser().getId(), e)); getRequest().setAttribute("tip", e.getMessage()); log.error("业务异常:", e); return new ErrorTip(e.getCode(), e.getMessage()); } /** * 用户未登录异常 */ @ExceptionHandler(AuthenticationException.class) @ResponseStatus(HttpStatus.UNAUTHORIZED) public String unAuth(AuthenticationException e) { log.error("用户未登陆:", e); return "/login.html"; } /** * 账号被冻结异常 */ @ExceptionHandler(DisabledAccountException.class) @ResponseStatus(HttpStatus.UNAUTHORIZED) public String accountLocked(DisabledAccountException e, Model model) { String username = getRequest().getParameter("username"); LogManager.me().executeLog(LogTaskFactory.loginLog(username, "账号被冻结", getIp())); model.addAttribute("tips", "账号被冻结"); return "/login.html"; } /** * 账号密码错误异常 */ @ExceptionHandler(CredentialsException.class) @ResponseStatus(HttpStatus.UNAUTHORIZED) public String credentials(CredentialsException e, Model model) { String username = getRequest().getParameter("username"); LogManager.me().executeLog(LogTaskFactory.loginLog(username, "账号密码错误", getIp())); model.addAttribute("tips", "账号密码错误"); return "/login.html"; } /** * 验证码错误异常 */ @ExceptionHandler(InvalidKaptchaException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public String credentials(InvalidKaptchaException e, Model model) { String username = getRequest().getParameter("username"); LogManager.me().executeLog(LogTaskFactory.loginLog(username, "验证码错误", getIp())); model.addAttribute("tips", "验证码错误"); return "/login.html"; } /** * 无权访问该资源异常 */ @ExceptionHandler(UndeclaredThrowableException.class) @ResponseStatus(HttpStatus.UNAUTHORIZED) @ResponseBody public ErrorTip credentials(UndeclaredThrowableException e) { getRequest().setAttribute("tip", "权限异常"); log.error("权限异常!", e); return new ErrorTip(BizExceptionEnum.NO_PERMITION.getCode(), BizExceptionEnum.NO_PERMITION.getMessage()); } /** * 拦截未知的运行时异常 */ @ExceptionHandler(RuntimeException.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ResponseBody public ErrorTip notFount(RuntimeException e) { LogManager.me().executeLog(LogTaskFactory.exceptionLog(ShiroKit.getUser().getId(), e)); getRequest().setAttribute("tip", "服务器未知运行时异常"); log.error("运行时异常:", e); return new ErrorTip(BizExceptionEnum.SERVER_ERROR.getCode(), BizExceptionEnum.SERVER_ERROR.getMessage()); } /** * 请求参数类型不匹配异常 * 例如本应传递int,却传递了String * * @param e * @return */ @ResponseStatus(HttpStatus.OK) @ExceptionHandler({MethodArgumentTypeMismatchException.class}) public ErrorTip handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) { log.warn("方法参数类型不匹配异常: {}", e); return new ErrorTip(6001, "方法请求参数类型不匹配异常"); } /** * 缺少servlet请求参数抛出的异常 * * @param e * @return */ @ResponseStatus(HttpStatus.OK) @ExceptionHandler({MissingServletRequestParameterException.class}) public ErrorTip handleMissingServletRequestParameterException(MissingServletRequestParameterException e) { log.warn(" 参数错误: {}", e.getParameterName()); return new ErrorTip(6001, "方法请求参数类型不匹配异常"); } /** * 请求参数不能正确读取解析时,抛出的异常,比如传入和接受的参数类型不一致 * * @param e * @return */ @ResponseStatus(HttpStatus.OK) @ExceptionHandler({HttpMessageNotReadableException.class}) public ErrorTip handleHttpMessageNotReadableException(HttpMessageNotReadableException e) { log.error("参数解析失败:", e); return new ErrorTip(6002, "传入和接受的参数类型不一致"); } /** * 请求参数无效抛出的异常 * 校验参数抛出的异常 * * @param e * @return */ @ResponseStatus(HttpStatus.OK) @ExceptionHandler({MethodArgumentNotValidException.class}) public ErrorTip handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { BindingResult result = e.getBindingResult(); String message = getBindResultMessage(result); log.error("参数验证失败:" + message); return new ErrorTip(6003, "参数验证失败"); } private String getBindResultMessage(BindingResult result) { // 多个错误随机取值的 FieldError error = result.getFieldError(); String field = error != null ? error.getField() : "空"; String code = error != null ? error.getDefaultMessage() : "空"; return String.format("%s:%s", field, code); } }