项目开发笔记——传智健康三:图床与定时垃圾处理

本文介绍了如何在前端使用Element UI的上传组件结合七牛云存储实现图片上传,以及在后端使用Spring Boot处理图片上传、CRUD操作。通过在Redis中维护两个集合,实现了垃圾图片的定时清理,确保了资源的有效管理。
摘要由CSDN通过智能技术生成

概述

其实本部分也是一个一对多的CRUD,与检查组单纯的字段内容所不同的是,这里涉及到图片的处理,我们首先来看一下前端是如何描述图片上传部分以及相应数据绑定的

<el-form-item label="上传图片">
    <el-upload
               class="avatar-uploader"
               action="/setMeal/upload.do"
               :auto-upload="autoUpload"
               name="imgFile"
               :show-file-list="false"
               :on-success="handleAvatarSuccess"
               :before-upload="beforeAvatarUpload">
        <img v-if="imageUrl" :src="imageUrl" class="avatar">
        <i v-else class="el-icon-plus avatar-uploader-icon"></i>
    </el-upload>
</el-form-item>
        data: {
            autoUpload: true,//自动上传
            imageUrl: null,//模型数据,用于上传图片完成后图片预览
            activeName: 'first',//添加/编辑窗口Tab标签名称
            pagination: {//分页相关属性
                currentPage: 1,
                pageSize: 10,
                total: 100,
                queryString: null,
            },
            dataList: [],//列表数据
            formData: {},//表单数据
            tableData: [],//添加表单窗口中检查组列表数据
            checkgroupIds: [],//添加表单窗口中检查组复选框对应id
            dialogFormVisible: false, //控制添加窗口显示/隐藏
            dialogFormVisible4Edit: false //控制编辑窗口显示/隐藏
        },

这里有几项是值得注意的,action代表的是图片上传路径,auto-upload代表启用自动上传,name代表文件名称:on-success和before-upload图片成功上传后和上传之前所执行的方法,imgUrl代表图片的路径,下面分别来看

    //文件上传成功后的钩子,response为服务端返回的值,file为当前上传的文件封装成的js对象
    handleAvatarSuccess(response, file) {
        //为模型数据赋值,用于页面图片预览
        this.imageUrl = 'http://qu0dxvmvo.hd-bkt.clouddn.com/' + response.data;
        this.$message({
            type: response.flag ? 'success' : 'error',
            message: response.message
        });
        //设置图片名称以方便在数据库中进行img的存储
        this.formData.img = response.data;
    },
        //上传图片之前执行
        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;
        },
  • 上传前进行了格式和大小的校验

  • 上传成功后对image的url进行了赋值以方便进行预览,更重要的是,表单数据的img属性被赋值为了图片在图床中所存储的图片名称,以方便表单的体交

这里的imageUrl是来自于七牛云的对象存储服务所提供的外链,外链加上图片名称就是可以访问到图片的URL路径。我们就很容易发现,只要在数据库存储好图片的名称,就可以利用图片的名称来显示图片了,这样就把图片的CRUD更改成了普通的字段CRUD,剩下的处理就和之前的检查项、检查组一样了。但是既然要用图片名字唯一定位图片,就要保证图片名字唯一,我们采用UUID来处理,下面给出相应的CRUD

前端CRUD

