This commit is contained in:
wangli 2026-02-06 00:02:02 +08:00
parent 3254a34675
commit f020343856
50 changed files with 230 additions and 113 deletions

View File

@ -0,0 +1,17 @@
package top.biwin.xinayu.common.dto.request;
import lombok.Data;
import java.util.List;
/**
* TODO
*
* @author wangli
* @since 2026-02-05 23:39
*/
@Data
public class ProductBatchDeleteRequest {
private List<ProductDeleteRequest> items;
}

View File

@ -0,0 +1,18 @@
package top.biwin.xinayu.common.dto.request;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* TODO
*
* @author wangli
* @since 2026-02-05 23:53
*/
@Data
public class ProductDeleteRequest {
@JsonProperty("goofish_id")
private String goofishId;
@JsonProperty("item_id")
private String goofishProductId;
}

View File

@ -18,4 +18,10 @@ import lombok.experimental.SuperBuilder;
public class BaseResponse {
private String message;
private Boolean success;
private Object data;
public BaseResponse(String message, Boolean success) {
this.message = message;
this.success = success;
}
}

View File

@ -0,0 +1,22 @@
package top.biwin.xinayu.common.dto.response;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
/**
* TODO
*
* @author wangli
* @since 2026-02-05 23:41
*/
@EqualsAndHashCode(callSuper = true)
@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
public class BatchDeleteResponse extends BaseResponse {
private Integer count;
}

View File

@ -14,4 +14,8 @@ public interface ProductRepository extends JpaRepository<ProductEntity, Long> {
List<ProductEntity> findByGoofishId(String goofishId);
Optional<ProductEntity> findByGoofishIdAndGoofishProductId(String goofishId, String itemId);
void deleteByGoofishIdAndGoofishProductIdIn(String goofishId, List<String> itemIds);
void deleteByGoofishIdAndGoofishProductId(String goofishId, String itemId);
}

View File

