转自https://blog.csdn.net/hao_kkkkk/article/details/80538955

最近在做项目时需要对异常进行全局统一处理,主要是一些分类入库以及记录日志等,因为项目是基于Springboot的,所以去网络上找了一些博客文档,然后再结合项目本身的一些特殊需求做了些许改造,现在记录下来便于以后查看。

在网络上找到关于Springboot全局异常统一处理的文档博客主要是两种方案:

1、基于@ControllerAdvice注解的Controller层的全局异常统一处理

以下是网上一位博主给出的代码示例,该博客地址为:https://www.cnblogs.com/magicalSam/p/7198420.html

import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

/**
* controller 增强器
*
* @author sam
* @since 2017/7/17
*/
@ControllerAdvice
public class MyControllerAdvice {

/**
* 全局异常捕捉处理
* @param ex
* @return
*/
@ResponseBody
@ExceptionHandler(value = Exception.class)
public Map errorHandler(Exception ex) {
Map map = new HashMap();
map.put("code", 100);
map.put("msg", ex.getMessage());
return map;
}

/**
* 拦截捕捉自定义异常 MyException.class
* @param ex
* @return
*/
@ResponseBody
@ExceptionHandler(value = MyException.class)
public Map myErrorHandler(MyException ex) {
Map map = new HashMap();
map.put("code", ex.getCode());
map.put("msg", ex.getMsg());
return map;
}

}
这个代码示例写的非常浅显易懂,但是需要注意的是:基于@ControllerAdvice注解的全局异常统一处理只能针对于Controller层的异常,意思是只能捕获到Controller层的异常,在service层或者其他层面的异常都不能捕获。

根据这段示例代码以及结合项目本身的实际需求,对该实例代码做了稍微改造(其实几乎没做改造,只是业务处理不一样而已):

@ControllerAdvice
public class AdminExceptionHandler {

private static final Logger logger = LoggerFactory.getLogger(AdminExceptionHandler.class);

/**
* @Author: gmy
* @Description: 系统异常捕获处理
* @Date: 16:07 2018/5/30
*/
@ResponseBody
@ExceptionHandler(value = Exception.class)
public APIResponse javaExceptionHandler(Exception ex) {//APIResponse是项目中对外统一的出口封装,可以根据自身项目的需求做相应更改
logger.error("捕获到Exception异常",ex);
//异常日志入库

return new APIResponse(APIResponse.FAIL,null,ex.getMessage());
}

/**
* @Author: gmy
* @Description: 自定义异常捕获处理
* @Date: 16:08 2018/5/30
*/
@ResponseBody
@ExceptionHandler(value = MessageCenterException.class)//MessageCenterException是自定义的一个异常
public APIResponse messageCenterExceptionHandler(MessageCenterException ex) {
logger.error("捕获到MessageCenterException异常",ex.getException());
//异常日志入库

return ex.getApiResponse();
}

}
public class MessageCenterException extends RuntimeException {

public MessageCenterException(APIResponse apiResponse, Exception exception){
this.apiResponse = apiResponse;
this.exception = exception;
}

private Exception exception;
private APIResponse apiResponse;

public Exception getException() {
return exception;
}

public void setException(Exception exception) {
this.exception = exception;
}

public APIResponse getApiResponse() {
return apiResponse;
}

public void setApiResponse(APIResponse apiResponse) {
this.apiResponse = apiResponse;
}
}
经过测试发现可以捕获到Controller层的异常,当前前提是Controller层没有对异常进行catch处理,如果Controller层对异常进行了catch处理,那么在这里就不会捕获到Controller层的异常了,所以这一点要特别注意。

在实际测试中还发现,如果在Controller中不做异常catch处理,在service中抛出异常(service中也不错异常catch处理),那么也是可以在这里捕获到异常的。

2、基于Springboot自身的全局异常统一处理,主要是实现ErrorController接口或者继承AbstractErrorController抽象类或者继承BasicErrorController类

