完成这项任务前要配合redis数据库进行
配置如下:
yml文件:
#=========================Redis================= redis: host: 8.130.125.162 port: 6333 password: 123456 database: 1 timeout: 18000 lettuce: pool: enabled: true max-idle: 10 min-idle: 3 max-wait: -1
1.配置QuartzConfig配置类
package com.igeek.logistics.config; import com.igeek.logistics.job.CleanImgJob; import org.quartz.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * TODO * * @author chemin * @since 2024/7/16 */ @Configuration public class QuartzConfig { //定义清除图片的工作明细 @Bean public JobDetail cleanImgJobDetail(){ return JobBuilder.newJob(CleanImgJob.class).storeDurably().build(); } //定义清除图片的触发器 @Bean public Trigger cleanImgTrigger(){ //构建定时任务,并指定cron表达式 // 0 0 2 * * ? 每天凌晨两点 // 0/20 * * * * ? 每隔20s执行 //0/5 * * * * ? 每隔5s执行一次 ScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/5 * * * * ? "); return TriggerBuilder.newTrigger().forJob(cleanImgJobDetail()).withSchedule(scheduleBuilder).build(); } } 在里面进行规定定时删除的时间
2.配置RedisConfig配置类
package com.igeek.logistics.config; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import java.lang.reflect.Method; import java.time.Duration; /** * @Author chenmin * @Description TODO */ //配置类 @Configuration //开启缓存 @EnableCaching public class RedisConfig { /** * 自定义key规则 * @return */ @Bean public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { StringBuilder sb = new StringBuilder(); //key 会追加上类的名字 sb.append(target.getClass().getName()); //key 会追加上方法的名字 sb.append(method.getName()); for (Object obj : params) { //key 会追加上形参的名字 sb.append(obj.toString()); } return sb.toString(); } }; } /** * 其实SpringBoot自动帮我们在容器中生成了一个RedisTemplate和一个StringRedisTemplate。 * 但是,这个RedisTemplate的泛型是<Object,Object>,写代码不方便,需要写好多类型转换的代码;我们需要一个泛型为<String,Object>形式的RedisTemplate * 同时,设置key-value的序列化方式 */ @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<String, Object>(); template.setConnectionFactory(factory); // 设置序列化参数 StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值 Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class); ObjectMapper om = new ObjectMapper(); // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常 om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); //解决jackson2无法序列化LocalDateTime的问题,这里扩展一个LocalDateTime类型,它是日期类型对象 jdk1.8出的(并且这个类是不可变的和线程安全的,可以研究一下它的API),当然还需要对这个对象进行json格式的转换,如下: om.disable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS); om.registerModule(new JavaTimeModule()); jackson2JsonRedisSerializer.setObjectMapper(om); // key采用String的序列化方式 template.setKeySerializer(stringRedisSerializer); // hash的key也采用String的序列化方式 template.setHashKeySerializer(stringRedisSerializer); // value序列化方式采用jackson template.setValueSerializer(jackson2JsonRedisSerializer); // hash的value序列化方式采用jackson template.setHashValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } /** * 设置CacheManager缓存规则 * @param factory * @return */ @Bean public CacheManager cacheManager(RedisConnectionFactory factory) { RedisSerializer<String> redisSerializer = new StringRedisSerializer(); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); //解决查询缓存转换异常的问题 ObjectMapper om = new ObjectMapper(); // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常 om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); //解决jackson2无法序列化LocalDateTime的问题,这里扩展一个LocalDateTime类型,它是日期类型对象 jdk1.8出的(并且这个类是不可变的和线程安全的,可以研究一下它的API),当然还需要对这个对象进行json格式的转换,如下: om.disable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS); om.registerModule(new JavaTimeModule()); jackson2JsonRedisSerializer.setObjectMapper(om); // 配置序列化(解决乱码的问题),过期时间600秒 RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofSeconds(4*60*60)) //指定缓存的过期时间 //.prefixCacheNameWith("") //指定前缀 //.disableCachingNullValues() //不缓存空值 .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)); RedisCacheManager cacheManager = RedisCacheManager.builder(factory) .cacheDefaults(config) .build(); return cacheManager; } } 这个配置类的目的在于配置
@Autowired private RedisTemplate<String,Object> redisTemplate;
自带的是一个RedisTemplate<Objet,Object> redisTemplate;
改成我们自己需求的
3.写出RedisImgConstant常量
package com.igeek.logistics.constant; public class RedisImgConstant { //记录上传图片 public static final String UPLOAD_IMG = "upload_img"; //记录实际在数据库中的图片 public static final String UPLOAD_DB_IMG = "upload_db_img"; } 目的在于定义记录上传图片以及记录实际在数据库中的图片的键的常量
4.写出CleanImgJob
package com.igeek.logistics.job;
import com.igeek.logistics.constant.RedisImgConstant;
import com.igeek.logistics.utils.QiniuUtils;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.util.CollectionUtils;
import java.util.Set;
/**
* TODO
*
* @author chemin
* @since 2024/7/16
*/
@Slf4j
public class CleanImgJob extends QuartzJobBean {
@Autowired
private RedisTemplate<String,Object> redisTemplate;
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
log.info("--------------> 执行删除图片的定时任务....");
//差集 查询出不在数据库中使用的图片信息
Set<Object> set = redisTemplate.opsForSet().difference(RedisImgConstant.UPLOAD_IMG, RedisImgConstant.UPLOAD_DB_IMG);
if(!CollectionUtils.isEmpty(set)){
for (Object o : set) {
String img = o.toString();
//七牛云删除图片
boolean flag = QiniuUtils.deleteFromQiniu(img);
if(flag){
//Redis中删除图片
redisTemplate.opsForSet().remove(RedisImgConstant.UPLOAD_IMG , img);
log.info("{} 删除成功" , img);
}
}
}
}
}
目的在于完成具体的清除图片任务
5.最后一步
分别在
String picName = QiniuUtils.uploadForQiniu(inputStream,newName); if (StringUtils.hasLength(picName)){ //记录实际在数据库中的图片数据信息 Set类型:无序不重复 差集 redisTemplate.opsForSet().add(RedisImgConstant.UPLOAD_IMG ,picName); return new Result(true,"头像上传成功",picName); }
以及
Boolean flag = warehouseManagementService.post(warehouseManagement); if (flag){ //记录实际在数据库中的图片数据信息 Set类型:无序不重复 差集 redisTemplate.opsForSet().add(RedisImgConstant.UPLOAD_DB_IMG , warehouseManagement.getAvatar()); return new Result(true, MessageConstant.ADD_CHECKITEM_SUCCESS); }
完成即可