SPRINGBOOT高级教程知识

时间:2024-05-05 12:10:47

**************************************************************************************************************************************************************

1、Springboot与缓存
【1】访问量大、临时性数据
【2】JSR107(用的少)、缓存抽象

**************************************************************************************************************************************************************

2、Spring缓存抽象
【1】CacheManager与Cache获取
【2】@Cacheable、@CacheEvict、@CachePut、@EableCaching、keyGenerator、serialize

**************************************************************************************************************************************************************

3、缓存-基本环境搭建
【1】BigController 
package com.day.study.controller;
import com.day.study.mapper.BigMapper;
import com.day.study.pojo.Employee;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class BigController {
    @Resource
    BigMapper bigMapper;
    @GetMapping("/employee")
    public Employee selectEmployee(Employee employee) {
        return bigMapper.selectEmployeeById(employee);
    }
}

**************************************************************************************************************************************************************

4、Cacheable初体验
【1】开启基于注解的缓存 @EnableCaching在SpringBoot上面;
【2】标注缓存注解即可
【3】如果没有缓存,都是每次都从数据库拿到
# log
logging.level.com.day.study.mapper=debug
【4】标记可以用缓存的Mapper中的方法
package com.day.study.mapper;
import com.day.study.pojo.Employee;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.cache.annotation.Cacheable;
@Mapper
public interface BigMapper {
    // 查询
    @Cacheable(cacheNames = "employee")
    Employee selectEmployeeById(@Param("employee") Employee employee);
    // 添加
    void insertEmployee(@Param("employee") Employee employee);
    // 修改
    void updateEmployee(@Param("employee") Employee employee);
    // 删除
    void deleteEmployee(@Param("employee") Employee employee);
}
【5】Controller里也要同步
package com.day.study.controller;
import com.day.study.mapper.BigMapper;
import com.day.study.pojo.Employee;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class BigController {
    @Resource
    BigMapper bigMapper;

    @Cacheable(cacheNames = "employee")
    @GetMapping("/employee")
    public Employee selectEmployee(Employee employee) {
        return bigMapper.selectEmployeeById(employee);
    }
}
【6】CacheManager 缓存管理器、Condition在满足条件的情况下才缓存
【7】还有异步等模式

**************************************************************************************************************************************************************

5、缓存工作原理与执行流程
【1】自动配置类、缓存配置类
【2】注册了一个缓存管理器
【3】生成Key的策略、@Cacheable标注的方法执行之前会先看缓存中是否存在,按照key去缓存查询
【4】核心:
(1)CacheManager 按照名字得到Cache组件
(2)Key是使用SimpleKeyGenerator生成的
(3)根据Key看缓存是否存在,不存在查,存在用

**************************************************************************************************************************************************************

6、@Cacheable别的属性
【1】cacheNames和value一样,可以指定多个名字
【2】key="#root.methodName+'['+#id+']'"
【3】condition 在某种条件满足的时候才缓存,如="#a0>1"
【4】unless="#a0==2" 如果第一个参数的值为2则不缓存

**************************************************************************************************************************************************************

7、缓存CachePut概述
【1】既调用方法,又更新缓存数据:典型场景-修改数据库的某个数据,同时更新缓存
【2】缓存和CachePut更新缓存的ID必须一致,不然就出现不一致了。(没有Redis好用!!!!!!!!!!!!!!!!!!!!)
package com.day.study.controller;
import com.day.study.mapper.BigMapper;
import com.day.study.pojo.Employee;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class BigController {
    @Resource
    BigMapper bigMapper;
    @Cacheable(cacheNames = "employee", key = "#employee.id")
    @GetMapping("/selectEmployee")
    public Employee selectEmployee(Employee employee) {
        return bigMapper.selectEmployeeById(employee);
    }
    @CachePut(cacheNames = "employee", key = "#employee.id")
    @GetMapping("/updateEmployee")
    public Employee updateEmployee(Employee employee) {
        bigMapper.updateEmployee(employee);
        return employee;
    }
}

**************************************************************************************************************************************************************

