商品详情展示

This commit is contained in:
yovinchen 2023-10-08 22:07:41 +08:00
parent cfeefe2dc6
commit bf4e5a807d
23 changed files with 390 additions and 18 deletions

View File

@ -1,6 +1,9 @@
package com.atguigu.ssyx.client.activity;
import io.swagger.annotations.ApiOperation;
import org.springframework.cloud.openfeign.FeignClient;
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.RequestBody;
@ -19,4 +22,8 @@ public interface ActivityFeignClient {
@PostMapping("/api/activity/inner/findActivity")
Map<Long, List<String>> findActivity(@RequestBody List<Long> skuIdList);
@ApiOperation("根据skuID获取营销数据和优惠卷")
@GetMapping("/api/activity/inner/findActivityAndCoupon/{skuId}/{userId}")
Map<String, Object> findActivityAndCoupon(@PathVariable("skuId") Long skuId, @PathVariable("userId") Long userId);
}

View File

@ -2,6 +2,7 @@ package com.atguigu.ssyx.client.product;
import com.atguigu.ssyx.model.product.Category;
import com.atguigu.ssyx.model.product.SkuInfo;
import com.atguigu.ssyx.vo.product.SkuInfoVo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@ -70,7 +71,7 @@ public interface ProductFeignClient {
* @return
*/
@GetMapping("/api/product/inner/findAllCategoryList")
public List<Category> findAllCategoryList();
List<Category> findAllCategoryList();
/**
* 获取新人优惠
@ -78,5 +79,14 @@ public interface ProductFeignClient {
* @return
*/
@GetMapping("/api/product/inner/findNewPersonSkuInfoList")
public List<SkuInfo> findNewPersonSkuInfoList();
List<SkuInfo> findNewPersonSkuInfoList();
/**
* 根据skuId获取sku信息
*
* @param skuId
* @return
*/
@GetMapping("/api/product/inner/getSkuInfoVo/{skuId}")
SkuInfoVo getSkuInfoVo(@PathVariable Long skuId);
}

View File

@ -1,8 +1,10 @@
package com.atguigu.ssyx.client.search;
import com.atguigu.ssyx.model.search.SkuEs;
import io.swagger.annotations.ApiOperation;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.List;
@ -17,5 +19,9 @@ import java.util.List;
public interface SkuFeignClient {
@GetMapping("/api/search/sku/inner/findHotSkuList")
public List<SkuEs> findHotSkuList();
List<SkuEs> findHotSkuList();
@ApiOperation(value = "更新商品热度")
@GetMapping("/api/search/sku/inner/incrHotScore/{skuId}")
Boolean incrHotScore(@PathVariable("skuId") Long skuId);
}

View File

@ -4,10 +4,7 @@ import com.atguigu.ssyx.activity.service.ActivityInfoService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@ -34,4 +31,10 @@ public class ActivityApiController {
public Map<Long, List<String>> findActivity(@RequestBody List<Long> skuIdList) {
return activityInfoService.findActivity(skuIdList);
}
@ApiOperation("根据skuID获取营销数据和优惠卷")
@GetMapping("inner/findActivityAndCoupon/{skuId}/{userId}")
public Map<String, Object> findActivityAndCoupon(@PathVariable Long skuId, @PathVariable Long userId) {
return activityInfoService.findActivityAndCoupon(skuId, userId);
}
}

View File

@ -2,6 +2,9 @@ package com.atguigu.ssyx.activity.mapper;
import com.atguigu.ssyx.model.activity.CouponInfo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* <p>
@ -13,4 +16,14 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
*/
public interface CouponInfoMapper extends BaseMapper<CouponInfo> {
/**
* 根据条件查询skuId + 分类id + userId
*
* @param id
* @param categoryId
* @param userId
* @return
*/
List<CouponInfo> selectCouponInfoList(
@Param("skuId") Long id, @Param("categoryId") Long categoryId, @Param("userId") Long userId);
}

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.ssyx.activity.mapper.CouponInfoMapper">
</mapper>

View File

@ -60,4 +60,13 @@ public interface ActivityInfoService extends IService<ActivityInfo> {
* @return
*/
Map<Long, List<String>> findActivity(List<Long> skuIdList);
/**
* 根据skuID获取营销数据和优惠卷
*
* @param skuId
* @param userId
* @return
*/
Map<String, Object> findActivityAndCoupon(Long skuId, Long userId);
}

View File

@ -58,4 +58,14 @@ public interface CouponInfoService extends IService<CouponInfo> {
* @return
*/
List<CouponInfo> findCouponByKeyword(String keyword);
/**
* 根据skuId+userId查询优惠卷信息
*
* @param skuId
* @param userId
* @return
*/
List<CouponInfo> findCouponInfoList(Long skuId, Long userId);
}

