Comprehensive Java SDK for WeChat MiniApp development with complete platform integration
—
User authentication, profile information, phone number access, and user data management for WeChat MiniApp users. This service handles the complete user lifecycle from login to data access.
Core user operations including session management, profile decryption, and user data storage.
public interface WxMaUserService {
// Authentication
WxMaJscode2SessionResult getSessionInfo(String jsCode) throws WxErrorException;
// User Profile Data
WxMaUserInfo getUserInfo(String sessionKey, String encryptedData, String ivStr) throws WxErrorException;
boolean checkUserInfo(String sessionKey, String rawData, String signature) throws WxErrorException;
// Phone Number Access (New Method - Base Library 2.21.2+)
WxMaPhoneNumberInfo getPhoneNumber(String code) throws WxErrorException;
// Phone Number Access (Legacy Method - Deprecated)
@Deprecated
WxMaPhoneNumberInfo getPhoneNoInfo(String sessionKey, String encryptedData, String ivStr) throws WxErrorException;
// User Storage (Mini Games)
void setUserStorage(Map<String, String> kvMap, String sessionKey, String openid) throws WxErrorException;
}Data models for user profile information and phone number data.
public class WxMaUserInfo implements Serializable {
private String openId; // User unique identifier
private String nickName; // User nickname
private String gender; // Gender (0: unknown, 1: male, 2: female)
private String city; // City
private String province; // Province
private String country; // Country
private String avatarUrl; // Avatar URL
private String unionId; // Union ID (if available)
private String language; // User language (zh_CN, en_US, etc.)
private WxMaUserInfo.Watermark watermark; // Watermark info
// Getters and setters
public String getOpenId();
public void setOpenId(String openId);
public String getNickName();
public void setNickName(String nickName);
public String getGender();
public void setGender(String gender);
public String getCity();
public void setCity(String city);
public String getProvince();
public void setProvince(String province);
public String getCountry();
public void setCountry(String country);
public String getAvatarUrl();
public void setAvatarUrl(String avatarUrl);
public String getUnionId();
public void setUnionId(String unionId);
public String getLanguage();
public void setLanguage(String language);
public Watermark getWatermark();
public void setWatermark(Watermark watermark);
// Nested watermark class
public static class Watermark {
private Long timestamp; // Data timestamp
private String appid; // App ID
public Long getTimestamp();
public void setTimestamp(Long timestamp);
public String getAppid();
public void setAppid(String appid);
}
// Utility methods
public static WxMaUserInfo fromJson(String json);
public String toJson();
}public class WxMaPhoneNumberInfo implements Serializable {
private String phoneNumber; // Phone number with country code
private String purePhoneNumber; // Pure phone number without country code
private String countryCode; // Country code
private WxMaPhoneNumberInfo.Watermark watermark; // Watermark info
// Getters and setters
public String getPhoneNumber();
public void setPhoneNumber(String phoneNumber);
public String getPurePhoneNumber();
public void setPurePhoneNumber(String purePhoneNumber);
public String getCountryCode();
public void setCountryCode(String countryCode);
public Watermark getWatermark();
public void setWatermark(Watermark watermark);
// Nested watermark class
public static class Watermark {
private Long timestamp; // Data timestamp
private String appid; // App ID
public Long getTimestamp();
public void setTimestamp(Long timestamp);
public String getAppid();
public void setAppid(String appid);
}
// Utility methods
public static WxMaPhoneNumberInfo fromJson(String json);
public String toJson();
}Session data model for user login sessions.
public class WxMaJscode2SessionResult implements Serializable {
private String sessionKey; // Session key for encryption operations
private String openid; // User OpenID
private String unionid; // Union ID (cross-app identifier)
// Factory method
public static WxMaJscode2SessionResult fromJson(String json);
// Getters and setters
public String getSessionKey();
public void setSessionKey(String sessionKey);
public String getOpenid();
public void setOpenid(String openid);
public String getUnionid();
public void setUnionid(String unionid);
// Utility methods
public String toJson();
@Override
public String toString();
}// 1. Exchange login code for session (from wx.login())
String jsCode = "061XaW100MIVdh1U8l000qdncT3XaW1g";
try {
WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(jsCode);
String openid = session.getOpenid();
String sessionKey = session.getSessionKey();
String unionid = session.getUnionid(); // May be null
// Store session info securely (don't expose sessionKey to client)
} catch (WxErrorException e) {
if (e.getError().getErrorCode() == 40029) {
// Invalid js_code (expired, used, or invalid)
return ResponseEntity.badRequest().body("Login code expired");
}
throw e;
}// Client provides encrypted user data (from wx.getUserInfo() or getUserProfile())
String encryptedData = "CiyLU1Aw2KjvrjMdj8YKliAjtP4gsMZM...";
String iv = "r7BXXKkLb8qrSNn05n0qiA==";
try {
WxMaUserInfo userInfo = wxService.getUserService().getUserInfo(
sessionKey, // From login session
encryptedData, // From client
iv // From client
);
// Access user profile data
String nickname = userInfo.getNickName();
String avatarUrl = userInfo.getAvatarUrl();
String gender = userInfo.getGender(); // "0", "1", "2"
String city = userInfo.getCity();
String province = userInfo.getProvince();
String country = userInfo.getCountry();
String unionId = userInfo.getUnionId(); // Cross-app user ID
// Check data freshness
WxMaUserInfo.Watermark watermark = userInfo.getWatermark();
if (watermark != null) {
long timestamp = watermark.getTimestamp();
String appid = watermark.getAppid();
// Verify data is recent and from correct app
long now = System.currentTimeMillis() / 1000;
if (now - timestamp > 300) { // Data older than 5 minutes
// Consider refreshing user data
}
}
} catch (WxErrorException e) {
// Handle decryption errors
logger.error("Failed to decrypt user info: {}", e.getMessage());
}// Verify user data hasn't been tampered with
String rawData = "{\"nickName\":\"Band\",\"gender\":1,\"language\":\"zh_CN\",\"city\":\"Guangzhou\",\"province\":\"Guangdong\",\"country\":\"CN\",\"avatarUrl\":\"http://wx.qlogo.cn/mmopen/vi_32/1vS19XGlp/0\"}";
String signature = "75e81ceda165f4ffa64f4068af58c64b8f54b88c";
try {
boolean isValid = wxService.getUserService().checkUserInfo(sessionKey, rawData, signature);
if (isValid) {
// Data integrity verified - safe to use rawData
ObjectMapper mapper = new ObjectMapper();
JsonNode userJson = mapper.readTree(rawData);
String nickname = userJson.get("nickName").asText();
} else {
// Data may have been tampered with
logger.warn("User data signature verification failed");
}
} catch (WxErrorException e) {
logger.error("Error verifying user data: {}", e.getMessage());
}// New method for getting phone number (Base Library 2.21.2+)
// Client calls wx.getPhoneNumber() and provides code
String phoneCode = "e6fd60b3b24e4d24bb7c3b42e0b3b3b3";
try {
WxMaPhoneNumberInfo phoneInfo = wxService.getUserService().getPhoneNumber(phoneCode);
String fullPhoneNumber = phoneInfo.getPhoneNumber(); // +86138****1234
String purePhoneNumber = phoneInfo.getPurePhoneNumber(); // 138****1234
String countryCode = phoneInfo.getCountryCode(); // "86"
// Verify data freshness
WxMaPhoneNumberInfo.Watermark watermark = phoneInfo.getWatermark();
if (watermark != null) {
long timestamp = watermark.getTimestamp();
String appid = watermark.getAppid();
}
} catch (WxErrorException e) {
int errorCode = e.getError().getErrorCode();
if (errorCode == 40001) {
// Invalid access token
} else if (errorCode == 47001) {
// Data decryption failed
}
}// Legacy method - decrypt phone number from encrypted data
String encryptedData = "Kf3TdPbzEmhWMuPKtlKxIWDkijhn...";
String iv = "r7BXXKkLb8qrSNn05n0qiA==";
try {
@SuppressWarnings("deprecation")
WxMaPhoneNumberInfo phoneInfo = wxService.getUserService().getPhoneNoInfo(
sessionKey, encryptedData, iv
);
String phoneNumber = phoneInfo.getPhoneNumber();
String purePhoneNumber = phoneInfo.getPurePhoneNumber();
String countryCode = phoneInfo.getCountryCode();
} catch (WxErrorException e) {
// Handle decryption errors
logger.error("Phone number decryption failed: {}", e.getMessage());
}// Store key-value data for user in mini games
Map<String, String> kvMap = new HashMap<>();
kvMap.put("level", "10");
kvMap.put("score", "95000");
kvMap.put("items", "sword,shield,potion");
try {
wxService.getUserService().setUserStorage(kvMap, sessionKey, openid);
// Data stored successfully
// Can be retrieved by mini game client using wx.getStorageSync()
} catch (WxErrorException e) {
// Handle storage errors
int errorCode = e.getError().getErrorCode();
if (errorCode == 47001) {
// Invalid session key
} else if (errorCode == 40003) {
// Invalid openid
}
}@Service
public class UserService {
@Autowired
private WxMaService wxMaService;
public UserRegistrationResult registerUser(String jsCode, String encryptedData,
String iv, String phoneCode) {
try {
// 1. Get session info
WxMaJscode2SessionResult session = wxMaService.getUserService()
.getSessionInfo(jsCode);
String openid = session.getOpenid();
String sessionKey = session.getSessionKey();
String unionid = session.getUnionid();
// 2. Decrypt user profile
WxMaUserInfo userInfo = wxMaService.getUserService()
.getUserInfo(sessionKey, encryptedData, iv);
// 3. Get phone number
WxMaPhoneNumberInfo phoneInfo = wxMaService.getUserService()
.getPhoneNumber(phoneCode);
// 4. Create user record
User user = new User();
user.setOpenid(openid);
user.setUnionid(unionid);
user.setNickname(userInfo.getNickName());
user.setAvatarUrl(userInfo.getAvatarUrl());
user.setGender(userInfo.getGender());
user.setCity(userInfo.getCity());
user.setProvince(userInfo.getProvince());
user.setCountry(userInfo.getCountry());
user.setPhoneNumber(phoneInfo.getPurePhoneNumber());
user.setCountryCode(phoneInfo.getCountryCode());
user.setCreatedAt(new Date());
// 5. Save to database
userRepository.save(user);
// 6. Generate JWT or session token
String accessToken = jwtService.generateToken(user);
return new UserRegistrationResult(user, accessToken);
} catch (WxErrorException e) {
throw new UserRegistrationException("Registration failed: " + e.getMessage(), e);
}
}
}public class WeChatUserException extends RuntimeException {
private final int errorCode;
public WeChatUserException(int errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
public int getErrorCode() { return errorCode; }
}
public WxMaUserInfo getUserInfo(String sessionKey, String encryptedData, String iv) {
try {
return wxMaService.getUserService().getUserInfo(sessionKey, encryptedData, iv);
} catch (WxErrorException e) {
int code = e.getError().getErrorCode();
String msg = e.getError().getErrorMsg();
switch (code) {
case 41003:
throw new WeChatUserException(code, "Session key invalid or expired");
case 47001:
throw new WeChatUserException(code, "Data decryption failed");
case 40013:
throw new WeChatUserException(code, "Invalid app ID");
default:
throw new WeChatUserException(code, "User info error: " + msg);
}
}
}The user management service provides secure, comprehensive access to WeChat user data while handling encryption, verification, and data integrity automatically.
Install with Tessl CLI
npx tessl i tessl/maven-com-github-binarywang--weixin-java-miniapp