微信公众号开发-接入

一 首先实现内网穿透,公众号需要连接我们的服务器,内外无法访问,所以先实现自己的内网可以测试时连接外网,下载natapp,选择windows,顺便下载config,ini 配置文件。注册好购买免费的隧道 然后将token写入配置文件中,操作很简单,windows中需要加入环境变量,因为我直接放到D盘的natapp文件夹中,所以路劲为D:\natapp即可,双击.exe 就能启动   http://phxgaj.natappfree.cc -> 127.0.0.1:90  通过前面的网址phxgaj.natappfree.cc 访问就能连接我们自己的内网环境了。

二 自然是注册微信公众号了,注册的时候要瞪大眼睛了,微信公众平台 微信开发平台 服务号订阅号小程序一定要分清楚,一个邮箱只能注册一个功能,所以要慎重选,我注册的是 微信公众平台的 服务号,适合公司使用

三 公众号接入,在开发者配置中,写进这个方法,我用的是springmvc,所以要写到这个指定的路径

 

   import java.io.IOException;
  5 import java.io.UnsupportedEncodingException;
  6 import java.security.MessageDigest;
  7 import java.security.NoSuchAlgorithmException;
  8 import java.util.Arrays;
  9 import java.util.Map;
 10 
 11 import javax.servlet.http.HttpServletRequest;
 12 import javax.servlet.http.HttpServletResponse;
 13 
 14 import org.slf4j.Logger;
 15 import org.slf4j.LoggerFactory;
 16 import org.springframework.beans.BeansException;
 17 import org.springframework.context.ApplicationContext;
 18 import org.springframework.context.ApplicationContextAware;
 19 import org.springframework.stereotype.Component;
 20 import org.springframework.stereotype.Controller;
 21 import org.springframework.web.bind.annotation.RequestMapping;
 22 import org.springframework.web.bind.annotation.RequestMethod;
 23 
 24 import com.alibaba.fastjson.JSON;
 25 import com.alibaba.fastjson.JSONObject;
 26 import com.fuyin.mp.entity.AccessToken;
 27 import com.fuyin.mp.utils.GetMenuJson;
 28 import com.fuyin.mp.utils.MessageHandlerUtil;
 29 import com.fuyin.mp.utils.NetWorkHelper;
 30 import com.fuyin.mp.utils.WxaApi;
 31 @Controller
 32 @RequestMapping("wxconnect.action")
 33 public class WxBase  {
 34     private static final Logger logger = LoggerFactory.getLogger(WxBase.class);
 35     /*
 36     * 自定义token, 用作生成签名,从而验证安全性
 37     * */
 38     private final String TOKEN = WxaApi.TOKEN;
 39     /**
 40      * 检验签名
 41      * @param req
 42      * @param res
 43      */
 44     @RequestMapping(method = RequestMethod.GET)
 45     public void wxconnect(HttpServletRequest req,HttpServletResponse res){
 46         logger.debug("-----开始校验签名-----");
 47          /**
 48           * 接收微信服务器发送请求时传递过来的参数
 49           */
 50          String signature = req.getParameter("signature");
 51          String timestamp = req.getParameter("timestamp");
 52          String nonce = req.getParameter("nonce"); //随机数
 53          String echostr = req.getParameter("echostr");//随机字符串
 54     
 55          /**
 56           * 将token、timestamp、nonce三个参数进行字典序排序
 57           * 并拼接为一个字符串
 58           */
 59          String sortStr = sort(TOKEN,timestamp,nonce);
 60          /**
 61           * 字符串进行shal加密
 62           */
 63          String mySignature = shal(sortStr);
 64          /**
 65           * 校验微信服务器传递过来的签名 和  加密后的字符串是否一致, 若一致则签名通过
 66           */
 67          if(!"".equals(signature) && !"".equals(mySignature) && signature.equals(mySignature)){
 68              try {
 69                 logger.debug("-----签名校验通过-----");
 70                  res.getWriter().write(echostr);
 71             } catch (IOException e) {
 72                 // TODO Auto-generated catch block
 73                 e.printStackTrace();
 74             }
 75          }else {
 76              logger.debug("-----校验签名失败-----");
 77          }
 78     }
 79     @RequestMapping(method = RequestMethod.POST)
 80     protected void doPost(HttpServletRequest request, HttpServletResponse response) {
 81         // TODO 接收、处理、响应由微信服务器转发的用户发送给公众帐号的消息
 82         // 将请求、响应的编码均设置为UTF-8(防止中文乱码)
 83         try {
 84             request.setCharacterEncoding("UTF-8");
 85             response.setCharacterEncoding("UTF-8");
 86             System.out.println("请求进入");
 87             String result = "";
 88             try {
 89                 Map<String,String> map = MessageHandlerUtil.parseXml(request);
 90                 System.out.println("开始构造消息");
 91                 result = MessageHandlerUtil.buildResponseMessage(map, "你好");
 92                 System.out.println(result);
 93                 if(result.equals("")){
 94                     result = "未正确响应";
 95                 }
 96             } catch (Exception e) {
 97                 e.printStackTrace();
 98                 System.out.println("发生异常:"+ e.getMessage());
 99             }
100             response.getWriter().write(result);
101         } catch (UnsupportedEncodingException e) {
102             // TODO Auto-generated catch block
103             e.printStackTrace();
104         } catch (IOException e) {
105             // TODO Auto-generated catch block
106             e.printStackTrace();
107         }
108     }
109         
110     /**
111      * 参数排序
112      * @param token
113      * @param timestamp
114      * @param nonce
115      * @return
116      */
117     public String sort(String token, String timestamp, String nonce) {
118         String[] strArray = {token, timestamp, nonce};
119         Arrays.sort(strArray);
120         StringBuilder sb = new StringBuilder();
121         for (String str : strArray) {
122             sb.append(str);
123         }
124         return sb.toString();
125     }
126     
127     /**
128      * 字符串进行shal加密
129      * @param str
130      * @return
131      */
132     public String shal(String str){
133         try {
134             MessageDigest digest = MessageDigest.getInstance("SHA-1");
135             digest.update(str.getBytes());
136             byte messageDigest[] = digest.digest();
137     
138             StringBuffer hexString = new StringBuffer();
139             // 字节数组转换为 十六进制 数
140             for (int i = 0; i < messageDigest.length; i++) {
141                 String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
142                 if (shaHex.length() < 2) {
143                     hexString.append(0);
144                 }
145                 hexString.append(shaHex);
146             }
147             return hexString.toString();
148     
149         } catch (NoSuchAlgorithmException e) {
150             e.printStackTrace();
151         }
152         return "";
153     }
154 }

 

WxApi 这个是工具类,因为测试用的穿透所以一直要改Ip,干脆提取出来修改方便,上面代码是接入微信服务。

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fuyin.mp.entity.AccessToken;
import com.fuyin.mp.utils.GetMenuJson;
import com.fuyin.mp.utils.NetWorkHelper;
import com.fuyin.mp.utils.WxaApi;

/**
 * 线程 自动获得token 
 * @author Administrator
 *
 */
@Controller
public class AccessTokenInit  implements ApplicationContextAware{
    private static final Logger logger = LoggerFactory.getLogger(AccessTokenInit.class);
    @Override
    public void setApplicationContext(ApplicationContext arg0) throws BeansException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                 while (true) {
                        try {
                            //获取accessToken
                            System.out.println("开始获取TOKEN");
                            WxaApi.accessToken = getAccessToken(WxaApi.appID, WxaApi.appsecret);
                            //获取成功
                            if ( WxaApi.accessToken== null) {
                                //获取失败
                                Thread.sleep(1000 * 3); //获取的access_token为空 休眠3秒
                            } else {
                                //获取到access_token 休眠7000秒,大约2个小时左右
                                Thread.sleep(7000 * 1000);
                                //Thread.sleep(10 * 1000);//10秒钟获取一次
                            }
                        } catch (Exception e) {
                            System.out.println("发生异常:" + e.getMessage());
                            e.printStackTrace();
                            try {
                                Thread.sleep(1000 * 10); //发生异常休眠1秒
                            } catch (Exception e1) {

                            }
                        }
                    }

                }
                
        }).start();
        
        
        
    }
    /**
     * 获取access_token
     *
     * @return AccessToken
     */
    private AccessToken getAccessToken(String appId, String appSecret) {
        NetWorkHelper netHelper = new NetWorkHelper();
        String Url=WxaApi.GetTokenApi.replace("APPID", appId).replaceAll("APPSECRET", appSecret);;
        //此请求为https的get请求,返回的数据格式为{"access_token":"ACCESS_TOKEN","expires_in":7200}
        String result = netHelper.getHttpsResponse(Url, "",null);
        System.out.println("获取到的access_token="+result);
        //使用FastJson将Json字符串解析成Json对象
        JSONObject json = JSON.parseObject(result);
        AccessToken token = new AccessToken();
        token.setAccessToken(json.getString("access_token"));
        token.setExpiresin(json.getInteger("expires_in"));
        return token;
    }

}

