Basic knowledge with spring boot

Spring Boot

structure

Spring Boot 注解

Spring Boot 注解

目前刚入手,也不会ssm的bean那套,听说spring boot只需要会用类的注解就可以,不需要在xml里面配置bean,所以就记录一下常用的注解。资料来自于JavaGuide

注解原理

Spring Boot 利用 AOP 和 依赖注入(DI) 机制来实现注解驱动的功能,具体地,它是通过以下步骤进行处理的:

  1. 扫描注解: Spring Boot 在启动时会扫描所有 Bean 定义,找到被注解标记的类和方法。
  2. 创建动态代理对象: 对于标记了 @Transactional 这样的注解的方法,Spring 会使用动态代理技术生成一个代理对象,对该方法进行拦截。一般注解会由在JVM中nio-x线程的ThreadLocal中的管理器给管理
  3. 拦截执行: 当该方法被调用时,动态代理对象会拦截方法调用,并在方法执行前执行事务开启操作,并在方法执行后进行事务提交或回滚操作。

Spring Boot 常用注解

  1. @SpringBootApplication 这个注解是SpringBoot的核心注解,可以标注在启动类上(会默认加在主类上),SpringBoot会自动扫描该类所在的包及其子包下所有的类。并且这玩意由三个注解组合而成:

    1. @EnableAutoConfiguration:启用 SpringBoot 的自动配置机制。触发Spring Boot的自动配置特性,即根据classpath(类路径)下的jar包,自动配置程序所需的bean。
    2. @ComponentScan:扫描被@Component (@Repository,@Service, @Controller)注解的 bean,注解默认会扫描该类所在的包下所有的类。
    3. @Configuration:允许在 Spring 上下文中注册额外的 bean 或导入其他配置类
  2. @Bean
    放在启动类的方法的上面, 把方法的返回值对象,注入到spring容器中。

  3. @Autowired
    加在类的method上,通过容器自动注入bean。当然如果某个类基本都被加@Autowired,那么可以直接加在类上。

  4. @Component,@Mapper,@Service, @Controller
    @Component:通用的注解,标记某个代码段使得容器可以扫描到它,从而成为 Spring 组件。如果一个 Bean 不知道属于哪个层,可以使用@Component 注解标注。而下面这三个其实都是它的衍生注解。放在类的上面,创建此类的对象,放入到容器中。
    @Mapper: 让MyBatis找到接口, 创建它的代理对象。
    @Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。一般标注在Service层。
    @Controller : 对应 Spring MVC 控制层,主要用于接受用户请求并调用 Service 层返回数据给前端页面。一般标注在Controller层。

  5. @RestController (@Controller + @ResponseBody)
    @RestController 注解相当于 @Controller@ResponseBody 注解的组合,可以将返回值直接写入 HTTP 响应体中。现在很少裸用@Controller,一般都是用@RestController。

  6. Scope
    @Scope 注解用于指定 Spring Bean 的作用域(生命周期),共有以下几种:

    • singleton:单例模式,Spring 容器中只会存在一个 Bean 实例。
    • prototype:原型模式,每次调用getBean()方法时,都会返回一个新的 Bean 实例。
    • request:请求作用域,每个 HTTP 请求都会产生一个新的 Bean 实例,仅适用于 Web 应用。
    • session:会话作用域,每个 HTTP 会话都会产生一个新的 Bean 实例,仅适用于 Web 应用。
    • global-session:全局会话作用域,一般用于 Portlet 应用。
    • websocket:WebSocket 作用域,每个 WebSocket 会话都会产生一个新的 Bean 实例,仅适用于 WebSocket 应用。
  7. @Configuration
    @Configuration 注解用于将类声明为 Spring 配置类,可以用来注册 Bean。也可以用@Component代替。表示这是个配置类,相当于xml配置文件。

  8. HTTP 请求

    1. 总结来说 Get获取特定数据,Post创建新数据,Put更新数据,Delete删除特定数据。
    2. @GetMapping, @PostMapping, @PutMapping, @DeleteMapping
      这几个注解用于映射 HTTP 请求方法和 URL。
    3. @PathVariable
      用于绑定 URL 路径参数到方法参数。
    4. @RequestParam
      用于绑定请求参数到方法参数。
    5. @RequestBody
      用于绑定请求体中的 JSON 数据到方法参数。(Json -> Java)
    6. @RequestHeader
      用于绑定请求头信息到方法参数。
    7. @ResponseBody
      用于将方法的返回值直接写入 HTTP 响应体中。表示方法的返回值是数据,而不是视图。
  9. 读取配置信息

    1. @Value
      用于读取简单的配置信息
    2. @ConfigurationProperties
      用于读取复杂的配置信息,将配置文件中的属性映射到 bean 的属性上。
  10. 校验

