⼩程序-登录+⽀付(后台Java)Demo实战(环境搭建+源码)
读者要求:已经学过⼩程序的⼊门官⽅教程,即其。
另外:如您的⼩程序需要进⾏⽀付,则⾸先需要完成认证(个⼈号不⽀持认证):【登录⼩程序】—>【设置】—>【认证详情】,同时,申请⽀付:认证后,可以在⼩程序后台,点击⽀付菜单项,选择申请⽀付。申请完成后,会发送⽀付商户号,商户平台⽤户名密码等信息到注册者邮箱。
如下介绍⼀个可运⾏的⼩程序登录+⽀付的demo。接触了⼩程序简易教程的,想必都知道我们必然有⾃⼰的后台应⽤服务器,来处理我们⾃⼰的业务逻辑、请求服务完成⼀定的功能。在此,我们的后台采⽤java环境,本⽂将⾸先介绍环境搭建的过程,随后介绍登录+⽀付的流程及代码。
⼀、后台web服务环境搭建
1. 安装jdk、tomcat,ICP备案的域名准备。
Linux安装jdk:
Linux 安装tomcat:
经过icp备案的域名,请⾃⾏准备。
2.配置https,由于⼩程序请求url必须是https,故⽽必须配置⽀持https请求。本⼈采⽤的是在阿⾥云购买的域名,故⽽采⽤的证书也是阿⾥云⽣成的ssl证书,可参考如下两篇博⽂进⾏配置。当然,你也可以通过别的⽅式⽣成证书,更或者通过nginx作反向代理到你的服务器。
同时,务必将您的⼩程序域名绑定在⼩程序后端。登⼊⼩程序后台,【设置】-【开发设置】-【服务器域名】
3. 部署web服务
如上两步完成后,请务必确认通过你的域名(.)可以展⽰tomcat的默认页之后,开始部署我们的web服务。在此,就简单粗暴的在webapps 下建⽴⼩程序的根⽬录,我命名为wechatserver,在此⽬录下,创建WEB-INFO,下⾯的⽬录结构如下:
classes存放⾃⼰写的类的classes⽂件,lib存放我们项⽬依赖的jar包,logs⽤于存放我们的⽇志输出,l是我们这个项⽬的配置。 demo中,我们只有⼀个servlet接收⼩程序前端请求,l中增加配置如下:
<servlet>
<servlet-name>WechatServlet</servlet-name>
<servlet-class>com.icbc.servlet.WechatServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>WechatServlet</servlet-name>
<url-pattern>/servlet/WechatServlet</url-pattern>
</servlet-mapping>
4. log4j 应⽤
在开发调试中,我们免不了需要通过打印⽇志进⾏调试,因此在此增加了⽇志的使⽤。l中增加配置:
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classes/log4j.properties</param-value>
</context-param>
在classes增加⽂件,log4j.properties,内容如下:
Console=org.apache.log4j.ConsoleAppender
Console.Target=System.out
Console.layout=org.apache.log4j.PatternLayout
Console.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] [%p] %m%n
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.file = 你的⽬录/common.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = info
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
log4j.appender.D.DatePattern='.'yyyy-MM-dd'.log'
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.file = 你的⽬录/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
log4j.appender.D.DatePattern='.'yyyy-MM-dd'.log'
log4j 在java中的引⽤、使⽤:
public static Logger logger = Logger(WechatServlet.class);
logger.info(“打印信息”);
⼆、⼩程序登录+⽀付
1. ⼩程序前端⽬录准备
基于⼩程序⼯具⽣成的默认hello world程序,pages下先建⽴⽬录order,随后在order⽬录⽣成⼀个新的page,命名为order,结构如下图:
在index中增加按钮,进⼊order。
index.wxml
<view>
<navigator class="index-intro__btn btn btn-danger btn-md"url="/pages/order/order">进⼊商城</navigator>
</view>
order.js ⽀付事件处理。
2. 登录+⽀付 code
流程⼤概分为⼏步:
1)登录,获取code(⼀个code只能⽤⼀次)
2)通过code获取openid(通过请求服务器,由服务器请求获取并返回⼩程序)。
3)⼩程序请求服务器进⾏预下单,上送商品详情、⾦额、openid。
4)服务器端接收请求,根据请求订单数据、⽣成第三⽅订单号,调⽤的。
5)服务器收到预下单信息后,签名并组装⽀付数据,返回给⼩程序。所需数据见: 6)⼩程序前端发起⽀付,并⽀付完成
7)服务器收到回调。
2.1 登录,获取code、
onLoad: function(options) {
// 登录
wx.login({
success: function(res) {
// 发送 de 到后台换取 openId, sessionKey, unionId
var that = this;
if (de) {
console.log('获取⽤户登录态success!' + de)
de = de
} else {
console.log('获取⽤户登录态失败!' + Msg)
}
}
})
},
2.2 通过code 获取openid(前端)
getOpenId:function(that, code){
console.log(code);
let operFlag = "getOpenid";
console.log(operFlag);
url: 'xxx/wechatserver/servlet/WechatServlet',
data: {
code:code,
operFlag:operFlag
},
header: { 'content-type': 'application/json' },
success: function(res) {
console.log(res);
var openid = res.data.openid;
console.log(openid);
that.paypay(that, openid); //预下单并⽀付
},
fail: function(res) {
console.log(sg);
console.log(de);
},
complete:function(res){
}
})
},
2.2 服务器端servlet(复写HttpServlet的doGet doPost函数)doPost的代码⽚段:
//获取操作类型,根据类型执⾏不同操作
String operFlag = Parameter("operFlag");
logger.info("operFlag=" + operFlag);
String results = "";
if("getOpenid".equals(operFlag)){
String code = Parameter("code");
logger.info("code=" + code);
String url = "api.weixin.qq/sns/jscode2session?appid=" + appid
+ "&secret=" + secretKey + "&js_code=" + code + "&grant_type=authorization_code";
logger.info("url=" + url);
results = sendGetReq(url);//发送http请求
}
logger.info("results = " + results);
response.setContentType("application/json;charset=UTF-8");
response.setHeader("catch-control", "no-catch");
PrintWriter out = Writer();
out.write(results);
out.flush();
out.close();
2.3 前端上送订单信息、openid请求预下单(在此,为⽅便,订单信息直接写死在服务器端了),若成功,则根据服务器端返回数据发起⽀付。
paypay: function(that, openid) {
let operFlag = 'pay';
url: 'xxx/wechatserver/servlet/WechatServlet',
data: {
openid: openid,
operFlag: operFlag
},
header: { 'content-type': 'application/json' },
success: function(res) {
console.log(res);
'timeStamp': res.data.timeStamp,
'nonceStr': Str,
'package': res.data.package,
'signType': 'MD5',
'paySign': res.data.sign,
'success': function(res) {
if (Msg == "requestPayment:ok") {
wx.showToast({
title: '⽀付成功'
})
}
},
'fail': function(res) {
}
})
},
fail: function(res) {
console.log(sg);
console.log(de);
},
complete: function(res) {
}
})
},
2.4 服务器端预下单,2.5并签名返回⽀付请求数据
附函数if("pay".equals(operFlag)){
String openid = Parameter("openid");
logger.info("openid = " + openid);
String url = "h.weixin.qq/pay/unifiedorder";
String reqStr = getReqStr(openid); //组装预下单的请求数据
logger.info("reqStr=" + reqStr);
results = sendPost(url,reqStr);//发送post数据到预下单
logger.info("prepay from weixin: \n " + results);
Map<String,String> return_data = null;
try {
return_data = lToMap(results);//的⼀个⼯具类
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
<(e.getMessage());
}
String return_code = ("return_code");
logger.info("return_code=" + return_code);
if("SUCCESS".equals(return_code)){
String prepay_id = ("prepay_id");
results = conPayParam(prepay_id); //组装返回数据
}else{入门的java游戏小程序
results ="{\"return_code\":\"fail\"}";
}
}
//组装预下单的请求数据
public static String getReqStr(String openid){
Map<String,String> data = new HashMap<String,String>();
String out_trade_no = setTradeNo();//
/
/
data.put("appid", appid);
data.put("mch_id",mer_id);
data.put("nonce_str", ateUUID());
data.put("sign_type", "MD5");
data.put("body", "spy test");
data.put("out_trade_no", out_trade_no);
data.put("device_info", "");
data.put("fee_type", "CNY");
data.put("total_fee", "1");//1分钱
data.put("spbill_create_ip", "123.12.12.123");
data.put("notify_url", "xxx/wxpay/notify");
data.put("trade_type", "JSAPI");
data.put("product_id", "12");
data.put("openid", openid);
try {
String sign = ateSignature(data, merKey, SignType.MD5);            data.put("sign", sign);
} catch (Exception e) {
e.printStackTrace();
<("sign error");
}
String reqBody = null;
try {
reqBody = WXPayUtil.mapToXml(data);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return reqBody;
}