移动开发之手机微信开发java版 —— 配置微信服务器环境

     没有开场白,直接步入正题,首先呢兄弟们听我白话一段大笑,这个表情。。。

     明确下我们要做的微信公众号开发,服务器的环境我们使用java环境,框架为 springmvc+mybatis,说好的微信开发怎么变成了java环境了呢?

    说了好多的废话,其实微信开发 java能做的事情很少,但是所做的事情是非常强大的,原因是我们在与微信做任何交易的时候都需要做验证,真的是一件很烦的事情,所以我选择了java 帮我去验证; 好在现在有好多第三方的开发工具也可以使用,而且帮我们省去了好多步骤,其实网上有好多有关微信开发的代码,我在查询了一番之后在这里整理下;

进入正题首先准备一些事情;

测试的公众号:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login


获得appId 和appsecret 为配置微信服务端;


配置接口信息, 稍后讲解;



为了方便微信测试 :http://www.ngrok.cc/ 看下图文字叙述,没什么可说的,


java web环境:下图采用的是 spring4MVC 、jdk1.8、 tomact8,使用的是maven管理工具;


到此准备的差不多了; 下面开始配置微信环境;

还得多说两句,微信开发主要就是通过微信的令牌获得微信的一些特权,为了达到这个效果,需要让微信知道我们的服务器, 我们服务器写一个微信接口供微信调用,同时响应微信发送的token验证,官方文档有介绍,不再赘述,上代码;

@Controller  
@RequestMapping("/test")
public class WXAuthtokenController {

	@RequestMapping(value="/wxToken", method = RequestMethod.GET, produces="application/json")
	@ResponseBody
	public String wxToken(HttpServletRequest request,ModelMap map,
			@RequestParam(value="signature")String signature,
			@RequestParam(value="timestamp")String timestamp,
			@RequestParam(value="nonce")String nonce,
			@RequestParam(value="echostr")String echostr){ 
		System.out.println("请求成功");//因为测试,这里未做验证;
         
	    return echostr;                                                   
	}
}
至此,微信和我们的服务器,能沟通了 偷笑,我们继续,,,

由于我们启动时需要加载微信的accessToken,和JSAPI接口的飞机票,JSApiTicket,下面配置web.xml

<servlet-name>InitAccessTokenServlet</servlet-name>  
    <servlet-class>com.oa.wx.utils.InitAccessTokenServlet</servlet-class>  
      
    <init-param>  
        <param-name>appid</param-name>  
        <param-value>wx4fb90asd5015e9820</param-value>  
    </init-param>  
    <init-param>  
        <param-name>appsecret</param-name>  
        <param-value>f7850725c4fff0423349c2a62e2d430</param-value>  
    </init-param>  
          
    <load-on-startup>2</load-on-startup>  
</servlet>
  
上面配置的目的就是当项目启动时加载 InitAccessTokenServlet 获取我们想要的信息;

为了方便我们建立两个实体类用于获取参数 ,同时准备一些类供加载时调用:

package com.oa.wx.utils;

public class AccessToken implements java.io.Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	// 接口访问凭证  
    private String accessToken;  
    // 凭证有效期,单位:秒  
    private int expiresIn;  
  
    public AccessToken() {  
  
    }  
  
    public String getAccessToken() {  
        return accessToken;  
    }  
  
    public void setAccessToken(String accessToken) {  
        this.accessToken = accessToken;  
    }  
  
    public int getExpiresIn() {  
        return expiresIn;  
    }  
  
    public void setExpiresIn(int expiresIn) {  
        this.expiresIn = expiresIn;  
    }  

}
package com.oa.wx.utils;

public class JsApiTicket implements java.io.Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private String ticket;  
    // 凭证有效期,单位:秒  
    private int expiresIn;  
  
    public JsApiTicket() {  
  
    }  
  
    public String getTicket() {  
        return ticket;  
    }  
  
    public void setTicket(String ticket) {  
        this.ticket = ticket;  
    }  
  
    public int getExpiresIn() {  
        return expiresIn;  
    }  
  
    public void setExpiresIn(int expiresIn) {  
        this.expiresIn = expiresIn;  
    }  

}
编写获取accessToken 和飞机票的接口,在网上找了个例子,编写了个工具类如下、

package com.oa.wx.utils;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;  

public class WeiXinUtil {

	// 凭证获取(GET)——access_token  
    public final static String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
    // 微信JSSDK的ticket请求URL地址——jsapi_ticket  
    public final static String JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
    //微信APPID
    public final static String APP_ID="wx4fb9062502315e9820";
    //微信APPSECRET
    public final static String APPSECRET="19751e4ebd34c56e763f28b1a8c8263053";
    
	/**  
     * 排序方法  
     *   
     * @param token  
     * @param timestamp  
     * @param nonce  
     * @return  
     */  
    public static String sort(String token, String timestamp, String nonce) {  
        String[] strArray = { token, timestamp, nonce };  
        Arrays.sort(strArray);  
  
        StringBuilder sbuilder = new StringBuilder();  
        for (String str : strArray) {  
            sbuilder.append(str);  
        }  
  
        return sbuilder.toString();  
    }
   
