開發工具
前端 | 微信小程序開發工具 |
---|---|
後端 | idea 2018.3 +mysql8.0 |
後端技術棧 ----Springboot+mybatis
ps:因爲我是後端開發 所以只能寫後端。。
開發階段
一 準備賬號
郵箱註冊微信公衆平臺小程序 !!! 着重強調 是小程序註冊 !!!
註冊鏈接:微信公衆平臺
註冊完成之後 ,在開發-開發設置裏邊可以看到appid和secret,註冊的目的就是爲了獲取這兩個參數,以爲了向微信服務器發送請求
二 準備域名
因爲微信平臺的要求,需要用http:或者https:開頭的合法域名,我這裏採用的是natapp 購買的隧道,類似於服務器+域名(9RMB一個月,作爲調試開發還是可以的) ,然後將域名配置到微信的開發-開發設置裏邊
這裏需要注意的是:前端訪問的域名不能是服務器ip+端口號+接口名的方式,是要以這個request合法域名+接口名發送請求,否則請求不能發送到微信服務器端
三 代碼實現
因爲前端的同學跟我是第一次開發微信小程序,登錄獲取用戶授權頁面有點簡陋,就不發wxml了(微信版html)
前端js代碼
// pages/indxe/login/login.js
Page({
/**
* 頁面的初始數據
*/
data: {
},
getUserInfoBtn:function(){
wx.login({
success:function(data){
var code=data.code
wx.getUserInfo({
success:function(res){
var userInfor=res
var rawData=res.rawData
var iv=res.iv
var encryptedData = res.encryptedData
console.log(encryptedData)
wx.request({
url:'//微信要求的合法域名+後端請求接口'
data: {
iv: iv,
encryptedData: encryptedData,
code: code
},
header: {
'content-type': 'application/json' //默認值
},
success: function (res) {
console.log(res.data)
}
})
}
})
}
})
},
/**
* 生命週期函數--監聽頁面加載
*/
onLoad: function (options) {
},
/**
* 生命週期函數--監聽頁面初次渲染完成
*/
onReady: function () {
},
/**
* 生命週期函數--監聽頁面顯示
*/
onShow: function () {
},
/**
* 生命週期函數--監聽頁面隱藏
*/
onHide: function () {
},
/**
* 生命週期函數--監聽頁面卸載
*/
onUnload: function () {
},
/**
* 頁面相關事件處理函數--監聽用戶下拉動作
*/
onPullDownRefresh: function () {
http://wechatapptest.natapp1.cc/takeaway/user/login',
},
/**
* 頁面上拉觸底事件的處理函數
*/
onReachBottom: function () {
},
/**
* 用戶點擊右上角分享
*/
onShareAppMessage: function () {
}
})
後端yml文件配置
spring:
datasource:
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/takeaway_applet?useSSL=false&characterEncoding=utf-8
type: com.alibaba.druid.pool.DruidDataSource
druid:
# 初始化大小,最小,最大
initial-size: 5
min-idle: 5
max-active: 50
# 獲取連接等待超時的時間
max-wait: 60000
# 配置間隔多久才進行一次檢測,檢測需要關閉的空閒連接,單位是毫秒
time-between-eviction-runs-millis: 60000
# 配置一個連接在池中最小生存的時間,單位是毫秒
min-evictable-idle-time-millis: 300000
mybatis:
mapper-locations: classpath:mappers/*.xml
type-aliases-package: com.swpu.uchain.takeawayapplet.entity
configuration:
map-underscore-to-camel-case: true
use-generated-keys: true
file:
upload-dir: "/home/hobo/testFile"
#微信端配置
wechat:
appid: wx08cbe6a7723b4059
secret: 184d33fb3de278d49a1411cd111eeaa2
配置文件對應類
/**
* @ClassName WeChatAccountConfig
* @Author hobo
* @Date 19-3-8 下午9:49
* @Description
**/
@Data
@ConfigurationProperties(prefix = "wechat")
@Component
public class WeChatProperties {
/**
* 微信小程序appId
*/
private String appid;
/**
* 微信小程序的Secret
*/
private String secret;
/**
* 微信小程序消息服務器配置的token
*/
private String token;
/**
* 設置微信小程序消息服務器配置的EncodingAESKey
*/
private String aesKey;
/**
* 消息格式,XML或者JSON
*/
private String msgDataFormat;
/**
* 開放平臺id
*/
private String openAppId;
/***
* 開放平臺祕鑰
*/
private String openAppSecret;
/**
* 商戶號
*/
private String mchId;
/**
* 商戶密鑰
*/
private String mchKey;
/**
* 商戶證書路徑
*/
private String keyPath;
/**
* 微信異步通知地址
*/
private String notifyUrl;
/**
* 商品簡單描述
*/
private String title;
/**
* 支付類型 小程序爲JSAPI
*/
private String tradeType;
}
WXController
PS: 微信小程序登錄分爲兩種,一種是前端在發送登錄請求時,隨機發送code,不需要用戶授權,這種方式只獲得用戶的openId,另一種方式是從微信端發來iv,encryptedData,code。後端經過算法解密處理得到用戶的一些信息,包括微信暱稱及頭像等等,我這次是採用了後者。根據前端代碼大家也可以看出前端是傳了這三個參數的。
@ApiOperation("普通用戶登錄授權接口")
@GetMapping(value = "/login", name = "普通用戶登錄")
public Object getUserInfo(String encryptedData, String iv, String code) {
Map map = new HashMap();
if (code == null) {
return ResultUtil.error(ResultEnum.CODE_EMPTY);
}
//微信登錄請求URL
String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + weChatProperties.getAppid() + "&secret=" + weChatProperties.getSecret() + "&js_code=" + code + "&grant_type=authorization_code";
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.getForObject(url, String.class);
//將Json對象轉換爲Java對象
WeChatVO weChatVO = JSONObject.parseObject(response, WeChatVO.class);
String openId = weChatVO.getOpenId();
String sessionKey = weChatVO.getSessionKey();
//解密用戶信息
String result = AesCbcUtil.decrypt(encryptedData, sessionKey, iv, "UTF-8");
if (null != result && result.length() > 0) {
//ResultUtil是我自定義的Json化工具類
return ResultUtil.success(result);
}
return ResultUtil.error(ResultEnum.DECRYPTION_FAILURE);
}
解密工具類
需要引入bcprov-ext-jdk16的依賴
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-ext-jdk16</artifactId>
<version>1.46</version>
<type>jar</type>
</dependency>
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.spec.InvalidParameterSpecException;
/**
* @ClassName AesCbcUtil
* @Author hobo
* @Date 19-3-15 下午3:15
* @Description 用於用戶解密
**/
public class AesCbcUtil {
static {
Security.addProvider(new BouncyCastleProvider());
}
/**
* @return java.security.Security
* @Author hobo
* @Description : AES解密
* @Param data //密文 加密的數據
* @Param key //祕鑰
* @Param iv //偏移量
* @Param encodingFormat //解密後結果的編碼格式
**/
public static String decrypt(String data, String key, String iv, String encodingFormat) {
byte[] dataByte = Base64.decodeBase64(data);
byte[] keyByte = Base64.decodeBase64(key);
byte[] ivByte = Base64.decodeBase64(iv);
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
parameters.init(new IvParameterSpec(ivByte));
cipher.init(Cipher.DECRYPT_MODE, spec, parameters);
byte[] resultByte = cipher.doFinal(dataByte);
if (null != resultByte && resultByte.length > 0) {
String result = new String(resultByte, encodingFormat);
return result;
}
return null;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidParameterSpecException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
}
效果展示
{"openId":"oFVAK4_iFtKuKDMpzEfAfjeI6ysQ","nickName":"菜逼玉","gender":1,"language":"zh_CN","city":"Chengdu","province":"Sichuan","country":"China","avatarUrl":"https://wx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTL94p6V7YgKUP2r9X4mLibwblyib3YAicRG54qAw2EEz0dO2ibMBLSnMqcm2CichAd3yZ36ZjBbMAdh7Wg/132","watermark":{"timestamp":1553434671,"appid":"wx08cbe6a7723b4059"}}
可以看到 我的微信的個人信息已經獲得
四 小白踩坑記錄
github上邊有sdk可以用微信開發者聯盟,但發現自己能力不足,只能用原生的方法。
大家在開發前一定要看小程序開發Api,不然會踩大坑。
新人第一篇博客 QQ:1056024860 敬候志同道合的同學跟我一起探討微信開發