SpringBoot部分功能总结

这篇博客总结了SpringBoot的关键特性,包括日志配置(slf4j、logback、log4j的关系及使用)、Swagger的整合、@Async异步处理框架的使用、统一返回的R类封装、Spring容器注入的几种方式、全局异常处理、以及SpringBoot集成Mybatis Plus的基础操作。内容涵盖了从日志配置到API文档生成,再到异步任务和数据库操作的方方面面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

查漏补缺,对SpringBoot相关技术进行总结!!!

1.SpringBoot的日志文件

在开发过程中,会经常使用到日志,下面对日志相关知识进行总结,方便之后的查阅。
slf4j
在springboot的底层日志结构中对应:spring-boot-starter-logging可以看出,它依赖了三个框架分别是:

  • slf4j
  • logback
  • log4j

那么,这三者是什么关系呢?我们实际开发中使用哪个呢?如何使用?

1、logback和log4j是日志实现框架,
2、slf4j:提供了java所有的日志框架的简单抽象(使用了日志的门面设计模式),
slf4j必须要结logbacklog4j日志框架来结合使用。

springboot2.x以后默认采用了:slf4j+logback的日志搭配。
在开发过程中,我们可以采用slf4j的api去记录日志,底层的实现就是根据配置文件来决定使用logback还是log4j日志框架。

使用
private static final Logger log = LoggerFactory.getLogger(类名.class);
调用log.info(“日志信息,自定义的”);

日志级别
一般用info(默认info)
log.trace("----------trace--------");
log.debug("----------debug--------");
log.info("----------info--------");
log.warn("----------warn--------");
log.error("----------error--------");
顺序是:trace>debug>info>warn>error
比如:日志级别是info的,则打印info、warn、error

日志级别的修改

配置文件yaml修改

#  指定日志级别 把springboot的所有日志修改成为debug
logging:
  level:
    root: debug

日志输出文件

默认情况下关闭

logging:
  file:
    #路径
    path: output/logs 
    #日志输出方式,文件、控制台
    pattern:
      file:
      console: 

日志格式

%c 输出logger名称
%C 输出类名
%d{HH:mm:ss.SSS} 表示输出到毫秒的时间
%t 输出当前线程名称
%-5level 输出日志级别,-5表示左对齐并且固定输出5个字符,如果不足在右边补0
%logger 输出logger名称,因为Root Logger没有名称,所以没有输出
%msg 日志文本
%n 换行
其他常用的占位符有:
%F 输出所在的类文件名,如Log4j2Test.java
%L 输出行号
%M或%method 输出所在方法名
%l 输出完整的错误位置, 包括类名、方法名、文件名、行数
%p 该条日志的优先级
%replace{pattern}{regex}{substitution} 将pattern的输出结果pattern按照正则表达式regex替换成substitution

lombok优化日志的定义

注解:@Slf4j@Log4j2 建议在开发过程中就默认选择:@Slf4j

日志级别隔离

在实际开发中,分为生成环境和开发环境。开发环境的级别一般使用:debug或者info,在生产环境中建议一般使用error

所以,有了环境隔离的概念,生产环境使用appliaction-prod.yaml配置文件,开发环境使用application-dev配置文件。
如何切换?

# 环境激活
spring:
  profiles:
    active: dev
    #active: prod

2.SpringBoot整合Swagger

Swagger是什么

Swagger是依赖内嵌在项目中的一款在线文档测试工具

怎么用

1、导入pom依赖

<!-- Swagger -->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>

<!-- 文档 -->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
    <exclusions>
        <exclusion>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-models</artifactId>
        </exclusion>
        <exclusion>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>io.swagger</groupId>
    <artifactId>swagger-models</artifactId>
    <version>1.5.21</version>
</dependency>

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>

<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>swagger-bootstrap-ui</artifactId>
    <version>1.8.5</version>
</dependency>

2、定义和开启swagger的配置类

@Configuration
@EnableSwagger2
public class SwaggerConfiguration {
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(getApiInfo())
                .select()
                // 核心:读取把那个包下面的方法作为接口,只能是:controller
                .apis(RequestHandlerSelectors.basePackage("com.zwh.slf4j.config"))
                .paths(PathSelectors.any())
                .build();
    }
    private ApiInfo getApiInfo() {
        return new ApiInfoBuilder()
                .title("学习Swagger")
                .description("Swagger在线文档")
                .termsOfServiceUrl("")
                .version("1.0")
                .build();
    }
}

