微信端代码如下:
支付按钮:
<view class="container">
<input bindinput="getOrderCode" style="border:1px solid #ccc;" type="text" placeholder="请填写订单号" />
<button bindtap="pay">立即支付</button></view>
js代码:
pay() {
let orderCode = this.orderCode;
wepy.login({
success: res => {
if (res.code) {
HTTP.get({
url: constant.restServer.host + '/weChatApplePay/toPay',
params: {
key: constant.restServer.wxapp_id,
code: res.code,
orderCode: orderCode
},
headers: {
'Content-Type': 'application/json'
},
mask: false,
loading: false,
}).then((data) => {
console.log('后台下单返回数据', data)
wx.requestPayment({
timeStamp: data.data.timeStamp,
nonceStr: data.data.nonceStr,
package: data.data.package,
signType: data.data.signType,
paySign: data.data.paySign,
success: res => {
console.log(res);
},
fail: () => {
console.log(res);
},
complete: () => {
console.log(res);
} })
}).
catch((error) => {
console.log('app.wpy signin login get jscode error...', error)
})
} else {
console.log('获取用户登录态失败!' + res.errMsg)
}
}
});
},
//获取订单号 自定义输入
getOrderCode(e) {
this.orderCode = e.detail.value;
this.$apply();
},
};
后台实现代码 才用java编写:
Controller:
public static final String PATH = "weChatApplePay";
@Autowired
private WechatServiceApplet wechatServiceApplet;
@ApiOperation("微信小程序统一下单接口")
@RequestMapping(value = "toPay", method = RequestMethod.GET)
public RestfulApiResponse<JSONObject> toPay(@RequestParam @ApiParam(value = "登录返回的code 换取openid的登录凭证", required = true) String code, @RequestParam @ApiParam(value = "订单号", required = true) String orderCode, @RequestParam @ApiParam(value = "订单号", required = true) String key) {
return RestfulApiResponse.success("获取成功",wechatServiceApplet.toPay(code,orderCode,key));
}
@ApiOperation("微信端回调地址 后期需要修改订单状态")
@RequestMapping(value = "payResult", method = {RequestMethod.GET, RequestMethod.POST})
public void payResult(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
String reqParams = StreamUtil.read(request.getInputStream());
System.out.println("-------支付结果:"+reqParams);
StringBuffer sb = new StringBuffer("<xml><return_code>SUCCESS</return_code><return_msg>OK</return_msg></xml>");
response.getWriter().append(sb.toString());
}
wechatServiceApplet:
private static final Logger logger = LoggerFactory.getLogger(WechatServiceApplet.class);
@Autowired
private AppletSettingService appletSettingService;
//发起支付
public JSONObject toPay(String code, String orderCode, String key) {
try {
AppletSetting appletSetting = appletSettingService.selectByKey(key); //这个是我自定义 根据key 取后台appId,根据场景,自定义。
if (null == appletSetting)
throw new AppletSettingException("该小程序信息不存在");
OrderInfo order = new OrderInfo();
order.setAppid(appletSetting.getAppId());
order.setMch_id(Configure.getMch_id());//后期需要从数据库中取数据
order.setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
order.setBody("dfdfdf");
order.setOut_trade_no(orderCode);
order.setTotal_fee("1");//从前端传数据
order.setSpbill_create_ip("");//后期需要从数据库中取数据 终端IP
order.setNotify_url("");//测环境 后期需要从数据库中取数据
order.setTrade_type("JSAPI");
order.setSign_type("MD5");
return getOrder(order, code,appletSetting);
} catch (Exception e) {
e.printStackTrace();
logger.error("-------", e);
}
return null;
}
//下单 生成prepay_id 用于签名 小程序端发起支付
private JSONObject getOrder(OrderInfo order, String code,AppletSetting appletSetting) throws UnrecoverableKeyException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, ClientProtocolException, IllegalAccessException, ServletException, IOException {
//生成签名
order.setOpenid(getOpenId(code,appletSetting));
String sign = Signature.getSign(order);
order.setSign(sign);
String result = HttpRequest.sendPost(WechatAppletConfig.APPLET_PAY, order);
logger.info("---------下单返回:" + result);
return sign(convertXml(result).getPrepay_id(),appletSetting);
}
//下单之后的签名小程序端发起支付
private JSONObject sign(String repay_id,AppletSetting appletSetting) throws IllegalAccessException {
SignInfo signInfo = new SignInfo();
signInfo.setAppId(appletSetting.getAppId());
long time = System.currentTimeMillis() / 1000;
signInfo.setTimeStamp(String.valueOf(time));
signInfo.setNonceStr(RandomStringGenerator.getRandomStringByLength(32));
signInfo.setRepay_id("prepay_id=" + repay_id);
signInfo.setSignType("MD5");
//生成签名
String sign = Signature.getSign(signInfo);
JSONObject json = new JSONObject();
json.put("timeStamp", signInfo.getTimeStamp());
json.put("nonceStr", signInfo.getNonceStr());
json.put("package", signInfo.getRepay_id());
json.put("signType", signInfo.getSignType());
json.put("paySign", sign);
return json;
}
//获取openId 用于下单参数
private String getOpenId(String code,AppletSetting appletSetting) throws ServletException, IOException {
HttpGet httpGet = new HttpGet("https://api.weixin.qq.com/sns/jscode2session?appid=" + appletSetting.getAppId() + "&secret=" + appletSetting.getAppSecret() + "&js_code=" + code + "&grant_type=authorization_code");
//设置请求器的配置
HttpClient httpClient = HttpClients.createDefault();
HttpResponse res = httpClient.execute(httpGet);
HttpEntity entity = res.getEntity();
String result=EntityUtils.toString(entity, "UTF-8");
return convertOpenId(result);
}
//结果转Map 取出openId
private String convertOpenId(String result){
Gson gson = new Gson();
Map<String, Object> map = new HashMap<String, Object>();
map = gson.fromJson(result, map.getClass());
String openId=(String) map.get("openid");
return openId;
}
//xml 转json 取prepay_id
private OrderReturnInfo convertXml(String result){
JSONObject obj = new JSONObject();
try {
Document doc = DocumentHelper.parseText(result);
Element root = doc.getRootElement();
obj.put(root.getName(), iterateElement(root));
OrderReturnInfo orderReturnInfo = JSON.toJavaObject(obj.getJSONObject("xml"),OrderReturnInfo.class);
return orderReturnInfo;
}catch (Exception e){
e.printStackTrace();
return null;
}
}
@SuppressWarnings("unchecked")
private static Map iterateElement(Element element) {
List jiedian = element.elements();
Element et = null;
Map obj = new HashMap();
Object temp;
List list = null;
for (int i = 0; i < jiedian.size(); i++) {
list = new LinkedList();
et = (Element) jiedian.get(i);
if (et.getTextTrim().equals("")) {
if (et.elements().size() == 0)
continue;
if (obj.containsKey(et.getName())) {
temp = obj.get(et.getName());
if(temp instanceof List){
list = (List)temp;
list.add(iterateElement(et));
}else if(temp instanceof Map){
list.add((HashMap)temp);
list.add(iterateElement(et));
}else{
list.add((String)temp);
list.add(iterateElement(et));
}
obj.put(et.getName(), list);
}else{
obj.put(et.getName(), iterateElement(et));
}
} else {
if (obj.containsKey(et.getName())) {
temp = obj.get(et.getName());
if(temp instanceof List){
list = (List)temp;
list.add(et.getTextTrim());
}else if(temp instanceof Map){
list.add((HashMap)temp);
list.add(iterateElement(et));
}else{
list.add((String)temp);
list.add(et.getTextTrim());
}
obj.put(et.getName(), list);
}else{
obj.put(et.getName(), et.getTextTrim());
}
}
}
return obj;
}
OrderInfo:
/**
* 预订单
*
* @author zuoliangzhu
*
*/
public class OrderInfo {
private String appid;// 小程序ID
private String mch_id;// 商户号
private String nonce_str;// 随机字符串
private String sign_type;//签名类型
private String sign;// 签名
private String body;// 商品描述
private String out_trade_no;// 商户订单号
private String total_fee;// 标价金额 ,单位为分
private String spbill_create_ip;// 终端IP
private String notify_url;// 通知地址
private String trade_type;// 交易类型
private String openid;//用户标识
}
public class Configure {
private static String key = "你的商户的api秘钥";
//商户号
private static String mch_id = "";
//
}
Signature:
public class Signature {
private static final Logger L = Logger.getLogger(Signature.class);
/**
* 签名算法
* @param o 要参与签名的数据对象
* @return 签名
* @throws IllegalAccessException
*/
public static String getSign(Object o) throws IllegalAccessException {
ArrayList<String> list = new ArrayList<String>();
Class cls = o.getClass();
Field[] fields = cls.getDeclaredFields();
for (Field f : fields) {
f.setAccessible(true);
if (f.get(o) != null && f.get(o) != "") {
String name = f.getName();
XStreamAlias anno = f.getAnnotation(XStreamAlias.class);
if(anno != null)
name = anno.value();
list.add(name + "=" + f.get(o) + "&");
}
}
int size = list.size();
String [] arrayToSort = list.toArray(new String[size]);
Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
StringBuilder sb = new StringBuilder();
for(int i = 0; i < size; i ++) {
sb.append(arrayToSort[i]);
}
String result = sb.toString();
result += "key=" + Configure.getKey();//后期需要从数据库中取数据
System.out.println("签名数据:"+result);
result = MD5.MD5Encode(result).toUpperCase();
return result;
}
public static String getSign(Map<String,Object> map){
ArrayList<String> list = new ArrayList<String>();
for(Map.Entry<String,Object> entry:map.entrySet()){
if(entry.getValue()!=""){
list.add(entry.getKey() + "=" + entry.getValue() + "&");
}
}
int size = list.size();
String [] arrayToSort = list.toArray(new String[size]);
Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
StringBuilder sb = new StringBuilder();
for(int i = 0; i < size; i ++) {
sb.append(arrayToSort[i]);
}
String result = sb.toString();
result += "key=" + Configure.getKey();//后期需要从数据库中取数据
//Util.log("Sign Before MD5:" + result);
result = MD5.MD5Encode(result).toUpperCase();
//Util.log("Sign Result:" + result);
return result;
}
}