SpringBoot框架整合超详细

SpringBoot框架

1.什么是SpringBoot?

SpringBoot是一个框架,一种全新的编程规范,它的产生简化了框架的使用,所谓简化是指简化了Spring众多框架中所需的大量且繁琐的配置文件,所以SpringBoot是一个服务于框架的框架,服务范围是简化配置文件

1.1 SpringBoot的优缺点。

SpringBoot的优点

  1. 约定优于配置思想

  2. 专注与业务逻辑之间思维切换

  3. 基于Spring的开发提供更快入门体验

  4. 开箱即用,没有代码生成,无需XML配置。

  5. 支持修改默认配置满足特定需求

  6. 提供大型项目中常见的非功能性特性,如嵌入Tomcat服务器、安全、指标、健康检测、外部配置等

SpringBoot的缺点

1、缺少服务注册发现等外围方案;

2、缺少外围监控集成方案;

3、缺少外围安全管理方案;

4、缺少rest落地的URI规划方案。。。

5、将原有的spring项目转成springboot项目,很困难,更适合新建的项目。

6、集成度很高,对于了解底层不容易

2. SpringBoot功能

1.自动配置

​ springboot的自动配置是一个运行时的过程(更准确的说是应用程序启动时的过程),考虑了多种因素,才决定Spring配置应该用那个,不该用那个。该过程是SpringBoot自动完成的。

2.起步依赖

​ 起步依赖本质上是一个Maven项目对象模型,定义了对其它库的传递依赖,这些东西加在一起即支持某项功能。 简单说,起步依赖是将具备某种功能的坐标打包到一起,并提供一些默认的功能。

3.辅助功能

提供了一些大项目中常见的非功能性特性,如嵌入式服务器,安全,指标,健康检测,外部配置等。

小结

SpringBoot并不是对Spring功能上的增强,而是提供了一种快速使用Spring的方式

Spring的缺点:

​ 配置繁琐

​ 依赖繁琐

SpringBoot功能:

​ 自动配置

​ 起步依赖:依赖传递

​ 辅助功能

3.SpringBoot入门

springboot在创建项目时,使用jar的打包方式。

springboot的引导类,是项目的入口,运行run方法就可以启动项目

4.SpringBoot配置

4.1 YAML配置文件

SpringBoot提供了两种配置文件类型,properties和yml/yaml。三个配置文件执行的顺序为:1.properties、2.yml、3.yaml。

YAML

properties:

server.port=8080
server.address=127.0.0.1

xml:

<server>
	<port>8080</port>
	<address>127.0.0.1</address>
</server>

yml

server:
	port:8080
	address:127.0.0.1

简洁,以数据为核心。

4.2 YAML基本语法

大小写敏感

数据值前边必须有空格,作为分隔符

使用缩进表示层级关系

缩进时不允许使用Tab键,只允许使用空格(各个系统Tab对应的空格数目可能不同,导致层次混乱)。

缩进的空格数目不重要,要相同层级的元素左侧对齐即可。

#表示注释,从这个字符一直到行尾,都会被解析器忽略。

server:
	port:8080
	address:127.0.0.1
	
name:abc

4.3 YAML数据格式

对象(map):键值对儿的集合

server:
  port: 8081
name: abc
#对象
person:
  name: zhangsan
  age: 23
#对象的行内写法
person2: {name: lisi,age: 20}

数组:一组按次序排列的值

#数组
address:
  - beijing
  - shanghai
#数组的行内写法
address2: [beijing,shanghai]

纯量:单个的,不可再分的值

#纯量
msg1: 'hello \n world' #不会识别转义字符,会原样输出
msg2: "hello \n world" #会识别转移字符

4.4 读取配置文件的内容

1.@Value

2.Environment

3.@ConfigurationProperties

@RestController
public class ReadConfigFiles {

    @Value("${name}")//大括号里面的值要和配置文件中要获取的key一样
    private String name;

    @Value("${person.name}")//大括号里面的值要和配置文件中要获取的key一样
    private String personName;

    @Value("${person.age}")//大括号里面的值要和配置文件中要获取的key一样
    private int personAge;

    @Value("${address1[0]}")//大括号里面的值要和配置文件中要获取的key一样
    private String address1;

    @Value("${msg1}")//大括号里面的值要和配置文件中要获取的key一样
    private String msg1;

    @Value("${msg2}")//大括号里面的值要和配置文件中要获取的key一样
    private String msg2;

    @Autowired //这个注解的功能 注入
    private Environment environment;//只需要注入这一个对象就可以用这个对象获取配置文件中的其它值。

    @RequestMapping("/config")
    public String getConfigFilesName(){
        System.out.println(name);
        System.out.println(personName);
        System.out.println(personAge);
        System.out.println(address1);
        System.out.println(msg1);
        System.out.println(msg2);
        System.out.println("---------------");
        System.out.println(environment.getProperty("person.name"));//传入yml文件中的key获取对应的值
        System.out.println(environment.getProperty("msg1"));
        return "springboot的yml配置文件测试";
    }
}

@ConfigurationProperties

@Component//表示这个类是个bean类,被spring识别
@ConfigurationProperties(prefix = "person")//为yml中的person下面的内容注入值
public class Person {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
@RestController
public class ReadConfigFiles { 	
 	@Autowired
    private Person person;

