微信小程序的开发

一、基本概念

微信小程序:它是一种不需要下载安装即可使用的应用程序,它基于微信平台开发,能够在微信内直接运行的小型化的应用程序。相较于传统的原生应用程序,小程序具有轻量化、便捷性的特点,无需在设备上进行繁琐的下载和安装过程,用户可以直接在微信中查找和使用。它的主要用途涉及生活服务、购物消费、社会娱乐等方面

WXML:全称是 WeiXin Markup Language,即微信标记语言。专门为微信小程序设计的一种描述页面结构的标记语言, 用于定义小程序页面的布局和内容结构。WXML的核心功能可以概括为以下几点:
1、定义页面结构:在 WXML 中,开发者可以通过特定的标签来显示文本、图片、视频、按钮等页面元素,以及将数据绑定到页面中
2、数据绑定:在 WXML 中,双大括号{ {}} 用于数据绑定,允许开发者将 JavaScript 代码中的数据动态地绑定到页面上,例如 <text>{ {userName}}</text>。
3、UI 组件:WXML 还定义了小程序的 UI 组件。微信小程序提供了丰富的内置组件,如 viewbuttonimageswiper(轮播图)等。开发者可以使用这些组件来构建页面,类似于 HTML 中的 divbuttonimg 等元素,例如 <button bindtap="onTap">点击我</button>。
4、WXSS:WXML 主要用于定义页面的结构,而 WXSS(微信样式表)则用于定义页面的样式。WXSS 与 CSS 类似,但在某些方面有所不同,如支持小程序的尺寸单位(如 rpx,响应式单位),例如 <view class="container">{ {text}}</view>。
5、组件化和模板支持:WXML 支持组件化开发,开发者可以在 WXML 中嵌套自定义组件,类似于 Web 开发中的 Web Components 或 Vue、React 等框架的组件化机制。组件可以包含自己的模板、样式和逻辑,形成独立的功能模块,例如 <custom-component></custom-component>。
(WXML 用来描述微信小程序页面的结构和内容,类似于 HTML,但专门针对微信小程序的需求进行了优化)

WXSS:全称是Weixin Style Sheets,即微信样式表。是微信小程序特有的样式表语言。WXSS 主要与 WXML结合使用,WXML 是微信小程序的结构层,负责页面元素的布局和结构,而 WXSS则负责定义页面元素的样式。WXSS 的语法与标准的 CSS 基本相同,支持选择器、属性和值来设置元素的样式,但是WXSS 采用 rpx(响应式像素)作为布局单位,而不是传统的 px 或 em。rpx 是微信小程序特有的单位,能够根据设备屏幕的宽度自适应调整,具有更好的跨设备适配能力。例如:
.button {
  background-color: #4CAF50;
  color: white;
  padding: 15rpx 32rpx;
}
(通过使用 WXSS,开发者能够对小程序的界面和用户体验进行精确控制,同时确保跨设备的一致性,并使得开发过程更加高效)

JS/TS:JavaScript(简称JS)是一种脚本语言用于网页的客户端编程。其设计目标是使网页更加互动和动态,支持浏览器端的脚本执行。而TypeScript 是 JavaScript 的超集,它在 JavaScript 的基础上引入了静态类型,即允许开发者在编写代码时显式地指定变量的类型。
(在微信小程序的开发中,JavaScript 和 TypeScript 都可以用于编写前端逻辑代码)

WXS:全称是Weixin Script,即微信脚本。它与 JavaScript (JS) 相似,但专为小程序前端开发设计,存在有一些不同的特点和用途。与 JS 不同的是,WXS 主要运行在微信小程序的渲染引擎中,不能直接访问小程序的 API,因此它的功能和用途较为有限。它是微信为小程序定制的一种轻量级脚本语言,用于在小程序页面中处理数据,做一些计算、过滤、格式化等任务,通常用于模板中或页面逻辑中需要频繁计算的部分。常见的应用场景包括
1、数据格式化:可以用 WXS 来格式化日期、数字等常见的数据类型,减少 JS 代码的复杂度。例如,格式化时间戳为用户友好的时间字符串。
2、列表过滤和排序:在模板渲染时,可以使用 WXS 进行数据的过滤、排序、查找等操作,尤其是在数据量较大时,WXS 的执行效率较高。
3、简单计算和逻辑处理:例如,计算折扣、价格、库存等常见的数字处理。
例如:
pages/cart/cart.wxs:

module.exports = {
  formatPrice: function (price) {
    return "¥" + price.toFixed(2);  // 保留两位小数并加上“¥”符号
  }
}

pages/cart/cart.wxml:

<view>
  <view wx:for="{
  
  {items}}" wx:key="index">
    <text>{
  
  {wxs.formatPrice(item.price)}}</text>
  </view>
</view>

(WXS 专注于前端渲染时的计算任务,可以提高页面渲染效率,WXS 可以与 JavaScript 配合使用,从而在保证页面性能的同时,处理数据展示和逻辑操作,提升小程序的用户体验)

组件化开发:它是一种将系统或应用分解为多个独立、可重用的组件的开发方法。核心理念是将复杂的系统拆分成多个小而独立的模块,这些模块(或组件)可以单独开发、测试、更新和维护,并且能够在多个地方重复使用。具有模块化、重用性、可维护性、易于扩展等特点。
(微信小程序本身就支持组件化开发,可以通过自定义组件的方式来进行开发,因此微信小程序的组件可以分为两类,一是原生组件:微信提供的一些基础组件,如 <view><button><text> 等,都是由微信小程序官方提供的原生组件,开发者可以直接使用,可参考视图容器 | 微信开放文档。二是自定义组件:开发者可以根据自己的需求自定义组件,通过 component 配置来封装功能,并在其他页面或组件中进行引用。例如要开发一个常用的卡片组件,先在项目中创建一个名为 card的组件目录,然后编写组件代码
card.wxml: 

<view class="card">
  <image class="card-image" src="{
  
  {imgSrc}}" />
  <text class="card-title">{
  
  {title}}</text>
  <text class="card-price">{
  
  {price}}</text>
</view>

card.wxss:

.card {
  padding: 10px;
  border-radius: 10px;
  background-color: #fff;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.card-image {
  width: 100%;
  height: auto;
  border-radius: 5px;
}
.card-title {
  font-size: 16px;
  font-weight: bold;
}
.card-price {
  color: red;
  font-size: 14px;
}

card.js:

Component({
  properties: {
    title: String,
    price: String,
    imgSrc: String
  }
});

在其他页面引用组件:
<import src="../../components/card/card.wxml" />
<template is="card" data="{ {title: '商品A', price: '¥100', imgSrc: 'path/to/image'}}" />
)

API接口:是 Application Programming Interface(应用程序编程接口)的缩写,API接口是指一组规范或协议,允许不同的软件系统、组件或模块之间进行交互与通信。API定义了两个软件系统之间如何通过调用某些预定的接口(函数、方法、URL等)来交换数据或请求服务。
(在微信小程序开发中,API接口扮演着至关重要的角色,小程序通常需要从服务器获取数据(例如用户信息、商品列表、天气信息等),这些数据通过调用微信小程序提供的 wx.request() 方法发起HTTP请求,调用后端提供的API接口来获取,或者在小程序中进行的某些操作(如支付、订单创建、评论提交等)通过API接口与后端交互,完成相应的业务逻辑处理,例如

wx.request({
  url: 'https://example.com/api/getData',
  method: 'GET',
  success(res) {
    console.log(res.data);
  },
  fail: (error) => {
    console.error("调用失败", error);
  }
});

另外微信小程序不仅能够调用外部API,还提供了大量的内置API,供开发者进行用户身份验证、设备信息获取、支付、分享等操作,例如

// 获取用户的基本信息(如昵称、头像等):
wx.getUserInfo({
  success: res => {
    console.log(res.userInfo);
  },
  fail: (error) => {
    console.error("调用失败", error);
  }
});
// 跳转到某个页面,保持当前页面:
wx.navigateTo({ url: '/pages/details/details?id=123' });
// 显示模态对话框:
wx.showModal({
  title: '提示',
  content: '是否确认删除该项目?',
  success (res) {
    if (res.confirm) {
      console.log('用户点击确定');
    } else if (res.cancel) {
      console.log('用户点击取消');
    }
  },
  fail: (error) => {
    console.error("调用失败", error);
  }
});

对于内置API,前端调用微信内置 API(如 wx.getUserProfilewx.login 等)时,不需要 access_token,这些 API 是通过微信小程序的运行环境直接调用的,由微信平台负责验证开发者的身份。后端调用微信的服务端接口(如 code2Session模板消息发送支付接口)时,通常需要使用 access_token 或其他签名/加密机制来确保请求的合法性,而是否需要签名/加密,视具体API接口而定,可见概述 | 微信开放文档。更多内置API可参考基础 | 微信开放文档。)

