merge master
This commit is contained in:
commit
0c3a1928ff
171
README.md
171
README.md
@ -1,5 +1,9 @@
|
||||
## Lilishop B2B2C商城系统
|
||||
|
||||
##### 开源不易,如有帮助请点Star
|
||||
[](https://gitee.com/beijing_hongye_huicheng/lilishop/stargazers)
|
||||
|
||||
|
||||
### 介绍
|
||||
**官网**:https://pickmall.cn
|
||||
|
||||
@ -60,21 +64,24 @@ Lilishop 是一款Java开发,基于SpringBoot的B2B2C多用户商城,前端
|
||||
`git clone https://gitee.com/beijing_hongye_huicheng/docker.git `
|
||||
##### 部署基础环境
|
||||
`docker-compose up -d`
|
||||
|
||||
##### 部署应用
|
||||
`docker-compose -f docker-compose-application.yml up -d`
|
||||
|
||||
|
||||
|
||||
PS:单独部署的话,数据库文件访问这里:https://gitee.com/beijing_hongye_huicheng/docker/tree/master/init/mysql
|
||||
|
||||
##### 各个地址
|
||||
|
||||
| API | 地址 |
|
||||
| -------------- | --------------- |
|
||||
| 买家api | http://127.0.0.1:8888 |
|
||||
| 商家api | http://127.0.0.1:8889 |
|
||||
| 管理端api | http://127.0.0.1:8887 |
|
||||
| 通用api | http://127.0.0.1:8890 |
|
||||
| 买家API | http://127.0.0.1:8888 |
|
||||
| 商家API | http://127.0.0.1:8889 |
|
||||
| 管理端API | http://127.0.0.1:8887 |
|
||||
| 通用API | http://127.0.0.1:8890 |
|
||||
|
||||
| 演示 | 地址 |
|
||||
| 前端演示 | 地址 |
|
||||
| -------------- | --------------- |
|
||||
| PC | http://127.0.0.1:10000 |
|
||||
| WAP | http://127.0.0.1:10001 |
|
||||
@ -83,6 +90,44 @@ Lilishop 是一款Java开发,基于SpringBoot的B2B2C多用户商城,前端
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 功能列表
|
||||
|
||||
|
||||
|
||||
#### 平台功能
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
#### 商家端功能
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 功能展示
|
||||
|
||||
|
||||
|
||||
#### 移动端
|
||||
|
||||
<img src="https://pickmall.cn/assets/imgs/other/app.gif" alt="移动端功能展示" style="width:300px;" />
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### 管理端
|
||||
|
||||
<img src="https://pickmall.cn/assets/imgs/other/manager.gif" alt="管理端功能展示" />
|
||||
|
||||
|
||||
|
||||
### 技术选型
|
||||
|
||||
##### Java后台
|
||||
@ -136,125 +181,35 @@ Lilishop 是一款Java开发,基于SpringBoot的B2B2C多用户商城,前端
|
||||
| CSS预处理 | scss |
|
||||
| 地图引擎 | amap |
|
||||
|
||||
|
||||
|
||||
### 功能列表
|
||||
|
||||
<table>
|
||||
<tr><td colspan="2">运营后台功能</td></tr>
|
||||
<tr><td>首页</td><td>平台统计、待办事项、流量统计</td></tr>
|
||||
<tr><td rowspan="5">会员</td><td>会员列表</td></tr>
|
||||
<tr><td>评价列表</td></tr>
|
||||
<tr><td>积分历史</td></tr>
|
||||
<tr><td>会员资金</td></tr>
|
||||
<tr><td>充值记录</td></tr>
|
||||
<tr><td rowspan="6">订单</td><td>商品订单</td></tr>
|
||||
<tr><td>订单售后</td></tr>
|
||||
<tr><td>交易投诉</td></tr>
|
||||
<tr><td>售后原因</td></tr>
|
||||
<tr><td>收款流水</td></tr>
|
||||
<tr><td>退款流水</td></tr>
|
||||
<tr><td rowspan="6">商品</td><td>商品列表</td></tr>
|
||||
<tr><td>商品审核</td></tr>
|
||||
<tr><td>商品分类</td></tr>
|
||||
<tr><td>商品品牌</td></tr>
|
||||
<tr><td>商品规格</td></tr>
|
||||
<tr><td>计量单位</td></tr>
|
||||
<tr><td rowspan="5">促销</td><td>优惠券</td></tr>
|
||||
<tr><td>秒杀活动</td></tr>
|
||||
<tr><td>拼团活动</td></tr>
|
||||
<tr><td>积分商品</td></tr>
|
||||
<tr><td>积分分类</td></tr>
|
||||
<tr><td rowspan="5">店铺</td><td>店铺管理</td></tr>
|
||||
<tr><td>店铺结算</td></tr>
|
||||
<tr><td>店铺结算</td></tr>
|
||||
<tr><td>店铺结算</td></tr>
|
||||
<tr><td>店铺对账</td></tr>
|
||||
<tr><td rowspan="9">运营</td><td>店铺对账</td></tr>
|
||||
<tr><td>PC端楼层装修</td></tr>
|
||||
<tr><td>移动端楼层装修</td></tr>
|
||||
<tr><td>分销管理</td></tr>
|
||||
<tr><td>文章管理</td></tr>
|
||||
<tr><td>意见反馈</td></tr>
|
||||
<tr><td>站内信</td></tr>
|
||||
<tr><td>短信管理</td></tr>
|
||||
<tr><td>APP版本管理</td></tr>
|
||||
<tr><td rowspan="4">统计</td><td>会员统计</td></tr>
|
||||
<tr><td>订单统计</td></tr>
|
||||
<tr><td>商品统计</td></tr>
|
||||
<tr><td>流量统计</td></tr>
|
||||
<tr><td rowspan="11">设置</td><td>用户管理</td></tr>
|
||||
<tr><td>菜单管理</td></tr>
|
||||
<tr><td>部门管理</td></tr>
|
||||
<tr><td>系统设置</td></tr>
|
||||
<tr><td>OSS资源</td></tr>
|
||||
<tr><td>行政地区</td></tr>
|
||||
<tr><td>物流公司</td></tr>
|
||||
<tr><td>信任登录</td></tr>
|
||||
<tr><td>支付设置</td></tr>
|
||||
<tr><td>验证码管理</td></tr>
|
||||
<tr><td>敏感词管理</td></tr>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<tr><td colspan="2">店铺后台功能列表</td></tr>
|
||||
<tr><td rowspan="3">首页</td><td>店铺信息</td></tr>
|
||||
<tr><td>待办事项</td></tr>
|
||||
<tr><td>平台公告</td></tr>
|
||||
<tr><td rowspan="3">商品</td><td>商品发布</td></tr>
|
||||
<tr><td>商品列表</td></tr>
|
||||
<tr><td>店铺商品分类</td></tr>
|
||||
<tr><td rowspan="5">订单</td><td>商品订单</td></tr>
|
||||
<tr><td>退货管理</td></tr>
|
||||
<tr><td>退款管理</td></tr>
|
||||
<tr><td>投诉管理</td></tr>
|
||||
<tr><td>评价管理</td></tr>
|
||||
<tr><td rowspan="3">财务</td><td>财务对账</td></tr>
|
||||
<tr><td>店铺结算</td></tr>
|
||||
<tr><td>发票管理</td></tr>
|
||||
<tr><td rowspan="5">促销</td><td>拼团管理</td></tr>
|
||||
<tr><td>秒杀活动</td></tr>
|
||||
<tr><td>满额活动</td></tr>
|
||||
<tr><td>优惠券</td></tr>
|
||||
<tr><td>分销商品</td></tr>
|
||||
<tr><td rowspan="2">统计</td><td>商品统计</td></tr>
|
||||
<tr><td>订单统计</td></tr>
|
||||
<tr><td rowspan="5">设置</td><td>配送模板</td></tr>
|
||||
<tr><td>物流公司</td></tr>
|
||||
<tr><td>店铺设置</td></tr>
|
||||
<tr><td>自提点管理</td></tr>
|
||||
<tr><td>系统消息</td></tr>
|
||||
</table>
|
||||
|
||||
### 技术亮点
|
||||
|
||||
|
||||
1.后端框架基于Springboot,构建基于maven,持久层使用MyBatisPlus。使用elasticsearch、redis、mongodb、rocketmq 等各种中间健。都是主流架构,轻松应对各种环境。
|
||||
|
||||
|
||||
2.支持集群、分布式,支持docker 轻松部署,解决各种复杂场景!
|
||||
|
||||
|
||||
3.代码模块清晰,主要分为三端api(买家、卖家、管理),各端API互相隔离,自己鉴权,自己操作业务。
|
||||
|
||||
|
||||
4.使用阿里开源的RocketMQ,基于mq解决各种并发场景,解决事务一致性,解决搞并发延迟场景问题。
|
||||
|
||||
|
||||
5.项目使用多级缓存,应用不同场景,redis缓存业务数据、mongodb缓存关系型多对多关系问题、nginx缓存高频访问低频修改的页面。
|
||||
|
||||
|
||||
6.支持各种联合登陆,支持各种客户端的支付问题,灵活配置灵活开启。
|
||||
|
||||
|
||||
7.内置完善的楼层装修机制,各种拖拉拽,维护跳转页面或外网,即便是一个什么都不懂的运营也可以轻松掌握。
|
||||
|
||||
|
||||
8.内置阿里短信接口,可以在线申请短信模版。内置阿里oss系统,可以对文件执行各种操作。oss商家端资源相互隔离。
|
||||
|
||||
|
||||
10.强大的统计报表,统计效果,可以实现各个场景,包含在线人数,历史在线人数,活跃人数等信息。
|
||||
|
||||
|
||||
11.标准Api接口、提供swagger文档,快速二开。
|
||||
|
||||
|
||||
12.分布式调度任务中心,解决分布式定时任务多次执行问题。
|
||||
|
||||
|
||||
13.代码注释完善,快速上手。
|
||||
|
||||
|
||||
14.非移动端采用IView框架,各种自定义插件、选择器实现。移动端采用uniapp,一次编写,全端使用
|
||||
|
||||
|
||||
15.已经对接好各种第三方插件,支持各种复杂等联合登陆,联合支付等场景。
|
||||
|
||||
|
||||
|
@ -11,7 +11,6 @@ import cn.lili.modules.promotion.service.*;
|
||||
import cn.lili.timetask.handler.EveryDayExecute;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
@ -59,11 +58,14 @@ public class PromotionEverydayExecute implements EveryDayExecute {
|
||||
public void execute() {
|
||||
|
||||
Query query = new Query();
|
||||
query.addCriteria(Criteria.where("promotionStatus").ne(PromotionStatusEnum.END.name()).orOperator(Criteria.where("promotionStatus").ne(PromotionStatusEnum.CLOSE.name())));
|
||||
// 结束条件 活动关闭/活动结束
|
||||
query.addCriteria(Criteria.where("promotionStatus").ne(PromotionStatusEnum.END.name())
|
||||
.orOperator(Criteria.where("promotionStatus").ne(PromotionStatusEnum.CLOSE.name())));
|
||||
query.addCriteria(Criteria.where("endTime").lt(new Date()));
|
||||
|
||||
List<String> promotionIds = new ArrayList<>();
|
||||
|
||||
//关闭满减活动
|
||||
List<FullDiscountVO> fullDiscountVOS = mongoTemplate.find(query, FullDiscountVO.class);
|
||||
if (!fullDiscountVOS.isEmpty()) {
|
||||
List<String> ids = new ArrayList<>();
|
||||
@ -80,9 +82,10 @@ public class PromotionEverydayExecute implements EveryDayExecute {
|
||||
fullDiscountService.update(this.getUpdatePromotionWrapper(ids));
|
||||
promotionIds.addAll(ids);
|
||||
}
|
||||
|
||||
//关闭拼团活动
|
||||
List<PintuanVO> pintuanVOS = mongoTemplate.find(query, PintuanVO.class);
|
||||
if (!pintuanVOS.isEmpty()) {
|
||||
//准备修改活动的id
|
||||
List<String> ids = new ArrayList<>();
|
||||
for (PintuanVO vo : pintuanVOS) {
|
||||
vo.setPromotionStatus(PromotionStatusEnum.END.name());
|
||||
@ -98,6 +101,7 @@ public class PromotionEverydayExecute implements EveryDayExecute {
|
||||
promotionIds.addAll(ids);
|
||||
}
|
||||
|
||||
//关闭优惠券活动
|
||||
List<CouponVO> couponVOS = mongoTemplate.find(query, CouponVO.class);
|
||||
if (!couponVOS.isEmpty()) {
|
||||
List<String> ids = new ArrayList<>();
|
||||
@ -121,13 +125,22 @@ public class PromotionEverydayExecute implements EveryDayExecute {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取促销修改查询条件 修改活动状态
|
||||
* @param ids
|
||||
* @return
|
||||
*/
|
||||
private UpdateWrapper getUpdatePromotionWrapper(List<String> ids) {
|
||||
UpdateWrapper updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.in("id", ids);
|
||||
updateWrapper.set("promotion_status", PromotionStatusEnum.END.name());
|
||||
return updateWrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品的促销修改查询条件 修改商品状态
|
||||
* @param ids
|
||||
* @return
|
||||
*/
|
||||
private UpdateWrapper getUpdatePromotionGoodsWrapper(List<String> ids) {
|
||||
UpdateWrapper updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.in("promotion_id", ids);
|
||||
|
@ -12,7 +12,6 @@ import cn.lili.config.rocketmq.RocketmqCustomProperties;
|
||||
import cn.lili.modules.order.order.service.OrderService;
|
||||
import cn.lili.modules.promotion.entity.enums.PromotionStatusEnum;
|
||||
import cn.lili.modules.promotion.service.PromotionService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
@ -65,6 +64,7 @@ public class PromotionTimeTriggerExecutor implements TimeTriggerExecutor {
|
||||
}
|
||||
return;
|
||||
}
|
||||
//拼团订单消息
|
||||
PintuanOrderMessage pintuanOrderMessage = JSONUtil.toBean(JSONUtil.parseObj(object), PintuanOrderMessage.class);
|
||||
if (pintuanOrderMessage != null && pintuanOrderMessage.getPintuanId() != null) {
|
||||
log.info("拼团订单信息消费:{}", pintuanOrderMessage);
|
||||
|
@ -55,7 +55,6 @@ public class SmsUtilAliImplService implements SmsUtil, AliSmsUtil {
|
||||
public void sendSmsCode(String mobile, VerificationEnums verificationEnums, String uuid) {
|
||||
|
||||
String code = CommonUtil.getRandomNum();
|
||||
code = "111111";
|
||||
|
||||
switch (verificationEnums) {
|
||||
//如果某个模版需要自定义,则在此处进行调整
|
||||
@ -67,7 +66,7 @@ public class SmsUtilAliImplService implements SmsUtil, AliSmsUtil {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("code", code);
|
||||
cache.put(cacheKey(verificationEnums, mobile, uuid), code, 300L);
|
||||
//this.sendSmsCode("北京宏业汇成科技有限公司",mobile, params, verificationEnums.getSmsTemplate());
|
||||
this.sendSmsCode("北京宏业汇成科技有限公司",mobile, params, "SMS_205755300");
|
||||
break;
|
||||
}
|
||||
case UPDATE_PASSWORD: {
|
||||
@ -80,7 +79,7 @@ public class SmsUtilAliImplService implements SmsUtil, AliSmsUtil {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("code", code);
|
||||
cache.put(cacheKey(verificationEnums, memberMobile, uuid), code, 300L);
|
||||
//this.sendSmsCode("北京宏业汇成科技有限公司",mobile, params, verificationEnums.getSmsTemplate());
|
||||
this.sendSmsCode("北京宏业汇成科技有限公司",mobile, params, "SMS_205755297");
|
||||
break;
|
||||
}
|
||||
//如果不是有效的验证码手段,则此处不进行短信操作
|
||||
@ -162,19 +161,22 @@ public class SmsUtilAliImplService implements SmsUtil, AliSmsUtil {
|
||||
//设置参数添加短信签名
|
||||
com.aliyun.dysmsapi20170525.Client client = this.createClient();
|
||||
|
||||
System.out.println(smsSign.getBusinessLicense().substring(smsSign.getBusinessLicense().lastIndexOf(".") + 1));
|
||||
//营业执照
|
||||
AddSmsSignRequest.AddSmsSignRequestSignFileList signFileList0 = new AddSmsSignRequest.AddSmsSignRequestSignFileList()
|
||||
.setFileContents(Base64Utils.encode(smsSign.getBusinessLicense()))
|
||||
.setFileSuffix(smsSign.getBusinessLicense().substring(smsSign.getBusinessLicense().lastIndexOf(".") + 1));
|
||||
AddSmsSignRequest.AddSmsSignRequestSignFileList signFileList1 = new AddSmsSignRequest.AddSmsSignRequestSignFileList()
|
||||
.setFileContents(Base64Utils.encode(smsSign.getLicense()))
|
||||
.setFileSuffix(smsSign.getLicense().substring(smsSign.getBusinessLicense().lastIndexOf(".") + 1));
|
||||
//授权委托书
|
||||
// AddSmsSignRequest.AddSmsSignRequestSignFileList signFileList1 = new AddSmsSignRequest.AddSmsSignRequestSignFileList()
|
||||
// .setFileContents(Base64Utils.encode(smsSign.getLicense()))
|
||||
// .setFileSuffix(smsSign.getLicense().substring(smsSign.getLicense().lastIndexOf(".") + 1));
|
||||
//添加短信签名
|
||||
AddSmsSignRequest addSmsSignRequest = new AddSmsSignRequest()
|
||||
.setSignName(smsSign.getSignName())
|
||||
.setSignSource(smsSign.getSignSource())
|
||||
.setRemark(smsSign.getRemark())
|
||||
.setSignFileList(java.util.Arrays.asList(
|
||||
signFileList0,
|
||||
signFileList1
|
||||
signFileList0
|
||||
));
|
||||
AddSmsSignResponse response = client.addSmsSign(addSmsSignRequest);
|
||||
if (!response.getBody().getCode().equals("OK")) {
|
||||
|
@ -6,13 +6,11 @@ import cn.lili.common.security.enums.UserEnums;
|
||||
import cn.lili.common.token.Token;
|
||||
import cn.lili.common.token.TokenUtil;
|
||||
import cn.lili.common.token.base.AbstractTokenGenerate;
|
||||
import cn.lili.common.enums.SwitchEnum;
|
||||
import cn.lili.modules.member.entity.dos.Member;
|
||||
import cn.lili.modules.member.service.MemberService;
|
||||
import cn.lili.modules.store.entity.dos.Store;
|
||||
import cn.lili.modules.store.service.StoreService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@ -37,10 +35,10 @@ public class StoreTokenGenerate extends AbstractTokenGenerate {
|
||||
public Token createToken(String username, Boolean longTerm) {
|
||||
// 生成token
|
||||
Member member = memberService.findByUsername(username);
|
||||
if (member.getHaveStore().equals(SwitchEnum.CLOSE.name())) {
|
||||
if (!member.getHaveStore()) {
|
||||
throw new ServiceException("该会员未开通店铺");
|
||||
}
|
||||
AuthUser user = new AuthUser(member.getUsername(), member.getId(),member.getNickName(), UserEnums.STORE);
|
||||
AuthUser user = new AuthUser(member.getUsername(), member.getId(), member.getNickName(), UserEnums.STORE);
|
||||
LambdaQueryWrapper<Store> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(Store::getMemberId, member.getId());
|
||||
Store store = storeService.getOne(queryWrapper);
|
||||
|
@ -24,7 +24,6 @@ import cn.lili.modules.search.repository.EsGoodsIndexRepository;
|
||||
import cn.lili.modules.search.service.EsGoodsIndexService;
|
||||
import cn.lili.modules.search.service.EsGoodsSearchService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.assertj.core.util.IterableUtil;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
@ -44,6 +43,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 商品索引业务层实现
|
||||
*
|
||||
* @author paulG
|
||||
* @since 2020/10/14
|
||||
**/
|
||||
@ -64,19 +64,26 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements
|
||||
|
||||
@Override
|
||||
public void addIndex(EsGoodsIndex goods) {
|
||||
//索引名称拼接
|
||||
String indexName = elasticsearchProperties.getIndexPrefix() + "_" + EsSuffix.GOODS_INDEX_NAME;
|
||||
try {
|
||||
//分词器分词
|
||||
AnalyzeRequest analyzeRequest = AnalyzeRequest.withIndexAnalyzer(indexName, "ik_max_word", goods.getGoodsName());
|
||||
AnalyzeResponse analyze = client.indices().analyze(analyzeRequest, RequestOptions.DEFAULT);
|
||||
List<AnalyzeResponse.AnalyzeToken> tokens = analyze.getTokens();
|
||||
|
||||
if (goods.getAttrList() != null && !goods.getAttrList().isEmpty()) {
|
||||
//保存分词
|
||||
for (EsGoodsAttribute esGoodsAttribute : goods.getAttrList()) {
|
||||
wordsToDb(esGoodsAttribute.getValue());
|
||||
}
|
||||
}
|
||||
//分析词条
|
||||
for (AnalyzeResponse.AnalyzeToken token : tokens) {
|
||||
//保存词条进入数据库
|
||||
wordsToDb(token.getTerm());
|
||||
}
|
||||
//生成索引
|
||||
goodsIndexRepository.save(goods);
|
||||
} catch (IOException e) {
|
||||
log.error("为商品[" + goods.getGoodsName() + "]生成索引异常", e);
|
||||
@ -112,6 +119,7 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements
|
||||
@Override
|
||||
public void updateIndexCommentNum(String id, Integer commentNum, Integer highPraiseNum, Double grade) {
|
||||
EsGoodsIndex goodsIndex = this.findById(id);
|
||||
//写入新的商品数据
|
||||
goodsIndex.setCommentNum(commentNum);
|
||||
goodsIndex.setHighPraiseNum(highPraiseNum);
|
||||
goodsIndex.setGrade(grade);
|
||||
@ -139,8 +147,10 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements
|
||||
|
||||
@Override
|
||||
public void initIndex(List<EsGoodsIndex> goodsIndexList) {
|
||||
//索引名称拼接
|
||||
String indexName = elasticsearchProperties.getIndexPrefix() + "_" + EsSuffix.GOODS_INDEX_NAME;
|
||||
// deleteIndexRequest(indexName);
|
||||
//如果索引不存在,则创建索引
|
||||
if (!indexExist(indexName)) {
|
||||
createIndexRequest(indexName);
|
||||
}
|
||||
@ -156,11 +166,14 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements
|
||||
public void updateEsGoodsIndex(String id, BasePromotion promotion, String key, Double price) {
|
||||
EsGoodsIndex goodsIndex = findById(id);
|
||||
if (goodsIndex != null) {
|
||||
//如果有促销活动开始,则将促销金额写入
|
||||
if (promotion.getPromotionStatus().equals(PromotionStatusEnum.START.name()) && price != null) {
|
||||
goodsIndex.setPromotionPrice(price);
|
||||
} else {
|
||||
//否则促销金额为商品原价
|
||||
goodsIndex.setPromotionPrice(goodsIndex.getPrice());
|
||||
}
|
||||
//更新索引
|
||||
this.updateGoodsIndexPromotion(goodsIndex, key, promotion);
|
||||
} else {
|
||||
log.error("更新索引商品促销信息失败!skuId 为 【{}】的索引不存在!", id);
|
||||
@ -170,6 +183,7 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements
|
||||
@Override
|
||||
public void updateEsGoodsIndexByList(List<PromotionGoods> promotionGoodsList, BasePromotion promotion, String key) {
|
||||
if (promotionGoodsList != null) {
|
||||
//循环更新 促销商品索引
|
||||
for (PromotionGoods promotionGoods : promotionGoodsList) {
|
||||
updateEsGoodsIndex(promotionGoods.getSkuId(), promotion, key, promotionGoods.getPrice());
|
||||
}
|
||||
@ -186,15 +200,20 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements
|
||||
@Override
|
||||
public void updateEsGoodsIndexAllByList(BasePromotion promotion, String key) {
|
||||
List<EsGoodsIndex> goodsIndices;
|
||||
//如果storeid不为空,则表示是店铺活动
|
||||
if (promotion.getStoreId() != null) {
|
||||
EsGoodsSearchDTO searchDTO = new EsGoodsSearchDTO();
|
||||
searchDTO.setStoreId(promotion.getStoreId());
|
||||
//查询出店铺商品
|
||||
Page<EsGoodsIndex> esGoodsIndices = goodsSearchService.searchGoods(searchDTO, null);
|
||||
goodsIndices = esGoodsIndices.getContent();
|
||||
} else {
|
||||
//否则是平台活动
|
||||
Iterable<EsGoodsIndex> all = goodsIndexRepository.findAll();
|
||||
// 查询出全部商品
|
||||
goodsIndices = new ArrayList<>(IterableUtil.toCollection(all));
|
||||
}
|
||||
//更新商品索引
|
||||
for (EsGoodsIndex goodsIndex : goodsIndices) {
|
||||
this.updateGoodsIndexPromotion(goodsIndex, key, promotion);
|
||||
}
|
||||
@ -202,8 +221,10 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements
|
||||
|
||||
@Override
|
||||
public void deleteEsGoodsPromotionIndexByList(List<String> skuIds, PromotionTypeEnum promotionType) {
|
||||
//批量删除活动索引
|
||||
for (String skuId : skuIds) {
|
||||
EsGoodsIndex goodsIndex = findById(skuId);
|
||||
//商品索引不为空
|
||||
if (goodsIndex != null) {
|
||||
Map<String, Object> promotionMap = goodsIndex.getPromotionMap();
|
||||
if (promotionMap != null && !promotionMap.isEmpty()) {
|
||||
@ -220,16 +241,19 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所以商品索引的无效促销活动
|
||||
* 清除所有商品索引的无效促销活动
|
||||
*/
|
||||
@Override
|
||||
public void cleanInvalidPromotion() {
|
||||
Iterable<EsGoodsIndex> all = goodsIndexRepository.findAll();
|
||||
for (EsGoodsIndex goodsIndex : all) {
|
||||
Map<String, Object> promotionMap = goodsIndex.getPromotionMap();
|
||||
//获取商品索引
|
||||
if (promotionMap != null && !promotionMap.isEmpty()) {
|
||||
//促销不为空则进行清洗
|
||||
for (Map.Entry<String, Object> entry : promotionMap.entrySet()) {
|
||||
BasePromotion promotion = (BasePromotion) entry.getValue();
|
||||
//判定条件为活动已结束
|
||||
if (promotion.getEndTime().getTime() > DateUtil.date().getTime()) {
|
||||
promotionMap.remove(entry.getKey());
|
||||
}
|
||||
@ -258,6 +282,8 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements
|
||||
@Override
|
||||
public Map<String, Object> getPromotionMap(String id) {
|
||||
EsGoodsIndex goodsIndex = this.findById(id);
|
||||
|
||||
// 如果商品索引不为空,返回促销信息,否则返回空
|
||||
if (goodsIndex != null) {
|
||||
Map<String, Object> promotionMap = goodsIndex.getPromotionMap();
|
||||
if (promotionMap == null || promotionMap.isEmpty()) {
|
||||
@ -278,11 +304,14 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements
|
||||
@Override
|
||||
public List<String> getPromotionIdByPromotionType(String id, PromotionTypeEnum promotionTypeEnum) {
|
||||
Map<String, Object> promotionMap = this.getPromotionMap(id);
|
||||
//如果没有促销信息,则返回新的
|
||||
if (promotionMap == null || promotionMap.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
//对促销进行过滤
|
||||
List<String> keyCollect = promotionMap.keySet().stream().filter(i -> i.contains(promotionTypeEnum.name())).collect(Collectors.toList());
|
||||
List<String> promotionIds = new ArrayList<>();
|
||||
//写入促销id
|
||||
for (String key : keyCollect) {
|
||||
BasePromotion promotion = (BasePromotion) promotionMap.get(key);
|
||||
promotionIds.add(promotion.getId());
|
||||
@ -299,25 +328,37 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements
|
||||
@Override
|
||||
public EsGoodsIndex resetEsGoodsIndex(GoodsSku goodsSku) {
|
||||
EsGoodsIndex index = new EsGoodsIndex(goodsSku);
|
||||
//获取活动信息
|
||||
Map<String, Object> goodsCurrentPromotionMap = promotionService.getGoodsCurrentPromotionMap(index);
|
||||
//写入促销信息
|
||||
index.setPromotionMap(goodsCurrentPromotionMap);
|
||||
this.addIndex(index);
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改商品活动索引
|
||||
*
|
||||
* @param goodsIndex 商品索引
|
||||
* @param key 关键字
|
||||
* @param promotion 活动
|
||||
*/
|
||||
private void updateGoodsIndexPromotion(EsGoodsIndex goodsIndex, String key, BasePromotion promotion) {
|
||||
Map<String, Object> promotionMap;
|
||||
//数据非空处理,如果空给一个新的信息
|
||||
if (goodsIndex.getPromotionMap() == null || goodsIndex.getPromotionMap().isEmpty()) {
|
||||
promotionMap = new HashMap<>(1);
|
||||
} else {
|
||||
promotionMap = goodsIndex.getPromotionMap();
|
||||
}
|
||||
|
||||
|
||||
//如果活动已结束
|
||||
if (promotion.getPromotionStatus().equals(PromotionStatusEnum.END.name()) || promotion.getPromotionStatus().equals(PromotionStatusEnum.CLOSE.name())) {
|
||||
//如果存在活动
|
||||
if (promotionMap.containsKey(key)) {
|
||||
//删除活动
|
||||
promotionMap.remove(key);
|
||||
} else {
|
||||
//不存在则说明是秒杀活动,尝试删除秒杀信息
|
||||
this.removePromotionKey(key, promotionMap, PromotionTypeEnum.SECKILL.name());
|
||||
}
|
||||
} else {
|
||||
@ -337,9 +378,13 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements
|
||||
* @param needRemoveKeys 需移除的促销活动
|
||||
*/
|
||||
private void removePromotionKey(String currentKey, Map<String, Object> promotionMap, String... needRemoveKeys) {
|
||||
//判定是否需要移除
|
||||
if (CharSequenceUtil.containsAny(currentKey, needRemoveKeys)) {
|
||||
|
||||
List<String> removeKeys = new ArrayList<>();
|
||||
//促销循环
|
||||
for (String entry : promotionMap.keySet()) {
|
||||
//需要移除则进行移除处理
|
||||
for (String needRemoveKey : needRemoveKeys) {
|
||||
if (entry.contains(needRemoveKey) && currentKey.contains(needRemoveKey)) {
|
||||
removeKeys.add(entry);
|
||||
@ -347,6 +392,7 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements
|
||||
}
|
||||
}
|
||||
}
|
||||
//移除促销信息
|
||||
promotionMap.keySet().removeAll(removeKeys);
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ public class StoreEditDTO extends StoreDetail {
|
||||
private String storeDisable;
|
||||
|
||||
@ApiModelProperty(value = "是否自营", required = true)
|
||||
private Integer selfOperated;
|
||||
private Boolean selfOperated;
|
||||
|
||||
@ApiModelProperty(value = "经纬度")
|
||||
private String storeCenter;
|
||||
|
@ -3,7 +3,6 @@ package cn.lili.modules.store.serviceimpl;
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.lili.common.enums.ResultCode;
|
||||
import cn.lili.common.enums.SwitchEnum;
|
||||
import cn.lili.common.exception.ServiceException;
|
||||
import cn.lili.common.security.context.UserContext;
|
||||
import cn.lili.common.utils.BeanUtil;
|
||||
@ -98,24 +97,24 @@ public class StoreServiceImpl extends ServiceImpl<StoreMapper, Store> implements
|
||||
throw new ServiceException(ResultCode.USER_NOT_EXIST);
|
||||
}
|
||||
//判断是否拥有店铺
|
||||
if (SwitchEnum.OPEN.name().equals(member.getHaveStore())) {
|
||||
if (member.getHaveStore()) {
|
||||
throw new ServiceException(ResultCode.STORE_APPLY_DOUBLE_ERROR);
|
||||
}
|
||||
|
||||
//添加店铺
|
||||
Store store=new Store(member,adminStoreApplyDTO);
|
||||
Store store = new Store(member, adminStoreApplyDTO);
|
||||
this.save(store);
|
||||
|
||||
//判断是否存在店铺详情,如果没有则进行新建,如果存在则进行修改
|
||||
StoreDetail storeDetail = new StoreDetail(store,adminStoreApplyDTO);
|
||||
StoreDetail storeDetail = new StoreDetail(store, adminStoreApplyDTO);
|
||||
|
||||
storeDetailService.save(storeDetail);
|
||||
|
||||
//设置会员-店铺信息
|
||||
memberService.update(new LambdaUpdateWrapper<Member>()
|
||||
.eq(Member::getId,member.getId())
|
||||
.set(Member::getHaveStore,SwitchEnum.OPEN.name())
|
||||
.set(Member::getStoreId,store.getId()));
|
||||
.eq(Member::getId, member.getId())
|
||||
.set(Member::getHaveStore, true)
|
||||
.set(Member::getStoreId, store.getId()));
|
||||
return store;
|
||||
|
||||
}
|
||||
@ -173,6 +172,12 @@ public class StoreServiceImpl extends ServiceImpl<StoreMapper, Store> implements
|
||||
store.setStoreDisable(StoreStatusEnum.OPEN.value());
|
||||
//添加店铺页面
|
||||
pageDataService.addStorePageData(store.getId());
|
||||
//修改会员 表示已有店铺
|
||||
Member member = memberService.getById(store.getMemberId());
|
||||
member.setHaveStore(true);
|
||||
member.setStoreId(id);
|
||||
memberService.updateById(member);
|
||||
|
||||
} else {
|
||||
store.setStoreDisable(StoreStatusEnum.REFUSED.value());
|
||||
}
|
||||
@ -190,6 +195,7 @@ public class StoreServiceImpl extends ServiceImpl<StoreMapper, Store> implements
|
||||
goodsService.underStoreGoods(id);
|
||||
return this.updateById(store);
|
||||
}
|
||||
|
||||
throw new ServiceException(ResultCode.STORE_NOT_EXIST);
|
||||
}
|
||||
|
||||
@ -281,26 +287,26 @@ public class StoreServiceImpl extends ServiceImpl<StoreMapper, Store> implements
|
||||
@Override
|
||||
public void updateStoreGoodsNum(String storeId) {
|
||||
//获取店铺已上架已审核通过商品数量
|
||||
Integer goodsNum=goodsService.count(new LambdaQueryWrapper<Goods>()
|
||||
.eq(Goods::getStoreId,storeId)
|
||||
Integer goodsNum = goodsService.count(new LambdaQueryWrapper<Goods>()
|
||||
.eq(Goods::getStoreId, storeId)
|
||||
.eq(Goods::getIsAuth, GoodsAuthEnum.PASS.name())
|
||||
.eq(Goods::getMarketEnable, GoodsStatusEnum.UPPER.name()));
|
||||
//修改店铺商品数量
|
||||
this.update(new LambdaUpdateWrapper<Store>()
|
||||
.set(Store::getGoodsNum,goodsNum)
|
||||
.eq(Store::getId,storeId));
|
||||
.set(Store::getGoodsNum, goodsNum)
|
||||
.eq(Store::getId, storeId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStoreCollectionNum(String goodsId) {
|
||||
String storeId=goodsSkuService.getById(goodsId).getStoreId();
|
||||
String storeId = goodsSkuService.getById(goodsId).getStoreId();
|
||||
//获取店铺收藏数量
|
||||
Integer collectionNum=storeCollectionService.count(new LambdaQueryWrapper<StoreCollection>()
|
||||
.eq(StoreCollection::getStoreId,storeId));
|
||||
Integer collectionNum = storeCollectionService.count(new LambdaQueryWrapper<StoreCollection>()
|
||||
.eq(StoreCollection::getStoreId, storeId));
|
||||
//修改店铺收藏数量
|
||||
this.update(new LambdaUpdateWrapper<Store>()
|
||||
.set(Store::getCollectionNum,collectionNum)
|
||||
.eq(Store::getId,storeId));
|
||||
.set(Store::getCollectionNum, collectionNum)
|
||||
.eq(Store::getId, storeId));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,11 +46,14 @@ public class ElasticsearchController {
|
||||
|
||||
@GetMapping
|
||||
public void init() {
|
||||
//查询商品信息
|
||||
LambdaQueryWrapper<GoodsSku> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(GoodsSku::getIsAuth, GoodsAuthEnum.PASS.name());
|
||||
queryWrapper.eq(GoodsSku::getMarketEnable, GoodsStatusEnum.UPPER.name());
|
||||
|
||||
List<GoodsSku> list = goodsSkuService.list(queryWrapper);
|
||||
List<EsGoodsIndex> esGoodsIndices = new ArrayList<>();
|
||||
//库存锁是在redis做的,所以生成索引,同时更新一下redis中的库存数量
|
||||
for (GoodsSku goodsSku : list) {
|
||||
EsGoodsIndex index = new EsGoodsIndex(goodsSku);
|
||||
Map<String, Object> goodsCurrentPromotionMap = promotionService.getGoodsCurrentPromotionMap(index);
|
||||
@ -58,6 +61,7 @@ public class ElasticsearchController {
|
||||
esGoodsIndices.add(index);
|
||||
stringRedisTemplate.opsForValue().set(GoodsSkuService.getStockCacheKey(goodsSku.getId()), goodsSku.getQuantity().toString());
|
||||
}
|
||||
//初始化商品索引
|
||||
esGoodsIndexService.initIndex(esGoodsIndices);
|
||||
Assertions.assertTrue(true);
|
||||
}
|
||||
|
1
pom.xml
1
pom.xml
@ -23,7 +23,6 @@
|
||||
<module>buyer-api</module>
|
||||
<module>manager-api</module>
|
||||
<module>seller-api</module>
|
||||
<module>socket-api</module>
|
||||
<module>common-api</module>
|
||||
<module>consumer</module>
|
||||
</modules>
|
||||
|
@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>socket-api</artifactId>
|
||||
<parent>
|
||||
<groupId>cn.lili</groupId>
|
||||
<artifactId>lili-shop-parent</artifactId>
|
||||
<version>1.0.1</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.lili</groupId>
|
||||
<artifactId>framework</artifactId>
|
||||
<version>1.0.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -1,32 +0,0 @@
|
||||
package cn.lili;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
|
||||
/**
|
||||
* @author Chopper
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class SocketApiApplication extends WebMvcConfigurerAdapter {
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
System.setProperty("es.set.netty.runtime.available.processors", "false");
|
||||
SpringApplication.run(SocketApiApplication.class, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
|
||||
registry.addMapping("/**")
|
||||
.allowCredentials(true)
|
||||
.allowedHeaders("*") //允许任何头
|
||||
.allowedOrigins("*") //允许任何域名
|
||||
.allowedMethods("*"); //允许任何方法
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
package cn.lili.scocket.listener;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.lili.common.rocketmq.tags.OtherTagsEnum;
|
||||
import cn.lili.common.utils.BeanUtil;
|
||||
import cn.lili.modules.message.entity.dos.Message;
|
||||
import cn.lili.modules.message.entity.enums.MessageShowType;
|
||||
import cn.lili.modules.message.entity.vos.MessageShowVO;
|
||||
import cn.lili.modules.message.mapper.StoreMessageMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
|
||||
import org.apache.rocketmq.spring.core.RocketMQListener;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
|
||||
/**
|
||||
* @author paulG
|
||||
* @since 2020/12/9
|
||||
**/
|
||||
@Component
|
||||
@CrossOrigin
|
||||
@Slf4j
|
||||
@RocketMQMessageListener(topic = "${lili.data.rocketmq.other-topic}", consumerGroup = "${lili.data.rocketmq.other-group}")
|
||||
public class MessageSendListener implements RocketMQListener<MessageExt> {
|
||||
|
||||
|
||||
|
||||
@Autowired
|
||||
private SimpMessagingTemplate simpMessagingTemplate;
|
||||
|
||||
@Override
|
||||
public void onMessage(MessageExt messageExt) {
|
||||
log.info(messageExt.getTags());
|
||||
switch (OtherTagsEnum.valueOf(messageExt.getTags())) {
|
||||
//站内消息提醒
|
||||
case MESSAGE:
|
||||
System.out.println("消息提醒");
|
||||
sendNoticeMessage(messageExt);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 给商家发送站内信息
|
||||
*
|
||||
* @param messageExt
|
||||
*/
|
||||
private void sendNoticeMessage(MessageExt messageExt) {
|
||||
MessageShowVO messageVO = new MessageShowVO();
|
||||
Message message = JSONUtil.toBean(new String(messageExt.getBody()), Message.class);
|
||||
//构建vo
|
||||
BeanUtil.copyProperties(message, messageVO);
|
||||
messageVO.setType(MessageShowType.NOTICE.name());
|
||||
if (message.getMessageRange().equals("ALL")) {
|
||||
simpMessagingTemplate.convertAndSend("/topic/subscribe", messageVO);
|
||||
} else {
|
||||
for (String id : message.getUserIds()) {
|
||||
simpMessagingTemplate.convertAndSendToUser("SHOP_" + id, "/queue/subscribe", messageVO);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package cn.lili.scocket.listener;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
|
||||
|
||||
/**
|
||||
* spring Security 核心配置类 Store安全配置中心
|
||||
*
|
||||
* @author Chopper
|
||||
* @version v4.0
|
||||
* @Description:
|
||||
* @since 2020/11/14 16:20
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
|
||||
public class ScoketSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
|
||||
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http
|
||||
.authorizeRequests();
|
||||
registry.antMatchers("**").permitAll();
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user