SpringBoot

SpringBoot原理初探

狂神说:狂神说SpringBoot02:运行原理初探 (qq.com)

yaml配置注入

代替@value赋值法

语法对比

properties与yaml

SpringBoot使用一个全局的配置文件 , 配置文件名称是固定的

  • application.properties

    • 语法结构 :key=value
  • application.yaaml

    • 语法结构 :key:空格 value

xml与yaml

传统xml配置:

<server> <port>8081<port> </server>

yaml配置:

server: prot: 8080

yaml基础语法

1、空格不能省略

2、以缩进来控制层级关系,只要是左边对齐的一列数据都是同一个层级的。

3、属性和值的大小写都是十分敏感的。

4、要与实体类的属性对象名一一对应

注意:

  • “ ” 双引号,不会转义字符串里面的特殊字符 , 特殊字符会作为本身想表示的意思;

    比如 :name: "kuang \n shen" 输出 :kuang 换行 shen

  • '' 单引号,会转义特殊字符 , 特殊字符最终会变成和普通字符一样输出

    比如 :name: ‘kuang \n shen’ 输出 :kuang \n shen

对象、Map(键值对)

#对象、Map格式 k: v1: v2:

在下一行来写对象的属性和值得关系,注意缩进;比如:

student: name: qinjiang age: 3

行内写法

student: {name: qinjiang,age: 3}

数组( List、set )

用 - 值表示数组中的一个元素,比如:

pets: - cat - dog - pig

行内写法

pets: [cat,dog,pig]

使用

原先方法

@Component //注册bean public class Dog { @Value("阿黄") private String name; @Value("18") private Integer age; }
@SpringBootTest class DemoApplicationTests { @Autowired //将狗狗自动注入进来 Dog dog; @Test public void contextLoads() { System.out.println(dog); //打印看下狗狗对象 } }

使用yaml处理复杂实体类

实体类

/* @ConfigurationProperties作用: 将配置文件中配置的每一个属性的值,映射到这个组件中; 告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定 参数 prefix = “person” : 将配置文件中的person下面的所有属性一一对应 */ @Component //注册bean @ConfigurationProperties(prefix = "person") public class Person { private String name; private Integer age; private Boolean happy; private Date birth; private Map<String,Object> maps; private List<Object> lists; private Dog dog; }

yaml配置

person: name: qinjiang age: 3 happy: false birth: 2000/01/01 maps: {k1: v1,k2: v2} lists: - code - girl - music dog: name: 旺财 age: 1

新增依赖(可以不配置)

<!-- 导入配置文件处理器,配置文件进行绑定就会有提示,需要重启 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>

test

@SpringBootTest class DemoApplicationTests { @Autowired Person person; //将person自动注入进来 @Test public void contextLoads() { System.out.println(person); //打印person信息 } }

扩展

配置文件占位符 配置文件还可以编写占位符生成随机数 person: name: qinjiang${random.uuid} # 随机uuid age: ${random.int} # 随机int happy: false birth: 2000/01/01 maps: {k1: v1,k2: v2} lists: - code - girl - music dog: name: ${person.hello:other}_旺财 age: 1

图片

1、@ConfigurationProperties只需要写一次即可 , @Value则需要每个字段都添加

2、松散绑定:这个什么意思呢? 比如我的yml中写的last-name,这个和lastName是一样的, - 后面跟着的字母默认是大写的。这就是松散绑定。可以测试一下

3、JSR303数据校验 , 这个就是我们可以在字段是增加一层过滤器验证 , 可以保证数据的合法性

4、复杂类型封装,yml中可以封装对象 , 使用value就不支持

结论:

配置yml和配置properties都可以获取到值 , 强烈推荐 yml;

如果我们在某个业务中,只需要获取配置文件中的某个值,可以使用一下 @value;

如果说,我们专门编写了一个JavaBean来和配置文件进行一一映射,就直接@configurationProperties,不要犹豫!

JSR303数据校验

Springboot中可以用@validated来校验数据,如果数据异常则会统一抛出异常,方便异常中心统一处理。

常用注解

@NotNull(message="名字不能为空") private String userName; @Max(value=120,message="年龄最大不能查过120") private int age; @Email(message="邮箱格式错误") private String email; 空检查 @Null 验证对象是否为null @NotNull 验证对象是否不为null, 无法查检长度为0的字符串 @NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格. @NotEmpty 检查约束元素是否为NULL或者是EMPTY. Booelan检查 @AssertTrue 验证 Boolean 对象是否为 true @AssertFalse 验证 Boolean 对象是否为 false 长度检查 @Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内 @Length(min=, max=) string is between min and max included. 日期检查 @Past 验证 Date 和 Calendar 对象是否在当前时间之前 @Future 验证 Date 和 Calendar 对象是否在当前时间之后 @Pattern 验证 String 对象是否符合正则表达式的规则 .......等等 除此以外,我们还可以自定义一些数据校验规则

多环境配置

配置文件加载地址

springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件:

  • 优先级1:项目路径下的config文件夹配置文件
  • 优先级2:项目路径下配置文件
  • 优先级3:资源路径下的config文件夹配置文件
  • 优先级4:资源路径下配置文件

优先级由高到底,高优先级的配置会覆盖低优先级的配置;

SpringBoot会从这四个位置全部加载主配置文件;互补配置;

多环境切换

多配置文件

我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml , 用来指定多个环境版本;

例如:

application-test.properties 代表测试环境配置

application-dev.properties 代表开发环境配置

但是Springboot并不会直接启动这些配置文件,它默认使用application.properties主配置文件

我们需要通过一个配置来选择需要激活的环境:

#比如在配置文件中指定使用dev环境,我们可以通过设置不同的端口号进行测试; #我们启动SpringBoot,就可以看到已经切换到dev下的配置了; spring.profiles.active=dev

多文档块

server: port: 8081 #选择要激活那个环境块 spring: profiles: active: prod --- server: port: 8083 spring: profiles: dev #配置环境的名称 --- server: port: 8084 spring: profiles: prod #配置环境的名称

注意:如果yml和properties同时都配置了端口,并且没有激活其他环境 , 默认会使用properties配置文件的!

SpringBoot Web开发

前提:原来我们是一个web应用,main下会有一个webapp文件夹,以前都是将所有页面导在这里面的。但是现在我们打包方式为jar方式,需要改变写页面的方式

静态资源

在springboot中我们可以使用以下方式处理静态资源

