feat: 新功能开发,监测历史记录。微信和物联网平台,模块搭建。

This commit is contained in:
tianyongbao
2025-11-05 00:35:23 +08:00
parent 4d10d291a3
commit 8fd28e727e
38 changed files with 2099 additions and 49 deletions

View File

@@ -0,0 +1,37 @@
package com.intc.weixin.config;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 微信小程序配置
*
* @author intc
*/
@Configuration
@RequiredArgsConstructor
@ConditionalOnProperty(prefix = "wx.miniapp", name = "app-id")
public class WxMaConfiguration {
private final WxMaProperties wxMaProperties;
@Bean
public WxMaService wxMaService() {
WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
config.setAppid(wxMaProperties.getAppId());
config.setSecret(wxMaProperties.getSecret());
config.setToken(wxMaProperties.getToken());
config.setAesKey(wxMaProperties.getAesKey());
config.setMsgDataFormat(wxMaProperties.getMsgDataFormat());
WxMaService service = new WxMaServiceImpl();
service.setWxMaConfig(config);
return service;
}
}

View File

@@ -0,0 +1,42 @@
package com.intc.weixin.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 微信小程序配置属性
*
* @author intc
*/
@Data
@Component
@ConfigurationProperties(prefix = "wx.miniapp")
public class WxMaProperties {
/**
* 小程序appId
*/
private String appId;
/**
* 小程序Secret
*/
private String secret;
/**
* 小程序token
*/
private String token;
/**
* 小程序EncodingAESKey
*/
private String aesKey;
/**
* 消息格式XML或者JSON
*/
private String msgDataFormat;
}

View File

@@ -0,0 +1,36 @@
package com.intc.weixin.config;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 微信公众号配置
*
* @author intc
*/
@Configuration
@RequiredArgsConstructor
@ConditionalOnProperty(prefix = "wx.mp", name = "app-id")
public class WxMpConfiguration {
private final WxMpProperties wxMpProperties;
@Bean
public WxMpService wxMpService() {
WxMpDefaultConfigImpl config = new WxMpDefaultConfigImpl();
config.setAppId(wxMpProperties.getAppId());
config.setSecret(wxMpProperties.getSecret());
config.setToken(wxMpProperties.getToken());
config.setAesKey(wxMpProperties.getAesKey());
WxMpService service = new WxMpServiceImpl();
service.setWxMpConfigStorage(config);
return service;
}
}

View File

@@ -0,0 +1,37 @@
package com.intc.weixin.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 微信公众号配置属性
*
* @author intc
*/
@Data
@Component
@ConfigurationProperties(prefix = "wx.mp")
public class WxMpProperties {
/**
* 公众号appId
*/
private String appId;
/**
* 公众号Secret
*/
private String secret;
/**
* 公众号token
*/
private String token;
/**
* 公众号EncodingAESKey
*/
private String aesKey;
}

View File

@@ -0,0 +1,39 @@
package com.intc.weixin.config;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 微信支付配置
*
* @author intc
*/
@Configuration
@RequiredArgsConstructor
@ConditionalOnProperty(prefix = "wx.pay", name = "mch-id")
public class WxPayConfiguration {
private final WxPayProperties wxPayProperties;
@Bean
public WxPayService wxPayService() {
WxPayConfig config = new WxPayConfig();
config.setMchId(wxPayProperties.getMchId());
config.setMchKey(wxPayProperties.getMchKey());
config.setKeyPath(wxPayProperties.getKeyPath());
config.setApiV3Key(wxPayProperties.getApiV3Key());
config.setCertSerialNo(wxPayProperties.getCertSerialNo());
config.setPrivateKeyPath(wxPayProperties.getPrivateKeyPath());
config.setPrivateCertPath(wxPayProperties.getPrivateContent());
WxPayService service = new WxPayServiceImpl();
service.setConfig(config);
return service;
}
}

View File

@@ -0,0 +1,52 @@
package com.intc.weixin.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 微信支付配置属性
*
* @author intc
*/
@Data
@Component
@ConfigurationProperties(prefix = "wx.pay")
public class WxPayProperties {
/**
* 商户号
*/
private String mchId;
/**
* 商户密钥
*/
private String mchKey;
/**
* apiclient_cert.p12文件的绝对路径或者以classpath:开头的类路径
*/
private String keyPath;
/**
* apiV3秘钥
*/
private String apiV3Key;
/**
* 证书序列号
*/
private String certSerialNo;
/**
* 私钥路径
*/
private String privateKeyPath;
/**
* 私钥内容
*/
private String privateContent;
}

View File