1.  `@NotNull` 被注释元素不能为null
2.  `@NotEmpty` 被注释的字符串不能为空
3.  `@NotBlank` 被注释的字符串不能为空并且必须包含一个非空白字符
4.  `@Email` 被注释的字符串必须是有效的电子邮件地址
5.  `@Pattern` 被注释的字符串必须匹配指定的正则表达式,
6.  `@Positive` 被注释的元素必须是一个正数
7.  `@Max(value)` 被注释的元素必须小于等于value
8.  `@Min(value)` 被注释的元素必须大于等于value
9.  `@DecimalMax` `@DecimalMin` 类似同上
10.  `@Size(max=, min=)` 被注释的元素的大小必须在min和max之间
11.  `@Past` 被注释的元素必须是一个过去的日期
12.  `@Future` 被注释的元素必须是一个将来的日期
13.  `@PastOrPresent` `@FutureOrPresent` 同上
14.  `@Range` 被注释的元素必须在指定的范围内
15.  `@Valid` 被注释的元素必须是一个合法的对象
16.  `@Validated` 被注释的元素必须是一个合法的对象,并且应用 Bean Validation 验证规则
  1. JPA (Java Persistence API) 即数据库相关
1.  `@Entity`声明一个类对应一个数据库实体。
2.  `@Table` 设置表名
3.  `@Id` 设置主键
4.  `@GeneratedValue` 设置主键生成策略,如AUTO(数据库默认), IDENTITY(数据库自增长), SEQUENCE(序列), TABLE(通过特定的表)
5.  `@Column` 设置列名和类型
6.  `@Transient` 声明属性不映射到数据库表
7.  `@Lob` 声明一个大字段,比如图片、视频等
8.  `@enumerated` 设置枚举类型
9.  `@Transacional` 声明事务,具体用来配置事务传播属性。
    1.  对于Transactional这个事务注解,常用的就是**ROLLBACK\_FOR(默认)**、REQUIRED、REQUIRES\_NEW、NEVER、MANDATORY这几个属性。ROLLBACK\_FOR表示遇到运行时异常,事务回滚,里面**一般填写Exception.class**;REQUIRED表示遇到运行时异常,事务不回滚,继续运行;REQUIRES\_NEW表示遇到运行时异常,开启一个新的事务,继续运行;NEVER表示不管遇到什么异常,都不开启事务;MANDATORY表示必须开启事务,如果没有事务,就抛出异常。
  1. @Slf4j 日志注解,可以自动生成日志对象。打印日志时,可以直接使用log.info()等方法。

  2. @ActiveProfiles 作用于测试类种,用于指定激活的配置文件,默认使用 application.properties。

  3. @Test 作用于测试方法,对一个method进行测试声明,用于声明测试用例。

  4. @Transactional 作用于方法上,声明一个事务,用于测试事务相关的操作。

  5. Mock相关:Mock是一种测试技术,可以模拟一个对象,使其在测试中可以替代真实的对象。Spring Boot中提供了Mock相关的注解,包括:

*   @Mock 用于创建Mock对象
*   @Spy 用于创建Spy对象
*   @InjectMocks 用于注入Spy对象到被测试对象中
*   @MockBean 用于创建Mock对象并注入到Spring容器中

Spring Boot 3 项目创建

这个真的踩了好多坑,跟着网上教程好久一步步来都能报错

  1. maven源设置

这个可搞可不搞,不能科学上网的话,搞一个下载速度提示还是比较显著的。

这个在maven安装目录下的setting.xml文件中设置,在标签下添加如下代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13


<mirror>

    <id>aliyunmaven</id>

    <mirrorOf>*</mirrorOf>

    <name>阿里云公共仓库</name>

    <url>https://maven.aliyun.com/repository/public</url>

</mirror>
  1. 项目创建

这个start.spring.io源不建议换,project name随你,jdk版本也随便,按照它的来

  1. 依赖选择

这里就算你要改spring boot的版本,你别急待会可以改的。基本常用的依赖就这几个,mybatis-plus的依赖进去了再加。

  1. 导入MySQL数据库

  1. 修改spring boot版本

pom.xml文件中修改版本号

比如我创建的时候是3.3多,现在随便改

这个需要注意,springboot应该是更新的快,然后mybatis-plus是来不及更新,所以遇到类似这样的报错,你可以尝试把spring boot的版本降低。

1
2
3


java.lang.IllegalArgumentException: Invalid value type for attribute 'factoryBeanObjectType': java.lang.String
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
  <parent>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-parent</artifactId>

    <version>3.2.6</version>

    <relativePath/> <!-- lookup parent from repository -->

  </parent>