<script>
    var vue = new Vue({
        el: '#app',
        data: {
            autoUpload: true,//自动上传
            imageUrl: null,//模型数据,用于上传图片完成后图片预览
            activeName: 'first',//添加/编辑窗口Tab标签名称
            pagination: {//分页相关属性
                currentPage: 1,
                pageSize: 10,
                total: 100,
                queryString: null,
            },
            dataList: [],//列表数据
            formData: {},//表单数据
            tableData: [],//添加表单窗口中检查组列表数据
            checkgroupIds: [],//添加表单窗口中检查组复选框对应id
            dialogFormVisible: false, //控制添加窗口显示/隐藏
            dialogFormVisible4Edit: false //控制编辑窗口显示/隐藏
        },
        created() {
            this.findPage();
        },
        methods: {
            //文件上传成功后的钩子,response为服务端返回的值,file为当前上传的文件封装成的js对象
            handleAvatarSuccess(response, file) {
                //为模型数据赋值,用于页面图片预览
                this.imageUrl = 'http://qu0dxvmvo.hd-bkt.clouddn.com/' + response.data;
                this.$message({
                    type: response.flag ? 'success' : 'error',
                    message: response.message
                });
                //设置图片名称以方便在数据库中进行img的存储
                this.formData.img = response.data;
            },
            //上传图片之前执行
            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;
            },
            //编辑选项提交表单
            handleEdit() {
                axios.post("/setMeal/edit.do?checkGroupIds=" + this.checkgroupIds, 						this.formData).then((res) => {
                    if (res.data.flag == true) {
                        //弹出提示
                        this.$message({
                            message: res.data.message,
                            type: 'success'
                        });
                        //关闭编辑窗口
                        this.dialogFormVisible4Edit = false;
                        this.findPage();
                    } else {
                        this.$message.error(res.data.message);
                    }
                });
            },
            //添加
            handleAdd() {
                axios.post("/setMeal/add.do?checkGroupIds=" + this.checkgroupIds, 						this.formData).then((res) => {
                    if (res.data.flag == true) {
                        //弹出提示
                        this.$message({
                            message: res.data.message,
                            type: 'success'
                        });
                        //关闭新建窗口
                        this.dialogFormVisible = false;
                        this.findPage();
                    } else {
                        this.$message.error(res.data.message);
                    }
                });
            },
            handleDelete(row) {
                this.$confirm("确定删除?", "提示", {
                    type: 'warning'
                }).then(() => {
                    var setMealId = row.id;
                    //发送异步请求
                    //如果还是采用双变量是会返回空的
                    axios.post("/setMeal/delete.do?setMealId=" + setMealId).then((res) => 						{
                        //根据数据返回情况进行处理
                        if (res.data.flag == true) {
                            this.$message({
                                message: res.data.message,
                                type: 'success'
                            });
                            this.findPage();
                        } else {
                            this.$message({
                                message: res.error(data.message),
                            });
                        }
                    });
                }).catch(() => {
                    this.$message({
                        message: '操作已取消',
                        type: 'info'
                    });
                })
            },
            //分页查询
            findPage() {
                var param = {
                    currentPage: this.pagination.currentPage,
                    pageSize: this.pagination.pageSize,
                    queryString: this.pagination.queryString
                }
                axios.post("/setMeal/findPage.do", param).then((res) => {
                    this.pagination.total = res.data.total;
                    this.dataList = res.data.rows;
                });
            },
            // 重置表单
            resetForm() {
                this.imageUrl = null;
                this.formData = {};
                this.checkgroupIds = [];
                this.activeName = 'first';
            },
            // 弹出添加窗口
            handleCreate() {
                this.resetForm();
                this.dialogFormVisible = true;
                axios.get("/checkGroup/findAll.do").then((res) => {
                    if (res.data.flag == true) {
                        this.tableData = res.data.data;
                    } else {
                        this.$message.error(res.data.message);
                    }
                });
            },
            //弹出编辑窗口,完成数据动态显示
            handleUpdate(row) {
                var setMealId = row.id;
                this.resetForm();

                //获取表单数据
                axios.get("/setMeal/findById.do?setMealId=" + setMealId).then((res)=>{
                    if (res.data.flag == true) {
                        //表单数据赋值
                        this.formData = res.data.data;
                        //图片预览更新
                        this.imageUrl = 'http://qu0dxvmvo.hd-bkt.clouddn.com/' + 												res.data.data.img;
                    } else {
                        this.$message.error(res.data.message);
                    }
                });
                //获取全部可选项
                axios.get("/checkGroup/findAll.do").then((res) => {
                    if (res.data.flag == true) {
                        this.tableData = res.data.data;
                    } else {
                        this.$message.error(res.data.message);
                    }
                });
                //获取已选项
                axios.get("/setMeal/findRelationship.do?setMealId=" + 										setMealId).then((res)=>{
                    if (res.data.flag == true) {
                        //数组赋值
                        this.checkgroupIds = res.data.data;
                    } else {
                        this.$message.error(res.data.message);
                    }
                });

                this.dialogFormVisible4Edit = true;
            },
            //切换页码
            handleCurrentChange(currentPage) {
                this.pagination.currentPage = currentPage;
                this.findPage();
            }
        }
    })
