spring项目中,我们通常规定了返回的格式(成功-失败-异常),特别是异常怎么处理方便呢?

1.自定义状态码实体

package com.ruoyi.common.constant;

/**
* 返回状态码
*
* @author ruoyi
*/
public class HttpStatus
{
/**
* 操作成功
*/
public static final int SUCCESS = 200; /**
* 对象创建成功
*/
public static final int CREATED = 201; /**
* 请求已经被接受
*/
public static final int ACCEPTED = 202; /**
* 操作已经执行成功,但是没有返回数据
*/
public static final int NO_CONTENT = 204; /**
* 资源已被移除
*/
public static final int MOVED_PERM = 301; /**
* 重定向
*/
public static final int SEE_OTHER = 303; /**
* 资源没有被修改
*/
public static final int NOT_MODIFIED = 304; /**
* 参数列表错误(缺少,格式不匹配)
*/
public static final int BAD_REQUEST = 400; /**
* 未授权
*/
public static final int UNAUTHORIZED = 401; /**
* 访问受限,授权过期
*/
public static final int FORBIDDEN = 403; /**
* 资源,服务未找到
*/
public static final int NOT_FOUND = 404; /**
* 不允许的http方法
*/
public static final int BAD_METHOD = 405; /**
* 资源冲突,或者资源被锁
*/
public static final int CONFLICT = 409; /**
* 不支持的数据,媒体类型
*/
public static final int UNSUPPORTED_TYPE = 415; /**
* 系统内部错误
*/
public static final int ERROR = 500; /**
* 接口未实现
*/
public static final int NOT_IMPLEMENTED = 501;
}

2.创建返回实体

  按照规定的格式创建返回实体,这样子就可以规范返回的格式-下面是一个自定义的返回实体

package com.ruoyi.common.core.domain;

import java.util.HashMap;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.utils.StringUtils; /**
* 操作消息提醒
*
* @author ruoyi
*/
public class AjaxResult extends HashMap<String, Object>
{
private static final long serialVersionUID = 1L; /** 状态码 */
public static final String CODE_TAG = "code"; /** 返回内容 */
public static final String MSG_TAG = "msg"; /** 数据对象 */
public static final String DATA_TAG = "data"; /**
* 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
*/
public AjaxResult()
{
} /**
* 初始化一个新创建的 AjaxResult 对象
*
* @param code 状态码
* @param msg 返回内容
*/
public AjaxResult(int code, String msg)
{
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
} /**
* 初始化一个新创建的 AjaxResult 对象
*
* @param code 状态码
* @param msg 返回内容
* @param data 数据对象
*/
public AjaxResult(int code, String msg, Object data)
{
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
if (StringUtils.isNotNull(data))
{
super.put(DATA_TAG, data);
}
} /**
* 返回成功消息
*
* @return 成功消息
*/
public static AjaxResult success()
{
return AjaxResult.success("操作成功");
} /**
* 返回成功数据
*
* @return 成功消息
*/
public static AjaxResult success(Object data)
{
return AjaxResult.success("操作成功", data);
} /**
* 返回成功消息
*
* @param msg 返回内容
* @return 成功消息
*/
public static AjaxResult success(String msg)
{
return AjaxResult.success(msg, null);
} /**
* 返回成功消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 成功消息
*/
public static AjaxResult success(String msg, Object data)
{
return new AjaxResult(HttpStatus.SUCCESS, msg, data);
} /**
* 返回错误消息
*
* @return
*/
public static AjaxResult error()
{
return AjaxResult.error("操作失败");
} /**
* 返回错误消息
*
* @param msg 返回内容
* @return 警告消息
*/
public static AjaxResult error(String msg)
{
return AjaxResult.error(msg, null);
} /**
* 返回错误消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 警告消息
*/
public static AjaxResult error(String msg, Object data)
{
return new AjaxResult(HttpStatus.ERROR, msg, data);
} /**
* 返回错误消息
*
* @param code 状态码
* @param msg 返回内容
* @return 警告消息
*/
public static AjaxResult error(int code, String msg)
{
return new AjaxResult(code, msg, null);
}
}

3.使用@RestControllerAdvice创建全局处理器

  @RestControllerAdvice是@ControllerAdvice和@ResponseBody的合并。此注解标记的类就是全局处理类,在这个类中可以自定义一个个的方法,用 @ExceptionHandler(异常类型)注解,那么它就回去拦截对应的异常,在该方法中进行处理,且把处理结果返回给页面。

3.1创建全局异常处理器

package com.ruoyi.framework.web.exception;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.exception.BaseException;
import com.ruoyi.common.exception.CustomException;
import com.ruoyi.common.exception.DemoModeException;
import com.ruoyi.common.utils.StringUtils; /**
* 全局异常处理器
*
* @author ruoyi
*/
@RestControllerAdvice //标识这是全局异常处理器
public class GlobalExceptionHandler
{
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); /**
* 基础异常
*/
@ExceptionHandler(BaseException.class) //表示对指定异常进行拦截并处理
public AjaxResult baseException(BaseException e)
{
return AjaxResult.error(e.getMessage());
}

   /**
     * 业务异常
     */
    @ExceptionHandler(CustomException.class)
    public AjaxResult businessException(CustomException e)
    {
        if (StringUtils.isNull(e.getCode()))
        {
            return AjaxResult.error(e.getMessage());
        }
        return AjaxResult.error(e.getCode(), e.getMessage());
    }
