cron,Timer、quartz-scheduler,Stream流HTTPS
某个时间点触发
10 * * * * ? 每分钟第10秒执行 30 10 1 * * ? 每天1点10分30秒触发任务 "30 10 1 20 10 ? 2011" 2011年10月20号1点10分30秒触发任务 "15/5 * * * * ?" 每分钟的每15秒开始触发,每隔5秒触发一次 秒、分、小时、日期、月份、星期和年份
0/5 * * * * ? 每5秒执行一次
Timer
@Service
public class IndexTaskImpl extends TimerTask implements IIndexTask {
@Autowired
Scheduler scheduler;
@Value("${statistics_cron:0 0 2 * * ?}")
private String statisticsCron ;
@PostConstruct
public void initTask(){
Timer timer = new Timer();
timer.schedule(this, 3*60*1000); // 3分钟后执行
}
public void statisticsTask(){
try {
String key = "statisticsTask";
//创建触发器
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(key)
// 0 0 2 * * ? 0/10 * * * * ?
.withSchedule(CronScheduleBuilder.cronSchedule(statisticsCron))
.startNow()
.build();
log.info("*******statisticsTask**************");
JobDetail jobDetail = scheduler.getJobDetail(JobKey.jobKey(key));//服务再次启动,以创建的任务无需再建
if(jobDetail == null) {
//创建任务
jobDetail = JobBuilder.newJob(IndexStatisticsJob.class).withIdentity(key).build();
//调度作业
scheduler.scheduleJob(jobDetail, trigger);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void run() {
statisticsTask();
}
//创建触发器 重复执行某个任务三次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(xxx.getId())
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInMinutes(xxx.getResendInterval()).withRepeatCount(2)) // 重复2次,总共执行3次(包括启动时的一次)
.startAt(xxx.getFirstRunTime())
.build();
quartz-scheduler 分布式任务,多台实例,只会有一台执行,相同mysql数据源
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.6.8</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.3</version>
</dependency>
@Service
public class QuartzServiceImpl implements IQuartzService {
@Autowired
Scheduler scheduler;
@Override
public void addJob() {
ScheduleJob job = new ScheduleJob();
job.setJobName("job1");
job.setCronExpression("0/5 * * * * ?");
try {
//创建触发器
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(job.getJobName())
.withSchedule(CronScheduleBuilder.cronSchedule(job.getCronExpression()))
.startNow()
.build();
//创建任务
JobDetail jobDetail = JobBuilder.newJob(QuartzJob.class)
.withIdentity(job.getJobName()).build();
//QuartzFactory传入调度的参数
jobDetail.getJobDataMap().put("scheduleJob",job);
log.info("addJob****1******"+job.getJobName());
//调度作业
JobKey jobKey = new JobKey(job.getJobName());
scheduler.deleteJob(jobKey);
scheduler.scheduleJob(jobDetail,trigger);
log.info("addJob****2******"+job.getJobName());
} catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public void operateJob(JobOperateEnum jobOperateEnum, String jobName) throws SchedulerException {
JobKey jobKey = new JobKey(jobName);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if (jobDetail == null){
throw new SchedulerException("此定时任务不存在");
}
//任务操作
switch (jobOperateEnum){
case START: //启动
scheduler.resumeJob(jobKey);
break;
case PAUSE: //暂停
scheduler.pauseJob(jobKey);
break;
case DELETE: //删除
scheduler.deleteJob(jobKey);
break;
default:
break;
}
}
@Override
public void startAllJob() throws SchedulerException {
scheduler.start();
}
@Override
public void pauseAllJob() throws SchedulerException {
scheduler.standby();
}
public class QuartzJob implements Job {
@SneakyThrows
@Override
public void execute(JobExecutionContext jobExecutionContext) {
//获取调度数据
ScheduleJob scheduleJob = (ScheduleJob) jobExecutionContext.getMergedJobDataMap().get("scheduleJob");
//获取对应的bean
try {
log.info("开始执行任务xxxx==》{}",scheduleJob.getJobName());
//利用反射执行对应方法
// Class<?> jobClass = Class.forName(scheduleJob.getBeanName());
// Method method = jobClass.getMethod(scheduleJob.getMethodName(), JobExecutionContext.class);
// method.invoke(jobClass.newInstance(), jobExecutionContext);
} catch (Exception e) {
log.error("任务调度工厂方法执行异常==》{}",e.getMessage());
}
}
}
@Configuration
public class QuartzConfig {
@Autowired
private JobFactory jobFactory;
//创建调度器工厂
@Bean
public SchedulerFactoryBean schedulerFactoryBean(){
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
schedulerFactoryBean.setAutoStartup(true);
//覆盖已存在的任务
//schedulerFactoryBean.setOverwriteExistingJobs(true);
//注意这里是重点
// schedulerFactoryBean.setJobFactory(jobFactory);
//这样当spring关闭时,会等待所有已经启动的quartz job结束后spring才能完全shutdown。
schedulerFactoryBean.setWaitForJobsToCompleteOnShutdown(true);
//服务启动20秒后启动定时任务
schedulerFactoryBean.setStartupDelay(20);
return schedulerFactoryBean;
}
/**
* 创建scheduler
* @return Scheduler
*/
@Bean(name = "scheduler")
public Scheduler scheduler(){
return schedulerFactoryBean().getScheduler();
}
/**
* quartz初始化监听器 用处: 服务启动时执行任务 ,非必要配置
*/
// @Bean
// public QuartzInitializerListener executorListener() {
// return new QuartzInitializerListener();
// }
}
/**
* @ClassName JobFactory
* @Description 创建job 实例工厂,解决spring注入问题,如果使用默认会导致spring的@Autowired 无法注入问题
* @Author chaic
* @Date 2020/6/8 12:02
* @Version 1.0
*/
@Component
public class JobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
//进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ScheduleJob implements Serializable {
private static final long serialVersionUID = 4069043308097112481L;
/**
* 任务主键
*/
private String id;
/**
* 任务名称
*/
private String jobName;
/**
* cron表达式
*/
private String cronExpression;
/**
* 服务名称
*/
private String beanName;
quartz-sheduler集群模式
spring:
quartz:
autoStartup: true
job-store-type: jdbc
wait-for-jobs-to-complete-on-shutdown: false
overwrite-existing-jobs: false
jdbc:
initialize-schema: never
properties:
org:
quartz:
scheduler:
instanceId: AUTO
instanceName: clusteredScheduler
jobStore:
class: org.springframework.scheduling.quartz.LocalDataSourceJobStore
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
useProperties: false
tablePrefix: QRTZ_
misfireThreshold: 60000
clusterCheckinInterval: 5000
isClustered: true
threadPool:
class: org.quartz.simpl.SimpleThreadPool
threadCount: 10
threadPriority: 5
threadsInheritContextClassLoaderOfInitializingThread: true
quartz-sheduler集群模式-其他方式
quartz-scheduler http://www.quartz-scheduler.org
2.2.3 官网下载sql脚本 \quartz-2.2.3-distribution\quartz-2.2.3\docs\dbTables
quartz https://zhuanlan.zhihu.com/p/684740530
修改任务
public void rescheduleJob(Scheduler scheduler, String triggerName, String triggerGroup, String newCronExpression) throws SchedulerException {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroup);
// 获取旧的触发器
CronTrigger oldTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 定义新的触发器,使用新的cron表达式
Trigger newTrigger = oldTrigger.getTriggerBuilder()
.withSchedule(CronScheduleBuilder.cronSchedule(newCronExpression))
.build();
// 重新调度作业
scheduler.rescheduleJob(triggerKey, newTrigger);
}
在集群模式下,Quartz通过数据库锁来确保同一个任务不会被多个节点同时执行。当一个调度器实例尝试执行一个任务时,它会先在数据库中对该任务加锁。如果加锁成功,该实例就会执行任务;否则,意味着有其他实例已经在执行该任务,当前实例就会放弃执行。
org.quartz.scheduler.instanceName: MyClusteredScheduler
org.quartz.scheduler.instanceId: AUTO
org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.useProperties: false
org.quartz.jobStore.dataSource: myDS
org.quartz.jobStore.tablePrefix: QRTZ_
org.quartz.jobStore.isClustered: true
org.quartz.dataSource.myDS.driver: com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL: jdbc:mysql://x.x.x.x:3306/a_test?useSSL=false
org.quartz.dataSource.myDS.user: x
org.quartz.dataSource.myDS.password: xx
org.quartz.dataSource.myDS.maxConnections: 5
org.quartz.threadPool.threadConut:20 线程数
org.quartz.threadPool.threadPriority:5 线程优先级
//创建调度器工厂
@Bean
public SchedulerFactoryBean schedulerFactoryBean(){
//追加如下代码
File file ;
InputStream inputStream = null;
Resource resource= null;
try {
// file = ResourceUtils.getFile("classpath:quartz.properties");//在linux环境中无法读
// inputStream = new FileInputStream(file);
// resource = new InputStreamResource(inputStream);
// resource = new ClassPathResource("quartz.properties");
resource = resourceLoader.getResource("classpath:quartz.properties");
} catch (Exception e) {
e.printStackTrace();
}
schedulerFactoryBean.setConfigLocation(resource);
return schedulerFactoryBean;
}
//去掉如下配置
/**
* quartz初始化监听器
*/
// @Bean
// public QuartzInitializerListener executorListener() {
// return new QuartzInitializerListener();
// }
可增加如下配置
schedulerFactoryBean.setTaskExecutor(taskExecutor());
@Bean
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(500);
return executor;
}
@Controller @RequestMapping("/hello3") @ResponseBody 直接响应json格式
OutputStream 输出流,用来write写的,把数据写进入
如果是文件输出流,结果就是把数据写入文件
如果是HttpURLConnection输出流,结果就是把数据写入http发送数据
InputStream 输入流,用来read读取的,把数据读出来
如果是文件输入流,结果就是把数据从文件中读取到字节、字符数组中
如果是HttpURLConnection输入流,结果就是读取数据接收http数据
字符流(一次可以处理一个缓冲区)一次操作比字节流(一次一个字节)效率高。
字节流通常用于处理二进制数据,不支持直接读写字符;字符流通常用于处理文本数据
在读写文件需要对文本内容进行处理:按行处理、比较特定字符的时候一般会选择字符流;仅仅读写文件,不处理内容,一般选择字节流
https://ww.cnblogs.com/liangbaolong/p/12880487.html
public static byte[] readFromFile(){
String path = "test.txt";
byte[] data = new byte[10];
char[] chars = new char[10];
try {
FileInputStream fileInputStream = new FileInputStream(new File(path));
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
Reader reader = new BufferedReader(inputStreamReader);
FileOutputStream fileOutputStream = new FileOutputStream(new File("test2.txt"));
int b = 0;
while ((b = fileInputStream.read(data)) >=0){
fileOutputStream.write(data,0,b);
data = new byte[10];
}
fileOutputStream.flush();
fileOutputStream.close();
fileInputStream.close();
FileWriter fw = new FileWriter(new File("test2.txt")); //文件输出流 (字符流)
int b = 0;
while ( (b = reader.read(chars)) >= 0) {
System.out.println(b);
fw.write(chars,0,b);//此写法可以防止最后一组数据填不满,把null数据也写到fw里
// fw.write(chars);
chars = new char[10];
}
fw.flush();
reader.close();
fw.close();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
从目标文件或资源读取
URL u = new URL(url);
UrlResource ur = new UrlResource(u);
输入读:
InputStream in = ur.getInputStream(); //字节输入流 例如从url资源获取
FileInputStream in = new FileInputStream(new File("D:/test.txt")); 文件输入流(字节流)
FileReader fr = new FileReader(new File("D:/test.txt")); 文件输入流(字符流)
InputStreamReader isr = new InputStreamReader(in,"gbk"); 字符输入流
Reader read = new BufferedReader(isr); 字符输入流
输出写:
OutputStream outStream = response.getOutputStream(); 字节输出流 例如从http响应获取
ByteArrayOutputStream bao = new ByteArrayOutputStream(); 字节输出流
FileOutputStream fos = new FileOutputStream(file); 文件输出流 (字节流)
FileWriter fw = new FileWriter(new File("D:/test2.txt")); 文件输出流 (字符流)
OutputStreamWriter out = new OutputStreamWriter(fos); 字符输出流
Writer wr = new BufferedWriter(out); 字符输出流
字节流:
while((i=in.read(b))>=0){//从输入流读取到字节数组 i是返回的读到b的字节个数 返回-1表示已读完
bao.write(b);//字节数组写入输出流
b = new byte[1024];
}
字符流:
while((c= read.read(ch))>=0){ //从输入流读取字符数组
//out.write(ch,0, c); //字符数组写入输出流
wr.write(ch);
ch = new char[5];
}
wr.flush();
wr.close();
操作字符流涉及字符编码,字节流不涉及
基于字节流的stream:
DataOutputStream----DataInputStream:
FileOutputStream-----FileInputStream:
基于字符流的stream(典型的以write和reader来标识的):
FileWriter---FileReader:
StringWriter---StringReader:
BufferedWriter--BufferedReader
@RequestMapping("/hello2")
public void hello2(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
MultipartFile multipartFile = multipartRequest.getFile("file");
String imageNameOriginal = multipartFile.getOriginalFilename();
System.out.println("uploadCostomerImg imageNameOriginal:"+imageNameOriginal);
String[] ss = imageNameOriginal.split("\\\\");
File fileupload = new File("F:\\study-idea\\space\\xmhAID\\file\\"+ss[ss.length-1]);
//读取图片
multipartFile.transferTo(fileupload);//读取流到本地文件
System.out.println("uploadCostomerImg 图片地址:"+ fileupload);
}
## 是设置单个文件的大小
spring.http.multipart.maxFileSize=300Mb
是设置单次请求的文件的总大小
spring.http.multipart.maxRequestSize=300Mb
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<form action="http://192.168.206.1:9990/hello2" enctype="multipart/form-data" method="post">
上传文件:<input type="file" name="file"><br/>
<input type="submit" value="提交">
</form>
https服务器搭建
https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter2_7.shtml
public static void main(String[] args) {
//传入null请求接收方会报错
String s1 = httpReq("http://localhost:9098/insurance/insuranceAward/insuranceSport2.json?userId=123&policyNo=321","123xxxxxxmmmmmmm");
System.out.println("result:"+s1);
}
@RequestMapping(value = "/insuranceSport2")
@ResponseBody
public ResultVO<String> test2(@Valid MyRequest request, HttpServletRequest req, HttpServletResponse res,@RequestBody String jsonString) {
ResultVO rs = new ResultVO();
System.out.println(request);
System.out.println(jsonString);
return rs;
}
public static String httpReq(String url, String params) {
StringBuffer bufferRes = new StringBuffer();
HttpURLConnection conn = null;
InputStream in = null;
try {
URL realUrl = new URL(url);
conn = (HttpURLConnection) realUrl
.openConnection();
// 连接超时
conn.setConnectTimeout(30000);
// 读取超时 --服务器响应比较慢,增大时间
conn.setReadTimeout(30000);
HttpURLConnection.setFollowRedirects(true);
// 请求方式
conn.setRequestMethod("GET");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
if (StringUtils.isNotBlank(params)) {
conn.setRequestProperty("CONTENT_LENGTH","" + params.length());
}
// conn.setRequestProperty("Accept-Charset", "UTF-8");
conn.setRequestProperty("User-Agent",
"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0");
conn.setRequestProperty("Referer", "https://api.weixin.qq.com/");
// 发送请求参数
if (params != null) {
OutputStream out = conn.getOutputStream();
out.write(params.getBytes("UTF-8"));
out.flush();
out.close();
out = null;
}
//接收返回
public static void main(String[] args) {
//传入null请求接收方会报错
String s1 = httpReq("http://localhost:9098/insurance/insuranceAward/insuranceSport2.json?userId=123&policyNo=321","123xxxxxxmmmmmmm");
System.out.println("result:"+s1);
}
@RequestMapping(value = "/insuranceSport2")
@ResponseBody
public ResultVO<String> test2(@Valid MyRequest request, HttpServletRequest req, HttpServletResponse res,@RequestBody String jsonString) {
ResultVO rs = new ResultVO();
System.out.println(request);
System.out.println(jsonString);
return rs;
}
public static String httpReq(String url, String params) {
StringBuffer bufferRes = new StringBuffer();
HttpURLConnection conn = null;
InputStream in = null;
try {
URL realUrl = new URL(url);
conn = (HttpURLConnection) realUrl
.openConnection();
// 连接超时
conn.setConnectTimeout(30000);
// 读取超时 --服务器响应比较慢,增大时间
conn.setReadTimeout(30000);
HttpURLConnection.setFollowRedirects(true);
// 请求方式
conn.setRequestMethod("GET");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
if (StringUtils.isNotBlank(params)) {
conn.setRequestProperty("CONTENT_LENGTH","" + params.length());
}
// conn.setRequestProperty("Accept-Charset", "UTF-8");
conn.setRequestProperty("User-Agent",
"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0");
conn.setRequestProperty("Referer", "https://api.weixin.qq.com/");
// 发送请求参数
if (params != null) {
OutputStream out = conn.getOutputStream();
out.write(params.getBytes("UTF-8"));
out.flush();
out.close();
out = null;
}
//接收返回
in = conn.getInputStream();
BufferedReader read = new BufferedReader(new InputStreamReader(in,"UTF-8"));
String valueString = null;
while ((valueString = read.readLine()) != null) {
bufferRes.append(valueString);
}
in.close();
read.close();
in = null;
read = null;
if (conn != null) {
conn.disconnect();
}
} catch (Exception e) {
LOGGER.error("http请求微信服务异常", e);
} finally{
conn = null;
in = null;
}
return bufferRes.toString();
} in = conn.getInputStream();
BufferedReader read = new BufferedReader(new InputStreamReader(in,"UTF-8"));
String valueString = null;
while ((valueString = read.readLine()) != null) {
bufferRes.append(valueString);
}
in.close();
read.close();
in = null;
read = null;
if (conn != null) {
conn.disconnect();
}
} catch (Exception e) {
LOGGER.error("http请求微信服务异常", e);
} finally{
conn = null;
in = null;
}
return bufferRes.toString();
}
// https
public static String httpRequest(String requestUrl, String outputStr) {
StringBuffer buffer = new StringBuffer();
try {
TrustManager[] tm = { new TrustAnyTrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection httpUrlConn = (HttpsURLConnection) url
.openConnection();
httpUrlConn.setSSLSocketFactory(ssf);
httpUrlConn.setDoOutput(true);
httpUrlConn.setDoInput(true);
httpUrlConn.setUseCaches(false);
// 设置请求方式(GET/POST)
httpUrlConn.setRequestMethod("POST");
if (null != outputStr) {
OutputStream outputStream = httpUrlConn.getOutputStream();
// 注意编码格式,防止中文乱码
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 将返回的输入流转换成字符串
InputStream inputStream = httpUrlConn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(
inputStream, "UTF-8");
BufferedReader bufferedReader = new BufferedReader(
inputStreamReader);
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
// 释放资源
inputStream.close();
inputStream = null;
httpUrlConn.disconnect();
return buffer.toString();
} catch (Exception e) {
LOGGER.error("WeixinHttpUtil-->httpRequest error"+e.getMessage(),e);
}
return "";
}

浙公网安备 33010602011771号