这是一个springmvc启动以后就会启动的线程,用来自动获取token

工具类 用来发送https请求

  1 import javax.net.ssl.*;
  2 import java.io.BufferedReader;
  3 import java.io.InputStream;
  4 import java.io.InputStreamReader;
  5 import java.io.OutputStream;
  6 import java.io.UnsupportedEncodingException;
  7 import java.net.URL;
  8 import java.net.URLEncoder;
  9 import java.security.cert.CertificateException;
 10 import java.security.cert.X509Certificate;
 11 
 12 /**
 13  * 访问网络用到的工具类
 14  */
 15 public class NetWorkHelper {
 16 
 17     /**
 18      * 发起Https请求
 19      * @param reqUrl 请求的URL地址
 20      * @param requestMethod
 21      * @return 响应后的字符串
 22      */
 23     public String getHttpsResponse(String reqUrl, String requestMethod,String outputStr) {
 24         URL url;
 25         InputStream is;
 26         String resultData = "";
 27         try {
 28             url = new URL(reqUrl);
 29             HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
 30             TrustManager[] tm = {xtm};
 31 
 32             SSLContext ctx = SSLContext.getInstance("TLS");
 33             ctx.init(null, tm, null);
 34             con.setSSLSocketFactory(ctx.getSocketFactory());
 35             con.setHostnameVerifier(new HostnameVerifier() {
 36                 @Override
 37                 public boolean verify(String arg0, SSLSession arg1) {
 38                     return true;
 39                 }
 40             });
 41 
 42             
 43             con.setDoInput(true); //允许输入流,即允许下载
 44 
 45             //在android中必须将此项设置为false
 46             con.setDoOutput(true); //允许输出流,即允许上传
 47             con.setUseCaches(false); //不使用缓冲
 48             if (null != requestMethod && !requestMethod.equals("")) {
 49                 con.setRequestMethod(requestMethod); //使用指定的方式
 50             } else {
 51                 con.setRequestMethod("GET"); //使用get请求
 52             }
 53             con.setRequestProperty("content-type",
 54                     "application/x-www-form-urlencoded");
 55             // 当outputStr不为null时向输出流写数据
 56             if (null != outputStr) {
 57                 OutputStream outputStream = con.getOutputStream();
 58                 // 注意编码格式
 59                 outputStream.write(outputStr.getBytes("UTF-8"));
 60                 outputStream.close();
 61             }
 62             is = con.getInputStream();   //获取输入流,此时才真正建立链接
 63             InputStreamReader isr = new InputStreamReader(is);
 64             BufferedReader bufferReader = new BufferedReader(isr);
 65             String inputLine;
 66             while ((inputLine = bufferReader.readLine()) != null) {
 67                 resultData += inputLine + "\n";
 68             }
 69            // System.out.println(resultData);
 70 
 71         } catch (Exception e) {
 72             e.printStackTrace();
 73         }
 74         return resultData;
 75     }
 76 
 77     X509TrustManager xtm = new X509TrustManager() {
 78         @Override
 79         public X509Certificate[] getAcceptedIssuers() {
 80             return null;
 81         }
 82 
 83         @Override
 84         public void checkServerTrusted(X509Certificate[] arg0, String arg1)
 85                 throws CertificateException {
 86 
 87         }
 88 
 89         @Override
 90         public void checkClientTrusted(X509Certificate[] arg0, String arg1)
 91                 throws CertificateException {
 92 
 93         }
 94     };
 95     /**
 96      * 对URL地址进行EnCode处理
 97      * @param url
 98      * @return
 99      */
100     public static String urlEnCode(String url)
101     {
102         String enCodedUrl = "";
103 
104         try
105         {
106             enCodedUrl = URLEncoder.encode(url, "utf-8");
107         }
108         catch (UnsupportedEncodingException e)
109         {
110             // TODO Auto-generated catch block
111             e.printStackTrace();
112             System.out.println("转码失败!");
113         }
114 
115         return enCodedUrl;
116     }
117 }

 

 

线程启动可能会获取两次token是因为springmvc把项目的Bean扫描了两次,可以把applicationContext.xml配置成只扫描mapper,其他不扫,由springmvc.xml去扫面serveice 和controller,因为我这样还是失败了,所以把线程的类也定义成controller,这样用前面的方法只会扫描一次

 

posted on 2018-12-25 16:11  奶茶好喝的  阅读(296)  评论(0编辑  收藏  举报