7 仓库服务
7.1 数据表的说明
用到gulimall_wms数据库中的的两张表,第一张是wms_ware_info
,表示有几个仓库
第二张表是wms_ware_sku
,表每个仓库有几个sku商品
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、配置后测试仓库维护
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
效果展示
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、效果展示:
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、采购逻辑,新建采购需求后还要可以提供合并采购单,比如一个仓库的东西可以合并到一起,让采购人员一趟采购完
新建采购需求后还要可以提供合并采购单,比如一个仓库的东西可以合并到一起,让采购人员一趟采购完
新建采购单,可以在采购单后面分配给员工,员工可以在系统管理->管理员列表中新建
7.6 查询未领取的采购单
1、库存系统05、url:/ware/purchase/unreceive/list
, 查询未领取的采购单
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、效果展示
7.7 合并采购需求
1、库存系统04,url:/ware/purchase/merge
选择要合并的采购需求,然后合并到整单
如果不选择整单id,则自动创建新的采购单
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、效果展示
合并
新建
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
5、效果展示
采购需求变为 正在采购
采购单2号变成 已领取
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":"无货"}
]
}
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、效果展示:测试,点击规格
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);
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、效果展示:添加机身材质工艺
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 分布式基础篇总结
- 分布式基附概念
- 微服务、注册中心、配置中心、远程调用、 Feign、网关
- 基础开发
- springboot2.0、 SpringCloud、 Mybatis-Plus、Vue组件化、阿里云对象存储
- 环境
- Vmware/Vagrant、 Linux、 Docker、 MYSQL、 Redis、逆向工程&人人开源
- 开发规范
- 数据校验JSR303、全局异常处理、全局统一返回、全局跨域处理
- 枚举状态,业务状态码、VO与TO与PO划分,逻组删除
- Lombok: @Data @Slf4j