最近,api老不稳定呀,要等用户反馈才知道问题,老板火了,问同事做过没,没做过呀,小码农我只能翻身干活儿,这个需求被自己想起到基本框架实现,也就10来分钟的样子;能准确理解需求,然后迅速转化为代码实现,属于现学现用,很多不大会,但只要花时间基本都可以会,在自我看来几乎是没有上限的,只是感叹时间在哪儿,能超过这种理解能力的应该大有人在,不过超过这种水平的人一般不在我们面前装逼,因为确实是高手;还有一种偶尔写了一个文章就开始装了,大多半桶水,必须吐槽一下,没时间写文章,吐槽一定还是有时间的,兴趣之一
直接上代码,有需要讨论的欢迎讨论,有不完善的欢迎纠正
数据库设计:
代码语言:javascript复制
Create Table
CREATE TABLE `api_info` (
`api_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`api_url` char(200) DEFAULT NULL,
`api_name` char(200) NOT NULL DEFAULT '""' COMMENT 'api名称',
`method` char(10) DEFAULT 'GET' COMMENT 'GET/POST/DELETE/PUT',
`header` char(255) NOT NULL DEFAULT 'application/json' COMMENT 'application',
`params` char(255) DEFAULT NULL COMMENT '参数',
`result` text NOT NULL COMMENT '结果',
`extract_variable_value` char(200) DEFAULT '""' COMMENT '提取变量值',
`time_interval` int(11) NOT NULL DEFAULT '5' COMMENT '请求时间间隔,单位秒',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`group_id` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`api_id`),
UNIQUE KEY `api_url` (`api_url`,`params`)
) ENGINE=InnoDB AUTO_INCREMENT=54 DEFAULT CHARSET=utf8mb4
核心代码:
代码语言:javascript复制package io.xx.xx.api.cron;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.xx.xx.api.entity.ApiMonitor;
import io.xx.xx.api.service.ApiMonitorService;
import io.xx.xx.core.bean.OkHttpUtils;
import io.xx.xx.framework.service.MailSendService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
@Configuration //1.主要用于标记配置类,兼备Component的效果。
@EnableScheduling // 2.开启定时任务
@EnableAsync
public class ApiMonitorCron implements Runnable {
private static ExecutorService pool;
private static final Logger logger = LoggerFactory.getLogger(ApiMonitorCron.class);
private MailSendService mailSendService;
@Autowired
private ApiMonitorService apiMonitorService;
static AtomicInteger i = new AtomicInteger(-1);
static AtomicInteger n = new AtomicInteger(0);
static List<ApiMonitor> apiInfolist = new ArrayList<>();
public static void main(String[] args) {
//maximumPoolSize设置为2 ,拒绝策略为AbortPolic策略,直接抛出异常
pool = new ThreadPoolExecutor(3, 5, 1000, MILLISECONDS, new SynchronousQueue<Runnable>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
for (int i = 0; i < 5; i ) {
pool.execute(new ApiMonitorCron());
}
}
@Async
@Scheduled(cron = "0/10 * * * * ?")
public void configureTasks() {
apiInfolist = apiMonitorService.listAll();
n = new AtomicInteger(apiInfolist.size() - 1);
i = new AtomicInteger(-1);
pool = new ThreadPoolExecutor(3, 5, 5000, MILLISECONDS, new SynchronousQueue<Runnable>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
for (int i = 0; i < 5; i ) {
pool.execute(new ApiMonitorCron());
}
}
public void run() {
System.err.println("执行静态定时任务时间: " LocalDateTime.now() "i:" i.get());
// ApiMonitor apiMonitor = apiInfolist.get(i.get());
ApiMonitor apiMonitor = new ApiMonitor();
String result = "";
Map<String, Object> map = new ConcurrentHashMap<>();
if (i.get() < n.get()) {
// System.out.println(i.get());
System.out.println(Thread.currentThread().getName());
apiMonitor = apiInfolist.get(i.incrementAndGet());
String url = apiMonitor.getApi_url();
String params = apiMonitor.getParams();
String targetResult = apiMonitor.getResult();
// JSONObject targetJo = JSON.parseObject(targetResult);
String header = apiMonitor.getHeader();
if (apiMonitor.getMethod().equals("POST")) {
if (header.equals("Content-Type:application/json")) {
result = OkHttpUtils.httpPostJson(url, params);
map = check(result, apiMonitor);
} else if (header.equals("Content-Type:application/graphql")) {
String strs[] = header.split("\:");
Map<String, String> map2 = new ConcurrentHashMap<>();
map2.put(strs[0], strs[1]);
result = OkHttpUtils.postDataByGraphql(url, params, map2);
map = check(result, apiMonitor);
}
boolean flag = (boolean) map.get("flag");
if (flag == false) {
System.err.println((String) map.get("message") " 报警 id:" apiMonitor.getApi_id() ";" LocalDateTime.now() ";return result:" result ";extract_variable_value:" apiMonitor.getExtract_variable_value());
} else {
//成功记录日志
//logger.info((String)map.get("message") " success id:" apiMonitor.getApi_id() ";" LocalDateTime.now() ";return result:" result ";extract_variable_value:" apiMonitor.getExtract_variable_value());
}
} else if (apiMonitor.getMethod().equals("GET")) {
if (url.indexOf("?") >= 0) {
url = url "&" params;
} else {
url = url "?" params;
}
result = OkHttpUtils.httpGet(url);
map = check(result, apiMonitor);
}
boolean flag = (boolean) map.get("flag");
if (flag == false) {
System.err.println((String) map.get("message") " 报警 id:" apiMonitor.getApi_id() ";" LocalDateTime.now() ";return result:" result ";extract_variable_value:" apiMonitor.getExtract_variable_value());
} else {
//成功记录日志
//logger.info((String)map.get("message") " success id:" apiMonitor.getApi_id() ";" LocalDateTime.now() ";return result:" result ";extract_variable_value:" apiMonitor.getExtract_variable_value());
}
} else {
// System.out.println("new i before:" i);
// i = new AtomicInteger(0);
// i.incrementAndGet();
}
}
private static HashMap check(String result, ApiMonitor apiMonitor) {
boolean flag = true;
HashMap map = new HashMap();
String message = "";
String extract_variable_value = apiMonitor.getExtract_variable_value();
List<String> valueList = Arrays.asList(extract_variable_value.split("\,"));
JSONObject jo = JSON.parseObject(result);
if (result == null || result.equals("")) {
//报警
flag = false;
message = "resut null 报警:id:";
} else if (extract_variable_value == null || extract_variable_value.equals("")) {
if (jo.getInteger("code") != 1000 && jo.getString("code").equals("1000") == false) {
flag = false;
message = "extract_variable_value null code 1000";
}
} else {
for (int j = 0; j < valueList.size(); j ) {
String extra_value = valueList.get(j);
int pos = result.indexOf(extra_value);
// 创建 Pattern 对象
Pattern r = Pattern.compile(extra_value);
Matcher m = r.matcher(result);
boolean findFlag = m.find();
// boolean isMatch = Pattern.matches(extra_value, result);
if (findFlag == false) {
flag = false;
message = "extract_variable_value compare ";
}
}
}
map.put("flag", flag);
map.put("message", message);
return map;
}
}
OKhttpUtils:
代码语言:javascript复制package io.xx.xx.core.bean;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.util.CollectionUtils;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
/**
* @author
* @since 2020-09-25
*/
public class OkHttpUtils {
private static final Logger log = LoggerFactory.getLogger(OkHttpUtils.class);
private static final String HTTP_JSON = "application/json; charset=utf-8";
private static final String HTTP_GRAPHQL = "application/graphql; charset=utf-8";
private static final String HTTP_FORM = "application/x-www-form-urlencoded; charset=utf-8";
private static final OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(120, TimeUnit.SECONDS)
.readTimeout(120, TimeUnit.SECONDS)
.writeTimeout(120, TimeUnit.SECONDS)
.build();
/**
* get请求
* 对于小文档,响应体上的string()方法非常方便和高效。
* 但是,如果响应主体很大(大于1 MB),则应避免string(),
* 因为它会将整个文档加载到内存中。在这种情况下,将主体处理为流。
*
* @param url
* @return
*/
public static String httpGet(String url) {
if (url == null || "".equals(url)) {
log.error("url为null!");
return "";
}
Request.Builder builder = new Request.Builder();
Request request = builder.get().url(url).build();
try {
Response response = okHttpClient.newCall(request).execute();
if (response.code() == 200) {
log.info("http GET 请求成功; [url={}]", url);
return response.body().string();
} else {
log.warn("Http GET 请求失败; [errorCode = {} , url={}]", response.code(), url);
}
} catch (IOException e) {
throw new RuntimeException("同步http GET 请求失败,url:" url, e);
}
return null;
}
public static String httpGet(String url, Map<String, String> headers) {
if (CollectionUtils.isEmpty(headers)) {
return httpGet(url);
}
Request.Builder builder = new Request.Builder();
headers.forEach((String key, String value) -> builder.header(key, value));
Request request = builder.get().url(url).build();
try {
Response response = okHttpClient.newCall(request).execute();
if (response.code() == 200) {
log.info("http GET 请求成功; [url={}]", url);
return response.body().string();
} else {
log.warn("Http GET 请求失败; [errorxxCode = {} , url={}]", response.code(), url);
}
} catch (IOException e) {
throw new RuntimeException("同步http GET 请求失败,url:" url, e);
}
return null;
}
/**
* 同步 POST调用 无Header
*
* @param url
* @param json
* @return
*/
public static String httpPostJson(String url, String json) {
if (url == null || "".equals(url)) {
log.error("url为null!");
return "";
}
MediaType JSON = MediaType.parse(HTTP_JSON);
RequestBody body = RequestBody.create(JSON, json);
Request.Builder requestBuilder = new Request.Builder().url(url);
Request request = requestBuilder.post(body).build();
try {
Response response = okHttpClient.newCall(request).execute();
if (response.code() == 200) {
log.info("http Post 请求成功; [url={}, requestContent={}]", url, json);
return response.body().string();
} else {
log.warn("Http POST 请求失败; [ errorCode = {}, url={}, param={}]", response.code(), url, json);
}
} catch (IOException e) {
throw new RuntimeException("同步http请求失败,url:" url, e);
}
return null;
}
/**
* 同步 POST调用 有Header
*
* @param url
* @param headers
* @param json
* @return
*/
public static String httpPostJson(String url, Map<String, String> headers, String json) {
if (CollectionUtils.isEmpty(headers)) {
httpPostJson(url, json);
}
MediaType JSON = MediaType.parse(HTTP_JSON);
RequestBody body = RequestBody.create(JSON, json);
Request.Builder requestBuilder = new Request.Builder().url(url);
headers.forEach((k, v) -> requestBuilder.addHeader(k, v));
Request request = requestBuilder.post(body).build();
try {
Response response = okHttpClient.newCall(request).execute();
if (response.code() == 200) {
log.info("http Post 请求成功; [url={}, requestContent={}]", url, json);
return response.body().string();
} else {
log.warn("Http POST 请求失败; [ errorCode = {}, url={}, param={}]", response.code(), url, json);
}
} catch (IOException e) {
throw new RuntimeException("同步http请求失败,url:" url, e);
}
return null;
}
/**
* 提交表单
* @param url
* @param content
* @param headers
* @return
*/
public static String postDataByForm(String url, String content, Map<String, String> headers) {
MediaType JSON = MediaType.parse(HTTP_FORM);
RequestBody body = RequestBody.create(JSON, content);
Request.Builder requestBuilder = new Request.Builder().url(url);
if (headers != null && headers.size() > 0) {
headers.forEach((k, v) -> requestBuilder.addHeader(k, v));
}
Request request = requestBuilder
.post(body)
.build();
Response response = null;
try {
response = okHttpClient.newCall(request).execute();
if (response.code() == 200) {
log.info("postDataByForm; [postUrl={}, requestContent={}, responseCode={}]", url, content, response.code());
return response.body().string();
} else {
log.warn("Http Post Form请求失败,[url={}, param={}]", url, content);
}
} catch (IOException e) {
log.error("Http Post Form请求失败,[url={}, param={}]", url, content, e);
throw new RuntimeException("Http Post Form请求失败,url:" url);
}
return null;
}
public static String postDataByGraphql(String url, String content, Map<String, String> headers) {
MediaType JSON = MediaType.parse(HTTP_GRAPHQL);
RequestBody body = RequestBody.create(JSON, content);
Request.Builder requestBuilder = new Request.Builder().url(url);
if (headers != null && headers.size() > 0) {
headers.forEach((k, v) -> requestBuilder.addHeader(k, v));
}
Request request = requestBuilder
.post(body)
.build();
Response response = null;
try {
response = okHttpClient.newCall(request).execute();
if (response.code() == 200) {
log.info("postDataByForm; [postUrl={}, requestContent={}, responseCode={}]", url, content, response.code());
return response.body().string();
} else {
log.warn("Http Post Form请求失败,[url={}, param={}]", url, content);
}
} catch (IOException e) {
log.error("Http Post Form请求失败,[url={}, param={}]", url, content, e);
throw new RuntimeException("Http Post Form请求失败,url:" url);
}
return null;
}
/**
* 异步Http调用参考模板:Get、Post、Put
* 需要异步调用的接口一般情况下你需要定制一个专门的Http方法
*
* @param httpMethod
* @param url
* @param content
* @return
*/
@Deprecated
public static Future<Boolean> asyncHttpByJson(HttpMethod httpMethod, String url, Map<String, String> headers, String content) {
MediaType JSON = MediaType.parse(HTTP_JSON);
RequestBody body = RequestBody.create(JSON, content);
Request.Builder requestBuilder = new Request.Builder()
.url(url);
if (!CollectionUtils.isEmpty(headers)) {
headers.forEach((key, value) -> requestBuilder.header(key, value));
}
switch (httpMethod) {
case GET:
requestBuilder.get();
break;
case POST:
requestBuilder.post(body);
break;
default:
}
Request request = requestBuilder.build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
log.error("异步http {} 请求失败,[url={}, param={}]", httpMethod.name(), url, content);
throw new RuntimeException("异步http请求失败,url:" url);
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
if (response.code() == 200) {
System.out.println("需要加入异步回调操作");
} else {
log.error("异步http {} 请求失败,错误码为{},请求参数为[url={}, param={}]", httpMethod.name(), response.code(), url, content);
}
}
});
return new AsyncResult(true);
}
/**
* lambda表达式异步调用http模板,不建议使用
*
* @param request
* @param failure
* @param respConsumer
*/
public static void asyncCall(Request request, Consumer<Exception> failure, Consumer<Response> respConsumer) {
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
failure.accept(e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
respConsumer.accept(response);
}
});
}
//test
public static void main(String[] args) {
String url = "http://www.baidu.com";
System.out.println(httpGet(url));
}
}