石一歌的SpringBoot笔记

运行原理探究(2.6.2)

基于狂神的springboot运行原理探究,自己操作一下 2.6.2版本

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.6.2</version>
	<relativePath/> 
</parent>

前置知识

java元注解

  • @Target 表示该注解用于什么地方。
  • @Retention 表示在什么级别保存该注解信息。
  • @Documented 将此注解包含在 javadoc 中 ,它代表着此注解会被javadoc工具提取成文档。
  • @Inherited 允许子类继承父类中的注解。

@SpringBootApplication

主启动类,主要目的是开启自动配置

@Target({ElementType.TYPE})// 元注解,该注解可修饰类,接口(包括注解类型)或enum声明 
@Retention(RetentionPolicy.RUNTIME)// 元注解,注解保留级别 VM将在运行期保留注释,可通过反射读取注解的信息
@Documented// 元注解 注解会被javadoc工具提取成文档
@Inherited// 元注解 允许子类继承父类中的注解
@SpringBootConfiguration// springboot配置注解
@EnableAutoConfiguration// 自动配置注解 核心
@ComponentScan(// 组件扫描注解
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
  	...
}

@SpringBootConfiguration

SpringBoot的配置类,继承了@Configuration,功能类似

@Target({ElementType.TYPE})// 元注解,该注解可修饰类,接口(包括注解类型)或enum声明 
@Retention(RetentionPolicy.RUNTIME)// 元注解,注解保留级别 VM将在运行期保留注释,可通过反射读取注解的信息
@Documented// 元注解 注解会被javadoc工具提取成文档
@Configuration// 配置注解 将当前类标注为配置类,配合@bean使用
@Indexed// 索引注解,为Spring的模式注解添加索引,以提升应用启动性能。
public @interface SpringBootConfiguration {
    ...
}

@EnableAutoConfiguration

开启自动配置

@Target({ElementType.TYPE})// 元注解,该注解可修饰类,接口(包括注解类型)或enum声明 
@Retention(RetentionPolicy.RUNTIME)// 元注解,注解保留级别 VM将在运行期保留注释,可通过反射读取注解的信息
@Documented// 元注解 注解会被javadoc工具提取成文档
@Inherited// 元注解 允许子类继承父类中的注解
@AutoConfigurationPackage// 自动配置包注解,启动类注解所在包的自包
@Import({AutoConfigurationImportSelector.class})// 导入自动配置导入选择器组件
public @interface EnableAutoConfiguration {
    ...
}
AutoConfigurationImportSelector

自动配置导入选择器

 protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }

调用SpringFactoriesLoader.loadFactoryNames()方法

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        ClassLoader classLoaderToUse = classLoader;
        if (classLoader == null) {
            classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
        }

        String factoryTypeName = factoryType.getName();
        return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
    }

调用SpringFactoriesLoader.loadSpringFactories()方法

 private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
        Map<String, List<String>> result = (Map)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            HashMap result = new HashMap();

            try {
                Enumeration urls = classLoader.getResources("META-INF/spring.factories");

                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        String factoryTypeName = ((String)entry.getKey()).trim();
                        String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        String[] var10 = factoryImplementationNames;
                        int var11 = factoryImplementationNames.length;

                        for(int var12 = 0; var12 < var11; ++var12) {
                            String factoryImplementationName = var10[var12];
                            ((List)result.computeIfAbsent(factoryTypeName, (key) -> {
                                return new ArrayList();
                            })).add(factoryImplementationName.trim());
                        }
                    }
                }

                result.replaceAll((factoryType, implementations) -> {
                    return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
                });
                cache.put(classLoader, result);
                return result;
            } catch (IOException var14) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
            }
        }
    }

源头

image-20211231221420074

@AutoConfigurationPackage
@Target({ElementType.TYPE})// 元注解,该注解可修饰类,接口(包括注解类型)或enum声明 
@Retention(RetentionPolicy.RUNTIME)// 元注解,注解保留级别 VM将在运行期保留注释,可通过反射读取注解的信息
@Documented// 元注解 注解会被javadoc工具提取成文档
@Inherited// 元注解 允许子类继承父类中的注解
@Import({Registrar.class})// 导入注册组件,将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器
public @interface AutoConfigurationPackage {
    ...
}

@ComponentScan

自动扫描并加载符合条件的组件或bean