附上修改maven依赖的下载位置,如何改变防止C盘爆红

  1. 添加mybatis-plus依赖

添加到pom.xml文件中,改完记得刷新maven

注意这个版本号千万不能错,mybaits-plus的3.5.7版本对应spring-boot的3.2.6版本,如果你用的版本不一样,记得改。这个你可以去GitHub上查查。

1
2
3
4
5
6
7
8
9
    <dependency>

      <groupId>com.baomidou</groupId>

      <artifactId>mybatis-plus-boot-starter</artifactId>

      <version>3.5.7</version>

    </dependency>
  1. 修改application.properties文件

这里我不确定跟步骤4是否重复,但是我只做4好像会报错。

首先,修改为yml文件,因为这个可读性什么的都比properties好。然后添加数据库源的设置。

  1. 测试运行

到这里就成功啦,去浏览器访问http://localhost:8080/试试吧。

这里还有一个Warning是因为还没有具体设置。

Mybatis

官方文档: Mybatis-Plus, Mybatis-Plus-Join

个人觉得看官方文档大于看那些杂七杂八的视频,真的文档半个小时学会所有语法,看那些什么黑马啊,几个小时你还用不明白。就算忘记了,也可以去文档,就跟小时候查字典一样,哪里不会查哪里,越用越熟的。

先来概述一波,搞java后端说白了就是玩数据库的(并把操控的接口暴露给前端使用)。而为了要能在Spring Boot框架下的Java项目操控DB,就需要JDBC,它使得我们可以在Java代码中直接操作数据库。但是,问题在于JDBC还是很复杂,我们进行了简化就有了基于ORM框架的Mybatis。

你先别急,还有但是,Mybatis其实还是不够简单,为了照顾”低能”的Java程序员,我们连SQL语句都不想打怎么办,就出现了Mybatis Plus,有了它我们甚至只需要用它的封装库,就可以对数据库单表进行CRUD操作。

但是,事情还没完,Java程序员发现,对于多表查询(Join)和分页处理(一个表可能放不下输出),MP还是需要SQL语句的编写,所以引入了Mybatis Plus Join和Mybatis Plus Extension。它们前者可以进行join操作,后者可以进行分页处理。

但是,这是最后一个但是了。Java程序员一想,SQL语句可以不用写了,我连代码都不想写了,反正Entity和Mapper都是固定的,为什么不能一键生成代码呢?于是MybatisX就出现了,它能根据你数据库的形式,自动生成代码,包括Entity,Mapper,XML。

导入依赖

我本地用的是Spring Boot 3.1.6, Java 17。在pom.xml中引入依赖:

Mybatis-Plus

1
2
3
4
5
6
7
8
9
        <dependency>

            <groupId>com.baomidou</groupId>

            <artifactId>mybatis-plus-boot-starter</artifactId>

            <version>3.5.7</version>

        </dependency>

Mybatis-Plus-Extension

1
2
3
4
5
6
7
8
9
        <dependency>

            <groupId>com.baomidou</groupId>

            <artifactId>mybatis-plus-extension</artifactId>

            <version>3.5.7</version>

        </dependency>

Mybatis-Plus-Join

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
        <!-- https://mvnrepository.com/artifact/com.github.yulichang/mybatis-plus-join -->

        <dependency>

            <groupId>com.github.yulichang</groupId>

            <artifactId>mybatis-plus-join</artifactId>

            <version>1.4.13</version>

        </dependency>

安装插件

配置文件

  1. 配置application.yml以连接到数据库

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    
    
    datasource:
    
        url: spring.application.name=bank-simulation
    
        driver-class-name: com.mysql.cj.jdbc.Driver
    
        name: root
    
        password: 123456
    
  2. 在根包下创建包config,然后创建MybatisPlusConfig.java。这个很无脑的,只要你用的MySQL基本这样能应对99%的情况,如果不是的话,你换成你用的其他DB也可以的。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    
    
    @Configuration
    
    // @MapperScan("org.tsu.banksimulation.mapper")
    
    public class MybatisPlusConfig {
    
        @Bean
    
        public MybatisPlusInterceptor mybatisPlusInterceptor() {
    
            MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
    
            return interceptor;
    
        }
    
    }
    
  3. 右侧栏的Datasource导入就不赘述,之前讲过而且很简单。

生成代码

MyBatisX大显身手

效果很惊艳的,我就不放图了

MPJ微调

这些都放心调就行了,因为这些MPJ开头的类都是扩展自Base开头的MP类,所以后者有的,前者不会拉下。

  1. 将所有mapper文件做调整,获取MPJ的接口实现(必须),而且记得加这个注解,不加的话,任何test测试都会报错
1
2
3
4
5
6
7


@Mapper

