基于websocket實(shí)現(xiàn)掃描小程序碼登錄web頁(yè)面和微信小程序(雙端登錄)

SpringBoot+WebSocket+Redis控制二維碼失效時(shí)間

類似于騰訊文檔網(wǎng)頁(yè)版掃描小程序碼登錄的模式

騰訊文檔采用的是輪詢的方式,我在這里采用websocket的方式.

這里運(yùn)用了github上基于微信SDK的更易用的SDK weixin-java-miniapp

第一步:導(dǎo)入需要的maven依賴



<!--springboot整合了websocket-->

? <dependency>

? ? ? ? ? ? <groupId>org.springframework.boot</groupId>

? ? ? ? ? ? <artifactId>spring-boot-starter-websocket</artifactId>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>com.github.binarywang</groupId>

? ? ? ? ? ? <artifactId>weixin-java-miniapp</artifactId>

? ? ? ? ? ? <version>3.3.0</version>

? ? ? ? </dependency>

第二步:配置websocket



@Configuration

public class WebSocketConfig {

? ? @Bean

? ? public ServerEndpointExporter serverEndpointExporter(){

? ? ? ? return new ServerEndpointExporter();

? ? }

}

這里的socketKey對(duì)應(yīng)@PathParam定義的名字,用來(lái)識(shí)別唯一的socket連接


@Component

@ServerEndpoint(value = "/socketLogin/{socketKey}")

public class LoginSocket {

? ? private static Logger log= LoggerFactory.getLogger(LoginSocket.class);

? ? private static ConcurrentHashMap<String, Session> sessionMap = new ConcurrentHashMap<>();

? ? private Session session;

? ? /**

? ? * 連接建立成功調(diào)用的方法*/

? ? @OnOpen

? ? public void onOpen(Session session, @PathParam("socketKey")String socketKey) {

? ? ? ? this.session=session;

? ? ? ? log.info("[微信小程序websocket]socketKey:{}",socketKey +"-->建立連接");

? ? ? ? sessionMap.put(socketKey,session);

? ? }

? ? /**

? ? * 連接關(guān)閉調(diào)用的方法

? ? */

? ? @OnClose

? ? public void onClose(@PathParam("socketKey") String socketKey) {

? ? ? ? log.info("[微信小程序websocket]socketKey:{}",socketKey +"-->斷開(kāi)連接");

? ? ? ? sessionMap.remove(socketKey);

? ? }

? ? public ConcurrentHashMap<String, Session> getSessionMap() {

? ? ? ? return sessionMap;

? ? }

}

第三步:完成socket配置后,正式開(kāi)始微信小程序開(kāi)發(fā)

開(kāi)發(fā)之前需要準(zhǔn)備好申請(qǐng)的小程序APPID SECRET

編寫工具類(整合weixin-java-miniapp),這個(gè)工具類根據(jù)自身需求,靈活設(shè)置WxMaInMemoryConfig里面的內(nèi)容



@Configuration

public class WxMaConfiguration {

? ? private static String appId;

? ? private static String secret;

? ? @Value("${weixin.applet_appid}")

? ? public void setAppId(String appId) {

? ? ? ? WxMaConfiguration.appId = appId;

? ? }

? ? @Value("${weixin.applet_secret}")

? ? public void setSecret(String secret) {

? ? ? ? WxMaConfiguration.secret = secret;

? ? }

? ? private static WxMaService wxMaService=null;

? ? @Bean

? ? public Object services(){

? ? ? ? WxMaInMemoryConfig config = new WxMaInMemoryConfig();

? ? ? ? config.setAppid(appId);

? ? ? ? config.setSecret(secret);

? ? ? ? wxMaService = new WxMaServiceImpl();

? ? ? ? wxMaService.setWxMaConfig(config);

? ? ? ? return Boolean.TRUE;

? ? }

? ? public static WxMaService getWxMaService(){

? ? ? ? return wxMaService;

? ? }

}

