转载自:http://blog.csdn.net/wangqianjiao/article/details/8469780
微信公众平台现在推出自动回复消息接口,但是由于是接口内容用的是PHP语言写的,很多地方操作起来让本人这个对java比较熟悉的小伙很别扭,所以仿照PHP的接口代码做了一套jsp语言编写的接口。
首先先把整个接口代码贴出来做下比较,然后我们再分析代码:
PHP代码:
<?php
/**
* wechat php test
*/
//define your token
define("TOKEN", "weixin");
$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)){
$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()
{
$signature = $_GET["signature"];
$timestamp = $_GET["timestamp"];
$nonce = $_GET["nonce"];
$token = TOKEN;
$tmpArr = array($token, $timestamp, $nonce);
sort($tmpArr);
$tmpStr = implode( $tmpArr );
$tmpStr = sha1( $tmpStr );
if( $tmpStr == $signature ){
return true;
}else{
return false;
}
}
}
?>
JAVA代码:
<%@page import="java.util.Date"%>
<%@page import="org.dom4j.Element"%>
<%@page import="org.dom4j.DocumentHelper"%>
<%@page import="org.dom4j.Document"%>
<%@page import="java.io.IOException"%>
<%@page import="java.io.InputStreamReader"%>
<%@page import="java.io.BufferedReader"%>
<%@page import="java.io.Reader"%>
<%@page import="java.security.MessageDigest"%>
<%@page import="java.util.Arrays"%>
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%
//WeiXinHandler为内部类不能使用非final类型的对象
final String TOKEN="weixin";
final HttpServletRequest final_request=request;
final HttpServletResponse final_response=response;
%>
<%
class WeiXinHandler{
public void valid(){
String echostr=final_request.getParameter("echostr");
if(null==echostr||echostr.isEmpty()){
responseMsg();
}else{
if(this.checkSignature()){
this.print(echostr);
}else{
this.print("error");
}
}
}
//自动回复内容
public void responseMsg(){
String postStr=null;
try{
postStr=this.readStreamParameter(final_request.getInputStream());
}catch(Exception e){
e.printStackTrace();
}
//System.out.println(postStr);
if (null!=postStr&&!postStr.isEmpty()){
Document document=null;
try{
document = DocumentHelper.parseText(postStr);
}catch(Exception e){
e.printStackTrace();
}
if(null==document){
this.print("");
return;
}
Element root=document.getRootElement();
String fromUsername = root.elementText("FromUserName");
String toUsername = root.elementText("ToUserName");
String keyword = root.elementTextTrim("Content");
String time = new Date().getTime()+"";
String textTpl = "<xml>"+
"<ToUserName><![CDATA[%1$s]]></ToUserName>"+
"<FromUserName><![CDATA[%2$s]]></FromUserName>"+
"<CreateTime>%3$s</CreateTime>"+
"<MsgType><![CDATA[%4$s]]></MsgType>"+
"<Content><![CDATA[%5$s]]></Content>"+
"<FuncFlag>0</FuncFlag>"+
"</xml>";
if(null!=keyword&&!keyword.equals(""))
{
String msgType = "text";
String contentStr = "Welcome to wechat world!";
String resultStr = textTpl.format(textTpl, fromUsername, toUsername, time, msgType, contentStr);
this.print(resultStr);
}else{
this.print("Input something...");
}
}else {
this.print("");
}
}
//微信接口验证
public boolean checkSignature(){
String signature = final_request.getParameter("signature");
String timestamp = final_request.getParameter("timestamp");
String nonce = final_request.getParameter("nonce");
String token=TOKEN;
String[] tmpArr={token,timestamp,nonce};
Arrays.sort(tmpArr);
String tmpStr=this.ArrayToString(tmpArr);
tmpStr=this.SHA1Encode(tmpStr);
if(tmpStr.equalsIgnoreCase(signature)){
return true;
}else{
return false;
}
}
//向请求端发送返回数据
public void print(String content){
try{
final_response.getWriter().print(content);
final_response.getWriter().flush();
final_response.getWriter().close();
}catch(Exception e){
}
}
//数组转字符串
public String ArrayToString(String [] arr){
StringBuffer bf = new StringBuffer();
for(int i = 0; i < arr.length; i++){
bf.append(arr[i]);
}
return bf.toString();
}
//sha1加密
public String SHA1Encode(String sourceString) {
String resultString = null;
try {
resultString = new String(sourceString);
MessageDigest md = MessageDigest.getInstance("SHA-1");
resultString = byte2hexString(md.digest(resultString.getBytes()));
} catch (Exception ex) {
}
return resultString;
}
public final String byte2hexString(byte[] bytes) {
StringBuffer buf = new StringBuffer(bytes.length * 2);
for (int i = 0; i < bytes.length; i++) {
if (((int) bytes[i] & 0xff) < 0x10) {
buf.append("0");
}
buf.append(Long.toString((int) bytes[i] & 0xff, 16));
}
return buf.toString().toUpperCase();
}
//从输入流读取post参数
public String readStreamParameter(ServletInputStream in){
StringBuilder buffer = new StringBuilder();
BufferedReader reader=null;
try{
reader = new BufferedReader(new InputStreamReader(in));
String line=null;
while((line = reader.readLine())!=null){
buffer.append(line);
}
}catch(Exception e){
e.printStackTrace();
}finally{
if(null!=reader){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return buffer.toString();
}
}
%>
<%
WeiXinHandler handler=new WeiXinHandler();
handler.valid();
%>
以上就是PHP接口和JSP接口的所有代码,现在我们来对一些需要注意的地方做下分析:
首先的从总体看的话,jsp要比PHP繁琐一些,因为很多函数需要自己写,像sha1加密,解析xml字符串等都需要自己找第三方的库。
第一点,我们要获取微信公众平台给jsp发送的post或get参数,正常情况下都是用request.getParameter就可以获取到,但是在写的过程中发现PHP是这样获取
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
这时通过查询一些资料知道这样获取的是无法通过$_GET或$_POST函数得到的”未识别 MIME 类型的数据“,原始的 POST 数据
(参考:http://blog.csdn.net/china_skag/article/details/7284227)
所以这里使用获取原始数据流的方式来解析post的xml数据
String postStr=null;
try{
postStr=this.readStreamParameter(final_request.getInputStream());
}catch(Exception e){
e.printStackTrace();
}
//从输入流读取post参数
public String readStreamParameter(ServletInputStream in){
StringBuilder buffer = new StringBuilder();
BufferedReader reader=null;
try{
reader = new BufferedReader(new InputStreamReader(in));
String line=null;
while((line = reader.readLine())!=null){
buffer.append(line);
}
}catch(Exception e){
e.printStackTrace();
}finally{
if(null!=reader){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return buffer.toString();
}
第二个,是response消息返回给微信平台,我尝试的用最一般的out.print去做,但是发现没反应,观察PHP的代码写法
echo ""; exit;
猜想可能需要有个刷新的操作才能把消息response回去,于是找了下response内的一些函数做出以下尝试
//向请求端发送返回数据
public void print(String content){
try{
final_response.getWriter().print(content);
final_response.getWriter().flush();
final_response.getWriter().close();
}catch(Exception e){
}
}
发现以上做法是可以在微信发送端得到消息的;
第三个,接口描述上说目前只支持80端口的服务端地址,所以我这里的做法是用apache服务器路由到tomcat的jsp上
关于微信公众平台的消息接口的详细介绍,可以参看微信公众平台的官方文档,里面介绍了消息的xml的格式和消息的发送方式等。
其实也就是自定义了一个Adapter,也可以使用SimpleExpandableListAdapter来代替。
package com.szy;
import android.app.ExpandableListActivity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;
/**
* 扩展的Listview
* @author Administrator
*
*/
public class MainActivity extends ExpandableListActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
MyExpandableListAdapter adapter=new MyExpandableListAdapter();
setListAdapter(adapter);
}
public class MyExpandableListAdapter extends BaseExpandableListAdapter{
public String[] groups={"我的好友","大学同学","高中同学"};
public String[][] childrens={{"刘亦菲","林志玲","林心如"},{"诸葛孔明","关羽"},{"周迅","周星驰","成龙"}};
public Object getChild(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return childrens[groupPosition][childPosition];
}
public long getChildId(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return childPosition;
}
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
TextView textView=getGenericView();
textView.setText(getChild(groupPosition, childPosition).toString());
return textView;
}
//新建一个TextView
public TextView getGenericView() {
// Layout parameters for the ExpandableListView
AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, 64);
TextView textView = new TextView(MainActivity.this);
textView.setLayoutParams(lp);
// Center the text vertically
textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
// Set the text starting position
textView.setPadding(36, 0, 0, 0);
return textView;
}
public int getChildrenCount(int groupPosition) {
// TODO Auto-generated method stub
return childrens[groupPosition].length;
}
public Object getGroup(int groupPosition) {
// TODO Auto-generated method stub
return groups[groupPosition];
}
public int getGroupCount() {
// TODO Auto-generated method stub
return groups.length;
}
public long getGroupId(int groupPosition) {
// TODO Auto-generated method stub
return groupPosition;
}
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
TextView textView = getGenericView();
textView.setText(getGroup(groupPosition).toString()+"ABCD");
return textView;
}
public boolean hasStableIds() {
// TODO Auto-generated method stub
return true;
}
public boolean isChildSelectable(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return true;
}
}
}
http://www.eoeandroid.com/thread-273332-1-1.html
用libgdx开发了一小段时间,做做笔记有的地方也许不对见谅
1.使用libgdx看重了跨平台功能和使用java语言开发两点
2.这个框架使用起来还是非常简单.方便的,而且可以直接用桌面版运行测试,大大的提高了开发效率
3.建议使用,opengl2来开发 虽然少部分机型不支持
4.事件传递是从stage开始
暂时就这么点了