springboot开发微信小程序

简介: springboot开发微信小程序

一、依赖

maven仓库地址

https://mvnrepository.com/artifact/com.github.binarywang/weixin-java-miniapp

  <dependency>
            <groupId>com.github.binarywang</groupId>
            <artifactId>weixin-java-miniapp</artifactId>
            <version>4.3.0</version>
        </dependency>

二、配置

application.yml

wx:
  miniapp:
    configs:
        - appid: #微信小程序的appid
          secret: #微信小程序的Secret
          token: #微信小程序消息服务器配置的token
          aesKey: #微信小程序消息服务器配置的EncodingAESKey
          msgDataFormat: JSON
package com.github.binarywang.demo.wx.miniapp.config;
 
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage;
import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import cn.binarywang.wx.miniapp.config.impl.WxMaRedisConfigImpl;
import cn.binarywang.wx.miniapp.message.WxMaMessageHandler;
import cn.binarywang.wx.miniapp.message.WxMaMessageRouter;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.error.WxRuntimeException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
 
import java.io.File;
import java.util.List;
import java.util.stream.Collectors;
 
/**
 * @author <a href="https://github.com/binarywang">Binary Wang</a>
 */
@Slf4j
@Configuration
@EnableConfigurationProperties(WxMaProperties.class)
public class WxMaConfiguration {
    private final WxMaProperties properties;
 
    @Autowired
    public WxMaConfiguration(WxMaProperties properties) {
        this.properties = properties;
    }
 
    @Bean
    public WxMaService wxMaService() {
        List<WxMaProperties.Config> configs = this.properties.getConfigs();
        if (configs == null) {
            throw new WxRuntimeException("大哥,拜托先看下项目首页的说明(readme文件),添加下相关配置,注意别配错了!");
        }
        WxMaService maService = new WxMaServiceImpl();
        maService.setMultiConfigs(
            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());
                    return config;
                }).collect(Collectors.toMap(WxMaDefaultConfigImpl::getAppid, a -> a, (o, n) -> o)));
        return maService;
    }
 
    @Bean
    public WxMaMessageRouter wxMaMessageRouter(WxMaService wxMaService) {
        final WxMaMessageRouter router = new WxMaMessageRouter(wxMaService);
        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;
    };
 
}
package com.github.binarywang.demo.wx.miniapp.config;
 
import java.util.List;
 
import org.springframework.boot.context.properties.ConfigurationProperties;
 
import lombok.Data;
 
/**
 * @author <a href="https://github.com/binarywang">Binary Wang</a>
 */
@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;
    }
 
}

三、使用

package com.github.binarywang.demo.wx.miniapp.controller;
 
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.constant.WxMaConstants;
import cn.binarywang.wx.miniapp.util.WxMaConfigHolder;
import com.google.common.collect.Lists;
import com.google.common.io.Files;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
 
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
 
/**
 * <pre>
 *  小程序临时素材接口
 *  Created by BinaryWang on 2017/6/16.
 * </pre>
 *
 * @author <a href="https://github.com/binarywang">Binary Wang</a>
 */
@RestController
@AllArgsConstructor
@Slf4j
@RequestMapping("/wx/media/{appid}")
public class WxMaMediaController {
    private final WxMaService wxMaService;
 
    /**
     * 上传临时素材
     *
     * @return 素材的media_id列表,实际上如果有的话,只会有一个
     */
    @PostMapping("/upload")
    public List<String> uploadMedia(@PathVariable String appid, HttpServletRequest request) throws WxErrorException {
        if (!wxMaService.switchover(appid)) {
            throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid));
        }
 
        CommonsMultipartResolver resolver = new CommonsMultipartResolver(request.getSession().getServletContext());
 
        if (!resolver.isMultipart(request)) {
            WxMaConfigHolder.remove();//清理ThreadLocal
            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());
                log.info("filePath is :" + newFile.toString());
                file.transferTo(newFile);
                WxMediaUploadResult uploadResult = wxMaService.getMediaService().uploadMedia(WxMaConstants.KefuMsgType.IMAGE, newFile);
                log.info("media_id : " + uploadResult.getMediaId());
                result.add(uploadResult.getMediaId());
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        }
        WxMaConfigHolder.remove();//清理ThreadLocal
        return result;
    }
 
    /**
     * 下载临时素材
     */
    @GetMapping("/download/{mediaId}")
    public File getMedia(@PathVariable String appid, @PathVariable String mediaId) throws WxErrorException {
        if (!wxMaService.switchover(appid)) {
            throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid));
        }
        File media = wxMaService.getMediaService().getMedia(mediaId);
        WxMaConfigHolder.remove();//清理ThreadLocal
        return media;
    }
}