Swagger访问地址

旧版

http://localhost:8080/swagger-ui.html

新版

http://localhost:8080/doc.html

注:只能访问controller,因为只有这一层才和前端交互,这才是swagger的作用所在。

常用注解

@Api :用在类上,说明该类的作用
@ApiImplicitParams :用在方法上包含一组参数说明
@ApiResponses :用于表示一组响应
@ApiOperation() 用于方法;表示一个http请求的操作
 * value用于方法描述
 * notes用于提示内容
 * tags可以重新分组(视情况而用)
 @ApiParam() 用于方法,参数,字段说明;表示对参数的添加元数据(说明或是否必填等)
 * name–参数名
 * value–参数说明
 * required–是否必填
@ApiModel()用于类 ;表示对类进行说明,用于参数用实体类接收
 * value–表示对象名
 * description–描述
 * 都可省略
@ApiModelProperty()用于方法,字段; 表示对model属性的说明或者数据操作更改
 * value–字段说明
 * name–重写属性名字
 * dataType–重写属性类型
 * required–是否必填
 * example–举例说明
 * hidden–隐藏
@ApiIgnore()用于类或者方法上,可以不被swagger显示在页面上 比较简单, 这里不做举例
@ApiImplicitParam() 用于方法
 * 表示单独的请求参数
@ApiImplicitParams() 用于方法,包含多个 @ApiImplicitParam
 * name–参数ming
 * value–参数说明
 * dataType–数据类型
 * paramType–参数类型

3.SpringBoot中的异步处理框架@Async

何时使用异步

大部分开发中,是使用串行执行的。但是,在一些特殊情况下,当一个业务和另外一个业务的关联性不是强耦合,执行失败或者成功都不影响它核心业务。就可以将这些业务剥离处理用异步执行。比如在用户注册中,有发送短信和发送邮件的业务逻辑

异步编程的框架:消息中间件(ActiveMQ、RabbitMQ)

如何使用异步处理框架

1、打开springboot的异步处理框架

在springboot的启动类上添加@EnableAsync,开启异步

2、定义个异步处理的注册service

service层方法上加上@Async

@Service
@Slf4j
public class RegService {