以下是网上一位博主给出的示例代码,博客地址为:https://blog.csdn.net/king_is_everyone/article/details/53080851

@Controller
@RequestMapping(value = "error")
@EnableConfigurationProperties({ServerProperties.class})
public class ExceptionController implements ErrorController {

private ErrorAttributes errorAttributes;

@Autowired
private ServerProperties serverProperties;

/**
* 初始化ExceptionController
* @param errorAttributes
*/
@Autowired
public ExceptionController(ErrorAttributes errorAttributes) {
Assert.notNull(errorAttributes, "ErrorAttributes must not be null");
this.errorAttributes = errorAttributes;
}

/**
* 定义404的ModelAndView
* @param request
* @param response
* @return
*/
@RequestMapping(produces = "text/html",value = "404")
public ModelAndView errorHtml404(HttpServletRequest request,
HttpServletResponse response) {
response.setStatus(getStatus(request).value());
Map<String, Object> model = getErrorAttributes(request,
isIncludeStackTrace(request, MediaType.TEXT_HTML));
return new ModelAndView("error/404", model);
}

/**
* 定义404的JSON数据
* @param request
* @return
*/
@RequestMapping(value = "404")
@ResponseBody
public ResponseEntity<Map<String, Object>> error404(HttpServletRequest request) {
Map<String, Object> body = getErrorAttributes(request,
isIncludeStackTrace(request, MediaType.TEXT_HTML));
HttpStatus status = getStatus(request);
return new ResponseEntity<Map<String, Object>>(body, status);
}

/**
* 定义500的ModelAndView
* @param request
* @param response
* @return
*/
@RequestMapping(produces = "text/html",value = "500")
public ModelAndView errorHtml500(HttpServletRequest request,
HttpServletResponse response) {
response.setStatus(getStatus(request).value());
Map<String, Object> model = getErrorAttributes(request,
isIncludeStackTrace(request, MediaType.TEXT_HTML));
return new ModelAndView("error/500", model);
}

/**
* 定义500的错误JSON信息
* @param request
* @return
*/
@RequestMapping(value = "500")
@ResponseBody
public ResponseEntity<Map<String, Object>> error500(HttpServletRequest request) {
Map<String, Object> body = getErrorAttributes(request,
isIncludeStackTrace(request, MediaType.TEXT_HTML));
HttpStatus status = getStatus(request);
return new ResponseEntity<Map<String, Object>>(body, status);
}

/**
* Determine if the stacktrace attribute should be included.
* @param request the source request
* @param produces the media type produced (or {@code MediaType.ALL})
* @return if the stacktrace attribute should be included
*/
protected boolean isIncludeStackTrace(HttpServletRequest request,
MediaType produces) {
ErrorProperties.IncludeStacktrace include = this.serverProperties.getError().getIncludeStacktrace();
if (include == ErrorProperties.IncludeStacktrace.ALWAYS) {
return true;
}
if (include == ErrorProperties.IncludeStacktrace.ON_TRACE_PARAM) {
return getTraceParameter(request);
}
return false;
}

/**
* 获取错误的信息
* @param request
* @param includeStackTrace
* @return
*/
private Map<String, Object> getErrorAttributes(HttpServletRequest request,
boolean includeStackTrace) {
RequestAttributes requestAttributes = new ServletRequestAttributes(request);
return this.errorAttributes.getErrorAttributes(requestAttributes,
includeStackTrace);
}

/**
* 是否包含trace
* @param request
* @return
*/
private boolean getTraceParameter(HttpServletRequest request) {
String parameter = request.getParameter("trace");
if (parameter == null) {
return false;
}
return !"false".equals(parameter.toLowerCase());
}

/**
* 获取错误编码
* @param request
* @return
*/
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;
}
}

/**
* 实现错误路径,暂时无用
* @see ExceptionMvcAutoConfiguration#containerCustomizer()
* @return
*/
@Override
public String getErrorPath() {
return "";
}

}
该示例写的也是非常简单明了的,但是结合本身项目的实际需求,也是不能直接拿来用的,需要做相应的改造,改造主要有以下方面:

