feat(system): 新增方舟账号管理与任务接口
- 新增 MarkController 控制器,提供方舟任务列表获取和新建任务接口 - 实现 IMarkService 接口及 MarkServiceImpl 实现类,支持注册、登录和MD5加密功能 - 在 CacheConstants 中添加方舟账号 Redis key 常量 - 集成 RestTemplate用于调用方舟API,支持自动注册与登录机制- 添加文件上传支持,用于新建任务时提交文件 - 实现 token 失效自动重新登录逻辑,确保接口调用稳定性
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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("=================================");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user