图片存储及定时清理

文章目录

一、 介绍

在实际开发中,我们会有很多处理不同功能的服务器。
分服务器处理的目的是让服务器各司其职,从而提高我们项目的运行效率。

如:

  • 应用服务器:负责部署我们的应用
  • 数据库服务器:运行我们的数据库
  • 文件服务器:负责存储用户上传文件的服务器

在这里插入图片描述

常见的图片存储方案:

  • 方案一:使用nginx搭建图片服务器
  • 方案二:使用开源的分布式文件存储系统,例如Fastdfs、HDFS等
  • 方案三:使用云存储,例如阿里云、七牛云等

二、七牛云存储

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

1、 使用Java SDK操作七牛云 并利用redis定时清理释放磁盘空间

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

1)需导入如下maven坐标:
<!--七牛云-->
<dependency>
  <groupId>com.qiniu</groupId>
  <artifactId>qiniu-java-sdk</artifactId>
  <version>7.2.0</version>
</dependency>
<!--定时组件Quartz 通过Quartz实现定时清理-->
<dependency>
  <groupId>org.quartz-scheduler</groupId>
  <artifactId>quartz</artifactId>
  <version>2.2.1</version>
</dependency>
<dependency>
  <groupId>org.quartz-scheduler</groupId>
  <artifactId>quartz-jobs</artifactId>
  <version>2.2.1</version>
</dependency>
2) redis配置文件spring-redis.xml
2.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" 
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" 
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
                         http://www.springframework.org/schema/beans/spring-beans.xsd
        				http://www.springframework.org/schema/mvc 
                         http://www.springframework.org/schema/mvc/spring-mvc.xsd
        				http://code.alibabatech.com/schema/dubbo 
                         http://code.alibabatech.com/schema/dubbo/dubbo.xsd
        				http://www.springframework.org/schema/context 
                         http://www.springframework.org/schema/context/spring-context.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>
2.2)将添加的图片名称(已保存到数据库中的)保存到redis的另一个Set集合中

在health_service_provider项目中提供Spring配置文件spring-redis.xml

内容同(2.1)
3)在springmvc.xml中配置文件上传组件 + 加载spring-redis.xml配置文件

(backend工程中)

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

<!--加载spring-redis.xml配置文件-->
<import resource="spring-redis.xml"></import>

Note:health_service_provider项目中的spring-redis.xml不用另写加载了,因为命名为spring…,在health_service_provider的web.xml中 如下代码。所以不用引用了

<param-value>classpath*:spring*.xml</param-value>
4)图片上传并预览
  • 流程:
    使用ElementUI提供的el-upload上传组件,将图片先上传到Controller;
    通过Controller调用封装的七牛云工具类,将图片上传到七牛云服务器上(就会有网络地址);
    拿到网络地址,将网络地址值设置给模型数据imageUrl,此时将展示此图片。
4.1)页面:
4.1.1)定义模型数据,用于后面上传文件的图片预览:
imageUrl:null, //模型数据,用于上传图片完成后图片预览
4.1.2)定义上传组件:
  <!--
  el-upload:上传组件
  action:上传的提交地址 值为Controller的请求路径
  auto-upload:选中文件后是否自动上传
  name:上传文件的名称,服务端可以根据名称获得上传的文件对象(Controller需获取到上传的图片,所以需要指定上传文件的名称)
  show-file-list:是否显示已上传文件列表(false表示不展示上传列表)
  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">
  <!--用于上传图片预览 imageUrl:模型数据,用于上传图片完成后图片预览。上传完成后需给imageUrl赋值-->
  <img v-if="imageUrl" :src="imageUrl" class="avatar">
  <!--用于展示上传图标-->
  <i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
4.1.3)定义对应的钩子函数:
   //文件上传成功后的钩子,response为服务端返回的值,file为当前上传的文件封装成的js对象
handleAvatarSuccess(response, file) {
   	//设置模型数据 展示图片
  		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;
}

//上传文件之前的钩子
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;
}
4.2)后台:
4.2.1)Java SDK操作七牛云封装为工具类
/**
 * 七牛云工具类
 */
public class QiniuUtils {
    public  static String accessKey = "gf5kMH-bWascazlb4p8QjFjoQCzcEIQNuqle5vCZ";
    public  static String secretKey = "RYawJkLea7dZhVT-30GG3ysY6ytepT-iiJMhdcP7";
    public  static String bucket = "lymhealthproject";//存储空间名称

