一、倉儲服務
1、整合ware服務
(1)將gulimall-ware(倉儲服務)加到注冊中心nacos中
(a)修改application.yml

(b)開啟服務注冊發現功能
順便開啟事務注解
(c)啟動gulimall-ware,觀察nacos-server
至此,服務注冊成功
注意:啟動報錯是配置中心的錯誤,暫時全部不用管,后期統一處理
(2)配置網關路由
修改gulimall-gateway的application.yml
- id: ware_route
uri: lb://gulimall-ware
predicates:
- Path=/api/ware/**
filters:
- RewritePath=/api/(?<segment>/?.*),/$\{segment}

修改完畢后,重啟網關服務,查看
2、獲取倉庫列表
(1)修改gulimall-ware的application.yml,設置日志打印級別

(2)修改com.atguigu.gulimall.ware.service.impl.WareInfoServiceImpl 的 queryPage 方法
@Override
public PageUtils queryPage(Map<String, Object> params) {
QueryWrapper<WareInfoEntity> wrapper = new QueryWrapper<>();
String key = (String) params.get("key");
if(!StringUtils.isEmpty(key)){
wrapper.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),
wrapper
);
return new PageUtils(page);
}
效果:

3、查詢庫存
(1)修改com.atguigu.gulimall.ware.service.impl.WareSkuServiceImpl的 queryPage 方法
@Override
public PageUtils queryPage(Map<String, Object> params) {
QueryWrapper<WareSkuEntity> wrapper = new QueryWrapper<>();
String skuId = (String) params.get("skuId");
if(!StringUtils.isEmpty(skuId)){
wrapper.eq("sku_id",skuId);
}
String wareId = (String) params.get("wareId");
if(!StringUtils.isEmpty(wareId)){
wrapper.eq("ware_id",wareId);
}
IPage<WareSkuEntity> page = this.page(
new Query<WareSkuEntity>().getPage(params),
wrapper
);
return new PageUtils(page);
}
4、查詢采購需求
(1)修改com.atguigu.gulimall.ware.service.impl.PurchaseDetailServiceImpl的 queryPage 方法
@Override
public PageUtils queryPage(Map<String, Object> params) {
QueryWrapper<PurchaseDetailEntity> wrapper = new QueryWrapper<>();
String key = (String) params.get("key");
if(!StringUtils.isEmpty(key)){
wrapper.and(w->{
w.eq("purchase_id",key).or().eq("sku_id",key);
});
}
String status = (String) params.get("status");
if(!StringUtils.isEmpty(status)){
wrapper.eq("status",status);
}
String wareId = (String) params.get("wareId");
if(!StringUtils.isEmpty(wareId)){
wrapper.eq("ware_id",wareId);
}
IPage<PurchaseDetailEntity> page = this.page(
new Query<PurchaseDetailEntity>().getPage(params),
wrapper
);
return new PageUtils(page);
}

5、合並采購需求
(1)采購簡要流程

(2)查詢未領取的采購單
(a)com.atguigu.gulimall.ware.controller.PurchaseController 新加方法 unreceivelist
/**
* 查詢未領取的采購單
* @param params
* @return
*/
///ware/purchase/unreceive/list
@RequestMapping("/unreceive/list")
//@RequiresPermissions("ware:purchase:list")
public R unreceivelist(@RequestParam Map<String, Object> params){
PageUtils page = purchaseService.queryUnreceivePage(params);
return R.ok().put("page", page);
}
(b)新增接口和實現方法 queryUnreceivePage
/**
* 查詢未領取的采購單
* @param params
* @return
*/
@Override
public PageUtils queryUnreceivePage(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);
}
效果

(3)合並采購需求
(a)gulimall-common 新增文件 com.atguigu.common.constant.WareConstant
package com.atguigu.common.constant;
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,"已分配"),
BUYING(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;
}
}
}
(b)新建文件 com.atguigu.gulimall.ware.vo.MergeVo
package com.atguigu.gulimall.ware.vo;
import lombok.Data;
import java.util.List;
@Data
public class MergeVo {
private Long purchaseId; //整單id
private List<Long> items;//[1,2,3,4] //合並項集合
}
(c)com.atguigu.gulimall.ware.controller.PurchaseController 新加方法 merge
/**
* 合並采購需求
* @param mergeVo
* @return
*/
///ware/purchase/merge
@PostMapping("/merge")
public R merge(@RequestBody MergeVo mergeVo){
purchaseService.mergePurchase(mergeVo);
return R.ok();
}
(d)新增接口和實現方法 mergePurchase
/**
* 合並采購需求
* @param mergeVo
* @return
*/
@Override
@Transactional
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();
}
//TODO 確認采購單狀態是0或者1才可以合並
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());
purchaseEntity.setCreateTime(new Date());
this.updateById(purchaseEntity);
}
(e)修改application.yml

6、領取采購單
(1)com.atguigu.gulimall.ware.controller.PurchaseController 新加方法 received
/**
* 領取采購單
* @param ids
* @return
*/
///ware/purchase/received
@PostMapping("/received")
public R received(@RequestBody List<Long> ids){
purchaseService.received(ids);
return R.ok();
}
(2)新增接口和實現方法 received
/**
* 領取采購單
* @param ids:采購單id
*/
@Override
@Transactional
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.PurchaseDetailStatusEnum.CREATED.getCode() ||
item.getStatus() == WareConstant.PurchaseDetailStatusEnum.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.BUYING.getCode());
return entity1;
}).collect(Collectors.toList());
detailService.updateBatchById(detailEntities);
});
}
(3)com.atguigu.gulimall.ware.service.PurchaseDetailService 新增方法 listDetailByPurchaseId
/**
* 根據采購單查詢采購項
* @param id
* @return
*/
@Override
public List<PurchaseDetailEntity> listDetailByPurchaseId(Long id) {
List<PurchaseDetailEntity> purchaseId = this.list(new QueryWrapper<PurchaseDetailEntity>().eq("purchase_id", id));
return purchaseId;
}
(4)測試

