SpringBoot [ 2.统一响应&&异常处理&&日志输出 ] - 目录
SpringBoot服务搭建服务完毕,就可以写一下服务的CURD(增删改查),但是在此之前必须要把一个项目最基本组件完善起来
我是用SpringBoot的这个过程,其实我接触到的项目都是前端后端分离的项目,由后端提供接口,前端通过ajax请求拿到后端数据进行渲染,那么为了方便前端处理,就要求后端接口以统一的数据结构响应前端数据.
我这里是封装了ExceptionConstant类,Result类来处理
package com.mantou.boot.constants;
/**
* 异常定义-常量
*
* @author mantou
*/
public class ExceptionConstant {
/**----------------------------------------------------操作类--------------------------------------------------------*/
/**
* 操作成功
*/
public static final String RET_CODE_SUCCESS = "00200";
public static final String RET_INFO_SUCCESS = "Operate Successfully ( 操作成功 ) !";
/**
* 操作失败
*/
public static final String RET_CODE_FAILED = "00500";
public static final String RET_INFO_FAILED = "Operate Failure ( 操作失败 ) !";
/**-----------------------------------------------------操作类-------------------------------------------------------*/
/**---------------------------------------------------服务/业务类-------------------------------------------------------*/
/**
* 业务异常
*/
public static final String RET_CODE_BUSINESS_EXCEPTION = "00010";
public static final String RET_INFO_BUSINESS_EXCEPTION = "Business Exception ( 业务异常 ) !";
/**
* 服务异常
*/
public static final String RET_CODE_SERVER_EXCEPTION = "01000";
public static final String RET_INFO_SERVER_EXCEPTION = "Server Exception ( 服务异常 ) !";
/**---------------------------------------------------服务/业务类-------------------------------------------------------*/
/**----------------------------------------------------请求/参数类----------------------------------------------------*/
/**
* HTTP请求不正确定义: 后端接口HTTP.METHOD定义与前端发起的HTTP.METHOD不符,则视为HTTP请求不正确
*/
public static final String RET_CODE_REQUEST_EXCEPTION = "00001";
public static final String RET_INFO_REQUEST_EXCEPTION = "Current Request Method ( GET POST PUT DELETE ) Not Supported ( 不支持当前请求方法 ) !";
/**
* 参数无意义empty定义: 前端请求参数无意义(null, "", []等, 视为empty)
*/
public static final String RET_CODE_PARAM_EMPTY = "00002";
public static final String RET_INFO_PARAM_EMPTY = "Parameters Is Empty ( 参数无意义 ) !";
/**-----------------------------------------------------请求/参数类----------------------------------------------------*/
}
Result类
package com.mantou.boot.result;
import com.mantou.boot.constants.ExceptionConstant;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
/**
* 项目统一响应结果类
*
* @author mantou
*/
@Data
public class Result implements Serializable {
private static final long serialVersionUID = 4559672604634663976L;
/**
* 返回码
*/
private String retCode;
/**
* 返回基础信息
*/
private String retInfo;
/**
* 返回数据
*/
private T data;
/**------------------------------------------------------操作类方法-----------------------------------------------------**/
/**
* 操作成功 - 构造方法
*
* @return
*/
public static Result success() {
return new Result(ExceptionConstant.RET_CODE_SUCCESS, ExceptionConstant.RET_INFO_SUCCESS);
}
/**
* 操作成功 - 构造方法
*
* @param data
* @return
*/
public static Result success(Object data) {
return new Result(ExceptionConstant.RET_CODE_SUCCESS, ExceptionConstant.RET_INFO_SUCCESS, data);
}
/**
* 操作失败 - 构造方法
*
* @return
*/
public static Result failed() {
return new Result(ExceptionConstant.RET_CODE_FAILED, ExceptionConstant.RET_INFO_FAILED);
}
/**
* 操作失败 - 构造方法 自定义返回基础信息
*
* @return
*/
public static Result failed(String retInfo) {
return new Result(ExceptionConstant.RET_CODE_FAILED, retInfo);
}
/**
* 操作是否成功 - 构造方法
*/
public static Result isSuccess(boolean isSuccess, String errorMessage, T data) {
return isSuccess ? Result.success(data) : Result.failed(errorMessage);
}
/**------------------------------------------------------操作类方法-----------------------------------------------------**/
/**----------------------------------------------------服务/业务类方法----------------------------------------------------**/
/**
* 服务异常 - 构造方法
*
* @return
*/
public static Result serverException() {
return new Result(ExceptionConstant.RET_CODE_SERVER_EXCEPTION, ExceptionConstant.RET_INFO_SERVER_EXCEPTION);
}
/**
* 服务异常 - 构造方法 自定义返回基础信息
*
* @return
*/
public static Result serverException(String retInfo) {
return new Result(ExceptionConstant.RET_CODE_SERVER_EXCEPTION, retInfo);
}
/**
* 业务异常 - 构造方法
*
* @return
*/
public static Result businessException() {
return new Result(ExceptionConstant.RET_CODE_BUSINESS_EXCEPTION, ExceptionConstant.RET_INFO_BUSINESS_EXCEPTION);
}
/**
* 业务异常 - 构造方法 自定义返回基础信息
*
* @param retInfo
* @return
*/
public static Result businessException(String retInfo) {
return new Result(ExceptionConstant.RET_CODE_BUSINESS_EXCEPTION, retInfo);
}
/**
* 参数无意义 - 构造方法
*
* @return
*/
public static Result paramsEmpty() {
return new Result(ExceptionConstant.RET_CODE_PARAM_EMPTY, ExceptionConstant.RET_INFO_PARAM_EMPTY);
}
/**----------------------------------------------------服务/业务类方法----------------------------------------------------**/
/**-----------------------------------------------------自定义类方法------------------------------------------------------**/
/**
* 自定义返回码, 返回基础信息 - 构造方法
*
* @param retCode
* @param retInfo
*/
public Result(String retCode, String retInfo) {
this.retCode = retCode;
this.retInfo = retInfo;
}
/**
* 自定义返回码, 返回基础信息, 返回数据 - 构造方法
*
* @param retCode
* @param retInfo
* @param data
*/
public Result(String retCode, String retInfo, T data) {
this.retCode = retCode;
this.retInfo = retInfo;
this.data = data;
}
/**
* 自定义返回码, 返回基础信息 - Set方法
*
* @param retCode
* @param retInfo
*/
public void setCodeInfo(String retCode, String retInfo) {
this.retCode = retCode;
this.retInfo = retInfo;
}
/**------------------------------------------------------自定义类方法----------------------------------------------------**/
}
除了接口统一响应,异常处理也是一个项目的必要组成
为什么异常要自定义异常?
首先因为Java的程序异常Exception有一般异常和运行时异常,出现这个异常一般是程序的异常导致; 在项目中某一个接口的业务发生异常时,为了标识这类业务异常,我们通常会进行自定义异常。当在接口层(controller)出现业务异常时,我们可以使用Result.failed()来对前端响应业务异常信息,在业务层(service)出现业务异常时,我们可以throw new BusinessException(“业务异常”)抛出异常,再由全局异常处理器捕获住异常,最后给前端响应异常信息。
我这里定义了一个BusinessException
**
* @description 业务异常
* @author mantou
*/
public class BusinessException extends RuntimeException {
private String info;
private String code;
/**
* 异常码, 异常信息
* @param code
* @param info
*/
public BusinessException(String code, String info) {
super(info);
this.info = info;
this.code = code;
}
/**
* 异常信息
* @param info
*/
public BusinessException(String info) {
super(info);
this.info = info;
this.code = ExceptionConstant.RET_CODE_BUSINESS_EXCEPTION;
}
public BusinessException() {
this(ExceptionConstant.RET_CODE_BUSINESS_EXCEPTION, ExceptionConstant.RET_INFO_BUSINESS_EXCEPTION);
}
}
全局异常处理器的作用就是捕获项目中的异常,并且按照一定的规则响应给前端异常信息
使用@RestControllerAdvice注解实现全局异常处理器
/**
* @description 全局异常处理器
* @author mantou
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* 请求方法不正确
* @param exception
* @return
*/
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public Result HttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException exception) {
//打印日志
log("[HttpRequest异常,请求方法不正确]", exception);
return Result.failed(exception.getMessage());
}
/**
* SysException异常处理
* @param e
* @return
*/
@ExceptionHandler(value = BusinessException.class)
public Result sysExceptionHandler(BusinessException e){
//打印日志
log("[SysException业务异常]", e);
return Result.failed(e.getMessage());
}
/**
* Exception异常处理
* @param e
* @return
*/
@ExceptionHandler(value = Exception.class)
public Result defaultErrorHandler(Exception e){
//打印日志
log("[Exception系统异常]", e);
return Result.failed(e.getMessage());
}
/**
* 打印日志
* @param e
*/
private void log(String message, Exception e) {
log.error("--------------------------------------异常开始------------------------------------------");
log.error(e.getMessage(), e);
log.error("--------------------------------------异常结束------------------------------------------");
}
日志作为项目十分重要的一个组成,一定要重视!!!
它的作用实在是太大了,可以用来调试程序,用来监控程序…
可以看一下依赖,SpringBoot默认的日志是Logback,由于Logback兼容其他日志,实现了Slf4j的API,所以我这里日志使用Slf4j进行日志打印,用LogBack来配置日志的输出格式与输出格式;
引入Lombok依赖,Lombok提供@Slf4j注解
org.projectlombok
lombok
provided
在类上使用@Slf4j注解即可使用log进行日志打印
logback.xml主要是用来控制日志的输出等级,日志的输出路径,日志的输出格式等
日志的等级有很多,但是项目开发通常只用四种,从高到低分别是ERROR,WARN,DEBUG,INFO; 级别越高输出的日志信息越少,比如说现在输出了这四种级别的日志,当前日志等级为ERROR就只输出ERROR日志,当前日志等级为WARN就输出ERROR,WARN;DEBUG和INFO依此类推。
${CONSOLE_LOG_PATTERN}
${log.path}/debug_${application.name}.log
${log.path}/%d{yyyy-MM, aux}/debug_${application.name}.%d{yyyy-MM-dd}.%i.log.gz
50MB
30
%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n
${log.path}/error_${application.name}.log
${log.path}/%d{yyyy-MM}/error_${application.name}.%d{yyyy-MM-dd}.%i.log.gz
50MB
30
%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n
ERROR