    @RequestMapping("/config")
    public String getConfigFilesName(){
        System.out.println(person);
        return "springboot的yml配置文件测试";
    }
}
<!--yml提示(自己写的类也可以提示)-->
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-configuration-processor</artifactId>
     <optional>true</optional>
 </dependency>

4.5 profile(动态配置切换)

​ 在我们开发SpringBoot应用时,一套程序会被安装到不同的环境,如:开发,测试,生产。其中数据库地址,服务器端口等等配置都是不同的,如果每次打包时,都要修改配置文件,那么非常麻烦。profile功能就是来进行动态配置切换的

1.profile配置方式

​ 多profile文件方式

#application.properties
spring.profiles.active=dev
#application-dev.properties 开发环境
server.port=8081
#application-test.properties 测试环境
server.port=8082
##application-pro.properties 生产环境
server.port=8083

​ yml多文档方式

​ 在yml中使用 — 分隔不同的配置

---
server:
  port: 8090
spring:
  profiles: dev
---
server:
  port: 8091
spring:
  profiles: test
---
server:
  port: 8092
spring:
  profiles: pro
---

2.profile激活方式

​ 配置文件:在配置文件中配置:spring.profiles.active=dev

​ 虚拟机参数:再VM options指定:-Dspring.profiles.active=dev

​ 命令行参数:java-jar xxx.jar --spring.profiles.active=dev

4.6 内部配置加载顺序

SpringBoot程序启动时,会从以下位置加载配置文件:

	1. file:./config/:当前项目下的/config目录下
	2. file:./            :当前项目的根目录
            		3. classpath:/config/:classpath的/config目录
        		4. classpath:/ :classpath的根目录

加载顺序为上文的排列顺序,高优先级配置的属性会生效

5. SpringBoot整合其它框架

5.1 SpringBoot整合Junit

首先创建一个service类

@Service
public class UserService {
    public void add(){
        System.out.println("add()....");
    }
}

然后再test文件夹中创建

/**
 * userService的测试类
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Springboot4JunitApplication.class)
public class UserServiceTest {
    @Autowired
    private UserService userService;
    @Test
    public void testAdd(){
        userService.add();
    }
}

5.2 SpringBoot整合Redis

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
package com.lanou.springboot5redis;

import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
class Springboot5RedisApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void testSet() {
        //存入数据
        redisTemplate.boundValueOps("name").set("zhangsan");
    }

    @Test
    public void testGet() {
        Object name = redisTemplate.boundValueOps("name").get();
        System.out.println(name);
    }
}
spring:
  redis:
    host: 127.0.0.1 #redis的主机IP
    port: 6379

5.3 SpringBoot整合数据库

再pom文件中添加依赖

<!--mysql驱动-->
<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <scope>runtime</scope>
</dependency>       

yml配置

#datasource
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mysql1?characterEncoding=utf-8&useSSL=false
    username: root
    password: 123456

测试代码

@Controller
public class DeptController {
    @Autowired
    private DataSource dataSource;
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @RequestMapping
    @ResponseBody
    public String test1(){
        System.out.println(dataSource);
        List<Map<String, Object>> list = jdbcTemplate.queryForList("select * from status_inf");
        System.out.println(list);
        return "main";
    }
}

5.4 SpringBoot整合MyBatis

1.搭建springboot工程

2.引入mybatis的起步依赖,添加mybatis驱动

3.编写DataSource和MyBatis相关配置

4.定义表和实体类

5.编写dao和mapper文件/纯注解开发

6.测试

方式1. 用注解的方式整合

首先添加依赖

<dependency>
	<groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.0</version>
</dependency>            

写出接口

public interface UserMapper {
    @Select("select * from user")
    public List<User> queryAll();
}

让mapper接口起作用

@MapperScan("com.lanou.mapper")
@SpringBootApplication
public class Springboot6MybatisApplication {
    public static void main(String[] args) {
        SpringApplication.run(Springboot6MybatisApplication.class, args);
    }
}
方式2. 用xml的方式整合

在yml中配置

#datasource
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/shiro?characterEncoding=utf-8&useSSL=false
    username: root
    password: 123456

#配置mybatis
mybatis:
  mapper-locations: classpath: mapper/*Mapper.xml #mapper映射文件路径
  type-aliases-package: com.lanou.bean;
  config-location: classpath: mapper/mybatis-config.xml #指定mybatis的核心配置文件
  
#添加sql日志
logging:
  level:
    com:
      lanou:
        mapper: debug

mapper接口

@Mapper//加了@Mapper注解后,spring会自动扫包,创建工具类,加载映射文件并生成对相应的mapper
@Repository
public interface UserXmlMapper {
    public List<User> findAll();
}

userMapper.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.lanou.mapper.UserXmlMapper">
    <select id="findAll" resultType="User">
        select * from user
    </select>
</mapper>

测试

@Controller
public class DeptController {
    @Autowired
    private DataSource dataSource;
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private DeptMapper deptMapper;
    @RequestMapping
    @ResponseBody
    public String test1(){
        List<Dept> all = deptMapper.getAll();
        System.out.println(all);
        System.out.println(dataSource);
        List<Map<String, Object>> list = jdbcTemplate.queryForList("select * from status_inf");
        System.out.println(list);
        return "main";
    }
}

5.5 SpringBoot整合Email

  • 邮件发送需要引入spring-boot-start-mail

  • SpringBoot 自动配置MailSenderAutoConfiguration

  • 定义MailProperties内容,配置在application.yml中

  • 自动装配JavaMailSender

  • 测试邮件发送

pom文件

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

properties文件

spring.mail.username=#发件人邮箱
spring.mail.password=#你的qq授权码
spring.mail.host=smtp.qq.com
#qq需要配置ssl
spring.mail.properties.mail.smtp.ssl.enable=true

测试类

@SpringBootTest
public class SpringbootAsyncEmailApplicationTests {
    @Autowired
    public JavaMailSender javaMailSender;
    //发邮件
    @Test
    void contextLoads1() {
        SimpleMailMessage message = new SimpleMailMessage();
        //邮件设置
        message.setSubject("springboot整合email发送信息或文件!");//设置标题
        message.setText("你真好看。");//设置内容
        message.setFrom("xxxxxx@qq.com");//发送端
        message.setTo("xxxxx@163.com");//接收端
        javaMailSender.send(message);
    }
    
    //发送含有html页面的邮件
    @Test
    void contextLoads2() throws MessagingException {
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage);
        //邮件设置
        messageHelper.setSubject("验证码邮件");//主题 需要抛出异常
        messageHelper.setText("邮件内容");
        messageHelper.setText("<h1>验证码内容: 9093</h1>",true);
        messageHelper.setFrom("xxxxxx@qq.com");//发送端
        messageHelper.setTo("xxxxx@163.com");//接收端
        javaMailSender.send(mimeMessage);
    }

    //发送内嵌图片的邮件
    @Test
    void contextLoads3() throws MessagingException {
        MimeMessage mimeMessage2 = javaMailSender.createMimeMessage();
        MimeMessageHelper messageHelper2 = new MimeMessageHelper(mimeMessage2,true);
        //邮件设置
        String id = "3";
        String ImgPath = "C:\\Users\\24329\\Pictures\\Saved Pictures\\3.jpeg";
        messageHelper2.setSubject("含有图片的邮件");//主题 需要抛出异常
        messageHelper2.setText("<h1>图片:</h1><img src='cid:"+id+"'/>",true);
        FileSystemResource fileSystemResource = new FileSystemResource(new File(ImgPath));
        messageHelper2.addInline(id,fileSystemResource);
        messageHelper2.setFrom("xxxxxx@qq.com");//发送端
        messageHelper2.setTo("xxxxx@163.com");//接收端
        javaMailSender.send(mimeMessage2);
    }

    //发送含有附件的邮件
    @Test
    void contextLoads4() throws MessagingException {
        MimeMessage mimeMessage2 = javaMailSender.createMimeMessage();
        MimeMessageHelper messageHelper2 = new MimeMessageHelper(mimeMessage2,true);
        //邮件设置
        String id = "3";
        String ImgPath = "C:\\Users\\24329\\Pictures\\Saved Pictures\\1.jpeg";
        messageHelper2.setSubject("含有附件的邮件");//主题 需要抛出异常
        messageHelper2.setText("<h1>图片:</h1><img src='cid:"+id+"'/>",true);
        FileSystemResource fileSystemResource = new FileSystemResource(new File(ImgPath));
        messageHelper2.addInline(id,fileSystemResource);
        //添加addAttachment方法可是实现发送附件
        messageHelper2.addAttachment("1.jepg",fileSystemResource);
        message.setFrom("xxxxxx@qq.com");//发送端
        message.setTo("xxxxx@163.com");//接收端
        javaMailSender.send(mimeMessage2);
    }
    
}

5.6 SpringBoot异步任务

异步处理还是非常常用的,比如我们在网站上发送邮件,后台会去发送邮件,此时前台会造成响应不动,直到邮件发送完毕,响应才会成功,所以我们一般会采用多线程的方式去处理这些任务。

@EnableAsync //开启异步注解功能 这个注解需要在启动控制类上加
@Async //异步方法
spring.mail.username=#发件人邮箱
spring.mail.password=#你的qq授权码
spring.mail.host=smtp.qq.com
#qq需要配置ssl
spring.mail.properties.mail.smtp.ssl.enable=true
@EnableAsync //开启异步注解功能
@SpringBootApplication
public class SpringbootAsyncEmailApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootAsyncEmailApplication.class, args);
    }
}
@Service
public class AsyncService {

    @Autowired
    public JavaMailSender javaMailSender;

    @Async //声明email是一个异步方法
    public void email() throws InterruptedException {
        Thread.sleep(3000);//等3秒钟
        SimpleMailMessage message = new SimpleMailMessage();
        //邮件设置
        message.setSubject("异步email发送信息或文件!");//设置主题
        message.setText("你真好看。");//设置内容
        message.setFrom("xxxxxx@qq.com");//发送端
        message.setTo("xxxxxx@163.com");//接收端
        javaMailSender.send(message);
    }
}
@RestController
public class AsyncController {
    @Autowired
    public AsyncService asyncService;

    @RequestMapping("/sendEmail")
    public String sendEamil() throws InterruptedException {
        asyncService.email();
        return "ok";
    }

}

5.7 SpringBoot整合定时器

项目开发中经常需要执行一些定时任务,比如需要在每天凌晨的时候,分析一次前一天的日志信息,Spring为我们提供了异步执行任务调度的方式,提供了两个接口。

  • TaskExecutor接口
  • TaskScheduler接口

两个注解:

  • @EnableScheduling:开启定时任务
  • @Scheduled:定时方法

cron表达式:

图片

图片

定时任务常用表达式(cron表达式)

https://www.bejson.com/othertools/cron/ 在线生成表达式工具

(1)0/2 * * * * ?   表示每2秒 执行任务
(1)0 0/2 * * * ?   表示每2分钟 执行任务
(1)0 0 2 1 * ?   表示在每月的1日的凌晨2点调整任务
(2)0 15 10 ? * MON-FRI   表示周一到周五每天上午10:15执行作业
(3)0 15 10 ? 6L 2002-2006   表示2002-2006年的每个月的最后一个星期五上午10:15执行作
(4)0 0 10,14,16 * * ?   每天上午10点,下午2点,4点
(5)0 0/30 9-17 * * ?   朝九晚五工作时间内每半小时
(6)0 0 12 ? * WED   表示每个星期三中午12点
(7)0 0 12 * * ?   每天中午12点触发
(8)0 15 10 ? * *   每天上午10:15触发
(9)0 15 10 * * ?     每天上午10:15触发
(10)0 15 10 * * ?   每天上午10:15触发
(11)0 15 10 * * ? 2005   2005年的每天上午10:15触发
(12)0 * 14 * * ?     在每天下午2点到下午2:59期间的每1分钟触发
(13)0 0/5 14 * * ?   在每天下午2点到下午2:55期间的每5分钟触发
(14)0 0/5 14,18 * * ?     在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
(15)0 0-5 14 * * ?   在每天下午2点到下午2:05期间的每1分钟触发
(16)0 10,44 14 ? 3 WED   每年三月的星期三的下午2:10和2:44触发
(17)0 15 10 ? * MON-FRI   周一至周五的上午10:15触发
(18)0 15 10 15 * ?   每月15日上午10:15触发
(19)0 15 10 L * ?   每月最后一日的上午10:15触发
(20)0 15 10 ? * 6L   每月的最后一个星期五上午10:15触发
(21)0 15 10 ? * 6L 2002-2005   2002年至2005年的每月的最后一个星期五上午10:15触发
(22)0 15 10 ? * 6#3   每月的第三个星期五上午10:15触发

代码实现

主程序上增加**@EnableScheduling** 开启定时任务功能

@EnableScheduling//开启定时任务   在启动控制类上加
//cron表达式中参数的意义:秒 分 时 日 月 周几
@Scheduled(cron = "0/2 * * * * ?")//定时的方法   需要定时的方法上加上该注解
spring.mail.username=#发件人邮箱
spring.mail.password=#你的qq授权码
spring.mail.host=smtp.qq.com
#qq需要配置ssl
spring.mail.properties.mail.smtp.ssl.enable=true
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
</dependency>
@EnableAsync //开启异步注解功能
@EnableScheduling//开启定时任务
@SpringBootApplication
public class SpringbootAsyncEmailApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootAsyncEmailApplication.class, args);
    }
}
@Service
public class ScheduleService {

    @Autowired
    public JavaMailSender javaMailSender;

    //定时任务
    //cron表达式中参数的意义:秒 分 时 日 月 周几
    @Scheduled(cron = "0 3 5 * * ?")//需要定时的方法上加上该注解
    public void task() throws InterruptedException {
        System.out.println("启动执行定时任务!");
        Thread.sleep(3000);//等3秒钟
        SimpleMailMessage message = new SimpleMailMessage();
        //邮件设置
        message.setSubject("定时email发送信息或文件!");//设置主题
        message.setText("你真好看。");//设置内容
        message.setFrom("xxxxx@qq.com");//发送端
        message.setTo("xxxxx@163.com");//接收端
        javaMailSender.send(message);
    }

}

5.9 SpringBoot整合redis

pom文件

<!--redis起步依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

properties文件

#配置redis
sping.redis.host=127.0.0.1
spring.redis.port=6379

代码实现

@RunWith(SpringRunner.class)
@SpringBootTest
class Springboot5RedisApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void contextLoads() {
        //redisTemplate操作不同的数据类型和操作的指令是一样的
        //opsForValue 操作字符串 类似于String
        //opsForList 操作List 类似于List
        //opsForHash
        //opsForSet
        //opsForZSet
        //opsForGeo

        //除了基本的操作,我们常用的方法都可直接使用redisTemplate操作,

        //获取数据库连接
//        RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
//        connection.flushDb();
//        connection.flushAll();
//        connection.close();

        redisTemplate.opsForValue().set("key1","zhangsan");
        System.out.println(redisTemplate.opsForValue().get("key1"));

    }
}

配置自己的RedisTemplate序列化模板(一般公司用的)

@Configuration
public class RedisConfig {
    //编写我们自己的redisTemplate 固定模板
    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory) {
        //我们为了自己开发方便,一般直接使用<String,Object>类型
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        //获取连接
        redisTemplate.setConnectionFactory(factory);
        //json序列化配置
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        //String的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        //key采用String的序列化方式
        redisTemplate.setKeySerializer(stringRedisSerializer);
        //hash的key也采用String的序列化方式
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        //value序列化方式采用jackson
        redisTemplate.setValueSerializer(stringRedisSerializer);
        //hash的value序列化方式采用jackson
        redisTemplate.setHashValueSerializer(stringRedisSerializer);
        redisTemplate.afterPropertiesSet();

        return redisTemplate;
    }
}

RedisUtils工具类

package com.lanou.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Component
public final class RedisUtil {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // =============================common============================
    /**
     * 指定缓存失效时间
     * @param key  键
     * @param time 时间(秒)
     */
    public boolean expire(String key, long time) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据key 获取过期时间
     * @param key 键 不能为null
     * @return 时间(秒) 返回0代表为永久有效
     */
    public long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }


    /**
     * 判断key是否存在
     * @param key 键
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 删除缓存
     * @param key 可以传一个值 或多个
     */
    @SuppressWarnings("unchecked")
    public void del(String... key) {
        if (key != null && key.length > 0) {
            if (key.length == 1) {
                redisTemplate.delete(key[0]);
            } else {
                redisTemplate.delete(CollectionUtils.arrayToList(key));
            }
        }
    }


    // ============================String=============================

    /**
     * 普通缓存获取
     * @param key 键
     * @return 值
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }

    /**
     * 普通缓存放入
     * @param key   键
     * @param value 值
     * @return true成功 false失败
     */

    public boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 普通缓存放入并设置时间
     * @param key   键
     * @param value 值
     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
     * @return true成功 false 失败
     */

    public boolean set(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 递增
     * @param key   键
     * @param delta 要增加几(大于0)
     */
    public long incr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递增因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }


    /**
     * 递减
     * @param key   键
     * @param delta 要减少几(小于0)
     */
    public long decr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递减因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, -delta);
    }


    // ================================Map=================================

    /**
     * HashGet
     * @param key  键 不能为null
     * @param item 项 不能为null
     */
    public Object hget(String key, String item) {
        return redisTemplate.opsForHash().get(key, item);
    }

    /**
     * 获取hashKey对应的所有键值
     * @param key 键
     * @return 对应的多个键值
     */
    public Map<Object, Object> hmget(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * HashSet
     * @param key 键
     * @param map 对应多个键值
     */
    public boolean hmset(String key, Map<String, Object> map) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * HashSet 并设置时间
     * @param key  键
     * @param map  对应多个键值
     * @param time 时间(秒)
     * @return true成功 false失败
     */
    public boolean hmset(String key, Map<String, Object> map, long time) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value, long time) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 删除hash表中的值
     *
     * @param key  键 不能为null
     * @param item 项 可以使多个 不能为null
     */
    public void hdel(String key, Object... item) {
        redisTemplate.opsForHash().delete(key, item);
    }


    /**
     * 判断hash表中是否有该项的值
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return true 存在 false不存在
     */
    public boolean hHasKey(String key, String item) {
        return redisTemplate.opsForHash().hasKey(key, item);
    }


    /**
     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
     *
     * @param key  键
     * @param item 项
     * @param by   要增加几(大于0)
     */
    public double hincr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, by);
    }


    /**
     * hash递减
     *
     * @param key  键
     * @param item 项
     * @param by   要减少记(小于0)
     */
    public double hdecr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, -by);
    }


    // ============================set=============================

    /**
     * 根据key获取Set中的所有值
     * @param key 键
     */
    public Set<Object> sGet(String key) {
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 根据value从一个set中查询,是否存在
     *
     * @param key   键
     * @param value 值
     * @return true 存在 false不存在
     */
    public boolean sHasKey(String key, Object value) {
        try {
            return redisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 将数据放入set缓存
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSet(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }


    /**
     * 将set数据放入缓存
     *
     * @param key    键
     * @param time   时间(秒)
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSetAndTime(String key, long time, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if (time > 0)
                expire(key, time);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }


    /**
     * 获取set缓存的长度
     *
     * @param key 键
     */
    public long sGetSetSize(String key) {
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }


    /**
     * 移除值为value的
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 移除的个数
     */

    public long setRemove(String key, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().remove(key, values);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    // ===============================list=================================

    /**
     * 获取list缓存的内容
     *
     * @param key   键
     * @param start 开始
     * @param end   结束 0 到 -1代表所有值
     */
    public List<Object> lGet(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 获取list缓存的长度
     *
     * @param key 键
     */
    public long lGetListSize(String key) {
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }


    /**
     * 通过索引 获取list中的值
     *
     * @param key   键
     * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
     */
    public Object lGetIndex(String key, long index) {
        try {
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     */
    public boolean lSet(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 将list放入缓存
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     */
    public boolean lSet(String key, Object value, long time) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0)
                expire(key, time);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }


    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, List<Object> value) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }


    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     * @return
     */
    public boolean lSet(String key, List<Object> value, long time) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0)
                expire(key, time);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 根据索引修改list中的某条数据
     *
     * @param key   键
     * @param index 索引
     * @param value 值
     * @return
     */
    public boolean lUpdateIndex(String key, long index, Object value) {
        try {
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 移除N个值为value
     *
     * @param key   键
     * @param count 移除多少个
     * @param value 值
     * @return 移除的个数
     */
    public long lRemove(String key, long count, Object value) {
        try {
            Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

}

测试redisUtil

@Autowired
private RedisUtil redisUtil;
@Test
public void redisUtilTest(){
    redisUtil.set("name","zhangsan")
    System.out.println(redisUtil.get("name"));
}

5.9 SpringBoot整合Shiro

shiro三大组件

<!--
    shiro
        Subject:用户
        SeurityManager:管理所有用户
        Realm 连接数据
-->

pom文件

 <!--连接数据库-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!--mybatis依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>

        <!--log4j-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
 <!--shiro整合Spring-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>
 <!--thymeleaf-->
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-java8time</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>jetty</artifactId>
            <version>6.1.25</version>
        </dependency>

        <!--shiro-thymeleaf-->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

代码实现

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p>首页</p>
<div th:if="${session.loginUser==null}">
    <a th:href="@{/toLogin}">登录</a>
</div>
<p th:text="${msg}"></p><!--访问传递的msg信息-->

<hr>

<div shiro:hasPermission="user:add">
    <a th:href="@{/user/add}">add</a>
</div>

<div shiro:hasPermission="user:update">
    <a th:href="@{/user/update}">update</a>
</div>

</body>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
<h1>登录</h1>
<hr>
<p th:text="${msg}" style="color: red;"></p>
<form th:action="@{/login}">
    <p>用户名:<input type="text" name="username"></p>
    <p>密码:<input type="text" name="password"></p>
    <p><input type="submit"></p>
</form>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>update</h1>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>add</h1>
</body>
</html>
public class User {
    private int id;
    private String name;
    private String password;
    private String perms;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getPerms() {
        return perms;
    }

    public void setPerms(String perms) {
        this.perms = perms;
    }

    public User() {
    }

    public User(int id, String name, String password, String perms) {
        this.id = id;
        this.name = name;
        this.password = password;
        this.perms = perms;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", password='" + password + '\'' +
                ", perms='" + perms + '\'' +
                '}';
    }
}
@Mapper
@Repository
public interface UserMapper {
    public User queryUserByName(String name);
}
<?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.lanou.mapper.UserMapper">
    <select id="queryUserByName" parameterType="String" resultType="User">
        select * from user where name = #{name}
    </select>
</mapper>
public interface UserService {
    public User queryUserByName(String name);
}
@Service
public class UserServiceImpl implements UserService{
   @Autowired
    public UserMapper userMapper;
    @Override
    public User queryUserByName(String name) {
        return userMapper.queryUserByName(name);
    }
}
package com.lanou.config;

import com.lanou.pojo.User;
import com.lanou.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;

//自定义的UserRealm    extends AuthorizingRealm
public class UserRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了授权方法=>授权doGetAuthorizationInfo");
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//        info.addStringPermission("user:add");
        //拿到当前用户对象
        Subject subject = SecurityUtils.getSubject();
        User currentUser = (User) subject.getPrincipal();//拿到user对象
        //设置当前用户权限
        info.addStringPermission(currentUser.getPerms());
        return info;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("执行了认证方法=>认证doGetAuthorizationInfo");
        //用户名密码,数据库中取。先伪造数据
//        String name = "root";
//        String password = "123456";
        UsernamePasswordToken userToken = (UsernamePasswordToken) token;
        //连接真实数据库
        User user = userService.queryUserByName(userToken.getUsername());
        if (null==user) {//没有这个人
            return null;//抛出异常 UnknownAccountException
        }

        Subject subject1 = SecurityUtils.getSubject();
        Session session = subject1.getSession();
        session.setAttribute("loginUser",user);

        //密码认证,shiro做
        return new SimpleAuthenticationInfo(user,user.getPassword(),"");
    }
}
package com.lanou.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

    //ShiroFilterFactoryBean:3:连接到前端
    @Bean("shiroFilterFactoryBean")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);
        /*
          添加shiro的内置过滤器:(设置用户登陆权限)
            anon:无需认证就可以访问
            authc:必须认证了才能访问
            user:必须拥有 记住我 功能才能使用
            perms:拥有对某个资源的权限才能使用
            role:拥有某个角色授权才能访问
//        filterMap.put("/user/add","anon");
//        filterMap.put("/user/update","authc");
         */
        Map<String,String> filterMap = new LinkedHashMap<>();
        //拦截
        filterMap.put("/user/add","authc");
        //filterMap.put("/user/*","authc");//认证之后才能访问
        //授权,正常情况下,没有授权的会跳转到未授权页面
        filterMap.put("/user/add","perms[user:add]");
        filterMap.put("/user/update","perms[user:update]");
        //设置过滤器的链
        bean.setFilterChainDefinitionMap(filterMap);
        //如果没有权限 需要设置登录请求(拦截之后需要跳转到登录页面)
        bean.setLoginUrl("/toLogin");
        //设置未授权请求页面
        bean.setUnauthorizedUrl("/noauth");
        return bean;
    }


    //DafaultWebSecurityManage:2:管理realm对象
    @Bean(name = "securityManager")                           //@Qualifier指定方法名
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联UserRealm
        securityManager.setRealm(userRealm);
        return securityManager;
    }


    //创建realm对象。需要自定义类UserRealm。1
    //用户认证放在userRealm()方法里
    @Bean//将UserRealm注入到bean
    public UserRealm userRealm(){ return new UserRealm(); }


    //整合Shiro方言:用来整合shiro thymeleaf
    @Bean
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }

}
package com.lanou.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @PackageName: com.lanou.controller
 * @ClassName: MyController
 * @author: zhangpan
 * @data: 2021/11/15 18:01
 */