1、因为项目是前后端分离的,所以Controller层不会有ModelAndView返回类型,需要返回自身的APIResponse返回类型

2、项目需要统计全部的异常,而不只是404或者500的异常

3、捕获到异常之后需要做特殊化的业务处理

所以基于以上几方面对示例代码做了改造,具体改造代码如下:

/**
* @Author: gmy
* @Description: Springboot全局异常统一处理
* @Date: 2018/5/30
* @Time: 16:41
*/
@RestController
@EnableConfigurationProperties({ServerProperties.class})
public class ExceptionController implements ErrorController {

private ErrorAttributes errorAttributes;

@Autowired
private ServerProperties serverProperties;

/**
* 初始化ExceptionController
* @param errorAttributes
*/
@Autowired
public ExceptionController(ErrorAttributes errorAttributes) {
Assert.notNull(errorAttributes, "ErrorAttributes must not be null");
this.errorAttributes = errorAttributes;
}

@RequestMapping(value = "/error")
@ResponseBody
public APIResponse error(HttpServletRequest request) {
Map<String, Object> body = getErrorAttributes(request,
isIncludeStackTrace(request, MediaType.ALL));
HttpStatus status = getStatus(request);
return new APIResponse(APIResponse.FAIL,null,body.get("message").toString());
}

/**
* Determine if the stacktrace attribute should be included.
* @param request the source request
* @param produces the media type produced (or {@code MediaType.ALL})
* @return if the stacktrace attribute should be included
*/
protected boolean isIncludeStackTrace(HttpServletRequest request,
MediaType produces) {
ErrorProperties.IncludeStacktrace include = this.serverProperties.getError().getIncludeStacktrace();
if (include == ErrorProperties.IncludeStacktrace.ALWAYS) {
return true;
}
if (include == ErrorProperties.IncludeStacktrace.ON_TRACE_PARAM) {
return getTraceParameter(request);
}
return false;
}

/**
* 获取错误的信息
* @param request
* @param includeStackTrace
* @return
*/
private Map<String, Object> getErrorAttributes(HttpServletRequest request,
boolean includeStackTrace) {
RequestAttributes requestAttributes = new ServletRequestAttributes(request);
return this.errorAttributes.getErrorAttributes(requestAttributes,
includeStackTrace);
}

/**
* 是否包含trace
* @param request
* @return
*/
private boolean getTraceParameter(HttpServletRequest request) {
String parameter = request.getParameter("trace");
if (parameter == null) {
return false;
}
return !"false".equals(parameter.toLowerCase());
}

/**
* 获取错误编码
* @param request
* @return
*/
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;
}
}

/**
* 实现错误路径,暂时无用
* @return
*/
@Override
public String getErrorPath() {
return "";
}

}
经过测试,可以捕获到所有层面上的异常,当前前提仍然是没有对异常进行catch处理,否则这里也是捕获不到

以上为网络上常用的两种全局异常统一处理方案,经过实际测试发现都可以实现满足要求。

其实基于AOP也可以实现异常的全局处理,自己相应的做了测试发现也满足要求,相应的代码如下:

/**
* @Author: gmy
* @Description: 基于AOP的全局异常统一处理
* @Date: 2018/6/1
* @Time: 13:46
*/
@Component
@Aspect
public class ExceptionAspectController {
public static final Logger logger = LoggerFactory.getLogger(ExceptionAspectController.class);

@Pointcut("execution(* com.test.test.*.*(..))")//此处基于自身项目的路径做具体的设置
public void pointCut(){}

@Around("pointCut()")
public Object handleControllerMethod(ProceedingJoinPoint pjp) {
Stopwatch stopwatch = Stopwatch.createStarted();

APIResponse<?> apiResponse;
try {
logger.info("执行Controller开始: " + pjp.getSignature() + " 参数:" + Lists.newArrayList(pjp.getArgs()).toString());
apiResponse = (APIResponse<?>) pjp.proceed(pjp.getArgs());
logger.info("执行Controller结束: " + pjp.getSignature() + ", 返回值:" + apiResponse.toString());
logger.info("耗时:" + stopwatch.stop().elapsed(TimeUnit.MILLISECONDS) + "(毫秒).");
} catch (Throwable throwable) {
apiResponse = handlerException(pjp, throwable);
}

return apiResponse;
}

private APIResponse<?> handlerException(ProceedingJoinPoint pjp, Throwable e) {
APIResponse<?> apiResponse = null;
if(e.getClass().isAssignableFrom(MessageCenterException.class) ){
MessageCenterException messageCenterException = (MessageCenterException)e;
logger.error("RuntimeException{方法:" + pjp.getSignature() + ", 参数:" + pjp.getArgs() + ",异常:" + messageCenterException.getException().getMessage() + "}", e);
apiResponse = messageCenterException.getApiResponse();
} else if (e instanceof RuntimeException) {
logger.error("RuntimeException{方法:" + pjp.getSignature() + ", 参数:" + pjp.getArgs() + ",异常:" + e.getMessage() + "}", e);
apiResponse = new APIResponse(APIResponse.FAIL,null,e.getMessage());
} else {
logger.error("异常{方法:" + pjp.getSignature() + ", 参数:" + pjp.getArgs() + ",异常:" + e.getMessage() + "}", e);
apiResponse = new APIResponse(APIResponse.FAIL,null,e.getMessage());
}

return apiResponse;
}
}
经过测试,在执行切点中配置的路径中的方法有异常时,可以被这里捕获到。

以上是自己了解到并且亲自测试可行的全局异常统一处理方案,如果各位博友有什么问题或者有什么新的方案可以一块探讨下

2018/11/28最新编辑

经过一段时间的使用,现在项目里已经统一使用AOP方式来做全局异常统一处理了,选用AOP方式主要是因为AOP不只可以做全局异常统一处理还可以统一打印接口请求入参和返回结果日志,打印接口访问性能日志,处理sql注入攻击以及处理入参特殊字符等问题