@ExceptionHandler(Exception.class)
public AjaxResult handleException(Exception e)
{
log.error(e.getMessage(), e);
return AjaxResult.error(e.getMessage());
} }

  注解1:@RestControllerAdvice //标识这是全局异常处理器

  注解2:@ExceptionHandler(BaseException.class) //表示对指定异常进行拦截并处理。当我们抛出指定的异常(可以自定义异常)时,会被ExceptionHandler拦截,并进行处理

3.2上面使用了自定义的异常

package com.ruoyi.common.exception;

/**
* 自定义异常
*
* @author ruoyi
*/
public class CustomException extends RuntimeException
{
private static final long serialVersionUID = 1L; private Integer code; private String message; public CustomException(String message)
{
this.message = message;
} public CustomException(String message, Integer code)
{
this.message = message;
this.code = code;
} public CustomException(String message, Throwable e)
{
super(message, e);
this.message = message;
} @Override
public String getMessage()
{
return message;
} public Integer getCode()
{
return code;
}
}

3.3业务中抛出异常

  public String login(String username, String password, String code, String uuid)
{
//1.校验验证码
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid; //缓存中存入验证码格式 {Constants.CAPTCHA_CODE_KEY + uuid:验证码}
String captcha = redisCache.getCacheObject(verifyKey);
redisCache.deleteObject(verifyKey);
if (captcha == null)
{ //缓存中没有验证码 发起一个异步任务-记录此次错误登录信息
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
throw new CaptchaExpireException();
}
if (!code.equalsIgnoreCase(captcha)) //验证码错误 发起一个异步任务-记录此次错误登录信息
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
throw new CaptchaException();
}
// 2.用户验证
Authentication authentication = null;
try
{
// 该方法会去调用package com.ruoyi.framework.web.service.UserDetailsServiceImpl.loadUserByUsername 若是校验失败,会抛出异常
authentication = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(username, password)); //loadUserByUsername方法会获取用户,匹配密码是自动完成的
}
catch (Exception e)
{
if (e instanceof BadCredentialsException) //用户密码不匹配 发起一个异步任务-记录此次错误登录信息
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
throw new UserPasswordNotMatchException();
}
else
{ //其它不匹配 比如没有该用户 该用户被停用等等 发起一个异步任务-记录此次错误登录信息
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
throw new
CustomException(e.getMessage());
}

} //发起一个异步任务-记录此次成功登录信息
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
// 生成token
return tokenService.createToken(loginUser);
}

  throw new CustomException(e.getMessage());

  这里我们在service层就直接抛出异常CustomException,会被上面的全局异常处理器拦截,和@ExceptionHandler(CustomException.class)匹配,匹配到了下面的方法

/**
* 业务异常
*/
@ExceptionHandler(CustomException.class)
public AjaxResult businessException(CustomException e)
{
if (StringUtils.isNull(e.getCode()))
{
return AjaxResult.error(e.getMessage());
}
return AjaxResult.error(e.getCode(), e.getMessage());
}

  抛出CustomException,该方法执行,最后返回一个AjaxResult对象给页面 ----return AjaxResult.error(e.getCode(), e.getMessage());

  {

code: 状态码
msg: 返回内容
data :数据对象

  }

3.4说明

  全局异常管理器实际上就是创建了拦截器对抛出的异常进行处理,并把处理结果返回给页面

  上面我们使用的是@RestControllerAdvice而不是@ControllerAdvice,它是@ControllerAdvice@ResponseBody的结合,返回的都是json数据。如果使用@ControllerAdvice,方法上需要添加@ResponseBody才能返回json格式数据。

最新文章

  1. 学习javascript数据结构(一)——栈和队列
  2. 4种解决json日期格式问题的办法
  3. JAVA源码分析-HashMap源码分析(二)
  4. 帆布指纹识别(canvas fingerprinting)
  5. [c#]一个窗体调用另一个窗体的事件
  6. ReactiveCocoa基础知识内容2
  7. SQL/LINQ/Lamda
  8. codeforces 709B Checkpoints
  9. 斯坦福第七课:正则化(Regularization)
  10. have you declared this activity in your AndroidManifest.xml
  11. git status message - Your branch is ahead of origin/master by X commits
  12. Eclipse创建第一个springWebMVC项目
  13. log4net 部署到服务器之后 无法记录日志问题 解决方法
  14. 11.9Daily Scrum
  15. JS点击任意标签获得该标签属性,以获得ID为例,以及AJAX的异步原理和 $(document).ready()与window.onload加载方法的区别
  16. Lucas定理及其应用
  17. 编程实现改变win7主题
  18. web版扫雷小游戏(三)
  19. VMware安装CentOS 6.7系统
  20. hiveQL求差集

热门文章

  1. C#一个16进制数用二进制数表示是几位?
  2. Linux下安装 SkyWalking 分布式追踪系统
  3. 使用 Go HTTP 框架 Hertz 进行 JWT 认证
  4. golang 概念理解
  5. 【iOS逆向】某营业厅算法分析
  6. day18-web工程路径
  7. 【大数据面试】【框架】Linux命令、Shell工具、常见Shell脚本(群起脚本、数仓导入)
  8. whistle证书过期或不信任
  9. utf-8与utf8mb4与base64和md5
  10. 东拼西凑学java