@Controller
public class MyController {
    @RequestMapping({"/","/index"})
    public String toIndex(Model model){
        model.addAttribute("msg","hello,Shiro");
        return "index";
    }

    @RequestMapping("/user/add")
    public String add(){
        return "user/add";
    }

    @RequestMapping("/user/update")
    public String update(){
        return "user/update";
    }

    @RequestMapping("/toLogin")
    public String toLogin(){ return "login"; }

    @RequestMapping("/login")
    public String login(String username, String password, Model model){
        //1.获取当前的用户
        Subject subject = SecurityUtils.getSubject();
        //2.封装用户的登录数据
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);

        try {
            subject.login(token);//执行登录方法,如果没有异常,说明ok了
            return "index";//登录成功返回首页
        } catch (UnknownAccountException e) {//用户名不存在
            model.addAttribute("msg","用户名错误");
            System.out.println("用户名错误!");
            return "login";
        } catch (IncorrectCredentialsException e) {//密码不存在
            model.addAttribute("msg","密码错误");
            System.out.println("密码错误!");
            return "login";
        }
    }

    @RequestMapping("/noauth")
    @ResponseBody
    public String unauthorized(){//未授权页面
        return "未经授权无法访问此页面。";
    }
}

5.10 SpringBoot整合elsearch

