2022-12-08 SSM项目转springboot整合jsp
admin
2024-03-28 04:55:39
0

目录

1.添加springboot相关pom依赖

2.Springboot整合jsp

2.1.使用打jar包方式执行

2.2.打war包执行

3.多数据源xml文件配置提取

3.1.数据源bean提取

3.2.创建数据源bean

3.3.创建相关配置bean

4.Spring全局事务配置类提取

5.SpringAop的xml开发转为注解开发

6.SpringMVC相关xml配置提取

6.1 视图文件路径配置(视图解析器)

6.2 拦截器注册

6.3 文件上传限制

6.4 全局异常处理

7.web.xml配置提取

7.1 全局应用上下文配置

7.2 全局上下文参数配置

7.3 session超时时间

7.4 字符过滤

7.5 filter注册

7.6 listener注册

7.7 前端控制器配置

7.8 开启后缀匹配

8.springboot集成log4j2日志

8.1 pom依赖

8.2 log4j2.xml文件

9.定时任务

9.1 Quartz 定时任务

9.2 Springboot整合Quartz

10.全局属性配置文件提取

10.1 自定义全局yml配置

10.2 注入配置类

11.自定义yml配置文件读取加载

11.1.创建yaml工厂类

11.2.在配置类上指定使用的配置文件


1.添加springboot相关pom依赖

注意:springboot6.x+版本更改了匹配策略ant_path_matcherpath_pattern_parser,并且关闭了依赖循环

如需依赖循环需要

spring:main:allow-circular-references: true #依赖循环mvc:pathmatch:use-suffix-pattern: true #后缀匹配matching-strategy: ant_path_matcher #匹配策略

2.Springboot整合jsp

2.1.使用打jar包方式执行

1.添加tomcat编译jsp的依赖

      org.apache.tomcat.embedtomcat-embed-jasper

2.添加springboot的maven插件

注意:springboot整合jsp时,插件版本必须是 1.4.2.RELEASE 时才能直接使用jar包方式运行

org.springframework.bootspring-boot-maven-plugin1.4.2.RELEASE

3.指定jsp编译文件输出位置

src/main/java**/*.*src/main/resources**/*.*src/main/webappMETA-INF/resources**/**false

4.运行

直接启动或使用 java -jar xxx.jar命令

2.2.打war包执行

1.指定打包后的文件名称

xxx

2.指定jsp编译目录


src/main/webappMETA-INF/resources**/*.*src/main/java**/*.xmlsrc/main/resources**/*.*

3.执行打包是war


war

4.主启动类继承SpringBootServletInitializer

/*** SpringBootServletInitializer: 继承这个类, 才能使用独立tomcat服务器*/
@SpringBootApplication
public class JspApplication  extends SpringBootServletInitializer  {
​public static void main(String[] args) {SpringApplication.run(JspApplication.class, args);}
​@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {return builder.sources(JspApplication.class);}
}

5.部署war

把war放到tomcat等服务器的发布目录中。 tomcat为例, myboot.war放到tomcat/webapps目录。

3.多数据源xml文件配置提取

3.1.数据源bean提取

使用druid数据源,将数据源bean提取到yml配置文件

spring:datasource:#使用Druid数据源连接池type: com.alibaba.druid.pool.DruidDataSourcedb1:jdbc-url: jdbc:oracle:thin:@xx.xxx.xx.xx:1521:ORCLusername: xxxpassword: xxxdriverClassName: oracle.jdbc.driver.OracleDriver# 下面为连接池的补充设置druid:initialSize: 20   #初始化连接个数minIdle: 10       #最小空闲连接个数maxActive: 100    #最大连接个数maxWait: 60000    #获取连接时最大等待时间,单位毫秒。timeBetweenEvictionRunsMillis: 10000  #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒minEvictableIdleTimeMillis: 10000     #配置一个连接在池中最小生存的时间,单位是毫秒validationQuery: SELECT x #用来检测连接是否有效的sql,要求是一个查询语句。db2:jdbc-url: jdbc:oracle:thin:@xx.xxx.xx.xx:1521:ORCLusername: xxxpassword: xxxdriverClassName: oracle.jdbc.driver.OracleDriver# 下面为连接池的补充设置druid:initialSize: 20   #初始化连接个数minIdle: 10       #最小空闲连接个数maxActive: 100    #最大连接个数maxWait: 60000    #获取连接时最大等待时间,单位毫秒。timeBetweenEvictionRunsMillis: 10000  #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒minEvictableIdleTimeMillis: 10000     #配置一个连接在池中最小生存的时间,单位是毫秒validationQuery: SELECT x #用来检测连接是否有效的sql,要求是一个查询语句。
#自定义配置文件
apply:mybatis:mapperLocations: classpath:mapping/**/*.xmlconfigLocation:  classpath:config/sql-map-config.xml