View File

@ -4,11 +4,13 @@ import com.atguigu.ssyx.activity.mapper.ActivityInfoMapper;
import com.atguigu.ssyx.activity.mapper.ActivityRuleMapper;
import com.atguigu.ssyx.activity.mapper.ActivitySkuMapper;
import com.atguigu.ssyx.activity.service.ActivityInfoService;
import com.atguigu.ssyx.activity.service.CouponInfoService;
import com.atguigu.ssyx.client.product.ProductFeignClient;
import com.atguigu.ssyx.enums.ActivityType;
import com.atguigu.ssyx.model.activity.ActivityInfo;
import com.atguigu.ssyx.model.activity.ActivityRule;
import com.atguigu.ssyx.model.activity.ActivitySku;
import com.atguigu.ssyx.model.activity.CouponInfo;
import com.atguigu.ssyx.model.product.SkuInfo;
import com.atguigu.ssyx.vo.activity.ActivityRuleVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@ -51,6 +53,9 @@ public class ActivityInfoServiceImpl extends ServiceImpl<ActivityInfoMapper, Act
@Autowired
private ProductFeignClient productFeignClient;
@Autowired
private CouponInfoService couponInfoService;
/**
* 优惠活动列表方法
*
@ -72,7 +77,7 @@ public class ActivityInfoServiceImpl extends ServiceImpl<ActivityInfoMapper, Act
}
/**
* 活动规则列表方法
* 根据活动Id查询活动规则列表方法
*
* @param activityId
* @return
@ -172,6 +177,7 @@ public class ActivityInfoServiceImpl extends ServiceImpl<ActivityInfoMapper, Act
return findSkuList;
}
//拼接文字
private String getRuleDesc(ActivityRule activityRule) {
ActivityType activityType = activityRule.getActivityType();
StringBuffer ruleDesc = new StringBuffer();
@ -216,4 +222,37 @@ public class ActivityInfoServiceImpl extends ServiceImpl<ActivityInfoMapper, Act
});
return result;
}
/**
* 根据skuID获取营销数据和优惠卷
*
* @param skuId
* @param userId
* @return
*/
@Override
public Map<String, Object> findActivityAndCoupon(Long skuId, Long userId) {
//1 根据skuId获取sku营销活动一个活动有多个规则
List<ActivityRule> activityRuleList = this.findActivityRuleBySkuId(skuId);
//2 根据skuId+userId查询优惠卷信息
List<CouponInfo> couponInfoList = couponInfoService.findCouponInfoList(skuId, userId);
//3 封装到map集合返回
Map<String, Object> map = new HashMap<>();
map.put("couponInfoList", couponInfoList);
map.put("activityRuleList", activityRuleList);
return map;
}
//根据skuId获取活动规则数据
public List<ActivityRule> findActivityRuleBySkuId(Long skuId) {
List<ActivityRule> activityRuleList = baseMapper.findActivityRule(skuId);
for (ActivityRule activityRule : activityRuleList) {
String ruleDesc = this.getRuleDesc(activityRule);
activityRule.setRuleDesc(ruleDesc);
}
return activityRuleList;
}
}

View File

