Java小程序对接案例如何实操

wen java案例 31

本文目录导读:

Java小程序对接案例如何实操

  1. 核心流程概述
  2. 环境准备
  3. 核心代码实现
  4. 小程序端对接代码(示例)
  5. 关键注意事项
  6. 调试建议
  7. 完整项目结构

我来为您详细介绍Java小程序对接的实操案例,由于“小程序”通常指微信小程序,这里以Java后端对接微信小程序为例。

核心流程概述

微信小程序的登录流程:

  1. 小程序端获取 code(临时登录凭证)
  2. code 发送给Java后端
  3. Java后端调用微信接口(code2Session)换取 openidsession_key
  4. 后端生成自定义登录态返回给小程序

环境准备

依赖配置(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());
    }
}

调试建议

  1. 使用微信开发者工具:可模拟真实环境
  2. 检查参数:确保appid和secret正确
  3. 域名配置:微信小程序后台配置request合法域名
  4. 日志记录:记录code和返回结果便于排查
  5. 测试工具:使用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地址和参数不同。

抱歉,评论功能暂时关闭!