1、引入依赖
<dependency><groupId>com.github.binarywang</groupId><artifactId>weixin-java-miniapp</artifactId><version>4.1.0</version></dependency>
2、引入封装好的工具类
import cn.binarywang.wx.miniapp.api.WxMaService;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;@Data
public class WxAppInfo {/*** 微信服务*/@JsonIgnoreprivate WxMaService wxMaService;/*** 微信App信息*/private Wxapp wxapp;
}
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import org.springframework.data.redis.core.RedisTemplate;import java.util.concurrent.TimeUnit;/*** 基于Redis的微信配置provider.*/
@SuppressWarnings("serial")
public class WxMaInRedisConfigStorage extends WxMaDefaultConfigImpl {public static final String ACCESS_TOKEN_KEY = "wx:ma:access_token:";public final static String JSAPI_TICKET_KEY = "wx:ma:jsapi_ticket:";public final static String CARDAPI_TICKET_KEY = "wx:ma:cardapi_ticket:";private final RedisTemplate<String, String> redisTemplate;public WxMaInRedisConfigStorage(RedisTemplate redisTemplate) {this.redisTemplate = redisTemplate;}private String accessTokenKey;private String jsapiTicketKey;private String cardapiTicketKey;/*** 每个公众号生成独有的存储key.*/@Overridepublic void setAppid(String appId) {super.setAppid(appId);this.accessTokenKey = ACCESS_TOKEN_KEY.concat(appId);this.jsapiTicketKey = JSAPI_TICKET_KEY.concat(appId);this.cardapiTicketKey = CARDAPI_TICKET_KEY.concat(appId);}/*** @return*/@Overridepublic String getAccessToken() {return redisTemplate.opsForValue().get(this.accessTokenKey);}/*** @return*/@Overridepublic boolean isAccessTokenExpired() {return redisTemplate.getExpire(accessTokenKey) < 2;}/*** @param accessToken* @param expiresInSeconds*/@Overridepublic synchronized void updateAccessToken(String accessToken, int expiresInSeconds) {redisTemplate.opsForValue().set(this.accessTokenKey, accessToken, expiresInSeconds - 200, TimeUnit.SECONDS);}/****/@Overridepublic void expireAccessToken() {redisTemplate.expire(this.accessTokenKey, 0, TimeUnit.SECONDS);}/*** @return*/@Overridepublic String getJsapiTicket() {return redisTemplate.opsForValue().get(this.jsapiTicketKey);}/*** @return*/@Overridepublic String getCardApiTicket() {return redisTemplate.opsForValue().get(cardapiTicketKey);}
}
3、工具类
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.hutool.core.codec.Base64;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yami.shop.bean.model.Wxapp;
import com.yami.shop.service.WxAppService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.cert.X509Certificate;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;@Slf4j
@Configuration
public class WxMaConfiguration {private static RedisTemplate redisTemplate;private static WxAppService wxappService;private static Map<String, WxAppInfo> wxAppInfoMap = new ConcurrentHashMap<>();private static Map<String, X509Certificate> wxPlatCertMap = new ConcurrentHashMap<>();public WxMaConfiguration(RedisTemplate redisTemplate, WxAppService wxAppService) {this.redisTemplate = redisTemplate;this.wxappService = wxAppService;}/*** 获取WxMaService** @return*/public static WxAppInfo getWxAppInfo() {//替换你的获取小程序配置信息的sqlWxapp wxapp = wxappService.getOne(Wrappers.<Wxapp>lambdaQuery().orderByDesc(Wxapp::getCreateTime));WxAppInfo wxAppInfo = wxAppInfoMap.get(wxapp.getId());if (wxAppInfo != null && wxAppInfo.getWxMaService() != null) {return wxAppInfo;}WxMaInRedisConfigStorage configStorage = new WxMaInRedisConfigStorage(redisTemplate);configStorage.setAppid(wxapp.getId());configStorage.setSecret(wxapp.getSecret());WxMaService wxMaService = new WxMaServiceImpl();wxMaService.setWxMaConfig(configStorage);wxAppInfo = new WxAppInfo();wxAppInfo.setWxMaService(wxMaService);wxAppInfo.setWxapp(wxapp);wxAppInfoMap.put(wxapp.getId(), wxAppInfo);return wxAppInfo;}/*** @Description:解密手机号*/public static String decrypt(String keyStr, String ivStr, String encDataStr) {try {byte[] encData = Base64.decode(encDataStr.getBytes("GBK"));byte[] iv = Base64.decode(ivStr.getBytes("GBK"));byte[] keyByte = Base64.decode(keyStr.getBytes("GBK"));// 如果密钥不足16位,那么就补足. 这个if 中的内容很重要int base = 16;if (keyByte.length % base != 0) {int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);byte[] temp = new byte[groups * base];Arrays.fill(temp, (byte) 0);System.arraycopy(keyByte, 0, temp, 0, keyByte.length);keyByte = temp;}AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv);Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);return new String(cipher.doFinal(encData), "UTF-8");} catch (Exception e) {e.printStackTrace();}return null;}}
4、调用获取小程序openid
/*** 小程序用户登录** @param loginDTO* @return*/@GetMapping("/login")public void login(String jsCode) {WxMaJscode2SessionResult jscode2session = null;try {jscode2session = WxMaConfiguration.getWxAppInfo().getWxMaService().jsCode2SessionInfo(jsCode);//生成accessToken方法 已经封装好直接调用即可 已做缓存处理
// String accessToken = WxMaConfiguration.getWxAppInfo()
// .getWxMaService().getAccessToken();} catch (Exception e) {e.printStackTrace();}Assert.notNull(jscode2session, "用户信息获取失败,请稍后重试!");User user = userService.getOne(Wrappers.<User>lambdaQuery().eq(User::getOpenId, jscode2session.getOpenid()));if (null == user) {user = new User();//保存用户信息user.setOpenId(jscode2session.getOpenid());}user.setSessionKey(jscode2session.getSessionKey());userService.saveOrUpdate(user);//todo 生成toke登录信息}
5、获取手机号
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
public class GetPhoneDTO {@NotBlank(message = "encryptedData is required")private String encryptedData;@NotBlank(message = "iv is required")private String iv;@NotBlank(message = "code is required")private String code;private String appId;private Long userId;}/*** 获取用户手机号** @param getPhoneDTO* @return*/
@PostMapping("/getMobile")
public void getMobile(@Valid @RequestBody GetPhoneDTO getPhoneDTO)
{JSONObject result = JSONObject.parseObject(WxMaConfiguration.decrypt("sessionKey", getPhoneDTO.getIv(), getPhoneDTO.getEncryptedData()));String phone = result.getString("phoneNumber");
}