下面贴出代码,供大家参考,也仅供参考

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
* @Author: gmy
* @Description: 调用接口打印性能日志以及接口报错之后记录错误日志
* @Date: 2018/9/20
* @Time: 15:16
*/
@Component
@Aspect
public class InterfaceRequestErrrorAndPerformanceLog {

public static final Logger logger = LoggerFactory.getLogger(InterfaceRequestErrrorAndPerformanceLog.class);

@Value("${dc.log.bad.value:3000}")
private int performanceBadValue;

@Resource
private RabbitMQService rabbitMQService;
@Resource
private InterfaceErrorService interfaceErrorService;

@Pointcut("execution(* test.test.test.test.test.controller.*.*.*(..))")
public void pointCut(){}

@Around("pointCut()")
public APIResponse handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable{
Stopwatch stopwatch = Stopwatch.createStarted();

APIResponse apiResponse;
try {
logger.info("执行Controller开始: " + pjp.getSignature() + " 参数:" + Lists.newArrayList(pjp.getArgs()).toString());
//处理入参特殊字符和sql注入攻击
checkRequestParam(pjp);
//执行访问接口操作
apiResponse = (APIResponse) pjp.proceed(pjp.getArgs());
try{
logger.info("执行Controller结束: " + pjp.getSignature() + ", 返回值:" + JSONObject.toJSONString(apiResponse));
//此处将日志打印放入try-catch是因为项目中有些对象实体bean过于复杂,导致序列化为json的时候报错,但是此处报错并不影响主要功能使用,只是返回结果日志没有打印,所以catch中也不做抛出异常处理
}catch (Exception ex){
logger.error(pjp.getSignature()+" 接口记录返回结果失败!,原因为:{}",ex.getMessage());
}
Long consumeTime = stopwatch.stop().elapsed(TimeUnit.MILLISECONDS);
logger.info("耗时:" + consumeTime + "(毫秒).");
//当接口请求时间大于3秒时,标记为异常调用时间,并记录入库
if(consumeTime > performanceBadValue){
DcPerformanceEntity dcPerformanceEntity = new DcPerformanceEntity();
dcPerformanceEntity.setInterfaceName(pjp.getSignature().toString());
dcPerformanceEntity.setRequestParam(Lists.newArrayList(pjp.getArgs()).toString());
dcPerformanceEntity.setConsumeTime(consumeTime + "毫秒");
RabbitMQMessageTarget mqTarget = RabbitMQMessageTarget.createFanoutTarget(ProjectConstants.DC_KEY_EXCHANGE_PERFORMANCE, new String[] { ProjectConstants.DC_KEY_QUEUE_PERFORMANCE});
rabbitMQService.send(mqTarget, JSON.toJSONString(dcPerformanceEntity));
}
} catch (Exception throwable) {
apiResponse = handlerException(pjp, throwable);
}

return apiResponse;
}

/**
* @Author: gmy
* @Description: 处理接口调用异常
* @Date: 15:13 2018/10/25
*/
private APIResponse handlerException(ProceedingJoinPoint pjp, Throwable e) {
APIResponse apiResponse;
if(e.getClass().isAssignableFrom(ProjectException.class) ){
//ProjectException为自定义异常类,项目中Controller层会把所有的异常都catch掉,并手工封装成ProjectException抛出来,这样做的目的是ProjectException会记录抛出异常接口的路径,名称以及请求参数等等,有助于错误排查
ProjectException projectException = (ProjectException)e;
logger.error("捕获到ProjectException异常:",JSONObject.toJSONString(projectException.getDcErrorEntity()));
RabbitMQMessageTarget mqTarget = RabbitMQMessageTarget.createFanoutTarget(ProjectConstants.DC_KEY_EXCHANGE_INTERFACE_ERROR, new String[] { ProjectConstants.DC_KEY_QUEUE_INTERFACE_ERROR});
rabbitMQService.send(mqTarget, JSON.toJSONString(dataCenterException.getDcErrorEntity()));
apiResponse = new APIResponse(APIResponse.FAIL,null,projectException.getDcErrorEntity().getErrorMessage());
} else if (e instanceof RuntimeException) {
logger.error("RuntimeException{方法:" + pjp.getSignature() + ", 参数:" + pjp.getArgs() + ",异常:" + e.getMessage() + "}", e);
apiResponse = new APIResponse(APIResponse.FAIL,null,e.getMessage());
} else {
logger.error("异常{方法:" + pjp.getSignature() + ", 参数:" + pjp.getArgs() + ",异常:" + e.getMessage() + "}", e);
apiResponse = new APIResponse(APIResponse.FAIL,null,e.getMessage());
}

return apiResponse;
}

/**
* @Author: gmy
* @Description: 处理入参特殊字符和sql注入攻击
* @Date: 15:37 2018/10/25
*/
private void checkRequestParam(ProceedingJoinPoint pjp){
String str = String.valueOf(pjp.getArgs());
if (!IllegalStrFilterUtil.sqlStrFilter(str)) {
logger.info("访问接口:" + pjp.getSignature() + ",输入参数存在SQL注入风险!参数为:" + Lists.newArrayList(pjp.getArgs()).toString());
DcErrorEntity dcErrorEntity = interfaceErrorService.processDcErrorEntity(pjp.getSignature() + "",Lists.newArrayList(pjp.getArgs()).toString(),"输入参数存在SQL注入风险!");
throw new DataCenterException(dcErrorEntity);
}
if (!IllegalStrFilterUtil.isIllegalStr(str)) {
logger.info("访问接口:" + pjp.getSignature() + ",输入参数含有非法字符!,参数为:" + Lists.newArrayList(pjp.getArgs()).toString());
DcErrorEntity dcErrorEntity = interfaceErrorService.processDcErrorEntity(pjp.getSignature() + "",Lists.newArrayList(pjp.getArgs()).toString(),"输入参数含有非法字符!");
throw new DataCenterException(dcErrorEntity);
}
}

}

