Recently, I need to help my girlfriend implement a wechat app, so I went to learn about the development of the app. For the development of wechat applets, I haven't been in touch with it before (but I have some experience in front-end development). As a complete novice, the starting materials must be Wechat applet development document According to the experience of the development process these days, it's better to go through the official website documents in detail first. Most of the holes are due to not reading the documents in detail, while the other part is due to not writing the documents...
Note: the project architecture is: C/S architecture, the front end is completely separated from the back end, the front end is wechat applet, and the back end is springboot
The pits encountered in the development process are mainly as follows:
- Wechat login implementation module
In the development documentation, Logon logic The description is very clear. First, applet wx.login() in the small program to get the temporary login certificate code provided by WeChat, then transmit code to the developer server (our back-end server), then use the exclusive appid and appsecret, code (the code that just passed the front end) as the three input, and call the WeChat authorized url (https://api.weixin.qq.com/sns/JSCODE2sess). Ion? Appid = appid & SECRET = SECRET & JS? Code = JSCODE & Grant? Type = authorization? Code (appid is appid, SECRET is appsecret, JSCODE is code, and others remain unchanged)), wechat authorization center will return two fields: user's unique identification OpenID and session key session? Key; for security, session? Key is not used as session ID, but a session ID is generated by itself, I use jwt technology to generate and verify the sessionId.
java implementation code:
@PostMapping("/wxLogin") public Result wxLogin(LoginVo loginVo) { log.info("wxLogin request:{}", loginVo); String url = "https://api.weixin.qq.com/sns/jscode2session"; Map<String, String> param = new HashMap<>(); param.put("appid", Constants.WEIXIN_APPID); param.put("secret", Constants.WEIXIN_SECRET); param.put("js_code", loginVo.getCode()); param.put("grant_type", "authorization_code"); String wxResult = HttpClientUtil.doGet(url, param); log.info("weixin response:{}", wxResult); WXSessionVo wxSessionVo = FastJsonUtil.fromJson(wxResult, WXSessionVo.class); if (wxSessionVo == null){ return Result.fail(LOGIN_FAIL.getDesc(), LOGIN_FAIL.getCode()); } UserInfo oldUserInfo = userInfoService.queryByOpenId(wxSessionVo.getOpenid()); String token = ""; if (oldUserInfo == null) { //Write to database UserInfo newUserInfo = new UserInfo(); newUserInfo.setHeaderUrl(loginVo.getHeaderUrl()); newUserInfo.setUserName(loginVo.getUserName()); newUserInfo.setOpenId(wxSessionVo.getOpenid()); newUserInfo.setGmtDate(System.currentTimeMillis()); userInfoService.save(newUserInfo); log.info("after userInfoService save, userInfo:{}", newUserInfo); token = TokenUtil.sign(newUserInfo.getId()); } else { token = TokenUtil.sign(oldUserInfo.getId()); } return Result.success(token); } @Data public class LoginVo implements Serializable { private String userName; private String headerUrl; private String code; private static final long serialVersionUID = 1L; }
Front end code implementation:
wx.login({ success: function(res) { var code = res.code; //Logon Credentials if (code) { //2. Call get user information interface wx.getUserInfo({ success: function(res) { app.globalData.userInfo = res.userInfo; //3. Request your own server, var argu = { code: code, userName: res.userInfo.nickName, headerUrl: res.userInfo.avatarUrl, } //This place is changed to wx.request method to initiate http request. For convenience, I encapsulated wx.request method httpClient.login(argu).then((data) => { console.log("login http", data); if (data.status == 200) { //Then set the token on the header of each http request. The back-end setting interceptor takes the token to verify the login logic app.globalData.token = data.data; //If the back-end verification is successful, then directly jump to the home page wx.switchTab({ url: '../index/index' }) } else { wx.switchTab({ url: '../auth/auth' }) } }).catch(e => console.log(e)); }, fail: function() { console.log('Failed to get user information') } }) } else { console.log('Failed to get user login status!' + r.errMsg) } }, fail: function() { console.log('Landing failed') } });
It needs to be emphasized here that the login authorization page is a separate page, not the home page. How to start the page before jumping to the home page when loading the applet? stay Global configuration In, there is a bold sentence, the first item of the array represents the initial page (home page) of the applet. All authorized pages can be executed first as long as they are placed in the first item in pages; after the login is successful, they will jump to the real home page.
//app.json { "pages": ["pages/auth/auth", "pages/index/index"] }
Note: at that time, because I didn't carefully read the official documents, I saw from the demo downloaded by github that the authorized landing page was not called by the home page, but it was executed before the home page. I was deeply confused. After a long time of troubleshooting, it was suspected that it was the page configuration sequence, and then reread the document to find out the answer.
- Non button button button, through bindtap = "clickFunctionName", after clicking to trigger the corresponding method, specific parameters need to be passed.
- Scenario: for displaying item data of article list in for loop, click a piece of data to trigger the corresponding method, but you need to know the unique identification id of this piece of data
- Implementation method: use the data parameter method in wxml. When you click the implementation method toDiary: function(event), you can get the value of the parameter. That is to say, use event.currentTarget.dataset.patameter in js to get the bound value. If you need to transfer multiple parameters, set multiple data parameters.
Note: there is a big hole here, which is used to the java Naming Method hump naming method. When data parameter binds parameters, do not use this naming method at last, because in the event object, the parameterName will be automatically converted to lowercase, so the anti human design is a real hole, for example, in wxml, data traceability id = "1", and then in js, e.currentt Arget.dataset.traditionid, you can never get the value of traditionid, but if e.currenttarget.dataset.traditionid can get the value of traditionid; therefore, in an applet, no matter you are data-traditionid = 1, or data-traditionid = 1, js can only get the value of e.currenttarget.dataset.traditionid parameter in lowercase.
<view class="content" data-tranctionid="{{item.id}}" data-type="{{item.type}}" bindtap="toDiary"> toDiary: function(e) { console.log("toTopicOrDiary click", e) if (e.currentTarget.dataset.type == app.globalData.publishTypeEnum.topic) { wx.navigateTo({ url: '../topic/topic?topicId='+e.currentTarget.dataset.tranctionid }) }else{ wx.navigateTo({ url: '../diary/diary?diaryId='+e.currentTarget.dataset.tranctionid }) } },
- Front end page url jump, get the parameters on the url link on the new page
- Scenario: from the list of articles, click Find an article to jump to the details of the article
- Implementation method: This is different from the normal way for web js to obtain the parameters on the url. In the wechat applet, the parameters in the url are put into the options object of the new page onload(options) method. The way to obtain the parameter value is options.parameterName.
// url: '../topic/topic?topicId='+e.currentTarget.dataset.tranctionid onLoad: function(options) { console.log('options', options); var diaryId = options.topicId; }
Here, the hump naming method can be used for the parameter naming of url. The parameterName in your options will not be converted to lowercase,,,
- After dynamic data binding, how to change the value of variables in js? The page will automatically render the new value of variables
- Scenario: the number of comments on an article is displayed. When you click to view the details of an article, you need to go to the backend first to get the current number of comments, and then I add a comment at the bottom, so the number of comments is increased by 1.
- Realization way
<view class="operation-btn flex-item"> <text>{{commentNum}}</text> </view> //js data: { commentNum: 0 }, //There are two ways to modify the values of attributes in data: 1. this.data.commentNum = this.data.commentNum + 1; 2. this.setData({ commentNum: this.data.commentNum + 1 }) //The difference between the two is that, first, only the value of commentNum in js will be changed, but the value of commentNum in the page will not be re rendered and refreshed, //The second is that the value of the commentNum bound in the page that can be implemented is also refreshed. There is no hint in the official documents,,,
- Upload image by uploader component
- Scene: in order to upload pictures, wechat official service is directly used The uploader component of the weUI framework , to be honest, it may be because of the brand-new whitespace of small program development. It feels that the component demo is too simple to write, so how to upload to its own server and the problem of multi graph upload...
- Implementation mode:
uplaodFile(files) { console.log('upload files', files) var _this = this; //File upload function, return a promise return new Promise((resolve, reject) => { for (var i = 0; i < files.tempFilePaths.length; i++) { wx.uploadFile({ //I had to use wx.uploadFile instead of wx.request. I tried this place for half a day, but it was not successful. I found the right demo on github before I found the problem url: URL.UPLOAD_DIARY_FILES, // Upload the interface address of your own server filePath: files.tempFilePaths[i], name: 'file', // Parameter name, the name of the parameter when the backend receives it formData: {}, header: { "Content-Type": "multipart/form-data", //Transfer file must be of form data type 'Authorization': app.globalData.token }, success: (res) => { // After the image is uploaded successfully, the backend will return the id saved to the file storage path //Note that the data returned by the backend return is in res.data, and the data is in jsonString (string format), not in json format, //I said that data.data has always reported an error, so if you want to get a field value by referencing the field with an object, you must first parse JSON.parse. This is so important that the official document doesn't even explain,,,, var data = JSON.parse(res.data); _this.data.picUrlIds.push(data.data); }, fail: (err) => { console.log("error", err) } }) } }) },
Note: due to the special role of the applet, we will not share all the source code of the applet. Please understand! If you have any questions, you can comment and discuss with me. After all, I am just a novice.