middle

NODE中間層-day6html

01-反饋前端

姓名 意見或建議
*** 今天最後一天了,剛哥講完臨走前來首歌吧,十分不捨的你。
*** 老師能不能介紹一下koa
*** 周哥今天是你最後一天了,,,難受ing 我還想聽你講一遍組件之間的傳智,尤爲是子傳父和非父子 ..謝謝您咧❀❀❀❀node

02-回顧express

...json

  • 頭部購物車信息展現:
    • 購物車中全部商品件數總和
    • 購物車中全部商品名稱的列表
  • 在全局中間件去實現獲取購物車數據
    • global的中間件
    • 已有獲取分類信息異步操做
    • 也有獲取購物車數據異步操做
    • 把分類業務 和 購物車業務 封裝成兩個promise對象
    • Promise.all()

中間件內代碼:api

// 分類業務
const setCategory = () => {
  return new Promise((resolve, reject) => {
    if (req.app.locals.category) {
      res.locals.category = req.app.locals.category
      // 處理成功
      resolve()
    } else {
      categoryModel.getCategory().then(data => {
        // 緩存
        req.app.locals.category = data
        res.locals.category = data
        resolve()
      }).catch(err => reject(err))
    }
  })
}

// setCategory().then(()=>{
//   next()
// }).catch(err=>next(err))

// 購物車業務
const setHeadCart = () => {
  return new Promise((resolve, reject) => {
    if (!req.session.user) {
      const cookieString = req.cookies[cart.key] || '[]'
      // [{id:100,amount:3},...]
      const cartList = JSON.parse(cookieString)
      const promiseArr = cartList.map(item => productModel.getProductBase(item.id))
      Promise.all(promiseArr).then(results => {
        // [{id:'',name:'',...},...]
        // 總件數
        // Array.reduce()  遍歷---累加
        // arr.reduce((prev,item)=>prev+item,0)
        // item 遍歷的時候每一項的值
        // prev 上一次回調函數的返回結果
        // 若是是第一次遍歷 就沒有上一次 最好設置一個默認值
        // reduce(callback,initValue)  initValue 起始值
        const count = cartList.reduce((prev,item) => item.amount + prev, 0)
        // 名稱數組 ['名字1','名字2']
        const nameList = results.map(item => item.name)
        res.locals.headCart = {count, nameList}
        resolve()
      }).catch(err => {
        reject(err)
      })
    } else {
      cartModel.getCart(req.session.user.id).then(data => {
        res.locals.headCart = {
          count: data.reduce((prev,item) => item.amount + prev, 0),
          nameList: data.map(item => item.name)
        }
        resolve()
      }).catch(err => {
        reject(err)
      })
    }
  })
}

Promise.all([
  setCategory(),
  setHeadCart()
]).then(results => {
  // 兩個操做成功
  // 在購物車頁面  修改數量的時候  同時修改頭部購物車的數量
  next()
}).catch(err => {
  next(err)
})
複製代碼

頭部代碼:數組

<div class="yui3-u Right shopArea">
  <div class="fr shopcar">
    <div class="show-shopcar">
      <span class="car"></span>
      <a class="sui-btn btn-default btn-xlarge" href="/cart">
        <span>個人購物車</span>
        <i class="shopnum">{{headCart.count}}</i>
      </a>
      <div class="clearfix shopcarlist">
        <ul>
          {{each headCart.nameList item i}}
          <li>{{item}}</li>
          {{/each}}
        </ul>
      </div>
    </div>
  </div>
</div>
複製代碼

// find() findIndex() includes() from() [].foreach.call( 僞數組,callback) map filter reducepromise

補充購物車數量聯動頭部購物車數量:緩存

// 僞數組
const $arr = $('.cart-list [type="text"]')
const headCount = [].reduce.apply($arr,[(prev,item)=>+item.value+prev,0])
$('.shopnum').html(headCount)
複製代碼