    public static void upload2Qiniu(String filePath,String fileName){
        //构造一个带指定Zone对象的配置类
        Configuration cfg = new Configuration(Zone.zone2());
        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.zone2());
        //...其他参数参考类注释
        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.zone2());
        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());
        }
    }
}
4.2.2)在health_common工程中提供Redis常量类 (common工程的constant包下)
public class RedisConstant {
    //套餐图片所有图片名称
    public static final String SETMEAL_PIC_RESOURCES = "setmealPicResources";
    //套餐图片保存在数据库中的图片名称
    public static final String SETMEAL_PIC_DB_RESOURCES = "setmealPicDbResources";
}
4.2.3) …Controller:
	@Autowired
	private JedisPool jedisPool;//使用JedisPool操作Redis服务
	
	// 图片上传
    @RequestMapping("/upload")
    public Result upload(@RequestParam("imgFile") MultipartFile imgFile){
        try {
            // 1. 生成新fileName:
              // 1)原文件名
            String originalFilename = imgFile.getOriginalFilename();
              // 2)获取问后缀
            int lastIndexOf = originalFilename.lastIndexOf('.');
            String suffix = originalFilename.substring(lastIndexOf);
              // 3)新名字  使用UUID随机产生文件名称,防止同名文件覆盖
            String fileName = UUID.randomUUID().toString()+suffix;
            // 2.上传
            QiniuUtils.upload2Qiniu(imgFile.getBytes(),fileName);
			Result result = new Result(true,MessageConstant.PIC_UPLOAD_SUCCESS,fileName);
    		// 3.将上传的图片名称存入Redis,基于Redis的Set集合存储 🌟
    		jedisPool.getResource().sadd(RedisConstant.SETMEAL_PIC_RESOURCES,fileName);
    				return result;
        } catch (IOException e) {
            //上传失败
            e.printStackTrace();
            return new Result(false,MessageConstant.PIC_UPLOAD_FAIL);
        }
    }
4.2.4)实现类…ServiceImpl中

(在保存完数据库后将图片名称存储到redis集合中)

	@Autowired
	private JedisPool jedisPool;
	//新增套餐
	public void add(Setmeal setmeal, Integer[] checkgroupIds) {
		// 1 添加套餐
  		setmealDao.add(setmeal);
  		// 2 绑定套餐和检查组的多对多关系
  		if(checkgroupIds != null && checkgroupIds.length > 0){
    		this.setSetmealAndCheckGroup(setmeal.getId(),checkgroupIds);
  		}
  		//3 将图片名称保存到Redis    setmeal.getImg():获得图片名称🌟
  		this.savePic2Redis(setmeal.getImg());
	}
	
	//将图片名称保存到Redis
	private void savePic2Redis(String pic){
  		jedisPool.getResource().sadd(RedisConstant.SETMEAL_PIC_DB_RESOURCES,pic);
	}
5)定时任务 清理垃圾图片
  • 若不定时清理,则会存在一个问题,就是如果用户只上传了图片而没有最终保存套餐信息到我们的数据库,这时我们上传的图片就变为了垃圾图片。对于这些垃圾图片我们需要定时清理来释放磁盘空间。这就需要我们能够区分出来哪些是垃圾图片,哪些不是垃圾图片。如何实现呢?
  • 计算setmealPicResources集合与setmealPicDbResources集合的差值,结果就是垃圾图片的名称集合,通过定时任务组件Quartz定时清理这些垃圾图片
  • Quartz详情 见三
  • 方案:利用redis来保存图片名称具体做法为:(详见6))
    (1)当用户上传图片后,将图片名称保存到redis的一个Set集合中; 例如:集合名称为setmealPicResources
    (2)当用户添加套餐后,将图片名称保存到redis的另一个Set集合中;例如:集合名称为setmealPicDbResources
    (3)计算setmealPicResources集合与setmealPicDbResources集合的差值,结果就是垃圾图片的名称集合,清理这些图片即可
5.1)创建maven工程health_jobs(继承父工程),打包方式为war

pom.xml中:依赖…_interface工程;导入Quartz等相关坐标;指定端口;

	<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>
      <!--依赖health_interface接口工程-->
        <dependency>
            <groupId>com.lym</groupId>
            <artifactId>health_interface</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
      <!--定时任务quartz  Note:parent工程中已锁定版本!-->
        <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><!--tomcat插件 需借助插件启动项目-->
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <configuration>
                    <!-- 指定端口 -->
                    <port>83</port>
                    <!-- 请求路径 -->
                    <path>/</path>
                </configuration>
            </plugin>
        </plugins>
    </build>
