Commit f374e778bb5d7c70d6ffc08ee2f02ad91f183093
1 parent
86a9c4bb
商品:增加商品浏览记录
Showing
16 changed files
with
550 additions
and
3 deletions
sql/mysql/optinal/product_browse_history.sql
0 → 100644
| 1 | +CREATE TABLE product_browse_history | |
| 2 | +( | |
| 3 | + id bigint AUTO_INCREMENT COMMENT '记录编号' | |
| 4 | + PRIMARY KEY, | |
| 5 | + user_id bigint NOT NULL COMMENT '用户编号', | |
| 6 | + spu_id bigint NOT NULL COMMENT '商品 SPU 编号', | |
| 7 | + user_deleted bit DEFAULT b'0' NOT NULL COMMENT '用户是否删除', | |
| 8 | + creator varchar(64) DEFAULT '' NULL COMMENT '创建者', | |
| 9 | + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL COMMENT '创建时间', | |
| 10 | + updater varchar(64) DEFAULT '' NULL COMMENT '更新者', | |
| 11 | + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', | |
| 12 | + deleted bit DEFAULT b'0' NOT NULL COMMENT '是否删除', | |
| 13 | + tenant_id bigint DEFAULT 0 NOT NULL COMMENT '租户编号' | |
| 14 | +) | |
| 15 | + COMMENT '商品浏览记录表'; | |
| 16 | + | |
| 17 | +CREATE INDEX idx_spuId | |
| 18 | + ON product_browse_history (spu_id); | |
| 19 | + | |
| 20 | +CREATE INDEX idx_userId | |
| 21 | + ON product_browse_history (user_id); | |
| 22 | + | ... | ... |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/history/ProductBrowseHistoryController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.product.controller.admin.history; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 5 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 6 | +import cn.iocoder.yudao.module.product.controller.admin.history.vo.ProductBrowseHistoryPageReqVO; | |
| 7 | +import cn.iocoder.yudao.module.product.controller.admin.history.vo.ProductBrowseHistoryRespVO; | |
| 8 | +import cn.iocoder.yudao.module.product.dal.dataobject.history.ProductBrowseHistoryDO; | |
| 9 | +import cn.iocoder.yudao.module.product.service.history.ProductBrowseHistoryService; | |
| 10 | +import io.swagger.v3.oas.annotations.Operation; | |
| 11 | +import io.swagger.v3.oas.annotations.tags.Tag; | |
| 12 | +import jakarta.annotation.Resource; | |
| 13 | +import jakarta.validation.Valid; | |
| 14 | +import org.springframework.security.access.prepost.PreAuthorize; | |
| 15 | +import org.springframework.validation.annotation.Validated; | |
| 16 | +import org.springframework.web.bind.annotation.GetMapping; | |
| 17 | +import org.springframework.web.bind.annotation.RequestMapping; | |
| 18 | +import org.springframework.web.bind.annotation.RestController; | |
| 19 | + | |
| 20 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | |
| 21 | + | |
| 22 | +@Tag(name = "管理后台 - 商品浏览记录") | |
| 23 | +@RestController | |
| 24 | +@RequestMapping("/product/browse-history") | |
| 25 | +@Validated | |
| 26 | +public class ProductBrowseHistoryController { | |
| 27 | + | |
| 28 | + @Resource | |
| 29 | + private ProductBrowseHistoryService browseHistoryService; | |
| 30 | + | |
| 31 | + @GetMapping("/page") | |
| 32 | + @Operation(summary = "获得商品浏览记录分页") | |
| 33 | + @PreAuthorize("@ss.hasPermission('product:browse-history:query')") | |
| 34 | + public CommonResult<PageResult<ProductBrowseHistoryRespVO>> getBrowseHistoryPage(@Valid ProductBrowseHistoryPageReqVO pageReqVO) { | |
| 35 | + PageResult<ProductBrowseHistoryDO> pageResult = browseHistoryService.getBrowseHistoryPage(pageReqVO); | |
| 36 | + return success(BeanUtils.toBean(pageResult, ProductBrowseHistoryRespVO.class)); | |
| 37 | + } | |
| 38 | + | |
| 39 | +} | |
| 0 | 40 | \ No newline at end of file | ... | ... |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/history/vo/ProductBrowseHistoryPageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.product.controller.admin.history.vo; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.SortablePageParam; | |
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | +import lombok.Data; | |
| 6 | +import lombok.EqualsAndHashCode; | |
| 7 | +import lombok.ToString; | |
| 8 | +import org.springframework.format.annotation.DateTimeFormat; | |
| 9 | + | |
| 10 | +import java.time.LocalDateTime; | |
| 11 | + | |
| 12 | +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | |
| 13 | + | |
| 14 | +@Schema(description = "管理后台 - 商品浏览记录分页 Request VO") | |
| 15 | +@Data | |
| 16 | +@EqualsAndHashCode(callSuper = true) | |
| 17 | +@ToString(callSuper = true) | |
| 18 | +public class ProductBrowseHistoryPageReqVO extends SortablePageParam { | |
| 19 | + | |
| 20 | + @Schema(description = "用户编号", example = "4314") | |
| 21 | + private Long userId; | |
| 22 | + | |
| 23 | + @Schema(description = "用户是否删除", example = "false") | |
| 24 | + private Boolean userDeleted; | |
| 25 | + | |
| 26 | + @Schema(description = "商品 SPU 编号", example = "42") | |
| 27 | + private Long spuId; | |
| 28 | + | |
| 29 | + @Schema(description = "创建时间") | |
| 30 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 31 | + private LocalDateTime[] createTime; | |
| 32 | + | |
| 33 | +} | |
| 0 | 34 | \ No newline at end of file | ... | ... |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/history/vo/ProductBrowseHistoryRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.product.controller.admin.history.vo; | |
| 2 | + | |
| 3 | +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | +import com.alibaba.excel.annotation.ExcelProperty; | |
| 5 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 6 | +import lombok.Data; | |
| 7 | + | |
| 8 | +import java.time.LocalDateTime; | |
| 9 | + | |
| 10 | +@Schema(description = "管理后台 - 商品浏览记录 Response VO") | |
| 11 | +@Data | |
| 12 | +@ExcelIgnoreUnannotated | |
| 13 | +public class ProductBrowseHistoryRespVO { | |
| 14 | + | |
| 15 | + @Schema(description = "记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26055") | |
| 16 | + @ExcelProperty("记录编号") | |
| 17 | + private Long id; | |
| 18 | + | |
| 19 | + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4314") | |
| 20 | + @ExcelProperty("用户编号") | |
| 21 | + private Long userId; | |
| 22 | + | |
| 23 | + @Schema(description = "用户是否删除", example = "false") | |
| 24 | + private Boolean userDeleted; | |
| 25 | + | |
| 26 | + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "42") | |
| 27 | + @ExcelProperty("商品 SPU 编号") | |
| 28 | + private Long spuId; | |
| 29 | + | |
| 30 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 31 | + @ExcelProperty("创建时间") | |
| 32 | + private LocalDateTime createTime; | |
| 33 | + | |
| 34 | +} | |
| 0 | 35 | \ No newline at end of file | ... | ... |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/history/AppProductBrowseHistoryController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.product.controller.app.history; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 5 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 6 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 7 | +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; | |
| 8 | +import cn.iocoder.yudao.module.product.controller.admin.history.vo.ProductBrowseHistoryPageReqVO; | |
| 9 | +import cn.iocoder.yudao.module.product.controller.app.history.vo.AppProductBrowseHistoryDeleteReqVO; | |
| 10 | +import cn.iocoder.yudao.module.product.controller.app.history.vo.AppProductBrowseHistoryPageReqVO; | |
| 11 | +import cn.iocoder.yudao.module.product.controller.app.history.vo.AppProductBrowseHistoryRespVO; | |
| 12 | +import cn.iocoder.yudao.module.product.dal.dataobject.history.ProductBrowseHistoryDO; | |
| 13 | +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; | |
| 14 | +import cn.iocoder.yudao.module.product.service.history.ProductBrowseHistoryService; | |
| 15 | +import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; | |
| 16 | +import io.swagger.v3.oas.annotations.Operation; | |
| 17 | +import io.swagger.v3.oas.annotations.tags.Tag; | |
| 18 | +import jakarta.annotation.Resource; | |
| 19 | +import jakarta.validation.Valid; | |
| 20 | +import org.springframework.web.bind.annotation.*; | |
| 21 | + | |
| 22 | +import java.util.Map; | |
| 23 | +import java.util.Optional; | |
| 24 | +import java.util.Set; | |
| 25 | + | |
| 26 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | |
| 27 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | |
| 28 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | |
| 29 | +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | |
| 30 | + | |
| 31 | +@Tag(name = "用户 APP - 商品浏览记录") | |
| 32 | +@RestController | |
| 33 | +@RequestMapping("/product/browse-history") | |
| 34 | +public class AppProductBrowseHistoryController { | |
| 35 | + | |
| 36 | + @Resource | |
| 37 | + private ProductBrowseHistoryService productBrowseHistoryService; | |
| 38 | + @Resource | |
| 39 | + private ProductSpuService productSpuService; | |
| 40 | + | |
| 41 | + @DeleteMapping(value = "/delete") | |
| 42 | + @Operation(summary = "删除商品浏览记录") | |
| 43 | + @PreAuthenticated | |
| 44 | + public CommonResult<Boolean> deleteBrowseHistory(@RequestBody @Valid AppProductBrowseHistoryDeleteReqVO reqVO) { | |
| 45 | + productBrowseHistoryService.hideUserBrowseHistory(getLoginUserId(), reqVO.getSpuIds()); | |
| 46 | + return success(Boolean.TRUE); | |
| 47 | + } | |
| 48 | + | |
| 49 | + @DeleteMapping(value = "/clean") | |
| 50 | + @Operation(summary = "清空商品浏览记录") | |
| 51 | + @PreAuthenticated | |
| 52 | + public CommonResult<Boolean> cleanBrowseHistory() { | |
| 53 | + productBrowseHistoryService.hideUserBrowseHistory(getLoginUserId(), null); | |
| 54 | + return success(Boolean.TRUE); | |
| 55 | + } | |
| 56 | + | |
| 57 | + @GetMapping(value = "/get-count") | |
| 58 | + @Operation(summary = "获得商品浏览记录数量") | |
| 59 | + @PreAuthenticated | |
| 60 | + public CommonResult<Long> getBrowseHistoryCount() { | |
| 61 | + return success(productBrowseHistoryService.getBrowseHistoryCount(getLoginUserId(), false)); | |
| 62 | + } | |
| 63 | + | |
| 64 | + @GetMapping(value = "/page") | |
| 65 | + @Operation(summary = "获得商品浏览记录分页") | |
| 66 | + @PreAuthenticated | |
| 67 | + public CommonResult<PageResult<AppProductBrowseHistoryRespVO>> getBrowseHistoryPage(AppProductBrowseHistoryPageReqVO reqVO) { | |
| 68 | + ProductBrowseHistoryPageReqVO pageReqVO = BeanUtils.toBean(reqVO, ProductBrowseHistoryPageReqVO.class); | |
| 69 | + pageReqVO.setUserId(getLoginUserId()); | |
| 70 | + // 排除用户已删除的(隐藏的) | |
| 71 | + pageReqVO.setUserDeleted(false); | |
| 72 | + PageResult<ProductBrowseHistoryDO> pageResult = productBrowseHistoryService.getBrowseHistoryPage(pageReqVO); | |
| 73 | + if (CollUtil.isEmpty(pageResult.getList())) { | |
| 74 | + return success(PageResult.empty()); | |
| 75 | + } | |
| 76 | + | |
| 77 | + // 得到商品 spu 信息 | |
| 78 | + Set<Long> spuIds = convertSet(pageResult.getList(), ProductBrowseHistoryDO::getSpuId); | |
| 79 | + Map<Long, ProductSpuDO> spuMap = convertMap(productSpuService.getSpuList(spuIds), ProductSpuDO::getId); | |
| 80 | + | |
| 81 | + // 转换 VO 结果 | |
| 82 | + PageResult<AppProductBrowseHistoryRespVO> result = BeanUtils.toBean(pageResult, AppProductBrowseHistoryRespVO.class, | |
| 83 | + vo -> Optional.ofNullable(spuMap.get(vo.getSpuId())).ifPresent(spu -> { | |
| 84 | + vo.setSpuName(spu.getName()); | |
| 85 | + vo.setPicUrl(spu.getPicUrl()); | |
| 86 | + })); | |
| 87 | + return success(result); | |
| 88 | + } | |
| 89 | + | |
| 90 | +} | ... | ... |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/history/vo/AppProductBrowseHistoryDeleteReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.product.controller.app.history.vo; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import jakarta.validation.constraints.NotEmpty; | |
| 5 | +import lombok.Data; | |
| 6 | + | |
| 7 | +import java.util.List; | |
| 8 | + | |
| 9 | +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; | |
| 10 | + | |
| 11 | +@Schema(description = "用户 APP - 删除商品浏览记录的 Request VO") | |
| 12 | +@Data | |
| 13 | +public class AppProductBrowseHistoryDeleteReqVO { | |
| 14 | + | |
| 15 | + @Schema(description = "商品 SPU 编号数组", requiredMode = REQUIRED, example = "29502") | |
| 16 | + @NotEmpty(message = "商品 SPU 编号数组不能为空") | |
| 17 | + private List<Long> spuIds; | |
| 18 | + | |
| 19 | +} | ... | ... |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/history/vo/AppProductBrowseHistoryPageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.product.controller.app.history.vo; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | |
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | +import lombok.Data; | |
| 6 | +import lombok.EqualsAndHashCode; | |
| 7 | +import lombok.ToString; | |
| 8 | +import org.springframework.format.annotation.DateTimeFormat; | |
| 9 | + | |
| 10 | +import java.time.LocalDateTime; | |
| 11 | + | |
| 12 | +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | |
| 13 | + | |
| 14 | +@Schema(description = "用户 APP - 商品浏览记录分页 Request VO") | |
| 15 | +@Data | |
| 16 | +@EqualsAndHashCode(callSuper = true) | |
| 17 | +@ToString(callSuper = true) | |
| 18 | +public class AppProductBrowseHistoryPageReqVO extends PageParam { | |
| 19 | + @Schema(description = "创建时间") | |
| 20 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 21 | + private LocalDateTime[] createTime; | |
| 22 | + | |
| 23 | +} | |
| 0 | 24 | \ No newline at end of file | ... | ... |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/history/vo/AppProductBrowseHistoryRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.product.controller.app.history.vo; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; | |
| 7 | + | |
| 8 | +@Schema(description = "用户 App - 商品浏览记录 Response VO") | |
| 9 | +@Data | |
| 10 | +public class AppProductBrowseHistoryRespVO { | |
| 11 | + | |
| 12 | + @Schema(description = "编号", requiredMode = REQUIRED, example = "1") | |
| 13 | + private Long id; | |
| 14 | + | |
| 15 | + @Schema(description = "商品 SPU 编号", requiredMode = REQUIRED, example = "29502") | |
| 16 | + private Long spuId; | |
| 17 | + | |
| 18 | + // ========== 商品相关字段 ========== | |
| 19 | + | |
| 20 | + @Schema(description = "商品 SPU 名称", example = "赵六") | |
| 21 | + private String spuName; | |
| 22 | + | |
| 23 | + @Schema(description = "商品封面图", example = "https://domain/pic.png") | |
| 24 | + private String picUrl; | |
| 25 | + | |
| 26 | + @Schema(description = "商品单价", example = "100") | |
| 27 | + private Integer price; | |
| 28 | + | |
| 29 | +} | ... | ... |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java
| ... | ... | @@ -14,6 +14,7 @@ import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert; |
| 14 | 14 | import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; |
| 15 | 15 | import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; |
| 16 | 16 | import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; |
| 17 | +import cn.iocoder.yudao.module.product.service.history.ProductBrowseHistoryService; | |
| 17 | 18 | import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; |
| 18 | 19 | import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; |
| 19 | 20 | import io.swagger.v3.oas.annotations.Operation; |
| ... | ... | @@ -48,6 +49,8 @@ public class AppProductSpuController { |
| 48 | 49 | private ProductSpuService productSpuService; |
| 49 | 50 | @Resource |
| 50 | 51 | private ProductSkuService productSkuService; |
| 52 | + @Resource | |
| 53 | + private ProductBrowseHistoryService productBrowseHistoryService; | |
| 51 | 54 | |
| 52 | 55 | @Resource |
| 53 | 56 | private MemberLevelApi memberLevelApi; |
| ... | ... | @@ -122,6 +125,11 @@ public class AppProductSpuController { |
| 122 | 125 | throw exception(SPU_NOT_ENABLE); |
| 123 | 126 | } |
| 124 | 127 | |
| 128 | + // 增加浏览量 | |
| 129 | + productSpuService.updateBrowseCount(id, 1); | |
| 130 | + // 保存浏览记录 | |
| 131 | + productBrowseHistoryService.createBrowseHistory(getLoginUserId(), id); | |
| 132 | + | |
| 125 | 133 | // 拼接返回 |
| 126 | 134 | List<ProductSkuDO> skus = productSkuService.getSkuListBySpuId(spu.getId()); |
| 127 | 135 | AppProductSpuDetailRespVO detailVO = ProductSpuConvert.INSTANCE.convertForGetSpuDetail(spu, skus); | ... | ... |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/history/ProductBrowseHistoryDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.product.dal.dataobject.history; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | |
| 4 | +import com.baomidou.mybatisplus.annotation.KeySequence; | |
| 5 | +import com.baomidou.mybatisplus.annotation.TableId; | |
| 6 | +import com.baomidou.mybatisplus.annotation.TableName; | |
| 7 | +import lombok.*; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * 商品浏览记录 DO | |
| 11 | + * | |
| 12 | + * @author owen | |
| 13 | + */ | |
| 14 | +@TableName("product_browse_history") | |
| 15 | +@KeySequence("product_browse_history_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | |
| 16 | +@Data | |
| 17 | +@EqualsAndHashCode(callSuper = true) | |
| 18 | +@ToString(callSuper = true) | |
| 19 | +@Builder | |
| 20 | +@NoArgsConstructor | |
| 21 | +@AllArgsConstructor | |
| 22 | +public class ProductBrowseHistoryDO extends BaseDO { | |
| 23 | + | |
| 24 | + /** | |
| 25 | + * 记录编号 | |
| 26 | + */ | |
| 27 | + @TableId | |
| 28 | + private Long id; | |
| 29 | + /** | |
| 30 | + * 商品 SPU 编号 | |
| 31 | + */ | |
| 32 | + private Long spuId; | |
| 33 | + /** | |
| 34 | + * 用户编号 | |
| 35 | + */ | |
| 36 | + private Long userId; | |
| 37 | + /** | |
| 38 | + * 用户是否删除 | |
| 39 | + */ | |
| 40 | + private Boolean userDeleted; | |
| 41 | + | |
| 42 | +} | |
| 0 | 43 | \ No newline at end of file | ... | ... |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/history/ProductBrowseHistoryMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.product.dal.mysql.history; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | |
| 6 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | |
| 7 | +import cn.iocoder.yudao.module.product.controller.admin.history.vo.ProductBrowseHistoryPageReqVO; | |
| 8 | +import cn.iocoder.yudao.module.product.dal.dataobject.history.ProductBrowseHistoryDO; | |
| 9 | +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | |
| 10 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | |
| 11 | +import org.apache.ibatis.annotations.Mapper; | |
| 12 | + | |
| 13 | +import java.util.Collection; | |
| 14 | + | |
| 15 | +/** | |
| 16 | + * 商品浏览记录 Mapper | |
| 17 | + * | |
| 18 | + * @author owen | |
| 19 | + */ | |
| 20 | +@Mapper | |
| 21 | +public interface ProductBrowseHistoryMapper extends BaseMapperX<ProductBrowseHistoryDO> { | |
| 22 | + | |
| 23 | + default PageResult<ProductBrowseHistoryDO> selectPage(ProductBrowseHistoryPageReqVO reqVO) { | |
| 24 | + return selectPage(reqVO, new LambdaQueryWrapperX<ProductBrowseHistoryDO>() | |
| 25 | + .eqIfPresent(ProductBrowseHistoryDO::getUserId, reqVO.getUserId()) | |
| 26 | + .eqIfPresent(ProductBrowseHistoryDO::getUserDeleted, reqVO.getUserDeleted()) | |
| 27 | + .eqIfPresent(ProductBrowseHistoryDO::getSpuId, reqVO.getSpuId()) | |
| 28 | + .betweenIfPresent(ProductBrowseHistoryDO::getCreateTime, reqVO.getCreateTime()) | |
| 29 | + .orderByDesc(ProductBrowseHistoryDO::getId)); | |
| 30 | + } | |
| 31 | + | |
| 32 | + default void updateUserDeletedByUserId(Long userId, Collection<Long> spuIds, Boolean userDeleted) { | |
| 33 | + update(new LambdaUpdateWrapper<ProductBrowseHistoryDO>() | |
| 34 | + .eq(ProductBrowseHistoryDO::getUserId, userId) | |
| 35 | + .in(CollUtil.isNotEmpty(spuIds), ProductBrowseHistoryDO::getSpuId, spuIds) | |
| 36 | + .set(ProductBrowseHistoryDO::getUserDeleted, userDeleted)); | |
| 37 | + } | |
| 38 | + | |
| 39 | + default Long selectCountByUserIdAndUserDeleted(Long userId, Boolean userDeleted) { | |
| 40 | + return selectCount(new LambdaQueryWrapperX<ProductBrowseHistoryDO>() | |
| 41 | + .eq(ProductBrowseHistoryDO::getUserId, userId) | |
| 42 | + .eqIfPresent(ProductBrowseHistoryDO::getUserDeleted, userDeleted)); | |
| 43 | + } | |
| 44 | + | |
| 45 | + default Page<ProductBrowseHistoryDO> selectPageByUserIdOrderByCreateTimeAsc(Long userId) { | |
| 46 | + Page<ProductBrowseHistoryDO> page = Page.of(0, 1); | |
| 47 | + return selectPage(page, new LambdaQueryWrapperX<ProductBrowseHistoryDO>() | |
| 48 | + .eqIfPresent(ProductBrowseHistoryDO::getUserId, userId) | |
| 49 | + .orderByAsc(ProductBrowseHistoryDO::getCreateTime)); | |
| 50 | + } | |
| 51 | + | |
| 52 | +} | |
| 0 | 53 | \ No newline at end of file | ... | ... |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java
| ... | ... | @@ -71,7 +71,7 @@ public interface ProductSpuMapper extends BaseMapperX<ProductSpuDO> { |
| 71 | 71 | query.eq(ProductSpuDO::getRecommendBenefit, true); |
| 72 | 72 | } else if (ObjUtil.equal(pageReqVO.getRecommendType(), AppProductSpuPageReqVO.RECOMMEND_TYPE_BEST)) { |
| 73 | 73 | query.eq(ProductSpuDO::getRecommendBest, true); |
| 74 | - } else if (ObjUtil.equal(pageReqVO.getRecommendType(), AppProductSpuPageReqVO.RECOMMEND_TYPE_NEW)) { | |
| 74 | + } else if (ObjUtil.equal(pageReqVO.getRecommendType(), AppProductSpuPageReqVO.RECOMMEND_TYPE_NEW)) { | |
| 75 | 75 | query.eq(ProductSpuDO::getRecommendNew, true); |
| 76 | 76 | } else if (ObjUtil.equal(pageReqVO.getRecommendType(), AppProductSpuPageReqVO.RECOMMEND_TYPE_GOOD)) { |
| 77 | 77 | query.eq(ProductSpuDO::getRecommendGood, true); |
| ... | ... | @@ -141,8 +141,8 @@ public interface ProductSpuMapper extends BaseMapperX<ProductSpuDO> { |
| 141 | 141 | /** |
| 142 | 142 | * 添加后台 Tab 选项的查询条件 |
| 143 | 143 | * |
| 144 | - * @param tabType 标签类型 | |
| 145 | - * @param query 查询条件 | |
| 144 | + * @param tabType 标签类型 | |
| 145 | + * @param query 查询条件 | |
| 146 | 146 | */ |
| 147 | 147 | static void appendTabQuery(Integer tabType, LambdaQueryWrapperX<ProductSpuDO> query) { |
| 148 | 148 | // 出售中商品 |
| ... | ... | @@ -169,4 +169,17 @@ public interface ProductSpuMapper extends BaseMapperX<ProductSpuDO> { |
| 169 | 169 | } |
| 170 | 170 | } |
| 171 | 171 | |
| 172 | + /** | |
| 173 | + * 更新商品 SPU 浏览量 | |
| 174 | + * | |
| 175 | + * @param id 商品 SPU 编号 | |
| 176 | + * @param incrCount 增加的数量 | |
| 177 | + */ | |
| 178 | + default void updateBrowseCount(Long id, int incrCount) { | |
| 179 | + LambdaUpdateWrapper<ProductSpuDO> updateWrapper = new LambdaUpdateWrapper<ProductSpuDO>() | |
| 180 | + .setSql(" browse_count = browse_count +" + incrCount) | |
| 181 | + .eq(ProductSpuDO::getId, id); | |
| 182 | + update(null, updateWrapper); | |
| 183 | + } | |
| 184 | + | |
| 172 | 185 | } | ... | ... |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/history/ProductBrowseHistoryService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.product.service.history; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.module.product.controller.admin.history.vo.ProductBrowseHistoryPageReqVO; | |
| 5 | +import cn.iocoder.yudao.module.product.dal.dataobject.history.ProductBrowseHistoryDO; | |
| 6 | + | |
| 7 | +import java.util.Collection; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * 商品浏览记录 Service 接口 | |
| 11 | + * | |
| 12 | + * @author owen | |
| 13 | + */ | |
| 14 | +public interface ProductBrowseHistoryService { | |
| 15 | + | |
| 16 | + /** | |
| 17 | + * 创建商品浏览记录 | |
| 18 | + * | |
| 19 | + * @param userId 用户编号 | |
| 20 | + * @param spuId SPU 编号 | |
| 21 | + * @return 编号 | |
| 22 | + */ | |
| 23 | + Long createBrowseHistory(Long userId, Long spuId); | |
| 24 | + | |
| 25 | + /** | |
| 26 | + * 隐藏用户商品浏览记录 | |
| 27 | + * | |
| 28 | + * @param userId 用户编号 | |
| 29 | + * @param spuId SPU 编号 | |
| 30 | + */ | |
| 31 | + void hideUserBrowseHistory(Long userId, Collection<Long> spuId); | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * 获得商品浏览记录 | |
| 35 | + * | |
| 36 | + * @param id 编号 | |
| 37 | + * @return 商品浏览记录 | |
| 38 | + */ | |
| 39 | + ProductBrowseHistoryDO getBrowseHistory(Long id); | |
| 40 | + | |
| 41 | + /** | |
| 42 | + * 获取用户记录数量 | |
| 43 | + * | |
| 44 | + * @param userId 用户编号 | |
| 45 | + * @param userDeleted 用户是否删除 | |
| 46 | + * @return 数量 | |
| 47 | + */ | |
| 48 | + Long getBrowseHistoryCount(Long userId, Boolean userDeleted); | |
| 49 | + | |
| 50 | + /** | |
| 51 | + * 获得商品浏览记录分页 | |
| 52 | + * | |
| 53 | + * @param pageReqVO 分页查询 | |
| 54 | + * @return 商品浏览记录分页 | |
| 55 | + */ | |
| 56 | + PageResult<ProductBrowseHistoryDO> getBrowseHistoryPage(ProductBrowseHistoryPageReqVO pageReqVO); | |
| 57 | + | |
| 58 | +} | |
| 0 | 59 | \ No newline at end of file | ... | ... |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/history/ProductBrowseHistoryServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.product.service.history; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 5 | +import cn.iocoder.yudao.module.product.controller.admin.history.vo.ProductBrowseHistoryPageReqVO; | |
| 6 | +import cn.iocoder.yudao.module.product.dal.dataobject.history.ProductBrowseHistoryDO; | |
| 7 | +import cn.iocoder.yudao.module.product.dal.mysql.history.ProductBrowseHistoryMapper; | |
| 8 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | |
| 9 | +import jakarta.annotation.Resource; | |
| 10 | +import org.springframework.stereotype.Service; | |
| 11 | +import org.springframework.validation.annotation.Validated; | |
| 12 | + | |
| 13 | +import java.util.Collection; | |
| 14 | + | |
| 15 | +/** | |
| 16 | + * 商品浏览记录 Service 实现类 | |
| 17 | + * | |
| 18 | + * @author owen | |
| 19 | + */ | |
| 20 | +@Service | |
| 21 | +@Validated | |
| 22 | +public class ProductBrowseHistoryServiceImpl implements ProductBrowseHistoryService { | |
| 23 | + private static final int USER_STORE_MAXIMUM = 100; | |
| 24 | + | |
| 25 | + @Resource | |
| 26 | + private ProductBrowseHistoryMapper browseHistoryMapper; | |
| 27 | + | |
| 28 | + @Override | |
| 29 | + public Long createBrowseHistory(Long userId, Long spuId) { | |
| 30 | + // 情况一:同一个商品,只保留最新的一条记录 | |
| 31 | + ProductBrowseHistoryDO historyDO = browseHistoryMapper.selectOne(ProductBrowseHistoryDO::getUserId, userId, ProductBrowseHistoryDO::getSpuId, spuId); | |
| 32 | + if (historyDO != null) { | |
| 33 | + browseHistoryMapper.deleteById(historyDO); | |
| 34 | + } else { | |
| 35 | + // 情况二:限制每个用户的浏览记录的条数 | |
| 36 | + Page<ProductBrowseHistoryDO> pageResult = browseHistoryMapper.selectPageByUserIdOrderByCreateTimeAsc(userId); | |
| 37 | + if (pageResult.getTotal() >= USER_STORE_MAXIMUM) { | |
| 38 | + // 删除最早的一条 | |
| 39 | + browseHistoryMapper.deleteById(CollUtil.getFirst(pageResult.getRecords())); | |
| 40 | + } | |
| 41 | + } | |
| 42 | + | |
| 43 | + // 插入 | |
| 44 | + ProductBrowseHistoryDO browseHistory = new ProductBrowseHistoryDO() | |
| 45 | + .setUserId(userId) | |
| 46 | + .setSpuId(spuId); | |
| 47 | + browseHistoryMapper.insert(browseHistory); | |
| 48 | + // 返回 | |
| 49 | + return browseHistory.getId(); | |
| 50 | + } | |
| 51 | + | |
| 52 | + @Override | |
| 53 | + public void hideUserBrowseHistory(Long userId, Collection<Long> spuIds) { | |
| 54 | + browseHistoryMapper.updateUserDeletedByUserId(userId, spuIds, true); | |
| 55 | + } | |
| 56 | + | |
| 57 | + @Override | |
| 58 | + public ProductBrowseHistoryDO getBrowseHistory(Long id) { | |
| 59 | + return browseHistoryMapper.selectById(id); | |
| 60 | + } | |
| 61 | + | |
| 62 | + @Override | |
| 63 | + public Long getBrowseHistoryCount(Long userId, Boolean userDeleted) { | |
| 64 | + return browseHistoryMapper.selectCountByUserIdAndUserDeleted(userId, userDeleted); | |
| 65 | + } | |
| 66 | + | |
| 67 | + @Override | |
| 68 | + public PageResult<ProductBrowseHistoryDO> getBrowseHistoryPage(ProductBrowseHistoryPageReqVO pageReqVO) { | |
| 69 | + return browseHistoryMapper.selectPage(pageReqVO); | |
| 70 | + } | |
| 71 | + | |
| 72 | +} | |
| 0 | 73 | \ No newline at end of file | ... | ... |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java
| ... | ... | @@ -148,4 +148,12 @@ public interface ProductSpuService { |
| 148 | 148 | */ |
| 149 | 149 | List<ProductSpuDO> validateSpuList(Collection<Long> ids); |
| 150 | 150 | |
| 151 | + /** | |
| 152 | + * 更新商品 SPU 浏览量 | |
| 153 | + * | |
| 154 | + * @param id 商品 SPU 编号 | |
| 155 | + * @param incrCount 增加的数量 | |
| 156 | + */ | |
| 157 | + void updateBrowseCount(Long id, int incrCount); | |
| 158 | + | |
| 151 | 159 | } | ... | ... |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
| ... | ... | @@ -158,6 +158,11 @@ public class ProductSpuServiceImpl implements ProductSpuService { |
| 158 | 158 | } |
| 159 | 159 | |
| 160 | 160 | @Override |
| 161 | + public void updateBrowseCount(Long id, int incrCount) { | |
| 162 | + productSpuMapper.updateBrowseCount(id , incrCount); | |
| 163 | + } | |
| 164 | + | |
| 165 | + @Override | |
| 161 | 166 | @Transactional(rollbackFor = Exception.class) |
| 162 | 167 | public void deleteSpu(Long id) { |
| 163 | 168 | // 校验存在 | ... | ... |