图片云存储方案-使用Redis存储垃圾图片-使用Quartz定时任务组件清理垃圾图片

1.1介绍

在实际开发中,我们会有很多处理不同功能的服务器。例如:
应用服务器:负责部署我们的应用
数据库服务器:运行我们的数据库
文件服务器:负责存储用户上传文件的服务器
在这里插入图片描述
分服务器处理的目的是让服务器各司其职,从而提高我们项目的运行效率。
常见的图片存储方案:
方案一:使用nginx搭建图片服务器(或tomcat)(原始方法)
方案二:使用开源的分布式文件存储系统,例如Fastdfs、HDFS等
方案三:使用云存储,例如阿里云、七牛云等

1.2七牛云存储

七牛云(隶属于上海七牛信息技术有限公司)是国内领先的以视觉智能和数据智能为核心的企业级云计算服务商,同时也是国内知名智能视频云服务商,累计为70多万家企业提供服务,覆盖了国内80%网民。围绕富媒体场景推出了对象存储、融合CDN加速、容器云、大数据平台、深度学习平台等产品、并提供一站式智能视频云解决方案。为各行业及应用提供可持续发展的智能视频云生态,帮助企业快速上云,创造更广阔的商业价值。
官网:https://www.qiniu.com/
在这里插入图片描述
通过七牛云官网介绍我们可以知道其提供了多种服务,我们主要使用的是七牛云提供的对象存储服务来存储图片。

1.2.1注册、登录

要使用七牛云的服务,首先需要注册成为会员。地址:https://portal.qiniu.com/signup
在这里插入图片描述
注册完成后就可以使用刚刚注册的邮箱和密码登录到七牛云:
登录成功后点击页面右上角管理控制台:
在这里插入图片描述
注意:登录成功后还需要进行实名认证才能进行相关操作。

1.2.2新建存储空间

要进行图片存储,我们需要在七牛云管理控制台新建存储空间(用于存放我们的上传的图片)。点击管理控制台首页对象存储下的立即添加按钮,页面跳转到新建存储空间页面:
在这里插入图片描述
在这里插入图片描述
可以创建多个存储空间,各个存储空间是相互独立的.

1.2.3查看存储空间信息

存储空间创建后,会在左侧的存储空间列表菜单中展示创建的存储空间名称,点击存储空间名称可以查看当前存储空间的相关信息

在这里插入图片描述
我们可以通过外链域名来访问我们存储空间当中的图片

1.2.4开发者中心

可以通过七牛云提供的开发者中心学习如何操作七牛云服务,地址:https://developer.qiniu.com/
在这里插入图片描述
点击对象存储,跳转到对象存储开发页面,地址:https://developer.qiniu.com/kodo添加链接描述
在这里插入图片描述
七牛云提供了多种方式操作对象存储服务,本项目采用JavaSDK方式,地址:https://developer.qiniu.com/kodo/sdk/1239/java

使用JavaSDK操作七牛云需要导入如下maven坐标:
在这里插入图片描述

<dependency>
  <groupId>com.qiniu</groupId>
  <artifactId>qiniu-java-sdk</artifactId>
  <version>[7.2.0, 7.2.99]</version>
</dependency>

1.2.5鉴权

