Compare commits

...

3 Commits

Author SHA1 Message Date
dzq fe5a19157a docs(ShopController): 添加微信和企业微信相关接口的注释
为微信端授权登录、企业微信推送消息跳转、企业微信聊天界面跳转等接口添加详细注释,明确各接口的功能和使用场景
2025-05-05 16:43:50 +08:00
dzq b4d4e658dd feat(ShopController): 添加企业微信认证和重定向功能
新增了企业微信认证和重定向功能,根据用户设备类型(移动端或PC端)进行不同的重定向处理。同时,优化了URL编码的测试代码。
2025-05-05 16:35:32 +08:00
dzq 455cdb2f1a refactor(mqtt): 重构MQTT服务以支持多客户端配置
重构MqttService类,引入ClientConfig和MqttConfig枚举类,支持多客户端连接和配置管理。移除硬编码的MQTT配置,改为通过枚举动态管理多个客户端的连接和订阅。提升代码的可扩展性和可维护性。
2025-05-05 11:41:40 +08:00
2 changed files with 164 additions and 25 deletions

View File

@ -1,6 +1,7 @@
package com.agileboot.api.controller;
import cn.hutool.core.util.URLUtil;
import cn.hutool.http.useragent.UserAgentUtil;
import cn.hutool.json.JSONUtil;
import com.agileboot.api.response.ShopGoodsResponse;
import com.agileboot.common.constant.WeixinConstants;
@ -66,6 +67,12 @@ public class ShopController {
return ResponseDTO.ok(new ShopGoodsResponse(goodsWithCabinetList, categoryList, "0"));
}
/**
* 微信端商店入口用于微信端授权登录
* 参数中包含token为汇邦云登录
* @param request
* @return
*/
@GetMapping("/wechatAuth")
public RedirectView wechatAuthRedirect(HttpServletRequest request) {
/*java.util.StringJoiner joiner = new java.util.StringJoiner("&");
@ -103,6 +110,11 @@ public class ShopController {
return new RedirectView(authUrl);
}
/**
* 企业微信推送消息点击商品图片后跳转的地址
* @param request
* @return
*/
@GetMapping("/qy/wechatAuth")
public RedirectView qyWechatAuthRedirect(HttpServletRequest request) {
/*java.util.StringJoiner joiner = new java.util.StringJoiner("&");
@ -122,6 +134,11 @@ public class ShopController {
return new RedirectView(authUrl);
}
/**
* 企业微信推送消息点击商品图片后跳转的地址
* @param request
* @return
*/
@GetMapping("/approvalRedirect")
public RedirectView approvalRedirect(HttpServletRequest request) {
UriComponentsBuilder builder = UriComponentsBuilder
@ -138,8 +155,77 @@ public class ShopController {
return new RedirectView(builder.build().encode().toUriString());
}
/**
* 企业微信聊天界面点击进入主页后跳转的地址
* @param request
* @return
*/
@GetMapping("/qy/wechatAuth/home")
public RedirectView qyWechatAuthHomeRedirect(HttpServletRequest request) {
String userAgent = request.getHeader("User-Agent");
boolean isMobile = UserAgentUtil.parse(userAgent).isMobile();
String redirectPath = isMobile ? "homeRedirect" : "adminRedirect";
String authUrl = "https://open.weixin.qq.com/connect/oauth2/authorize"
+ "?appid=" + WeixinConstants.corpid
+ "&redirect_uri=http%3A%2F%2Fwxshop.ab98.cn%2Fshop-api%2Fapi%2Fshop%2F" + redirectPath
+ "&response_type=code"
+ "&scope=snsapi_base"
+ "&state=STATE"
+ "&agentid=" + WeixinConstants.agentid
+ "#wechat_redirect";
return new RedirectView(authUrl);
}
/**
* 企业微信聊天界面点击进入主页后跳转的地址
* 移动端
* @param request
* @return
*/
@GetMapping("/homeRedirect")
public RedirectView homeRedirect(HttpServletRequest request) {
UriComponentsBuilder builder = UriComponentsBuilder
.fromHttpUrl("http://wxshop.ab98.cn/shop")
.queryParam("corpid", WeixinConstants.corpid)
.queryParam("device", "APP");
request.getParameterMap().forEach((key, values) -> {
if (!"corpid".equals(key) && !"device".equals(key)) {
builder.queryParam(key, (Object[]) values);
}
});
return new RedirectView(builder.build().encode().toUriString());
}
/**
* 企业微信聊天界面点击进入主页后跳转的地址
* PC端
* @param request
* @return
*/
@GetMapping("/adminRedirect")
public RedirectView adminRedirect(HttpServletRequest request) {
UriComponentsBuilder builder = UriComponentsBuilder
.fromHttpUrl("http://wxshop.ab98.cn/shop-admin")
.queryParam("corpid", WeixinConstants.corpid)
.queryParam("device", "PC");
request.getParameterMap().forEach((key, values) -> {
if (!"corpid".equals(key) && !"device".equals(key)) {
builder.queryParam(key, (Object[]) values);
}
});
return new RedirectView(builder.build().encode().toUriString());
}
public static void main(String[] args) throws UnsupportedEncodingException {
String res = URLEncoder.encode("token=12312", StandardCharsets.UTF_8.name());
System.out.println(res);
String url = URLUtil.encode("http://wxshop.ab98.cn/shop-api/api/shop/");
System.out.println(url);
}
}

View File

@ -1,6 +1,9 @@
package com.agileboot.domain.mqtt;
import javax.annotation.PostConstruct;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
@ -8,25 +11,46 @@ import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.stereotype.Service;
import org.eclipse.paho.client.mqttv3.*;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Service
@RequiredArgsConstructor
public class MqttService implements MqttCallback {
private final List<ClientConfig> clientConfigs = new ArrayList<>();
@AllArgsConstructor
private static class ClientConfig {
private final MqttClient client;
private final MqttConfig config;
}
@AllArgsConstructor
@Getter
private enum MqttConfig {
LOCK("lock", "lock@ys#6785$", "lock/up/S4202414S", "lock/down/S4202414S"),
SELL("sell", "sell@ys#6785$", "lock/up/S5200184S", "lock/down/S5200184S");
private final String username;
private final String password;
private final String topicFilter;
private final String publishTopic;
}
private static final String SERVER_URL = "tcp://221.7.159.46:1883";
// private static final String USERNAME = "lock";
// private static final String PASSWORD = "lock@ys#6785$";
// private static final String TOPIC_FILTER = "lock/up/S4202414S";
// private static final String TOPIC = "lock/down/S4202414S";
private static final String USERNAME = "sell";
private static final String PASSWORD = "sell@ys#6785$";
private static final String TOPIC_FILTER = "lock/up/S5200184S";
private static final String TOPIC = "lock/down/S5200184S";
// private static final String USERNAME = "sell";
// private static final String PASSWORD = "sell@ys#6785$";
// private static final String TOPIC_FILTER = "lock/up/S5200184S";
// private static final String TOPIC = "lock/down/S5200184S";
// private static final String USERNAME = "iot";
// private static final String PASSWORD = "iot@ys#9963$";
// private static final String TOPIC_FILTER = "hongfa/2401310026C50D24FE/upload/";
// private static final String TOPIC = "hongfa/2401310026C50D24FE/download/";
private MqttClient client;
// private MqttClient client;
@Setter
private List<String> activeTopics = new ArrayList<>();
// 设置自定义消息处理器
@Setter
private MessageHandler messageHandler; // 自定义消息处理器接口
@ -38,7 +62,7 @@ public class MqttService implements MqttCallback {
@PostConstruct
public void init() throws MqttException {
connect();
subscribe(TOPIC_FILTER);
// subscribe(TOPIC_FILTER);
setMessageHandler((String topic, String hexPayload) -> {
log.info("收到消息 topic: {}, hexPayload: {}", topic, hexPayload);
@ -46,31 +70,54 @@ public class MqttService implements MqttCallback {
}
public void connect() throws MqttException {
client = new MqttClient(SERVER_URL, MqttClient.generateClientId(), new MemoryPersistence());
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(USERNAME);
options.setPassword(PASSWORD.toCharArray());
options.setCleanSession(true);
options.setAutomaticReconnect(true);
for (MqttConfig config : MqttConfig.values()) {
MqttClient client = new MqttClient(SERVER_URL, MqttClient.generateClientId(), new MemoryPersistence());
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(config.getUsername());
options.setPassword(config.getPassword().toCharArray());
options.setCleanSession(true);
options.setAutomaticReconnect(true);
client.setCallback(new MqttCallback() {
@Override
public void messageArrived(String topic, MqttMessage message) {
MqttService.this.messageArrived(topic, message);
}
@Override public void connectionLost(Throwable cause) {}
@Override public void deliveryComplete(IMqttDeliveryToken token) {}
});
client.connect(options);
client.subscribe(config.getTopicFilter());
clientConfigs.add(new ClientConfig(client, config));
log.info("成功连接MQTT账号{}", config.getUsername());
}
client.setCallback(this);
client.connect(options);
log.info("连接 MQTT 服务器 {}", SERVER_URL);
}
public void subscribe(String topic) throws MqttException {
/*public void subscribe(String topic) throws MqttException {
client.subscribe(topic);
}
}*/
public void publish(String data) throws MqttException {
// lockCmd((byte) 0x8A, (byte) 0x01, (byte) 0x01, (byte) 0x33, null);
String bcc = BCCCalculator.calculateBCC(data);
MqttMessage message = new MqttMessage(BCCCalculator.hexStringToByteArray(data + bcc));
client.publish(TOPIC, message);
clientConfigs.forEach(cc -> {
try {
cc.client.publish(cc.config.getPublishTopic(), message);
} catch (MqttException e) {
log.error("消息发送失败", e);
}
});
}
public void disconnect() throws MqttException {
client.disconnect();
for (ClientConfig cc : clientConfigs) {
MqttClient client = cc.client;
client.disconnect();
client.close();
}
}
@Override
@ -108,7 +155,7 @@ public class MqttService implements MqttCallback {
指令0x9E读取所有锁状态
指令中未标注cmdSub指令参数的固定为0x33
*******************************************************/
private boolean lockCmd(byte cmdNo, byte boardNo, byte lockNo, byte cmdSub, String[] rsMsg)
/*private boolean lockCmd(byte cmdNo, byte boardNo, byte lockNo, byte cmdSub, String[] rsMsg)
{
try
{
@ -121,12 +168,18 @@ public class MqttService implements MqttCallback {
//发送数据并获取返回值
MqttMessage message = new MqttMessage(sendData);
client.publish(TOPIC, message);
clientConfigs.forEach(cc -> {
try {
cc.client.publish(cc.config.getPublishTopic(), message);
} catch (MqttException e) {
log.error("消息发送失败", e);
}
});
} catch(Exception e) {
log.error("lockCmd", e);
}
return false;
}
}*/
}