03-結算-業務分析服務器

  • 發起結算業務:購物車選中了一些商品後 發起業務
  • 獲取選中的商品ID (100,101)字符串 提交給後臺
  • 結算:
    • 生成訂單

    • 覈對訂單

      // 6. 提交結算數據 ('.sum-btn').on('click', function () {
  constarr = ('.cart-list [type="checkbox"]:checked')
  const ids = []arr.each(function (i,item) { ids.push(item.dataset.id) }) if (!ids.length) return alert('請選擇商品後去結算') location.href = '/order/add?ids=' + ids.join(',') })

04-結算-路由規則

  • router.get('/order/add',checkLogin, userController.orderAdd)
    router.get('/checkout',checkLogin, userController.checkout)
    複製代碼
  • 生成訂單後:作什麼???
  • 重定向:結算頁面

05-結算-生成訂單

// 生成訂單
exports.orderAdd = (req, res, next) => {
  const items = req.query.ids
  const userId = req.session.user.id
  // 數據操做
  userModel.createOrder(userId, items)
    .then(data => {
      // data  訂單數據
      // 未來結算頁面須要根據訂單編號查詢訂單信息
      res.redirect('/checkout?num=' + data.order_number)
    })
    .catch(err => next(err))
}
// 生成訂單
exports.checkout = (req, res, next) => {
  // 渲染頁面:
  // a. 訂單數據
  // b. 收貨地址列表數據
  res.send('結算頁面')
}
複製代碼

06-結算-頁面渲染

  • 獲取數據:訂單數據,收貨地址數據

    const num = req.query.num const userId = req.session.user.id // 渲染頁面: // a. 訂單數據 // b. 收貨地址列表數據 Promise.all([ userModel.getOrder(num), userModel.getAddressList(userId) ]).then(results=>{ res.send(results) }).catch(err=>next(err))

  • 渲染頁面

    • 加了一塊內容:默認選中的收貨地址--->後臺生成默認把你的收貨地址中的第一條看成默認地址

