谷粒商城之分布式基础(三)

7 仓库服务

7.1 数据表的说明

用到gulimall_wms数据库中的的两张表,第一张是wms_ware_info,表示有几个仓库

1668868582049

第二张表是wms_ware_sku,表每个仓库有几个sku商品

1668868613256

7.2 整合仓库服务

1、要整合仓库服务,首先把仓库服务注册到nacos中

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
  application:
    name: gulimall-ware

2、配置网关

        - id: ware_route
          uri: lb://gulimall-ware
          predicates:
            - Path=/api/ware/**
          filters:
            - RewritePath=/api/(?<segment>/?.*), /$\{segment}

3、配置后测试仓库维护

image-20211008203531424

4、实现仓库模糊查询功能

点击查询,查看url

http://localhost:88/api/ware/wareinfo/list?t=1633696575331&page=1&limit=10&key=

WareInfoController.java

 /**
     * 列表
     */
    @RequestMapping("/list")
    //@RequiresPermissions("ware:wareinfo:list")
    public R list(@RequestParam Map<String, Object> params){
        PageUtils page = wareInfoService.queryPage(params);

        return R.ok().put("page", page);
    }

WareInfoServiceImpl.java

 @Override
    public PageUtils queryPage(Map<String, Object> params) {

        QueryWrapper<WareInfoEntity> wareInfoEntityQueryWrapper = new QueryWrapper<>();
		// 模糊查询
        String key = (String) params.get("key");
        if (!StringUtils.isEmpty(key)){
            wareInfoEntityQueryWrapper.eq("id",key).or()
                    .like("name",key)
                    .or().like("address",key)
                    .or().like("areacode",key);
        }

        IPage<WareInfoEntity> page = this.page(
                new Query<WareInfoEntity>().getPage(params),
                wareInfoEntityQueryWrapper
        );

        return new PageUtils(page);
    }

设置日志输出级别,方便查看sql语句

logging:
  level:
    com.atguigu: debug

效果展示

1668868943322

7.3 查询库存的模糊查询

1、库存系统02,url:/ware/waresku/list

2、实现库存模糊查询功能,WareSkuServiceImpl.java