5.11 SpringBoot整合fastdfs

pom文件

<!--fastdfs依赖-->
<dependency>
     <groupId>com.github.tobato</groupId>
     <artifactId>fastdfs-client</artifactId>
     <version>1.26.1-RELEASE</version>
</dependency>

yml文件

fdfs:
  so-timeout: 1501
  connect-timeout: 601
  thumb-image:
    width: 60
    height: 60
  tracker-list: # tracker地址  虚拟机IP地址 + 22122
    - IP:22122

配置文件类

@Configuration
@Import(FdfsClientConfig.class) // 解决jmx重复注册bean的问题
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
public class FastdfsClientImporter {}

实现代码

@RestController
public class UpLoadController {
    @Autowired
    private FastFileStorageClient storageClient;
    @RequestMapping("/up")
    public String testUpload() throws FileNotFoundException {
        // 要上传的文件
        File file = new File("D:\\123.jpg");
        // 上传并保存图片,参数:1-上传的文件流 2-文件的大小 3-文件的后缀 4-可以不管他
        StorePath storePath = this.storageClient.uploadFile( new FileInputStream(file), file.length(), "jpg", null);
        // 带分组的路径
        System.out.println(storePath.getFullPath());
        // 不带分组的路径
        System.out.println(storePath.getPath());
        return "success";
    }
}