第四步:網(wǎng)頁(yè)端獲取小程序二維碼接口

建議小程序二維碼里面的scene參數(shù)和建立websocket連接的key保持一致

pathStr:小程序登錄成功后微信小程序的跳轉(zhuǎn)地址,而不是網(wǎng)頁(yè)的跳轉(zhuǎn)地址.如:pages/index/index

注意此處:3.3.0之前版本的 weixin-java-miniapp無(wú)法通過(guò)createWxaCodeUnlimitBytes返回byte字節(jié),返回的都是File文件


/**

? ? * 獲取微信小程序帶參數(shù)的二維碼

? ? *

? ? * @return

? ? */

? ? @RequestMapping("/getAppletQrCode")

? ? public void getAppletCode(@RequestParam("sceneStr") String sceneStr, @RequestParam("pathStr") String pathStr, HttpServletResponse response) {

? ? ? ? logger.info("[微信小程序]獲取微信小程序二維碼,參數(shù)->sceneStr:"+sceneStr+", pathStr:"+pathStr);

? ? ? ? WxMaService wxMaService = WxMaConfiguration.getWxMaService();

? ? ? ? // 獲取小程序二維碼生成實(shí)例

? ? ? ? WxMaQrcodeService wxMaQrcodeService = wxMaService.getQrcodeService();

? ? ? ? // 設(shè)置小程序二維碼線條顏色為黑色

? ? ? ? WxMaCodeLineColor lineColor = new WxMaCodeLineColor("0", "0", "0");

? ? ? ? // 生成二維碼圖片字節(jié)流?

? ? ? ? byte[] qrCodeBytes = null;

? ? ? ? try {

? ? ? ? ? ? qrCodeBytes = wxMaQrcodeService.createWxaCodeUnlimitBytes(sceneStr, pathStr, 430, false, lineColor, false);

? ? ? ? ? ? //設(shè)置二維碼180s失效

? ? ? ? ? ? redisUtils.setex("qrcode:"+sceneStr,3*60,sceneStr);

? ? ? ? } catch (Exception e) {

? ? ? ? ? ? logger.error("[微信小程序]生成小程序碼出現(xiàn)異常:{}",e);

? ? ? ? }

? ? ? ? response.setContentType("image/png");

? ? ? ? //寫入response的輸出流中

? ? ? ? try {

? ? ? ? ? ? OutputStream outputStream = response.getOutputStream();

? ? ? ? ? ? outputStream.write(Base64.encodeBase64(qrCodeBytes));

? ? ? ? ? ? outputStream.flush();

? ? ? ? ? ? outputStream.close();

? ? ? ? } catch (Exception e) {

? ? ? ? ? ? logger.error("[微信小程序]輸出流寫出小程序碼出現(xiàn)異常:{}",e);

? ? ? ? }

? ? }

第五步:小程序登錄接口,對(duì)于前端來(lái)說(shuō)以上接口都在網(wǎng)頁(yè)端調(diào)取,而此接口在小程序端調(diào)取,要做好兼容



/**

? ? * 初次未授權(quán)登錄

? ? * 微信小程序授權(quán)登錄

? ? *

? ? * @param code

? ? * @return https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code

? ? */

? ? @RequestMapping("/weChatAppletLogin")

? ? @ResponseBody

