From eb41f35a03fdc283d2e4326040f3281c17811a59 Mon Sep 17 00:00:00 2001 From: dzq Date: Wed, 5 Nov 2025 10:14:45 +0800 Subject: [PATCH] =?UTF-8?q?feat(wx):=20=E6=B7=BB=E5=8A=A0=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E5=B0=8F=E7=A8=8B=E5=BA=8F=E7=99=BB=E5=BD=95=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增微信小程序登录相关功能,包括: 1. 添加微信常量配置类WxConstant 2. 创建微信access token实体类WxAccessToken 3. 实现微信服务类WxService用于获取openid 4. 添加微信控制器WxController提供API接口 5. 创建微信用户信息表wx_user --- .../api/controller/WxController.java | 45 +++++++++++++++++++ .../agileboot/domain/wx/WxAccessToken.java | 26 +++++++++++ .../com/agileboot/domain/wx/WxConstant.java | 7 +++ .../com/agileboot/domain/wx/WxService.java | 45 +++++++++++++++++++ sql/20251029_wx_user.sql | 18 ++++++++ 5 files changed, 141 insertions(+) create mode 100644 agileboot-api/src/main/java/com/agileboot/api/controller/WxController.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/wx/WxAccessToken.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/wx/WxConstant.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/wx/WxService.java create mode 100644 sql/20251029_wx_user.sql diff --git a/agileboot-api/src/main/java/com/agileboot/api/controller/WxController.java b/agileboot-api/src/main/java/com/agileboot/api/controller/WxController.java new file mode 100644 index 0000000..13b6db3 --- /dev/null +++ b/agileboot-api/src/main/java/com/agileboot/api/controller/WxController.java @@ -0,0 +1,45 @@ +package com.agileboot.api.controller; + +import cn.hutool.http.HttpUtil; +import cn.hutool.json.JSONUtil; +import com.agileboot.common.core.dto.ResponseDTO; +import com.agileboot.common.exception.ApiException; +import com.agileboot.common.exception.error.ErrorCode; +import com.agileboot.domain.wx.WxService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestClientException; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@RestController +@CrossOrigin(origins = "*", allowedHeaders = "*") +@RequiredArgsConstructor +@RequestMapping("/api/wx") +public class WxController { + private final WxService wxService; + + /** + * 获取小程序用户OpenID + * @param code 微信授权码 + * @return 包含openid的响应结果 + * @throws ApiException 当code无效或微信接口调用失败时抛出 + */ + @GetMapping("/mpCodeToOpenId") + public ResponseDTO mpCodeToOpenId(String code) { + try { + String openid = wxService.getSmallOpenid(code); + + return ResponseDTO.ok(openid); + } catch (Exception e) { + log.error("获取openid失败", e); + return ResponseDTO.fail(new ApiException(ErrorCode.Client.COMMON_REQUEST_PARAMETERS_INVALID, e.getMessage())); + } + } +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/wx/WxAccessToken.java b/agileboot-domain/src/main/java/com/agileboot/domain/wx/WxAccessToken.java new file mode 100644 index 0000000..4e8c22c --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/wx/WxAccessToken.java @@ -0,0 +1,26 @@ +package com.agileboot.domain.wx; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class WxAccessToken { + private String code; + private String state; + private Integer errcode; + private String errmsg; + @JsonProperty("access_token") + private String accessToken; + @JsonProperty("expires_in") + private Integer expiresIn; + @JsonProperty("refresh_token") + private String refreshToken; + private String openid; + private String scope; + private String unionid; + @JsonProperty("session_key") + private String sessionKey; + private Integer sex; + private String nickName; + private String headImg; +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/wx/WxConstant.java b/agileboot-domain/src/main/java/com/agileboot/domain/wx/WxConstant.java new file mode 100644 index 0000000..045a746 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/wx/WxConstant.java @@ -0,0 +1,7 @@ +package com.agileboot.domain.wx; + +public class WxConstant { + public static final String MpOpenidUrl = "https://api.weixin.qq.com/sns/jscode2session"; + public static final String MpAppid = "wxb9ab79f2ddd11af0"; + public static final String MpSecret = "ca211a454b3a1d6189b3f0a946f2ce29"; +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/wx/WxService.java b/agileboot-domain/src/main/java/com/agileboot/domain/wx/WxService.java new file mode 100644 index 0000000..f323e0d --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/wx/WxService.java @@ -0,0 +1,45 @@ +package com.agileboot.domain.wx; + +import cn.hutool.http.HttpUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import static com.agileboot.domain.wx.WxConstant.MpOpenidUrl; + +@Slf4j +@Service +@RequiredArgsConstructor +public class WxService { + + + /** + * 获取小程序openid信息 + * @param code + * @return + */ + public String getSmallOpenid(String code) { + String url = MpOpenidUrl + + "?appid="+ WxConstant.MpAppid+ + "&secret="+ WxConstant.MpSecret+ + "&js_code="+code+ + "&grant_type=authorization_code"; + String result = HttpUtil.get(url); + if (StringUtils.isBlank(result)){ + return null; + } + JSONObject jsonObject = JSONUtil.parseObj(result); + if (jsonObject.getStr("errcode") != null && !StringUtils.equals(jsonObject.getStr("errcode"), "0")){ + throw new RuntimeException(jsonObject.getStr("errmsg")); + } + WxAccessToken wxAccessToken = JSONUtil.toBean(result, WxAccessToken.class); + if (wxAccessToken.getOpenid() == null || "".equals(wxAccessToken.getOpenid().trim())) { + System.out.println("openid为空"); + return null; + } + return wxAccessToken.getOpenid(); + } +} diff --git a/sql/20251029_wx_user.sql b/sql/20251029_wx_user.sql new file mode 100644 index 0000000..dd2f676 --- /dev/null +++ b/sql/20251029_wx_user.sql @@ -0,0 +1,18 @@ +CREATE TABLE `wx_user` ( + `wx_user_id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `openid` varchar(32) DEFAULT NULL COMMENT 'openid', + `ab98_user_id` bigint DEFAULT NULL COMMENT '汇邦云用户ID', + `qy_user_id` bigint DEFAULT NULL COMMENT '企业用户id', + `nick_name` varchar(50) NOT NULL COMMENT '昵称', + `tel` varchar(20) NULL COMMENT '手机号码', + `wx_balance` int NOT NULL DEFAULT '0' COMMENT '用户余额(单位:分)', + `creator_id` bigint NULL DEFAULT '0' COMMENT '创建者ID', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` bigint NULL DEFAULT '0' COMMENT '更新者ID', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除标志(0存在 1删除)', + PRIMARY KEY (`wx_user_id`), + KEY `idx_openid` (`openid`), + KEY `idx_tel` (`tel`), + KEY `idx_nick_name` (`nick_name`) +) ENGINE=InnoDB AUTO_INCREMENT=75 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='微信用户信息表';