总结

  • @SpringBootApplication 主配置类

    • @SpringBootConfiguration SpringBoot的配置类

      • Configuration 配置类对应spring的xml
  • @EnableAutoConfiguration springboot自动配置

    • @AutoConfigurationPackage 自动配置包

      • @import(Registrar.class) 将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器
    • @Import({AutoConfigurationImportSelector.class}) :自动配置导入选择器

      • AutoConfigurationImportSelector.getCandidateConfigurations 调用
        • SpringFactoriesLoader.loadFactoryNames 调用
          • SpringFactoriesLoader.loadSpringFactories 调用
            • META-INF/spring.factories 配置源文件
  • @ComponentScan 自动扫描并加载符合条件的组件或bean

结论:

  1. SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值
  2. 将这些值作为自动配置类导入容器 , 自动配置类生效 ,进行自动配置工作
  3. 整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中
  4. 它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件 , 并配置好这些组件

自动装配原理

//表明为配置类
@Configuration(
    proxyBeanMethods = false
)
//判断 有DataSource.class, EmbeddedDatabaseType.class,实例化
@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})
//判断 无io.r2dbc.spi.ConnectionFactory,实例化
@ConditionalOnMissingBean(
    type = {"io.r2dbc.spi.ConnectionFactory"}
)
//自动配置之前加载SqlInitializationAutoConfiguration.class
@AutoConfigureBefore({SqlInitializationAutoConfiguration.class})
//将配置文件中对应的值和DataSourceProperties绑定起来;并把DataSourceProperties加入到ioc容器中
@EnableConfigurationProperties({DataSourceProperties.class})
//导入DataSourcePoolMetadataProvidersConfiguration.class, InitializationSpecificCredentialsDataSourceInitializationConfiguration.class, SharedCredentialsDataSourceInitializationConfiguration.class
@Import({DataSourcePoolMetadataProvidersConfiguration.class, InitializationSpecificCredentialsDataSourceInitializationConfiguration.class, SharedCredentialsDataSourceInitializationConfiguration.class})
public class DataSourceAutoConfiguration {
    public DataSourceAutoConfiguration() {
    }
    ...
}

总结

  • 一但这个配置类生效;这个配置类就会给容器中添加各种组件;
  • 这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的;
  • 所有在配置文件中能配置的属性都是在xxxxProperties类中封装着;
  • 配置文件能配置什么就可以参照某个功能对应的这个属性类

Springboot启动流程

  1. SpringBoot启动加载大量的自动配置类(spring.factories)

  2. SpringBoot默认写好的自动配置类

  3. 自动配置类中配置组件

  4. 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性(用配置文件可修改)。

Yaml注入配置文件

用@ConfigurationProperties(prefix = "person")代替@Value

此注解需要导入配置文件处理器

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-configuration-processor</artifactId>
  <optional>true</optional>
</dependency>

配置javabean Person

@PropertySource(value = "classpath:person.yaml")//指定配置文件
@Component //注册bean
@ConfigurationProperties(prefix = "person")//与配置文件下person属性对应
public class Person {
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;
    
    //有参无参构造、get、set方法、toString()方法  
}

yaml文件 person.yaml

person:
  name: qinjiang${random.uuid} # 随机uuid 占位符
  age: ${random.int}  # 随机int 占位符
  happy: false
  birth: 2000/01/01
  maps: {k1: v1,k2: v2}
  lists:
   - code
   - girl
   - music
  dog:
    name: 旺财
    age: 1

数据校验

类注解@Validated

参数注解如下

空检查
@Null       验证对象是否为null
@NotNull    验证对象是否不为null, 无法查检长度为0的字符串
@NotBlank   检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
@NotEmpty   检查约束元素是否为NULL或者是EMPTY.
    
Booelan检查
@AssertTrue     验证 Boolean 对象是否为 true  
@AssertFalse    验证 Boolean 对象是否为 false  
    
长度检查
@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内  
@Length(min=, max=) string is between min and max included.

日期检查
@Past       验证 Date 和 Calendar 对象是否在当前时间之前  
@Future     验证 Date 和 Calendar 对象是否在当前时间之后  
@Pattern    验证 String 对象是否符合正则表达式的规则

多配置文件切换

2.4版本之后spring.profiles.active弃用升级到spring.config.activate.on-profile

properties

  • application.properties主配置文件选择具体配置文件

    • spring.config.activate.on-profile=dev
  • 命名格式:application-{profile}.properties)

yaml

  • 文件块区分

  • spring:
      profiles:
        active: test #选择要激活那个环境块
    ---
    server:
      port: 8082
    spring:
      config:
        activate:
          on-profile: dev
    ---
    server:
      port: 8083
    spring:
      config:
        activate:
          on-profile: test
    