8、缓存CacheEvict
【1】缓存删除
【2】删除后就回重新从数据库查询,不如Redis
    @Resource
    BigMapper bigMapper;
    @Cacheable(cacheNames = "employee", key = "#employee.id")
    @GetMapping("/selectEmployee")
    public Employee selectEmployee(Employee employee) {
        return bigMapper.selectEmployeeById(employee);
    }
    @CachePut(cacheNames = "employee", key = "#employee.id")
    @GetMapping("/updateEmployee")
    public Employee updateEmployee(Employee employee) {
        bigMapper.updateEmployee(employee);
        return employee;
    }
    @CacheEvict(cacheNames = "employee", key = "#employee.id")
    @GetMapping("/deleteEmployee")
    public Employee deleteEmployee(Employee employee) {
        System.out.println("执行删除...");
        //bigMapper.deleteEmployee(employee);
        return employee;
    }

**************************************************************************************************************************************************************

9、缓存Caching与CacheConfig
【1】复杂的缓存规则组合
【2】CacheConfig在Controller上面标记,这样不用每一个都单独标记了

**************************************************************************************************************************************************************

10、Redis环境配置
【1】缓存中间件redis、memcached、ehcache
【2】整合redis作为缓存,就以阿里云的redis为例(用docker也可以安装)
【3】用RDM连接后可以界面化操作redis
【4】执行一些基本的控制台操作命令

**************************************************************************************************************************************************************

11、RedisTemplate与序列化机制
【1】redis的startes
 <!--redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
【2】数据类型字符串String、List 列表、Set集合、Hash散列、Zset集合
【3】properties配置
# redis
spring.redis.host=wdfgdzx.top
spring.redis.port=6379
spring.redis.password=s19911009!
spring.redis.database=0
【4】测试相关方法
(1)保存对象需要序列化
(2)以JSON保存数据
(3)存对象都是二进制,来改变其序列化规则
package com.day.study.config;

import com.day.study.pojo.Employee;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;

@Configuration
public class MyRedisConfig {
    @Bean
    public RedisTemplate<Object, Employee> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws Exception {
        RedisTemplate<Object, Employee> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer<Employee> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Employee.class);
        redisTemplate.setDefaultSerializer(jackson2JsonRedisSerializer);
        return redisTemplate;
    }
}
(4)方法
package com.day.study.controller;
import com.day.study.mapper.BigMapper;
import com.day.study.pojo.Employee;
import org.junit.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.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class Controller {
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    RedisTemplate<Object, Employee> redisTemplate;
    @Autowired
    BigMapper bigMapper;

    @Test
    public void contextLoads() {
        //stringRedisTemplate.opsForValue().append("msg", "Hello");
        //System.out.println(stringRedisTemplate.opsForValue().get("msg"));
        //stringRedisTemplate.opsForList().leftPush("myList", "1");
        //stringRedisTemplate.opsForList().leftPush("myList", "2");
        Employee employee = new Employee();
        employee.setId(1);
        employee.setEmail("wdfgdzx@163.com");
        redisTemplate.opsForValue().set("emp01", employee);
    }
}

**************************************************************************************************************************************************************

12、缓存-自定义CacheManager
【1】被RedisCacheManager接管了
【2】技术更新太快了,老师一堂课不如网上百度一下
package com.day.study.config;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
@Configuration
public class MyRedisConfig {

    @Bean
    public RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) {
        CacheProperties.Redis redisProperties = cacheProperties.getRedis();
        RedisCacheConfiguration config = RedisCacheConfiguration
                .defaultCacheConfig();
        config = config.serializeValuesWith(RedisSerializationContext.SerializationPair
                .fromSerializer(new GenericJackson2JsonRedisSerializer()));
        //还有另外一种写法
        if (redisProperties.getTimeToLive() != null) {
            config = config.entryTtl(redisProperties.getTimeToLive());
        }
        if (redisProperties.getKeyPrefix() != null) {
            config = config.prefixKeysWith(redisProperties.getKeyPrefix());
        }
        if (!redisProperties.isCacheNullValues()) {
            config = config.disableCachingNullValues();
        }
        if (!redisProperties.isUseKeyPrefix()) {
            config = config.disableKeyPrefix();
        }
        return config;
    }
}
【3】名称也可以自定义  @Cacheable(value = "files", key = "'selfDefineName'")
【4】这个MyRedisConfig 就比较实用了,适用多个类
package com.day.study.controller;
import com.day.study.mapper.BigMapper;
import com.day.study.pojo.Department;
import com.day.study.pojo.Employee;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class BigController {
    @Resource
    BigMapper bigMapper;
    @Cacheable(cacheNames = "employee", key = "#employee.id")
    @GetMapping("/selectEmployee")
    public Employee selectEmployee(Employee employee) {
        return bigMapper.selectEmployeeById(employee);
    }
    @CachePut(cacheNames = "employee", key = "#employee.id")
    @GetMapping("/updateEmployee")
    public Employee updateEmployee(Employee employee) {
        bigMapper.updateEmployee(employee);
        return employee;
    }
    @CacheEvict(cacheNames = "employee", key = "#employee.id")
    @GetMapping("/deleteEmployee")
    public Employee deleteEmployee(Employee employee) {
        System.out.println("执行删除...");
        //bigMapper.deleteEmployee(employee);
        return employee;
    }
    @Cacheable(cacheNames = "department", key = "'department'")
    @GetMapping("/selectDepartment")
    public Department department(Department department) {
        return bigMapper.selectDepartmentById(department);
    }
}
【5】也可以拿到缓存模板直接使用
@Resource
private StringRedisTemplate stringRedisTemplate;

