java springboot集成微信小程序【详细教程】

简介: java springboot集成微信小程序【详细教程】

申请小程序账号

注册小程序点我

https://mp.weixin.qq.com/cgi-bin/registermidpage?action=index&lang=zh_CN&token=

引入依赖

<!-- 小程序依赖 -->
<dependency>
    <groupId>com.github.binarywang</groupId>
    <artifactId>weixin-java-miniapp</artifactId>
    <version>4.3.0</version>
</dependency>
<dependency>
    <groupId>com.github.binarywang</groupId>
    <artifactId>weixin-java-common</artifactId>
    <version>4.3.0</version>
</dependency>
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
</dependency>  

yml配置

wx:
  miniapp:
    configs:
      - appid: 12313#微信小程序的appid
        secret: 1231313#微信小程序的Secret
        token:  #微信小程序消息服务器配置的token
        aesKey:  #微信小程序消息服务器配置的EncodingAESKey
        msgDataFormat: JSON

读取配置文件类WxMaProperties

@Data
@ConfigurationProperties(prefix = "wx.miniapp")
public class WxMaProperties {
    private List<Config> configs;
    @Data
    public static class Config {
        /**
         * 设置微信小程序的appid
         */
        private String appid;
        /**
         * 设置微信小程序的Secret
         */
        private String secret;
        /**
         * 设置微信小程序消息服务器配置的token
         */
        private String token;
        /**
         * 设置微信小程序消息服务器配置的EncodingAESKey
         */
        private String aesKey;
        /**
         * 消息格式,XML或者JSON
         */
        private String msgDataFormat;
    }
}

配置文件加载

@Slf4j
@Configuration
@EnableConfigurationProperties(WxMaProperties.class)
public class WxMaConfiguration {
    private final WxMaProperties properties;
    private static final Map<String, WxMaMessageRouter> routers = Maps.newHashMap();
    private static Map<String, WxMaService> maServices;
    @Autowired
    public WxMaConfiguration(WxMaProperties properties) {
        this.properties = properties;
    }
    public static WxMaService getMaService(String appid) {
        WxMaService wxService = maServices.get(appid);
        if (wxService == null) {
            throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid));
        }
        return wxService;
    }
    public static WxMaMessageRouter getRouter(String appid) {
        return routers.get(appid);
    }
    @PostConstruct
    public void init() {
        List<WxMaProperties.Config> configs = this.properties.getConfigs();
        if (configs == null) {
            throw new WxRuntimeException("大哥,拜托先看下项目首页的说明(readme文件),添加下相关配置,注意别配错了!");
        }
        maServices = configs.stream()
            .map(a -> {
                WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
//                WxMaDefaultConfigImpl config = new WxMaRedisConfigImpl(new JedisPool());
                // 使用上面的配置时,需要同时引入jedis-lock的依赖,否则会报类无法找到的异常
                config.setAppid(a.getAppid());
                config.setSecret(a.getSecret());
                config.setToken(a.getToken());
                config.setAesKey(a.getAesKey());
                config.setMsgDataFormat(a.getMsgDataFormat());
                WxMaService service = new WxMaServiceImpl();
                service.setWxMaConfig(config);
                routers.put(a.getAppid(), this.newRouter(service));
                return service;
            }).collect(Collectors.toMap(s -> s.getWxMaConfig().getAppid(), a -> a));
    }
    private WxMaMessageRouter newRouter(WxMaService service) {
        final WxMaMessageRouter router = new WxMaMessageRouter(service);
        router
            .rule().handler(logHandler).next()
            .rule().async(false).content("订阅消息").handler(subscribeMsgHandler).end()
            .rule().async(false).content("文本").handler(textHandler).end()
            .rule().async(false).content("图片").handler(picHandler).end()
            .rule().async(false).content("二维码").handler(qrcodeHandler).end();
        return router;
    }
    private final WxMaMessageHandler subscribeMsgHandler = (wxMessage, context, service, sessionManager) -> {
        service.getMsgService().sendSubscribeMsg(WxMaSubscribeMessage.builder()
            .templateId("此处更换为自己的模板id")
            .data(Lists.newArrayList(
                new WxMaSubscribeMessage.MsgData("keyword1", "339208499")))
            .toUser(wxMessage.getFromUser())
            .build());
        return null;
    };
    private final WxMaMessageHandler logHandler = (wxMessage, context, service, sessionManager) -> {
        log.info("收到消息:" + wxMessage.toString());
        service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("收到信息为:" + wxMessage.toJson())
            .toUser(wxMessage.getFromUser()).build());
        return null;
    };
    private final WxMaMessageHandler textHandler = (wxMessage, context, service, sessionManager) -> {
        service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("回复文本消息")
            .toUser(wxMessage.getFromUser()).build());
        return null;
    };
    private final WxMaMessageHandler picHandler = (wxMessage, context, service, sessionManager) -> {
        try {
            WxMediaUploadResult uploadResult = service.getMediaService()
                .uploadMedia("image", "png",
                    ClassLoader.getSystemResourceAsStream("tmp.png"));
            service.getMsgService().sendKefuMsg(
                WxMaKefuMessage
                    .newImageBuilder()
                    .mediaId(uploadResult.getMediaId())
                    .toUser(wxMessage.getFromUser())
                    .build());
        } catch (WxErrorException e) {
            e.printStackTrace();
        }
        return null;
    };
    private final WxMaMessageHandler qrcodeHandler = (wxMessage, context, service, sessionManager) -> {
        try {
            final File file = service.getQrcodeService().createQrcode("123", 430);
            WxMediaUploadResult uploadResult = service.getMediaService().uploadMedia("image", file);
            service.getMsgService().sendKefuMsg(
                WxMaKefuMessage
                    .newImageBuilder()
                    .mediaId(uploadResult.getMediaId())
                    .toUser(wxMessage.getFromUser())
                    .build());
        } catch (WxErrorException e) {
            e.printStackTrace();
        }
        return null;
    };
}

