本文章仅作为个人笔记
微信Android接入指南,需要登陆后查看(开放平台->资源中心->开发资源->移动应用->接入指南)
微信IOS接入指南,需要登陆后查看(开放平台->资源中心->开发资源->移动应用->接入指南)
微信开放平台
- 首先要注册成为微信开放平台用户
- 通过开发者资质认证
- 提供个人信息
- 提供公司营业执照等信息
- 300rmb
- 创建移动应用并通过审核
- 提供应用描述
- 提供应用logo
- 提供应用安装包
- 提供应用签名信息(建议下载官方签名获取apk获取签名提交,另外万一签名错误导致登录时返回-6错误码,网页更改签名后需要清理客户端微信缓存再重新尝试。)
- 万事具备后可以查看到应用的AppID和AppSecret
- 开始代码模块
- IOS端(swift):
-
导入第三方库(cocopods集成)(记得 pod install):
pod 'WechatOpenSDK'
-
引用:在桥接文件中添加以下代码(桥接文件为项目根目录下的.h文件,如果没有可创建并添加)
#import "WXApi.h"
-
部分设置:
打开项目info.plist,加入如下代码(主要是NSAllowsArbitraryLoads及其值还有就是weixin/wechat):
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict> <key>LSApplicationQueriesSchemes</key> <array> <string>weixin</string> <string>wechat</string> </array>
-
-
等所有配置完毕即可进行编程了。
-
先贴上AppDelegate部分主要代码
@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var wechatAuthBack: HttpUtilsBack? var wechatPayBack: HttpUtilsBack? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { _ = WXApi.registerApp(StaticParam.WECHART_APPID)//appid字符串 return true } func application(_ application: UIApplication, handleOpen url: URL) -> Bool { switch url.scheme { case StaticParam.WECHART_APPID: _ = WXApi.handleOpen(url, delegate: self) default: print("handleOpenUrl1") } return true } func application(_ application: UIApplication, open url: URL , sourceApplication: String?, annotation: Any) -> Bool { switch url.scheme { case StaticParam.WECHART_APPID: _ = WXApi.handleOpen(url, delegate: self) default: print("handleOpenUrl2") } return true } } extension AppDelegate: WXApiDelegate { func onReq(_ req: BaseReq!) { } func onResp(_ resp: BaseResp!) { var code: String? var error: BaseError? if resp.isKind(of: SendAuthResp.self) { let authResp = resp as! SendAuthResp if authResp.errCode == 0 { code = authResp.code } else { error = BaseError(authResp.errStr) } } else if resp.isKind(of: PayResp.self) { let payResp = resp as! PayResp if payResp.errCode == 0 { code = payResp.returnKey } else { error = BaseError(payResp.errStr) } } if wechatAuthBack != nil { if error == nil && code == nil { error = "登录失败" } wechatAuthBack?.finish(result: code, error: error) } else if wechatPayBack != nil { if error == nil && code == nil { error = "支付失败" } wechatPayBack?.finish(result: code, error: error) } } } protocol HttpUtilsBack { func finish(result: String?, error: BaseError?) }
-
再贴上登录部分主要代码
let req = SendAuthReq() req.scope = "snsapi_userinfo" //获取用户信息 req.state = String(Date().timeIntervalSince1970) //随机值即可,这里用时间戳 WXApi.send(req)
-
贴上登录回调代码:
appDelegate?.wechatAuthBack = WechatAuthBack() //创建回调类 struct WechatAuthBack: HttpUtilsBack { func finish(result: String?, error: BaseError?) { if error == nil { //登录成功回调 } else { //登录失败回调 } } }
-
如果调用成功会回调onResp方法,后续在onResp内处理即可,处于安全考虑,建议用户信息解析给服务器端处理,这里直接将获取的信息上传至服务器即可
-
Android端:
-
引入jar包(在build.gradle文件内)
dependencies { api 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+' }
-
添加必要权限
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
登录相关代码
//初始化IWXAPI实例 IWXAPI api = WXAPIFactory.createWXAPI(activity, appId, true); api.registerApp(appId); //初始化登录请求对象 SendAuth.Req req = new SendAuth.Req(); req.scope = "snsapi_userinfo"; req.state = String.valueOf(System.currentTimeMillis()); //发送登录请求 api.sendReq(req); //最后记得在activity的onDestroy方法内取消注册IWXAPI对象 api.unregisterApp();
-
登录结果接收类
在{包名}.wxapi下创建WXEntryActivity类
-
本人写的代码(WXEntryActivity)如下:
import android.app.Activity; import android.os.Bundle; import android.util.Log; import com.tencent.mm.opensdk.constants.ConstantsAPI; import com.tencent.mm.opensdk.modelbase.BaseReq; import com.tencent.mm.opensdk.modelbase.BaseResp; import com.tencent.mm.opensdk.modelmsg.SendAuth; import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler; public class WXEntryActivity extends Activity implements IWXAPIEventHandler { public static final String APP_ID = "";//这里写自己的appid public static Back authBack; private IWXAPI api; public interface Back { public void onFiled(int errorCode); public void onSuccess(String code, String state); } public static void registAuthBack(Back back) { authBack = back; } public static void unregistAuthBack() { authBack = null; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); api = WXAPIFactory.createWXAPI(this, appId, true); api.handleIntent(this, this) } @Override public void onReq(BaseReq baseReq) { Log.e("-----1", "baseReq=" + baseReq); } @Override public void onResp(BaseResp baseResp) { switch (baseResp.getType()) { case ConstantsAPI.COMMAND_PAY_BY_WX: Log.e("-----1", "onPayFinish,errCode=" + baseResp.errCode); // 0:成功; -1:错误; -2:用户取消; break; case ConstantsAPI.COMMAND_SENDAUTH: Log.e("-----1", "onAuthFinish,errCode=" + baseResp.errCode); if (authBack != null) { // 0:成功; -1:错误; -2:用户取消; SendAuth.Resp authResp = (SendAuth.Resp) baseResp; if (authResp.errCode == 0) { authBack.onSuccess(authResp.code, authResp.state); } else { authBack.onFiled(baseResp.errCode); } } break; } finish(); } @Override protected void onDestroy() { super.onDestroy(); api.unregisterApp(); } }
-
记得在AndroidManifest.xml文件下注册此Activity时需使用如下格式(主要是确保有android:exported="true"属性):
<activity android:name=".wxapi.WXEntryActivity" android:exported="true" android:label="@string/app_name" />
相信大家也看到WXEntryActivity类下有个registAuthBack方法,传入了一个回调,这个就是当你调起微信登录后可以调用的,获取登录结果,返回的code字符串上传至服务器获取用户信息(也可以在客户端做,但是不安全,建议在服务器做)。
-
-
服务器端:
- 因为只是发送get请求然后解析结果,所以直接上2个工具类:
-
网络请求封装类:
import javax.net.ssl.HttpsURLConnection; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.Proxy; import java.net.URL; import java.util.HashMap; import java.util.List; import java.util.Map; public class HttpUtils { private String HTTPS = "https"; private String GET = "GET"; private String POST = "POST"; private static HttpUtils httpUtils; private HttpUtils() { } public static HttpUtils getInstance() { if (httpUtils == null) { httpUtils = new HttpUtils(); } return httpUtils; } public interface IWebCallback { void onCallback(int status, String message, Map<String, List<String>> heard, byte[] data); void onFail(int status, String message); } public byte[] getURLResponse(String urlString, HashMap<String, String> heads) { byte[] result = null; if (urlString != null) { HttpURLConnection conn = null; //连接对象 InputStream is = null; ByteArrayOutputStream baos = null; try { URL url = new URL(urlString); //URL对象 if (urlString.startsWith(HTTPS)) { conn = (HttpsURLConnection) url.openConnection(); } else { conn = (HttpURLConnection) url.openConnection(); } conn.setConnectTimeout(5 * 1000); conn.setDoOutput(true); conn.setRequestMethod(GET); if (heads != null) { for (String key : heads.keySet()) { conn.addRequestProperty(key, heads.get(key)); } } is = conn.getInputStream(); //获取输入流,此时才真正建立链接 baos = new ByteArrayOutputStream(); byte[] temp = new byte[1024]; int len; while ((len = is.read(temp)) != -1) { baos.write(temp, 0, len); } result = baos.toByteArray(); } catch (Exception e) { } finally { CloseUtils.closeSilently(is); CloseUtils.closeSilently(baos); if (conn != null) { conn.disconnect(); } } } return result; } public void getURLResponse(String urlString, HashMap<String, String> heads, IWebCallback iWebCallback) { getURLResponse(urlString, heads, null, iWebCallback); } public void getURLResponse(String urlString, HashMap<String, String> heads, Proxy proxy, IWebCallback iWebCallback) { if (urlString != null) { HttpURLConnection conn = null; //连接对象 InputStream is = null; ByteArrayOutputStream baos = null; try { URL url = new URL(urlString); //URL对象 if (proxy == null) { if (urlString.startsWith(HTTPS)) { conn = (HttpsURLConnection) url.openConnection(); } else { conn = (HttpURLConnection) url.openConnection(); } } else { if (urlString.startsWith(HTTPS)) { conn = (HttpsURLConnection) url.openConnection(proxy); } else { conn = (HttpURLConnection) url.openConnection(proxy); } } conn.setConnectTimeout(5 * 1000); conn.setDoOutput(true); conn.setRequestMethod(GET); if (heads != null) { for (String key : heads.keySet()) { conn.addRequestProperty(key, heads.get(key)); } } is = conn.getInputStream(); //获取输入流,此时才真正建立链接 baos = new ByteArrayOutputStream(); byte[] temp = new byte[1024]; int len; while ((len = is.read(temp)) != -1) { baos.write(temp, 0, len); } if (iWebCallback != null) { iWebCallback.onCallback(conn.getResponseCode(), conn.getResponseMessage(), conn.getHeaderFields(), baos.toByteArray()); } } catch (Exception e) { int code = 600; try { code = conn == null ? 600 : conn.getResponseCode(); } catch (Exception e1) { } if (iWebCallback != null) { iWebCallback.onFail(code, e.toString()); } } finally { CloseUtils.closeSilently(is); CloseUtils.closeSilently(baos); if (conn != null) { conn.disconnect(); } } } } public byte[] postURLResponse(String urlString, HashMap<String, String> headers, byte[] postData) { byte[] result = null; if (urlString != null) { HttpURLConnection conn = null; //连接对象 InputStream is = null; ByteArrayOutputStream baos = null; try { URL url = new URL(urlString); //URL对象 if (urlString.startsWith(HTTPS)) { conn = (HttpsURLConnection) url.openConnection(); } else { conn = (HttpURLConnection) url.openConnection(); } conn.setConnectTimeout(5 * 1000); conn.setDoOutput(true); conn.setRequestMethod(POST); //使用post请求 conn.setRequestProperty("Charsert", "UTF-8"); if (headers != null) { for (Map.Entry<String, String> temp : headers.entrySet()) { conn.setRequestProperty(temp.getKey(), temp.getValue()); } } conn.getOutputStream().write(postData); is = conn.getInputStream(); //获取输入流,此时才真正建立链接 baos = new ByteArrayOutputStream(); byte[] temp = new byte[1024]; int len; while ((len = is.read(temp)) != -1) { baos.write(temp, 0, len); } result = baos.toByteArray(); } catch (Exception e) { } finally { CloseUtils.closeSilently(is); CloseUtils.closeSilently(baos); if (conn != null) { conn.disconnect(); } } } return result; } public void postURLResponse(String urlString, HashMap<String, String> headers, byte[] postData, IWebCallback iWebCallback) { if (urlString != null) { HttpURLConnection conn = null; //连接对象 InputStream is = null; ByteArrayOutputStream baos = null; try { URL url = new URL(urlString); //URL对象 if (urlString.startsWith(HTTPS)) { conn = (HttpsURLConnection) url.openConnection(); } else { conn = (HttpURLConnection) url.openConnection(); } conn.setConnectTimeout(5 * 1000); conn.setDoOutput(true); conn.setRequestMethod(POST); //使用post请求 conn.setRequestProperty("Charsert", "UTF-8"); if (headers != null) { for (Map.Entry<String, String> temp : headers.entrySet()) { conn.setRequestProperty(temp.getKey(), temp.getValue()); } } conn.getOutputStream().write(postData); is = conn.getInputStream(); //获取输入流,此时才真正建立链接 baos = new ByteArrayOutputStream(); byte[] temp = new byte[1024]; int len; while ((len = is.read(temp)) != -1) { baos.write(temp, 0, len); } if (iWebCallback != null) { iWebCallback.onCallback(conn.getResponseCode(), conn.getResponseMessage(), conn.getHeaderFields(), baos.toByteArray()); } } catch (Exception e) { int code = 600; try { code = conn == null ? 600 : conn.getResponseCode(); } catch (Exception e1) { } if (iWebCallback != null) { iWebCallback.onFail(code, e.toString()); } } finally { CloseUtils.closeSilently(is); CloseUtils.closeSilently(baos); if (conn != null) { conn.disconnect(); } } } } }
-
用于解析支付订单查询返回信息解析
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; @JacksonXmlRootElement(localName = "xml") public class WXPayResponse { @JacksonXmlProperty(localName = "return_code") private String returnCode;//返回码 @JacksonXmlProperty(localName = "return_msg") private String returnMsg;//返回信息 @JacksonXmlProperty(localName = "appid") private String appid;//appid @JacksonXmlProperty(localName = "mch_id") private String mchId;//商户号 @JacksonXmlProperty(localName = "nonce_str") private String nonceStr;//随机字符串 @JacksonXmlProperty(localName = "sign") private String sign;//签名 @JacksonXmlProperty(localName = "result_code") private String resultCode;//业务结果 @JacksonXmlProperty(localName = "err_code") private String errCode;//错误代码 @JacksonXmlProperty(localName = "err_code_des") private String errCodeDes;//错误代码描述 @JacksonXmlProperty(localName = "device_info") private String deviceInfo;//设备号 @JacksonXmlProperty(localName = "openid") private String openid;//用户标识 @JacksonXmlProperty(localName = "is_subscribe") private String isSubscribe;//是否关注公众账号 @JacksonXmlProperty(localName = "trade_type") private String tradeType;//交易类型 @JacksonXmlProperty(localName = "trade_state") private String tradeState;//交易状态 @JacksonXmlProperty(localName = "bank_type") private String bankType;//付款银行 @JacksonXmlProperty(localName = "total_fee") private String totalFee;//总金额 @JacksonXmlProperty(localName = "fee_type") private String feeType;//货币种类 @JacksonXmlProperty(localName = "cash_fee") private String cashFee;//现金支付金额 @JacksonXmlProperty(localName = "cash_fee_type") private String cashFeeType;//现金支付货币类型 @JacksonXmlProperty(localName = "settlement_total_fee") private String settlementTotalFee;//应结订单金额 @JacksonXmlProperty(localName = "coupon_fee") private String couponFee;//代金券金额 @JacksonXmlProperty(localName = "coupon_count") private String couponCount;//代金券使用数量 @JacksonXmlProperty(localName = "transaction_id") private String transactionId;//微信支付订单号 @JacksonXmlProperty(localName = "out_trade_no") private String outTradeNo;//商户订单号 @JacksonXmlProperty(localName = "attach") private String attach;//附加数据 @JacksonXmlProperty(localName = "time_end") private String timeEnd;//支付完成时间 @JacksonXmlProperty(localName = "trade_state_desc") private String tradeStateDesc;//交易状态描述 public String getReturnCode() { return returnCode; } public void setReturnCode(String returnCode) { this.returnCode = returnCode; } public String getReturnMsg() { return returnMsg; } public void setReturnMsg(String returnMsg) { this.returnMsg = returnMsg; } public String getAppid() { return appid; } public void setAppid(String appid) { this.appid = appid; } public String getMchId() { return mchId; } public void setMchId(String mchId) { this.mchId = mchId; } public String getNonceStr() { return nonceStr; } public void setNonceStr(String nonceStr) { this.nonceStr = nonceStr; } public String getSign() { return sign; } public void setSign(String sign) { this.sign = sign; } public String getResultCode() { return resultCode; } public void setResultCode(String resultCode) { this.resultCode = resultCode; } public String getErrCode() { return errCode; } public void setErrCode(String errCode) { this.errCode = errCode; } public String getErrCodeDes() { return errCodeDes; } public void setErrCodeDes(String errCodeDes) { this.errCodeDes = errCodeDes; } public String getDeviceInfo() { return deviceInfo; } public void setDeviceInfo(String deviceInfo) { this.deviceInfo = deviceInfo; } public String getOpenid() { return openid; } public void setOpenid(String openid) { this.openid = openid; } public String getIsSubscribe() { return isSubscribe; } public void setIsSubscribe(String isSubscribe) { this.isSubscribe = isSubscribe; } public String getTradeType() { return tradeType; } public void setTradeType(String tradeType) { this.tradeType = tradeType; } public String getTradeState() { return tradeState; } public void setTradeState(String tradeState) { this.tradeState = tradeState; } public String getBankType() { return bankType; } public void setBankType(String bankType) { this.bankType = bankType; } public String getTotalFee() { return totalFee; } public void setTotalFee(String totalFee) { this.totalFee = totalFee; } public String getFeeType() { return feeType; } public void setFeeType(String feeType) { this.feeType = feeType; } public String getCashFee() { return cashFee; } public void setCashFee(String cashFee) { this.cashFee = cashFee; } public String getCashFeeType() { return cashFeeType; } public void setCashFeeType(String cashFeeType) { this.cashFeeType = cashFeeType; } public String getSettlementTotalFee() { return settlementTotalFee; } public void setSettlementTotalFee(String settlementTotalFee) { this.settlementTotalFee = settlementTotalFee; } public String getCouponFee() { return couponFee; } public void setCouponFee(String couponFee) { this.couponFee = couponFee; } public String getCouponCount() { return couponCount; } public void setCouponCount(String couponCount) { this.couponCount = couponCount; } public String getTransactionId() { return transactionId; } public void setTransactionId(String transactionId) { this.transactionId = transactionId; } public String getOutTradeNo() { return outTradeNo; } public void setOutTradeNo(String outTradeNo) { this.outTradeNo = outTradeNo; } public String getAttach() { return attach; } public void setAttach(String attach) { this.attach = attach; } public String getTimeEnd() { return timeEnd; } public void setTimeEnd(String timeEnd) { this.timeEnd = timeEnd; } public String getTradeStateDesc() { return tradeStateDesc; } public void setTradeStateDesc(String tradeStateDesc) { this.tradeStateDesc = tradeStateDesc; } @Override public String toString() { return "WXPayResponse{" + "returnCode='" + returnCode + '\'' + ", returnMsg='" + returnMsg + '\'' + ", appid='" + appid + '\'' + ", mchId='" + mchId + '\'' + ", nonceStr='" + nonceStr + '\'' + ", sign='" + sign + '\'' + ", resultCode='" + resultCode + '\'' + ", errCode='" + errCode + '\'' + ", errCodeDes='" + errCodeDes + '\'' + ", deviceInfo='" + deviceInfo + '\'' + ", openid='" + openid + '\'' + ", isSubscribe='" + isSubscribe + '\'' + ", tradeType='" + tradeType + '\'' + ", tradeState='" + tradeState + '\'' + ", bankType='" + bankType + '\'' + ", totalFee='" + totalFee + '\'' + ", feeType='" + feeType + '\'' + ", cashFee='" + cashFee + '\'' + ", cashFeeType='" + cashFeeType + '\'' + ", settlementTotalFee='" + settlementTotalFee + '\'' + ", couponFee='" + couponFee + '\'' + ", couponCount='" + couponCount + '\'' + ", transactionId='" + transactionId + '\'' + ", outTradeNo='" + outTradeNo + '\'' + ", attach='" + attach + '\'' + ", timeEnd='" + timeEnd + '\'' + ", tradeStateDesc='" + tradeStateDesc + '\'' + '}'; } }
-
解析微信登录支付签名返回对象
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; @JacksonXmlRootElement(localName = "xml") public class WXResponse { @JacksonXmlProperty(localName = "return_code") private String returnCode;//返回码 @JacksonXmlProperty(localName = "return_msg") private String returnMsg;//返回信息 @JacksonXmlProperty(localName = "appid") private String appid;//appid @JacksonXmlProperty(localName = "mch_id") private String mchId;//商户号 @JacksonXmlProperty(localName = "nonce_str") private String nonceStr;//随机字符串 @JacksonXmlProperty(localName = "sign") private String sign;//签名 @JacksonXmlProperty(localName = "result_code") private String resultCode;//结果码 @JacksonXmlProperty(localName = "err_code") private String errCode;//错误码 @JacksonXmlProperty(localName = "err_code_des") private String errCodeDes;//错误描述 @JacksonXmlProperty(localName = "prepay_id") private String prepayId;//支付id @JacksonXmlProperty(localName = "trade_type") private String tradeType;//支付类型 @JacksonXmlProperty(localName = "device_info") private String deviceInfo;//设备信息 public String getReturnCode() { return returnCode; } public void setReturnCode(String returnCode) { this.returnCode = returnCode; } public String getReturnMsg() { return returnMsg; } public void setReturnMsg(String returnMsg) { this.returnMsg = returnMsg; } public String getAppid() { return appid; } public void setAppid(String appid) { this.appid = appid; } public String getMchId() { return mchId; } public void setMchId(String mchId) { this.mchId = mchId; } public String getNonceStr() { return nonceStr; } public void setNonceStr(String nonceStr) { this.nonceStr = nonceStr; } public String getSign() { return sign; } public void setSign(String sign) { this.sign = sign; } public String getResultCode() { return resultCode; } public void setResultCode(String resultCode) { this.resultCode = resultCode; } public String getErrCode() { return errCode; } public void setErrCode(String errCode) { this.errCode = errCode; } public String getErrCodeDes() { return errCodeDes; } public void setErrCodeDes(String errCodeDes) { this.errCodeDes = errCodeDes; } public String getPrepayId() { return prepayId; } public void setPrepayId(String prepayId) { this.prepayId = prepayId; } public String getTradeType() { return tradeType; } public void setTradeType(String tradeType) { this.tradeType = tradeType; } public String getDeviceInfo() { return deviceInfo; } public void setDeviceInfo(String deviceInfo) { this.deviceInfo = deviceInfo; } @Override public String toString() { return "WXResponse{" + "returnCode='" + returnCode + '\'' + ", returnMsg='" + returnMsg + '\'' + ", appid='" + appid + '\'' + ", mchId='" + mchId + '\'' + ", nonceStr='" + nonceStr + '\'' + ", sign='" + sign + '\'' + ", resultCode='" + resultCode + '\'' + ", errCode='" + errCode + '\'' + ", errCodeDes='" + errCodeDes + '\'' + ", prepayId='" + prepayId + '\'' + ", tradeType='" + tradeType + '\'' + ", deviceInfo='" + deviceInfo + '\'' + '}'; } }
-
用于返回给客户端
public class ResponseWX { private String appid; private String partnerid; private String noncestr; private String packageName; private String prepayid; private String timestamp; private String sign; private String orderNumber; public String getAppid() { return appid; } public void setAppid(String appid) { this.appid = appid; } public String getPartnerid() { return partnerid; } public void setPartnerid(String partnerid) { this.partnerid = partnerid; } public String getNoncestr() { return noncestr; } public void setNoncestr(String noncestr) { this.noncestr = noncestr; } public String getPackageName() { return packageName; } public void setPackageName(String packageName) { this.packageName = packageName; } public String getPrepayid() { return prepayid; } public void setPrepayid(String prepayid) { this.prepayid = prepayid; } public String getTimestamp() { return timestamp; } public void setTimestamp(String timestamp) { this.timestamp = timestamp; } public String getSign() { return sign; } public void setSign(String sign) { this.sign = sign; } public String getOrderNumber() { return orderNumber; } public void setOrderNumber(String orderNumber) { this.orderNumber = orderNumber; } @Override public String toString() { return "ResponseWX{" + "appid='" + appid + '\'' + ", partnerid='" + partnerid + '\'' + ", noncestr='" + noncestr + '\'' + ", packageName='" + packageName + '\'' + ", prepayid='" + prepayid + '\'' + ", timestamp='" + timestamp + '\'' + ", sign='" + sign + '\'' + ", orderNumber='" + orderNumber + '\'' + '}'; } }
关键工具类
-
- 因为只是发送get请求然后解析结果,所以直接上2个工具类:
import com.alibaba.fastjson.JSON;
import java.util.*;
public class WechartUtils {
private static final String APP_ID = "";//应用ID
private static final String CT_NUMBER = "";//商户号
private static final String SECRET = "";//这些都能从官方文档获取
private static final String KEY = "";//
private static final String GET_ACCESS_TOKEN = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="
+ APP_ID + "&secret=" + SECRET + "&code=%s&grant_type=authorization_code";
private static final String GET_USER_INFO = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s";
private static final String GET_FIRST_ORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";
private static final String GET_ORDER = "https://api.mch.weixin.qq.com/pay/orderquery";
public static boolean checkWXOrder(String orderNumber) {
SortedMap<String, String> temp = new TreeMap<String, String>() {
{
put("appid", APP_ID);//应用ID
put("mch_id", CT_NUMBER);//商户号
put("nonce_str", MD5Utils.MD5(String.valueOf(System.currentTimeMillis()), false));//随机字符串
put("out_trade_no", orderNumber);//商户订单号
}
};
temp.put("sign", getSign(temp));
String xml = getXml(temp);
byte[] result = HttpUtils.getInstance().postURLResponse(GET_ORDER, null, xml.getBytes());
WXPayResponse wxPayResponse = XMLUtils.getObject(new String(result), WXPayResponse.class);
return wxPayResponse != null && "SUCCESS".equals(wxPayResponse.getReturnCode())
&& "SUCCESS".equals(wxPayResponse.getResultCode())
&& "SUCCESS".equals(wxPayResponse.getTradeState());
}
public static ResponseWX getWXResponse(String goodsName, String goodsDesc
, String orderNumber, String price, String ip) throws Exception {
SortedMap<String, String> temp = new TreeMap<String, String>() {
{
put("appid", APP_ID);//应用ID
put("mch_id", CT_NUMBER);//商户号
put("nonce_str", MD5Utils.MD5(String.valueOf(System.currentTimeMillis()), false));//随机字符串
put("body", goodsName);//商品描述
put("attach", goodsDesc);//附加数据
put("out_trade_no", orderNumber);//商户订单号
put("total_fee", price);//总金额
put("spbill_create_ip", ip);//终端IP
put("notify_url", "");//这里填写自己的回调通知地址
put("trade_type", "APP");//交易类型
}
};
temp.put("sign", getSign(temp));
String xml = getXml(temp);
byte[] result = HttpUtils.getInstance().postURLResponse(GET_FIRST_ORDER, null, xml.getBytes());
WXResponse response = XMLUtils.getObject(new String(result), WXResponse.class);
if (response != null && "SUCCESS".equals(response.getReturnCode())
&& "SUCCESS".equals(response.getResultCode())
&& response.getPrepayId() != null) {
ResponseWX responseWX = new ResponseWX();
responseWX.setAppid(response.getAppid());
responseWX.setNoncestr(response.getNonceStr());
responseWX.setPackageName("Sign=WXPay");
responseWX.setPartnerid(response.getMchId());
responseWX.setTimestamp(String.valueOf(System.currentTimeMillis() / 1000));
responseWX.setPrepayid(response.getPrepayId());
responseWX.setSign(getSign(new TreeMap<String, String>() {
{
put("appid", responseWX.getAppid());//应用ID
put("partnerid", responseWX.getPartnerid());//商户号
put("noncestr", responseWX.getNoncestr());//商品描述
put("package", responseWX.getPackageName());//随机字符串
put("prepayid", responseWX.getPrepayid());//商户订单号
put("timestamp", responseWX.getTimestamp());//附加数据
}
}));
responseWX.setOrderNumber(orderNumber);
return responseWX;
}
throw new Exception("签名失败");
}
private static String getXml(SortedMap<String, String> data) {
StringBuilder result = new StringBuilder("<xml>");
for (Map.Entry<String, String> kv : data.entrySet()) {
result.append("<").append(kv.getKey()).append(">").append(kv.getValue())
.append("</").append(kv.getKey()).append(">");
}
return result.append("</xml>").toString();
}
private static String getSign(SortedMap<String, String> data) {
String result = null;
if (data != null) {
StringBuilder key = new StringBuilder();
boolean isFirst = true;
for (Map.Entry<String, String> kv : data.entrySet()) {
if (isFirst) {
isFirst = false;
} else {
key.append("&");
}
key.append(kv.getKey());
key.append("=");
key.append(kv.getValue());
}
key.append("&key=").append(KEY);
return MD5Utils.MD5(key.toString(), false).toUpperCase();
}
return result;
}
public static WechartUserResponse getUser(String authCode) {
WechartUserResponse result = null;
String host = String.format(GET_ACCESS_TOKEN, authCode);
byte[] response = HttpUtils.getInstance().getURLResponse(host, null);
if (response != null) {
AccessTokenResponse accessTokenResponse;
try {
accessTokenResponse = JSON.parseObject(new String(response), AccessTokenResponse.class);
} catch (Exception e) {
System.out.println("Format response error.e=" + e + ";response=" + new String(response));
return result;
}
if (accessTokenResponse != null && accessTokenResponse.accessToken != null) {
response = HttpUtils.getInstance().getURLResponse(host, null);
if (response != null) {
host = String.format(GET_USER_INFO, accessTokenResponse.accessToken, accessTokenResponse.openid);
response = HttpUtils.getInstance().getURLResponse(host, null);
try {
result = JSON.parseObject(new String(response), WechartUserResponse.class);
if (result.unionid == null) {
System.out.println("Get user info error." + ";response=" + new String(response));
result = null;
}
} catch (Exception e) {
System.out.println("Format response error.e=" + e + ";response=" + new String(response));
}
}
}
}
return result;
}
public static class WechartUserResponse {
private String openid;
private String nickname;
private int sex;
private String language;
private String city;
private String province;
private String country;
private String headimgurl;
private String unionid;
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getHeadimgurl() {
return headimgurl;
}
public void setHeadimgurl(String headimgurl) {
this.headimgurl = headimgurl;
}
public String getUnionid() {
return unionid;
}
public void setUnionid(String unionid) {
this.unionid = unionid;
}
@Override
public String toString() {
return "WechartUserResponse{" +
"openid='" + openid + '\'' +
", nickname='" + nickname + '\'' +
", sex=" + sex +
", language='" + language + '\'' +
", city='" + city + '\'' +
", province='" + province + '\'' +
", country='" + country + '\'' +
", headimgurl='" + headimgurl + '\'' +
", unionid='" + unionid + '\'' +
'}';
}
}
private static class AccessTokenResponse {
private String accessToken;
private int expiresIn;
private String refreshToken;
private String openid;
private String scope;
private String unionid;
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public int getExpiresIn() {
return expiresIn;
}
public void setExpiresIn(int expiresIn) {
this.expiresIn = expiresIn;
}
public String getRefreshToken() {
return refreshToken;
}
public void setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
public String getUnionid() {
return unionid;
}
public void setUnionid(String unionid) {
this.unionid = unionid;
}
}
}
因为中间用了xml解析,所以需要导入"com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.9.5" 的jar包,这里为gradle导入
最后服务器端只需要开接口接收客户端传递的code,然后调用getUser()方法返回用户对象。
至此微信登录对接就完成了,如果还有其他问题或者觉得不对的地方可以评论提出。