5.11 SpringBoot整合rabbitmq

6. SpringBoot自动配置

6.1 Condition(条件,状况)

Condition是在Spring4.0增加的条件判断功能,通过这个可以实现选择性的创建Bean操作。

matches方法的返回值

public class ConditionClass implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return true; //如果返回true,则创建bean对象
        //return false; //如果返回false,则不创建bean对象
    }
}
Condition案例1
<!--redis依赖-->
<dependency>
	<groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>                    
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>
public class User {}
public class ConditionClass implements Condition {
    /**
     * @param context:上下文对象。用于获取环境,IOC容器,ClassLoader对象
     * @param metadata:注解的原对象,可以用于获取注解定义的属性值
     * @return
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //1.需求:导入Jedis坐标后创建Bean
        //思路:判断redis.clients.jedis.Jedis.class文件是否存在
        boolean flag = true;
        try {
            Class<?> aClass = Class.forName("redis.clients.jedis.Jedis");
        } catch (ClassNotFoundException e) {
            flag = false;
        }
        return flag;
    }
}
@Configuration
public class UserConfig {
    @Bean
    @Conditional(ConditionClass.class) //如果ConditionClass类中的matches方法返回true则创建对象,返回false则不创建对象
    public User user(){
        return new User();
    }
}
@SpringBootApplication
public class Springboot7ConditionApplication {
    public static void main(String[] args) {
        //启动SpringBoot应用,返回Spring的IOC容器
        ConfigurableApplicationContext context = SpringApplication.run(Springboot7ConditionApplication.class, args);
        //获取自己定义的Bean
        Object user = context.getBean("user");
        System.out.println(user);
    }
}
Condition案例2 注意

自定义注解,判断类是否存在

public class User {}
public class ConditionClass implements Condition {
    /**
     * @param context:上下文对象。用于获取环境,IOC容器,ClassLoader对象
     * @param metadata:注解的原对象,可以用于获取注解定义的属性值
     * @return
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //1.需求:导入Jedis坐标后创建Bean
        //思路:判断redis.clients.jedis.Jedis.class文件是否存在
        boolean flag = true;
        try {
            Class<?> aClass = Class.forName("redis.clients.jedis.Jedis");
        } catch (ClassNotFoundException e) {
            flag = false;
        }
        return flag;
    }
}
/**
 * 创建一个Annotation类,自定义一个注解
 */
@Target({ElementType.TYPE, ElementType.METHOD}) //这个注解的意思是:我们自定义的注解可以加那个范围上,类上面和方法上面
@Retention(RetentionPolicy.RUNTIME) //注解生效的时机
@Documented //生成javaDoc文档
@Conditional(ConditionClass.class)
public @interface ConditionalOnClass {
    String[] value();
}
@Configuration
public class UserConfig {
    @Bean
//  @Conditional(ConditionClass.class) //如果ConditionClass类中的matches方法返回true则创建对象,返回false则不创建对象
    @ConditionalOnClass("redis.clients.jedis.Jedis")//自定义的注解
    public User user(){
        return new User();
    }
}
@SpringBootApplication
public class Springboot7ConditionApplication {
    public static void main(String[] args) {
        //启动SpringBoot应用,返回Spring的IOC容器
        ConfigurableApplicationContext context = SpringApplication.run(Springboot7ConditionApplication.class, args);
        //使用自定义注解获取自己定义的Bean
        Object user = context.getBean("user");
        System.out.println(user);
    }
}
Condition小结

自定义条件

