tulip notes
首页
  • 学习笔记

    • 《Vue》
  • 踩坑日记

    • JavaScript
  • MQ
  • Nginx
  • IdentityServer
  • Redis
  • Linux
  • Java
  • SpringBoot
  • SpringCloud
  • MySql
  • docker
  • 算法与设计模式
  • 踩坑与提升
  • Git
  • GitHub技巧
  • Mac
  • 网络
  • 项目构建合集
  • 一些技巧
  • 面试
  • 一些杂货
  • 友情链接
  • 项目发布
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Star-Lord

希望一天成为大师的学徒
首页
  • 学习笔记

    • 《Vue》
  • 踩坑日记

    • JavaScript
  • MQ
  • Nginx
  • IdentityServer
  • Redis
  • Linux
  • Java
  • SpringBoot
  • SpringCloud
  • MySql
  • docker
  • 算法与设计模式
  • 踩坑与提升
  • Git
  • GitHub技巧
  • Mac
  • 网络
  • 项目构建合集
  • 一些技巧
  • 面试
  • 一些杂货
  • 友情链接
  • 项目发布
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 探索SpringBoot

  • 常用功能实现

    • SpringBoot常用功能实现_1
      • 1.SpringBoot中处理跨域问题
        • 使用注解 @CrossOrigin[局部]
        • 通过配置文件【全局配置】
      • 2.整合Druid
      • 3.整合swagger
        • 引入对应pom
        • 为项目开启swagger
        • 问题与解决
        • 访问
        • 为接口添加信息
      • 4.整合validation数据校验
        • 首先引入pom坐标
        • 对数据进行添加校验
        • 运行与实验
      • 6.定时器_@EnableScheduling
      • 7.集成邮件
      • 8.异步调用
        • 开启异步
        • 线程池与异步
    • SpringBoot中拦截器与日志
    • 多环境配置与数据绑定
    • 异步方法(线程池)的实现
    • controller参数接收
    • SpringBoot中关于日志的更好使用
    • 异常捕获的一些细节
    • 时间跟其他数据的序列化
    • 面向切面跟自定义注解的结合
  • Security认证授权

  • 扩展

  • 实战与注意事项

  • 其它

  • 《SpringBoot》笔记
  • 常用功能实现
EffectTang
2023-11-12
目录

SpringBoot常用功能实现_1

# SpringBoot常用功能实现_1

# 1.SpringBoot中处理跨域问题

跨域问题(Cross-Origin Resource Sharing,CORS):当前发起请求的域与该请求指向的资源所在的域不一样,凡是发送请求的url的 协议、域名、端口号三者之间任意一者与当前页面地址不同的请求。

同域:简单的解释就是域名相同,端口相同,协议相同

解决方法;

# 使用注解 @CrossOrigin[局部]

用在某个方法上 则该方法 跨域,用在某个类上 则该类下的所有方法 跨域

@CrossOrigin(origins = "http://192.168.1.10:8080", maxAge = 3600)
@RequestMapping("/index")
@RestController
public class IndexController{
    .......
}
//@CrossOrigin这个注解在controller类中使用,
// 就可以指定该controller中所有方法都能处理来自http:19.168.1.10:8080中的请求。
1
2
3
4
5
6
7
8

# 通过配置文件【全局配置】

创建一个实现接口 WebMvcConfigurer 的配置类(或者继承WebMvcConfigurerAdapter),并覆盖其 addCorsMappings() 方法:

@Configuration
public class CorsConfig implements WebMvcConfigurer {

   @Override
   public void addCorsMappings(CorsRegistry registry) {
     registry.addMapping("/**")
                // 设置允许跨域请求的域名
                .allowedOriginPatterns("*")
                // 是否允许证书(cookies)
                .allowCredentials(true)
                // 设置允许的方法
                .allowedMethods("*")
                // 跨域允许时间
                .maxAge(3600);
   }
}
// 在一些旧版本中 继承WebMvcConfigurerAdapter 高一些的版本中已被抛弃
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Configuration
public class CorsConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowCredentials(true)
                .allowedMethods("GET", "POST", "DELETE", "PUT")
                .maxAge(3600);
    }
}
1
2
3
4
5
6
7
8
9
10
11

在一些旧版本中 继承WebMvcConfigurerAdapter 高一些的版本中已被抛弃

# 2.整合Druid

Druid 是阿里巴巴开源平台上一个数据库连接池实现,结合了 C3P0、DBCP 等 DB 池的优点,同时加入了日志监控。

