微信小程序-共享单车

共享单车程序开发及数据采集

1. 注册微信小程序

https://mp.weixin.qq.com/

最重要的是知道AppID(小程序ID)

2. 开发者工具下载

https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html

3. 项目结构

1
2
3
4
5
6
7
8
9
10
11
12
13
├── app.js             
├── app.json
├── app.wxss
├── pages
│ │── index
│ │ ├── index.wxml html
│ │ ├── index.js js
│ │ ├── index.json
│ │ └── index.wxss css
│ └── logs
│ ├── logs.wxml
│ └── logs.js
└── utils

4. 显示地图

https://developers.weixin.qq.com/miniprogram/dev/component/map.html

属性 说明
id map主键标识
longitude 中心经度
latitude 中心纬度
controls 页面控件,扫码登录等图标位置
show-location 显示带有方向的当前定位点
bindcontroltap 点击控件时触发
scale 缩放级别,取值范围为3-20
markers 标记点,显示附近车辆
bindregionchange 视野发生变化时触发
style 整个map大小

5. 生命周期

onload 监听页面加载

onReady 监听页面初次渲染完成

6. 获取设备定位

允许设备取值

在app.json

“page”下 添加

1
2
3
4
5
6
7
"pages": [
],
"permission":{
"scope.userLocation": {
"desc": "您的位置将用于车辆查询"
}
},

index.wxml

longitude,longitude的值从js内获取

1
2
3
4
5
6
7
8
<map 
id="mymap"
longitude='{{longitude}}'
latitude='{{longitude}}'
show-location="true"
scale="17"
style='width:100%;height:100%'>
</map>

index.js

获取当前设备信息

wx.getLocation()

获取成功后调用,res中存储了定位信息

1
success: function(res) {}

将值设置为页面全局变量

1
2
3
4
that.setData({
longitude:long,
latitude:lat
})

整合代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Page({
data: {
longitude: 0,
latitude: 0,
},
/**
* 监听页面函数 -- 监听页面加载
*/
onLoad: function () {
//存储当前页面
var that =this;
//模拟器位置
wx.getLocation({
success: function(res) {
//console.log(res);
var long=res.longitude;
var lat = res.latitude;
that.setData({
longitude:long,
latitude:lat
})
},
})
}
})

模拟器无法定位,模拟定位

在线查找经纬度 http://www.gpsspg.com/maps.htm

7. 添加事件

7.1. 添加图片

1
<map controls='{{controls}}'></map>

wx.getSystemInfo 获取设备信息,成功返回res数据

1
2
3
4
wx.getSystemInfo({
success: function(res) {
},
})

通过屏幕宽和高相对摆放组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
that.setData({
controls: [
{
//扫码开锁
//组件标识
id: 1,
//图片路径
iconPath: '/images/lock.png',
//图片位置
position: {
width: 100,
height: 50,
left: width/2-50,
top: height-60
},
//可点击
clickable:true
},
{
//钱包
id: 2,
iconPath: '/images/pay.png',
position: {
width: 35,
height: 35,
left: width - 40,
top: height - 100
},
clickable: true
}
]
})

整合代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
Page({
data: {
longitude: 0,
latitude: 0,
controls:[],
},
//设备信息
onLoad: function () {
//存储当前页面
var that =this;
//模拟器位置
wx.getLocation({
success: function(res) {
//console.log(res);
var long=res.longitude;
var lat = res.latitude;
that.setData({
longitude:long,
latitude:lat
})
},
})
wx.getSystemInfo({
success: function(res) {
//屏幕宽
var width=res.windowWidth;
//屏幕高
var height=res.windowHeight;
that.setData({
controls: [
{
//扫码开锁
id: 1,
iconPath: '/images/lock.png',
position: {
width: 100,
height: 50,
left: width/2-50,
top: height-60
},
clickable:true
},
{
//钱包
id: 2,
iconPath: '/images/pay.png',
position: {
width: 35,
height: 35,
left: width - 40,
top: height - 100
},
clickable: true
},
{
//报警
id: 3,
iconPath: '/images/warn.png',
position: {
width: 35,
height: 35,
left: width - 40,
top: height - 60
},
clickable: true
},
{
//定位点
id: 4,
iconPath: '/images/locate.png',
position: {
width: 35,
height: 35,
left: width/30,
top: height - 60
},
clickable: true
},
{
//图标中心点
id: 5,
iconPath: '/images/cur.png',
position: {
width: 23,
height: 40,
left: width / 2 -12,
top: height /2 - 40
},
},
{
//添加车辆
id: 6,
iconPath: '/images/add.png',
position: {
width: 35,
height: 35,
left: width / 30,
top: height / 30
},
clickable: true
}]
})
},
})
}
})