代码中使用了一些其他的工具类,比如IllegalStrFilterUtil等,我也把代码贴出来

import org.slf4j.LoggerFactory;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* @Author: gmy
* @Description: 特殊字符检测工具(防止传入非法字符和sql注入攻击)
* @Date: 2018/10/25
* @Time: 15:08
*/
public class IllegalStrFilterUtil {
private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(IllegalStrFilterUtil.class);

private static final String REGX = "!|!|@|◎|#|#|(\\$)|¥|%|%|(\\^)|……|(\\&)|※|(\\*)|×|(\\()|(|(\\))|)|_|——|(\\+)|+|(\\|)|§ ";

/**
* 对常见的sql注入攻击进行拦截
*
* @param sInput
* @return
* true 表示参数不存在SQL注入风险
* false 表示参数存在SQL注入风险
*/
public static Boolean sqlStrFilter(String sInput) {
if (sInput == null || sInput.trim().length() == 0) {
return false;
}
sInput = sInput.toUpperCase();

if (sInput.indexOf("DELETE") >= 0 || sInput.indexOf("ASCII") >= 0 || sInput.indexOf("UPDATE") >= 0 || sInput.indexOf("SELECT") >= 0
|| sInput.indexOf("'") >= 0 || sInput.indexOf("SUBSTR(") >= 0 || sInput.indexOf("COUNT(") >= 0 || sInput.indexOf(" OR ") >= 0
|| sInput.indexOf(" AND ") >= 0 || sInput.indexOf("DROP") >= 0 || sInput.indexOf("EXECUTE") >= 0 || sInput.indexOf("EXEC") >= 0
|| sInput.indexOf("TRUNCATE") >= 0 || sInput.indexOf("INTO") >= 0 || sInput.indexOf("DECLARE") >= 0 || sInput.indexOf("MASTER") >= 0) {
Logger.error("该参数怎么SQL注入风险:sInput=" + sInput);
return false;
}
Logger.info("通过sql检测");
return true;
}

/**
* 对非法字符进行检测
*
* @param sInput
* @return
* true 表示参数不包含非法字符
* false 表示参数包含非法字符
*/
public static Boolean isIllegalStr(String sInput) {

if (sInput == null || sInput.trim().length() == 0) {
return false;
}
sInput = sInput.trim();
Pattern compile = Pattern.compile(REGX, Pattern.CASE_INSENSITIVE);
Matcher matcher = compile.matcher(sInput);
Logger.info("通过字符串检测");
return matcher.find();
}
}
以上代码中涉及到真实项目信息的内容我都做了相应修改,代码仅供技术交流使用。
---------------------
作者:hao_kkkkk
来源:CSDN
原文:https://blog.csdn.net/hao_kkkkk/article/details/80538955
版权声明:本文为博主原创文章,转载请附上博文链接!

