preface
In August 2017, I created a small program called “Find your book”. Users can manage their own bookshelves/study through this small program, and then match the taste of books and you have the same preferences of people, and displayed on the map.
At that time, after the development of some crazy self-recommendation, by chance, I also met investors willing to do angel investment for this product
This is part of the BP that was written at the time
However, since I didn’t have a clear idea of the business loop and profit model, I decided not to continue, and I returned the investment money to the investors.
The sharing economy is hot in 2017, so a lot of people are thinking about sharing, including me. Now it turns out that most of the sharing economy concepts of that time are dead. The price of books in Our country is very cheap, sharing books can not even afford the logistics cost, and the social system in the business plan can not be set up in a short time.
At that time, I did the whole product design, planning, front-end development and back-end PHP all by myself… I’ve been learning more about uniCloud recently, so I resurrected the idea with UNI-App +uniCloud, since cloud development doesn’t require any server costs anyway.
Don’t want to see a long wordy article can directly jump to the end of the download source
UniCloud cloud development
To be clear in advance, I do not have uniCloud meal, but uniCloud is really good, ali Cloud to the free limit is also high. I have used uniCloud several times to build several apps at no cost. I even used uniCloud for the back end and the Flutter for the front end.
What about the benefits of cloud development? FAAS = Functions as a Service
With cloud development, we developers only need to focus on writing business logic code, and the above knowledge is not relevant to business. The business process for developing a product has also changed dramatically
The traditional process
Cloud-based development processes
UniCloud offers the following services, but these basic services are actually provided by Alibaba Cloud and Tencent Cloud, and you have to choose which service provider to use before using them.
Here directly recommend you to use uniCloud choose Ali cloud, because Tencent really cut ah ~ that point free amount or forget it, but the only benefit of Tencent cloud is Tencent department ecology can be exempted from authentication
Obtain wechat user information
To obtain the openid
uni.login({
provider:"weixin".success:(res) = >{
uniCloud.callFunction({
name:"login".data: {code:res.code
}
})
}
})
Copy the code
AppId and AppSecret obtained from the background of the small program are called in the cloud function of wechat server APIcode2session
const { code } = event;
const res = await uniCloud.httpclient.request(
"https://api.weixin.qq.com/sns/jscode2session?appid="+appId+"&secret="+appSecret+"&js_code="+code+"&grant_type=authorization_code",
{
dataType:"json"})const openid = res.data.openid;
Copy the code
In this way, we have got the OpenID of wechat users, which can be used to establish user identification and user system. All subsequent user product data will be associated with this OpenID.
JWT implements user credentials
There is no such thing as a Session in cloud development, so you can’t use a session-like mechanism to implement user credentials
However, there are more advanced mechanisms at our disposal.
- The server encrypts the user ID or information to be carried into a Token. The encryption key is saved only on the server.
- It is returned to the front end through the login interface, and the front end caches itself.
- Carry this on all subsequent requests
Token
As a parameter, the cloud function obtains Token decryption and checks the validity
Install jsonWebToken dependencies
npm install jsonwebtoken
Copy the code
Using JWT signature, I am here in order not to directly expose OpenID, the key to write a random string, here to save trouble, directly use the small program appSecret
const jwt = require('jsonwebtoken');
/ / token is generated
//jwt.sign(with options such as data, key, expiration time, etc.);
jwt.sign({openid:openid},appSecret,{expiresIn:60*60*24});
Copy the code
The front-end encapsulates the NETWORK request API, and as long as the cached token is found, subsequent requests will be carried automatically. All interfaces that need to verify the user also verify the validity of the token, and then decrypt the OpenID for the user’s data operation.
jwt.verify(token,appSecret);
{openid:openid}
Copy the code
Get the nickname Avatar
Small program SDK has also been iterating, this year a lot of small programs in the user nickname has become wechat users right, is because this interface changed.
Instead of using getUserInfo in the past, we can use getUserProfile to obtain wechat users’ nicknames, profile pictures and other data. It’s just that the API will pop up to the user every time
uni.getUserProfile({
desc: 'To improve member information'.// Mandatory parameter
success: (res) = >{ res.userInfo; }})Copy the code
My personal approach is to exchange for OpenID through login first. Users will then see that they do not have a nickname or profile picture, and will be prompted to synchronize their wechat user information via a button. Click and call getUserProfile to get the information displayed and updated to the user database.
// the cloud function takes arguments
const { userInfo,token } = event;
// Get the database object
const db = uniCloud.database();
// Verify and decrypt the token
const payload = verifyToken(token);
// Update the openID user information in the database
const dbRes = await db.collection("users").where({
openid:payload.openid
}).update({
nickName:userInfo.nickName,
avatarUrl:userInfo.avatarUrl,
gender:userInfo.gender,
country:userInfo.country,
province:userInfo.province,
city:userInfo.city
});
Copy the code
Cloud Database Operations
With the above jsonWebToken-based user credentials, the next business is basically CRUD to other data sets, create bookshelves, upload books, get bookshelf list, get book list, delete bookshelves, delete books…
Library/bookshelf database
constpayload = event.token? verifyToken(event.token):null;
const action = event.action;
let dbRes;
if(action=="create") {// Submit the library name to the content security review
const res = await msgSecCheck(payload.openid,event.name);
if(res.result.suggest! ="pass") {return {err:1.msg:"Content is not secure"};
}
// The security content is written to the database to create the shelf data
dbRes = await db.collection("bookshelfs").add({
owner:payload.openid,
name:event.name,
address:event.address,
geopoint:new db.Geo.Point(event.longitude, event.latitude),
totalbook:0
})
return dbRes;
}
Copy the code
When creating a study, the study name is user-defined and visible to other users. This is called UGC content and must pass content security review…
Implement content security review in uniCloud
const res = await uniCloud.httpclient.request("https://api.weixin.qq.com/wxa/msg_sec_check?access_token="+access_token,{
method:"POST".dataType:"json".headers: {"Content-Type":"application/json"
},
data: {version:"2".openid:"Openid of content producer".scene:2.content:"Text content to be reviewed"}});Copy the code
Our bookshelves needed to be displayed on a map, so we had to let the user select and submit a location. The cloud database also makes it very easy to add location-based indexes, allowing us to list shelf data through location-based query methods
newDb.geo.Point(longitude, latitude)Copy the code
Get library list
The data related to the identity will be verified by token to obtain the OpenID
else if(action=="listmy"){
dbRes = await db.collection('bookshelfs').where({
owner:dbCmd.eq(payload.openid)
})
.orderBy("_id"."desc")
.limit(10)
.get()
}
Copy the code
Look for the study nearest me
else if(action=="listbygeo"){
dbRes = await db.collection('bookshelfs').field({owner:false}).where({
geopoint:dbCmd.geoNear({
geometry: new db.Geo.Point(event.longitude, event.latitude),
maxDistance: 3000.M / / unit
minDistance: 0
})
})
.limit(100)// Set a quantity limit
.get()
}
Copy the code
Modify the study
else if(action=="update") {const res = await msgSecCheck(payload.openid,event.name);
if(res.result.suggest! ="pass") {return {err:1.msg:"Content is not secure"};
}
dbRes = await db.collection("bookshelfs").where({
"_id":dbCmd.eq(event._id),
"owner":dbCmd.eq(payload.openid)
}).limit(1).update({
name:event.name,
address:event.address,
geopoint:new db.Geo.Point(event.longitude, event.latitude)
})
return dbRes;
}
Copy the code
To delete a study
else if(action=="delete"){
dbRes = await db.collection("bookshelfs").where({
"_id":dbCmd.eq(event._id),
"owner":dbCmd.eq(payload.openid)
}).remove();
}
Copy the code
Book database
Through ISBN to climb douban book information
First, scanCodeapi is used to scan the bar code behind the book. After obtaining the bar code information, the cloud function is used to crawl to a certain section to get the book title and cover
let { isbn } = event;
let res = await uniCloud.httpclient.request("https://search.douban.com/book/subject_search?search_text="+isbn+"&cat=1001");
let reg = /window\.__DATA__ = "(.*)"/;
if(reg.test(res.data)){
let bookdata=RegExp. $1;// The data is encrypted and needs to be decrypted
}
Copy the code
Crawl to the information need to decrypt, this article will not tell about the decryption process, partners can see the source code.
Is this reptile illegal? I don’t think it is illegal, because the cover and title information belong to public information and can not be crawled from a certain section. We can also obtain it from other places, such as book e-commerce, such as payment API, etc. In addition, we did not collect the ratings, comments and other data unique to a certain segment.
But if you have another opinion, please help me out in the comments section
Build your own ISBN library
- Upload the cover image to the cloud storage system
let coverImage = await uniCloud.httpclient.request(data.cover_url);
let uploadResult = await uniCloud.uploadFile({
cloudPath:isbn+".jpg".fileContent:coverImage.data
})
Copy the code
- Own ISBN database
let resData = {
isbn:isbn,
title:data.title,// Book title
cover_url:uploadResult.fileID,// The cover is in the cloud storage URL
abstract:data.abstract// Book additional information
}
dbResult = await db.collection("isbnlib").add(resData);
Copy the code
So with our own ISBN database, when users scan the same books next time, the information will be returned directly from our OWN ISBN database without having to crawl. This is also a method to build a database by using the crowdsourcing mechanism
let dbResult = await db.collection("isbnlib").limit(1).where({
isbn:isbn
}).get();
// If the database already has the same ISBN, the database directly returns the information
if(dbResult.affectedDocs>0) {return dbResult.data[0];
}
Copy the code
Bookshelf database
We create a new table of books for bookshelf management and bind the bookshelf ID and ISBN
- Get book information from the ISBN library
const bookInfo = await db.collection("isbnlib").doc(event.isbnid).get();
Copy the code
- Set up book data
Bind the bookshelf ID, ISBNID, openID, etc to determine who owns the book and in which bookshelf.
dbRes = await db.collection("books").add({
owner:payload.openid,
shelfid:event.shelfid,
title:bookInfo.data[0].title,
cover_url:bookInfo.data[0].cover_url,
isbn:bookInfo.data[0].isbn,
isbnid:event.isbnid,
createtime:now,
updatetime:now,
});
Copy the code
- Bookshelf total number field updated
await db.collection("bookshelfs").where({
owner:payload.openid,
_id:event.shelfid,
}).update({
totalbook:dbCmd.inc(1)//inc increments the value of the current field
})
return dbRes;
Copy the code
- Book search
dbRes = await db.collection('isbnlib')
.where({
title=new RegExp(event.keyword, 'i')
})
.orderBy("_id"."desc")
.orderBy("updatetime"."desc")
.limit(12)
.get();
Copy the code
Generate bookshelf posters
Use canvas to generate posters, canvas drawing details we see the project source code. Here I mainly use the applets interface to get the applets with parameters.
There are three kinds of API for generating small program code, among which interface A and interface C are limited in number and can only generate 10W at most. In case this small program user quantity is large, the library bookshelf quantity exceeds 10W, that cannot use interface A. So we’re going to use interface B, which is infinite.
- The cloud function calls the Wxacode interface
const access_token = await getAccessToken();
const res = await uniCloud.httpclient.request("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token="+access_token,{
method:"POST".headers: {"Content-Type":"application/json"
},
data: {scene:"The information that can be obtained in the small program after scanning the code in wechat".page:"Scan code to enter the applet page"}});Copy the code
However, the limitation of interface B is that the scene field is up to 32 characters long and the parameter name can only be called scene. And this interface can only be used with published applets.
conclusion
This is the core technology part of my book sharing project in 2017, which is re-implemented with uniCloud. This article shares the core process like a running account. The reading experience may not be good, but sharing is not easy.
Program source code
Wechat search public number Da Shuai Lao Ape, reply books social small program to get all the source code of this project.