您的位置:首页 > 移动开发 > 微信开发

Java与微信不得不说的故事——实现微信公众平台与sae服务器的对接

2015-06-14 20:59 525 查看
  又颓废了些日子,说好认真来半年的,那就接着来啊,公司的easyUI平台慢慢开始明白了,可是最近bug太多了,只能找时间在研究了,平时无聊看见了了java微信平台开发,感觉有点意思呀,自己也来试试,不过又得求教博客园里面的大神们了,现在开始研究。

  一开始无聊的时候,自己在新浪云服务器注册了一个账号,可以建立一些应用在上面,微信平台也是可以的。于是自己照着微信官方的例子,建立了微信公众平台与新浪云服务器的接口,成功了。不过官方是用PHP语言写的(也许PHP是世界上最好的语言)。可是作为一个Javaer,当然要学会怎么写Java了。先贴把这个例子贴一下吧。

  

<?php
/**
* wechat php test
*/

//define your token
define("TOKEN", "haojiahongxihuanliyuan");
$wechatObj = new wechatCallbackapiTest();
$wechatObj->valid();

class wechatCallbackapiTest
{
public function valid()
{
$echoStr = $_GET["echostr"];

//valid signature , option
if($this->checkSignature()){
echo $echoStr;
exit;
}
}

public function responseMsg()
{
//get post data, May be due to the different environments
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];

//extract post data
if (!empty($postStr)){
/* libxml_disable_entity_loader is to prevent XML eXternal Entity Injection,
the best way is to check the validity of xml by yourself */
libxml_disable_entity_loader(true);
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$fromUsername = $postObj->FromUserName;
$toUsername = $postObj->ToUserName;
$keyword = trim($postObj->Content);
$time = time();
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
<FuncFlag>0</FuncFlag>
</xml>";
if(!empty( $keyword ))
{
$msgType = "text";
$contentStr = "Welcome to wechat world!";
$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
echo $resultStr;
}else{
echo "Input something...";
}

}else {
echo "";
exit;
}
}

private function checkSignature()
{
// you must define TOKEN by yourself
if (!defined("TOKEN")) {
throw new Exception('TOKEN is not defined!');
}

$signature = $_GET["signature"];
$timestamp = $_GET["timestamp"];
$nonce = $_GET["nonce"];

$token = TOKEN;
$tmpArr = array($token, $timestamp, $nonce);
// use SORT_STRING rule
sort($tmpArr, SORT_STRING);
$tmpStr = implode( $tmpArr );
$tmpStr = sha1( $tmpStr );

if( $tmpStr == $signature ){
return true;
}else{
return false;
}
}
}

?>


  这个是官方提过的接口程序。

  下面开始研究Java接口程序。

  当用户通过微信客服端发送消息到微信服务后,微信服务器会将此消息转发给我们的公网服务器,也就是上面所说sae新浪云服务器。具体的业务逻辑就在sae上完成,处理完后再将结果发回微信服务器,微信服务器再发给用户。

  让两个完全不沾边的服务器(微信服务器和sae)对接是有风险,因此必须有验证机制的存在。具体的验证过程是



代码如下:

微信公众平台去请求sae中的coreServlet。

package org.liufeng.course.servlet;

import java.io.IOException;
import java.io.PrintWriter;

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

import org.liufeng.course.service.CoreService;
import org.liufeng.course.util.SignUtil;

/**
* 请求处理的核心类
*
* @author liufeng
* @date 2013-09-29
*/
public class CoreServlet extends HttpServlet {
private static final long serialVersionUID = 4440739483644821986L;

/**
* 请求校验(确认请求来自微信服务器)
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 微信加密签名
String signature = request.getParameter("signature");
// 时间戳
String timestamp = request.getParameter("timestamp");
// 随机数
String nonce = request.getParameter("nonce");
// 随机字符串
String echostr = request.getParameter("echostr");

PrintWriter out = response.getWriter();
// 请求校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
if (SignUtil.checkSignature(signature, timestamp, nonce)) {
out.print(echostr);
}
out.close();
out = null;
}

/**
* 处理微信服务器发来的消息
*/
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 将请求、响应的编码均设置为UTF-8(防止中文乱码)
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");

// 调用核心业务类接收消息、处理消息
String respXml = CoreService.processRequest(request);

// 响应消息
PrintWriter out = response.getWriter();
out.print(respXml);
out.close();
}
}


消息处理类:

package org.liufeng.course.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

/**
* 请求校验工具类
*
* @author liufeng
* @date 2013-09-01
*/
public class SignUtil {
// 与开发模式接口配置信息中的Token保持一致
private static String token = "weixinCourse";

/**
* 校验签名
*
* @param signature 微信加密签名
* @param timestamp 时间戳
* @param nonce 随机数
* @return
*/
public static boolean checkSignature(String signature, String timestamp, String nonce) {
// 对token、timestamp和nonce按字典排序
String[] paramArr = new String[] { token, timestamp, nonce };
Arrays.sort(paramArr);

// 将排序后的结果拼接成一个字符串
String content = paramArr[0].concat(paramArr[1]).concat(paramArr[2]);

String ciphertext = null;
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
// 对接后的字符串进行sha1加密
byte[] digest = md.digest(content.toString().getBytes());
ciphertext = byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}

// 将sha1加密后的字符串与signature进行对比
return ciphertext != null ? ciphertext.equals(signature.toUpperCase()) : false;
}

/**
* 将字节数组转换为十六进制字符串
*
* @param byteArray
* @return
*/
private static String byteToStr(byte[] byteArray) {
String strDigest = "";
for (int i = 0; i < byteArray.length; i++) {
strDigest += byteToHexStr(byteArray[i]);
}
return strDigest;
}

/**
* 将字节转换为十六进制字符串
*
* @param mByte
* @return
*/
private static String byteToHexStr(byte mByte) {
char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
char[] tempArr = new char[2];
tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
tempArr[1] = Digit[mByte & 0X0F];

String s = new String(tempArr);
return s;
}
}


web.xml中配置了coreServlet:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet>
<servlet-name>coreServlet</servlet-name>
<servlet-class>
org.liufeng.course.servlet.CoreServlet
</servlet-class>
</servlet>

<!-- /coreServlet用于指定该Servlet的访问路径 -->
<servlet-mapping>
<servlet-name>coreServlet</servlet-name>
<url-pattern>/coreServlet</url-pattern>
</servlet-mapping>

<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>


微信公众平台的配置截图:



微信平台提示接入成功。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: