Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
custom-server
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lizhonghong
custom-server
Commits
cd858559
Commit
cd858559
authored
Jun 11, 2026
by
Lizh
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
优化pageList查询接口
parent
315f36e6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
217 additions
and
173 deletions
+217
-173
custom-server-app/src/main/java/com/jomalls/custom/app/dto/CustomProductInfoSnakeDTO.java
+3
-3
custom-server-app/src/main/java/com/jomalls/custom/app/enums/ProcessingStatus.java
+23
-0
custom-server-app/src/main/java/com/jomalls/custom/app/service/CustomProductInfoService.java
+0
-2
custom-server-app/src/main/java/com/jomalls/custom/app/service/impl/CustomProductInfoServiceImpl.java
+146
-159
custom-server-app/src/main/java/com/jomalls/custom/app/service/impl/LogCustomProductServiceImpl.java
+6
-5
custom-server-integrate/src/main/java/com/jomalls/custom/integrate/service/SaasAdminService.java
+39
-4
No files found.
custom-server-app/src/main/java/com/jomalls/custom/app/dto/CustomProductInfoSnakeDTO.java
View file @
cd858559
...
@@ -3,9 +3,7 @@ package com.jomalls.custom.app.dto;
...
@@ -3,9 +3,7 @@ package com.jomalls.custom.app.dto;
import
com.fasterxml.jackson.annotation.JsonSetter
;
import
com.fasterxml.jackson.annotation.JsonSetter
;
import
com.jomalls.custom.page.PageRequest
;
import
com.jomalls.custom.page.PageRequest
;
import
io.swagger.v3.oas.annotations.media.Schema
;
import
io.swagger.v3.oas.annotations.media.Schema
;
import
jakarta.validation.constraints.Digits
;
import
jakarta.validation.constraints.*
;
import
jakarta.validation.constraints.NotNull
;
import
jakarta.validation.constraints.Size
;
import
lombok.Data
;
import
lombok.Data
;
import
lombok.EqualsAndHashCode
;
import
lombok.EqualsAndHashCode
;
...
@@ -140,6 +138,8 @@ public class CustomProductInfoSnakeDTO extends PageRequest {
...
@@ -140,6 +138,8 @@ public class CustomProductInfoSnakeDTO extends PageRequest {
* <p>
* <p>
* 兼容前端发送 Boolean(true→1, false→0)和 Number(0/1/2)。
* 兼容前端发送 Boolean(true→1, false→0)和 Number(0/1/2)。
*/
*/
@Min
(
value
=
0
,
message
=
"processing 不能小于0"
)
@Max
(
value
=
2
,
message
=
"processing 不能大于2"
)
@Schema
(
description
=
"是否九猫处理(0=否 1=是 2=未设置,也支持 true/false)"
)
@Schema
(
description
=
"是否九猫处理(0=否 1=是 2=未设置,也支持 true/false)"
)
private
Integer
processing
;
private
Integer
processing
;
...
...
custom-server-app/src/main/java/com/jomalls/custom/app/enums/ProcessingStatus.java
0 → 100644
View file @
cd858559
package
com
.
jomalls
.
custom
.
app
.
enums
;
import
lombok.Getter
;
/**
* @Author: Lizh
* @Date: 2026/6/11 16:47
* @Description:
* @Version: 1.0
*/
@Getter
public
enum
ProcessingStatus
{
/** 是否九猫处理(0=否 1=是 2=未设置,也支持 true/false) */
NO
(
0
),
YES
(
1
),
NOT_SET
(
2
);
// 2表示IS NULL
private
final
int
code
;
ProcessingStatus
(
int
code
)
{
this
.
code
=
code
;
}
}
custom-server-app/src/main/java/com/jomalls/custom/app/service/CustomProductInfoService.java
View file @
cd858559
...
@@ -103,8 +103,6 @@ public interface CustomProductInfoService {
...
@@ -103,8 +103,6 @@ public interface CustomProductInfoService {
*/
*/
List
<
CraftCenterVO
>
getCraftById
(
Integer
id
);
List
<
CraftCenterVO
>
getCraftById
(
Integer
id
);
// ==================== ERP 专用接口(对齐 TS) ====================
/**
/**
* ERP 分页查询(对齐 TS erpPage)
* ERP 分页查询(对齐 TS erpPage)
* <p>
* <p>
...
...
custom-server-app/src/main/java/com/jomalls/custom/app/service/impl/CustomProductInfoServiceImpl.java
View file @
cd858559
package
com
.
jomalls
.
custom
.
app
.
service
.
impl
;
package
com
.
jomalls
.
custom
.
app
.
service
.
impl
;
import
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
;
import
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
;
import
com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
;
import
com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper
;
import
com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper
;
import
com.baomidou.mybatisplus.core.metadata.IPage
;
import
com.baomidou.mybatisplus.core.metadata.IPage
;
import
com.baomidou.mybatisplus.extension.plugins.pagination.Page
;
import
com.baomidou.mybatisplus.extension.plugins.pagination.Page
;
import
com.jomalls.custom.app.dto.*
;
import
com.jomalls.custom.app.dto.*
;
import
com.jomalls.custom.app.enums.ProcessingStatus
;
import
com.jomalls.custom.app.enums.SkuGenerateEnums
;
import
com.jomalls.custom.app.enums.SkuGenerateEnums
;
import
com.jomalls.custom.app.enums.TemplateStatus
;
import
com.jomalls.custom.app.enums.TemplateStatus
;
import
com.jomalls.custom.app.exception.ServiceException
;
import
com.jomalls.custom.app.exception.ServiceException
;
...
@@ -88,19 +88,21 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -88,19 +88,21 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
@Override
@Override
public
IPage
<
CustomProductInfoSnakeVO
>
pageList
(
CustomProductInfoSnakeDTO
param
)
{
public
IPage
<
CustomProductInfoSnakeVO
>
pageList
(
CustomProductInfoSnakeDTO
param
)
{
CustomAsserts
.
nonNull
(
param
,
"分页查询参数不能为空"
);
CustomAsserts
.
nonNull
(
param
,
"分页查询参数不能为空"
);
QueryWrapper
<
CustomProductInfoEntity
>
queryWrapper
=
new
QueryWrapper
<>();
LambdaQueryWrapper
<
CustomProductInfoEntity
>
queryWrapper
=
new
Lambda
QueryWrapper
<>();
// 构造查询条件
// 构造查询条件
toQueryWrapper
(
param
,
queryWrapper
);
toQueryWrapper
(
param
,
queryWrapper
);
IPage
<
CustomProductInfoEntity
>
page
=
customProductInfoDomainService
.
selectPage
(
queryWrapper
,
param
);
IPage
<
CustomProductInfoEntity
>
page
=
customProductInfoDomainService
.
selectPage
(
queryWrapper
,
param
);
return
page
.
convert
(
e
->
{
return
page
.
convert
(
e
->
{
CustomProductInfoSnakeVO
snakeVO
=
BeanMapper
.
snakeCase
().
convert
(
e
,
CustomProductInfoSnakeVO
.
class
);
CustomProductInfoSnakeVO
snakeVO
=
BeanMapper
.
snakeCase
().
convert
(
e
,
CustomProductInfoSnakeVO
.
class
);
if
(
StringUtils
.
isNotBlank
(
e
.
getColorImages
()))
{
snakeVO
.
setColorImageList
(
Arrays
.
asList
(
e
.
getColorImages
().
split
(
","
)));
snakeVO
.
setColorImageList
(
Arrays
.
asList
(
e
.
getColorImages
().
split
(
","
)));
}
return
snakeVO
;
return
snakeVO
;
});
});
}
}
/** 标准分页查询条件构建(非 ERP) */
/** 标准分页查询条件构建(非 ERP) */
private
void
toQueryWrapper
(
CustomProductInfoSnakeDTO
param
,
QueryWrapper
<
CustomProductInfoEntity
>
queryWrapper
)
{
private
void
toQueryWrapper
(
CustomProductInfoSnakeDTO
param
,
Lambda
QueryWrapper
<
CustomProductInfoEntity
>
queryWrapper
)
{
toQueryWrapper
(
param
,
queryWrapper
,
false
);
toQueryWrapper
(
param
,
queryWrapper
,
false
);
}
}
...
@@ -109,7 +111,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -109,7 +111,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
*
*
* @param isErp true=ERP 模式(title 双字段 OR 搜索,processing 支持 2=IS NULL,跳过 DIY/黑名单过滤)
* @param isErp true=ERP 模式(title 双字段 OR 搜索,processing 支持 2=IS NULL,跳过 DIY/黑名单过滤)
*/
*/
private
void
toQueryWrapper
(
CustomProductInfoSnakeDTO
param
,
QueryWrapper
<
CustomProductInfoEntity
>
queryWrapper
,
boolean
isErp
)
{
private
void
toQueryWrapper
(
CustomProductInfoSnakeDTO
param
,
Lambda
QueryWrapper
<
CustomProductInfoEntity
>
queryWrapper
,
boolean
isErp
)
{
// 分类层级过滤
// 分类层级过滤
if
(
param
.
getCategory_id
()
!=
null
)
{
if
(
param
.
getCategory_id
()
!=
null
)
{
List
<
CategoryInfoModel
>
cateList
=
saasAdminService
.
getAllList
();
List
<
CategoryInfoModel
>
cateList
=
saasAdminService
.
getAllList
();
...
@@ -120,7 +122,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -120,7 +122,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
CategoryInfoModel
cate
=
cateList
.
stream
().
filter
(
c
->
c
.
getId
().
equals
(
param
.
getCategory_id
()))
CategoryInfoModel
cate
=
cateList
.
stream
().
filter
(
c
->
c
.
getId
().
equals
(
param
.
getCategory_id
()))
.
findFirst
().
orElseThrow
(()
->
new
ServiceException
(
"不存在该类别, category_id="
+
param
.
getCategory_id
()));
.
findFirst
().
orElseThrow
(()
->
new
ServiceException
(
"不存在该类别, category_id="
+
param
.
getCategory_id
()));
String
pids
=
String
.
valueOf
(
cate
.
getId
());
String
pids
=
String
.
valueOf
(
cate
.
getId
());
if
(
cate
.
getPids
()
!=
null
&&
!
cate
.
getPids
().
isEmpty
(
))
{
if
(
StringUtils
.
isNotBlank
(
cate
.
getPids
()
))
{
pids
=
cate
.
getPids
()
+
","
+
pids
;
pids
=
cate
.
getPids
()
+
","
+
pids
;
}
}
String
finalPids
=
pids
;
String
finalPids
=
pids
;
...
@@ -132,10 +134,10 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -132,10 +134,10 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
})
})
.
map
(
CategoryInfoModel:
:
getId
).
collect
(
Collectors
.
toList
());
.
map
(
CategoryInfoModel:
:
getId
).
collect
(
Collectors
.
toList
());
cateIds
.
add
(
cate
.
getId
());
cateIds
.
add
(
cate
.
getId
());
queryWrapper
.
in
(
"category_id"
,
cateIds
);
queryWrapper
.
in
(
CustomProductInfoEntity:
:
getCategoryId
,
cateIds
);
}
}
// 工厂 ID 过滤(通过 product_factory_rel M2M 表
,对齐 TS:271-283
)
// 工厂 ID 过滤(通过 product_factory_rel M2M 表)
if
(
param
.
getFactory_id
()
!=
null
)
{
if
(
param
.
getFactory_id
()
!=
null
)
{
List
<
Integer
>
factoryProductIds
=
productFactoryRelDomainService
.
list
(
List
<
Integer
>
factoryProductIds
=
productFactoryRelDomainService
.
list
(
new
LambdaQueryWrapper
<
ProductFactoryRelEntity
>()
new
LambdaQueryWrapper
<
ProductFactoryRelEntity
>()
...
@@ -143,122 +145,117 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -143,122 +145,117 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
.
stream
().
map
(
ProductFactoryRelEntity:
:
getProductId
)
.
stream
().
map
(
ProductFactoryRelEntity:
:
getProductId
)
.
distinct
().
collect
(
Collectors
.
toList
());
.
distinct
().
collect
(
Collectors
.
toList
());
if
(
factoryProductIds
.
isEmpty
())
{
if
(
factoryProductIds
.
isEmpty
())
{
// 没有关联商品时返回空结果
queryWrapper
.
eq
(
CustomProductInfoEntity:
:
getId
,
-
1
);
queryWrapper
.
eq
(
"id"
,
-
1
);
}
else
{
}
else
{
queryWrapper
.
in
(
"id"
,
factoryProductIds
);
queryWrapper
.
in
(
CustomProductInfoEntity:
:
getId
,
factoryProductIds
);
}
}
}
}
// DIY 用户过滤与黑名单过滤(仅标准分页使用,ERP权限过滤)
// DIY 用户过滤与黑名单过滤(仅标准分页使用,ERP权限过滤)
if
(!
isErp
)
{
if
(!
isErp
)
{
applyDiyAndBlacklistFilter
(
param
,
queryWrapper
);
applyDiyAndBlacklistFilter
(
param
,
queryWrapper
);
// 排序:按 id 降序(对齐 TS:337)
queryWrapper
.
orderByDesc
(
CustomProductInfoEntity:
:
getId
);
queryWrapper
.
orderByDesc
(
"id"
);
}
}
// 是否九猫处理过滤
// 是否九猫处理过滤
(0=否 1=是 2=未设置,也支持 true/false)
Integer
processing
=
param
.
getProcessing
();
Integer
processing
=
param
.
getProcessing
();
if
(
processing
!=
null
)
{
if
(
processing
!=
null
)
{
if
(
processing
==
2
)
{
if
(
processing
==
ProcessingStatus
.
NOT_SET
.
getCode
())
{
// ERP: processing=2 → IS NULL(对齐 TS:626)
queryWrapper
.
isNull
(
CustomProductInfoEntity:
:
getProcessing
);
queryWrapper
.
isNull
(
"processing"
);
}
else
{
}
else
{
queryWrapper
.
eq
(
"processing"
,
processing
);
queryWrapper
.
eq
(
CustomProductInfoEntity:
:
getProcessing
,
processing
);
}
}
}
}
// 直接列等值过滤
// 直接列等值过滤
if
(
param
.
getId
()
!=
null
)
{
if
(
param
.
getId
()
!=
null
)
{
queryWrapper
.
eq
(
"id"
,
param
.
getId
());
queryWrapper
.
eq
(
CustomProductInfoEntity:
:
getId
,
param
.
getId
());
}
}
// sku 支持逗号分隔多值 IN 查询
(ERP查询逻辑)
// sku 支持逗号分隔多值 IN 查询
if
(
StringUtils
.
isNotBlank
(
param
.
getSku
()))
{
if
(
StringUtils
.
isNotBlank
(
param
.
getSku
()))
{
String
[]
skuArr
=
param
.
getSku
().
split
(
","
);
String
[]
skuArr
=
param
.
getSku
().
split
(
","
);
if
(
skuArr
.
length
>
1
)
{
if
(
skuArr
.
length
>
1
)
{
queryWrapper
.
in
(
"sku"
,
(
Object
[])
skuArr
);
queryWrapper
.
in
(
CustomProductInfoEntity:
:
getSku
,
(
Object
[])
skuArr
);
}
else
{
}
else
{
queryWrapper
.
eq
(
"sku"
,
param
.
getSku
());
queryWrapper
.
eq
(
CustomProductInfoEntity:
:
getSku
,
param
.
getSku
());
}
}
}
}
if
(
param
.
getStatus
()
!=
null
)
{
if
(
param
.
getStatus
()
!=
null
)
{
queryWrapper
.
eq
(
"status"
,
param
.
getStatus
());
queryWrapper
.
eq
(
CustomProductInfoEntity:
:
getStatus
,
param
.
getStatus
());
}
}
if
(
StringUtils
.
isNotBlank
(
param
.
getProduct_type
()))
{
if
(
StringUtils
.
isNotBlank
(
param
.
getProduct_type
()))
{
queryWrapper
.
eq
(
"product_type"
,
param
.
getProduct_type
());
queryWrapper
.
eq
(
CustomProductInfoEntity:
:
getProductType
,
param
.
getProduct_type
());
}
}
// 货号:逗号分隔多值 IN 查询,单个值模糊 LIKE 查询
(对齐 TS:774-779)
// 货号:逗号分隔多值 IN 查询,单个值模糊 LIKE 查询
if
(
StringUtils
.
isNotBlank
(
param
.
getProduct_no
()))
{
if
(
StringUtils
.
isNotBlank
(
param
.
getProduct_no
()))
{
String
[]
productNoArr
=
param
.
getProduct_no
().
split
(
","
);
String
[]
productNoArr
=
param
.
getProduct_no
().
split
(
","
);
if
(
productNoArr
.
length
>
1
)
{
if
(
productNoArr
.
length
>
1
)
{
queryWrapper
.
in
(
"product_no"
,
(
Object
[])
productNoArr
);
queryWrapper
.
in
(
CustomProductInfoEntity:
:
getProductNo
,
(
Object
[])
productNoArr
);
}
else
{
}
else
{
queryWrapper
.
like
(
"product_no"
,
param
.
getProduct_no
());
queryWrapper
.
like
(
CustomProductInfoEntity:
:
getProductNo
,
param
.
getProduct_no
());
}
}
}
}
if
(
param
.
getPrint_type
()
!=
null
)
{
if
(
param
.
getPrint_type
()
!=
null
)
{
queryWrapper
.
eq
(
"print_type"
,
param
.
getPrint_type
());
queryWrapper
.
eq
(
CustomProductInfoEntity:
:
getPrintType
,
param
.
getPrint_type
());
}
}
if
(
StringUtils
.
isNotBlank
(
param
.
getName
()))
{
if
(
StringUtils
.
isNotBlank
(
param
.
getName
()))
{
queryWrapper
.
like
(
"name"
,
param
.
getName
());
queryWrapper
.
like
(
CustomProductInfoEntity:
:
getName
,
param
.
getName
());
}
}
// ERP: title 关键词同时搜索 name 和 title 两列
(对齐 TS:610-611)
// ERP: title 关键词同时搜索 name 和 title 两列
if
(
StringUtils
.
isNotBlank
(
param
.
getTitle
()))
{
if
(
StringUtils
.
isNotBlank
(
param
.
getTitle
()))
{
if
(
isErp
)
{
if
(
isErp
)
{
queryWrapper
.
and
(
w
->
w
.
like
(
"name"
,
param
.
getTitle
()).
or
().
like
(
"title"
,
param
.
getTitle
()));
queryWrapper
.
and
(
w
->
w
.
like
(
CustomProductInfoEntity:
:
getName
,
param
.
getTitle
())
.
or
().
like
(
CustomProductInfoEntity:
:
getTitle
,
param
.
getTitle
()));
}
else
{
}
else
{
queryWrapper
.
like
(
"title"
,
param
.
getTitle
());
queryWrapper
.
like
(
CustomProductInfoEntity:
:
getTitle
,
param
.
getTitle
());
}
}
}
}
// 工厂过滤(factoryIds 直接列 — 用于创建/更新场景,保留兼容)
// 工厂过滤(factoryIds 直接列 — 用于创建/更新场景,保留兼容)
if
(
param
.
getFactoryIds
()
!=
null
)
{
if
(
param
.
getFactoryIds
()
!=
null
)
{
queryWrapper
.
in
(
"factory_id"
,
param
.
getFactoryIds
());
queryWrapper
.
in
(
CustomProductInfoEntity:
:
getFactoryId
,
param
.
getFactoryIds
());
}
}
}
}
/**
/**
* DIY 用户与黑名单过滤(标准分页专用)
* DIY 用户与黑名单过滤(标准分页专用)
* <p>
* <p>
*
对齐 TS page:284-322 —
diyUserId 与 blackUserId 互斥(else if),
* diyUserId 与 blackUserId 互斥(else if),
* diyUserId=-1 使用 LEFT JOIN 语义查找无绑定的商品。
* diyUserId=-1 使用 LEFT JOIN 语义查找无绑定的商品。
*/
*/
private
void
applyDiyAndBlacklistFilter
(
CustomProductInfoSnakeDTO
param
,
QueryWrapper
<
CustomProductInfoEntity
>
queryWrapper
)
{
private
void
applyDiyAndBlacklistFilter
(
CustomProductInfoSnakeDTO
param
,
Lambda
QueryWrapper
<
CustomProductInfoEntity
>
queryWrapper
)
{
if
(
param
.
getDiyUserId
()
!=
null
)
{
if
(
param
.
getDiyUserId
()
!=
null
)
{
// diyUserId 过滤
List
<
Integer
>
productIds
;
if
(
param
.
getDiyUserId
()
==
-
1
)
{
if
(
param
.
getDiyUserId
()
==
-
1
)
{
// 查找无任何 diy_user 绑定的商品(对齐 TS:287-295 LEFT JOIN WHERE IS NULL)
// 查找无任何 diy_user 绑定的商品(通过 Domain 层 LEFT JOIN 查询)
// 通过 Domain 层 Mapper XML 的 selectIdsWithoutDiyUserBind 执行 LEFT JOIN 查询
List
<
Integer
>
unboundIds
=
customProductInfoDomainService
.
selectIdsWithoutDiyUserBind
();
List
<
Integer
>
unboundIds
=
customProductInfoDomainService
.
selectIdsWithoutDiyUserBind
();
if
(
CollectionUtils
.
isEmpty
(
unboundIds
))
{
if
(
CollectionUtils
.
isEmpty
(
unboundIds
))
{
queryWrapper
.
eq
(
"id"
,
-
1
);
// 无匹配结果
queryWrapper
.
eq
(
CustomProductInfoEntity:
:
getId
,
-
1
);
}
else
{
}
else
{
queryWrapper
.
in
(
"id"
,
unboundIds
);
queryWrapper
.
in
(
CustomProductInfoEntity:
:
getId
,
unboundIds
);
}
}
}
else
{
}
else
{
productIds
=
customProductDiyUserRelDomainService
.
list
(
List
<
Integer
>
productIds
=
customProductDiyUserRelDomainService
.
list
(
new
LambdaQueryWrapper
<
CustomProductDiyUserRelEntity
>()
new
LambdaQueryWrapper
<
CustomProductDiyUserRelEntity
>()
.
eq
(
CustomProductDiyUserRelEntity:
:
getDiyUserId
,
param
.
getDiyUserId
()))
.
eq
(
CustomProductDiyUserRelEntity:
:
getDiyUserId
,
param
.
getDiyUserId
()))
.
stream
().
map
(
CustomProductDiyUserRelEntity:
:
getProductId
)
.
stream
().
map
(
CustomProductDiyUserRelEntity:
:
getProductId
)
.
distinct
().
collect
(
Collectors
.
toList
());
.
distinct
().
collect
(
Collectors
.
toList
());
if
(
CollectionUtils
.
isEmpty
(
productIds
))
{
if
(
CollectionUtils
.
isEmpty
(
productIds
))
{
queryWrapper
.
eq
(
"id"
,
-
1
);
// 无匹配结果
queryWrapper
.
eq
(
CustomProductInfoEntity:
:
getId
,
-
1
);
}
else
{
}
else
{
queryWrapper
.
in
(
"id"
,
productIds
);
queryWrapper
.
in
(
CustomProductInfoEntity:
:
getId
,
productIds
);
}
}
}
}
}
else
if
(
param
.
getBlackUserId
()
!=
null
)
{
}
else
if
(
param
.
getBlackUserId
()
!=
null
)
{
// blackUserId 过滤(仅在 diyUserId 未设置时生效
,对齐 TS else if:311-322
)
// blackUserId 过滤(仅在 diyUserId 未设置时生效)
List
<
Integer
>
productIds
=
customProductBlacklistDomainService
.
list
(
List
<
Integer
>
productIds
=
customProductBlacklistDomainService
.
list
(
new
LambdaQueryWrapper
<
CustomProductBlacklistEntity
>()
new
LambdaQueryWrapper
<
CustomProductBlacklistEntity
>()
.
eq
(
CustomProductBlacklistEntity:
:
getDiyUserId
,
param
.
getBlackUserId
()))
.
eq
(
CustomProductBlacklistEntity:
:
getDiyUserId
,
param
.
getBlackUserId
()))
.
stream
().
map
(
CustomProductBlacklistEntity:
:
getProductId
)
.
stream
().
map
(
CustomProductBlacklistEntity:
:
getProductId
)
.
distinct
().
collect
(
Collectors
.
toList
());
.
distinct
().
collect
(
Collectors
.
toList
());
if
(
productIds
.
isEmpty
())
{
if
(
productIds
.
isEmpty
())
{
queryWrapper
.
eq
(
"id"
,
-
1
);
// 无匹配结果
queryWrapper
.
eq
(
CustomProductInfoEntity:
:
getId
,
-
1
);
}
else
{
}
else
{
queryWrapper
.
in
(
"id"
,
productIds
);
queryWrapper
.
in
(
CustomProductInfoEntity:
:
getId
,
productIds
);
}
}
}
}
}
}
...
@@ -396,7 +393,29 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -396,7 +393,29 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
@Override
@Override
public
CustomProductInfoSnakeVO
getByIdOrSku
(
Integer
id
,
String
sku
,
String
namespace
)
{
public
CustomProductInfoSnakeVO
getByIdOrSku
(
Integer
id
,
String
sku
,
String
namespace
)
{
// 1. 查询主表
// 1. 校验并查询主表
CustomProductInfoEntity
entity
=
validateAndQueryEntity
(
id
,
sku
);
final
Integer
productId
=
entity
.
getId
();
// 2. 查询用户(如果指定了 namespace)
DbDiyUserEntity
user
=
queryUserByNamespace
(
namespace
);
// 3. 并行查询所有子表数据
ProductRelatedData
relatedData
=
queryRelatedDataInParallel
(
productId
);
// 4. 组合完整 VO
CustomProductInfoSnakeVO
fullVO
=
buildProductFullVO
(
entity
,
relatedData
.
items
,
relatedData
.
images
,
relatedData
.
factoryPrices
,
relatedData
.
diyUserIds
,
relatedData
.
craftIds
,
relatedData
.
warehouseIds
,
relatedData
.
remark
,
relatedData
.
cnRemark
,
relatedData
.
factoryIds
);
// 5. 解析属性名称
resolvePropertyNames
(
relatedData
.
properties
,
fullVO
);
// 6. 应用用户折扣
if
(
user
!=
null
)
{
diyUserService
.
setProductExternalPrice
(
user
,
fullVO
);
}
return
fullVO
;
}
/** 校验并查询商品主表实体 */
private
CustomProductInfoEntity
validateAndQueryEntity
(
Integer
id
,
String
sku
)
{
CustomProductInfoEntity
entity
;
CustomProductInfoEntity
entity
;
if
(
id
!=
null
)
{
if
(
id
!=
null
)
{
entity
=
customProductInfoDomainService
.
getById
(
id
);
entity
=
customProductInfoDomainService
.
getById
(
id
);
...
@@ -408,18 +427,27 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -408,18 +427,27 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
if
(
entity
==
null
)
{
if
(
entity
==
null
)
{
throw
new
ServiceException
(
"商品信息不存在, id="
+
id
+
", sku="
+
sku
);
throw
new
ServiceException
(
"商品信息不存在, id="
+
id
+
", sku="
+
sku
);
}
}
final
Integer
productId
=
entity
.
getId
();
return
entity
;
}
// 1a. 根据 namespace 查询 DIY 用户(对齐 TS:197-203)
/**
DbDiyUserEntity
user
=
null
;
* 根据 namespace 查询用户
if
(
StringUtils
.
isNotBlank
(
namespace
))
{
*/
user
=
diyUserService
.
getByNamespace
(
namespace
);
private
DbDiyUserEntity
queryUserByNamespace
(
String
namespace
)
{
if
(
StringUtils
.
isBlank
(
namespace
))
{
return
null
;
}
DbDiyUserEntity
user
=
diyUserService
.
getByNamespace
(
namespace
);
if
(
user
==
null
)
{
if
(
user
==
null
)
{
throw
new
ServiceException
(
"用户不存在, namespace="
+
namespace
);
throw
new
ServiceException
(
"用户不存在, namespace="
+
namespace
);
}
}
return
user
;
}
}
// 2. 并行查询所有子表(单表查询,Java 层组合,使用自定义线程池 + 超时保护)
/**
* 并行查询所有子表数据,带超时保护
*/
private
ProductRelatedData
queryRelatedDataInParallel
(
Integer
productId
)
{
CompletableFuture
<
List
<
CustomProductItemEntity
>>
itemsFuture
=
CompletableFuture
.
supplyAsync
(()
->
CompletableFuture
<
List
<
CustomProductItemEntity
>>
itemsFuture
=
CompletableFuture
.
supplyAsync
(()
->
customProductItemDomainService
.
list
(
new
LambdaQueryWrapper
<
CustomProductItemEntity
>()
customProductItemDomainService
.
list
(
new
LambdaQueryWrapper
<
CustomProductItemEntity
>()
.
eq
(
CustomProductItemEntity:
:
getProductId
,
productId
)
.
eq
(
CustomProductItemEntity:
:
getProductId
,
productId
)
...
@@ -458,15 +486,14 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -458,15 +486,14 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
.
stream
().
map
(
r
->
r
.
getWarehouseId
().
intValue
())
.
stream
().
map
(
r
->
r
.
getWarehouseId
().
intValue
())
.
collect
(
Collectors
.
toList
()),
threadPoolExecutor
);
.
collect
(
Collectors
.
toList
()),
threadPoolExecutor
);
CompletableFuture
<
CustomProductRemarkEntity
>
remarkFuture
=
CompletableFuture
.
supplyAsync
(()
->
customProductRemarkDomainService
.
getOne
(
CompletableFuture
<
CustomProductRemarkEntity
>
remarkFuture
=
CompletableFuture
.
supplyAsync
(()
->
new
LambdaQueryWrapper
<
CustomProductRemarkEntity
>()
customProductRemarkDomainService
.
getOne
(
new
LambdaQueryWrapper
<
CustomProductRemarkEntity
>()
.
eq
(
CustomProductRemarkEntity:
:
getProductId
,
productId
)),
threadPoolExecutor
);
.
eq
(
CustomProductRemarkEntity:
:
getProductId
,
productId
)),
threadPoolExecutor
);
CompletableFuture
<
CustomProductCnRemarkEntity
>
cnRemarkFuture
=
CompletableFuture
.
supplyAsync
(()
->
customProductCnRemarkDomainService
.
getOne
(
CompletableFuture
<
CustomProductCnRemarkEntity
>
cnRemarkFuture
=
CompletableFuture
.
supplyAsync
(()
->
new
LambdaQueryWrapper
<
CustomProductCnRemarkEntity
>()
customProductCnRemarkDomainService
.
getOne
(
new
LambdaQueryWrapper
<
CustomProductCnRemarkEntity
>()
.
eq
(
CustomProductCnRemarkEntity:
:
getProductId
,
productId
)),
threadPoolExecutor
);
.
eq
(
CustomProductCnRemarkEntity:
:
getProductId
,
productId
)),
threadPoolExecutor
);
// 工厂关联 ID 列表(product_factory_rel 表)
CompletableFuture
<
List
<
Integer
>>
factoryIdsFuture
=
CompletableFuture
.
supplyAsync
(()
->
CompletableFuture
<
List
<
Integer
>>
factoryIdsFuture
=
CompletableFuture
.
supplyAsync
(()
->
productFactoryRelDomainService
.
list
(
productFactoryRelDomainService
.
list
(
new
LambdaQueryWrapper
<
ProductFactoryRelEntity
>()
new
LambdaQueryWrapper
<
ProductFactoryRelEntity
>()
...
@@ -474,7 +501,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -474,7 +501,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
.
stream
().
map
(
ProductFactoryRelEntity:
:
getFactoryId
)
.
stream
().
map
(
ProductFactoryRelEntity:
:
getFactoryId
)
.
collect
(
Collectors
.
toList
()),
threadPoolExecutor
);
.
collect
(
Collectors
.
toList
()),
threadPoolExecutor
);
//
3. 等待所有查询完成(带超时保护,防止某个查询永久阻塞
)
//
等待所有查询完成(带超时保护
)
try
{
try
{
CompletableFuture
.
allOf
(
itemsFuture
,
imagesFuture
,
propertiesFuture
,
CompletableFuture
.
allOf
(
itemsFuture
,
imagesFuture
,
propertiesFuture
,
factoryPriceFuture
,
diyUserIdsFuture
,
craftIdsFuture
,
factoryPriceFuture
,
diyUserIdsFuture
,
craftIdsFuture
,
...
@@ -483,7 +510,6 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -483,7 +510,6 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
.
orTimeout
(
QUERY_TIMEOUT_SECONDS
,
TimeUnit
.
SECONDS
)
.
orTimeout
(
QUERY_TIMEOUT_SECONDS
,
TimeUnit
.
SECONDS
)
.
join
();
.
join
();
}
catch
(
CompletionException
e
)
{
}
catch
(
CompletionException
e
)
{
// 超时或异常时取消所有未完成的任务
cancelAll
(
itemsFuture
,
imagesFuture
,
propertiesFuture
,
cancelAll
(
itemsFuture
,
imagesFuture
,
propertiesFuture
,
factoryPriceFuture
,
diyUserIdsFuture
,
craftIdsFuture
,
factoryPriceFuture
,
diyUserIdsFuture
,
craftIdsFuture
,
warehouseIdsFuture
,
remarkFuture
,
cnRemarkFuture
,
warehouseIdsFuture
,
remarkFuture
,
cnRemarkFuture
,
...
@@ -492,36 +518,33 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -492,36 +518,33 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
.
setDetailMessage
(
e
.
toString
());
.
setDetailMessage
(
e
.
toString
());
}
}
// 4. Java 层组合结果
// 收集结果
CustomProductInfoSnakeVO
fullVO
;
List
<
CustomProductInfoPropertyEntity
>
properties
;
try
{
try
{
properties
=
propertiesFuture
.
get
();
return
new
ProductRelatedData
(
fullVO
=
buildProductFullVO
(
entity
,
itemsFuture
.
get
(),
imagesFuture
.
get
(),
propertiesFuture
.
get
(),
itemsFuture
.
get
(),
factoryPriceFuture
.
get
(),
diyUserIdsFuture
.
get
(),
craftIdsFuture
.
get
(),
imagesFuture
.
get
(),
warehouseIdsFuture
.
get
(),
remarkFuture
.
get
(),
cnRemarkFuture
.
get
(),
factoryPriceFuture
.
get
(),
diyUserIdsFuture
.
get
(),
craftIdsFuture
.
get
(),
warehouseIdsFuture
.
get
(),
remarkFuture
.
get
(),
cnRemarkFuture
.
get
(),
factoryIdsFuture
.
get
());
factoryIdsFuture
.
get
());
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
throw
new
ServiceException
(
"组装商品详情失败, productId="
+
productId
+
": "
+
e
.
getMessage
())
throw
new
ServiceException
(
"组装商品详情失败, productId="
+
productId
+
": "
+
e
.
getMessage
())
.
setDetailMessage
(
e
.
toString
());
.
setDetailMessage
(
e
.
toString
());
}
}
// 5. 通过 AdminPropertyService 解析属性名称(对齐 TS:217-236)
resolvePropertyNames
(
properties
,
fullVO
);
// 6. 如果查询了用户,应用外部定价折扣(对齐 TS:241-243)
if
(
user
!=
null
)
{
diyUserService
.
setProductExternalPrice
(
user
,
fullVO
);
}
}
return
fullVO
;
/**
}
* 并行查询结果聚合
*/
private
record
ProductRelatedData
(
List
<
CustomProductItemEntity
>
items
,
List
<
CustomProductImageEntity
>
images
,
List
<
CustomProductInfoPropertyEntity
>
properties
,
List
<
CustomProductFactoryPriceRelEntity
>
factoryPrices
,
List
<
Integer
>
diyUserIds
,
List
<
Long
>
craftIds
,
List
<
Integer
>
warehouseIds
,
CustomProductRemarkEntity
remark
,
CustomProductCnRemarkEntity
cnRemark
,
List
<
Integer
>
factoryIds
)
{}
/**
/**
* 通过 AdminPropertyService 解析属性名称,填充到 FullVO 的 skuProperties / normalProperties 中
* 通过 AdminPropertyService 解析属性名称,填充到 FullVO 的 skuProperties / normalProperties 中
...
@@ -625,7 +648,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -625,7 +648,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
CustomAsserts
.
nonNull
(
dto
,
"黑名单参数不能为空"
);
CustomAsserts
.
nonNull
(
dto
,
"黑名单参数不能为空"
);
CustomAsserts
.
nonNull
(
dto
.
getProductIds
(),
"商品 ID 列表不能为空"
);
CustomAsserts
.
nonNull
(
dto
.
getProductIds
(),
"商品 ID 列表不能为空"
);
// 1. 校验客户是否存在
(对齐 TS:563-568)
// 1. 校验客户是否存在
String
logStr
;
String
logStr
;
if
(
dto
.
getDiyUserIds
()
!=
null
&&
!
dto
.
getDiyUserIds
().
isEmpty
())
{
if
(
dto
.
getDiyUserIds
()
!=
null
&&
!
dto
.
getDiyUserIds
().
isEmpty
())
{
List
<
DbDiyUserEntity
>
diyUsers
=
dbDiyUserDomainService
.
listByIds
(
dto
.
getDiyUserIds
());
List
<
DbDiyUserEntity
>
diyUsers
=
dbDiyUserDomainService
.
listByIds
(
dto
.
getDiyUserIds
());
...
@@ -677,7 +700,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -677,7 +700,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
}
}
/**
/**
* 获取商品绑定的 DIY 模板列表
(对齐 TS:513-526)
* 获取商品绑定的 DIY 模板列表
* <p>
* <p>
* 通过 product_template_info 表查询商品关联的所有 diy_id,
* 通过 product_template_info 表查询商品关联的所有 diy_id,
* 再批量查询 db_diy 表返回完整模板信息。
* 再批量查询 db_diy 表返回完整模板信息。
...
@@ -726,7 +749,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -726,7 +749,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
}
}
/**
/**
* 获取商品绑定的工艺列表
(对齐 TS:786-788 → getCraftByProductId)
* 获取商品绑定的工艺列表
* <p>
* <p>
* 通过 custom_product_craft_rel 查 craft_id 列表,
* 通过 custom_product_craft_rel 查 craft_id 列表,
* 再批量查询 craft_center 表返回完整工艺实体。
* 再批量查询 craft_center 表返回完整工艺实体。
...
@@ -753,8 +776,6 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -753,8 +776,6 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
.
collect
(
Collectors
.
toList
());
.
collect
(
Collectors
.
toList
());
}
}
// ==================== ERP 专用接口 ====================
@Override
@Override
public
List
<
DbDiySnakeVO
>
getBindsDiyByIdAndUserMark
(
Integer
id
,
String
userMark
,
String
namespace
)
{
public
List
<
DbDiySnakeVO
>
getBindsDiyByIdAndUserMark
(
Integer
id
,
String
userMark
,
String
namespace
)
{
CustomAsserts
.
nonNull
(
id
,
"商品 ID 不能为空"
);
CustomAsserts
.
nonNull
(
id
,
"商品 ID 不能为空"
);
...
@@ -778,7 +799,8 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -778,7 +799,8 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
}
}
List
<
Integer
>
diyIds
=
templates
.
stream
().
map
(
ProductTemplateInfoEntity:
:
getDiyId
)
List
<
Integer
>
diyIds
=
templates
.
stream
().
map
(
ProductTemplateInfoEntity:
:
getDiyId
)
.
filter
(
Objects:
:
nonNull
).
distinct
().
collect
(
Collectors
.
toList
());
.
filter
(
Objects:
:
nonNull
).
distinct
().
collect
(
Collectors
.
toList
());
// 3. 查询 db_diy,根据用户类型过滤状态
// 3. 查询 db_diy,SQL 层完成状态过滤 + FIND_IN_SET 权限过滤(对齐 TS:766-783)
final
Integer
userId
=
user
.
getId
();
List
<
Integer
>
statusList
;
List
<
Integer
>
statusList
;
String
userName
=
user
.
getName
();
String
userName
=
user
.
getName
();
if
(
"demo"
.
equals
(
userName
))
{
if
(
"demo"
.
equals
(
userName
))
{
...
@@ -787,23 +809,23 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -787,23 +809,23 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
statusList
=
Collections
.
singletonList
(
TemplateStatus
.
SHELF_CODE
);
statusList
=
Collections
.
singletonList
(
TemplateStatus
.
SHELF_CODE
);
}
}
List
<
DbDiyEntity
>
diys
=
dbDiyDomainService
.
list
(
new
LambdaQueryWrapper
<
DbDiyEntity
>()
List
<
DbDiyEntity
>
diys
=
dbDiyDomainService
.
list
(
new
LambdaQueryWrapper
<
DbDiyEntity
>()
.
in
(
DbDiyEntity:
:
getId
,
diyIds
).
in
(
DbDiyEntity:
:
getStatus
,
statusList
));
.
in
(
DbDiyEntity:
:
getId
,
diyIds
)
.
in
(
DbDiyEntity:
:
getStatus
,
statusList
)
// user_ids 权限:NULL(对所有人开放)OR FIND_IN_SET(userId, user_ids) > 0
.
and
(
w
->
w
.
isNull
(
DbDiyEntity:
:
getUserIds
)
.
or
().
apply
(
"FIND_IN_SET({0}, user_ids) > 0"
,
userId
))
// ban_user_ids 排除:NULL(无人被禁止)OR FIND_IN_SET(userId, ban_user_ids) = 0
.
and
(
w
->
w
.
isNull
(
DbDiyEntity:
:
getBanUserIds
)
.
or
().
apply
(
"FIND_IN_SET({0}, ban_user_ids) = 0"
,
userId
)));
if
(
CollectionUtils
.
isEmpty
(
diys
))
{
if
(
CollectionUtils
.
isEmpty
(
diys
))
{
return
Collections
.
emptyList
();
return
Collections
.
emptyList
();
}
}
// 4. 权限过滤:user_ids / ban_user_ids
// 4. 批量查询所有效果图,按 diyId 分组(1 次 IN 查询替代 N 次逐条查询)
final
Integer
userId
=
user
.
getId
();
diys
=
diys
.
stream
().
filter
(
d
->
isUserAuthorized
(
d
.
getUserIds
(),
userId
))
.
filter
(
d
->
!
isUserBanned
(
d
.
getBanUserIds
(),
userId
)).
collect
(
Collectors
.
toList
());
if
(
CollectionUtils
.
isEmpty
(
diys
))
{
return
Collections
.
emptyList
();
}
// 5. 批量查询所有效果图,按 diyId 分组(1 次 IN 查询替代 N 次逐条查询)
List
<
Integer
>
ids
=
diys
.
stream
().
map
(
DbDiyEntity:
:
getId
).
collect
(
Collectors
.
toList
());
List
<
Integer
>
ids
=
diys
.
stream
().
map
(
DbDiyEntity:
:
getId
).
collect
(
Collectors
.
toList
());
Map
<
Integer
,
List
<
DbDiyXiaoguotuEntity
>>
xiaoguotuMap
=
dbDiyXiaoguotuDomainService
.
selectByDiyIds
(
ids
)
Map
<
Integer
,
List
<
DbDiyXiaoguotuEntity
>>
xiaoguotuMap
=
dbDiyXiaoguotuDomainService
.
selectByDiyIds
(
ids
)
.
stream
().
collect
(
Collectors
.
groupingBy
(
DbDiyXiaoguotuEntity:
:
getDiyId
));
.
stream
().
collect
(
Collectors
.
groupingBy
(
DbDiyXiaoguotuEntity:
:
getDiyId
));
//
6
. 转换为 VO 并附带效果图
//
5
. 转换为 VO 并附带效果图
return
diys
.
stream
().
map
(
diy
->
{
return
diys
.
stream
().
map
(
diy
->
{
DbDiySnakeVO
vo
=
BeanMapper
.
snakeCase
().
convert
(
diy
,
DbDiySnakeVO
.
class
);
DbDiySnakeVO
vo
=
BeanMapper
.
snakeCase
().
convert
(
diy
,
DbDiySnakeVO
.
class
);
List
<
DbDiyXiaoguotuEntity
>
xiaoguotus
=
xiaoguotuMap
.
getOrDefault
(
diy
.
getId
(),
Collections
.
emptyList
());
List
<
DbDiyXiaoguotuEntity
>
xiaoguotus
=
xiaoguotuMap
.
getOrDefault
(
diy
.
getId
(),
Collections
.
emptyList
());
...
@@ -815,38 +837,6 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -815,38 +837,6 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
}).
collect
(
Collectors
.
toList
());
}).
collect
(
Collectors
.
toList
());
}
}
/**
* 检查用户是否在授权名单中(对齐 TS:774-777 FIND_IN_SET)
* <p>
* user_ids 为 null 或空字符串 = 对所有人开放。
* 使用 FIND_IN_SET 语义:逗号分隔值中精确匹配用户 ID。
*/
private
boolean
isUserAuthorized
(
String
userIds
,
Integer
userId
)
{
if
(
StringUtils
.
isBlank
(
userIds
))
{
return
true
;
}
String
targetId
=
String
.
valueOf
(
userId
);
return
Arrays
.
stream
(
userIds
.
split
(
","
))
.
map
(
String:
:
strip
)
.
anyMatch
(
s
->
s
.
equals
(
targetId
));
}
/**
* 检查用户是否在黑名单中(对齐 TS:778-781 FIND_IN_SET)
* <p>
* ban_user_ids 为 null 或空字符串 = 无人被禁止。
* 使用 FIND_IN_SET 语义:逗号分隔值中精确匹配用户 ID。
*/
private
boolean
isUserBanned
(
String
banUserIds
,
Integer
userId
)
{
if
(
StringUtils
.
isBlank
(
banUserIds
))
{
return
false
;
}
String
targetId
=
String
.
valueOf
(
userId
);
return
Arrays
.
stream
(
banUserIds
.
split
(
","
))
.
map
(
String:
:
strip
)
.
anyMatch
(
s
->
s
.
equals
(
targetId
));
}
@Override
@Override
public
IPage
<
CustomProductInfoVO
>
erpPage
(
CustomProductInfoSnakeDTO
param
)
{
public
IPage
<
CustomProductInfoVO
>
erpPage
(
CustomProductInfoSnakeDTO
param
)
{
CustomAsserts
.
nonNull
(
param
,
"分页查询参数不能为空"
);
CustomAsserts
.
nonNull
(
param
,
"分页查询参数不能为空"
);
...
@@ -860,8 +850,8 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -860,8 +850,8 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
}
}
}
}
// 2. 构建查询条件
(ERP 模式:title OR 搜索,processing 支持 2=IS NULL,跳过 DIY/黑名单)
// 2. 构建查询条件
QueryWrapper
<
CustomProductInfoEntity
>
queryWrapper
=
new
QueryWrapper
<>();
LambdaQueryWrapper
<
CustomProductInfoEntity
>
queryWrapper
=
new
Lambda
QueryWrapper
<>();
toQueryWrapper
(
param
,
queryWrapper
,
true
);
toQueryWrapper
(
param
,
queryWrapper
,
true
);
// 3. DIY 模板过滤(对齐 TS:630-657)
// 3. DIY 模板过滤(对齐 TS:630-657)
...
@@ -894,7 +884,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -894,7 +884,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
if
(
productIds
.
isEmpty
())
{
if
(
productIds
.
isEmpty
())
{
return
emptyPage
(
param
);
return
emptyPage
(
param
);
}
}
queryWrapper
.
in
(
"id"
,
productIds
);
queryWrapper
.
in
(
CustomProductInfoEntity:
:
getId
,
productIds
);
}
}
// 4. 仓库国家过滤(对齐 TS:673-681)
// 4. 仓库国家过滤(对齐 TS:673-681)
...
@@ -914,23 +904,20 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -914,23 +904,20 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
}
}
List
<
Integer
>
productIds
=
rels
.
stream
()
List
<
Integer
>
productIds
=
rels
.
stream
()
.
map
(
CustomProductWarehouseRelEntity:
:
getProductId
).
distinct
().
collect
(
Collectors
.
toList
());
.
map
(
CustomProductWarehouseRelEntity:
:
getProductId
).
distinct
().
collect
(
Collectors
.
toList
());
queryWrapper
.
in
(
"id"
,
productIds
);
queryWrapper
.
in
(
CustomProductInfoEntity:
:
getId
,
productIds
);
}
}
// 5. ERP 权限过滤(对齐 TS:686-706 — native SQL 黑名单排除 + 用户绑定过滤)
// 5. ERP 权限过滤
// 使用单次 JOIN 查询,避免 Java 层多次查询+set 操作,保证性能
if
(
user
!=
null
)
{
if
(
user
!=
null
)
{
List
<
Integer
>
allowedIds
=
customProductInfoDomainService
.
selectIdsByErpPermission
(
user
.
getId
());
List
<
Integer
>
allowedIds
=
customProductInfoDomainService
.
selectIdsByErpPermission
(
user
.
getId
());
if
(
allowedIds
.
isEmpty
())
{
if
(
allowedIds
.
isEmpty
())
{
return
emptyPage
(
param
);
return
emptyPage
(
param
);
}
}
// MyBatis-Plus 多个 in("id", ...) 叠加 = SQL 层 AND 交集
queryWrapper
.
in
(
CustomProductInfoEntity:
:
getId
,
allowedIds
);
queryWrapper
.
in
(
"id"
,
allowedIds
);
}
}
// 6. 排序(对齐 TS:716-721:sort IS NULL ASC, sort ASC, id DESC)
// 6. 排序(对齐 TS:716-721:sort IS NULL ASC, sort ASC, id DESC)
// MySQL 默认 ASC 时空值排最前,等价于 sort IS NULL ASC
queryWrapper
.
orderByAsc
(
CustomProductInfoEntity:
:
getSort
).
orderByDesc
(
CustomProductInfoEntity:
:
getId
);
queryWrapper
.
orderByAsc
(
"sort"
).
orderByDesc
(
"id"
);
// 7. 执行分页查询
// 7. 执行分页查询
IPage
<
CustomProductInfoEntity
>
page
=
customProductInfoDomainService
.
selectPage
(
queryWrapper
,
param
);
IPage
<
CustomProductInfoEntity
>
page
=
customProductInfoDomainService
.
selectPage
(
queryWrapper
,
param
);
...
@@ -977,7 +964,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -977,7 +964,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
/**
/**
* 批量查询 DIY 模板上架状态,返回 diyId → isShelf 映射
* 批量查询 DIY 模板上架状态,返回 diyId → isShelf 映射
* <p>
* <p>
*
对齐 TS:724-731,
使用单次 IN 查询代替 N+1 逐条查询。
* 使用单次 IN 查询代替 N+1 逐条查询。
*/
*/
private
Map
<
Integer
,
Boolean
>
batchQueryDiyShelfStatus
(
List
<
CustomProductInfoEntity
>
rows
)
{
private
Map
<
Integer
,
Boolean
>
batchQueryDiyShelfStatus
(
List
<
CustomProductInfoEntity
>
rows
)
{
List
<
Integer
>
diyIds
=
rows
.
stream
()
List
<
Integer
>
diyIds
=
rows
.
stream
()
...
@@ -1060,7 +1047,6 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -1060,7 +1047,6 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
* 逐条保存子项并返回原始 SKU → 已保存实体的映射
* 逐条保存子项并返回原始 SKU → 已保存实体的映射
* <p>
* <p>
* 逐条保存是为了获取每条记录的自增 ID,供后续工厂价格关联的 item_id 填充使用。
* 逐条保存是为了获取每条记录的自增 ID,供后续工厂价格关联的 item_id 填充使用。
* 对齐 TS {@code save} 方法 100-117 行。
*
*
* @return Map<原始DTO中的SKU, 已保存的实体(含自增ID和替换后的SKU)>
* @return Map<原始DTO中的SKU, 已保存的实体(含自增ID和替换后的SKU)>
*/
*/
...
@@ -1094,7 +1080,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -1094,7 +1080,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
/**
/**
* 保存工厂价格关联(利用 itemMap 替换 item_sku 为生成的 SKU 并填充 item_id)
* 保存工厂价格关联(利用 itemMap 替换 item_sku 为生成的 SKU 并填充 item_id)
* <p>
* <p>
* 对齐 TS {@code save}
方法 132-139 行。
* 对齐 TS {@code save}
*/
*/
private
void
saveFactoryPriceRels
(
List
<
FactoryPriceRelSnakeDTO
>
factoryPriceList
,
private
void
saveFactoryPriceRels
(
List
<
FactoryPriceRelSnakeDTO
>
factoryPriceList
,
Integer
productId
,
Integer
productId
,
...
@@ -1120,7 +1106,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -1120,7 +1106,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
/**
/**
* 保存产品-工厂关联(product_factory_rel 表)
* 保存产品-工厂关联(product_factory_rel 表)
* <p>
* <p>
* 对齐 TS {@code save} 方法
162-163 行。
* 对齐 TS {@code save} 方法
*/
*/
private
void
saveFactoryRels
(
List
<
Integer
>
factoryIds
,
Integer
productId
)
{
private
void
saveFactoryRels
(
List
<
Integer
>
factoryIds
,
Integer
productId
)
{
if
(
factoryIds
==
null
||
factoryIds
.
isEmpty
())
{
if
(
factoryIds
==
null
||
factoryIds
.
isEmpty
())
{
...
@@ -1171,7 +1157,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -1171,7 +1157,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
* 保存价格区间关联
* 保存价格区间关联
*/
*/
private
void
saveFactoryPriceIntervalRels
(
List
<
FactoryPriceIntervalRelSnakeDTO
>
intervals
,
Integer
productId
)
{
private
void
saveFactoryPriceIntervalRels
(
List
<
FactoryPriceIntervalRelSnakeDTO
>
intervals
,
Integer
productId
)
{
if
(
intervals
==
null
||
intervals
.
isEmpty
(
))
{
if
(
CollectionUtils
.
isEmpty
(
intervals
))
{
return
;
return
;
}
}
List
<
CustomProductFactoryPriceIntervalRelEntity
>
rels
=
intervals
.
stream
().
map
(
dto
->
{
List
<
CustomProductFactoryPriceIntervalRelEntity
>
rels
=
intervals
.
stream
().
map
(
dto
->
{
...
@@ -1302,12 +1288,10 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -1302,12 +1288,10 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
customProductWarehouseRelDomainService
.
saveBatch
(
rels
);
customProductWarehouseRelDomainService
.
saveBatch
(
rels
);
}
}
// -------- updateFull 辅助方法 --------
/**
/**
* 处理子项变更(增/删/改)
* 处理子项变更(增/删/改)
* <p>
* <p>
*
对齐 TS update:407-420 —
新增子项逐条保存以获取自增 ID,
* 新增子项逐条保存以获取自增 ID,
* 返回 SKU→Entity 映射供后续工厂价格 item_id 回填。
* 返回 SKU→Entity 映射供后续工厂价格 item_id 回填。
*
*
* @return 新增子项的原始 SKU → 已保存实体映射(含自增 ID)
* @return 新增子项的原始 SKU → 已保存实体映射(含自增 ID)
...
@@ -1363,7 +1347,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -1363,7 +1347,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
}
}
/**
/**
* 将 sizeChange 合并到 imageChange
(对齐 TS:369-379)
* 将 sizeChange 合并到 imageChange
* <p>
* <p>
* sizeChange 的 addList/updateList 设置 type=1 后合并到 imageChange,
* sizeChange 的 addList/updateList 设置 type=1 后合并到 imageChange,
* removeList 也合并,最终统一处理。
* removeList 也合并,最终统一处理。
...
@@ -1420,8 +1404,8 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -1420,8 +1404,8 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
/**
/**
* 处理工厂价格变更(增/删/改)
* 处理工厂价格变更(增/删/改)
* <p>
* <p>
*
对齐 TS update:422-430 —
顺序:新增 → 修改 → 删除。
* 顺序:新增 → 修改 → 删除。
* 新增时从 newItemMap 回填 item_id
(对齐 TS:413-416)
。
* 新增时从 newItemMap 回填 item_id。
*/
*/
private
void
handleFactoryPriceChanges
(
private
void
handleFactoryPriceChanges
(
CustomProductInfoUpdateSnakeDTO
.
ProductFactoryPriceChangeDTO
change
,
Integer
productId
,
CustomProductInfoUpdateSnakeDTO
.
ProductFactoryPriceChangeDTO
change
,
Integer
productId
,
...
@@ -1431,7 +1415,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -1431,7 +1415,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
for
(
FactoryPriceRelSnakeDTO
dto
:
change
.
getAddList
())
{
for
(
FactoryPriceRelSnakeDTO
dto
:
change
.
getAddList
())
{
CustomProductFactoryPriceRelEntity
rel
=
BeanMapper
.
snakeCase
().
convert
(
dto
,
CustomProductFactoryPriceRelEntity
.
class
);
CustomProductFactoryPriceRelEntity
rel
=
BeanMapper
.
snakeCase
().
convert
(
dto
,
CustomProductFactoryPriceRelEntity
.
class
);
rel
.
setProductId
(
productId
);
rel
.
setProductId
(
productId
);
// 从新增子项映射中回填 item_id 和 item_sku
(对齐 TS:413-416)
// 从新增子项映射中回填 item_id 和 item_sku
if
(
newItemMap
!=
null
&&
StringUtils
.
isNotBlank
(
dto
.
getItem_sku
()))
{
if
(
newItemMap
!=
null
&&
StringUtils
.
isNotBlank
(
dto
.
getItem_sku
()))
{
CustomProductItemEntity
newItem
=
newItemMap
.
get
(
dto
.
getItem_sku
());
CustomProductItemEntity
newItem
=
newItemMap
.
get
(
dto
.
getItem_sku
());
if
(
newItem
!=
null
)
{
if
(
newItem
!=
null
)
{
...
@@ -1590,6 +1574,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -1590,6 +1574,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
logEntry
.
setDescription
(
description
);
logEntry
.
setDescription
(
description
);
logEntry
.
setEmployeeId
(
loginUser
.
getUserId
());
logEntry
.
setEmployeeId
(
loginUser
.
getUserId
());
logEntry
.
setEmployeeAccount
(
loginUser
.
getUsername
());
logEntry
.
setEmployeeAccount
(
loginUser
.
getUsername
());
logEntry
.
setCreateTime
(
new
Date
());
logCustomProductDomainService
.
save
(
logEntry
);
logCustomProductDomainService
.
save
(
logEntry
);
}
}
...
@@ -1598,6 +1583,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -1598,6 +1583,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
*/
*/
private
void
saveLogBatch
(
String
action
,
List
<
Integer
>
productIds
)
{
private
void
saveLogBatch
(
String
action
,
List
<
Integer
>
productIds
)
{
LoginUser
loginUser
=
SecurityUtils
.
getLoginUser
();
LoginUser
loginUser
=
SecurityUtils
.
getLoginUser
();
Date
now
=
new
Date
();
List
<
LogCustomProductEntity
>
logs
=
new
ArrayList
<>();
List
<
LogCustomProductEntity
>
logs
=
new
ArrayList
<>();
for
(
Integer
productId
:
productIds
)
{
for
(
Integer
productId
:
productIds
)
{
LogCustomProductEntity
logEntry
=
new
LogCustomProductEntity
();
LogCustomProductEntity
logEntry
=
new
LogCustomProductEntity
();
...
@@ -1605,6 +1591,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -1605,6 +1591,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
logEntry
.
setDescription
(
action
);
logEntry
.
setDescription
(
action
);
logEntry
.
setEmployeeId
(
loginUser
.
getUserId
());
logEntry
.
setEmployeeId
(
loginUser
.
getUserId
());
logEntry
.
setEmployeeAccount
(
loginUser
.
getUsername
());
logEntry
.
setEmployeeAccount
(
loginUser
.
getUsername
());
logEntry
.
setCreateTime
(
now
);
logs
.
add
(
logEntry
);
logs
.
add
(
logEntry
);
}
}
logCustomProductDomainService
.
saveBatch
(
logs
);
logCustomProductDomainService
.
saveBatch
(
logs
);
...
@@ -1621,8 +1608,6 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -1621,8 +1608,6 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
}
}
}
}
// -------- getByIdOrSku 辅助方法 --------
/**
/**
* 将并行查询结果组装为 FullVO
* 将并行查询结果组装为 FullVO
*/
*/
...
@@ -1638,18 +1623,20 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -1638,18 +1623,20 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
List
<
Integer
>
factoryIds
)
{
List
<
Integer
>
factoryIds
)
{
CustomProductInfoSnakeVO
fullVO
=
BeanMapper
.
snakeCase
().
convert
(
entity
,
CustomProductInfoSnakeVO
.
class
);
CustomProductInfoSnakeVO
fullVO
=
BeanMapper
.
snakeCase
().
convert
(
entity
,
CustomProductInfoSnakeVO
.
class
);
// 子项(
对齐 TS:209-214 —
同步主表的 print_type 到每个子项)
// 子项(同步主表的 print_type 到每个子项)
fullVO
.
setProductList
(
items
.
stream
()
fullVO
.
setProductList
(
items
.
stream
()
.
map
(
e
->
{
.
map
(
e
->
{
CustomProductItemSnakeVO
vo
=
BeanMapper
.
snakeCase
().
convert
(
e
,
CustomProductItemSnakeVO
.
class
);
CustomProductItemSnakeVO
vo
=
BeanMapper
.
snakeCase
().
convert
(
e
,
CustomProductItemSnakeVO
.
class
);
// 同步主表 printType 到子项
(对齐 TS:212)
// 同步主表 printType 到子项
vo
.
setPrint_type
(
entity
.
getPrintType
());
vo
.
setPrint_type
(
entity
.
getPrintType
());
return
vo
;
return
vo
;
})
})
.
collect
(
Collectors
.
toList
()));
.
collect
(
Collectors
.
toList
()));
// 图片拆分:按类型分为普通图和尺码图(对齐 TS:205-206)
// 图片拆分:按类型分为普通图和尺码图
if
(
entity
.
getColorImages
()
!=
null
)
{
fullVO
.
setColorImageList
(
Arrays
.
asList
(
entity
.
getColorImages
().
split
(
","
)));
fullVO
.
setColorImageList
(
Arrays
.
asList
(
entity
.
getColorImages
().
split
(
","
)));
}
fullVO
.
setImageList
(
images
.
stream
()
fullVO
.
setImageList
(
images
.
stream
()
.
filter
(
img
->
img
.
getType
()
==
null
||
img
.
getType
()
==
IMAGE_TYPE_NORMAL
)
.
filter
(
img
->
img
.
getType
()
==
null
||
img
.
getType
()
==
IMAGE_TYPE_NORMAL
)
.
map
(
img
->
BeanMapper
.
snakeCase
().
convert
(
img
,
CustomProductImageSnakeVO
.
class
))
.
map
(
img
->
BeanMapper
.
snakeCase
().
convert
(
img
,
CustomProductImageSnakeVO
.
class
))
...
@@ -1667,7 +1654,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
...
@@ -1667,7 +1654,7 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
fullVO
.
setDiyUserIds
(
diyUserIds
);
fullVO
.
setDiyUserIds
(
diyUserIds
);
fullVO
.
setCraftIds
(
craftIds
.
stream
().
map
(
String:
:
valueOf
).
collect
(
Collectors
.
toList
()));
fullVO
.
setCraftIds
(
craftIds
.
stream
().
map
(
String:
:
valueOf
).
collect
(
Collectors
.
toList
()));
fullVO
.
setWarehouseIds
(
warehouseIds
);
fullVO
.
setWarehouseIds
(
warehouseIds
);
// 工厂关联 ID 列表
(对齐 TS:238)
// 工厂关联 ID 列表
fullVO
.
setFactoryIds
(
factoryIds
);
fullVO
.
setFactoryIds
(
factoryIds
);
// 备注
// 备注
...
...
custom-server-app/src/main/java/com/jomalls/custom/app/service/impl/LogCustomProductServiceImpl.java
View file @
cd858559
package
com
.
jomalls
.
custom
.
app
.
service
.
impl
;
package
com
.
jomalls
.
custom
.
app
.
service
.
impl
;
import
com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
;
import
com.baomidou.mybatisplus.core.conditions.query.
Lambda
QueryWrapper
;
import
com.jomalls.custom.app.vo.LogCustomProductSnakeVO
;
import
com.jomalls.custom.app.vo.LogCustomProductSnakeVO
;
import
com.jomalls.custom.app.service.LogCustomProductService
;
import
com.jomalls.custom.app.service.LogCustomProductService
;
import
com.jomalls.custom.app.utils.BeanMapper
;
import
com.jomalls.custom.app.utils.BeanMapper
;
...
@@ -32,11 +32,12 @@ public class LogCustomProductServiceImpl implements LogCustomProductService {
...
@@ -32,11 +32,12 @@ public class LogCustomProductServiceImpl implements LogCustomProductService {
@Override
@Override
public
List
<
LogCustomProductSnakeVO
>
getListByProductId
(
Integer
productId
)
{
public
List
<
LogCustomProductSnakeVO
>
getListByProductId
(
Integer
productId
)
{
CustomAsserts
.
nonNull
(
productId
,
"商品 ID 不能为空"
);
CustomAsserts
.
nonNull
(
productId
,
"商品 ID 不能为空"
);
// 按 product_id 查询
所有日志,按 id 降序排列
// 按 product_id 查询
日志,按 id 降序,限制 100 条防止数据膨胀
List
<
LogCustomProductEntity
>
logs
=
logCustomProductDomainService
.
list
(
List
<
LogCustomProductEntity
>
logs
=
logCustomProductDomainService
.
list
(
new
QueryWrapper
<
LogCustomProductEntity
>()
new
LambdaQueryWrapper
<
LogCustomProductEntity
>()
.
eq
(
"product_id"
,
productId
)
.
eq
(
LogCustomProductEntity:
:
getProductId
,
productId
)
.
orderByDesc
(
"id"
));
.
orderByDesc
(
LogCustomProductEntity:
:
getId
)
.
last
(
"LIMIT 100"
));
return
logs
.
stream
()
return
logs
.
stream
()
.
map
(
e
->
BeanMapper
.
snakeCase
().
convert
(
e
,
LogCustomProductSnakeVO
.
class
))
.
map
(
e
->
BeanMapper
.
snakeCase
().
convert
(
e
,
LogCustomProductSnakeVO
.
class
))
.
collect
(
Collectors
.
toList
());
.
collect
(
Collectors
.
toList
());
...
...
custom-server-integrate/src/main/java/com/jomalls/custom/integrate/service/SaasAdminService.java
View file @
cd858559
...
@@ -19,6 +19,7 @@ import java.util.Collections;
...
@@ -19,6 +19,7 @@ import java.util.Collections;
import
java.util.HashMap
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map
;
import
java.util.concurrent.atomic.AtomicReference
;
/**
/**
* 商品分类服务
* 商品分类服务
...
@@ -43,8 +44,14 @@ public class SaasAdminService {
...
@@ -43,8 +44,14 @@ public class SaasAdminService {
private
static
final
int
DEFAULT_MAP_SIZE
=
2
;
private
static
final
int
DEFAULT_MAP_SIZE
=
2
;
/** 分类列表缓存 TTL(毫秒):5 分钟 */
private
static
final
long
CACHE_TTL_MS
=
5
*
60
*
1000
;
private
final
RemoteApiClient
remoteApiClient
;
private
final
RemoteApiClient
remoteApiClient
;
/** 分类列表本地缓存 */
private
final
AtomicReference
<
CacheEntry
<
List
<
CategoryInfoModel
>>>
categoryCache
=
new
AtomicReference
<>();
@Value
(
"${server.admin.base-url:https://admin.jomalls.com}"
)
@Value
(
"${server.admin.base-url:https://admin.jomalls.com}"
)
private
String
adminBaseUrl
;
private
String
adminBaseUrl
;
...
@@ -178,26 +185,54 @@ public class SaasAdminService {
...
@@ -178,26 +185,54 @@ public class SaasAdminService {
}
}
/**
/**
* 查询所有分类
* 查询所有分类
(带本地缓存,TTL 5 分钟)
* <p>
* <p>
* 对齐 TS {@code allList()}
* 对齐 TS {@code allList()}。分类数据不频繁变动,
* 使用本地缓存避免每次分页查询都发起远程 HTTP 调用。
*/
*/
public
List
<
CategoryInfoModel
>
getAllList
()
{
public
List
<
CategoryInfoModel
>
getAllList
()
{
// 命中缓存且未过期 → 直接返回
CacheEntry
<
List
<
CategoryInfoModel
>>
entry
=
categoryCache
.
get
();
if
(
entry
!=
null
&&
!
entry
.
isExpired
())
{
return
entry
.
data
;
}
// 未命中或已过期 → 远程调用刷新
try
{
try
{
ResponseEntity
<
SaasAdminApiResponseModel
<
List
<
CategoryInfoModel
>>>
response
=
remoteApiClient
.
get
(
ResponseEntity
<
SaasAdminApiResponseModel
<
List
<
CategoryInfoModel
>>>
response
=
remoteApiClient
.
get
(
adminBaseUrl
+
GET_ALL_LIST_URL
,
adminBaseUrl
+
GET_ALL_LIST_URL
,
new
ParameterizedTypeReference
<>()
{},
new
ParameterizedTypeReference
<>()
{},
getHeader
());
getHeader
());
if
(
response
!=
null
&&
response
.
getBody
()
!=
null
)
{
if
(
response
!=
null
&&
response
.
getBody
()
!=
null
)
{
log
.
debug
(
"[ SaasAdminService ] getAllList 成功, 返回: {}"
,
response
.
toString
());
SaasAdminApiResponseModel
<
List
<
CategoryInfoModel
>>
responseBody
=
response
.
getBody
();
SaasAdminApiResponseModel
<
List
<
CategoryInfoModel
>>
responseBody
=
response
.
getBody
();
if
(
responseBody
.
getCode
()
==
CodeEnum
.
SUCCESS
.
getCode
())
{
if
(
responseBody
.
getCode
()
==
CodeEnum
.
SUCCESS
.
getCode
())
{
return
responseBody
.
getData
();
List
<
CategoryInfoModel
>
data
=
responseBody
.
getData
();
categoryCache
.
set
(
new
CacheEntry
<>(
data
));
return
data
;
}
}
}
}
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
log
.
error
(
"[ SaasAdminService ] getAllList 调用失败"
,
e
);
log
.
error
(
"[ SaasAdminService ] getAllList 调用失败"
,
e
);
}
}
// 远程调用失败但有旧缓存 → 降级返回旧缓存
if
(
entry
!=
null
)
{
log
.
warn
(
"[ SaasAdminService ] getAllList 远程失败,降级使用过期缓存"
);
return
entry
.
data
;
}
return
Collections
.
emptyList
();
return
Collections
.
emptyList
();
}
}
/** 简单 TTL 缓存条目 */
private
static
class
CacheEntry
<
T
>
{
final
T
data
;
final
long
expireAt
;
CacheEntry
(
T
data
)
{
this
.
data
=
data
;
this
.
expireAt
=
System
.
currentTimeMillis
()
+
CACHE_TTL_MS
;
}
boolean
isExpired
()
{
return
System
.
currentTimeMillis
()
>
expireAt
;
}
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment