|
圖片來源于@谷歌黑板報(bào) “AI比人聰明系列”、“大概收錄了無數(shù)個(gè)靈魂畫手的作品”,昨日谷歌的AI應(yīng)用“猜畫小歌”剛一入駐微信小程序,就俘獲了一群靈魂畫手,網(wǎng)友們一邊在朋友圈展示著自己的畫作,一邊感慨著AI的神奇之處。 據(jù) 谷歌黑板報(bào) 介紹,為了讓用戶體驗(yàn)人工智能技術(shù)驅(qū)動(dòng)下的人機(jī)交互,谷歌開發(fā)了這款小游戲。猜畫小歌由谷歌AI的神經(jīng)網(wǎng)絡(luò)驅(qū)動(dòng),該網(wǎng)絡(luò)源自全世界最大的、囊括超過 5000 萬個(gè)手繪素描的數(shù)據(jù)群。 這種計(jì)算機(jī)視覺技術(shù)能夠讓計(jì)算機(jī)理解并“看到”輸入的視覺信息,比如說能夠通過粗糙的草圖辨認(rèn)物體,或者通過隨意的涂鴉辨認(rèn)出長著耳朵的墨跡是熊貓。 游戲操作簡潔,從小程序進(jìn)入“猜畫小歌”后,網(wǎng)友就可以和AI組隊(duì)。主頁分為“開始作畫”、“排行榜”和“我的畫作”三個(gè)欄目。系統(tǒng)給出關(guān)鍵詞,網(wǎng)友要在限時(shí)18秒內(nèi)完成畫作,AI隊(duì)友需要在倒計(jì)時(shí)前猜出物體。猜出的圖畫越多,連勝次數(shù)也會(huì)越多,畫手的級(jí)別就會(huì)越高。單局完成后用戶可選擇保存長圖或者直接分享,也可以邀請(qǐng)朋友一起挑戰(zhàn)最長的連勝紀(jì)錄。 排行榜會(huì)實(shí)時(shí)更新排名,目前單局成績第一名已經(jīng)可以在18分鐘內(nèi)完成264張畫作。在“我的畫作”里,用戶可以瀏覽自己解鎖的所有關(guān)鍵詞。這既能激起用戶的挑戰(zhàn)心理,又滿足了用戶分享討論的樂趣。
網(wǎng)友的“猜畫小歌”簡筆畫 這可能是國內(nèi)大多數(shù)用戶第一次接觸谷歌AI技術(shù),雖然只是一次AI落地的小水花,但因?yàn)殚T檻低,接地氣,又頗具社交娛樂性,因此在社交媒體流傳開來。 “猜畫小歌”是谷歌觸達(dá)中國用戶的一次嘗試,也是谷歌在中國部署AI的一次試水。因?yàn)楣雀钁?yīng)用商店在國內(nèi)使用受限,谷歌一直在尋求獲取中國用戶的渠道。入駐微信小程序,意味著谷歌可以繞過谷歌或者應(yīng)用商店,通過微信平臺(tái)直達(dá)數(shù)億中國網(wǎng)民。據(jù)QuestMobile數(shù)據(jù),截止到2018年6月,微信月活躍用戶規(guī)模已達(dá)9.3億。 況且,小程序正是微信關(guān)注的的焦點(diǎn),開發(fā)者也表現(xiàn)出對(duì)小程序變現(xiàn)的支持。據(jù)7月11日微信團(tuán)隊(duì)公布的數(shù)據(jù),目前微信已上線小程序100多萬,有超過150萬的開發(fā)者和5000個(gè)第三方開發(fā)平臺(tái)。在7月13日的調(diào)整中,微信給小程序設(shè)置了固定入口,小程序的戰(zhàn)役即將升級(jí)。 如果說谷歌蹭微信小程序的熱度只不過是“過家家”,那在中國展開AI技術(shù)研究就是動(dòng)真格了。 2017年12月13日, 谷歌在國內(nèi)開設(shè)了第一家人工智能實(shí)驗(yàn)室 。提及成立AI實(shí)驗(yàn)室的原因,谷歌云首席科學(xué)家李飛飛在谷歌中國開發(fā)者大會(huì)上表示,“中國在AI領(lǐng)域已經(jīng)成為最重要的領(lǐng)導(dǎo)者之一,中國在ImageNet、Kaggle、基礎(chǔ)科研等方面有巨大的成就。” 她還補(bǔ)充說,“除了發(fā)表自己的作品,谷歌人工智能實(shí)驗(yàn)室還將通過資助AI相關(guān)研討會(huì)和中國的AI人才,支持人工智能的研究社區(qū)。” 該實(shí)驗(yàn)室與國內(nèi)互聯(lián)網(wǎng)巨頭BAT、AI領(lǐng)域獨(dú)角獸Face ++和商湯科技展開了AI人才的爭奪。谷歌開設(shè)人工智能實(shí)驗(yàn)室時(shí)正值中美競爭加劇,全球AI人才稀缺。像阿里、騰訊、百度和科大訊飛都已經(jīng)或者計(jì)劃在美國開設(shè)AI實(shí)驗(yàn)室。 不過設(shè)立實(shí)驗(yàn)室并不代表谷歌會(huì)在國內(nèi)推出AI服務(wù),目前谷歌招攬的AI人才只會(huì)與谷歌遍布世界各地的團(tuán)隊(duì)一起工作。 今年1月17日,谷歌又一鼓作氣在深圳設(shè)立了辦公室。深圳是中國科技巨頭的大本營,騰訊、華為和中興的總部均在深圳,阿里巴巴也在深圳設(shè)立了辦公室。深圳是智能硬件中心,谷歌落戶深圳也有著手智能硬件的考量。 谷歌一直在推進(jìn)其“中國戰(zhàn)略”,除了布局AI實(shí)驗(yàn)室招攬人才,谷歌也相繼在中國推出了三款產(chǎn)品。包括:移動(dòng)版本的谷歌翻譯;與小米合作推出ARcore,以及在推出針對(duì)Android設(shè)備的文件管理服務(wù)Files Go之后,上線其中文版“文件極客”。 昨日上線的“猜畫小歌”只是谷歌AI場景落地的一個(gè)小水花,至于會(huì)激起多大的漣漪,還需要看谷歌中國戰(zhàn)略的下一步怎么走 |
|
文章有不當(dāng)之處,歡迎指正,如果喜歡微信閱讀,你也可以關(guān)注我的微信公眾號(hào): 好好學(xué)java,獲取優(yōu)質(zhì)學(xué)習(xí)資源。 一、登錄流程圖
二、小程序客戶端
doLogin:function(callback = () =>{}){
let that = this;
wx.login({
success:function(loginRes){
if(loginRes){
//獲取用戶信息
wx.getUserInfo({
withCredentials:true,//非必填 默認(rèn)為true
success:function(infoRes){
console.log(infoRes,'>>>');
//請(qǐng)求服務(wù)端的登錄接口
wx.request({
url: api.loginUrl,
data:{
code:loginRes.code,//臨時(shí)登錄憑證
rawData:infoRes.rawData,//用戶非敏感信息
signature:infoRes.signature,//簽名
encrypteData:infoRes.encryptedData,//用戶敏感信息
iv:infoRes.iv//解密算法的向量
},
success:function(res){
console.log('login success');
res = res.data;
if(res.result==0){
that.globalData.userInfo = res.userInfo;
wx.setStorageSync('userInfo',JSON.stringify(res.userInfo));
wx.setStorageSync('loginFlag',res.skey);
console.log("skey="+res.skey);
callback();
}else{
that.showInfo('res.errmsg');
}
},
fail:function(error){
//調(diào)用服務(wù)端登錄接口失敗
// that.showInfo('調(diào)用接口失敗');
console.log(error);
}
});
}
});
}else{
}
}
});
}
復(fù)制代碼
微信小程序端發(fā)起登錄請(qǐng)求,攜帶的參數(shù)主要有:
code:loginRes.code,//臨時(shí)登錄憑證
rawData:infoRes.rawData,//用戶非敏感信息
signature:infoRes.signature,//簽名
encrypteData:infoRes.encryptedData,//用戶敏感信息
iv:infoRes.iv//解密算法的向量
復(fù)制代碼
參數(shù)解釋: code:loginRes.code,//臨時(shí)登錄憑證: 必傳 ,通過code來換取后臺(tái)的 sessionKey和 openId rawData:infoRes.rawData,//用戶非敏感信息 signature:infoRes.signature,//簽名 encrypteData:infoRes.encryptedData,//用戶敏感信息 iv:infoRes.iv//解密算法的向量 signature,//簽名、 encryptedData ,//用戶敏感信息、 iv //解密算法的向量: 這三個(gè)參數(shù)是用來解碼用戶敏感信息的,比如電話號(hào)碼等信息。 需要的數(shù)據(jù)主要有: skey ,用于標(biāo)志用戶的唯一性。 三、Java后臺(tái)
/**
* 登陸接口
*/
@RequestMapping("/login")
@ApiResponses({
@ApiResponse(code = 404, message = "服務(wù)器未找到資源"),
@ApiResponse(code = 200, message = "請(qǐng)求成功"),
@ApiResponse(code = 500, message = "服務(wù)器錯(cuò)誤"),
@ApiResponse(code = 401, message = "沒有訪問權(quán)限"),
@ApiResponse(code = 403, message = "服務(wù)器拒絕訪問"),
})
@ApiOperation(value = "小程序登錄", httpMethod = "POST", notes = "小程序登錄")
public ResponseEntity<LoginDataResult> login(
@ApiParam(required = true, value = "臨時(shí)登錄憑證code", name = "code") String code,
@ApiParam(required = true, value = "用戶非敏感信息", name = "rawData")
@RequestParam(value = "rawData", required = true) String rawData,
@ApiParam(required = true, value = "簽名", name = "signature")
@RequestParam(value = "signature", required = true) String signature,
@ApiParam(required = true, value = "用戶敏感信息", name = "encrypteData")
@RequestParam(value = "encrypteData", required = true) String encrypteData,
@ApiParam(required = true, value = "解密算法的向量", name = "iv")
@RequestParam(value = "iv", required = true) String iv
) {
ObjectMapper mapper = new ObjectMapper();
logger.info("signature============================================================="+signature);
logger.info("encrypteData=========================================================="+encrypteData);
logger.info("iv========================================================================"+iv);
RawData data = null;
WxMaJscode2SessionResult session = null;
String openid = null;
String sessionKey = null;
String phoneNumber = null;
try {
if (rawData != null && !"".equals(rawData)) {
//1、獲取用戶非敏感信息
data = mapper.readValue(rawData, RawData.class);
}
session = this.wxService.getUserService().getSessionInfo(code);
//獲取到openid和sessionkey
openid = session.getOpenid();
sessionKey = session.getSessionKey();
logger.info("sessionkey========================================================="+sessionKey);
/* //2、獲取用戶手機(jī)號(hào)
phoneNumber = phone(code, signature, rawData, encrypteData, iv);
logger.info("phoneNumber========================================="+phoneNumber);
*/
} catch (IOException e) {
e.printStackTrace();
logger.info("獲取用戶信息失敗");
LoginDataResult loginDataResult = new LoginDataResult();
loginDataResult.setCode("2");
loginDataResult.setMsg("請(qǐng)求失敗");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(loginDataResult);
} catch (WxErrorException e) {
e.printStackTrace();
logger.info("獲取用戶信息失敗");
}
//3、向數(shù)據(jù)庫插入用戶信息
String skey = insertUser(data, openid, phoneNumber);
//4、緩存openid, sessionKey, skey到redis
redisCache(openid, sessionKey, skey);
//5、把新的skey返回給小程序
LoginDataResult loginDataResult = new LoginDataResult();
loginDataResult.setSkey(skey);
loginDataResult.setCode("1");
loginDataResult.setMsg("請(qǐng)求成功");
return ResponseEntity.status(HttpStatus.OK).body(loginDataResult);
}
/**
* 緩存openid,sessionKey,skey等信息
* @param openid 小程序用戶唯一標(biāo)志
* @param sessionKey 小程序會(huì)話標(biāo)志
* @param skey 后臺(tái)生成的用戶唯一標(biāo)志,會(huì)話管理
*/
private void redisCache(String openid, String sessionKey, String skey) {
//根據(jù)openid查詢skey是否存在
String skey_redis = jedisClient.hget("WEXIN_USER_OPENID_SKEY", openid);
if (StringUtils.isNotBlank(skey_redis)) {
//存在 刪除 skey 重新生成skey 將skey返回
jedisClient.hdel("WEXIN_USER_OPENID_SKEY", openid);
jedisClient.hdel("WEIXIN_USER_SKEY_OPENID", skey_redis);
jedisClient.hdel("WEIXIN_USER_SKEY_SESSIONKEY", skey_redis);
}
// 緩存一份新的
jedisClient.hset("WEXIN_USER_OPENID_SKEY", openid, skey);
jedisClient.expire("WEXIN_USER_OPENID_SKEY",432000);//設(shè)置5天過期
jedisClient.hset("WEIXIN_USER_SKEY_OPENID", skey, openid);
jedisClient.expire("WEIXIN_USER_SKEY_OPENID",432000);//設(shè)置5天過期
jedisClient.hset("WEIXIN_USER_SKEY_SESSIONKEY", skey, sessionKey);
jedisClient.expire("WEIXIN_USER_SKEY_SESSIONKEY",432000);//設(shè)置5天過期
}
/**
* 將用戶信息插入到數(shù)據(jù)庫
* @param data 用戶信息
* @param openid
* @param phoneNumber 手機(jī)號(hào)
* @return
*/
private String insertUser(RawData data, String openid, String phoneNumber) {
//判斷用戶數(shù)據(jù)庫是否存在,不存在,入庫。
Member user = userService.selectUserByOpenid(openid);
//uuid生成唯一key
String skey = UUID.randomUUID().toString();
if (user == null) {
//入庫
user = new Member();
user.setId(skey);
user.setCountry(data.getCountry());
user.setCreatedate(new Date());
user.setDf(1);
user.setGender(data.getGender().equals("1") ? 1 : 2);//1為男,2為女
user.setHeadimg(data.getAvatarUrl());
user.setNickname(data.getNickName());
user.setOpenid(openid);
user.setCitycode(data.getCity());
user.setProvincecode(data.getProvince());
user.setMobileno(phoneNumber);
//插入到數(shù)據(jù)庫
userService.insertUser(user);
} else {
//已存在
logger.info("用戶openid已存在,不需要插入");
return user.getId();//返回用戶唯一標(biāo)志skey
}
return skey;
}
/**
* 獲取用戶板綁定的手機(jī)號(hào)
* @param sessionKey 小程序session
* @param signature 簽名
* @param rawData 用戶信息
* @param encryptedData 小程序加密數(shù)據(jù)
* @param iv 小程序向量
* @return
*/
@ApiOperation(value = "用戶手機(jī)號(hào)獲取", httpMethod = "GET", notes = "用戶手機(jī)號(hào)獲取")
public String phone(String sessionKey, String signature, String rawData, String encryptedData, String iv) {
String phoneNumber = null;
try {
byte[] bytes = WxMiniappUtils.decrypt(Base64.decodeBase64(sessionKey), Base64.decodeBase64(iv), Base64.decodeBase64(encryptedData));
String phone = new String(bytes, "UTF8");
logger.info("phone====================================="+phone);
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException 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;
}
復(fù)制代碼
下面對(duì)上面代碼進(jìn)行分析: 3.1獲取openid和sessionKeysession = this.wxService.getUserService().getSessionInfo(code); //獲取到openid和sessionkey openid = session.getOpenid(); sessionKey = session.getSessionKey(); 復(fù)制代碼 這段代碼是不是十分的簡潔,這里用到了一個(gè) 第三方的sdk(weixin-java-tools) ,通過這個(gè)sdk可以非常簡便的獲取到openid和sessionKey,具體的 demo 。 當(dāng)然,如果你不想用 第三方的sdk ,也可以自己實(shí)現(xiàn),實(shí)現(xiàn)代碼如下:
public static JSONObject getSessionKeyOrOpenId(String code){
//微信端登錄code
String wxCode = code;
String requestUrl = "https://api.weixin.qq.com/sns/jscode2session";
Map<String,String> requestUrlParam = new HashMap<String, String>( );
requestUrlParam.put( "appid","你的小程序appId" );//小程序appId
requestUrlParam.put( "secret","你的小程序appSecret" );
requestUrlParam.put( "js_code",wxCode );//小程序端返回的code
requestUrlParam.put( "grant_type","authorization_code" );//默認(rèn)參數(shù)
//發(fā)送post請(qǐng)求讀取調(diào)用微信接口獲取openid用戶唯一標(biāo)識(shí)
JSONObject jsonObject = JSON.parseObject( UrlUtil.sendPost( requestUrl,requestUrlParam ));
return jsonObject;
}
復(fù)制代碼
3.2解密用戶敏感數(shù)據(jù)獲取用戶信息3.2.1controller這個(gè)部分自己遇到了好多的坑,由于需要獲取用戶的手機(jī)號(hào)碼,需要解密用戶的信息。
/**
* 獲取用戶板綁定的手機(jī)號(hào)
* @param sessionKey 小程序session
* @param signature 簽名
* @param rawData 用戶信息
* @param encryptedData 小程序加密數(shù)據(jù)
* @param iv 小程序向量
* @return
*/
@ApiOperation(value = "用戶手機(jī)號(hào)獲取", httpMethod = "GET", notes = "用戶手機(jī)號(hào)獲取")
public String phone(String sessionKey, String signature, String rawData, String encryptedData, String iv) {
String phoneNumber = null;
try {
byte[] bytes = WxMiniappUtils.decrypt(Base64.decodeBase64(sessionKey), Base64.decodeBase64(iv), Base64.decodeBase64(encryptedData));
String phone = new String(bytes, "UTF8");
logger.info("phone====================================="+phone);
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException 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;
}
復(fù)制代碼
3.2.2decrypt工具類這里調(diào)用了 WxMiniappUtils.decrypt 這個(gè)工具類,工具類如下:
/**
* 解密用戶手機(jī)號(hào)算法
* @param sessionkey 小程序登錄sessionKey
* @param iv 向量
* @param encryptedData
* @return
* @throws NoSuchPaddingException
* @throws NoSuchAlgorithmException
* @throws InvalidAlgorithmParameterException
* @throws InvalidKeyException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
*/
public static byte[] decrypt(byte[] sessionkey, byte[] iv, byte[] encryptedData)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(sessionkey, "AES");
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
return cipher.doFinal(encryptedData);
}
復(fù)制代碼
這里用到的 Cipher 類是 javax.crypto 的類。 3.2.3問題但是這里使用這個(gè) decrypt 工具類的時(shí)候,遇到了好多的問題。 第一:AES解密是報(bào)錯(cuò)javax.crypto.BadPaddingException: pad block corrupted 這個(gè)問題是由于,工具類使用了 Cipher.getInstance("AES/CBC/PKCS5Padding") 。 解決:Cipher cipher = Cipher.getInstance("AES/ECB/ZeroBytePadding");。 第二:java.security.InvalidAlgorithmParameterException: Wrong IV length: must be 16 這個(gè)問題是由于,解碼出來的iv不是16位,好像是15位,這個(gè)為什么我也不太清楚。 解決:這個(gè)怎么解決,自己也沒有找到方法,如果有大神解決,望告知! 我的解決方法:其實(shí)我發(fā)現(xiàn)這個(gè)問題并不是這個(gè)工具類的問題,我折騰了一天發(fā)現(xiàn),這個(gè)工具類并不是不能夠解碼手機(jī)號(hào),有的是可以的,有的解析不到手機(jī)號(hào),只有普通的信息,所以我覺得,這個(gè)可能是微信用戶注冊(cè)的時(shí)候,是不是用手機(jī)號(hào)注冊(cè)的,所以會(huì)出現(xiàn)有些能夠解析,有的不能解析。如果有大神有其他方法,望告知! 3.2.4解析成功數(shù)據(jù)
{"phoneNumber":"13880684012","purePhoneNumber":"13880684012","countryCode":"86","watermark":{"timestamp":1519460296,"appid":"wx6ede2086ee29a89f"}}
復(fù)制代碼
如果解析到了這樣的json數(shù)據(jù),說明是成功了的。 3.2.5 另外一種方案
public class AES {
public static final AES instance = new AES();
public static boolean initialized = false;
/**
* AES解密
* @param content 密文
* @return
* @throws InvalidAlgorithmParameterException
* @throws NoSuchProviderException
*/
public byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) throws InvalidAlgorithmParameterException {
initialize();
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
Key sKeySpec = new SecretKeySpec(keyByte, "AES");
cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));// 初始化
byte[] result = cipher.doFinal(content);
return result;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (NoSuchProviderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static void initialize(){
if (initialized) return;
Security.addProvider(new BouncyCastleProvider());
initialized = true;
}
//生成iv
public static AlgorithmParameters generateIV(byte[] iv) throws Exception{
AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
params.init(new IvParameterSpec(iv));
return params;
}
}
復(fù)制代碼
這個(gè)也會(huì)有上面的問題,有時(shí)候會(huì)解析失??!具體方法,還在摸索中,有大神知道方法和原有,望告知! 3.2.6第三方sdk方法
WxMaPhoneNumberInfo phoneNoInfo = this.wxService.getUserService().getPhoneNoInfo(sessionKey, encryptedData, iv);
phoneNumber = phoneNoInfo.getPurePhoneNumber();
復(fù)制代碼
這個(gè)也會(huì)有上面的問題出現(xiàn),有時(shí)候會(huì)解析失??! 四、總結(jié)1.小程序端發(fā)起請(qǐng)求并攜帶主要參數(shù) 2.java后臺(tái)接到/login請(qǐng)求后,根據(jù)code去調(diào)用微信接口獲取用戶唯一標(biāo)識(shí)openid和sessionKey 3.根據(jù)openid查詢mysql數(shù)據(jù)庫,判斷該用戶是否存在,如果不存在將用戶非敏感信息和其他初始化數(shù)據(jù)存入到數(shù)據(jù)庫中,如果已存在,不操作 4.根據(jù)openid查詢r(jià)edis數(shù)據(jù)庫,判斷openid對(duì)應(yīng)的skey是否存在,如果存在則刪除原來老的skey以及對(duì)應(yīng)的openid和sessionKey 5.通過uuid生成唯一的skey,用openid做鍵,skey做值,存入到redis中 6.然后把skey做鍵,openid和sessionKey的json串做值也重新存入到redis中 7.根據(jù)解密算法,參數(shù)有encryptedData、sessionKey和iv,獲取用戶信息userInfo,如果userInfo字段不滿足需要,可通過userInfo.put( "balance",user.getUbalance() );添加所需要的字段和值 8.將微信小程序需要的數(shù)據(jù)封裝到map中,返回給小程序端。 |