  1. 定义条件类:自定义实现Condition接口,重写matches方法,在matches方法中进行逻辑判断,返回boolean值。matches方法两个参数:

    context:上下文对象。用于获取环境,IOC容器,ClassLoader对象

    metadata:注解的原对象,可以用于获取注解定义的属性值

    1. 判断条件:在初始化Bean时,使用 @Conditional(条件类.class) 注解

SpringBoot提供的常用条件注解

  1. ConditionalOnProperty:判断配置文件中是否有对应属性和值才初始化Bean
  2. ConditionalOnClass:判断环境中是否有对应字节码文件才初始化Bean
  3. ConditionalOnMissingBean:判断环境中没有对应Bean才初始化Bean

6.2 切换内置web服务器

​ SpringBoot的web环境中默认使用tomcat作为内置服务器,其实SpringBoot提供了4中内置服务器供我们选择,我们可以很方便的进行切换。

<!--springboot的web项目依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <!--切换内置服务器-->
    <!--从spring-boot-satrt-web中排除tomcat依赖-->
    <exclusions>
    <exclusion>
       <groupId>spring-boot-starter-tomcat</groupId>
       <artifactId>org.springframework.boot</artifactId>
    </exclusion>
    </exclusions>
</dependency>

<!--引入jetty依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

6.3 Enable*注解

​ SpringBoot中提供了很多Enable开头的注解,这些注解都是用于动态启用某些功能的。而其底层原理使用@Import注解导入一些配置类,实现Bean的动态加载。

首先创建两个模块

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qujqfbUT-1637053496554)(D:\zhangpan\JavaPDF\自学笔记\springbootenable.png)]