json返回工具类

public class JsonUtils {
    private static final ObjectMapper JSON = new ObjectMapper();
    static {
        JSON.setSerializationInclusion(Include.NON_NULL);
        JSON.configure(SerializationFeature.INDENT_OUTPUT, Boolean.TRUE);
    }
    public static String toJson(Object obj) {
        try {
            return JSON.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
}

控制层

小程序临时素材接口

@RestController
@RequestMapping("/wx/media/{appid}")
public class WxMaMediaController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    /**
     * 上传临时素材
     *
     * @return 素材的media_id列表,实际上如果有的话,只会有一个
     */
    @PostMapping("/upload")
    public List<String> uploadMedia(@PathVariable String appid, HttpServletRequest request) throws WxErrorException {
        final WxMaService wxService = WxMaConfiguration.getMaService(appid);
        CommonsMultipartResolver resolver = new CommonsMultipartResolver(request.getSession().getServletContext());
        if (!resolver.isMultipart(request)) {
            return Lists.newArrayList();
        }
        MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
        Iterator<String> it = multiRequest.getFileNames();
        List<String> result = Lists.newArrayList();
        while (it.hasNext()) {
            try {
                MultipartFile file = multiRequest.getFile(it.next());
                File newFile = new File(Files.createTempDir(), file.getOriginalFilename());
                this.logger.info("filePath is :" + newFile.toString());
                file.transferTo(newFile);
                WxMediaUploadResult uploadResult = wxService.getMediaService().uploadMedia(WxMaConstants.KefuMsgType.IMAGE, newFile);
                this.logger.info("media_id : " + uploadResult.getMediaId());
                result.add(uploadResult.getMediaId());
            } catch (IOException e) {
                this.logger.error(e.getMessage(), e);
            }
        }
        return result;
    }
    /**
     * 下载临时素材
     */
    @GetMapping("/download/{mediaId}")
    public File getMedia(@PathVariable String appid, @PathVariable String mediaId) throws WxErrorException {
        final WxMaService wxService = WxMaConfiguration.getMaService(appid);
        return wxService.getMediaService().getMedia(mediaId);
    }
}


微信小程序用户接口

@RestController
@RequestMapping("/wx/user/{appid}")
public class WxMaUserController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    /**
     * 登陆接口
     */
    @GetMapping("/login")
    public String login(@PathVariable String appid, String code) {
        if (StringUtils.isBlank(code)) {
            return "empty jscode";
        }
        final WxMaService wxService = WxMaConfiguration.getMaService(appid);
        try {
            WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(code);
            this.logger.info(session.getSessionKey());
            this.logger.info(session.getOpenid());
            //TODO 可以增加自己的逻辑,关联业务相关数据
            return JsonUtils.toJson(session);
        } catch (WxErrorException e) {
            this.logger.error(e.getMessage(), e);
            return e.toString();
        }
    }
    /**
     * <pre>
     * 获取用户信息接口
     * </pre>
     */
    @PostMapping("/info")
    public String info(@PathVariable String appid, @RequestBody Map<String, String> map) {
        final WxMaService wxService = WxMaConfiguration.getMaService(appid);
        String sessionKey = map.get("sessionKey");
        String signature = map.get("signature");
        String rawData = map.get("rawData");
        String encryptedData = map.get("encryptedData");
        String iv = map.get("iv");
        // 用户信息校验
        if (!wxService.getUserService().checkUserInfo(sessionKey, rawData, signature)) {
            return "user check failed";
        }
        // 解密用户信息
        WxMaUserInfo userInfo = wxService.getUserService().getUserInfo(sessionKey, encryptedData, iv);
        return JsonUtils.toJson(userInfo);
    }
    /**
     * <pre>
     * 获取用户绑定手机号信息
     * </pre>
     */
    @PostMapping("/phone")
    public String phone(@PathVariable String appid, @RequestBody Map<String, String> map) {
        final WxMaService wxService = WxMaConfiguration.getMaService(appid);
        String sessionKey = map.get("sessionKey");
        String signature = map.get("signature");
        String rawData = map.get("rawData");
        String encryptedData = map.get("encryptedData");
        String iv = map.get("iv");
        // 用户信息校验
        if (!wxService.getUserService().checkUserInfo(sessionKey, rawData, signature)) {
            return "user check failed";
        }
        // 解密
        WxMaPhoneNumberInfo phoneNoInfo = wxService.getUserService().getPhoneNoInfo(sessionKey, encryptedData, iv);
        return JsonUtils.toJson(phoneNoInfo);
    }
}


