缓存
缓存的作用
- 自定义缓存,使用HashMap对象模拟一个缓存(我查出来以后,我把我的数据放在这里边,下次再查,我就从这里拿,就不走数据库了)
@Autowired
private BookDao bookDao;
private HashMap<Integer,Book> cache = new HashMap<Integer,Book>();
@Override
public Book getById(Integer id) {
//如果当前缓存中没有本次要查询的数据,则进行查询,否则直接从缓存中获取数据返回
Book book = cache.get(id);
if(book == null){
book = bookDao.selectById(id);
cache.put(id,book);
}
return book;
}
在缓存中根据id查询到一个book,如果这个book为null,也就是说不可不存在的话,那么就从数据库中查询book,查询完毕之后,再将结果放到缓存当中,如果缓存中存在,则直接返回缓存中数据。
- 获取和校验验证码案例(提供临时的数据存储空间)
private HashMap<String ,String> cache = new HashMap<String,String>();
@Override
public String get(String tele) {
String code = tele.substring(tele.length() - 6);
cache.put(tele,code);
return code;
}
@Override
public boolean check(String tele, String code) {
String queryCode = cache.get(tele);
return code.equals(queryCode);
}
获取验证码部分将tele的后六位作为验证码放入到缓存当中,校验部分将手机号和验证码作为参数传递,并从缓存当中获取对应t的queryCode,并将缓存中的code与参数code的请比较。
- 缓存是一种介于数据永久存储介质与数据应用之间的数据临时存储介质
- 使用缓存可以有效的减少低速数据读取过程的次数( 例如磁盘I0),提高系统性能
- 缓存不仅可以用于提高永久性存储介质的数据读取效率,还可以提供临时的数据存储空间
Spring缓存使用方式
SpringBoot提供了缓存技术,方便缓存使用。缓存应该怎么设计?在程序中应该有这么几个操作,第一要告诉程序这个数据进缓存,第二要告诉程序这个数据从缓存读。
- 导入缓存技术对应的坐标
<!--cache-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
- 启用缓存,就在引导类上面添加注解@EnabledCaching,有了这个注解就可以开启缓存功能
@SpringBootApplication
//开启缓存功能
@EnableCaching
public class Springboot19CacheApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot19CacheApplication.class, args);
}
}
- 设定使其使用缓存,在业务方法上添加注解 @Cacheable()
该注解需要传入两个参数,第一个参数value需要说明缓需要存放的位置,相当于存储空间名;第二个参数key说明缓存中保存数据的名称,在参数名前加#,例如#id。
现在这个程序运行之后就会把查询的数据放到这个id作为key的那个存储空间中,当前存储空间叫cacheSpace。
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookDao bookDao;
@Cacheable(value="cacheSpace",key="#id")
public Book getById(Integer id) {
return bookDao.selectById(id);
}
}
具体的表现形式为,第一次发起查询请求在控制台上输出查询结果,第二次发起同样的查询请求,就不会再控制台上输出查询结果,因为并没有通过查询数据库而是查询缓存返回结果。
手机验证码案例——生成验证码
需求
- 输入手机号获取验证码,组织文档以短信形式发送给用户(页面模拟)
- 输入手机号和验证码验证结果
需求分析
- 提供controller, 传入手机号,业务层通过手机号计算出独有的6位验证码数据,存入缓存后返回此数据
- 提供controller, 传入手机号与验证码,业务层通过手机号从缓存中读取验证码与输入验证码进行比对,返回比对结果
步骤:
- 1. 定义实体类,封装属性
@Data
public class SMSCode {
private String tele;
private String code;
}
- 2. 定义业务层(Service)接口与实现类
当前方法(sendCodeToSMS)的返回值进入到这个key对应的缓存中存储起来,但是下一次他来这里检测这个key还存在,他不会再重新运行生成一次了,所以@Cacheable不适用了,我们要的仅仅是把我们这次的运行操作放到缓存中,但是不要从缓存中读,而@Cacheable不仅有往里放,还有一个往外取的功能操作。
@CachePut只有往里放,没有往外取的功能。
public interface SMSCodeService {
public String sendCodeToSMS(String tele);
public boolean checkCode(SMSCode smsCode);
}
@Service
public class SMSCodeServiceImpl implements SMSCodeService {
@Autowired
private CodeUtils codeUtils;
@CachePut(value = "smsCode", key = "#tele")
public String sendCodeToSMS(String tele) {
String code = codeUtils.generator(tele);
return code;
}
public boolean checkCode(SMSCode smsCode) {
return false;
}
}
- 3. 创建用于生成验证码的CodeUtils类(根据tele和加密算法生成)
@Component
public class CodeUtils {
private String [] patch = {"000000","00000","0000","000","00","0",""};
public String generator(String tele){
int hash = tele.hashCode();
int encryption = 20206666;
long result = hash ^ encryption;
long nowTime = System.currentTimeMillis();
result = result ^ nowTime;
long code = result % 1000000;
code = code < 0 ? -code : code;
String codeStr = code + "";
int len = codeStr.length();
return patch[len] + codeStr;
}
}
- 4. 定义表现层(Controller),分别设置获取验证码和校验的方法
@RestController
@RequestMapping("/sms")
public class SMSCodeController {
@Autowired
private SMSCodeService smsCodeService;
@GetMapping
public String getCode(String tele){
String code = smsCodeService.sendCodeToSMS(tele);
return code;
}
@PostMapping
public boolean checkCode(SMSCode smsCode){
return smsCodeService.checkCode(smsCode);
}
}
手机验证码案例——验证码校验
校验即看请求参数中的code与缓存中的code是否相同。
在CodeUtils下添加,因为该类有@Component,可以以bean的形式调用,即该方法在bean里,才能加载注解,他没有走spring容器管理bean这一系列操作,是不会加载的。
//获取缓存中的验证码,要以bean 方式注入到spring的容器中
@Cacheable(value = "smsCode", key = "#tele")
public String get(String tele) {
return null;
}
此注解通过key得到缓存中的code,因为我们仅仅是通过这个方法来取缓存中的数据,所以直接return null即可,只要缓存中有数据,它就能得到,如果缓存中没有,它就会返回null。
public boolean checkCode(SMSCode smsCode) {
String code = smsCode.getCode();
//取出内存中的验证码与传递过来的验证码比对,如果相同,返回true
String cacheCode = codeUtils.get(smsCode.getTele());
return code.equals(cacheCode);
}
变更缓存供应商Ehcache
- 导入对应坐标
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
- 配置缓存技术实现使用Ehcache
spring:
cache:
type: ehcache
#ehcache配置文件路径
ehcache:
config: classpath:/ehcache.xml
对ehcache来说,这是一个spring体系外的技术,ehcache他有自己的配置,这个配置必须得加载进来。ehcache的配置有独立的配置文件格式,所以需要指定ehcache的配置文件,以便于读取相应配置。
在resources下添加ehcache.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">
<diskStore path="D:\ehcache" />
<!--默认缓存策略 -->
<!-- external:是否永久存在,设置为true则不会被清除,此时与timeout冲突,通常设置为false-->
<!-- diskPersistent:是否启用磁盘持久化-->
<!-- maxElementsInMemory:最大缓存数量-->
<!-- overflowToDisk:超过最大缓存数量是否持久化到磁盘-->
<!-- timeToIdleSeconds:最大不活动间隔,设置过长缓存容易溢出,设置过短无效果,可用于记录时效性数据,例如验证码-->
<!-- timeToLiveSeconds:最大存活时间-->
<!-- memoryStoreEvictionPolicy:缓存清除策略-->
<defaultCache
eternal="false"
diskPersistent="false"
maxElementsInMemory="1000"
overflowToDisk="false"
timeToIdleSeconds="60"
timeToLiveSeconds="60"
memoryStoreEvictionPolicy="LRU" />
<cache
<!-- 不同的缓存使用name属性来区分-->
name="smsCode"
eternal="false"
diskPersistent="false"
maxElementsInMemory="1000"
overflowToDisk="false"
timeToIdleSeconds="10"
timeToLiveSeconds="10"
memoryStoreEvictionPolicy="LRU" />
</ehcache>
在程序里面缓存的使用位置处有这几行代码
@Override
@CachePut(value = "smsCode",key="#tele")
public String sendCodeToSMS(String tele) {
String code = codeUtils.generator(tele);
return code;
}
其中value = “smsCode”这一句话代表他要去缓存中去找一个名称叫做smsCode的配置,故需要在ehcache中设定一个缓存空间名称叫做smsCode的配置。通过设置不同名称的cache来设定不同的缓存策略,应用于不同的缓存数据。
可以发现,原始代码没有任何修改,仅仅是加了一组配置就可以变更缓存供应商了,这也是springboot提供了统一的缓存操作接口的优势,变更实现并不影响原始代码的书写。
数据淘汰策略
- LRU(Least Recently Used):淘汰长时间不活动的数据
- LFU(Least Frequently Used):淘汰使用次数最少的数据
变更缓存供应商Redis
- 导入坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 修改配置
spring:
redis:
host: localhost
port: 6379
cache:
type: redis
如果需要配置redis作为缓存使用相关的配置,则其属于spring.cache.redis节点下。
spring: redis: host: localhost port: 6379 cache: type: redis redis: use-key-prefix: false # 是否使用前缀名(系统定义前缀名)值为 false, key-prefix设置无效 key-prefix: sms_ # 追加自定义前缀名 cache-null-values: false # 是否允许存储空值 time-to-live: 10s # 有效时长
占位,以后来补
任务
邮件
SpringBoot整合JavaMail
- SMTP (Simple Mail Transfer Protocol) :简单邮件传输协议,用于发送电子邮件的传输协议
- POP3 (Post Office Protocol – Version3) :用于接收电子邮件的标准协议
- IMAP (Internet Mail Access Protocol) :互联网消息协议,是POP3的替代协议
- 1.导入相应坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
- 配置邮箱的登录信息
spring:
mail:
host: smtp.126.com
username: test@126.com
password: test
消息
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/99453.html