JavaSDK的所有的功能,都需要合法的授权。授权凭证的签算需要七牛账号下的一对有效的AccessKey和SecretKey,这对密钥可以在七牛云管理控制台的个人中心(https://portal.qiniu.com/user/key)获得,如下图:
在这里插入图片描述

1.2.6JavaSDK操作七牛云

我们就需要使用七牛云提供的JavaSDK完成图片上传和删除,我们可以参考官方提供的例子。
在这里插入图片描述

//构造一个带指定 Region 对象的配置类,这里的Region.region0()表示华东区域机房,我们在创建存储空间的时候,根据选择的机房位置选择不同的Region对象。对应Zone.zone0()其实是maven依赖低时使用的对象

Configuration cfg = new Configuration(Region.region0());
//...其他参数参考类注释

UploadManager uploadManager = new UploadManager(cfg);
//...生成上传凭证,然后准备上传
String accessKey = "your access key";
String secretKey = "your secret key";
String bucket = "your bucket name";
//如果是Windows情况下,格式是 D:\\qiniu\\test.png
String localFilePath = "/home/qiniu/test.png";
//默认不指定key的情况下,以文件内容的hash值作为文件名
String key = null;

Auth auth = Auth.create(accessKey, secretKey);
String upToken = auth.uploadToken(bucket);

try {
    
    
    Response response = uploadManager.put(localFilePath, key, upToken);
    //解析上传成功的结果
    DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
    System.out.println(putRet.key);
    System.out.println(putRet.hash);
} catch (QiniuException ex) {
    
    
    Response r = ex.response;
    System.err.println(r.toString());
    try {
    
    
        System.err.println(r.bodyString());
    } catch (QiniuException ex2) {
    
    
        //ignore
    }
}

接下来测试使用七牛云上传本地的图片:
测试代码:
在这里插入图片描述
在这里插入图片描述
查看对象存储空间:
在这里插入图片描述
图片上传成功。我们开发工具IDEA的控制台就会返回存储服务器上存储的文件名称(文件存储名称我们可以自定义)
其实这个图片我们可以通过器牛云提供的外链域名来访问
在这里插入图片描述

扫描二维码关注公众号,回复: 11696536 查看本文章

删除空间中的文件

官网提供的代码
在这里插入图片描述
测试代码:
在这里插入图片描述
再次查看对象存储服务器,发现图片已经删除;

封装工具类

为了方便操作七牛云存储服务,我们可以将官方提供的案例简单改造成一个工具类,在我们的项目中直接使用此工具类来操作就可以:

package com.itheima.utils;

import com.google.gson.Gson;
import com.qiniu.common.QiniuException;
import com.qiniu.common.Zone;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

/**
 * 七牛云工具类
 */
public class QiniuUtils {
    
    
    public  static String accessKey = ""; //秘钥管理中的AK
    public  static String secretKey = ""; //秘钥管理中的SK
    public  static String bucket = "";                       //七牛云存储空间的名称

    public static void upload2Qiniu(String filePath,String fileName){
    
    
        //构造一个带指定Zone对象的配置类
        Configuration cfg = new Configuration(Zone.zone0());
        UploadManager uploadManager = new UploadManager(cfg);
        Auth auth = Auth.create(accessKey, secretKey);
        String upToken = auth.uploadToken(bucket);
        try {
    
    
            Response response = uploadManager.put(filePath, fileName, upToken);
            //解析上传成功的结果
            DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
        } catch (QiniuException ex) {
    
    
            Response r = ex.response;
            try {
    
    
                System.err.println(r.bodyString());
            } catch (QiniuException ex2) {
    
    
                //ignore
            }
        }
    }

    //上传文件
    public static void upload2Qiniu(byte[] bytes, String fileName){
    
    
        //构造一个带指定Zone对象的配置类
        Configuration cfg = new Configuration(Zone.zone0());
        //...其他参数参考类注释
        UploadManager uploadManager = new UploadManager(cfg);

        //默认不指定key的情况下,以文件内容的hash值作为文件名
        String key = fileName;
        Auth auth = Auth.create(accessKey, secretKey);
        String upToken = auth.uploadToken(bucket);
        try {
    
    
            Response response = uploadManager.put(bytes, key, upToken);
            //解析上传成功的结果
            DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
            System.out.println(putRet.key);
            System.out.println(putRet.hash);
        } catch (QiniuException ex) {
    
    
            Response r = ex.response;
            System.err.println(r.toString());
            try {
    
    
                System.err.println(r.bodyString());
            } catch (QiniuException ex2) {
    
    
                //ignore
            }
        }
    }

    //删除文件
    public static void deleteFileFromQiniu(String fileName){
    
    
        //构造一个带指定Zone对象的配置类
        Configuration cfg = new Configuration(Zone.zone0());
        String key = fileName;
        Auth auth = Auth.create(accessKey, secretKey);
        BucketManager bucketManager = new BucketManager(auth, cfg);
        try {
    
    
            bucketManager.delete(bucket, key);
        } catch (QiniuException ex) {
    
    
            //如果遇到异常,说明删除失败
            System.err.println(ex.code());
            System.err.println(ex.response.toString());
        }
    }
}

七牛云上传图片案例:

图片上传并预览
此处使用的是ElementUI提供的上传组件el-upload,提供了多种不同的上传效果,上传成功后可以进行预览。

将图片上传到Controller层,然后通过七牛云工具类,将图片上传到七牛云服务器上,并且在页面上实现预览。

实现步骤:
(1)定义模型数据,用于后面上传文件的图片预览

imageUrl:null,//模型数据,用于上传图片完成后图片预览

2)定义上传组件