方式1:

在springboot8-enable-other中创建

public class User {}
package com.lanou.config;

@Configuration
public class UserConfig {
    @Bean
    public User user() {
        return new User();
    }
}

在springboot8-enable中创建

/**
 * @ComponentScan("") :扫描范围是当前引导类所在包及其子包
 * com.lanou.springboot8enable;
 * com.lanou.config;
 * 两个不属于父子包关系
 * //1.使用@ComponentScan扫描com.lanou.config包
 */
@SpringBootApplication
@ComponentScan("com.lanou.config")//把配置类所在的包添加到扫描的范围里面
public class Springboot8EnableApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Springboot8EnableApplication.class, args);
        //1.获取Bean
        Object user = context.getBean("user");
        System.out.println(user);
    }
}
方式2:

在springboot8-enable-other中创建

public class User {}
@Configuration
public class UserConfig {
    @Bean
    public User user() {
        return new User();
    }
}

在springboot8-enable中创建

/**
 * @ComponentScan("") :扫描范围是当前引导类所在包及其子包
 * com.lanou.springboot8enable;
 * com.lanou.config;
 * 两个不属于父子包关系
 * //2.使用@Import注解,加载类。这些类都会被Spring创建,并且放入IOC容器
 */
@SpringBootApplication
@Import(UserConfig.class)//把配置类所在的包添加到扫描的范围里面
public class Springboot8EnableApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Springboot8EnableApplication.class, args);
        //1.获取Bean
        Object user = context.getBean("user");
        System.out.println(user);
    }
}
方式3:
public class User {}
@Configuration
public class UserConfig {
    @Bean
    public User user() {
        return new User();
    }
}
/**
 * 自定义注解
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(UserConfig.class)
public @interface EnableUser {}
/**
 * 两个不属于父子包关系 需要扫描范围是当前引导类所在包及其子包
 * //3.可以对Import注解进行封装。
 */
@SpringBootApplication
@EnableUser
public class Springboot8EnableApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Springboot8EnableApplication.class, args);
        //1.获取Bean
        Object user = context.getBean("user");
        System.out.println(user);
    }
}

-1637053496554)]

方式1:

在springboot8-enable-other中创建

public class User {}
package com.lanou.config;

@Configuration
public class UserConfig {
    @Bean
    public User user() {
        return new User();
    }
}

在springboot8-enable中创建

/**
 * @ComponentScan("") :扫描范围是当前引导类所在包及其子包
 * com.lanou.springboot8enable;
 * com.lanou.config;
 * 两个不属于父子包关系
 * //1.使用@ComponentScan扫描com.lanou.config包
 */
@SpringBootApplication
@ComponentScan("com.lanou.config")//把配置类所在的包添加到扫描的范围里面
public class Springboot8EnableApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Springboot8EnableApplication.class, args);
        //1.获取Bean
        Object user = context.getBean("user");
        System.out.println(user);
    }
}
方式2:

在springboot8-enable-other中创建

public class User {}
@Configuration
public class UserConfig {
    @Bean
    public User user() {
        return new User();
    }
}

在springboot8-enable中创建

/**
 * @ComponentScan("") :扫描范围是当前引导类所在包及其子包
 * com.lanou.springboot8enable;
 * com.lanou.config;
 * 两个不属于父子包关系
 * //2.使用@Import注解,加载类。这些类都会被Spring创建,并且放入IOC容器
 */
@SpringBootApplication
@Import(UserConfig.class)//把配置类所在的包添加到扫描的范围里面
public class Springboot8EnableApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Springboot8EnableApplication.class, args);
        //1.获取Bean
        Object user = context.getBean("user");
        System.out.println(user);
    }
}
方式3:
public class User {}
@Configuration
public class UserConfig {
    @Bean
    public User user() {
        return new User();
    }
}
/**
 * 自定义注解
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(UserConfig.class)
public @interface EnableUser {}
/**
 * 两个不属于父子包关系 需要扫描范围是当前引导类所在包及其子包
 * //3.可以对Import注解进行封装。
 */
@SpringBootApplication
@EnableUser
public class Springboot8EnableApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Springboot8EnableApplication.class, args);
        //1.获取Bean
        Object user = context.getBean("user");
        System.out.println(user);
    }
}
  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Boot整合指的是将Spring Boot与其他技术或框架集成在一起,以实现更强大的功能或特性。其中,常见的整合包括数据库整合、Swagger整合等。 对于数据库整合,可以使用Spring Boot提供的JDBC Starter和相应的数据库驱动依赖(如MySQL Connector)来连接数据库并进行数据操作。通过配置数据源的相关参数,可以在应用启动时自动加载对应的自动装配类,实现数据库的初始化和连接。 对于Swagger整合,可以使用Spring Boot提供的Swagger2注解@EnableSwagger2,开启Swagger的注解。通过引入相应的Swagger依赖,可以生成API文档,并提供交互式的API界面,方便开发人员调试和测试API接口。 需要注意的是,Spring Boot的设计目的是简化Spring应用的搭建和开发过程。它采用特定的配置方式,减少了冗余的配置代码,提高了开发效率。同时,Spring Boot也具有自动装配、内嵌服务器等特性,使得应用部署和运行更加方便。 总结起来,Spring Boot整合是通过引入相应的依赖和注解,将Spring Boot与其他技术或框架集成在一起,以实现更强大的功能和特性。常见的整合包括数据库整合和Swagger整合等。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [JAVA高级篇--springboot自动装配](https://blog.csdn.net/lpt1314/article/details/125943497)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [springboot框架整合](https://blog.csdn.net/DDHuao/article/details/130077877)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值