  • webjars 使用webjars依赖后可以将静态资源存到他生成的包下,访问时通过localhost:8080/webjars/+后续内容
  • public, static, /**, resources 这四个包(/**就是resources包本身,而第四个意思是在resources包下再创建一个名为resouces包),他们下面的静态资源可以通过 localhost:8080/上述包名/静态资源来访问
    • 优先级:resources > static(默认) > public
"classpath:/META-INF/resources/" "classpath:/resources/" "classpath:/static/" "classpath:/public/"
  • resources下的tempalates包 在templates目录下的所有页面只能通过controller来跳转

首页如何定制

不同版本的使用方法不一样,但是最关键的就是需要将图标文件命名为favicon.ico。

低版本需要在配置文件中关闭默认图标,但是新版本中只要把图标文件放在static文件夹下就可以生效

thymeleaf模板引擎

狂神说SpringBoot11:Thymeleaf模板引擎 (qq.com)

前端交给我们的页面,是html页面。如果是我们以前开发,我们需要把他们转成jsp页面,jsp好处就是当我们查出一些数据转发到JSP页面以后,我们可以用jsp轻松实现数据的显示,及交互等。

jsp支持非常强大的功能,包括能写Java代码,但是呢,我们现在的这种情况,SpringBoot这个项目首先是以jar的方式,不是war,像第二,我们用的还是嵌入式的Tomcat,所以呢,他现在默认是不支持jsp的

那不支持jsp,如果我们直接用纯静态页面的方式,那给我们开发会带来非常大的麻烦,那怎么办呢?

SpringBoot推荐你可以来使用模板引擎:

模板引擎,我们其实大家听到很多,其实jsp就是一个模板引擎,还有用的比较多的freemarker,包括SpringBoot给我们推荐的Thymeleaf

Thymeleaf依赖

<!--thymeleaf--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>

使用

我们只需要把我们的html页面放在类路径下的templates下,thymeleaf就可以帮我们自动渲染了

语法

  • 我们要使用thymeleaf,需要在html文件中导入命名空间的约束,方便提示。我们可以去官方文档的#3中看一下命名空间拿来过来: xmlns:th="http://www.thymeleaf.org"
  • 具体内容自搜Thymeleaf 官网:https://www.thymeleaf.org/,一个例子:
@RequestMapping("/t2") public String test2(Map<String,Object> map){ //存入数据 map.put("msg","<h1>Hello</h1>"); map.put("users", Arrays.asList("qinjiang","kuangshen")); //classpath:/templates/test.html return "test"; }
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>狂神说</title> </head> <body> <h1>测试页面</h1> <div th:text="${msg}"></div> <!--不转义--> <div th:utext="${msg}"></div> <!--遍历数据--> <!--th:each每次遍历都会生成当前这个标签:官网#9--> <h4 th:each="user :${users}" th:text="${user}"></h4> <h4> <!--行内写法:官网#12--> <span th:each="user:${users}">[[${user}]]</span> </h4> </body> </html>

扩展SpringMVC

写一个实现WebMvcConfigurer接口的类,并使用@Configuration注解,在这个类中实现功能的扩展。再使用@@EnableWebMvc(这个注解就是导入一个类,会从容器中获取所有的webmvcconfig)则SpringBoot会全面接管MVC(SpringBoot对SpringMVC的自动配置不需要了,所有都是我们自己去配置! )

官方原话

如果您希望保留Spring Boot MVC功能,并且希望添加其他MVC配置(拦截器、格式化程序、视图控制器和其他功能),则可以添加自己的@configuration类,类型为webmvcconfiguer,但不添加@EnableWebMvc。如果希望提供RequestMappingHandlerMapping、RequestMappingHandlerAdapter或ExceptionHandlerExceptionResolver的自定义实例,则可以声明WebMVCregistrationAdapter实例来提供此类组件。

视图解析器

  • SpringBoot自带两个视图解析器ContentNegotiatingViewResolver和BeanNameViewResolver

  • 使用thymeleaf引擎,他也会给我们提供一个视图解析器

  • 也可以自定义一个视图解析器:

    • 自定义一个实现ViewResolver接口的静态类,重写方法
    • 使用@Bean将这个组件交给SpringBoot,SpringBoot会帮我们自动装配

员工管理系统

首页配置

所有页面的静态资源(css,图片等)都需要使用thymeleaf接管

添加完头文件后<html lang="en" xmlns:th="http://www.thymeleaf.org">,使用th:与@{}

<link th:href="@{css/bootstrap.min.css}" rel="stylesheet">

页面国际化(i18n)

  • 在resources下创建i18n包,并添加配置文件
  • 如果需要在项目中进行按钮自动切换,需要自定义组件LocaleResolver
  • 将组件通过@Bean注册岛spring容器中
//自定义的国际化组件就生效了 @Bean public LocaleResolver localeResolver(){ return new MyLocaleResolver(); }

https://mp.weixin.qq.com/s/e4Jd3xIMF4C4HBzPQfakvg

登录+拦截器

员工列表展示

  1. 提取公共页面

  2. th:fragment="sidebar"

  3. th:replace="~{commons/commons::topbar}"

  4. 如果要传递参数可以直接使用()传参,接收判断即可

  5. 列表循环展示

整合JDBC使用

使用Spring-Data

  • 创建Spring-Boot工程时至少选上

  • 数据库连接配置写在application.yml中,使用spring.datasource.xxx编写用户名,密码,url等内容

spring: datasource: username: password: url: driver-class-name:
  • 使用@Autowired注入Spring帮我们配置的Datasource对象
  • 这个对象的getConnection可以获得connection对象
  • 使用jdbc可以直接注入一个spring写好的模板JdbcTemplate(xxxxTemplate都是写好的一些模板,拿来即用),然后使用这个对象的方法进行jdbc操作

整合Druid数据源

导入Druid依赖

在整合JDBC的yml(也可以是properties文件,只不过写法不一样)中,datasource下再增加一条type,并且内容为DruidDataSource即可。

增加后可以在datasource下添加很多配置

spring: datasource: username: root password: 123456 #?serverTimezone=UTC解决时区的报错 url: jdbc:mysql://localhost:3306/springboot?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource #Spring Boot 默认是不注入这些属性值的,需要自己绑定 #druid 数据源专有配置 initialSize: 5 minIdle: 5 maxActive: 20 maxWait: 60000 timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 validationQuery: SELECT 1 FROM DUAL testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入 #如果允许时报错 java.lang.ClassNotFoundException: org.apache.log4j.Priority #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j filters: stat,wall,log4j maxPoolPreparedStatementPerConnectionSize: 20 useGlobalDataSourceStat: true connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

配置德鲁伊监控器

因为SpringBoot内置了servlet容器,所以没有web.xml,注册Servlet的替代方法为将类注入Bean

//配置 Druid 监控管理后台的Servlet; //内置 Servlet 容器时没有web.xml文件,所以使用 Spring Boot 的注册 Servlet 方式 @Bean public ServletRegistrationBean statViewServlet() { ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*"); // 这些参数可以在 com.alibaba.druid.support.http.StatViewServlet // 的父类 com.alibaba.druid.support.http.ResourceServlet 中找到 Map<String, String> initParams = new HashMap<>(); initParams.put("loginUsername", "admin"); //后台管理界面的登录账号 initParams.put("loginPassword", "123456"); //后台管理界面的登录密码 //后台允许谁可以访问 //initParams.put("allow", "localhost"):表示只有本机可以访问 //initParams.put("allow", ""):为空或者为null时,表示允许所有访问 initParams.put("allow", ""); //deny:Druid 后台拒绝谁访问 //initParams.put("kuangshen", "192.168.1.20");表示禁止此ip访问 //设置初始化参数 bean.setInitParameters(initParams); return bean; }

整合Mybatis框架

使用整合包mybatis-spring-boot-starter

原先Mybatis:先写一个接口,再通过mapper.xml实现里面关于数据库操作的方法

现在:

  • 在properties中配置数据库并整合Mybatis
spring.datasource.username=root # ...................... # 整合mybatis # 给包下内容起别名 mybatis.type-aliases-package=com.zaughter.pojo # mapper地址 mybatis.mapper-loaction=classpath:mybatis/mapper/*.xml
  • 接口使用@Mapper声明是Mapper类,使用@Repository将其与spring关联
//@Mapper : 表示本类是一个 MyBatis 的 Mapper @Mapper @Repository public interface DepartmentMapper { // 获取所有部门信息 List<Department> getDepartments(); // 通过id获得部门 Department getDepartment(Integer id); }
  • 在resources文件夹下创建mybatis文件夹,再在mybatis下创建mapper文件夹,里面创建.xml文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.kuang.mapper.DepartmentMapper"> <select id="getDepartments" resultType="Department"> select * from department; </select> <select id="getDepartment" resultType="Department" parameterType="int"> select * from department where id = #{id}; </select> </mapper>
  • 编写EmployeeController类进行测试
@RestController public class EmployeeController { @Autowired EmployeeMapper employeeMapper; // 获取所有员工信息 @GetMapping("/getEmployees") public List<Employee> getEmployees(){ return employeeMapper.getEmployees(); } }

SpringSecurity(安全)

狂神说SpringBoot18:集成SpringSecurity (qq.com)

主要两个功能:认证,授权

SpringSecurity与shiro都是用来做安全的框架,两者很像

运用AOP思想

三个重要元素:

  • WebSecurityConfigurerAdapter:自定义Security策略
  • AuthenticationManagerBuilder:自定义认证策略
  • @EnableWebSecurity:开启WebSecurity模式

基础配置类

package com.zaughter.config; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @EnableWebSecurity // 开启WebSecurity模式 public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { //首页所有人可以访问,但是里面的功能页只有对应有权限的人才能访问 //注意中间没有分号:链式编程 http.authorizeRequests() .antMatchers("/").permitAll() .antMatchers("/level1/**").hasRole("vip1") .antMatchers("/level2/**").hasRole("vip2") .antMatchers("/level3/**").hasRole("vip3"); // 开启自动配置的登录功能,如果没有权限就会跳转到登录页面 //可以再添加.loginPage()来做其他请求,这样可以用自己设计的登录页面 // /login 请求来到登录页 // /login?error 重定向到这里表示登录失败 http.formLogin(); //关闭csrf功能,防止被攻击 http.csrf().disable(); //开启注销功能,请求是/logout,注销后跳转到首页 http.logout().logoutSuccessUrl("/"); //开启记住我功能,cookie默认保存两周 http.rememberMe(); } }

定义认证规则

在springboot 2.1.x可以正常使用

但是现在版本要求进行密码编码加密(防止反编译),在Spring Secutiry5.0+中新增了许多加密方式

//定义认证规则 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { //在内存中定义,也可以在jdbc中去拿....正常是从数据库中拿 auth.inMemoryAuthentication() .withUser("kuangshen").password("123456").roles("vip2","vip3") .and() //通过and增加用户 .withUser("root").password("123456").roles("vip1","vip2","vip3") .and() .withUser("guest").password("123456").roles("vip1","vip2"); }

改进为:

//定义认证规则 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { //要想我们的项目还能够正常登陆,需要修改一下configure中的代码。我们要将前端传过来的密码进行某种方式加密 //spring security 官方推荐的是使用bcrypt加密方式。 auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()) .withUser("kuangshen").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3") .and() //通过and增加用户 .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3") .and() .withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2"); }

shirio

选择性内容,跳过

任务

异步任务

例子:

编写方法,假装正在处理数据,使用线程设置一些延时,模拟同步等待的情况

我们如果想让用户直接得到消息,就在后台使用多线程的方式进行处理即可,但是每次都需要自己手动去编写多线程的实现的话,太麻烦了,我们只需要用一个简单的办法,在我们的方法上加一个简单的注解即可

//告诉Spring这是一个异步方法 @Async public void hello(){ try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("业务进行中...."); }
@RestController public class AsyncController { @Autowired AsyncService asyncService; @GetMapping("/hello") public String hello(){ asyncService.hello(); return "success"; } }

SpringBoot就会自己开一个线程池,进行调用!但是要让这个注解生效,我们还需要在主程序上添加一个注解@EnableAsync ,开启异步注解功能

@EnableAsync //开启异步注解功能 @SpringBootApplication public class SpringbootTaskApplication { public static void main(String[] args) { SpringApplication.run(SpringbootTaskApplication.class, args); } }

邮件任务

添加spring-boot-starter-mail

配置文件

spring.mail.username=24736743@qq.com spring.mail.password=你的qq授权码,在qq邮箱中获取,可以保护自己的密码不显示 spring.mail.host=smtp.qq.com # qq需要配置ssl spring.mail.properties.mail.smtp.ssl.enable=true

测试

@Autowired JavaMailSenderImpl mailSender; @Test public void contextLoads() { //邮件设置1:一个简单的邮件 SimpleMailMessage message = new SimpleMailMessage(); message.setSubject("通知-明天来狂神这听课"); message.setText("今晚7:30开会"); message.setTo("24736743@qq.com"); message.setFrom("24736743@qq.com"); mailSender.send(message); } @Test public void contextLoads2() throws MessagingException { //邮件设置2:一个复杂的邮件 MimeMessage mimeMessage = mailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); helper.setSubject("通知-明天来狂神这听课"); //使用true后可以识别字符串中的html元素 helper.setText("<b style='color:red'>今天 7:30来开会</b>",true); //发送附件 helper.addAttachment("1.jpg",new File("")); helper.addAttachment("2.jpg",new File("")); helper.setTo("24736743@qq.com"); helper.setFrom("24736743@qq.com"); mailSender.send(mimeMessage); }

定时任务

两个接口:

  • TaskExecutor接口
  • TaskScheduler接口

两个注解:

  • @EnableScheduling
  • @Scheduled

需要使用cron表达式

狂神说SpringBoot15:异步、定时、邮件任务 (qq.com)

测试步骤:

1、创建一个ScheduledService

我们里面存在一个hello方法,他需要定时执行,怎么处理呢?

@Service public class ScheduledService { //秒 分 时 日 月 周几 //0 * * * * MON-FRI //注意cron表达式的用法; @Scheduled(cron = "0 * * * * 0-7") public void hello(){ System.out.println("hello....."); } }

2、这里写完定时任务之后,我们需要在主程序上增加@EnableScheduling 开启定时任务功能

@EnableAsync //开启异步注解功能 @EnableScheduling //开启基于注解的定时任务 @SpringBootApplication public class SpringbootTaskApplication { public static void main(String[] args) { SpringApplication.run(SpringbootTaskApplication.class, args); } }

3、我们来详细了解下cron表达式;

http://www.bejson.com/othertools/cron/

4、常用的表达式

(1)0/2 * * * * ? 表示每2秒 执行任务 (1)0 0/2 * * * ? 表示每2分钟 执行任务 (1)0 0 2 1 * ? 表示在每月的1日的凌晨2点调整任务 (2)0 15 10 ? * MON-FRI 表示周一到周五每天上午10:15执行作业 (3)0 15 10 ? 6L 2002-2006 表示2002-2006年的每个月的最后一个星期五上午10:15执行作 (4)0 0 10,14,16 * * ? 每天上午10点,下午2点,4点 (5)0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时 (6)0 0 12 ? * WED 表示每个星期三中午12点 (7)0 0 12 * * ? 每天中午12点触发 (8)0 15 10 ? * * 每天上午10:15触发 (9)0 15 10 * * ? 每天上午10:15触发 (10)0 15 10 * * ? 每天上午10:15触发 (11)0 15 10 * * ? 2005 2005年的每天上午10:15触发 (12)0 * 14 * * ? 在每天下午2点到下午2:59期间的每1分钟触发 (13)0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发 (14)0 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发 (15)0 0-5 14 * * ? 在每天下午2点到下午2:05期间的每1分钟触发 (16)0 10,44 14 ? 3 WED 每年三月的星期三的下午2:10和2:44触发 (17)0 15 10 ? * MON-FRI 周一至周五的上午10:15触发 (18)0 15 10 15 * ? 每月15日上午10:15触发 (19)0 15 10 L * ? 每月最后一日的上午10:15触发 (20)0 15 10 ? * 6L 每月的最后一个星期五上午10:15触发 (21)0 15 10 ? * 6L 2002-2005 2002年至2005年的每月的最后一个星期五上午10:15触发 (22)0 15 10 ? * 6#3 每月的第三个星期五上午10:15触发

__EOF__

本文作者Zaughter
本文链接https://www.cnblogs.com/zaughtercode/p/17062955.html
关于博主:qq:1730119093 欢迎加我讨论
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Zaughter  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示