<!‐‐el‐upload:上传组件
action:上传的提交地址
auto‐upload:选中文件后是否自动上传
name:上传文件的名称,服务端可以根据名称获得上传的文件对象
show‐file‐list:是否显示已上传文件列表
on‐success:文件上传成功时的钩子
before‐upload:上传文件之前的钩子
‐‐>
<el‐upload
	class="avatar‐uploader"
	action="/setmeal/upload.do":
	auto‐upload="autoUpload"
	name="imgFile"
	:show‐file‐list="false"
	:on‐success="handleAvatarSuccess"
	:before‐upload="beforeAvatarUpload">
	<!‐‐用于上传图片预览‐‐>
	<imgv‐if="imageUrl":src="imageUrl"class="avatar">
	<!‐‐用于展示上传图标‐‐>
	<iv‐elseclass="el‐icon‐plusavatar‐uploader‐icon"></i>
</el‐upload>

3)定义对应的钩子函数:

//上传文件之前的钩子
beforeAvatarUpload(file){
    
    
	const  isJPG=file.type==='image/jpeg';
	const  isLt2M=file.size/1024/1024<2;
if(!isJPG){
    
    
	this.$message.error('上传套餐图片只能是JPG格式!');
}
if(!isLt2M){
    
    
	this.$message.error('上传套餐图片大小不能超过2MB!');
}
	return isJPG && isLt2M;
}
//文件上传成功后的钩子,response为服务端返回的值,file为当前上传的文件封装成的js对象,我们需要将上传的文件名称返回回来,将文件名称赋值给imageUrl来进行图片的预览
handleAvatarSuccess(response,file){
    
    
	//http://pqjroc654.bkt.clouddn.com/:七牛云上的域名
	//response.data:controller层返回回来的图片名称
	this.imageUrl="http://pqjroc654.bkt.clouddn.com/"+response.data;
this.$message({
    
    
	message:response.message,
	type:response.flag?'success':'error'
});
//设置模型数据(图片名称),后续提交ajax请求时会提交到后台最终保存到数据库
	this.formData.img=response.data;
}

(4)创建SetmealController,接收上传的文件
注意:别忘了在spring配置文件中配置文件上传组件

<!‐‐文件上传组件‐‐>
<bean id="multipartResolver"  class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<propertyname="maxUploadSize"value="104857600"/>
		<propertyname="maxInMemorySize"value="4096"/>
		<propertyname="defaultEncoding"value="UTF‐8"/>
</bean>

同时注意七牛云工具类当中的秘钥管理中的AK秘钥管理中的SK七牛云存储空间的名称
在这里插入图片描述

@RestController
@RequestMapping("/setmeal")
public class SetmealController {
    
    

    //图片上传
    @RequestMapping("/upload")
    public Result upload(@RequestParam("imgFile") MultipartFile imgFile){
    
    
        try{
    
    
            //获取原始文件名
            String originalFilename = imgFile.getOriginalFilename();

            //文件最后一个“.”后缀索引位置
            int lastIndexOf = originalFilename.lastIndexOf(".");

            //获取文件后缀
            String suffix = originalFilename.substring(lastIndexOf - 1);

            //不适用原始文件名originalFilename  使用UUID随机产生文件名称,防止同名文件覆盖
            String fileName = UUID.randomUUID().toString() + suffix;

            //使用七牛云工具类上传图片
            QiniuUtils.upload2Qiniu(imgFile.getBytes(),fileName);

            //图片上传成功
            Result result = new Result(true, MessageConstant.PIC_UPLOAD_SUCCESS);

            //将七牛云服务器上的文件名称返回到前台,用于图片的预览
            result.setData(fileName);
            return result;
        }catch (Exception e){
    
    
            e.printStackTrace();
            //图片上传失败
            return new Result(false, MessageConstant.PIC_UPLOAD_FAIL);
        }
    }

}

