ソースを参照

客户管家:获取微信公众号token

yusm 1 ヶ月 前
コミット
99bdae349e

+ 46 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/WechatAccountController.java

@@ -0,0 +1,46 @@
+package com.management.platform.controller;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.management.platform.entity.User;
+import com.management.platform.entity.WechatAccount;
+import com.management.platform.service.UserService;
+import com.management.platform.service.WechatAccountService;
+import com.management.platform.util.HttpRespMsg;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * <p>
+ * 微信公众号账号表 前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-15
+ */
+@RestController
+@RequestMapping("/wechat-account")
+public class WechatAccountController {
+
+    @Resource
+    private WechatAccountService wechatAccountService;
+
+    @Resource
+    private UserService userService;
+
+    @RequestMapping("/getAccessToken")
+    private HttpRespMsg getAccessToken(HttpServletRequest request) {
+        HttpRespMsg httpRespMsg = new HttpRespMsg();
+        String token = request.getHeader("Token");
+        User user = userService.getById(token);
+        WechatAccount wechatAccount = wechatAccountService.getOne(new QueryWrapper<WechatAccount>().eq("company_id", user.getCompanyId()));
+        String accessToken = wechatAccountService.getAccessToken(user.getCompanyId(), wechatAccount.getAppId());
+        httpRespMsg.setData(accessToken);
+        return httpRespMsg;
+    }
+
+}
+

+ 152 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/WeiXinTicketController.java

@@ -0,0 +1,152 @@
+package com.management.platform.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.management.platform.entity.WeiXinTicketEntity;
+import com.management.platform.util.HttpRespMsg;
+import com.management.platform.util.HttpUtil;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 生成带参二维码的ticket值
+ * @author wyx
+ *
+ */
+
+@RestController
+@RequestMapping("weixinTicket")
+public class WeiXinTicketController {
+
+	@Value("${weixin.ticket.action_name.QR_SCENE}")
+    private String 	QRSCENE;
+	@Value("${weixin.ticket.action_name.QR_STR_SCENE}")
+    private String 	QR_STR_SCENE;
+
+	private static final String APP_ID = "wx1c1d8fc81bc073a8";
+	private static final String APP_SECRET = "17ad07f90ee845f99f4c1605647ef755";
+	private static final String GRANT_TYPE = "client_credential";
+
+	
+	@RequestMapping(value = "sendInterviewInvitation",method=RequestMethod.POST)
+	public HttpRespMsg sendInterviewInvitation(@RequestBody WeiXinTicketEntity reqDto) throws Exception{
+		HttpRespMsg msg = new HttpRespMsg();
+		try {
+			String accessToken = getWeiXinAccessToken();
+			String sceneStr = reqDto.getSceneStr();
+			String result = new WeiXinTicketController().createForeverStrTicket(accessToken, sceneStr);
+			JSONObject jsonObject = JSONObject.parseObject(result);
+			String ticket = null ;
+			if(null!=jsonObject){
+				ticket = jsonObject.getString("ticket");  
+                System.out.println("创建永久带参二维码成功,ticket="+ticket);  
+	        }    
+			msg.data=ticket;
+			return msg;
+		} catch (Exception e) {
+			throw new Exception(e);
+		}
+	}
+	
+	/**
+	 * 创建临时带参数二维码 
+	 * 获取灵石带参二维码ticket
+	 * 
+	 * @param accessToken
+	 * @expireSeconds 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒。
+	 * @param sceneId 场景Id
+	 * @return
+	 */
+	public String createTempTicket(String accessToken, String expireSeconds, int sceneId) throws Exception {
+		Map<String, Integer> intMap = new HashMap<>();
+		intMap.put("scene_id", sceneId);
+		Map<String, Map<String, Integer>> mapMap = new HashMap<>();
+		mapMap.put("scene", intMap);
+		Map<String, Object> paramsMap = new HashMap<>();
+		paramsMap.put("expire_seconds", expireSeconds);
+		paramsMap.put("action_name", QRSCENE);
+		paramsMap.put("action_info", mapMap);
+		String  jsonObject = JSONObject.toJSONString(paramsMap);
+		String requestUrl = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token="+accessToken;
+		String result = HttpUtil.post(requestUrl,accessToken, jsonObject);
+		return result;
+	 
+	}
+	 
+	/**
+	 * 创建永久二维码(数字)
+	 * 
+	 * @param accessToken
+	 * @param sceneId
+	 *            场景Id
+	 * @return
+	 */
+	public String createForeverTicket(String accessToken, int sceneId) throws Exception {
+		Map<String, Integer> intMap = new HashMap<>();
+		intMap.put("scene_id", sceneId);
+		Map<String, Map<String, Integer>> mapMap = new HashMap<>();
+		mapMap.put("scene", intMap);
+		Map<String, Object> paramsMap = new HashMap<>();
+		paramsMap.put("action_name", QR_STR_SCENE);
+		paramsMap.put("action_info", mapMap);
+		String  jsonObject = JSONObject.toJSONString(paramsMap);
+		String requestUrl = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=";
+		String result = HttpUtil.post(requestUrl,accessToken, jsonObject);
+		return result;
+	}
+	 
+	/**
+	 * 创建永久二维码(字符串)
+	 * 
+	 * @param accessToken
+	 * @param sceneStr
+	 *            场景str
+	 * @return
+	 */
+	public String createForeverStrTicket(String accessToken, String sceneStr) throws Exception {
+		Map<String, String> intMap = new HashMap<>();
+		intMap.put("scene_str", sceneStr);
+		Map<String, Map<String, String>> mapMap = new HashMap<>();
+		mapMap.put("scene", intMap);
+		Map<String, Object> paramsMap = new HashMap<>();
+		paramsMap.put("action_name", QR_STR_SCENE);
+		paramsMap.put("action_info", mapMap);
+		String  jsonObject = JSONObject.toJSONString(paramsMap);
+		String requestUrl = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token="+accessToken;
+		String result = HttpUtil.post(requestUrl,accessToken, jsonObject);
+		return result;
+	}
+
+
+	//获取第三方应用临时凭证
+	private String getWeiXinAccessToken() {
+		RestTemplate restTemplate = new RestTemplate();
+		String response = restTemplate.getForObject(
+				"https://api.weixin.qq.com/cgi-bin/token",
+				String.class,
+				GRANT_TYPE,
+				APP_ID,
+				APP_SECRET);
+
+		JSONObject jsonObject = JSON.parseObject(response);
+		if (jsonObject.containsKey("access_token")) {
+			return jsonObject.getString("access_token");
+		} else {
+			System.err.println("获取access_token失败: " + response);
+			return null;
+		}
+
+	}
+
+
+
+ 
+ 
+}

