SpringMvc微信公众平台开发(一)···新手接入

一直以来博客都懒得打理,两年了才有这么几篇文章,大部分都还是转的。感觉是时候写一些原创性的东西了,想了想最近的工作,感觉也就微信公众平台的开发可以拿出来跟大家分享一下,再加上jsp做这个开发的不多,大部分都是php的,所以就拿这个做开端了,有什么不正确或者不合适的地方,请留言告知。

接下来就是微信公众平台开发的入门了,首先请大家记下以下两个地址,这是以后微信开发中会经常访问的地址:

  1. 微信公众平台官网:https://mp.weixin.qq.com
  2. 微信公众平台开发文档:https://mp.weixin.qq.com/wiki/

下面开始正式教程,首先是新手接入,告诉你如何接入微信公众平台,这里可以参考微信官方接入指南,重点是接入指南中的第二步,想要接入官方平台必须要支持微信发来的GET请求,就像正常的浏览器访问一样,你必须提供一个url来让微信的服务器去访问,官方的接入指南只提供php版本的代码,我们必须自己写一个java版本的出来。

我们可以先封装两个实体bean,一个是用于接收微信公众平台的全局返回码,一个是用于接收验证URL有效性的参数,代码如下:

package com.yimik.wechat.wechat.model;

public class ErrorCodeModel {
    private String errcode;//全局返回码
    private String errmsg;//说明
    
    public String getErrcode() {
        return errcode;
    }
    public void setErrcode(String errcode) {
        this.errcode = errcode;
    }
    public String getErrmsg() {
        return errmsg;
    }
    public void setErrmsg(String errmsg) {
        this.errmsg = errmsg;
    }
}
package com.yimik.wechat.wechat.model;

public class CheckModel extends ErrorCodeModel{
    String signature;
    Long timestamp;
    Long nonce;
    String echostr;
    
    
    public String getSignature() {
        return signature;
    }
    public void setSignature(String signature) {
        this.signature = signature;
    }
    public Long getTimestamp() {
        return timestamp;
    }
    public void setTimestamp(Long timestamp) {
        this.timestamp = timestamp;
    }
    public Long getNonce() {
        return nonce;
    }
    public void setNonce(Long nonce) {
        this.nonce = nonce;
    }
    public String getEchostr() {
        return echostr;
    }
    public void setEchostr(String echostr) {
        this.echostr = echostr;
    }  
}

其中全局返回码具体代表什么错误可以参考官方文档中的全局返回码说明,而这个验证的Action我们可以这么写

package com.yimik.wechat.wechat.web;

import java.io.IOException;
import java.text.ParseException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.yimik.wechat.wechat.model.CheckModel;
import com.yimik.wechat.wechat.service.TokenService;

@Controller
@RequestMapping("/wechat")
public class TokenController {
    
    @Autowired
    private TokenService tokenService;
    
    /**
     * 开发者模式token校验
     *
     * @param wxAccount 开发者url后缀
     * @param response
     * @param tokenModel
     * @throws ParseException
     * @throws IOException
     */
    @RequestMapping(value = "/check/{wxToken}", method = RequestMethod.GET, produces = "text/plain")
    public @ResponseBody String validate(@PathVariable("wxToken")String wxToken,CheckModel tokenModel) throws ParseException, IOException {
        return tokenService.validate(wxToken,tokenModel);
    }
}

Action所调用的tokenService(重要)代码如下:

package com.yimik.wechat.wechat.service;

import java.util.Arrays;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.yimik.wechat.tool.EncoderHandler;
import com.yimik.wechat.wechat.model.CheckModel;

@Service
public class TokenService {
    /**
     * 微信开发者验证
     * @param wxAccount
     *
     * @param signature
     * @param timestamp
     * @param nonce
     * @param echostr
     * @return
     */
    @Transactional
    public String validate(String wxToken, CheckModel tokenModel){
        String signature = tokenModel.getSignature();
        Long timestamp = tokenModel.getTimestamp();
        Long nonce =tokenModel.getNonce();
        String echostr = tokenModel.getEchostr();
        if(signature!=null&&timestamp!=null&nonce!=null) {
            String[] str = {wxToken, timestamp+"", nonce+""};
            Arrays.sort(str); // 字典序排序
            String bigStr = str[0] + str[1] + str[2];
            // SHA1加密    
            String digest = EncoderHandler.encode("SHA1", bigStr).toLowerCase();
            // 确认请求来至微信
            if (digest.equals(signature)) {
                //最好此处将echostr存起来,以后每次校验消息来源都需要用到
                return echostr;
            }
        }
        return "error";
    }
}

tokenService中的引用了一个工具类EncoderHandler,其主要作用是进行一些加密运算,代码如下:

package com.yimik.wechat.tool;

import java.security.MessageDigest;

/**
 *
 */
public class EncoderHandler {

    private static final String ALGORITHM = "MD5";

    private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

    /**
     * encode string
     *
     * @param algorithm
     * @param str
     * @return String
     */
    public static String encode(String algorithm, String str) {
        if (str == null) {
            return null;
        }
        try {
            MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
            messageDigest.update(str.getBytes());
            return getFormattedText(messageDigest.digest());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * encode By MD5
     *
     * @param str
     * @return String
     */
    public static String encodeByMD5(String str) {
        if (str == null) {
            return null;
        }
        try {
            MessageDigest messageDigest = MessageDigest.getInstance(ALGORITHM);
            messageDigest.update(str.getBytes());
            return getFormattedText(messageDigest.digest());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * Takes the raw bytes from the digest and formats them correct.
     *
     * @param bytes
     *            the raw bytes from the digest.
     * @return the formatted bytes.
     */
    private static String getFormattedText(byte[] bytes) {
        int len = bytes.length;
        StringBuilder buf = new StringBuilder(len * 2);
        // 把密文转换成十六进制的字符串形式
        for (int j = 0; j < len; j++) {             
            buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
            buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
        }
        return buf.toString();
    }
}

至此,微信公众平台的新手接入功能就算完成了,将应用部署到线上以后就可以测试绑定了,在登陆微信公众平台以后的左侧菜单中点击开发者中心,填写对应的url和token,在此程序中token是自己随便定义的,url为http://你的服务器路径/wechat/check/你的自定义token(当然,你的url可以自定义,在Action的@RequestMapping注解中,你可以不用token做唯一标识,如果单独为某一公众号做开发,甚至可以没有唯一标识,笔者因为懒,直接就用token当做唯一标识了)。

操作成功后结果如下图:

e
分享:

10 条评论

Dawn

wxToken 也是微信传来的,还有必要做验证吗? 那其它公众号请求你的服务也能通过了

回复
骑驴过街

从这个代码上看,是这样的,token正常情况下是存储在服务端的,无论是数据库还是配置文件。当时写代码的时候只是考虑算法,没有考虑其他问题

回复

发表评论

邮箱地址不会被公开。 必填项已用*标注

😉😐😡😈🙂😯🙁🙄😛😳😮:mrgreen:😆💡😀👿😥😎😕

验证码 *