Bootstrap

一、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

IDEA整合JDK

3.maven

IDEA整合Maven

3.创建、配置、启动SpringBoot项目

SpringBoot项目搭建

SpringBoot项目层次结构和配置文件(pom.xml和application.yml)介绍

4.SpringBoot其他配置

在这里插入图片描述

【Spring】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(), "用户名密码错误");
    }
 
 
}

参考文章:SpringBoot教程(九) | SpringBoot统一异常处理

;