我的視頻課程(基礎):《(NDK)FFmpeg打造Android萬能音頻播放器》
我的視頻課程(進階):《(NDK)FFmpeg打造Android視頻播放器》
我的視頻課程(編碼直播推流):《Android視頻編碼和直播推流》
目錄:
移動大腦-SpringMVc搭建RestFul後臺服務(一)-環境搭建
移動大腦-SpringMVc搭建RestFul後臺服務(二)-配置mysql數據庫
移動大腦-SpringMVc搭建RestFul後臺服務(三)-RestFul接口編寫(模擬用戶註冊登錄)
移動大腦-SpringMVc搭建RestFul後臺服務(四)-添加Token攔截器
移動大腦-SpringMVc搭建RestFul後臺服務(五)-支付寶支付
移動大腦-SpringMVc搭建RestFul後臺服務(六)-微信支付(Android)
移動大腦-SpringMVc搭建RestFul後臺服務(七)-增量更新
上一篇博客《移動大腦-SpringMVc搭建RestFul後臺服務(四)-添加Token攔截器》中爲服務器端程序加了Token驗證來確保一定的安全性,這篇和下一篇將介紹接入支付寶支付和微信支付功能。
先來看看這篇文章所達到的效果如圖:
支付寶支付邏輯主要是:
APP端發送支付請求---->服務端生成本地支付訂單---->服務端調用支付寶接口在支付寶後臺生成支付寶支付訂單---->支付寶生成支付訂單返回給服務端---->服務端把支付寶返回的支付訂單信息返回給APP端---->APP獲取服務端返回的支付寶支付訂單信息調起本地支付寶支付(支付寶客戶端/支付寶H5支付頁面)---->APP端成功付款---->支付寶同步通知APP支付結果並異步調用服務器回調接口告訴服務器支付結果---->服務端驗證支付寶回調結果簽名以及商戶信息是否合法---->服務端處理相應的結果返回給支付寶服務器。這樣就完成了一次支付過程。
開始搬磚
一、添加訂單表“t_order”
1.1訂單實體類OrderBean.java
package com.ywl5320.appservice.bean;
/**
* Created by ywl5320 on 2017/10/19.
*/
public class OrderBean extends BaseBean{
private Integer id;
private Integer userId;
private String phone;
private String orderNo;//訂單號
private String payMoney; //支付金額
private String payGoods; //支付的商品名稱
private Integer payStatus;//支付狀態 0:未支付 1:支付成功
private String payTime;//支付時間
private Integer payWay;//支付方式 1:支付寶 2:微信
private String subject;
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
public String getPayMoney() {
return payMoney;
}
public void setPayMoney(String payMoney) {
this.payMoney = payMoney;
}
public String getPayGoods() {
return payGoods;
}
public void setPayGoods(String payGoods) {
this.payGoods = payGoods;
}
public Integer getPayStatus() {
return payStatus;
}
public void setPayStatus(Integer payStatus) {
this.payStatus = payStatus;
}
public String getPayTime() {
return payTime;
}
public void setPayTime(String payTime) {
this.payTime = payTime;
}
public Integer getPayWay() {
return payWay;
}
public void setPayWay(Integer payWay) {
this.payWay = payWay;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
}
1.2在entitis.hbm.xml中配置表結構
<class name="com.ywl5320.appservice.bean.OrderBean" table="t_order">
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="userId" column="userId"></property>
<property name="phone" column="phone"></property>
<property name="orderNo" column="orderNo"></property>
<property name="payMoney" column="payMoney"></property>
<property name="payGoods" column="payGoods"></property>
<property name="payStatus" column="payStatus"></property>
<property name="payTime" column="payTime"></property>
<property name="payWay" column="payWay"></property>
</class>
二、編寫Dao層支付代碼
2.1 OrderDao.java,包含四個方法,可看註解
package com.ywl5320.appservice.dao;
import com.ywl5320.appservice.bean.OrderBean;
/**
* Created by ywl5320 on 2017/10/19.
*/
public interface OrderDao {
/**
* 生成訂單
* @param orderBean
*/
void createOrder(OrderBean orderBean);
/**
* 根據訂單ID獲取訂單
* @param orderNo
* @return
*/
OrderBean getOrderById(int userId, String orderNo);
/**
* 更新訂單
* @param orderBean
*/
void updateOrder(OrderBean orderBean);
/**
* 獲取訂單信息
* @param orderNo
* @return
*/
OrderBean getOrderByOrNo(String orderNo);
}
2.2 OrderDaoImpl.java
package com.ywl5320.appservice.dao;
import com.ywl5320.appservice.bean.OrderBean;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import java.util.List;
/**
* Created by ywl5320 on 2017/10/19.
*/
public class OrderDaoImpl extends HibernateDaoSupport implements OrderDao{
public void createOrder(OrderBean orderBean) {
// TODO Auto-generated method stub
this.getHibernateTemplate().save(orderBean);
}
public OrderBean getOrderById(int userId, String orderNo) {
// TODO Auto-generated method stub
List<OrderBean> orders = (List<OrderBean>) this.getHibernateTemplate().find("from OrderBean where userId=? and orderNo=?", userId, orderNo);
if(orders != null && orders.size() > 0)
{
return orders.get(0);
}
return null;
}
public void updateOrder(OrderBean orderBean) {
// TODO Auto-generated method stub
this.getHibernateTemplate().update(orderBean);
}
public OrderBean getOrderByOrNo(String orderNo) {
// TODO Auto-generated method stub
List<OrderBean> orders = (List<OrderBean>) this.getHibernateTemplate().find("from OrderEntity where orderNo=?", orderNo);
if(orders != null && orders.size() > 0)
{
return orders.get(0);
}
return null;
}
}
2.3 在beans.xml中配置OrderDaoImpl
<bean id="orderDaoImpl" class="com.ywl5320.appservice.dao.OrderDaoImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
三、編寫支付Service層
3.1下載新版支付寶服務端APP支付SDK(https://docs.open.alipay.com/54/106370),然後添加到web/WEB-INF/lib中並添加到項目中。
3.2創建PayService.java
package com.ywl5320.appservice.service;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.ywl5320.appservice.bean.*;
import com.ywl5320.appservice.dao.OrderDao;
import com.ywl5320.appservice.dao.UserDao;
import com.ywl5320.appservice.util.CommonUtils;
import com.ywl5320.appservice.util.MD5;
import com.ywl5320.appservice.util.RestFulUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
/**
* Created by ywl5320 on 2017/10/19.
*/
@Transactional
public class PayService {
public static final String ALI_APPID = "";
public static final String ALI_RSA2_PRIVATE_KEY = "";
public static final String ALI_PUBLIC_KEY = "";
String lockSuo = "createOrder";
@Autowired
private OrderDao orderDao;
public RestFulBean<BaseBean> createOrder(int userId, String payGoods, String payMoney, int payWay, String subject)
{
String payTime = String.valueOf(System.currentTimeMillis());
String orderNo = "";
OrderBean order = null;
AliPayBean aliPayBean = null;
WxPayBean wxPayBean = null;
synchronized (lockSuo) {
try {
orderNo = MD5.encryptMD5(userId + payTime + payMoney + subject + "md5_create_order");//生成訂單ID
OrderBean orderBean = new OrderBean();
orderBean.setSubject(subject);
orderBean.setOrderNo(orderNo);
orderBean.setUserId(userId);
orderBean.setPayGoods(payGoods);
orderBean.setPayMoney(payMoney);
orderBean.setPayStatus(0);//0:未支付 1:已支付
orderBean.setPayTime(CommonUtils.getNowTime());
orderBean.setPayWay(payWay);//1:支付寶支付 2:微信支付
orderDao.createOrder(orderBean);
order = orderDao.getOrderById(userId, orderNo);
if(order != null)
{
if(payWay == 1)//支付寶
{
//實例化客戶端
AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", ALI_APPID, ALI_RSA2_PRIVATE_KEY, "json", "utf-8", ALI_PUBLIC_KEY, "RSA2");
//實例化具體API對應的request類,類名稱和接口名稱對應,當前調用接口名稱:alipay.trade.app.pay
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
//SDK已經封裝掉了公共參數,這裏只需要傳入業務參數。以下方法爲sdk的model入參方式(model和biz_content同時存在的情況下取biz_content)。
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setBody("我是測試數據");
model.setSubject(orderBean.getSubject());
model.setOutTradeNo(orderBean.getOrderNo());
model.setTimeoutExpress("30m");
model.setTotalAmount(orderBean.getPayMoney());
model.setProductCode("QUICK_MSECURITY_PAY");
request.setBizModel(model);
request.setNotifyUrl("http://10.50.50.205:8080/pay/verifyalipayresult.do");//注意:實際情況填寫自己的服務器接口地址,外網才能訪問。
try {
//這裏和普通的接口調用不同,使用的是sdkExecute
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
aliPayBean = new AliPayBean();
aliPayBean.setOrderId(response.getOutTradeNo());
aliPayBean.setOrderInfo(response.getBody());
// System.out.println(response.getBody());//就是orderString 可以直接給客戶端請求,無需再做處理。
} catch (AlipayApiException e) {
e.printStackTrace();
}
}
else if(payWay == 2)//微信支付
{
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(payWay == 1)
{
if(aliPayBean != null)
{
return RestFulUtil.getInstance().getResuFulBean(aliPayBean, 0, "支付寶訂單生成成功");
}
else
{
return RestFulUtil.getInstance().getResuFulBean(null, 1, "支付寶訂單生成失敗");
}
}
else if(payWay == 2)
{
return RestFulUtil.getInstance().getResuFulBean(null, 1, "微信支付研發中");
}
else
{
return RestFulUtil.getInstance().getResuFulBean(null, 1, "支付方式不對");
}
}
/**
* 支付寶驗證,更新訂單信息
* @param params
* @return
*/
public String verifyAliPay(Map<String, String> params)
{
OrderBean orderBean = orderDao.getOrderByOrNo(params.get("out_trade_no"));
if(orderBean != null)
{
orderBean.setPayStatus(1);//已經支付
orderDao.updateOrder(orderBean);
return "success";
}
return "fail";
}
}
這裏需要填寫自己申請的支付寶相關的APPID和key信息。生成支付訂單參照支付寶文檔:https://docs.open.alipay.com/54/106370
3.3在beans.xml中配置payService
<bean id="payService" class="com.ywl5320.appservice.service.PayService"/>
四、編寫PayAction
package com.ywl5320.appservice.action;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.ywl5320.appservice.bean.BaseBean;
import com.ywl5320.appservice.bean.OrderBean;
import com.ywl5320.appservice.bean.RestFulBean;
import com.ywl5320.appservice.bean.UserBean;
import com.ywl5320.appservice.service.PayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* Created by ywl5320 on 2017/10/19.
*/
@Controller
@RequestMapping("/pay")
public class PayAction {
@Autowired
private PayService payService;
String alilock = "alilock";
/**
* 生成訂單
* @param userId
* @param payGoods
* @param payMoney
* @param payWay
* @param subject
* @return
*/
@ResponseBody
@RequestMapping(value="/createOrder.do", method= RequestMethod.PUT)
public RestFulBean<BaseBean> register(int userId, String payGoods, String payMoney, int payWay, String subject)
{
return payService.createOrder(userId, payGoods, payMoney, payWay, subject);
}
/**
* 支付寶回調接口
* @param request
* @param resp
* @return
*/
@ResponseBody
@RequestMapping(value="/verifyalipayresult.do", method=RequestMethod.POST)
public String verifyAliPayRight(HttpServletRequest request, HttpServletResponse resp)
{
synchronized (alilock) {
Map<String,String> params = new HashMap<String,String>();
Map requestParams = request.getParameterMap();
for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i]
: valueStr + values[i] + ",";
}
params.put(name, valueStr);
}
try {
boolean flag = AlipaySignature.rsaCheckV1(params, PayService.ALI_PUBLIC_KEY, "utf-8", "RSA2");
if(flag)
{
if(params.get("trade_status").equals("TRADE_SUCCESS") && params.get("app_id").equals(PayService.ALI_APPID) && params.get("seller_id").equals("*****************"))
{
return payService.verifyAliPay(params);
}
}
} catch (AlipayApiException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return "fail";
}
}
return "fail";
}
}
這裏創建訂單採用PUT方式,支付寶服務端異步回調參照支付寶文檔:https://docs.open.alipay.com/54/106370
以上就完成了支付寶服務端的全部操作,注意:這裏支付驗證裏面僅僅做了支付訂單狀態的更改,實際情況根據自身需求來處理,比如購買VIP服務,就需要給用戶一個VIP狀態和過期時間等信息。
最後給出一段客戶端調用支付寶的代碼,具體可見文末尾源碼。
獲取支付訂單並調用支付寶支付:
btnAliPay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(MyApplication.getInstance().getUserBean() == null)
{
Toast.makeText(MainActivity.this, "請先登錄", Toast.LENGTH_LONG).show();
return;
}
showLoadDialog("創建訂單");
PayApi.getInstance().createOrder(MyApplication.getInstance().getUserBean().getId(), "支付寶支付測試", "0.01", 1, "新本版支付寶SDK支付", new HttpSubscriber<AliPayBean>(new SubscriberOnListener<AliPayBean>() {
@Override
public void onSucceed(final AliPayBean data) {
hideLoadDialog();
System.out.println("支付寶支付信息:" + data.getOrderInfo());
Runnable payRunnable = new Runnable() {
@Override
public void run() {
PayTask alipay = new PayTask(MainActivity.this);
Map<String, String> result = alipay.payV2(data.getOrderInfo(),true);
Message msg = new Message();
msg.obj = result;
mHandler.sendMessage(msg);
}
};
// 必須異步調用
Thread payThread = new Thread(payRunnable);
payThread.start();
}
@Override
public void onError(int code, String msg) {
hideLoadDialog();
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG).show();
}
}, MainActivity.this));
}
});
支付結果處理:
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
PayResult payResult = new PayResult((Map<String, String>) msg.obj);
String resultStatus = payResult.getResultStatus();
// 判斷resultStatus 爲9000則代表支付成功
if (TextUtils.equals(resultStatus, "9000")) {
// 該筆訂單是否真實支付成功,需要依賴服務端的異步通知。
Toast.makeText(MainActivity.this, "支付成功", Toast.LENGTH_SHORT).show();
} else {
// 該筆訂單真實的支付結果,需要依賴服務端的異步通知。
Toast.makeText(MainActivity.this, "支付失敗", Toast.LENGTH_SHORT).show();
}
}
};
到這裏,就完成了支付寶的支付了。附:支付寶的支付還可以全程在客戶端下單支付,但是爲了安全,不暴露支付寶信息,還是在服務端下單最爲保險。
源碼下載:GitHub AppServiceRestFul 下一篇文章將會添加微信支付