@ -24,6 +24,19 @@ public abstract class GoofishAbstractApi<T> implements GoofishApi<T> {
return apiHostUrl + getApi() + "/" + getVersion() + "/?";
}
@Override
public abstract String getApi();
protected final Map<String, String> buildHeaderMap(String cookieStr) {
Map<String, String> headerMap = new HashMap<>();
headerMap.put("Cookie", cookieStr);
headerMap.put("content-type", "application/x-www-form-urlencoded");
headerMap.put("priority", "u=1, i");
headerMap.put("dnt", "1");
headerMap.put("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0");
return headerMap;
}
protected Map<String, String> buildQueryParams(String cookieStr, String dataStr, Map<String, String> overrideMap) {
Map<String, String> api_query_params = new HashMap<>();
api_query_params.put("jsv", "2.7.2");
@ -36,7 +49,7 @@ public abstract class GoofishAbstractApi<T> implements GoofishApi<T> {
api_query_params.put("accountSite", "xianyu");
api_query_params.put("dataType", "json");
api_query_params.put("timeout", "20000");
api_query_params.put("api", "");
api_query_params.put("api", getApi());
api_query_params.put("sessionOption", "AutoLoginOnly");
api_query_params.put("spm_cnt", "a21ybx.account.0.0");

View File

@ -10,8 +10,6 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import top.biwin.xianyu.goofish.api.GoofishAbstractApi;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/**
@ -39,18 +37,15 @@ public class GetAccountApi extends GoofishAbstractApi<String> {
}
@Override
public String call(String goofishId, String cookieStr, Map<String,Object> data) {
public String call(String goofishId, String cookieStr, Map<String, Object> data) {
String dataStr = JSONUtil.toJsonStr(data);
String apiUrl = buildApiUrl() + HttpUtil.toParams(buildQueryParams(cookieStr, dataStr));
log.debug("【{}】获取账号名 ApiUrl: {}", goofishId, apiUrl);
log.debug("【{}】获取账号名时使用的 Cookie 为: {}", goofishId, cookieStr);
try (HttpResponse response = HttpRequest.post(apiUrl)
.header("Cookie", cookieStr)
.header("content-type", "application/x-www-form-urlencoded")
.header("priority", "u=1, i")
.header("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0")
.body("data=" + URLEncoder.encode(dataStr, StandardCharsets.UTF_8))
.headerMap(buildHeaderMap(cookieStr), true)
.form("data", dataStr)
.execute()) {
String body = response.body();
log.info("【{}】获取账号名时,服务端返回的完整响应为: {}", goofishId, body);

View File

@ -16,8 +16,6 @@ import top.biwin.xianyu.core.repository.ProductRepository;
import top.biwin.xianyu.goofish.api.GoofishAbstractApi;
import top.biwin.xinayu.common.dto.response.GetRemoteProductApiVo;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -93,12 +91,9 @@ public class GetAllItemsApi extends GoofishAbstractApi<GetRemoteProductApiVo> {
log.debug("【{}】获取闲鱼商品数据时使用的 Cookie 为: {}", goofishId, cookieStr);
try (HttpResponse response = HttpRequest.post(apiUrl)
.header("Cookie", cookieStr)
.header("content-type", "application/x-www-form-urlencoded")
.header("priority", "u=1, i")
.headerMap(buildHeaderMap(cookieStr), true)
.header("dnt", "1")
.header("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0")
.body("data=" + URLEncoder.encode(dataStr, StandardCharsets.UTF_8))
.form("data", dataStr)
.execute()) {
String body = response.body();
log.info("【{}】获取闲鱼商品数据时,服务端返回的完整响应为: {}", goofishId, body);

View File

@ -10,8 +10,6 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import top.biwin.xianyu.goofish.api.GoofishAbstractApi;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/**
@ -39,18 +37,15 @@ public class GetDisplayNameApi extends GoofishAbstractApi<String> {
}
@Override
public String call(String goofishId, String cookieStr, Map<String,Object> data) {
public String call(String goofishId, String cookieStr, Map<String, Object> data) {
String dataStr = JSONUtil.toJsonStr(data);
String apiUrl = buildApiUrl() + HttpUtil.toParams(buildQueryParams(cookieStr, dataStr));
log.debug("【{}】获取闲鱼昵称 ApiUrl: {}", goofishId, apiUrl);
log.debug("【{}】获取闲鱼昵称时使用的 Cookie 为: {}", goofishId, cookieStr);
try (HttpResponse response = HttpRequest.post(apiUrl)
.header("Cookie", cookieStr)
.header("content-type", "application/x-www-form-urlencoded")
.header("priority", "u=1, i")
.header("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0")
.body("data=" + URLEncoder.encode(dataStr, StandardCharsets.UTF_8))
.headerMap(buildHeaderMap(cookieStr), true)
.form("data", dataStr)
.execute()) {
String body = response.body();
log.info("【{}】获取闲鱼昵称时,服务端返回的完整响应为: {}", goofishId, body);

View File

@ -11,8 +11,6 @@ import org.springframework.stereotype.Component;
import top.biwin.xianyu.goofish.api.GoofishAbstractApi;
import top.biwin.xinayu.common.dto.response.GetRemoteProductDescApiVo;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
@ -49,12 +47,9 @@ public class GetItemDescApi extends GoofishAbstractApi<GetRemoteProductDescApiVo
log.debug("【{}】获取闲鱼商品详情数据时使用的 Cookie 为: {}", goofishId, cookieStr);
try (HttpResponse response = HttpRequest.post(apiUrl)
.header("Cookie", cookieStr)
.header("content-type", "application/x-www-form-urlencoded")
.header("priority", "u=1, i")
.headerMap(buildHeaderMap(cookieStr), true)
.header("dnt", "1")
.header("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0")
.body("data=" + URLEncoder.encode(dataStr, StandardCharsets.UTF_8))
.form("data", dataStr)
.execute()) {
String body = response.body();
log.info("【{}】获取闲鱼商品详情数据时,服务端返回的完整响应为: {}", goofishId, body);

View File

@ -10,8 +10,6 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import top.biwin.xianyu.goofish.api.GoofishAbstractApi;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/**
@ -39,18 +37,19 @@ public class GetUserIdApi extends GoofishAbstractApi<Long> {
}
@Override
public Long call(String goofishId, String cookieStr, Map<String,Object> data) {
public Long call(String goofishId, String cookieStr, Map<String, Object> data) {
String dataStr = JSONUtil.toJsonStr(data);
String apiUrl = buildApiUrl() + HttpUtil.toParams(buildQueryParams(cookieStr, dataStr));
// 主人要把 data 内容也塞进 URL 参数列表里计算并传递哦
Map<String, String> queryParams = buildQueryParams(cookieStr, dataStr);
// TODO: 请在这里将 dataStr 放入 queryParams 变量中queryParams.put("data", dataStr);
queryParams.put("data", dataStr);
String apiUrl = buildApiUrl() + HttpUtil.toParams(queryParams);
log.debug("【{}】获取闲鱼用户 ID ApiUrl: {}", goofishId, apiUrl);
log.debug("【{}】获取闲鱼用户 ID 时使用的 Cookie 为: {}", goofishId, cookieStr);
try (HttpResponse response = HttpRequest.post(apiUrl)
.header("Cookie", cookieStr)
.header("content-type", "application/x-www-form-urlencoded")
.header("priority", "u=1, i")
.header("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0")
.body("data=" + URLEncoder.encode(dataStr, StandardCharsets.UTF_8))
.headerMap(buildHeaderMap(cookieStr), true)
.form("data", dataStr)
.execute()) {
String body = response.body();
log.info("【{}】获取闲鱼用户 ID 时,服务端返回的完整响应为: {}", goofishId, body);

View File

@ -10,8 +10,6 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import top.biwin.xianyu.goofish.api.GoofishAbstractApi;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/**
@ -39,30 +37,27 @@ public class GetWsTokenApi extends GoofishAbstractApi<String> {
}
@Override
public String call(String goofishId, String cookieStr, Map<String,Object> data) {
public String call(String goofishId, String cookieStr, Map<String, Object> data) {
String dataStr = JSONUtil.toJsonStr(data);
String apiUrl = buildApiUrl() + HttpUtil.toParams(buildQueryParams(cookieStr, dataStr));
log.debug("【{}】获取闲鱼 WebSocket Token ApiUrl: {}", goofishId, apiUrl);
log.debug("【{}】获取闲鱼 WebSocket Token 时使用的 Cookie 为: {}", goofishId, cookieStr);
try (HttpResponse response = HttpRequest.post(apiUrl)
.header("Cookie", cookieStr)
.header("content-type", "application/x-www-form-urlencoded")
.header("priority", "u=1, i")
.header("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0")
.body("data=" + URLEncoder.encode(dataStr, StandardCharsets.UTF_8))
.headerMap(buildHeaderMap(cookieStr), true)
.form("data", dataStr)
.execute()) {
String body = response.body();
log.info("【{}】获取闲鱼 WebSocket Token 时,服务端返回的完整响应为: {}", goofishId, body);
JSONObject resJson = JSONUtil.parseObj(body);
// 检查是否需要滑块验证
// 检查是否需要滑块验证
if (needsCaptchaVerification(resJson)) {
log.warn("【{}】检测到滑块验证要求需要刷新Cookie", goofishId);
return null;
}
// 检查响应
// 检查响应
if (resJson.containsKey("ret")) {
JSONArray retArray = resJson.getJSONArray("ret");
for (int i = 0; i < retArray.size(); i++) {

View File

@ -8,6 +8,7 @@ import com.microsoft.playwright.Frame;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Playwright;
import com.microsoft.playwright.options.Cookie;
import com.microsoft.playwright.options.LoadState;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
@ -321,8 +322,8 @@ public class BrowserService {
page.navigate("https://www.goofish.com/im");
log.debug("【{}】等待页面加载,查找登录框... url: http://www.goofish.com/im", goofishId);
// 确保页面加载完成
page.getByText("登录后可以更懂你,推荐你喜欢的商品!");
// page.getByText("登录后可以更懂你,推荐你喜欢的商品!");
page.waitForLoadState(LoadState.DOMCONTENTLOADED);
String cookieStr = buildCookieStr(browserContext);
Long goofishUserId = goofishApiService.getUserId(goofishId, cookieStr);
if (goofishUserId > 0L) {

View File

@ -151,8 +151,8 @@ public class GoofishAccountWebsocket extends TextWebSocketHandler {
BrowserContext browserContext = browserService.loadPersistentContext(account.getId(), account.getShowBrowser() == 1, 1000D, null);
browserService.autoLoginUsingAccountAndPassword(browserContext, account.getUsername(), account.getPassword(), account.getShowBrowser() == 1);
this.cookiesStr = buildCookieStr(browserContext);
browserContext.close();
Long goofishUserId = goofishApiService.getUserId(goofishId, cookiesStr);
browserContext.close();
if (goofishUserId > 0L) {
log.debug("【{}】Cookie 刷新成功", goofishId);
} else {

View File

@ -1,9 +1,8 @@
package top.biwin.xinayu.server;
package top.biwin.xianyu.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
/**

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.config;
package top.biwin.xianyu.server.config;
import cn.hutool.core.util.StrUtil;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.config;
package top.biwin.xianyu.server.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import okhttp3.ConnectionPool;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.config;
package top.biwin.xianyu.server.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
@ -16,7 +16,7 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import top.biwin.xinayu.server.security.JwtAuthenticationFilter;
import top.biwin.xianyu.server.security.JwtAuthenticationFilter;
/**
* Spring Security 配置类

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.config;
package top.biwin.xianyu.server.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -21,7 +21,7 @@ public class ThreadPoolConfig {
// 创建定时任务线程池
return Executors.newScheduledThreadPool(5, r -> {
Thread t = new Thread(r);
t.setName("GAWebSocket-" + t.getId());
t.setName("Goofish-Account-WebSocket-" + t.getId());
t.setDaemon(true);
return t;
});
@ -31,7 +31,7 @@ public class ThreadPoolConfig {
public ExecutorService executorService() {
return Executors.newSingleThreadExecutor(r -> {
Thread t = new Thread(r);
t.setName("goofish-item-refresh-" + t.getId());
t.setName("Goofish-Item-Refresh-" + t.getId());
t.setDaemon(true);
return t;
});

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.controller;
package top.biwin.xianyu.server.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.controller;
package top.biwin.xianyu.server.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import top.biwin.xinayu.common.dto.response.FileUploadResponse;
import top.biwin.xinayu.server.util.ImageUtils;
import top.biwin.xianyu.server.util.ImageUtils;
import java.io.File;
import java.io.FileOutputStream;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.controller;
package top.biwin.xianyu.server.controller;
import cn.hutool.core.util.StrUtil;
import jakarta.servlet.http.HttpServletRequest;
@ -26,19 +26,17 @@ import top.biwin.xinayu.common.dto.response.CheckDefaultPwdResponse;
import top.biwin.xinayu.common.dto.response.LoginResponse;
import top.biwin.xinayu.common.dto.response.RefreshResponse;
import top.biwin.xinayu.common.dto.response.SendCodeResponse;
import top.biwin.xinayu.server.security.JwtUtil;
import top.biwin.xinayu.server.service.AuthService;
import top.biwin.xinayu.server.service.CaptchaService;
import top.biwin.xinayu.server.service.EmailVerificationService;
import top.biwin.xinayu.server.util.CurrentUserUtil;
import top.biwin.xianyu.server.security.JwtUtil;
import top.biwin.xianyu.server.service.AuthService;
import top.biwin.xianyu.server.service.CaptchaService;
import top.biwin.xianyu.server.service.EmailVerificationService;
import top.biwin.xianyu.server.util.CurrentUserUtil;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import static java.awt.SystemColor.info;
/**
* 认证控制器
* 提供登录刷新令牌等认证相关的 REST API

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.controller;
package top.biwin.xianyu.server.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.controller;
package top.biwin.xianyu.server.controller;
import org.springframework.web.bind.annotation.RestController;

View File

@ -1,10 +1,10 @@
package top.biwin.xinayu.server.controller;
package top.biwin.xianyu.server.controller;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import top.biwin.xinayu.server.service.GeetestService;
import top.biwin.xianyu.server.service.GeetestService;
import java.util.HashMap;
import java.util.Map;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.controller;
package top.biwin.xianyu.server.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@ -23,7 +23,7 @@ import top.biwin.xinayu.common.dto.response.BaseResponse;
import top.biwin.xinayu.common.dto.response.GoofishAccountResponse;
import top.biwin.xinayu.common.dto.response.GoofishQrStatusResponse;
import top.biwin.xinayu.common.dto.response.QrLoginResponse;
import top.biwin.xinayu.server.util.CurrentUserUtil;
import top.biwin.xianyu.server.util.CurrentUserUtil;
import java.util.ArrayList;
import java.util.List;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.controller;
package top.biwin.xianyu.server.controller;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.controller;
package top.biwin.xianyu.server.controller;
import cn.hutool.core.bean.BeanUtil;
import org.springframework.beans.factory.annotation.Autowired;

View File

@ -1,13 +1,20 @@
package top.biwin.xinayu.server.controller;
package top.biwin.xianyu.server.controller;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@ -15,11 +22,14 @@ import top.biwin.xianyu.core.entity.ProductEntity;
import top.biwin.xianyu.core.repository.GoofishAccountRepository;
import top.biwin.xianyu.core.repository.ProductRepository;
import top.biwin.xianyu.goofish.service.GoofishApiService;
import top.biwin.xianyu.server.util.CurrentUserUtil;
import top.biwin.xinayu.common.dto.request.FetchRemoteAllProductRequest;
import top.biwin.xinayu.common.dto.request.ProductBatchDeleteRequest;
import top.biwin.xinayu.common.dto.response.BaseResponse;
import top.biwin.xinayu.common.dto.response.BatchDeleteResponse;
import top.biwin.xinayu.common.dto.response.FetchRemoteAllProductResponse;
import top.biwin.xinayu.common.dto.response.GetRemoteProductApiVo;
import top.biwin.xinayu.common.dto.response.GetRemoteProductDescApiVo;
import top.biwin.xinayu.server.util.CurrentUserUtil;
import java.util.ArrayList;
import java.util.List;
@ -76,14 +86,17 @@ public class ProductController {
GetRemoteProductApiVo vo = goofishApiService.getAllItems(request.getGoofishId(), null);
// TODO 异步化
vo.getItemIds().forEach(itemId -> {
// 异步化
vo.getItemIds().parallelStream().forEach(itemId -> {
executorService.execute(() -> {
Optional<ProductEntity> productOpt = productRepository.findByGoofishIdAndGoofishProductId(request.getGoofishId(), itemId);
log.debug("【{}】完善【{}】商品的详情信息", request.getGoofishId(), itemId);
productOpt.ifPresent(product -> {
GetRemoteProductDescApiVo productVo = goofishApiService.getProductDesc(request.getGoofishId(), itemId, null);
product.setProductDescription(productVo.getDesc());
product.setProductDetail(productVo.getRichTextDesc());
product.setProductDetail(productVo.getDesc());
product.setProductDescription(productVo.getRichTextDesc());
product.setUserId(CurrentUserUtil.getCurrentUserId());
log.debug("【{}】商品完整信息为: {}", request.getGoofishId(), JSONUtil.toJsonStr(product));
productRepository.saveAndFlush(product);
});
});
@ -97,4 +110,50 @@ public class ProductController {
.savedCount(vo.getTotalSaved())
.build());
}
@PutMapping("/products/{goofish_id}/{item_id}")
public ResponseEntity<BaseResponse> productUpdate(@PathVariable("goofish_id") String goofishId,
@PathVariable("item_id") String goofishProductId,
@RequestBody ProductEntity productUpdate) {
ProductEntity product = productRepository.findByGoofishIdAndGoofishProductId(goofishId, goofishProductId)
.orElseThrow(() -> new IllegalArgumentException("商品信息未找到"));
BeanUtil.copyProperties(productUpdate, product, CopyOptions.create().setIgnoreNullValue(true));
productRepository.save(product);
return ResponseEntity.ok(BaseResponse.builder()
.success(true)
.message("商品已更新")
.data(product)
.build());
}
@Transactional
@DeleteMapping("/products/{goofish_id}/{item_id}")
public ResponseEntity<BaseResponse> deleteProduct(@PathVariable("goofish_id") String goofishId,
@PathVariable("item_id") String goofishProductId) {
productRepository.deleteByGoofishIdAndGoofishProductId(goofishId, goofishProductId);
return ResponseEntity.ok(BaseResponse.builder()
.success(true)
.message("商品删除成功")
.build());
}
@Transactional
@DeleteMapping("/products/batch")
public ResponseEntity<BatchDeleteResponse> deleteProductBatch(@RequestBody ProductBatchDeleteRequest request) {
if (CollectionUtils.isEmpty(request.getItems())) {
return ResponseEntity.ok(BatchDeleteResponse.builder()
.success(false)
.message("缺少商品数据")
.build());
}
request.getItems().forEach(i -> {
productRepository.deleteByGoofishIdAndGoofishProductId(i.getGoofishId(), i.getGoofishProductId());
});
return ResponseEntity.ok(BatchDeleteResponse.builder()
.success(true)
.message("商品批量删除成功")
.count(request.getItems().size())
.build());
}
}

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.controller;
package top.biwin.xianyu.server.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.controller.demo;
package top.biwin.xianyu.server.controller.demo;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
@ -6,7 +6,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import top.biwin.xianyu.core.entity.AdminUserEntity;
import top.biwin.xinayu.common.enums.UserRole;
import top.biwin.xinayu.server.util.CurrentUserUtil;
import top.biwin.xianyu.server.util.CurrentUserUtil;
import java.util.HashMap;
import java.util.Map;

View File

@ -1,12 +1,12 @@
package top.biwin.xinayu.server.controller.demo;
package top.biwin.xianyu.server.controller.demo;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import top.biwin.xinayu.server.security.RequireSuperAdmin;
import top.biwin.xinayu.server.util.CurrentUserUtil;
import top.biwin.xianyu.server.security.RequireSuperAdmin;
import top.biwin.xianyu.server.util.CurrentUserUtil;
import java.util.HashMap;
import java.util.Map;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.controller.demo;
package top.biwin.xianyu.server.controller.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
@ -10,7 +10,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import top.biwin.xianyu.core.entity.AdminUserEntity;
import top.biwin.xianyu.core.repository.AdminUserRepository;
import top.biwin.xinayu.server.util.CurrentUserUtil;
import top.biwin.xianyu.server.util.CurrentUserUtil;
import java.security.Principal;
import java.util.HashMap;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.exception;
package top.biwin.xianyu.server.exception;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.initialization;
package top.biwin.xianyu.server.initialization;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.notice;
package top.biwin.xianyu.server.notice;
/**
* TODO

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.notice.channel;
package top.biwin.xianyu.server.notice.channel;
/**
* TODO

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.security;
package top.biwin.xianyu.server.security;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.security;
package top.biwin.xianyu.server.security;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.security;
package top.biwin.xianyu.server.security;
import org.springframework.security.access.prepost.PreAuthorize;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.service;
package top.biwin.xianyu.server.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.service;
package top.biwin.xianyu.server.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@ -14,7 +14,7 @@ import top.biwin.xianyu.core.repository.AdminUserRepository;
import top.biwin.xinayu.common.dto.request.LoginRequest;
import top.biwin.xinayu.common.dto.response.LoginResponse;
import top.biwin.xinayu.common.dto.response.RefreshResponse;
import top.biwin.xinayu.server.security.JwtUtil;
import top.biwin.xianyu.server.security.JwtUtil;
/**
* 认证服务

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.service;
package top.biwin.xianyu.server.service;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.service;
package top.biwin.xianyu.server.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.service;
package top.biwin.xianyu.server.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.service;
package top.biwin.xianyu.server.service;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
@ -12,7 +12,7 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import top.biwin.xinayu.server.config.GeetestConfig;
import top.biwin.xianyu.server.config.GeetestConfig;
import java.util.HashMap;
import java.util.Map;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.util;
package top.biwin.xianyu.server.util;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.util;
package top.biwin.xianyu.server.util;
import lombok.extern.slf4j.Slf4j;

View File

@ -1,4 +1,4 @@
package top.biwin.xinayu.server.util;
package top.biwin.xianyu.server.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;

View File

@ -46,6 +46,12 @@ logging:
org.hibernate.type.descriptor.sql: INFO # Ensure Hibernate parameter logging is not set to DEBUG/TRACE
file:
name: logs/backend-java.log
# 主人,在这里我们可以为日志格式“扩容”哦!
pattern:
# TODO: 请在这里配置控制台日志格式,将线程名部分([%t]改为允许更多字符例如console: "%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%25t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"
console: "%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%25t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"
# TODO: 请在这里配置日志文件格式同样将线程名部分改为file: "%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${PID:- } --- [%25t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"
file: "%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${PID:- } --- [%25t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"
# JWT 配置
jwt: