summary
In fact, this part is also a one to many CRUD. Different from the simple field content of the inspection team, it involves the processing of images. First, let's take a look at how the front end describes the image upload part and the corresponding data binding
<el-form-item label="Upload pictures"> <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,//Automatic upload imageUrl: null,//Model data, which is used for picture preview after uploading pictures activeName: 'first',//Add / edit window Tab label name pagination: {//Paging related properties currentPage: 1, pageSize: 10, total: 100, queryString: null, }, dataList: [],//List data formData: {},//Form Data tableData: [],//Check group list data in the add form window checkgroupIds: [],//id corresponding to the check group check box in the add form window dialogFormVisible: false, //Controls the display / hiding of the add window dialogFormVisible4Edit: false //Controls the display / hiding of the edit window },
Here are several items worth noting. action represents the image upload path, auto upload represents enabling automatic upload, name represents the file name: on success and before upload, the methods executed after and before the successful upload of the image, and imgUrl represents the path of the image. See the following separately
//The hook after the file is uploaded successfully. The response is the value returned by the server, and the file is the js object encapsulated by the currently uploaded file handleAvatarSuccess(response, file) { //Assign value to model data for page image preview this.imageUrl = 'http://qu0dxvmvo.hd-bkt.clouddn.com/' + response.data; this.$message({ type: response.flag ? 'success' : 'error', message: response.message }); //Set the picture name to facilitate img storage in the database this.formData.img = response.data; }, //Execute before uploading pictures beforeAvatarUpload(file) { const isJPG = file.type === 'image/jpeg'; const isLt2M = file.size / 1024 / 1024 < 2; if (!isJPG) { this.$message.error('Upload package pictures can only be JPG format!'); } if (!isLt2M) { this.$message.error('Upload package picture size cannot exceed 2 MB!'); } return isJPG && isLt2M; },
-
The format and size are verified before uploading
-
After the upload is successful, the url of the image is assigned to facilitate the preview. More importantly, the img attribute of the form data is assigned to the picture name stored in the picture bed to facilitate the body communication of the form
The imageUrl here is the external chain provided by the object storage service of qiniu cloud. The external chain plus the picture name is the URL path to access the picture. We can easily find that as long as we store the name of the picture in the database, we can use the name of the picture to display the picture. In this way, the CRUD of the picture is changed to an ordinary field CRUD, and the rest of the processing is the same as the previous inspection items and inspection groups. However, since we want to use the image name to uniquely locate the image, we must ensure that the image name is unique. We use UUID to deal with it. The corresponding CRUD is given below
Front end CRUD
<script> var vue = new Vue({ el: '#app', data: { autoUpload: true,//Automatic upload imageUrl: null,//Model data, which is used for picture preview after uploading pictures activeName: 'first',//Add / edit window Tab label name pagination: {//Paging related properties currentPage: 1, pageSize: 10, total: 100, queryString: null, }, dataList: [],//List data formData: {},//Form Data tableData: [],//Check group list data in the add form window checkgroupIds: [],//id corresponding to the check group check box in the add form window dialogFormVisible: false, //Controls the display / hiding of the add window dialogFormVisible4Edit: false //Controls the display / hiding of the edit window }, created() { this.findPage(); }, methods: { //The hook after the file is uploaded successfully. The response is the value returned by the server, and the file is the js object encapsulated by the currently uploaded file handleAvatarSuccess(response, file) { //Assign value to model data for page image preview this.imageUrl = 'http://qu0dxvmvo.hd-bkt.clouddn.com/' + response.data; this.$message({ type: response.flag ? 'success' : 'error', message: response.message }); //Set the picture name to facilitate img storage in the database this.formData.img = response.data; }, //Execute before uploading pictures beforeAvatarUpload(file) { const isJPG = file.type === 'image/jpeg'; const isLt2M = file.size / 1024 / 1024 < 2; if (!isJPG) { this.$message.error('Upload package pictures can only be JPG format!'); } if (!isLt2M) { this.$message.error('Upload package picture size cannot exceed 2 MB!'); } return isJPG && isLt2M; }, //Edit options submit form handleEdit() { axios.post("/setMeal/edit.do?checkGroupIds=" + this.checkgroupIds, this.formData).then((res) => { if (res.data.flag == true) { //Pop up prompt this.$message({ message: res.data.message, type: 'success' }); //Close the edit window this.dialogFormVisible4Edit = false; this.findPage(); } else { this.$message.error(res.data.message); } }); }, //add to handleAdd() { axios.post("/setMeal/add.do?checkGroupIds=" + this.checkgroupIds, this.formData).then((res) => { if (res.data.flag == true) { //Pop up prompt this.$message({ message: res.data.message, type: 'success' }); //Close new window this.dialogFormVisible = false; this.findPage(); } else { this.$message.error(res.data.message); } }); }, handleDelete(row) { this.$confirm("Are you sure to delete?", "Tips", { type: 'warning' }).then(() => { var setMealId = row.id; //Send asynchronous request //If you still use double variables, it will return null axios.post("/setMeal/delete.do?setMealId=" + setMealId).then((res) => { //Process according to the data return 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: 'Operation cancelled', type: 'info' }); }) }, //Paging query 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; }); }, // Reset Form resetForm() { this.imageUrl = null; this.formData = {}; this.checkgroupIds = []; this.activeName = 'first'; }, // The add window pops up 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); } }); }, //Pop up the editing window to complete the dynamic display of data handleUpdate(row) { var setMealId = row.id; this.resetForm(); //Get form data axios.get("/setMeal/findById.do?setMealId=" + setMealId).then((res)=>{ if (res.data.flag == true) { //Form data assignment this.formData = res.data.data; //Picture preview update this.imageUrl = 'http://qu0dxvmvo.hd-bkt.clouddn.com/' + res.data.data.img; } else { this.$message.error(res.data.message); } }); //Get all options axios.get("/checkGroup/findAll.do").then((res) => { if (res.data.flag == true) { this.tableData = res.data.data; } else { this.$message.error(res.data.message); } }); //Get selected axios.get("/setMeal/findRelationship.do?setMealId=" + setMealId).then((res)=>{ if (res.data.flag == true) { //Array assignment this.checkgroupIds = res.data.data; } else { this.$message.error(res.data.message); } }); this.dialogFormVisible4Edit = true; }, //Switch page number handleCurrentChange(currentPage) { this.pagination.currentPage = currentPage; this.findPage(); } } }) </script>
You can see that in the front-end part, it is no different from the inspection items of the inspection team, except that the form is updated and the preview is generated after the picture is uploaded
Note the selection of HTTP request method here. GET is used for request parameters and POST is used for obtaining parameters. The details are described in more detail in the Java Web learning notes
Control layer CRUD
Previously, the img field has been used to make one-to-one correspondence between the picture and the picture in qiniu cloud storage. Therefore, the CRUD of the package is basically the same as the previous inspection item inspection group. However, in addition to the processing field, it is also necessary to upload the picture to the server. In the picture upload component, the path is bound as / setMeal/upload. The corresponding processing method is written in the control layer as follows
//Upload pictures to qiniu cloud @RequestMapping("/upload") public Result upload(MultipartFile imgFile) { //Get the file name and intercept the suffix String originalFilename = imgFile.getOriginalFilename(); int index = originalFilename.lastIndexOf('.'); String extension = originalFilename.substring(index - 1); //Use UUID to generate file names and retain suffixes String fileName = UUID.randomUUID().toString() + extension; try { //Upload using qiniu cloud component 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); } }
The relevant upload methods of qiniu cloud have been encapsulated, and the specific implementation can be found on qiniu's official website.
However, there is a problem with this processing: our CRUD processes the fields, and the pictures stored in the server have not been deleted. Even if the form is not submitted, simply uploading and previewing the pictures will store the pictures in the server, which will cause a large number of garbage pictures to accumulate. Therefore, we need to design methods to process the garbage pictures, The method we adopt here is to design two set sets in Redis, one to store the name of the picture stored in the database processed by CRUD and the other to process the name of all the pictures uploaded to the server. We can get which are spam pictures by taking the difference between the two.
We will use Quartz timing to clean up the garbage images later. In the control layer, the business layer only needs to maintain two Redis collections. Therefore, the image upload method is modified as follows. First, configure jedis in Spring
<?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 Related configuration of connection pool--> <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> <!--use windows of Redis,therefore 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>
Add a sentence after uploading
jedisPool.getResource().sadd(RedisConstant.SETMEAL_PIC_RESOURCES, fileName);
Of course, Autowired should also be used in the method
@Autowired private JedisPool jedisPool;
In this way, the image upload is done, and then the simple CRUD is done. The complete control layer code is given below
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; /** * Package management */ @RestController @RequestMapping("/setMeal") public class SetMealController { @Reference private SetMealService setMealService; @Autowired private JedisPool jedisPool; //Upload pictures to qiniu cloud @RequestMapping("/upload") public Result upload(MultipartFile imgFile) { //Get the file name and intercept the suffix String originalFilename = imgFile.getOriginalFilename(); int index = originalFilename.lastIndexOf('.'); String extension = originalFilename.substring(index - 1); //Use UUID to generate file names and retain suffixes String fileName = UUID.randomUUID().toString() + extension; try { //Upload using qiniu cloud component QiniuUtils.upload2Qiniu(imgFile.getBytes(), fileName); //Store picture name to 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); } } //Add package @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); } } //Edit Package @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); } } //Delete package @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); } } //Package paging query @RequestMapping("/findPage") public PageResult findPage(@RequestBody QueryPageBean queryPageBean) { return setMealService.findPage(queryPageBean); } //Query package by 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); } } //Query relation table by 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); } } }
Business layer CRUD
The garbage pictures are processed by Quartz, and the CRUD logic of the pictures stored in the server needs to be processed manually in the business layer, so the business layer involves three parts
- Form processing
- Redis collection processing
- Server image processing
The complete code is given below
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; //New business @Override public void add(Setmeal setmeal, Integer[] checkGroupIds) { //Update package table setMealDao.add(setmeal); //Update relation table for (Integer checkGroupId : checkGroupIds) { setMealDao.addRelationShip(setmeal.getId(), checkGroupId); } //Update Redis if (setmeal.getImg() != null) jedisPool.getResource().sadd(RedisConstant.SETMEAL_PIC_DB_RESOURCES, setmeal.getImg()); } //Editing business @Override public void edit(Setmeal setmeal, Integer[] checkGroupIds) { //Be sure to query the old pictures according to the id before updating String preImg = setMealDao.getImgById(setmeal.getId()); //Update package table setMealDao.update(setmeal); //Update relation table //Delete old relationship setMealDao.delRelationship(setmeal.getId()); //Add new relationships for (Integer checkGroupId : checkGroupIds) { setMealDao.addRelationShip(setmeal.getId(), checkGroupId); } //Update Redis Jedis resource = jedisPool.getResource(); String newImg = setmeal.getImg(); //Replace with new picture //Delete content in Redis resource.srem(RedisConstant.SETMEAL_PIC_DB_RESOURCES, preImg); //Delete the content in qiniu ECS //Here, garbage cleaning jobs may not be deleted, so write logic to delete them separately, because garbage cleaning will update the records of uploaded pictures QiniuUtils.deleteFileFromQiniu(preImg); resource.sadd(RedisConstant.SETMEAL_PIC_DB_RESOURCES, newImg); } @Override public void delete(Integer setMealId) { //Delete Redis cache String img = setMealDao.getImgById(setMealId); jedisPool.getResource().srem(RedisConstant.SETMEAL_PIC_DB_RESOURCES, img); //Delete the content in qiniu ECS QiniuUtils.deleteFileFromQiniu(img); //Delete relation table setMealDao.delRelationship(setMealId); //Delete package form 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); } }
Persistence layer CRUD
Both the server drawing bed and Redis collection are delivered to the business layer for processing. At the persistence layer, there is only simple form processing. The code is given as follows
/** * Package service interface */ 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); }
Corresponding mapping profile
<?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 timing processing
Quartz is a task scheduling framework, which can be used for timing processing
A new module called health is created for timing processing_ Jobs, a web app file packaged in war mode, first on the web Load Spring container in 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> <!-- load spring container --> <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 configuring 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>
Configure the Quartz plug-in for applicationcentext jobs (the plug-in has done dependency injection in 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/> <!--Register custom job--> <bean id="clearImgJob" class="com.cui.jobs.ClearImgJob"/> <bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <!-- Inject target object --> <property name="targetObject" ref="clearImgJob"/> <!-- Injection target method --> <property name="targetMethod" value="clearImg"/> </bean> <!-- Register a trigger and specify the time when the task is triggered --> <bean id="myTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <!-- injection JobDetail --> <property name="jobDetail" ref="jobDetail"/> <!-- Specifies the time to trigger, based on Cron expression --> <property name="cronExpression"> <!--0 0 2 * * ?--> <!--Every 10 s Clean up junk files once--> <value>0/10 * * * * ?</value> </property> </bean> <!-- Register a unified scheduling factory to schedule tasks through this scheduling factory --> <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <!-- Inject multiple triggers --> <property name="triggers"> <list> <ref bean="myTrigger"/> </list> </property> </bean> </beans>
Here we focus on four items: customized job, target object, target method and timing time
Custom job: indicates which class is our custom job
<!--Register custom job--> <bean id="clearImgJob" class="com.cui.jobs.ClearImgJob"/>
Target object and target method: one is to generate the target object by registering the bean of the custom job, and the other is to indicate which target method we need to obtain the bean of jobDetail
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <!-- Inject target object --> <property name="targetObject" ref="clearImgJob"/> <!-- Injection target method --> <pproperty name="targetMethod" value="clearImg"/> </bean>
The third is the trigger, which defines the trigger time of the task through the corresponding statement, and the timed statement has the corresponding statement generation tool
<!-- Register a trigger and specify the time when the task is triggered --> <bean id="myTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <!-- injection JobDetail --> <property name="jobDetail" ref="jobDetail"/> <!-- Specifies the time to trigger, based on Cron expression --> <property name="cronExpression"> <!--0 0 2 * * ?--> <!--Every 10 s Clean up junk files once--> <value>0/10 * * * * ?</value> </property> </bean>
Finally, there is a unified task scheduling factory, which can inject multiple triggers to execute multiple tasks
<!-- Register a unified scheduling factory to schedule tasks through this scheduling factory --> <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <!-- Inject multiple triggers --> <property name="triggers"> <list> <ref bean="myTrigger"/> </list> </property> </bean>
The last is the custom garbage disposal task
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; /** * Custom job to remove garbage pictures */ public class ClearImgJob { @Autowired private JedisPool jedisPool; public void clearImg() { //Calculate the difference according to the set set in Redis Set<String> trash = jedisPool.getResource().sdiff(RedisConstant.SETMEAL_PIC_RESOURCES, RedisConstant.SETMEAL_PIC_DB_RESOURCES); if (trash != null) { for (String trashName : trash) { //Delete the picture on qiniu ECS QiniuUtils.deleteFileFromQiniu(trashName); //Update Redis jedisPool.getResource().srem(RedisConstant.SETMEAL_PIC_RESOURCES, trashName); System.out.println(trashName + "Cleaned up"); } } } }