一、搭建order-consumer环境

1、依赖

  1. 与前几个消费者模块的依赖基本一致

2、application.yml

server:
  port: 6000
spring:
  application:
    name: crowd-order
  thymeleaf:
    prefix: classpath:/templates/
    suffix: .html
  redis:
    host: 192.168.0.101
  session:
    store-type: redis
eureka:
  client:
    service-url:
      defaultZone: http://localhost:1000/eureka/

3、在Zuul中添加模块

zuul:
  ignored-services: "*"       # 表示忽视直接通过application-name访问微服务,必须通过route
  sensitive-headers: "*"      # 在Zuul向其他微服务重定向时,保持原本的头信息(请求头、响应头)
  routes:                     # 指定网关路由
    crowd-protal:
      service-id: crowd-auth  # 对应application-name
      path: /**               # 表示直接通过根路径访问,必须加上**,否则多层路径无法访问
    crowd-project:
      service-id: crowd-project
      path: /project/**
    crowd-order:
      service-id: crowd-order
      path: /order/**

二、创建对应数据库表

# 建表t_order(订单表)
CREATE TABLE `t_order` (
    `id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
    `order_num` CHAR(100) COMMENT '订单号',
    `pay_order_num` CHAR(100) COMMENT '支付宝流水号',
    `order_amount` DOUBLE(10,5) COMMENT '订单金额',
    `invoice` INT COMMENT '是否开发票(0 不开,1 开)',
    `invoice_title` CHAR(100) COMMENT '发票抬头',
    `order_remark` CHAR(100) COMMENT '订单备注',
    `address_id` CHAR(100) COMMENT '收货地址 id', 
    PRIMARY KEY (`id`)
);


# 建表t_address(收货地址表)
CREATE TABLE t_address (
    `id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
    `receive_name` CHAR(100) COMMENT '收件人',
    `phone_num` CHAR(100) COMMENT '手机号',
    `address` CHAR(200) COMMENT '收货地址',
    `member_id` INT COMMENT '用户 id',
    PRIMARY KEY (`id`)
);


# 建表t_order_project(项目信息表)
CREATE TABLE `t_order_project` (
    `id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
    `project_name` CHAR(200) COMMENT '项目名称',
    `launch_name` CHAR(100) COMMENT '发起人',
    `return_content` CHAR(200) COMMENT '回报内容',
    `return_count` INT COMMENT '回报数量',
    `support_price` INT COMMENT '支持单价',
    `freight` INT COMMENT '配送费用',
    `order_id` INT COMMENT '订单表的主键', 
    PRIMARY KEY (`id`)
);

三、页面-确认回报内容

1、跳转到确认回报页面

修改project-consumer模块的project-show-detail.html页面代码,使点击支持按钮后跳转到确认回报的页面(需要附带上当前回报内容的id):

<a class="btn btn-warning btn-lg" th:href="'http://localhost/order/confirm/return/info/' + ${return.returnId}">
    支持
</a>

通过order-consumer模块的handler方法,进入确认回报页面

    // 进入确认回报信息的页面
    @RequestMapping("/confirm/return/info/{returnId}")
    public String confirmReturnInfo(
            @PathVariable("returnId") Integer returnId,
            HttpSession session) {

        ResultEntity<OrderProjectVO> resultEntity = mySQLRemoteService.getOrderProjectVO(returnId);

        if (ResultEntity.SUCCESS.equals(resultEntity.getResult())){
            session.setAttribute("orderProjectVO", resultEntity.getData());
        }

        return "order-confirm-return";
    }

2、远程方法

api接口模块:

@RequestMapping("/get/order/project/vo/remote")
ResultEntity<OrderProjectVO> getOrderProjectVO(@RequestParam("returnId") Integer returnId);

mysql模块的handler方法:

@RequestMapping("/get/order/project/vo/remote")
ResultEntity<OrderProjectVO> getOrderProjectVO(@RequestParam("returnId") Integer returnId) {

    try {
        OrderProjectVO orderProjectVO = orderService.getOrderProjectVO(returnId);
        return ResultEntity.successWithData(orderProjectVO);
    } catch (Exception e) {
        e.printStackTrace();
        return ResultEntity.failed(e.getMessage());
    }
}

mysql模块的service实现类方法(接口代码省略):

@Override
public OrderProjectVO getOrderProjectVO(Integer returnId) {
    return orderProjectPOMapper.selectOrderProjectVO(returnId);
}

mapper接口中,selectOrderProjectVO抽象方法对应的Mybatis代码:

<select id="selectOrderProjectVO" resultType="org.fall.entity.vo.OrderProjectVO">
  select distinct
    project_name projectName,
    description_simple launchName,
    content returnContent,
    count returnCount,
    t_return.supportmoney supportPrice,
    freight,
    signalpurchase signalPurchase,
    purchase
  from t_project
  left join t_member_launch_info on t_project.memberid = t_member_launch_info.memberid
  left join t_return on t_project.id = t_return.projectid
  where t_return.id = #{returnId}
</select>

3、前台显示

截取,从session域中通过orderProjectVO得到项目与回报的各种信息:

<div class="col-md-12 column">
    <table class="table table-bordered" style="text-align:center;">
        <thead>
        <tr style="background-color:#ddd;">
            <td>项目名称</td>
            <td>发起人</td>
            <td width="300">回报内容</td>
            <td width="80">回报数量</td>
            <td>支持单价</td>
            <td>配送费用</td>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td th:text="${session.orderProjectVO.projectName}">活性富氢净水直饮机</td>
            <td th:text="${session.orderProjectVO.launchName}">深圳市博实永道电子商务有限公司</td>
            <td th:text="${session.orderProjectVO.returnContent}">每满1750人抽取一台活性富氢净水直饮机,至少抽取一台。</td>
            <td >
                <input id="returnCountInput" type="text" class="form-control" style="width:60px;" th:value="${session.orderProjectVO.returnCount}">
            </td>
            <td style="color:#F60">¥[[${session.orderProjectVO.supportPrice}]]</td>
            <td th:if="${session.orderProjectVO.freight} == 0">免运费</td>
            <td th:if="${session.orderProjectVO.freight} > 0" th:text="${session.orderProjectVO.freight}">运费</td>
        </tr>
        </tbody>
    </table>
    <div style="float:right;">
        <p>总价(含运费):¥
            <span id="totalAmount" style="font-size:16px;color:#F60;" 
                          th:text="${session.orderProjectVO.freight} + (${session.orderProjectVO.supportPrice} * ${session.orderProjectVO.returnCount})">1.00
            </span>
        </p>
        <button id="submitBtn" type="button" class="btn btn-warning btn-lg" style="float:right;" >
            <i class="glyphicon glyphicon-credit-card"></i> 去结算
        </button>
    </div>
</div>

为了实现修改回报数量文本框中的内容,自动修改总价的功能:

12前台-确认订单 - 图1

通过一端js代码:

var signalPurchase = [[${session.orderProjectVO.signalPurchase}]];

var purchase = [[${session.orderProjectVO.purchase}]];

var freight = [[${session.orderProjectVO.freight}]]

var supportPrice = [[${session.orderProjectVO.supportPrice}]]

// 自动修正总价的功能
// 当id=returnCountInput的标签发送改动时触发
$("#returnCountInput").change(function () {
    // 得到回报数量框内输入的量
    var count = $.trim($(this).val());
    // 判断是否输入了有效数字
    if (count == null || count == "") {
        alert("请输入有效的数字!");
        // 恢复为默认值
        $(this).val(this.defaultValue);
    }
    // 判断是否超过限购数量
    if (signalPurchase == 1 && purchase < count) {
        alert("不能超过限购数量!");
        // 恢复为默认值
        $(this).val(this.defaultValue);
        return ;
    }

    // 满足上述条件 计算最后的总价
    $("#totalAmount").text(freight + supportPrice * count);
});

四、页面-确认订单

1、跳转到确认订单的页面

通过给确认回报内容的页面的“去结算”按钮添加单击响应函数:

12前台-确认订单 - 图2

$("#submitBtn").click(function () {
    var returnCount = $("#returnCountInput").val();
    window.location.href="/order/confirm/order/" + returnCount;
});

后端handler方法进行跳转操作:

@RequestMapping("/confirm/order/{returnCount}")
public String toConfirmOrderPage(
        @PathVariable("returnCount") Integer returnCount,
        HttpSession session ) {

    // 从session域拿到orderProjectVO对象
    OrderProjectVO orderProjectVO = (OrderProjectVO) session.getAttribute("orderProjectVO");

    // 给orderProjectVO设置回报的数量
    orderProjectVO.setReturnCount(returnCount);

    // 重新将orderProjectVO放回session域
    session.setAttribute("orderProjectVO",orderProjectVO);

    // 获取当前的用户的Address对象(即收货地址信息)

    // 1、先得到当前的用户id
    LoginMemberVO loginMember = (LoginMemberVO)session.getAttribute(CrowdConstant.ATTR_NAME_LOGIN_MEMBER);
    Integer memberId = loginMember.getId();

    // 2、通过用户id得到他的收货地址的List
    ResultEntity<List<AddressVO>> resultEntity = mySQLRemoteService.getAddressListByMemberIdRemote(memberId);

    if (ResultEntity.SUCCESS.equals(resultEntity.getResult())) {
        // 3、如果成功,则将收货地址放入session域
        List<AddressVO> addressVOList = resultEntity.getData();
        session.setAttribute("addressVOList", addressVOList);
    }

    // 进入确认订单页面
    return "order-confirm-order";
}

2、在确认订单页面显示需要的数据

显示收货信息

<div th:if="${#strings.isEmpty(session.addressVOList)}" th:text="暂时没有地址信息"></div>
<div th:if="${not #strings.isEmpty(session.addressVOList)}">
    <div th:each="addressVO : ${session.addressVOList}" class="radio">
        <label>
            <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" th:value="${addressVO.id}" checked>
            [[${addressVO.receiveName}]] [[${addressVO.phoneNum}]]   [[${addressVO.address}]]
        </label>
    </div>
</div>

显示回报信息与总价格

(详见代码)

<table class="table table-bordered" style="text-align:center;">
    <thead>
    <tr style="background-color:#ddd;">
        <td>项目名称</td>
        <td>发起人</td>
        <td width="300">回报内容</td>
        <td width="80">回报数量</td>
        <td>支持单价</td>
        <td>配送费用</td>
    </tr>
    </thead>
    <tbody>
    <tr>
        <td th:text="${session.orderProjectVO.projectName}">活性富氢净水直饮机</td>
        <td th:text="${session.orderProjectVO.launchName}">深圳市博实永道电子商务有限公司</td>
        <td th:text="${session.orderProjectVO.returnContent}">每满1750人抽取一台活性富氢净水直饮机,至少抽取一台。抽取名额</td>
        <td th:text="${session.orderProjectVO.returnCount}"></td>
        <td style="color:#F60">¥[[${session.orderProjectVO.supportPrice}]]</td>
        <td th:if="${session.orderProjectVO.freight} == 0">免运费</td>
        <td th:if="${session.orderProjectVO.freight} > 0" th:text="${session.orderProjectVO.freight}">运费</td>
    </tr>
    </tbody>
</table>
<!-- ... ... -->
<ul style="list-style:none;" >
    <li style="margin-top:10px;">支持金额:<span style="color:red;">¥[[${session.orderProjectVO.returnCount} * ${session.orderProjectVO.supportPrice}]]</span></li>
    <li style="margin-top:10px;">配送费用:<span style="color:red;">¥[[${session.orderProjectVO.freight}]]</span></li>
    <li style="margin-top:10px;margin-bottom:10px;">
        <h2>支付总金额:
            <span style="color:red;">
           ¥[[${session.orderProjectVO.freight}+(${session.orderProjectVO.supportPrice}*${session.orderProjectVO.returnCount})]]
            </span>
        </h2>
    </li>
    <li style="margin-top:10px;padding:5px;border:1px solid #F00;display:initial;background:#FFF;">
        <i class="glyphicon glyphicon-info-sign"></i> 
        <strong>您需要先 <a href="#address">设置配送信息</a> ,再提交订单</strong>
    </li>
    <li style="margin-top:10px;">
        请在下单后15分钟内付款,否则您的订单会被自动关闭。
    </li>
    <li style="margin-top:10px;">
        <button disabled="disabled" type="button" class="btn btn-warning btn-lg">
            <i class="glyphicon glyphicon-credit-card"></i> 立即付款
        </button>
    </li>
    <li style="margin-top:10px;">
        <div class="checkbox">
            <label>
                <input type="checkbox" checked> 我已了解风险和规则
            </label>
        </div>
    </li>
</ul>

3、新增收货地址功能

修改原始的新地址的表单,加上action、method、name等:

<form action="/order/save/address" method="post" class="form-horizontal">
    <input type="hidden" name="memberId" th:value="${session.loginMember.id}">
    <div class="form-group">
        <label class="col-sm-2 control-label">收货人(*)</label>
        <div class="col-sm-10">
            <input name="receiveName" type="text" class="form-control" style="width:200px;" placeholder="请填写收货人姓名" >
        </div>
    </div>
    <div class="form-group">
        <label class="col-sm-2 control-label">手机(*)</label>
        <div class="col-sm-10">
            <input name="phoneNum" class="form-control" type="text" style="width:200px;" placeholder="请填写11位手机号码"></input>
        </div>
    </div>
    <div class="form-group">
        <label class="col-sm-2 control-label">地址(*)</label>
        <div class="col-sm-10">
            <input name="address" class="form-control" type="text" style="width:400px;" placeholder="请填写收货地址"></input>
        </div>
    </div>
    <div class="form-group">
        <label for="inputEmail3" class="col-sm-2 control-label"></label>
        <div class="col-sm-10">
            <button type="submit" class="btn btn-primary">确认配送信息</button>
        </div>
    </div>
</form>

后端handler接收

@RequestMapping("/save/address")
public String saveAddress(AddressVO addressVO, HttpSession session) {

    // 通过远程方法保存地址信息
    ResultEntity<String> resultEntity = mySQLRemoteService.saveAddressRemote(addressVO);

    // 从session域得到当前的orderProjectVO
    OrderProjectVO orderProjectVO = (OrderProjectVO) session.getAttribute("orderProjectVO");

    // 得到当前的回报数量
    Integer returnCount = orderProjectVO.getReturnCount();

    // 再次重定向到确认订单的页面(附带回报数量)
    return "redirect:http://localhost/order/confirm/order/" + returnCount;
}

api接口模块:

@RequestMapping("/save/address/remote")
ResultEntity<String> saveAddressRemote(@RequestBody AddressVO addressVO);

mysql模块的远程方法:

@RequestMapping("/save/address/remote")
ResultEntity<String> saveAddressRemote(@RequestBody AddressVO addressVO) {
    try {
        orderService.saveAddressPO(addressVO);
        return ResultEntity.successWithoutData();
    } catch (Exception e) {
        e.printStackTrace();
        return ResultEntity.failed(e.getMessage());
    }
}

service层方法:

@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
@Override
public void saveAddressPO(AddressVO addressVO) {
    AddressPO addressPO = new AddressPO();
    BeanUtils.copyProperties(addressVO,addressPO);
    addressPOMapper.insert(addressPO);
}

4、控制“立即付款”按钮是否有效

通过js代码实现勾选“我已了解风险和规则”后才能点击立即付款

下面两个标签设置id,付款按钮默认是disabled的

<li style="margin-top:10px;">
    <button id="payBtn" disabled="disabled" type="button" class="btn btn-warning btn-lg" onclick="window.location.href='pay-step-3.html'">
        <i class="glyphicon glyphicon-credit-card"></i> 立即付款
    </button>
</li>
<li style="margin-top:10px;">
    <div class="checkbox">
        <label>
            <input id="knowCheckbox" type="checkbox"> 我已了解风险和规则
        </label>
    </div>
</li>

js代码:

<script>
    $("#knowCheckbox").click(function () {
        // 得到当前的勾选状态
        var currentStatus = this.checked;
        // 根据是否勾选,设置付款按钮是否可用
        if (currentStatus) {
            $("#payBtn").prop("disabled","");
        } else {
            $("#payBtn").prop("disabled","disabled");
        }
    });
</script>