测试:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
查看七牛云服务器:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
图片文件已经上传到服务器,那么我们的数据库需要存储的是文件的名称,我们看一下提交表单的数据,包括图片的信息
在这里插入图片描述
在这里插入图片描述
完善文件上传
前面我们已经完成了文件上传,将图片存储在了七牛云服务器中。但是这个过程存在一个问题,就是如果用户只上传了图片而没有最终保存套餐信息到我们的数据库,这时我们上传的图片就变为了垃圾图片。对于这些垃圾图片我们需要定时清理来释放七牛云磁盘空间。这就需要我们能够区分出来哪些是垃圾图片,哪些不是垃圾图片。如何实现呢?

方案就是利用redis来保存图片名称,具体做法为:
1、当用户上传图片后,将图片名称保存到redis的一个Set集合中,例如集合名称为setmealPicResources
2、当用户添加套餐后,将图片名称保存到redis的另一个Set集合中,例如集合名称为setmealPicDbResources
在这里插入图片描述
相当于setmealPicDbResources集合是setmealPicResources的子集,
3、计算setmealPicResources集合与setmealPicDbResources集合的差值,结果就是垃圾图片的名称集合,清理这些图片即可,这也是我们使用redis的set存储方式的原因,可以计算差值。
在这里插入图片描述

实现步骤:
(1)在health_backend项目中提供Spring配置文件spring-redis.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--Jedis连接池的相关配置-->
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxTotal">
            <value>200</value>
        </property>
        <property name="maxIdle">
            <value>50</value>
        </property>
        <property name="testOnBorrow" value="true"/>
        <property name="testOnReturn" value="true"/>
    </bean>

        <!--redis客户端工具-->
    <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
        <constructor-arg name="poolConfig" ref="jedisPoolConfig" />
        <constructor-arg name="host" value="127.0.0.1" />
        <constructor-arg name="port" value="6379" type="int" />
        <constructor-arg name="timeout" value="30000" type="int" />
    </bean>
</beans>

在这里插入图片描述
2)在health_common工程中提供Redis常量类

public class RedisConstant {
    
    

    //套餐图片所有图片名称
    public static final String SETMEAL_PIC_RESOURCES = "setmealPicResources";

    //套餐图片保存在数据库中的图片名称
    public static final String SETMEAL_PIC_DB_RESOURCES = "setmealPicDbResources";
}

3)完善SetmealController,在文件上传成功后将图片名称保存到redis集合中

/**
 * 套餐管理
 */
@RestController
@RequestMapping("/setmeal")
public class SetmealController {
    
    

    @Reference
    private SetmealService setmealService;

    @Autowired
    private JedisPool jedisPool;

    //图片上传
    @RequestMapping("/upload")
    public Result upload(@RequestParam("imgFile")MultipartFile imgFile){
    
    
        try{
    
    
            //获取原始文件名
            String originalFilename = imgFile.getOriginalFilename();
            int lastIndexOf = originalFilename.lastIndexOf(".");
            //获取文件后缀
            String suffix = originalFilename.substring(lastIndexOf - 1);
            //使用UUID随机产生文件名称,防止同名文件覆盖
            String fileName = UUID.randomUUID().toString() + suffix;

            QiniuUtils.upload2Qiniu(imgFile.getBytes(), fileName);

            //图片上传成功
            Result result = new Result(true, MessageConstant.PIC_UPLOAD_SUCCESS);
            result.setData(fileName);

            //将上传图片名称存入Redis,基于Redis的Set集合存储
        jedisPool.getResource().sadd(RedisConstant.SETMEAL_PIC_RESOURCES, fileName);

            return result;
        }catch (Exception e){
    
    
            e.printStackTrace();
            //图片上传失败
            return new Result(false, MessageConstant.PIC_UPLOAD_FAIL);
        }
    }