07-結算-新增收貨地址

  • 路由: /order/address post

    // 讓表單外的按鈕去控制表單 form ----> id="addressForm"
    button -----> form="addressForm" // 去掉 屬性 阻止提交 data-ok="modal"

    exports.orderAddressAdd = (req, res, next) => { // 添加收貨地址,跳轉當前的訂單結算頁面 // 須要數據:收件人 地址 手機號 郵編 訂單編號 const {name, address, phone, code, num} = req.body userModel.addAddress(req.session.user.id, name, address, phone, code) .then(data => { res.redirect('/checkout?num=' + num) }).catch(err => next(err)) }

08-結算-選擇收貨地址

  • 路由: /order/address get
  • 分析:
    • 選中的收貨地址數據:從order取出,屬於訂單
    • 其餘的數據,從收貨地址列表中取出,和訂單無關,列表這裏選中
  • 結果:修改order
  • 修改:order中的express_address字段
    • 準備字段的值:根據收貨地址數據的ID去查詢

    • 傳order的num

      router.get('/order/address',checkLogin, userController.orderAddressEdit) router.get('/checkout',checkLogin, userController.checkout)

      exports.orderAddressEdit = (req, res, next) => { // num 訂單編號 addressId 選中的收貨地址數據ID const num = req.query.num const addressId = req.query.addressId const userId = req.session.user.id // 調用接口 先調用獲取收貨地址的接口 在去修改訂單 userModel.getAddress(userId, addressId) .then(data => { // data 單條收貨地址信息數據 {id,name,address,phone,code} const address = ${data.name} ${data.address} ${data.phone} ${data.code} return userModel.editOrderAddress(num, address) }) .then(data => { // 回到結算頁面 重定向 res.redirect(/checkout?num=${num}&addressId=${addressId}) }).catch(err => next(err)) }

      // 修改收貨地址的時候纔會傳 可能沒有這項數據 const addressId = req.query.addressId || ''

      {{if !addressId}}

    • {{else}}
    • {{/if}}

09-支付-業務分析

  • 買家帳號 jfjbwb4477@sandbox.com
  • 登陸密碼 111111
  • 支付密碼 111111

10-支付-瞭解alipay沙箱

  • 測試環境

11-支付-生成支付地址

依賴 node-alipay-sdk

var ali = new Alipay({
	// 平臺id
    appId: '2016080300159077',
    // 通知支付結果的地址
    notifyUrl: 'http://www.xxx.com/callback/alipay',
    // 私鑰
    rsaPrivate: fs.readFileSync(path.resolve('./pem/sandbox_private.pem'), 'utf-8'),
   	// 公鑰
    rsaPublic: fs.readFileSync(path.resolve('./pem/sandbox_ali_public.pem'), 'utf-8'),
    // 沙箱
    sandbox: true,
    // 加密類型
    signType: 'RSA2',
    // 日誌
    openLog: true
});

var params = ali.pagePay({
    // 品優購商品
    subject: '測試商品',
    // 那些商品
    body: '測試商品描述',
    // 平臺交易編號
    outTradeId: outTradeId,
    // 超時時間
    timeout: '10m',
    // 支付的金額
    amount: '10.00',
    // 產品類型  0 虛擬 1 實物
    goodsType: '0',
    // 二維碼類型
    qrPayMode: 0
});
複製代碼

params:加密後的傳參

支付寶網關:openapi.alipaydev.com/gateway.do

最終支付的地址= 支付寶網關+ params

工具:uitl/alipay.js

12-支付-支付頁面付款

<a class="sui-btn btn-danger btn-xlarge fr" href="/pay?num={{order.order_number}}">當即支付</a>

// 支付跳轉
exports.pay = (req, res, next) => {
  const num = req.query.num
  userModel.getOrder(num)
    .then(data => {
      const payUrl = getPayUrl(data)
      res.redirect(payUrl)
    })
    .catch(err => next(err))
}
複製代碼

13-支付-付款成功後回跳

  • 回調 平臺系統 品優購
  • 回調 地址: http://127.0.0.1:3000/pay/callback
  • // 回調的地址 alipay.js
    return_url: 'http://127.0.0.1:3000/pay/callback'
    複製代碼

14-支付-回跳後修改訂單

// 支付成功後的回調
exports.callback = (req, res, next) => {
  const pay_status = 1 //支付成功
  const trade_no = req.query.trade_no  //支付交易流水
  const send_status = 0
  const num = req.query.out_trade_no  // 訂單編號
  userModel.editOrder(num, pay_status, send_status, trade_no)
    .then(data=>{
      // 支付成功的提示頁面  包含訂單信息
      res.locals.order = data
      res.render('callback.art')
    }).catch(err=>next(err))
}
複製代碼

15-支付-瞭解notify功能

  • 纔是去修改訂單狀態的操做
  • 操做;支付寶服務器 請求 平臺服務器
  • 是外網環境 訪問不到 局域網
  • 通知 本地服務器 接收不到
  • 沒法完成 修改訂單的 操做
  • 因此:把修改訂單的操做放到 callback 去執行 http://127.0.0.1:3000/pay/callback

16-擴展-自動登陸

  • 訪問該網站的時候 實現自動登陸

  • cookie存儲 {id:'',pw:''}

  • 前提:當前沒有登陸 存儲了自動登陸的信息

    exports.autoLogin = (req, res, next) => { const cookieString = req.cookies[autoLoginConfig.key] if (!req.session.user && cookieString) { // 自動登陸 const autoUser = JSON.parse(cookieString) //{id,pw} userModel.getUser(autoUser.id).then(data => { if (data.password === autoUser.pw) { // 自動登陸成功 req.session.user = data next() } else { // 匹配不正確 無效信息 清除 res.cookie(autoLoginConfig.key,'') } }) } else { next() } }

17-總結

  • node中間層
    • node調用接口
    • 後臺渲染
    • 返回json前端渲染
  • UI和接口服務器解耦
  • 技術棧統一
  • 併發高

目標:

  • 增強nodejs開發能力
  • 瞭解 電商業務
  • 簡歷:加一筆
相關文章
相關標籤/搜索