</script>

可以看到在前端部分,除了图片上传后更新表单与生成预览外,与检查组检查项等没什么不同

注意这里HTTP请求方法的选择,请求参数使用GET,获取参数使用POST,详细的内容在JavaWeb学习笔记中有更详细的说明

控制层CRUD

之前已经通过img字段将图片与七牛云存储中的图片做了一一对应,因此对于套餐的CRUD跟之前的检查项检查组基本一致,但是除了处理字段之外,还要实现图片向服务器的上传,在图片上传组件中绑定了路径为/setMeal/upload,在控制层中写相应的处理方法如下

    //向七牛云上传图片
    @RequestMapping("/upload")
    public Result upload(MultipartFile imgFile) {
        //获取文件名并截取后缀
        String originalFilename = imgFile.getOriginalFilename();
        int index = originalFilename.lastIndexOf('.');
        String extension = originalFilename.substring(index - 1);
        //使用UUID生成文件名,并保留后缀
        String fileName = UUID.randomUUID().toString() + extension;

        try {
            //使用七牛云组件上传
            QiniuUtils.upload2Qiniu(imgFile.getBytes(), fileName);
            return new Result(true,MessageConstant.PIC_UPLOAD_SUCCESS,fileName);
        } catch (IOException e) {
            e.printStackTrace();
            return new Result(false,MessageConstant.PIC_UPLOAD_FAIL);
        }
    }

七牛云的相关上传方法已经做了封装,具体实现可以在七牛官网找到。

但是这样处理存在一个问题:我们的CRUD是对字段进行处理的,服务器中存储的图片并没有被删除,并且就算没有提交表单,单纯的上传图片与预览就会在服务器存储图片,会造成大量的垃圾图片堆积,因此要设计方法将垃圾图片进行处理,我们这里采取的方法是在Redis中设计两个set集合,一个存储经CRUD处理的数据库中存储的图片的名称,一个处理所有上传到服务器的图片的名称,对二者取差值就可以得出哪些是垃圾图片。

垃圾图片的清理我们后续用Quartz定时来处理,在控制层业务层只需要维护好两个Redis集合就可以了,因此将图片上传方法修改如下,首先在Spring中配置jedis

<?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>
    <!--采用windows的Redis,因此ip为127.0.0.1-->
    <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>

在上传之后增加一句

jedisPool.getResource().sadd(RedisConstant.SETMEAL_PIC_RESOURCES, fileName);

当然在方法中也要用Autowired引入

@Autowired
private JedisPool jedisPool;

这样图片上传就做好了,再就是做简单的CRUD了。下面给出完整的控制层代码

package com.cui.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.cui.constant.MessageConstant;
import com.cui.constant.RedisConstant;
import com.cui.entity.PageResult;
import com.cui.entity.QueryPageBean;
import com.cui.entity.Result;
import com.cui.pojo.Setmeal;
import com.cui.service.SetMealService;
import com.cui.utils.QiniuUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import redis.clients.jedis.JedisPool;

import java.io.IOException;
import java.util.List;
import java.util.UUID;

/**
 * 套餐管理
 */

@RestController
@RequestMapping("/setMeal")
public class SetMealController {