? ? public ResultBean weChatAuthLogin(@RequestParam("code") String code, @RequestParam("encryptedData") String encryptedData, @RequestParam("ivStr") String ivStr, @RequestParam("nickname") String nickname, @RequestParam("headurl") String headurl, @RequestParam("socketKey") String socketKey,HttpServletResponse response) {

? ? ? ? logger.info("[微信小程序]微信小程序和網(wǎng)頁(yè)端登錄,參數(shù)->code:"+code+", encryptedData:"+encryptedData+", nickname:"+nickname+", headurl:"+headurl+", socketKey:"+socketKey);

? ? ? ? if (StringUtils.isBlank(code)) {

? ? ? ? ? ? return ResultBean.setError(1, "code碼為空");

? ? ? ? }

? ? ? ? //微信接口參數(shù)

? ? ? ? Map<String, String> params = new HashMap<>();

? ? ? ? params.put("appid", APPLET_APPID);

? ? ? ? params.put("secret", APPLET_SECRET);

? ? ? ? params.put("js_code", code);

? ? ? ? params.put("grant_type", "authorization_code");

? ? ? ? try {

? ? ? ? ? ? String wxResult = HttpUtil.doGet(APPLET_URL, params);

? ? ? ? ? ? JSONObject jsonObject = JSONObject.parseObject(wxResult);

? ? ? ? ? ? if (jsonObject.get("errcode") != null && StringUtils.equalsIgnoreCase(jsonObject.get("errcode").toString(), "40163")) {

? ? ? ? ? ? ? ? return ResultBean.setError(1, "code碼失效");

? ? ? ? ? ? }

? ? ? ? ? ? String session_key = jsonObject.get("session_key").toString();

? ? ? ? ? ? //第一次登錄沒(méi)有unionid

? ? ? ? ? ? Object unionidObj = jsonObject.get("unionid");

? ? ? ? ? ? Map<String,String> userInfo=null;

? ? ? ? ? ? String unionid=null;

? ? ? ? ? ? //第一次授權(quán)

? ? ? ? ? ? if (unionidObj == null) {

? ? ? ? ? ? ? ? userInfo = getAuthUnionId(session_key, encryptedData, ivStr);

? ? ? ? ? ? ? ? unionid = userInfo.get("unionid");

? ? ? ? ? ? }else{

? ? ? ? ? ? ? ? unionid=jsonObject.get("unionid").toString();

? ? ? ? ? ? }

? ? ? ? ? ? WXUser wxUser = wxService.findWXUserByunionid(unionid);

? ? ? ? ? ? WXUser user = new WXUser();

? ? ? ? ? ? user.setUnionid(unionid);

? ? ? ? ? ? user.setNickname(nickname);

? ? ? ? ? ? user.setHeadimgurl(headurl);

? ? ? ? ? ? //微信信息存在

? ? ? ? ? ? if (wxUser != null) {

? ? ? ? ? ? ? ? wxService.updateCloudWXUser(user);

? ? ? ? ? ? } else {

? ? ? ? ? ? ? ? //第一次登陸

? ? ? ? ? ? ? ? wxService.addWXUser(user);

? ? ? ? ? ? }

? ? ? ? ? ? Map<String, String> result = new HashMap<>();

? ? ? ? ? ? result.put("unionid", unionid);

? ? ? ? ? ? //設(shè)置小程序的登錄狀態(tài)緩存(若不設(shè)置,微信默認(rèn)30天內(nèi)沒(méi)有操作就重新登錄)

? ? ? ? ? ? //redisUtils.setex("applet:"+unionid,30*24*60*60,unionid);

? ? ? ? ? ? //這是網(wǎng)頁(yè)端的socket返回?cái)?shù)據(jù)

? ? ? ? ? ? ConcurrentHashMap<String, Session> sessionMap = loginSocket.getSessionMap();

? ? ? ? ? ? if (StringUtils.isNotBlank(socketKey)) {

? ? ? ? ? ? ? ? Session currentSession = sessionMap.get(socketKey);

? ? ? ? ? ? ? ? if (currentSession != null) {

? ? ? ? ? ? ? ? ? ? String codeKey = redisUtils.getString("qrcode:" + socketKey);

? ? ? ? ? ? ? ? ? ? ResultBean resultBean=null;

? ? ? ? ? ? ? ? ? ? if(StringUtils.isBlank(codeKey)){

? ? ? ? ? ? ? ? ? ? ? ? resultBean = ResultBean.setOk(1, "二維碼已失效");

? ? ? ? ? ? ? ? ? ? }else{

? ? ? ? ? ? ? ? ? ? ? ? //掃描后刪除緩存的二維碼

? ? ? ? ? ? ? ? ? ? ? ? redisUtils.delString("qrcode:" + socketKey);

? ? ? ? ? ? ? ? ? ? ? ? //設(shè)置網(wǎng)頁(yè)端登錄有效時(shí)長(zhǎng)為6小時(shí)

? ? ? ? ? ? ? ? ? ? ? ? redisUtils.setex(unionid, 3600 * 6, unionid);

? ? ? ? ? ? ? ? ? ? ? ? resultBean = ResultBean.setOk(0, "掃碼登錄成功",unionid);

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? String res = JSON.toJSONString(resultBean);

? ? ? ? ? ? ? ? ? ? currentSession.getAsyncRemote().sendText(res);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? ? ? return ResultBean.setOk(0, "授權(quán)登錄小程序成功", result);

? ? ? ? } catch (Exception e) {

? ? ? ? ? ? logger.error("[微信小程序]小程序授權(quán)登錄出現(xiàn)異常:{}",e);

? ? ? ? ? ? return ResultBean.setError(1, "授權(quán)登錄小程序失敗");

? ? ? ? }

? ? }

/**

? ? * 授權(quán)過(guò)后的再次免授權(quán)登錄

? ? *

? ? * @param sessionKey

? ? * @param encryptedData

? ? * @param ivStr

? ? * @return 利用微信工具sdk對(duì)獲取的用戶信息解密

? ? */

? ? public Map<String,String> getAuthUnionId(String sessionKey, String encryptedData,String ivStr) {

? ? ? ? try {

? ? ? ? ? ? WxMaService wxMaService = WxMaConfiguration.getWxMaService();

? ? ? ? ? ? WxMaUserService userService = new WxMaUserServiceImpl(wxMaService);

? ? ? ? ? ? WxMaUserInfo userInfo = userService.getUserInfo(sessionKey, encryptedData, ivStr);

? ? ? ? ? ? String unionId = userInfo.getUnionId();

? ? ? ? ? ? String nickName = userInfo.getNickName();

? ? ? ? ? ? String avatarUrl = userInfo.getAvatarUrl();

? ? ? ? ? ? Map<String, String> userInfoMap = new HashMap<>();

? ? ? ? ? ? userInfoMap.put("unionid", unionId);

? ? ? ? ? ? userInfoMap.put("nickname", nickName);

? ? ? ? ? ? userInfoMap.put("headurl",avatarUrl);

? ? ? ? ? ? return userInfoMap;

? ? ? ? } catch (Exception e) {

? ? ? ? ? ? logger.error("[微信小程序]已授權(quán)登錄出現(xiàn)異常:{}",e);

? ? ? ? ? ? return null;

? ? ? ? }

? ? }

前端demo

<!DOCTYPE html>

<html lang="en">

<head>

? ? <meta charset="UTF-8">

? ? <title>Title</title>

? ? <script src="http://libs.baidu.com/jquery/1.9.1/jquery.js"></script>

? ? <script type="text/javascript">

? ? ? ? $(function () {

? ? ? ? ? ? var ip="xxx.xxx.xxx.xxx";

? ? ? ? ? ? var sceneStr = "scend-" + new Date().getTime() + Math.ceil(Math.random() * 888888 + 1000000);

? ? ? ? ? ? //建立websocket192.168.101.123

? ? ? ? ? ? //var s = encodeURIComponent(sceneStr);

? ? ? ? ? ? var ws = new WebSocket("ws://"+ip+":端口號(hào)/項(xiàng)目名(沒(méi)有不寫)/websocket路徑/" + sceneStr)

? ? ? ? ? ? ws.onopen = function () {

? ? ? ? ? ? ? ? console.log("websocket建立連接")

? ? ? ? ? ? }

? ? ? ? ? ? ws.onmessage = function (ev) {

? ? ? ? ? ? ? ? var parse = JSON.parse(ev.data);

? ? ? ? ? ? ? ? console.log(parse)

? ? ? ? ? ? ? ? var code1 = parse.code;

? ? ? ? ? ? ? ? if(code1==0){

? ? ? ? ? ? ? ? ? ? ws.onclose=function () { console.log("websocket連接關(guān)閉")}

? ? ? ? ? ? ? ? ? ? window.location.;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? ? ? var url="小程序碼接口地址";

? ? ? ? ? ? var pathStr="pages/index/index";

? ? ? ? ? ? $.post(url,{

? ? ? ? ? ? ? ? sceneStr: sceneStr,

? ? ? ? ? ? ? ? pathStr: pathStr

? ? ? ? ? ? },function(result){

? ? ? ? ? ? ? ? $("#qrcode").attr("src","data:image/png;base64,"+result);

? ? ? ? ? ? })

? ? ? ? })

? ? </script>

</head>

<body>

<img id="qrcode" src="">

</body>

</html>

小程序端demo(此demo僅做參考)



import {

? Base64,

? Crypto

} from './utils/ossUpload';

import {

? format

} from './utils/util.js';

App({

? onLaunch: function(option) {

? ? this.onLaunchArgu = option;

? ? console.log(option)

? ? this.init();

? ? this.globalData.os = this._getSystemOs()

? ? console.log(this._getSystemInfo())

? },

? requestArr:[],

? // 初始化

? init(fallback){

? ? wx.checkSession({

? ? ? success: () => {

? ? ? ? console.log('登錄沒(méi)過(guò)期了')

? ? ? ? ? // 獲取用戶信息

? ? ? ? ? wx.getSetting({

? ? ? ? ? ? success: res => {

? ? ? ? ? ? ? if (res.authSetting['scope.userInfo']) {

? ? ? ? ? ? ? ? // 已經(jīng)授權(quán),可以直接調(diào)用 getUserInfo 獲取頭像昵稱,不會(huì)彈框

? ? ? ? ? ? ? ? this.getUserInfo().then(res => {

? ? ? ? ? ? ? ? ? this.globalData.userInfo = res.userInfo

? ? ? ? ? ? ? ? ? // 由于 getUserInfo 是網(wǎng)絡(luò)請(qǐng)求窃爷,可能會(huì)在 Page.onLoad 之后才返回

? ? ? ? ? ? ? ? ? // 所以此處加入 callback 以防止這種情況

? ? ? ? ? ? ? ? ? if (this.userInfoReadyCallback) {

? ? ? ? ? ? ? ? ? ? this.userInfoReadyCallback(res)

? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }, () => {})

? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? ? })

? ? ? },

? ? ? fail(res) {

? ? ? ? console.log('登錄過(guò)期了');

? ? ? },

? ? ? complete(res) {

? ? ? ? console.log(res);

? ? ? }

? ? })

? },

? login(callback) {

? ? wx.login({

? ? ? success: res => {

? ? ? ? const code = res.code;

? ? ? ? this.getUserInfo().then(res => {

? ? ? ? ? this.request({

? ? ? ? ? ? url: '/studyassistant/weixin/weChatAppletLogin',

? ? ? ? ? ? data: {

? ? ? ? ? ? ? #這里的參數(shù)是掃二維碼獲取到的,方便調(diào)試,直接拿取

? ? ? ? ? ? ? socketKey: this.onLaunchArgu.query.scene,?

? ? ? ? ? ? ? code,

? ? ? ? ? ? ? encryptedData: res.encryptedData,

? ? ? ? ? ? ? ivStr: res.iv,

? ? ? ? ? ? ? headurl: res.userInfo.avatarUrl,

? ? ? ? ? ? ? nickname: encodeURIComponent(res.userInfo.nickName)

? ? ? ? ? ? }

? ? ? ? ? }, false).then(res => {

? ? ? ? ? ? this.globalData.unionId = res.data.unionid;

? ? ? ? ? ? this._setStorageSync({

? ? ? ? ? ? ? unionId: res.data.unionid,

? ? ? ? ? ? })

? ? ? ? ? ? if (this.requestArr.length) {

? ? ? ? ? ? ? this.requestArr.map((item) => {

? ? ? ? ? ? ? ? this.request(item.option, item.author);

? ? ? ? ? ? ? })

? ? ? ? ? ? ? this.request()

? ? ? ? ? ? }

? ? ? ? ? ? callback();

? ? ? ? ? })

? ? ? ? }, () => {})

? ? ? }

? ? })

? },

微信小程序調(diào)試


這里的啟動(dòng)參數(shù)就是頁(yè)面上小程序二維碼里面的參數(shù)scene=(你的參數(shù))

這樣調(diào)試的時(shí)候,就不用了手機(jī)掃碼了


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末序仙,一起剝皮案震驚了整個(gè)濱河市疗垛,隨后出現(xiàn)的幾起案子纹笼,更是在濱河造成了極大的恐慌饱普,老刑警劉巖孵延,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吕漂,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡尘应,警方通過(guò)查閱死者的電腦和手機(jī)惶凝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)菩收,“玉大人梨睁,你說(shuō)我怎么就攤上這事∧榷” “怎么了坡贺?”我有些...
    開(kāi)封第一講書人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)箱舞。 經(jīng)常有香客問(wèn)我遍坟,道長(zhǎng),這世上最難降的妖魔是什么晴股? 我笑而不...
    開(kāi)封第一講書人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任愿伴,我火速辦了婚禮,結(jié)果婚禮上电湘,老公的妹妹穿的比我還像新娘隔节。我一直安慰自己鹅经,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布怎诫。 她就那樣靜靜地躺著瘾晃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪幻妓。 梳的紋絲不亂的頭發(fā)上蹦误,一...
    開(kāi)封第一講書人閱讀 49,929評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音肉津,去河邊找鬼强胰。 笑死,一個(gè)胖子當(dāng)著我的面吹牛妹沙,可吹牛的內(nèi)容都是我干的偶洋。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼初烘,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼涡真!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起肾筐,我...
    開(kāi)封第一講書人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎缸剪,沒(méi)想到半個(gè)月后吗铐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡杏节,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年唬渗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奋渔。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡镊逝,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嫉鲸,到底是詐尸還是另有隱情撑蒜,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布玄渗,位于F島的核電站座菠,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏藤树。R本人自食惡果不足惜浴滴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望岁钓。 院中可真熱鬧升略,春花似錦微王、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至腰根,卻和暖如春激才,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背额嘿。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工瘸恼, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人册养。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓东帅,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親球拦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子靠闭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容

  • /** * @author vincent * @date */ @Controller @RequestMapp...
    有夢(mèng)想的咸魚_87af閱讀 773評(píng)論 0 0
  • 1 去微信開(kāi)放平臺(tái)創(chuàng)建應(yīng)用 審核通過(guò)后會(huì)得到AppID和AppSecret(這兩個(gè)很重要) 2 接入自己的網(wǎng)站 (...
    史史小子閱讀 1,202評(píng)論 0 2
  • 微信授權(quán)登錄流程 第一步:wx.login獲取 用戶臨時(shí)登錄憑證code 第二步:wx.getUserInfo獲取...
    小李不小閱讀 23,266評(píng)論 0 5
  • 注意:沒(méi)有在微信開(kāi)放平臺(tái)(不是公眾平臺(tái))做開(kāi)發(fā)者資質(zhì)認(rèn)證的就不要浪費(fèi)時(shí)間了愧膀,沒(méi)認(rèn)證無(wú)法獲取unionId,認(rèn)證費(fèi)用...
    前端記事本閱讀 1,849評(píng)論 0 1
  • 剪柳春風(fēng)無(wú)處追谣光, 朱欄蒼瓦照秋水檩淋。 天香樓上異鄉(xiāng)人, 相對(duì)青萍憐不起萄金。
    A_master閱讀 200評(píng)論 0 7