    @Async
    public void sendMsg(){
        // todo :模拟耗时5秒
        try {
            Thread.sleep(5000);
            log.info("-----发送消息-----");
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }

    @Async
    public void addScore(){
        // todo :模拟耗时5秒
        try {
            Thread.sleep(5000);
            log.info("-----处理积分-----");
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }
}

3、调用异步处理

controller层调用service的方法

@RestController
@Slf4j
public class RegController {
    @Autowired
    private RegService regService;
    @GetMapping("reg")
    public String reguser() {
        // 1: 注册用户
        log.info("新用户注册");
        //dosomething

        // 2: 发送短信
        log.info("发送短信");
        regService.sendMsg();

        // 3: 添加积分
        log.info("添加积分");
        regService.addScore();

        return "ok";
    }
}

总结

使用@Async来实现异步代码逻辑,但是这种方法还是使用java代码来实现,会通过JVM来占用内存。之后,随着业务的升级,可以使用消息中间件来进行异步处理。

4.封装统一返回的R类

将controller的返回封装成一个java类,R.java或者Result.java

成功只有一种情况,失败才有很多种情况!!!

根据自己的需要调整
注意,建议构造函数使用private(构造函数私有化
原因:让调用过程变得单一,只允许用类去调用方法,不允许用new去调用

private int code;
private String msg;
private T data;
/**
 *  成功时候的调用
 * */
public static  <T> Result<T> success(T data){
	return new Result<T>(data);
}
/**
 *  失败时候的调用
 * */
public static  <T> Result<T> error(CodeMsg codeMsg){
	return new Result<T>(codeMsg);
}

错误信息返回,集中管理

1、使用常量类来管理

private int code;
private String msg;
//通用的错误码
public static CodeMsg SUCCESS = new CodeMsg(0, "success");
public static CodeMsg SERVER_ERROR = new CodeMsg(500100, "服务端异常");
public static CodeMsg BIND_ERROR = new CodeMsg(500101, "参数校验异常:%s");
public static CodeMsg REQUEST_ILLEGAL = new CodeMsg(500102, "请求非法");
public static CodeMsg ACCESS_LIMIT_REACHED= new CodeMsg(500104, "访问太频繁!");

2、使用枚举来维护错误信息的返回

SUCCESS(0, "success"),
SERVER_ERROR(500100, "服务端异常"),
 BIND_ERROR(500101, "参数校验异常:%s"),
 REQUEST_ILLEGAL(500102, "请求非法"),
 ACCESS_LIMIT_REACHED(500104, "访问太频繁!");

 private Integer code;
 private String msg;

 EnumCodeMsg(Integer code, String msg) {
     this.code = code;
     this.msg = msg;
    }

拦截增强实现R类

可以使用SpringBoot的拦截器功能实现R类的效果,实现ResponseBodyAdvice即可。
ResponseBodyAdvice的作用是:拦截Controller方法的返回值,统一处理返回值到响应体中,一般来做response的统一格式,加密,签名等。如下:

@ControllerAdvice(basePackages = "包名")
public class ResultResponseHandler implements ResponseBodyAdvice<Object> {
    /**
     * 是否支持advice功能,true是支持 false是不支持
     * @param methodParameter
     * @param aClass
     * @return
     */
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }
    // 参数o 代表其实就是springmvc的请求的方法的结果
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        // 对请求的结果在这里统一返回和处理
        return R.success(o);
    }
}

原理:它是利用spring中的AOP机制来完成的一种,对springmvc请求过程中对请求方法的结果进行增强的一种通知。它会对你的结果进行加密,加工等处理,把加工的数据返回给浏览器。
这种方法总的来说就是在返回结果的基础上,包装上一层R类,更加规范。

5.Spring的容器注入

注入的每一个bean,都是通过beanFactory往beanDefinitionMap中注入bean,可以通过applicationContext查看

bean
所有的bean都会注册到beanDefinitonMap中,默认以类名小写作为key,对象作为value

依赖注入的几种方式

1、构造函数注入
2、set注入
3、@Autowired、@Resource注入
@Autowired和@Resource的区别
@Autowired:默认情况下是根据byType匹配。如果有多个对象,会byName匹配,详情见下图。
img
@Resource:默认byName自动装配

4、FactoryBean注入(工厂注入)

6.SpringBoot统一异常处理

什么是全局异常处理

全局异常处理就是指把整个系统的异常统一自动处理的机制,这样就可以做到不用try/catch就能进行处理项目中出现的异常。

怎么用

首先我们定义一个枚举类ResultCodeEnum ,来存储异常信息,包含success、code、message三个成员变量,通过getter方法获取。

@Getter
public enum ResultCodeEnum {
 	UNKNOWN_REASON(false, 20001, "未知错误"),
    SERVER_ERROR(false, 500, "服务器忙,请稍后在试"),
    ORDER_CREATE_FAIL(false, 601, "订单下单失败");