配置文件:配置文件在微信小程序开发中扮演着非常重要的角色,它们定义了小程序的全局(app.json)和页面级别(xxx.json)的设置.。app.json它用于描述整个小程序的全局配置信息,位于项目的根目录下。
app.json的主要配置为:
1、页面路径列表定义了小程序所有页面的路径(即pages字段),这是小程序启动时用来构建页面栈的基础。第一个页面通常是小程序启动时默认打开的页面(index.wxml)。当新配置一个页面路径时,开发工具会自动生成页面的.wxml .wxss .json .ts文件
2、窗口表现:可以设置小程序所有页面的一些公共样式属性,如导航栏颜色、标题文字等(即 "window"字段)。
3、TabBar配置:如果小程序有底部或顶部的TabBar,可以在app.json中定义其图标、文字以及对应的页面路径(即 "tabBar"字段)。
4、网络超时时间:可以设定网络请求的超时时间(即 "networkTimeout"字段)。
5、调试模式:可以通过设置debug字段来开启或关闭调试模式(即 "debug"字段)。
6、其他配置:包括但不限于是否启用分包加载、性能监控等功能。
上述配置如下:
{
  "pages": [
    "pages/index/index",
    "pages/logs/logs",
    "pages/user/user"
  ],
  "window": {
    "backgroundTextStyle": "light",
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "WeChat",
    "navigationBarTextStyle": "black"
  },
  "tabBar": {
    "color": "#000",
    "selectedColor": "#1aad19",
    "borderStyle": "black",
    "list": [
      {
        "pagePath": "pages/index/index",
        "text": "首页",
        "iconPath": "images/home.png",
        "selectedIconPath": "images/home-active.png"
      },
      {
        "pagePath": "pages/logs/logs",
        "text": "日志",
        "iconPath": "images/logs.png",
        "selectedIconPath": "images/logs-active.png"
      }
    ]
  },
  "networkTimeout": {
    "request": 10000,
    "downloadFile": 10000
  },
  "debug": true
}
xxx.json的主要配置为页面特定配置:允许为每个页面单独设置窗口表现,例如背景颜色、导航栏样式等,这些设置会覆盖app.json中的相同配置。
(app.jsonpage.json 文件通过提供结构化的配置选项,帮助开发者对小程序的外观和行为进行精确控制。)

调试工具:指微信开发者工具,它是微信官方提供的一款集成开发环境(IDE),专门用于开发、调试和测试微信小程序、小游戏以及小程序插件的工具,并且提供了从代码编辑、调试到上传发布的全方位支持。

二、操作步骤

1、注册小程序账号

首先需要提供相关信息注册小程序账号,包括邮箱验证、个人身份信息、小程序名称等。

注册地址:微信小程序
(用于后续在开发工具中进行登录,以便将开发的小程序与账号相关联)

2、完成小程序备案

在小程序首页进行小程序信息、类目及其他信息(比如后端服务器)的补充,并发起备案申请。

首页地址:小程序
(根据微信官方要求,小程序备案是一个必要的步骤,确保开发的小程序符合微信的相关法律和内容规定)

3、下载微信开发者工具

微信提供了官方的小程序开发工具,用于编写和调试小程序,安装完成后,使用注册的小程序账号进行登录,并填入账户信息中的AppID(小程序ID)


下载地址:微信开发者工具下载地址与更新日志 | 微信开放文档
( 微信开发者工具使用小程序调试,可以完成小程序的前端页面和API的开发调试、代码查看和编辑、小程序预览和发布等功能)