    /** 
     * 发送https请求 
     *  
     * @param requestUrl 
     *            请求地址 
     * @param requestMethod 
     *            请求方式(GET、POST) 
     * @param outputStr 
     *            提交的数据 
     * @return rootNode(通过rootNode.get(key)的方式获取json对象的属性值) 
     */  
    public static JsonNode httpsRequest(String requestUrl, String requestMethod, String outputStr) {  
        ObjectMapper mapper = new ObjectMapper();  
        JsonNode rootNode = null;  
        StringBuffer buffer = new StringBuffer();  
        try {  
            // 创建SSLContext对象,并使用我们指定的信任管理器初始化  
            TrustManager[] tm = { new MyX509TrustManager() };  
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");  
  
            sslContext.init(null, tm, new java.security.SecureRandom());  
            // 从上述SSLContext对象中得到SSLSocketFactory对象  
            SSLSocketFactory ssf = sslContext.getSocketFactory();  
  
            URL url = new URL(requestUrl);  
            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();  
            conn.setSSLSocketFactory(ssf);  
  
            conn.setDoOutput(true);  
            conn.setDoInput(true);  
            conn.setUseCaches(false);  
            // 设置请求方式(GET/POST)  
            conn.setRequestMethod(requestMethod);  
            //conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");  
            if ("GET".equalsIgnoreCase(requestMethod))  
                conn.connect();  
  
            // 当outputStr不为null时向输出流写数据  
            if (null != outputStr) {  
                OutputStream outputStream = conn.getOutputStream();  
                // 注意编码格式  
                outputStream.write(outputStr.getBytes("UTF-8"));  
                outputStream.close();  
            }  
  
            // 从输入流读取返回内容  
            InputStream inputStream = conn.getInputStream();  
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");  
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);  
            String str = null;  
            while ((str = bufferedReader.readLine()) != null) {  
                buffer.append(str);  
            }  
  
            // 释放资源  
            bufferedReader.close();  
            inputStreamReader.close();  
            inputStream.close();  
            inputStream = null;  
            conn.disconnect();  
            rootNode = mapper.readTree(buffer.toString());  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return rootNode;  
    }  
    
    
    
    
    /** 
     * 获取接口访问凭证 
     *  
     * @param appid 
     *            凭证 
     * @param appsecret 
     *            密钥 
     * @return 
     */  
    public static AccessToken getAccessToken() {  
        AccessToken accessToken = null;  
        String requestUrl = ACCESS_TOKEN_URL.replace("APPID", APP_ID).replace("APPSECRET", APPSECRET);  
        // 发起GET请求获取凭证  
        JsonNode rootNode = httpsRequest(requestUrl, "GET", null);  
        System.out.println("rootNoderootNoderootNode"+rootNode);
        if (null != rootNode.get("access_token")) {  
            accessToken = new AccessToken();  
            accessToken.setAccessToken(rootNode.get("access_token").textValue());  
            accessToken.setExpiresIn(toInt(rootNode.get("expires_in").toString()));  
        }  
        return accessToken;  
    }
    
    
    /** 
     * 调用微信JS接口的临时票据 
     *  
     * @param access_token 
     *            接口访问凭证 
     * @return 
     */  
    public static JsApiTicket getJsApiTicket(String access_token) {  
        String requestUrl = JSAPI_TICKET_URL.replace("ACCESS_TOKEN", access_token);  
        // 发起GET请求获取凭证  
        JsonNode rootNode = httpsRequest(requestUrl, "GET", null);  
        System.out.println(rootNode.toString());
        JsApiTicket jsApiTicket = null;  
        if (null != rootNode.get("ticket")) {  
            jsApiTicket = new JsApiTicket();  
            jsApiTicket.setTicket(rootNode.get("ticket").textValue());  
            jsApiTicket.setExpiresIn(toInt(rootNode.get("expires_in").toString()));  
        }  
        return jsApiTicket;  
    }  
  
    public static Integer toInt(String str) {
        if (str == null || str.equals("")) {
            return null;
        }
        return Integer.valueOf(str);
    }
    
    /** 
     * 获取接口访问凭证 
     *  
     * @param appid 
     *            凭证 
     * @param appsecret 
     *            密钥 
     * @return 
     */  
    public static String getAuthorize(String url) {  
        AccessToken accessToken = null;  
        String requestUrl = ACCESS_TOKEN_URL.replace("APPID", APP_ID).replace("APPURL", url);  
        // 发起GET请求获取凭证  
        JsonNode rootNode = httpsRequest(requestUrl, "GET", null);  
        System.out.println(rootNode.toString());
        return rootNode.toString();
    }
    
    public static String create_nonce_str() {  
        return UUID.randomUUID().toString();  
    }  
  
    public static String create_timestamp() {  
        return Long.toString(System.currentTimeMillis() / 1000);  
    }
    
    public static String byteToHex(final byte[] hash) {  
        Formatter formatter = new Formatter();  
        for (byte b : hash) {  
            formatter.format("%02x", b);  
        }  
        String result = formatter.toString();  
        formatter.close();  
        return result;  
    }
    