+ 82 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/WechatAccount.java

@@ -0,0 +1,82 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 微信公众号账号表
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-15
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class WechatAccount extends Model<WechatAccount> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 企业ID
+     */
+    @TableField("company_id")
+    private Integer companyId;
+
+    /**
+     * 公众号AppID
+     */
+    @TableField("app_id")
+    private String appId;
+
+    /**
+     * 公众号AppSecret
+     */
+    @TableField("app_secret")
+    private String appSecret;
+
+    /**
+     * 访问令牌
+     */
+    @TableField("access_token")
+    private String accessToken;
+
+    /**
+     * 令牌过期时间
+     */
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField("token_expire_time")
+    private LocalDateTime tokenExpireTime;
+
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField("create_time")
+    private LocalDateTime createTime;
+
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField("update_time")
+    private LocalDateTime updateTime;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

+ 18 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/WeiXinTicketEntity.java

@@ -0,0 +1,18 @@
+package com.management.platform.entity;
+ 
+import lombok.Data;
+ 
+/**
+ * 
+ * @author 
+ *
+ */
+@Data
+public class WeiXinTicketEntity {
+	/*场景值ID,临时二维码时为32位非0整型,永久二维码时最大值为100000(目前参数只支持1--100000)*/
+	private int sceneId;
+	/*该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒*/
+	private String expireSeconds;
+	/*场景值ID(字符串形式的ID),字符串类型,长度限制为1到64*/
+	private String sceneStr;
+}

+ 31 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/mapper/WechatAccountMapper.java

@@ -0,0 +1,31 @@
+package com.management.platform.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.management.platform.entity.WechatAccount;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
+
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 微信公众号账号表 Mapper 接口
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-15
+ */
+public interface WechatAccountMapper extends BaseMapper<WechatAccount> {
+    @Select("SELECT * FROM wechat_account WHERE company_id = #{companyId} AND app_id = #{appId}")
+    WechatAccount findByCompanyAndApp(@Param("companyId") Integer companyId,
+                                      @Param("appId") String appId);
+
+    @Update("UPDATE wechat_account SET access_token = #{accessToken}, " +
+            "token_expire_time = #{tokenExpireTime} " +
+            "WHERE company_id = #{companyId} AND app_id = #{appId}")
+    int updateTokenInfo(@Param("companyId") Integer companyId,
+                        @Param("appId") String appId,
+                        @Param("accessToken") String accessToken,
+                        @Param("tokenExpireTime") LocalDateTime tokenExpireTime);
+}

+ 16 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/WechatAccountService.java

@@ -0,0 +1,16 @@
+package com.management.platform.service;
+
+import com.management.platform.entity.WechatAccount;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 微信公众号账号表 服务类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-15
+ */
+public interface WechatAccountService extends IService<WechatAccount> {
+    public String getAccessToken(Integer companyId, String appId) ;
+}

