一、SpringBoot框架搭建
系列文章目录
一、SpringBoot框架搭建
二、Java中SpringBoot组件集成接入【MySQL和MybatisPlus】
三、SpringBoot项目中根据数据表自动生成entity\DAO\DTO\VO\QO\Convertor\service\service.impl\controller等基础CRUD代码
四、Java中SpringBoot组件集成接入【Knife4j接口文档(swagger增强)】
五、Java中SpringBoot组件集成接入【slf4j日志文档】
六、Java中SpringBoot组件集成接入【MQTT中间件】
七、Java中SpringBoot组件集成接入【Minio文件服务器】
1.SpringBoot简介
Spring Boot是一个用于快速开发Spring应用程序的开源框架。它简化了Spring应用程序的开发和配置过程,提供了丰富的特性和工具,帮助开发者快速构建高效的应用程序。
2.基础环境
1.idea
网上关于IDEA下载、激活、初始化配置、使用教程的文章很多,可以自行查找。
2.jdk
3.maven
3.创建、配置、启动SpringBoot项目
SpringBoot项目层次结构和配置文件(pom.xml和application.yml)介绍
4.SpringBoot其他配置
1.SpringBoot开发拦截器和解决跨域问题
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//过滤掉这些path的请求
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
private static final Logger LOG = LoggerFactory.getLogger(CorsConfiguration.class);
/**
* 增加跨域配置
*
* @return 配置
*/
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
if (LOG.isInfoEnabled()) {
LOG.info("初始化 CORSConfiguration 配置");
}
registry.addMapping("/**")
.allowedHeaders("*")
.allowedMethods("*")
.allowedOrigins("*")
.allowCredentials(true);
}
};
}
}
开发拦截器参考文章:SpringBoot教程(六) | SpringBoot开发拦截器
解决跨域问题参考文章:SpringBoot教程(七) | SpringBoot解决跨域问题
2.SpringBoot统一结果封装
下面的是简易版的响应通用参数包装类;想要有不同的错误码,可以看参考文章
@ApiModel(value = "RestResponse<T>", description = "响应通用参数包装")
@Data
public class RestResponse<T> {
public static final int SUCCESS = 1;
public static final int FAILURE = 0;
@ApiModelProperty("响应错误编码,1为正常")
private int code;
@ApiModelProperty("响应错误信息")
private String msg;
@ApiModelProperty("响应内容")
private T result;
/**
* 成功不带参
* @param <T>
* @return
*/
public static <T> RestResponse<T> success() {
RestResponse<T> response = new RestResponse<>();
response.setCode(1);
return response;
}
/**
* 成功带参
* @param <T>
* @return
*/
public static <T> RestResponse<T> success(T result) {
RestResponse<T> response = new RestResponse<T>();
response.setCode(1);
response.setResult(result);
return response;
}
/**
* 错误带参数
* @param msg
* @param <T>
* @return
*/
public static <T> RestResponse<T> error(String msg) {
RestResponse<T> response = new RestResponse<T>();
response.setCode(0);
response.setMsg(msg);
return response;
}
/**
* 错误不带参
* @param <T>
* @return
*/
public static <T> RestResponse<T> error() {
return new RestResponse<T>();
}
}
参考文章:SpringBoot教程(八) | SpringBoot统一结果封装
3.SpringBoot统一异常处理
对全局异常(运行时异常、空指针)处理;
在程序中可以抛出自定义异常响应;
1.Result(通用返回结果)
public class Result<T> implements Serializable {
private static final long serialVersionUID = -3960261604605958516L;
private int code;
private String msg;
private T data;
// get set方法,限于篇幅问题,这里不写了,大家操作的时候自己生成一下。或者使用lombok
public static <T> Result<T> success() {
return new Result<>();
}
/**
* 成功,默认状态码,返回消息,自定义返回数据
*
* @param data 自定义返回数据
* @param <T> 返回类泛型,不能为String
* @return 通用返回Result
*/
public static <T> Result<T> success(T data) {
return new Result<>(data);
}
/**
* 成功,默认状态码,自定义返回消息,无返回数据
*
* @param msg 自定义返回消息
* @param <T> 返回类泛型
* @return 通用返回Result
*/
public static <T> Result<T> success(String msg) {
return new Result<>(msg);
}
/**
* 成功,默认状态码,自定义返回消息,返回数据
*
* @param msg 自定义返回消息
* @param data 自定义返回数据
* @param <T> 返回类泛型
* @return 通用返回Result
*/
public static <T> Result<T> success(String msg, T data) {
return new Result<>(msg, data);
}
/**
* 失败,默认状态码,返回消息,无返回数据
*
* @param <T> 返回类泛型
* @return 通用返回Result
*/
public static <T> Result<T> error() {
return new Result<>(ResultCode.ERROR);
}
/**
* 失败,默认状态码,自定义返回消息,无返回数据
*
* @param <T> 返回类泛型
* @return 通用返回Result
*/
public static <T> Result<T> error(String msg) {
return new Result<>(ResultCode.ERROR.getCode(), msg);
}
/**
* 失败,自定义状态码,返回消息,无返回数据
*
* @param code 自定义状态码
* @param msg 自定义返回消息
* @param <T> 返回类泛型
* @return 通用返回Result
*/
public static <T> Result<T> error(int code, String msg) {
return new Result<>(code, msg);
}
/**
* 失败,使用CodeMsg状态码,返回消息,无返回数据
*
* @param resultCode CodeMsg,参数如下:
* <p> code 状态码
* <p> msg 返回消息
* @param <T> 返回类泛型
* @return 通用返回Result
*/
public static <T> Result<T> error(ResultCode resultCode) {
return new Result<>(resultCode);
}
/**
* 成功构造器,无返回数据
*/
private Result() {
this(ResultCode.SUCCESS);
}
/**
* 成功构造器,自定义返回数据
*
* @param data 返回数据
*/
private Result(T data) {
this(ResultCode.SUCCESS, data);
}
/**
* 成功构造器,自定义返回消息,无返回数据
*
* @param msg 返回消息
*/
private Result(String msg) {
this(ResultCode.SUCCESS.getCode(), msg);
}
/**
* 成功构造器,自定义返回信息,返回数据
*
* @param msg 返回信息
* @param data 返回数据
*/
private Result(String msg, T data) {
this(ResultCode.SUCCESS.getCode(), msg, data);
}
/**
* 构造器,自定义状态码,返回消息
*
* @param code 状态码
* @param msg 返回消息
*/
private Result(int code, String msg) {
this.code = code;
this.msg = msg;
}
/**
* 构造器,自定义状态码,返回消息,返回数据
*
* @param code 状态码
* @param msg 返回消息
* @param data 返回数据
*/
private Result(int code, String msg, T data) {
this(code, msg);
this.data = data;
}
/**
* 构造器,使用CodeMsg状态码与返回信息
*
* @param resultCode CodeMsg,参数如下:
* <p> code 状态码
* <p> msg 返回消息
*/
private Result(ResultCode resultCode) {
this(resultCode.getCode(), resultCode.getMsg());
}
/**
* 构造器,使用CodeMsg状态码与返回信息,自定义返回数据
*
* @param resultCode CodeMsg,参数如下:
* <p> code 状态码
* <p> msg 返回消息
* @param data 返回数据
*/
private Result(ResultCode resultCode, T data) {
this(resultCode);
this.data = data;
}
}
2.ResultCode(响应码+响应信息)
@Data
@Builder
public class ResultCode implements Serializable {
private static final long serialVersionUID = -6269841958947880397L;
/**
* 状态码
*/
private int code;
/**
* 状态信息
*/
private String msg;
/**
* 默认成功
*/
public final static ResultCode SUCCESS = dispose(ResultCodeEnum.SUCCESS);
/**
* 默认失败
*/
public final static ResultCode ERROR = dispose(ResultCodeEnum.ERROR);
/**
* 通用业务异常
*/
public final static ResultCode BIZ_ERROR = dispose(ResultCodeEnum.BIZ_ERROR);
/**
* 文件超出最大限制
*/
public final static ResultCode FILE_OUT_MAX = dispose(ResultCodeEnum.FILE_OUT_MAX);
/**
* 文件格式不正确
*/
public final static ResultCode FILE_FORMAT_ERROR = dispose(ResultCodeEnum.FILE_FORMAT_ERROR);
/**
* 参数错误
*/
public final static ResultCode PARAM_ERROR = dispose(ResultCodeEnum.PARAM_ERROR);
/**
* Json解析异常
*/
public final static ResultCode JSON_FORMAT_ERROR = dispose(ResultCodeEnum.JSON_FORMAT_ERROR);
/**
* Sql解析异常
*/
public final static ResultCode SQL_ERROR = dispose(ResultCodeEnum.SQL_ERROR);
/**
* 网络超时
*/
public final static ResultCode NETWORK_TIMEOUT = dispose(ResultCodeEnum.NETWORK_TIMEOUT);
/**
* 未知的接口
*/
public final static ResultCode UNKNOWN_INTERFACE = dispose(ResultCodeEnum.UNKNOWN_INTERFACE);
/**
* 请求方式不支持
*/
public final static ResultCode REQ_MODE_NOT_SUPPORTED = dispose(ResultCodeEnum.REQ_MODE_NOT_SUPPORTED);
/**
* 系统异常
*/
public final static ResultCode SYS_ERROR = dispose(ResultCodeEnum.SYS_ERROR);
private static ResultCode dispose(ResultCodeEnum codeEnum) {
return ResultCode.builder().code(codeEnum.getCode()).msg(codeEnum.getMsg()).build();
}
public ResultCode(int code, String msg) {
this.code = code;
this.msg = msg;
}
}
3.ResultCodeEnum (响应码枚举)
public enum ResultCodeEnum {
SUCCESS(0, "操作成功"),
ERROR(1, "操作失败"),
BIZ_ERROR(1000, "通用业务异常"),
FILE_OUT_MAX(9000, "文件超出最大限制"),
FILE_FORMAT_ERROR(9001, "文件格式不正确"),
PARAM_ERROR(9050, "参数错误"),
JSON_FORMAT_ERROR(9051, "Json解析异常"),
SQL_ERROR(9052, "Sql解析异常"),
NETWORK_TIMEOUT(9510, "网络超时"),
UNKNOWN_INTERFACE(9520, "未知的接口"),
REQ_MODE_NOT_SUPPORTED(9530, "请求方式不支持"),
SYS_ERROR(9999, "系统异常");
/**
* 状态码
*/
private final int code;
/**
* 状态信息
*/
private final String msg;
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
ResultCodeEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}
}
4.测试Result
@GetMapping("/withinRangeResource")
public Result<List<EmergencyExpertResVO>> withinRangeResource(@Valid ResourceRangeReqVO param) {
List<EmergencyExpertResVO> expertResVOS = emergencyExpertBiz.getWithinRangeResource(param);
return Result.success(expertResVOS);
}
5.GlobalExceptionHandler (全局异常处理)
@RestControllerAdvice
@Order(1)
public class GlobalExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
public GlobalExceptionHandler() {
}
@ExceptionHandler({ParamException.class, MethodArgumentNotValidException.class, ConstraintViolationException.class, BindException.class, HttpMessageNotReadableException.class, MissingServletRequestPartException.class, MissingServletRequestParameterException.class, MultipartException.class})
public Result<?> paramsExceptionHandler(HttpServletRequest request, Exception e) {
String msg;
if (e instanceof MethodArgumentNotValidException) {
MethodArgumentNotValidException ex = (MethodArgumentNotValidException)e;
msg = this.handlerErrors(ex.getBindingResult());
} else if (e instanceof BindException) {
BindException ex = (BindException)e;
msg = this.handlerErrors(ex.getBindingResult());
} else if (e instanceof ConstraintViolationException) {
ConstraintViolationException ex = (ConstraintViolationException)e;
Optional<ConstraintViolation<?>> first = ex.getConstraintViolations().stream().findFirst();
msg = (String)first.map(ConstraintViolation::getMessage).get();
} else {
msg = e.getMessage();
}
Result<?> result = Result.error(ResultCode.PARAM_ERROR.getCode(), msg);
return this.printLogAndReturn(request, result, e);
}
private String handlerErrors(BindingResult bindingResult) {
List<FieldError> errors = bindingResult.getFieldErrors();
FieldError error = (FieldError)errors.get(0);
return error.getDefaultMessage();
}
@ExceptionHandler({BizException.class})
public Result<?> bizExceptionHandler(HttpServletRequest request, BizException e) {
Result<?> result = Result.error(e.getCode() == null ? ResultCode.BIZ_ERROR.getCode() : e.getCode(), e.getMessage());
return this.printLogAndReturn(request, result, e);
}
@ExceptionHandler({HttpRequestMethodNotSupportedException.class, HttpMediaTypeNotSupportedException.class})
public Result<?> httpRequestMethodNotSupportedExceptionHandler(HttpServletRequest request, Exception e) {
Result<?> result = Result.error(ResultCode.REQ_MODE_NOT_SUPPORTED);
return this.printLogAndReturn(request, result, e);
}
@ExceptionHandler({JSONException.class})
public Result<?> jsonExceptionHandler(HttpServletRequest request, Exception e) {
Result<?> result = Result.error(ResultCode.JSON_FORMAT_ERROR);
return this.printLogAndReturn(request, result, e);
}
@ExceptionHandler({DataAccessException.class})
public Result<?> sqlExceptionHandler(HttpServletRequest request, Exception e) {
Result<?> result = Result.error(ResultCode.SQL_ERROR);
return this.printLogAndReturn(request, result, e);
}
@ExceptionHandler({Exception.class})
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Result<?> exceptionHandler(HttpServletRequest request, Exception e) {
Result<?> result = Result.error(ResultCode.SYS_ERROR);
return this.printLogAndReturn(request, result, e);
}
private Result<?> printLogAndReturn(HttpServletRequest request, Result<?> result, Exception e) {
String requestUrl = request.getRequestURL().toString() + (StringUtil.isEmpty(request.getQueryString()) ? "" : "?" + request.getQueryString());
log.error("<-异常返回-> 请求接口:{} | 异常时间:{} | 异常结果:{}", new Object[]{requestUrl, System.currentTimeMillis(), JSON.toJSONString(result)});
log.error("<--异常堆栈信息-->");
log.error(Throwables.getStackTraceAsString(e));
return result;
}
}
6.BizException (自定义异常类)
public class BizException extends RuntimeException {
private Integer code;
public BizException() {
}
public BizException(String message) {
super(message);
}
public BizException(Integer code, String message) {
super(message);
this.code = code;
}
public BizException(ResultCode resultCode) {
super(resultCode.getMsg());
this.code = resultCode.getCode();
}
public BizException(String message, Throwable cause) {
super(message, cause);
}
public BizException(int code, String message, Throwable cause) {
super(message, cause);
this.code = code;
}
public BizException(ResultCode resultCode, Throwable cause) {
super(resultCode.getMsg(), cause);
this.code = resultCode.getCode();
}
public Integer getCode() {
return this.code;
}
public void setCode(Integer code) {
this.code = code;
}
}
@RestControllerAdvice
@Order(1)
public class GlobalExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
public GlobalExceptionHandler() {
}
private String handlerErrors(BindingResult bindingResult) {
List<FieldError> errors = bindingResult.getFieldErrors();
FieldError error = (FieldError)errors.get(0);
return error.getDefaultMessage();
}
@ExceptionHandler({BizException.class})
public Result<?> bizExceptionHandler(HttpServletRequest request, BizException e) {
Result<?> result = Result.error(e.getCode() == null ? ResultCode.BIZ_ERROR.getCode() : e.getCode(), e.getMessage());
return this.printLogAndReturn(request, result, e);
}
@ExceptionHandler({HttpRequestMethodNotSupportedException.class, HttpMediaTypeNotSupportedException.class})
public Result<?> httpRequestMethodNotSupportedExceptionHandler(HttpServletRequest request, Exception e) {
Result<?> result = Result.error(ResultCode.REQ_MODE_NOT_SUPPORTED);
return this.printLogAndReturn(request, result, e);
}
@ExceptionHandler({Exception.class})
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Result<?> exceptionHandler(HttpServletRequest request, Exception e) {
Result<?> result = Result.error(ResultCode.SYS_ERROR);
return this.printLogAndReturn(request, result, e);
}
private Result<?> printLogAndReturn(HttpServletRequest request, Result<?> result, Exception e) {
ObjectMapper mapper = new ObjectMapper();
String requestUrl = request.getRequestURL().toString() + (!StringUtils.hasLength(request.getQueryString()) ? "" : "?" + request.getQueryString());
try {
log.error("<-异常返回-> 请求接口:{} | 异常时间:{} | 异常结果:{}", new Object[]{requestUrl, System.currentTimeMillis(), mapper.writeValueAsString(result)});
} catch (JsonProcessingException jsonProcessingException) {
jsonProcessingException.printStackTrace();
}
log.error("<--异常堆栈信息-->");
StringWriter stringWriter = new StringWriter();
e.printStackTrace(new PrintWriter(stringWriter));
log.error(stringWriter.toString());
return result;
}
}
7.测试BizException
@RestController
public class ThirdExceptionController {
@GetMapping("exception")
public User second(){
System.out.println(1);
throw new BizException(ResultCode.BIZ_ERROR.getCode(), "用户名密码错误");
}
}