    //新增
    @RequestMapping("/add")
    public Result add(@RequestBody Setmeal setmeal, Integer[] checkgroupIds){
    
    
        try {
    
    
            setmealService.add(setmeal, checkgroupIds);
        }catch (Exception e){
    
    
            //新增套餐失败
            return new Result(false, MessageConstant.ADD_SETMEAL_FAIL);
        }
        //新增套餐成功
        return new Result(true, MessageConstant.ADD_SETMEAL_SUCCESS);
    }

}

以上其实就完成了方案的第一步;

当用户上传图片后,将图片名称保存到redis的一个Set集合中,例如集合名称为setmealPicResources

4)在health_service_provider项目中提供Spring配置文件spring-redis.xml,和之前的配置一样,只不过这次配置文件,由监听器加载(在提供者方也要配置redis,因为当套餐数据整体提交过程是在提供者方完成的,套餐整体数据提交也要使用redis存储图片数据
在这里插入图片描述
5)完善SetmealServiceImpl服务类,在保存完成套餐信息后将图片名称存储到redis集合中

/**
 * 体检套餐服务实现类
 */
@Service(interfaceClass = SetmealService.class)
@Transactional
public class SetmealServiceImpl implements SetmealService {
    
    

    @Autowired
    private SetmealDao setmealDao;

    @Autowired
    private JedisPool jedisPool;

    //新增套餐
    public void add(Setmeal setmeal, Integer[] checkgroupIds) {
    
    
        setmealDao.add(setmeal);
        if (checkgroupIds != null && checkgroupIds.length > 0) {
    
    
            //绑定套餐和检查组的多对多关系
            setSetmealAndCheckGroup(setmeal.getId(), checkgroupIds);
        }

        //将图片名称保存到Redis
        jedisPool.getResource().sadd(RedisConstant.SETMEAL_PIC_DB_RESOURCES, setmeal.getImg());
    }

    //绑定套餐和检查组的多对多关系
    private void setSetmealAndCheckGroup(Integer id, Integer[] checkgroupIds) {
    
    
        for (Integer checkgroupId : checkgroupIds) {
    
    
            Map<String, Integer> map = new HashMap<>();
            map.put("setmeal_id", id);
            map.put("checkgroup_id", checkgroupId);
            setmealDao.setSetmealAndCheckGroup(map);
        }
    }
}

测试:
记得将redis服务器开启
首先将redis和七牛云服务器当中的数据全部清除,便于观察:

在这里插入图片描述
在这里插入图片描述
启动服务,访问项目:
首先只添加图片,也就是垃圾图片:
在这里插入图片描述
查看redis服务器和七牛云服务器:
在这里插入图片描述
在这里插入图片描述
可以观察到,垃圾图片保存在redis和七牛云服务器上保存成功。
此时,页面数据继续接着添加套餐数据并提交
在这里插入图片描述
在这里插入图片描述
以上是正常情况下的图片保存。

还有一种情况:选择图片上传之后,套餐数据没有写入,直接关闭弹窗
在这里插入图片描述
这个时候观察redis服务器:
在这里插入图片描述

定时清理垃圾图片

前面我们已经完成了体检套餐的管理,在新增套餐时套餐的基本信息和图片是分两次提交到后台进行操作的。也就是用户首先将图片上传到七牛云服务器,然后再提交新增窗口中录入的其他信息。如果用户只是上传了图片而没有提交录入的其他信息,此时的图片就变为了垃圾图片,因为在数据库中并没有记录它的存在。此时我们要如何处理这些垃圾图片呢?

解决方案就是通过定时任务组件定时清理这些垃圾图片。为了能够区分出来哪些图片是垃圾图片,我们在文件上传成功后将图片保存到了一个redis集合中,当套餐数据插入到数据库后我们又将图片名称保存到了另一个redis集合中,通过计算这两个集合的差值就可以获得所有垃圾图片的名称。

我们就会基于Quartz定时任务,通过计算redis两个集合的差值找出所有的垃圾图片,就可以将垃圾图片清理掉。