    private Boolean success;
    private Integer code;
    private String message;
    private ResultCodeEnum(Boolean success, Integer code, String message) {
        this.success = success;
        this.code = code;
        this.message = message;
    }
}

将异常枚举类的信息封装在ErrorHandler中,在全局异常管理中直接调用ErrorHandler的fail方法即可。

@Builder//这个注解是lombok的,作用:建造者模式调用
@AllArgsConstructor
@NoArgsConstructor
@Data
@ToString
public class ErrorHandler {
    // ErrorHandler === R 答案:不想破坏R类。
    // 异常的状态码,从枚举中获得
    private Integer status;
    // 异常的消息,写用户看得懂的异常,从枚举中得到
    private String message;
    // 异常的名字
    private String exception;
    /**
     * 对异常处理进行统一封装
     * @param resultCodeEnum 异常枚举
     * @param throwable 出现异常
     * @param message 异常的消息 null /by zero
     * @return
     */
    public static ErrorHandler fail(ResultCodeEnum resultCodeEnum, Throwable throwable, String message) {
        ErrorHandler errorHandler = ErrorHandler.fail(resultCodeEnum, throwable);
        errorHandler.setMessage(message);
        return errorHandler;
    }
    /**
     * 对异常枚举进行封装
     * @param resultCodeEnum
     * @param throwable
     * @return
     */
    public static ErrorHandler fail(ResultCodeEnum resultCodeEnum, Throwable throwable) {
        ErrorHandler errorHandler = new ErrorHandler();
        errorHandler.setMessage(resultCodeEnum.getMessage());
        errorHandler.setStatus(resultCodeEnum.getCode());
        errorHandler.setException(throwable.getClass().getName());
        return errorHandler;
    }
}

全局异常控制

全局异常管理,用于捕获或抛出异常时,跳转到GlobalExceptionHandler的makeExcepton方法,调用fail方法,返回errorHandler对象。但是,这种做法比较单一,返回的异常信息仅有一种。

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    /**
     * 对服务器端出现500异常进行统一处理
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(Throwable.class)
    public ErrorHandler makeExcepton(Throwable e, HttpServletRequest request) {
        ErrorHandler errorHandler = ErrorHandler.fail(ResultCodeEnum.SERVER_ERROR, e);
        log.error("请求的地址是:{},出现的异常是:{}", request.getRequestURL(), e);
        return errorHandler;
    }
}
  • makeExcepton方法的作用是:把运行时异常封装为ErrorHandler对象进行统一捕获处理。
  • @RestControllerAdvice和@ControllerAdvice它是对controller的增强扩展处理,而全局异常就是一种扩展能力之一。
  • @ExceptionHandler(Throwable.class) :统一处理某一类型异常,从而减少代码的出现异常的复杂度和重复率,
  • @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR):指定客户端收到的http状态码,这里配置的是500,就显示成500错误。不指定也是没问题的。因为返回是根据自己的枚举进行处理了。

自定义异常

为了解决全局异常管理存在的弊端,可以使用自定义异常。

下面以定义的业务异常为例:

@Data
public class BusinessException extends RuntimeException {

    private Integer code;
    private String message;

    public BusinessException(ResultCodeEnum resultCodeEnum) {
        this.code = resultCodeEnum.getCode();
        this.message = resultCodeEnum.getMessage();
    }
    public BusinessException(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}

在全局异常管理类GlobalExceptionHandler中,添加一个方法handlerBusinessException,对业务异常进行管理。

 /**
     * 对自定义异常进行统一处理
     */
    @ExceptionHandler(BusinessException.class)
    public ErrorHandler handlerBusinessException(BusinessException e, HttpServletRequest request) {
        ErrorHandler errorHandler = ErrorHandler.builder()
                .status(e.getCode())
                .message(e.getMessage())
                .exception(e.getClass().getName())
                .build();
        log.error("请求的地址是:{},BusinessException出现异常:{}", request.getRequestURL(), e);
        return errorHandler;
    }

当然,在返回异常信息到浏览器之前,可以在包裹上一层R类,需要使用R类拦截器

@ControllerAdvice(basePackages = "包名")
public class ResultResponseHandler implements ResponseBodyAdvice<Object> {
    /**
     * 是否支持advice功能,true是支持 false是不支持
     * @param methodParameter
     * @param aClass
     * @return
     */
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }
    // 参数o 代表其实就是springmvc的请求的方法的结果
    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        // 对请求的结果在这里统一返回和处理
        if (o instanceof ErrorHandler) {
            // 1、如果返回的结果是一个异常的结果,就把异常返回的结构数据倒腾到R.fail里面即可
            ErrorHandler errorHandler = (ErrorHandler) o;
            return R.fail(errorHandler.getStatus(), errorHandler.getMessage());
        } else if (o instanceof String) {
            // 2、因为springmvc数据转换器对String是有特殊处理 StringHttpMessageConverter
            ObjectMapper objectMapper = new ObjectMapper();
            R r = R.success(o);
            return objectMapper.writeValueAsString(r);
        }
        return R.success(o);
    }
}

7.SpringBoot集成校验器

校验器的用途

在日常的开发中,服务端对象的校验是非常重要的一个环节,校验包括前端校验和后端校验,本文只探讨后端校验。

比如在注册模块,会用到校验用户名,密码,身份证,邮箱等信息是否为空,以及格式是否正确等功能。这时候,如果有快速开发的校验框架将十分方便。

Validator框架应运而生,它的出现就是为了提升开发效率。

我们使用的Spring框架集成了校验功能,Spring的validator校验框架遵守的是JSR-303的验证规范(参数校验规范),JSP全称:Java Specification Requests缩写。

在默认情况下:SpringBoot会引入hibernate validation机制来支持JSR-303验证规范。

SpringBoot的validator校验框架支持如下特征:

  • JSR303特征:JSR303是一项标准,只提供规范不提供实现。规定一些校验规范即校验注解。比如:@Null@NotNull@Pattern。这些类都位于:javax.validation.constraints包下。
  • hibernate validation特征:hibernate validation是对JSR303规范的实现并且进行了增强和扩展。并增加了注解:@Email@Length@Range等等。
  • Spring Validation:Spring Validation是对Hibernate Validation的二次封装。在SpringMvc模块中添加了自动校验器。并将校验信息封装到特定的类中。
    validator
    从图中也可以看出,整个校验功能的体系结构。

