1. 买家地址列表
1.1 后端代码
1)修改pinyougou-user-interface的AddressService.java,新增方法定义
/**
* 根据用户查询地址
* @param userId
* @return
*/
public List<TbAddress> findListByUserId(String userId );
2)修改pinyougou-user-service的AddressServiceImpl.java
/**
* 根据用户查询地址
* @param userId
* @return
*/
public List<TbAddress> findListByUserId(String userId ){
TbAddressExample example=new TbAddressExample();
Criteria criteria = example.createCriteria();
criteria.andUserIdEqualTo(userId);
return addressMapper.selectByExample(example);
}
3)修改pinyougou-cart-web的AddressController.java
@RequestMapping("/findListByLoginUser")
public List<TbAddress> findListByLoginUser(){
String userId = SecurityContextHolder.getContext().getAuthentication().getName();
return addressService.findListByUserId(userId);
}
1.2 前端代码
1)pinyougou-cart-web的cartService.js
//获取地址列表
this.findAddressList=function(){
return $http.get('address/findListByLoginUser.do');
}
2)pinyougou-cart-web的cartController.js
//获取地址列表
$scope.findAddressList=function(){
cartService.findAddressList().success(
function(response){
$scope.addressList=response;
}
);
}
3)修改getOrderInfo.html
引入头文件
<script type="text/javascript" src="plugins/angularjs/angular.min.js"> </script>
<script type="text/javascript" src="js/base.js"> </script>
<script type="text/javascript" src="js/service/cartService.js"> </script>
<script type="text/javascript" src="js/controller/cartController.js"> </script>
添加指令
<body ng-app="pinyougou" ng-controller="cartController" ng-init="findAddressList()">
循环列表
<div ng-repeat="address in addressList" >
<div class="con name">
<a href="javascript:;" >{{address.contact}}<span title="点击取消选择"> </a>
</div>
<div class="con address" >{{address.address}}<span>{{address.mobile}}</span>
<span class="base" ng-if="address.isDefault=='1'">默认地址</span>
<span class="edittext"><a data-toggle="modal" data-target=".edit" data-keyboard="false" >编辑</a> <a href="javascript:;">删除</a></span>
</div>
<div class="clearfix"></div>
</div>
1.3 地址选择样式逻辑
1)在cartController.js增加代码
// 选择地址
$scope.selectAddress = function(address) {
$scope.address = address;
}
// 是否选择
$scope.ifSelect = function(address) {
if($scope.address == address){
return true;
}
return false;
}
2)修改findAddressList方法,添加默认地址选择逻辑
3)html样式与指令调用
2. 结算页其他关键信息完善
2.1 支付方式选择
2.1.1 前端控制层
$scope.order={paymentType:'1'};
//选择支付方式
$scope.selectPayType=function(type){
$scope.order.paymentType= type;
}
2.1.2 页面
<li class="selected" ng-click="selectPayType('1')">微信付款<span title="点击取消选择"></span></li>
<li ng-click="selectPayType('2')">货到付款<span title="点击取消选择"></span></li>
2.2 商品清单与金额显示
2.2.1 显示商品清单
1)页面getOrderInfo.html上初始化调用
<body ng-app="pinyougou" ng-controller="cartController" ng-init="findAddressList();findCartList()">
2)循环显示商品清单
<div ng-repeat="cart in cartList">
<ul class="yui3-g" ng-repeat="orderItem in cart.orderItemList">
<li class="yui3-u-1-6">
<span><img src="{{orderItem.picPath}}"/></span>
</li>
<li class="yui3-u-7-12">
<div class="desc">{{orderItem.title}}</div>
<div class="seven">7天无理由退货</div>
</li>
<li class="yui3-u-1-12">
<div class="price">¥{{orderItem.price}}</div>
</li>
<li class="yui3-u-1-12">
<div class="num">X{{orderItem.num}}</div>
</li>
<li class="yui3-u-1-12">
<div class="exit">有货</div>
</li>
</ul>
</div>
3)显示合计金额
<div class="list">
<span><i class="number">{{totalValue.totalNum}}</i>件商品,总商品金额</span>
<em class="allprice">¥{{totalValue.totalMoney.toFixed(2)}}</em>
</div>
......
<div class="fc-price">应付金额:
<span class="price">¥{{totalValue.totalMoney.toFixed(2)}}</span></div>
3. 保存订单
订单是另一套逻辑,我们需要重新创建一个order的服务工程,web工程还是用购物车的web工程
1)创建pinyougou-order-interface 引入依赖pinyougou-pojo
2)创建pinyougou-order-service (WAR) 参照其它服务工程引入依赖
3.1 分布式ID生成器
我们采用的是开源的twitter( 非官方中文惯称:推特.是国外的一个网站,是一个社交网络及微博客服务) 的snowflake算法
工具类:
package util;
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
/**
* <p>名称:IdWorker.java</p>
* <p>描述:分布式自增长ID</p>
* <pre>
* Twitter的 Snowflake JAVA实现方案
* </pre>
* 核心代码为其IdWorker这个类实现,其原理结构如下,我分别用一个0表示一位,用—分割开部分的作用:
* 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
* 在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,
* 然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),
* 然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。
* 这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和机器ID作区分),
* 并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。
* <p>
* 64位ID (42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))
*
* @author Polim
*/
public class IdWorker {
// 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
private final static long twepoch = 1288834974657L;
// 机器标识位数
private final static long workerIdBits = 5L;
// 数据中心标识位数
private final static long datacenterIdBits = 5L;
// 机器ID最大值
private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
// 数据中心ID最大值
private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
// 毫秒内自增位
private final static long sequenceBits = 12L;
// 机器ID偏左移12位
private final static long workerIdShift = sequenceBits;
// 数据中心ID左移17位
private final static long datacenterIdShift = sequenceBits + workerIdBits;
// 时间毫秒左移22位
private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
/* 上次生产id时间戳 */
private static long lastTimestamp = -1L;
// 0,并发控制
private long sequence = 0L;
private final long workerId;
// 数据标识id部分
private final long datacenterId;
public IdWorker(){
this.datacenterId = getDatacenterId(maxDatacenterId);
this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
}
/**
* @param workerId
* 工作机器ID
* @param datacenterId
* 序列号
*/
public IdWorker(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
/**
* 获取下一个ID
*
* @return
*/
public synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
if (lastTimestamp == timestamp) {
// 当前毫秒内,则+1
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
// 当前毫秒内计数满了,则等待下一秒
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
// ID偏移组合生成最终的ID,并返回ID
long nextId = ((timestamp - twepoch) << timestampLeftShift)
| (datacenterId << datacenterIdShift)
| (workerId << workerIdShift) | sequence;
return nextId;
}
private long tilNextMillis(final long lastTimestamp) {
long timestamp = this.timeGen();
while (timestamp <= lastTimestamp) {
timestamp = this.timeGen();
}
return timestamp;
}
private long timeGen() {
return System.currentTimeMillis();
}
/**
* <p>
* 获取 maxWorkerId
* </p>
*/
protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
StringBuffer mpid = new StringBuffer();
mpid.append(datacenterId);
String name = ManagementFactory.getRuntimeMXBean().getName();
if (!name.isEmpty()) {
/*
* GET jvmPid
*/
mpid.append(name.split("@")[0]);
}
/*
* MAC + PID 的 hashcode 获取16个低位
*/
return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
}
/**
* <p>
* 数据标识id部分
* </p>
*/
protected static long getDatacenterId(long maxDatacenterId) {
long id = 0L;
try {
InetAddress ip = InetAddress.getLocalHost();
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
if (network == null) {
id = 1L;
} else {
byte[] mac = network.getHardwareAddress();
id = ((0x000000FF & (long) mac[mac.length - 1])
| (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
id = id % (maxDatacenterId + 1);
}
} catch (Exception e) {
System.out.println(" getDatacenterId: " + e.getMessage());
}
return id;
}
}
3.2 后端代码
3.2.1 服务层实现
修改pinyougou-order-service的OrderServiceImpl.java
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private TbOrderItemMapper orderItemMapper;
@Autowired
private IdWorker idWorker;
/**
* 增加
*/
@Override
public void add(TbOrder order) {
//得到购物车数据
List<Cart> cartList = (List<Cart>)
redisTemplate.boundHashOps("cartList").get( order.getUserId() );
for(Cart cart:cartList){
long orderId = idWorker.nextId();
System.out.println("sellerId:"+cart.getSellerId());
TbOrder tborder=new TbOrder();//新创建订单对象
tborder.setOrderId(orderId);//订单ID
tborder.setUserId(order.getUserId());//用户名
tborder.setPaymentType(order.getPaymentType());//支付类型
tborder.setStatus("1");//状态:未付款
tborder.setCreateTime(new Date());//订单创建日期
tborder.setUpdateTime(new Date());//订单更新日期
tborder.setReceiverAreaName(order.getReceiverAreaName());//地址
tborder.setReceiverMobile(order.getReceiverMobile());//手机号
tborder.setReceiver(order.getReceiver());//收货人
tborder.setSourceType(order.getSourceType());//订单来源
tborder.setSellerId(cart.getSellerId());//商家ID
//循环购物车明细
double money=0;
for(TbOrderItem orderItem :cart.getOrderItemList()){
orderItem.setId(idWorker.nextId());
orderItem.setOrderId( orderId );//订单ID
orderItem.setSellerId(cart.getSellerId());
money+=orderItem.getTotalFee().doubleValue();//金额累加
orderItemMapper.insert(orderItem);
}
tborder.setPayment(new BigDecimal(money));
orderMapper.insert(tborder);
}
redisTemplate.boundHashOps("cartList").delete(order.getUserId());
}
3.2.2 控制层
修改pinyougou-cart-web的OrderController.java
/**
* 增加
* @param order
* @return
*/
@RequestMapping("/add")
public Result add(@RequestBody TbOrder order){
//获取当前登录人账号
String username = SecurityContextHolder.getContext().getAuthentication().getName();
order.setUserId(username);
order.setSourceType("2");//订单来源 PC
try {
orderService.add(order);
return new Result(true, "增加成功");
} catch (Exception e) {
e.printStackTrace();
return new Result(false, "增加失败");
}
}
3.3 前端代码
3.3.1 前端服务层
修改pinyougou-cart-web的cartService.js
//保存订单
this.submitOrder=function(order){
return $http.post('order/add.do',order);
}
3.3.2 控制层
修改cartController.js
//保存订单
$scope.submitOrder=function(){
$scope.order.receiverAreaName=$scope.address.address;//地址
$scope.order.receiverMobile=$scope.address.mobile;//手机
$scope.order.receiver=$scope.address.contact;//联系人
cartService.submitOrder( $scope.order ).success(
function(response){
if(response.success){
//页面跳转
if($scope.order.paymentType=='1'){//如果是微信支付,跳转到支付页面
location.href="pay.html";
}else{//如果货到付款,跳转到提示页面
location.href="paysuccess.html";
}
}else{
alert(response.message); //也可以跳转到提示页面
}
}
);
}
3.3.3 页面
修改getOrderInfo.html
<a class="sui-btn btn-danger btn-xlarge" ng-click="submitOrder()" >提交订单</a>
将静态原型中的pay.html paysuccess.html payfail.html 拷贝到pinyougou-cart-web中