记得上下班打卡 | git大法好,push需谨慎
Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
liquidnet-bus-v1
Project
Project
Details
Activity
Releases
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
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
董敬伟
liquidnet-bus-v1
Commits
4e23bb64
Commit
4e23bb64
authored
May 12, 2026
by
姜秀龙
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
sqb sku只展示关联的
parent
155ea2c4
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
114 additions
and
29 deletions
+114
-29
GoblinFrontController.java
...dnet/service/goblin/controller/GoblinFrontController.java
+7
-2
GoblinFrontServiceImpl.java
...t/service/goblin/service/impl/GoblinFrontServiceImpl.java
+107
-27
No files found.
liquidnet-bus-service/liquidnet-service-goblin/liquidnet-service-goblin-impl/src/main/java/com/liquidnet/service/goblin/controller/GoblinFrontController.java
View file @
4e23bb64
...
@@ -76,8 +76,13 @@ public class GoblinFrontController {
...
@@ -76,8 +76,13 @@ public class GoblinFrontController {
@GetMapping
(
"getGoodsDetail"
)
@GetMapping
(
"getGoodsDetail"
)
@ApiOperation
(
"获得商品详情"
)
@ApiOperation
(
"获得商品详情"
)
public
ResponseDto
<
GoblinFrontGoodDetailVo
>
getGoodsDetail
(
@RequestParam
(
name
=
"spuId"
,
required
=
true
)
String
spuId
)
throws
ParseException
{
@ApiImplicitParams
({
GoblinFrontGoodDetailVo
vo
=
goblinFrontService
.
getGoodsDetail
(
spuId
);
@ApiImplicitParam
(
paramType
=
"query"
,
required
=
false
,
dataType
=
"String"
,
name
=
"performancesId"
,
value
=
"演出ID,可选;收钱吧商品(spuType=33)时传入则仅返回该演出已关联的 SKU"
)
})
public
ResponseDto
<
GoblinFrontGoodDetailVo
>
getGoodsDetail
(
@RequestParam
(
name
=
"spuId"
,
required
=
true
)
String
spuId
,
@RequestParam
(
name
=
"performancesId"
,
required
=
false
)
String
performancesId
)
throws
ParseException
{
GoblinFrontGoodDetailVo
vo
=
goblinFrontService
.
getGoodsDetail
(
spuId
,
performancesId
);
if
(
vo
==
null
){
if
(
vo
==
null
){
return
ResponseDto
.
failure
(
"商品不存在"
);
return
ResponseDto
.
failure
(
"商品不存在"
);
}
}
...
...
liquidnet-bus-service/liquidnet-service-goblin/liquidnet-service-goblin-impl/src/main/java/com/liquidnet/service/goblin/service/impl/GoblinFrontServiceImpl.java
View file @
4e23bb64
...
@@ -79,6 +79,69 @@ public class GoblinFrontServiceImpl implements GoblinFrontService {
...
@@ -79,6 +79,69 @@ public class GoblinFrontServiceImpl implements GoblinFrontService {
return
vo
!=
null
&&
vo
.
getSpuType
()
==
33
;
return
vo
!=
null
&&
vo
.
getSpuType
()
==
33
;
}
}
/**
* 单场次演出下全部关联关系(status=1):先读 Redis {@link GoblinRedisUtils#getSqbPerformanceGoodsListCache},
* 未命中再查库并回写,与 {@link #getPerformanceSelectGoods} 一致。
*/
private
List
<
GoblinSqbPerformanceGoods
>
loadSqbPerformanceGoodsRelationsFromCacheOrDb
(
String
performancesId
)
{
if
(
StringUtil
.
isBlank
(
performancesId
))
{
return
new
ArrayList
<>();
}
String
pid
=
performancesId
.
trim
();
List
<
GoblinSqbPerformanceGoods
>
relations
=
goblinRedisUtils
.
getSqbPerformanceGoodsListCache
(
pid
);
if
(
relations
==
null
)
{
relations
=
goblinSqbPerformanceGoodsMapper
.
selectList
(
new
LambdaQueryWrapper
<
GoblinSqbPerformanceGoods
>()
.
eq
(
GoblinSqbPerformanceGoods:
:
getPerformancesId
,
pid
)
.
eq
(
GoblinSqbPerformanceGoods:
:
getStatus
,
1
)
.
orderByAsc
(
GoblinSqbPerformanceGoods:
:
getSort
,
GoblinSqbPerformanceGoods:
:
getMid
));
if
(
relations
==
null
)
{
relations
=
new
ArrayList
<>();
}
goblinRedisUtils
.
setSqbPerformanceGoodsListCache
(
pid
,
relations
);
}
return
relations
;
}
/**
* 收钱吧演出-SKU 关联(status=1)。<br>
* 有 performancesId 时与列表接口共用 Redis 缓存,仅内存过滤当前 spu 的 skuId;<br>
* 无 performancesId 时(详情并集)当前无按 SPU 的缓存结构,仍查库。
*/
private
Set
<
String
>
loadSqbLinkedSkuIdSet
(
String
spuId
,
String
performancesId
)
{
if
(
StringUtil
.
isBlank
(
spuId
))
{
return
Collections
.
emptySet
();
}
String
spu
=
spuId
.
trim
();
if
(
StringUtil
.
isNotBlank
(
performancesId
))
{
List
<
GoblinSqbPerformanceGoods
>
relations
=
loadSqbPerformanceGoodsRelationsFromCacheOrDb
(
performancesId
);
LinkedHashSet
<
String
>
ids
=
new
LinkedHashSet
<>();
for
(
GoblinSqbPerformanceGoods
r
:
relations
)
{
if
(
r
==
null
||
StringUtil
.
isBlank
(
r
.
getSkuId
()))
{
continue
;
}
if
(
StringUtil
.
isBlank
(
r
.
getSpuId
())
||
!
spu
.
equals
(
r
.
getSpuId
().
trim
()))
{
continue
;
}
ids
.
add
(
r
.
getSkuId
().
trim
());
}
return
ids
;
}
LambdaQueryWrapper
<
GoblinSqbPerformanceGoods
>
w
=
new
LambdaQueryWrapper
<
GoblinSqbPerformanceGoods
>()
.
eq
(
GoblinSqbPerformanceGoods:
:
getSpuId
,
spu
)
.
eq
(
GoblinSqbPerformanceGoods:
:
getStatus
,
1
);
List
<
GoblinSqbPerformanceGoods
>
rows
=
goblinSqbPerformanceGoodsMapper
.
selectList
(
w
);
LinkedHashSet
<
String
>
ids
=
new
LinkedHashSet
<>();
if
(
rows
!=
null
)
{
for
(
GoblinSqbPerformanceGoods
r
:
rows
)
{
if
(
r
!=
null
&&
StringUtil
.
isNotBlank
(
r
.
getSkuId
()))
{
ids
.
add
(
r
.
getSkuId
().
trim
());
}
}
}
return
ids
;
}
@Override
@Override
public
ArrayList
<
GoblinFrontBannerVo
>
getListBanner
()
{
public
ArrayList
<
GoblinFrontBannerVo
>
getListBanner
()
{
List
<
GoblinFrontBanner
>
list
=
goblinRedisUtils
.
getListBanner
();
List
<
GoblinFrontBanner
>
list
=
goblinRedisUtils
.
getListBanner
();
...
@@ -323,6 +386,13 @@ public class GoblinFrontServiceImpl implements GoblinFrontService {
...
@@ -323,6 +386,13 @@ public class GoblinFrontServiceImpl implements GoblinFrontService {
* 前台展示用:仅包含未删除且已上架的 SKU,并填充库存、限购可买数等(与 {@link #getGoodsDetail} 一致)
* 前台展示用:仅包含未删除且已上架的 SKU,并填充库存、限购可买数等(与 {@link #getGoodsDetail} 一致)
*/
*/
private
ArrayList
<
GoblinGoodsSkuInfoDetailVo
>
buildOnShelfSkuDetailList
(
GoblinGoodsInfoVo
goblinGoodsInfoVo
)
{
private
ArrayList
<
GoblinGoodsSkuInfoDetailVo
>
buildOnShelfSkuDetailList
(
GoblinGoodsInfoVo
goblinGoodsInfoVo
)
{
return
buildOnShelfSkuDetailList
(
goblinGoodsInfoVo
,
null
);
}
/**
* @param allowedSkuIds 非 null 时仅保留集合内的 SKU(用于收钱吧演出关联 SKU、spuType=33 详情)
*/
private
ArrayList
<
GoblinGoodsSkuInfoDetailVo
>
buildOnShelfSkuDetailList
(
GoblinGoodsInfoVo
goblinGoodsInfoVo
,
Set
<
String
>
allowedSkuIds
)
{
ArrayList
<
GoblinGoodsSkuInfoDetailVo
>
list
=
ObjectUtil
.
goblinGoodsSkuInfoDetailVos
();
ArrayList
<
GoblinGoodsSkuInfoDetailVo
>
list
=
ObjectUtil
.
goblinGoodsSkuInfoDetailVos
();
if
(
goblinGoodsInfoVo
==
null
)
{
if
(
goblinGoodsInfoVo
==
null
)
{
return
list
;
return
list
;
...
@@ -334,6 +404,9 @@ public class GoblinFrontServiceImpl implements GoblinFrontService {
...
@@ -334,6 +404,9 @@ public class GoblinFrontServiceImpl implements GoblinFrontService {
}
}
Integer
buyCount
=
0
;
Integer
buyCount
=
0
;
for
(
String
sku
:
skuIdList
)
{
for
(
String
sku
:
skuIdList
)
{
if
(
allowedSkuIds
!=
null
&&
!
allowedSkuIds
.
contains
(
sku
))
{
continue
;
}
String
userId
=
CurrentUtil
.
getCurrentUid
();
String
userId
=
CurrentUtil
.
getCurrentUid
();
if
(
StringUtils
.
isNotBlank
(
userId
))
{
if
(
StringUtils
.
isNotBlank
(
userId
))
{
buyCount
=
goblinRedisUtils
.
getSkuCountByUid
(
userId
,
sku
);
buyCount
=
goblinRedisUtils
.
getSkuCountByUid
(
userId
,
sku
);
...
@@ -370,6 +443,13 @@ public class GoblinFrontServiceImpl implements GoblinFrontService {
...
@@ -370,6 +443,13 @@ public class GoblinFrontServiceImpl implements GoblinFrontService {
* 获得商品详情
* 获得商品详情
*/
*/
public
GoblinFrontGoodDetailVo
getGoodsDetail
(
String
spuId
)
{
public
GoblinFrontGoodDetailVo
getGoodsDetail
(
String
spuId
)
{
return
getGoodsDetail
(
spuId
,
null
);
}
/**
* @param performancesId 可选;spuType=33 时传入则只返回该演出已关联的 SKU,不传则返回该商品在任意演出下已关联 SKU 的并集
*/
public
GoblinFrontGoodDetailVo
getGoodsDetail
(
String
spuId
,
String
performancesId
)
{
GoblinFrontGoodDetailVo
goblinFrontGoodDetailVo
=
GoblinFrontGoodDetailVo
.
getNew
();
GoblinFrontGoodDetailVo
goblinFrontGoodDetailVo
=
GoblinFrontGoodDetailVo
.
getNew
();
GoblinGoodsInfoVo
goblinGoodsInfoVo
=
goblinRedisUtils
.
getGoodsInfoVo
(
spuId
);
GoblinGoodsInfoVo
goblinGoodsInfoVo
=
goblinRedisUtils
.
getGoodsInfoVo
(
spuId
);
GoblinGoodsInfoDetailVo
goblinGoodsInfoDetailVo
=
GoblinGoodsInfoDetailVo
.
getNew
();
GoblinGoodsInfoDetailVo
goblinGoodsInfoDetailVo
=
GoblinGoodsInfoDetailVo
.
getNew
();
...
@@ -378,7 +458,11 @@ public class GoblinFrontServiceImpl implements GoblinFrontService {
...
@@ -378,7 +458,11 @@ public class GoblinFrontServiceImpl implements GoblinFrontService {
BeanUtils
.
copyProperties
(
goblinGoodsInfoVo
,
goblinGoodsInfoDetailVo
);
BeanUtils
.
copyProperties
(
goblinGoodsInfoVo
,
goblinGoodsInfoDetailVo
);
goblinFrontGoodDetailVo
.
setGoblinGoodsInfoVo
(
goblinGoodsInfoDetailVo
);
goblinFrontGoodDetailVo
.
setGoblinGoodsInfoVo
(
goblinGoodsInfoDetailVo
);
// int limit= getStockCount(goblinGoodsInfoVo.getStoreId());
// int limit= getStockCount(goblinGoodsInfoVo.getStoreId());
ArrayList
<
GoblinGoodsSkuInfoDetailVo
>
list
=
buildOnShelfSkuDetailList
(
goblinGoodsInfoVo
);
Set
<
String
>
sqbSkuAllow
=
null
;
if
(
isSqbSpuGoods
(
goblinGoodsInfoVo
))
{
sqbSkuAllow
=
loadSqbLinkedSkuIdSet
(
spuId
,
performancesId
);
}
ArrayList
<
GoblinGoodsSkuInfoDetailVo
>
list
=
buildOnShelfSkuDetailList
(
goblinGoodsInfoVo
,
sqbSkuAllow
);
//goblinGoodsInfoVo
//goblinGoodsInfoVo
GoblinStoreInfoVo
goblinStoreInfoVo
=
this
.
getStore
(
goblinGoodsInfoVo
.
getStoreId
());
GoblinStoreInfoVo
goblinStoreInfoVo
=
this
.
getStore
(
goblinGoodsInfoVo
.
getStoreId
());
if
(
null
!=
goblinStoreInfoVo
)
{
if
(
null
!=
goblinStoreInfoVo
)
{
...
@@ -1150,44 +1234,37 @@ public class GoblinFrontServiceImpl implements GoblinFrontService {
...
@@ -1150,44 +1234,37 @@ public class GoblinFrontServiceImpl implements GoblinFrontService {
}
}
}
}
// 1. 尝试从 Redis 缓存获取全量已关联商品关系(Raw Relations)提高性能
// 1. 全量关联关系:Redis → DB → 回写(与 loadSqbLinkedSkuIdSet 有演出 ID 时共用)
List
<
GoblinSqbPerformanceGoods
>
relations
=
goblinRedisUtils
.
getSqbPerformanceGoodsListCache
(
performancesId
);
List
<
GoblinSqbPerformanceGoods
>
relations
=
loadSqbPerformanceGoodsRelationsFromCacheOrDb
(
performancesId
);
if
(
relations
==
null
)
{
// 2. 缓存失效,查询数据库获取“原始关联关系”
relations
=
goblinSqbPerformanceGoodsMapper
.
selectList
(
new
LambdaQueryWrapper
<
GoblinSqbPerformanceGoods
>()
.
eq
(
GoblinSqbPerformanceGoods:
:
getPerformancesId
,
performancesId
)
.
eq
(
GoblinSqbPerformanceGoods:
:
getStatus
,
1
)
.
orderByAsc
(
GoblinSqbPerformanceGoods:
:
getSort
,
GoblinSqbPerformanceGoods:
:
getMid
));
if
(
relations
==
null
)
{
relations
=
new
ArrayList
<>();
}
// 3. 将关联关系(SPU 列表及其结算价/排序等)写入 Redis 缓存
goblinRedisUtils
.
setSqbPerformanceGoodsListCache
(
performancesId
,
relations
);
}
// 4. 每次请求都实时校验商品状态(delFlg, shelvesStatus 等)
// 4. 每次请求都实时校验商品状态(delFlg, shelvesStatus 等)
// 这样如果商品在 SPU 层面下架,虽然关联关系还在缓存,但这里会动态过滤掉
// 这样如果商品在 SPU 层面下架,虽然关联关系还在缓存,但这里会动态过滤掉
ArrayList
<
GoblinSqbPerformanceGoodsInfoVo
>
allGoods
=
new
ArrayList
<
GoblinSqbPerformanceGoodsInfoVo
>();
ArrayList
<
GoblinSqbPerformanceGoodsInfoVo
>
allGoods
=
new
ArrayList
<
GoblinSqbPerformanceGoodsInfoVo
>();
if
(!
CollectionUtils
.
isEmpty
(
relations
))
{
if
(!
CollectionUtils
.
isEmpty
(
relations
))
{
//
说明:relations 关联的是 SKU(同一 SPU 可能多条),下单侧需要完整 SKU 关系,所以 Redis 缓存必须保留全量
。
//
relations 按 SKU 关联:同一 SPU 可多条;列表按 SPU 去重展示,但 SKU 列表只保留本演出已关联的 SKU
。
// 前端“推荐商品列表”展示按 SPU 去重:取排序最靠前的一条关联作为该 SPU 的展示代表。
LinkedHashMap
<
String
,
GoblinSqbPerformanceGoods
>
firstRelBySpu
=
new
LinkedHashMap
<>();
LinkedHashMap
<
String
,
GoblinSqbPerformanceGoods
>
uniqueSpuRelMap
=
new
LinkedHashMap
<>();
LinkedHashMap
<
String
,
LinkedHashSet
<
String
>>
linkedSkusBySpu
=
new
LinkedHashMap
<>();
for
(
GoblinSqbPerformanceGoods
rel
:
relations
)
{
for
(
GoblinSqbPerformanceGoods
rel
:
relations
)
{
if
(
rel
==
null
||
StringUtil
.
isBlank
(
rel
.
getSpuId
()))
{
if
(
rel
==
null
||
StringUtil
.
isBlank
(
rel
.
getSpuId
()))
{
continue
;
continue
;
}
}
if
(!
uniqueSpuRelMap
.
containsKey
(
rel
.
getSpuId
()))
{
firstRelBySpu
.
putIfAbsent
(
rel
.
getSpuId
(),
rel
);
uniqueSpuRelMap
.
put
(
rel
.
getSpuId
(),
rel
);
if
(
StringUtil
.
isNotBlank
(
rel
.
getSkuId
()))
{
linkedSkusBySpu
.
computeIfAbsent
(
rel
.
getSpuId
(),
k
->
new
LinkedHashSet
<>()).
add
(
rel
.
getSkuId
().
trim
());
}
}
}
}
for
(
GoblinSqbPerformanceGoods
rel
:
uniqueSpuRelMap
.
values
())
{
for
(
GoblinSqbPerformanceGoods
rel
:
firstRelBySpu
.
values
())
{
if
(
rel
==
null
||
StringUtil
.
isBlank
(
rel
.
getSpuId
()))
{
if
(
rel
==
null
||
StringUtil
.
isBlank
(
rel
.
getSpuId
()))
{
continue
;
continue
;
}
}
LinkedHashSet
<
String
>
linkedSkuIds
=
linkedSkusBySpu
.
get
(
rel
.
getSpuId
());
if
(
linkedSkuIds
==
null
)
{
linkedSkuIds
=
new
LinkedHashSet
<>();
}
if
(
linkedSkuIds
.
isEmpty
())
{
continue
;
}
// 从 Redis SPU 缓存获取详情(SPU 详情由其他逻辑负责更新缓存,这里始终拿最新状态)
// 从 Redis SPU 缓存获取详情(SPU 详情由其他逻辑负责更新缓存,这里始终拿最新状态)
GoblinGoodsInfoVo
goodsInfoVo
=
goblinRedisUtils
.
getGoodsInfoVo
(
rel
.
getSpuId
());
GoblinGoodsInfoVo
goodsInfoVo
=
goblinRedisUtils
.
getGoodsInfoVo
(
rel
.
getSpuId
());
if
(
goodsInfoVo
==
null
)
{
if
(
goodsInfoVo
==
null
)
{
...
@@ -1209,11 +1286,11 @@ public class GoblinFrontServiceImpl implements GoblinFrontService {
...
@@ -1209,11 +1286,11 @@ public class GoblinFrontServiceImpl implements GoblinFrontService {
GoblinSqbPerformanceGoodsInfoVo
frontGoods
=
new
GoblinSqbPerformanceGoodsInfoVo
();
GoblinSqbPerformanceGoodsInfoVo
frontGoods
=
new
GoblinSqbPerformanceGoodsInfoVo
();
BeanUtils
.
copyProperties
(
goodsInfoVo
,
frontGoods
);
BeanUtils
.
copyProperties
(
goodsInfoVo
,
frontGoods
);
BigDecimal
normalPrice
=
resolveGoodsSellPrice
(
goodsInfoVo
);
BigDecimal
normalPrice
=
resolveGoodsSellPrice
(
goodsInfoVo
,
linkedSkuIds
);
frontGoods
.
setSellPrice
(
normalPrice
);
frontGoods
.
setSellPrice
(
normalPrice
);
frontGoods
.
setPrice
(
normalPrice
);
frontGoods
.
setPrice
(
normalPrice
);
frontGoods
.
setSettlementPrice
(
rel
.
getSettlementPrice
());
frontGoods
.
setSettlementPrice
(
rel
.
getSettlementPrice
());
frontGoods
.
setGoblinGoodsSkuInfoVolist
(
buildOnShelfSkuDetailList
(
goodsInfoVo
));
frontGoods
.
setGoblinGoodsSkuInfoVolist
(
buildOnShelfSkuDetailList
(
goodsInfoVo
,
linkedSkuIds
));
allGoods
.
add
(
frontGoods
);
allGoods
.
add
(
frontGoods
);
}
}
}
}
...
@@ -1233,7 +1310,7 @@ public class GoblinFrontServiceImpl implements GoblinFrontService {
...
@@ -1233,7 +1310,7 @@ public class GoblinFrontServiceImpl implements GoblinFrontService {
return
respVo
;
return
respVo
;
}
}
private
BigDecimal
resolveGoodsSellPrice
(
GoblinGoodsInfoVo
goodsInfoVo
)
{
private
BigDecimal
resolveGoodsSellPrice
(
GoblinGoodsInfoVo
goodsInfoVo
,
Set
<
String
>
allowedSkuIds
)
{
if
(
goodsInfoVo
==
null
)
{
if
(
goodsInfoVo
==
null
)
{
return
null
;
return
null
;
}
}
...
@@ -1244,6 +1321,9 @@ public class GoblinFrontServiceImpl implements GoblinFrontService {
...
@@ -1244,6 +1321,9 @@ public class GoblinFrontServiceImpl implements GoblinFrontService {
BigDecimal
minSkuPrice
=
null
;
BigDecimal
minSkuPrice
=
null
;
if
(!
CollectionUtils
.
isEmpty
(
goodsInfoVo
.
getSkuIdList
()))
{
if
(!
CollectionUtils
.
isEmpty
(
goodsInfoVo
.
getSkuIdList
()))
{
for
(
String
skuId
:
goodsInfoVo
.
getSkuIdList
())
{
for
(
String
skuId
:
goodsInfoVo
.
getSkuIdList
())
{
if
(
allowedSkuIds
!=
null
&&
!
allowedSkuIds
.
contains
(
skuId
))
{
continue
;
}
GoblinGoodsSkuInfoVo
skuInfoVo
=
goblinRedisUtils
.
getGoodsSkuInfoVo
(
skuId
);
GoblinGoodsSkuInfoVo
skuInfoVo
=
goblinRedisUtils
.
getGoodsSkuInfoVo
(
skuId
);
if
(
skuInfoVo
==
null
)
{
if
(
skuInfoVo
==
null
)
{
continue
;
continue
;
...
...
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