(如需完整代码,开发遇到什么问题,可与本人联系,代码给大家下载并帮你解决问题,微信号:1131237188)
1.公众号开发,首先需要微信公众号的appId,secret 相当于账号密码
2.到公众号后台配置域名,微信用户授权,微信支付目录(在公众号平台配置不了,要到商户后台配置)
3.配置好了之后就可以开发了,直接上代码
微信用户授权
/**
* Desc:请求微信接口URL1获取code跳转到redirect_url,请求微信接口URL2获取openId
* param:
* return:openid
* Author:LiuChuanting
* Date:2017/9/14
**/
public void getUrlCode(){
String status = this.getRequest().getParameter("status");
if(StringUtils.isNotBlank(status)){
CacheKit.put("reder", "status_code","1");
}
String url = Constant.WECHAT_INFO.URL1;
String appid= Constant.WECHAT_INFO.APP_ID;
String REDIRECT_URI = Constant.WECHAT_INFO.REDIRECT_URL;
url = url.replace("APPID",ToolUtil.str2Encode(appid));
url = url.replace("REDIRECT_URI",ToolUtil.str2Encode(REDIRECT_URI));
//getUserInfo();
this.redirect(url);
}
/**
* Desc:请求微信接口URL2获取openId
* param:code
* return:无
* Author:LiuChuanting
* Date:2017/9/14
**/
public void getUrlOpenid(){
String code = this.getPara("code");
String openId = HttpClientConnectionManager.getOpendId(code);
this.setAttr("openId",openId);
String status = CacheKit.get("reder","status_code");
if("1".equals(status)){
//从菜单进入个人中心
CacheKit.remove("reder","status_code");
this.render("/admin/page/redirectCenter.jsp");
}else{
//去下单用户授权
this.render("/admin/page/redirect.jsp");
}
}
用户授权原理是后台获取openid 返回到第三方页面 在第三方页面进行跳转到H5页面,并且带上openId ,一般我们放到cookie
<script type="text/javascript">
function setCookie(key, value) {
if(!key) return;
var option = {
Domain: "",
Path: "/"
};
if(/(\.cn|\.com)/.test(window.location.host)) {
var tmp = window.location.host.split("\.");
var t = tmp[tmp.length - 1].split(":");
option.Domain = "." + tmp[tmp.length - 2] + "." + t[0];
}
if(typeof(value) === "object") {
value = JSON.stringify(value);
}
var tmp = "";
for(var s in option ){
tmp += ";" + s + "=" + option[s];
}
document.cookie = key + "=" + escape(value) + tmp;
/* var Days = 30;
var exp = new Date();
exp.setTime(exp.getTime() + 60 * 5000);//过期时间5分钟
*/
//document.cookie = name + "=" + escape(value) + ";expires=" + exp.toGMTString();
}
setCookie("openId",'${openId}');
window.location.href = "http://wechat.qzt360.com/page/index.html";
</script>
获取微信用户的基本信息,根据页面传过来的openId查询ACCESS_TOKEN
在根据获取的ACCESS_TOKEN请求微信服务器获取用户信息并然后返回JSONObject对象
/**
* Desc:获取微信用户信息
* param:openid
* return:无
* Author:LiuChuanting
* Date:2017/9/14
**/
public void getUserInfo(){
String openId = getOpenId();
String user = HttpClientConnectionManager.getUserInFo(openId);
renderRb(user);
}
/**
* Desc:获取cookie openId
* param:
* return:无
* Author:LiuChuanting
* Date:2017/9/21
**/
public String getOpenId(){
String openId = "";
javax.servlet.http.Cookie[] cookies = this.getRequest().getCookies();
for(javax.servlet.http.Cookie cookie : cookies){
if(cookie.getName().equals("openId")){
openId = cookie.getValue();
}
}
return openId;
}
/**
* Desc:获取cookie 订单编号
* param:
* return:订单编号
* Author:LiuChuanting
* Date:2017/9/21
**/
public String getOrderCode(){
String orderCode = "";
javax.servlet.http.Cookie[] cookies = this.getRequest().getCookies();
for(javax.servlet.http.Cookie cookie : cookies){
if(cookie.getName().equals("orderCode")){
orderCode = cookie.getValue();
}
}
return orderCode;
}
获取access_token的原理是 先去缓存拿 如果缓存为空,去请求微信服务器,并更新到缓存中,如果从缓存拿到不为空 根据access_token请求用户信息,报access_token过期(默认两个小时过期)再去请求拿access_token并更新到缓存(获取access_token需要公众号的appid和secret的两个参数就可以请求到)
//根据用户ID和token获取用户信息
public static String getUserInFo(String openId){
DefaultHttpClient client = new DefaultHttpClient();
JSONObject jsonObject = null;
Object token = CacheKit.get("ACCESS_TOKEN","token");
//第一次请求token为空,需要去获取
if(token == null){
String accessToken = HttpClientConnectionManager.getAccessToken();
token = accessToken;
//token放到缓存
CacheKit.put("ACCESS_TOKEN","token", accessToken);
}
String url = Constant.WECHAT_INFO.GET_USERINFO_URL;
url = url.replace("ACCESS_TOKEN",token.toString()).replace("OPENID",openId);
HttpGet get = HttpClientConnectionManager.getGetMethod(url);
HttpResponse response;
try {
response = client.execute(get);
String jsonStr = EntityUtils.toString(response.getEntity(), "utf-8");
jsonObject= (JSONObject) JSON.parse(jsonStr);
if(jsonObject.get("errcode") != null){
//token过期重新获取
String accessToken = HttpClientConnectionManager.getAccessToken();
//token放到缓存
CacheKit.put("ACCESS_TOKEN","token", accessToken);
getUserInFo(openId);
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return jsonObject.toString();
}
微信开发需要的一些参数
/**
* 微信接口参数snsapi_userinfo/snsapi_base
*/
public static class WECHAT_INFO {
public static final String APP_ID = ""; //公众号ID
public static final String SECRET= ""; //公众号秘钥
public static final String ACCESS_TOKEN= "NaR8fNK4LXfaqUekYQhViOpEszPo8mIszyWYA58hKtF5hdxW_0ropKxmR4VeThq8jspiA8Y76-fn8bZZOTnDcG5mCle0ifd19IZPqVED0UCz81dm3P7cpYK3TbZh-HtiHUAcAFAWJP"; //公众号token
public static final String URL1= "https://open.weixin.qq.com/connect/oauth2/authorize?"
+ "appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";//获取code的url
public static final String REDIRECT_URL= "http://wechat.qzt360.com/api/weTrack/getUrlOpenid";//重定向的本地URL返回code
public static final String URL2= "https://api.weixin.qq.com/sns/oauth2/access_token?appid=AppId&secret=AppSecret&code=CODE&grant_type=authorization_code";//获取用户openid的URL
public static final String GET_TOKEN_URL= "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";//获取用户公众号token
public static final String GET_USERINFO_URL= "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID";//获取用户信息
}
/**
* 微信支付参数
*/
public static class WECHAT_PAY {
public static final String CALLBACK_URL = "http://wechat.qzt360.com/api/weTrack/getPayResult"; //请求支付后回调路径
public static final String DESCRIPTION = "企智通设备购买"; //商品描述
public static final String ATTACH = "qztgm"; //附加数据
public static final String MCH_ID = "1488893999"; //商户号
public static final String USER_IP = "192.168.1.1"; //用户终端IP
public static final String PAY_KEY= "BA6B005BEF79E7B95F3E097887HGHGH"; //支付KEY
public static final String SIGN_TYPE= "MD5"; //签名类型
public static final Integer LOGISTICE_MONEY= 15; //运费
public static final String ORDER_URL= "https://api.mch.weixin.qq.com/pay/unifiedorder"; //统一下单URL
}
接下来就是微信支付接口了,支付接口非常简单,首先要先预下单去请求微信服务器,返回prepay_id,通过这个ID进行封装,和生成签名返回给H5页面调用微信支付页面弹窗支付密码的窗口,支付成功后 进行回调修改后台业务状态就OK了。
/**
* Desc:微信支付获取支付配置参数
* param:code
* return:无
* Author:LiuChuanting
* Date:2017/9/19
**/
public void getPayConfig(){
String ipurl = this.getRequest().getRemoteAddr();
String openId = getOpenId();
String orderCode = getOrderCode();
JSONObject json = new JSONObject();
try {
//调用微信接口统一下单,获取prepayId
String prepayId = WeChatService.me.getPrepayId(openId,ipurl,orderCode);
//生成支付参数返回到页面请求
json = WeChatService.me.createPayConfig(prepayId);
} catch (Exception e) {
logger.error(e.getMessage());
}
renderRb(json);
}
/**
* 统一下单
* @param ipurl
* @param orderCode2
* @Title: unifiedOrder
* @Description: TODO
* @param: @param openId 微信用户openId
* @param: @param callbackUrl 回调路径
* @param: @return
* @return: PrepayId
*/
public String getPrepayId(String openId, String ipurl, String orderCode) {
Record order = Order.me.selectOrderDetail(orderCode);
Integer price = order.getInt("pay_money");
UnifiedOrder unifiedOrder = new UnifiedOrder();
unifiedOrder.setAppid(Constant.WECHAT_INFO.APP_ID);
unifiedOrder.setAttach(Constant.WECHAT_PAY.ATTACH);
unifiedOrder.setBody(Constant.WECHAT_PAY.DESCRIPTION);
unifiedOrder.setMch_id(Constant.WECHAT_PAY.MCH_ID);
String nonce = UUID.randomUUID().toString().substring(0, 30);
unifiedOrder.setNonce_str(nonce);
unifiedOrder.setNotify_url(Constant.WECHAT_PAY.CALLBACK_URL);
unifiedOrder.setOpenid(openId);
unifiedOrder.setOut_trade_no(orderCode);
unifiedOrder.setSpbill_create_ip(ipurl);
unifiedOrder.setTotal_fee(1);
String sign = createUnifiedOrderSign(unifiedOrder);
unifiedOrder.setSign(sign);
unifiedOrder.setSign_type(Constant.WECHAT_PAY.SIGN_TYPE);
/**
* 转成XML格式
*/
String xml = XmlKit.getBeanXml(unifiedOrder);
String response = null;
try {
response = HttpConnection.post(Constant.WECHAT_PAY.ORDER_URL, xml);
} catch (Exception e) {
e.printStackTrace();
}
Map<String, String> responseMap = XmlKit.getXml2Map(response);
return responseMap.get("prepay_id");
}
注意签名的参数要跟请求统一下单的参数要保持一致除了key,sign以外,因为你自己生成的签名,和你统一下单的参数一起请求微信服务器接口,微信根据你的参数也生存一个签名,然后跟你的签名进行对比,如果不一致会返回 “签名错误” 状态信息
/**
* 获取统一下单签名
* @Title: createUnifiedOrderSign
* @Description: TODO
* @param @param unifiedOrder
* @param @return
* @return String
* @throws
*/
public String createUnifiedOrderSign(UnifiedOrder unifiedOrder){
StringBuffer sign = new StringBuffer();
sign.append("appid=").append(unifiedOrder.getAppid());
/*sign.append("&attach=").append(unifiedOrder.getAttach());*/
sign.append("&body=").append(unifiedOrder.getBody());
sign.append("&mch_id=").append(unifiedOrder.getMch_id());
sign.append("&nonce_str=").append(unifiedOrder.getNonce_str());
sign.append("¬ify_url=").append(unifiedOrder.getNotify_url());
sign.append("&openid=").append(unifiedOrder.getOpenid());
sign.append("&out_trade_no=").append(unifiedOrder.getOut_trade_no());
sign.append("&spbill_create_ip=").append(unifiedOrder.getSpbill_create_ip());
sign.append("&total_fee=").append(unifiedOrder.getTotal_fee());
sign.append("&trade_type=").append(unifiedOrder.getTrade_type());
sign.append("&key=").append(Constant.WECHAT_PAY.PAY_KEY);
return DigestUtils.md5Hex(sign.toString()).toUpperCase();
}
微信支付回调
/**
* 获取支付配置
* @Title: createPayConfig
* @Description: TODO
* @param @param preayId 统一下单prepay_id
* @param @return 返回json参数到H5页面调起微信支付
* @param @throws Exception
* @return JsAPIConfig
* @throws
*/
public JSONObject createPayConfig(String prepayId){
JsAPIConfig config = new JsAPIConfig();
JSONObject json = new JSONObject();
try {
String nonce = UUID.randomUUID().toString();
String timestamp = Long.toString(System.currentTimeMillis() / 1000);
String packageName = "prepay_id="+prepayId;
StringBuffer sign = new StringBuffer();
sign.append("appId=").append(Constant.WECHAT_INFO.APP_ID);
sign.append("&nonceStr=").append(nonce);
sign.append("&package=").append(packageName);
sign.append("&signType=").append(config.getSignType());
sign.append("&timeStamp=").append(timestamp);
sign.append("&key=").append(Constant.WECHAT_PAY.PAY_KEY);
String signature = DigestUtils.md5Hex(sign.toString()).toUpperCase();
json.put("appId",Constant.WECHAT_INFO.APP_ID);
json.put("timeStamp",timestamp);
json.put("nonceStr",nonce);
json.put("package",packageName);
json.put("signType",config.getSignType());
json.put("paySign",signature);
} catch (Exception e) {
logger.error(e.getMessage());
}
return json;
}
/**
* 微信支付回调页面
* @Title: wechatPayNotify
* @Description: TODO
* @param @param request
* @param @param trade_status
* @param @param out_trade_no
* @param @param trade_no
* @return void
* @throws
*/
public String getPayResult(){
try {
Map<String, String> map = XmlKit.getCallbackParams(this.getRequest());
if (map.get(Constant.RESULT_CODE).toString().equalsIgnoreCase(Constant.STATUS)) {
//这里写成功后的业务逻辑
WeChatService.me.finishOrder(map,0);
logger.equals("支付成功");
}else{
logger.equals("支付失败");
WeChatService.me.finishOrder(map,1);
}
} catch (Exception e) {
logger.error(e.getMessage());
}
return XmlKit.getPayCallback();
}