一、项目结构
二、全局异常
(1)启动类
package com.mgx;
import com.mgx.common.dto.Result;
import com.mgx.utils.ErrorUtil;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author mgx
*/
@ControllerAdvice
@MapperScan("com.mgx.mapper")
@SpringBootApplication
public class SpringbootMgxApplication {
public static void main(String[] args) {
System.out.println("开始启动");
SpringApplication.run(SpringbootMgxApplication.class, args);
System.out.println("启动成功");
}
/**
* 全局异常处理
*
* @param exception Exception
* @return R
*/
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result<String> defaultExceptionHandler(Exception exception) {
return ErrorUtil.handleException(exception);
}
}
⚠️注意:@ControllerAdvice是@Controller 的增强版。@ControllerAdvice主要用来处理全局数据,一般搭配@ExceptionHandler、@ModelAttribute以及@InitBinder使用。全局异常处理,将配合@ExceptionHandler定义全局异常捕获机制。
(2)CuzException类
package com.mgx.exception;
import com.mgx.common.enums.MsgCode;
/**
* @author mgx
*/
public class CuzException extends RuntimeException {
private MsgCode msgCode;
@Override
public String getMessage() {
return msgCode.getMsg();
}
public CuzException(MsgCode msgCode) {
this.msgCode = msgCode;
}
public MsgCode getMsgCode() {
return msgCode;
}
public void setMsgCode(MsgCode msgCode) {
this.msgCode = msgCode;
}
}
(3)ErrorUtil
package com.mgx.utils;
import com.mgx.common.dto.Result;
import com.mgx.common.enums.MsgCode;
import com.mgx.exception.CuzException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.sql.SQLException;
import java.util.Enumeration;
/**
* @author mgx
*/
@Slf4j
public class ErrorUtil {
private static Result<String> getParamErrorMessage(MethodArgumentNotValidException e) {
//按需重新封装需要返回的错误信息
StringBuilder stringBuilder = new StringBuilder();
//解析原错误信息,封装后返回,此处返回非法的字段名称,错误信息
for (FieldError error : e.getBindingResult().getFieldErrors()) {
if (stringBuilder.length() > 1) {
stringBuilder.append("; ");
}
stringBuilder.append(error.getDefaultMessage());
}
return Result.failure().code(MsgCode.Code_500.getCode()).message(stringBuilder.toString()).build();
}
public static Result<String> handleException(Exception exception) {
try {
// 打印全部异常信息
log.error("系统异常:", exception);
throw exception;
} catch (CuzException e) {
MsgCode msgCode = e.getMsgCode();
return Result.failure().code(msgCode == null ? MsgCode.Code_500.getCode() : msgCode.getCode()).message(msgCode == null ? e.getMessage() : msgCode.getMsg()).build();
} catch (IllegalAccessException e) {
return Result.failure().code(MsgCode.Code_503.getCode()).build();
} catch (MethodArgumentNotValidException e) {
printException();
return getParamErrorMessage(e);
} catch (HttpMessageNotReadableException e) {
printException();
return Result.failure().code(MsgCode.Code_2002.getCode()).build();
} catch (HttpRequestMethodNotSupportedException e) {
return Result.failure().code(MsgCode.Code_2004.getCode()).build();
} catch (MissingServletRequestParameterException e) {
return Result.failure().code(MsgCode.Code_2003.getCode()).build();
} catch (IllegalArgumentException e) {
return Result.failure().code(MsgCode.Code_2001.getCode()).build();
} catch (BindException e) {
return Result.failure().code(MsgCode.Code_500.getCode()).message(e.getAllErrors().get(0).getDefaultMessage()).build();
} catch (SQLException | DataIntegrityViolationException | BadSqlGrammarException e) {
return Result.failure().code(MsgCode.Code_2005.getCode()).build();
} catch (Exception e) {
return Result.failure().code(MsgCode.Code_500.getCode()).build();
}
}
private static void printException(){
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if(attributes == null){
return;
}
HttpServletRequest request = attributes.getRequest();
// 记录下请求内容
log.error("URL : " + request.getRequestURL().toString());
log.error("HTTP_METHOD : " + request.getMethod());
log.error("IP : " + request.getRemoteAddr());
Enumeration<String> enu = request.getParameterNames();
while (enu.hasMoreElements()) {
String name = enu.nextElement();
log.error("name:{},value:{}", name, request.getParameter(name));
}
}
}
三、测试
(1)下面的SQL明显是错误的,那么我们调用含该SQL的接口,看会返给我们什么
接口调用测试
(2)没有该数据,接口逻辑中抛异常,看会返给我们什么
接口调用测试
(3)自定义SQL语法错误的全局异常,与返回一致,全局异常处理成功。