本文讲解讲解微信小程序开发的相关的内容。
这里假设我们已经通过微信开发者工具新建了项目。
获取用户地理位置
通过用户授权获取用户的地理位置信息,授权一次之后,下次不需要进行授权。
添加 wxml
html
<!--pages/index/index.wxml-->
<scroll-view class="scrollarea" scroll-y type="list">
<view class="view1" bindtap="getLocation">点击获取用户位置</view>
<view>latitude: {{latitude}}</view>
<view>longitude: {{longitude}}</view>
</scroll-view>
上面有方法 getLocation
,点击 点击获取用户位置
按钮,获取用户当前的经纬度,并在页面上展示出来。
添加 js
javascript
// pages/index/index.js
Component({
data: {
latitude: 0,
longitude: 0
},
methods: {
getLocation() {
var that = this;
wx.getLocation({
type: 'gcj02',
success (res) {
const latitude = res.latitude
const longitude = res.longitude
that.setData({
latitude: latitude,
longitude: longitude
})
},
fail: function (error) {
wx.showModal({
title: '授权提示',
content: '需要获取您的地理位置信息,请打开设置页面手动授权。',
showCancel: false,
success: function (modalRes) {
if (modalRes.confirm) {
wx.openSetting({
success: function (settingRes) {
if (settingRes.authSetting['scope.userLocation']) {
console.log('用户已手动授权');
} else {
console.log('用户依然拒绝授权');
}
}
});
}
}
});
}
})
}
},
})
我们设置了对应的经纬度变量 - latitude
和 longitude
。通过调用微信方法 wx.getLocation
来获取当前用户的经纬度信息。如果用户允许授权,则直接将获取到的经纬度进行赋值;如果用户拒绝授权,则来到 fail
的部分,我们调用弹窗方法 wx.showModal
对用户进行提示,跳转到用户手动授权地理位置的页面。如果用户依旧不进行授权,我们可以对用户的其他操作进行限制,比如,直接限制进入详情页面。
这里我们为了更加准确获到用户的地理位置信息,使用了 type: 'gcj02'
。
当然,只是通过配置上面的内容信息,我们还不能获取到用户的地理位置信息。我们还得添加点配置信息。
添加配置信息
我们需要在 app.json
文件中,添加下面的配置信息:
json
{
# 其他内容
"permission": {
"scope.userLocation": {
"desc": "你的位置信息将用于小程序位置接口的效果展示"
}
},
"requiredPrivateInfos": ["getLocation"]
}
👌,这时候,我们点击 点击获取用户位置
,进行允许后,就可以得到用户的位置信息了。
PS: 注意⚠️ 模拟器获取的用户位置不准确,真机上获取准确
获取用户 openId
获取用户的 openId
需要后端服务来配合。
什么是 OpenId? 当微信用户登录公众号或小程序时,微信平台为每一个微信登录者分配的一个唯一标识符号。
前端部分
我们封装接口请求,在 utils/request.js
文件中,添加内容:
javascript
function wxRequest(config) {
// 其他内容
// 服务器基地址
let serverUrl = 'http://127.0.0.1:8080/';
// 请求地址
let url = serverUrl + config.url;
return new Promise(function(resolve, reject) {
// 调用微信的请求
wx.request({
url: url,
data: data,
// 返回的数据类型
dataType: dataType,
enableCache: false,
enableHttp2: false,
enableQuic: false,
method: method,
header: header,
responseType: responseType,
timeout: timeout,
success: (res) => {
console.log('requestData', res)
if(res.cookies != null && res.cookies.length != 0) {
wx.setStorageSync('sessionId', res.cookies[0])
}
resolve(res)
},
fail: (error) => {
console.log('requestException', error)
reject(error)
}
})
})
}
exports.wxRequest = wxRequest
上面我们调用了本地的服务,并将其请求进行封装后导出。
因为,我们一进入小程序就获取用户的 openId
,所以,我们在入口文件 ./app.js
中添加下面的内容:
javascript
// app.js
const app = getApp();
const httpRequest = require('./utils/request.js')
App({
onLaunch() {
/**
* 检查微信用户是否已经登陆到后台服务器
* 已经登陆的标记,数据库中存在 OPENID
*/
let code = null;
// 调用 login 接口
wx.login({
success: (res) => {
code = res.code;
// 得到登陆用户的临时 code
wx.getUserInfo({
success: (data) => {
// 向开发者服务器发送请求
let api = 'wx/getLoginCertificate'
let config = {
url: api,
method: 'POST',
data: {
code: code
}
}
let promise = httpRequest.wxRequest(config);
promise.then(res => {
let isHas = null;
// 有没有完整的微信登陆者信息
isHas = res.data == 0 ? false : true;
app.globalData.isHasUserInfo = isHas
}).catch(error => {
console.log('fail ', error)
})
}
})
}
})
},
globalData: {
userInfo: null,
isHasUserInfo: false
}
})
在前端中,我们将用户登陆生成的随机的 code
等信息,发送给后端,由后端去请求相关的内容,返回 openId
等信息回来给前端。
我们用本地地址来调试接口,所以要在微信开发工具中设定允许本地地址调试。本地设置 -> "勾选" 不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书
。
后端部分
下面,我们来讲讲后端的部分。假设我们新建的项目是 com.wechat/wechatservice
。
后端的开发环境:
bash
- java 版本 17
- spring boot 版本 3.2.1
- Postman - Version 8.12.1
- Navicat Premium - 16.0.12
我们安装的依赖如下:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.modelmapper/modelmapper -->
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>3.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
其他相关的文件内容如下。
配置好 mapper
,在入口文件 com.wechat.wechatservice/WechatServiceAppliation.java
中添加内容:
java
package com.wechat.wechatservice;
@SpringBootApplication
public class WechatServiceApplication {
// 使用 model mapper
@Bean
public ModelMapper modelMapper() {
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration()
.setMatchingStrategy(MatchingStrategies.STRICT); // https://stackoverflow.com/questions/58838964/modelmapper-failed-to-convert-java-lang-string-to-java-lang-long
return modelMapper;
}
public static void main(String[] args) {
SpringApplication.run(WechatServiceApplication.class, args);
}
}
这里我们使用过本地的数据库,所以在 resources/application.properties
中添加内容:
java
spring.datasource.url=jdbc:mysql://localhost:3306/todo_management
spring.datasource.username=root
spring.datasource.password=
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=update
接着我们创建 bean
包,其下添加 WxUserInfo.java
内容,这里因为是 demo
,我们怎么简单怎么来:
java
package com.wechat.wechatservice.bean;
@Getter
@Setter
public class WxUserInfo {
String code;
}
添加 entity
包,其下添加 WxUserInfo.java
文件,添加内容:
kotlin
package com.wechat.wechatservice.entity;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "wx_users") // 表名为 wx_users
public class WxUserInfo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "open_id", nullable = false)
private String openId;
}
新建 dto
包,在其下添加文件 WxUserInfoDto.java
,其内容是 entity
中的映射,其内容如下:
java
package com.wechat.wechatservice.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class WxUserInfoDto {
private String openId;
}
新建 repository
包,添加文件 WxUserInfoRepository.java
,内容如下:
java
package com.wechat.wechatservice.repository;
public interface WxUserInfoRepository extends JpaRepository<WxUserInfo, Long> {
}
添加 util
方法,这样方便管理相关的微信小程序的参数,当然,你也可以放在 application.properties
文件中管理。
java
package com.wechat.wechatservice.utils;
public class WxUtil {
private final static String APP_ID = "wx430***";
private final static String APP_SECRET = "60**";
private final static String WX_LOGIN_SEVER_URL = "https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&js_code={2}&grant_type=authorization_code";
// 获取微信服务请求地址
public static String getWxServerUrl(String code) throws IOException {
String url = MessageFormat.format(WX_LOGIN_SEVER_URL, new String[]{APP_ID, APP_SECRET, code});
return url;
}
}
再新建 HttpClient.java
文件,内容如下:
java
package com.wechat.wechatservice.utils;
public class HttpClientUtils {
/**
* GET 请求
*/
public static String getRequest(String url) throws Exception {
CloseableHttpClient httpClient = httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
try {
HttpGet httpGet = new HttpGet(url);
response = httpClient.execute(httpGet);
// 相应体
HttpEntity entity = response.getEntity();
if(entity != null) {
// 格式化相应体
return EntityUtils.toString(entity);
}
} catch (ClientProtocolException e) {
throw e;
} catch (IOException e) {
throw e;
} finally {
response.close();
httpClient.close();
}
return null;
}
}
接着,我们就可以写服务了。新建 service
包,在其下面实现接口类 IWxService.java
,内容如下:
java
package com.wechat.wechatservice.service;
import com.wechat.wechatservice.dto.WxUserInfoDto;
public interface IWxService {
String getLoginCertificate(String code) throws Exception;
WxUserInfoDto addWxUserInfo(WxUserInfoDto wxUserInfoDto);
}
然后,我们对接口类 IWxService.java
进行具体实现。在 service
包下新建包 impl
,然后在其下新建 WxServiceImpl.java
文件,内容如下:
java
package com.wechat.wechatservice.service;
public interface IWxService {
// 请求地址
String code = wxUserDto.getCode();
String requestUrl = WxUtil.getWxServerUrl(code);
// 发送请求
String response = HttpClientUtils.getRequest(requestUrl);
// 格式化数据
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(response);
String openId = jsonNode.get("openid").asText();
// 转换数据格式
UserDto userDto = new UserDto();
userDto.setOpenId(openId);
// 查找是否存在一条数据
Optional<User> userExist = userRepository.findOneByOpenId(openId);
if(userExist.isEmpty()) {
// 转换为 entity
User user = modelMapper.map(userDto, User.class);
// 写入数据
userRepository.save(user);
return userDto;
}
return userDto;
}
最后,我们实现控制器,我们在 com.wechat.wechatservice
下新建包 controller
,然后添加文件 WxAction.java
,内容如下:
java
package com.wechat.wechatservice.controller;
@RestController
@RequestMapping("/wx")
@AllArgsConstructor
public class WxAction {
private IWxService iWxService;
// Get wetchat user open id
@PostMapping("/getLoginCertificate")
public String getLoginCertificate(@RequestBody WxUserInfo wxUserInfo) throws Exception {
String result = this.iWxService.getLoginCertificate(wxUserInfo.getCode());
return result;
}
}
到此,我们可以通过使用 postman
进行接口调用,在 Navicat
中验证是否添加数据成功了。
小程序跳转
小程序的跳转,需要对方的小程序允许我们的小程序。这里假设我们已经有了跳转的条件了。
实现的跳转逻辑,我们需要获取到对方小程序的 appId
和 path
,才能知道往哪里跳。如下:
javascript
// 小程序跳转
jumpMiniProgram() {
let wxAppId = this.data.wx_appid;
let wxAppPath = this.data.wx_path;
wx.navigateToMiniProgram({
appId: wxAppId,
path: wxAppPath,
success(res) {
console.log(res, 'success');
},
fail(err) {
console.log(err, "error");
}
});
}
引入 vant
我们引入成熟的 UI
框架加快开发速度。这里我们选择了 vant
。
我们可以参考 vant weapp 小程序 - 快速上手 来集成。
构建 npm
的过程可能会报错。配置好文件后,需要关闭开发者工具,再打开。参考文件 构建npm时报错 NPM packages not found. Please confirm npm packages ......
完成构建之后,会多出一个文件夹 miniprogram_npm
。
分享功能
微信小程序的分享功能,着手:
- 分享给好友
- 分享到朋友圈
开启分享
typescript
onLaunch() {
// 微信分享 - https://developers.weixin.qq.com/miniprogram/dev/api/share/wx.showShareMenu.html
wx.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
}
分享给好友
在页面中添加,比如页面 pages/index/index.ts
页面中添加:
typescript
methods: {
// 分享给好友
onShareAppMessage() {
return {
title: "分享标题",
path: "/pages/index/index",
imageUrl: "/assets/imgs/share.png"
}
},
}
分享到朋友圈
在页面中添加,比如页面 pages/index/index.ts
页面中添加:
typescript
methods: {
// 分享到朋友圈
onShareTimeline() {
return {
title: "分享标题",
query: "/pages/index/index",
imageUrl: "/assets/imgs/share.png"
}
},
}
上线设置域名
设置域名的步骤如下:
-
登陆小程序管理后台
-
前往 开发 -> 开发设置
-
tab 业务域名设置,需要管理员扫码登陆
-
按提示将校验文件放在服务的根目录,然后验证是否成功添加(根据域名路径访问该文件)
-
添加域名