赞
踩
目录
9.3 对于quartz定时任务job中不能注入bean对象处理
注意:springboot6.x+版本更改了匹配策略ant_path_matcher为path_pattern_parser,并且关闭了依赖循环
如需依赖循环需要
- spring:
- main:
- allow-circular-references: true #依赖循环
- mvc:
- pathmatch:
- use-suffix-pattern: true #后缀匹配
- matching-strategy: ant_path_matcher #匹配策略
1.添加tomcat编译jsp的依赖
- <!--tomcat-->
- <dependency>
- <groupId>org.apache.tomcat.embed</groupId>
- <artifactId>tomcat-embed-jasper</artifactId>
- </dependency>
2.添加springboot的maven插件
注意:springboot整合jsp时,插件版本必须是 1.4.2.RELEASE 时才能直接使用jar包方式运行
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- <!--打包jar, 有jsp文件时,必须指定maven-plugin插件的版本是 1.4.2.RELEASE-->
- <version>1.4.2.RELEASE</version>
- </plugin>
- </plugins>
3.指定jsp编译文件输出位置
- <resources>
- <resource>
- <directory>src/main/java</directory>
- <includes>
- <include>**/*.*</include>
- </includes>
- </resource>
- <resource>
- <directory>src/main/resources</directory>
- <includes>
- <include>**/*.*</include>
- </includes>
- </resource>
-
- <!-- 打包时将jsp文件拷贝到META-INF目录下 -->
- <resource>
- <!-- 指定resources插件处理哪个目录下的资源文件 -->
- <directory>src/main/webapp</directory>
- <!--注意此次必须要放在此目录下才能被访问到 -->
- <targetPath>META-INF/resources</targetPath>
- <includes>
- <include>**/**</include>
- </includes>
- <filtering>false</filtering>
- </resource>
-
- </resources>
4.运行
直接启动或使用 java -jar xxx.jar命令
1.指定打包后的文件名称
- <build>
- <!--打包后的文件名称-->
- <finalName>xxx</finalName>
- </build>
2.指定jsp编译目录
- <!--resources插件, 把jsp编译到指定的目录-->
- <resources>
- <resource>
- <directory>src/main/webapp</directory>
- <targetPath>META-INF/resources</targetPath>
- <includes>
- <include>**/*.*</include>
- </includes>
- </resource>
-
- <!--使用了mybatis ,而且mapper文件放在src/main/java目录-->
- <resource>
- <directory>src/main/java</directory>
- <includes>
- <include>**/*.xml</include>
- </includes>
- </resource>
-
- <!--把src/main/resources下面的所有文件,都包含到classes目录-->
- <resource>
- <directory>src/main/resources</directory>
- <includes>
- <include>**/*.*</include>
- </includes>
- </resource>
- </resources>
3.执行打包是war
- <!--打包类型-->
- <packaging>war</packaging>
4.主启动类继承SpringBootServletInitializer
- /**
- * SpringBootServletInitializer: 继承这个类, 才能使用独立tomcat服务器
- */
- @SpringBootApplication
- public class JspApplication extends SpringBootServletInitializer {
-
- public static void main(String[] args) {
- SpringApplication.run(JspApplication.class, args);
- }
-
- @Override
- protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
- return builder.sources(JspApplication.class);
- }
- }
5.部署war
把war放到tomcat等服务器的发布目录中。 tomcat为例, myboot.war放到tomcat/webapps目录。
使用druid数据源,将数据源bean提取到yml配置文件
- spring:
- datasource:
- #使用Druid数据源连接池
- type: com.alibaba.druid.pool.DruidDataSource
- db1:
- jdbc-url: jdbc:oracle:thin:@xx.xxx.xx.xx:1521:ORCL
- username: xxx
- password: xxx
- driverClassName: 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:ORCL
- username: xxx
- password: xxx
- driverClassName: 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/**/*.xml
- configLocation: classpath:config/sql-map-config.xml
编写配置类,使用数据源builder自动创建对应数据源
由于使用多数据源,所以使用自定义的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<Object,Object> 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;
- }
-
- /**
- * 数据源事务管理
- */
- @Bean
- public DataSourceTransactionManager dataSourceTransactionManager(@Qualifier("dataSource") DynamicDataSource dataSource) {
- return new DataSourceTransactionManager(dataSource);
- }
- }
排除数据源springboot的自动配置
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
全局自定义配置抽取
- 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;
-
- @Resource
- private PlatformTransactionManager transactionManager;
-
-
- /**
- * 增强(事务)的属性的配置
- * @return TransactionInterceptor
- */
- @SuppressWarnings({ "unchecked", "rawtypes" })
- @Bean
- public 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配置定义切面和切点的信息
- */
- @Bean
- public Advisor txAdviceAdvisor() {
- AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
- pointcut.setExpression(aopPointctExpression);//设置切点表达式
- return new DefaultPointcutAdvisor(pointcut, txAdvice());
- }
- }
注意:需在数据源配置类中向事务管理器注入动态数据源
- spring:
- mvc:
- #springmvc视图解析路径
- view:
- prefix: /WEB-INF/views/
- suffix: .jsp
- /**
- * 权限控制拦截器注册
- */
- @Configuration
- public class AccessInterceptorConfig implements WebMvcConfigurer {
- @Override
- public void addInterceptors(InterceptorRegistry registry) {
- // 1. registry.addInterceptor(new LoginInterceptor()) 注册登录拦截器
- // 2. addPathPatterns("/**") 拦截器拦截所有地址
- // 3. excludePathPatterns(excludes) 指定不被拦截的路径
- registry.addInterceptor(new AccessControlInterceptor());
- }
- }
配置类配置
- @Bean
- public 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 #当文件达到多少时进行磁盘写入
未测试
- /**
- * SpringMvc异常解析器
- */
- @Bean
- public 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";
- }
-
- }
- server:
- servlet:
- # 应用上下文路径
- context-path: /xxx
- server:
- servlet:
- context-parameters:
- log4jRefreshInterval: 6000
- server:
- #session超时时间
- servlet:
- session:
- timeout: 30m
- /**
- * 字符过滤
- */
- @Bean
- public FilterRegistrationBean<CharacterEncodingFilter> characterFilterRegistrationBean(){
- FilterRegistrationBean<CharacterEncodingFilter> 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
- /**
- * 过滤器注册配置
- *
- */
- @Configuration
- public class WebFilterConfig {
-
- /**
- * 过滤器注册
- * session过期跳登录页
- */
- @Bean
- public FilterRegistrationBean<BasicFilter> basicFilterRegistrationBean(){
- FilterRegistrationBean<BasicFilter> bean = new FilterRegistrationBean<>();
- bean.setFilter( new BasicFilter());
- bean.addUrlPatterns("*.do","*.action");
- return bean;
- }
- }
- /**
- * 注册listener
- */
- @SuppressWarnings({ "rawtypes", "unchecked" })
- @Bean
- public ServletListenerRegistrationBean listenerRegister() {
- ServletListenerRegistrationBean srb = new ServletListenerRegistrationBean();
- srb.setListener(new RequestContextListener());
- return srb;
- }
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 {
-
- @Override
- public 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 {
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
-
- }
-
- @Override
- public 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");
- }
-
- @Override
- public void destroy() {
-
- }
- }
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 {
-
- @Override
- public 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 #匹配策略
-
- <!-- web:spring boot的依赖 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- <exclusions><!-- 去掉springboot默认配置 -->
- <exclusion>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-logging</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <!-- 引入log4j2依赖 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-log4j2</artifactId>
- </dependency>
-
- <?xml version="1.0" encoding="UTF-8"?>
- <!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
- <!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
- <configuration monitorInterval="5">
- <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
-
- <!--变量配置-->
- <Properties>
- <!-- 格式化输出:%date表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
- <!-- %logger{36} 表示 Logger 名字最长36个字符 -->
- <property name="LOG_PATTERN" value="%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" />
- <!-- 定义日志存储的路径 -->
- <property name="FILE_PATH" value="logs" />
- <property name="FILE_NAME" value="项目名" />
- </Properties>
-
- <appenders>
-
- <console name="Console" target="SYSTEM_OUT">
- <!--输出日志的格式-->
- <PatternLayout pattern="${LOG_PATTERN}"/>
- <!--控制台只输出level及其以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
- <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
- </console>
-
- <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,适合临时测试用-->
- <File name="Filelog" fileName="${FILE_PATH}/test.log" append="false">
- <PatternLayout pattern="${LOG_PATTERN}"/>
- </File>
-
- <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
- <RollingFile name="RollingFileInfo" fileName="${FILE_PATH}/info.log" filePattern="${FILE_PATH}/${FILE_NAME}-INFO-%d{yyyy-MM-dd}_%i.log.gz">
- <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
- <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
- <PatternLayout pattern="${LOG_PATTERN}"/>
- <Policies>
- <!--interval属性用来指定多久滚动一次,默认是1 hour-->
- <TimeBasedTriggeringPolicy interval="1"/>
- <SizeBasedTriggeringPolicy size="10MB"/>
- </Policies>
- <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
- <DefaultRolloverStrategy max="15"/>
- </RollingFile>
-
- <!-- 这个会打印出所有的warn及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
- <RollingFile name="RollingFileWarn" fileName="${FILE_PATH}/warn.log" filePattern="${FILE_PATH}/${FILE_NAME}-WARN-%d{yyyy-MM-dd}_%i.log.gz">
- <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
- <ThresholdFilter level="WARN" onMatch="ACCEPT" onMismatch="DENY"/>
- <PatternLayout pattern="${LOG_PATTERN}"/>
- <Policies>
- <!--interval属性用来指定多久滚动一次,默认是1 hour-->
- <TimeBasedTriggeringPolicy interval="1"/>
- <SizeBasedTriggeringPolicy size="10MB"/>
- </Policies>
- <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
- <DefaultRolloverStrategy max="15"/>
- </RollingFile>
-
- <!-- 这个会打印出所有的error及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
- <RollingFile name="RollingFileError" fileName="${FILE_PATH}/error.log" filePattern="${FILE_PATH}/${FILE_NAME}-ERROR-%d{yyyy-MM-dd}_%i.log.gz">
- <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
- <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
- <PatternLayout pattern="${LOG_PATTERN}"/>
- <Policies>
- <!--interval属性用来指定多久滚动一次,默认是1 hour-->
- <TimeBasedTriggeringPolicy interval="1"/>
- <SizeBasedTriggeringPolicy size="10MB"/>
- </Policies>
- <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
- <DefaultRolloverStrategy max="15"/>
- </RollingFile>
-
- </appenders>
-
- <!--Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。-->
- <!--然后定义loggers,只有定义了logger并引入的appender,appender才会生效-->
- <loggers>
-
- <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
- <!-- <logger name="org.mybatis" level="info" additivity="false">
- <AppenderRef ref="Console"/>
- </logger>-->
- <!--监控系统信息-->
- <!--若是additivity设为false,则 子Logger 只会在自己的appender里输出,而不会在 父Logger 的appender里输出。-->
- <Logger name="org.springframework" level="DEBUG" additivity="false">
- <AppenderRef ref="Console"/>
- </Logger>
-
- <root level="info">
- <appender-ref ref="Console"/>
- <appender-ref ref="Filelog"/>
- <appender-ref ref="RollingFileInfo"/>
- <appender-ref ref="RollingFileWarn"/>
- <appender-ref ref="RollingFileError"/>
- </root>
- </loggers>
-
- </configuration>
1.依赖
- <!--quartz-->
- <dependency>
- <groupId>org.quartz-scheduler</groupId>
- <artifactId>quartz</artifactId>
- <version>2.2.1</version>
- </dependency>
- <!--quartz-jobs-->
- <dependency>
- <groupId>org.quartz-scheduler</groupId>
- <artifactId>quartz-jobs</artifactId>
- <version>2.2.1</version>
- </dependency>
2.普通方法定时任务配置
- /**
- * Quartz配置(方法测试任务配置)
- */
- @Configuration
- public class QuartzConfig {
-
- /**
- * 要调用的工作类
- */
- @Bean
- public 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;
- }
-
- @Bean
- public 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<ContextRefreshedEvent> {
- @Autowired
- private StdSchedulerFactory schedulerFactory ;
- 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<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
- // 触发器名,触发器组
- triggerBuilder.withIdentity(triggerName, triggerGroupName);
- triggerBuilder.startNow();
- // 触发器时间设定
- triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
- // 创建Trigger对象
- CronTrigger trigger = (CronTrigger) triggerBuilder.build();
- // 调度容器设置JobDetail和Trigger
- sched.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<String,Object> dataMap) {
- try {
- Scheduler sched = schedulerFactory.getScheduler();
- // 任务名,任务组,任务执行类
- JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();
- // 参数
- JobDataMap jobDataMap = jobDetail.getJobDataMap();
- jobDataMap.putAll(dataMap);//传递的所有参数
- // 触发器
- TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
- // 触发器名,触发器组
- triggerBuilder.withIdentity(triggerName, triggerGroupName);
- triggerBuilder.startNow();
- // 触发器时间设定
- triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
- // 创建Trigger对象
- CronTrigger trigger = (CronTrigger) triggerBuilder.build();
- // 调度容器设置JobDetail和Trigger
- sched.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<Trigger> 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<? extends Job> 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 {
-
- schedulerFactory .initialize(Thread.currentThread().getContextClassLoader().getResource(CONFIG_FILE).getFile());
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- @Override
- public void onApplicationEvent(ContextRefreshedEvent event) {
-
- if (null == event.getApplicationContext().getParent()) {
- init();
-
- }
- }
- }
1.依赖
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-quartz</artifactId>
- </dependency>
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: scheduler
- instanceId: AUTO
- # 持久化相关
- jobStore:
- class: org.quartz.impl.jdbcjobstore.JobStoreTX
- driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
- # 表示数据库中相关表是QRTZ_开头的
- tablePrefix: QRTZ_
- useProperties: false
- # 线程池相关
- threadPool:
- class: org.quartz.simpl.SimpleThreadPool
- # 线程数
- threadCount: 10
- # 线程优先级
- threadPriority: 5
- threadsInheritContextClassLoaderOfInitializingThread: true
3.编写核心任务方法
- public class QuartzTestJob extends QuartzJobBean{
- @Override
- protected 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();
- }
-
- @Bean
- public Trigger printTimeJobTrigger() {
- // 每秒执行一次
- CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/1 * * * * ?");
- return TriggerBuilder.newTrigger()
- //.forJob(helloJobDetail())
- .withIdentity("quartzTaskService")
- .withSchedule(cronScheduleBuilder)
- .build();
- }
- }
注意事项:
Quartz的定时任务的job类中实现的StatefulJob接口已过时,在开发时尽量使用 实现Job接口或者继承QuartzJobBean类的方式进行执行类的实现。
由于Quartz的job类中无法直接注入spring容器的bean对象,会报空指针异常,所以在config包下配置了自定义的quartz的工厂来将spring的bean进行注入,然后在调度器工厂的bean中进行设置,即可以在job类中对bean进行注入,但在操作时需要注入自己配置的工厂bean对象。
1.自定义工厂配置类
- @Component
- public class CustomJobFactory extends AdaptableJobFactory {
-
- @Autowired
- private AutowireCapableBeanFactory capableBeanFactory;
-
- @Override
- protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
- //调用父类的方法
- Object jobInstance = super.createJobInstance(bundle);
- //进行注入
- capableBeanFactory.autowireBean(jobInstance);
- return jobInstance;
- }
-
- }
2.使用配置类注入自定义工厂
- /**
- * QuartZ定时任务配置
- */
- @Configuration
- public class QuartzConfig {
-
- @Autowired
- private CustomJobFactory customJobFactory;
-
- @SneakyThrows
- @Bean("schedulerFactory")
- public StdSchedulerFactory scheduler(){
- StdSchedulerFactory schedulerFactory = new StdSchedulerFactory();
- Scheduler scheduler = schedulerFactory.getScheduler();
- // 自定义 JobFactory 使得在 Quartz Job 中可以使用 @Autowired
- scheduler.setJobFactory(customJobFactory);
- scheduler.start();
- return schedulerFactory;
- }
-
- }
3.在操作工具类初始化时中注入自定义的调度器
- @Autowired
- private StdSchedulerFactory schedulerFactory ;
-
- schedulerFactory .initialize(Thread.currentThread().getContextClassLoader().getResource(CONFIG_FILE).getFile());
- #自定义全局配置
- apply:
- appRoot: xxx
- datePatterns: yyyy-MM-dd,yyyy-MM-dd HH:mm:ss,yyyy-MM-dd HH:mm,yyyyMMdd,yyyyMMddmm,yyyyMMddHHmmss
- sysUserLoginLogEnabled: true
- 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;
- }
- }
- 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 {
- @Override
- public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
- if (resource == null) {
- return super.createPropertySource(name, resource);
- }
- List<PropertySource<?>> sources = new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource());
- return sources.get(0);
- }
- }
- @PropertySource(value = {"classpath:customize-context.yml"}, factory = YamlPropertySourceFactory.class)
- @ConfigurationProperties(prefix = "apply.transaction"
1. 依赖
- <!--swagger3-->
- <dependency>
- <groupId>io.springfox</groupId>
- <artifactId>springfox-boot-starter</artifactId>
- <version>3.0.0</version>
- </dependency>
- <!--Swagger的ui-->
- <dependency>
- <groupId>com.github.xiaoymin</groupId>
- <artifactId>swagger-bootstrap-ui</artifactId>
- <version>1.9.0</version>
- </dependency>
2.自定义yml配置
- apply:
- swagger:
- groupName: xx
- title: 数据xx
- enable: false
- description: API-接口说明
- basePath: com.li
- version: 1.0.01
3.配置类
- @Configuration
- @EnableOpenApi
- @EnableSwaggerBootstrapUI
- @ConfigurationProperties(prefix = "apply.swagger")
- public class SwaggerAutoConfiguration {
-
-
- private static String basePath;
-
- /**
- * 是否开启swagger配置,生产环境需关闭
- */
- private boolean enable;
- private String title;
- private String description;
- private String version;
- private String groupName;
-
- @Value("${server.address}")
- private String address;
- @Value("${server.servlet.context-path}")
- private String contextPath;
- @Value("${server.port}")
- private String port;
-
-
- @Bean
- public Docket createRestApi() {
- return new Docket(DocumentationType.OAS_30)
- .apiInfo(apiInfo())
- .groupName(groupName)
- //是否开启 (true 开启 false隐藏。生产环境建议隐藏)
- .enable(enable)
- .select()
- //扫描的路径包,设置basePackage会将包下的所有被@Api标记类的所有方法作为api
- .apis(RequestHandlerSelectors.basePackage(basePath))
- //指定路径处理PathSelectors.any()代表所有的路径
- .paths(PathSelectors.any())
- .build();
- }
-
- /**
- * 配置基本信息
- *
- * @return
- */
- @Bean
- public ApiInfo apiInfo() {
- String termsOfServiceUrl = "http://"+address+":"+port+contextPath+"/";
- return new ApiInfoBuilder()
- //设置文档标题(API名称)
- .title(title)
- //文档描述
- .description(description)
- //服务条款URL
- .termsOfServiceUrl(termsOfServiceUrl)
- //版本号
- .version(version)
- .build();
- }
- }
在项目部署时,会默认加载同jar包文件夹下的application.yml配置文件,如果与项目yml的配置文件属性相同的值则会进行覆盖。如果要切换配置文件可在外部指定spring.profiles.active 属性。
通过spring.profiles.active属性进行配置文件切换时,springboot会优先查找config资源目录下的application-xxx.yml配置文件,来切换指定的yml
- #切换配置
- spring:
- profiles:
- #切换后缀
- active: windows
- #包含文件后缀数组
- include:
- - common
被切换的文件需指定自己的引用
- spring:
- config:
- activate:
- on-profile: windows
1.非静态属性变量或方法获取配置文件及属性值
当工具类读取属性配置文件时,通过@Value注解获取对应的config下已切换的application-xxx.yml的值 ,自定义的apply.properties.active.xxx的对应的切换后缀值进行注入,然后进行字符串或对应文件目录拼接获取。
在每种配置文件中加入自己对应的切换后缀,在spring.profiles.active切换yml时就能读取到对应的properties配置文件的后缀,再注入拼接字符串
如application-windows.yml
- #自定义配置文件切换
- apply:
- properties:
- active:
- #切换文件后缀配置
- dataxBase: windows
- config: windows
2.非静态属性变量或方法获取配置文件及属性值
由于@Value注解不能注入静态属性值,对于部分静态方法和构造调用如果强行注入则会为空值,则需通过自定义PropertiesActiveConfig下的yml工厂来获取指定的yml配置文件来手动获取对应的值, 在自定义工具类中,通过手动注入spring.profiles.active,来判断当前获取的是那个yml配置文件,由于获取的配置文件值的工厂方法为静态方法,所以需要通过手动的set方法对静态变量进行注入。
配置类
- /**
- * yml切换配置静态属性文件读取工具类
- */
- @Slf4j
- @Component
- public class PropertiesActiveConfig {
-
- private static String active;
-
- @Value("${spring.profiles.active}")
- public void setActive(String active) {
- PropertiesActiveConfig.active = active;
- }
-
- public static Object getCommonYml(Object key){
- Resource resource = new ClassPathResource("/config/application-"+active+".yml");
- log.info("属性文件切换:{}",active);
- Properties properties = null;
- try {
- YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean();
- yamlFactory.setResources(resource);
- properties = yamlFactory.getObject();
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- return properties.get(key);
- }
-
- }
调用获取指定属性
public static String suffix = (String) PropertiesActiveConfig.getCommonYml("apply.properties.active.config");
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。