**************************************************************************************************************************************************************

13、消息中间件概述
【1】用户注册—>发邮件—>发短信怎么优化处理?
(1)写数据库后:多线程边发邮件,边发短信
(2)消息队列,写数据库后,写进消息队列(消息队列再发短信、发邮件)
【2】应用解耦:订单 VS 库存
(1)订单、库存单独抽取出来
(2)订单消费、库存订阅消息队列
【3】流量削峰
用户请求—>消息队列(1W+)—>秒杀业务处理
【4】消息服务:消息代理(服务器)、目的地
(1)目的地包括:队列(Queue)-点对点通信、主体(Topic)-发布订阅模式
(2)点对点 A 发给队列—>队列—>B B从队列收
(3)发布订阅:A发布到主题里,B C D同时监听收到
【5】JMS:JAVA MESSAGE SERVICE;Java消息服务
(1)基于JVM消息代理规范,如ActiveMQ、HornetMQ就是JMS的实现
【6】AMQP高级消息队列协议,兼容JMS,大名鼎鼎的RabbitMQ就是AMQP的实现
【7】Springboot的配置
(1)RabbitAutoConfiguration

**************************************************************************************************************************************************************

14、RabbitMQ概述
【1】RMQ:核实概念-Message(消息头、消息体)
(1)路由键、优先权、是否持久化存储
(2)生产者:消息生产者、发布给交换器
(3)交换器:四种类型direct点对点;fanout、topic、headers实现发布订阅模型
(4)消息队列:用来保存消息的
(5)绑定:交换器与队列之间的绑定关系
(6)网络连接:如TCP连接
(7)Channel:信道,一个TCP连接可以开多个信道
(8)消费者
(9)虚拟主机
(10)Broke消息代理,就是服务器

**************************************************************************************************************************************************************

15、RMQ的核心运行机制
【1】增加了Exchange(四种类型)与Binding的角色
(1)direct 直连型
(2)Fanout Exchange,接收到消息后,会分发给它自己的所有队列,速度最快
(3)Topic Exchange,支持模糊匹配(感觉不实用)

**************************************************************************************************************************************************************

16、RMQ安装测试
【1】docker pull rabbitmq:3-management
【2】docker run -d -p 5672:5672 -p 15672:15672 --name my_rabbitmq 镜像ID
【3】访问http://192.168.0.105:15672/
【4】账号+密码 guest guest
【5】添加三个交换器
exchange.direct     direct	D		
exchange.fanout    fanout	D		
exchange.topick     topic	D	
【6】建立四个队列
wdfgdzx
wdfgdzx.news
wdfgdzx.emps
it.news
【7】绑定交互器与队列
【8】可以在界面测试不同模式发送消息,消息的接受情况

**************************************************************************************************************************************************************