整体显示

7.2. 绑定事件

1
<map bindcontroltap="controltap"></map>

controltap定义为一个函数

e 返回点击事件数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
page({
onload:funtion(){
//创建一个map上下文,用于调用地图相关方法
this.mapCtx=wx.createMapContext("mymap");
},
/**
* 控件点击事件
*/
controltap: function(e){
//console.log(e);
//包装page页面
var that = this;
var id = e.controlId;
switch(id){
case 1:{
//扫码开锁
break;
}
case 4:{
//返回到定位点
this.mapCtx.moveToLocation();
break;
}
case 6:
{
//添加车辆
break;
}
}
}
})

7.3. 点击事件实现

wx.navigateTo({ })

当点击扫码开锁时扫码

在线制作二维码https://www.liantu.com/

事件 wx.scanCode({})

成功时返回二维码内容

1
2
3
success:function(e){
console.log(e.result);
}

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
controltap: function(e){
//console.log(e);
var that = this;
var id = e.controlId;
switch(id){
case 1:{
//扫码开锁按钮
wx.scanCode({
success:function(e){
console.log(e.result);
}
})
break;
}
case 4:{
//locate定位
this.mapCtx.moveToLocation()
break;
}
case 6:
{
break;
}
}
}

8. SpringBoot

https://start.spring.io/

9. 设置全局数值

app.js中的方法,值是所有页面共享的

设置status,用于定位用户状态

status:0-未注册,1-未支付,2-未实名 ,3-开始用车

1
2
3
4
5
6
7
8
9
10
App({
onLaunch: function () {

},
//页面共享数据
globalData: {
userInfo: null,
status:0
}
})

页面获取全局数据

1
var status=this.getApp().globalData.status;

10. 注册页面

10.1. 添加注册页面

不需要手动添加

app.json中添加register页面,保存,自动生成

这里的顺序即为页面调用顺序

1
2
3
4
5
"pages": [
"pages/index/index",
"pages/register/register",
"pages/logs/logs"
],

当status=0跳转到注册页面

wx.navigateTo()

1
2
3
4
5
if(status==0){
wx.navigateTo({
url: '../register/register',
})
}

10.2. 实现手机绑定

手机国际区号选择

picker

bindchange=”bindCountryCodeChange”

value=”“

range=”

显示

后台数据

data: {

​ countryCodes: [“86”, “80”, “84”, “87”],

​ countryCodeIndex: 0,

},

1
2
3
4
<picker bindchange="bindCountryCodeChange" value="{{countryCodeIndex}}" range="{{countryCodes}}">
<view class="weui-select">{{countryCodes[countryCodeIndex]}} </view>
</picker>

点击事件

1
2
3
4
5
6
bindCountryCodeChange: function (e) {
//console.log('picker country code 发生选择改变,携带值为', e.detail.value);
this.setData({
countryCodeIndex: e.detail.value
})
},

填写手机号

绑定输入事件,获取输入内容

bindinput

1
<input class="weui-input" name="phoneNum" placeholder="请输入手机号码" bindinput="inputPhoneNum"/>

获取

1
2
3
4
5
6
7
8
9
data: {
phoneNum: ""
},
inputPhoneNum: function (e) {
//console.log(e)
this.setData({
phoneNum: e.detail.value
})
},

获取验证码点击事件

1
<view class="weui-vcode-btn" bindtap="genVerifyCode">获取验证码</view>