@ -120,6 +120,11 @@ public class CouponInfoServiceImpl extends ServiceImpl<CouponInfoMapper, CouponI
return result;
}
/**
* 新增优惠券规则
*
* @param couponRuleVo
*/
@Override
public void saveCouponRule(CouponRuleVo couponRuleVo) {
//优惠券couponInfo couponRange 要一起操作先删除couponRange 更新couponInfo 再新增couponRange
@ -149,4 +154,22 @@ public class CouponInfoServiceImpl extends ServiceImpl<CouponInfoMapper, CouponI
public List<CouponInfo> findCouponByKeyword(String keyword) {
return baseMapper.selectList(new LambdaQueryWrapper<CouponInfo>().like(CouponInfo::getCouponName, keyword));
}
/**
* 根据skuId+userId查询优惠卷信息
*
* @param skuId
* @param userId
* @return
*/
@Override
public List<CouponInfo> findCouponInfoList(Long skuId, Long userId) {
//远程调用根据skuId获取skuInfo
SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
//根据条件查询skuId + 分类id + userId
List<CouponInfo> couponInfoList = baseMapper.selectCouponInfoList(skuInfo.getId(), skuInfo.getCategoryId(), userId);
return couponInfoList;
}
}

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.ssyx.activity.mapper.CouponInfoMapper">
<resultMap id="CouponInfoMap" type="com.atguigu.ssyx.model.activity.CouponInfo" autoMapping="true"></resultMap>
<!--//1 根据userId获取用户全部优惠卷-->
<select id="selectCartCouponInfoList" resultMap="CouponInfoMap">
select info.id,
info.coupon_type,
info.coupon_name,
info.amount,
info.condition_amount,
info.start_time,
info.end_time,
info.range_type,
info.range_desc,
info.publish_count,
info.per_limit,
info.use_count,
info.receive_count,
info.expire_time,
info.publish_status,
info.create_time,
info.update_time,
info.is_deleted,
cuse.coupon_status
from coupon_use cuse
inner join coupon_info info on cuse.coupon_id = info.id
<where>
and cuse.user_id = #{userId}
and info.expire_time >= now()
</where>
order by info.amount desc
</select>
<!--//2 根据skuId+分类id+userId查询优惠卷信息-->
<select id="selectCouponInfoList" resultMap="CouponInfoMap">
select info.id,
info.coupon_type,
info.coupon_name,
info.amount,
info.condition_amount,
info.start_time,
info.end_time,
info.range_type,
info.range_desc,
info.publish_count,
info.per_limit,
info.use_count,
info.receive_count,
info.expire_time,
info.publish_status,
info.create_time,
info.update_time,
info.is_deleted,
cuse.coupon_status
from coupon_info info
left join coupon_range crange on info.id = crange.coupon_id
left join coupon_use cuse on info.id = cuse.coupon_id and cuse.user_id = #{userId}
where (info.range_type = 1 or (info.range_type = 2 and crange.range_id = #{skuId})
or (info.range_type = 3 and crange.range_id = #{categoryId})
)
and info.is_deleted = 0
and crange.is_deleted = 0
and cuse.is_deleted = 0
and now() between info.start_time and info.end_time
order by info.amount desc
</select>
</mapper>

View File

@ -35,6 +35,16 @@
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>service-activity-client</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,26 @@
package com.atguigu.ssyx.home.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* ClassName: ThreadPoolConfig
* Package: com.atguigu.ssyx.home.config
*
* @author yovinchen
* @Create 2023/10/8 14:47
*/
@Configuration
public class ThreadPoolConfig {
@Bean
public ThreadPoolExecutor threadPoolExecutor() {
return new ThreadPoolExecutor(2, 5, 2, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
}
}

View File

@ -4,10 +4,12 @@ import com.atguigu.ssyx.client.product.ProductFeignClient;
import com.atguigu.ssyx.common.auth.AuthContextHolder;
import com.atguigu.ssyx.common.result.Result;
import com.atguigu.ssyx.home.service.HomeService;
import com.atguigu.ssyx.home.service.ItemService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@ -27,7 +29,8 @@ import java.util.Map;
@RestController
@RequestMapping("api/home")
public class HomeApiController {
@Autowired
private ItemService itemService;
@Resource
private ProductFeignClient productFeignClient;
@Autowired
@ -42,13 +45,18 @@ public class HomeApiController {
return Result.ok(map);
}
@ApiOperation(value = "获取分类信息")
@GetMapping("category")
public Result category() {
return Result.ok(productFeignClient.findAllCategoryList());
}
@GetMapping("item/{id}")
@ApiOperation("商品详情")
public Result index(@PathVariable Long id) {
Long userId = AuthContextHolder.getUserId();
Map<String, Object> map = itemService.item(id, userId);
return Result.ok(map);
}
}

View File

@ -0,0 +1,21 @@
package com.atguigu.ssyx.home.service;
import java.util.Map;
/**
* ClassName: ItemService
* Package: com.atguigu.ssyx.home.service
*
* @author yovinchen
* @Create 2023/10/7 15:01
*/
public interface ItemService {
/**
* 商品详情
*
* @param skuId
* @param userId
* @return
*/
Map<String, Object> item(Long skuId, Long userId);
}

View File

@ -0,0 +1,75 @@
package com.atguigu.ssyx.home.service.impl;
import com.atguigu.ssyx.client.activity.ActivityFeignClient;
import com.atguigu.ssyx.client.product.ProductFeignClient;
import com.atguigu.ssyx.client.search.SkuFeignClient;
import com.atguigu.ssyx.home.service.ItemService;
import com.atguigu.ssyx.vo.product.SkuInfoVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
/**
* ClassName: ItemServiceImpl
* Package: com.atguigu.ssyx.home.service.impl
*
* @author yovinchen
* @Create 2023/10/7 15:02
*/
@Service
public class ItemServiceImpl implements ItemService {
@Autowired
private ProductFeignClient productFeignClient;
@Autowired
private ActivityFeignClient activityFeignClient;
@Autowired
private SkuFeignClient skuFeignClient;
@Resource
private ThreadPoolExecutor threadPoolExecutor;
/**
* 商品详情
*
* @param skuId
* @param userId
* @return
*/
@Override
public Map<String, Object> item(Long skuId, Long userId) {
Map<String, Object> result = new HashMap<>();
//skuId查询
CompletableFuture<SkuInfoVo> skuInfocompletableFuture = CompletableFuture.supplyAsync(() -> {
//远程调用获取sku对应数据
SkuInfoVo skuInfoVo = productFeignClient.getSkuInfoVo(skuId);
result.put("skuInfoVo", skuInfoVo);
return skuInfoVo;
}, threadPoolExecutor);
//sku对应优惠卷信息
CompletableFuture<Void> activityCompletableFuture = CompletableFuture.runAsync(() -> {
//远程调用获取优惠卷
Map<String, Object> activityMap = activityFeignClient.findActivityAndCoupon(skuId, userId);
result.putAll(activityMap);
}, threadPoolExecutor);
//更新商品热度
CompletableFuture<Void> hotCompletableFuture = CompletableFuture.runAsync(() -> {
//远程调用更新热度
skuFeignClient.incrHotScore(skuId);
}, threadPoolExecutor);
//任务组合
CompletableFuture.allOf(skuInfocompletableFuture, activityCompletableFuture, hotCompletableFuture)
.join();
return result;
}
}

View File

@ -1,5 +1,6 @@
server:
port: 8207
feign:
sentinel:
enabled: true

View File

@ -4,6 +4,7 @@ import com.atguigu.ssyx.model.product.Category;
import com.atguigu.ssyx.model.product.SkuInfo;
import com.atguigu.ssyx.product.service.CategoryService;
import com.atguigu.ssyx.product.service.SkuInfoService;
import com.atguigu.ssyx.vo.product.SkuInfoVo;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@ -68,4 +69,10 @@ public class ProductInnnerController {
public List<SkuInfo> findNewPersonSkuInfoList() {
return skuInfoService.findNewPersonSkuInfoList();
}
@ApiOperation(value = "根据skuId获取sku信息")
@GetMapping("inner/getSkuInfoVo/{skuId}")
public SkuInfoVo getSkuInfoVo(@PathVariable Long skuId) {
return skuInfoService.getSkuInfoVo(skuId);
}
}

View File

@ -35,7 +35,7 @@ public interface SkuInfoService extends IService<SkuInfo> {
void saveSkuInfo(SkuInfoVo skuInfoVo);
/**
* 获取商品sku信息
* 根据id获取商品sku信息
*
* @param id
* @return

View File

@ -134,7 +134,6 @@ public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoMapper, SkuInfo> impl
/**
* 修改商品sku信息
*
* @param skuInfoVo
*/
@Override

View File

@ -62,4 +62,11 @@ public class SkuApiController {
Page<SkuEs> pageModel = skuService.search(pageable, searchParamVo);
return Result.ok(pageModel);
}
@ApiOperation(value = "更新商品热度")
@GetMapping("inner/incrHotScore/{skuId}")
public Boolean incrHotScore(@PathVariable("skuId") Long skuId) {
skuService.incrHotScore(skuId);
return true;
}
}

View File

@ -48,4 +48,11 @@ public interface SkuService {
* @return
*/
Page<SkuEs> search(Pageable pageable, SkuEsQueryVo searchParamVo);
/**
* 更新商品热度
*
* @param skuId
*/
void incrHotScore(Long skuId);
}

View File

@ -16,6 +16,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
@ -23,6 +24,7 @@ import org.springframework.util.StringUtils;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
/**
@ -38,12 +40,16 @@ public class SkuServiceImpl implements SkuService {
@Autowired
private ProductFeignClient productFeignClient;
@Autowired
private ActivityFeignClient activityFeignClient;
@Autowired
private SkuRepository skuRepository;
@Autowired
private RedisTemplate redisTemplate;
/**
* 上架商品列表
*
@ -155,4 +161,25 @@ public class SkuServiceImpl implements SkuService {
return pageModel;
}
/**
* 更新商品热度
*
* @param skuId
*/
@Override
public void incrHotScore(Long skuId) {
String key = "hotScore";
//redis保存数据每次+1
Double hotScore = redisTemplate.opsForZSet()
.incrementScore(key, "skuId:" + skuId, 1);
//规则
if (hotScore % 10 == 0) {
//更新es
Optional<SkuEs> optional = skuRepository.findById(skuId);
SkuEs skuEs = optional.get();
skuEs.setHotScore(Math.round(hotScore));
skuRepository.save(skuEs);
}
}
}