7、完成采購
(1)處理分頁問題
新建文件 com.atguigu.gulimall.ware.config.MyBatisConfig
package com.atguigu.gulimall.ware.config;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
@MapperScan("com.atguigu.gulimall.ware.dao")
public class MyBatisConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 設置請求的頁面大於最大頁后操作, true調回到首頁,false 繼續請求 默認false
paginationInterceptor.setOverflow(true);
// 設置最大單頁限制數量,默認 500 條,-1 不受限制
paginationInterceptor.setLimit(1000);
// 開啟 count 的 join 優化,只針對部分 left join
paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}
}
(2)新建遠程調用接口 com.atguigu.gulimall.ware.feign.ProductFeignService
package com.atguigu.gulimall.ware.feign;
import com.atguigu.common.utils.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@FeignClient("gulimall-product")
public interface ProductFeignService {
/**
* /product/skuinfo/info/{skuId}
*
*
* 1)、讓所有請求過網關;
* 1、@FeignClient("gulimall-gateway"):給gulimall-gateway所在的機器發請求
* 2、/api/product/skuinfo/info/{skuId}
* 2)、直接讓后台指定服務處理
* 1、@FeignClient("gulimall-gateway")
* 2、/product/skuinfo/info/{skuId}
*
* @return
*/
@RequestMapping("/product/skuinfo/info/{skuId}")
public R info(@PathVariable("skuId") Long skuId);
}
(3)開啟遠程調用服務功能

(4)新增文件 com.atguigu.gulimall.ware.vo.PurchaseDoneVo
package com.atguigu.gulimall.ware.vo;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.util.List;
@Data
public class PurchaseDoneVo {
@NotNull
private Long id;//采購單id
private List<PurchaseItemDoneVo> items;
}
(5)新增文件 com.atguigu.gulimall.ware.vo.PurchaseItemDoneVo
package com.atguigu.gulimall.ware.vo;
import lombok.Data;
@Data
public class PurchaseItemDoneVo {
//{itemId:1,status:4,reason:""}
private Long itemId;
private Integer status;
private String reason;
}
(6)com.atguigu.gulimall.ware.controller.PurchaseController 新加方法 done /** * 完成采購 * @param doneVo * @return */ ///ware/purchase/done @PostMapping("/done") public R done(@RequestBody PurchaseDoneVo doneVo){ purchaseService.done(doneVo); return R.ok(); }
(7)com.atguigu.gulimall.ware.service.impl.PurchaseServiceImpl 新增接口和實現類
/**
* 完成采購
* @param doneVo
*/
@Override
@Transactional
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());
purchaseEntity.setUpdateTime(new Date());
this.updateById(purchaseEntity);
}
(8)com.atguigu.gulimall.ware.service.impl.WareSkuServiceImpl 新增接口和實現方法
/**
* 入庫
* @param skuId
* @param wareId
* @param skuNum
*/
@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異常
//TODO 還可以用什么辦法讓異常出現以后不回滾?高級
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){
}
wareSkuDao.insert(skuEntity);
}else{
wareSkuDao.addStock(skuId,wareId,skuNum);
}
}
(9)com.atguigu.gulimall.ware.dao.WareSkuDao 新增接口 addStock
void addStock(@Param("skuId") Long skuId, @Param("wareId") Long wareId, @Param("skuNum") Integer skuNum);
(10)WareSkuDao.xml 新增xml方法
<update id="addStock">
UPDATE wms_ware_sku SET stock=stock+#{skuNum} WHERE sku_id=#{skuId} AND ware_id=#{wareId}
</update>
二、商品管理
1、SPU規格維護
(1)解決spu管理規格點擊404

點規格,404,前端改一下:
/src/router/index.js 在mainRoutes->children【】里面加上:
{ path: '/product-attrupdate', component: _import('modules/product/attrupdate'), name: 'attr-update', meta: { title: '規格維護', isTab: true } }
修改后:
(2)獲取spu規格
(a)com.atguigu.gulimall.product.controller.AttrController 新增方法 baseAttrlistforspu
/**
* 獲取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);
}
(b)新增接口和實現類方法 baseAttrlistforspu
/**
* 獲取spu規格
* @param spuId
* @return
*/
@Override
public List<ProductAttrValueEntity> baseAttrlistforspu(Long spuId) {
List<ProductAttrValueEntity> spu_id = this.baseMapper.selectList(new QueryWrapper<ProductAttrValueEntity>().eq("spu_id", spuId));
return spu_id;
}
效果:

回顯成功
(3)修改商品規格
(a)com.atguigu.gulimall.product.controller.AttrController 新增方法 updateSpuAttr
/**
* 修改商品規格
* @param spuId
* @param entities
* @return
*/
///product/attr/update/{spuId}
@RequestMapping("/update/{spuId}")
public R updateSpuAttr(@PathVariable("spuId") Long spuId, @RequestBody List<ProductAttrValueEntity> entities){
productAttrValueService.updateSpuAttr(spuId, entities);
return R.ok();
}
(b)新增接口和實現類方法
@Transactional
@Override
public void updateSpuAttr(Long spuId, List<ProductAttrValueEntity> entities) {
//1、刪除這個spuId之前對應的所有屬性
this.baseMapper.delete(new QueryWrapper<ProductAttrValueEntity>().eq("spu_id",spuId));
List<ProductAttrValueEntity> collect = entities.stream().map(item -> {
item.setSpuId(spuId);
return item;
}).collect(Collectors.toList());
this.saveBatch(collect);
}