10.2.1. 连接服务器

wx.request({})

url 请求地址

data 请求参数

method 请求方式

sunccess 响应数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
genVerifyCode: function () {
var index = this.data.countryCodeIndex;
var countryCode = this.data.countryCodes[index];
var phoneNum = this.data.phoneNum;
// console.log(countryCode,phoneNum)
wx.request({
//小程序访问的网络请求协议必须是https,url里面不能有端口号
url: "http://localhost:8080/user/genCode",
data: {
countryCode: countryCode,
phoneNum: phoneNum
},
method: 'GET',
success: function (res) {
wx.showToast({
title: '已发送,请查收!',
duration: 2000
})
//console.log(res)
}
})
},

点击获取验证码,

查看Console 虽然错误但得到一个请求URLhttp://localhost:8080/user/genCode?countryCode=86&phoneNum=123

10.2.2. SpringBoot–redis

采用redis存储数据,实现只存在3分钟

创建UserController.java 接收区号和手机号,使其返回json类型的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.runaccpeted.controller;

import javax.annotation.Resource;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.runaccpeted.service.UserService;

@Controller
@RequestMapping("/user")
public class UserController {
@Resource
UserService service;

@RequestMapping("/genCode")
@ResponseBody
public String genCode(String countryCode,String phoneNum){
String code=service.register(countryCode,phoneNum);
//System.out.println(code);
return code;
}

}

对应创建UserService接口 进行操作

1
2
3
4
5
6
7
package com.runaccpeted.service;

public interface UserService {

String register(String countryCode, String phoneNum);

}

创建具体实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.runaccpeted.service.impl;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.runaccpeted.dao.UserDao;
import com.runaccpeted.service.UserService;

@Service
public class UserServiceImpl implements UserService {

@Resource
UserDao dao;

@Override
public String register(String countryCode, String phoneNum) {
return dao.register(countryCode,phoneNum);
}
}

对应数据库dao层,对接数据库

需要添加redis依赖

1
2
3
4
5
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置redis

1
2
3
4
5
6
7
8
9
10
11
12
#配置redis
spring.redis.host=192.168.0.101 #本地IP

spring.redis.port=6379

spring.redis.pool.max-active=20

spring-redis.pool.max-idle=10

spring-redis.pool.min-idle=10

spring-redis.pool.max-wait=-1

10.2.3. 腾讯云短信服务

https://console.cloud.tencent.com/smsv2

需要实名认证! 没上线怎么认证,又不是企业

记录SpringBoot操作流程

https://cloud.tencent.com/document/product/382/13613

添加依赖

1
2
3
4
5
6
 <!-- 短信云服务 -->
<dependency>
<groupId>com.github.qcloudsms</groupId>
<artifactId>qcloudsms</artifactId>
<version>1.0.6</version>
</dependency>

使用

将appid,appkey永久存入redis中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package com.runaccpeted.dao;


import java.io.IOException;
import java.util.concurrent.TimeUnit;

import org.json.JSONException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import com.github.qcloudsms.SmsSingleSender;
import com.github.qcloudsms.SmsSingleSenderResult;
import com.github.qcloudsms.httpclient.HTTPException;

@Component
public class UserDao {

@Autowired
private StringRedisTemplate redisTemplate;

public boolean register(String countryCode, String phoneNum) {

int appid = Integer.parseInt(redisTemplate.opsForValue().get("appid"));
String appkey = redisTemplate.opsForValue().get("appkey");
boolean flag=true;

//生成4位验证码
String code="";
for(int i=0;i<4;i++){
code+=(int)(Math.random()*10)+"";
}
//手机号,验证码保存到redis中 300s
redisTemplate.opsForValue().set(phoneNum, code, 300,TimeUnit.SECONDS);

//腾讯云短信业务
SmsSingleSender ssender = new SmsSingleSender(appid, appkey);
try {
//send(单发, 国际区号, 手机号, 短信模板, "", "");
//短信模板与配置中一致
SmsSingleSenderResult result = ssender.send(0, countryCode, phoneNum, "您的登陆验证码为"+code, "", "");

//手机号,验证码保存到redis中 300s
redisTemplate.opsForValue().set(phoneNum, code, 300,TimeUnit.SECONDS);
} catch (HTTPException | JSONException | IOException e) {
flag=false;
e.printStackTrace();
}
return flag;
}
}