    @Reference
    private SetMealService setMealService;

    @Autowired
    private JedisPool jedisPool;

    //向七牛云上传图片
    @RequestMapping("/upload")
    public Result upload(MultipartFile imgFile) {
        //获取文件名并截取后缀
        String originalFilename = imgFile.getOriginalFilename();
        int index = originalFilename.lastIndexOf('.');
        String extension = originalFilename.substring(index - 1);
        //使用UUID生成文件名,并保留后缀
        String fileName = UUID.randomUUID().toString() + extension;

        try {
            //使用七牛云组件上传
            QiniuUtils.upload2Qiniu(imgFile.getBytes(), fileName);
            //存储图片名称至Redis
            jedisPool.getResource().sadd(RedisConstant.SETMEAL_PIC_RESOURCES, fileName);
            return new Result(true,MessageConstant.PIC_UPLOAD_SUCCESS,fileName);
        } catch (IOException 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);
            return new Result(true, MessageConstant.ADD_SETMEAL_SUCCESS);
        } catch (Exception e) {
            e.printStackTrace();
            return new Result(false, MessageConstant.ADD_SETMEAL_FAIL);
        }
    }

    //编辑套餐
    @RequestMapping("/edit")
    public Result edit (@RequestBody Setmeal setmeal, Integer[] checkGroupIds) {
        try {
            setMealService.edit(setmeal, checkGroupIds);
            return new Result(true, MessageConstant.EDIT_SETMEAL_SUCCESS);
        } catch (Exception e) {
            e.printStackTrace();
            return new Result(false, MessageConstant.EDIT_SETMEAL_FAIL);
        }
    }

    //删除套餐
    @RequestMapping("/delete")
    public Result delete(Integer setMealId) {
        try {
            setMealService.delete(setMealId);
            return new Result(true, MessageConstant.DELETE_SETMEAL_SUCCESS);
        } catch (Exception e) {
            e.printStackTrace();
            return new Result(false, MessageConstant.DELETE_SETMEAL_FAIL);
        }
    }

    //套餐分页查询
    @RequestMapping("/findPage")
    public PageResult findPage(@RequestBody QueryPageBean queryPageBean) {
        return setMealService.findPage(queryPageBean);
    }

    //根据Id查询套餐
    @RequestMapping("/findById")
    public Result findById(Integer setMealId) {
        try {
            Setmeal setmeal = setMealService.findById(setMealId);
            return new Result(true, MessageConstant.QUERY_SETMEAL_SUCCESS, setmeal);
        } catch (Exception e) {
            e.printStackTrace();
            return new Result(false, MessageConstant.QUERY_SETMEAL_FAIL);
        }
    }

    //根据id查询关系表
    @RequestMapping("/findRelationship")
    public Result findRelationship(Integer setMealId) {
        try {
            List<Integer> checkGroupList = setMealService.findRelationship(setMealId);
            return new Result(true, MessageConstant.QUERY_CHECKGROUP_SUCCESS, checkGroupList);
        } catch (Exception e) {
            e.printStackTrace();
            return new Result(false, MessageConstant.QUERY_CHECKGROUP_FAIL);
        }
    }
}

业务层CRUD

垃圾图片由Quartz处理,而服务器中存储的图片的CRUD逻辑就需要在业务层中手动处理了,因此业务层涉及了三部分的内容

  1. 表单的处理
  2. Redis集合的处理
  3. 服务器图片的处理

下面给出完整的代码

package com.cui.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.cui.constant.RedisConstant;
import com.cui.dao.SetMealDao;
import com.cui.entity.PageResult;
import com.cui.entity.QueryPageBean;
import com.cui.pojo.Setmeal;
import com.cui.service.SetMealService;
import com.cui.utils.QiniuUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.List;

@Service(interfaceClass = com.cui.service.SetMealService.class)
@Transactional
public class SetMealServiceImpl implements SetMealService {