public interface UserMapper extends MPJBaseMapper<User> {

}
  1. 将所有service文件做调整,获取MPJ的接口实现(可选)
1
2
3
4
5
6
7


public interface UserService extends MPJBaseService<User> {

    // 添加接口

}
  1. 将所有serviceImpl文件做调整,获取MPJ的接口实现(可选)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11


@Service

public class UserServiceImpl extends MPJBaseServiceImpl<UserMapper, User>

    implements UserService{

    // 添加实现

}

总结

再提一点我的个人体验,MP和MybatisX是我平时一直用的,但是这俩仅限于单表CRUD操作,对于多表查询和分页处理,还是需要SQL语句的编写。

而MPJ我感觉其实并不好用,不如你直接去Mapper里面直接用SQL语句实现,其实写个SQL并没有很难。而且最主要的一点是,如果你select的字段同时在两个表的话,就需要多出一个entity类去装结果字段,而且这个result实体类得跟select的字段一一对应,少一个就不显示,多一个就永远为null。况且Join类的多表操作其实并不多,它的效率问题就注定了频率不可能很高。

但是MPJ你装了肯定无伤大雅的,它是对MP的扩展,MP有的它都有的,万一用到了对吧,而且它的封装更好听更规范。

Wrapper这个概念在MP里面也算是重点了,我的经验是抛弃所有普通Wrapper,只用LambdaWrapper,不论你是单纯查询还是更新。二者区别就是,前者来做判断是用字段名称的String形式区分,后者调用实体类的方法来区分,前者你可能记错,后者不可能对错。

而在MPJ里面,只有MPJLambdaWrapperMPJQueryWrapper。这里老样子我还是建议使用前者,不同点在于后者是要写SQL语句的,前者可以用Class::GetMethod的办法,因为你都用这些插件了,还用SQL不是脱裤子放屁吗。

Spring Boot整合knife4j

最近在开发新项目,在整合Swagger的时候出现了很多问题,踩了很多坑,特此记录一下。

首先最需要提的springfox这个其实已经过时了,从Maven Repository上次更新就可以看出,swagger已经停止更新了四年之久。

而网上比如去搜swagger的使用,比如国内经常鼓吹的StackOverFlow网站,上面就说了让我们去用springfox-boot-starter这个依赖,但是它仍然不是一个较好的解决方案。而且比如我使用的是阿里云的仓库,出于国内直连网速的限制,阿里云的maven仓库甚至没有新的(3.0.0)版本的swagger2。

所以我开始探索,现在的主流方案是怎么样的。先叠个甲,还是有很多公司在用swagger的老版本,那当然是可以用的,还有些公司可能直接用apifox,我也觉得蛮好用的。

官方文档

其实Knife4j的官方文档写的挺详细的,挺不错的。quick-start

引入依赖

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11


<dependency>

    <groupId>com.github.xiaoymin</groupId>

    <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>

    <version>4.4.0</version>

</dependency>

配置application.yml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35


# springdoc-openapi项目配置

springdoc:

  swagger-ui:

    path: /swagger-ui.html

    tags-sorter: alpha

    operations-sorter: alpha

  api-docs:

    path: /v3/api-docs

  group-configs:

    - group: 'default'

      paths-to-match: '/**'

      packages-to-scan: com.xiaominfo.knife4j.demo.web

# knife4j的增强配置不需要增强可以不配

knife4j:

  enable: true

  setting:

    language: zh_cn

编写Controller

大概规则就是在Controller类上加注解@Tag(name = "xxx")用来注释类,在类内方法上加注解@Operation(summary = "xxx")用来注释方法,然后在类内方法上加注解@Parameter(name = "xxx", description = "xxx", in = ParameterIn.QUERY/path, required = true)用来注释参数。

启动项目

  1. 先启动我们的Spring Boot项目,默认端口是8080。
  2. 访问http://localhost:8080/swagger-ui.html,可以看到Swagger的页面。这个是我们在application.yml中配置的路径。
  3. 点击接口,可以看到接口的详细信息。

踩坑记录

  1. 如果出现依赖问题,则mvn clean install清一下nexus缓存。还不行,则清一下IDEA的缓存,运行File -> Invalidate Caches / Restart...来清理缓存、重启项目。如果还不行,就直接把maven本地的依赖全部整个删除,重装整个项目的依赖。
  2. swagger3.0.0已不再维护,别用。至于网上说的,什么wagger-ui和swagger二合一的解决方案,别试。
  3. swagger2.10.x版本的@EnableSwagger2注解被废弃了,改成@EnableSwagger2WebMvc注解。
If you have any questions, please contact me via the repo. Issues are welcome.
Built with Hugo
Theme Stack designed by Jimmy