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格式数据。

@RestControllerAdvice全局异常统一处理的更多相关文章

  1. SpringMVC全局异常统一处理

    SpringMVC全局异常统一处理以及处理顺序最近在使用SpringMVC做全局异常统一处理的时候遇到的问题,就是想把ajax请求和普通的网页请求分开返回json错误信息或者跳转到错误页. 在实际做的 ...

  2. Springboot项目全局异常统一处理

    转自https://blog.csdn.net/hao_kkkkk/article/details/80538955 最近在做项目时需要对异常进行全局统一处理,主要是一些分类入库以及记录日志等,因为项 ...

  3. Android app 全局异常统一处理

    异常处理需求 Android app 出现 crash 时,会出现 "程序异常退出" 的提示并关闭,体验不好,另外主要是无法知道哪里出现的崩溃,需要知道哪里造成的异常,就需要一个全 ...

  4. springBoot 全局异常方式处理自定义异常 @RestControllerAdvice + @ExceptionHandler

    前言 本文讲解使用 @ControllerAdvice + @ExceptionHandler 进行全局的 Controller 层异常处理,可以处理大部分开发中用到的自自定义业务异常处理了,再也不用 ...

  5. Spring boot异常统一处理方法:@ControllerAdvice注解的使用、全局异常捕获、自定义异常捕获

    一.全局异常 1.首先创建异常处理包和类 2.使用@ControllerAdvice注解,全局捕获异常类,只要作用在@RequestMapping上,所有的异常都会被捕获 package com.ex ...

  6. SpringBoot系列五:SpringBoot错误处理(数据验证、处理错误页、全局异常)

    声明:本文来源于MLDN培训视频的课堂笔记,写在这里只是为了方便查阅. 1.概念: SpringBoot 错误处理 2.具体内容 在之前的程序里面如果一旦出现了错误之后就会出现一堆的大白板,这个白板会 ...

  7. @ControllerAdvice全局异常拦截

    @ControllerAdvice 拦截异常并统一处理 在spring 3.2中,新增了@ControllerAdvice 注解,可以用于定义@ExceptionHandler.@InitBinder ...

  8. SpringBoot:如何优雅地处理全局异常?

    之前用springboot的时候,只知道捕获异常使用try{}catch,一个接口一个try{}catch,这也是大多数开发人员异常处理的常用方式,虽然屡试不爽,但会造成一个问题,就是一个Contro ...

  9. springboot之全局处理统一返回

    springboot之全局处理统一返回 简介 在REST风格的开发中,避免通常会告知前台返回是否成功以及状态码等信息.这里我们通常返回的时候做一次util的包装处理工作,如:Result类似的类,里面 ...

  10. SpringBoot 全局异常配置

    在日常web开发中发生了异常,往往是需要通过一个统一的异常处理来保证客户端能够收到友好的提示. 一.默认异常机制 默认异常处理(SpringBoot 默认提供了两种机制,一种是针对于web浏览器访问的 ...

随机推荐

  1. <六>指向类成员的指针

    指向类成员(成员变量和成员方法)的指针 1:定义一个指针指向类的普通成员变量 示例代码1 点击查看代码 class Test2{ public: int ma; static int mb; void ...

  2. C#自定义控件(3)—PanelHead控件

    有时候我们会需要这样一种控件效果,上面是标题,下面是另外一个区域,且分别需要设置不同的颜 色等,当然我们可以使用splitContainer控件来制作,也可以直接使用自定义控件来,这样可以减少一 定的 ...

  3. CAN总线数据链路层(一)

    1.通信机制 发送报文. 1.首先检测Bus状态,空闲 则发送 报文且回读         2.线与机制,若有两个节点同时发报文          报文结构:          通过ID进行仲裁(规则 ...

  4. win10+vs2019 编译webrtc m108

    不能访问外网途径的捷径 已经下载好的资源,可以直接生成工程: https://pan.baidu.com/s/14plvXZD_qX9nn441RbsCwA?pwd=ww8c 该资源可以跳过的步骤 步 ...

  5. js 评级五星设置

    <input type="text" class="tt" style="color:red;border-style:none"&g ...

  6. ORCL 时间

    一.计算时间差 两个Date类型字段:START_DATE,END_DATE,计算这两个日期的时间差(分别以天,小时,分钟,秒,毫秒): 天: ROUND(TO_NUMBER(END_DATE - S ...

  7. labuladong算法笔记总结

    动态规划解题套路框架 学习计划: 最长回文子序列 〇.必读文章 1.数据结构和算法学习指南(学习算法和刷题的框架思维) 了解数据结构的操作和遍历(迭代or递归) 从树刷起,结合框架思维,有利于理解(回 ...

  8. 基于EasyCode定制Mybatisplus全自动单表实现:新增/批量新增/修改/批量删除/分页查询/ID查询

    基于EasyCode定制Mybatisplus全自动单表实现CRUD接口 分页查询 ID查询 新增 批量新增 修改 批量删除 注意使用了MybatisPlus的自动填充功能,和insertBatchS ...

  9. 云知声: 基于 JuiceFS 的超算平台存储实践

    云知声从一家专注于语音及语言处理的技术公司,现在技术栈已经发展到具备图像.自然语言处理.信号等全栈式的 AI 能力,是国内头部人工智能独角兽企业.公司拥抱云计算,在智慧医疗.智慧酒店.智慧教育等方面都 ...

  10. 结合商业项目深入理解Go知识点

    这篇文章比较硬核,爆肝5千字,把之前整理的知识点都串起来了.建议先收藏,慢慢看. 前言 上一篇文章 #[Go WEB进阶实战]开源的电商前后台API系统 很受大家欢迎,有好多小伙伴私信我问题:&quo ...