3.2.创建数据源bean

编写配置类,使用数据源builder自动创建对应数据源

3.3.创建相关配置bean

由于使用多数据源,所以使用自定义的sqlsessionFactory和sqlsession配置,排除自动配置

注意事项:多数据源时需要使用@Primary指定主数据源,否则spring会不知道先创建那个数据源的bean,会造成依赖循环错误

完整配置类代码

/*** 数据源配置*/
@Data
@Configuration
@ConfigurationProperties(prefix = "apply.mybatis")
@MapperScan(basePackages = "com.ws.*.mapper",sqlSessionFactoryRef = "sqlSessionFactory",sqlSessionTemplateRef = "sqlSessionTemplate")
public class DataSourceConfig {private String mapperLocations; //mapper路径地址private String configLocation; //mybatis配置文件地址/*** 数据源构建* @return*/@Primary@Bean(name = "dataSource_1")@ConfigurationProperties("spring.datasource.db1")public DataSource db1DataSource() {return DataSourceBuilder.create().build();}@Bean(name = "dataSource_2")@ConfigurationProperties("spring.datasource.db2")public DataSource db2DataSource() {return DataSourceBuilder.create().build();}/*** 动态数据源* @param dataSource1* @param dataSource2* @return*/@Bean(name = "dataSource")public DynamicDataSource dataSource(@Qualifier("dataSource_1")DataSource dataSource1,@Qualifier("dataSource_2")DataSource dataSource2){DynamicDataSource dynamicDataSource = new DynamicDataSource();Map map = new HashMap<>();map.put("dataSource_1",dataSource1);map.put("dataSource_2",dataSource2);dynamicDataSource.setTargetDataSources(map);dynamicDataSource.setDefaultTargetDataSource(dataSource1);return dynamicDataSource;}/*** sqlSessionFactory* @param dataSource* @return* @throws Exception*/@Bean(name = "sqlSessionFactory")public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DynamicDataSource dataSource) throws Exception {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setDataSource(dataSource);bean.setConfigLocation(new PathMatchingResourcePatternResolver().getResource(configLocation));bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));return bean.getObject();}/*** sqlSession* @param sqlSessionFactory* @return* @throws Exception*/@Bean(name = "sqlSessionTemplate")@Scope("prototype")public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {SqlSessionTemplate bean = new SqlSessionTemplate(sqlSessionFactory);return bean;}/***  数据源事务管理*/@Beanpublic DataSourceTransactionManager dataSourceTransactionManager(@Qualifier("dataSource") DynamicDataSource dataSource) {return new DataSourceTransactionManager(dataSource);}
}

排除数据源springboot的自动配置

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

4.Spring全局事务配置类提取

全局自定义配置抽取

apply:#全局事务配置项transaction:#切点表达式aopPointctExpression: (execution(* com.li.*.service..*(..))) || (execution(* com.li.*.**.service..*(..)))#操作方法数组saveMethodPrefix:- '*insert*'- '*add*'- '*update*'- '*save*'- '*delete*'#读取方法数组readMethodPrefix:- '*select*'- '*get*'- '*find*'- '*query*'

全局事务切面