4、配置git账户及仓库

为了更好地管理小程序项目代码,可以使用Git进行版本控制。在本地小程序代码对应的文件夹下进行git相关的配置。
Git全局设置:
git config --global user.name "xxx"
git config --global user.email "xxx@xxx"
初始化git仓库
git init
git remote add origin xxxx
git add .
git commit
git push -u origin master

代码管理地址:登录 - 微信开发者代码管理
(在小程序开发中,使用 Git 可以方便地记录代码的开发历史,便于多人协作开发,并且能够轻松地回滚到之前的版本,以解决代码出现的问题)

5、小程序代码开发

前端代码开发
使用WXML(微信标记语言)和WXSS(微信样式表)来构建页面和样式
使用JavaScript或TS来处理业务逻辑、事件绑定、页面生命周期等
可通过微信小程序API来实现用户授权、获取数据、支付等功能
后端调用
小程序可以通过wx.request向服务器发起HTTP请求,获取后端数据
后端服务通常使用Python、Java、PHP等开发语言,处理小程序的业务逻辑和数据存储
数据的传输可以采用JSON格式,确保小程序与后端的通信高效、准确
小程序开发文档地址:微信开放文档
(代码开发时小程序开发的核心步骤,它直接影响到上传、审核、上线后的稳定性以及用户体验效果,基本步骤可参考 额外补充 -》前后端交互的主要步骤)

6、上传代码,提交审核

完成开发后,在开发者工具的“工具”菜单栏中选择“上传”按钮,将本地开发版本上传到微信服务器。上传后,可以在微信公众平台小程序首页的版本管理中填写小程序的版本号、描述等信息并提交审核,审核通过后就可以选择将小程序发布上线。

7、正式上线验证

程序上线后,即可进行正式的验证,确保小程序在正式环境中的正常运行。

总结

微信小程序的开发流程的本质就是注册和备案小程序后,用专门的开发工具以及特别的写法开发界面并调用后端,然后提交审核上线。关键点在于对开发文档中包括特殊标签、样式、API及脚本的写法的理解与使用

三、额外补充

1、如何打断点调试

1.1、在开发者工具中调试

打开 模拟器 及 调试器,在调试器的弹窗中点击wxml tab标签可看到页面结构,进行样式调整,点击调试器弹窗右上角的三个点,可见 Search,点击Search后搜索对应代码,然后即可在Surces中显示出对应文件,然后在对应代码行打上断点,在模拟器中操作即可进行调试

1.2、真机调试

可在开发者工具中 真机调试-》自动真机调试-》编译并自动调试(选择自己移动设备对应的系统),编译启动后,在微信界面会自动打开要调试的小程序,同时开发者工具也会自动弹出一个调试弹窗(类似浏览器的控制台)
然后在弹窗中点击wxml tab标签可看到页面结构,进行样式调整,点击Sources->user可看到自己小程序的所有js/ts文件,点击打开文件在对应代码行打上断点,操作移动设备即可进行调试

2、前后端交互的主要步骤

2.1、前端获取code

初始加载时,前端在app.ts中wx.login获取code并将code保存发送到后端

App<IAppOption>({
  globalData: {
    loginCode: "",
    token: ""
  },
  onLaunch() {
    // 前端代码
    wx.login({
      success: (res) => {
        if (res.code) {
          console.log("登录成功,code:", res.code);
          this.globalData.loginCode = res.code; // 保存到全局变量
        } else {
          console.error("登录失败", res.errMsg);
        }
      },
    });
  },
})

在其他页面中假设存在confirm函数

confirm(){
      const app = getApp<IAppOption>(); // 获取全局 App 实例
      const loginCode = app.globalData.loginCode; // 获取保存的 code
          // 调用 wx.getUserProfile 获取用户信息
          wx.getUserProfile({
            desc: "用于完善用户信息",
            success: (profileRes) => {
              const { nickName, avatarUrl } = profileRes.userInfo; // 用户昵称和头像
              // 发送到后端
              wx.request({
                url: "https://xxx.xxx/program/saveUser", // 替换为后端接口地址
                method: "POST",
                data: {
                  code: loginCode,
                  nickName: nickName,
                  avatarUrl: avatarUrl,
                },
                success: (result) => {
                  app.globalData.token = result.data.toString();
                  console.log("用户信息保存成功", app.globalData.token);
                },
                fail: (error) => {
                  console.error("保存用户信息失败", error);
                },
              });
            },
            fail: (error) => {
              console.error("用户拒绝授权", error); // 检查这里是否输出错误信息
            }
          });
    }