注意事项:配置小程序appid等正确,WxMaConfiguration可以被启动了扫描;

相关实践学习
消息队列+Serverless+Tablestore:实现高弹性的电商订单系统
基于消息队列以及函数计算,快速部署一个高弹性的商品订单系统,能够应对抢购场景下的高并发情况。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
1天前
|
JSON 小程序 前端开发
创建一个属于自己的小程序(注册开发账号)
介绍如何创建微信小程序账号,包括注册流程、下载安装微信开发者工具、创建项目以及项目结构介绍。
创建一个属于自己的小程序(注册开发账号)
|
4天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的医院门诊预约挂号系统
基于Java+Springboot+Vue开发的医院门诊预约挂号系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的门诊预约挂号管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
29 2
基于Java+Springboot+Vue开发的医院门诊预约挂号系统
ly~
|
1天前
|
存储 供应链 小程序
除了微信小程序,PHP 还可以用于开发哪些类型的小程序?
除了微信小程序,PHP 还可用于开发多种类型的小程序,包括支付宝小程序、百度智能小程序、抖音小程序、企业内部小程序及行业特定小程序。在电商、生活服务、资讯、工具、娱乐、营销等领域,PHP 能有效管理商品信息、订单处理、支付接口、内容抓取、复杂计算、游戏数据、活动规则等多种业务。同时,在企业内部,PHP 可提升工作效率,实现审批流程、文件共享、生产计划等功能;在医疗和教育等行业,PHP 能管理患者信息、在线问诊、课程资源、成绩查询等重要数据。
ly~
19 6
ly~
|
1天前
|
开发框架 小程序 前端开发
抖音小程序的开发难度大吗?
抖音小程序的开发难度因人而异,主要取决于开发者经验、技能及功能需求。技术上需掌握前端技术及抖音开发框架,了解平台生态与规则;设计上需符合用户审美和习惯,具备创新性和实用性。此外,严格的审核标准和激烈的市场竞争增加了开发难度,开发者需制定有效推广策略并持续优化小程序以保持竞争力。
ly~
25 4
|
1天前
|
小程序 JavaScript API
微信小程序开发学习之页面导航(声明式导航和编程式导航)
这篇文章介绍了微信小程序中页面导航的两种方式:声明式导航和编程式导航,包括如何导航到tabBar页面、非tabBar页面、后退导航,以及如何在导航过程中传递参数和获取传递的参数。
微信小程序开发学习之页面导航(声明式导航和编程式导航)
|
9天前
|
机器学习/深度学习 数据采集 JavaScript
ADR智能监测系统源码,系统采用Java开发,基于SpringBoot框架,前端使用Vue,可自动预警药品不良反应
ADR药品不良反应监测系统是一款智能化工具,用于监测和分析药品不良反应。该系统通过收集和分析病历、处方及实验室数据,快速识别潜在不良反应,提升用药安全性。系统采用Java开发,基于SpringBoot框架,前端使用Vue,具备数据采集、清洗、分析等功能模块,并能生成监测报告辅助医务人员决策。通过集成多种数据源并运用机器学习算法,系统可自动预警药品不良反应,有效减少药害事故,保障公众健康。
ADR智能监测系统源码,系统采用Java开发,基于SpringBoot框架,前端使用Vue,可自动预警药品不良反应
|
15天前
|
存储 移动开发 监控
微信支付开发避坑指南
【9月更文挑战第11天】在进行微信支付开发时,需遵循官方文档,确保权限和参数配置正确。开发中应注重安全,验证用户输入,合理安排接口调用顺序,并处理异常。上线后需实时监控支付状态,定期检查配置,关注安全更新,确保系统稳定运行。
消息中间件 缓存 监控
75 0
|
21天前
|
移动开发 小程序 JavaScript
uni-app开发微信小程序
本文详细介绍如何使用 uni-app 开发微信小程序,涵盖需求分析、架构思路及实施方案。主要功能包括用户登录、商品列表展示、商品详情、购物车及订单管理。技术栈采用 uni-app、uView UI 和 RESTful API。文章通过具体示例代码展示了从初始化项目、配置全局样式到实现各页面组件及 API 接口的全过程,并提供了完整的文件结构和配置文件示例。此外,还介绍了微信授权登录及后端接口模拟方法,确保项目的稳定性和安全性。通过本教程,读者可快速掌握使用 uni-app 开发微信小程序的方法。
52 3
|
10天前
|
小程序 前端开发 JavaScript
Java开发工程师转小程序开发的前景如何?
Java开发工程师转小程序开发的前景如何?
23 0