17、RabbitTemplate发送接受消息与序列化机制
【1】引入MAVEN依赖
 <!--amqp-->
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
【2】RabbitTemplate类似于RedisTemplate
package com.day.study.controller;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@RunWith(SpringRunner.class)
@SpringBootTest
public class Controller {
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Test
    public void contextLoads() {
        // rabbitTemplate.send(exchange,routeKey,message);
        // rabbitTemplate.convertAndSend(exchange, routeKey, object);
        Map<String, Object> map = new HashMap<>();
        map.put("msg", "这是第一个消息");
        map.put("data", Arrays.asList("Hello", 123, false));
        rabbitTemplate.convertAndSend("exchange.direct",
                "wdfgdzx.news",
                map);// 对象默认被序列化以后发送出去
    }
    @Test
    public void receive() {
        // 接受数据
        Object object = rabbitTemplate.receiveAndConvert("wdfgdzx.news");
        System.out.println(object.getClass());
        System.out.println(object);
    }
}
【3】配置存储JSON
package com.day.study.config;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyRMQConfig {
    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }
}
【4】其他模式只需要指定交换器和队列就行了,听君一席话,胜过单独学RMQ,使用主义最重要!!!

**************************************************************************************************************************************************************

18、消息监听@RabbitLister与@EnableRabbit
【1】@RabbitListener(queues = "wdfgdzx.news")+@EnableRabbit // 开启基于注解RMQ
开启自动监听,并实时接受消息
【2】Service
package com.day.study.service;

import com.day.study.pojo.Employee;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;

@Service
public class EmployeeService {
    @RabbitListener(queues = "wdfgdzx.news")
    public void receive(Employee employee) {
        System.out.println("收到消息..." + employee);
    }
    @RabbitListener(queues = "wdfgdzx.news")
    public void receive02(Message message) {
        System.out.println("收到消息..." + message.getMessageProperties() + "..." + message.getBody());
    }
}
【3】启动类
package com.day.study;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@EnableCaching
@SpringBootApplication
@MapperScan("com.day.study.mapper")
@EnableRabbit // 开启基于注解RMQ
public class SpringBoot {
    public static void main(String[] args) {
        SpringApplication.run(SpringBoot.class, args);
    }
}
【4】测试控制器
package com.day.study.controller;
import com.day.study.pojo.Employee;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@RunWith(SpringRunner.class)
@SpringBootTest
public class Controller {
    @Autowired
    RabbitTemplate rabbitTemplate;

    @Test
    public void contextLoads() {
        // rabbitTemplate.send(exchange,routeKey,message);
        // rabbitTemplate.convertAndSend(exchange, routeKey, object);
        Employee employee = new Employee();
        employee.setId(1);
        employee.setName("陈翔");
        employee.setEmail("cx@163.com");
        rabbitTemplate.convertAndSend("exchange.fanout",
                "wdfgdzx.news",
                employee);// 对象默认被序列化以后发送出去
    }

    @Test
    public void receive() {
        // 接受数据
        Object object = rabbitTemplate.receiveAndConvert("wdfgdzx.news");
        System.out.println(object.getClass());
        System.out.println(object);
    }
}

**************************************************************************************************************************************************************

19、AmqpAdmin管理组件的使用
【1】帮助我们创建删除交换器和队列
 @Autowired
    AmqpAdmin amqpAdmin;
    @Test
    public void createExchange() {
        // 交换器
        amqpAdmin.declareExchange(new DirectExchange("amqpadmin.exchange"));
        System.out.println("创建完成");
        // 队列
        amqpAdmin.declareQueue(new Queue("amqpadmin.queue", true));
        System.out.println("创建完成");
        // 绑定关系
        amqpAdmin.declareBinding(new Binding("amqpadmin.queue",
                Binding.DestinationType.QUEUE,
                "amqpadmin.exchange",
                "amqp.Hello", null));
        System.out.println("绑定成功");
    }

**************************************************************************************************************************************************************

20、Elasticsearch概述与安装
【1】ElasticSearch是全文搜索引擎的首选
【2】环境搭建docker pull elasticsearch
【3】docker run -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -d -p 9200:9200 -p 9300:9300 --name es 镜像ID
【4】docker rm -f $(docker ps -a -q)
【5】访问http://192.168.0.105:9200/ 能看到JSON说明就安装成功了

**************************************************************************************************************************************************************