常用的校验注解

JSR提供的校验注解:         
@Null   被注释的元素必须为 null    
@NotNull    被注释的元素必须不为 null    
@AssertTrue     被注释的元素必须为 true    
@AssertFalse    被注释的元素必须为 false    
@Min(value)     被注释的元素必须是一个数字,其值必须大于等于指定的最小值    
@Max(value)     被注释的元素必须是一个数字,其值必须小于等于指定的最大值    
@DecimalMin(value)  被注释的元素必须是一个数字,其值必须大于等于指定的最小值    
@DecimalMax(value)  被注释的元素必须是一个数字,其值必须小于等于指定的最大值    
@Size(max=, min=)   被注释的元素的大小必须在指定的范围内    
@Digits (integer, fraction)     被注释的元素必须是一个数字,其值必须在可接受的范围内    
@Past   被注释的元素必须是一个过去的日期    
@Future     被注释的元素必须是一个将来的日期    
@Pattern(regex=,flag=)  被注释的元素必须符合指定的正则表达式    
Hibernate Validator提供的校验注解:  
@NotBlank(message =)   验证字符串非null,且trim后长度必须大于0    
@Email  被注释的元素必须是电子邮箱地址    
@Length(min=,max=)  被注释的字符串的大小必须在指定的范围内    
@NotEmpty   被注释的字符串的必须非空    
@Range(min=,max=,message=)  被注释的元素必须在合适的范围内

依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

怎么用

在spring框架框架的开发中,只需要两个步骤:

  • 在需要校验的bean(entity)中的属性上增加对应注解
  • 在springmvc的方法参数中的 entity中加==@Validated==的注解即可。

建一个实体类UserVo,对user的成员变量进行校验

@Data
public class UserVo {
    @NotNull(message = "用户id不能为空")
    private Long userId;
    @NotBlank(message = "用户名不能为空")
    @Length(max = 20, message = "用户名不能超过20个字符")
    @Pattern(regexp = "^[\\u4E00-\\u9FA5A-Za-z0-9\\*]*$", message = "用户昵称限制:最多20字符,包含文字、字母和数字")
    private String username;
    @NotBlank(message = "手机号不能为空")
    @Pattern(regexp = "^[1][3,4,5,6,7,8,9][0-9]{9}$", message = "手机号格式有误")
    private String mobile;
    @NotBlank(message = "联系邮箱不能为空")
    @Email(message = "邮箱格式不对")
    private String email;
    @Future(message = "时间必须是将来时间")
    private Date createTime;
}

controller层测试

@RestController
@Api(description = "用户校验")
@RequestMapping("/user")
public class UserValiatorController {
    @PostMapping("/valiator/reg")
    public UserVo createUser(@RequestBody @Validated UserVo userVo) {
        return userVo;
    }
}

这时,如果我们在swagger中输入参数为空,会报MethodArgumentNotValidException的异常。这是因为校验失败,springmvc的validator内部会以异常的方式进行返回。报错异常就是MethodArgumentNotValidException 。而这个异常里面,会包含所有的校验提示信息。

我们肯定是想捕获异常,取出校验提示信息,并返回浏览器。那么,就用到了全局异常捕获。

    /**
     * 对验证的统一异常进行统一处理
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ErrorHandler handlerValiator(MethodArgumentNotValidException e, HttpServletRequest request) throws JsonProcessingException {
        // 1: 从MethodArgumentNotValidException提取验证失败的所有的信息。返回一个List<FieldError>
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        // 2: 把fieldErrors中,需要的部分提出出来进行返回
        List<Map<String, String>> mapList = toValidatorMsg(fieldErrors);
        // 3: 把需要的异常信息转换成json进行返回
        ObjectMapper objectMapper = new ObjectMapper();
        String mapJson = objectMapper.writeValueAsString(mapList);
        ErrorHandler errorHandler = ErrorHandler.fail(ResultCodeEnum.PARAM_ERROR, e, mapJson);
        return errorHandler;
    }

    /**
     * 对验证异常进行统一处理提取需要的部分
     *
     * @param fieldErrorList
     * @return
     */
    private List<Map<String, String>> toValidatorMsg(List<FieldError> fieldErrorList) {
        List<Map<String, String>> mapList = new ArrayList<>();
        // 循环提取
        for (FieldError fieldError : fieldErrorList) {
            Map<String, String> map = new HashMap<>();
            // 获取验证失败的属性
            map.put("field", fieldError.getField());
            // 获取验证失败的的提示信息
            map.put("msg", fieldError.getDefaultMessage());
            mapList.add(map);
        }
        return mapList;
    }