配置文件优先级

优先级自上而下

  • 项目路径下的config文件夹配置文件

  • 项目路径下配置文件

  • 资源路径下的config文件夹配置文件

  • 资源路径下配置文件

  • properties

  • yaml

自定义Starter

数据源

Hikari(默认)

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
    driver-class-name: com.mysql.cj.jdbc.Driver
	type: com.zaxxer.hikari.HikariDataSource #Spring Boot 2.0 默认,无需配置
    hikari:
      maximum-pool-size: 15 #最大连接数
      minimum-idle: 5 #最小空闲连接
      connection-timeout: 60000 #连接超时时间(毫秒)
      idle-timeout: 600000 #连接在连接池中空闲的最长时间
      max-lifetime: 3000000 #连接最大存活时间
      connection-test-query: select 1 #连接测试查询
      auto-commit: true #自动提交行为
      pool-name: HikariCPDataSource

Druid

传统配置

pom

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.6</version>
        </dependency>

application.yaml

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://127.0.0.1:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource

    #druid 数据源专有配置,Spring Boot无法解析,自己绑定
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true

    #配置监控统计拦截的filters,stat:监控统计 log4j:日志记录 wall:防御sql注入
    #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
    #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

DruidConfig.java

Druid配置文件:绑定druid专有配置,设置监控及其过滤器

@Configuration
public class DruidConfig {
    //绑定配置文件
    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource druidDataSource() {
        return new DruidDataSource();
    }
    
    //配置 Druid 监控管理后台的Servlet;
	//内置 Servlet 容器时没有web.xml文件,所以使用 Spring Boot 的注册 Servlet 方式
	@Bean
	public ServletRegistrationBean statViewServlet() {
    	ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");

        // 这些参数可以在 com.alibaba.druid.support.http.StatViewServlet 
        // 的父类 com.alibaba.druid.support.http.ResourceServlet 中找到
        Map<String, String> initParams = new HashMap<>();
        initParams.put("loginUsername", "admin"); //后台管理界面的登录账号
        initParams.put("loginPassword", "123456"); //后台管理界面的登录密码

        //后台允许谁可以访问
        //initParams.put("allow", "localhost"):表示只有本机可以访问
        //initParams.put("allow", ""):为空或者为null时,表示允许所有访问
        initParams.put("allow", "");
        //deny:Druid 后台拒绝谁访问
        //initParams.put("kuangshen", "192.168.1.20");表示禁止此ip访问

        //设置初始化参数
        bean.setInitParameters(initParams);
        return bean;
	}
    //配置 Druid 监控 之  web 监控的 filter
    //WebStatFilter:用于配置Web和Druid数据源之间的管理关联监控统计
    @Bean
    public FilterRegistrationBean webStatFilter() {
        FilterRegistrationBean bean = new FilterRegistrationBean();
        bean.setFilter(new WebStatFilter());

        //exclusions:设置哪些请求进行过滤排除掉,从而不进行统计
        Map<String, String> initParams = new HashMap<>();
        initParams.put("exclusions", "*.js,*.css,/druid/*,/jdbc/*");
        bean.setInitParameters(initParams);

        //"/*" 表示过滤所有请求
        bean.setUrlPatterns(Arrays.asList("/*"));
        return bean;
    }
}

