1、swagger
swagger是一个用来生成API文档的框架
1.1、swagger配置
1.1.1、springboot + swagger
在pom里添加依赖
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
新建一个SwaggerConfig.java配置类
package com.haha.myboot.controller;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration //配置类
@EnableSwagger2// 开启Swagger2的自动配置
public class SwaggerConfig {
}
建完运行并访问:http://localhost:8080/swagger-ui.html
1.1.2、配置swagger首页
先看看要配置什么
还是在SwaggerConfig.java配置类里面配置
package com.haha.myboot;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
@Configuration //配置类
@EnableSwagger2// 开启Swagger2的自动配置
public class SwaggerConfig {
@Bean //配置docket以配置Swagger具体参数
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
}
//配置文档信息
private ApiInfo apiInfo() {
Contact contact = new Contact("联系人名字", "http://xxx.xxx.com/联系人访问链接", "联系人邮箱");
return new ApiInfo(
"这里填标题", // 标题
"这是一段描述", // 描述
"v1.0", // 版本
"http://terms.service.url/组织链接", // 组织链接
contact, // 联系人信息
"Apach 2.0 许可", // 许可
"许可链接", // 许可连接
new ArrayList<>()// 扩展
);
}
}
运行、访问 http://localhost:8080/swagger-ui.html 可以看到
1.1.3、配置扫描接口
// select()配置扫描接口
.select()
// RequestHandlerSelectors配置如何扫描接口
.apis(RequestHandlerSelectors.basePackage("com.haha.myboot.controller"))
.build();
运行、访问 http://localhost:8080/swagger-ui.html 可以看到
RequestHandlerSelectors接口扫描方式,
后面除了可以跟basePackage还可以跟以下方法
// 扫描所有,项目中的所有接口都会被扫描到
any()
// 不扫描接口
none()
// 通过方法上的注解扫描,如withMethodAnnotation(GetMapping.class)只扫描get请求
withMethodAnnotation(final Class<? extends Annotation> annotation)
// 通过类上的注解扫描,如.withClassAnnotation(Controller.class)只扫描有controller注解的类中的接口
withClassAnnotation(final Class<? extends Annotation> annotation)
basePackage(final String basePackage) // 根据包路径扫描接口
1.1.4、接口扫描过滤
放在.build();之前
// 配置如何通过path过滤,即这里只扫描请求以/user开头的接口
.paths(PathSelectors.ant("/user/**"))
PathSelectors后面除了跟.ant方法,还可以跟其他方法
any() // 任何请求都扫描
none() // 任何请求都不扫描
regex(final String pathRegex) // 通过正则表达式控制
ant(final String antPattern) // 通过ant()控制
1.1.5、swagger与多环境
设置swagger处于prod时不显示
// 设置要显示swagger的环境
Profiles of = Profiles.of("dev", "test");
// 判断当前是否处于该环境
// 通过 enable() 接收此参数判断是否要显示
boolean b = en.acceptsProfiles(of);
。。。。
。。。。
.enable(b)
1.1.6、API 配置分组
没有分组,默认是default。
如下,配置多个Docket方法可以配置多个组
@Bean
public Docket docket1(){
return new Docket(DocumentationType.SWAGGER_2).groupName("group1");
}
@Bean
public Docket docket2(){
return new Docket(DocumentationType.SWAGGER_2).groupName("group2");
}
@Bean
public Docket docket3(){
return new Docket(DocumentationType.SWAGGER_2).groupName("group3");
}
通过groupName()方法即可配置组名
.groupName("hello") // 配置分组
1.1.7、导入不同的包实现不同的皮肤
bootstrap-ui
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.1</version>
</dependency>
运行后访问地址: http://localhost:8080/doc.html
其他的:
Layui-ui 访问 http://localhost:8080/docs.html
<!-- 引入swagger-ui-layer包 /docs.html-->
<dependency>
<groupId>com.github.caspar-chen</groupId>
<artifactId>swagger-ui-layer</artifactId>
<version>1.1.3</version>
</dependency>
mg-ui 访问 http://localhost:8080/document.html
<!-- 引入swagger-ui-layer包 /document.html-->
<dependency>
<groupId>com.zyplayer</groupId>
<artifactId>swagger-mg-ui</artifactId>
<version>1.0.6</version>
</dependency>
1.2、开始使用swagger
新建 SwaggerConfig配置文件,内容如下(仅配置了首页和扫描接口)
package com.haha.myboot;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.haha.myboot.controller"))
.build();
}
private ApiInfo apiInfo() {
Contact contact = new Contact("联系人名字", "http://xxx.xxx.com/联系人访问链接", "联系人邮箱");
return new ApiInfo(
"这里填标题",
"这是一段描述",
"v1.0",
"http://terms.service.url/组织链接",
contact,
"Apach 2.0 许可",
"许可链接",
new ArrayList<>()
);
}
}
新建pojo包,新建User.java实体类
package com.haha.myboot.pojo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel("用户实体")
public class User {
@ApiModelProperty("用户名")
private String name;
@ApiModelProperty("年龄")
private int age;
public int getAge() {
return age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
}
@ApiModel为类添加注释
@ApiModelProperty为类属性添加注释
新建uuu.java
package com.haha.myboot.controller;
import com.haha.myboot.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class uuu {
@RequestMapping("/getUser")
public User getUser(){ return new User(); }
}
运行后访问
其他常用注解
Swagger注解 | 简单说明 |
---|---|
@Api(tags = “xxx模块说明”) | 作用在模块类上 |
@ApiOperation(“xxx接口说明”) | 作用在接口方法上 |
@ApiModel(“xxxPOJO说明”) | 作用在模型类上:如VO、BO |
@ApiModelProperty(value = “xxx属性说明”,hidden = true) | 作用在类方法和属性上,hidden设置为true可以隐藏该属性 |
@ApiParam(“xxx参数说明”) | 作用在参数、方法和字段上,类似@ApiModelProperty |
如下例
package com.haha.myboot.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class uuu {
@PostMapping("/getUser")
@ApiOperation("获取user的接口")
@ResponseBody
public String getUser(@ApiParam("这个名字会被返回") String name){
return name;
}
}
2、springboot 异步任务
2.1、同步等待
1、创建一个service包,包下新建类AsyncService(异步任务)
@Service
public class AsyncService {
public void hello(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("业务进行中....");
}
}
@Service相当于springmvc里配置里的bean,注解为一个服务
2、controller包下新建类AsyncController
@RestController
public class AsyncController {
@Autowired
AsyncService asyncService;
@GetMapping("/hello")
public String hello(){
asyncService.hello();
return "success";
}
}
@RestController = @Controller + @ResponseBody
@Autowired:自动装配。被标注的类,会根据类型在ioc容器中找到匹配的类注入
运行项目,访问:http://localhost:8080/hello
转3秒后出现success,这个同步等待的线程就完成了
2.2、异步线程
在方法头上加一个@Async
在MybootApplication中添加@EnableAsync,开启异步功能
自动装配
运行项目,访问:http://localhost:8080/hello
这次不会等待3秒了,直接出来
2.3、定时任务
在Service包下新建TimeService类
这里用到了Cron表达式,见本文第4章
import org.springframework.stereotype.Service;
@Service
public class AsyncService {
public void hello(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("业务进行中....");
}
}
在MybootApplication中开启定时任务功能
@EnableAsync //开启异步注解功能
@EnableScheduling //开启基于注解的定时任务
测试运行
2.4、邮件任务
springboot中文手册,邮件任务:https://www.php.cn/manual/view/22279.html
总共三个步骤
1、加入依赖
2、添加Spring Boot配置
调用JavaMailSender接口发送邮件
步骤一:在pom中导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
第二步:添加Spring Boot配置
这里我们使用QQ邮箱为例
在QQ邮箱中的设置->账户->开启pop3和smtp服务
添加Spring Boot配置
默认的配置文件是application.properties
这里我改成了application.yaml
## QQ邮箱配置
spring:
mail:
host: smtp.qq.com #发送邮件服务器
username: 1*****7@qq.com # 发件人
password: m************cc #客户端授权码,不是邮箱密码,这个在qq邮箱设置里面自动生成的
properties.mail.smtp.port: 465 #端口号465或587
properties.mail.smtp.starttls.enable: true
properties.mail.smtp.starttls.required: true
properties.mail.smtp.ssl.enable: true
default-encoding: utf-8
新建IMailService.java,封装一个发邮件的接口
package com.haha.myboot02;
/**
* @Description: 封装一个发邮件的接口,后边直接调用即可
*/
public interface IMailService {
/**
* 发送文本邮件
* @param to 收件人
* @param subject 主题
* @param content 内容
*/
void sendSimpleMail(String to, String subject, String content);
/**
* 发送HTML邮件
* @param to 收件人
* @param subject 主题
* @param content 内容
*/
public void sendHtmlMail(String to, String subject, String content);
/**
* 发送带附件的邮件
* @param to 收件人
* @param subject 主题
* @param content 内容
* @param filePath 附件
*/
public void sendAttachmentsMail(String to, String subject, String content, String filePath);
}
新建IMailServiceImpl.java实现类
package com.haha.myboot02;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
@Service
public class IMailServiceImpl implements IMailService {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* Spring Boot 提供了一个发送邮件的简单抽象,使用的是下面这个接口,这里直接注入即可使用
*/
@Autowired
private JavaMailSender mailSender;
/**
* 配置文件中我的qq邮箱
*/
@Value("${spring.mail.username}")
private String username;
/**
* 简单文本邮件
* @param to 收件人
* @param subject 主题
* @param content 内容
*/
@Override
public void sendSimpleMail(String to, String subject, String content) {
//创建SimpleMailMessage对象
SimpleMailMessage message = new SimpleMailMessage();
//邮件发送人
message.setFrom(username);
//邮件接收人
message.setTo(to);
//邮件主题
message.setSubject(subject);
//邮件内容
message.setText(content);
//发送邮件
mailSender.send(message);
}
/**
* html邮件
* @param to 收件人
* @param subject 主题
* @param content 内容
*/
@Override
public void sendHtmlMail(String to, String subject, String content) {
//获取MimeMessage对象
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper messageHelper;
try {
messageHelper = new MimeMessageHelper(message, true);
//邮件发送人
messageHelper.setFrom(from);
//邮件接收人
messageHelper.setTo(to);
//邮件主题
message.setSubject(subject);
//邮件内容,html格式
messageHelper.setText(content, true);
//发送
mailSender.send(message);
//日志信息
logger.info("邮件已经发送。");
} catch (MessagingException e) {
logger.error("发送邮件时发生异常!", e);
}
}
/**
* 带附件的邮件
* @param to 收件人
* @param subject 主题
* @param content 内容
* @param filePath 附件
*/
@Override
public void sendAttachmentsMail(String to, String subject, String content, String filePath) {
MimeMessage message = mailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(username);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content, true);
FileSystemResource file = new FileSystemResource(new File(filePath));
String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
helper.addAttachment(fileName, file);
mailSender.send(message);
//日志信息
logger.info("邮件已经发送。");
} catch (MessagingException e) {
logger.error("发送邮件时发生异常!", e);
}
}
}
测试类 MailTest .java
package com.haha.myboot02;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class MailTest {
/**
* 注入发送邮件的接口
*/
@Autowired
private IMailService mailService;
/**
* 测试发送文本邮件
*/
@Test
public void sendmail() {
mailService.sendSimpleMail("1********4@qq.com","主题:你好普通邮件","内容:第一封邮件");
}
@Test
public void sendmailHtml(){
mailService.sendHtmlMail("1********4@qq.com","主题:你好html邮件","<h1>html邮件</h1>");
}
}
如下是建完后目录结构
之后测试运行就能发送邮件了
其他邮箱只需要改改服务器地址就可以了:
126邮箱SMTP服务器地址:smtp.126.com
163邮箱SMTP服务器地址:smtp.163.com
yeah邮箱SMTP服务器地址:smtp.yeah.net
简单分析一下主要代码:以发送简单文本这个方法为例分析
3、Spring Security
Spring Security用来干嘛:用来控制权限和认证的。
什么叫权限:例如 访问的权限、读写的权限、位置权限等
什么叫认证:根据提供的用户和密码进行校验。
spring-security官方文档:https://docs.spring.io/spring-security/site/docs
点进去后根据自己的spring版本查看
常见的安全管理技术栈的组合是这样的:
- SSM + Shiro
- Spring Boot/Spring Cloud + Spring Security
Spring Security不仅是在springboot中常用,在spring mvc中也常用
3.1、查看spring版本
在测试类中 写如下测试方法
@Test
public void Test1(){
System.out.println("spring版本:"+SpringVersion.getVersion());
System.out.println("springBoot版本:"+SpringBootVersion.getVersion());
}
运行测试方法就可以查看到版本
3.2、爱的初体验(认证功能)
第一步:pom中需要有的三个模块web、thymeleaf、starter-security
<!--thymeleaf模板语法-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--web容器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--starter-security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
第二步:新建个RouterController.java尝尝鲜
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class RouterController{
@GetMapping("/hello")
public String hello() {
return "哒哒哒";
}
}
@Controller 可以返回html、jsp
@RestController 可以返回json ,但不能返回html、jsp了
@ResponseBody+@Controller 可以返回json ,但不能返回html、jsp了
@RestController = @ResponseBody+@Controller
运行项目,访问:ocalhost:8080/hello
浏览器页面(发现进入页面需要输入账号密码才能进)
看看输出日志:
使用这个账号密码登陆后就可以成功进入页面了
在postman里面我们发现,Spring Security 支持两种不同的认证方式:
- form 表单来认证
- HttpBasic 来认证
如下:
get httpbasic验证
表单验证:(当然这里不能直接用postman提交表单,从浏览器看到还需csrf码)
3.3、用户、密码配置
在application.properties 文件中配置
spring.security.user.name=root
spring.security.user.password=123
也可以在java代码里写,新建一个SecurityConfig.java
两种方式仅选其一
@EnableWebSecurity // 开启WebSecurity模式
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//下面这两行配置表示在内存中配置了两个用户
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("root").roles("user1").password(new BCryptPasswordEncoder().encode("123456"))
.and()
.withUser("admin").roles("user1","user2").password(new BCryptPasswordEncoder().encode("123456"));
}
}
加密:如上配置了两个用户,Spring5 开始,强制要求加密,如果不想加密,可以使用一个过期的 PasswordEncoder 的实例 NoOpPasswordEncoder,但是不建议。
解密:Spring Security 中提供了 BCryptPasswordEncoder 密码编码工具,相同明文每次加密出来的结果不同,
3.4、用户、密码配置时需要注意
需要注意的第一点:你会看到不同的教程种SecurityConfig有这几种注解
我们在使用过程中发现这三种都能正常运行。
那么我们这两个注解都不加呢?
我们发现都不加相当于没有这个SecurityConfig配置类。
那到底怎么写?
1、只写中一个就可以
- @Configuration :定义它是配置类。
- @EnableWebSecurity :定义启用Web安全的配置类。
2、为啥它两都可以
- 首先 @EnableWebSecurity里面包含了@Configuration。
- 其次 springboot的pom中导入了spring-boot-starter-security,就自动装配了@EnableWebSecurity 安全机制。且多次使用@EnableWebSecurity和只用一次效果一样。
- 所以 在springboot中它两都可以,在非springboot的Spring Web MVC中用@EnableWebSecurity
3、那用谁好一点呢?
用@EnableWebSecurity 嘛,这样你在非springboot的Spring Web MVC中也用它,统一、好记。
需要注意的第二点:添加用户、密码
- 可以写在:配置文件、java类、数据库里,只在其中一处添加
- 在配置文件中添加后自动加密
- 在java类中需要手动加密
3.5、Spring Security的三个configure方法
点开WebSecurityConfigurerAdapter类
查看类里包含的方法 快捷键:ctrl+fn+f12
发现WebSecurityConfigurerAdapter类里包含有三个configure方法
传参类型分别是:AuthenticationManagerBuilder、HttpSecurity、WebSecurity
我们在上两章使用的是AuthenticationManagerBuilder
他们三的区别如下:
方法 | 作用 |
---|---|
configure(AuthenticationManagerBuilder a) | 记录账号,密码,角色信息。 |
configure(HttpSecurity h) | 页面跳转、拦截、session、cookie |
configure(WebSecurity w) | 静态资源控制 |
3.5.1、HttpSecurity
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// 跳转登录页面
.formLogin()
// http.logout(); 注销功能开启
// .logoutSuccessUrl注销后跳转页面
.logout().logoutSuccessUrl("/a02");
// /admin/**路径下的必须有v1角色才能访问
.antMatchers("/admin/**").hasRole("v1")
// 角色v1、v2可访问(两种写法)
.antMatchers("/admin/**").hasAnyRole("v1","v2")
.antMatchers("/admin/**").access("hasAnyRole('v1','v2')")
// 表示剩下的任何请求只要验证之后都可以访问
.anyRequest().authenticated()
//登录页面,(默认是/login)
.loginPage("/login_p")
//退出登陆页面(默认是/logout)
.logoutUrl("/logout_P")
//和表单登录相关的接口统统都直接通过
.permitAll()
//定义登录时,用户名的 key,默认为 username
.usernameParameter("uname")
//定义登录时,用户密码的 key,默认为 password
.passwordParameter("passwd")
//登录处理接口
.loginProcessingUrl("/doLogin")
//登录成功的处理器
.successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
out.write("success");
out.flush();
}
})
//登录失败的处理器
.failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException exception) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
out.write("fail");
out.flush();
}
})
}
3.5.2、WebSecurity
@Override
public void configure(WebSecurity web) throws Exception {
// /ver 会直接跳过Spring Security 过滤器链
web.ignoring().antMatchers("/ver");
}
}
3.6、用户信息 注销与记住 实例
http.logout();和 http.rememberMe();
先写两个页面
RouterController控制器类
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class RouterController{
@GetMapping("/a01")
public String logoin() {
return "a01";
}
@GetMapping("/a02")
public String out() {
return "a02";
}
}
SecurityConfig配置类
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@EnableWebSecurity // 开启WebSecurity模式
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//下面这两行配置了两个用户
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("root").roles("123").password(new BCryptPasswordEncoder().encode("123"))
.and()
.withUser("admin").roles("000").password(new BCryptPasswordEncoder().encode("123"));
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// 跳转登录页面
http.formLogin();
http.logout().logoutSuccessUrl("/a02");
http .rememberMe();
}
}
运行,访问
记住密码默认保留14天
4、POJO和javaBean的区别
简单的说,pojo比javaBean更纯净,javaBean可以往往会封装一些简单逻辑
5、cron详解
Cron表达式是一个字符串,用于指定定时任务。
每一项都可以用 | 含义 |
---|---|
* | 每一(如例1) |
? | 通配(如例2) |
- | 范围(如例3) |
/ | 每隔(如例4) |
# | #后面的数字表示第几周 |
L | 用于日域时表示当月最后一天,用于周域如果前面不加数字表示周六,加数字表示最后一个周值(如例5) |
W | 只能用在月份中,表示最接近指定天的工作日 |
Cron表达式生成器 :http://www.bejson.com/othertools/cron/
例1:表示每10分钟执行一次
例2:表示每个月的1日,不管这一天匹配的星期几都执行
例3:表示 2020到2030年里每个月的1日12点都执行
例4:表示每天3点开始执行,每隔5个小时执行一次,即3点、8点、13点、18点、23点各执行一次
例5:" 0 0 23 ? * 3L * "表示每月最后一个周二的23点执行
LW可以一起用,表示这个月最后一周的工作日
字符“C”允许在日期域和星期域出现。这个字符依靠一个指定的“日历”。也就是说这个表达式的值依赖于相关的“日历”的计算结果,如果没有“日历”关联,则等价于所有包含的“日历”。如:日期域是“5C”表示关联“日历”中第一天,或者这个月开始的第一天的后5天。星期域是“1C”表示关联“日历”中第一天,或者星期的第一天的后1天,也就是周日的后一天(周一)。
星期的表示:有的语言用的0-6,有的用的1-7,所以用英文最准确,月份也是用英文表达不容易出差错
6、…可变长度参数 与 数组
6.1、String… string可变长度参数
用法示例:
这个语法从Java 5开始支持。
表示此处接受的参数为0到多个Object类型的对象。
例:
private void test(String...strings){
for(String str:strings){
System.out.print(str + ", ");
}
System.out.println();
}
调用的时候可以直接test(),如果是String[] strings就不行,String[]必须传数组
// String...strings 可以如下方式传参、调用
test();
test("a","b");
test(new String[]{"aaa","bbb"});
test("ccc");
另外如果既有test(String…strings)函数,又有test()函数,我们在调用test()时,会优先使用test()函数。只有当没有test()函数式,我们调用test(),程序才会走test(String…strings)。
6.2、数组
这里复习一下string数组的定义的四种写法:
String[ ] a = new String[10];
String[ ] a = new String[ ]{“张三”,“李四”}; // 声明的同时序列化
String a[ ] = new String[10];
String a[ ] = {“张三”,“李四”};
List< String >和String[]的区别:
- List< String >:动态数组,泛型为String,可以往里面添加或减少元素。
- String[] :数组,长度固定,不可变。
两者相互转换:
// String[]转化为List<String>
List<String> list = Arrays.asList(strings);
// List<String>转化为String[]
String[] strs = list.toArray(new String[]{});
// list序列化
System.out.println("list<String>:"+list.toString());
// string[]序列化
System.out.println("String[]:"+Arrays.toString(strs));