+ 98 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/WechatAccountServiceImpl.java

@@ -0,0 +1,98 @@
+package com.management.platform.service.impl;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.management.platform.entity.WechatAccount;
+import com.management.platform.mapper.WechatAccountMapper;
+import com.management.platform.service.WechatAccountService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 微信公众号账号表 服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-15
+ */
+@Service
+@RequiredArgsConstructor
+public class WechatAccountServiceImpl extends ServiceImpl<WechatAccountMapper, WechatAccount> implements WechatAccountService {
+
+    private final WechatAccountMapper wechatAccountMapper;
+    private final RestTemplate restTemplate;
+
+    // 提前5分钟刷新,避免临界点问题
+    private static final int TOKEN_EXPIRE_BUFFER = 5 ;
+
+    /**
+     * 获取AccessToken
+     * @param companyId 企业ID
+     * @param appId 公众号AppID
+     * @return AccessToken
+     */
+    public String getAccessToken(Integer companyId, String appId) {
+        // 1. 从数据库获取账号信息
+        WechatAccount account = wechatAccountMapper.findByCompanyAndApp(companyId, appId);
+        if (account == null) {
+            throw new RuntimeException("未找到对应的公众号配置");
+        }
+
+        // 2. 检查Token是否有效
+        if (isTokenValid(account)) {
+            return account.getAccessToken();
+        }
+
+        // 3. Token无效则重新获取
+        return refreshAccessToken(account);
+    }
+
+    /**
+     * 判断Token是否有效
+     */
+    private boolean isTokenValid(WechatAccount account) {
+        return account.getAccessToken() != null
+                && account.getTokenExpireTime() != null
+                && account.getTokenExpireTime().isAfter(
+                LocalDateTime.now().plusMinutes(TOKEN_EXPIRE_BUFFER));
+    }
+
+    /**
+     * 刷新AccessToken
+     */
+    private String refreshAccessToken(WechatAccount account) {
+        String url = String.format(
+                "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
+                account.getAppId(), account.getAppSecret());
+
+        try {
+            System.out.println("url==>"+url);
+            String response = restTemplate.getForObject(url, String.class);
+            JSONObject json = JSON.parseObject(response);
+
+            if (json.containsKey("access_token")) {
+                String newToken = json.getString("access_token");
+                int expiresIn = json.getIntValue("expires_in");
+                LocalDateTime expireTime = LocalDateTime.now().plusSeconds(expiresIn);
+
+                // 更新数据库
+                wechatAccountMapper.updateTokenInfo(
+                        account.getCompanyId(),
+                        account.getAppId(),
+                        newToken,
+                        expireTime);
+
+                return newToken;
+            } else {
+                throw new RuntimeException("获取AccessToken失败: " + response);
+            }
+        } catch (Exception e) {
+            throw new RuntimeException("调用微信API失败", e);
+        }
+    }
+}

+ 12 - 3
fhKeeper/formulahousekeeper/management-crm/src/main/resources/application.yml

@@ -1,5 +1,5 @@
 server:
-  port: 10010
+  port: 10011
   tomcat:
     uri-encoding: utf-8
     max-http-form-post-size: -1
@@ -15,7 +15,7 @@ spring:
       location: C:/upload/
   datasource:
     driver-class-name: com.mysql.cj.jdbc.Driver
-    url: jdbc:mysql://1.94.62.58:17089/man_crm_bk?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&useSSL=false
+    url: jdbc:mysql://1.94.62.58:17089/man_crm?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&useSSL=false
     username: root
     password: P011430@Huoshi*
 
@@ -171,4 +171,13 @@ supersonic:
 
 aiask:
   fileaskurl: http://123.60.32.117:5000/analyze
-  askurl: http://123.60.32.117:5000/analyzeOnlyQuestion
+  askurl: http://123.60.32.117:5000/analyzeOnlyQuestion
+
+  #临时的整型参数值
+weixin:
+  ticket:
+    action_name:
+     QR_SCENE: QR_SCENE
+     QR_STR_SCENE: QR_STR_SCENE
+     QR_LIMIT_SCENE: QR_LIMIT_SCENE
+     QR_LIMIT_STR_SCENE: QR_LIMIT_STR_SCENE

+ 22 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/WechatAccountMapper.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.management.platform.mapper.WechatAccountMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.WechatAccount">
+        <id column="id" property="id" />
+        <result column="company_id" property="companyId" />
+        <result column="app_id" property="appId" />
+        <result column="app_secret" property="appSecret" />
+        <result column="access_token" property="accessToken" />
+        <result column="token_expire_time" property="tokenExpireTime" />
+        <result column="create_time" property="createTime" />
+        <result column="update_time" property="updateTime" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, company_id, app_id, app_secret, access_token, token_expire_time, create_time, update_time
+    </sql>
+
+</mapper>