@Override
    public PageUtils queryPage(Map<String, Object> params) {

        // skuId: 1
        // wareId: 2

        QueryWrapper<WareSkuEntity> queryWrapper = new QueryWrapper<>();

        String skuId = (String) params.get("skuId");
        if (!StringUtils.isEmpty(skuId)){
            queryWrapper.eq("sku_id",skuId);
        }

        String wareId = (String) params.get("wareId");
        if (!StringUtils.isEmpty(wareId)){
            queryWrapper.eq("ware_id",wareId);
        }

        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

3、效果展示:

1668872029447

7.4 采购需求的模糊查询

1、库存系统03,url:/ware/purchasedetail/list

2、PurchaseDetailServiceImpl.java

 @Override
    public PageUtils queryPage(Map<String, Object> params) {
        QueryWrapper<PurchaseDetailEntity> queryWrapper = new QueryWrapper<>();

        // status: 0,//状态
        //wareId: 1,//仓库id

        //模糊查询
        String key = (String) params.get("key");
        if (!StringUtils.isEmpty(key)){
            // purchase_id  sku_id
            queryWrapper.and(w ->{
                w.eq("purchase_id",key).or().eq("sku_id",key);
            });
        }

        //状态
        String status = (String) params.get("status");
        if (!StringUtils.isEmpty(status)){
            queryWrapper.eq("status",status);
        }
        //仓库
        String wareId = (String) params.get("wareId");
        if (!StringUtils.isEmpty(wareId)){
            queryWrapper.eq("ware_id",wareId);
        }


        IPage<PurchaseDetailEntity> page = this.page(
                new Query<PurchaseDetailEntity>().getPage(params),
                queryWrapper

        );

        return new PageUtils(page);
    }

7.5 合并采购流程

1、采购逻辑,新建采购需求后还要可以提供合并采购单,比如一个仓库的东西可以合并到一起,让采购人员一趟采购完

1668909900164

新建采购需求后还要可以提供合并采购单,比如一个仓库的东西可以合并到一起,让采购人员一趟采购完

1668909956298

新建采购单,可以在采购单后面分配给员工,员工可以在系统管理->管理员列表中新建

image-20211009142748552

7.6 查询未领取的采购单

1、库存系统05、url:/ware/purchase/unreceive/list, 查询未领取的采购单

image-20211009142933952

2、PurchaseController.java

/**
     * 查询未领取的采购单
     * ///ware/purchase/unreceive/list
     * @param params
     * @return
     */
    @RequestMapping("/unreceive/list")
    //@RequiresPermissions("ware:purchase:list")
    public R unreceivelist(@RequestParam Map<String, Object> params){
        PageUtils page = purchaseService.queryPageUnreceive(params);

        return R.ok().put("page", page);
    }

3、在 gulimall-common 服务下新建常量枚举类constant.WareConstant

public class WareConstant {

    /** 采购单状态枚举 */
    public enum PurchaseStatusEnum {
        CREATED(0,"新建"), ASSIGNED(1,"已分配"),
        RECEIVE(2,"已领取"), FINISH(3,"已完成"),
        HASERROR(4,"有异常");

        private int code;
        private String msg;

        PurchaseStatusEnum(int code, String msg) {
            this.code = code;
            this.msg = msg;
        }

        public int getCode() {
            return code;
        }

        public String getMsg() {
            return msg;
        }
    }

    /** 采购需求枚举 */
    public enum PurchaseDetailStatusEnum {
        CREATED(0,"新建"), ASSIGNED(1,"已分配"),
        RECEIVE(2,"正在采购"), FINISH(3,"已完成"),
        HASERROR(4,"采购失败");

        private int code;
        private String msg;

        PurchaseDetailStatusEnum(int code, String msg) {
            this.code = code;
            this.msg = msg;
        }

        public int getCode() {
            return code;
        }

        public String getMsg() {
            return msg;
        }
    }
}

4、queryPageUnreceive.java

@Override
    public PageUtils queryPageUnreceive(Map<String, Object> params) {


        IPage<PurchaseEntity> page = this.page(
                new Query<PurchaseEntity>().getPage(params),
                new QueryWrapper<PurchaseEntity>().eq("status",0).or().eq("status",1)
        );

        return new PageUtils(page);


    }

5、效果展示

1668910331507

7.7 合并采购需求

1、库存系统04,url:/ware/purchase/merge

选择要合并的采购需求,然后合并到整单

image-20211009143734631

如果不选择整单id,则自动创建新的采购单

image-20211009144346072

2、新建MergerVo.java

@Data
public class MergeVo {


   private Long purchaseId; //整单id
   private List<Long> items; //[1,2,3,4] //合并项集合
}

3、分配,就是修改【采购需求】里对应的【采购单id、采购需求状态】,即purchase_detail表

并且不能重复分配采购需求给不同的采购单,如果还没去采购,或者采购失败,就可以修改

PurchaseController.java

 /**
     * 合并采购需求
     * // /ware/purchase/merge
     * @param mergeVo
     * @return
     */
    @PostMapping("/merge")
    public R merge(@RequestBody MergeVo mergeVo){

        purchaseService.mergePurchase(mergeVo);
        return R.ok();
    }

PurchaseServiceImpl.java

@Override
    public void mergePurchase(MergeVo mergeVo) {

        Long purchaseId = mergeVo.getPurchaseId();
        if (purchaseId == null){  //说明是新增的
            //1.新建一个
            PurchaseEntity purchaseEntity = new PurchaseEntity();
            purchaseEntity.setStatus(WareConstant.PurchaseStatusEnum.CREATED.getCode());
            purchaseEntity.setCreateTime(new Date());
            purchaseEntity.setUpdateTime(new Date());
            this.save(purchaseEntity);
           purchaseId =  purchaseEntity.getId();
        }

        //合并
        List<Long> items = mergeVo.getItems();
        Long finalPurchaseId = purchaseId;

        List<PurchaseDetailEntity> collect = items.stream().map(i -> {
            PurchaseDetailEntity detailEntity = new PurchaseDetailEntity();

            detailEntity.setId(i);
            detailEntity.setPurchaseId(finalPurchaseId);
            detailEntity.setStatus(WareConstant.PurchaseDetailStatusEnum.ASSIGNED.getCode());
            return detailEntity;
        }).collect(Collectors.toList());


        detailService.updateBatchById(collect);

        //修改一些更新日期
        PurchaseEntity purchaseEntity = new PurchaseEntity();
        purchaseEntity.setId(purchaseId);
        purchaseEntity.setUpdateTime(new Date());
        this.updateById(purchaseEntity);

    }

在配置文件中对时间json进行格式化

  jackson:
    date-format: yyyy-MM-dd HH:mm:ss

4、效果展示

合并

1668875078398

新建

1668875134134

7.8 领取采购单

采购单分配给了采购人员,采购人员在手机端领取采购单,此时的采购单应该为新建或已分配状态,在采购人员领取后采购单的状态变为已领取,采购需求的状态变为正在采购

1、库存系统06、url:/ware/purchase/received

2、PurchaseController.java

 /*
        //ware/purchase/received
     * 领取采购单
     * @param ids
     * @return
     */
    @PostMapping("/received")
    public R received(@RequestBody List<Long> ids){

        purchaseService.received(ids);

        return R.ok();

    }

3、PurchaseServiceImpl.java

 /**
     *
     * @param ids 采购单id
     */
    @Override
    public void received(List<Long> ids) {
        //1.确认当前采购单是新建或者已分配状态
        List<PurchaseEntity> collect = ids.stream().map(id -> {
            PurchaseEntity byId = this.getById(id);
            return byId;
        }).filter(item -> {
            //判断状态
            if (item.getStatus() == WareConstant.PurchaseStatusEnum.CREATED.getCode() ||
                    item.getStatus() == WareConstant.PurchaseStatusEnum.ASSIGNED.getCode()) {
                return true;
            }
            return false;
        }).map(item ->{
            item.setStatus(WareConstant.PurchaseStatusEnum.RECEIVE.getCode()); //设置最新的状态
            item.setUpdateTime(new Date()); //设置修改的时间
            return item;
        }).collect(Collectors.toList());

        //2.改变采购单的状态
        this.updateBatchById(collect);

        //3.改变采购项的状态
        collect.forEach((item) ->{
            List<PurchaseDetailEntity> entities =  detailService.listDetailByPurchaseId(item.getId());
            List<PurchaseDetailEntity> detailEntities = entities.stream().map(entity -> {
                PurchaseDetailEntity entity1 = new PurchaseDetailEntity();
                entity1.setId(entity.getId());
                entity1.setStatus(WareConstant.PurchaseDetailStatusEnum.RECEIVE.getCode());//更新状态
                return entity1;
            }).collect(Collectors.toList());
            detailService.updateBatchById(detailEntities);
        });

    }


其中用到的   listDetailByPurchaseId 方法(PurchaseDetailServiceImpl@Override
    public List<PurchaseDetailEntity> listDetailByPurchaseId(Long id) {

        List<PurchaseDetailEntity> purchaseId = this.list(new QueryWrapper<PurchaseDetailEntity>().eq("purchase_id", id));

        return purchaseId;
    }

4、用 APIfox 进行 采购人员领取采购单测试

http://localhost:88/api/ware/purchase/received

1668913386490

5、效果展示

采购需求变为 正在采购

1668913422313

采购单2号变成 已领取

1668913448279

7.9 完成采购

完成采购的步骤:

判断所有采购需求的状态,采购需求全部完成时,采购单状态才为完成
采购项完成的时候,增加库存(调用远程获取skuName)
加上分页插件
1、库存系统07,url:/ware/purchase/done

2、新建PurchaseItemDoneVo,PurchaseDoneVo

@Data
public class PurchaseDoneVo {


    @NotNull
    private Long id;//采购单id

    private List<PurchaseItemDoneVo> items;完成/失败的需求详情

}
@Data
public class PurchaseItemDoneVo {


    // [{itemId:1,status:4,reason:""}]
    private Long itemId;
    private Integer status;
    private String reason;


}

3、PurchaseController.java

 /**
     * 完成采购
     *    // /ware/purchase/done
     * @param doneVo
     * @return
     */
    @PostMapping("/done")
    public R finish(@RequestBody PurchaseDoneVo doneVo){
        purchaseService.done(doneVo);

        return R.ok();
    }

4、PurchaseServiceImpl.java

    @Autowired
    PurchaseDetailService detailService;

    @Autowired
    WareSkuService wareSkuService;

	@Transactional
    @Override
    public void done(PurchaseDoneVo doneVo) {
        Long id = doneVo.getId();

        //2.改变采购项的状态
        Boolean flag = true;

        List<PurchaseItemDoneVo> items = doneVo.getItems();

        List<PurchaseDetailEntity> updates = new ArrayList<>();
        for (PurchaseItemDoneVo item : items) {
            PurchaseDetailEntity detailEntity = new PurchaseDetailEntity();
            //采购需求失败
            if (item.getStatus() == WareConstant.PurchaseDetailStatusEnum.HASERROR.getCode()){
                flag = false;
                detailEntity.setStatus(item.getStatus());
            }else{
                detailEntity.setStatus(WareConstant.PurchaseDetailStatusEnum.FINISH.getCode());
                //3.将成功采购的进行入库
                PurchaseDetailEntity entity = detailService.getById(item.getItemId());//查出当前采购项的详细信息
                wareSkuService.addStock(entity.getSkuId(),entity.getWareId(),entity.getSkuNum());

            }
            采购需求成功
            detailEntity.setId(item.getItemId());
            updates.add(detailEntity);
        }

        detailService.updateBatchById(updates);

        //1.改变采购单的状态
        PurchaseEntity purchaseEntity = new PurchaseEntity();
        purchaseEntity.setId(id);
        purchaseEntity.setStatus(flag?WareConstant.PurchaseStatusEnum.FINISH.getCode() : WareConstant.PurchaseStatusEnum.HASERROR.getCode());
        this.updateById(purchaseEntity);

    }

5、新建feign.ProductFeignService接口,用来远程获取skuName

ProductFeignService.java

@FeignClient("gulimall-product")
public interface ProductFeignService {

    /**
     * 这里路径有两种写法
     * 1.让所有请求过网关:
     *    1)、@FeignClient("gulimall-gateway"):给gulimall-gateway所在的机器发请求
     *    2)、/api/product/skuinfo/info/{skuId}
     *
     * 2.直接让后台指定服务器
     *    1)、@FeignClient("gulimall-product")
     *    2)、/product/skuinfo/info/{skuId}
     *
     * @return
     */
    @RequestMapping("/product/skuinfo/info/{skuId}")
    //@RequiresPermissions("product:skuinfo:info")
    public R info(@PathVariable("skuId") Long skuId);
}

6、主启动类加上注解@EnableFeignClients

7、WareSkuServiceImpl.java 实现入库操作

    @Autowired
    WareSkuDao wareSkuDao;

    @Autowired
    ProductFeignService productFeignService; 

	@Override
    public void addStock(Long skuId, Long wareId, Integer skuNum) {
        //1.判断如果还没有这个库存记录就新增
        List<WareSkuEntity> entities = wareSkuDao.selectList(new QueryWrapper<WareSkuEntity>().eq("sku_id", skuId).eq("ware_id", wareId));
        if (entities == null || entities.size() == 0){  //如果仓库中没有商品的话新增
            WareSkuEntity skuEntity = new WareSkuEntity();
            skuEntity.setSkuId(skuId);
            skuEntity.setStock(skuNum);
            skuEntity.setWareId(wareId);
            skuEntity.setStockLocked(0);

            //TODO 远程查询sku的名字,如果失败,整个事务无需回滚
            //1.自己catch异常
            try {
                R info = productFeignService.info(skuId);
             Map<String,Object> data = (Map<String, Object>) info.get("skuInfo");

             if (info.getCode() == 0){
                 skuEntity.setSkuName((String) data.get("skuName"));
             }
            }catch(Exception e){

            }
            //TODO  还可以用什么办法让异常出现以后不会滚? 高级

            skuEntity.setSkuName("");
            wareSkuDao.insert(skuEntity);
        }else { //如果仓库中有商品的话更新,增加库存
            wareSkuDao.addStock(skuId,wareId,skuNum);
        }

    }



8、WareInfoDao.xml

    <update id="addStock">
        UPDATE `wms_ware_sku` SET stock = stock +#{skuNum} WHERE sku_id =#{skuId} AND ware_id =#{wareId}
    </update>

9、添加分页插件,复制product服务中的即可

MyBatisConfig.java

@EnableTransactionManagement //开启事务
@MapperScan("com.atguigu.gulimall.ware.dao")
@Configuration
public class MyBatisConfig {


    //引入分页插件
    @Bean
    public PaginationInterceptor paginationInterceptor(){
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        //设置请求的页面大于最大页后操作,true调回到首页,false继续请求,默认false
        paginationInterceptor.setOverflow(true);
        //设置最大单页限制数量,默认 500 条,-1 不受限制
        paginationInterceptor.setLimit(1000);
        return paginationInterceptor;
    }
}

10、效果展示:

POST http://localhost:88/api/ware/purchase/done
Content-Type: application/json

{
  "id": 2,
  "items": [
    {"itemId":1,"status":3,"reason":"完成"},
    {"itemId":2,"status":4,"reason":"无货"}
  ]
}

1668922114997

1668922143112

1668922163827

7.10 获取spu规格

1、商品系统22、url:/product/attr/base/listforspu/{spuId}

2、AttrController.java

/**
     * 获取spu规格
     * @param spuId
     * @return
     */
    // /product/attr/base/listforspu/{spuId}
    @GetMapping("/base/listforspu/{spuId}")
    public R baseAttrlistforspu(@PathVariable("spuId") Long spuId){
     List<ProductAttrValueEntity> entities =    productAttrValueService.baseAttrlistforspu(spuId);

     return R.ok().put("data",entities);
    }

3、ProductAttrValueServiceImpl.java

 @Override
    public List<ProductAttrValueEntity> baseAttrlistforspu(Long spuId) {

        List<ProductAttrValueEntity> entities = this.baseMapper.selectList(new QueryWrapper<ProductAttrValueEntity>().eq("spu_id", spuId));

        return entities;
    }

4、效果展示:测试,点击规格

1668929872351

ps:如果出现 400 页面提示:

点击规格找不到页面,解决如下:往数据库中插入信息
INSERT INTO sys_menu (menu_id, parent_id, name, url, perms, type, icon, order_num) VALUES (76, 37, ‘规格维护’, ‘product/attrupdate’, ‘’, 2, ‘log’, 0);

1668930089904

7.11修改商品规格

1、商品系统23,url:/product/attr/update/{spuId}

2、AttrController.java

 /**
     *     // /product/attr/update/{spuId}
     * 修改商品规格
     * @param spuId
     * @param entities
     * @return
     */
    @PostMapping("/update/{spuId}")
    public R updateSpuAttr(@PathVariable("spuId") Long spuId,
                           @RequestBody List<ProductAttrValueEntity> entities){
        productAttrValueService.updateSpuAttr(spuId,entities);

        return R.ok();
    }

3、ProductAttrValueServiceImpl.java

因为修改的时候,有新增有修改有删除。 所以就先把spuId对应的所有属性都删了,再新增

    @Transactional
    @Override
    public void updateSpuAttr(Long spuId, List<ProductAttrValueEntity> entities) {
        //1. 删除这个 spuId之前对应的所有属性
        this.baseMapper.delete(new QueryWrapper<ProductAttrValueEntity>().eq("spu_id",spuId));

        //2.保存最新的 spu 属性
        List<ProductAttrValueEntity> collect = entities.stream().map(item -> {
            item.setSpuId(spuId);
            return item;
        }).collect(Collectors.toList());

        this.saveBatch(collect);
    }

4、效果展示:添加机身材质工艺

1668929850851

8 项目中的分页逻辑分析

1、以spu检索为例,请求参数为:

{
   page: 1,//当前页码
   limit: 10,//每页记录数
   sidx: 'id',//排序字段
   order: 'asc/desc',//排序方式
   key: '华为',//检索关键字
   catelogId: 6,//三级分类id
   brandId: 1,//品牌id 
   status: 0,//商品状态
}

2、响应参数为:

{
	"msg": "success",
	"code": 0,
	"page": {
		"totalCount": 0,
		"pageSize": 10,
		"totalPage": 0,
		"currPage": 1,
		"list": [{

			"brandId": 0, //品牌id
			"brandName": "品牌名字",
			"catalogId": 0, //分类id
			"catalogName": "分类名字",
			"createTime": "2019-11-13T16:07:32.877Z", //创建时间
			"id": 0, //商品id
			"publishStatus": 0, //发布状态
			"spuDescription": "string", //商品描述
			"spuName": "string", //商品名字
			"updateTime": "2019-11-13T16:07:32.877Z", //更新时间
			"weight": 0 //重量

		}]
	}
}

3、page中的数据由common里com.xmh.common.utils.PageUils类封装而成,PageUils的构造器中要传入参数:Ipage接口的实现类page,从page中读取到数据

/**
 * 分页工具类
 *
 * @author Mark sunlightcs@gmail.com
 */
public class PageUtils implements Serializable {
	private static final long serialVersionUID = 1L;
	/**
	 * 总记录数
	 */
	private int totalCount;
	/**
	 * 每页记录数
	 */
	private int pageSize;
	/**
	 * 总页数
	 */
	private int totalPage;
	/**
	 * 当前页数
	 */
	private int currPage;
	/**
	 * 列表数据
	 */
	private List<?> list;
	
	/**
	 * 分页
	 * @param list        列表数据
	 * @param totalCount  总记录数
	 * @param pageSize    每页记录数
	 * @param currPage    当前页数
	 */
	public PageUtils(List<?> list, int totalCount, int pageSize, int currPage) {
		this.list = list;
		this.totalCount = totalCount;
		this.pageSize = pageSize;
		this.currPage = currPage;
		this.totalPage = (int)Math.ceil((double)totalCount/pageSize);
	}

	/**
	 * 分页
	 */
	public PageUtils(IPage<?> page) {
		this.list = page.getRecords();
		this.totalCount = (int)page.getTotal();
		this.pageSize = (int)page.getSize();
		this.currPage = (int)page.getCurrent();
		this.totalPage = (int)page.getPages();
	}

	

4、构造一个page需要传入两个参数,第一个参数是page,第二个参数是QueryWrapper(查询条件)

    @Override
    public PageUtils queryPageByCondition(Map<String, Object> params) {

        QueryWrapper<SpuInfoEntity> wrapper = new QueryWrapper<>();

       
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                wrapper
        );
        return new PageUtils(page);
    }

page的方法,返回根据QueryWrapper和page查出的封装好的IPage实现类

@Override
    public IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper) {
        return baseMapper.selectPage(page, queryWrapper);
    }

5、第一个参数page,由com.atguigu.common.utils.Query类封装,调用Query类的getPage方法,根据前端传来的参数返回一个IPage实现类

/**
 * 查询参数
 *
 * @author Mark sunlightcs@gmail.com
 */
public class Query<T> {

    public IPage<T> getPage(Map<String, Object> params) {
        return this.getPage(params, null, false);
    }

    public IPage<T> getPage(Map<String, Object> params, String defaultOrderField, boolean isAsc) {
        //分页参数
        long curPage = 1;
        long limit = 10;

        if(params.get(Constant.PAGE) != null){
            curPage = Long.parseLong((String)params.get(Constant.PAGE));
        }
        if(params.get(Constant.LIMIT) != null){
            limit = Long.parseLong((String)params.get(Constant.LIMIT));
        }

        //分页对象
        Page<T> page = new Page<>(curPage, limit);

        //分页参数
        params.put(Constant.PAGE, page);

        //排序字段
        //防止SQL注入(因为sidx、order是通过拼接SQL实现排序的,会有SQL注入风险)
        String orderField = SQLFilter.sqlInject((String)params.get(Constant.ORDER_FIELD));
        String order = (String)params.get(Constant.ORDER);


        //前端字段排序
        if(StringUtils.isNotEmpty(orderField) && StringUtils.isNotEmpty(order)){
            if(Constant.ASC.equalsIgnoreCase(order)) {
                return  page.addOrder(OrderItem.asc(orderField));
            }else {
                return page.addOrder(OrderItem.desc(orderField));
            }
        }

        //没有排序字段,则不排序
        if(StringUtils.isBlank(defaultOrderField)){
            return page;
        }

        //默认排序
        if(isAsc) {
            page.addOrder(OrderItem.asc(defaultOrderField));
        }else {
            page.addOrder(OrderItem.desc(defaultOrderField));
        }

        return page;
    }
}

总的流程就是:

  • 前端传过来分页的参数
  • 根据参数新建IPage接口的实现类page,需要两个参数(page,wrapper)
    • 第一个参数用com.atguigu.common.utils.Query中的.getpage(param)方法生成
    • 第二个参数就是查询条件
  • 生成的page,传入com.atguigu.common.utils.PageUils中,封装成PageUils
    最后在controller中把返回的PageUtils封装成R返回给前端

9 bug收集

下面是其他网友出现的一些bug问题,这里简单收集了一下,希望有用!

84 pubsub、publish报错
解决如下:
1 npm install --save pubsub-js
2 在src下的main.js中引用:
import PubSub from 'pubsub-js'
Vue.prototype.PubSub = PubSub

85 数据库里少了value_type字段
解决如下:
在数据库的 pms_attr 表加上value_type字段,类型为tinyint就行;
在代码中,AttyEntity.java、AttrVo.java中各添加:private Integer valueType,
在AttrDao.xml中添加:<result property="valueType" column="value_type"/>

85 规格参数显示不出来页面,原因是要在每个分组属性上至少关联一个属性。控制台foreach报错null
解决如下:
在spuadd.vue的showBaseAttrs()方法中在 //先对表单的baseAttrs进行初始化加上非空判断 if (item.attrs != null)就可以了
          data.data.forEach(item => {
            let attrArray = [];
            if (item.attrs != null) {
              item.attrs.forEach(attr => {
              attrArray.push({
                attrId: attr.attrId,
                attrValues: "",
                showDesc: attr.showDesc
              });
            });
            }
            
            this.dataResp.baseAttrs.push(attrArray);
          });


92 feign超时异常导致读取失败
解决如下:
在gulimall-product的application.yml添加如下即可解决(时间设置长点就行了)
ribbon:
  ReadTimeout: 30000
  ConnectTimeout: 30000

100 点击规格找不到页面,以及规格回显问题解决
1 点击规格找不到页面,解决如下:
INSERT INTO sys_menu (menu_id, parent_id, name, url, perms, type, icon, order_num) VALUES (76, 37, '规格维护', 'product/attrupdate', '', 2, 'log', 0);

2 规格回显问题不出来
原因:
因为那个属性的值类型是多选而pms_product_attr_value这个表里面的属性值存的单个值。前端展示将这个值用;切割成数组来展示的。切完数组里面只有一个值就转成字符串。所以在多选下拉就赋不了值
解决如下:
将页面attrupdate.vue中showBaseAttrs这个方法里面的代码
if (v.length == 1) {
      v = v[0] +  ''
 }
换成下面这个
if (v.length == 1 && attr.valueType == 0) {
     v = v[0] + ''
}

10 分布式基础篇总结

  1. 分布式基附概念
    • 微服务、注册中心、配置中心、远程调用、 Feign、网关
  2. 基础开发
    • springboot2.0、 SpringCloud、 Mybatis-Plus、Vue组件化、阿里云对象存储
  3. 环境
    • Vmware/Vagrant、 Linux、 Docker、 MYSQL、 Redis、逆向工程&人人开源
  4. 开发规范
    • 数据校验JSR303、全局异常处理、全局统一返回、全局跨域处理
    • 枚举状态,业务状态码、VO与TO与PO划分,逻组删除
    • Lombok: @Data @Slf4j
gulimall_pms 商品 drop table if exists pms_attr; drop table if exists pms_attr_attrgroup_relation; drop table if exists pms_attr_group; drop table if exists pms_brand; drop table if exists pms_category; drop table if exists pms_category_brand_relation; drop table if exists pms_comment_replay; drop table if exists pms_product_attr_value; drop table if exists pms_sku_images; drop table if exists pms_sku_info; drop table if exists pms_sku_sale_attr_value; drop table if exists pms_spu_comment; drop table if exists pms_spu_images; drop table if exists pms_spu_info; drop table if exists pms_spu_info_desc; /*==============================================================*/ /* Table: pms_attr */ /*==============================================================*/ create table pms_attr ( attr_id bigint not null auto_increment comment '属性id', attr_name char(30) comment '属性名', search_type tinyint comment '是否需要检索[0-不需要,1-需要]', icon varchar(255) comment '属性图标', value_select char(255) comment '可选值列表[用逗号分隔]', attr_type tinyint comment '属性类型[0-销售属性,1-基本属性,2-既是销售属性又是基本属性]', enable bigint comment '启用状态[0 - 禁用,1 - 启用]', catelog_id bigint comment '所属分类', show_desc tinyint comment '快速展示【是否展示在介绍上;0-否 1-是】,在sku中仍然可以调整', primary key (attr_id) ); alter table pms_attr comment '商品属性'; /*==============================================================*/ /* Table: pms_attr_attrgroup_relation */ /*==============================================================*/ create table pms_attr_attrgroup_relation ( id bigint not null auto_increment comment 'id', attr_id bigint comment '属性id', attr_group_id bigint comment '属性分组id', attr_sort int comment '属性组内排序', primary key (id) ); alter table pms_attr_attrgroup_relation comment '属性&
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值