自定义校验器

当已有的校验注解不能满足开发需求时,我们可以参考源码来自定义相关注解。

比如,以定义手机Phone注解为例:

1、@Phone定义如下:

@Documented
//核心:告诉当前的注解最后会选中哪个类进行校验(选择校验规则)
@Constraint(validatedBy = PhoneValidator.class)
//该注解在哪些范围上生效,在方法和属性上是可以去定义
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Phone {
    String message() default "手机格式不正确!";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
    @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface List {
        Phone[] value();
    }
}

2、定义一个校验器PhoneValidator,要实现ConstraintValidator

public class PhoneValidator implements ConstraintValidator<Phone, String> {
    @Override
    public boolean isValid(String phonevalue, ConstraintValidatorContext constraintValidatorContext) {
        // 1: 如果用户没输入直接返回不校验,因为空的判断应该交给@NotNull去做就行了
        if (StringUtils.isEmpty(phonevalue)) {
            return true;
        }
        // 2: 如果填写手机号码就进行正则校验
        Pattern p = Pattern.compile("^(13[0-9]|14[5|7|9]|15[0|1|2|3|5|6|7|8|9]|17[0|1|6|7|8]|18[0-9])\\d{8}$");
        // 2:如果校验通过就返回true,否则返回false;
        Matcher matcher = p.matcher(phonevalue);
        return matcher.matches();
    }
    @Override
    public void initialize(Phone constraintAnnotation) {
    }
}

3、直接使用注解即可

@Data
public class UserVo {
    @NotBlank(message = "请输入phone")
    @Phone
    private String phone;
}

校验工具类ValidateUtil

/**
 * 常用的一些验证,如手机、移动号码、联通号码、电信号码、密码、座机、 邮政编码、邮箱、年龄、身份证、URL、QQ、汉字、字母、数字等
 */