import lombok.Data;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionInterceptor;import javax.annotation.Resource;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;/*** 全局事务配置切面*/@Data
@Aspect
@Order(2)
@Configuration
@ConfigurationProperties(prefix = "apply.transaction")
public class SpringTxAspectConfig {/** 定义切点表达式 **/private String aopPointctExpression;/** 操作方法数组*/private String[] saveMethodPrefix;/** 读取方法数组*/private String[] readMethodPrefix;@Resourceprivate PlatformTransactionManager transactionManager;/*** 增强(事务)的属性的配置* @return TransactionInterceptor*/@SuppressWarnings({ "unchecked", "rawtypes" })@Beanpublic TransactionInterceptor txAdvice() {NameMatchTransactionAttributeSource txAttributeS = new NameMatchTransactionAttributeSource();RuleBasedTransactionAttribute requiredAttr = new RuleBasedTransactionAttribute();// 设置事务传播 ,PROPAGATION_REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中requiredAttr.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);// 抛出异常后执行切点回滚requiredAttr.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));//设置只读requiredAttr.setReadOnly(false);RuleBasedTransactionAttribute supportsAttr = new RuleBasedTransactionAttribute();//设置传播规则, PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行supportsAttr.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);// 只读事务,不做更新操作supportsAttr.setReadOnly(true);//切入方法Map txMethod = new HashMap();for (String prefix : saveMethodPrefix) {txMethod.put(prefix, requiredAttr);}for (String prefix : readMethodPrefix) {txMethod.put(prefix, supportsAttr);}txAttributeS.setNameMap(txMethod);TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager, txAttributeS);return txAdvice;}/*** AOP配置定义切面和切点的信息*/@Beanpublic Advisor txAdviceAdvisor() {AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();pointcut.setExpression(aopPointctExpression);//设置切点表达式return new DefaultPointcutAdvisor(pointcut, txAdvice());}
}

注意:需在数据源配置类中向事务管理器注入动态数据源

5.SpringAop的xml开发转为注解开发

6.SpringMVC相关xml配置提取

6.1 视图文件路径配置(视图解析器)

spring:mvc:#springmvc视图解析路径view:prefix: /WEB-INF/views/suffix: .jsp

6.2 拦截器注册

/*** 权限控制拦截器注册*/
@Configuration
public class AccessInterceptorConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 1.  registry.addInterceptor(new LoginInterceptor())       注册登录拦截器// 2.  addPathPatterns("/**")                                拦截器拦截所有地址// 3.  excludePathPatterns(excludes)                         指定不被拦截的路径registry.addInterceptor(new AccessControlInterceptor());}
}

6.3 文件上传限制

