文章目录
Spring学习(下)
专题三:JavaMail邮件发送
API与环境配置
JavaMail是一套收发电子邮件的API,未包含在JDK中,而是作为JavaEE的一部分。
厂商可以提供自己的实现类,有选择地实现某些邮件协议:
SMTP(Simple Mail Transport Protocal):简单邮件传输协议 POP3:接收电子邮件的标准协议 IMAP:互联网消息协议,是POP3的替代协议 都有对应SSL加密传输的协议,SMTPS,POP3S,IMAPS。 |
除javamail服务提供程序外,
还需要JAF(JavaBeans Activation Framework)来处理不是纯文本的邮件内容, 这包括MIME(多用途互联网邮件扩展Multipurpose Internet Mail Extensions),URL页面和文件附件等内容。JAF在java6之后已经合并到JDK中。 |
流程:邮件发送投递到邮箱服务器(163,126,139等)–> 对方登录到客户端之后,下载邮件到本地
JavaMail的关键对象
1:Properties属性对象
javamail通过properties对象封装诸多属性信息比如:服务器地址,端口,用户名,密码等。
2:Session会话对象
这里的session只是一对配置信息的集合,不是httpsession。作用是:<1>接收各种配置属性信息。<2>初始化javamail环境,根据javamail的配置文件。
3:Transport和Store:传输与存储
邮件操作只有发送与接收两种处理方式,传输对应邮件的发送,存储对应邮件的接收。
4:Message消息对象
此为一个抽象类,必须使用一个子类,通常为MimeMessage;
5:Address:地址
也是一个抽象类,用InternetAddress类。
6:Authenticator:认证者
访问邮箱服务器用这个进行用户名与密码进行认证,也是抽象类,有默认实现类。
代码实现
//普通邮件发送
public static void mail01(){
Message message = null;
Session session = null;
Properties properties = null;
try {
properties = new Properties();
//设置邮箱服务器域名
properties.put("mail.smtp.host","smtp.126.com");
//设置邮箱端口号,一般为25
properties.put("mail.smtp.port","25");
//设置邮箱认证的标识
properties.put("mail.smtp.auth",true);
session = Session.getDefaultInstance(properties,new MyAuthenticator("linghe***n@126.com","**"));
message = new MimeMessage(session);
//补全message
/*1,邮件消息发送人,接收人
2,消息主题
3,邮件内容*/
Address address = new InternetAddress("linghefei**@126.com");
//设置发送人
message.setFrom(address);
//设置接收人
message.setRecipients(Message.RecipientType.TO,new InternetAddress[]{new InternetAddress("*****")});
//设置主题
message.setSubject("java mail待你查收!");
//设置内容
message.setText("你好吗?!");
Transport.send(message);
} catch (Exception e) {
e.printStackTrace();
}
}
class MyAuthenticator extends Authenticator{
private String userName;
private String password;
public MyAuthenticator(String userName, String password) {
this.userName = userName;
this.password = password;
}
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(userName, password);
}
}
//html邮件发送
public static void mail02(){
Message message = null;
Session session = null;
Properties properties = null;
Multipart multipart = null;
BodyPart bodyPart = null;
try {
properties = new Properties();
//设置邮箱服务器域名
properties.put("mail.smtp.host","smtp.126.com");
//设置邮箱端口号,一般为25
properties.put("mail.smtp.port","25");
//设置邮箱认证的标识
properties.put("mail.smtp.auth",true);
session = Session.getDefaultInstance(properties,new MyAuthenticator("lingh*****@126.com","***"));
message = new MimeMessage(session);
//补全message
/*1,邮件消息发送人,接收人
2,消息主题
3,邮件内容html*/
Address address = new InternetAddress("ling***@126.com");
//设置发送人
message.setFrom(address);
//设置接收人
message.setRecipients(Message.RecipientType.TO,new InternetAddress[]{new InternetAddress("*******")});
//设置主题
message.setSubject("java mail待你查收!");
//设置内容
multipart = new MimeMultipart();
bodyPart = new MimeBodyPart();
bodyPart.setContent("<image src='https://www.baidu.com/img/dong_8f1d47bcb77d74a1e029d8cbb3b33854.gif'/><a herf='https://www.baidu.com'>百度</a>",
"text/html;charset=utf-8");
multipart.addBodyPart(bodyPart);
message.setContent(multipart);
Transport.send(message);
} catch (Exception e) {
e.printStackTrace();
}
}
//html邮件+附件
public static void mail03(){
Message message = null;
Session session = null;
Properties properties = null;
Multipart multipart = null;
BodyPart bodyPart = null;
try {
properties = new Properties();
//设置邮箱服务器域名
properties.put("mail.smtp.host","smtp.126.com");
//设置邮箱端口号,一般为25
properties.put("mail.smtp.port","25");
//设置邮箱认证的标识
properties.put("mail.smtp.auth",true);
session = Session.getDefaultInstance(properties,new MyAuthenticator("l***@126.com","***50"));
message = new MimeMessage(session);
//补全message
/*1,邮件消息发送人,接收人
2,消息主题
3,邮件内容html*/
Address address = new InternetAddress("li***@126.com");
//设置发送人
message.setFrom(address);
//设置接收人
message.setRecipients(Message.RecipientType.TO,new InternetAddress[]{new InternetAddress("h****")});
//设置主题
message.setSubject("java mail待你查收!");
//设置内容
multipart = new MimeMultipart();
bodyPart = new MimeBodyPart();
bodyPart.setContent("<image src='https://www.baidu.com/img/dong_8f1d47bcb77d74a1e029d8cbb3b33854.gif'/><a herf='https://www.baidu.com'>百度</a>",
"text/html;charset=utf-8");
multipart.addBodyPart(bodyPart);//html内容添加
//添加附件:
bodyPart = new MimeBodyPart();//重新将变量调整下指向
bodyPart.setDataHandler(new DataHandler(new FileDataSource(new File("what.txt"))));
bodyPart.setFileName("what.txt");
//防止中文名称下客户端服务端编码不统一而乱码:
// bodyPart.setFileName(MimeUtility.encodeText("what.txt"));
multipart.addBodyPart(bodyPart);//附件添加
message.setContent(multipart);
Transport.send(message);
} catch (Exception e) {
e.printStackTrace();
}
}
代码封装:
@SuppressWarnings("all")
@Component
public class MailSender {
public void sendMail(String from, String[] to, String subject, String content, String[] files) {
//参数校验
/*from邮箱格式的合法性
to非空 邮箱格式合法
subject非空
content非空*/
Message message = null;
Session session = null;
Properties properties = null;
Multipart multipart = null;
BodyPart bodyPart = null;
try {
properties = new Properties();
//设置邮箱服务器域名
properties.put("mail.smtp.host", "smtp.126.com");
//设置邮箱端口号,一般为25
properties.put("mail.smtp.port", "25");
//设置邮箱认证的标识
properties.put("mail.smtp.auth", true);
session = Session.getDefaultInstance(properties, new MyAuthenticator("lingh***com", "**"));
message = new MimeMessage(session);
//补全message
/*1,邮件消息发送人,接收人
2,消息主题
3,邮件内容html*/
Address address = new InternetAddress(from);
//设置发送人
message.setFrom(address);
//设置接收人
//构建接收方
InternetAddress[] receivers = new InternetAddress[to.length];
for (int i = 0; i < to.length; i++) {
receivers[i] = new InternetAddress(to[i]);
}
message.setRecipients(Message.RecipientType.TO, receivers);
//设置主题
String subjectAfter = MimeUtility.encodeWord(subject, "UTF-8", "Q");
message.setSubject(subjectAfter);
//设置内容
multipart = new MimeMultipart();
bodyPart = new MimeBodyPart();
// "<image src='https://www.baidu.com/img/dong_8f1d47bcb77d74a1e029d8cbb3b33854.gif'/><a herf='https://www.baidu.com'>百度</a>"
bodyPart.setContent(content, "text/html;charset=utf-8");
multipart.addBodyPart(bodyPart);//html内容添加
//因为附件可添加可不添加:
if (null != files && files.length > 0) {
for (String file : files) {
File temp = new File(file);
//添加附件:
bodyPart = new MimeBodyPart();//重新将变量调整下指向
bodyPart.setDataHandler(new DataHandler(new FileDataSource(temp)));
bodyPart.setFileName(temp.getName());
//防止中文名称下客户端服务端编码不统一而乱码:
// bodyPart.setFileName(MimeUtility.encodeText("what.txt"));
multipart.addBodyPart(bodyPart);//附件添加
}
}
message.setContent(multipart);
Transport.send(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
main函数:
public class Mail {
public static void main(String[] args) {
BeanFactory ad = new ClassPathXmlApplicationContext("spring.xml");
MailSender mailSender = (MailSender) ad.getBean("mailSender");
mailSender.sendMail("lingh***com",new String[]{"****cn"},
"java mail待你查收!",
"<image src='https://www.baidu.com/img/dong_8f1d47bcb77d74a1e029d8cbb3b33854.gif'/><a herf='https://www.baidu.com'>百度</a>",
null);
}
}
<?xml version='1.0' encoding='UTF-8' ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--
引入扫描器 base-package为扫描范围
并不会全部实例化,需使用注解@Repository(注解在类级别上)
-->
<context:component-scan base-package="org.example"/>
</beans>
专题四:AOP
aop概念特点
主要用于日志记录,性能统计,安全控制,事务处理等方面,实现公共功能性的重复使用。
带来的好处:
1:解耦,降低模块间的耦合度(高内聚,低耦合)
2:提高代码的复用性。
3:提高系统的扩展性。
基本概念:
Joinpoint(连接点)
被拦截到的每个点,spring中指被拦截到的每个方法。一个连接点代表一个方法的执行。
Pointcut(切入点)
对连接点进行拦截的定义(匹配规则定义 规定拦截哪些方法。对哪些方法进行处理。)
Advice(通知)
拦截到每一个连接点即(每一个方法)后所要做的操作。
1,前置通知(前置增强)–before()执行方法前通知。
2,返回通知(返回增强)–afterReturn()方法正常结束返回后的通知。
3,异常抛出通知(异常抛出增强)–afterThrow()
4,最终通知–after 无论方法是否发生异常,均会执行该通知
5,环绕通知–around 包围一个连接点的通知,如方法调用。
环绕通知可以在方法调用前后完成自定义的行为。
Aspect(切面)
切入点与通知的结合,决定了切面的定义。切入点定义了要拦截哪些类的哪些方法。
通知则定义了拦截方法后要做什么,切面则是横切关注点的抽象。
Target(目标对象)
被代理的目标对象
Weave(织入)
将切面应用到目标对象并生成代理对象的这个过程。
Introduction(引入)
在不修改原有应用程序代码的情况下,在程序运行期为类动态添加方法或字段的过程。
aop注解实现
因为spring-context引入了aop,还需要在环境中引入aspect-jweaver。
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
引用命名空间与xsd
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"
开启aop环境
<!--
开启aop环境
-->
<aop:aspectj-autoproxy/>
/**定义切面类
* 切入点
* 通知
*/
@Component
@Aspect
public class LogAspect {
/**定义切入点
* execution 执行匹配
* 第一个* public|private|protected这三个访问符修饰的方法
* ..*代表包以及子包下的所有类 *为通配符,可以为具体值
* .*(..)代表包以及子包下的所有类的所有方法
*/
@Pointcut("execution(* org.example..*.myWife(..))")
public void cut(){}
@Before(value = "cut()")
public void before(){
System.out.println("今天来的人好多,请耐心等待。。");
}
@AfterReturning(value = "cut()")
public void afterReturning(){
System.out.println("婚礼结束,散场。。");
}
@After(value = "cut()")
public void after(){
System.out.println("虽然仪器坏了,照样进行。");
}
@AfterThrowing(value = "cut()",throwing = "e")
public void afterThrowing(Exception e){
System.out.println("仪器坏了,师傅快来修。"+e);
}
@Around(value="cut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
Object result = null;
System.out.println("round方法开始执行。");
result = pjp.proceed();
System.out.println("round方法执行结束。");
Object[] args = pjp.getArgs();
for (Object arg : args) {
System.out.println(arg);
}
System.out.println(pjp.getSignature());
System.out.println(pjp.getTarget());
return result;
}
}
/**
* 目标类
*/
@Component
public class MyWedding {
public void myWife(String prince,String princess){
System.out.println(String.format("今天的新人婚礼,新郎是%s,新娘是%s。", prince,princess));
}
}
public class AspectTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
MyWedding wedding = (MyWedding) ac.getBean("myWedding");
// MyWedding wedding = new MyWedding();
wedding.myWife("张三","李四");
}
}
在上面程序中,要使用xml加载的bean才可以使用切面。
执行任意公共方法:
execution(public (…))
执行任意的set方法(set开头的):
execution( set*(…))
执行com.xyz.service包下任意类的任意方法:
execution(* com.xyz.service..(…))
执行com.xyz.service包 以及子包下任意类的任意方法:
execution(* com.xyz.service….(…))
另外一种匹配方式:
匹配注解:
“@annotation(定义注解的路径)”
可以直接标注对哪些方法进行增强。不需要艰难地过滤。
//自定义一个注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno {
String name() default "";
}
//切面类
@Pointcut("@annotation(org.example.aspect.MyAnno)")
public void cut(){}
@Around(value="cut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
Object result = null;
System.out.println("round方法开始执行。");
result = pjp.proceed();
System.out.println("round方法执行结束。");
Object[] args = pjp.getArgs();
for (Object arg : args) {
System.out.println(arg);
}
System.out.println(pjp.getSignature());
System.out.println(pjp.getTarget());
//展示了如何获取自定义注解的属性:通过Signature的实现类接口
//调用getMethod获取方法,再获取注解。
//注解也是对象!
MethodSignature siture = (MethodSignature) pjp.getSignature();
Method method = siture.getMethod();
MyAnno myAnno = method.getAnnotation(MyAnno.class);
if(null != myAnno){
System.out.println(myAnno.name());
}
return result;
}
//测试方法
public class AspectTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
MyWedding wedding = (MyWedding) ac.getBean("myWedding");
// MyWedding wedding = new MyWedding();
wedding.myWife("张三","李四");
}
}
注解属性的使用可以简化编程,比如可以设置权限码之类的。
代理–静态代理实现
代理设计模式
目的:增强目标类的行为
静态代理实现的三要素:
1,接口(共同的行为)
2,目标类(被代理的角色)
3,代理类
与目标类实现共同的行为(与目标类实现同一接口)
增强目标类的行为
持有目标类的引用
例子:Marry为共同接口,下面一个toMarry的方法。
You是目标类,Marry接口的实现类。
MarryCompany是代理类,也实现了Marry这个接口,而且
此代理类持有You对象的引用,因此在MarryCompany的toMarry方法中
可以调用You的toMarry方法,增强You的行为。
public interface IMarry {
void toMarry();
}
/**
目标类
*/
public class You implements IMarry{
@Override
public void toMarry() {
System.out.println("等了这么久,终于等到你。。。");
}
}
/**
代理类,代理目标类行为
增强目标类的方法。
*/
public class MarryCompany implements IMarry{
private IMarry target;
public MarryCompany(IMarry target) {
this.target = target;
}
public void before(){
System.out.println("婚礼庆典即将开始。");
}
public void after(){
System.out.println("结婚快乐,早生贵子。");
}
@Override
public void toMarry() {
//行为增强
before();
target.toMarry();
//行为增强
after();
}
}
public class TestStaticProxy {
public static void main(String[] args) {
MarryCompany marryCompany = new MarryCompany(new You());
marryCompany.toMarry();
}
}
静态代理的特点:
1,程序运行前,需要应用程序制作代理角色
2,代理的目标类 类型固定。
3,缺陷:对于每一类接口,如果需要作代理,应用程序需要提供大量的代理类
随着应用程序的复杂度上升,代理类的数据越来越大,维护比较麻烦。
多线程是静态代理的应用
代理–动态代理实现–JDK实现
动态代理最明显特点:在程序运行期为目标类动态地创建代理角色。
实现方式:
1,JDK内部
要求目标类必须存在接口实现。目标类不存在接口实现,无法创建代理对象。
(代理类是跟目标类平级的,不能用目标类来转换对象)
public static Object newProxyInstance(ClassLoader loader, //因为是动态代理,需要加载器
Class<?>[] interfaces, //目标类所有实现的接口
InvocationHandler h) //一个接口,值钱的就是下面这个准重写方法。
invoke(Object proxy,Method method,Object[] args)
返回指定接口的代理实例,该代理实例将方法调用分派给指定的调用处理程序。
二合一写法: |
/**
* 仅仅用于产生动态代理类并且实现InvokeHandler
*/
public class JdkHandler implements InvocationHandler {
//目标类
private Object target;
public JdkHandler(Object target) {
this.target = target;
}
public Object getProxy(){
/*1,类加载器
2,目标类实现的所有接口数组
3,实现类InvocationHandler接口的类实例*/
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
public void before(){
System.out.println("婚礼庆典即将开始。");
}
public void after(){
System.out.println("结婚快乐,早生贵子。");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = null;
//执行目标类的方法:
result = method.invoke(target,args);
after();
return result;
}
}
用接口来接收代理类。
public class TestDynamicProxyJdk {
public static void main(String[] args) {
JdkHandler jdkHandler = new JdkHandler(new You());
//采用父类来接收参数
IMarry dynamicProxy = (IMarry) jdkHandler.getProxy();
dynamicProxy.toMarry();
}
}
/**
目标类
*/
public class You implements IMarry{
@Override
public void toMarry() {
System.out.println("等了这么久,终于等到你。。。");
}
}
目标类必须实现了接口。
public interface IMarry {
void toMarry();
}
代理类与目标类不能相互转换。 因此JDK无法满足给没有接口实现的目标类做代理的需求。
代理–动态代理–CGLIB实现
对于目标类是否存在接口实现没有要求(继承思想)
代理类属于目标类的子类。因此目标类可以引用代理类。
引用环境
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.3.0</version>
</dependency>
通过Enhancer这个类来实现:
此类有个create方法,需要设置两个参数(superclass以及callback)
callback为一个接口,使用其实现接口MethodInterceptor。
public class CGLibHandler implements MethodInterceptor {
private Object target;
public CGLibHandler(Object target) {
this.target = target;
}
public Object getProxy(){
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
//返回代理类
return enhancer.create();
}
public void before(){
System.out.println("婚礼庆典即将开始。");
}
public void after(){
System.out.println("结婚快乐,早生贵子。");
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object result = null;
before();
result = methodProxy.invoke(target, objects);
after();
return result;
}
}
用目标类You来接收动态代理。
public class TestDynamicProxyJdk {
public static void main(String[] args) {
CGLibHandler cgLibHandler = new CGLibHandler(new You());
//获取动态代理
You youproxy = (You) cgLibHandler.getProxy();
//多态,执行子类方法
youproxy.toMarry();
}
}
JDK制作动态代理时,制作效率较高。
AOP内部实现原理是JDK+CGLib。如果目标类有接口实现,采用JDK,如果没有,使用CGLib。
专题五:定时任务
1:概述
二叉树:有多种类型,分为满二叉树与完全二叉树。完全二叉树是指除了最后一层,其他层都是满节点,且最后一层节点靠左。
堆:堆是一种完全二叉树,且任何一个节点都不大于(或者不小于)父节点的值。
小顶堆:完全二叉树且每一节点都不小于父节点的值。
堆的存取:存在数组里面,第一个数组元素不放值,这样下标除二得到父节点位置。存的时候存在最后面,然后上浮。取的时候取最上面的,然后将最后一个值填充到第一个,然后下沉。
定时任务用到小顶堆,每个节点存放一个任务,当任务量巨大时会耗性能。
时间轮:round型时间轮,依然会遍历每个数组。分层时间轮将月轮与天轮分开,方便简洁。
实现定时器的大概有几种方式,一个是JDK自带的timer。
Timer的使用:(单线程+小顶堆)
package com.hxh.timer;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
/**
*
* 问题是由单线程的任务阻塞引起的。
* task.run()方法导致的,单线程任务阻塞导致。
* 在run方法中使用多线程,另起线程,线程池即可。
*
* 对系统时间比较敏感,任务调度基于绝对时间。
*
* TaskQueue小顶堆
*/
public class TimerTest {
public static void main(String[] args) {
Timer timer = new Timer();//任务启动
for (int i=0;i<2;i++){
TimerTask timerTask =new FooTimerTask("foo"+i);
//中间参数,立即启动
// timer.schedule(timerTask,new Date(),2000);//任务添加,真正的执行时间取决于上一个任务执行的时间。
//任务超时时,schecule存在丢任务的风险,执行周期小于(时间推迟了就是丢任务了。)
//任务超时时,scheduleAtFixedRate严格按照period执行。但是会导致任务执行混乱掉。
timer.schedule(timerTask,new Date(),8000);//优先使用这个函数,多个任务执行时间小于period
}
}
}
class FooTimerTask extends TimerTask{
private String name;
public FooTimerTask(String name) {
this.name = name;
}
@Override
public void run() {
try {
System.out.println("name ---> "+name+" ,startTime"+new Date());
Thread.sleep(3000);
System.out.println("name ---> "+name+" ,endTime"+new Date());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
线程池的使用(多线程+小顶堆)
package com.hxh.pool;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 定时任务线程池
* 在timer的基础上做了优化
*
*小顶堆
* leader-follower模式:只有leader线程执行任务,
* 其他follower线程等待变为leader线程,避免没必要的唤醒与阻塞操作。
*
* 任务同时启动,如果任务超时间隔周期,则任务结束后会立即启动。
*
*/
public class ScheduleThreadPoolTest {
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorPool = Executors.newScheduledThreadPool(5);
for (int i=0;i<2;i++){
//需要一个Runnable command
//.schedule未传间隔时间,只执行一次,需要用到
//.scheduleAtFixedRate可设置间隔时间
scheduledExecutorPool.scheduleAtFixedRate(new Task("masaka--"+i),0,4, TimeUnit.SECONDS);
}
}
}
class Task implements Runnable{
private String name;
public Task(String name) {
this.name = name;
}
@Override
public void run() {
try {
System.out.println("name ---> "+name+" ,startTime"+new Date());
Thread.sleep(3000);
System.out.println("name ---> "+name+" ,endTime"+new Date());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
2:quartz
并发任务,且每次创建一个新的job实例。可以规避并发访问的问题。
@DisallowConcurrentExecution
这个注解无视执行触发时间间隔,只有j每次的job执行完毕后,下一个才开始。
@PersistJobDataAfterExecution
让JobData持久化,可以递增一些data,这两个注解标注在Job任务上,但是后者只对jobDetail里的.usingJobData有效。如果一个任务不是持久化的,则当没有触发器关联它的时候,Quartz会从schedule中删除它。
trigger里的usingJobData会覆盖jobDetail里的同key值data。
trigger的其他内容:
同时触发的trigger之间才会比较优先级,如果trigger是可恢复的,在恢复后再调度时,优先级不变。
misfire错过触发:判断misfire的条件:1,job达到触发时间没有被执行;2,被执行的延迟时间超过了Quartz配置的misfire Threshold。
3:时间解析
//如何将UTC统一时间规范化。
String timmi = "2020-12-22T06:18:55.592Z";
SimpleDateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
SimpleDateFormat df2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date1 = df1.parse(timmi);
String date2 = df2.format(date1);
System.out.println(date1);//Tue Dec 22 06:18:55 CST 2020
System.out.println(date2);//2020-12-22 06:18:55
System.out.println(date1.getTime());//long 1608589135592
Timestamp timestamp = new Timestamp(date1.getTime());//根据long类型建立实例
System.out.println(timestamp.getTime());//输出1608589135592
System.out.println(timestamp.toLocalDateTime());//2020-12-22T06:18:55.592
System.out.println(timestamp);//2020-12-22 06:18:55.592
System.out.println(timestamp.toString());//自身toString长这个样子。2020-12-22 06:18:55.592
String hxh1 = Long.toString(1608589135592L);
String hxh2 = String.valueOf(1608589135592L);
//*******************************************
//项目使用:
String timmi = "2020-12-22T06:18:55.592Z";
SimpleDateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
Date date1 = df1.parse(timmi);
Timestamp timestamp = new Timestamp(date1.getTime());
//再把timestamp插入到数据库。
//将时间的日期插入到sql中。
java.sql.Date sql_date = new java.sql.Date(date1.getTime());
System.out.println(sql_date);//输出2020-12-22