public class ValidateUtil {
    /**
     * 手机号规则
     */
    public static final String MOBILE_PATTERN = "^((13[0-9])|(14[0-9])|(15[0-9])|(17[0-9])|(18[0-9]))(\\d{8})$";
    /**
     * 中国电信号码格式验证 手机段: 133,153,180,181,189,177,1700,173
     **/
    private static final String CHINA_TELECOM_PATTERN = "(?:^(?:\\+86)?1(?:33|53|7[37]|8[019])\\d{8}$)|(?:^(?:\\+86)?1700\\d{7}$)";
    /**
     * 中国联通号码格式验证 手机段:130,131,132,155,156,185,186,145,176,1707,1708,1709,175
     **/
    private static final String CHINA_UNICOM_PATTERN = "(?:^(?:\\+86)?1(?:3[0-2]|4[5]|5[56]|7[56]|8[56])\\d{8}$)|(?:^(?:\\+86)?170[7-9]\\d{7}$)";
    /**
     * 中国移动号码格式验证 手机段:134,135,136,137,138,139,150,151,152,157,158,159,182,183,184,187,188,147,178,1705
     **/
    private static final String CHINA_MOVE_PATTERN = "(?:^(?:\\+86)?1(?:3[4-9]|4[7]|5[0-27-9]|7[8]|8[2-478])\\d{8}$)|(?:^(?:\\+86)?1705\\d{7}$)";
    /**
     * 密码规则(6-16位字母、数字)
     */
    public static final String PASSWORD_PATTERN = "^[0-9A-Za-z]{6,16}$";
    /**
     * 固号(座机)规则
     */
    public static final String LANDLINE_PATTERN = "^(?:\\(\\d{3,4}\\)|\\d{3,4}-)?\\d{7,8}(?:-\\d{1,4})?$";
    /**
     * 邮政编码规则
     */
    public static final String POSTCODE_PATTERN = "[1-9]\\d{5}";
    /**
     * 邮箱规则
     */
    public static final String EMAIL_PATTERN = "^([a-z0-9A-Z]+[-|_|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
    /**
     * 年龄规则 1-120之间
     */
    public static final String AGE_PATTERN = "^(?:[1-9][0-9]?|1[01][0-9]|120)$";
    /**
     * 身份证规则
     */
    public static final String IDCARD_PATTERN = "^\\d{15}|\\d{18}$";
    /**
     * URL规则,http、www、ftp
     */
    public static final String URL_PATTERN = "http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w- ./?%&=]*)?";
    /**
     * QQ规则
     */
    public static final String QQ_PATTERN = "^[1-9][0-9]{4,13}$";
    /**
     * 全汉字规则
     */
    public static final String CHINESE_PATTERN = "^[\u4E00-\u9FA5]+$";
    /**
     * 全字母规则
     */
    public static final String STR_ENG_PATTERN = "^[A-Za-z]+$";
    /**
     * 整数规则
     */
    public static final String INTEGER_PATTERN = "^-?[0-9]+$";
    /**
     * 正整数规则
     */
    public static final String POSITIVE_INTEGER_PATTERN = "^\\+?[1-9][0-9]*$";
    /**
     * @param mobile 手机号码
     * @return boolean
     * @Description: 验证手机号码格式
     */
    public static boolean validateMobile(String mobile) {
        if (StringUtils.isEmpty(mobile)) {
            return Boolean.FALSE;
        }
        return mobile.matches(MOBILE_PATTERN);
    }
    /**
     * 验证是否是电信手机号,133、153、180、189、177
     *
     * @param mobile 手机号
     * @return boolean
     */
    public static boolean validateTelecom(String mobile) {
        if (StringUtils.isEmpty(mobile)) {
            return Boolean.FALSE;
        }
        return mobile.matches(CHINA_TELECOM_PATTERN);
    }
    /**
     * 验证是否是联通手机号 130,131,132,155,156,185,186,145,176,1707,1708,1709,175
     *
     * @param mobile 电话号码
     * @return boolean
     */
    public static boolean validateUnionMobile(String mobile) {
        if (StringUtils.isEmpty(mobile)) {
            return Boolean.FALSE;
        }
        return mobile.matches(CHINA_UNICOM_PATTERN);
    }
    /**
     * 验证是否是移动手机号
     *
     * @param mobile 手机号 134,135,136,137,138,139,150,151,152,157,158,159,182,183,184,187,188,147,178,1705
     * @return boolean
     */
    public static boolean validateMoveMobile(String mobile) {
        if (StringUtils.isEmpty(mobile)) {
            return Boolean.FALSE;
        }
        return mobile.matches(CHINA_MOVE_PATTERN);
    }
    /**
     * @param pwd 密码
     * @return boolean
     * @Description: 验证密码格式  6-16 位字母、数字
     */
    public static boolean validatePwd(String pwd) {
        if (StringUtils.isEmpty(pwd)) {
            return Boolean.FALSE;
        }
        return Pattern.matches(PASSWORD_PATTERN, pwd);
    }
    /**
     * 验证座机号码,格式如:58654567,023-58654567
     *
     * @param landline 固话、座机
     * @return boolean
     */
    public static boolean validateLandLine(final String landline) {
        if (StringUtils.isEmpty(landline)) {
            return Boolean.FALSE;
        }
        return landline.matches(LANDLINE_PATTERN);
    }
    /**
     * 验证邮政编码
     *
     * @param postCode 邮政编码
     * @return boolean
     */
    public static boolean validatePostCode(final String postCode) {
        if (StringUtils.isEmpty(postCode)) {
            return Boolean.FALSE;
        }
        return postCode.matches(POSTCODE_PATTERN);
    }
    /**
     * 验证邮箱(电子邮件)
     *
     * @param email 邮箱(电子邮件)
     * @return boolean
     */
    public static boolean validateEamil(final String email) {
        if (StringUtils.isEmpty(email)) {
            return Boolean.FALSE;
        }
        return email.matches(EMAIL_PATTERN);
    }
    /**
     * 判断年龄,1-120之间
     *
     * @param age 年龄
     * @return boolean
     */
    public static boolean validateAge(final String age) {
        if (StringUtils.isEmpty(age)) {
            return Boolean.FALSE;
        }
        return age.matches(AGE_PATTERN);
    }
    /**
     * 身份证验证
     *
     * @param idCard 身份证
     * @return boolean
     */
    public static boolean validateIDCard(final String idCard) {
        if (StringUtils.isEmpty(idCard)) {
            return Boolean.FALSE;
        }
        return idCard.matches(IDCARD_PATTERN);
    }
    /**
     * URL地址验证
     *
     * @param url URL地址
     * @return boolean
     */
    public static boolean validateUrl(final String url) {
        if (StringUtils.isEmpty(url)) {
            return Boolean.FALSE;
        }
        return url.matches(URL_PATTERN);
    }
    /**
     * 验证QQ号
     *
     * @param qq QQ号
     * @return boolean
     */
    public static boolean validateQq(final String qq) {
        if (StringUtils.isEmpty(qq)) {
            return Boolean.FALSE;
        }
        return qq.matches(QQ_PATTERN);
    }
    /**
     * 验证字符串是否全是汉字
     *
     * @param str 字符串
     * @return boolean
     */
    public static boolean validateChinese(final String str) {
        if (StringUtils.isEmpty(str)) {
            return Boolean.FALSE;
        }
        return str.matches(CHINESE_PATTERN);
    }
    /**
     * 判断字符串是否全字母
     *
     * @param str 字符串
     * @return boolean
     */
    public static boolean validateStrEnglish(final String str) {
        if (StringUtils.isEmpty(str)) {
            return Boolean.FALSE;
        }
        return str.matches(STR_ENG_PATTERN);
    }
    /**
     * 判断是否是整数,包括负数
     *
     * @param str 字符串
     * @return boolean
     */
    public static boolean validateInteger(final String str) {
        if (StringUtils.isEmpty(str)) {
            return Boolean.FALSE;
        }
        return str.matches(INTEGER_PATTERN);
    }
    /**
     * 判断是否是大于0的正整数
     *
     * @param str 字符串
     * @return boolean
     */
    public static boolean validatePositiveInt(final String str) {
        if (StringUtils.isEmpty(str)) {
            return Boolean.FALSE;
        }
        return str.matches(POSITIVE_INTEGER_PATTERN);
    }
}