21、ES入门
【1】JSON代表数据对象
【2】索引(库)、类型(表)、文档(记录)、属性(列)
【3】PUT /megacorp/employee/1
{
"fristName":"陈",
"lastName":"翔",
"age":25,
"about":"I love china",
"interests":["ball","play"]
}
【4】用postman发送请求,注意是PUT方式http://192.168.0.105:9200/megacorp/employee/1
(1)然后body-raw-JSON
(2)复制粘贴数据,发起请求即可
{
"fristName":"陈",
"lastName":"翔",
"age":25,
"about":"I love china",
"interests":["ball","play"]
}
【5】寻找数据 GET http://192.168.0.105:9200/megacorp/employee/3
【6】其他操作
(1)HEAD请求,看是否存在,存在200,不存在404 http://192.168.0.105:9200/megacorp/employee/3
(2)DELETE删除请求http://192.168.0.105:9200/megacorp/employee/3
(3)更新也是用PUT,会看到_version有变化
【7】GET http://192.168.0.105:9200/megacorp/employee/_search 查所有
【8】按条件找
http://192.168.0.105:9200/megacorp/employee/_search?q=lastName:球
【9】用JSON规则匹配查找
(1)POST  http://192.168.0.105:9200/megacorp/employee/_search
(2)JSON过滤规则
{
    "query":{
        "match":{
            "lastName":"头"
        }
    }
}
(3)其他过滤规则
{
    "query":{
        "match":{
            "about":"china"
        }
    }
}
(4)找到并高亮
{
    "query":{
        "match":{
            "about":"china"
        }
    },
    "highlight":{
        "fields":{
            "about":{}
        }
    }
}

**************************************************************************************************************************************************************

22、Springboot整合Jest操作ES
【1】引入依赖
  <!--elasticsearch-->
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
【2】两种技术交互Jest与SpringData ElasticSearch
(1)Jest 需要导入工具包
(2)我觉得还是用官方的SpringData操作

**************************************************************************************************************************************************************

23、整合SpringDataElasticSearch
【1】注意版本适配关系
【2】如果不适配,需要将es版本调成一致(可以从maven依赖查看版本)
(1)docker pull elasticsearch:6.4.3
(2)/usr/share/elasticsearch/config
(3)docker run -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -d -p 9200:9200 -p 9300:9300 --name es  01e5bee1e059
(4)docker rm -f $(docker ps -a -q)
(5)docker exec -it es /bin/bash 进到docker里yum install net-tools,可以用netstat -lnp|grep 9查看端口监听情况
(6)访问http://192.168.0.105:9200/,注意cluster_name对应的值,这个很重要
(7)历经艰险,ES重要配置成功了
【3】解决es与redis的netty-transport版本冲突
public class SpringBoot {
    public static void main(String[] args) {
        // 解决es与redis的netty-transport版本冲突
        System.setProperty("es.set.netty.runtime.available.processors", "false");
        SpringApplication.run(SpringBoot.class, args);
    }
}
【4】插入ES数据
@Resource
    EmployeeRepository employeeRepository;

    @RequestMapping("/insertEs")
    public String insertEs(Employee employee) {
        employee.setId(110161);
        employee.setName("陈翔...");
        employeeRepository.index(employee);
        return "es 插入成功";
    }
【5】查询ES数据
http://192.168.0.105:9200/wdfgdzx/employee/_search
【6】还可以通过另一种方式
(1)service里写方法
package com.day.study.service;
import com.day.study.pojo.Employee;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import java.util.List;
public interface EmployeeRepository extends ElasticsearchRepository<Employee, Integer> {
    public List<Employee> findByEmployeeName(String name);
}
(2)controller写查询
    @RequestMapping("/selectEs")
    public List<Employee> selectEs(Employee employee) {
        List<Employee> employeeList = employeeRepository.findByEmployeeName("陈");
        return employeeList;
    }
(3)浏览器查询http://localhost:8080/selectEs
[{"id":110161,"employeeName":"陈翔...","email":null}]

**************************************************************************************************************************************************************

24、Springboot执行任务
【1】异步、定时、发邮件任务
【2】异步类
package com.day.study.service;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class AsyncService {
    @Async //告诉Spring 这是一个异步方法
    public void say() throws InterruptedException {
        Thread.sleep(3000);
        System.out.println("处理数据中...");
    }
}
【3】启动类
@EnableAsync // 开启异步注解
【4】Controller
@RequestMapping("/say")
    public String say() throws InterruptedException {
        asyncService.say();
        return "调用成功...";
    }

**************************************************************************************************************************************************************

