add client ip info
This commit is contained in:
parent
e5f5e6ca75
commit
4351c0ef03
@ -1,216 +1,216 @@
|
||||
package top.baogutang.admin.schedule;
|
||||
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import cn.hutool.http.Header;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.handler.IJobHandler;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
import top.baogutang.admin.domain.IphoneProductDto;
|
||||
import top.baogutang.admin.utils.DingTalkMsgPushUtils;
|
||||
import top.baogutang.admin.utils.IphoneProductParserUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @description: 苹果库存监控
|
||||
* @author: nikooh
|
||||
* @date: 2023/10/13 : 15:12
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RefreshScope
|
||||
public class AppleInventoryScheduleHandler extends IJobHandler {
|
||||
|
||||
@Value("${baogutang.apple.country_code:cn}")
|
||||
private String countryCode;
|
||||
|
||||
@Value("${baogutang.apple.device_code:17-pro}")
|
||||
private String deviceCode;
|
||||
|
||||
@Value("${baogutang.apple.location:'上海 上海 闵行区'}")
|
||||
private String location;
|
||||
|
||||
@Value("${baogutang.apple.switch:true}")
|
||||
private Boolean appleInventoryMonitorSwitch;
|
||||
|
||||
// @Value("${baogutang.apple.storeList}")
|
||||
private List<String> storeList = new ArrayList<>();
|
||||
|
||||
@Resource
|
||||
private IphoneProductParserUtils iphoneProductParserUtils;
|
||||
|
||||
@Resource
|
||||
private DingTalkMsgPushUtils dingTalkMsgPushUtils;
|
||||
|
||||
@Scheduled(cron = "0 0/1 * * * ? ")
|
||||
public void appleInventoryMonitor() {
|
||||
if (!Boolean.TRUE.equals(appleInventoryMonitorSwitch)) {
|
||||
log.info(">>>>>>>>>>apple inventory monitor switch closed!<<<<<<<<<<");
|
||||
return;
|
||||
}
|
||||
// 获取设备信息
|
||||
List<IphoneProductDto> products = iphoneProductParserUtils.getProducts(deviceCode, countryCode);
|
||||
//监视机型型号
|
||||
products.forEach(product -> {
|
||||
this.doMonitor(product);
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException e) {
|
||||
log.error(">>>>>>>>>>apple inventory monitor error:{}<<<<<<<<<<", e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void doMonitor(IphoneProductDto product) {
|
||||
|
||||
|
||||
Map<String, Object> queryMap = new HashMap<>(5);
|
||||
queryMap.put("pl", "true");
|
||||
queryMap.put("mts.0", "regular");
|
||||
queryMap.put("parts.0", product.getModel());
|
||||
queryMap.put("location", location);
|
||||
|
||||
String baseUrl = String.format("https://www.apple.com.%s", countryCode);
|
||||
Map<String, List<String>> headers = buildHeaders(baseUrl, deviceCode, product.getModel());
|
||||
String url = baseUrl + "/shop/fulfillment-messages?" + URLUtil.buildQuery(queryMap, CharsetUtil.CHARSET_UTF_8);
|
||||
try {
|
||||
HttpResponse httpResponse = HttpRequest.get(url)
|
||||
.header(headers)
|
||||
.execute();
|
||||
if (!httpResponse.isOk()) {
|
||||
log.warn(">>>>>>>>>>请求可能过于频繁,请稍后再试~<<<<<<<<<<");
|
||||
return;
|
||||
}
|
||||
JSONObject responseJsonObject = JSON.parseObject(httpResponse.body());
|
||||
JSONObject pickupMessage = responseJsonObject.getJSONObject("body").getJSONObject("content").getJSONObject("pickupMessage");
|
||||
JSONArray stores = pickupMessage.getJSONArray("stores");
|
||||
if (stores == null) {
|
||||
// log.info(pickupMessage.toString());
|
||||
return;
|
||||
}
|
||||
if (stores.isEmpty()) {
|
||||
log.info("您所在的 {} 附近没有Apple直营店,请检查您的地址是否正确", location);
|
||||
return;
|
||||
}
|
||||
StringBuilder pushContentBuilder = new StringBuilder();
|
||||
List<String> availableStoreNameList = stores.stream()
|
||||
.filter(store -> filterStore((JSONObject) store))
|
||||
.filter(k -> judgingStoreInventory((JSONObject) k, product.getModel()))
|
||||
.map(store -> ((JSONObject) store).getString("storeName")
|
||||
.trim())
|
||||
.collect(Collectors.toList());
|
||||
if (CollectionUtils.isEmpty(availableStoreNameList)) {
|
||||
return;
|
||||
}
|
||||
JSONObject storeJson = (JSONObject) stores.get(0);
|
||||
JSONObject partsAvailability = storeJson.getJSONObject("partsAvailability");
|
||||
String deviceName = partsAvailability.getJSONObject(product.getModel()).getJSONObject("messageTypes").getJSONObject("regular").getString("storePickupProductTitle");
|
||||
pushContentBuilder.append("**")
|
||||
.append(deviceName)
|
||||
.append("**")
|
||||
.append("今天可取货:")
|
||||
.append("<br />");
|
||||
availableStoreNameList.forEach(availableStoreName ->
|
||||
pushContentBuilder.append("**")
|
||||
.append(availableStoreName)
|
||||
.append("** <br />"));
|
||||
dingTalkMsgPushUtils.robotMarkdownMsgPush("苹果商店监控", "前往购买", "https://www.apple.com/" + countryCode + "/shop/buy-iphone/iphone-" + deviceCode, pushContentBuilder.toString());
|
||||
} catch (Exception e) {
|
||||
log.error("AppleMonitor error", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* build request headers
|
||||
*
|
||||
* @param baseUrl base country url
|
||||
* @param productCode product code
|
||||
* @return headers
|
||||
*/
|
||||
private Map<String, List<String>> buildHeaders(String baseUrl, String deviceCode, String productCode) {
|
||||
|
||||
ArrayList<String> referer = new ArrayList<>();
|
||||
referer.add(baseUrl + "/shop/buy-iphone/" + deviceCode + "/" + productCode);
|
||||
|
||||
Map<String, List<String>> headers = new HashMap<>(10);
|
||||
headers.put(Header.REFERER.getValue(), referer);
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
private boolean filterStore(JSONObject storeInfo) {
|
||||
if (CollectionUtils.isEmpty(storeList)) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
String storeName = storeInfo.getString("storeName");
|
||||
return storeList.stream()
|
||||
.anyMatch(k -> storeName.contains(k) || k.contains(storeName));
|
||||
}
|
||||
|
||||
/**
|
||||
* check store inventory
|
||||
*
|
||||
* @param storeJson store json
|
||||
* @param productCode product code
|
||||
* @return boolean
|
||||
*/
|
||||
private boolean judgingStoreInventory(JSONObject storeJson, String productCode) {
|
||||
JSONObject partsAvailability = storeJson.getJSONObject("partsAvailability");
|
||||
String status = partsAvailability.getJSONObject(productCode).getString("pickupDisplay");
|
||||
return "available".equals(status);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* build pickup information
|
||||
*
|
||||
* @param retailStore retailStore
|
||||
* @return pickup message
|
||||
*/
|
||||
private String buildPickupInformation(JSONObject retailStore) {
|
||||
String distanceWithUnit = retailStore.getString("distanceWithUnit");
|
||||
String twoLineAddress = retailStore.getJSONObject("address").getString("twoLineAddress");
|
||||
String daytimePhone = retailStore.getJSONObject("address").getString("daytimePhone");
|
||||
String messageTemplate = "\n取货地址:{},电话:{},距离{}:{}";
|
||||
return CharSequenceUtil.format(messageTemplate, twoLineAddress.replace("\n", " "), daytimePhone, location, distanceWithUnit);
|
||||
}
|
||||
|
||||
@Override
|
||||
@XxlJob("appleInventoryScheduleHandler")
|
||||
public ReturnT<String> execute(String params) throws Exception {
|
||||
if (!Boolean.TRUE.equals(appleInventoryMonitorSwitch)) {
|
||||
log.info(">>>>>>>>>>apple inventory monitor switch closed!<<<<<<<<<<");
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
// 获取设备信息
|
||||
List<IphoneProductDto> products = iphoneProductParserUtils.getProducts(deviceCode, countryCode);
|
||||
//监视机型型号
|
||||
products.forEach(product -> {
|
||||
this.doMonitor(product);
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException e) {
|
||||
log.error(">>>>>>>>>>apple inventory monitor error:{}<<<<<<<<<<", e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
}
|
||||
//package top.baogutang.admin.schedule;
|
||||
//
|
||||
//import cn.hutool.core.text.CharSequenceUtil;
|
||||
//import cn.hutool.core.util.CharsetUtil;
|
||||
//import cn.hutool.core.util.URLUtil;
|
||||
//import cn.hutool.http.Header;
|
||||
//import cn.hutool.http.HttpRequest;
|
||||
//import cn.hutool.http.HttpResponse;
|
||||
//import com.alibaba.fastjson.JSON;
|
||||
//import com.alibaba.fastjson.JSONArray;
|
||||
//import com.alibaba.fastjson.JSONObject;
|
||||
//import com.xxl.job.core.biz.model.ReturnT;
|
||||
//import com.xxl.job.core.handler.IJobHandler;
|
||||
//import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
//import lombok.extern.slf4j.Slf4j;
|
||||
//import org.apache.commons.collections.CollectionUtils;
|
||||
//import org.springframework.beans.factory.annotation.Value;
|
||||
//import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
//import org.springframework.scheduling.annotation.Scheduled;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//import top.baogutang.admin.domain.IphoneProductDto;
|
||||
//import top.baogutang.admin.utils.DingTalkMsgPushUtils;
|
||||
//import top.baogutang.admin.utils.IphoneProductParserUtils;
|
||||
//
|
||||
//import javax.annotation.Resource;
|
||||
//import java.util.ArrayList;
|
||||
//import java.util.HashMap;
|
||||
//import java.util.List;
|
||||
//import java.util.Map;
|
||||
//import java.util.stream.Collectors;
|
||||
//
|
||||
///**
|
||||
// * @description: 苹果库存监控
|
||||
// * @author: nikooh
|
||||
// * @date: 2023/10/13 : 15:12
|
||||
// */
|
||||
//@Slf4j
|
||||
//@Component
|
||||
//@RefreshScope
|
||||
//public class AppleInventoryScheduleHandler extends IJobHandler {
|
||||
//
|
||||
// @Value("${baogutang.apple.country_code:cn}")
|
||||
// private String countryCode;
|
||||
//
|
||||
// @Value("${baogutang.apple.device_code:17-pro}")
|
||||
// private String deviceCode;
|
||||
//
|
||||
// @Value("${baogutang.apple.location:'上海 上海 闵行区'}")
|
||||
// private String location;
|
||||
//
|
||||
// @Value("${baogutang.apple.switch:true}")
|
||||
// private Boolean appleInventoryMonitorSwitch;
|
||||
//
|
||||
// // @Value("${baogutang.apple.storeList}")
|
||||
// private List<String> storeList = new ArrayList<>();
|
||||
//
|
||||
// @Resource
|
||||
// private IphoneProductParserUtils iphoneProductParserUtils;
|
||||
//
|
||||
// @Resource
|
||||
// private DingTalkMsgPushUtils dingTalkMsgPushUtils;
|
||||
//
|
||||
// @Scheduled(cron = "0 0/1 * * * ? ")
|
||||
// public void appleInventoryMonitor() {
|
||||
// if (!Boolean.TRUE.equals(appleInventoryMonitorSwitch)) {
|
||||
// log.info(">>>>>>>>>>apple inventory monitor switch closed!<<<<<<<<<<");
|
||||
// return;
|
||||
// }
|
||||
// // 获取设备信息
|
||||
// List<IphoneProductDto> products = iphoneProductParserUtils.getProducts(deviceCode, countryCode);
|
||||
// //监视机型型号
|
||||
// products.forEach(product -> {
|
||||
// this.doMonitor(product);
|
||||
// try {
|
||||
// Thread.sleep(2000);
|
||||
// } catch (InterruptedException e) {
|
||||
// log.error(">>>>>>>>>>apple inventory monitor error:{}<<<<<<<<<<", e.getMessage(), e);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// private void doMonitor(IphoneProductDto product) {
|
||||
//
|
||||
//
|
||||
// Map<String, Object> queryMap = new HashMap<>(5);
|
||||
// queryMap.put("pl", "true");
|
||||
// queryMap.put("mts.0", "regular");
|
||||
// queryMap.put("parts.0", product.getModel());
|
||||
// queryMap.put("location", location);
|
||||
//
|
||||
// String baseUrl = String.format("https://www.apple.com.%s", countryCode);
|
||||
// Map<String, List<String>> headers = buildHeaders(baseUrl, deviceCode, product.getModel());
|
||||
// String url = baseUrl + "/shop/fulfillment-messages?" + URLUtil.buildQuery(queryMap, CharsetUtil.CHARSET_UTF_8);
|
||||
// try {
|
||||
// HttpResponse httpResponse = HttpRequest.get(url)
|
||||
// .header(headers)
|
||||
// .execute();
|
||||
// if (!httpResponse.isOk()) {
|
||||
// log.warn(">>>>>>>>>>请求可能过于频繁,请稍后再试~<<<<<<<<<<");
|
||||
// return;
|
||||
// }
|
||||
// JSONObject responseJsonObject = JSON.parseObject(httpResponse.body());
|
||||
// JSONObject pickupMessage = responseJsonObject.getJSONObject("body").getJSONObject("content").getJSONObject("pickupMessage");
|
||||
// JSONArray stores = pickupMessage.getJSONArray("stores");
|
||||
// if (stores == null) {
|
||||
//// log.info(pickupMessage.toString());
|
||||
// return;
|
||||
// }
|
||||
// if (stores.isEmpty()) {
|
||||
// log.info("您所在的 {} 附近没有Apple直营店,请检查您的地址是否正确", location);
|
||||
// return;
|
||||
// }
|
||||
// StringBuilder pushContentBuilder = new StringBuilder();
|
||||
// List<String> availableStoreNameList = stores.stream()
|
||||
// .filter(store -> filterStore((JSONObject) store))
|
||||
// .filter(k -> judgingStoreInventory((JSONObject) k, product.getModel()))
|
||||
// .map(store -> ((JSONObject) store).getString("storeName")
|
||||
// .trim())
|
||||
// .collect(Collectors.toList());
|
||||
// if (CollectionUtils.isEmpty(availableStoreNameList)) {
|
||||
// return;
|
||||
// }
|
||||
// JSONObject storeJson = (JSONObject) stores.get(0);
|
||||
// JSONObject partsAvailability = storeJson.getJSONObject("partsAvailability");
|
||||
// String deviceName = partsAvailability.getJSONObject(product.getModel()).getJSONObject("messageTypes").getJSONObject("regular").getString("storePickupProductTitle");
|
||||
// pushContentBuilder.append("**")
|
||||
// .append(deviceName)
|
||||
// .append("**")
|
||||
// .append("今天可取货:")
|
||||
// .append("<br />");
|
||||
// availableStoreNameList.forEach(availableStoreName ->
|
||||
// pushContentBuilder.append("**")
|
||||
// .append(availableStoreName)
|
||||
// .append("** <br />"));
|
||||
// dingTalkMsgPushUtils.robotMarkdownMsgPush("苹果商店监控", "前往购买", "https://www.apple.com/" + countryCode + "/shop/buy-iphone/iphone-" + deviceCode, pushContentBuilder.toString());
|
||||
// } catch (Exception e) {
|
||||
// log.error("AppleMonitor error", e);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * build request headers
|
||||
// *
|
||||
// * @param baseUrl base country url
|
||||
// * @param productCode product code
|
||||
// * @return headers
|
||||
// */
|
||||
// private Map<String, List<String>> buildHeaders(String baseUrl, String deviceCode, String productCode) {
|
||||
//
|
||||
// ArrayList<String> referer = new ArrayList<>();
|
||||
// referer.add(baseUrl + "/shop/buy-iphone/" + deviceCode + "/" + productCode);
|
||||
//
|
||||
// Map<String, List<String>> headers = new HashMap<>(10);
|
||||
// headers.put(Header.REFERER.getValue(), referer);
|
||||
//
|
||||
// return headers;
|
||||
// }
|
||||
//
|
||||
// private boolean filterStore(JSONObject storeInfo) {
|
||||
// if (CollectionUtils.isEmpty(storeList)) {
|
||||
// return Boolean.TRUE;
|
||||
// }
|
||||
// String storeName = storeInfo.getString("storeName");
|
||||
// return storeList.stream()
|
||||
// .anyMatch(k -> storeName.contains(k) || k.contains(storeName));
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * check store inventory
|
||||
// *
|
||||
// * @param storeJson store json
|
||||
// * @param productCode product code
|
||||
// * @return boolean
|
||||
// */
|
||||
// private boolean judgingStoreInventory(JSONObject storeJson, String productCode) {
|
||||
// JSONObject partsAvailability = storeJson.getJSONObject("partsAvailability");
|
||||
// String status = partsAvailability.getJSONObject(productCode).getString("pickupDisplay");
|
||||
// return "available".equals(status);
|
||||
//
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * build pickup information
|
||||
// *
|
||||
// * @param retailStore retailStore
|
||||
// * @return pickup message
|
||||
// */
|
||||
// private String buildPickupInformation(JSONObject retailStore) {
|
||||
// String distanceWithUnit = retailStore.getString("distanceWithUnit");
|
||||
// String twoLineAddress = retailStore.getJSONObject("address").getString("twoLineAddress");
|
||||
// String daytimePhone = retailStore.getJSONObject("address").getString("daytimePhone");
|
||||
// String messageTemplate = "\n取货地址:{},电话:{},距离{}:{}";
|
||||
// return CharSequenceUtil.format(messageTemplate, twoLineAddress.replace("\n", " "), daytimePhone, location, distanceWithUnit);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// @XxlJob("appleInventoryScheduleHandler")
|
||||
// public ReturnT<String> execute(String params) throws Exception {
|
||||
// if (!Boolean.TRUE.equals(appleInventoryMonitorSwitch)) {
|
||||
// log.info(">>>>>>>>>>apple inventory monitor switch closed!<<<<<<<<<<");
|
||||
// return ReturnT.SUCCESS;
|
||||
// }
|
||||
// // 获取设备信息
|
||||
// List<IphoneProductDto> products = iphoneProductParserUtils.getProducts(deviceCode, countryCode);
|
||||
// //监视机型型号
|
||||
// products.forEach(product -> {
|
||||
// this.doMonitor(product);
|
||||
// try {
|
||||
// Thread.sleep(2000);
|
||||
// } catch (InterruptedException e) {
|
||||
// log.error(">>>>>>>>>>apple inventory monitor error:{}<<<<<<<<<<", e.getMessage(), e);
|
||||
// }
|
||||
// });
|
||||
// return ReturnT.SUCCESS;
|
||||
// }
|
||||
//}
|
||||
|
||||
@ -14,6 +14,10 @@ import top.baogutang.common.domain.Results;
|
||||
import top.baogutang.common.utils.JacksonUtil;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import static top.baogutang.common.config.MdcRequestIdFilter.REQUEST_ID_KEY;
|
||||
import static top.baogutang.common.config.MdcRequestIdFilter.CLIENT_IP_KEY;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @description:
|
||||
@ -39,23 +43,36 @@ public class LogAspect {
|
||||
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
|
||||
assert sra != null;
|
||||
HttpServletRequest request = sra.getRequest();
|
||||
String requestId = MDC.get("X-Request-Id");
|
||||
String requestId = MDC.get(REQUEST_ID_KEY);
|
||||
String clientIp = MDC.get(CLIENT_IP_KEY);
|
||||
long startMills = System.currentTimeMillis();
|
||||
long cost = 0;
|
||||
try {
|
||||
result = pjp.proceed();
|
||||
cost = System.currentTimeMillis() - startMills;
|
||||
log.info("请求结束!本次请求耗时:{},url: {}, method: {}, params: {},user:{}, token: {}, 响应结果:{}",
|
||||
cost, request.getRequestURL().toString(),
|
||||
request.getMethod(), pjp.getArgs(), JacksonUtil.toJson(request.getAttribute("user")), request.getHeader("authorization"),
|
||||
log.info("请求结束! client ip:{},本次请求耗时:{},url: {}, method: {}, params: {},user:{}, token: {}, 响应结果:{}",
|
||||
clientIp,
|
||||
cost,
|
||||
request.getRequestURL().toString(),
|
||||
request.getMethod(),
|
||||
pjp.getArgs(),
|
||||
JacksonUtil.toJson(request.getAttribute("user")),
|
||||
request.getHeader("authorization"),
|
||||
JacksonUtil.toJson(result));
|
||||
if (result instanceof Results) {
|
||||
Results r = (Results) result;
|
||||
Results<?> r = (Results<?>) result;
|
||||
r.setRid(requestId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("请求异常!!!本次请求耗时:{},error:{},url: {}, method: {}, params: {},user:{}, token: {}", cost, e, request.getRequestURL().toString(),
|
||||
request.getMethod(), pjp.getArgs(), JacksonUtil.toJson(request.getAttribute("user")), request.getHeader("token"));
|
||||
log.error("请求异常!!! client ip:{},本次请求耗时:{},error:{},url: {}, method: {}, params: {},user:{}, token: {}",
|
||||
clientIp,
|
||||
cost,
|
||||
e.getMessage(),
|
||||
request.getRequestURL().toString(),
|
||||
request.getMethod(),
|
||||
pjp.getArgs(),
|
||||
JacksonUtil.toJson(request.getAttribute("user")),
|
||||
request.getHeader("token"));
|
||||
throw e;
|
||||
}
|
||||
return result;
|
||||
|
||||
@ -23,22 +23,92 @@ import java.util.UUID;
|
||||
@Order(1)
|
||||
public class MdcRequestIdFilter extends OncePerRequestFilter {
|
||||
|
||||
private static final String REQUEST_ID_KEY = "X-Request-Id";
|
||||
public static final String REQUEST_ID_KEY = "X-Request-Id";
|
||||
public static final String CLIENT_IP_KEY = "clientIp";
|
||||
|
||||
// 静态资源后缀列表
|
||||
private static final String[] STATIC_RESOURCES = {
|
||||
".css", ".js", ".jpg", ".jpeg", ".png", ".gif", ".ico", ".svg", ".woff", ".woff2", ".ttf", ".eot", ".map", ".gz", ".rar", ".zip", ".7z", ".pdf",
|
||||
".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".txt", ".mp3", ".mp4", ".avi", ".wmv", ".flv", ".swf", ".exe", ".dll", ".ico", ".psd", ".ai",
|
||||
".eps", ".svg", ".ttf", ".woff", ".woff2", ".eot", ".otf", ".otc", ".ttc", ".ttf", ".woff", ".woff2", ".eot", ".otf", "json"
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
// 判断是否为静态资源请求
|
||||
String uri = request.getRequestURI();
|
||||
if (isStaticResource(uri)) {
|
||||
// 静态资源请求直接放行,不处理
|
||||
filterChain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 获取真实客户端IP
|
||||
String clientIp = getClientIp(request);
|
||||
MDC.put(CLIENT_IP_KEY, clientIp);
|
||||
String traceId = request.getHeader(REQUEST_ID_KEY);
|
||||
if (traceId == null) {
|
||||
traceId = UUID.randomUUID().toString().replace("-", "");
|
||||
log.info("requestId为空,自动生成 {}", traceId);
|
||||
log.info("requestId为空,自动生成 {}, client ip: {}", traceId, clientIp);
|
||||
request.setAttribute(REQUEST_ID_KEY, traceId);
|
||||
}
|
||||
MDC.put(REQUEST_ID_KEY, traceId);
|
||||
filterChain.doFilter(request, response);
|
||||
} finally {
|
||||
MDC.remove(REQUEST_ID_KEY);
|
||||
MDC.remove(CLIENT_IP_KEY);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为静态资源请求
|
||||
*/
|
||||
private boolean isStaticResource(String uri) {
|
||||
if (uri == null || uri.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String lowerUri = uri.toLowerCase();
|
||||
for (String suffix : STATIC_RESOURCES) {
|
||||
if (lowerUri.endsWith(suffix)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端真实IP地址
|
||||
* 优先从代理请求头中获取,如果没有则使用remoteAddr
|
||||
*/
|
||||
private String getClientIp(HttpServletRequest request) {
|
||||
String ip = request.getHeader("X-Forwarded-For");
|
||||
if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
|
||||
// X-Forwarded-For可能包含多个IP,取第一个
|
||||
if (ip.indexOf(",") > 0) {
|
||||
ip = ip.substring(0, ip.indexOf(","));
|
||||
}
|
||||
return ip.trim();
|
||||
}
|
||||
|
||||
ip = request.getHeader("X-Real-IP");
|
||||
if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
|
||||
return ip.trim();
|
||||
}
|
||||
|
||||
ip = request.getHeader("Proxy-Client-IP");
|
||||
if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
|
||||
return ip.trim();
|
||||
}
|
||||
|
||||
ip = request.getHeader("WL-Proxy-Client-IP");
|
||||
if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
|
||||
return ip.trim();
|
||||
}
|
||||
|
||||
// 如果所有代理头都没有,使用remoteAddr
|
||||
return request.getRemoteAddr();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user