在springboot中切换数据源非常简单,在引入对应pom坐标后,只需要在配置文件中指定 spring.datasource.type为我们指定的类型就好了。

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid-spring-boot-starter</artifactId>
  <version>1.1.22</version>
</dependency>
1
2
3
4
5

引入druid-starter便不用再进行编写Java配置类了,但配置文件中还需要指定datasource.type

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/diy?useSSL=false&autoReconnect=true&characterEncoding=utf8
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
    # Druid datasource
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      # 初始化大小
      initial-size: 5
      # 最小连接数
      min-idle: 10
      # 最大连接数
      max-active: 20
      # 获取连接时的最大等待时间
      max-wait: 60000
      # 一个连接在池中最小生存的时间,单位是毫秒
      min-evictable-idle-time-millis: 300000
      # 多久才进行一次检测需要关闭的空闲连接,单位是毫秒
      time-between-eviction-runs-millis: 60000
      # 配置扩展插件:stat-监控统计,log4j-日志,wall-防火墙(防止SQL注入),去掉后,监控界面的sql无法统计
      filters: stat,wall
      # 检测连接是否有效的 SQL语句,为空时以下三个配置均无效
      validation-query: SELECT 1
      # 申请连接时执行validationQuery检测连接是否有效,默认true,开启后会降低性能
      test-on-borrow: true
      # 归还连接时执行validationQuery检测连接是否有效,默认false,开启后会降低性能
      test-on-return: true
      # 申请连接时如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效,默认false,建议开启,不影响性能
      test-while-idle: true
      # 是否开启 StatViewServlet
      stat-view-servlet:
        enabled: true
        # 访问监控页面 白名单,默认127.0.0.1
        allow: 127.0.0.1
        login-username: admin
        login-password: admin
      # FilterStat
      filter:
        stat:
          # 是否开启 FilterStat,默认true
          enabled: true
          # 是否开启 慢SQL 记录,默认false
          log-slow-sql: true
          # 慢 SQL 的标准,默认 3000,单位:毫秒
          slow-sql-millis: 5000
          # 合并多个连接池的监控数据,默认false
          merge-sql: false
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49

测试方法,看项目的数据源是否是druid