25、定时任务
【1】比如每天凌晨,跑前一天的数据
【2】类
package com.day.study.service;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Service
public class ScheduleService {
    // 六位表达式
    @Scheduled(cron = "0 * * * * MON-SAT")  //每整分钟就打印一个Hello
    public void say() {
        System.out.println("Hello...");
    }
}
【3】启动类
@EnableScheduling
【4】每分钟都会执行一次方法
【5】具体的写法可以百度

**************************************************************************************************************************************************************

26、邮件任务
【1】依赖
<!--mail-->
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
</dependency>
【2】配置
# mail
spring.mail.host=220.181.15.111
spring.mail.username=wdfgdzx@126.com
spring.mail.password=GAVHJSFHPCUOYMPP
【3】测试发送邮件
 @Autowired
    JavaMailSenderImpl javaMailSender;
    @org.junit.Test
    public void textMail() {
        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
        //邮件设置
        simpleMailMessage.setSubject("通知-会议");
        simpleMailMessage.setText("今晚7:30开会");
        simpleMailMessage.setTo("wdfgdzx@163.com");
        simpleMailMessage.setFrom("wdfgdzx@126.com");
        javaMailSender.send(simpleMailMessage);
    }
    @org.junit.Test
    public void textMailTwo() throws Exception {
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
        mimeMessageHelper.setSubject("通知-会议");
        mimeMessageHelper.setText("<b style='color:red'>今晚7:30开会</b>", true);
        mimeMessageHelper.setTo("wdfgdzx@163.com");
        mimeMessageHelper.setFrom("wdfgdzx@126.com");
        //上传附件
        mimeMessageHelper.addAttachment("1.jpg", new File("src/main/resources/mapper/BigMapper.xml"));
        javaMailSender.send(mimeMessage);
    }

**************************************************************************************************************************************************************

27、Springboot与安全
【1】Spring Security
【2】就是为了实现认证和授权
【3】依赖引入
 <!--security-->
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
</dependency>
【4】引入指定页面thymeleaf
  <!--thymeleaf-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
【5】@org.springframework.stereotype.Controller

**************************************************************************************************************************************************************

28、权限控制-注销
【1】配置类
package com.day.study.config;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@EnableWebSecurity //内部带Configuration所以无需再次标注
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        //super.configure(httpSecurity);
        // 定制请求的授权规则
        httpSecurity.authorizeRequests().antMatchers("/index")
                .permitAll()
                .antMatchers("/low/**").hasRole("VIP")
                .antMatchers("/high/**").hasRole("H VIP");
        // 开启自动配置的登录功能
        httpSecurity.formLogin();
        // 1、/login来到登录页 2、重定向到error表示登录失败 3、更多详析规则
        // 效果就是没有权限,就来到登录页面
        // 开启自动配置的注销功能
        httpSecurity.logout().logoutSuccessUrl("/index");
        // 1、会清空session 2、注销成功跳转的页面
    }
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //super.configure(auth);
        // 按道理从数据库拿,但是这里演示就存内存
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("VIP").password(new BCryptPasswordEncoder().encode("123")).roles("VIP")
                .and()
                .withUser("H VIP").password(new BCryptPasswordEncoder().encode("123")).roles("H VIP");
    }
}
【2】配置@org.springframework.stereotype.Controller
package com.day.study.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@org.springframework.stereotype.Controller
public class Controller {
    @RequestMapping("index")
    public ModelAndView index() {
        ModelAndView mv = new ModelAndView("index");
        return mv;
    }
    @RequestMapping("low")
    public ModelAndView low() {
        ModelAndView mv = new ModelAndView("low");
        return mv;
    }
    @RequestMapping("high")
    public ModelAndView high() {
        ModelAndView mv = new ModelAndView("high");
        return mv;
    }
}
【3】没有权限看不到,这个就不配置了
(1)界面写的也有点冗余,不如用vue写了

**************************************************************************************************************************************************************

30、定制登录页
【1】就是使用cookie记录用户信息
【2】可以定制Security的登录页面

**************************************************************************************************************************************************************

31、Springboot与分布式
【1】Dubbo/Zookeeper、Springboot/Cloud
【2】注册中心

**************************************************************************************************************************************************************

32、Zookeeper安装
【1】docker rm -f $(docker ps -a -q)
【2】docker pull zookeeper
【3】docker run --name zk -p 2181:2181 --restart always -d 979f6ccbba92
【4】启动成功

**************************************************************************************************************************************************************