Springboot项目全局异常统一处理的更多相关文章

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

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

  2. Springboot项目中异常拦截设计与处理

    背景: 项目运行过程中会出现各种各样的问题,常见的有以下几种情况: 业务流程分析疏漏,对业务流程的反向操作.边界分析设计不充分 调用外部服务.调用外部系统出现的超时.错误.返回值与预期不符 外部资源连 ...

  3. SpringMVC全局异常统一处理

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

  4. (办公)springboot配置全局异常

    项目用到了springboot,本来很高兴,但是项目里什么东西都没有,验证,全局异常这些都需要自己区配置.最近springboot用的还是蛮多的,我还是做事情,把经验发表一下.全局统一的异常,首先异常 ...

  5. springmvc、 springboot 项目全局异常处理

    异常在项目中那是不可避免的,通常情况下,我们需要对全局异常进行处理,下面介绍两种比较常用的情况. 准备工作: 在捕获到异常的时候,我们通常需要返回给前端错误码,错误信息等,所以我们需要手动封装一个js ...

  6. 4、springboot之全局异常捕获

    1.新建一个springboot项目 添加一个全局异常的类 import org.springframework.web.bind.annotation.ControllerAdvice; impor ...

  7. (入门SpringBoot)SpringBoot配置全局异常(五)

    Spring的全局异常,用于捕获程序员没有捕获的异常.具体请看下面代码: 1.ControllerAdvice拦截异常,统一处理.通过Spring的AOP来管理. @ControllerAdvicep ...

  8. 【spring】-- springboot配置全局异常处理器

    一.为什么要使用全局异常处理器? 什么是全局异常处理器? 就是把错误异常统一处理的方法. 应用场景: 1.当你使用jsr303参数校验器,如果参数校验不通过会抛异常,而且无法使用try-catch语句 ...

  9. SpringBoot(6) SpringBoot配置全局异常

    1.全局异常 @ControllerAdvice 如果是返回json数据 则用 RestControllerAdvice,就可以不加 @ResponseBody //捕获全局异常,处理所有不可知的异常 ...

随机推荐

  1. 网站性能优化(website performance optimization)2

    我们先研究下构建渲染树前的几个步骤:也就是DOM和CSSOM,通常这些步骤的效果最差使你的网页呈现速度非常慢,我们是讨论尽可能快的将HTML流式传输给客户端,使浏览器能够开始构建DOM,还有其他注意事 ...

  2. VisualBasic文件与目录管理FileSystem 类

    注解 下表列出了涉及 My.Computer.FileSystem 对象的任务示例. 功能 查看 从文本文件读取 如何:读取文本文件 从带分隔符的文本文件中读取 如何:读取逗号分隔的文本文件 从固定宽 ...

  3. SQL的循环嵌套算法:NLP算法和BNLP算法

    MySQL的JOIN(二):JOIN原理 表连接算法 Nested Loop Join(NLJ)算法: 首先介绍一种基础算法:NLJ,嵌套循环算法.循环外层是驱动表,循坏内层是被驱动表.驱动表会驱动被 ...

  4. SVN随笔记录(二)

    二.TortoiseSVN操作 1.下载,安装,过程中需要勾选x ,目的是为了后期绑定idea 2.如果点击后出现一系列的找不到目标文件提示,重启电脑 3.重启后,绑定仓库路径 4.一般情况输入账号密 ...

  5. # Excel批量处理数据

    Excel批量处理数据 拖住框下拉即可得到每行+3的结果

  6. IOS订阅优惠-PHP生成ECDSA算法签名

    <?php use Ramsey\Uuid\Uuid; class ItunesSignatureGenerator { private $appBundleID = 'www.u17.com' ...

  7. SVN简单流程总结

    1   创建仓库 2   启动svn服务器 svnserve -d -r 仓库地址(如:D:\SVN\repoDemo1) 3   新的用户第一次与服务器交互时,需要使用checkout将仓库检出到本 ...

  8. vue项目中微信jssdk在ios签名失败

    一.问题描述 1. vue项目中微信jssdk签名时,在安卓和ios是有差异的,签名时使用的url=window.location.href.split('#')[0],此时在安卓没问题,在ios会导 ...

  9. 小知识 Sql 格式化工具 AutoPostBack后的定位 Post和Get区别 防止被 Fream

    T-Sql 格式化工具 http://jinzb.name/Common/SqlFormat.html AutoPostBack后的定位问题: 给Page 增加属性,MaintainScrollPos ...

  10. ajax的交互原理,同步和异步的区别

    ajax的交互原理分别为: 创建对象——建立连接——发送数据——注册回调——执行回调 var xhr=new XMLHttpRequest()//创建对象 xhr.open(请求,url,true或者 ...