@@ -0,0 +1,109 @@
package com.intc.weixin.controller;
import com.intc.common.core.domain.R;
import com.intc.common.web.core.BaseController;
import com.intc.weixin.service.WxMaService;
import com.intc.weixin.service.WxMpService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Optional;
/**
* 微信对接控制器
*
* @author intc
*/
@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/weixin")
@Tag(name = "微信对接管理", description = "微信对接相关接口")
public class WeixinController extends BaseController {
@Autowired(required = false)
private WxMpService wxMpService;
@Autowired(required = false)
private WxMaService wxMaService;
@Operation(summary = "测试接口")
@GetMapping("/test")
public R<String> test() {
return R.ok("微信模块测试成功!");
}
@Operation(summary = "获取公众号用户信息")
@GetMapping("/mp/user/{openId}")
public R<WxMpUser> getMpUserInfo(
@Parameter(description = "用户openId") @PathVariable String openId) {
try {
if (wxMpService == null) {
return R.fail("公众号配置未启用");
}
WxMpUser userInfo = wxMpService.getUserInfo(openId);
return R.ok(userInfo);
} catch (WxErrorException e) {
log.error("获取用户信息失败", e);
return R.fail("获取用户信息失败: " + e.getMessage());
}
}
@Operation(summary = "生成公众号二维码")
@GetMapping("/mp/qrcode")
public R<String> createMpQrCode(
@Parameter(description = "场景值") @RequestParam String scene) {
try {
if (wxMpService == null) {
return R.fail("公众号配置未启用");
}
String qrCodeUrl = wxMpService.createQrCode(scene);
return R.ok(qrCodeUrl);
} catch (WxErrorException e) {
log.error("生成二维码失败", e);
return R.fail("生成二维码失败: " + e.getMessage());
}
}
@Operation(summary = "小程序登录")
@GetMapping("/ma/login")
public R<String> maLogin(
@Parameter(description = "登录code") @RequestParam String code) {
try {
if (wxMaService == null) {
return R.fail("小程序配置未启用");
}
String openId = wxMaService.code2Session(code);
return R.ok(openId);
} catch (WxErrorException e) {
log.error("小程序登录失败", e);
return R.fail("小程序登录失败: " + e.getMessage());
}
}
@Operation(summary = "生成小程序码")
@GetMapping("/ma/qrcode")
public R<String> createMaQrCode(
@Parameter(description = "场景值") @RequestParam String scene,
@Parameter(description = "页面路径") @RequestParam(required = false) String page) {
try {
if (wxMaService == null) {
return R.fail("小程序配置未启用");
}
byte[] qrCodeBytes = wxMaService.getUnlimitedQrCode(scene, page);
// 这里可以将字节数组上传到OSS或者直接返回给前端
return R.ok("二维码生成成功,大小: " + qrCodeBytes.length + " bytes");
} catch (WxErrorException e) {
log.error("生成小程序码失败", e);
return R.fail("生成小程序码失败: " + e.getMessage());
}
}
}

View File

@@ -0,0 +1,74 @@
package com.intc.weixin.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 微信用户信息
*
* @author intc
*/
@Data
@TableName("wx_user")
public class WxUser implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId
private Long id;
/**
* 微信openId
*/
private String openId;
/**
* 微信unionId
*/
private String unionId;
/**
* 昵称
*/
private String nickname;
/**
* 头像
*/
private String avatar;
/**
* 性别 0-未知 1-男 2-女
*/
private Integer gender;
/**
* 手机号
*/
private String mobile;
/**
* 来源类型mp-公众号 ma-小程序
*/
private String sourceType;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 更新时间
*/
private LocalDateTime updateTime;
}

View File

@@ -0,0 +1,31 @@
package com.intc.weixin.service;
import me.chanjar.weixin.common.error.WxErrorException;
/**
* 微信小程序服务接口
*
* @author intc
*/
public interface WxMaService {
/**
* 登录凭证校验
*
* @param code 登录时获取的 code
* @return sessionKey和openId
* @throws WxErrorException 微信异常
*/
String code2Session(String code) throws WxErrorException;
/**
* 获取小程序码
*
* @param scene 场景值
* @param page 页面路径
* @return 二进制图片数据
* @throws WxErrorException 微信异常
*/
byte[] getUnlimitedQrCode(String scene, String page) throws WxErrorException;
}

View File

@@ -0,0 +1,31 @@
package com.intc.weixin.service;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
/**
* 微信公众号服务接口
*
* @author intc
*/
public interface WxMpService {
/**
* 获取用户信息
*
* @param openId 用户openId
* @return 用户信息
* @throws WxErrorException 微信异常
*/
WxMpUser getUserInfo(String openId) throws WxErrorException;
/**
* 生成二维码ticket
*
* @param sceneStr 场景值
* @return ticket
* @throws WxErrorException 微信异常
*/
String createQrCode(String sceneStr) throws WxErrorException;
}

View File

@@ -0,0 +1,38 @@
package com.intc.weixin.service.impl;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import com.intc.weixin.service.WxMaService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.stereotype.Service;
/**
* 微信小程序服务实现
*
* @author intc
*/
@Slf4j
@Service
@RequiredArgsConstructor
@ConditionalOnBean(cn.binarywang.wx.miniapp.api.WxMaService.class)
public class WxMaServiceImpl implements WxMaService {
private final cn.binarywang.wx.miniapp.api.WxMaService wxMaService;
@Override
public String code2Session(String code) throws WxErrorException {
log.info("小程序登录, code: {}", code);
WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(code);
return session.getOpenid();
}
@Override
public byte[] getUnlimitedQrCode(String scene, String page) throws WxErrorException {
log.info("生成小程序码, scene: {}, page: {}", scene, page);
return wxMaService.getQrcodeService().createWxaCodeUnlimitBytes(scene, page, false, null, 430, true, null, false);
}
}

View File

@@ -0,0 +1,39 @@
package com.intc.weixin.service.impl;
import com.intc.weixin.service.WxMpService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.stereotype.Service;
/**
* 微信公众号服务实现
*
* @author intc
*/
@Slf4j
@Service
@RequiredArgsConstructor
@ConditionalOnBean(me.chanjar.weixin.mp.api.WxMpService.class)
public class WxMpServiceImpl implements WxMpService {
private final me.chanjar.weixin.mp.api.WxMpService wxMpService;
@Override
public WxMpUser getUserInfo(String openId) throws WxErrorException {
log.info("获取微信用户信息, openId: {}", openId);
return wxMpService.getUserService().userInfo(openId);
}
@Override
public String createQrCode(String sceneStr) throws WxErrorException {
log.info("创建微信二维码, sceneStr: {}", sceneStr);
WxMpQrCodeTicket ticket = wxMpService.getQrcodeService()
.qrCodeCreateTmpTicket(sceneStr, 2592000);
return ticket.getUrl();
}
}