eshop商城项目实训系列教程导航

  1. eshop商城项目实训源码 <= 当前位置
  2. eshop商城项目实训代码重构

基本架构

要先把基本框架搭建起来,才能够愉快的写代码

1. domain

eshop-business模块下新建src\main\java的文件夹,在该文件夹下创建com.eshop.modules.business.domain的包,在该包下创建StoreProductRelation的实体类,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.eshop.module.business.domain;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.eshop.domain.BaseDomain;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class StoreProductRelation extends BaseDomain {

private static final long serialVersionUID = 1L;

@TableId(value = "id", type = IdType.AUTO)
private Long id;

@ApiModelProperty(value = "用户ID")
private Long uid;

@ApiModelProperty(value = "商品ID")
private Long productId;

@ApiModelProperty(value = "类型(收藏(collect)、点赞(like)、足迹(foot))")
private String type;

@ApiModelProperty(value = "某种类型的商品(普通商品、秒杀商品)")
private String category;
}

部分注解说明:

  • @Builder:为类生成相对略微复杂的构建器 API
  • @ApiModelProperty:添加和操作属性模块的数据

2. mapper

mapper的包下新建ProductRelationMapper的类,代码如下:

1
2
3
4
5
6
7
8
9
package com.eshop.module.business.mapper;

import com.eshop.common.mapper.CoreMapper;
import com.eshop.module.business.domain.StoreProductRelation;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface ProductRelationMapper extends CoreMapper<StoreProductRelation> {
}

其中接口ProductRelationMapper继承的CoreMapperCoreMapper继承BaseMapper,相当于ProductRelationMapper继承CoreMapper

image-20230329123904643

3. service

service的包下新建ProductRelationService的类,代码如下:

1
2
3
4
5
6
7
package com.eshop.module.business.service;

import com.eshop.common.service.BaseService;
import com.eshop.module.business.domain.StoreProductRelation;

public interface ProductRelationService extends BaseService<StoreProductRelation> {
}

新建ProductRelationServiceImpl的实现类,实现ProductRelationService的接口,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.eshop.module.business.service.impl;


import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.eshop.api.EshopException;
import com.eshop.common.service.impl.BaseServiceImpl;
import com.eshop.dozer.service.IGenerator;
import com.eshop.module.business.domain.StoreProductRelation;
import com.eshop.module.business.mapper.ProductRelationMapper;
import com.eshop.module.business.service.ProductRelationService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
@AllArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class ProductRelationServiceImpl extends BaseServiceImpl<ProductRelationMapper, StoreProductRelation> implements ProductRelationService {

private final ProductRelationMapper productRelationMapper;
private final IGenerator generator;
}

4. controller

com.eshop下新建一个包,包名叫controller,新建一个类,类名叫ProductCollectController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.eshop.controller;

import com.eshop.module.business.service.ProductRelationService;
import io.swagger.annotations.Api;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@Api(value = "产品模块", tags = "商城:产品模块")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ProductCollectController {

private final ProductRelationService productRelationService;
}

部分注解说明:

  • @Api:用在请求的类上,表示对类的说明
  • @RequiredArgsConstructor:生成带有必需参数的构造函数

功能编码

1. 商品添加收藏

前端发过来的请求(使用的是post方式):http://localhost:8008/api/collect/add

image-20230329114943308

看报错Request method 'POST' not supported,不支持请求方法“POST”

开始编写controller层的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 添加收藏
* @param param body部分,需要查询的参数
* @return 是否成功:成功 true,失败 false
*/
@AppLog(value = "添加收藏", type = 1)
@NoRepeatSubmit
@AuthCheck
@PostMapping("//collect/add")
@ApiModelProperty(value = "添加收藏", notes = "添加收藏")
public ApiResult<Boolean> collectAdd(@Validated @RequestBody StoreProductRelationQueryParam param){
Long uid = LocalUser.getUser().getUid();
if (!NumberUtil.isNumber(param.getId())){
throw new EshopException("参数非法");
}
// 调业务层
productRelationService.addRroductRelation(Long.valueOf(param.getId()), uid, param.getCategory());
return ApiResult.ok();
}

部分注解说明:

  • @AppLog:自定义日志注解
  • @NoRepeatSubmit:防止重复提交自定义注解
  • @AuthCheck:自定义注解实现用户行为认证
  • @ApiModelProperty:添加和操作属性模块的数据

1.1 是否收藏

service接口:

1
2
3
4
5
6
7
/**
* 是否收藏
* @param productId 商品ID
* @param uid 用户ID
* @return Boolean
*/
Boolean isProductRelation(long productId, long uid);

实现该业务功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 是否收藏
* @param productId 商品ID
* @param uid 用户ID
* @return Boolean
*/
@Override
public Boolean isProductRelation(long productId, long uid) {
int count = productRelationMapper
.selectCount(Wrappers.<StoreProductRelation>lambdaQuery()
.eq(StoreProductRelation::getUid,uid)
.eq(StoreProductRelation::getType,"collect")
.eq(StoreProductRelation::getProductId,productId));
if(count > 0) {
return true;
}
return false;
}

1.2 添加收藏

service接口:

1
2
3
4
5
6
/**
*添加收藏
* @param productId 商品id
* @param uid 用户id
*/
void addRroductRelation(long productId,long uid,String category);

实现该业务功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 添加收藏
* @param productId 商品id
* @param uid 用户id
*/
@Override
public void addRroductRelation(long productId,long uid,String category) {
if(isProductRelation(productId,uid)) {
throw new EshopException("已收藏");
}
StoreProductRelation storeProductRelation = StoreProductRelation.builder()
.productId(productId)
.uid(uid)
.type(category)
.build();
productRelationMapper.insert(storeProductRelation);
}

2. 商品取消收藏

前端发过来的请求(使用的是post方式):http://localhost:8008/api/collect/del

controller层:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 取消收藏
*/
@AppLog(value = "取消收藏", type = 1)
@NoRepeatSubmit
@AuthCheck
@PostMapping("/collect/del")
@ApiOperation(value = "取消收藏",notes = "取消收藏")
public ApiResult<Boolean> collectDel(@Validated @RequestBody StoreProductRelationQueryParam param){
long uid = LocalUser.getUser().getUid();
if(!NumberUtil.isNumber(param.getId())) {
throw new EshopException("参数非法");
}
productRelationService.delRroductRelation(Long.valueOf(param.getId()),
uid,param.getCategory());
return ApiResult.ok();
}

service接口:

1
2
3
4
5
6
/**
* 取消收藏
* @param productId 商品id
* @param uid 用户id
*/
void delRroductRelation(long productId,long uid,String category);

实现该业务功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 取消收藏
* @param productId 商品id
* @param uid 用户id
*/
@Override
public void delRroductRelation(long productId,long uid,String category) {
StoreProductRelation productRelation = this.lambdaQuery()
.eq(StoreProductRelation::getProductId,productId)
.eq(StoreProductRelation::getUid,uid)
.eq(StoreProductRelation::getType,category)
.one();
if(productRelation == null) {
throw new EshopException("已取消");
}
this.removeById(productRelation.getId());
}

3. 批量删除收藏/足迹

前端发过来的请求(使用的是post方式):http://localhost:8008/api/collect/dels/{productIds}

controller层:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@AppLog(value = "批量取消收藏", type = 1)
@NoRepeatSubmit
@AuthCheck
@PostMapping("/collect/dels/{productIds}")
@ApiOperation(value = "批量取消收藏",notes = "批量取消收藏")
@Transactional(rollbackFor = Exception.class)
public ApiResult<Boolean> collectDels(@PathVariable String productIds,@RequestBody StoreProductRelationQueryParam param){
long uid = LocalUser.getUser().getUid();
String[] ids = productIds.split(",");
if(ids.length > 0){
for (String id : ids){
productRelationService.delRroductRelation(Long.parseLong(id), uid, param.getCategory());
}
}else{
throw new EshopException("参数非法");
}
return ApiResult.ok();
}

4. 获取收藏或足迹

前端发过来的请求(使用的是get方式):http://localhost:8008/api/collect/user

controller层:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@AuthCheck
@GetMapping("/collect/user")
@ApiImplicitParams({
@ApiImplicitParam(name = "page", value = "页码,默认为1", paramType = "query", dataType = "int"),
@ApiImplicitParam(name = "limit", value = "页大小,默认为10", paramType = "query", dataType = "int"),
@ApiImplicitParam(name = "type", value = "foot为足迹,collect为收藏", paramType = "query", dataType = "String")
})
@ApiOperation(value = "获取收藏产品,或足迹",notes = "获取收藏产品,或足迹")
public ApiResult<List<StoreProductRelationQueryVo>> collectUser(@RequestParam(value = "page",defaultValue = "1") int page,
@RequestParam(value = "limit",defaultValue = "500") int limit,
@RequestParam(value = "type") String type){
Long uid = LocalUser.getUser().getUid();
List<StoreProductRelationQueryVo> storeProductRelationQueryVos = productRelationService.userCollectProduct(page, limit, uid, type);
return ApiResult.ok(storeProductRelationQueryVos);
}

此时我们现有的实体类对象返回的数据,并不能够满足我们的需求,因此需要在vo包下造个StoreProductRelationQueryVo的类,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package com.eshop.modules.business.vo;


import com.eshop.serializer.DoubleSerializer;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

@Data
@ApiModel(value = "StoreProductRelationQueryVo对象", description = "商品点赞和收藏表查询参数")
public class StoreProductRelationQueryVo implements Serializable {
private static final long serialVersionUID = 1L;

private Long id;

@ApiModelProperty(value = "用户ID")
private Long uid;

@ApiModelProperty(value = "商品ID")
private Long productId;

@ApiModelProperty(value = "类型(收藏(collect)、点赞(like))")
private String type;

@ApiModelProperty(value = "某种类型的商品(普通商品、秒杀商品)")
private String category;

@ApiModelProperty(value = "添加时间")
private Date createTime;

@ApiModelProperty(value = "产品图片")
private String image;

@ApiModelProperty(value = "是否显示")
private Integer isShow;

@ApiModelProperty(value = "原价")
@JsonSerialize(using = DoubleSerializer.class)
private Double otPrice;

@ApiModelProperty(value = "父ID")
private Integer pid;

@ApiModelProperty(value = "产品价格")
@JsonSerialize(using = DoubleSerializer.class)
private Double price;

@ApiModelProperty(value = "产品销量")
private Integer sales;

@ApiModelProperty(value = "商品名称")
private String storeName;

@ApiModelProperty(value = "是否开启积分兑换")
private Integer isIntegral;

@ApiModelProperty(value = "积分")
private Integer integral;

}

service层:

1
2
3
4
5
6
7
8
/**
* 获取用户收藏列表
* @param page page
* @param limit limit
* @param uid 用户id
* @return list
*/
List<StoreProductRelationQueryVo> userCollectProduct(int page, int limit, Long uid, String type);

实现该业务功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 获取用户收藏列表
* @param page page
* @param limit limit
* @param uid 用户id
* @return list
*/
@Override
public List<StoreProductRelationQueryVo> userCollectProduct(int page, int limit, Long uid, String type) {
Page<StoreProductRelation> pageModel = new Page<>(page, limit);
List<StoreProductRelationQueryVo> list = productRelationMapper.selectRelationList(pageModel,uid,type);
return list;
}

因为此操作涉及到多表查询,mybatisplus并未给我们提供相关可以调用的接口,因此我们需要自己编写接口,实现我们的需求。代码如下:

1
2
3
4
5
@Select("select B.id pid,A.type as category,B.store_name as storeName,B.price,B.is_integral as isIntegral," +
"B.ot_price as otPrice,B.sales,B.image,B.is_show as isShow,B.integral as integral" +
" from store_product_relation A left join store_product B " +
"on A.product_id = B.id where A.type=#{type} and A.uid=#{uid} and A.is_del = 0 and B.is_del = 0 order by A.create_time desc")
List<StoreProductRelationQueryVo> selectRelationList(Page page, @Param("uid") Long uid, @Param("type") String type);

至此接口编写完毕!!

程序排错