前端代码-小程序项目哦,hubild直接创建

<template>
  <view class="content">
    <image class="logo" src="/static/logo.png"></image>
    <view class="text-area">
      <text class="title">{{title}}</text>
    </view>
    <view>
      <button @click="login">登录</button>
      <!-- 先点击 登录、获取头像昵称按钮才可以点击下面这两个按钮!!! -->
      <button @click="info">获取用户信息</button>
      <button @click="phone">获取手机号信息</button>
    </view>
    <view class="container">
      <view class="userinfo">
        <block>
          <button @click="getUserProfile"> 获取头像昵称 </button>
        </block>
      </view>
    </view>
  </view>
</template>
<script>
  export default {
    data() {
      return {
        title: 'Hello2',
        openId: "",
        session: "",
        userInfo: {},
        hasUserInfo: false,
        canIUseGetUserProfile: false,
        signature:'',
        rawData:'',
        encryptedData:'',
        iv:''
      }
    },
    onLoad() {
    },
    methods: {
      login() {
        let that = this;
        wx.login({
          success (res) {
            console.log("res::",res)
            if (res.code) {
              //发起网络请求
              wx.request({
                url: 'http://localhost:8080/wx/user/wx35784428afa871df/login?code='+res.code,
            method: 'GET',
            success(res) {
              console.log("success res :" ,res)
              that.openId = res.data.openid;
              that.session = res.data.sessionKey;
            },
            fail(res) {
              console.log("fail res : ", res)
            }
              })
            } else {
              console.log('登录失败!' + res.errMsg)
            }
          }
        })
      },
      info() {
        console.log("sessionKey::",this.session)
        wx.request({
          url: 'http://localhost:8080/wx/user/wx35784428afa871df/info',
          method: 'POST',
          data:{
            sessionKey: this.session,
            signature: this.signature,
            rawData: this.rawData,
            encryptedData: this.encryptedData,
            iv: this.iv
          },
          success(res) {
            console.log("后端获取:success res :" ,res)
          },
          fail(res) {
            console.log("后端获取:fail res : ", res)
          }
        })
      },
      phone() {
        wx.request({
          url: 'http://localhost:8080/wx/user/wx35784428afa871df/phone',
          method: 'POST',
          data:{
            sessionKey: this.session,
            signature: this.signature,
            rawData: this.rawData,
            encryptedData: this.encryptedData,
            iv: this.iv
          },
          success(res) {
            console.log("后端获取手机号:success res :" ,res)
          },
          fail(res) {
            console.log("后端获取手机号:fail res : ", res)
          }
        })
      },
      getUserProfile(e) {
        let that = this;
          // 推荐使用 wx.getUserProfile 获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
          // 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
          wx.getUserProfile({
            desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
            success: (res) => {
              console.log("user info res :", res)
          that.signature = res.signature;
          that.rawData = res.rawData;
          that.encryptedData = res.encryptedData;
          that.iv = res.iv;
            }
          })
        },
        getUserInfo(e) {
          // 不推荐使用 getUserInfo 获取用户信息,预计自2021年4月13日起,getUserInfo将不再弹出弹窗,并直接返回匿名的用户个人信息
          this.setData({
            userInfo: e.detail.userInfo,
            hasUserInfo: true
          })
        },
    }
  }
</script>
<style>
  .content {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
  }
  .logo {
    height: 200rpx;
    width: 200rpx;
    margin-top: 200rpx;
    margin-left: auto;
    margin-right: auto;
    margin-bottom: 50rpx;
  }
  .text-area {
    display: flex;
    justify-content: center;
  }
  .title {
    font-size: 36rpx;
    color: #8f8f94;
  }
</style>

界面效果图

效果

3958b4b3689e4d1585a1d68dac6e244c.png



点击登录

