feat(system): 新增方舟账号管理与任务接口

- 新增 MarkController 控制器,提供方舟任务列表获取和新建任务接口
- 实现 IMarkService 接口及 MarkServiceImpl 实现类,支持注册、登录和MD5加密功能
- 在 CacheConstants 中添加方舟账号 Redis key 常量
- 集成 RestTemplate用于调用方舟API,支持自动注册与登录机制- 添加文件上传支持,用于新建任务时提交文件
- 实现 token 失效自动重新登录逻辑,确保接口调用稳定性
This commit is contained in:
2025-10-30 13:55:07 +08:00
parent d0a930d4f2
commit 87a4a2fed0
16 changed files with 423 additions and 69 deletions

View File

@@ -1,5 +1,5 @@
package com.tashow.erp.config; package com.tashow.erp.config;
import com.tashow.erp.utils.SeleniumStealthUtil; import com.tashow.erp.utils.SeleniumUtil;
import jakarta.annotation.PreDestroy; import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeDriver;
@@ -23,14 +23,14 @@ public class ChromeDriverPreloader implements ApplicationRunner {
@Override @Override
public void run(ApplicationArguments args) { public void run(ApplicationArguments args) {
new Thread(() -> { new Thread(() -> {
globalDriver = SeleniumStealthUtil.createDriver(true); globalDriver = SeleniumUtil.createDriver(true);
log.info("ChromeDriver 预加载完成"); log.info("ChromeDriver 预加载完成");
}, "ChromeDriver-Preloader").start(); }, "ChromeDriver-Preloader").start();
} }
@Bean @Bean
public ChromeDriver chromeDriver() { public ChromeDriver chromeDriver() {
if (globalDriver == null) globalDriver = SeleniumStealthUtil.createDriver(true); if (globalDriver == null) globalDriver = SeleniumUtil.createDriver(true);
return globalDriver; return globalDriver;
} }

View File

@@ -14,6 +14,12 @@ import jakarta.servlet.http.HttpServletRequest;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
/**
* 亚马逊数据控制器
* 提供亚马逊商品采集、批量获取、Excel导入等功能
*
* @author 占子杰牛逼
*/
@RestController @RestController
@RequestMapping("/api/amazon") @RequestMapping("/api/amazon")
public class AmazonController { public class AmazonController {
@@ -23,6 +29,13 @@ public class AmazonController {
@Autowired @Autowired
private AmazonProductRepository amazonProductRepository; private AmazonProductRepository amazonProductRepository;
/**
* 批量获取亚马逊商品信息
*
* @param request 包含asinList、batchId和region的请求参数
* @param httpRequest HTTP请求对象用于获取用户信息
* @return 商品列表和总数
*/
@PostMapping("/products/batch") @PostMapping("/products/batch")
public JsonData batchGetProducts(@RequestBody Map<String, Object> request, HttpServletRequest httpRequest) { public JsonData batchGetProducts(@RequestBody Map<String, Object> request, HttpServletRequest httpRequest) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -39,6 +52,12 @@ public class AmazonController {
return JsonData.buildSuccess(Map.of("products", products, "total", products.size())); return JsonData.buildSuccess(Map.of("products", products, "total", products.size()));
} }
/**
* 获取最新的亚马逊商品数据
*
* @param request HTTP请求对象用于获取用户信息
* @return 最新商品列表和总数
*/
@GetMapping("/products/latest") @GetMapping("/products/latest")
public JsonData getLatestProducts(HttpServletRequest request) { public JsonData getLatestProducts(HttpServletRequest request) {
String username = JwtUtil.getUsernameFromRequest(request); String username = JwtUtil.getUsernameFromRequest(request);
@@ -56,6 +75,12 @@ public class AmazonController {
return JsonData.buildSuccess(Map.of("products", products, "total", products.size())); return JsonData.buildSuccess(Map.of("products", products, "total", products.size()));
} }
/**
* 从Excel文件导入ASIN列表
*
* @param file Excel文件
* @return ASIN列表和总数
*/
@PostMapping("/import/asin") @PostMapping("/import/asin")
public JsonData importAsinFromExcel(@RequestParam("file") MultipartFile file) { public JsonData importAsinFromExcel(@RequestParam("file") MultipartFile file) {
try { try {

View File

@@ -12,6 +12,12 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
/**
* 斑马订单控制器
* 提供斑马订单查询、店铺列表等功能
*
* @author 占子杰牛逼
*/
@RestController @RestController
@RequestMapping("/api/banma") @RequestMapping("/api/banma")
public class BanmaOrderController { public class BanmaOrderController {
@@ -21,6 +27,19 @@ public class BanmaOrderController {
@Autowired @Autowired
BanmaOrderRepository banmaOrderRepository; BanmaOrderRepository banmaOrderRepository;
/**
* 分页查询斑马订单
*
* @param accountId 账号ID可选
* @param startDate 开始日期(可选)
* @param endDate 结束日期(可选)
* @param page 页码默认为1
* @param pageSize 每页大小默认为10
* @param batchId 批次ID
* @param shopIds 店铺ID列表多个用逗号分隔可选
* @param request HTTP请求对象用于获取用户信息
* @return 订单列表和分页信息
*/
@GetMapping("/orders") @GetMapping("/orders")
public JsonData getOrders( public JsonData getOrders(
@RequestParam(required = false, name = "accountId") Long accountId, @RequestParam(required = false, name = "accountId") Long accountId,
@@ -42,12 +61,25 @@ public class BanmaOrderController {
? JsonData.buildError((String)result.get("message")) ? JsonData.buildError((String)result.get("message"))
: JsonData.buildSuccess(result); : JsonData.buildSuccess(result);
} }
/**
* 获取店铺列表
*
* @param accountId 账号ID可选
* @return 店铺列表
*/
@GetMapping("/shops") @GetMapping("/shops")
public JsonData getShops(@RequestParam(required = false, name = "accountId") Long accountId) { public JsonData getShops(@RequestParam(required = false, name = "accountId") Long accountId) {
Map<String, Object> response = banmaOrderService.getShops(accountId); Map<String, Object> response = banmaOrderService.getShops(accountId);
return JsonData.buildSuccess(response); return JsonData.buildSuccess(response);
} }
/**
* 获取最新的斑马订单数据
*
* @param request HTTP请求对象用于获取用户信息
* @return 最新订单列表和总数
*/
@GetMapping("/orders/latest") @GetMapping("/orders/latest")
public JsonData getLatestOrders(HttpServletRequest request) { public JsonData getLatestOrders(HttpServletRequest request) {
String username = JwtUtil.getUsernameFromRequest(request); String username = JwtUtil.getUsernameFromRequest(request);

View File

@@ -15,6 +15,13 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import java.util.*; import java.util.*;
/**
* 乐天数据控制器
* 提供乐天商品采集、1688识图搜索等功能
*
* @author 占子杰牛逼
*/
@RestController @RestController
@RequestMapping("/api/rakuten") @RequestMapping("/api/rakuten")
@Slf4j @Slf4j
@@ -28,6 +35,15 @@ public class RakutenController {
@Autowired @Autowired
private DataReportUtil dataReportUtil; private DataReportUtil dataReportUtil;
/**
* 从Excel获取乐天商品信息
* 支持缓存机制,避免重复采集
*
* @param file 包含店铺名称的Excel文件
* @param batchId 批次ID可选
* @param request HTTP请求对象用于获取用户信息
* @return 商品列表、总数、跳过的店铺等信息
*/
@PostMapping(value = "/products") @PostMapping(value = "/products")
public JsonData getProducts(@RequestParam("file") MultipartFile file, @RequestParam(value = "batchId", required = false) String batchId, HttpServletRequest request) { public JsonData getProducts(@RequestParam("file") MultipartFile file, @RequestParam(value = "batchId", required = false) String batchId, HttpServletRequest request) {
try { try {
@@ -80,6 +96,14 @@ public class RakutenController {
} }
} }
/**
* 1688识图搜索
* 根据图片URL在1688平台进行识图搜索
*
* @param params 包含imageUrl和sessionId的参数
* @param request HTTP请求对象用于获取用户信息
* @return 搜索结果
*/
@PostMapping("/search1688") @PostMapping("/search1688")
public JsonData search1688(@RequestBody Map<String, Object> params, HttpServletRequest request) { public JsonData search1688(@RequestBody Map<String, Object> params, HttpServletRequest request) {
String imageUrl = (String) params.get("imageUrl"); String imageUrl = (String) params.get("imageUrl");
@@ -99,6 +123,12 @@ public class RakutenController {
} }
} }
/**
* 获取最新的乐天商品数据
*
* @param request HTTP请求对象用于获取用户信息
* @return 最新商品列表和总数
*/
@GetMapping("/products/latest") @GetMapping("/products/latest")
public JsonData getLatestProducts(HttpServletRequest request) { public JsonData getLatestProducts(HttpServletRequest request) {
try { try {

View File

@@ -13,6 +13,13 @@ import org.springframework.http.*;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import java.util.Map; import java.util.Map;
/**
* 系统管理控制器
* 提供系统配置、认证管理、设备信息等功能
*
* @author 占子杰牛逼
*/
@RestController @RestController
@RequestMapping("/api/system") @RequestMapping("/api/system")
public class SystemController { public class SystemController {
@@ -31,6 +38,13 @@ public class SystemController {
private String buildTime; private String buildTime;
@Value("${api.server.base-url}") @Value("${api.server.base-url}")
private String serverBaseUrl; private String serverBaseUrl;
/**
* 保存服务认证信息
*
* @param data 包含serviceName和authKey的认证信息
* @return 操作结果
*/
@PostMapping("/auth/save") @PostMapping("/auth/save")
public JsonData saveAuth(@RequestBody Map<String, Object> data) { public JsonData saveAuth(@RequestBody Map<String, Object> data) {
String serviceName = (String) data.get("serviceName"); String serviceName = (String) data.get("serviceName");
@@ -45,6 +59,12 @@ public class SystemController {
return JsonData.buildSuccess("认证信息保存成功"); return JsonData.buildSuccess("认证信息保存成功");
} }
/**
* 获取指定服务的认证信息
*
* @param serviceName 服务名称
* @return 认证token信息
*/
@GetMapping("/auth/get") @GetMapping("/auth/get")
public JsonData getAuth(@RequestParam String serviceName) { public JsonData getAuth(@RequestParam String serviceName) {
return JsonData.buildSuccess(authTokenRepository.findByServiceName(serviceName) return JsonData.buildSuccess(authTokenRepository.findByServiceName(serviceName)
@@ -52,36 +72,76 @@ public class SystemController {
.orElse(null)); .orElse(null));
} }
/**
* 删除指定服务的认证信息
*
* @param serviceName 服务名称
* @return 操作结果
*/
@DeleteMapping("/auth/remove") @DeleteMapping("/auth/remove")
public JsonData removeAuth(@RequestParam String serviceName) { public JsonData removeAuth(@RequestParam String serviceName) {
authTokenRepository.findByServiceName(serviceName).ifPresent(authTokenRepository::delete); authTokenRepository.findByServiceName(serviceName).ifPresent(authTokenRepository::delete);
return JsonData.buildSuccess("认证信息删除成功"); return JsonData.buildSuccess("认证信息删除成功");
} }
/**
* 获取设备唯一标识
*
* @return 设备ID
*/
@GetMapping("/device-id") @GetMapping("/device-id")
public JsonData getDeviceId() { public JsonData getDeviceId() {
return JsonData.buildSuccess(com.tashow.erp.utils.DeviceUtils.generateDeviceId()); return JsonData.buildSuccess(com.tashow.erp.utils.DeviceUtils.generateDeviceId());
} }
/**
* 获取本机IP地址
*
* @return 本机IP地址
* @throws Exception 获取IP失败时抛出异常
*/
@GetMapping("/local-ip") @GetMapping("/local-ip")
public JsonData getLocalIp() throws Exception { public JsonData getLocalIp() throws Exception {
return JsonData.buildSuccess(java.net.InetAddress.getLocalHost().getHostAddress()); return JsonData.buildSuccess(java.net.InetAddress.getLocalHost().getHostAddress());
} }
/**
* 获取计算机名称
*
* @return 计算机名称
*/
@GetMapping("/computer-name") @GetMapping("/computer-name")
public JsonData getComputerName() { public JsonData getComputerName() {
return JsonData.buildSuccess(System.getenv("COMPUTERNAME")); return JsonData.buildSuccess(System.getenv("COMPUTERNAME"));
} }
/**
* 获取系统版本信息
*
* @return 包含当前版本号和构建时间的信息
*/
@GetMapping("/version") @GetMapping("/version")
public Map<String, Object> getVersion() { public Map<String, Object> getVersion() {
return Map.of("success", true, "currentVersion", currentVersion, "buildTime", buildTime); return Map.of("success", true, "currentVersion", currentVersion, "buildTime", buildTime);
} }
/**
* 获取服务器配置信息
*
* @return 包含服务器基础URL和SSE URL的配置信息
*/
@GetMapping("/config/server") @GetMapping("/config/server")
public Map<String, Object> getServerConfig() { public Map<String, Object> getServerConfig() {
return Map.of("baseUrl", serverBaseUrl, "sseUrl", serverBaseUrl + "/monitor/account/events"); return Map.of("baseUrl", serverBaseUrl, "sseUrl", serverBaseUrl + "/monitor/account/events");
} }
/**
* 打开跟卖精灵网站
*
* @param accountId 账号ID
* @param request HTTP请求对象用于获取用户信息
* @return 操作结果
*/
@PostMapping("/genmai/open") @PostMapping("/genmai/open")
public JsonData openGenmaiWebsite(@RequestParam(required = false) Long accountId, HttpServletRequest request) { public JsonData openGenmaiWebsite(@RequestParam(required = false) Long accountId, HttpServletRequest request) {
try { try {
@@ -94,6 +154,13 @@ public class SystemController {
} }
} }
/**
* 图片代理接口
* 用于代理获取外部图片资源,解决跨域问题
*
* @param imageUrl 图片URL
* @return 图片字节数组响应
*/
@GetMapping("/proxy/image") @GetMapping("/proxy/image")
public ResponseEntity<byte[]> proxyImage(@RequestParam("url") String imageUrl) { public ResponseEntity<byte[]> proxyImage(@RequestParam("url") String imageUrl) {
if (imageUrl == null || imageUrl.isEmpty()) { if (imageUrl == null || imageUrl.isEmpty()) {
@@ -130,6 +197,11 @@ public class SystemController {
} }
} }
/**
* 清理系统缓存
*
* @return 操作结果
*/
@PostMapping("/cache/clear") @PostMapping("/cache/clear")
public JsonData clearCache() { public JsonData clearCache() {
cacheService.clearCache(); cacheService.clearCache();

View File

@@ -1,47 +0,0 @@
package com.tashow.erp.test;
import com.tashow.erp.utils.DeviceUtils;
/**
* 设备ID获取测试
* 独立运行,不依赖 Spring Boot
*/
public class DeviceIdTest {
public static void main(String[] args) {
System.out.println("=================================");
System.out.println("设备ID获取测试");
System.out.println("=================================\n");
try {
String deviceId = DeviceUtils.generateDeviceId();
System.out.println("✓ 成功获取设备ID: " + deviceId);
System.out.println("\n设备ID格式说明");
System.out.println(" MGUID_ - Windows MachineGuid最可靠");
System.out.println(" HW_ - 硬件UUID");
System.out.println(" CPU_ - 处理器ID");
System.out.println(" MB_ - 主板序列号");
System.out.println(" MAC_ - MAC地址");
System.out.println(" SYS_ - 系统信息组合");
// 再次获取,验证稳定性
System.out.println("\n验证稳定性再次获取");
String deviceId2 = DeviceUtils.generateDeviceId();
System.out.println("第二次获取: " + deviceId2);
if (deviceId.equals(deviceId2)) {
System.out.println("✓ 设备ID稳定两次获取结果一致");
} else {
System.out.println("✗ 警告设备ID不稳定两次获取结果不同");
}
} catch (Exception e) {
System.err.println("✗ 获取设备ID失败");
e.printStackTrace();
}
System.out.println("\n=================================");
System.out.println("测试完成");
System.out.println("=================================");
}
}

View File

@@ -1,12 +0,0 @@
package com.tashow.erp.test;
import com.tashow.erp.utils.DeviceUtils;
import java.util.regex.Pattern;
public class SeleniumWithProfile {
private static final Pattern WEIGHT_PATTERN = Pattern.compile("\"(?:unitWeight|weight)\":(\\d+(?:\\.\\d+)?)");
public static void main(String[] args) {
// 使用新的 DeviceUtils 获取设备ID
String deviceId = DeviceUtils.generateDeviceId();
System.out.println("设备ID: " + deviceId);
}
}

View File

@@ -65,7 +65,6 @@ public class Alibaba1688CookieUtil {
} }
cookieBuilder.append(entry.getKey()).append("=").append(entry.getValue()); cookieBuilder.append(entry.getKey()).append("=").append(entry.getValue());
} }
return cookieBuilder.toString(); return cookieBuilder.toString();
} }
/** /**

View File

@@ -1,19 +1,19 @@
package com.tashow.erp.utils; package com.tashow.erp.utils;
import io.github.bonigarcia.wdm.WebDriverManager; import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.chrome.ChromeOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.client.RestTemplate;
import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
/** /**
* Selenium 防检测工具类 * Selenium 防检测工具类
* 提供配置好的 ChromeDriver隐藏自动化痕迹 * 提供配置好的 ChromeDriver隐藏自动化痕迹
*/ */
public class SeleniumStealthUtil { public class SeleniumUtil {
/** /**
* 创建防检测的 ChromeDriver * 创建防检测的 ChromeDriver

View File

@@ -3,11 +3,15 @@ import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeDriver;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
@Component @Component
public class TrademarkCheckUtil { public class TrademarkCheckUtil {
@Autowired @Autowired
private ChromeDriver driver; private ChromeDriver driver;
@Autowired
RestTemplate restTemplate;
public boolean checkTrademark(String brandName) { public boolean checkTrademark(String brandName) {
try { try {
driver.get("https://tmsearch.uspto.gov/search/search-results"); driver.get("https://tmsearch.uspto.gov/search/search-results");
@@ -34,4 +38,5 @@ public class TrademarkCheckUtil {
} }
} }
} }

View File

@@ -0,0 +1,99 @@
package com.ruoyi.web.controller.tool;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.system.service.IMarkService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.util.logging.Handler;
@RequestMapping("/tool/mark")
@RestController
@Anonymous
public class MarkController {
private static final String API_SECRET = "e10adc3949ba59abbe56e057f20f883e";
private final RestTemplate restTemplate = new RestTemplate();
private final ObjectMapper objectMapper = new ObjectMapper();
@Autowired
private RedisCache redisCache;
@Autowired
private IMarkService markService;
/**
* 获取任务列表
*/
@GetMapping("/task")
public AjaxResult Task() {
try {
String token = redisCache.getCacheMapValue(CacheConstants.MARK_ACCOUNT_KEY, "token");
String d = "{\"name\":\"\",\"page_size\":20,\"current_page\":1}";
long ts = System.currentTimeMillis();
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("c", "TaskPageList");
formData.add("d", d);
formData.add("t", token);
formData.add("s", markService.md5(ts + d + API_SECRET));
formData.add("ts", String.valueOf(ts));
formData.add("website", "1");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);
String result = restTemplate.postForObject("https://api.fangzhoujingxuan.com/Task", requestEntity, String.class);
JsonNode json = objectMapper.readTree(result);
return AjaxResult.success(json.get("D").asText());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// 新建任务
@PostMapping("newTask")
public AjaxResult newTask(@RequestParam("file") MultipartFile file) {
try {
String token = redisCache.getCacheMapValue(CacheConstants.MARK_ACCOUNT_KEY, "token");
if (token == null) token = markService.reg();
String data =String.format("{\"name\":\"%s\",\"type\":1}", file.getOriginalFilename()) ;
MultiValueMap<String, Object> formData = new LinkedMultiValueMap<>();
formData.add("c", "Create");
formData.add("t", token);
formData.add("ts",System.currentTimeMillis());
formData.add("d", data);
formData.add("s", markService.md5(System.currentTimeMillis() + data + API_SECRET));
formData.add("website", "1");
formData.add("files", file.getResource());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(formData, headers);
String result = restTemplate.postForObject("https://api.fangzhoujingxuan.com/Task", requestEntity, String.class);
JsonNode jsonNode = objectMapper.readTree(result);
if(jsonNode.get("S").asInt()==-1006){
token= markService.login();
formData.add("t", token);
requestEntity = new HttpEntity<>(formData, headers);
result = restTemplate.postForObject("https://api.fangzhoujingxuan.com/Task", requestEntity, String.class);
jsonNode= objectMapper.readTree(result);
}
return jsonNode.get("S").asInt()==1?AjaxResult.success(result): AjaxResult.error( jsonNode.get("S").asText());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -41,4 +41,9 @@ public class CacheConstants
* 登录账户密码错误次数 redis key * 登录账户密码错误次数 redis key
*/ */
public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:"; public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
/**
* 方舟账号 redis key
*/
public static final String MARK_ACCOUNT_KEY = "mark_account:current";
} }

View File

@@ -0,0 +1,25 @@
package com.ruoyi.system.service;
/**
* 方舟Service接口
*/
public interface IMarkService {
/**
* 注册并保存到Redis
* @return token
*/
String reg() throws Exception;
/**
* MD5加密
* @param input 输入字符串
* @return MD5加密结果
*/
String md5(String input);
/**
* 登录
*/
String login();
}

View File

@@ -0,0 +1,123 @@
package com.ruoyi.system.service.impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.system.service.IMarkService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
@Service
public class MarkServiceImpl implements IMarkService {
private static final String API_SECRET = "e10adc3949ba59abbe56e057f20f883e";
private final RestTemplate restTemplate = new RestTemplate();
private final ObjectMapper objectMapper = new ObjectMapper();
@Autowired
private RedisCache redisCache;
@Override
public String reg() throws Exception {
String randomAccount = generatePhoneNumber();
String password = "123456";
String d = String.format("{\"referrer_id\":0,\"domain\":\"user.fangzhoujingxuan.com\",\"customer\":\"\",\"account\":\"%s\",\"code\":\"\",\"password\":\"%s\"}", randomAccount, password);
long ts = System.currentTimeMillis();
String sign = md5(ts + d + API_SECRET);
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("c", "Register");
formData.add("d", d);
formData.add("s", sign);
formData.add("ts", String.valueOf(ts));
formData.add("website", "1");
formData.add("t", String.valueOf(ts + (int) (Math.random() * 1000)));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);
String result = restTemplate.postForObject("https://api.fangzhoujingxuan.com/App", requestEntity, String.class);
JsonNode json = objectMapper.readTree(result);
int status = json.get("S").asInt();
if (status > 0) {
String token = json.get("D").get("key").asText();
Map<String, String> accountData = new HashMap<>();
accountData.put("account", randomAccount);
accountData.put("password", password);
accountData.put("token", token);
redisCache.setCacheMap(CacheConstants.MARK_ACCOUNT_KEY, accountData);
return token;
}
throw new RuntimeException("注册失败: " + json.get("M").asText());
}
@Override
public String login() {
try {
Map<String, String> accountData = redisCache.getCacheMap(CacheConstants.MARK_ACCOUNT_KEY);
String account = accountData.get("account");
String password = accountData.get("password");
String d = String.format("{\"account\":\"%s\",\"password\":\"%s\",\"domain\":\"user.fangzhoujingxuan.com\"}", account, password);
String ts = String.valueOf(System.currentTimeMillis());
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("c", "Login");
formData.add("d", d);
formData.add("s", md5(System.currentTimeMillis() + d + API_SECRET));
formData.add("ts", ts);
formData.add("website", "1");
formData.add("t", ts + (int) (Math.random() * 1000));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);
String result = restTemplate.postForObject("https://api.fangzhoujingxuan.com/App", requestEntity, String.class);
JsonNode json = objectMapper.readTree( result);
String token = json.get("D").get("key").asText();
if( token !=null)redisCache.setCacheMapValue(CacheConstants.MARK_ACCOUNT_KEY, "token",token);
return token;
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
/**
* 生成11位手机号
*/
private String generatePhoneNumber() {
Random random = new Random();
String[] prefixes = {"130", "131", "132", "133", "134", "135", "136", "137", "138", "139", "150", "151", "152", "153", "155", "156", "157", "158", "159", "180", "181", "182", "183", "184", "185", "186", "187", "188", "189", "170", "171", "172", "173", "174", "175", "176", "177", "178", "179"};
String prefix = prefixes[random.nextInt(prefixes.length)];
StringBuilder phoneNumber = new StringBuilder(prefix);
for (int i = 0; i < 8; i++) {
phoneNumber.append(random.nextInt(10));
}
return phoneNumber.toString();
}
@Override
public String md5(String input) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (Exception e) {
throw new RuntimeException("MD5加密失败", e);
}
}
}