feat: 新功能开发,监测历史记录。微信和物联网平台,模块搭建。
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user