@SpringBootTest
class DiyStarterApplicationTests {
    //DI注入数据源
    @Autowired
    DataSource dataSource;
    @Test
    void contextLoads() throws SQLException {
        //看一下默认数据源
        System.out.println(dataSource.getClass());
        //获得连接
        Connection connection =   dataSource.getConnection();
        System.out.println(connection);
        //关闭连接
        connection.close();
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

同时因为在配置文件中开启了stat-view-servlet,可以通过web网站查看sql执行情况

访问 http://localhost:8080/druid/datasource.html

admin/admin登录

druid官网文档 (opens new window)

# 3.整合swagger

以下使用的SpringBoot version 为v2.7.16,2.6之前的版本不存在兼容问题,但之后的需要做一些额外的处理

Swagger 目前有 2.x 和 3.x 两个主流版本,配置略有不同。

# 引入对应pom

  • 对于Swagger2.x 需要添加两项配置
<!--https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>

        <!--https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
<!-- 【可选】swagger的其它皮肤 引入swagger-bootstrap-ui包 /doc.html-->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>swagger-bootstrap-ui</artifactId>
            <version>1.9.1</version>
        </dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  • 对于 Swagger 3.x,只需要在 pom.xml 中添加一项配置
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-boot-starter -->
<dependency>
  <groupId>io.springfox</groupId>
  <artifactId>springfox-boot-starter</artifactId>
  <version>3.0.0</version>
</dependency>

1
2
3
4
5
6
7

# 为项目开启swagger

对于 Swagger 2.x,在启动类(或者swagger对应的配置类)上使用 @EnableSwagger2 注解开启 Swagger 功能,二者选其一。接着创建swaggerConfig的配置类,进行必要的配置

@EnableSwagger2
@EnableWebMvc
public class DiyStarterApplication {
  //启动类
}

// 配置类
@Configuration
//@EnableSwagger2
public class SwaggerConfig {
  @Bean
    public Docket createRestApi(){
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .enable(true)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.cogar.hep.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    public ApiInfo apiInfo(){
        return new ApiInfoBuilder()
                .title("API document")
                .description(" this is description message")
                .contact(new Contact("caprge",null,null))
                .version("1.0")
                .build();
    }
}
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
  • 对于 Swagger 3.x,使用 @EnableOpenApi 注解开启 Swagger 功能.接着创建swaggerConfig的配置类,进行必要的配置,配置类中Docket类型为DocumentationType.OAS_30
@EnableOpenApi
@EnableWebMvc
public class DiyStarterApplication {
  //启动类
}

@Configuration
public class SwaggerConfig {

    @Bean
    public Docket createRestApi(){
        return new Docket(DocumentationType.OAS_30)
                .apiInfo(apiInfo())
                .enable(true)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.cogar.hep.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    public ApiInfo apiInfo(){
        return new ApiInfoBuilder()
                .title("API document")
                .description(" this is description message")
                .contact(new Contact("caprge",null,null))
                .version("1.0")
                .build();
    }
}
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

# 问题与解决

  • SpringBoot高于2.6后,通常启动后会出现

org.springframework.context.ApplicationContextException:Failed to start bean ‘documentationPluginsBootstrapper’; nested exception is java.lang.NullPointerException

解决方法1:在配置文件中进行配置

spring:
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher
1
2
3
4

解决方法2:在项目启动类的上方添加注释 @EnableWebMvc

  • 在浏览器中进行访问,遇到404

Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Mon Dec 06 15:48:30 CST 2021

There was an unexpected error (type=Not Found, status=404).

No message available

查看控制台,发现

o.s.web.servlet.PageNotFound : No mapping for GET /swagger-ui.html

经过分析发现由于项目中有配置注解类(@Configuration)继承了[WebMvcConfigurationSupport],导致默认的Swagger静态资源被覆盖,而缺失了配置。

解决方法:在配置类中,显式添加如下swagger静态资源:

@Configuration
public class IntercepConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("doc.html")
                .addResourceLocations("classpath:/META-INF/resources/");

        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 访问

  • 对于 Swagger 2.x,访问 http://localhost:8080/swagger-ui.html
  • 对于 Swagger 3.x,访问 http://localhost:8080/swagger-ui/

当然引入新的皮肤后,访问的地址也会有所变化。例如引入上述皮肤后,访问 http://localhost:8080/doc.html (opens new window)

# 为接口添加信息

以下是一些常用的注解,更多的就不展示了

@ApiModelProperty("书本名称")
private String ename;

@ApiOperation("测试方法")
@GetMapping("/hello")
public String hello(){
  String sugar = helloService.sayHello("sugar");
  return "study like drink water---"+sugar;
}
@Api(tags = "swagger注解学习")
@RestController
public class HepController {
}
1
2
3
4
5
6
7
8
9
10
11
12
13

swagger官方网站 (opens new window)

# 4.整合validation数据校验

数据校验很重要,前端即使做了校验,后端仍需要进行。因为前端的校验可能被绕过,无法进行校验,同时有些数据可能非常复杂,无法通过简单的前端校验完成,这种情况下就需要后端校验了。此外它还可以帮助预防和检测潜在的安全威胁,例如SQL注入攻击。

# 首先引入pom坐标

 <!--参数校验-->
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-validation</artifactId>
 </dependency>
1
2
3
4
5

# 对数据进行添加校验

接下来将对应注解加到需要检验的JavaBean中即可,以下使用了@NotNull,@Range,@Pattern两个注解实现不能为空,取值范围跟正则表达式限制ename字段

@Data
@ApiModel("测试参数param")
public class ParamDto {

    @NotNull(message="the param is not null")
    @Range(min = 1,max = 999,message = "this param is not null")
    private Integer page;

    private Integer rows;

    @ApiModelProperty("书本名称")
    @Pattern(regexp = "^[A-Za-z0-9]+$",message = "this param is important")
    private String ename;

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

接着对某个接口加上对应注解@Valid,便实现了对数据的校验

@PostMapping("/ta")
    public String ta(@Valid ParamDto pd){
        userService.test();
        return "执行完毕,存在异常+事务回滚";
    }
1
2
3
4
5

# 运行与实验

如果使用不符合的数据进行请求,则能看到控制台出现如下异常:

: Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors<EOL>Field error in object 'paramDto' on field 'ename': rejected value []; codes [Pattern.paramDto.ename,Pattern.ename,Pattern.java.lang.String,Pattern]; arguments .....
1

若使用符合规范的数据,则能进行正常请求,到此数据校验就实现完毕

# 6.定时器_@EnableScheduling

不需要引入新的依赖 可用SpringBoot 自带框架实现加上Cron表达式也可用框架quartz (框架还是需要引入对应jar)

在启动类上 加上注解 @EnableScheduling ,再在对应类的方法上使用@Scheduled注解即可。

此外,使用@Scheduled的类,必须加入spring的ioc才行,也就是使用@Controller、@Service等注解才行,否则不会生效

@EnableScheduling
// 在启动类 加上 以上注解 

/**
* 固定时间间隔,fixedRate单位毫秒
*/
@Scheduled(fixedRate = 1000)
public void simple() throws InterruptedException {
    SimpleDateFormat formatter = new SimpleDateFormat("mm:ss");
    String dateString = formatter.format(new Date());
    Thread.sleep(2000);
    log.info("每隔5秒钟执行一次: {}", dateString);
}


/** 
* 自定义cron表达式跑批  cron
* 只有等上一次执行完成,下一次才会在下一个时间点执行,错过就错过
*/
@Scheduled(cron = "*/1 * * * * ?")
public void cron() throws InterruptedException {
    SimpleDateFormat formatter = new SimpleDateFormat("mm:ss SSS");
    String dateString = formatter.format(new Date());
    Thread.sleep(1500);
    log.info("每隔1秒钟执行一次: {}", dateString);
}
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

注意:定时任务耗时的长短很影响用户使用体验,日志记得记录定时任务的耗时

# 7.集成邮件

导包,底层导入的本质还是javax.mail 配置

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-mail</artifactId>
</dependency>
1
2
3
4

进行配置

spring:
  mail:
    username: 594042358@qq.com
  	# 该密码 不是邮箱的密码 而是授权码 
    password: qrfrhtepnixxbe3je
    host: smtp.qq.com
    # qq 邮箱需要开启这个
    properties: {"mail.smtp.ssl.enable": "true"}
1
2
3
4
5
6
7
8

使用直接使用 JavaMailSenderImpl 即可

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMailMessage;
import org.springframework.mail.javamail.MimeMessageHelper;


import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;


@SpringBootTest
class Springboot10TaskApplicationTests {
    
    @Autowired
    JavaMailSenderImpl mailSender;


    @Test
    void contextLoads() {
        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
        simpleMailMessage.setSubject("文飞扬你好呀~");
        simpleMailMessage.setText("你这家伙又在玩游戏了??");
        simpleMailMessage.setTo("594042358@qq.com");
        simpleMailMessage.setFrom("594042358@qq.com");
        mailSender.send(simpleMailMessage);
    }

    @Test
    void contextLoads2() throws MessagingException {
        // 一个复杂的邮件~
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        // 组装
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);

        // 正文
        helper.setSubject("雪山飞狐你好呀~plus");
        helper.setText("<p style='color:red'>你这家伙又在玩游戏了??</p>", true);

        // 添加附件
        helper.addAttachment("abc.jpg", new File("C:\\Users\\59404\\Pictures\\images\\jar\\abc.jpg"));

        helper.setTo("594042358@qq.com");
        helper.setFrom("594042358@qq.com");

        mailSender.send(mimeMessage);
    }
}
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

# 8.异步调用

异步执行本质上就是 为目标类生成一个代理类,新开一个线程去执行它

因此:需要注意有时 会有代理类失效的情况

同一个类中,A方法调用B方法,B有注解@Async(按理来说 应该能够异步执行 )但此时会失效

另外,事务的本质(生成一个代理类)也是如此,事务也有失效的情况 @Transactional

# 开启异步

最简单的方式,在SpringBoot的启动类上加@EnableAsync注解,之后在需要的方法上加上注解@Async即为——该方法开启异步执行

@EnableAsync
//在启动类 加上 以上注解

//再在对应的方法上 加上注解 @Async
//该方法即可实现异步执行
@Async
public void sendInfo(String name){
    webSocketServer.sendInfo("【"+name+"】被点赞");
}
1
2
3
4
5
6
7
8
9

# 线程池与异步

提示:异步化可以使用线程池,但是要是线程池中的线程都被使用完了,仍有【方法】需要开启异步化,此时的这个【方法】,还是会变成 “同步”

待补充-----

上次更新: 2025/05/21, 15:29:11
IOC的实现机制是什么
SpringBoot中拦截器与日志

← IOC的实现机制是什么 SpringBoot中拦截器与日志→

最近更新
01
面向切面跟自定义注解的结合
05-22
02
时间跟其他数据的序列化
05-19
03
数据加密与安全
05-17
更多文章>
Theme by Vdoing | Copyright © 2023-2025 EffectTang
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式