33、整合Dubbo与Zookeeper
【1】整合步骤
(1)服务提供者注册到注册中心
(2)引入依赖
(3)配置properties
(4)启动服务

**************************************************************************************************************************************************************

34、SpringCloud的注册中心
【1】是分布式的整体解决方案
【2】服务发现、负载均衡、断路器、服务网关、分布式配置
【3】引依赖
 <!--eureka server-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            <version>2.1.6.RELEASE</version>
        </dependency>
        <!--eureka client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.1.6.RELEASE</version>
        </dependency>
【4】配置properties
server.port=8083
# 实例的主机名
eureka.instance.hostname=eureka-server
# 不把自己注册
eureka.client.register-with-eureka=false
# 不获取服务注册信息
eureka.client.fetch-registry=false
eureka.client.service-url.defaultZone=http://localhost:8083/eureka/
【5】访问http://localhost:8083可以看到注册中心
【6】provider
server.port=8081
spring.application.name=provider
# 实例的主机名       注册服务时使用IP地址
eureka.instance.prefer-ip-address=true
eureka.client.service-url.defaultZone=http://localhost:8083/eureka/
【7】可以配置多个端口指向注册中心的

**************************************************************************************************************************************************************

36、配置消费者
【1】properties
server.port=8082
spring.application.name=consumer
# 实例的主机名       注册服务时使用IP地址
eureka.instance.prefer-ip-address=true
eureka.client.service-url.defaultZone=http://localhost:8083/eureka/
【2】Controller
package com.day.consumer.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@RestController
public class ConsumerController {
    @Resource
    RestTemplate restTemplate;
    @RequestMapping("buyTicket")
    public String buyTicket(String name) {
        String getTicketFromServer = restTemplate.getForObject("http://PROVIDER/getTicket", String.class);
        return name + "购买了" + getTicketFromServer;
    }
}
【3】卧槽惊艳了,挺好用的,牛批

**************************************************************************************************************************************************************

37、Springboot开发热部署
【1】推荐使用官方的spring-boot-devtools,Ctrl+F9
【2】没必要呀,手动重启不就行了

**************************************************************************************************************************************************************

38、Springboot与监控管理!!!!
【1】运维时重要的功能 spring-boot-starter-actuator
【2】依赖
<!--actuator监控模块-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
【3】配置properties
management.endpoints.web.exposure.include=*
management.endpoints.web.base-path=/
management.endpoint.health.show-details=always
management.endpoint.info.enabled=true
【4】访问监控信息
(1)http://localhost:8080/health 健康信息
(2)http://localhost:8080/auditevents 审计事件
(3)http://localhost:8080/beans 组件信息
(4)http://localhost:8080/info 配置文件里的info开头的配置
(5)http://localhost:8080/dump 线程信息
(6)http://localhost:8080/env 当前环境信息
(7)http://localhost:8080/mappings 请求映射信息
(8)http://localhost:8080/metrics 应用的各项指标

**************************************************************************************************************************************************************

39、定制端点
【1】改变端点的ID等信息
【2】开启和关闭某个端点
【3】定制根路径
【4】改变端点对应的端口号

**************************************************************************************************************************************************************

40、定制HealthIndicator
【1】这个监控可以检查不健康的配置
spring.redis.host=localhost
 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
【2】访问http://localhost:8080/health,redis的配置不正确
{"status":"DOWN","details":{"diskSpace":{"status":"UP","details":{"total":120032587776,"free":35320840192,"threshold":10485760}},"redis":{"status":"DOWN","details":{"error":"org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to localhost:6379"}}}}
【3】定制化:
(1)实现HealthIndicator接口
(2)名字 XXXHealthIndicator
(3)加入容器中
【4】定制化实例
package com.day.study.health;

import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;

@Component
public class MyHealthIndicator implements HealthIndicator {
    @Override
    public Health health() {
        // 自定义检查方法
        // ...
        // return Health.up(); 代表健康
        return Health.down().withDetail("msg", "服务异常").build();
    }
}
【5】访问http://localhost:8080/health 的效果
{"status":"DOWN","details":{"my":{"status":"DOWN","details":{"msg":"服务异常"}},"diskSpace":{"status":"UP","details":{"total":120032587776,"free":35317649408,"threshold":10485760}},"redis":{"status":"DOWN","details":{"error":"org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to localhost:6379"}}}}