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. Blender建模软件怎么安装?有哪些好用的插件?

    1.下载Blender软件包,将压缩包解压后,使用鼠标左键双击打开安装文件. 2.由于压缩包内有两个安装文件,用户需要根据系统版本选择安装.可以使用鼠标右键单击桌面上的"此电脑"图 ...

  2. mindxdl---common---db_handler.go

    // Copyright (c) 2021. Huawei Technologies Co., Ltd. All rights reserved.// Package common this file ...

  3. js 获取相同name元素的属性值

    如图有8-12月5个文本域,id为plan8-12,name同为plan. 现在要获取name同为plan的所有属性值: 方法一: var allplan =document.getElementsB ...

  4. Zabbix技术分享——使用Zabbix6.0监控业务日志

    企业日常IT运维过程中,常会碰到需要监控业务日志的情况,以下将介绍如何使用Zabbix6.0监控业务日志. 应用场景描述: 企业IT运维部门使用自建zabbix平台对公司某业务系统进行了监控.近段时间 ...

  5. 数据结构高阶--AVL(平衡二叉树)(图解+实现)

    AVL树(平衡二叉树) 概念 二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下.因此为了解决这个问题,两位俄罗斯的数学家发明 ...

  6. kubernetes CKA题库(附答案)

    第一题 RBAC授权问题权重: 4% 设置配置环境:[student@node-1] $ kubectl config use-context k8s Context为部署管道创建一个新的Cluste ...

  7. python实验报告(第11章)

    实验11:使用Python操作数据库 一.实验目的和要求 1.学会数据库编程接口: 2.学会使用SQLite: 3.学会使用MySQL. 二.实验环境 软件版本:Python 3.10 64_bit ...

  8. 终于弄明白了 RocketMQ 的存储模型

    RocketMQ 优异的性能表现,必然绕不开其优秀的存储模型 . 这篇文章,笔者按照自己的理解 , 尝试分析 RocketMQ 的存储模型,希望对大家有所启发. 1 整体概览 首先温习下 Rocket ...

  9. asp前端无法获取后端中select *查询带出来的全部字段

    1.环境 前端:ASP.vbscript 后端:vb 数据库:Sql Server 2.问题描述 最近在做需求时碰到一个很奇怪的问题,后端通过select *查询带出来的字段,在前端只能获取到部分字段 ...

  10. 控制台运行java

    控制台执行java 新建java代码 新建一个记事本文件,将文件名改为HelloWorld.java,注意:后缀是.java. 若没有显示文件后缀,可以在资源管理器打开显示后缀,然后再次修改文件名,一 ...