5.2)配置:
5.2.1) 配置web.xml (加载spring容器)
<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>
5.2.2)配置log4j.properties(resources下)
### 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:\\mylog.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=info, stdout
5.2.3)配置applicationContext-redis.xml(resources下)

因为需连接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" 
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" 
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
                         http://www.springframework.org/schema/beans/spring-beans.xsd
        				http://www.springframework.org/schema/mvc 
                          http://www.springframework.org/schema/mvc/spring-mvc.xsd
        				http://code.alibabatech.com/schema/dubbo 
                          http://code.alibabatech.com/schema/dubbo/dubbo.xsd
        				http://www.springframework.org/schema/context
                          http://www.springframework.org/schema/context/spring-context.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.2.4)配置applicationContext-jobs.xml(resources下)

定时任务相关配置

<?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"
	xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" 
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
							http://www.springframework.org/schema/beans/spring-beans.xsd
							http://www.springframework.org/schema/mvc
							http://www.springframework.org/schema/mvc/spring-mvc.xsd
							http://code.alibabatech.com/schema/dubbo
							http://code.alibabatech.com/schema/dubbo/dubbo.xsd
							http://www.springframework.org/schema/context
							http://www.springframework.org/schema/context/spring-context.xsd">
  <!--开启spring注解使用-->
	<context:annotation-config></context:annotation-config>
  <!--注册自定义Job-->
	<bean id="clearImgJob" class="com.lym.jobs.ClearImgJob"><!--可能需修改❗️--></bean>
  
	<bean id="jobDetail" 
          class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
		<!-- 注入目标对象 -->
		<property name="targetObject" ref="clearImgJob"/>
		<!-- 注入目标方法 -->
		<property name="targetMethod" value="clearImg"/><!--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>
5.3)创建ClearImgJob定时任务类(health_jobs工程 com.lym.jobs包下)
/**
 * 自定义Job,实现定时清理垃圾图片
 */
public class ClearImgJob {
	// applicationContext-jobs.xml中需开启注解<context:annotation-config></context:annotation-config>   Note:项目中若包含springmvc.xml 其中<mvc:annotation-driven就相当于开启注解,就不用再另外设置了
    @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);
            }
        }
    }
}
6)定时清理图片流程总结:

方案:利用redis来保存图片名称具体做法为:

  • (1)当用户上传图片后,将图片名称保存到redis的一个Set集合中; 例如:集合名称为setmealPicResources
  • (2)当用户添加套餐后,将图片名称保存到redis的另一个Set集合中;例如:集合名称为setmealPicDbResources
  • (3)计算setmealPicResources集合与setmealPicDbResources集合的差值,结果就是垃圾图片的名称集合,清理这些图片即可
    详细:
  • (1)将上传的图片名称保存到redis的Set集合中
    (1.1)在health_backend项目中提供Spring配置文件spring-redis.xml; --> 2.1)
    在springmvc.xml中加载spring-redis.xml配置文件(backend项目中. --> 3)
    (1.2)在health_common工程中提供Redis常量类 (common工程中constant包下)–> 4.2.1)
    (1.3)完善SetmealController,在文件上传成功后将图片名称保存到redis集合中. --> 4.2.2)
  • (2)将添加的图片名称(已保存到数据库中的)保存到redis的另一个Set集合中
    (2.1)在health_service_provider项目中提供Spring配置文件spring-redis.xml. --> 2.2)
    (内容同(1.1))
    (2.2)完善SetmealServiceImpl服务类,在保存完数据库后将图片名称存储到redis集合中 --> 4.2.3)
  • (3)清理垃圾图片
    计算setmealPicResources集合与setmealPicDbResources集合的差值,结果就是垃圾图片的名称,通过定时任务组件Quartz定时清理这些垃圾图片
    (3.1)创建maven工程health_jobs继承父工程,打包方式为war;依赖…_interface工程;导入Quartz等相关坐标;指定端口; -->5.1)
    (3.2)配置(加载spring容器) -->5.2)
    (3.3)创建ClearImgJob定时任务类(health_jobs工程 com.lym.jobs包下) -->5.3)

三、定时任务组件Quartz

Quartz是Job scheduling(作业调度)领域的一个开源项目,Quartz既可以单独使用也可以跟spring框架整合使用,在实际开发中一般会使用后者。使用Quartz可以开发一个或者多个定时任务,每个定时任务可以单独指定执行的时间,例如每隔1小时执行一次、每个月第一天上午10点执行一次、每个月最后一天下午5点执行一次等。
官网:http://www.quartz-scheduler.org/

