<delete id="deleteBatchRelation">
DELETE FROM pms_attr_attrgroup_relation WHERE
<foreach collection="entities" item="item" separator=" OR ">
(attr_id=#{item.attrId} AND attr_group_id=#{item.attrGroupId})
</foreach>
</delete>
平台属性
1. 规格新增与VO
1.1 对属性分组进行模糊查询功能
修改AttrGroupServiceImpl
//对分类属性进行查询和模糊查询功能
@Override
public PageUtils queryPage(Map<String, Object> params, Long catelogId) {
// 检索条件多匹配-- 模糊查询
String key = (String) params.getOrDefault("key", null);
QueryWrapper<AttrGroupEntity> wrapper = new QueryWrapper<AttrGroupEntity>();
if(!StringUtils.isEmpty(key)){
wrapper.and((obj)->{
obj.eq("attr_group_id",key).or().like("attr_group_name",key);
});
}
if(catelogId.equals(0L)){
IPage<AttrGroupEntity> page = this.page(
new Query<AttrGroupEntity>().getPage(params),
wrapper
);
return new PageUtils(page);
}else {
// 检索条件多匹配
wrapper.eq("catelog_id", catelogId);
IPage<AttrGroupEntity> page = this.page(
new Query<AttrGroupEntity>().getPage(params),
wrapper
);
return new PageUtils(page);
}
}
1.2 规格参数新增& 关联参数所在分组
逆向生成的规格参数新增,只有基础的新增,保存的有所属分类的信息,没有添加所属分组的关联关系。
VO值对象:接受页面传递来的数据,封装对象
创建包 com/atguigu/gulimall/product/VO 用来存储VO值
因为需要添加数据库中没有的字段,在entity中添加不符合代码规范,所以我们可以使用VO来进行存储数据。
将 AttrEntity 中的数据传入到 AttrVo 中
@Data
public class AttrVo {
private Long attrId;
/**
* 属性名
*/
private String attrName;
/**
* 是否需要检索[0-不需要,1-需要]
*/
private Integer searchType;
/**
* 属性图标
*/
private String icon;
/**
* 可选值列表[用逗号分隔]
*/
private String valueSelect;
/**
* 属性类型[0-销售属性,1-基本属性,2-既是销售属性又是基本属性]
*/
private Integer attrType;
/**
* 启用状态[0 - 禁用,1 - 启用]
*/
private Long enable;
/**
* 所属分类
*/
private Long catelogId;
/**
* 快速展示【是否展示在介绍上;0-否 1-是】,在sku中仍然可以调整
*/
private Integer showDesc;
/**
* 值类型[0-为单个值,1-可以选择多个值]
*/
private Integer valueType;
/**
* 所属分组
*/
private Long attrGroupId;
}
在 AttrController 修改对应的 AttrEntity 实体 为 AttrVo
@RestController
@RequestMapping("product/attr")
public class AttrController {
@Autowired
private AttrService attrService;
/**
* 保存
*/
@RequestMapping("/save")
public R save(@RequestBody AttrVo attr){
attrService.saveAttr(attr);
return R.ok();
}
}
在规格参数新增过程中添加 维护attr 与分组的 关系,使用AttrVo
public interface AttrService extends IService<AttrEntity> {
PageUtils queryPage(Map<String, Object> params);
//新增规格参数与分组的关联关系
void saveAttr(AttrVo attr);
}
在AttrServiceImpl 新增功能中引入 AttrAttrgroupRelationDao ,来维护属性与属性分组的关系
@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {
@Autowired
private AttrAttrgroupRelationDao RelationDao;
@Transactional(rollbackFor = Exception.class)
@Override
public void saveAttr(AttrVo attr) {
// 1. 保存基础数据
AttrEntity attrEntity = new AttrEntity();
BeanUtils.copyProperties(attr,attrEntity);
this.save(attrEntity);
// 2. 维护关联关系 属性与属性分组
AttrAttrgroupRelationEntity RelationEntity = new AttrAttrgroupRelationEntity();
RelationEntity.setAttrId(attrEntity.getAttrId());
RelationEntity.setAttrGroupId(attr.getAttrGroupId());
RelationDao.insert(RelationEntity);
}
}
Attr 与AttrGroup 关联关系表
2. 规格参数列表
新增Vo 类 AttrRespVo
因为在AttrEntity 中没有 所在分组名字和所在分类名字,我们需要在规格参数列表的详细信息中展示出来。我们可以直接新增Vo类 AttrRespVo 来继承AttrVo
@Data
public class AttrRespVo extends AttrVo{
/**
* 所属分组名称
*/
private String groupName;
/**
* 所属分类名称
*/
private String catelogName;
}
AttrController 新增展示列表方法
@RestController
@RequestMapping("product/attr")
public class AttrController {
@Autowired
private AttrService attrService;
@GetMapping("/base/list/{catelogId}")
public R baseAttrList(@RequestParam Map<String, Object> params,
@PathVariable("catelogId") Long catelogId){
PageUtils page = attrService.queryBaseAttrPage(params,catelogId);
return R.ok().put("page",page);
}
attrService新增 queryBaseAttrPage 方法
public interface AttrService extends IService<AttrEntity> {
PageUtils queryPage(Map<String, Object> params);
//新增规格参数与分组的关联关系
void saveAttr(AttrVo attr);
PageUtils queryBaseAttrPage(Map<String, Object> params, Long catelogId);
}
AttrServiceImpl 继承接口 AttrService
在AttrServiceImpl实现queryBaseAttrPage 方法中,通过查询表pms_attr_attrgroup_relation 的AttrId和AttrGroupId来分别查询pms_attr 和 pms_attr_group 中属性所在分组和分类的名字
@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {
@Autowired
private AttrAttrgroupRelationDao RelationDao;
@Resource
private AttrGroupDao attrGroupDao;
@Resource
private CategoryDao categoryDao;
@Override
public PageUtils queryBaseAttrPage(Map<String, Object> params, Long catelogId) {
QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<>();
if(catelogId!=0L){
queryWrapper.eq("catelog_id",catelogId);
}
String key = (String) params.get("key");
if(!StringUtils.isEmpty(key)){
queryWrapper.and((wrapper)->{
wrapper.eq("attr_id",key).or().like("attr_name",key);
});
}
IPage<AttrEntity> page = this.page(
new Query<AttrEntity>().getPage(params),
queryWrapper
);
PageUtils pageUtils = new PageUtils(page);
List<AttrEntity> records = page.getRecords();
List<AttrRespVo> attrRespVoList = records.stream().map((attrEntity) -> {
AttrRespVo attrRespVo = new AttrRespVo();
BeanUtils.copyProperties(attrEntity, attrRespVo);
// 所属分组
AttrAttrgroupRelationEntity attr_id = RelationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrEntity.getAttrId()));
// 可能属性与属性分组没有关联关系
if (attr_id != null) {
AttrGroupEntity groupEntity = attrGroupDao.selectById(attr_id.getAttrGroupId());
attrRespVo.setGroupName(groupEntity.getAttrGroupName());
}
// 所属分类
CategoryEntity categoryEntity = categoryDao.selectById(attrEntity.getCatelogId());
if (categoryEntity != null) {
attrRespVo.setCatelogName(categoryEntity.getName());
}
return attrRespVo;
}).collect(Collectors.toList());
pageUtils.setList(attrRespVoList);
return pageUtils;
}
}
2. 规格修改
2.1 回显规格信息
在AttrRespVo 中新增分类路径字段,用来回显规格中分类的数据。
AttrRespVo 包含了所有规格所有数据
@Data
public class AttrRespVo extends AttrVo{
/**
* 所属分组名称
*/
private String groupName;
/**
* 所属分类名称
*/
private String catelogName;
/**
* 所属分类的路径
*/
private Long[] catelogPath;
}
AttrController 层回显信息,创建新方法AttrService.getAttrInfo
@RestController
@RequestMapping("product/attr")
public class AttrController {
@Autowired
private AttrService attrService;
/**
* 修改回显信息
*/
@RequestMapping("/info/{attrId}")
public R info(@PathVariable("attrId") Long attrId){
//AttrEntity attr = attrService.getById(attrId);
AttrRespVo attrRespVo = attrService.getAttrInfo(attrId);
return R.ok().put("attr", attrRespVo);
}
}
public interface AttrService extends IService<AttrEntity> {
AttrRespVo getAttrInfo(Long attrId);
}
AttrServiceImpl 继承接口
@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {
@Autowired
private AttrAttrgroupRelationDao RelationDao;
@Resource
private AttrGroupDao attrGroupDao;
@Resource
private CategoryDao categoryDao;
@Autowired
private CategoryService categoryService;
@Override
public AttrRespVo getAttrInfo(Long attrId) {
AttrEntity attrEntity = this.getById(attrId);
AttrRespVo attrRespVo = new AttrRespVo();
BeanUtils.copyProperties(attrEntity, attrRespVo);
if (attrEntity.getCatelogId() != null) {
// 所属分类
Long[] catelogPath = categoryService.findCatelogPath(attrEntity.getCatelogId());
attrRespVo.setCatelogPath(catelogPath);
CategoryEntity categoryEntity = categoryDao.selectById(attrEntity.getCatelogId());
if (categoryEntity != null) {
attrRespVo.setCatelogName(categoryEntity.getName());
}
}
// 所属分组
AttrAttrgroupRelationEntity attrAttrgroupRelation = RelationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrId));
// 可能属性与属性分组没有关联关系
if (attrAttrgroupRelation != null) {
attrRespVo.setAttrGroupId(attrAttrgroupRelation.getAttrGroupId());
AttrGroupEntity groupEntity = attrGroupDao.selectById(attrAttrgroupRelation.getAttrGroupId());
if (groupEntity != null) {
attrRespVo.setGroupName(groupEntity.getAttrGroupName());
}
}
return attrRespVo;
}
}
回显分类和分组信息
2.2 规格信息修改
AttrController 进行规格参数修改,新增updateAttr 方法
@RestController
@RequestMapping("product/attr")
public class AttrController {
@Autowired
private AttrService attrService;
/**
* 规格参数修改
*/
@RequestMapping("/update")
public R update(@RequestBody AttrVo attr){
//attrService.updateById(attr);
attrService.updateAttr(attr); //新增修改规格属性方法
return R.ok();
}
}
public interface AttrService extends IService<AttrEntity> {
// 规格参数修改
void updateAttr(AttrVo attr);
}
AttrServiceImpl 实现update方法,主要有两部分,当分类或者分组数据为空时。此时我们可以使用insert方法来新增分类或者分组
@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {
@Autowired
private AttrAttrgroupRelationDao RelationDao;
@Resource
private AttrGroupDao attrGroupDao;
@Resource
private CategoryDao categoryDao;
@Autowired
private CategoryService categoryService;
//规格参数修改功能
@Override
public void updateAttr(AttrVo attr) {
AttrEntity attrEntity = new AttrEntity();
BeanUtils.copyProperties(attr,attrEntity);
// 修改属性
this.updateById(attrEntity);
// 修改属性和属性分组关系
if(attr.getAttrGroupId() != null) {
AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = RelationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attr.getAttrId()));
if(attrAttrgroupRelationEntity != null && !attr.getAttrGroupId().equals(attrAttrgroupRelationEntity.getAttrGroupId())){
// 修改
attrAttrgroupRelationEntity.setAttrGroupId(attr.getAttrGroupId());
RelationDao.updateById(attrAttrgroupRelationEntity);
}else {
// 不存在属性和属性分组关系,新增
AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
relationEntity.setAttrId(attr.getAttrId());
relationEntity.setAttrGroupId(attr.getAttrGroupId());
RelationDao.insert(relationEntity);
}
}
}
}
2.3 销售属性维护
修改pms_attr属性表的attr_type字段的注释为属性类型[0-销售属性,1-基本属性]。
修改AttrController控制层接口baseAttrList:
修改请求路径,添加路径参数attrType
@GetMapping("/base/list/{catelogId}")改为
@GetMapping("/{attrType}/list/{catelogId}")
由于销售属性和规格参数公用查询、新增、修改回显、修改接口,销售属性和规格参数的不同在于没有
所属分组,在这些接口通过属性类型attrType判断是否需要操作所属分组。
在gulimall-common模块,在ProductConstant类中定义AttrEnum枚举类代替常量区分属性类型。
销售属性与基本属性(规格参数)的信息基本一致,所以我们可以在基本属性的方法基础上,进行 if 选择。
//规格参数和销售属性显示列表信息,在common模块中定义一个attrtype类。
//当attrtype为 1 时为销售属性 为 0 时为基本属性
//所以我们需要重构 queryBaseAttrPage 方法。添加一个 type 参数
@GetMapping("/{attrType}/list/{catelogId}")
public R baseAttrList(@RequestParam Map<String, Object> params,
@PathVariable("catelogId") Long catelogId,
@PathVariable("attrType") String type){
PageUtils page = attrService.queryBaseAttrPage(params,catelogId,type);
return R.ok().put("page",page);
}
common模块中定义常量,当我们修改常量时就可以在common中进行修改。
package com.atguigu.Constant;
/**
* @author wen
* @createDate 2023/3/31 13:41
* @description 产品模块常量类
*/
public class ProductConstant {
public enum AttrEnum{
ATTR_TYPE_BASE(1,"基本属性"),
ATTR_TYPE_SALE(0,"销售属性");
private int code;
private String msg;
AttrEnum(int code,String msg){
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
}
public interface AttrService extends IService<AttrEntity> {
//根据分组id查询所有的属性
List<AttrEntity> getRelationAttr(Long attrGroupId);
}
@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {
@Autowired
private AttrAttrgroupRelationDao RelationDao;
@Resource
private AttrGroupDao attrGroupDao;
@Resource
private CategoryDao categoryDao;
@Autowired
private CategoryService categoryService;
@Autowired
private AttrAttrgroupRelationDao attrAttrgroupRelationDao;
@Override
public PageUtils queryPage(Map<String, Object> params) {
IPage<AttrEntity> page = this.page(
new Query<AttrEntity>().getPage(params),
new QueryWrapper<AttrEntity>()
);
return new PageUtils(page);
}
//新增数据
@Transactional(rollbackFor = Exception.class)
@Override
public void saveAttr(AttrVo attr) {
// 1. 保存基础数据
AttrEntity attrEntity = new AttrEntity();
BeanUtils.copyProperties(attr,attrEntity);
this.save(attrEntity);
// 2. 维护关联关系 属性与属性分组 attr.getAttrType() = 1时 基本属性
if(attr.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode() && attr.getAttrGroupId() != null) {
AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = new AttrAttrgroupRelationEntity();
attrAttrgroupRelationEntity.setAttrId(attrEntity.getAttrId());
attrAttrgroupRelationEntity.setAttrGroupId(attr.getAttrGroupId());
attrAttrgroupRelationDao.insert(attrAttrgroupRelationEntity);
}
}
@Override
public PageUtils queryBaseAttrPage(Map<String, Object> params, Long catelogId, String type) {
//搜索框功能, 因为将对于属性的判断是全局的,
QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<AttrEntity>().eq("attr_type","base".equalsIgnoreCase(type)? ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode():ProductConstant.AttrEnum.ATTR_TYPE_SALE.getCode());
if(catelogId!=0L){
queryWrapper.eq("catelog_id",catelogId);
}
String key = (String) params.get("key");
//通过Wrapper来存储AttrEntity实体类数据,当搜索框中的数据不为空时
if(!StringUtils.isEmpty(key)){
queryWrapper.and((wrapper)->{
wrapper.eq("attr_id",key).or().like("attr_name",key);
});
}
IPage<AttrEntity> page = this.page(
new Query<AttrEntity>().getPage(params),
queryWrapper
);
PageUtils pageUtils = new PageUtils(page);
List<AttrEntity> records = page.getRecords();
List<AttrRespVo> attrRespVoList = records.stream().map((attrEntity) -> {
AttrRespVo attrRespVo = new AttrRespVo();
BeanUtils.copyProperties(attrEntity, attrRespVo);
// 所属分组,销售属性没有分组,所以不处理分组事件
if("base".equalsIgnoreCase(type)) {
AttrAttrgroupRelationEntity attr_id = attrAttrgroupRelationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrEntity.getAttrId()));
// 可能属性与属性分组没有关联关系
if (attr_id != null && attr_id.getAttrGroupId() != null) {
AttrGroupEntity groupEntity = attrGroupDao.selectById(attr_id.getAttrGroupId());
attrRespVo.setGroupName(groupEntity.getAttrGroupName());
}
}
// 所属分类
CategoryEntity categoryEntity = categoryDao.selectById(attrEntity.getCatelogId());
if (categoryEntity != null) {
attrRespVo.setCatelogName(categoryEntity.getName());
}
return attrRespVo;
}).collect(Collectors.toList());
pageUtils.setList(attrRespVoList);
return pageUtils;
}
//获取规格参数(基本信息)和销售属性
@Override
public AttrRespVo getAttrInfo(Long attrId) {
AttrEntity attrEntity = this.getById(attrId); //通过属性Id 获取属性表中对应的实体信息
AttrRespVo attrRespVo = new AttrRespVo(); //创建一个Vo实体,用来返回对应的回显信息
BeanUtils.copyProperties(attrEntity, attrRespVo); //将获取的实体信息复制到Vo 实体中
if (attrEntity.getCatelogId() != null) { //当获取的分类id不为0时
// 所属分类
Long[] catelogPath = categoryService.findCatelogPath(attrEntity.getCatelogId()); //查找分类路径节点
attrRespVo.setCatelogPath(catelogPath); //将路径节点放到attrRespVo中
CategoryEntity categoryEntity = categoryDao.selectById(attrEntity.getCatelogId()); //通过获取的分类id获取分类实体
if (categoryEntity != null) { //当分类id不为0时
attrRespVo.setCatelogName(categoryEntity.getName()); //获取对应的分类的名字
}
}
// 所属分组
if(attrEntity.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()){
AttrAttrgroupRelationEntity attrAttrgroupRelation = RelationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrId));
// 可能属性与属性分组没有关联关系
if (attrAttrgroupRelation != null) {
attrRespVo.setAttrGroupId(attrAttrgroupRelation.getAttrGroupId());
AttrGroupEntity groupEntity = attrGroupDao.selectById(attrAttrgroupRelation.getAttrGroupId());
if (groupEntity != null) {
attrRespVo.setGroupName(groupEntity.getAttrGroupName());
}
}
}
return attrRespVo;
}
//修改基本信息(规格参数)和销售属性信息
@Transactional(rollbackFor = Exception.class)
@Override
public void updateAttr(AttrVo attr) {
AttrEntity attrEntity = new AttrEntity();
BeanUtils.copyProperties(attr,attrEntity);
// 修改属性
this.updateById(attrEntity);
// 修改属性和属性分组关系
if(attrEntity.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()) {
if (attr.getAttrGroupId() != null) {
AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = attrAttrgroupRelationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attr.getAttrId()));
if (attrAttrgroupRelationEntity != null) {
if(!attr.getAttrGroupId().equals(attrAttrgroupRelationEntity.getAttrGroupId())) {
// 修改
attrAttrgroupRelationEntity.setAttrGroupId(attr.getAttrGroupId());
attrAttrgroupRelationDao.updateById(attrAttrgroupRelationEntity);
}
} else {
// 不存在属性和属性分组关系,新增
AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
relationEntity.setAttrId(attr.getAttrId());
relationEntity.setAttrGroupId(attr.getAttrGroupId());
attrAttrgroupRelationDao.insert(relationEntity);
}
}
}
}
/**
* 根据分组id查询所有关联的基本属性
* @param attrGroupId
* @return
*/
@Override
public List<AttrEntity> getRelationAttr(Long attrGroupId) {
List<AttrAttrgroupRelationEntity> relationEntities = attrAttrgroupRelationDao.selectList(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_group_id", attrGroupId));
List<Long> attrIds = relationEntities.stream().map(relationEntitie -> {
return relationEntitie.getAttrId();
}).collect(Collectors.toList());
if(attrIds == null || attrIds.size()==0){
return null;
}
List<AttrEntity> attrEntities = this.listByIds(attrIds);
return attrEntities;
}
}
3. 查询分组关联属性&删除关联
3.1 查询分组与属性关联
@RestController
@RequestMapping("product/attrgroup")
public class AttrGroupController {
@Autowired
private AttrGroupService attrGroupService;
@Autowired
private CategoryService categoryService;
@Autowired
private AttrService attrService;
/**
* 根据属性分组ID查询所有关联的属性
* @return
*/
@GetMapping("/{attrgroupId}/attr/relation")
public R attrRelation(@PathVariable("attrgroupId") Long attrGroupId){
List<AttrEntity> attrEntities = attrService.getRelationAttr(attrGroupId);
return R.ok().put("data",attrEntities);
}
}
public interface AttrService extends IService<AttrEntity> {
...
List<AttrEntity> getRelationAttr(Long attrGroupId);
}
@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {
@Resource
private AttrAttrgroupRelationDao attrAttrgroupRelationDao;
@Resource
private AttrGroupDao attrGroupDao;
@Resource
private CategoryDao categoryDao;
@Resource
private CategoryService categoryService;
/**
* 根据分组id查询所有关联的基本属性
* @param attrGroupId
* @return
*/
@Override
public List<AttrEntity> getRelationAttr(Long attrGroupId) {
List<AttrAttrgroupRelationEntity> relationEntities = attrAttrgroupRelationDao.selectList(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_group_id", attrGroupId));
List<Long> attrIds = relationEntities.stream().map(relationEntitie -> {
return relationEntitie.getAttrId();
}).collect(Collectors.toList());
if(attrIds == null || attrIds.size()==0){
return null;
}
List<AttrEntity> attrEntities = this.listByIds(attrIds);
return attrEntities;
}
}
3.2 删除关联&批量删除
@RestController
@RequestMapping("product/attrgroup")
public class AttrGroupController {
@Autowired
private AttrGroupService attrGroupService;
@Autowired
private CategoryService categoryService;
@Autowired
private AttrService attrService;
@PostMapping("/attr/relation/delete")
public R deleteRelation(@RequestBody AttrGroupRelationVo[] vos){
attrService.deleteRelation(vos);
return R.ok();
}
}
public interface AttrService extends IService<AttrEntity> {
...
void deleteRelation(AttrGroupRelationVo[] vos);
}
@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {
@Resource
private AttrAttrgroupRelationDao attrAttrgroupRelationDao;
@Resource
private AttrGroupDao attrGroupDao;
@Resource
private CategoryDao categoryDao;
@Resource
private CategoryService categoryService;
/**
* 删除属性分组与属性关系
* @param vos
*/
@Override
public void deleteRelation(AttrGroupRelationVo[] vos) {
List<AttrAttrgroupRelationEntity> entityList = Arrays.asList(vos).stream().map(vo -> {
AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
BeanUtils.copyProperties(vo, relationEntity);
return relationEntity;
}).collect(Collectors.toList());
attrAttrgroupRelationDao.deleteBatchRelation(entityList);
}
}
@Mapper
public interface AttrAttrgroupRelationDao extends BaseMapper<AttrAttrgroupRelationEntity> {
void deleteBatchRelation(@Param("entities") List<AttrAttrgroupRelationEntity> entityList);
}
<delete id="deleteBatchRelation">
DELETE FROM pms_attr_attrgroup_relation WHERE
<foreach collection="entities" item="item" separator=" OR ">
(attr_id=#{item.attrId} AND attr_group_id=#{item.attrGroupId})
</foreach>
</delete>
4. 查询分组未关联的属性
在属性分组页面-->点击关联-->新增关联 展示在同一分类下,没有被其他分组关联的属性。
ArreGroupController
@RestController
@RequestMapping("product/attrgroup")
public class AttrGroupController {
@Autowired
private AttrGroupService attrGroupService;
@Autowired
private CategoryService categoryService;
@Autowired
private AttrService attrService;
@Autowired
private AttrAttrgroupRelationService attrAttrgroupRelationService;
//查询分组未关联的基本属性(一个分类代表多个分组,一个分组代表多个分类)
//可以进行新增的基本属性
@GetMapping("/{attrgroupId}/noattr/relation")
public R attrNoRelation(@PathVariable("attrgroupId") Long attrGroupId,
@RequestParam Map<String, Object> params){
PageUtils page = attrService.getNoRelationAttr(params,attrGroupId);
return R.ok().put("page",page);
}
}
public interface AttrService extends IService<AttrEntity> {
//查询分组未关联的基本属性
PageUtils getNoRelationAttr(Map<String, Object> params, Long attrGroupId);
}
@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {
@Autowired
private AttrAttrgroupRelationDao RelationDao;
@Resource
private AttrGroupDao attrGroupDao;
@Resource
private CategoryDao categoryDao;
@Autowired
private CategoryService categoryService;
@Autowired
private AttrAttrgroupRelationDao attrAttrgroupRelationDao;
/**
* 获取分组所属分类下未关联的属性
*
* @param params
* @param attrGroupId
* @return
*/
@Override
public PageUtils getNoRelationAttr(Map<String, Object> params, Long attrGroupId) {
// 当前分组只能关联自己所属分类下其他分组未关联的属性
AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attrGroupId);
// 获取当前分组的分类
Long catelogId = attrGroupEntity.getCatelogId();
// 获取其他分组关联的属性
// 1)获取同一分类下的所有分组(包括当前分组)
List<AttrGroupEntity> attrGroupEntities = attrGroupDao.selectList(new QueryWrapper<AttrGroupEntity>().eq("catelog_id", catelogId));
List<Long> appGroupIds = attrGroupEntities.stream().map(item -> {
return item.getAttrGroupId();
}).collect(Collectors.toList());
// 2)这些分组关联的属性
List<AttrAttrgroupRelationEntity> relationEntities = attrAttrgroupRelationDao.selectList(new QueryWrapper<AttrAttrgroupRelationEntity>().in("attr_group_id", appGroupIds));
List<Long> attrIds = relationEntities.stream().map(relationEntitie -> {
return relationEntitie.getAttrId();
}).collect(Collectors.toList());
// 3)当前分类下去除这些属性
// 当前分类下所有的基础属性
//QueryWrapper 主要用来查询功能,自身的内部属性 entity 也用于生成 where 条件 及 LambdaQueryWrappe
QueryWrapper<AttrEntity> wrapper = new QueryWrapper<AttrEntity>().eq("catelog_id", catelogId).eq("attr_type", ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode());
if (attrIds != null && attrIds.size() > 0) {
// 去除已经关联的属性
wrapper.notIn("attr_id", attrIds);
}
//搜索框功能
// 拼接条件查询
String key = (String) params.get("key");
if (!StringUtils.isEmpty(key)) {
wrapper.eq("attr_id", key).or().like("attr_name", key);
}
//进行分页查询
IPage<AttrEntity> page = this.page(
new Query<AttrEntity>().getPage(params),
wrapper
);
PageUtils pageUtils = new PageUtils(page);
return pageUtils;
}
}
5. 新增分组与属性关联
当点击确认新增时,属性分组与属性关联成功。
@RestController
@RequestMapping("product/attrgroup")
public class AttrGroupController {
@Autowired
private AttrGroupService attrGroupService;
@Autowired
private CategoryService categoryService;
@Autowired
private AttrService attrService;
@Autowired
private AttrAttrgroupRelationService attrAttrgroupRelationService;
@PostMapping("/attr/relation")
public R addRelation(@RequestBody List<AttrGroupRelationVo> vos){
// 添加属性分组与属性关联关系
attrAttrgroupRelationService.saveBatch(vos);
return R.ok();
}
}
public interface AttrAttrgroupRelationService extends IService<AttrAttrgroupRelationEntity> {
...
void saveBatch(List<AttrGroupRelationVo> vos);
}
@Service("attrAttrgroupRelationService")
public class AttrAttrgroupRelationServiceImpl extends ServiceImpl<AttrAttrgroupRelationDao, AttrAttrgroupRelationEntity> implements AttrAttrgroupRelationService {
@Override
public void saveBatch(List<AttrGroupRelationVo> vos) {
List<AttrAttrgroupRelationEntity> relationEntityList = vos.stream().map(vo -> {
AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
BeanUtils.copyProperties(vo, relationEntity);
return relationEntity;
}).collect(Collectors.toList());
this.saveBatch(relationEntityList);
}
}
新增商品
1. 调试会员等级相关接口
会员等级是在 member 项目中实现的。
所以我们要对 gulimall-member 进行关于nacos 的配置
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
application:
name: gulimall-member
在gulimall-gateway 中进行配置
将member模块的项目请求交给路由转发,由路由交给renrenfast处理。
- id: member_route
uri: lb://gulimall-member
predicates:
- Path=/api/member/**
filters:
- RewritePath=/api/?(?<segment>.*), /$\{segment}
进行新增会员等级
2. 获取分类关联的品牌
前台有关pubsub、publish报错,导致无法发送查询品牌信息的请求:
(1)npm install --save pubsub-js
(2)在src下的main.js中引用:
1)import PubSub from 'pubsub-js'
2)Vue.prototype.PubSub = PubSub
在商品发布页面,当我们获取商品对应的分类时,同时也能获取到分类对应的关联品牌
一个分类可以对应多个品牌,一个品牌可以对应多个属性分组,一个属性分组可以对应多个属性
CategoryBrandRelationController
@RestController
@RequestMapping("product/categorybrandrelation")
public class CategoryBrandRelationController {
@Autowired
private CategoryBrandRelationService categoryBrandRelationService;
/**
* 获取分类关联品牌
* /product/categorybrandrelation/brands/list
*/
@GetMapping("/brands/list")
public R relationBrandList(@RequestParam(value = "catId",required = true) Long catId){
List<BrandEntity> brandEntities = categoryBrandRelationService.getBrandCatId(catId);
List<BrandVo> collect = brandEntities.stream().map(item -> { //将获取的实体类封装起来,转化为想要的数据。
BrandVo brandVo = new BrandVo(); //新建一个实体类 BrandVo
brandVo.setBrandId(item.getBrandId()); //BrandVo 从item 中获取想要的品牌 Id 和品牌姓名
brandVo.setBrandName(item.getName());
return brandVo;
}).collect(Collectors.toList()); //‘将数据收集起来封装到collect 中
return R.ok().put("data", collect);
}
}
@Data
public class AttrGroupRelationVo {
private Long attrId;
private Long attrGroupId;
}
public interface CategoryBrandRelationService extends IService<CategoryBrandRelationEntity>
{
//获取某分类下所关联的所有品牌
List<BrandEntity> getBrandCatId(Long catId);
}
@Service("categoryBrandRelationService")
public class CategoryBrandRelationServiceImpl extends ServiceImpl<CategoryBrandRelationDao, CategoryBrandRelationEntity> implements CategoryBrandRelationService {
@Autowired
private CategoryDao categoryDao;
@Autowired
private BrandDao brandDao;
@Resource
private CategoryBrandRelationDao categoryBrandRelationDao;
@Resource
private BrandService brandService;
//获取某分类下所关联的所有品牌
@Override
public List<BrandEntity> getBrandCatId(Long catId) {
List<CategoryBrandRelationEntity> catelog_id = categoryBrandRelationDao.selectList(new QueryWrapper<CategoryBrandRelationEntity>().eq("catelog_id", catId));
List<BrandEntity> brandEntities = catelog_id.stream().map(item -> {
Long brandId = item.getBrandId();
BrandEntity byId = brandService.getById(brandId);
return byId;
}).collect(Collectors.toList());
return brandEntities;
}
}
3. 获取分类下所有分组以及属性
首先当我们完善商品的基本信息--分类信息时,在发布商品页面会出现相关联的品牌信息。
同时,我们也需要获取商品的基本信息,这个同时也可以通过分类 Id 进行查询。
我们可以通过分类 id 获取对应的属性分组和属性。
/**
* /product/attrgroup/{catelogId}/withattr
* 获取分类下所有的属性分组和属性, 分类与属性相关联,每一个分类下的属性大致相同
* @param catelogId
* @return
*/
@GetMapping("/{catelogId}/withattr")
public R getAttrGroupWithAttrs(@PathVariable("catelogId") Long catelogId){
// 查询当前分类下的所有属性分组
// 查询每个属性分组的所有属性
List<AttrGroupWithAttrsVo> vos = attrGroupService.getAttrGroupWithAttrsByCatelogId(catelogId);
return R.ok().put("data",vos);
}
@Data
public class AttrGroupRelationVo {
private Long attrId;
private Long attrGroupId;
}
public interface AttrGroupService extends IService<AttrGroupEntity> {
//通过分类 id 来获取对应的 属性分组以及属性
List<AttrGroupWithAttrsVo> getAttrGroupWithAttrsByCatelogId(Long catelogId);
}
@Service("attrGroupService")
public class AttrGroupServiceImpl extends ServiceImpl<AttrGroupDao, AttrGroupEntity> implements AttrGroupService {
@Autowired
private AttrService attrService;
/**
* 根据分类id查出所有的分组以及分组关联的属性
* @param catelogId
* @return
*/
@Override
public List<AttrGroupWithAttrsVo> getAttrGroupWithAttrsByCatelogId(Long catelogId) {
// 1.根据分类Id查询分组
List<AttrGroupEntity> attrGroupEntities = this.list(new QueryWrapper<AttrGroupEntity>().eq("catelog_id", catelogId));
// 2.根据分组查询属性
//封装attrGroupEntities 所属组的属性信息
List<AttrGroupWithAttrsVo> collect = attrGroupEntities.stream().map(group -> {
AttrGroupWithAttrsVo attrsVo = new AttrGroupWithAttrsVo();
BeanUtils.copyProperties(group, attrsVo);
List<AttrEntity> attrs = attrService.getRelationAttr(attrsVo.getAttrGroupId()); //通过 组ID 获取属性ID
attrsVo.setAttrs(attrs);
return attrsVo;
}).collect(Collectors.toList());
return collect;
}
}
4. 新增商品
当我们完善发布商品的信息时,我们需要存储以下页面数据
基本信息--spu 基本信息
规格参数
sku信息--基本信息+规格参数+销售属性
当我们点击完善最后一步sku基本信息,点击确认保存时
控制台会发送 json 数据,而这些jasn数据就是我们需要进行保存的数据
保存商品信息,新增vo的抽取:
(1)点击保存商品信息,复制控制台的json数据到JSON工具(https://www.bejson.com/);
(2)将控制台的数据粘贴在格式化校验输入栏;
(3)使用JSON工具将json数据转为实体;
(4)将生成的实体放在gulimall-product模块的com.wen.gulimall.product.vo包下;
(5)调整使用JSON工具生成的实体。
商品新增Vo:
@Data
public class SpuSaveVo {
private String spuName;
private String spuDescription;
private Long catalogId;
private Long brandId;
private BigDecimal weight;
private int publishStatus;
private List<String> decript;
private List<String> images;
private Bounds bounds;
private List<BaseAttrs> baseAttrs;
private List<Skus> skus;
}
@Data
public class Bounds {
private BigDecimal buyBounds;
private BigDecimal growBounds;
}
@Data
public class BaseAttrs {
private Long attrId;
private String attrValues;
private int showDesc;
}
@Data
public class Skus {
private List<Attr> attr;
private String skuName;
private BigDecimal price;
private String skuTitle;
private String skuSubtitle;
private List<Images> images;
private List<String> descar;
private int fullCount;
private BigDecimal discount;
private int countStatus;
private BigDecimal fullPrice;
private BigDecimal reducePrice;
private int priceStatus;
private List<MemberPrice> memberPrice;
}
@Data
public class Images {
private String imgUrl;
private int defaultImg;
}
@Data
public class MemberPrice {
private Long id;
private String name;
private BigDecimal price;
}
5. 商品新增业务流程分析
保存商品信息的流程:
1. 保存spu的基本信息 ;pms_spu_info 商品基本信息
2. 保存spu的描述图片 ;pms_spu_info_desc 商品的图片描述
3. 保存spu的图片集 ;pms_spu_images 商品的图片集
4. 保存spu的规格参数 ;pms_product_attr_value 商品的规格参数
5. 保存spu的积分信息 ;gulimall_sms-》sms_spu_bounds
6. 保存当前spu对应的所有sku信息 ;
6.1 sku的基本信息 ;pms_sku_info
6.2 sku的图片信息 ;pms_sku_images
6.2 sku的销售属性信息 ;pms_sku_sale_attr_value
6.2 sku的优惠、满减等信息 ;gulimall_sms-》sms_sku_ladder/sms_sku_full_reduction/sms_member_price
6. 保存 spu 基本信息
首先我们需要创建 保存spu和sku的请求方法
由于sku是spu信息对应的,所以我们可以在SpuInfoService 中进行保存数据
我们在 SkuInfoController 中进行 SpuInfoService的save 请求
@RestController
@RequestMapping("product/skuinfo")
public class SkuInfoController {
@Autowired
private SkuInfoService skuInfoService;
@Autowired
private SpuInfoService spuInfoService;
/**
* 保存
*/
@RequestMapping("/save")
public R save(@RequestBody SpuSaveVo vo){
// skuInfoService.save(skuInfo);
spuInfoService.saveSpuInfo(vo);
return R.ok();
}
}
public interface SpuInfoService extends IService<SpuInfoEntity> {
//保存 spu和sku的所有信息
void saveSpuInfo(SpuSaveVo vo);
}
@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {
@Resource
private SpuInfoDescService spuInfoDescService;
@Resource
private SpuImagesService imagesService;
@Resource
private AttrService attrService;
@Resource
private ProductAttrValueService productAttrValueService;
@Resource
private SkuInfoService skuInfoService;
@Resource
private SkuImagesService skuImagesService;
@Resource
private SkuSaleAttrValueService skuSaleAttrValueService;
@Override
public PageUtils queryPage(Map<String, Object> params) {
IPage<SpuInfoEntity> page = this.page(
new Query<SpuInfoEntity>().getPage(params),
new QueryWrapper<SpuInfoEntity>()
);
return new PageUtils(page);
}
@Transactional(rollbackFor = Exception.class)
@Override
public void saveSpuInfo(SpuSaveVo vo) {
// 1. 保存spu的基本信息 ;pms_spu_info
SpuInfoEntity InfoEntity = new SpuInfoEntity();
BeanUtils.copyProperties(vo,InfoEntity);
InfoEntity.setCreateTime(new Date());
InfoEntity.setUpdateTime(new Date());
this.saveBaseSpuInfo(InfoEntity);
// 2. 保存spu的描述图片 ;pms_spu_info_desc
List<String> decript = vo.getDecript();
SpuInfoDescEntity descEntity = new SpuInfoDescEntity();
descEntity.setSpuId(InfoEntity.getId());
descEntity.setDecript(String.join(",",decript));
spuInfoDescService.saveSpuInfoDesc(descEntity);
// 3. 保存spu的图片集 ;pms_spu_images
List<String> images = vo.getImages();
imagesService.saveImages(InfoEntity.getId(),images);
// 4. 保存spu的规格参数 ;pms_product_attr_value
List<BaseAttrs> baseAttrs = vo.getBaseAttrs();
List<ProductAttrValueEntity> collect = baseAttrs.stream().map(attr -> {
ProductAttrValueEntity valueEntity = new ProductAttrValueEntity();
valueEntity.setAttrId(attr.getAttrId());
AttrEntity byId = attrService.getById(attr.getAttrId());
valueEntity.setAttrName(byId.getAttrName());
valueEntity.setAttrValue(attr.getAttrValues());
valueEntity.setSpuId(InfoEntity.getId());
valueEntity.setQuickShow(attr.getShowDesc());
return valueEntity;
}).collect(Collectors.toList());
productAttrValueService.saveProductAttr(collect);
// 5. 保存spu的积分信息 ;gulimall_sms-》sms_spu_bounds
// 6. 保存当前spu对应的所有sku信息 ;
// 6.1 sku的基本信息 ;pms_sku_info
// 6.2 sku的图片信息 ;pms_sku_images
// 6.3 sku的销售属性信息 ;pms_sku_sale_attr_value
}
// 6.4 sku的优惠、满减等信息 ;gulimall_sms-》
}
}
@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {
@Override
public void saveBaseSpuInfo(SpuInfoEntity InfoEntity) {
this.baseMapper.insert(InfoEntity);
}
}
public interface SpuInfoDescService extends IService<SpuInfoDescEntity> {
PageUtils queryPage(Map<String, Object> params);
//保存 spu 描述图片
void saveSpuInfoDesc(SpuInfoDescEntity descEntity);
}
public interface SpuImagesService extends IService<SpuImagesEntity> {
PageUtils queryPage(Map<String, Object> params);
//保存spu 图片集
void saveImages(Long id, List<String> images);
}
public interface ProductAttrValueService extends IService<ProductAttrValueEntity> {
PageUtils queryPage(Map<String, Object> params);
//保存商品规格参数
void saveProductAttr(List<ProductAttrValueEntity> collect);
}
7. 保存 sku 基本信息
@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {
@Resource
private SpuInfoDescService spuInfoDescService;
@Resource
private SpuImagesService imagesService;
@Resource
private AttrService attrService;
@Resource
private ProductAttrValueService productAttrValueService;
@Resource
private SkuInfoService skuInfoService;
@Resource
private SkuImagesService skuImagesService;
@Resource
private SkuSaleAttrValueService skuSaleAttrValueService;
@Override
public PageUtils queryPage(Map<String, Object> params) {
IPage<SpuInfoEntity> page = this.page(
new Query<SpuInfoEntity>().getPage(params),
new QueryWrapper<SpuInfoEntity>()
);
return new PageUtils(page);
}
@Transactional(rollbackFor = Exception.class)
@Override
public void saveSpuInfo(SpuSaveVo vo) {
// 1. 保存spu的基本信息 ;pms_spu_info
SpuInfoEntity InfoEntity = new SpuInfoEntity();
BeanUtils.copyProperties(vo,InfoEntity);
InfoEntity.setCreateTime(new Date());
InfoEntity.setUpdateTime(new Date());
this.saveBaseSpuInfo(InfoEntity);
// 2. 保存spu的描述图片 ;pms_spu_info_desc
List<String> decript = vo.getDecript();
SpuInfoDescEntity descEntity = new SpuInfoDescEntity();
descEntity.setSpuId(InfoEntity.getId());
descEntity.setDecript(String.join(",",decript));
spuInfoDescService.saveSpuInfoDesc(descEntity);
// 3. 保存spu的图片集 ;pms_spu_images
List<String> images = vo.getImages();
imagesService.saveImages(InfoEntity.getId(),images);
// 4. 保存spu的规格参数 ;pms_product_attr_value
List<BaseAttrs> baseAttrs = vo.getBaseAttrs();
List<ProductAttrValueEntity> collect = baseAttrs.stream().map(attr -> {
ProductAttrValueEntity valueEntity = new ProductAttrValueEntity();
valueEntity.setAttrId(attr.getAttrId());
AttrEntity byId = attrService.getById(attr.getAttrId());
valueEntity.setAttrName(byId.getAttrName());
valueEntity.setAttrValue(attr.getAttrValues());
valueEntity.setSpuId(InfoEntity.getId());
valueEntity.setQuickShow(attr.getShowDesc());
return valueEntity;
}).collect(Collectors.toList());
productAttrValueService.saveProductAttr(collect);
// 5. 保存spu的积分信息 ;gulimall_sms-》sms_spu_bounds
// 6. 保存当前spu对应的所有sku信息 ;
List<Skus> skus = vo.getSkus();
if(skus != null && skus.size() > 0){
skus.forEach(item -> {
// 默认图片
String defaultImg = "";
List<Images> imagesList = item.getImages();
for (Images image : imagesList) {
if(image.getDefaultImg() == 1){
defaultImg = image.getImgUrl();
}
}
// private String skuName;
// private BigDecimal price;
// private String skuTitle;
// private String skuSubtitle;
SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
BeanUtils.copyProperties(item,skuInfoEntity);
skuInfoEntity.setBrandId(InfoEntity.getBrandId());
skuInfoEntity.setCatalogId(InfoEntity.getCatalogId());
skuInfoEntity.setSkuDefaultImg(defaultImg);
skuInfoEntity.setSaleCount(0L);
skuInfoEntity.setSpuId(InfoEntity.getId());
// 6.1 sku的基本信息 ;pms_sku_info
skuInfoService.saveSkuInfo(skuInfoEntity);
Long skuId = skuInfoEntity.getSkuId();
List<SkuImagesEntity> imagesEntities = imagesList.stream().map(img -> {
SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
skuImagesEntity.setSkuId(skuId);
skuImagesEntity.setImgUrl(img.getImgUrl());
skuImagesEntity.setDefaultImg(img.getDefaultImg());
return skuImagesEntity;
}).collect(Collectors.toList());
// 6.2 sku的图片信息 ;pms_sku_images
skuImagesService.saveBatch(imagesEntities);
List<Attr> attr = item.getAttr();
List<SkuSaleAttrValueEntity> skuSaleAttrValueEntities = attr.stream().map(attr1 -> {
SkuSaleAttrValueEntity skuSaleAttrValueEntity = new SkuSaleAttrValueEntity();
BeanUtils.copyProperties(attr1, skuSaleAttrValueEntity);
skuSaleAttrValueEntity.setSkuId(skuId);
return skuSaleAttrValueEntity;
}).collect(Collectors.toList());
// 6.3 sku的销售属性信息 ;pms_sku_sale_attr_value
skuSaleAttrValueService.saveBatch(skuSaleAttrValueEntities);
});
}
// 6.4 sku的优惠、满减等信息 ;gulimall_sms-》sms_sku_ladder/sms_sku_full_reduction/sms_member_price
}
}
public interface SkuInfoService extends IService<SkuInfoEntity> {
PageUtils queryPage(Map<String, Object> params);
//保存 sku 基本信息
void saveSkuInfo(SkuInfoEntity skuInfoEntity);
}
8. 调用远程服务保存优惠等相关信息
首先我们是使用gulimall-product 调用gulimall-coupon 的保存积分信息和优惠满减信息。
1. 在common 模块中放入 vo来存储对应数据
同时product项目开始扫描FeignClient功能
@Data
public class SpuBoundsTo {
private Long spuId;
private BigDecimal buyBounds;
private BigDecimal growBounds;
}
@Data
public class SkuReductionTo {
private Long skuId;
private int fullCount;
private BigDecimal discount;
private int countStatus;
private BigDecimal fullPrice;
private BigDecimal reducePrice;
private int priceStatus;
private List<MemberPrice> memberPrice;
}
@Data
public class MemberPrice {
private Long id;
private String name;
private BigDecimal price;
}
@EnableFeignClients(basePackages = "com.atguigu.gulimall.product.feign")
@EnableDiscoveryClient
@MapperScan("com.atguigu.gulimall.product.dao")
@SpringBootApplication
public class GulimallProductApplication {
public static void main(String[] args) {
SpringApplication.run(GulimallProductApplication.class, args);
}
}
2, gulimall-product 模块引入 @FeignClient 注解,开启远程调用功能。调用gulimall-coupon
@FeignClient("gulimall-coupon")
public interface CouponFeignService {
/**
* CouponFeignService.saveSpuBounds(spuBoundsTo)
* 1)、@RequestBody 将这个对象转为json.
* 2)、找到gulimall-coupon服务,给/coupon/spubounds/save发请求。
* 将上一步转的json放在请求体位置,发送请求;
* 3)、对方服务接收到请求。请求体里有json数据。
* (@RequestBody SpuBoundsEntity spuBounds)将请求体的json转为SpuBoundsEntity;
* 注意:只要json数据模型兼容(一致)。双方服务无需使用同一个实体。
* 方法名无需一致。
*
* @param spuBoundsTo
* @return
*/
@PostMapping("/coupon/spubounds/save")
public R saveSpuBounds(@RequestBody SpuBoundsTo spuBoundsTo);
@PostMapping("/coupon/skufullreduction/saveInfo")
public R saveSkuReduction(@RequestBody SkuReductionTo skuReductionTo);
}
/**
* CouponFeignService.saveSpuBounds(spuBoundsTo)
* 1)、@RequestBody 将这个对象转为json.
* 2)、找到gulimall-coupon服务,给/coupon/spubounds/save发请求。
* 将上一步转的json放在请求体位置,发送请求;
* 3)、对方服务接收到请求。请求体里有json数据。
* (@RequestBody SpuBoundsEntity spuBounds)将请求体的json转为SpuBoundsEntity;
* 注意:只要json数据模型兼容(一致)。双方服务无需使用同一个实体。
* 方法名无需一致。
*
* @param spuBoundsTo
* @return
保存积分信息 对应gulimall-coupon 中的SpuBoundsController 的 save 方法
/**
* 商品spu积分设置
*
* @author liyang
* @email [email protected]
* @date 2023-08-07 14:47:12
*/
@RestController
@RequestMapping("coupon/spubounds")
public class SpuBoundsController {
@Autowired
private SpuBoundsService spuBoundsService;
/**
* 保存
*/
@PostMapping("/save")
public R save(@RequestBody SpuBoundsEntity spuBounds){
spuBoundsService.save(spuBounds);
return R.ok();
}
}
满减优惠
/**
* 商品满减信息
*
* @author liyang
* @email [email protected]
* @date 2023-08-07 14:47:13
*/
@RestController
@RequestMapping("coupon/skufullreduction")
public class SkuFullReductionController {
@Autowired
private SkuFullReductionService skuFullReductionService;
/**
* 保存商品满减信息, 由gulimall-product 进行远程调用,保存 sku 信息
*/
@PostMapping("/saveInfo")
//@RequiresPermissions("coupon:skufullreduction:list")
public R saveInfo(@RequestBody SkuReductionTo skuReductionTo){
skuFullReductionService.saveSkuReduction(skuReductionTo);
return R.ok();
}
}
public interface SkuFullReductionService extends IService<SkuFullReductionEntity> {
PageUtils queryPage(Map<String, Object> params);
void saveSkuReduction(SkuReductionTo skuReductionTo);
}
@Service("skuFullReductionService")
public class SkuFullReductionServiceImpl extends ServiceImpl<SkuFullReductionDao, SkuFullReductionEntity> implements SkuFullReductionService {
@Resource
private SkuLadderService skuLadderService;
@Resource
private MemberPriceService memberPriceService;
...
@Override
public void saveSkuReduction(SkuReductionTo skuReductionTo) {
// sku的优惠、满减等信息 ;gulimall_sms-》sms_sku_ladder/sms_sku_full_reduction/sms_member_price
// 1. sms_sku_ladder
SkuLadderEntity skuLadderEntity = new SkuLadderEntity();
BeanUtils.copyProperties(skuReductionTo,skuLadderEntity);
skuLadderEntity.setAddOther(skuReductionTo.getCountStatus());
// 折后价price
skuLadderService.save(skuLadderEntity);
// 2. sms_sku_full_reduction
SkuFullReductionEntity skuFullReductionEntity = new SkuFullReductionEntity();
BeanUtils.copyProperties(skuReductionTo,skuFullReductionEntity);
skuFullReductionEntity.setAddOther(skuReductionTo.getPriceStatus());
this.save(skuFullReductionEntity);
// 3. sms_member_price
List<MemberPrice> memberPrice = skuReductionTo.getMemberPrice();
List<MemberPriceEntity> collect = memberPrice.stream().map(item -> {
MemberPriceEntity memberPriceEntity = new MemberPriceEntity();
memberPriceEntity.setSkuId(skuReductionTo.getSkuId());
memberPriceEntity.setMemberLevelId(item.getId());
memberPriceEntity.setMemberLevelName(item.getName());
memberPriceEntity.setMemberPrice(item.getPrice());
memberPriceEntity.setAddOther(1);
return memberPriceEntity;
}).collect(Collectors.toList());
memberPriceService.saveBatch(collect);
}
}
@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {
@Resource
private SpuInfoDescService spuInfoDescService;
@Resource
private SpuImagesService spuImagesService;
@Resource
private AttrService attrService;
@Resource
private ProductAttrValueService productAttrValueService;
@Resource
private SkuInfoService skuInfoService;
@Resource
private SkuImagesService skuImagesService;
@Resource
private SkuSaleAttrValueService skuSaleAttrValueService;
@Resource
private CouponFeignService couponFeignService;
...
@Transactional(rollbackFor = Exception.class)
@Override
public void saveSpuInfo(SpuSaveVo vo) {
// 1. 保存spu的基本信息 ;pms_spu_info
SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
BeanUtils.copyProperties(vo,spuInfoEntity);
spuInfoEntity.setCreateTime(new Date());
spuInfoEntity.setUpdateTime(new Date());
this.saveBaseSpuInfo(spuInfoEntity);
// 2. 保存spu的描述图片 ;pms_spu_info_desc
List<String> decript = vo.getDecript();
SpuInfoDescEntity descEntity = new SpuInfoDescEntity();
descEntity.setSpuId(spuInfoEntity.getId());
descEntity.setDecript(String.join(",",decript));
spuInfoDescService.saveSpuInfoDesc(descEntity);
// 3. 保存spu的图片集 ;pms_spu_images
List<String> images = vo.getImages();
spuImagesService.saveImages(spuInfoEntity.getId(),images);
// 4. 保存spu的规格参数 ;pms_product_attr_value
List<BaseAttrs> baseAttrs = vo.getBaseAttrs();
List<ProductAttrValueEntity> collect = baseAttrs.stream().map(attr -> {
ProductAttrValueEntity valueEntity = new ProductAttrValueEntity();
valueEntity.setAttrId(attr.getAttrId());
AttrEntity byId = attrService.getById(attr.getAttrId());
valueEntity.setAttrName(byId.getAttrName());
valueEntity.setAttrValue(attr.getAttrValues());
valueEntity.setSpuId(spuInfoEntity.getId());
valueEntity.setQuickShow(attr.getShowDesc());
return valueEntity;
}).collect(Collectors.toList());
productAttrValueService.saveProductAttr(collect);
// 5. 保存spu的积分信息 ;gulimall_sms-》sms_spu_bounds
Bounds bounds = vo.getBounds();
SpuBoundsTo spuBoundsTo = new SpuBoundsTo();
BeanUtils.copyProperties(bounds,spuBoundsTo);
spuBoundsTo.setSpuId(spuInfoEntity.getId());
R r = couponFeignService.saveSpuBounds(spuBoundsTo);
if(r.getCode() != 0){
log.error("远程保存spu积分信息失败");
}
// 6. 保存当前spu对应的所有sku信息 ;
List<Skus> skus = vo.getSkus();
if(skus != null && skus.size() > 0){
skus.forEach(item -> {
// 默认图片
String defaultImg = "";
List<Images> imagesList = item.getImages();
for (Images image : imagesList) {
if(image.getDefaultImg() == 1){
defaultImg = image.getImgUrl();
}
}
// private String skuName;
// private BigDecimal price;
// private String skuTitle;
// private String skuSubtitle;
SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
BeanUtils.copyProperties(item,skuInfoEntity);
skuInfoEntity.setBrandId(spuInfoEntity.getBrandId());
skuInfoEntity.setCatalogId(spuInfoEntity.getCatalogId());
skuInfoEntity.setSkuDefaultImg(defaultImg);
skuInfoEntity.setSaleCount(0L);
skuInfoEntity.setSpuId(spuInfoEntity.getId());
// 6.1 sku的基本信息 ;pms_sku_info
skuInfoService.saveSkuInfo(skuInfoEntity);
Long skuId = skuInfoEntity.getSkuId();
List<SkuImagesEntity> imagesEntities = imagesList.stream().map(img -> {
SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
skuImagesEntity.setSkuId(skuId);
skuImagesEntity.setImgUrl(img.getImgUrl());
skuImagesEntity.setDefaultImg(img.getDefaultImg());
return skuImagesEntity;
}).collect(Collectors.toList());
// 6.2 sku的图片信息 ;pms_sku_images
skuImagesService.saveBatch(imagesEntities);
List<Attr> attr = item.getAttr();
List<SkuSaleAttrValueEntity> skuSaleAttrValueEntities = attr.stream().map(attr1 -> {
SkuSaleAttrValueEntity skuSaleAttrValueEntity = new SkuSaleAttrValueEntity();
BeanUtils.copyProperties(attr1, skuSaleAttrValueEntity);
skuSaleAttrValueEntity.setSkuId(skuId);
return skuSaleAttrValueEntity;
}).collect(Collectors.toList());
// 6.3 sku的销售属性信息 ;pms_sku_sale_attr_value
skuSaleAttrValueService.saveBatch(skuSaleAttrValueEntities);
// 6.4 sku的优惠、满减等信息 ;gulimall_sms-》sms_sku_ladder/sms_sku_full_reduction/sms_member_price
SkuReductionTo skuReductionTo = new SkuReductionTo();
BeanUtils.copyProperties(item,skuReductionTo);
skuReductionTo.setSkuId(skuId);
R r1 = couponFeignService.saveSkuReduction(skuReductionTo);
if(r1.getCode() != 0){
log.error("远程保存sku优惠信息失败");
}
});
}
}
@Override
public void saveBaseSpuInfo(SpuInfoEntity spuInfoEntity) {
this.baseMapper.insert(spuInfoEntity);
}
}
9. 商品保存debug 完成
10. SPU 检索
当我们进入spu管理界面
会出现spu基本信息列表,当我们在搜索框输入相关信息是,希望能检索到相关信息
我们应该在SpuInfoController 中进行更改方法,使其能够进行搜索功能
SpuInfoController
/**
* spu管理页面列表
*/
@RequestMapping("/list")
public R list(@RequestParam Map<String, Object> params){
// PageUtils page = spuInfoService.queryPage(params);
PageUtils page = spuInfoService.queryPageCondition(params);
return R.ok().put("page", page);
}
@Service("SpuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {
@Resource
private SpuInfoDescService spuInfoDescService;
@Resource
private SpuImagesService spuImagesService;
@Resource
private AttrService attrService;
@Resource
private ProductAttrValueService productAttrValueService;
@Resource
private SkuInfoService skuInfoService;
@Resource
private SkuImagesService skuImagesService;
@Resource
private SkuSaleAttrValueService skuSaleAttrValueService;
@Resource
private CouponFeignService couponFeignService;
//spu 管理页面列表数据,同时加载搜索框功能
@Override
public PageUtils queryPageCondition(Map<String, Object> params) {
QueryWrapper<SpuInfoEntity> wrapper = new QueryWrapper<>();
/**
* status:
* 0
* key:
* brandId:
* 7
* catelogId:
* 225
*/
String key = (String) params.get("key");
if(!StringUtils.isEmpty(key)){
// 或两边的条件要括起来使用and()
wrapper.and((w) -> {
w.eq("id",key).or().like("spu_name",key);
});
}
String status = (String) params.get("status");
if(!StringUtils.isEmpty(status)){ //商品信息状态要与顶部状态栏一致
wrapper.eq("publish_status",status);
}
String brandId = (String) params.get("brandId"); //品牌Id
if(!StringUtils.isEmpty(brandId) && !"0".equals(brandId)){
wrapper.eq("brand_id",brandId);
}
String catelogId = (String)params.get("catelogId");
if(!StringUtils.isEmpty(catelogId) && !"0".equals(catelogId)){
wrapper.eq("catalog_id",catelogId);
}
IPage<SpuInfoEntity> page = this.page(
new Query<SpuInfoEntity>().getPage(params),
wrapper
);
return new PageUtils(page);
}
}
在application.yml 中添加配置,用来返回固定的日期格式
spring:
datasource:
username: root
password: abc123
url: jdbc:mysql://192.168.56.105:3306/gulimall_pms?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
alicloud:
access-key: LTAI5t68jUrcr46DeeeLjGDV
secret-key: SXwnCFGCmm0NbENoD2uPWg0xxAIdj5
oss:
endpoint: oss-cn-beijing.aliyuncs.com
jackson: #在spu检索中进行配置日期,返回格式要固定
date-format: yyyy-MM-dd HH:mm:ss
11. SKU 检索
@RestController
@RequestMapping("product/skuinfo")
public class SkuInfoController {
@Autowired
private SkuInfoService skuInfoService;
@Autowired
private SpuInfoService spuInfoService;
/**
* 列表
*/
@RequestMapping("/list")
public R list(@RequestParam Map<String, Object> params){
// PageUtils page = skuInfoService.queryPage(params);
PageUtils page = skuInfoService.queryPageCondition(params);
return R.ok().put("page", page);
}
}
public interface SkuInfoService extends IService<SkuInfoEntity> {
PageUtils queryPage(Map<String, Object> params);
//保存 sku 基本信息
void saveSkuInfo(SkuInfoEntity skuInfoEntity);
//Sku管理页面查询数据,添加搜索框功能
PageUtils queryPageCondition(Map<String, Object> params);
}
@Service("skuInfoService")
public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoDao, SkuInfoEntity> implements SkuInfoService {
//Sku 管理页面基本信息,添加搜索框功能
@Override
public PageUtils queryPageCondition(Map<String, Object> params) {
/**
* key:
* catelogId:
* 0
* brandId:
* 0
* min:
* 0
* max:
* 0
*/
QueryWrapper<SkuInfoEntity> wrapper = new QueryWrapper<>();
String key = (String) params.get("key");
if(!StringUtils.isEmpty(key)){
// 或两边的条件要括起来使用and()
wrapper.and((w) -> {
w.eq("sku_id",key).or().like("sku_name",key);
});
}
String brandId = (String) params.get("brandId");
if(!StringUtils.isEmpty(brandId) && !"0".equals(brandId)){
wrapper.eq("brand_id",brandId);
}
String catelogId = (String)params.get("catelogId");
if(!StringUtils.isEmpty(catelogId) && !"0".equals(catelogId)){
wrapper.eq("catalog_id",catelogId);
}
String min = (String) params.get("min");
if(!StringUtils.isEmpty(min)){
wrapper.ge("price",min);
}
//添加检索价格区间
String max = (String) params.get("max");
if(!StringUtils.isEmpty(max)){
try {
BigDecimal bigDecimal = new BigDecimal(max);
if(bigDecimal.compareTo(new BigDecimal("0")) == 1) {
wrapper.le("price", max);
}
} catch (Exception e) {
e.printStackTrace();
}
}
IPage<SkuInfoEntity> page = this.page(
new Query<SkuInfoEntity>().getPage(params),
wrapper
);
return new PageUtils(page);
}
}