。。。没认证手机是收不到的。。。

10.2.4. 不调用腾讯云短信服务

随机生成四位数字,充当验证码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.runaccpeted.dao;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

import org.json.JSONException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import com.github.qcloudsms.SmsSingleSender;
import com.github.qcloudsms.SmsSingleSenderResult;
import com.github.qcloudsms.httpclient.HTTPException;

@Component
public class UserDao {

@Autowired
private StringRedisTemplate redisTemplate;

public String register(String countryCode, String phoneNum) {
//生成4位验证码
String code="";
for(int i=0;i<4;i++){
code+=(int)(Math.random()*10)+"";
}
//手机号,验证码保存到redis中 300s
redisTemplate.opsForValue().set(phoneNum, code, 300,TimeUnit.SECONDS);
return code;
}
}

微信直接接收验证码

1
2
3
wx.showModal({
content:'您的注册验证码为'+res.data
})

需要修改redis保护模式

vi /usr/local/Cellar/redis/5.0.5/bin/redis.conf

protected-mode no

重启 redis-server

微信小程序点击获取验证码

redis

5分钟后

10.2.5. 验证用户输入

取用户输入的手机号和验证码与redis中进行匹配

整个注册页面的两个input框包在form中

bindsubmit 绑定提交事件

1
2
3
4
5
<form bindsubmit="formSubmit">
<input class="weui-input" name="phoneNum" placeholder="请输入手机号码" bindinput="inputPhoneNum"/>
<input class="weui-input" name="verifyCode" placeholder="请输入验证码" />
<button class="weui-btn" type="primary" formType="submit">确定</button>
</form>

提交事件 返回true/false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
formSubmit: function (e) {
var phoneNum = e.detail.value.phoneNum;
var verifyCode = e.detail.value.verifyCode;
wx.request({
url: 'http://localhost:8080/user/verify',
method:"POST",
header:{
'content-type': "application/x-www-form-urlencoded"
},
data:{
phoneNum:phoneNum,
verifyCode:verifyCode
},
success:function(res){
console.log(res);
}
})
}

取redis中的手机号对应验证码

Controller

1
2
3
4
5
@RequestMapping("/verify")
@ResponseBody
public boolean verify(String phoneNum,String verifyCode, HttpServletRequest request){
return service.verify(phoneNum,verifyCode);
}

service

1
2
3
4
@Override
public boolean verify(String phoneNum, String verifyCode) {
return dao.verify(phoneNum,verifyCode);
}

UserDao.java

1
2
3
4
5
6
7
8
public boolean verify(String phoneNum, String verifyCode) {
String code = redisTemplate.opsForValue().get(phoneNum);
//System.out.println("redis "+code);
if(verifyCode.equals(code)){
return true;
}
return false;
}

11. 注册用户到MongoDB

当/user/verify 返回true时,应该传入手机号和注册时间,注册到mongodb中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
success:function(res){
console.log(res);
if(res.data){
wx.request({
url: 'http://localhost:8080/user/register',
method:"POST",
//保存到mongodb中
data:{
phoneNum:phoneNum,
regDate:new Date(),
},
success: function (res) {
console.log(res)
}
})
}
}

将整个json数据映射到一个User类

@Document(collection=”user”) 注解标识为映射mongodb中的user表

@Id id为主键 自动对应_id

@Indexed 为其创建索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package com.runaccpeted.pojo;


import java.util.Date;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;