1 导入maven坐标
<dependency>
  <groupId>org.quartz-scheduler</groupId>
  <artifactId>quartz</artifactId>
  <version>2.2.1</version>
</dependency>
<dependency>
  <groupId>org.quartz-scheduler</groupId>
  <artifactId>quartz-jobs</artifactId>
  <version>2.2.1</version>
</dependency>
2 自定义一个Job
/**
 * 自定义Job
 */
public class JobDemo {
    public void run(){
        System.out.println("job execute...");
    }
}
3 提供Spring配置文件spring-jobs.xml(resources包下)

​ (1)配置自定义Job (需交给spring工厂初始化);
​ (2)任务描述
​ (3)触发器
​ (4)调度工厂等

<?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"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
						http://www.springframework.org/schema/beans/spring-beans.xsd
						http://www.springframework.org/schema/mvc
						http://www.springframework.org/schema/mvc/spring-mvc.xsd
						http://code.alibabatech.com/schema/dubbo
						http://code.alibabatech.com/schema/dubbo/dubbo.xsd
						http://www.springframework.org/schema/context
						http://www.springframework.org/schema/context/spring-context.xsd">
	<!-- 1)注册自定义Job   由spring工厂初始化它 (通过class将自定义的JobDemo注册到spring工厂中)-->
    <bean id="jobDemo" class="com.itheima.jobs.JobDemo"></bean>
	<!-- 2)注册JobDetail,作用是负责通过反射调用指定的Job及方法 -->
    <bean id="jobDetail" 
          class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <!-- 注入目标对象 (jobDemo对应bean的id)-->
        <property name="targetObject" ref="jobDemo"/>
        <!-- 注入目标方法 (run)-->
        <property name="targetMethod" value="run"/>
    </bean>
    <!-- 3)注册一个触发器,指定任务触发的时间 -->
    <bean id="myTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <!-- 注入JobDetail -->
        <property name="jobDetail" ref="jobDetail"/>
        <!-- 指定触发的时间,基于Cron表达式 (通过cronExpression传入Cron表达式)-->
        <property name="cronExpression">
            <value>0/10 * * * * ?</value><!--(Cron表达式值)表示每隔10秒触发一次-->
        </property>
    </bean>
    <!-- 4)注册一个统一的调度工厂,通过这个调度工厂调度任务 -->
    <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <!-- 注入多个触发器 -->
        <property name="triggers">
            <list>
                <ref bean="myTrigger"/><!--上面注册的触发器-->
            </list>
        </property>
    </bean>
</beans>
4 编写main方法进行测试

内容:

new ClassPathXmlApplicationContext("spring-jobs.xml");//此时就会自动执行
5 cron表达式
5.1) 通过cron表达式可以灵活的定义出符合要求的程序执行的时间

在这里插入图片描述
cron表达式分为七个域,之间使用空格分隔。其中最后一个域(年)可以为空。每个域都有自己允许的值和一些特殊字符构成。使用这些特殊字符可以使我们定义的表达式更加灵活。

下面是对这些特殊字符的介绍:
逗号(,):指定一个值列表,例如使用在月域上1,4,5,7表示1月、4月、5月和7月

横杠(-):指定一个范围,例如在时域上3-6表示3点到6点(即3点、4点、5点、6点)

星号(*):表示这个域上包含所有合法的值。例如,在月份域上使用星号意味着每个月都会触发

斜线(/):表示递增,例如使用在秒域上0/15表示每15秒

问号(?):只能用在日和周域上,但是不能在这两个域上同时使用。表示不指定

井号(#):只能使用在周域上,用于指定月份中的第几周的哪一天,例如6#3,意思是某月的第三个周五 (6=星期五,3意味着月份中的第三周)

L:某域上允许的最后一个值。只能使用在日和周域上。当用在日域上,表示的是在月域上指定的月份的最后一天。用于周域上时,表示周的最后一天,就是星期六

W:W 字符代表着工作日 (星期一到星期五),只能用在日域上,它用来指定离指定日的最近的一个工作日

5.2) cron表达式在线生成器

根据需求生成表达式:http://cron.qqe2.com/

  1. 编写main方法进行测试
    内容:
new ClassPathXmlApplicationContext("spring-jobs.xml");//此时就会自动执行
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值