2.2、后端保存用户信息

后端根据code以及appid\appSecrete调用jscode2session可获得标识唯一用户的openid,保存用户数据并生成token返回前端(mapper类及sql自行补充)

    @Value("${wx.appid}")
    private String appid;

    @Value("${wx.secret}")
    private String secret;

    @PostMapping("/saveUser")
    public String saveUser(@RequestBody UserSaveDTO userSaveDTO) {
        String code = userSaveDTO.getCode();
        String nickName = userSaveDTO.getNickName();
        String avatarUrl = userSaveDTO.getAvatarUrl();
        // 使用HTTPS GET请求微信API根据code换取openid和session_key
        String apiUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appid + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code";
        try {
            // 创建 URL 对象
            URL url = new URL(apiUrl);
            // 打开连接
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            // 设置请求方法为 GET
            connection.setRequestMethod("GET");
            // 获取响应码
            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                // 读取响应内容
                BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String line;
                StringBuilder response = new StringBuilder();
                while ((line = reader.readLine()) != null) {
                    response.append(line);
                }
                reader.close();
                // 打印响应结果
                Gson gson = new Gson();
                // 将 JSON 字符串转换为 Map
                Map<String, Object> map = gson.fromJson(response.toString(), Map.class);
                String openid = (String) map.get("openid");
                programMapper.insertUser(nickName, avatarUrl, openid);
                return JwtTokenUtil.generateToken(openid);
            } else {
                System.out.println("请求失败,响应码: " + responseCode);
                return "error";
            }
        } catch (Exception e) {
            throw new RuntimeException("保存用户信息接口失败", e);
        }
    }

JWT工具类

package com.example.demo.miniprogram.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;

import java.util.Date;

public class JwtTokenUtil {

    // 自定义密钥(实际使用时请妥善保管,建议配置到配置文件中)
    private static final String SECRET_KEY = "my_mini_program";
    // 30 分钟有效期(单位:毫秒)
    private static final long EXPIRATION_TIME = 30 * 60 * 1000;

    /**
     * 根据传入的 openid 生成 token,token 有效期为 30 分钟
     * @param openid 微信用户的 openid
     * @return JWT Token 字符串
     */
    public static String generateToken(String openid) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + EXPIRATION_TIME);

        return Jwts.builder()
                // 这里使用 subject 存放 openid,也可在 payload 中增加其他信息
                .setSubject(openid)
                // 也可以使用 claim 存放更多信息
                .claim("openid", openid)
                .setIssuedAt(now)
                .setExpiration(expiryDate)
                // 使用 HS512 对称加密算法签名
                .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
                .compact();
    }

    /**
     * 验证 token 的有效性,包含签名和是否过期的检查
     * @param token 待验证的 JWT Token
     * @return true 表示 token 有效;false 表示 token 无效或已过期
     */
    public static boolean validateToken(String token) {
        try {
            // 解析 token,如果解析成功则 token 合法
            Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token);
            return true;
        } catch (ExpiredJwtException e) {
            // token 已经过期
            System.out.println("Token 已过期:" + e.getMessage());
        } catch (SignatureException e) {
            // token 签名不正确
            System.out.println("Token 签名错误:" + e.getMessage());
        } catch (Exception e) {
            // 其他异常,例如 token 格式不正确
            System.out.println("Token 无效:" + e.getMessage());
        }
        return false;
    }

    /**
     * 刷新 token
     * 如果 token 合法(即使过期了也可以获取到 claims),则根据 token 中的 openid 生成新的 token。
     * 如果 token 无法解析,则返回 null。
     *
     * @param token 需要刷新的旧 token
     * @return 新的 JWT Token 字符串,或 null 表示 token 无法刷新
     */
    public static String refreshToken(String token) {
        try {
            // 尝试解析 token,获取 claims(如果 token 已过期,ExpiredJwtException 中也包含 claims)
            Claims claims = Jwts.parser()
                    .setSigningKey(SECRET_KEY)
                    .parseClaimsJws(token)
                    .getBody();
            String openid = claims.get("openid", String.class);
            return generateToken(openid);
        } catch (ExpiredJwtException e) {
            // 如果 token 已经过期,通过异常获取 claims
            Claims claims = e.getClaims();
            String openid = claims.get("openid", String.class);
            return generateToken(openid);
        } catch (Exception e) {
            // 如果 token 解析失败,无法刷新,返回 null 或者抛出自定义异常
            System.out.println("刷新 token 失败:" + e.getMessage());
            return null;
        }
    }
}