@Document(collection="user")
public class User {

@Id
private int id;
@Indexed
private String phoneNum;

private Date regDate;

private String nickName;

private String uname;

private double money;


public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getPhoneNum() {
return phoneNum;
}
public void setPhoneNum(String phoneNum) {
this.phoneNum = phoneNum;
}
public Date getRegDate() {
return regDate;
}
public void setRegDate(Date regDate) {
this.regDate = regDate;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
@Override
public String toString() {
return "User [id=" + id + ", phoneNum=" + phoneNum + ", regDate=" + regDate + ", nickName=" + nickName
+ ", uname=" + uname + ", money=" + money + "]";
}

}

传入的数据通过@RequestBody 会自动通过set/get注入到User类中

1
2
3
4
5
6
@RequestMapping("register")
@ResponseBody
public boolean register(@RequestBody User user){
//System.out.println(user);
return service.register(user);
}

service层

1
2
3
4
@Override
public boolean register(User user) {
return dao.register(user);
}

Dao层

1
2
3
4
5
6
7
8
public boolean register(User user) {
User u=mongoTemplate.insert(user);
System.out.println(user);
if(u!=null){
return true;
}
return false;
}

查看moogdb

use bike

db.user.find()

❌注册多个手机号

duplicate key error collection

11.1. _id 并不会自增

创建一个集合counters存入id,value

db.counters.insert({_id:”aid”,value:0})

每增加一条记录,令value自增+1,更新counters,取value值作为_id

counters中始终只有一条记录,故_id不会重复

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public boolean register(User user) {
//从1开始自增,实现唯一
user.setId(getIncrement("aid"));
User u=mongoTemplate.insert(user);
System.out.println(user);
if(u!=null){
return true;
}
return false;
}

private int getIncrement(String id){
Query query = new Query(Criteria.where("_id").is(id));
Update update = new Update();
//value自增
update.inc("value",1);
mongoTemplate.updateFirst(query, update, Counters.class);
//重新查找counters
Counters counters=mongoTemplate.findOne(query, Counters.class);
//取value值
return counters.getValue();
}

实现

11.2. 跳转页面&存数据

当/user/register返回true时,跳转到充值页面

注册充值页面

1
2
3
4
5
6
"pages": [
"pages/index/index",
"pages/register/register",
"pages/deposite/deposite",
"pages/logs/logs"
],

register.js

1
2
3
4
if(res.data){
wx.navigateTo({
url: '../deposite/deposite',
})

此时已完成注册手机号,应当保存用户状态,将状态设为全局变量

1
2
3
//更新内存中的数据
getApp().globalData.status = 1
getApp().globalData.phoneNum = phoneNum

并同时保存到手机内存中

1
2
wx.setStorageSync("status",1)
wx.setStorageSync("phoneNum",phoneNum)

index页可以根据status状态在用户退出程序时保存用户状态,在扫码开锁的点击事件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
case 1:{
//扫码开锁按钮
//数据来源于磁盘
var status=getApp().globalData["status"];
if(status==0){
wx.navigateTo({
url: '../register/register',
})
}else if(status==1){
wx.navigateTo({
url: '../deposite/deposite',
})
}
else if (status == 2) {
wx.navigateTo({
url: '../identify/identify',
})
}
}

其实数据可以来自内存,也可以是全局变量,新建myUtil.js

1
2
3
4
5
6
7
8
9
10
11
// 查找的DATA
function get(key) {
//内存
var status = wx.getStorageSync(key);
//如果没有就在当前操作周期的全局找
if (!status) {
//全局变量
status = getApp().globalData[key];
}
return status;
}

index.js导入包

1
var myUtils=require("../../utils/myUtil.js")

使用

1
var status=myUtils.get("status");

12. 充值页面

并不能实现个人账号支付,用loading模拟支付时长

点击按钮事件绑定 bindtap

1
<button type='primary' bindtap='deposit'>去充值</button>

事件

wx.showModal({}) 提示框,res.confirm点确定事件,按取消,页面不动

wx.showLoading({}) mask启动一个面罩,整个页面不能点击

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
deposit:function(){
var that = this;
//获取用户的手机号
var phoneNum = myUtils.get("phoneNum")
wx.showModal({
title:"提示",
content:"是否进行充值",
success:function(res){
if(res.confirm){
wx.showLoading({
title: '正在充值',
mask:true
})
}
}
})
}

页面

请求充值,存入手机号和金额,成功后进入实名认证页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
wx.request({
url: 'http://localhost:8080/user/deposite',
method:"POST",
// header:{
// 'content-type': "application/x-www-form-urlencoded"
// },
data:{
phoneNum:phoneNum,
deposit:299,
},
//成功说明请求成功,及时关闭遮罩
success:function(res){
//console.log(res);
// 关闭充值中的加载对话框
wx.hideLoading()
if(data.error){
wx.navigateTo({
url: '../identify/identify',
})
//更新用户状态
getApp().globalData.status = 2
wx.setStorageSync("status",2)
}

}
})

13. 实名认证页面

mongodb中存入用户名和身份证id,更新phoneNum相同的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

formSubmit: function(e){
//获取全局变量
var phoneNum = myUtils.get("phoneNum");
//获取输入的姓名和身份证号
var name = e.detail.value.name;
var idNum = e.detail.value.idNum;
//编辑遮罩
wx.showLoading({
title: '正在实名认证',
mask: true,
})
wx.request({
url: 'http://localhost:8080/user/identify',
method: 'POST',
data: {
//传入参数
phoneNum: phoneNum,
uname: name,
idNum: idNum,
},
success: function (res) {
if(res.data){
wx.hideLoading();
getApp().globalData.status = 3
wx.setStorageSync('status', 3)
wx.navigateTo({
url: '../index/index',
})

}
},
//响应404,400,500等
fail:function(){
wx.hideLoading()
wx.showModal({
title: '提示',
content: '服务器繁忙,请销后再试',
showCancel: false
})
}
})
}

同样使用RequestBody接收数据

1
2
3
4
5
6
 @RequestMapping("/identify")
@ResponseBody
public boolean identify(@RequestBody User user){
return service.identify(user);

}

mongodb更新语句

1
2
3
4
5
6
7
8
9
10
11
public boolean identify(User user) {
Query query = new Query(Criteria.where("phoneNum").is(user.getPhoneNum()));
Update update = new Update();
update.set("idNum", user.getIdNum());
update.set("uname", user.getUname());
UpdateResult result= mongoTemplate.updateFirst(query, update, User.class);
if(result.getModifiedCount()!=0){
return true;
}
return false;
}

14. 附近车辆

14.1. 添加车辆 - 临时数据

添加车辆图标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
that.setData({	
controls:[
{
//添加车辆
id: 6,
iconPath: '/images/add.png',
position: {
width: 35,
height: 35,
left: width / 30,
top: height / 30
},
clickable: true
}
]
})

添加点击事件

这里传入的是location:[log,lat] [经度,纬度]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
controltap:function(e){
var id = e.controlId;
switch(id){
case 6:
//添加车辆
var bikes=that.data.markers;
//移动后获取中心点
this.mapCtx.getCenterLocation({
success: function (res) {
//console.log(res);
var log=res.longitude;
var lat =res.latitude;
var bikeno=myUtils.get("bikeno");
//将数据发送到后台
wx.request({
url: 'http://localhost:8080/bike/add',
data: {
bikeno:bikeno,
location:[log,lat],
status:0
},
method:'POST',
success: function(res){
bikeno=bikeno+1;
getApp().globalData.bikeno=bikeno;
//console.log(getApp().globalData.bikeno);
//保存到手机存储卡中
wx.setStorageSync("bikeno", bikeno)
//findBikes(log,lat,that);
}
})
}
})
break;
}
}

14.2. 注册车辆到mongodb

新建bikecounters用于bikes集合主键自增

1
2
db.bikecounters.insert({_id:"aid",value:0})
db.bikecounters.find()

对应新建pojo-BikeCounters

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.runaccpeted.pojo;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;

@Document(collection="bikecounters")
public class BikeCounters {

@Id
private String id;
@Indexed
private int value;

public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
@Override
public String toString() {
return "BikeCounters [id=" + id + ", value=" + value + "]";
}
}

存储bikes,[id主键,bikeno车编号,location经纬度,status车辆状态]

@GeoSpatialIndexed 标记为其创建索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package com.runaccpeted.pojo;

import java.util.Arrays;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.GeoSpatialIndexType;
import org.springframework.data.mongodb.core.index.GeoSpatialIndexed;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;

@Document(collection="bikes")
public class Bike {
@Id
private int id;

@Indexed
private int bikeno;

@GeoSpatialIndexed(type=GeoSpatialIndexType.GEO_2DSPHERE)
private double[] location;

public double[] getLocation() {
return location;
}

public void setLocation(double[] location) {
this.location = location;
}

private int status;

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public int getBikeno() {
return bikeno;
}

public void setBikeno(int bikeno) {
this.bikeno = bikeno;
}

public int getStatus() {
return status;
}

public void setStatus(int status) {
this.status = status;
}

@Override
public String toString() {
return "Bike [id=" + id + ", bikeno=" + bikeno + ", location=" + Arrays.toString(location) + ", status="
+ status + "]";
}
}

添加车辆

注入车编号使用的是手机内存中存入全局变量bikeno:100000

每次调用bike/add bikeno+1 ,所以会存在bikeno不会相同,而经纬度相同。

当经纬度相同时,用更新,不同时,用插入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public boolean add(Bike bike){
Query query = new Query(Criteria.where("location").is(bike.getLocation()));
if (mongoTemplate.findOne(query, Bike.class)!=null) {
Update update = new Update();
update.set("bikeno", bike.getBikeno());
update.set("status", bike.getStatus());
UpdateResult result= mongoTemplate.updateFirst(query, update, Bike.class);
if (result.getModifiedCount()!=0) {
return true;
}else{
return false;
}
}else{
bike.setId(getIncrement("aid"));
Bike b = mongoTemplate.insert(bike);
if (b!=null) {
return true;

}else {
return false;
}
}
}

14.3. 显示附近车辆

findBikes(log,lat,that);

1
2
3
4
5
6
7
8
9
10
11
function findBikes(longitude,latitude,that){
wx.request({
url: "http://localhost:8080/bike/findNear",
method: "POST",
data: {
location: [longitude,latitude]
},
success: function (res) {
console.log(res)
}
})

从mongodb中读取附近车辆信息

1
2
3
4
5
6
7
8
9
10
11
12
13
public List<GeoResult<Bike>> findNear(Bike bike) {
//中心位置
Point location = new Point(bike.getLocation()[0], bike.getLocation()[1]);
//获取车辆附近信息
NearQuery query = NearQuery.near(location);
//附近200m
query.maxDistance(0.2,Metrics.KILOMETERS);
//车辆状态为0 未使用 ,取20辆
query.query(new Query(Criteria.where("status").is(0)).limit(20));

GeoResults<Bike> bikes=mongoTemplate.geoNear(query, Bike.class);
return bikes.getContent();
}

获取响应数据

“errmsg” : “no such command: ‘geoNear’”

?? mongodb没安装好,重装还是一样问题??版本问题,低版本下载?

安装mongodb-osx-ssl-x86_64-4.0.12.tgz 运行正确

返回数据

获取到经纬度,用map的markers属性,注入图标

1
2
3
4
5
6
7
8
9
10
11
12
13
var bikes = res.data.map((geoResult) => {
return {
longitude: geoResult.content.location[0],
latitude: geoResult.content.location[1],
width: 30,
height: 35,
iconPath: '/images/bike.png'
}
}
)
that.setData({
markers: bikes
})

实现效果

# 所用mongo命令

use bike

db.createUser({user:”bike”,pwd:”123456”,roles:[“readWrite”]})

db.auth(“bike”,”123456”)

db.usercounters.insert({_id:”aid”,value:0})

db.user.find()

db.usercounters.find()

db.usercounters.remove({})

db.user.drop()

db.bikecounters.insert({_id:”aid”,value:0})

db.bikes.find()

db.bikecounters.find()

db.bikecounters.remove({})

15. 扫码页面

本文结束  感谢您的阅读