Springboot借助微信开发工具weixin.java.tools完成微信授权登录,发送模板消息,发送客服消息,拉取用户信息列表功能

公司要求实现微信公众号的一些功能,本人经过查阅资料发现使用weixin.java.tools对微信进行开发十分便捷,遂将完成的几个小功能贴出来进行记录。

主要接入步骤:

  • 通过ngrok获取动态测试域名。(如果有的话可以用自己的域名,如果想要免费使用域名的话建议使用ngrok内网穿透工具。它的缺点是每次运行ngrok都会变更域名,免费的要求也不要这么多啦)
  • 申请测试公众号。(想要使用微信服务器提供的所有接口的话需要认证公众号,认证公众号一年掏三百多这里不建议)
  • 将微信端与本地服务器端进行对接。

开发工具:idea

其他工具 :ngrok(本文含下载链接),测试公众号(官网注册)

1.注册公众号:

2.运行ngrok内网穿透工具

输入命令行:ngrok 8080(如不行输入ngrok http 8080)

若运行成功则会动态分配一个域名

3.创建Springboot+Maven项目(如不会的自行百度)

4.引入Maven依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.6.RELEASE</version>

		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>weixin</artifactId>
	<packaging>jar</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>weixin</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>com.github.binarywang</groupId>
			<artifactId>weixin-java-mp</artifactId>
			<version>3.4.9.B</version>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.16.10</version>
		</dependency>


		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-test</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>5.1.8.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>net.minidev</groupId>
			<artifactId>json-smart</artifactId>
			<version>2.3</version>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.31</version>
		</dependency>


	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

其中引入的weixin-java-mp依赖就是我们今天的主角,weixin-java-tools是大神binarywang写的开发工具包,有了它我们将减少很多底层的工作量,如token的加密,accesstoken的周期管理,传入传出数据的封装与解析等都不用我们亲自动手完成:

<dependency>
   <groupId>com.github.binarywang</groupId>
   <artifactId>weixin-java-mp</artifactId>
   <version>3.4.9.B</version>
</dependency>

 

5.进行微信服务器端与本地服务器端的对接工作(代码模块正式开始)

配置文件

server.port = 8080
server.servlet.context-path = /weixin
mpAppId=        #公众号id
mpAppSecret=    #公众号密匙
token=smk666

其中公众号的信息在测试号里面都有:

微信服务器对接代码块

package com.example.demo.web;

@SpringBootApplication
@Controller
public class LoginController {
    @Value("${token}")//获取配置文件的值
    private String token;
    @RequestMapping(value = "/wx",method= RequestMethod.GET)
    public void login(HttpServletRequest request, HttpServletResponse response) throws IOException {
        System.out.println(token);
        //微信服务器get传递的参数
        String signature = request.getParameter("signature");//微信加密签名
        String timestamp = request.getParameter("timestamp");//时间戳
        String nonce = request.getParameter("nonce");//随机数
        String echostr = request.getParameter("echostr");//随机字符串(用来进行返回)
        //微信工具类
        WxMpService wxService=new WxMpServiceImpl();
        //注入token的配置参数
        /**
         * 生产环境 建议将WxMpInMemoryConfigStorage持久化
         */
        WxMpInMemoryConfigStorage wxConfigProvider=new WxMpInMemoryConfigStorage();
        //注入token值
        wxConfigProvider.setToken(token);
        wxService.setWxMpConfigStorage(wxConfigProvider);
        boolean flag=wxService.checkSignature(timestamp, nonce, signature);
        System.out.println(flag);
        PrintWriter out=response.getWriter();
        if(flag){
            out.print(echostr);
        }
        out.close();

    }
}

写完后在公众号测试号端进行测试,需要重点说明的是URL。

如以下URL:http://www.wx.fzy365.online(域名)+/weixin/wx(对接接口的地址)

测试成功后我们进行下一步

6.模板推送功能的实现

新增测试模板

其中模板ID用于我们后台接口的调用,模板内容为键值对形式,key1、key2为传入参数的键值且后缀加.DATA。

示例:姓名 {{key1.DATA}}

获取Accesstoken

调用微信接口必须得获取调用权限,其中Accesstoken就是该权限的凭证,两小时刷新一次,weixin.java.tool中已经封装好相关的管理方法,这里我将获取Accesstoken部分的代码单独写成一个工具类以便调用:

package com.example.demo.Util;

import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import java.io.IOException;
import java.util.Properties;

/**
 * @说明:
 * @创建人:孙明康
 * @创建时间:2019/8/1 15:57
 */