    @Autowired
    private SetMealDao setMealDao;

    @Autowired
    private JedisPool jedisPool;

    //新增业务
    @Override
    public void add(Setmeal setmeal, Integer[] checkGroupIds) {
        //更新套餐表
        setMealDao.add(setmeal);

        //更新关系表
        for (Integer checkGroupId : checkGroupIds) {
            setMealDao.addRelationShip(setmeal.getId(), checkGroupId);
        }

        //更新Redis
        if (setmeal.getImg() != null)
            jedisPool.getResource().sadd(RedisConstant.SETMEAL_PIC_DB_RESOURCES, setmeal.getImg());
    }

    //编辑业务
    @Override
    public void edit(Setmeal setmeal, Integer[] checkGroupIds) {
        //一定要在更新之前就根据id查询好旧图片
        String preImg = setMealDao.getImgById(setmeal.getId());

        //更新套餐表
        setMealDao.update(setmeal);

        //更新关系表
        //删除旧关系
        setMealDao.delRelationship(setmeal.getId());
        //增加新关系
        for (Integer checkGroupId : checkGroupIds) {
            setMealDao.addRelationShip(setmeal.getId(), checkGroupId);
        }

        //更新Redis
        Jedis resource = jedisPool.getResource();
        String newImg = setmeal.getImg();
        //替换为新图片
        //删除Redis中的内容
        resource.srem(RedisConstant.SETMEAL_PIC_DB_RESOURCES, preImg);
        //删除七牛云服务器中的内容
        //这里垃圾清理jobs是可能删不到的,因此要单独写逻辑来删除,因为垃圾清理会更新上传过的图片的记录
        QiniuUtils.deleteFileFromQiniu(preImg);
        resource.sadd(RedisConstant.SETMEAL_PIC_DB_RESOURCES, newImg);
    }

    @Override
    public void delete(Integer setMealId) {
        //删除Redis缓存
        String img = setMealDao.getImgById(setMealId);
        jedisPool.getResource().srem(RedisConstant.SETMEAL_PIC_DB_RESOURCES, img);
        //删除七牛云服务器中的内容
        QiniuUtils.deleteFileFromQiniu(img);
        //删除关系表
        setMealDao.delRelationship(setMealId);
        //删除套餐表单
        setMealDao.delete(setMealId);
    }

    @Override
    public PageResult findPage(QueryPageBean queryPageBean) {
        String queryString = queryPageBean.getQueryString();
        Integer currentPage = queryPageBean.getCurrentPage();
        Integer pageSize = queryPageBean.getPageSize();

        PageHelper.startPage(currentPage, pageSize);

        Page<Setmeal> page = setMealDao.findPage(queryString);
        return new PageResult(page.getTotal(), page.getResult());
    }

    @Override
    public Setmeal findById(Integer setMealId) {
        return setMealDao.findById(setMealId);
    }

    @Override
    public List<Integer> findRelationship(Integer setMealId) {
        return setMealDao.findRelationship(setMealId);
    }

}

持久层CRUD

服务器图床与Redis集合都交付给了业务层处理,到了持久层就只剩下单纯的表单处理了,给出代码如下

/**
 * 套餐服务接口
 */
public interface SetMealService {
    void add (Setmeal setmeal, Integer[] checkGroupIds);
    PageResult findPage(QueryPageBean queryPageBean);
    Setmeal findById(Integer setMealId);
    List<Integer> findRelationship(Integer setMealId);
    void edit(Setmeal setmeal, Integer[] checkGroupIds);
    void delete(Integer setMealId);
}

对应的映射配置文件