返回code码,我们拿code码进行获取openid


4844966aa6a74d90bcb2ae7ff738990f.png


获取头像昵称

拿到返回的信息进行获取用户信息


27c172f1ed7a4303a425b3dd359402b6.png


获取用户信息


f2907e19ec1945649f4032d26bbbbb1a.png

82be9a4aa77a4d6caff24b11427efe41.png



以上就完成了哦,简单教程


相关实践学习
消息队列+Serverless+Tablestore:实现高弹性的电商订单系统
基于消息队列以及函数计算,快速部署一个高弹性的商品订单系统,能够应对抢购场景下的高并发情况。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
2月前
|
弹性计算 机器人 应用服务中间件
一键部署开源Qwen3并集成到钉钉、企业微信
Qwen3系列模型现已正式发布并开源,包含8款“混合推理模型”,其中涵盖两款MoE模型(Qwen3-235B-A22B与Qwen3-30B-A3B)及六个Dense模型。阿里云计算巢已支持Qwen3-235B-A22B和Qwen3-32B的私有化部署,用户可通过计算巢轻松完成部署,并借助AppFlow集成至钉钉机器人或企业微信。文档详细介绍了从模型部署、创建应用到配置机器人的全流程,帮助用户快速实现智能助手的接入与使用。
一键部署开源Qwen3并集成到钉钉、企业微信
|
2月前
|
前端开发 Java 关系型数据库
基于Java+Springboot+Vue开发的鲜花商城管理系统源码+运行
基于Java+Springboot+Vue开发的鲜花商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的鲜花商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。技术学习共同进步
211 7
|
10天前
|
Oracle Java 关系型数据库
java 编程基础入门级超级完整版教程详解
这份文档是针对Java编程入门学习者的超级完整版教程,涵盖了从环境搭建到实际项目应用的全方位内容。首先介绍了Java的基本概念与开发环境配置方法,随后深入讲解了基础语法、控制流程、面向对象编程的核心思想,并配以具体代码示例。接着探讨了常用类库与API的应用,如字符串操作、集合框架及文件处理等。最后通过一个学生成绩管理系统的实例,帮助读者将理论知识应用于实践。此外,还提供了进阶学习建议,引导学员逐步掌握更复杂的Java技术。适合初学者系统性学习Java编程。资源地址:[点击访问](https://pan.quark.cn/s/14fcf913bae6)。
58 2
|
11天前
|
SQL Java 数据库
解决Java Spring Boot应用中MyBatis-Plus查询问题的策略。
保持技能更新是侦探的重要素质。定期回顾最佳实践和新技术。比如,定期查看MyBatis-Plus的更新和社区的最佳做法,这样才能不断提升查询效率和性能。
54 1
|
4月前
|
JavaScript NoSQL Java
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
276 96
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
|
1月前
|
JSON 机器人 API
gewe微信机器人搭建教程
GeWe开放平台是基于 微信开放平台的二次封装API服务,开发者可以使用本服务来处理微信中的各种事件,并可以通过后台调用对应的 API 来驱动微信自动执行任务,如自动收发消息、自动化应答、自动群邀请、群管理等,封装了 RPA技术流程,简化开发者二次开发难度,提供了开发者与微信对接的能力,使用简单,操作快捷,支持多种语言接入。
84 17
|
3月前
|
前端开发 Cloud Native Java
Java||Springboot读取本地目录的文件和文件结构,读取服务器文档目录数据供前端渲染的API实现
博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
Java||Springboot读取本地目录的文件和文件结构,读取服务器文档目录数据供前端渲染的API实现
|
3月前
|
存储 API UED
鸿蒙特效教程02-微信语音录制动画效果实现教程
本教程适合HarmonyOS初学者,通过简单到复杂的步骤,一步步实现类似微信APP中的语音录制动画效果。
154 0
鸿蒙特效教程02-微信语音录制动画效果实现教程
|
4月前
|
小程序 JavaScript Java
基于SpringBoot的智慧停车场微信小程序源码分享
智慧停车场微信小程序主要包含管理端和小程序端。管理端包括停车场管理,公告信息管理,用户信息管理,预定信息管理,用户反馈管理等功能。小程序端包括登录注册,预约停车位,停车导航,停车缴费,用户信息,车辆信息,钱包充值,意见反馈等功能。
189 5
基于SpringBoot的智慧停车场微信小程序源码分享
|
4月前
|
人工智能 安全 机器人
LangBot:无缝集成到QQ、微信等消息平台的AI聊天机器人平台
LangBot 是一个开源的多模态即时聊天机器人平台,支持多种即时通信平台和大语言模型,具备多模态交互、插件扩展和Web管理面板等功能。
990 14
LangBot:无缝集成到QQ、微信等消息平台的AI聊天机器人平台