starter

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    url: jdbc:mysql://localhost:3306/test01
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
  	druid:
        # Druid数据源配置
        # 初始连接数
        initialSize: 5
        # 最小连接池数量
        minIdle: 10
        # 最大连接池数量
        maxActive: 20
        # 配置获取连接等待超时的时间
        maxWait: 60000
        # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
        timeBetweenEvictionRunsMillis: 60000
        # 配置一个连接在池中最小生存的时间,单位是毫秒
        minEvictableIdleTimeMillis: 300000
        # 配置一个连接在池中最大生存的时间,单位是毫秒
        maxEvictableIdleTimeMillis: 900000
        # 配置检测连接是否有效
        validationQuery: SELECT 1
        #申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
        testWhileIdle: true
        #配置从连接池获取连接时,是否检查连接有效性,true每次都检查;false不检查。做了这个配置会降低性能。
        testOnBorrow: false
        #配置向连接池归还连接时,是否检查连接有效性,true每次都检查;false不检查。做了这个配置会降低性能。
        testOnReturn: false
        #打开PsCache,并且指定每个连接上PSCache的大小
        poolPreparedStatements: true
        maxPoolPreparedStatementPerConnectionSize: 20
        #配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
        filters: stat,wall,log4j
        #合并多个DruidDatasource的监控数据
        useGlobalDataSourceStat: true
        #通过connectProperties属性来打开mergesql功能罗慢sQL记录
        connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500;
        #开启监控页,设置账号密码
        stat-view-servlet:
			enabled: true
			login-password: 123456
			login-username: admin 
        #设置web过滤,过滤一些不必要的网页
        web-stat-filter:
			enabled: true
			url-pattern: /*
			exclusions: *.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*

整合mybatis

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.0</version>
</dependency>
mybatis:
	config-locations: classpath:mybatis/mybatis-config.xml  
	mapper-locations: classpath:mybatis/mapper/*.xml  
	type-aliases-package: com.nuc.pojo  

Web开发

静态资源处理

默认配置(resources文件夹之下)

"classpath:/META-INF/resources/"
"classpath:/resources/"
"classpath:/static/"
"classpath:/public/"

手动指定

spring:
	resources:
		static-locations: classpath:/coding/,classpath:/kuang/

首页处理

静态资源文件夹下的所有 index.html 页面;被 /** 映射

图标

  • 静态资源文件夹下自定义favicon.ico, 常放置在public文件夹下

  • 关闭springboot默认图标

    spring:
    	mvc:
    		favicon:
    			enabled: false
    

Thymeleaf

无需配置

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

语法

  • 命名空间

    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    
  • 类比jsp

    1418974-20200318132240409-1760266878

国际化

  • resources文件夹新建i18n文件夹

  • 其中新建properties文件

    命名格式 xxx.properties, xxx_en_US.properties, xxx_zh_CN.properties

  • 右击资源包,可以添加新的属性文件

  • 双击资源包,进入国际化视图,可以快速添加新属性

  • 配置路径

    spring:
    	messages:
    		basename: i18n.login
    
  • Thymeleaf获取国际化值 #

  • 前端链接修改

    <a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a>
    <a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>
    
  • 后端组件处理

    public class MyLocaleResolver implements LocaleResolver {
    
        //解析请求
        @Override
        public Locale resolveLocale(HttpServletRequest request) {
    
            String language = request.getParameter("l");
            Locale locale = Locale.getDefault(); // 如果没有获取到就使用系统默认的
            //如果请求链接不为空
            if (!StringUtils.isEmpty(language)){
                //分割请求参数
                String[] split = language.split("_");
                //国家,地区
                locale = new Locale(split[0],split[1]);
            }
            return locale;
        }
    
        @Override
        public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
        }
    }
    
  • web配置中注册bean

        @Bean
        public LocaleResolver localeResolver() {
            return new MyLocaleResolver();
        }
    

Swagger

swagger-ui

  • pom

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

    @Configuration //配置类
    @EnableSwagger2// 开启Swagger2的自动配置
    public class SwaggerConfig {
        @Bean
        public Docket docket(Environment environment) {
            Profiles of = Profiles.of("dev", "test");
            // 判断当前是否处于该环境
            // 通过 enable() 接收此参数判断是否要显示
            boolean swaggerEnable = environment.acceptsProfiles(of);
            return new Docket(DocumentationType.SWAGGER_2)
                    .apiInfo(apiInfo())
                    .enable(swaggerEnable) // 配置是否启用Swagger,如果是false,在浏览器将无法访问
                    .select()// 通过.select()方法,去配置扫描接口,RequestHandlerSelectors配置如何扫描接口
                    .apis(RequestHandlerSelectors.basePackage("com.nuc.controller.controller"))// RequestHandlerSelectors配置如何扫描接口
                    .paths(PathSelectors.ant("/nuc/**")) // 配置如何通过path过滤,即这里只扫描请求以/nuc开头的接口
                    .build();
        }
    
        private ApiInfo apiInfo() {
            Contact contact = new Contact("石一歌", "http://xxx.xxx.com/shiyge", "联系人邮箱");
            return new ApiInfoBuilder()
                    .title("XX服务后端API")
                    .description("XX服务专用API,其他系统请勿调用!")
                    .version("1.0")
                    .termsOfServiceUrl("http://www.springboot.vue.com")
                    .contact(contact)
                    .license("Apach 2.0 许可")
                    .licenseUrl("许可链接").build();
        }
    }
    
  • 搭配使用的注解

    • @Api:作用于类上,标识此类是Swagger的资源。
    • @ApiOperation:主要作用于方法上,用于对一个接口进行说明。
    • @ApiParam:用于方法,参数,字段上,用于对参数进行说明。
    • @ApiModel:作用于类上,主要用于实体类当接口参数时使用,对实体类进行说明。
    • @ApiModelProperty:作用于方法和字段上,一般用于实体类的属性说明。
  • 举例

    • 实体类

      @ApiModel(value = "管理员实体")
      @Data
      public class AdminDTO {
          @ApiModelProperty(value = "用户ID", required = true, example = "1548w4dwf7as1a21cv4")
          private String personId;
          @ApiModelProperty(value = "用户名", example = "陈皮")
          private String name;
          @ApiModelProperty(value = "用户年龄", required = true, example = "18")
          private Integer age;
      }
      
    • 接口类

      @Api(tags = {"管理员相关"})
      @RestController
      @RequestMapping("admin")
      public class AdminController {
          @ApiOperation(value = "添加管理员", notes = "注意:只有管理员权限才能添加管理员", produces = "application/json",
                  consumes = "application/json")
          @PostMapping("add")
          public AdminDTO add(@ApiParam(value = "参数体", required = true) @RequestBody AdminDTO adminDTO) {
              return adminDTO;
          }
          @ApiOperation(value = "管理员列表", notes = "注意:只有管理员权限才能获取管理员列表", produces = "application/json")
          @GetMapping("list")
          public List<AdminDTO> list(
                  @ApiParam(value = "页码,从1开始,1,2,3...", required = true,
                          example = "1") @RequestParam Integer pageIndex,
                  @ApiParam(value = "页量", required = true,
                          example = "10") @RequestParam Integer pageSize) {
              return new ArrayList<>();
          }
      }
      

Knife4J(推荐)

目前已经发行的Knife4j版本,其本身已经引入了springfox,所以我们不需要再单独引入Springfox的具体版本,否则会导致版本冲突。注意,使用Knife4j2.0.6及以上的版本,SpringBoot的版本必须大于等于2.2.x

pom

              <dependency>
                    <groupId>com.github.xiaoymin</groupId>
                    <artifactId>knife4j-spring-boot-starter</artifactId>
                    <version>3.0.3</version>
                </dependency>

Layui-ui

pom

              <dependency>
                    <groupId>com.github.caspar-chen</groupId>
                    <artifactId>swagger-ui-layer</artifactId>
                    <version>1.1.3</version>
                </dependency>

mg-ui

pom

              <dependency>
                    <groupId>com.zyplayer</groupId>
                    <artifactId>swagger-mg-ui</artifactId>
                    <version>2.0.1</version>
                </dependency>

异步任务

  • @Async

    该注解加在异步方法上,告诉springboot,该方法为异步方法

  • @EnableAsync

    该注解加在主启动类上,开启异步注解功能

定时任务

  • @Scheduled

    该注解加在定时方法上,告诉springboot,该方法为定时方法

    配合cron表达式使用,插一句,云服务器上跑脚本也常常用cron表达式

    @Scheduled(cron = "0 * * * * 0-7")
    

    alt text

    alt text

  • @EnableScheduling

    该注解加在主启动类上,开启定时任务功能

邮件任务

  • pom

    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>
    
  • yaml

    # qq需要配置ssl
    spring: 
    	mail:
    		username: 24736743@qq.com
    		password: qq授权码
    		host: smtp.qq.com
    		properties:
    			mail:
    				smtp:
    					ssl:
    						enable: true
    
  • 简单使用

    @Autowired
    JavaMailSenderImpl mailSender;
    
    @Test
    public void contextLoads() {
       //简单邮件
       SimpleMailMessage message = new SimpleMailMessage();
       message.setSubject("标题");
       message.setText("正文");
       message.setTo("收信地址");
       message.setFrom("发信地址");
       mailSender.send(message);
    }
    
    @Test
    public void contextLoads2() throws MessagingException {
       //复杂邮件
       MimeMessage mimeMessage = mailSender.createMimeMessage();
       MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
       helper.setSubject("标题");
       helper.setText("正文(可使用富文本)",true);
       helper.addAttachment("1.jpg",new File(""));//发送附件
       helper.setTo("收信地址");
       helper.setFrom("发信地址");
       mailSender.send(mimeMessage);
    }
    

富文本编辑器

Dubbo + Zookeeper

SpringSecurity

Shiro

posted @ 2022-01-03 19:45  Faetbwac  阅读(151)  评论(0编辑  收藏  举报