强大的 Java 工具包,让微信开发变得简单高效
WxJava 是一款开源的微信开发 Java SDK,支持包括微信支付、开放平台、公众号、企业微信/企业号、小程序等微信功能的后端开发。该项目基于 chanjarster 的 weixin-java-tools 发展而来,经过多次优化和重构,使得接口更易使用,方便开发者快速集成微信各项功能。
GIT: https://gitee.com/binary/weixin-java-tools
WxJava 包含 6 个主要模块,每个模块针对不同的微信开发场景:
| 模块名称 | 功能描述 |
|---|---|
| weixin-java-common | 基础工具类与通用接口(如消息加解密、HTTP请求封装) |
| weixin-java-mp | 公众号(订阅号和服务号)SDK |
| weixin-java-miniapp | 微信小程序 SDK |
| weixin-java-pay | 微信支付 SDK |
| weixin-java-cp | 企业号/企业微信 SDK |
| weixin-java-open | 微信开放平台(第三方平台)SDK |
对于 Spring Boot 项目,只需添加对应模块的 starter 依赖
xml <!-- 微信应用开发 --> <dependency> <groupId>com.github.binarywang</groupId> <artifactId>wx-java-mp-spring-boot-starter</artifactId> <version>4.7.0</version> </dependency>
对于非 Spring Boot 项目:
xml <dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-mp</artifactId> <version>4.7.0</version> </dependency>
在 application.yml 或 application.properties 中配置微信公众号参数:
yaml # 公众号配置(必填) wx: mp: appId: your_app_id secret: your_app_secret token: your_token # 存储配置redis(可选),默认是内存 config-storage: type: redistemplate redis: host: 127.0.0.1 port: 6379
微信公众号开发首先需要完成服务器验证,以下是一个简单的验证接口实现:
java @RestController public class WxController { @Autowired private WxMpService wxMpService; /** * 微信服务验证 */ @RequestMapping("/wx") public void wx(HttpServletRequest request, HttpServletResponse response) throws IOException { String signature = request.getParameter("signature"); String timestamp = request.getParameter("timestamp"); String nonce = request.getParameter("nonce"); String echostr = request.getParameter("echostr"); log.info("微信服务器的认证消息:signature :{},timestamp:{},nonce:{},echostr:{}", signature, timestamp, nonce, echostr); if (!wxMpService.checkSignature(timestamp, nonce, signature)) { log.error("消息不合法"); return; } PrintWriter writer = response.getWriter(); try { writer.println(echostr); log.info("验证成功,给微信服务返回消息:{}", echostr); } finally { writer.close(); } } }
WxJava 内置了消息加解密功能,确保与微信服务器通信的安全:
java public String decryptMsg(String msgSignature, String timestamp, String nonce, String encryptMsg) { // 1. 签名校验 String calSignature = SHA1.gen(..., token, timestamp, nonce); if(!msgSignature.equals(calSignature)) throw new Exception; // 2. AES解密 byte[] aesKey = Base64.decode(encodingAesKey); AES aes = new AES(Mode.CBC, Padding.PKCS7, aesKey, iv); return aes.decrypt(encryptMsg); }
WxJava 提供了简洁的 API 来管理微信公众号的素材:
java // 上传临时素材 @GetMapping("/saveTemporaryMaterial") public String saveTemporaryMaterial() { File file = new File("path/to/image.jpg"); WxMediaUploadResult result = wxService.getMaterialService() .mediaUpload(WxConsts.MediaFileType.IMAGE, file); return "上传成功,mediaId: " + result.getMediaId(); } // 上传永久素材 @GetMapping("/savePerpetualMaterial") public String savePerpetualMaterial() { File file = new File("path/to/image.jpg"); WxMpMaterial wxMpMaterial = new WxMpMaterial(); wxMpMaterial.setFile(file); wxMpMaterial.setName("logo"); WxMpMaterialUploadResult result = wxService.getMaterialService() .materialFileUpload(WxConsts.MediaFileType.IMAGE, wxMpMaterial); return "上传成功,mediaId: " + result.getMediaId(); }
获取用户信息是微信公众号开发的常见需求
java // 获取用户信息 WxOAuth2AccessToken wxOAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code); WxOAuth2UserInfo userInfo = wxMpService.getOAuth2Service().getUserInfo(wxOAuth2AccessToken, null);
场景:PC网站上提供二维码,通过微信扫码授权登录,获取微信授权的用户信息
java @Slf4j @RestController public class WxController { @Autowired private WxMpService wxMpService; @Resource private ImUsersService imUsersService; /** * 获取授权URL,生成二维码并转成 base64 */ @GetMapping("/login/qrcode") public QrCodeResponse authorizationUrl() { // 获取重定向URL String oauth2RedirectUrl = wxMpService.getWxMpConfigStorage().getOauth2RedirectUrl(); // 生成回调的state String state = IdUtil.fastUUID(); // 构建授权URL String authorizationUrl = wxMpService.getOAuth2Service().buildAuthorizationUrl(oauth2RedirectUrl, WxConsts.OAuth2Scope.SNSAPI_USERINFO, state); log.info("微信服务授权URL:{}", authorizationUrl); // 生成二维码 String qrCode = QrCodeUtil.generateAsBase64(authorizationUrl, new QrConfig(200, 200), ImgUtil.IMAGE_TYPE_JPG); // 缓存state,有效期1分钟 if (!RedisCacheUtil.setIfAbsent(String.format(RedisKeyDefine.LOGIN_STATE, state), LoginStateEnum.PENDING.name(), 1, TimeUnit.MINUTES)) { return this.authorizationUrl(); } return new QrCodeResponse(state, qrCode); } /** * 检查登录状态 */ @GetMapping("/login/check") public LoginStateEnum checkLoginStatus(@RequestParam("state") String state) { String value = RedisCacheUtil.get(String.format(RedisKeyDefine.LOGIN_STATE, state)); if (value == null) { return LoginStateEnum.EXPIRED; } else if (LoginStateEnum.PENDING.name().equals(value)) { return LoginStateEnum.PENDING; } // 登录成功,返回token并清除state RedisCacheUtil.delete(String.format(RedisKeyDefine.LOGIN_STATE, state)); return LoginStateEnum.SUCCESS; } /** * 微信服务授权后的回调 */ @GetMapping("/callback") public String callback(@RequestParam(name = "code") String code, @RequestParam(name = "state") String state) throws WxErrorException { log.info("微信服务回调:code:{}", code); // 获取用户信息 WxOAuth2AccessToken wxOAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code); WxOAuth2UserInfo userInfo = wxMpService.getOAuth2Service().getUserInfo(wxOAuth2AccessToken, null); log.info("微信服务回调:userInfo:{}", userInfo); // 更新state,二维码等回调呢 RedisCacheUtil.set(String.format(RedisKeyDefine.LOGIN_STATE, state), LoginStateEnum.SUCCESS.name()); // 初始化账户 imUsersService.initUser(userInfo); // 返回响应成功的页面 return "/success"; } /** * 微信服务验证 */ @RequestMapping("/wx") public void wx(HttpServletRequest request, HttpServletResponse response) throws IOException { String signature = request.getParameter("signature"); String timestamp = request.getParameter("timestamp"); String nonce = request.getParameter("nonce"); String echostr = request.getParameter("echostr"); log.info("微信服务器的认证消息:signature :{},timestamp:{},nonce:{},echostr:{}", signature, timestamp, nonce, echostr); if (!wxMpService.checkSignature(timestamp, nonce, signature)) { log.error("消息不合法"); return; } PrintWriter writer = response.getWriter(); try { writer.println(echostr); log.info("验证成功,给微信服务返回消息:{}", echostr); } finally { writer.close(); } } }
配置信息
java @Configuration @EnableConfigurationProperties({WxMpProperties.class, EchoIMProperties.class}) public class WxMpConfiguration { @Bean public WxMpService wxMpService(WxMpConfigStorage configStorage) { WxMpService wxMpService = new WxMpServiceImpl(); wxMpService.setWxMpConfigStorage(configStorage); return wxMpService; } @Bean public WxMpConfigStorage wxMpConfigStorage(WxMpProperties wxMpProperties, EchoIMProperties echoIMProperties) { WxMpDefaultConfigImpl configStorage = new WxMpDefaultConfigImpl(); configStorage.setAppId(wxMpProperties.getAppId()); configStorage.setSecret(wxMpProperties.getSecret()); configStorage.setToken(wxMpProperties.getToken()); configStorage.setAesKey(wxMpProperties.getAesKey()); // 回调地址 configStorage.setOauth2RedirectUrl(echoIMProperties.url() + "/callback"); return configStorage; } }
WxJava 提供了强大的消息路由功能,可以根据消息类型、内容等条件将消息路由到不同的处理器:
java // 初始化消息路由器 WxMpMessageRouter router = new WxMpMessageRouter(wxMpService); // 配置路由规则 router.rule() .msgType(WxConsts.XmlMsgType.TEXT) .handler(textHandler) .end() .rule() .msgType(WxConsts.XmlMsgType.IMAGE) .handler(imageHandler) .end(); // 处理微信消息 WxMpXmlMessage message = ...; WxMpXmlOutMessage response = router.route(message);
为了提高性能,WxJava 支持多种缓存策略,推荐使用 Redis 缓存 access_token 等敏感信息:
java // JSAPI ticket 缓存示例 public String getJsapiTicket() { String ticket = cache.get("jsapi_ticket"); if (ticket == null || isExpired(ticket)) { ticket = refreshTicket(); // 预留 5 分钟缓冲时间 cache.set("jsapi_ticket", ticket, 7200 - 300); } return ticket; }
WxJava 使用 WxErrorException 来封装微信接口返回的错误信息,便于统一异常处理:
java try { // 调用微信 API WxMpUser user = wxMpService.getUserService().userInfo(openId, lang); } catch (WxErrorException e) { // 处理微信接口错误 log.error("微信接口调用失败,错误码:{},错误信息:{}", e.getError().getErrorCode(), e.getError().getErrorMsg()); // 根据不同的错误码进行特定处理 }
根据实践经验,以下是使用 WxJava 的几点开发建议:
WxJava 作为一款功能全面、设计优雅的微信开发 Java SDK,极大地简化了微信生态各类应用的开发工作。其模块化设计、丰富的功能覆盖和活跃的社区支持,使其成为 Java 开发者进行微信开发的首选工具包。
无论是初学者还是经验丰富的开发者,都能通过 WxJava 快速构建稳定、高效的微信应用。随着微信生态的不断发展,WxJava 也在持续更新迭代,为开发者提供更好的开发体验和更强大的功能支持。
本文作者:张豪
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!