2.3、后端token验证

前端后续调用后端接口附带token,后端验证token后处理业务逻辑
假如我后续某个页面要搜索已经保存信息的用户名称

searchUserName: function (e) {
    const app = getApp();
    wx.request({
      url: 'https://xxx.xxx/program/selectUserByName?name='+e.detail.value,
      method: 'GET',
      header: {
        'Authorization': app.globalData.token, // 添加Authorization请求头
        'content-type': 'application/json' // 默认值,根据实际情况可能需要调整
      },
      success(res) {
        console.log(res.data);
      }
    });
  }

全局拦截器验证token

package com.example.demo.miniprogram.filter;

import com.example.demo.miniprogram.utils.JwtTokenUtil;
import org.springframework.stereotype.Component;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class JwtAuthenticationFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化配置,如果需要可以在这里加载配置参数
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // 强制转换为 HttpServletRequest 和 HttpServletResponse
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        // 获取请求 URI
        String uri = httpRequest.getRequestURI();

        // 如果请求路径为 /saveUser,则直接放行,不进行 token 验证
        if (uri.contains("/saveUser")) {
            chain.doFilter(request, response);
            return;
        }

        // 从请求头中获取 token,假设 token 存储在 "Authorization" 字段中
        String token = httpRequest.getHeader("Authorization");

        // 如果 token 为空或验证不通过,则返回 401 状态码
        if (token == null || !JwtTokenUtil.validateToken(token)) {
            httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            // 可根据需要返回错误信息
            httpResponse.getWriter().write("Unauthorized: Invalid or missing token.");
            return;
        }

        // token 验证通过,继续执行后续 Filter 或目标资源
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        // 资源释放操作,如无需要可留空
    }
}

2.4、后端调用微信API

后端调用微信内置API时,通过getAccessToken获取acess_token调用(某些场景的特殊API接口需要签名或加密解密处理(如支付接口、用户信息解密))

    // 获取 access_token 的 URL(注意:此接口适用于公众号和部分小程序场景,不同场景接口可能不同)
    private static final String ACCESS_TOKEN_URL =
            "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";

    /**
     * 通过调用微信接口获取 access_token
     * @return 微信接口返回的 access_token 字符串
     * @throws Exception 当获取 token 失败时抛出异常
     */
    public String getAccessToken() {
        try {
            String url = String.format(ACCESS_TOKEN_URL, appid, secret);
            ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
            String body = response.getBody();
            // 将返回的 JSON 字符串转换为 Map
            Map<String, Object> result = objectMapper.readValue(body, Map.class);
            return (String) result.get("access_token");
        }catch (Exception e){
            throw new RuntimeException("获取微信token接口失败", e);
        }
    }

    // TODO 使用accessToken调用小程序后端服务端的其他API

3、开发者工具缓存问题

修改或重新上传资源文件(比如图片)后,需要在开发工具 清缓存-》清除编译缓存 后重新编译,否则资源会刷新不过来
另外在调试时也会存在各种意料之外的问题,比如断点不进入,页面不刷新等,可以选择清缓存-》全部清除,后重新尝试,基本解决大部分问题

4、开发者工具拉取/推送代码失败

在微信小程序开发者工具中,拉取远程分支时提示 Pull failed Error: invalid authentication scheme,通常与认证方式或凭据问题有关。可尝试在 版本管理-》设置-》网络和认证 的认证方式中,将认证方式修改为使用用户名和密码,然后重新尝试

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值