<?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.cui.dao.SetMealDao">
    <insert id="add" parameterType="com.cui.pojo.Setmeal">
        <selectKey resultType="Integer" order="AFTER" keyProperty="id">
            select LAST_INSERT_ID()
        </selectKey>
        insert into t_setmeal
        (name, code, helpCode, sex, age, price, remark, attention, img)
        values
        (#{name}, #{code}, #{helpCode}, #{sex}, #{age}, #{price}, #{remark}, #{attention}, #{img})
    </insert>

    <insert id="addRelationShip">
        insert into t_setmeal_checkgroup
        (setmeal_id, checkgroup_id)
        values
        (#{setMealId}, #{checkGroupId})
    </insert>

    <select id="findPage" parameterType="String" resultType="com.cui.pojo.Setmeal">
        select * from t_setmeal
        <if test="value != null and value.length > 0">
            where code = #{value} or name = #{value}
        </if>
    </select>

    <select id="findById" parameterType="Integer" resultType="com.cui.pojo.Setmeal">
        select * from t_setmeal where id = #{value}
    </select>

    <select id="findRelationship" parameterType="Integer" resultType="Integer">
        select checkgroup_id from t_setmeal_checkgroup where setmeal_id = #{value}
    </select>

    <select id="delRelationship" parameterType="Integer">
        delete from t_setmeal_checkgroup where setmeal_id = #{value}
    </select>

    <update id="update" parameterType="com.cui.pojo.Setmeal">
        update t_setmeal
        set
            name = #{name},
            code = #{code},
            helpCode = #{helpCode},
            sex = #{sex},
            age = #{age},
            price = #{price},
            remark = #{remark},
            attention = #{attention},
            img = #{img}
        where
            id = #{id}
    </update>

    <select id="getImgById" parameterType="Integer" resultType="String">
        select img from t_setmeal where id = #{value}
    </select>

    <delete id="delete" parameterType="Integer">
        delete from t_setmeal where id = #{value}
    </delete>
</mapper>

Quartz定时处理

Quartz是一个任务调度框架,可以用于定时处理

定时处理新建了一个新的模块叫health_jobs,采用war方式打包的web-app文件,首先在web.xml中加载Spring容器

<!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>

applicationContext-Redis配置Redis

<?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">

        <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>

applicationCentext-jobs配置Quartz插件(插件已经在Maven中做了依赖注入)

<?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/>

    <!--注册自定义的job-->
    <bean id="clearImgJob" class="com.cui.jobs.ClearImgJob"/>

    <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">
            <!--0 0 2 * * ?-->
            <!--每隔10s清除一次垃圾文件-->
            <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>

这里关注四项内容:自定义的job、目标对象、目标方法、定时时间

自定义job:指明了哪个类是我们自定义的job

<!--注册自定义的job-->
<bean id="clearImgJob" class="com.cui.jobs.ClearImgJob"/>

目标对象与目标方法,一是通过注册自定义job的bean产生目标对象,二是指明哪个是我们所需要的目标方法,以获得jobDetail的bean

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

第三是触发器,里面通过相应的语句定义了任务的触发时间,定时时间的语句有相应的语句生成工具

    <!-- 注册一个触发器,指定任务触发的时间 -->
    <bean id="myTrigger"
          class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <!-- 注入JobDetail -->
        <property name="jobDetail" ref="jobDetail"/>
        <!-- 指定触发的时间,基于Cron表达式 -->
        <property name="cronExpression">
            <!--0 0 2 * * ?-->
            <!--每隔10s清除一次垃圾文件-->
            <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>

最后是自定义的垃圾处理任务

package com.cui.jobs;

import com.cui.constant.RedisConstant;
import com.cui.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> trash = jedisPool.getResource().sdiff(RedisConstant.SETMEAL_PIC_RESOURCES, RedisConstant.SETMEAL_PIC_DB_RESOURCES);

        if (trash != null) {
            for (String trashName : trash) {
                //删除七牛云服务器上的图片
                QiniuUtils.deleteFileFromQiniu(trashName);
                //更新Redis
                jedisPool.getResource().srem(RedisConstant.SETMEAL_PIC_RESOURCES, trashName);
                System.out.println(trashName + "已被清理");
            }
        }

    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值