Assert参数校验

Assert是断言的意思,它是Spring提供的一个工具类,在包org.springframework.util.Assert下。Web 应用在接受表单提交的数据后都需要对其进行合法性检查,如果表单数据不合法,请求将被驳回。类似的,当我们在编写类的方法时,也常常需要对方法入参进行合法性检查,如果入参不符合要求,方法将通过抛出异常的方式拒绝后续处理。

@PostMapping("/valiator/reg2")
public UserVo createUser2(String name,Integer flag) {
    Assert.isNull(name,"用户名不允许为空!");// 但是这个不明确不利于扩展
    return null;
}

8.SpringBoot整合Mybatis Plus

总结MybatisPlus的基本使用

pom依赖

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.17</version>
</dependency>
<!--mybatis-plus-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.0</version>
</dependency>

怎么用

1、创建一个实体类,映射数据库的表

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
//mybatis plus要求要写出表名
@TableName("数据库的表名")
public class User {
    // 用户编号
    //mybatis plus要求必须要有一个主键策略
    @TableId(type = IdType.AUTO)
    private Integer id;
    // 用户昵称
    private String nickname;
    // 密码
    private String password;
    // 年龄
    private Integer age;
    // 性别
    private Integer male;
    // 用户介绍
    private String userIntro;
}

2、创建一个UserMapper,要继承BaseMapper,注意:泛型传入< User >

public interface UserMapper extends BaseMapper<User> {
}

3、springboot启动类上加在启动类上增加@MapperScan("com.kuangstudy.mapper")

4、定义UserService,继承IService
定义UserServiceImpl ,继承ServiceImpl,实现UserService
注意:泛型传入<UserMapper,User>

在ServiceImpl中提供了大量的增删改查的方法,若不能能满足需求,可以在自己定义的UserService中添加。

public interface UserService extends IService<User> {
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements  UserService{
}

支持xml

yaml文件添加配置

##mybatis的原生态支持
mybatis-plus:
  mapper-locations: classpath*:/mapper/*.xml (xml文件位置)
  type-aliases-package: com.zwh.entity(包名)

mapper文件

public interface UserMapper extends BaseMapper<User> {
    User getByUserId(@Param("id") Integer id);
}

xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zwh.mapper.UserMapper">
    <select id="getByUserId" resultType="com.kuangstudy.entity.User">
        SELECT id,
           nickname,
           password,
           age,
           male,
           user_intro as userIntro
        FROM kss_user
        WHERE id = #{id}
    </select>
</mapper>

service层

public interface UserService extends IService<User> {
    User getByUserId(Integer id);
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements  UserService{
    public User getByUserId(Integer id){
        return this.baseMapper.getByUserId(id);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值