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

View File

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

View File

@@ -12,6 +12,12 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 斑马订单控制器
* 提供斑马订单查询、店铺列表等功能
*
* @author 占子杰牛逼
*/
@RestController
@RequestMapping("/api/banma")
public class BanmaOrderController {
@@ -21,6 +27,19 @@ public class BanmaOrderController {
@Autowired
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")
public JsonData getOrders(
@RequestParam(required = false, name = "accountId") Long accountId,
@@ -42,12 +61,25 @@ public class BanmaOrderController {
? JsonData.buildError((String)result.get("message"))
: JsonData.buildSuccess(result);
}
/**
* 获取店铺列表
*
* @param accountId 账号ID可选
* @return 店铺列表
*/
@GetMapping("/shops")
public JsonData getShops(@RequestParam(required = false, name = "accountId") Long accountId) {
Map<String, Object> response = banmaOrderService.getShops(accountId);
return JsonData.buildSuccess(response);
}
/**
* 获取最新的斑马订单数据
*
* @param request HTTP请求对象用于获取用户信息
* @return 最新订单列表和总数
*/
@GetMapping("/orders/latest")
public JsonData getLatestOrders(HttpServletRequest 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 jakarta.servlet.http.HttpServletRequest;
import java.util.*;
/**
* 乐天数据控制器
* 提供乐天商品采集、1688识图搜索等功能
*
* @author 占子杰牛逼
*/
@RestController
@RequestMapping("/api/rakuten")
@Slf4j
@@ -28,6 +35,15 @@ public class RakutenController {
@Autowired
private DataReportUtil dataReportUtil;
/**
* 从Excel获取乐天商品信息
* 支持缓存机制,避免重复采集
*
* @param file 包含店铺名称的Excel文件
* @param batchId 批次ID可选
* @param request HTTP请求对象用于获取用户信息
* @return 商品列表、总数、跳过的店铺等信息
*/
@PostMapping(value = "/products")
public JsonData getProducts(@RequestParam("file") MultipartFile file, @RequestParam(value = "batchId", required = false) String batchId, HttpServletRequest request) {
try {
@@ -80,6 +96,14 @@ public class RakutenController {
}
}
/**
* 1688识图搜索
* 根据图片URL在1688平台进行识图搜索
*
* @param params 包含imageUrl和sessionId的参数
* @param request HTTP请求对象用于获取用户信息
* @return 搜索结果
*/
@PostMapping("/search1688")
public JsonData search1688(@RequestBody Map<String, Object> params, HttpServletRequest request) {
String imageUrl = (String) params.get("imageUrl");
@@ -99,6 +123,12 @@ public class RakutenController {
}
}
/**
* 获取最新的乐天商品数据
*
* @param request HTTP请求对象用于获取用户信息
* @return 最新商品列表和总数
*/
@GetMapping("/products/latest")
public JsonData getLatestProducts(HttpServletRequest request) {
try {

View File

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

View File

@@ -1,19 +1,19 @@
package com.tashow.erp.utils;
import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.chrome.ChromeDriver;
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.util.Collections;
import java.util.Map;
/**
* Selenium 防检测工具类
* 提供配置好的 ChromeDriver隐藏自动化痕迹
*/
public class SeleniumStealthUtil {
public class SeleniumUtil {
/**
* 创建防检测的 ChromeDriver

View File

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