一、实验目的
1.使用 Spring Boot 完成异步任务、定时任务以及邮件任务。
二、实验内容
1.熟悉 Spring Boot 整合异步任务的实现
2.熟悉 Spring Boot 整合定时任务的实现
3.熟悉 Spring Boot 整合邮件任务的实现
三、实验步骤及截图
1.使用Idea+Maven新建项目,并进行必要配置。
2.编写入口类,并启用计划任务。
@EnableScheduling
@SpringBootApplication
public class ChapterAsync_LWL {
public static void main(String[] args){
SpringApplication.run(ChapterAsync_LWL.class,args);
}
}
3.在service类,编写方法测试cron定时任务。
// 简单的定时任务
@Scheduled(cron = "10 * * * * *")
public void Task01(){
System.out.println("***********每分钟的第10S启动!*********"+simpleDateFormat.format(new Date()));
}
4.在service类,编写方法测试fixedDelay定时任务。
//delay从第一次开始就计算间隔时间
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
int index = 1;
@Scheduled(fixedDelay = 10000)
public void Task02(){
System.out.println("***********Task02任务第"+index+"启动!*********"+simpleDateFormat.format(new Date()));
try{
Thread.sleep(5000);
}catch (Exception e){
System.out.println("错误!");
}
System.out.println("***********Task02任务第"+index+"结束!*********"+simpleDateFormat.format(new Date()));
index++;
}
5.在service类,编写方法测试fixedRate定时任务。
//rate从第一次开始就计算间隔时间
@Scheduled(fixedRate = 10000)
public void Task03(){
System.out.println("***********Task03任务第"+index+"启动!*********"+simpleDateFormat.format(new Date()));
try{
Thread.sleep(5000);
}catch (Exception e){
System.out.println("错误!");
}
System.out.println("***********Task03任务第"+index+"结束!*********"+simpleDateFormat.format(new Date()));
index++;
}
6.编写controller类,添加sendSms方法,调用无返回值的service方法。
@Autowired
AsynService asynService;
@GetMapping("/sendSMS")
public String sendSms() throws Exception{
System.out.println("***********主方法开始运行***********");
Long timeStart = System.currentTimeMillis();
asynService.sendSMS();
Long timeEnd = System.currentTimeMillis();
System.out.println("***********主方法结束运行--异步调用业务逻辑耗时"+(timeEnd-timeStart)+"***********");
return "success";
}
@Async//无返回值的被调用方法
public void sendSMS() throws Exception{
System.out.println("A无返回值***********耗时的业务逻辑开始被调用***********");
Long timeStart = System.currentTimeMillis();
Thread.sleep(50*1000);//模拟一个耗时的操作
Long timeEnd = System.currentTimeMillis();
System.out.println("B无返回值***********耗时的业务逻辑结束被调用,耗时:"+(timeEnd-timeStart)+"***********");
}
7.编写service类,完成无返回值的异步方法。
@GetMapping("/sendSMS")
public String sendSms() throws Exception{
System.out.println("***********主方法开始运行***********");
Long timeStart = System.currentTimeMillis();
asynService.sendSMS();
Long timeEnd = System.currentTimeMillis();
System.out.println("***********主方法结束运行--异步调用业务逻辑耗时"+(timeEnd-timeStart)+"***********");
return "success";
}
8.编写controller类,添加sendCallback方法,调用有返回值的service方法。
@GetMapping("/sendcb")
public String sendCallback() throws Exception{
System.out.println("***********主方法开始运行***********");
Long timeStart = System.currentTimeMillis();
Future<Integer> resultA = asynService.processA();
Future<Integer> resultB = asynService.processB();
Long timeEnd = System.currentTimeMillis();
System.out.println("***********主方法结束运行--异步调用2个业务逻辑耗时"+(timeEnd-timeStart)+"***********");
System.out.println("processA返回值:"+resultA.get()+"*****processB返回值:"+resultB.get()+"******主方法结束运行--异步调用2个业务逻辑耗时"+(timeEnd-timeStart)+"***********");
return "success";
}
@Async//有返回值的被调用方法
public Future<Integer> processA() throws Exception{
System.out.println("C有返回值***********耗时的业务逻辑开始被调用***********");
Long timeStart = System.currentTimeMillis();
Thread.sleep(25*1000);//模拟一个耗时的操作
Long timeEnd = System.currentTimeMillis();
System.out.println("D有返回值***********耗时的业务逻辑结束被调用--耗时:"+(timeEnd-timeStart)+"***********");
return new AsyncResult<Integer>(8000);
}
@Async//有返回值的被调用方法
public Future<Integer> processB() throws Exception{
System.out.println("E有返回值***********耗时的业务逻辑开始被调用***********");
Long timeStart = System.currentTimeMillis();
Thread.sleep(20*1000);//模拟一个耗时的操作
Long timeEnd = System.currentTimeMillis();
System.out.println("F有返回值***********耗时的业务逻辑结束被调用--耗时:"+(timeEnd-timeStart)+"***********");
return new AsyncResult<Integer>(8000);
}
9.编写service类,完成有返回值的异步方法。
@GetMapping("/sendcb")
public String sendCallback() throws Exception{
System.out.println("***********主方法开始运行***********");
Long timeStart = System.currentTimeMillis();
Future<Integer> resultA = asynService.processA();
Future<Integer> resultB = asynService.processB();
Long timeEnd = System.currentTimeMillis();
System.out.println("***********主方法结束运行--异步调用2个业务逻辑耗时"+(timeEnd-timeStart)+"***********");
System.out.println("processA返回值:"+resultA.get()+"*****processB返回值:"+resultB.get()+"******主方法结束运行--异步调用2个业务逻辑耗时"+(timeEnd-timeStart)+"***********");
return "success";
}
10.测试、分析 有返回值异步方法与无返回值异步方法的区别。
有返回值的异步方法和无返回值的异步方法主要区别在于其返回值的类型不同。
无返回值的异步方法一般不返回任何值,通常用于执行一些异步操作,不需要返回结果。在该类型的异步方法中,通常使用回调函数的方式处理异步操作的结果。
有返回值的异步方法用来执行某些计算任务,它们通常会返回一个结果,因此需要使用某个值类型来定义返回值。有返回值的异步方法通常由调用者调用时使用接口来获取计算结果,或者通过回调函数的方式处理异步操作的结果。
总的来说,无返回值的异步方法适用于执行一些无需返回结果的异步操作,有返回值的异步方法适用于执行一些需要计算并返回结果的异步操作。两者之间的主要区别在于返回值的类型以及处理方式的不同。
11.编写计划任务,访问tushare的Http接口,定时获取数据,并进行测试。
public class NetRequest {
public static JSONObject sendPost(String url,JSONObject jsonParam) throws Exception {
OutputStream out = null;
BufferedReader in = null;
StringBuilder result = new StringBuilder();
HttpURLConnection conn = null;
try {
// 创建url资源
URL url_ = new URL(url);
// 建立http连接
conn = (HttpURLConnection) url_.openConnection();
// 设置传递方式
conn.setRequestMethod("POST");
// 设置允许输入、允许输出
conn.setDoInput(true);
conn.setDoOutput(true);
// 设置不用缓存
conn.setUseCaches(false);
//设置连接超时时间和读取超时时间
conn.setConnectTimeout(30000);
conn.setReadTimeout(10000);
// 转换为字节数组
byte[] data = (jsonParam.toString()).getBytes();
// 设置文件长度
conn.setRequestProperty("Content-Length", String.valueOf(data.length));
// 设置文件类型:
conn.setRequestProperty("contentType", "application/json");
// 开始连接请求
conn.connect();
out = new DataOutputStream(conn.getOutputStream()) ;
// 写入请求的字符串(此时jsonParam数据是放在了请求正文body里)
out.write((jsonParam.toString()).getBytes());
out.flush();
out.close();
// 请求返回的状态
if (HttpURLConnection.HTTP_OK == conn.getResponseCode()){
// System.out.println("连接成功");
// 请求返回的数据
InputStream in1 = conn.getInputStream();
try {
String readLine=new String();
BufferedReader responseReader=new BufferedReader(new InputStreamReader(in1,"UTF-8"));
while((readLine=responseReader.readLine())!=null){
result.append(readLine).append("\n");
}
responseReader.close();
} catch (Exception e1) {
e1.printStackTrace();
}
} else {
System.out.println("ResponseCode is an error code:" + conn.getResponseCode());
}
} catch (Exception e) {
throw new Exception(e);
}finally {
try{
if(out != null){
out.close();
}
if(in != null){
in.close();
}
}catch (IOException ioe){
ioe.printStackTrace();
}
}
return JSONObject.parseObject(result.toString());
}
public static void main( String[] args ) throws Exception {
JSONObject jsonParam = new JSONObject();
jsonParam.put("para1", "para1");
jsonParam.put("para2", "para2");
jsonParam.put("para3", "para3");
String url="http://api.tushare.pro";
JSONObject data = sendPost(url,jsonParam);
System.out.println(data);
}
}
//获取互联网上接口的数据
@Scheduled(fixedRate = 60000)
public void getFianceData() throws Exception {
JSONObject jsonObject = new JSONObject();
jsonObject.put("api_name","trade_cal");
jsonObject.put("token","43a324154682799b54d2a59ecbd2fc8a16a8e2949cb4fb4551277455");
JSONObject jsonObject1 = new JSONObject();
jsonObject1.put("exchange","");
jsonObject1.put("start_date","20180910");
jsonObject1.put("end_date","20181001");
jsonObject1.put("is_open","0");
jsonObject1.put("params",jsonObject1);
jsonObject.put("filed","exchange,cal_data,is_open,pretrade_date");
JSONObject result = NetRequest.sendPost("http://api.tushare.pro",jsonObject);
System.out.println(result);
}
四、实验中遇到的问题及采取的措施(10分)
报错1:{"msg":"抱歉,您没有访问该接口的权限,权限的具体详情访问:https://tushare.pro/document/1?doc_id=108。","code":40203,"message":"抱歉,您没有访问该接口的权限,权限的具体详情访问:https://tushare.pro/document/1?doc_id=108。"}
排错过程1:
检查 API 接口权限:阅读 Tushare API 接口文档并查询具体接口的相关权限要求,确认自己是否满足访问该接口的条件,例如 Token 权限、调用策略等;
更新 Token 权限:如果您已经具有 Token 权限,但是访问某个 API 接口时出现了权限错误,那么可能需要查看您的 Token 权限是否满足该接口的要求,如果不满足,需要重新申请升级 Token 权限。可以在 Tushare 平台的“个人中心”页面查看 Token 权限和使用情况,进行相应的更新;
联系 Tushare 客服:如果以上方法都无法解决问题,可以联系 Tushare 客服,询问具体的错误原因和解决方法,以确保能够正确访问 API 接口获取数据。
原因分析1:
这个错误通常表示您尝试访问 Tushare 平台的某个 API 接口时没有相关的访问权限,根据错误信息,您可以访问提供的链接查看该 API 接口的具体权限要求和访问方式。
注:由于源码量过多,需要的朋友可在资源中下载,也可私信我拿取!