配置类配置

 @Beanpublic MultipartConfigElement multipartConfigElement(){MultipartConfigFactory factory = new MultipartConfigFactory();// 上传单个文件大小设置factory.setMaxFileSize(DataSize.ofMegabytes(104857600));// factory.setMaxFileSize("20M");// 上传多个文件总共大小设置//factory.setMaxRequestSize(DataSize.ofGigabytes(2L));return factory.createMultipartConfig();}

yml配置

spring:servlet:multipart:enabled: true #是否启用http上传处理max-request-size: 104857600 #最大请求文件的大小max-file-size: 20MB #设置单个文件最大长度file-size-threshold: 20MB #当文件达到多少时进行磁盘写入

6.4 全局异常处理

未测试

/*** SpringMvc异常解析器*/@Beanpublic SimpleMappingExceptionResolver exceptionResolver(){SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();simpleMappingExceptionResolver.setDefaultErrorView("/common/failure");Properties properties = new Properties();properties.setProperty("java.sql.SQLException","/common/failure");properties.setProperty("java.lang.RuntimeException","/common/failure");simpleMappingExceptionResolver.setExceptionMappings(properties);return simpleMappingExceptionResolver;}

springboot全局异常处理

/*** 全局异常处理*/
@ControllerAdvice
public class AdminExceptionHandler {private static final Logger logger = LoggerFactory.getLogger(AdminExceptionHandler.class);@ExceptionHandler(value = SQLException.class)public String javaExceptionHandler(SQLException ex) {logger.error("捕获到SQLException异常{}",ex);return "/common/failure";}@ExceptionHandler(value = RuntimeException.class)public String javaExceptionHandler(RuntimeException ex) {logger.error("捕获到RuntimeExceptionException异常{}",ex);return "/common/failure";}}

7.web.xml配置提取

7.1 全局应用上下文配置

server:servlet:# 应用上下文路径context-path: /xxx

7.2 全局上下文参数配置

server:servlet:context-parameters:log4jRefreshInterval: 6000

7.3 session超时时间

server:#session超时时间servlet:session:timeout: 30m

7.4 字符过滤

   /*** 字符过滤*/@Beanpublic FilterRegistrationBean characterFilterRegistrationBean(){FilterRegistrationBean bean  = new FilterRegistrationBean<>();//使用框架中的过滤器类CharacterEncodingFilter filter  = new CharacterEncodingFilter();//指定使用的编码方式filter.setEncoding("utf-8");//指定request , response都使用encoding的值filter.setForceEncoding(true);bean.setFilter( filter);//字符过滤bean.addUrlPatterns("/*");return bean;}

关闭springboot默认的字符过滤,否则不生效

server:encoding:enabled: false

使用系统字符过滤

server:servlet:#开启系统字符过滤encoding:enabled: true#强制request,response都使用charset属性的值force: true#指定使用的编码方式charset: utf-8

7.5 filter注册

/*** 过滤器注册配置**/
@Configuration
public class WebFilterConfig {
​/*** 过滤器注册* session过期跳登录页*/@Beanpublic FilterRegistrationBean basicFilterRegistrationBean(){FilterRegistrationBean bean  = new FilterRegistrationBean<>();bean.setFilter( new BasicFilter());bean.addUrlPatterns("*.do","*.action");return bean;}
}

7.6 listener注册

    /*** 注册listener*/@SuppressWarnings({ "rawtypes", "unchecked" })@Beanpublic ServletListenerRegistrationBean listenerRegister() {ServletListenerRegistrationBean srb = new ServletListenerRegistrationBean();srb.setListener(new RequestContextListener());return srb;}

7.7 前端控制器配置

springboot2.6.x以上该后缀匹配失效

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.XmlWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;
​
/*** 前端控制器配置*/
public class MyWebAppInitializer implements WebApplicationInitializer {
​@Overridepublic void onStartup(ServletContext container) {XmlWebApplicationContext appContext = new XmlWebApplicationContext();/*  appContext.setConfigLocation("classpath:spring-mvc.xml");*/DispatcherServlet dispatcherServlet = new DispatcherServlet(appContext);dispatcherServlet.setDispatchOptionsRequest(true);ServletRegistration.Dynamic dispatcher =container.addServlet("dispatcher", dispatcherServlet);dispatcher.setLoadOnStartup(1);dispatcher.addMapping("*.action","*.do");}
}
 spring:mvc:servlet:load-on-startup: 1 #servlet容器启动优先级

springboot2.6.x以上该后缀匹配失效解决方案

加过滤器,保证过滤器链中该过滤器先执行,需处理静态资源访问问题,使用a字母开头命名,确保连音顺序第一个执行

@Slf4j
@WebFilter(urlPatterns = "/*")
public class AServletFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;String uri = request.getRequestURI();if(!uri.contains(".")){log.info("请求路径:{}","http://"+request.getLocalAddr()+":"+request.getLocalPort()+request.getContextPath());response.sendRedirect("http://"+request.getLocalAddr()+":"+request.getLocalPort()+request.getContextPath()+"/common/failure.action");return;}//判断是否是静态资源目录if(uri.contains("/resource/")){//静态资源直接放行filterChain.doFilter(request,servletResponse);return;}//非静态资源判断后缀String endStr = uri.substring(uri.lastIndexOf("."));if(endStr.contains(".do")||endStr.contains(".action")){//静态资源直接放行filterChain.doFilter(request,servletResponse);return;}response.sendRedirect("http://"+request.getLocalAddr()+":"+request.getLocalPort()+request.getContextPath()+"/common/failure.action");}@Overridepublic void destroy() {}
}

7.8 开启后缀匹配

springboot2.6.x以下版本

import com.ws.sys.core.web.interceptor.AccessControlInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
​
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
​@Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {//开启路径后缀匹配configurer.setUseRegisteredSuffixPatternMatch(true);}
​
}

springboot2.6.x以上版本,需修改匹配策略

但是不加后缀时此时也可以正常访问,并且此时前端控制器的后缀路径配置失效

spring:main:allow-circular-references: true #依赖循环mvc:pathmatch:use-suffix-pattern: true #后缀匹配matching-strategy: ant_path_matcher #匹配策略

8.springboot集成log4j2日志

8.1 pom依赖

org.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-logging       org.springframework.bootspring-boot-starter-log4j2

8.2 log4j2.xml文件




9.定时任务

9.1 Quartz 定时任务

1.依赖

   org.quartz-schedulerquartz2.2.1org.quartz-schedulerquartz-jobs2.2.1

2.普通方法定时任务配置

/*** Quartz配置(方法测试任务配置)*/
@Configuration
public class QuartzConfig  {
​/*** 要调用的工作类*/@Beanpublic Task quartzDay(){return new Task();}
​
​// 配置中设定了// ① targetMethod: 指定需要定时执行scheduleInfoAction中的simpleJobTest()方法// ② concurrent:对于相同的JobDetail,当指定多个Trigger时, 很可能第一个job完成之前,// 第二个job就开始了。指定concurrent设为false,多个job不会并发运行,第二个job将不会在第一个job完成之前开始。// ③ cronExpression:0/10 * * * * ?表示每10秒执行一次,具体可参考附表。// ④ triggers:通过再添加其他的ref元素可在list中放置多个触发器。 scheduleInfoAction中的simpleJobTest()方法@Bean(name = "daymailtask")public MethodInvokingJobDetailFactoryBean detailFactoryBean(@Qualifier("quartzDay") Object quartzDay) {MethodInvokingJobDetailFactoryBean bean = new MethodInvokingJobDetailFactoryBean();bean.setTargetObject(quartzDay);bean.setTargetMethod("xxx");//调用方法名bean.setConcurrent(false);return bean;}@Bean(name = "daymailtaskB")public MethodInvokingJobDetailFactoryBean detailFactoryBean2(@Qualifier("quartzDay") Object quartzDay) {MethodInvokingJobDetailFactoryBean bean = new MethodInvokingJobDetailFactoryBean();bean.setTargetObject(quartzDay);bean.setTargetMethod("xxx");bean.setConcurrent(false);return bean;}
​
​@Bean(name = "doDayMailTime")public CronTriggerFactoryBean cronTriggerBean(@Qualifier("daymailtask") MethodInvokingJobDetailFactoryBean daymailtask) {CronTriggerFactoryBean tigger = new CronTriggerFactoryBean();tigger.setJobDetail(daymailtask.getObject());tigger.setCronExpression("0/10 * * * * ?");// 十秒一次return tigger;
​}
​@Bean(name = "doDayMailTimeB")public CronTriggerFactoryBean cronTriggerBean2(@Qualifier("daymailtaskB") MethodInvokingJobDetailFactoryBean daymailtaskB) {CronTriggerFactoryBean tigger = new CronTriggerFactoryBean();tigger.setJobDetail(daymailtaskB.getObject());tigger.setCronExpression("0/10 * * * * ?");// 十秒一次return tigger;
​}
​@Bean@Lazy(false)public SchedulerFactoryBean schedulerFactory(Trigger[] cronTriggerBean) throws IOException {SchedulerFactoryBean bean = new SchedulerFactoryBean();System.err.println(cronTriggerBean[0]);bean.setTriggers(cronTriggerBean);return bean;}
​@Beanpublic Scheduler scheduler(SchedulerFactoryBean schedulerFactoryBean) {return schedulerFactoryBean.getScheduler();}
}

3.连接数据库整合自定义配置文件

#Main Scheduler Settings
#配置集群时,quartz调度器的id,由于配置集群时,只有一个调度器,必须保证每个服务器该值都相同,可以不用修改,只要每个ams都一样就行 
org.quartz.scheduler.instanceName=quartzScheduler_ym
org.quartz.scheduler.rmi.export=false
org.quartz.scheduler.rmi.proxy=false
org.quartz.scheduler.wrapJobExecutionInUserTransaction=false
#集群中每台服务器自己的id,AUTO表示自动生成,无需修改 
org.quartz.scheduler.instanceId=AUTO
org.quartz.scheduler.threadsInheritContextClassLoaderOfInitializer=true
org.quartz.scheduler.skipUpdateCheck=true
#一次性取出的任务数,默认值是1,适合负载均衡,但不适合大量的短时任务
org.quartz.scheduler.batchTriggerAcquisitionMaxCount=25
​
#Configure ThreadPool
#quartz线程池的实现类,无需修改 
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool 
#quartz线程池中线程数,可根据任务数量和负载度来调整 
org.quartz.threadPool.threadCount=25
#quartz线程优先级 
org.quartz.threadPool.threadPriority=5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
​
#Configure JobStore
org.quartz.jobStore.acquireTriggersWithinLock=true
#表示如果某个任务到达执行时间,而此时线程池中没有可用线程时,任务等待的最大时间,如果等待时间超过下面配置的值(毫秒),本次就不在执行,而等待下一次执行时间的到来,可根据任务量和负责程度来调整 
org.quartz.jobStore.misfireThreshold=60000
#实现集群时,任务的存储实现方式,org.quartz.impl.jdbcjobstore.JobStoreTX表示数据库存储,无需修改 
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
#连接数据库数据源名称,与下面配置中org.quartz.dataSource.myDS的myDS一致即可,可以无需修改 
org.quartz.jobStore.dataSource=myDS
#quartz存储任务相关数据的表的前缀,无需修改 
org.quartz.jobStore.tablePrefix=QRTZ_
#是否启用集群,启用,改为true,注意:启用集群后,必须配置下面的数据源,否则quartz调度器会初始化失败 
org.quartz.jobStore.isClustered=true
#集群中服务器相互检测间隔,每台服务器都会按照下面配置的时间间隔往服务器中更新自己的状态,如果某台服务器超过以下时间没有checkin,调度器就会认为该台服务器已经down掉,不会再分配任务给该台服务器
org.quartz.jobStore.clusterCheckinInterval=10000
​
#Configure DataSources
org.quartz.dataSource.myDS.driver=oracle.jdbc.driver.OracleDriver
​
​
org.quartz.dataSource.myDS.URL=jdbc:oracle:thin:@xxxx:1521:ORCL
org.quartz.dataSource.myDS.user=xxx
org.quartz.dataSource.myDS.password=xxx
#配置连接数据库连接池大小,一般为上面配置的线程池的2倍 
org.quartz.dataSource.myDS.maxConnections=50
#org.quartz.dataSource.myDS.validationQuery=select 1 from dual

工具类

监听spring容器初始化,加载属性配置文件,此时添加完定时任务后,需执行调度器的stater方法进行执行。

​
@Component
public class QuartzManager implements ApplicationListener {private StdSchedulerFactory schedulerFactory = null;private static final String CONFIG_FILE = "quartz-job.properties";private Logger logger = LoggerFactory.getLogger(QuartzManager.class);
​/*** @Description:添加一个定时任务* @param:jobName:任务名* @param:jobGroupName:任务组名* @param:triggerName:触发器名* @param:triggerGroupName:触发器组名* @param:jobClass:任务* @param:cron:时间设置*/@SuppressWarnings({ "unchecked", "rawtypes" })public void addJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName, Class jobClass,String cron, String id) {try {Scheduler sched = schedulerFactory.getScheduler();// 任务名,任务组,任务执行类JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();// 参数JobDataMap jobDataMap = jobDetail.getJobDataMap();jobDataMap.put("jkConfigId", id);// 触发器TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger();// 触发器名,触发器组triggerBuilder.withIdentity(triggerName, triggerGroupName);triggerBuilder.startNow();// 触发器时间设定triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));// 创建Trigger对象CronTrigger trigger = (CronTrigger) triggerBuilder.build();// 调度容器设置JobDetail和Triggersched.scheduleJob(jobDetail, trigger);// 启动if (!sched.isShutdown()) {sched.start();}} catch (Exception e) {throw new RuntimeException(e);}}/*** @Description:添加一个定时任务* @param jobName* @param jobGroupName* @param triggerName* @param triggerGroupName* @param jobClass* @param cron* @param dataMap*/@SuppressWarnings({ "unchecked", "rawtypes" })public void addJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName, Class jobClass,String cron, Map dataMap) {try {Scheduler sched = schedulerFactory.getScheduler();// 任务名,任务组,任务执行类JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();// 参数JobDataMap jobDataMap = jobDetail.getJobDataMap();jobDataMap.putAll(dataMap);//传递的所有参数// 触发器TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger();// 触发器名,触发器组triggerBuilder.withIdentity(triggerName, triggerGroupName);triggerBuilder.startNow();// 触发器时间设定triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));// 创建Trigger对象CronTrigger trigger = (CronTrigger) triggerBuilder.build();// 调度容器设置JobDetail和Triggersched.scheduleJob(jobDetail, trigger);// 启动if (!sched.isShutdown()) {sched.start();}} catch (Exception e) {throw new RuntimeException(e);}}
​/*** @Description:修改一个任务的触发时间* @param:jobName* @param:jobGroupName* @param:triggerName:触发器名* @param:triggerGroupName:触发器组名* @param:cron:时间设置*/public void modifyJobTime(String jobName, String jobGroupName, String triggerName, String triggerGroupName,String cron) {try {Scheduler sched = schedulerFactory.getScheduler();TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);if (trigger == null) {return;}String oldTime = trigger.getCronExpression();if (!oldTime.equalsIgnoreCase(cron)) {/** 方式一:调用 rescheduleJob 开始 */// 触发器TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger();// 触发器名,触发组名triggerBuilder.startNow();// 触发器时间设定triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));// 创建Trigger对象trigger = (CronTrigger) triggerBuilder.build();// 方式一:修改一个任务的触发时间sched.rescheduleJob(triggerKey, trigger);/** 方式一:调用rescheduleJob 结束 */
​/** 方式二:先删除,然后再创建一个新的Job */// JobDetail jobDetail =// sched.getJobDetail(JobKey.jobKey(jobName,jobGroupName));// Class jobClass = jobDetail.getJobClass();// removeJob(jobName,jobGroupName,triggerName,triggerGroupName);// addJob(jobName,jobGroupName,triggerName,triggerGroupName,jobClass,cron);/** 方式二:先删除,然后再创建一个新的job */}} catch (Exception e) {throw new RuntimeException(e);}}
​/*** 触发状态为运行的任务* * @param jobName* @param jobGroupName* @param triggerName* @param triggerGroupName* @param cron*/public void triggerRunningJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName,String cron) {try {Scheduler sched = schedulerFactory.getScheduler();JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);sched.triggerJob(jobKey);} catch (Exception e) {throw new RuntimeException(e);}}
​/*** @Description:移除一个任务* @param:jobName* @param:jobGroupName* @param:triggerName* @param:triggerGroupName*/public void removeJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName) {try {Scheduler sched = schedulerFactory.getScheduler();TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);sched.pauseTrigger(triggerKey);// 停止触发器sched.unscheduleJob(triggerKey);// 移除触发器sched.deleteJob(JobKey.jobKey(jobName, jobGroupName));// 删除任务} catch (Exception e) {throw new RuntimeException(e);}}
​/*** @Description:启动所有定时任务*/public void startJobs() {try {Scheduler sched = schedulerFactory.getScheduler();sched.start();} catch (Exception e) {throw new RuntimeException(e);}}
​/*** @Description:关闭所有定时任务*/public void shutdownJobs() {try {Scheduler sched = schedulerFactory.getScheduler();if (!sched.isShutdown()) {sched.shutdown();}} catch (Exception e) {throw new RuntimeException(e);}}
​private void init() {try {logger.info("****************初始化Qutarz调度器*********************");schedulerFactory = new StdSchedulerFactory();schedulerFactory.initialize(Thread.currentThread().getContextClassLoader().getResource(CONFIG_FILE).getFile());} catch (Exception e) {e.printStackTrace();}}
​@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {if (event.getApplicationContext().getDisplayName().equals("Root WebApplicationContext")) {if (null == event.getApplicationContext().getParent()) {init();}}}
}

9.2 Springboot整合Quartz

1.依赖

  org.springframework.bootspring-boot-starter-quartz

2.分布式quartz的yml配置

 #定时任务quartz:# 将任务等保存化到数据库job-store-type: jdbc# 程序结束时会等待quartz相关的内容结束wait-for-jobs-to-complete-on-shutdown: true# QuartzScheduler启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录overwrite-existing-jobs: true# 这里居然是个map,搞得智能提示都没有properties:org:quartz:# scheduler相关scheduler:# scheduler的实例名instanceName: schedulerinstanceId: AUTO# 持久化相关jobStore:class: org.quartz.impl.jdbcjobstore.JobStoreTXdriverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate# 表示数据库中相关表是QRTZ_开头的tablePrefix: QRTZ_useProperties: false# 线程池相关threadPool:class: org.quartz.simpl.SimpleThreadPool# 线程数threadCount: 10# 线程优先级threadPriority: 5threadsInheritContextClassLoaderOfInitializingThread: true

3.编写核心任务方法

public class QuartzTestJob extends QuartzJobBean{@Overrideprotected void executeInternal(JobExecutionContext context) throws JobExecutionException {String userName = (String) context.getJobDetail().getJobDataMap().get("username");System.out.println("userName:" + userName);}
}

4.配置注册

@Configuration
public class TaskConfig {
​@Bean("helloJob")public JobDetail helloJobDetail() {return JobBuilder.newJob(QuartzTestJob.class).withIdentity("DateTimeJob").usingJobData("username", "Hello Quartz").storeDurably()//即使没有Trigger关联时,也不需要删除该JobDetail.build();}
​@Beanpublic Trigger printTimeJobTrigger() {// 每秒执行一次CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/1 * * * * ?");return TriggerBuilder.newTrigger()//.forJob(helloJobDetail()).withIdentity("quartzTaskService").withSchedule(cronScheduleBuilder).build();}
}

10.全局属性配置文件提取

10.1 自定义全局yml配置

#自定义全局配置
apply:appRoot: xxxdatePatterns: yyyy-MM-dd,yyyy-MM-dd HH:mm:ss,yyyy-MM-dd HH:mm,yyyyMMdd,yyyyMMddmm,yyyyMMddHHmmsssysUserLoginLogEnabled: true

10.2 注入配置类

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
​
/*** 自定义的参数yml配置*/
@Configuration
@ConfigurationProperties("apply")
@Data
public class ApplicationConfig {
​private String datePatterns;
​private boolean sysUserLoginLogEnabled;
​private static String appRoot;
​
​public static String getAppRoot(){return ApplicationConfig.appRoot;}
}
 

11.自定义yml配置文件读取加载

11.1.创建yaml工厂类

import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.DefaultPropertySourceFactory;
import org.springframework.core.io.support.EncodedResource;
​
import java.io.IOException;
import java.util.List;
​
​
public class YamlPropertySourceFactory extends DefaultPropertySourceFactory {@Overridepublic PropertySource createPropertySource(String name, EncodedResource resource) throws IOException {if (resource == null) {return super.createPropertySource(name, resource);}List> sources = new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource());return sources.get(0);}
}

11.2.在配置类上指定使用的配置文件

@PropertySource(value = {"classpath:customize-context.yml"}, factory = YamlPropertySourceFactory.class)
@ConfigurationProperties(prefix = "apply.transaction" 

相关内容

热门资讯

调整周期里的财务韧性,卓越商企... 卓越商企服务业绩会现场本报记者 张蓓 黄指南 深圳报道8月28日,卓越商企服务(06989.HK)召...
快手:持续创作超10年的作者超... 8月29日,快手科技创始人、董事长兼首席执行官程一笑在2026快手光合创作者大会上表示,现阶段,每天...
首次揭示,中国团队在量子相变领... 8月29日,从宁波东方理工大学获悉,该校余雪佳团队联合湖南大学、浙江大学相关研究团队,在量子相变与临...
重磅官宣!长鑫LPDDR6内存... 8月29日,微博“长鑫存储”发布消息称,长鑫LPDDR6内存正式量产,将首发搭载在小米18 Fold...
蒙牛2026年中报“八骏齐奔”... 蒙牛的“一体两翼”战略正渐入佳境。8月27日,蒙牛乳业(2319.HK)在中国香港召开2026年中期...
股价月内翻倍后高位回调,百花医... 8月29日,8月28日,百花医药盘中触及跌停。Wind数据显示,截至8月28日收盘,公司股价报15....
欣旺达的业绩,为什么会这么烂?... 今年上半年,全球储能电池出货量同比增长97.5%,国内动力电池装车量同比增长12%,锂电行业仍处高景...
胜宏科技董事长转让大额股份给其... 8月28日,惠州上市公司胜宏科技(惠州)股份有限公司(以下简称“胜宏科技”)发布公告称,公司于今日收...
山西焦煤:目前公司矿井基本全部... 8月29日,山西焦煤在业绩说明会表示,近期公司主要停产矿井有西曲矿、马兰矿、镇城底矿和西铭矿。其中,...
凌雄科技发布半年报 算力业务占... 中经记者 石健 北京报道8月27日,凌雄科技(02436.HK)发布2026年中期业绩公告。公告显示...