这里写目录标题
一认识开发工具
开发界面说明
1, wxml主要用来布局组件的(相当于大楼结构)
如:楼有几层,每层有多少房间,有什么设备
2, wxss主要决定显示样式(决定大楼的样式)
如:颜色,大小,宽高等
3, js主要用来处理逻辑(决定大楼具备哪些功能)
如:大楼具有电梯功能,空调制冷,灯光,供水,供电,主要是为了大厦的运行。
二级接口
参考:添加链接描述
wx.getUserProfile(Object object) 获取用户信息
获取用户信息。页面产生点击事件(例如 button 上 bindtap 的回调中)后才可调用,每次请求都会弹出授权窗口,用户同意后返回 userInfo
- 前端xml页面单机事件绑定wx.getUserProfile
<!-- 没有用户信息就绑定登录事件 -->
<button wx:if="{{!userInfo}}" bindtap="login">授权登录</button>
<view wx:else class="root">
<image class="touxiang" src="{{userInfo.avatarUrl}}"></image>
<text class="nicheng">{{userInfo.nickName}}</text>
<button bindtap="loginOut">退出登录</button>
</view>
- 触及获取用户信息接口
Page({
data: {
userInfo: ''
},
onLoad() {
let user = wx.getStorageSync('user')
console.log('进入小程序的index页面获取缓存', user)
this.setData({
userInfo: user
})
},
// 授权登录
login() {
wx.getUserProfile({
desc: '必须授权才可以继续使用',
success: res => {
let user = res.userInfo
// 把用户信息缓存到本地
wx.setStorageSync('user', user)
console.log("用户信息", user)
this.setData({
userInfo: user
})
},
fail: res => {
console.log('授权失败', res)
}
})
},
// 退出登录
loginOut() {
this.setData({
userInfo: ''
})
wx.setStorageSync('user', null)
}
})
wx.login(Object object) 获取code
1.调用此接口获取登录凭证(code)进而换取用户登录态信息,包括用户的唯一标识(openid) 及本次登录的 会话密钥(session_key)
2.然后我们拿这个code去自己的服务器换取用户openid和session_key
3.code是临时的,有效时间5分钟,
4.不是每次wx.login都会更新session_key,session_key的有效性微信是不会告诉开发者的,可以自定义登录状态会话session的有效性,也可以通过 auth.code2Session 接口更新服务器存储的 session_key
参考地址
5…openId 是不变的,如果有坏人拿着别人的 openId 来进行请求,那么就会出现冒充的情况。所以我们建议开发者可以自己在后台生成一个拥有有效期的 第三方session 来做登录态,用户每隔一段时间都需要进行更新以保障数据的安全性。
// 授权登录
login() {
wx.getUserProfile({
desc: '必须授权才可以继续使用',
success: res => {
let user = res.userInfo
// 把用户信息缓存到本地
wx.setStorageSync('user', user)
console.log("用户信息", user)
this.setData({
userInfo: user
})
// 获取code
wx.login({
success (res) {
if (res.code) {
//发起网络请求
// wx.request({
// url: 'https://example.com/onLogin',
// data: {
// code: res.code
// }
// })
console.log("获取到登录凭证:",res.code)
} else {
console.log('登录失败!' + res.errMsg)
}
}
})
},
fail: res => {
console.log('授权失败', res)
}
})
}
auth.code2Session 获取appID
通过 wx.login 接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程
登录地址:
GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
参考:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html
如何获取微信小程序/微信公众号的AppId和AppSecret
- 1.进入微信公众平台点击此处:
微信公众平台 - 2.然后扫码进入
前端完整代码
index.js
Page({
data: {
userInfo: ''
},
onLoad() {
let user = wx.getStorageSync('user')
console.log('进入小程序的index页面获取缓存', user)
this.setData({
userInfo: user
})
},
// 授权登录
login() {
wx.getUserProfile({
desc: '必须授权才可以继续使用',
success: res => {
let user = res.userInfo
// 把用户信息缓存到本地
wx.setStorageSync('user', user)
console.log("用户信息是:", user)
this.setData({
userInfo: user
})
// 获取code
wx.login({
success (res) {
if (res.code) {
console.log("code是:", res.code)
console.log("用户头像是:", user.avatarUrl)
console.log("用户昵称是:", user.nickName)
console.log("用户性别1是男性:", user.gender)
//发起网络请求
wx.request({
method:'POST',
header: {
'content-type': 'application/json'
},
url: 'http://127.0.0.1:19092/wechat/login',
data: {
code: res.code,
ninck: user.nickName,
avaurl: user.avatarUrl,
sex: user.gender
},
dataType:'json',
success: function(msg) {
if (msg) {
console.log('msg为:' +JSON.stringify(msg));
console.log('获取到的用户token为:' + msg.data.token);
//可以把token保存到本地缓存,前后端携带token交互
wx.setStorageSync('token', msg.data.token);
} else {
console.log('获取不到数据'+msg);
}
}
})
} else {
console.log('登录失败!' + res.errMsg)
}
}
})
},
fail: res => {
console.log('授权失败', res)
}
})
},
// 退出登录
loginOut() {
this.setData({
userInfo: ''
})
wx.setStorageSync('user', null)
wx.setStorageSync('token', null)
}
})
index.xml
<!-- 没有用户信息就绑定登录事件 -->
<button wx:if="{{!userInfo}}" bindtap="login">授权登录</button>
<view wx:else class="root">
<image class="touxiang" src="{{userInfo.avatarUrl}}"></image>
<text class="nicheng">{{userInfo.nickName}}</text>
<button bindtap="loginOut">退出登录</button>
</view>
后端接口获取openid和会话密钥 session_key
session_key不应该传递到小程序,应该结合openid一期自定义一个session-id 返回给小程序来鉴定客户端小程序的登录状态
!!!!!session_key则是微信服务器给开发者服务器颁发的身份凭证,开发者可以用session_key请求微信服务器其他接口来获取一些其他信息,由此可以看到,session_key不应该泄露或者下发到小程序前端。
1.控制层
/**
* @author an
* @version 1.0
* @date 2021/9/19 17:34
*/
@RestController
@RequestMapping("/wechat")
public class WeiXingLoginController {
private static final Logger logger = LoggerFactory.getLogger(WeiXingLoginController.class);
@Autowired
private WeiXingLoginServer weiXingLoginServer;
@PostMapping("/login")
public ResponseEntity<UserMsgDTO> wxLogin(@RequestBody UserMsgDTO userMsgDTO) {
if (StringUtils.isNotBlank(userMsgDTO.getCode())) {
logger.info("登录凭证code={}", userMsgDTO.getCode());
}
if (ObjectUtils.isEmpty(userMsgDTO)) {
throw new MyException(StatusCode.ERROR, "Code is not null", "wxLogin");
}
UserMsgDTO userDTO = weiXingLoginServer.weChatMiNiLogin(userMsgDTO);
logger.info("userDTO={}", userDTO);
return ResponseEntity.ok(userDTO);
}
}
2.表现层
**
* @author an
* @version 1.0
* @date 2021/9/19 17:46
*/
@Service
public class WeiXingLoginServer {
private static final Logger logger = LoggerFactory.getLogger(WeiXingLoginServer.class);
@Value("${wx.appid}")
private String appid;
@Value("${wx.secret}")
private String secret;
@Value("${wx.grant_type}")
private String grantType;
@Value("${wx.url}")
private String url;
public UserMsgDTO weChatMiNiLogin(UserMsgDTO userMsgDTO) {
Map<String, String> param = new HashMap<>();
param.put("appid", appid);
param.put("secret", secret);
param.put("js_code", userMsgDTO.getCode());
param.put("grant_type", grantType);
//请求获取小程序服务返回的session_id
//GET https://api.weixin.qq.com/sns/jscode2session?
// appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
logger.info("微信请求参数是:url={},param={}", url, param);
String wxResult = HttpClientUtil.doGet(url, param);
if (StringUtils.isBlank(wxResult)) {
throw new MyException(StatusCode.ERROR, "获取不到appid");
}
//解析相应内容(转换成json对象)
JSONObject jsonObject = JSONObject.parseObject(wxResult);
String openid = jsonObject.getString("openid");//用户唯一标识
String session_key = jsonObject.getString("session_key");获取会话密钥(session_key)
logger.info("微信返回的结果:jsonObject={}", jsonObject);
//
String token = UUID.randomUUID().toString();
RedisUtils.hPut(token, "openid", openid);
RedisUtils.hPut(token, "session_key", session_key);
RedisUtils.setHashKeyTime(token, 60*60, TimeUnit.SECONDS);
logger.info("返回的token={}", token);
UserMsgDTO userMsgDTORsp = new UserMsgDTO();
userMsgDTORsp.setToken(token);
return userMsgDTORsp;
}
}
3.pojo
/**
* @author an
* @version 1.0
* @date 2021/9/19 17:41
*/
@Getter
@Setter
public class UserMsgDTO implements Serializable {
private String id;
private String customerName;
private String mobilePhone;
private String avatarId;
private String fromSource;
private String code;
private String nickName;
private String avatarUrl;
//1是男的,2是女的
private String gender;
//session_key
private String session_key;
private String token;
}
4.工具类和配置文件
坐标依赖
<!-- httpClient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
配置文件:
server:
port: 19092
spring:
application:
name: weixing-login
redis:
host: 127.0.0.1
port: 6379
wx:
appid: "wx3*********25" # 小程序 appId
secret: "05465b*******a24c32" #小程序 appSecret
grant_type: "authorization_code" #授权类型,此处只需填写 authorization_code
url: "https://api.weixin.qq.com/sns/jscode2session" # 获取appID 的请求地址
HttpClientUtil :
public class HttpClientUtil {
private static Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);
//REQUEST GET
public static String doGet(String url, Map<String, String> param) {
// 创建Httpclient对象
CloseableHttpClient httpclient = HttpClients.createDefault();
String resultString = "";
CloseableHttpResponse response = null;
try {
// 创建uri
URIBuilder builder = new URIBuilder(url);
if (param != null) {
for (String key : param.keySet()) {
builder.addParameter(key, param.get(key));
}
}
URI uri = builder.build();
HttpGet httpGet = new HttpGet(uri); //创建http GET请求
response = httpclient.execute(httpGet);//执行请求
// 判断返回状态是否为200
if (response.getStatusLine().getStatusCode() == 200) {
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
}
} catch (Exception e) {
logger.info("REQUEST GET ExceptionError: [{}]", e.getMessage());
} finally {
try {
if (response != null) {
response.close();
}
httpclient.close();
} catch (IOException e) {
logger.info("REQUEST GET IOExceptionError: [{}]", e.getMessage());
}
}
logger.info("REQUEST GET OK, result={}", resultString);
return resultString;
}
public static String doGet(String url) {
return doGet(url, null);
}
//REQUEST GET
public static String doPost(String url, Map<String, String> param) {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
HttpPost httpPost = new HttpPost(url); // 创建Http Post请求
if (param != null) { // 创建参数列表
List<NameValuePair> paramList = new ArrayList<>();
logger.info("paramList: {}", param);
for (String key : param.keySet()) {
paramList.add(new BasicNameValuePair(key, param.get(key)));
}
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
httpPost.setEntity(entity);// 模拟表单
}
response = httpClient.execute(httpPost);// 执行http请求
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception e) {
logger.info("REQUEST POST ExceptionError: {}", e.getMessage());
} finally {
try {
response.close();
} catch (IOException e) {
logger.info("REQUEST POST IOExceptionError: {}", e.getMessage());
}
}
return resultString;
}
public static String doPost(String url) {
return doPost(url, null);
}
public static String doPostJson(String url, String json) {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
HttpPost httpPost = new HttpPost(url);
StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
httpPost.setEntity(entity);
response = httpClient.execute(httpPost);// 执行http请求
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
logger.info("doPostJson IOExceptionError: {}", e.getMessage());
}
}
return resultString;
}
}
RedisUtils :
/**
* @author an
* @version 1.0
* @date 2020/9/28 12:35
*/
@Component
public class RedisUtils {
@Autowired
private StringRedisTemplate redisTemplate;
private static RedisUtils redisUtils;
@PostConstruct
public void init() {
redisUtils = this;
redisUtils.redisTemplate = this.redisTemplate;
}
/*--------------------------------------key操作-------------------------------------------*/
/**
* 是否存在key
*
* @param key
* @return
*/
public static Boolean hasKey(String key) {
return redisUtils.redisTemplate.hasKey(key);
}
/**
* 设置过期时间
*
* @param key
* @param date
* @return
*/
public static Boolean expireAt(String key, Date date) {
return redisUtils.redisTemplate.expireAt(key, date);
}
/**
* 一键设置过期时间
*
* @param key
* @param value
* @param timeout (以秒为单位)
*/
public static void set(String key, String value, long timeout) {
redisUtils.redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
}
/*--------------------------------------String操作-------------------------------------------*/
/**
* 设置指定 key 的值
*
* @param key
* @param value
*/
public static void set(String key, String value) {
redisUtils.redisTemplate.opsForValue().set(key, value);
}
/**
* 获取指定 key 的值
*
* @param key
* @return
*/
public static String get(String key) {
return redisUtils.redisTemplate.opsForValue().get(key);
}
/*--------------------------------------hash操作-------------------------------------------*/
/**
* 获取存储在哈希表中指定字段的值
*
* @param key
* @param field
* @return
*/
public static Object hGet(String key, String field) {
return redisUtils.redisTemplate.opsForHash().get(key, field);
}
/**
* 存储希表中指定字段的值
*
* @param key
* @param hashKey
* @param value
*/
public static void hPut(String key, String hashKey, String value) {
redisUtils.redisTemplate.opsForHash().put(key, hashKey, value);
}
/**
* 给hash key设置过期时间
*
* @param key
*/
public static void setHashKeyTime(String key, long timeout, TimeUnit unit) {
redisUtils.redisTemplate.expire(key, timeout, unit);
}
/**
* 获取所有给定字段的值
*
* @param key
* @return
*/
public static Map<Object, Object> hGetAll(String key) {
return redisUtils.redisTemplate.opsForHash().entries(key);
}
/**
* 查看哈希表 key 中,指定的字段是否存在
*
* @param key
* @param field
* @return
*/
public static boolean hExists(String key, String field) {
return redisUtils.redisTemplate.opsForHash().hasKey(key, field);
}
/**
* 获取哈希表中字段的数量
*
* @param key
* @return
*/
public static Long hSize(String key) {
return redisUtils.redisTemplate.opsForHash().size(key);
}
}
二、前端一些解释
1. success: function (res){}
res是wx.getUserProfile接口触发后返回微信服务器返回的内容
login() {
wx.getUserProfile({
desc: '必须授权才可以继续使用',
success: res => {
let user = res.userInfo
// 把用户信息缓存到本地
wx.setStorageSync('user', user)
console.log("用户信息", user)
this.setData({
userInfo: user
})
},
fail: res => {
console.log('授权失败', res)
}
})
},
数据动态绑定
{{message}}
// js里如下
Page({
data: {
message: ‘我是动态绑定的数据’
}
})