增加发送小程序订阅消息相关方法
This commit is contained in:
parent
1a4736d91e
commit
19abeede3d
@ -13,6 +13,7 @@ import javax.servlet.http.HttpSession;
|
||||
*/
|
||||
public class SessionUtils {
|
||||
|
||||
public static final String SESSION_CURRENT_USER_ID = "user_id";
|
||||
public static final String SESSION_CURRENT_USER = "login_user";
|
||||
public static final String SESSION_TENANT_ID = "tenant_id";
|
||||
public static final String SESSION_TENANT_NAME = "tenant_name";
|
||||
@ -28,6 +29,7 @@ public class SessionUtils {
|
||||
session.setAttribute(SESSION_TENANT_ID, user.getTenant_id());
|
||||
session.setAttribute(SESSION_TENANT_NAME, tenant.getName());
|
||||
session.setAttribute(SESSION_ROLE, user.getRole());
|
||||
session.setAttribute(SESSION_CURRENT_USER_ID, user.getId());
|
||||
}
|
||||
|
||||
public static Integer getTenantId(HttpServletRequest request) {
|
||||
@ -37,4 +39,8 @@ public class SessionUtils {
|
||||
public static String getRole(HttpServletRequest request) {
|
||||
return (String) request.getSession().getAttribute(SESSION_ROLE);
|
||||
}
|
||||
|
||||
public static Long getUserId(HttpServletRequest request) {
|
||||
return (Long) request.getSession().getAttribute(SESSION_CURRENT_USER_ID);
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ public class WebMvcConfig implements WebMvcConfigurer {
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(authInterceptor)
|
||||
.addPathPatterns("/**")
|
||||
.excludePathPatterns("/**/*.js","/**/*.css","/**/*.jpg","/**/*.png", "/do_login", "/mini-register", "/login", "/test/**", "/api/**");
|
||||
.excludePathPatterns("/**/*.js","/**/*.css","/**/*.jpg","/**/*.png", "/do_login", "/mini-register", "/login", "/test/**", "/api/**",
|
||||
"/file/upload");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package com.imdroid.beidou.config;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@ -8,6 +10,8 @@ import org.springframework.context.annotation.Configuration;
|
||||
*
|
||||
* @author LiGang
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@Configuration
|
||||
@ConfigurationProperties("app.bis")
|
||||
public class WxMiniProperties {
|
||||
@ -16,21 +20,14 @@ public class WxMiniProperties {
|
||||
|
||||
private String secret;
|
||||
|
||||
/**
|
||||
* 设备型号id
|
||||
*/
|
||||
private String modelId;
|
||||
|
||||
public String getAppid() {
|
||||
return appid;
|
||||
}
|
||||
|
||||
public void setAppid(String appid) {
|
||||
this.appid = appid;
|
||||
}
|
||||
|
||||
public String getSecret() {
|
||||
return secret;
|
||||
}
|
||||
|
||||
public void setSecret(String secret) {
|
||||
this.secret = secret;
|
||||
}
|
||||
/**
|
||||
* 设备告警模板消息id
|
||||
*/
|
||||
private String deviceAlertTemplateId;
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,48 @@
|
||||
package com.imdroid.beidou.controller;
|
||||
|
||||
import com.imdroid.beidou.auth.SessionUtils;
|
||||
import com.imdroid.beidou.common.HttpResult;
|
||||
import com.imdroid.beidou.config.WxMiniProperties;
|
||||
import com.imdroid.beidou.data.dto.MiniSnTicketBodyDTO;
|
||||
import com.imdroid.beidou.data.vo.mini.DeviceSnTicketVO;
|
||||
import com.imdroid.beidou.utils.WXUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* 微信小程序相关API调用控制器
|
||||
*
|
||||
* @author LiGang
|
||||
* @date 2023/11/12 10:38
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/mini")
|
||||
@RequiredArgsConstructor
|
||||
public class MiniProgramController {
|
||||
|
||||
private final WxMiniProperties wxMiniProperties;
|
||||
private final WXUtils wxUtils;
|
||||
|
||||
/**
|
||||
* 获取设备snTicket
|
||||
*
|
||||
* @param request the http servlet request
|
||||
*/
|
||||
@GetMapping(value = "/getsnticket")
|
||||
public HttpResult getSnTicket(HttpServletRequest request) {
|
||||
Long userId = SessionUtils.getUserId(request);
|
||||
if (userId == null) {
|
||||
return HttpResult.fail("用户id为空");
|
||||
}
|
||||
MiniSnTicketBodyDTO snTicketBodyDTO = new MiniSnTicketBodyDTO(String.valueOf(userId), wxMiniProperties.getModelId());
|
||||
String snTicket = wxUtils.getSnTicket(snTicketBodyDTO);
|
||||
if (snTicket == null) {
|
||||
return HttpResult.fail("获取snTicket失败");
|
||||
}
|
||||
return HttpResult.success(new DeviceSnTicketVO(String.valueOf(userId), snTicket, wxMiniProperties.getModelId()));
|
||||
}
|
||||
}
|
||||
@ -33,7 +33,12 @@ public class OssFileController {
|
||||
*/
|
||||
@RequestMapping("/upload")
|
||||
public HttpResult upload(@RequestParam("file") MultipartFile multipartFile) throws Exception {
|
||||
String filename = multipartFile.getOriginalFilename();
|
||||
String originFilename = multipartFile.getOriginalFilename();
|
||||
if (originFilename == null) {
|
||||
originFilename = ".file";
|
||||
}
|
||||
String suffix = originFilename.substring(originFilename.lastIndexOf("."));
|
||||
String filename = UUID.randomUUID().toString().replace("-", "") + suffix;
|
||||
String url = aliyunOssUtils.uploadFile(multipartFile, filename, "common");
|
||||
return HttpResult.success(url);
|
||||
}
|
||||
|
||||
@ -0,0 +1,65 @@
|
||||
package com.imdroid.beidou.data.dto;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.imdroid.beidou.utils.GsonUtils;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 小程序硬件设备消息body对象
|
||||
*
|
||||
* @author LiGang
|
||||
* @date 2023/11/12 10:19
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class MiniHardwareDeviceMessageDTO {
|
||||
|
||||
@Expose
|
||||
private List<String> to_openid_list;
|
||||
|
||||
@Expose
|
||||
private String template_id;
|
||||
|
||||
@Expose
|
||||
private String sn;
|
||||
|
||||
@Expose
|
||||
private String modelId;
|
||||
|
||||
@Expose
|
||||
private String page;
|
||||
|
||||
@Expose
|
||||
private String miniprogram_state = "developer";
|
||||
|
||||
@Expose
|
||||
private String lang = "zh_CN";
|
||||
|
||||
@Expose
|
||||
private Map<String, Map<String, Object>> data;
|
||||
|
||||
|
||||
public void addDataItem(String key, Object value) {
|
||||
if (data == null) {
|
||||
data = new HashMap<>(8);
|
||||
}
|
||||
Map<String, Object> valueMap = new HashMap<>(1);
|
||||
valueMap.put("value", value);
|
||||
data.put(key, valueMap);
|
||||
}
|
||||
|
||||
public void removeDataItem(String key) {
|
||||
data.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return GsonUtils.toJsonExpose(this);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
package com.imdroid.beidou.data.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 小程序请求snTicket的body参数对象
|
||||
*
|
||||
* @author LiGang
|
||||
* @date 2023/11/12 10:14
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class MiniSnTicketBodyDTO {
|
||||
|
||||
/**
|
||||
* sn 设备唯一序列号。由厂商分配,长度不能超过128字节。字符只接受数字,大小写字母,下划线(_)和连字符(-)
|
||||
* 本程序可使用用户id,来实现用户接收多个设备的消息
|
||||
*/
|
||||
private String sn;
|
||||
|
||||
/**
|
||||
* 设备型号 id ,通过注册设备获得
|
||||
*/
|
||||
private String model_id;
|
||||
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
package com.imdroid.beidou.data.dto;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.imdroid.beidou.utils.GsonUtils;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 小程序订阅消息
|
||||
*
|
||||
* @author LiGang
|
||||
* @date 2023/11/11 16:09
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class MiniSubscribeMessageDTO {
|
||||
|
||||
@Expose
|
||||
private String touser;
|
||||
|
||||
@Expose
|
||||
private String template_id;
|
||||
|
||||
@Expose
|
||||
private String page;
|
||||
|
||||
@Expose
|
||||
private String miniprogram_state = "developer";
|
||||
|
||||
@Expose
|
||||
private String lang = "zh_CN";
|
||||
|
||||
@Expose
|
||||
private Map<String, Map<String, Object>> data;
|
||||
|
||||
|
||||
public void addDataItem(String key, Object value) {
|
||||
if (data == null) {
|
||||
data = new HashMap<>(8);
|
||||
}
|
||||
Map<String, Object> valueMap = new HashMap<>(1);
|
||||
valueMap.put("value", value);
|
||||
data.put(key, valueMap);
|
||||
}
|
||||
|
||||
public void removeDataItem(String key) {
|
||||
data.remove(key);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package com.imdroid.beidou.data.vo.mini;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 小程序设备SnTicket VO类
|
||||
*
|
||||
* @author LiGang
|
||||
* @date 2023/11/12 11:10
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DeviceSnTicketVO {
|
||||
|
||||
private String sn;
|
||||
|
||||
private String snTicket;
|
||||
|
||||
private String modelId;
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
package com.imdroid.beidou.utils;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* @author Layton
|
||||
* @date 2022/3/28 15:35
|
||||
*/
|
||||
public class GsonUtils {
|
||||
|
||||
private static final Gson gson = new Gson();
|
||||
|
||||
private static final Gson serializeNullGson = new GsonBuilder().serializeNulls().disableHtmlEscaping().create();
|
||||
|
||||
private static final Gson serializeExposeGson = new GsonBuilder().serializeNulls().excludeFieldsWithoutExposeAnnotation().create();
|
||||
|
||||
public static String toJsonSerializeNull(Object c) {
|
||||
return serializeNullGson.toJson(c);
|
||||
}
|
||||
|
||||
public static String toJson(Object c) {
|
||||
return gson.toJson(c);
|
||||
}
|
||||
|
||||
public static String toJsonExpose(Object c) {
|
||||
return serializeExposeGson.toJson(c);
|
||||
}
|
||||
|
||||
public static <T> T fromJson(String json, Class<T> clz) {
|
||||
return gson.fromJson(json, clz);
|
||||
}
|
||||
|
||||
public static <T> T fromJson(String json, Type typeOfT) {
|
||||
return gson.fromJson(json, typeOfT);
|
||||
}
|
||||
|
||||
public static String getValue(JsonObject jsonObject, String key) {
|
||||
JsonElement element = jsonObject.has(key) ? jsonObject.get(key) : null;
|
||||
if (element == null) {
|
||||
return "";
|
||||
}
|
||||
if (element.isJsonObject()) {
|
||||
return element.getAsJsonObject().toString();
|
||||
} else if (element.isJsonNull()) {
|
||||
return "";
|
||||
} else if (element.isJsonArray()) {
|
||||
return element.getAsJsonArray().toString();
|
||||
} else {
|
||||
if (element.getAsJsonPrimitive().isBoolean()) {
|
||||
return element.getAsBoolean() ? "true" : "false";
|
||||
} else {
|
||||
return element.getAsString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Number getNumber(JsonElement element) { ;
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
if (element.isJsonNull()) {
|
||||
return null;
|
||||
} else {
|
||||
try {
|
||||
return element.getAsNumber();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5,11 +5,14 @@ import com.imdroid.beidou.config.WxMiniProperties;
|
||||
import com.imdroid.beidou.data.WxMiniUserSession;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.imdroid.beidou.data.dto.MiniHardwareDeviceMessageDTO;
|
||||
import com.imdroid.beidou.data.dto.MiniSnTicketBodyDTO;
|
||||
import com.imdroid.beidou.data.dto.MiniSubscribeMessageDTO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
* 微信相关工具类
|
||||
*
|
||||
* @author LiGang
|
||||
*/
|
||||
@ -23,24 +26,120 @@ public class WXUtils {
|
||||
this.wxMiniProperties = wxMiniProperties;
|
||||
}
|
||||
|
||||
private String accessToken;
|
||||
private long accessTokenExpireTime = 0L;
|
||||
private static final long PRE_EXPIRE_TIME = 5 * 60 * 1000L;
|
||||
|
||||
/**
|
||||
* 微信api地址
|
||||
* 微信小程序登录api地址
|
||||
*/
|
||||
protected final String API_URL = "https://api.weixin.qq.com/sns/jscode2session";
|
||||
|
||||
protected final String API_SEND_SUBSCRIBE_MESSAGE_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send";
|
||||
|
||||
protected final String API_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";
|
||||
|
||||
protected final String API_SN_TICKET_URL = "https://api.weixin.qq.com/wxa/getsnticket";
|
||||
|
||||
protected final String API_HARDWARE_DEVICE_MESSAGE_URL = "https://api.weixin.qq.com/cgi-bin/message/device/subscribe/send";
|
||||
|
||||
/**
|
||||
* 获取小程序 access_token
|
||||
*
|
||||
* @return access_token
|
||||
*/
|
||||
public String getAccessToken() {
|
||||
if (accessTokenExpireTime - System.currentTimeMillis() >= PRE_EXPIRE_TIME ) {
|
||||
return accessToken;
|
||||
}
|
||||
String url = API_ACCESS_TOKEN_URL + "?grant_type=client_credential&appid=" + wxMiniProperties.getAppid() +
|
||||
"&secret=" + wxMiniProperties.getSecret();
|
||||
try {
|
||||
final String response = HttpUtil.doGet(url);
|
||||
log.info("小程序获取access_token结果:{}", response);
|
||||
JsonObject jsonObject = JsonParser.parseString(response).getAsJsonObject();
|
||||
accessTokenExpireTime = System.currentTimeMillis() + 7200 * 1000;
|
||||
accessToken = jsonObject.get("access_token").getAsString();
|
||||
return accessToken;
|
||||
} catch (Exception e) {
|
||||
log.error("小程序登录结果:{}", e.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取小程序用户的openid
|
||||
*
|
||||
* @param code 登录码
|
||||
* @return 小程序用户的openid
|
||||
*/
|
||||
public WxMiniUserSession getMiniProgramUserOpenid(String code) {
|
||||
String requestURL = String.format(API_URL + "?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code"
|
||||
String requestUrl = String.format(API_URL + "?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code"
|
||||
, wxMiniProperties.getAppid(), wxMiniProperties.getSecret(), code);
|
||||
try {
|
||||
final String response = HttpUtil.doGet(requestURL);
|
||||
final String response = HttpUtil.doGet(requestUrl);
|
||||
log.info("小程序登录结果:{}", response);
|
||||
JsonObject jsonObject = JsonParser.parseString(response).getAsJsonObject();
|
||||
String sessionKey = jsonObject.get("session_key").getAsString();
|
||||
String openid = jsonObject.get("openid").getAsString();
|
||||
return new WxMiniUserSession(sessionKey, openid);
|
||||
} catch (Exception e) {
|
||||
log.error("小程序登录结果:{}", e.toString());
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送小程序订阅消息
|
||||
*
|
||||
* @param miniSubscribeMessageDTO 小程序订阅消息对象
|
||||
*/
|
||||
public void sendSubscribeMessage(MiniSubscribeMessageDTO miniSubscribeMessageDTO) {
|
||||
String requestUrl = API_SEND_SUBSCRIBE_MESSAGE_URL + "?access_token=" + getAccessToken();
|
||||
try {
|
||||
String dataJson = GsonUtils.toJson(miniSubscribeMessageDTO);
|
||||
final String response = HttpUtil.doPostJson(requestUrl, dataJson);
|
||||
log.info("发送订阅消息结果:{}", response);
|
||||
} catch (Exception e) {
|
||||
log.error("发送订阅消息结果:{}",e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备snTicket
|
||||
*
|
||||
* @param miniSnTicketBodyDTO MiniSnTicketBodyDTO
|
||||
* @return 设备snTicket
|
||||
*/
|
||||
public String getSnTicket(MiniSnTicketBodyDTO miniSnTicketBodyDTO) {
|
||||
String requestUrl = API_SN_TICKET_URL + "?access_token=" + getAccessToken();
|
||||
try {
|
||||
String dataJson = GsonUtils.toJson(miniSnTicketBodyDTO);
|
||||
final String response = HttpUtil.doPostJson(requestUrl, dataJson);
|
||||
log.info("获取设备snTicket结果:{}", response);
|
||||
JsonObject jsonObject = JsonParser.parseString(response).getAsJsonObject();
|
||||
return jsonObject.get("sn_ticket").getAsString();
|
||||
} catch (Exception e) {
|
||||
log.error("获取设备snTicket结果:{}",e.toString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送设备消息
|
||||
*
|
||||
* @param hardwareDeviceMessageDTO MiniHardwareDeviceMessageDTO
|
||||
*/
|
||||
public void sendHardwareDeviceMessage(MiniHardwareDeviceMessageDTO hardwareDeviceMessageDTO) {
|
||||
String requestUrl = API_HARDWARE_DEVICE_MESSAGE_URL + "?access_token=" + getAccessToken();
|
||||
try {
|
||||
String dataJson = GsonUtils.toJson(hardwareDeviceMessageDTO);
|
||||
final String response = HttpUtil.doPostJson(requestUrl, dataJson);
|
||||
log.info("发送设备消息结果:{}", response);
|
||||
} catch (Exception e) {
|
||||
log.error("发送设备消息结果: {}", e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -34,6 +34,8 @@ default_pwd = 666666
|
||||
# miniprogram info
|
||||
app.bis.appid = wxb51f83011ecef07f
|
||||
app.bis.secret = fa046f918a7a10fe6f21c6ccfc4ea918
|
||||
app.bis.modelId = askdf
|
||||
app.bis.device-alert-template-id = asdf
|
||||
|
||||
aliyun.oss.endpoint = https://oss-cn-shanghai.aliyuncs.com
|
||||
aliyun.oss.accessKey = LTAI4G6hmpX7h9hQvUnwKWxj
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user