feat:getStoreXinFaDeviceDetail
This commit is contained in:
@@ -283,4 +283,10 @@ public class RedisConstant {
|
|||||||
public static final String SUBMIT_BUILD_KEY = "submit_build_key_";
|
public static final String SUBMIT_BUILD_KEY = "submit_build_key_";
|
||||||
|
|
||||||
public static final String GET_AI_MODULE = "get_ai_module_";
|
public static final String GET_AI_MODULE = "get_ai_module_";
|
||||||
|
|
||||||
|
public static final String HUOMA_STORE_DEVICE_RESOURCE_KEY = "huoma_store_device_resource";
|
||||||
|
|
||||||
|
public static final String HUO_MA_STORE_ID = "huo_ma_store_id";
|
||||||
|
|
||||||
|
public static final String HUO_MA_TOKEN= "huo_ma_token:{0}";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package com.cool.store.utils;
|
||||||
|
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/4 17:34
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
public class BrowserVersionUtils {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检测是否为旧版Chrome浏览器(版本小于60)
|
||||||
|
* @param userAgent 浏览器User-Agent字符串
|
||||||
|
* @return true-是旧版Chrome,false-不是旧版Chrome
|
||||||
|
*/
|
||||||
|
public static boolean isOldChromeBrowser(String userAgent) {
|
||||||
|
if (userAgent == null || userAgent.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否是Chrome浏览器
|
||||||
|
if (!userAgent.contains("Chrome")) {
|
||||||
|
return false; // 不是Chrome浏览器
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取Chrome版本号
|
||||||
|
Integer chromeVersion = extractChromeVersion(userAgent);
|
||||||
|
|
||||||
|
if (chromeVersion == null) {
|
||||||
|
return false; // 无法提取版本号
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断版本是否小于60
|
||||||
|
return chromeVersion < 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从User-Agent中提取Chrome主版本号
|
||||||
|
* @param userAgent 浏览器User-Agent字符串
|
||||||
|
* @return Chrome主版本号,如果无法提取返回null
|
||||||
|
*/
|
||||||
|
public static Integer extractChromeVersion(String userAgent) {
|
||||||
|
// 正则表达式匹配 Chrome/版本号 模式
|
||||||
|
Pattern pattern = Pattern.compile("Chrome/(\\d+)");
|
||||||
|
Matcher matcher = pattern.matcher(userAgent);
|
||||||
|
|
||||||
|
if (matcher.find()) {
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(matcher.group(1));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
System.err.println("版本号格式错误: " + matcher.group(1));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package com.cool.store.dto.huoma;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 火码账号DTO
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author wangff
|
||||||
|
* @since 2025/9/23
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class HuoMaAccountDTO {
|
||||||
|
/**
|
||||||
|
* 账号
|
||||||
|
*/
|
||||||
|
private String account;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密码
|
||||||
|
*/
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否已查询
|
||||||
|
*/
|
||||||
|
private Boolean isQuery;
|
||||||
|
|
||||||
|
public HuoMaAccountDTO(String account, String password) {
|
||||||
|
this.account = account;
|
||||||
|
this.password = password;
|
||||||
|
this.isQuery = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package com.cool.store.dto.huoma;
|
||||||
|
|
||||||
|
import com.cool.store.utils.BrowserVersionUtils;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: WangShuo
|
||||||
|
* @Date: 2025/08/13/16:24
|
||||||
|
* @Version 1.0
|
||||||
|
* @注释:
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class StoreEquipmentDTO {
|
||||||
|
/**
|
||||||
|
* 已授权登录数
|
||||||
|
*/
|
||||||
|
private Integer activeCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 总设备
|
||||||
|
*/
|
||||||
|
private Integer terminalCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网点ID
|
||||||
|
*/
|
||||||
|
private Integer pointId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网点号
|
||||||
|
*/
|
||||||
|
private String pointCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 签到数
|
||||||
|
*/
|
||||||
|
private Integer signCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在线
|
||||||
|
*/
|
||||||
|
|
||||||
|
private Integer connectCount;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
StoreEquipmentDTO that = (StoreEquipmentDTO) o;
|
||||||
|
return Objects.equals(pointCode, that.pointCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(pointCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.cool.store.dto.huoma;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/8/18 16:00
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class StoreRequestDTO {
|
||||||
|
|
||||||
|
private String reportCode;
|
||||||
|
|
||||||
|
private Integer index;
|
||||||
|
|
||||||
|
private Integer size;
|
||||||
|
|
||||||
|
private Params params;
|
||||||
|
|
||||||
|
public StoreRequestDTO(String reportCode, Integer index, Integer size, String shopCode) {
|
||||||
|
this.reportCode = reportCode;
|
||||||
|
this.index = index;
|
||||||
|
this.size = size;
|
||||||
|
this.params = new Params(shopCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
static class Params{
|
||||||
|
private String inputText_2;
|
||||||
|
|
||||||
|
public Params(String inputText_2) {
|
||||||
|
this.inputText_2 = inputText_2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.cool.store.dto.huoma;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/8/18 16:38
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class StoreXinFaDetailRequestDTO {
|
||||||
|
|
||||||
|
private Integer index;
|
||||||
|
|
||||||
|
private Integer size;
|
||||||
|
|
||||||
|
private Integer pointId;
|
||||||
|
|
||||||
|
public StoreXinFaDetailRequestDTO(Integer index, Integer size, Integer pointId) {
|
||||||
|
this.index = index;
|
||||||
|
this.size = size;
|
||||||
|
this.pointId = pointId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package com.cool.store.dto.huoma;
|
||||||
|
|
||||||
|
import com.cool.store.utils.BrowserVersionUtils;
|
||||||
|
import com.cool.store.utils.StringUtil;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/8/18 16:27
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class StoreXinFaDeviceDetail {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备ID
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "设备ID")
|
||||||
|
private String deviceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备名称
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "设备名称")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备连接状态 0:未连接 1:已连接
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "设备连接状态 false:未连接 true:已连接")
|
||||||
|
private Boolean isConnect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备总内存
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "设备总内存")
|
||||||
|
private String totalRam;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备可用内存
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "设备可用内存")
|
||||||
|
private String availRam;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备浏览器信息
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "设备浏览器信息")
|
||||||
|
private String userAgent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内用内存小于300M 或者 浏览器版本小于60
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "内用内存小于300M 或者 浏览器版本小于60")
|
||||||
|
private Boolean flag;
|
||||||
|
|
||||||
|
public boolean getFlag() {
|
||||||
|
if (StringUtil.isEmpty(availRam)||StringUtil.isEmpty(userAgent)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Boolean isOldChromeBrowser = BrowserVersionUtils.isOldChromeBrowser(userAgent);
|
||||||
|
long availableMemoryMB = Long.parseLong(availRam) / (1024 * 1024);
|
||||||
|
return availableMemoryMB < 300 || isOldChromeBrowser;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.cool.store.dto.huoma;
|
||||||
|
|
||||||
|
import io.swagger.models.auth.In;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/5 9:33
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class TagDTO {
|
||||||
|
|
||||||
|
private String channelType;
|
||||||
|
|
||||||
|
private Integer index;
|
||||||
|
|
||||||
|
private Integer size;
|
||||||
|
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
public TagDTO(String channelType, Integer index, Integer size, String type) {
|
||||||
|
this.channelType = channelType;
|
||||||
|
this.index = index;
|
||||||
|
this.size = size;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.cool.store.dto.huoma;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/5 9:41
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class TagDetailDTO {
|
||||||
|
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,383 @@
|
|||||||
|
package com.cool.store.service.xinfa;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.cool.store.constants.RedisConstant;
|
||||||
|
import com.cool.store.dto.huoma.*;
|
||||||
|
import com.cool.store.enums.ErrorCodeEnum;
|
||||||
|
import com.cool.store.exception.ServiceException;
|
||||||
|
import com.cool.store.utils.RedisUtilPool;
|
||||||
|
import com.cool.store.utils.poi.constant.Constants;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import okhttp3.*;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/4 15:47
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class XinFaDeviceService {
|
||||||
|
|
||||||
|
@Value("${huoMa.direct.stores.account}")
|
||||||
|
private String huoMaDirectStoresAccount;
|
||||||
|
@Value("${huoMa.direct.stores.password}")
|
||||||
|
private String huoMaDirectStoresPassword;
|
||||||
|
@Value("${huoMa.franchise.stores.account}")
|
||||||
|
private String huoMaFranchiseStoresAccount;
|
||||||
|
@Value("${huoMa.franchise.stores.password}")
|
||||||
|
private String huoMaFranchiseStoresPassword;
|
||||||
|
@Value("${huoMa.restaurant.stores.account}")
|
||||||
|
private String huoMaRestaurantStoresAccount;
|
||||||
|
@Value("${huoMa.restaurant.stores.password}")
|
||||||
|
private String huoMaRestaurantStoresPassword;
|
||||||
|
@Resource
|
||||||
|
RedisUtilPool redisUtilPool;
|
||||||
|
@Value("${huoMa.token.url}")
|
||||||
|
private String huoMaTokenUrl;
|
||||||
|
@Value("${huoMa.get.point.terminal.url}")
|
||||||
|
private String huoMaGetPointTerminalUrl;
|
||||||
|
@Value("${huoMa.id.url}")
|
||||||
|
private String huoMaGetStoreIdUrl;
|
||||||
|
@Value("${huoMa.store.device.detail.url}")
|
||||||
|
private String huoMaGetStoreXinFaDeviceDetailUrl ;
|
||||||
|
@Value("${huoMa.get.tag.url }")
|
||||||
|
private String huoMaGetTagUrl;
|
||||||
|
|
||||||
|
|
||||||
|
private final Map<String, HuoMaAccountDTO> accountMap = new HashMap<>();
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void initAccountMap() {
|
||||||
|
accountMap.put("restaurant", new HuoMaAccountDTO(huoMaRestaurantStoresAccount, huoMaRestaurantStoresPassword));
|
||||||
|
accountMap.put("direct", new HuoMaAccountDTO(huoMaDirectStoresAccount, huoMaDirectStoresPassword));
|
||||||
|
accountMap.put("franchise", new HuoMaAccountDTO(huoMaFranchiseStoresAccount, huoMaFranchiseStoresPassword));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStoreToken(String account, String password) {
|
||||||
|
String key = MessageFormat.format(RedisConstant.HUO_MA_TOKEN, account);
|
||||||
|
String accessToken = redisUtilPool.getString(key);
|
||||||
|
if (accessToken != null) {
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
Map<String, String> requestBody = new HashMap<>();
|
||||||
|
requestBody.put("account", account);
|
||||||
|
requestBody.put("password", password);
|
||||||
|
String responseBody = sendPostRequest(JSONObject.toJSONString(requestBody), huoMaTokenUrl);
|
||||||
|
try{
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
JsonNode rootNode = mapper.readTree(responseBody);
|
||||||
|
String token = rootNode.path("data").path("token").asText();
|
||||||
|
//缓存60秒
|
||||||
|
redisUtilPool.setString(key, token,60*60);
|
||||||
|
return token;
|
||||||
|
}catch (Exception e){
|
||||||
|
log.error("解析获取token失败,url:{},responseBody:{}",huoMaTokenUrl, responseBody);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<StoreEquipmentDTO> getStoreEquipmentDataByStoreNumList(List<String> storeNumList, String token) {
|
||||||
|
Map<String,List<String>> requestBody = new HashMap<>();
|
||||||
|
requestBody.put("codeList", storeNumList);
|
||||||
|
String responseBody = sendPostRequestByToken(JSONObject.toJSONString(requestBody), huoMaGetPointTerminalUrl,token);
|
||||||
|
try{
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
JsonNode rootNode = mapper.readTree(responseBody);
|
||||||
|
return mapper.convertValue(rootNode.get("data"),
|
||||||
|
mapper.getTypeFactory().constructCollectionType(List.class, StoreEquipmentDTO.class));
|
||||||
|
}catch (Exception e){
|
||||||
|
log.error("解析获取data失败,url:{},responseBody:{}",huoMaTokenUrl, responseBody);
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public Integer getStoreIdByStoreNum(String storeNum, String token) {
|
||||||
|
String houMaStoreId = redisUtilPool.hashGet(RedisConstant.HUO_MA_STORE_ID, storeNum);
|
||||||
|
if (houMaStoreId != null) {
|
||||||
|
try {
|
||||||
|
return Integer.valueOf(houMaStoreId);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
// 如果缓存中的数据格式不正确,继续执行正常逻辑
|
||||||
|
log.warn("Redis缓存中的门店ID格式不正确,storeNum: {}", storeNum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StoreRequestDTO requestBody = new StoreRequestDTO("point_report", 0, 10, storeNum);
|
||||||
|
String responseBody = sendPostRequestByToken(JSONObject.toJSONString(requestBody), huoMaGetStoreIdUrl,token);
|
||||||
|
try{
|
||||||
|
Integer storeId = extractIdsFromResponse(responseBody);
|
||||||
|
redisUtilPool.hashSet(RedisConstant.HUO_MA_STORE_ID, storeNum, storeId.toString());
|
||||||
|
return storeId;
|
||||||
|
}catch (Exception e){
|
||||||
|
log.error("解析获取data失败,url:{},responseBody:{}",huoMaTokenUrl, responseBody);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<StoreXinFaDeviceDetail> getStoreXinFaDeviceDetail(String storeNum) {
|
||||||
|
String source = redisUtilPool.hashGet(RedisConstant.HUOMA_STORE_DEVICE_RESOURCE_KEY, storeNum);
|
||||||
|
if (StringUtils.isNotBlank(source)) {
|
||||||
|
HuoMaAccountDTO huoMaAccountDTO = accountMap.get(source);
|
||||||
|
if (Objects.nonNull(huoMaAccountDTO)) {
|
||||||
|
String token = getStoreToken(huoMaAccountDTO.getAccount(), huoMaAccountDTO.getPassword());
|
||||||
|
List<StoreXinFaDeviceDetail> deviceDetailDetail = getStoreXinFaDeviceDetailDetail(storeNum, token);
|
||||||
|
if (CollectionUtils.isNotEmpty(deviceDetailDetail)) {
|
||||||
|
return deviceDetailDetail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Map.Entry<String, HuoMaAccountDTO> entry : accountMap.entrySet()) {
|
||||||
|
HuoMaAccountDTO huoMaAccountDTO = entry.getValue();
|
||||||
|
if (!huoMaAccountDTO.getIsQuery()) {
|
||||||
|
String token = getStoreToken(huoMaAccountDTO.getAccount(), huoMaAccountDTO.getPassword());
|
||||||
|
List<StoreXinFaDeviceDetail> deviceDetailDetail = getStoreXinFaDeviceDetailDetail(storeNum, token);
|
||||||
|
if (CollectionUtils.isNotEmpty(deviceDetailDetail)) {
|
||||||
|
redisUtilPool.hashSet(RedisConstant.HUOMA_STORE_DEVICE_RESOURCE_KEY, storeNum, entry.getKey(), Constants.REFRESH_TOKEN_EXPIRE);
|
||||||
|
return deviceDetailDetail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<StoreXinFaDeviceDetail> getStoreXinFaDeviceDetailDetail(String storeNum, String token) {
|
||||||
|
Integer storeIdByStoreNum = getStoreIdByStoreNum(storeNum, token);
|
||||||
|
return getStoreXinFaDeviceDetailByPointId(storeIdByStoreNum, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<TagDetailDTO> getAccountAllTags(String storeNum){
|
||||||
|
String source = redisUtilPool.hashGet(RedisConstant.HUOMA_STORE_DEVICE_RESOURCE_KEY, storeNum);
|
||||||
|
//获取标签 必须要知道门店属于哪个账号下 获取对应账号下的标签 如果获取不到 直接返回空
|
||||||
|
if (StringUtils.isEmpty(source)){
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
HuoMaAccountDTO huoMaAccountDTO = accountMap.get(source);
|
||||||
|
if (Objects.nonNull(huoMaAccountDTO)){
|
||||||
|
huoMaAccountDTO.setIsQuery(true);
|
||||||
|
String token = getStoreToken(huoMaAccountDTO.getAccount(), huoMaAccountDTO.getPassword());
|
||||||
|
return getAccountAllTags(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<StoreXinFaDeviceDetail> getStoreXinFaDeviceDetailByPointId(Integer pointId, String token) {
|
||||||
|
if (pointId != null){
|
||||||
|
StoreXinFaDetailRequestDTO storeXinFaDetailRequestDTO = new StoreXinFaDetailRequestDTO(0, 10, pointId);
|
||||||
|
String responseBody = null;
|
||||||
|
try{
|
||||||
|
responseBody = sendPostRequestByToken(JSONObject.toJSONString(storeXinFaDetailRequestDTO), huoMaGetStoreXinFaDeviceDetailUrl,token);
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
JsonNode rootNode = mapper.readTree(responseBody);
|
||||||
|
|
||||||
|
// 直接转换整个数组
|
||||||
|
return mapper.convertValue(
|
||||||
|
rootNode.path("data").path("content"),
|
||||||
|
mapper.getTypeFactory().constructCollectionType(List.class, StoreXinFaDeviceDetail.class)
|
||||||
|
);
|
||||||
|
}catch (Exception e){
|
||||||
|
log.error("getStoreXinFaDeviceDetailByPointId解析获取data失败,url:{},responseBody:{}",huoMaTokenUrl, responseBody);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer extractIdsFromResponse(String jsonResponse) throws IOException {
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
JsonNode rootNode = mapper.readTree(jsonResponse);
|
||||||
|
// 遍历dataList数组提取ID
|
||||||
|
JsonNode dataList = rootNode.path("data").path("dataList");
|
||||||
|
for (JsonNode item : dataList) {
|
||||||
|
if (item.has("ID")) {
|
||||||
|
//取出第一个id
|
||||||
|
return item.get("ID").asInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String sendPostRequest(String requestBody, String requestUrl) {
|
||||||
|
log.info("开始发送请求,url:{},requestBody:{}", requestUrl, requestBody);
|
||||||
|
|
||||||
|
int maxRetries = 3;
|
||||||
|
for (int i = 0; i < maxRetries; i++) {
|
||||||
|
try {
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(requestUrl)
|
||||||
|
.post(RequestBody.create(MediaType.parse("application/json"), requestBody))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return sendPost(requestUrl, request);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("请求失败,第{}次重试,错误: {}", i + 1, e.getMessage());
|
||||||
|
if (i == maxRetries - 1) {
|
||||||
|
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "请求重试失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
// 重试前等待
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000 * (i + 1));
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "重试被中断");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "请求重试失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String sendPostRequestByToken(String requestBody, String requestUrl, String token) {
|
||||||
|
log.info("开始发送请求,url:{},requestBody:{}", requestUrl, requestBody);
|
||||||
|
|
||||||
|
int maxRetries = 3;
|
||||||
|
for (int i = 0; i < maxRetries; i++) {
|
||||||
|
try {
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(requestUrl)
|
||||||
|
.post(RequestBody.create(MediaType.parse("application/json"), requestBody))
|
||||||
|
.addHeader("token", token)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
String result = sendPost(requestUrl, request);
|
||||||
|
|
||||||
|
// 检查是否token失效
|
||||||
|
if (isTokenExpired(result)) {
|
||||||
|
log.warn("Token已失效,正在清除缓存并重试,第{}次", i + 1);
|
||||||
|
// 直接清除对应账号的token缓存
|
||||||
|
token = clearAccountTokenCacheForToken(token);
|
||||||
|
|
||||||
|
// 抛出异常触发重试
|
||||||
|
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "Token失效,需要重试");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch (ServiceException e) {
|
||||||
|
log.warn("请求失败,第{}次重试,错误: {}", i + 1, e.getMessage());
|
||||||
|
if (i == maxRetries - 1) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000 * (i + 1));
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "重试被中断");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("请求异常,第{}次重试,错误: {}", i + 1, e.getMessage());
|
||||||
|
if (i == maxRetries - 1) {
|
||||||
|
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "请求重试失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000 * (20*i + 1));
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "重试被中断");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "请求重试失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTokenExpired(String responseBody) {
|
||||||
|
try {
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
JsonNode rootNode = mapper.readTree(responseBody);
|
||||||
|
int code = rootNode.path("code").asInt(-1);
|
||||||
|
String msg = rootNode.path("msg").asText("");
|
||||||
|
|
||||||
|
return code == 501;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("检查token失效状态时发生错误: {}", e.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String clearAccountTokenCacheForToken(String token) {
|
||||||
|
try {
|
||||||
|
// 遍历可能的账号,找到对应的缓存并删除
|
||||||
|
String[] accounts = {
|
||||||
|
huoMaDirectStoresAccount,
|
||||||
|
huoMaFranchiseStoresAccount,
|
||||||
|
huoMaRestaurantStoresAccount
|
||||||
|
};
|
||||||
|
|
||||||
|
for (String account : accounts) {
|
||||||
|
if (account != null) {
|
||||||
|
String key = MessageFormat.format(RedisConstant.HUO_MA_TOKEN, account);
|
||||||
|
String cachedToken = redisUtilPool.getString(key);
|
||||||
|
if (token.equals(cachedToken)) {
|
||||||
|
redisUtilPool.delKey(key);
|
||||||
|
log.info("已清除账号 {} 的token缓存", account);
|
||||||
|
|
||||||
|
// 根据账号类型获取对应的密码并重新获取token
|
||||||
|
String password = getPasswordForAccount(account);
|
||||||
|
if (password != null) {
|
||||||
|
String newToken = getStoreToken(account, password);
|
||||||
|
if (newToken != null) {
|
||||||
|
log.info("已为账号 {} 重新获取新的token", account);
|
||||||
|
return newToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("清除token缓存或重新获取token失败: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String getPasswordForAccount(String account) {
|
||||||
|
if (account.equals(huoMaDirectStoresAccount)) {
|
||||||
|
return huoMaDirectStoresPassword;
|
||||||
|
} else if (account.equals(huoMaFranchiseStoresAccount)) {
|
||||||
|
return huoMaFranchiseStoresPassword;
|
||||||
|
} else if (account.equals(huoMaRestaurantStoresAccount)) {
|
||||||
|
return huoMaRestaurantStoresPassword;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static String sendPost(String requestUrl, Request request) {
|
||||||
|
try (Response response = new OkHttpClient().newCall(request).execute()) {
|
||||||
|
log.info("发起请求 time:{}", System.currentTimeMillis());
|
||||||
|
if (!response.isSuccessful()) {
|
||||||
|
log.info("HTTP请求失败,msg: " + response.message());
|
||||||
|
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR,
|
||||||
|
"HTTP请求失败,状态码: " + response.code());
|
||||||
|
}
|
||||||
|
String responseBody = response.body().string();
|
||||||
|
log.info("请求成功responseBody:{}", JSONObject.toJSONString(responseBody));
|
||||||
|
return responseBody;
|
||||||
|
} catch (ServiceException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("API调用异常 - URL: {}, 错误: {}", requestUrl, e.getMessage(), e);
|
||||||
|
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "接口调用异常: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -220,4 +220,6 @@ public class Constants
|
|||||||
|
|
||||||
public static final String WANG_LEI_JOB_NUMBER = "19060164";
|
public static final String WANG_LEI_JOB_NUMBER = "19060164";
|
||||||
|
|
||||||
|
public static final int REFRESH_TOKEN_EXPIRE = 60*60*24*30;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import com.cool.store.dto.FoodTokenDTO;
|
|||||||
import com.cool.store.dto.GetAccessTokenDTO;
|
import com.cool.store.dto.GetAccessTokenDTO;
|
||||||
import com.cool.store.dto.HqtTokenDTO;
|
import com.cool.store.dto.HqtTokenDTO;
|
||||||
import com.cool.store.dto.ModifyPasswordDTO;
|
import com.cool.store.dto.ModifyPasswordDTO;
|
||||||
|
import com.cool.store.dto.huoma.StoreXinFaDeviceDetail;
|
||||||
import com.cool.store.dto.wechat.CallbackMessageDTO;
|
import com.cool.store.dto.wechat.CallbackMessageDTO;
|
||||||
import com.cool.store.dto.wechat.WechatTemplateMessageDTO;
|
import com.cool.store.dto.wechat.WechatTemplateMessageDTO;
|
||||||
import com.cool.store.entity.*;
|
import com.cool.store.entity.*;
|
||||||
@@ -41,6 +42,7 @@ import com.cool.store.service.impl.CommonService;
|
|||||||
import com.cool.store.service.impl.OrderSysInfoServiceImpl;
|
import com.cool.store.service.impl.OrderSysInfoServiceImpl;
|
||||||
import com.cool.store.service.impl.UserAuthMappingServiceImpl;
|
import com.cool.store.service.impl.UserAuthMappingServiceImpl;
|
||||||
import com.cool.store.service.wechat.WechatTemplateService;
|
import com.cool.store.service.wechat.WechatTemplateService;
|
||||||
|
import com.cool.store.service.xinfa.XinFaDeviceService;
|
||||||
import com.cool.store.utils.CoolDateUtils;
|
import com.cool.store.utils.CoolDateUtils;
|
||||||
import com.cool.store.utils.RedisConstantUtil;
|
import com.cool.store.utils.RedisConstantUtil;
|
||||||
import com.cool.store.utils.RedisUtilPool;
|
import com.cool.store.utils.RedisUtilPool;
|
||||||
@@ -605,5 +607,13 @@ public class PCTestController {
|
|||||||
return ApiResponse.success(true);
|
return ApiResponse.success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
XinFaDeviceService xinFaDeviceService;
|
||||||
|
@ApiOperation("测试门店设备信息")
|
||||||
|
@GetMapping("/getStoreXinFaDeviceDetail")
|
||||||
|
public ResponseResult<List<StoreXinFaDeviceDetail>> getStoreXinFaDeviceDetail(@RequestParam("shopId")String storeNum) {
|
||||||
|
return ResponseResult.success(xinFaDeviceService.getStoreXinFaDeviceDetail(storeNum));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,4 +141,15 @@ hqt.token.client.secret=rYe9Cwug5LwQNIBJAiW0a7weF9CAhYCD
|
|||||||
wechat.mp.appId=wx4a18ef8bb41aa55c
|
wechat.mp.appId=wx4a18ef8bb41aa55c
|
||||||
wechat.mp.appSecret=793904b58f4ecdead3bbe4312c5f5c45
|
wechat.mp.appSecret=793904b58f4ecdead3bbe4312c5f5c45
|
||||||
#xiaochengxu appid
|
#xiaochengxu appid
|
||||||
wechat.miniapp.appId=wxd77a2761c1911ee1
|
wechat.miniapp.appId=wxd77a2761c1911ee1
|
||||||
|
|
||||||
|
huoMa.token.url = https://www.huoMayunping.com/api/SAASLogin/merchant
|
||||||
|
huoMa.id.url = https://www.huomayunping.com/api/reportCenter/executeSql
|
||||||
|
huoMa.store.device.detail.url = https://www.huomayunping.com/api/terminal/search
|
||||||
|
huoMa.get.point.terminal.url = https://www.huoMayunping.com/api/terminal/getPointTerminalInfos
|
||||||
|
huoMa.direct.stores.account = 15370309163
|
||||||
|
huoMa.direct.stores.password = Zx@123456.
|
||||||
|
huoMa.franchise.stores.account = 13563273279
|
||||||
|
huoMa.franchise.stores.password = Zx@123456.
|
||||||
|
huoMa.restaurant.stores.account = 18656552865
|
||||||
|
huoMa.restaurant.stores.password = ZX123456
|
||||||
|
|||||||
@@ -154,3 +154,16 @@ wechat.miniapp.appId=wxd77a2761c1911ee1
|
|||||||
|
|
||||||
zx.iot.appId=p-ts3PhNyf
|
zx.iot.appId=p-ts3PhNyf
|
||||||
zx.iot.appSecret=X4cVmfxM+
|
zx.iot.appSecret=X4cVmfxM+
|
||||||
|
|
||||||
|
|
||||||
|
huoMa.token.url = https://www.huoMayunping.com/api/SAASLogin/merchant
|
||||||
|
huoMa.id.url = https://www.huomayunping.com/api/reportCenter/executeSql
|
||||||
|
huoMa.store.device.detail.url = https://www.huomayunping.com/api/terminal/search
|
||||||
|
huoMa.get.point.terminal.url = https://www.huoMayunping.com/api/terminal/getPointTerminalInfos
|
||||||
|
huoMa.get.tag.url = https://www.huomayunping.com/api/tag/search
|
||||||
|
huoMa.direct.stores.account = 15370309163
|
||||||
|
huoMa.direct.stores.password = Zx@123456.
|
||||||
|
huoMa.franchise.stores.account = 13563273279
|
||||||
|
huoMa.franchise.stores.password = Zx@123456.
|
||||||
|
huoMa.restaurant.stores.account = 18656552865
|
||||||
|
huoMa.restaurant.stores.password = ZX123456
|
||||||
|
|||||||
Reference in New Issue
Block a user