操作步骤:
(1)创建maven工程health_jobs,打包方式为war,导入Quartz等相关坐标
在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>health_parent</artifactId>
        <groupId>com.itheima</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>health_jobs</artifactId>
    <packaging>war</packaging>

    <name>health_jobs Maven Webapp</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-
            8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.itheima</groupId>
            <artifactId>health_interface</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <configuration>
                    <!-- 指定端口 -->
                    <port>83</port>
                    <!-- 请求路径 -->
                    <path>/</path>
                </configuration>
            </plugin>
        </plugins>
    </build>


</project>

(2)配置web.xml

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <!-- 加载spring容器 -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:applicationContext*.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
</web-app>

(3)配置log4j.properties

### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{
    
    ABSOLUTE} %5p %c{
    
    1}:%L - %m%n

### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c:\\health.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{
    
    ABSOLUTE} %5p %c{
    
    1}:%L - %m%n

### set log levels - for more verbose logging change 'info' to 'debug' ###

log4j.rootLogger=debug, stdout

(4)配置applicationContext-redis.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--Jedis连接池的相关配置-->
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxTotal">
            <value>200</value>
        </property>
        <property name="maxIdle">
            <value>50</value>
        </property>
        <property name="testOnBorrow" value="true"/>
        <property name="testOnReturn" value="true"/>
    </bean>

    <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
        <constructor-arg name="poolConfig" ref="jedisPoolConfig" />
        <constructor-arg name="host" value="127.0.0.1" />
        <constructor-arg name="port" value="6379" type="int" />
        <constructor-arg name="timeout" value="30000" type="int" />
    </bean>
</beans>

5)配置applicationContext-jobs.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd">

<!--    开启注解模式-->
    <context:annotation-config></context:annotation-config>

<!--    自定义定时任务bean对象-->
    <bean id="clearImgJob" class="com.itheima.jobs.ClearImgJob"></bean>

    <bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <!-- 注入目标对象 -->
        <property name="targetObject" ref="clearImgJob"/>
        <!-- 注入目标方法 -->
        <property name="targetMethod" value="clearImg"/>
    </bean>

    <!-- 注册一个触发器,指定任务触发的时间 -->
    <bean id="myTrigger"
          class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <!-- 注入JobDetail -->
        <property name="jobDetail" ref="jobDetail"/>
        <!-- 指定触发的时间,基于Cron表达式 -->
        <property name="cronExpression">
            <!--
                <value>0 0 2 * * ?</value>
            -->
            <value>0/10 * * * * ?</value>
        </property>
    </bean>

    <!-- 注册一个统一的调度工厂,通过这个调度工厂调度任务 -->
    <bean id="scheduler"
          class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <!-- 注入多个触发器 -->
        <property name="triggers">
            <list>
                <ref bean="myTrigger"/>
            </list>
        </property>
    </bean>
</beans>

(6)创建ClearImgJob定时任务类

package com.itheima.jobs;

import com.itheima.constant.RedisConstant;
import com.itheima.utils.QiniuUtils;
import org.springframework.beans.factory.annotation.Autowired;
import redis.clients.jedis.JedisPool;

import java.util.Set;

/**
 * 自定义Job,实现定时清理垃圾图片
 */
public class ClearImgJob {
    
    

    @Autowired
    private JedisPool jedisPool;

    public void clearImg(){
    
    

        //根据Redis中保存的两个set集合进行差值计算,获得垃圾图片名称集合
        Set<String> set = jedisPool.getResource().sdiff(RedisConstant.SETMEAL_PIC_RESOURCES,
                        RedisConstant.SETMEAL_PIC_DB_RESOURCES);
        
        if(set != null){
    
    
            for (String picName : set) {
    
    
                //删除七牛云服务器上的图片
                QiniuUtils.deleteFileFromQiniu(picName);
                //从Redis集合中删除图片名称
                jedisPool.getResource().srem(RedisConstant.SETMEAL_PIC_RESOURCES, picName);
                System.out.println("自定义任务执行,清理垃圾图片:" + picName);
            }
        }
    }


}

测试:
在这里插入图片描述
现在启动定时任务模块:
在这里插入图片描述
再次刷新redis服务器,发现垃圾图片呗清理:
在这里插入图片描述
在这里插入图片描述

======================================================

猜你喜欢

转载自blog.csdn.net/qq_44316726/article/details/105151852