public class GetAccessTokenUtil {
    /**
     * @Description:根据微信公众号id,secret获取access_token
     * @return: wxMpService(封装好的服务,内含调用微信接口必须的access_token)
     * @author: 孙明康 2019/8/3 17:06
     */
    private static Properties properties;
    public static WxMpService getAccessToken() {
        //获取配置信息中的公众号信息
            if (properties==null) {
                properties = new Properties();
                ClassLoader loader = Thread.currentThread().getContextClassLoader();
                try {
                    properties.load(loader.getResourceAsStream("application.properties"));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        String mpAppId = properties.getProperty("mpAppId");
        String mpAppSecret =properties.getProperty("mpAppSecret");
        WxMpInMemoryConfigStorage wxStorage = new WxMpInMemoryConfigStorage();
        wxStorage.setAppId(mpAppId);
        wxStorage.setSecret(mpAppSecret);
        WxMpService wxMpService = new WxMpServiceImpl();
        wxMpService.setWxMpConfigStorage(wxStorage);
        return wxMpService;
    }
    }

模版消息推送功能的代码实现

传入值为json格式,注释@param里面有写(后面的controller同理):

package com.example.demo.web;

import java.util.List;

/**
 * @说明:模版消息推送
 */
@CrossOrigin
@RestController
public class PushController {
    /**
     * @Description:模板消息推送
     * @param:目标用户id,推送模板id,模板信息列表:{'openid':'oopKVw3CjDqczvJ9fLSecbYZYl14','templateId':'eBcuETQZjL_R4ZzLd6L9rIehSiSGGCtWe_xpWqBkMnI','returnUrl':'www.baidu.com/','wxMpTemplateDataList':[{'name':'key1','value':'孙明康','color':'#FF00FF'},{'name':'key2','value':'您的服务器有新的预警情况哦','color':'#FF00FF'}]}
     * @return:状态返回值:{"statusMessage":true}
     * @author: 孙明康 2019/8/3 16:20
     */ 
    @PostMapping("/push")
    //正式发布public ApiResult push(String jsonString) throws WxErrorException {
    public ApiResult push(@RequestBody String jsonString) throws WxErrorException {
        String openid = null;
        String templateId= null;
        String returnUrl = null;
        String templateJsonArray = null;
        List<WxMpTemplateData> wxMpTemplateDataList = null;
        JSONObject jsonObj = JSONObject.parseObject(jsonString);
        if(null != jsonObj) {
            openid = jsonObj.getString("openid");
            templateId = jsonObj.getString("templateId");
            returnUrl = jsonObj.getString("returnUrl");
            //JSONArray templateJsonArray = jsonObj.getJSONArray("wxMpTemplateDataList");
            templateJsonArray = jsonObj.getString("wxMpTemplateDataList");
            wxMpTemplateDataList=JSONArray.parseArray(templateJsonArray,WxMpTemplateData.class);
        }
        //access_token为获取的接口调用taken
        WxMpService access_token = GetAccessTokenUtil.getAccessToken();
        //设置推送对象信息
        WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
                //
                .toUser(openid)//要推送的用户openid
                .templateId(templateId)//模版id
                .url(returnUrl)//点击模版消息要访问的网址
                .build();
        // 模板中的map值templateMessage.addData(new WxMpTemplateData(name2, value2, color2));
        String name = null;
        String value = null;
        String color = null;
        System.out.println("获取templateId的值----"+templateId);
        System.out.println("获取openid的值----"+openid);
        System.out.println("获取returnUrl的值----"+returnUrl);
        for(int i = 0;i < wxMpTemplateDataList.size(); i ++){
            WxMpTemplateData  wxMpTemplateDataEx =  wxMpTemplateDataList.get(i);
            name = wxMpTemplateDataEx.getName();
            value = wxMpTemplateDataEx.getValue();
            color = wxMpTemplateDataEx.getColor();
            templateMessage.addData(new WxMpTemplateData(name, value, color));
        }
        boolean statusMessage = true;
        try {
            //调用
            String zhaungtai = access_token.getTemplateMsgService().sendTemplateMsg(templateMessage);
            System.out.println("若传输成功返回的状态是"+zhaungtai);
        } catch (Exception e) {
            System.out.println("推送失败:" + e.getMessage());
            statusMessage = false;
            e.printStackTrace();
        }finally {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("statusMessage",statusMessage);
            return ResultApiUtils.getSuccessResult(jsonObject);
        }
    }

}

7.客服信息功能(主动向用户发送信息)功能的代码实现

这个功能比较鸡肋,如果客户在48小时之内没有跟你的公众号说过话就没法调用。

package com.example.demo.web;

/**
 * @说明:主动发送消息(客服消息)
 * @创建人:孙明康
 * @创建时间:2019/8/2 14:30
 */
@CrossOrigin
@RestController
public class KefuMessageController {
    /**
     * @Description:微信测试账号推送
     * @param:用户id及向用户发送的具体消息{openid:'oopKVw3CjDqczvJ9fLSecbYZYl14',content:'测试:\n超链接:<a href="http://www.4399.com/">预警情况</a>'}
     * @return:状态返回值:{"statusMessage":true}
     * @author: 孙明康 2019/8/3 16:47
     */
    @PostMapping("/kefu")
    // 正式发布public ApiResult kefu(String jsonString) {
    public ApiResult kefu(@RequestBody String jsonString) {
        String openid = null;
        String content = null;
        JSONObject jsonObj = JSONObject.parseObject(jsonString);
        if(null != jsonObj) {
            openid = jsonObj.getString("openid");
            content = jsonObj.getString("content");
        }
        //access_token为获取的接口调用accesstaken(接口自动刷新)
        WxMpService access_token = GetAccessTokenUtil.getAccessToken();
        //设置推送的具体信息
        WxMpKefuMessage message = new WxMpKefuMessage();
        message.setMsgType(WxConsts.KefuMsgType.TEXT);
        message.setToUser(openid);
        //测试:\n超链接:<a href="http://www.4399.com/">预警情况</a>
        message.setContent(content);
        boolean statusMessage = true;
        try {
            //getAccessTokenUtil.getAccessToken()用来设置accesstoken
            access_token.getKefuService().sendKefuMessage(message);
        } catch (Exception e) {
            System.out.println("推送失败:" + e.getMessage());
            statusMessage = false;
            e.printStackTrace();
        }finally {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("statusMessage",statusMessage);
            return ResultApiUtils.getSuccessResult(jsonObject);
        }
    }
}

8.客户信息列表的拉取

这里我调用了两个微信服务器提供的接口,分别为客户openID的批量拉取接口、单个客户信息的获取接口。

package com.example.demo.web;


/**
 * @说明:
 * @创建人:孙明康
 * @创建时间:2019/8/2 15:16
 */
@CrossOrigin
@RestController
public class WxUserController {
    /**
     * @Description:从微信端获取用户ID和个人信息
     * @param:拉取所有用户:{next_openid:''}or从该id向下进行拉取(不包含改id):{next_openid:'oopKVw10zjn0cqTCapx1wKY9WYF8'}
     * @return:用户信息列表userList:[{"subscribe":true,"openId":"oopKVw3CjDqczvJ9fLSecbYZYl14","nickname":"孙明康","sexDesc":"男","sex":1,"language":"zh_CN","city":"珠海","province":"广东","country":"中国","headImgUrl":"http://thirdwx.qlogo.cn/mmopen/1kc9BKglZaKic1etEeibLCvia5qSaz7tO5MePZe7BPtTxibXcWPRc6KMeFa7KatdW8Sm9BncY54vbdxWVvEwJO6Hbxy42q7z0HuC/132","subscribeTime":1564645086,"remark":"","groupId":0,"tagIds":[],"subscribeScene":"ADD_SCENE_QR_CODE","qrScene":"0","qrSceneStr":""}]
     * @author: 孙明康 2019/8/2 15:21
     */
    @GetMapping("/wxUser")
    //正式发布public ApiResult wxUser(String jsonString) throws WxErrorException {
    public ApiResult wxUser(@RequestBody String jsonString) throws WxErrorException {
        String next_openid = "";
        JSONObject jsonObj = JSONObject.parseObject(jsonString);
        if(null != jsonObj) {
            next_openid = jsonObj.getString("next_openid");
        }
        //access_token为获取的接口调用accesstaken(接口自动刷新)
        WxMpService access_token = GetAccessTokenUtil.getAccessToken();
        //获取存储在微信端的用户个人信息
        WxMpUserList wxUserList = access_token.getUserService().userList(next_openid);
        //获取用户信息
        List<WxMpUser> userList = new ArrayList();
        for(String userOpenId : wxUserList.getOpenids()) {
            String lang = "zh_CN"; //语言
            WxMpUser userMessage = access_token.getUserService().userInfo(userOpenId, lang);
            System.out.println("用户的个人信息:——————" + userMessage);
            userList.add(userMessage);
        }
        System.out.println("用户信息列表:——————" + userList);
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("userList",userList);
        return ResultApiUtils.getSuccessResult(resultMap);
    }
}

9.一些封装json的类

APIResult

package com.example.demo.entity;

/**
 * @说明:
 * @创建人:孙明康
 * @创建时间:2019/8/3 10:21
 */
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;

public class ApiResult implements Serializable {
    private static final long serialVersionUID = -7595446147358370950L;
    private int status;
    private String message;
    private Object data;
    private Date requesttime = Calendar.getInstance().getTime();

    public ApiResult() {
    }

    public Date getRequesttime() {
        return this.requesttime;
    }

    public ApiResult setRequesttime(Date requesttime) {
        this.requesttime = requesttime;
        return this;
    }

    public int getStatus() {
        return this.status;
    }

    public ApiResult setStatus(int status) {
        this.status = status;
        return this;
    }

    public String getMessage() {
        return this.message;
    }

    public ApiResult setMessage(String message) {
        this.message = message;
        return this;
    }

    public Object getData() {
        return this.data;
    }

    public ApiResult setData(Object data) {
        this.data = data;
        return this;
    }
}

ResultApiUtils

package com.example.demo.entity;

/**
 * @说明:
 * @创建人:孙明康
 * @创建时间:2019/8/3 10:24
 */
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import com.alibaba.fastjson.JSONObject;
import org.springframework.http.HttpStatus;
import com.example.demo.entity.ApiResult;


public class ResultApiUtils {
    private static final String DEFAULT_SUCCESS_MESSAGE = "success";
    private static final String DEFAULT_FAIL_MESSAGE = "fail";

    public ResultApiUtils() {
    }

    public static ApiResult getDefaultResult() {
        return new ApiResult();
    }

    public static ApiResult getSuccessResult() {
        return (new ApiResult()).setStatus(HttpStatus.OK.value()).setMessage("success");
    }

    public static ApiResult getSuccessResult(Object data) {
        return (new ApiResult()).setStatus(HttpStatus.OK.value()).setMessage("success").setData(data);
    }

    public static ApiResult getSuccessResult(int statusCode, String message, Object data) {
        return null == message?(new ApiResult()).setStatus(statusCode).setMessage("success").setData(data):(null == data?(new ApiResult()).setStatus(statusCode).setMessage(message):(new ApiResult()).setStatus(statusCode).setMessage(message).setData(data));
    }

    public static ApiResult getFailResult() {
        return (new ApiResult()).setStatus(HttpStatus.BAD_REQUEST.value()).setMessage("fail");
    }

    public static ApiResult getFailResult(String message) {
        return (new ApiResult()).setStatus(HttpStatus.BAD_REQUEST.value()).setMessage(message);
    }

    public static ApiResult getFailResult(int statusCode, String message) {
        return null == message?(new ApiResult()).setStatus(statusCode).setMessage("success"):(new ApiResult()).setStatus(statusCode).setMessage(message);
    }

    public static ApiResult getFailResult(int statusCode, String message, Object data) {
        return null == message?(new ApiResult()).setStatus(statusCode).setMessage("success").setData(data):(null == data?(new ApiResult()).setStatus(statusCode).setMessage(message):(new ApiResult()).setStatus(statusCode).setMessage(message).setData(data));
    }

    public static String resultToJson(ApiResult apiResult) {
        return JSONObject.toJSONString(apiResult);
    }
}

10.测试

好不容易就都写完啦,这里就展示一个模板消息推送接口的测试,其余测试同理。

PushControllerTest

package com.example.demo.Test;

        /**
         * @说明:
         * @创建人:孙明康
         * @创建时间:2019/8/1 16:51
         */
import com.example.demo.entity.ApiResult;
import com.example.demo.web.PushController;
import me.chanjar.weixin.common.error.WxErrorException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import static org.junit.Assert.*;

@RunWith(SpringRunner.class)
@SpringBootTest
public class PushControllerTest {

    @Autowired
    PushController pushController;

    @Test
    public void push() throws WxErrorException {
        ApiResult status=pushController.push("{'openid':'oopKVw3CjDqczvJ9fLSecbYZYl14','templateId':'eBcuETQZjL_R4ZzLd6L9rIehSiSGGCtWe_xpWqBkMnI','returnUrl':'www.baidu.com/','wxMpTemplateDataList':[{'name':'key1','value':'孙明康','color':'#FF00FF'},{'name':'key2','value':'您的服务器有新的预警情况哦','color':'#FF00FF'}]}");
        System.out.println(status.getData());
    }
}

11.小结

到这里本次微信接口demo的编写就全部完成辽,感觉目前网上面关于weixin.java.tool工具包的介绍不是很多,如果想自学的话建议去GitHub上面直接搜开发文档看。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值