    public static Map<String, String> sign(String jsapi_ticket, String url) {  
        Map<String, String> ret = new HashMap<String, String>();  
        String nonce_str = WeiXinUtil.create_nonce_str();  
        String timestamp = WeiXinUtil.create_timestamp();  
        String string1;  
        String signature = "";  
  
        // 注意这里参数名必须全部小写,且必须有序  
         string1 = "jsapi_ticket=" + jsapi_ticket +  
                 "&noncestr=" + nonce_str +  
                 "×tamp=" + timestamp +  
                 "&url=" + url;  
         System.out.println(string1);  
  
        try {  
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");  
            crypt.reset();  
            crypt.update(string1.getBytes("UTF-8"));  
            signature = WeiXinUtil.byteToHex(crypt.digest());  
        } catch (NoSuchAlgorithmException e) {  
            e.printStackTrace();  
        } catch (UnsupportedEncodingException e) {  
            e.printStackTrace();  
        }  
  
        ret.put("url", url);  
        ret.put("appId",WeiXinUtil.APP_ID);  
        ret.put("jsapi_ticket", jsapi_ticket);  
        ret.put("nonceStr", nonce_str);  
        ret.put("timestamp", timestamp);  
        ret.put("signature", signature);  
  
        return ret;  
    }
}
由于微信的一些情况 accessToken 每天的获取数量是有限的,所以需要做缓存处理,在这里写了两个线程,一个是获取 accessToken ,一个是JsApiTicket;

package com.oa.wx.utils;

import javax.servlet.ServletContext;

public class AccessTokenThread implements Runnable {

	public static String appid = "";  
    public static String appsecret = "";  
    public static AccessToken accessToken = null; 
    
    @Override  
    public void run() {  
        while (true) {  
            try {  
                accessToken = WeiXinUtil.getAccessToken();  
                if (null != accessToken) {  
                    System.out.println("accessToken初始化成功:" + accessToken.getAccessToken());  
                    // 全局缓存access_token  
                    ServletContext servletContext = ServletContextUtil.getServletContext();  
                    servletContext.setAttribute("access_token", accessToken.getAccessToken());  
                    // 有效期(秒)减去200秒,乘以1000(毫秒)——也就是在有效期的200秒前去请求新的accessToken  
                    Thread.sleep((accessToken.getExpiresIn() - 200) * 1000);  
                } else {  
                    // 等待一分钟,再次请求  
                    Thread.sleep(60 * 1000);  
                }  
            } catch (Exception e) {  
                try {  
                    // 等待一分钟,再次请求  
                    Thread.sleep(60 * 1000);  
                } catch (Exception ex) {  
                    ex.printStackTrace();  
                }  
                e.printStackTrace();  
            }  
        }  
    }  

}
package com.oa.wx.utils;

import javax.servlet.ServletContext;

public class JsApiTicketThread implements Runnable {

	@Override  
    public void run() {  
        while (true) {  
            try {  
                ServletContext servletContext = ServletContextUtil.getServletContext();  
                String access_token = (String) servletContext.getAttribute("access_token");  
                  
                JsApiTicket jsApiTicket = null;  
                  
                if(null != access_token && !"".equals(access_token)){  
                    // 获取jsapi_ticket  
                    jsApiTicket = WeiXinUtil.getJsApiTicket(access_token);  
                      
                    if (null != jsApiTicket) {  
                        System.out.println("jsapi_ticket获取成功:" + jsApiTicket.getTicket());  
                        // 全局缓存jsapi_ticket  
                        servletContext.setAttribute("jsapi_ticket", jsApiTicket.getTicket());  
                        Thread.sleep((jsApiTicket.getExpiresIn() - 200) * 1000);  
                    }  
                }  
                Thread.sleep(60 * 1000);  
            } catch (Exception e) {  
                try {  
                    Thread.sleep(60 * 1000);  
                } catch (Exception ex) {  
                    ex.printStackTrace();  
                }  
                e.printStackTrace();  
            }  
        }  
    }  

}

最后我们编写 InitAccessTokenServlet ,首次加载时调用;

package com.oa.wx.utils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;

public class InitAccessTokenServlet extends HttpServlet {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	public void init() throws ServletException {  
        // 获取web.xml中配置的参数  
        String WX_APPID ="wx4fb90625015e9820";
        String WX_APPSECRET = "19751e4ebdc56e763f28b1a8c8263053";
        AccessTokenThread.appid = WX_APPID;  
        AccessTokenThread.appsecret = WX_APPSECRET;  
  
        if ("".equals(AccessTokenThread.appid) || "".equals(AccessTokenThread.appsecret)) {  
            System.out.println("appid和appsecret未给出");  
        } else {  
            new Thread(new AccessTokenThread()).start();  
            new Thread(new JsApiTicketThread()).start();  
        }  
    }  

}
至此,微信服务端配置环境已结束,以上代码均在网上整理,为查阅方便整理到一起,如有侵权行为请与我联系。以上代码仅供参考,如遇问题可以留言!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值