由于品优购项目内容很多,这里只简单的介绍知识内容和做项目过程中遇到的问题,以及解决方案。品优购中涉及的具体技术,我在其他地方有详细的整理。限于文章篇幅不能全部写出。
目录
一、品牌管理
1.1 概要
学习angularJs,双向数据绑定,MVC模式,依赖注入,模块化
1.2 代码注意事项
正确写法:ng-click(search(paginationConf.currentPage,paginationConf.itemsPerPage)),指令中不能出现$scope域对象
二、规格及模板管理
2.1 概要
学习MVC分层思想,将angularJs的代码分别按controller和service抽取。
了解angularJs继承。
代码生成器
2.2 代码注意事项
单词第一次一定要写对。(ng-app写成了np-app,浏览器也不报错)
string = string +xxx ; 可以写成 string += xxx;
json字符串转json格式:var json = JSON.parse(jsonString);
2.3 遇到的问题
2.3.1 Angular $injector:unpr Unknown provider 问题原因:依赖没有定义。解决方案: .html文件中引入service.js依赖,<script src="../js/service/brandService.js"></script>
2.3.2 query function not defined for Select2 undefined error,<input select2 select2-model="entity.brandIds" config="brandList" multiple placeholder="关联品牌(多选)" class="form-control"/>
解决方案: 给brandList在controller.js中初始化,$scope.brandList={data:[]}
2.3.3 ng-init="findBrandList();findSpecificationList()" 解决方案 :用分号
三、安全框架与商家入驻审核
3.1 概要
遇到问题先请缓存测试一下,在判断是前台问题还是后台问题。
Spring_security 入门
angular指令ng-if
BCrypt加密算法
3.2 代码注意事项
有的时候是单词拼写错误导致的bug,直接删掉重写就行了,比找快。
前端表单提交:定义form表单:<form id="loginform" action="/login" method="post">表单里添加a标签提交:<a οnclick="document:loginform.submit()">登录</a>
四、商品录入
4.1 概要
4.1.1电商概念SPU与SKU
SPU = Standard Product Unit(标准产品单位)。iphone7就是一个SPU,与商家,与颜色、款式、套餐都无关。
SKU=stock keeping unit(库存量单位)。纺织品中一个SKU通常表示:规格、颜色、款式。
4.1.2富文本编辑器介绍。常用的富文本编辑器:
KindEditor http://kindeditor.net/
UEditor http://ueditor.baidu.com/website/
CKEditor http://ckeditor.com/
4.1.3 分布式文件服务器FastDFS
FastDFS 架构包括 Tracker server 和 Storage server。客户端请求 Tracker server 进行文件上传、下载,通过 Tracker server 调度最终由 Storage server 完成文件上传和下载。
Tracker server作用是负载均衡和调度,通过Tracker server在文件上传时可以根据一些策略找到Storage server提供文件上传服务。可以将tracker称为追踪服务器或调度服务器。
Storage server 作用是文件存储,客户端上传的文件最终存储在 Storage 服务器上,Storageserver 没有实现自己的文件系统而是利用操作系统 的文件系统来管理文件。可以将storage称为存储服务器。
4.1.4: angular的watch指令,angular的深度监控
4.1.5:angular的ng-options指令 slect标签的值的显示
4.1.6: angular的ng-true-value=””,ng-false-value=””的使用
4.1.7: js的深度循环嵌套。
4.1.8: angular的ng-checked=”fun(...)”的使用
4.2 代码注意事项
4.2.1加载properties文件里的值(文件需要加载) @Value("${FILE_SERVER_URL}")
4.2.2 js改了代码最好清一下浏览器缓存。
4.2.3 js:
JSON.parse();//将字符串转换成js对象
Java :JSPON.parse(); //将将字符串转换成js对象
JSON.parseObject() //可以将字符串转换成多个对象Map,List<Map>等
JSON.parseArray()
4.2.4 js深度克隆:var newRow = JSON.parse(JSON.stringify(oldRow)),先将对象序列化,在转换成js对象即完成深克隆。newRow 与oldRow没有关系
4.2.5:深度克隆,js循环(三层循环就能完成业务需求)
实现思路:实现思路:
先对选中的checkbox进行数据封装 : var x=[{name:”屏幕尺寸”,value=”4.0,4.5”},...,{}]
每次点击规格的checkbox时,下面的步骤依次进行。
1我们先定义一个初始的不带规格名称的集合A,只有一条记录。
2先循环此集合A
3创建一个新的集合 var newList=[]
4在循环集合x[j],
5用一个变量保存A[i]的值 var oldValue=A[i]
6在循环x的value值,
7对原来的数据oldValue进行深度克隆给newValue,在对newValue添加新的规格属性spec:{”屏幕尺寸”:”4.0”,...}
8最后将newValue添加到新的集合中
3-8步可以抽取成一个方法。
4.2.6:简述商品录入与修改
五、广告管理与缓存解决方案
5.1 概要
SpringDataRedis入门
连接池自动管理,提供了一个高度封装的“RedisTemplate”类
针对jedis客户端中大量api进行了归类封装,将同一类型操作封装为operation接口
5.2 代码注意事项
三元运算符 <li class="{{$index==0?'active':''}}" ng-repeat=”...”></li>
六、搜索解决方案-Solr
6.1 概要
Solr一些概念:中文分词器(*),配置域(数据库的字段),复制域,动态域。
SpringDataSolr:为了方便Solr的开发所研制的一个框架,其底层是对SolrJ(官方API)的封装。
@Field : 实体与索引字段的绑定
高亮显示 HighlightQuery HighlightOptions
分组显示 GroupOptions
过滤查询 FilterQuery
排序 new Sort(Sort.Direction.ASC, "item_"+sortField);
6.2 代码注意事项
6.2.1:字符串去空格:keywords.replace(" ","")
6.2.2:indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置aaa.indexOf(bbb)>=0
6.2.3 Long[] --> List :Arrays.asList(goodsIds)
6.2.4:查找接口的实现类:IDEA风格ctrl+alt+B
七、网页静态化解决方案-Freemarker
7.1 概要
7.1.1 网页静态化技术和缓存技术的共同点都是为了减轻数据库的访问压力,但是具体的应用场景不同,缓存比较适合小规模的数据,而网页静态化比较适合大规模且相对变化不太频繁的数据。
7.1.2 模板文件中四种元素
1、文本,直接输出的部分
2、注释,即<#--...-->格式不会输出
3、插值(Interpolation):即${..}部分,将使用数据模型中的部分替代输出
4、FTL指令:FreeMarker指令,和HTML标记类似,名字前加#予以区分,不会输出。
asign 指令:<#asign ...> 定义一个变量
include指令:<#include "xxx.ftl">
<#if success=true><#else></#if>
<#list alist as a></#list>索引,使用循环变量+_index就可以得到。
- 内建函数
集合总共多少元素:${goodsList?size}
JSON转为对象格式:<#assign data=test?eval />
日期:${myDate?date}${myDate?time}${myDate?datetime}
日期格式化: ${today?string("yyyy年MM月")}
数字转字符串:${number?c}
判断变量是否存在 :<#if aaa??>
缺失时变量默认值”!”:${bbb!’此变量默认值’}
6 逻辑运算符 && || !
7 比较运算符: > < = >= <= != (=和!=可以用于字符串,数值和日期来比较是否相等,但=和!=两边必须是相同类型的值)
7.2 代码注意事项
7.2.1 js循环对象,得到的是key,for(var key in map)
7.3 遇到的问题
7.3.1 com.alibaba.dubbo.rpc.RpcException(找不到服务),问题原因:impl类的@Service注解没加。
7.3.2 freemarker里插值作为方法参数时 :"${item.title!''}",需要用””
7.3.3 angular添加对象属性:$scope.XXX[name]=value;
7.3.4 遇到复杂的逻辑先写出思路,在开始写代码
八、消息中间件解决方案JMS
8.1 概要
8.1.1 消息中间件利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型,它可以在分布式环境下扩展进程间的通信。
8.1.2 常见的消息中间件产品:activeMQ,RabbitMQ,ZeroMQ,Kafka
8.1.3 JMS(Java Messaging Service)是Java平台上有关面向消息中间件的技术规范,它便于消息系统中的Java应用程序进行消息交换,并且通过提供标准的产生、发送、接收消息的接口简化企业应用的开发。
8.1.4: JMS 定义了五种不同的消息正文格式: TextMessage--一个字符串对象,MapMessage--一套名称-值对,ObjectMessage--一个序列化的 Java 对象, BytesMessage--一个字节的数据流,StreamMessage -- Java 原始值的数据流
8.1.5:消息中间件消息传递类型:
1: 点对点
2: 发布/订阅
8.1.6:官方网站下载:http://activemq.apache.org/
8.2 遇到的问题
8.2.1 spring整合JMS(与品优购无关)消费者一直在编译中,问题现象:运行完消费者,电脑就不能运行生产者了,发布订阅无法测试, 问题原因:自己电脑idea的问题,无法解决。
8.3 代码注意事项
8.3.1 消息类型的转化:
List->String final String jsonString = JSON.toJSONString(itemList);
发送消息: session.createTextMessage(jsonString);
接收消息: TextMessage msg = (TextMessage)message;
String text = msg.getText();
List<xxx> list = JSON.parseArray(text,XXX.class);
Long[]->Object Long[] ids = ...;
session.createObjectMessage(ids);
ObjectMessage msg = (ObjectMessage)message;
Long[] ids = (Long[])Msg.getObject();
Long[]->List: List list = Arrays.asList(ids);
Long ->String Long id=...;
session.createTextMessage(id+””);
TextMessage msg = (TextMessage)message;
String text = msg.getText();
Long id = Long.parseLong(text);
九、SpringBoot框架与短信解决方案
9.1 概要
9.1.1 Spring Boot 具有如下特性:
(1)为基于 Spring 的开发提供更快的入门体验
(2)开箱即用,没有代码生成,也无需 XML 配置。同时也可以修改默认值来满足特定的需求。
(3)提供了一些大型项目中常见的非功能性特性,如嵌入式服务器、安全、指标,健康检测、外部配置等。
(4)Spring Boot 并不是不对 Spring 功能上的增强,而是提供了一种快速使用 Spring 的方式。
9.2 遇到的问题
9.2.1如何导入module项目。找到项目的pom文件,添加即可
9.3 代码注意事项
1 springBoot启动类注解:@SpringBootApplication
2 启动语句:SpringApplication.run(Application.class,args);
3 springBoot整合activeMq:@JmsListener(destination = "sms")
4 activeMq发送MapMessage:
MapMessage mapMessage = session.createMapMessage();
mapMessage.setString("mobile", phone);//手机号 ...
return mapMessage;
十、单点登录解决方案-CAS
10.1 概要
10.1.1:单点登录
单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。
10.1.2: SSO单点登录访问流程主要有以下步骤:
1. 访问服务:SSO客户端发送请求访问应用系统提供的服务资源。
2. 定向认证:SSO客户端会重定向用户请求到SSO服务器。
3. 用户认证:用户身份认证。
4. 发放票据:SSO服务器会产生一个随机的Service Ticket。
5. 验证票据:SSO服务器验证票据Service Ticket的合法性,验证通过后,允许客户端访问服务。
6. 传输用户信息:SSO服务器验证票据通过后,传输用户认证结果信息给客户端。
10.2 代码注意事项
获取用户名(Springsecurity整合cas):
String name = SecurityContextHolder.getContext().getAuthentication().getName();
十一、购物车解决方案
11.1 概要
11.1.1 : 未登录用cookie存购物车,登录之后用redis存购物车,如果cookie中有值,将cookie中的购物车添加到redis,清除cookie,redis存入购物车。
11.1.2 : 购物车对象:商家id,商家名,购物明细list。
11.1.3 : 总件数和总金额在前台计算
11.1.4 :添加商品:
1根据商品id取出商家id sellerId
2根据sellerId 判断购物车中是否存在该商家商品
3如果不存在 ,新建购物车,保存值,直接将该商品存入购物车list。
4如果存在,判断购物车是否存在该商品
5如果存不存在该商品,直接添加商品明细。如果存在,商品累加
6如果该商品的数量为0,移出该商品明细
7如果该商家的商品list的size为0,移出该商家cart
11.2 代码注意事项
11.2.1:jsonString --> List<XX> : JSON.parseArray(jsonString,XX.class);
11.2.2: springSecurity不拦截2种方式:
<http pattern="/css/**" security="none"></http> 不走springSecurity
<intercept-url pattern="/cart/*.do" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
默认对象:anonymousUser
11.2.3 BigDecimal运算:
Add(加),subtract(减),negate(取反),multiply(乘),
divide(除法取余参数:四舍五入:BigDecimal.ROUND_HALF_UP,除数不能为0),
doubleValue:将bigdecimal转为double类型
11.2.4 Long与long的区别:
long是基本数据类型,能直接比较大小(=),Long是long的封装类,不能直接使用(=),需要转化为long: new Long(“1..5”).longValue()。
十二、跨域解决方案与提交订单
12.1 概要
12.1.1 : 只要协议、域名、端口有任何一个不同,都被当作是不同的域。
@CrossOrigin(origins="http://localhost:9105",allowCredentials="true") (跨域的方法上添加,第二个参数默认true 可以省略)
12.1.2 : twitter的snowflake(推特雪花)算法,功能比UUID强大
12.2 遇到的问题
12.2.1 : 项目无法clear,有程序没有关闭,可以关机重启,在clear
12.2.2 : dobbox服务不能调用,原因分析看看是不是配置文件漏写了,Service注解,web.xml的spring配置
十三、微信扫码支付
13.1 概要
13.1.1:二维码又称QR Code,QR全称Quick Response,是一个近几年来移动设备上超流行的一种编码方式,它比传统的Bar Code条形码能存更多的信息,也能表示更多的数据类型,黑色为1,白色为0
13.1.2:二维码优势
信息容量大, 可以容纳多达1850个大写字母或2710个数字或500多个汉字
应用范围广, 支持文字,声音,图片,指纹等等...
容错能力强, 即使图片出现部分破损也能使用
成本低, 容易制作
13.1.3 下面的代码即可生成一张二维码
<html>
<head>
<title>二维码入门小demo</title>
</head>
<body>
<img id="qrious">
<script src="qrious.min.js"></script>
<script>
var qr = new QRious({
element:document.getElementById('qrious'),
size:250, level:'H', value:'http://www.itcast.cn'
});
</script>
</body>
</html>
13.1.4 在线微信支付开发文档:https://pay.weixin.qq.com/wiki/doc/api/index.html
13.1.5 微信支付参数:
appid:微信公众账号或开放平台APP的唯一标识
mch_id:商户号 (配置文件中的partner)
partnerkey:商户密钥
sign:数字签名, 根据微信官方提供的密钥和一套算法生成的一个加密信息, 就是为了保证交易的安全性
13.1.6 :我们主要会用到微信支付SDK的以下功能
获取随机字符串: WXPayUtil.generateNonceStr()
MAP转换为XML字符串(自动添加签名):
WXPayUtil.generateSignedXml(param, partnerkey)
XML字符串转换为MAP: WXPayUtil.xmlToMap(result)
13.1.7: 封装的HttpClient工具类使用的步骤
HttpClient client=new HttpClient(请求的url地址);
client.setHttps(true);//是否是https协议
client.setXmlParam(xmlParam);//发送的xml数据
client.post();//执行post请求
String result = client.getContent(); //获取结果
13.1.8: 微信支付简单总结:
创建order订单,创建支付日志,将支付日志放入缓存,跳转到支付页面
从缓存提取支付日志,提取订单号和总价,调用微信支付接口:统一查询,并创建支付二维码
在调用微信支付接口:查询订单,需要循环调用,设置超时时间,超时需重新生成二维码
若支付成功,需要更改数据库订单和支付日志信息,并销毁支付日志缓存
13.2 遇到的问题
long->String : idWorker.nextId()+"";
String ->Long : Long.parseLong(orderId)
List<String> -> String:
list.toString().replace("[", "").replace("]", "").replace(" ","")
String ->String[]: string.split(",");
十四、秒杀解决方案
14.1 概要
14.1.1:秒杀商品通常有两种限制:库存限制、时间限制
14.1.2:秒杀技术实现核心思想是运用缓存减少数据库瞬间的访问压力!读取商品详细信息时运用缓存,当用户点击抢购时减少缓存中的库存数量,当库存数为0时或活动期结束时,同步到数据库。 产生的秒杀预订单也不会立刻写到数据库中,而是先写到缓存,当用户付款成功后再写入数据库。
14.1.3: 需求
商家提交秒杀商品申请,录入秒杀商品数据,主要包括:商品标题、原价、秒杀价、商品图片、介绍等信息
运营商审核秒杀申请
秒杀频道首页列出秒杀商品(进行中的)点击秒杀商品图片跳转到秒杀商品详细页。
商品详细页显示秒杀商品信息,点击立即抢购实现秒杀下单,下单时扣减库存。当库存为0或不在活动期范围内时无法秒杀。
秒杀下单成功,直接跳转到支付页面(微信扫码),支付成功,跳转到成功页,填写收货地址、电话、收件人等信息,完成订单。
当用户秒杀下单5分钟内未支付,取消预订单,调用微信支付的关闭订单接口,恢复库存。
14.2 代码注意事项
RedisTemplate获取List集合: redisTemplate.boundHashOps("seckillGoods").values();
十五、品优购系统业务分析
15.1 概要
15.1.1: 什么是MavenProfile
在我们平常的java开发中,会经常使用到很多配制文件(xxx.properties,xxx.xml),而当我们在本地开发(dev),测试环境测试(test),线上生产使用(product)时,需要不停的去修改这些配制文件,次数一多,相当麻烦。现在,利用maven的filter和profile功能,我们可实现在编译阶段简单的指定一个参数就能切换配制,提高效率,还不容易出错.
15.1.2: 什么是MongoDB
MongoDB 的官方网站地址是:http://www.mongodb.org/
MongoDB 是一个跨平台的,面向文档的数据库,它介于关系数据库和非关系数据库之间,是非关系数据库当中功能最丰富,最像关系数据库的产品。
具体特点总结如下:
面向集合存储,易于存储对象类型的数据
模式自由
支持动态查询
支持完全索引,包含内部对象
支持复制和故障恢复
使用高效的二进制数据存储,包括大型对象(如视频等)
自动处理碎片,以支持云计算层次的扩展性
支持 Python,PHP,Ruby,Java,C,C#,Javascript,Perl 及 C++语言的驱动程序,社区中也提供了对 Erlang 及.NET 等平台的驱动程序
文件存储格式为 BSON(一种 JSON 的扩展)
15.1.3: 品优购-其它业务功能分析
1用户中心(WEB)
用户在首页登陆系统后会进入到用户中心首页。
订单中心
功能需求:
实现对订单的查询功能
未付款订单的付款功能
未付款订单的取消功能
已付款提醒订单发货功能
确认收货
退货
用户评价
物流信息跟踪
秒杀订单中心
同上。
我的收藏
购物车中有将我的购物车商品移到我的收藏功能,在用户中心中可以查看我收藏的商品
对于这样的用户收藏数据,我们可以使用mongoDB来实现。
我的收藏列表
删除收藏
我的足迹
查看足迹列表
删除我的足迹
个人信息设置
个人信息
地址信息
密码重置
绑定手机
2商家后台-订单管理(WEB)
订单管理
订单查询
订单发货
订单退货
秒杀订单管理
秒杀中订单查询(查询redis )
已完成秒杀订单查询(查询数据库)
秒杀订单发货
秒杀订单退货查询
运营商后台-订单管理(WEB)
订单管理
根据商家、订单号、用户ID等信息查询订单列表
秒杀订单管理
查询秒杀中订单
查询已付款订单
3评价系统
针对评论这样数据量大并且价值不高的数据,我们通常采用MongoDB来实现存储。
评价系统-数据访问层
评价数据访问层-操作mongoDB
评价系统-服务层
评价服务层
web工程调用评价系统
在商品详细页显示该商品的所有评论信息(CORS跨域)
用户中心web工程引用评价服务 可以对已收货的订单追加评价。
商家后台web工程引用评价服务 可以查看订单的评价
运营商后台web工程引用评价服务 可以查看订单的评价
任务服务pinyougou-task-service 引用评价服务和搜索服务,统计每个商品的评价更新到solr索引库中。
4商家首页
构建商家首页工程,引用搜索服务,显示该商家的商品列表
5资金结算
用户购买商品是直接付款给平台的,而发货的是商家,那商家如何获得货款呢?这就需要运营商定期将货款转账给商家。
佣金与佣金比例
说到平台与商家之间的资金结算,我们必须要提一下佣金。佣金就是运营商以销售额为基础抽取的销售提成。 商品类型不同,设定相应的佣金比例也不同。例如食品类佣金比例为0.5% ,那么商家每产生100元的销售额就需要支付给运营商平台相应比例的佣金。
十六、品优购总结
电商项目体量还是十分庞大而且复杂的,往往单个逻辑理解起来并不难,但是很多个逻辑结合在一起理解起来就不是很容易了,需要及时的用文档来保存,方便后期维护。
品优购是由dubbox框架搭建的,里面有很多分布式的解决方案:微服务springboot,中间件mq,单点登录cas,页面静态化freemarker,全文搜索solr,图片服务器fastDfs,缓存技术,安全框架spring-security,微信支付接口使用,购物车解决方案以及跨域访问等等。
分析时应该先确定大的方向,然后确定一个主逻辑思路,然后在主要逻辑里添加其他逻辑,还要考虑异常情况。我想说的是分析问题要全面,严谨。要做到一丝不漏。
品优购只完成了电商项目的核心功能,由于时间关系并不能全部做完,但是我也从中学到了很多知识。先这样把。