本文目录导读:

我来为您详细介绍Java小程序对接的实操案例,由于“小程序”通常指微信小程序,这里以Java后端对接微信小程序为例。
核心流程概述
微信小程序的登录流程:
- 小程序端获取
code(临时登录凭证) - 将
code发送给Java后端 - Java后端调用微信接口(
code2Session)换取openid和session_key - 后端生成自定义登录态返回给小程序
环境准备
依赖配置(Maven)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.32</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version>
</dependency>
配置文件(application.yml)
wechat:
miniapp:
appid: your_appid_here
secret: your_secret_here
grant-type: authorization_code
login-url: https://api.weixin.qq.com/sns/jscode2session
核心代码实现
配置类
@Component
@ConfigurationProperties(prefix = "wechat.miniapp")
public class WechatConfig {
private String appid;
private String secret;
private String grantType;
private String loginUrl;
// getter/setter 省略
}
微信工具类
@Component
public class WechatUtil {
@Autowired
private WechatConfig wechatConfig;
/**
* 获取微信session信息
*/
public JSONObject getSessionInfo(String code) {
String url = String.format("%s?appid=%s&secret=%s&js_code=%s&grant_type=%s",
wechatConfig.getLoginUrl(),
wechatConfig.getAppid(),
wechatConfig.getSecret(),
code,
wechatConfig.getGrantType());
return HttpClientUtil.doGet(url);
}
/**
* 解密用户信息(获取手机号等敏感数据)
*/
public JSONObject decryptUserInfo(String encryptedData, String sessionKey, String iv) {
try {
byte[] result = AESDecryptUtil.decrypt(
Base64.decodeBase64(encryptedData),
Base64.decodeBase64(sessionKey),
Base64.decodeBase64(iv)
);
return JSON.parseObject(new String(result, "UTF-8"));
} catch (Exception e) {
throw new BusinessException("解密用户信息失败");
}
}
}
用户服务层
@Service
public class UserService {
@Autowired
private WechatUtil wechatUtil;
@Autowired
private UserMapper userMapper;
/**
* 小程序登录
*/
public LoginResponse login(LoginRequest request) {
// 1. 获取微信session
JSONObject sessionInfo = wechatUtil.getSessionInfo(request.getCode());
if (sessionInfo.containsKey("errcode") && sessionInfo.getInteger("errcode") != 0) {
throw new BusinessException("登录失败:" + sessionInfo.getString("errmsg"));
}
String openid = sessionInfo.getString("openid");
String sessionKey = sessionInfo.getString("session_key");
// 2. 查询或创建用户
User user = userMapper.selectByOpenid(openid);
if (user == null) {
user = new User();
user.setOpenid(openid);
user.setCreateTime(new Date());
userMapper.insert(user);
}
// 3. 生成自定义登录态(JWT Token)
String token = generateToken(user.getId(), openid);
// 4. 返回结果
LoginResponse response = new LoginResponse();
response.setToken(token);
response.setUserId(user.getId());
response.setSessionKey(sessionKey); // 注意:session_key不要返回给前端,仅在解密时使用
return response;
}
/**
* 获取用户手机号
*/
public String getUserPhone(DecryptRequest request) {
// 从session中获取session_key(实际项目中可以存入Redis)
String sessionKey = getSessionKeyByToken(request.getToken());
JSONObject userInfo = wechatUtil.decryptUserInfo(
request.getEncryptedData(),
sessionKey,
request.getIv()
);
// 更新用户手机号
String phone = userInfo.getString("phoneNumber");
userMapper.updatePhoneByOpenid(request.getOpenid(), phone);
return phone;
}
}
控制器层
@RestController
@RequestMapping("/api/wx")
public class WechatController {
@Autowired
private UserService userService;
/**
* 小程序登录
*/
@PostMapping("/login")
public Result<LoginResponse> login(@RequestBody LoginRequest request) {
LoginResponse response = userService.login(request);
return Result.success(response);
}
/**
* 获取手机号
*/
@PostMapping("/decrypt")
public Result<String> decryptPhone(@RequestBody DecryptRequest request) {
String phone = userService.getUserPhone(request);
return Result.success(phone);
}
}
请求/响应实体类
public class LoginRequest {
private String code; // 小程序端获取的code
// getter/setter
}
public class LoginResponse {
private String token;
private Long userId;
private String sessionKey;
// getter/setter
}
public class DecryptRequest {
private String token;
private String openid;
private String encryptedData;
private String iv;
// getter/setter
}
小程序端对接代码(示例)
登录流程
// app.js
wx.login({
success(res) {
if (res.code) {
// 将code发送到后端
wx.request({
url: 'https://your-domain.com/api/wx/login',
method: 'POST',
data: { code: res.code },
success(response) {
// 存储token到本地
wx.setStorageSync('token', response.data.data.token)
// 存储sessionKey(用于后续解密)
wx.setStorageSync('sessionKey', response.data.data.sessionKey)
}
})
}
}
})
获取手机号
// 用户点击"获取手机号"按钮
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">获取手机号</button>
Page({
getPhoneNumber(e) {
if (e.detail.errMsg === 'getPhoneNumber:ok') {
// 发送加密数据到后端解密
wx.request({
url: 'https://your-domain.com/api/wx/decrypt',
method: 'POST',
data: {
token: wx.getStorageSync('token'),
openid: '', // 从登录返回中保存
encryptedData: e.detail.encryptedData,
iv: e.detail.iv
},
success(res) {
console.log('手机号:', res.data.data)
}
})
}
}
})
关键注意事项
安全性
- session_key 绝对不能传输给前端或存储到客户端,仅在后端使用
- 使用 JWT 生成自定义token,有效期建议2小时
- 重要接口需校验JWT有效性
code 有效期
- 每个code只能使用一次,有效期5分钟
- 重新登录需要获取新的code
用户身份持久化
// 使用Redis缓存session_key
@Autowired
private RedisTemplate redisTemplate;
public void saveSessionKey(String token, String sessionKey) {
redisTemplate.opsForValue().set("session:" + token, sessionKey, 2, TimeUnit.HOURS);
}
数据解密(AES工具类)
public class AESDecryptUtil {
public static byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(ivByte);
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
return cipher.doFinal(content);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
异常处理
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
@ResponseBody
public Result handleBusinessException(BusinessException e) {
return Result.error(e.getMessage());
}
}
调试建议
- 使用微信开发者工具:可模拟真实环境
- 检查参数:确保appid和secret正确
- 域名配置:微信小程序后台配置request合法域名
- 日志记录:记录code和返回结果便于排查
- 测试工具:使用Postman测试后端接口
完整项目结构
src/main/java/com/example/wxapp/
├── config/
│ └── WechatConfig.java
├── controller/
│ └── WechatController.java
├── service/
│ └── UserService.java
├── util/
│ ├── WechatUtil.java
│ └── AESDecryptUtil.java
├── model/
│ ├── LoginRequest.java
│ ├── LoginResponse.java
│ └── DecryptRequest.java
├── mapper/
│ └── UserMapper.java
└── common/
├── Result.java
└── BusinessException.java
通过以上实现,您就完成了Java后端与微信小程序的完整对接,如果对接的是其他平台(如支付宝、抖音),核心流程类似,只是API地址和参数不同。