Java

Java

小黄鸡SimSimi API以及小i机器人的说明——如何免费使用?

移动开发atool 发表了文章 • 0 个评论 • 2880 次浏览 • 2016-04-22 12:57 • 来自相关话题

一、什么是Simsimi?

simsimi公司是提供智能服务,其中一个服务是simsimi聊天机器人服务,每天有超过百万的用户聊天,国内最大的搜索引擎——百度的产品siri使用的就是simsimi提供的api。

你可以在网址http://www.simsimi.com/talk.htm# 进行体验

SimSimi inc. is specialized in collective intelligence service. All kinds of services we provide generates unique entertainment and values through systemized collective intelligence.

One of our services, a chatting robot SimSimi exceeds the limitation of technology of natural-language processing system by collective intelligence and it has a chat with over millions user per day. Our Premium knowledge providing service “Jisikman” creates millions of valuable knowledges a day.

We invite you to our realm of service which is available through our cloud of collective intelligence, Crowd Cloud that SimSimi inc. creates.

二、Simsimi小黄鸡API

在去年的这个时候,小黄鸡的非官方api一度被大家疯狂的在微信公众号上使用,一时间不知道成就了多少微信营销号,同时,华科某位大四学生利用这个api,结合人人网开发平台,制作了一个小黄鸡的人人号,@小黄鸡之后,就可以利用api自动进行回复,是的这个人人号瞬间粉丝陡增。

然而大家使用的都是非官方的API,所谓非官方,就是不是simsimi公司提供的合法使用途径,API大致的原理是利用编程语言,模拟浏览器发送post请求到http://www.simsimi.com/talk.htm# 链接,解析响应,然后作成相关的小黄鸡API。这个方法后来被我在本博客中在博文中发布,导致使用人数激增,simsimi公司似乎察觉了什么,立马对这种模拟请求的方式做出了屏蔽,一旦某ip请求数量和频率超过限制,则终端对它的请求。正式官方对非法API的封锁,也使用国内的开发这关注到之前并不出名的小i机器人,同样使用语言模拟请求web聊天界面,时间没有过很久,这个页面就加入了图片验证码防止程序模拟。

至此,两个聊天机器人都走上了收费的道路...准确的说,应该是被这帮子开发者赶上了收费的道路,因为他们给它带来了知名度。

三、SimsimiAPI使用




目前,小黄鸡API已经公然收费(http://developer.simsimi.com/api)
不过,和之前一样,会给注册用户提供30天的试用API。
API请求链接为:
Trial-key    http://sandbox.api.simsimi.com/request.p
Paid-key    http://api.simsimi.com/request.p

API请求参数见官网。
 
API返回格式为:

result:100-ok. 400-Bad Request. 401-Unauthorized. 404-Not found. 500-Server Error.    返回的code

id:Response id. (you can get only if returning result is 100)回复的id,由系统生成,当请求成功返回时才有这个字段。 

response:Response message(you can get only if returning result is 100)返回的回复内容。

msg:Result  msg(Description of result code) 返回的code对应的含义

四、Simsimi使用举例

请求举例:

Trial-key    http://sandbox.api.simsimi.com ... %3Dhi   
Paid-key    http://api.simsimi.com/request ... %3Dhi

响应举例:

{ "result": 100, "response": "Who are you?!", "id": 13185569, "msg": "OK." }

五、如何免费的使用Simsimi API

我想,大家都懂了,写这篇文章的原因就是很多人搜索小黄鸡 api到我的博客,我想大家都是要找免费的小黄鸡API。这里提供给大家一个思路:
 
合作伙伴中,有人人网,为什么?本博文前面提高某大四学生做了一个人人号,@小黄鸡之后,会自动进行回复,他使用的就是simsimi的官方正版付费API,既然人人网提供开发平台,可以对帐号进行回复,获得回复等等操作,为什么不能使用程序,登录帐号,然后@小黄鸡,然后获得它的回复,再返回给你自己的用户呢?答案当然是可以的!!!

下面贴出一段可供参考的Java代码,之所以为仅供参考,就是说只能参考思路,代码运行是运行不起来的!!!如果能够帮助到你,希望回复点评一下,并点点广告,你懂的...
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
/**
* 利用httpclient操作人人网 比如登陆,发状态,模拟你访问任何人主页等等
* @author: http://50vip.com
*
*/
public class RenRen {
private String userName = "";
private String password = "";

private static String redirectURL = "http://www.renren.com/home";
private static String renRenLoginURL = "http://www.renren.com/PLogin.do";
private static String talkUrl = "http://photo.renren.com/photo/ ... 3B%3B
private HttpResponse response;
private DefaultHttpClient httpclient = null;
private String requestToken = null;
private String _rtk = null;

public RenRen(String userName, String password) {
this.userName = userName;
this.password = password;
}

public static void main(String[] args) {
RenRen rr = null;
rr = new RenRen("xxxxx@hotmail.com", "yyyyy");
rr.login();
System.out.println(rr.talk("820"));
}
/**
* 登陆
* @author: http://50vip.com
* @return
*/
public boolean login() {
if (httpclient != null) {
return true;
}
httpclient = null;
httpclient = new DefaultHttpClient();
HttpPost httpost = new HttpPost(renRenLoginURL);
// All the parameters post to the web site
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair("origURL", redirectURL));
nvps.add(new BasicNameValuePair("domain", "renren.com"));
nvps.add(new BasicNameValuePair("autoLogin", "true"));
nvps.add(new BasicNameValuePair("formName", ""));
nvps.add(new BasicNameValuePair("method", ""));
nvps.add(new BasicNameValuePair("submit", "登录"));
nvps.add(new BasicNameValuePair("email", userName));
nvps.add(new BasicNameValuePair("password", password));
try {
httpost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
response = httpclient.execute(httpost);
//System.out.println(response);
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
httpost.abort();
}

String redirectLocation = getRedirectLocation();
if (redirectLocation != null) {
// 跳到首页,登录完成
String indexHtml=getText(redirectLocation);

//获取requestToken get_check:'-2062261917'
Pattern pattern1 = Pattern.compile("get_check:'(.*)',get_check_x");
Matcher m1 = pattern1.matcher(indexHtml);
if (m1.find()) {
requestToken=m1.group(1);
} else {
System.out.println("获取requestToken失败!");
}

//"获取_rtk失败!"get_check_x:'50d55fbd'
Pattern pattern2 = Pattern.compile("get_check_x:'(.*)',env:");
Matcher m2 = pattern2.matcher(indexHtml);
if (m2.find()) {
_rtk=m2.group(1);
} else {
System.out.println("获取_rtk失败!");
}
}
return true;
}

/**
* 和人人的小黄鸡交谈
* @author: http://50vip.com
* @param msg
* @return
*/
public String talk(String msg) {
String repMsg="";//小黄的回复

HttpPost httpost = new HttpPost(talkUrl);
// All the parameters post to the web site
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair("_rtk", _rtk));
nvps.add(new BasicNameValuePair("requestToken", requestToken));
nvps.add(new BasicNameValuePair("message", msg));

try {
ResponseHandler<String> responseHandler = new BasicResponseHandler();
httpost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
repMsg=httpclient.execute(httpost, responseHandler);
} catch (Exception e) {
e.printStackTrace();
} finally {
httpost.abort();
}
return repMsg;
}

/**
* 此处人人网会302跳转
* @author: http://50vip.com
* @return
*/
private String getRedirectLocation() {
Header locationHeader = response.getFirstHeader("Location");
if (locationHeader == null) {
return null;
}
return locationHeader.getValue();
}

/**
* 读取首页内容
* @author: http://50vip.com
* @param redirectLocation
* @return
*/
private String getText(String redirectLocation) {
HttpGet httpget = new HttpGet(redirectLocation);
// Create a response handler
ResponseHandler<String> responseHandler = new BasicResponseHandler();
String responseBody = "";
try {
responseBody = httpclient.execute(httpget, responseHandler);
} catch (Exception e) {
e.printStackTrace();
responseBody = null;
} finally {
httpget.abort();
}
return responseBody;
}
} 查看全部
一、什么是Simsimi?

simsimi公司是提供智能服务,其中一个服务是simsimi聊天机器人服务,每天有超过百万的用户聊天,国内最大的搜索引擎——百度的产品siri使用的就是simsimi提供的api。

你可以在网址http://www.simsimi.com/talk.htm# 进行体验

SimSimi inc. is specialized in collective intelligence service. All kinds of services we provide generates unique entertainment and values through systemized collective intelligence.

One of our services, a chatting robot SimSimi exceeds the limitation of technology of natural-language processing system by collective intelligence and it has a chat with over millions user per day. Our Premium knowledge providing service “Jisikman” creates millions of valuable knowledges a day.

We invite you to our realm of service which is available through our cloud of collective intelligence, Crowd Cloud that SimSimi inc. creates.

二、Simsimi小黄鸡API

在去年的这个时候,小黄鸡的非官方api一度被大家疯狂的在微信公众号上使用,一时间不知道成就了多少微信营销号,同时,华科某位大四学生利用这个api,结合人人网开发平台,制作了一个小黄鸡的人人号,@小黄鸡之后,就可以利用api自动进行回复,是的这个人人号瞬间粉丝陡增。

然而大家使用的都是非官方的API,所谓非官方,就是不是simsimi公司提供的合法使用途径,API大致的原理是利用编程语言,模拟浏览器发送post请求到http://www.simsimi.com/talk.htm# 链接,解析响应,然后作成相关的小黄鸡API。这个方法后来被我在本博客中在博文中发布,导致使用人数激增,simsimi公司似乎察觉了什么,立马对这种模拟请求的方式做出了屏蔽,一旦某ip请求数量和频率超过限制,则终端对它的请求。正式官方对非法API的封锁,也使用国内的开发这关注到之前并不出名的小i机器人,同样使用语言模拟请求web聊天界面,时间没有过很久,这个页面就加入了图片验证码防止程序模拟。

至此,两个聊天机器人都走上了收费的道路...准确的说,应该是被这帮子开发者赶上了收费的道路,因为他们给它带来了知名度。

三、SimsimiAPI使用
13845160832840.jpg

目前,小黄鸡API已经公然收费(http://developer.simsimi.com/api
不过,和之前一样,会给注册用户提供30天的试用API。
API请求链接为:
Trial-key    http://sandbox.api.simsimi.com/request.p
Paid-key    http://api.simsimi.com/request.p

API请求参数见官网。
 
API返回格式为:

result:100-ok. 400-Bad Request. 401-Unauthorized. 404-Not found. 500-Server Error.    返回的code

id:Response id. (you can get only if returning result is 100)回复的id,由系统生成,当请求成功返回时才有这个字段。 

response:Response message(you can get only if returning result is 100)返回的回复内容。

msg:Result  msg(Description of result code) 返回的code对应的含义

四、Simsimi使用举例

请求举例:

Trial-key    http://sandbox.api.simsimi.com ... %3Dhi   
Paid-key    http://api.simsimi.com/request ... %3Dhi

响应举例:

{ "result": 100, "response": "Who are you?!", "id": 13185569, "msg": "OK." }

五、如何免费的使用Simsimi API

我想,大家都懂了,写这篇文章的原因就是很多人搜索小黄鸡 api到我的博客,我想大家都是要找免费的小黄鸡API。这里提供给大家一个思路:
 
合作伙伴中,有人人网,为什么?本博文前面提高某大四学生做了一个人人号,@小黄鸡之后,会自动进行回复,他使用的就是simsimi的官方正版付费API,既然人人网提供开发平台,可以对帐号进行回复,获得回复等等操作,为什么不能使用程序,登录帐号,然后@小黄鸡,然后获得它的回复,再返回给你自己的用户呢?答案当然是可以的!!!

下面贴出一段可供参考的Java代码,之所以为仅供参考,就是说只能参考思路,代码运行是运行不起来的!!!如果能够帮助到你,希望回复点评一下,并点点广告,你懂的...
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
/**
* 利用httpclient操作人人网 比如登陆,发状态,模拟你访问任何人主页等等
* @author: http://50vip.com
*
*/
public class RenRen {
private String userName = "";
private String password = "";

private static String redirectURL = "http://www.renren.com/home";
private static String renRenLoginURL = "http://www.renren.com/PLogin.do";
private static String talkUrl = "http://photo.renren.com/photo/ ... 3B%3B
private HttpResponse response;
private DefaultHttpClient httpclient = null;
private String requestToken = null;
private String _rtk = null;

public RenRen(String userName, String password) {
this.userName = userName;
this.password = password;
}

public static void main(String[] args) {
RenRen rr = null;
rr = new RenRen("xxxxx@hotmail.com", "yyyyy");
rr.login();
System.out.println(rr.talk("820"));
}
/**
* 登陆
* @author: http://50vip.com
* @return
*/
public boolean login() {
if (httpclient != null) {
return true;
}
httpclient = null;
httpclient = new DefaultHttpClient();
HttpPost httpost = new HttpPost(renRenLoginURL);
// All the parameters post to the web site
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair("origURL", redirectURL));
nvps.add(new BasicNameValuePair("domain", "renren.com"));
nvps.add(new BasicNameValuePair("autoLogin", "true"));
nvps.add(new BasicNameValuePair("formName", ""));
nvps.add(new BasicNameValuePair("method", ""));
nvps.add(new BasicNameValuePair("submit", "登录"));
nvps.add(new BasicNameValuePair("email", userName));
nvps.add(new BasicNameValuePair("password", password));
try {
httpost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
response = httpclient.execute(httpost);
//System.out.println(response);
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
httpost.abort();
}

String redirectLocation = getRedirectLocation();
if (redirectLocation != null) {
// 跳到首页,登录完成
String indexHtml=getText(redirectLocation);

//获取requestToken get_check:'-2062261917'
Pattern pattern1 = Pattern.compile("get_check:'(.*)',get_check_x");
Matcher m1 = pattern1.matcher(indexHtml);
if (m1.find()) {
requestToken=m1.group(1);
} else {
System.out.println("获取requestToken失败!");
}

//"获取_rtk失败!"get_check_x:'50d55fbd'
Pattern pattern2 = Pattern.compile("get_check_x:'(.*)',env:");
Matcher m2 = pattern2.matcher(indexHtml);
if (m2.find()) {
_rtk=m2.group(1);
} else {
System.out.println("获取_rtk失败!");
}
}
return true;
}

/**
* 和人人的小黄鸡交谈
* @author: http://50vip.com
* @param msg
* @return
*/
public String talk(String msg) {
String repMsg="";//小黄的回复

HttpPost httpost = new HttpPost(talkUrl);
// All the parameters post to the web site
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair("_rtk", _rtk));
nvps.add(new BasicNameValuePair("requestToken", requestToken));
nvps.add(new BasicNameValuePair("message", msg));

try {
ResponseHandler<String> responseHandler = new BasicResponseHandler();
httpost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
repMsg=httpclient.execute(httpost, responseHandler);
} catch (Exception e) {
e.printStackTrace();
} finally {
httpost.abort();
}
return repMsg;
}

/**
* 此处人人网会302跳转
* @author: http://50vip.com
* @return
*/
private String getRedirectLocation() {
Header locationHeader = response.getFirstHeader("Location");
if (locationHeader == null) {
return null;
}
return locationHeader.getValue();
}

/**
* 读取首页内容
* @author: http://50vip.com
* @param redirectLocation
* @return
*/
private String getText(String redirectLocation) {
HttpGet httpget = new HttpGet(redirectLocation);
// Create a response handler
ResponseHandler<String> responseHandler = new BasicResponseHandler();
String responseBody = "";
try {
responseBody = httpclient.execute(httpget, responseHandler);
} catch (Exception e) {
e.printStackTrace();
responseBody = null;
} finally {
httpget.abort();
}
return responseBody;
}
}

使用Java给微信公众号创建自定义的菜单

编程语言atool 发表了文章 • 0 个评论 • 1318 次浏览 • 2016-04-22 12:53 • 来自相关话题

最近一段时间,微信公众平台做了很多的改进啊~

微信目前将公众帐号分成服务号和订阅号两种,之前的微信公众号默认为订阅号,不过有一次机会可以自由选择,两者之间各有优劣:

服务号每月只能推送一条消息,不过消息是显示在消息列表中,并有消息提示;订阅号每天有一条消息推送,不过消息不显示在消息列表,没有消息提示。

除此之外,目前微信公众号可以自定义菜单,下面将介绍如果使用Java作一个微信公众号的菜单,参考API可到官网查看:http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E6%8E%A5%E5%8F%A3
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import org.json.JSONObject;

public class MenuUtil {
/**
* 获得ACCESS_TOKEN
* @Title: getAccess_token
* @Description: 获得ACCESS_TOKEN
* @param @return 设定文件
* @return String 返回类型
* @throws
*/
private static String getAccess_token(){

String APPID="";
String APPSECRET="";

String url = "https://api.weixin.qq.com/cgi- ... 3B%2B APPID + "&secret=" +APPSECRET;
String accessToken = null;
try {
URL urlGet = new URL(url);
HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();

http.setRequestMethod("GET"); //必须是get方式请求
http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");//连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); //读取超时30秒

http.connect();

InputStream is =http.getInputStream();
int size =is.available();
byte[] jsonBytes =new byte[size];
is.read(jsonBytes);
String message=new String(jsonBytes,"UTF-8");

JSONObject demoJson = new JSONObject(message);
accessToken = demoJson.getString("access_token");

System.out.println(message);
} catch (Exception e) {
e.printStackTrace();
}
return accessToken;
}

/**
* 创建Menu
* @Title: createMenu
* @Description: 创建Menu
* @param @return
* @param @throws IOException 设定文件
* @return int 返回类型
* @throws
*/
public static String createMenu() {
String menu = "{\"button\":[{\"type\":\"click\",\"name\":\"MENU01\",\"key\":\"1\"},{\"type\":\"click\",\"name\":\"天气查询\",\"key\":\"西安\"},{\"name\":\"日常工作\",\"sub_button\":[{\"type\":\"click\",\"name\":\"待办工单\",\"key\":\"01_WAITING\"},{\"type\":\"click\",\"name\":\"已办工单\",\"key\":\"02_FINISH\"},{\"type\":\"click\",\"name\":\"我的工单\",\"key\":\"03_MYJOB\"},{\"type\":\"click\",\"name\":\"公告消息箱\",\"key\":\"04_MESSAGEBOX\"},{\"type\":\"click\",\"name\":\"签到\",\"key\":\"05_SIGN\"}]}]}";

//此处改为自己想要的结构体,替换即可
String access_token= getAccess_token();

String action = "https://api.weixin.qq.com/cgi- ... en%3B
try {
URL url = new URL(action);
HttpURLConnection http = (HttpURLConnection) url.openConnection();

http.setRequestMethod("POST");
http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");//连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); //读取超时30秒

http.connect();
OutputStream os= http.getOutputStream();
os.write(menu.getBytes("UTF-8"));//传入参数
os.flush();
os.close();

InputStream is =http.getInputStream();
int size =is.available();
byte[] jsonBytes =new byte[size];
is.read(jsonBytes);
String message=new String(jsonBytes,"UTF-8");
return "返回信息"+message;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "createMenu 失败";
}

/**
* 删除当前Menu
* @Title: deleteMenu
* @Description: 删除当前Menu
* @param @return 设定文件
* @return String 返回类型
* @throws
*/
public static String deleteMenu()
{
String access_token= getAccess_token();
String action = "https://api.weixin.qq.com/cgi-bin/menu/delete? access_token="+access_token;
try {
URL url = new URL(action);
HttpURLConnection http = (HttpURLConnection) url.openConnection();

http.setRequestMethod("GET");
http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");//连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); //读取超时30秒

http.connect();
OutputStream os= http.getOutputStream();
os.flush();
os.close();

InputStream is =http.getInputStream();
int size =is.available();
byte[] jsonBytes =new byte[size];
is.read(jsonBytes);
String message=new String(jsonBytes,"UTF-8");
return "deleteMenu返回信息:"+message;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "deleteMenu 失败";
}

public static void main(String[] args) {
System.out.println(createMenu());
}
}代码来源于:http://www.oschina.net/code/snippet_945711_24355 ,后续会做PHP版,并加入到自己的微信公众号上面,我的微信公众号二维码见右侧。Enjoy~ 查看全部
最近一段时间,微信公众平台做了很多的改进啊~

微信目前将公众帐号分成服务号和订阅号两种,之前的微信公众号默认为订阅号,不过有一次机会可以自由选择,两者之间各有优劣:

服务号每月只能推送一条消息,不过消息是显示在消息列表中,并有消息提示;订阅号每天有一条消息推送,不过消息不显示在消息列表,没有消息提示。

除此之外,目前微信公众号可以自定义菜单,下面将介绍如果使用Java作一个微信公众号的菜单,参考API可到官网查看:http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E6%8E%A5%E5%8F%A3
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import org.json.JSONObject;

public class MenuUtil {
/**
* 获得ACCESS_TOKEN
* @Title: getAccess_token
* @Description: 获得ACCESS_TOKEN
* @param @return 设定文件
* @return String 返回类型
* @throws
*/
private static String getAccess_token(){

String APPID="";
String APPSECRET="";

String url = "https://api.weixin.qq.com/cgi- ... 3B%2B APPID + "&secret=" +APPSECRET;
String accessToken = null;
try {
URL urlGet = new URL(url);
HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();

http.setRequestMethod("GET"); //必须是get方式请求
http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");//连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); //读取超时30秒

http.connect();

InputStream is =http.getInputStream();
int size =is.available();
byte[] jsonBytes =new byte[size];
is.read(jsonBytes);
String message=new String(jsonBytes,"UTF-8");

JSONObject demoJson = new JSONObject(message);
accessToken = demoJson.getString("access_token");

System.out.println(message);
} catch (Exception e) {
e.printStackTrace();
}
return accessToken;
}

/**
* 创建Menu
* @Title: createMenu
* @Description: 创建Menu
* @param @return
* @param @throws IOException 设定文件
* @return int 返回类型
* @throws
*/
public static String createMenu() {
String menu = "{\"button\":[{\"type\":\"click\",\"name\":\"MENU01\",\"key\":\"1\"},{\"type\":\"click\",\"name\":\"天气查询\",\"key\":\"西安\"},{\"name\":\"日常工作\",\"sub_button\":[{\"type\":\"click\",\"name\":\"待办工单\",\"key\":\"01_WAITING\"},{\"type\":\"click\",\"name\":\"已办工单\",\"key\":\"02_FINISH\"},{\"type\":\"click\",\"name\":\"我的工单\",\"key\":\"03_MYJOB\"},{\"type\":\"click\",\"name\":\"公告消息箱\",\"key\":\"04_MESSAGEBOX\"},{\"type\":\"click\",\"name\":\"签到\",\"key\":\"05_SIGN\"}]}]}";

//此处改为自己想要的结构体,替换即可
String access_token= getAccess_token();

String action = "https://api.weixin.qq.com/cgi- ... en%3B
try {
URL url = new URL(action);
HttpURLConnection http = (HttpURLConnection) url.openConnection();

http.setRequestMethod("POST");
http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");//连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); //读取超时30秒

http.connect();
OutputStream os= http.getOutputStream();
os.write(menu.getBytes("UTF-8"));//传入参数
os.flush();
os.close();

InputStream is =http.getInputStream();
int size =is.available();
byte[] jsonBytes =new byte[size];
is.read(jsonBytes);
String message=new String(jsonBytes,"UTF-8");
return "返回信息"+message;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "createMenu 失败";
}

/**
* 删除当前Menu
* @Title: deleteMenu
* @Description: 删除当前Menu
* @param @return 设定文件
* @return String 返回类型
* @throws
*/
public static String deleteMenu()
{
String access_token= getAccess_token();
String action = "https://api.weixin.qq.com/cgi-bin/menu/delete? access_token="+access_token;
try {
URL url = new URL(action);
HttpURLConnection http = (HttpURLConnection) url.openConnection();

http.setRequestMethod("GET");
http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");//连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); //读取超时30秒

http.connect();
OutputStream os= http.getOutputStream();
os.flush();
os.close();

InputStream is =http.getInputStream();
int size =is.available();
byte[] jsonBytes =new byte[size];
is.read(jsonBytes);
String message=new String(jsonBytes,"UTF-8");
return "deleteMenu返回信息:"+message;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "deleteMenu 失败";
}

public static void main(String[] args) {
System.out.println(createMenu());
}
}
代码来源于:http://www.oschina.net/code/snippet_945711_24355 ,后续会做PHP版,并加入到自己的微信公众号上面,我的微信公众号二维码见右侧。Enjoy~

Java模拟登录微信公众平台,主动推送图文消息给用户

服务端atool 发表了文章 • 0 个评论 • 1333 次浏览 • 2016-04-22 11:37 • 来自相关话题

@2013-11-25,对博文进行说明,由于2013年10月底,微信公众平台界面完全改版,所以本博文的所有代码几乎全部不能使用,不过有网友对本博的代码进行修改并授权于我共享给大家,因此大家可以去看博文《【微信公众平台改版后】Java模拟登录微信平台,主动推送消息给用户》,本博文的思路,大家也可以看看进行参考。

很早之前,在博客中发表了关于使用java开发微信公众号接口的程序代码,详细见《微信公众号消息接口开发——Java Servlet开发》,例外利用java做了小黄鸡,小i机器人的微信聊天开发,所以之前很多人问我有关于java开发微信接口的东西~

除此之外,更重要的是:很多人还问我关于微信主动推送消息给用户的问题,我所给出的所有答案都是:微信官方没有给出主动推送的api,所有采用程序记录用户微信id,然后模拟微信接口的请求数据,去请求微信接口中设置的url,这些方法都是不可行的~

不过,要实现主动推送不是不可能的,最简单的一个思路就是使用java模拟登录微信公众平台,然后推送消息消息给用户,不过这种方式有推送限制。

由于问的人比较多,决定把代码放出来,代码还未整理,里面有解析数据可以用正则表达式替换也没做,有需要的可以自己在此基础上修改。如果你觉得有用,并帮助了你,感谢你对我的赞助和支持。
public boolean msgSend(MsgForm form, MsgType type) {
try {
if (!this.isLogin) {
this._login();
}
if (this.isLogin) {
form.setToken(this.token);
PostMethod post = new PostMethod(POST_MSG);
post.setRequestHeader(USER_AGENT_H, USER_AGENT);
post.setRequestHeader(REFERER_H, INDEX_URL);
post.setRequestHeader("Cookie", this.cookiestr);
NameValuePair[] params = null;
Part[] parts = null;
switch (type) {
case TEXT:

parts = new Part[]{
new StringPart("content", form.getContent(),
"UTF-8"),
new StringPart("type", form.getType()),
new StringPart("error", form.getError()),
new StringPart("needcomment", form.getNeedcomment()),
new StringPart("groupid", form.getGroupid()),
new StringPart("sex", form.getSex()),
new StringPart("country", form.getCountry()),
new StringPart("province", form.getProvince()),
new StringPart("city", form.getCity()),
new StringPart("token", form.getToken()),
new StringPart("ajax", form.getAjax()),
new StringPart("t", "ajax-response")};
break;
case IMAGE_TEXT:
parts = new Part[]{
new StringPart("content", form.getContent(),
"UTF-8"),
new StringPart("type", form.getType()),
new StringPart("error", form.getError()),
new StringPart("needcomment", form.getNeedcomment()),
new StringPart("groupid", form.getGroupid()),
new StringPart("sex", form.getSex()),
new StringPart("country", form.getCountry()),
new StringPart("province", form.getProvince()),
new StringPart("city", form.getCity()),
new StringPart("token", form.getToken()),
new StringPart("ajax", form.getAjax()),
new StringPart("t", "ajax-response")};
break;
default:
parts = new Part[]{
new StringPart("content", form.getContent(),
"UTF-8"),
new StringPart("type", form.getType()),
new StringPart("error", form.getError()),
new StringPart("needcomment", form.getNeedcomment()),
new StringPart("groupid", form.getGroupid()),
new StringPart("sex", form.getSex()),
new StringPart("country", form.getCountry()),
new StringPart("province", form.getProvince()),
new StringPart("city", form.getCity()),
new StringPart("token", form.getToken()),
new StringPart("ajax", form.getAjax()),
new StringPart("t", "ajax-response")};
break;
}
RequestEntity entity = new MultipartRequestEntity(parts,
post.getParams());
post.setRequestEntity(entity);
int status;
status = client.executeMethod(post);
if (status == HttpStatus.SC_OK) {
String text = post.getResponseBodyAsString();
try {
MsgJson ret = JSON.parseObject(text, MsgJson.class);
this.msgSendCode = ret.getRet();
switch (this.msgSendCode) {
case 0:
this.msgSendMsg = "发送成功";
return true;
case -2:
this.msgSendMsg = "参数错误,请仔细检查";
return false;
case 64004:
this.msgSendMsg = "今天的群发数量已到,无法群发";
return false;
case -20000:
this.msgSendMsg = "请求被禁止,请仔细检查token是否合法";
return false;
default:
this.msgSendMsg = "未知错误!";
return false;
}
} catch (Exception e) {
String info = "【群发信息失败】【解析json错误】" + e.getMessage()
+ "
【文本:】
" + text;
System.err.println(info);
log.debug(info);
log.info(info);
return false;
}
}
}
} catch (Exception e) {
String info = "【群发信息失败】" + e.getMessage();
System.err.println(info);
log.debug(info);
log.info(info);
return false;
}
return false;
} 查看全部
@2013-11-25,对博文进行说明,由于2013年10月底,微信公众平台界面完全改版,所以本博文的所有代码几乎全部不能使用,不过有网友对本博的代码进行修改并授权于我共享给大家,因此大家可以去看博文《【微信公众平台改版后】Java模拟登录微信平台,主动推送消息给用户》,本博文的思路,大家也可以看看进行参考。

很早之前,在博客中发表了关于使用java开发微信公众号接口的程序代码,详细见《微信公众号消息接口开发——Java Servlet开发》,例外利用java做了小黄鸡,小i机器人的微信聊天开发,所以之前很多人问我有关于java开发微信接口的东西~

除此之外,更重要的是:很多人还问我关于微信主动推送消息给用户的问题,我所给出的所有答案都是:微信官方没有给出主动推送的api,所有采用程序记录用户微信id,然后模拟微信接口的请求数据,去请求微信接口中设置的url,这些方法都是不可行的~

不过,要实现主动推送不是不可能的,最简单的一个思路就是使用java模拟登录微信公众平台,然后推送消息消息给用户,不过这种方式有推送限制。

由于问的人比较多,决定把代码放出来,代码还未整理,里面有解析数据可以用正则表达式替换也没做,有需要的可以自己在此基础上修改。如果你觉得有用,并帮助了你,感谢你对我的赞助和支持。
public boolean msgSend(MsgForm form, MsgType type) {
try {
if (!this.isLogin) {
this._login();
}
if (this.isLogin) {
form.setToken(this.token);
PostMethod post = new PostMethod(POST_MSG);
post.setRequestHeader(USER_AGENT_H, USER_AGENT);
post.setRequestHeader(REFERER_H, INDEX_URL);
post.setRequestHeader("Cookie", this.cookiestr);
NameValuePair[] params = null;
Part[] parts = null;
switch (type) {
case TEXT:

parts = new Part[]{
new StringPart("content", form.getContent(),
"UTF-8"),
new StringPart("type", form.getType()),
new StringPart("error", form.getError()),
new StringPart("needcomment", form.getNeedcomment()),
new StringPart("groupid", form.getGroupid()),
new StringPart("sex", form.getSex()),
new StringPart("country", form.getCountry()),
new StringPart("province", form.getProvince()),
new StringPart("city", form.getCity()),
new StringPart("token", form.getToken()),
new StringPart("ajax", form.getAjax()),
new StringPart("t", "ajax-response")};
break;
case IMAGE_TEXT:
parts = new Part[]{
new StringPart("content", form.getContent(),
"UTF-8"),
new StringPart("type", form.getType()),
new StringPart("error", form.getError()),
new StringPart("needcomment", form.getNeedcomment()),
new StringPart("groupid", form.getGroupid()),
new StringPart("sex", form.getSex()),
new StringPart("country", form.getCountry()),
new StringPart("province", form.getProvince()),
new StringPart("city", form.getCity()),
new StringPart("token", form.getToken()),
new StringPart("ajax", form.getAjax()),
new StringPart("t", "ajax-response")};
break;
default:
parts = new Part[]{
new StringPart("content", form.getContent(),
"UTF-8"),
new StringPart("type", form.getType()),
new StringPart("error", form.getError()),
new StringPart("needcomment", form.getNeedcomment()),
new StringPart("groupid", form.getGroupid()),
new StringPart("sex", form.getSex()),
new StringPart("country", form.getCountry()),
new StringPart("province", form.getProvince()),
new StringPart("city", form.getCity()),
new StringPart("token", form.getToken()),
new StringPart("ajax", form.getAjax()),
new StringPart("t", "ajax-response")};
break;
}
RequestEntity entity = new MultipartRequestEntity(parts,
post.getParams());
post.setRequestEntity(entity);
int status;
status = client.executeMethod(post);
if (status == HttpStatus.SC_OK) {
String text = post.getResponseBodyAsString();
try {
MsgJson ret = JSON.parseObject(text, MsgJson.class);
this.msgSendCode = ret.getRet();
switch (this.msgSendCode) {
case 0:
this.msgSendMsg = "发送成功";
return true;
case -2:
this.msgSendMsg = "参数错误,请仔细检查";
return false;
case 64004:
this.msgSendMsg = "今天的群发数量已到,无法群发";
return false;
case -20000:
this.msgSendMsg = "请求被禁止,请仔细检查token是否合法";
return false;
default:
this.msgSendMsg = "未知错误!";
return false;
}
} catch (Exception e) {
String info = "【群发信息失败】【解析json错误】" + e.getMessage()
+ "
【文本:】
" + text;
System.err.println(info);
log.debug(info);
log.info(info);
return false;
}
}
}
} catch (Exception e) {
String info = "【群发信息失败】" + e.getMessage();
System.err.println(info);
log.debug(info);
log.info(info);
return false;
}
return false;
}

dom4j解析创建Xml:org.dom4j.DocumentException: 2字节的UTF-8序列的2无效

编程语言atool 发表了文章 • 0 个评论 • 2217 次浏览 • 2016-04-22 11:26 • 来自相关话题

最近刚刚做完Java版Dota改键软件KeyHelper的界面配置操作,配置信息保存到xml中,采用dom4j进行解析和创建,基本做的差不多,并导出为jar自己在使用测试。

在Eclipse中运行时没有任何异常和错误,但是导出jar包之后使用start java -jar keyHelper.jar运行的时候,报异常:org.dom4j.DocumentException: 2字节的UTF-8序列的2无效...后面是一大串错误stack信息。

搜索了一下,网上关于dom4j解析xml汉字乱码问题一大堆,其中解决办法基本没有,大都是在网上发发问题,但是没有人解决,只有一个提到说将xml的编码改成为GBK或者GB2312,这个测试了,基本上是可行的,但是一般的软件开发都是采用UTF-8,将配置换成其他编码,会导致软件界面上是乱码,所以这个解决办法其实有一点鸡肋。自己尝试过在创建保存xml的时候,利用构造的domcument,调用asXml()方法得到document的string字符串,然后采用java io利用utf-8编码写入文件中,但是到读取的时候依然会报错。

再三折腾之下,发现了一个既不用修改xml编码,又可以解决这个中文解析的异常,贴出我的解析的创建xml的代码。

一、解析Config.xml配置信息
private void loadFromXml() {
try {
AXReader reader = new SAXReader();
File file = new File(CONFIG_FILE);
Document document = reader.read(new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8")));// 读取XML文件
Element xmlRoot = document.getRootElement();// 得到根节点
lastKeySet = xmlRoot.elementText("lastKeySet");
lastLocationX = Integer.valueOf(xmlRoot.elementText("lastLocationX"));
lastLocationY = Integer.valueOf(xmlRoot.elementText("lastLocationY"));
} catch (Exception e) {
e.printStackTrace();
lastKeySet = "";//上次选择的改键方案
lastLocationX = 500;//上次窗口位置
lastLocationY = 100;//上次窗口位置
}
}其中代码:Document document = reader.read(newBufferedReader(newInputStreamReader(newFileInputStream(file), "UTF-8")));是关键。

二、创建Config.xml配置信息
public void saveToXml() {
/** 建立document对象 */
Document document = DocumentHelper.createDocument();
/** 建立config根节点 */
Element configElement = document.addElement("config");
configElement.addElement("lastKeySet").setText(lastKeySet);
configElement.addElement("lastLocationX").setText(lastLocationX + "");
configElement.addElement("lastLocationY").setText(lastLocationY + "");
try{
/* 将document中的内容写入文件中 */
OutputFormat format = new OutputFormat();
format.setEncoding("UTF-8");
XMLWriter writer = new XMLWriter(new FileOutputStream(new File(CONFIG_FILE)), format);
writer.write(document);
writer.close();
} catch(Exception ex) {
ex.printStackTrace();
}
}其中代码:OutputFormat format = newOutputFormat();
format.setEncoding("UTF-8");
XMLWriter writer = newXMLWriter(newFileOutputStream(newFile(CONFIG_FILE)), format);是关键,请务必按照这个写法进行。具体为什么,我自己也不知道,唉~
Enjoy~ 查看全部
最近刚刚做完Java版Dota改键软件KeyHelper的界面配置操作,配置信息保存到xml中,采用dom4j进行解析和创建,基本做的差不多,并导出为jar自己在使用测试。

在Eclipse中运行时没有任何异常和错误,但是导出jar包之后使用start java -jar keyHelper.jar运行的时候,报异常:org.dom4j.DocumentException: 2字节的UTF-8序列的2无效...后面是一大串错误stack信息。

搜索了一下,网上关于dom4j解析xml汉字乱码问题一大堆,其中解决办法基本没有,大都是在网上发发问题,但是没有人解决,只有一个提到说将xml的编码改成为GBK或者GB2312,这个测试了,基本上是可行的,但是一般的软件开发都是采用UTF-8,将配置换成其他编码,会导致软件界面上是乱码,所以这个解决办法其实有一点鸡肋。自己尝试过在创建保存xml的时候,利用构造的domcument,调用asXml()方法得到document的string字符串,然后采用java io利用utf-8编码写入文件中,但是到读取的时候依然会报错。

再三折腾之下,发现了一个既不用修改xml编码,又可以解决这个中文解析的异常,贴出我的解析的创建xml的代码。

一、解析Config.xml配置信息
private void loadFromXml() {
try {
AXReader reader = new SAXReader();
File file = new File(CONFIG_FILE);
Document document = reader.read(new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8")));// 读取XML文件
Element xmlRoot = document.getRootElement();// 得到根节点
lastKeySet = xmlRoot.elementText("lastKeySet");
lastLocationX = Integer.valueOf(xmlRoot.elementText("lastLocationX"));
lastLocationY = Integer.valueOf(xmlRoot.elementText("lastLocationY"));
} catch (Exception e) {
e.printStackTrace();
lastKeySet = "";//上次选择的改键方案
lastLocationX = 500;//上次窗口位置
lastLocationY = 100;//上次窗口位置
}
}
其中代码:Document document = reader.read(newBufferedReader(newInputStreamReader(newFileInputStream(file), "UTF-8")));是关键。

二、创建Config.xml配置信息
public void saveToXml() {
/** 建立document对象 */
Document document = DocumentHelper.createDocument();
/** 建立config根节点 */
Element configElement = document.addElement("config");
configElement.addElement("lastKeySet").setText(lastKeySet);
configElement.addElement("lastLocationX").setText(lastLocationX + "");
configElement.addElement("lastLocationY").setText(lastLocationY + "");
try{
/* 将document中的内容写入文件中 */
OutputFormat format = new OutputFormat();
format.setEncoding("UTF-8");
XMLWriter writer = new XMLWriter(new FileOutputStream(new File(CONFIG_FILE)), format);
writer.write(document);
writer.close();
} catch(Exception ex) {
ex.printStackTrace();
}
}
其中代码:
OutputFormat format = newOutputFormat();
format.setEncoding("UTF-8");
XMLWriter writer = newXMLWriter(newFileOutputStream(newFile(CONFIG_FILE)), format);
是关键,请务必按照这个写法进行。具体为什么,我自己也不知道,唉~
Enjoy~

【错误】新浪SinaSAE 上传Java WAR包出现is not a javax.servlet.Filter

云计算atool 发表了文章 • 0 个评论 • 1199 次浏览 • 2016-04-22 11:22 • 来自相关话题

使用Java Web做了一个签到系统,使用的是Struts2 + ExtJs4 + BoneCP + Mysql。

准备部署到Sina SAE上面,之前部署微信公众号开发的的Java程序一点问题都没有,但是部署这个应用问题一堆。不过之前的应用使用的是Servlet,没有使用任何框架。

先说一个部署问题,大致是将war包上传之后,在SAE中的日志系统中的JVM日志有以下错误:

java.lang.IllegalStateException: class com.cxl.signin.filter.AuthFilter is not a javax.servlet.Filter

然后输入二级域名,发现前台显示也是报错的:

Error 404 - Not Found.No context on this server matched or handled this request.
Contexts known to this server are:...(后面是关于个人应用的一些乱鸡巴遭的东西)

最终在一个英文的讨论论坛找到了一个相关的回答:
My top-of-the-brain guess would be that you have two servlet JARs in your classpath, and jetty is using one but your WAR is using another.
Really weird error though, for sure.

大致意思是那哥们看到这个问题,第一感觉就是项目classpath里面有两个servlet jar包,服务器jetty使用一个,你的war包使用的另一个。

我想应该是sina的服务器classpath里面就有了servlet-api.jar包了,于是我删掉了web-INF/lib下面的这个包,上传,不报错,首页可以打开。我的二级域名为sign.sinaapp.com/login.jsp,大家测试。

另外还有一个需要注意的是:请不要用jre7的版本去编译你的项目...

除此之外,项目还有其他的问题,就是session问题,我Java开的是4个虚拟机,登陆的时候明明已经运行到登陆成功,session写入的那一步,然后该进入主界面了,但后面被登陆验证的过滤器拦截,得不到登陆时写入session,判定为没有登录,返回登陆页面.

有部署过类似Java项目到SAE上的同学帮个忙啊~~~ 查看全部
使用Java Web做了一个签到系统,使用的是Struts2 + ExtJs4 + BoneCP + Mysql。

准备部署到Sina SAE上面,之前部署微信公众号开发的的Java程序一点问题都没有,但是部署这个应用问题一堆。不过之前的应用使用的是Servlet,没有使用任何框架。

先说一个部署问题,大致是将war包上传之后,在SAE中的日志系统中的JVM日志有以下错误:

java.lang.IllegalStateException: class com.cxl.signin.filter.AuthFilter is not a javax.servlet.Filter

然后输入二级域名,发现前台显示也是报错的:

Error 404 - Not Found.No context on this server matched or handled this request.
Contexts known to this server are:...(后面是关于个人应用的一些乱鸡巴遭的东西)

最终在一个英文的讨论论坛找到了一个相关的回答:
My top-of-the-brain guess would be that you have two servlet JARs in your classpath, and jetty is using one but your WAR is using another.
Really weird error though, for sure.

大致意思是那哥们看到这个问题,第一感觉就是项目classpath里面有两个servlet jar包,服务器jetty使用一个,你的war包使用的另一个。

我想应该是sina的服务器classpath里面就有了servlet-api.jar包了,于是我删掉了web-INF/lib下面的这个包,上传,不报错,首页可以打开。我的二级域名为sign.sinaapp.com/login.jsp,大家测试。

另外还有一个需要注意的是:请不要用jre7的版本去编译你的项目...

除此之外,项目还有其他的问题,就是session问题,我Java开的是4个虚拟机,登陆的时候明明已经运行到登陆成功,session写入的那一步,然后该进入主界面了,但后面被登陆验证的过滤器拦截,得不到登陆时写入session,判定为没有登录,返回登陆页面.

有部署过类似Java项目到SAE上的同学帮个忙啊~~~

使用Java JMF技术编写视频播放器

图像/多媒体atool 发表了文章 • 0 个评论 • 698 次浏览 • 2016-04-22 11:21 • 来自相关话题

Java JMF意为Java媒体框架(JMF)。该核心框架支持不同媒体(如:音频输出和视频输出)间的时钟同步。它是一个标准的扩展框架,允许用户制作纯音频流和视频流。
下面的代码展示的是利用JMF和Java Swing编写的一个简单的视频播放器,因此运行这段代码,首先请安装JMF,安装地址,自己百度Google,完整代码如下:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.media.CannotRealizeException;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.EndOfMediaEvent;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.NoPlayerException;
import javax.media.Player;
import javax.media.PrefetchCompleteEvent;
import javax.media.RealizeCompleteEvent;
import javax.media.Time;
@SuppressWarnings({ "restriction", "unused" })
public class JMFSample implements ControllerListener {
public static void main(String[] args) {
JMFSample sp = new JMFSample();
sp.play();
}

private Player mediaPlayer;
private Frame f;
private Player player;
private Panel panel;
private Component visual;
private Component control = null;

public void play(){
f = new Frame("JMF Sample1");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
if(player != null) {
player.close();
}
System.exit(0);
}
});
f.setSize(500,400);
f.setVisible(true);
URL url = null;
try {
//准备一个要播放的视频文件的URL
url = new URL("file:/d:/2.mpg");
} catch (MalformedURLException e) {
e.printStackTrace();
}
try {
//通过调用Manager的createPlayer方法来创建一个Player的对象
//这个对象是媒体播放的核心控制对象
player = Manager.createPlayer(url);
} catch (NoPlayerException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
//对player对象注册监听器,能噶偶在相关事件发生的时候执行相关的动作
player.addControllerListener(this);

//让player对象进行相关的资源分配
player.realize();
}

private int videoWidth = 0;
private int videoHeight = 0;
private int controlHeight = 30;
private int insetWidth = 10;
private int insetHeight = 30;

//监听player的相关事件
public void controllerUpdate(ControllerEvent ce) {
if (ce instanceof RealizeCompleteEvent) {
//player实例化完成后进行player播放前预处理
player.prefetch();
} else if (ce instanceof PrefetchCompleteEvent) {
if (visual != null)
return;
//取得player中的播放视频的组件,并得到视频窗口的大小
//然后把视频窗口的组件添加到Frame窗口中,
if ((visual = player.getVisualComponent()) != null) {
Dimension size = visual.getPreferredSize();
videoWidth = size.width;
videoHeight = size.height;
f.add(visual);
} else {
videoWidth = 320;
}

//取得player中的视频播放控制条组件,并把该组件添加到Frame窗口中
if ((control = player.getControlPanelComponent()) != null) {
controlHeight = control.getPreferredSize().height;
f.add(control, BorderLayout.SOUTH);
}

//设定Frame窗口的大小,使得满足视频文件的默认大小
f.setSize(videoWidth + insetWidth, videoHeight + controlHeight + insetHeight);
f.validate();

//启动视频播放组件开始播放
player.start();
mediaPlayer.start();
} else if (ce instanceof EndOfMediaEvent) {
//当播放视频完成后,把时间进度条恢复到开始,并再次重新开始播放
player.setMediaTime(new Time(0));
player.start();
}
}
}JMF是专门用于做Java多媒体开发的。对于视频播放就是支持的格式少了一些,这个视频播放器可以播放mpg,avi,flv等等,想播放其他的请开发自己的插件。另外需要注明的是,有些不规范的avi格式的视频播放可能也会有问题。
下图是基于JMF和FFMPEG做的视频播放以及车牌识别定位的截图: 查看全部
Java JMF意为Java媒体框架(JMF)。该核心框架支持不同媒体(如:音频输出和视频输出)间的时钟同步。它是一个标准的扩展框架,允许用户制作纯音频流和视频流。
下面的代码展示的是利用JMF和Java Swing编写的一个简单的视频播放器,因此运行这段代码,首先请安装JMF,安装地址,自己百度Google,完整代码如下:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.media.CannotRealizeException;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.EndOfMediaEvent;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.NoPlayerException;
import javax.media.Player;
import javax.media.PrefetchCompleteEvent;
import javax.media.RealizeCompleteEvent;
import javax.media.Time;
@SuppressWarnings({ "restriction", "unused" })
public class JMFSample implements ControllerListener {
public static void main(String[] args) {
JMFSample sp = new JMFSample();
sp.play();
}

private Player mediaPlayer;
private Frame f;
private Player player;
private Panel panel;
private Component visual;
private Component control = null;

public void play(){
f = new Frame("JMF Sample1");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
if(player != null) {
player.close();
}
System.exit(0);
}
});
f.setSize(500,400);
f.setVisible(true);
URL url = null;
try {
//准备一个要播放的视频文件的URL
url = new URL("file:/d:/2.mpg");
} catch (MalformedURLException e) {
e.printStackTrace();
}
try {
//通过调用Manager的createPlayer方法来创建一个Player的对象
//这个对象是媒体播放的核心控制对象
player = Manager.createPlayer(url);
} catch (NoPlayerException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
//对player对象注册监听器,能噶偶在相关事件发生的时候执行相关的动作
player.addControllerListener(this);

//让player对象进行相关的资源分配
player.realize();
}

private int videoWidth = 0;
private int videoHeight = 0;
private int controlHeight = 30;
private int insetWidth = 10;
private int insetHeight = 30;

//监听player的相关事件
public void controllerUpdate(ControllerEvent ce) {
if (ce instanceof RealizeCompleteEvent) {
//player实例化完成后进行player播放前预处理
player.prefetch();
} else if (ce instanceof PrefetchCompleteEvent) {
if (visual != null)
return;
//取得player中的播放视频的组件,并得到视频窗口的大小
//然后把视频窗口的组件添加到Frame窗口中,
if ((visual = player.getVisualComponent()) != null) {
Dimension size = visual.getPreferredSize();
videoWidth = size.width;
videoHeight = size.height;
f.add(visual);
} else {
videoWidth = 320;
}

//取得player中的视频播放控制条组件,并把该组件添加到Frame窗口中
if ((control = player.getControlPanelComponent()) != null) {
controlHeight = control.getPreferredSize().height;
f.add(control, BorderLayout.SOUTH);
}

//设定Frame窗口的大小,使得满足视频文件的默认大小
f.setSize(videoWidth + insetWidth, videoHeight + controlHeight + insetHeight);
f.validate();

//启动视频播放组件开始播放
player.start();
mediaPlayer.start();
} else if (ce instanceof EndOfMediaEvent) {
//当播放视频完成后,把时间进度条恢复到开始,并再次重新开始播放
player.setMediaTime(new Time(0));
player.start();
}
}
}
JMF是专门用于做Java多媒体开发的。对于视频播放就是支持的格式少了一些,这个视频播放器可以播放mpg,avi,flv等等,想播放其他的请开发自己的插件。另外需要注明的是,有些不规范的avi格式的视频播放可能也会有问题。
下图是基于JMF和FFMPEG做的视频播放以及车牌识别定位的截图:
13659471585430.jpg

Java中java.util.PriorityQueue优先级队列使用方法

编程语言atool 发表了文章 • 0 个评论 • 463 次浏览 • 2016-04-22 11:10 • 来自相关话题

PriorityQueue是个基于优先级堆的极大优先级队列。
此队列按照在构造时所指定的顺序对元素排序,既可以根据元素的自然顺序来指定排序(参阅 Comparable),也可以根据 Comparator 来指定,这取决于使用哪种构造方法。优先级队列不允许 null 元素。依靠自然排序的优先级队列还不允许插入不可比较的对象(这样做可能导致 ClassCastException)。比如队列 1 3 5 10 2 自动会被排列 1 2 3 5 10。测试代码如下:
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;

public class PriorityQueueExample {
public static void main(String[] args) {
Queue<Integer> qi = new PriorityQueue<Integer>();

qi.add(5);
qi.add(2);
qi.add(1);
qi.add(10);
qi.add(3);

while (!qi.isEmpty()){
System.out.print(qi.poll() + ",");
}
System.out.println();
System.out.println("-----------------------------");
//自定义比较器
Comparator<Integer> cmp;
cmp = new Comparator<Integer>() {
public int compare(Integer e1, Integer e2) {
return e2 - e1;
}
};
Queue<Integer> q2 = new PriorityQueue<Integer>(5,cmp);
q2.add(2);
q2.add(8);
q2.add(9);
q2.add(1);
while (!q2.isEmpty()){
System.out.print(q2.poll() + ",");
}
}
}输出结果如下:
output

1,2,3,5,10,
-----------------------------
9,8,2,1,

代码中的自定义的比较器,可以让我们自由定义比较的顺序:
//自定义比较器
Comparator<Integer> cmp;
cmp = new Comparator<Integer>() {
public int compare(Integer e1, Integer e2) {
return e2 - e1;
}
};

此队列的头是按指定排序方式的最小元素。如果多个元素都是最小值,则头是其中一个元素——选择方法是任意的。队列检索操作 poll、remove、peek 和 element 访问处于队列头的元素。优先级队列是无界的,但是有一个内部容量,控制着用于存储队列元素的数组的大小。它总是至少与队列的大小相同。随着不断向优先级队列添加元素,其容量会自动增加。无需指定容量增加策略的细节。

注意1:该队列是用数组实现,但是数组大小可以动态增加,容量无限。

注意2:此实现不是同步的。不是线程安全的。如果多个线程中的任意线程从结构上修改了列表, 则这些线程不应同时访问 PriorityQueue。实例,这时请使用线程安全的PriorityBlockingQueue 类。

注意3:不允许使用 null 元素。

注意4:此实现为插入方法(offer、poll、remove() 和 add 方法)提供 O(log(n)) 时间;为 remove(Object) 和 contains(Object)方法提供线性时间;为检索方法(peek、element 和 size)提供固定时间。

注意5:方法iterator()中提供的迭代器并不保证以有序的方式遍历优先级队列中的元素。至于原因可参考下面关于PriorityQueue的内部实现如果需要按顺序遍历,请考虑使用 Arrays.sort(pq.toArray())。

注意6:可以在构造函数中指定如何排序。如:PriorityQueue()使用默认的初始容量(11)创建一个 PriorityQueue,并根据其自然顺序来排序其元素(使用 Comparable)。PriorityQueue(int initialCapacity)使用指定的初始容量创建一个 PriorityQueue,并根据其自然顺序来排序其元素(使用 Comparable)。PriorityQueue(int initialCapacity, Comparator comparator)。使用指定的初始容量创建一个PriorityQueue,并根据指定的比较器comparator来排序其元素。

注意7:此类及其迭代器实现了 Collection 和 Iterator 接口的所有可选 方法。PriorityQueue的内部实现。PriorityQueue对元素采用的是堆排序,头是按指定排序方式的最小元素。堆排序只能保证根是最大(最小),整个堆并不是有序的。方法iterator()中提供的迭代器可能只是对整个数组的依次遍历。也就只能保证数组的第一个元素是最小的。实例1的结果也正好与此相符。 查看全部
PriorityQueue是个基于优先级堆的极大优先级队列。
此队列按照在构造时所指定的顺序对元素排序,既可以根据元素的自然顺序来指定排序(参阅 Comparable),也可以根据 Comparator 来指定,这取决于使用哪种构造方法。优先级队列不允许 null 元素。依靠自然排序的优先级队列还不允许插入不可比较的对象(这样做可能导致 ClassCastException)。比如队列 1 3 5 10 2 自动会被排列 1 2 3 5 10。测试代码如下:
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;

public class PriorityQueueExample {
public static void main(String[] args) {
Queue<Integer> qi = new PriorityQueue<Integer>();

qi.add(5);
qi.add(2);
qi.add(1);
qi.add(10);
qi.add(3);

while (!qi.isEmpty()){
System.out.print(qi.poll() + ",");
}
System.out.println();
System.out.println("-----------------------------");
//自定义比较器
Comparator<Integer> cmp;
cmp = new Comparator<Integer>() {
public int compare(Integer e1, Integer e2) {
return e2 - e1;
}
};
Queue<Integer> q2 = new PriorityQueue<Integer>(5,cmp);
q2.add(2);
q2.add(8);
q2.add(9);
q2.add(1);
while (!q2.isEmpty()){
System.out.print(q2.poll() + ",");
}
}
}
输出结果如下:
output

1,2,3,5,10,
-----------------------------
9,8,2,1,

代码中的自定义的比较器,可以让我们自由定义比较的顺序:
//自定义比较器
Comparator<Integer> cmp;
cmp = new Comparator<Integer>() {
public int compare(Integer e1, Integer e2) {
return e2 - e1;
}
};

此队列的头是按指定排序方式的最小元素。如果多个元素都是最小值,则头是其中一个元素——选择方法是任意的。队列检索操作 poll、remove、peek 和 element 访问处于队列头的元素。优先级队列是无界的,但是有一个内部容量,控制着用于存储队列元素的数组的大小。它总是至少与队列的大小相同。随着不断向优先级队列添加元素,其容量会自动增加。无需指定容量增加策略的细节。

注意1:该队列是用数组实现,但是数组大小可以动态增加,容量无限。

注意2:此实现不是同步的。不是线程安全的。如果多个线程中的任意线程从结构上修改了列表, 则这些线程不应同时访问 PriorityQueue。实例,这时请使用线程安全的PriorityBlockingQueue 类。

注意3:不允许使用 null 元素。

注意4:此实现为插入方法(offer、poll、remove() 和 add 方法)提供 O(log(n)) 时间;为 remove(Object) 和 contains(Object)方法提供线性时间;为检索方法(peek、element 和 size)提供固定时间。

注意5:方法iterator()中提供的迭代器并不保证以有序的方式遍历优先级队列中的元素。至于原因可参考下面关于PriorityQueue的内部实现如果需要按顺序遍历,请考虑使用 Arrays.sort(pq.toArray())。

注意6:可以在构造函数中指定如何排序。如:PriorityQueue()使用默认的初始容量(11)创建一个 PriorityQueue,并根据其自然顺序来排序其元素(使用 Comparable)。PriorityQueue(int initialCapacity)使用指定的初始容量创建一个 PriorityQueue,并根据其自然顺序来排序其元素(使用 Comparable)。PriorityQueue(int initialCapacity, Comparator comparator)。使用指定的初始容量创建一个PriorityQueue,并根据指定的比较器comparator来排序其元素。

注意7:此类及其迭代器实现了 Collection 和 Iterator 接口的所有可选 方法。PriorityQueue的内部实现。PriorityQueue对元素采用的是堆排序,头是按指定排序方式的最小元素。堆排序只能保证根是最大(最小),整个堆并不是有序的。方法iterator()中提供的迭代器可能只是对整个数组的依次遍历。也就只能保证数组的第一个元素是最小的。实例1的结果也正好与此相符。

Java元组Tuple使用实例

编程语言atool 发表了文章 • 0 个评论 • 2228 次浏览 • 2016-04-22 11:07 • 来自相关话题

一、为什么使用元组tuple?
元组和列表list一样,都可能用于数据存储,包含多个数据;但是和列表不同的是:列表只能存储相同的数据类型,而元组不一样,它可以存储不同的数据类型,比如同时存储int、string、list等,并且可以根据需求无限扩展。
比如说在web应用中,经常会遇到一个问题就是数据分页问题,查询分页需要包含几点信息:当前页数、页大小;查询结果返回数据为:当前页的数据记录,但是如果需要在前台显示当前页、页大小、总页数等信息的时候,就必须有另外一个信息就是:数据记录总数,然后根据上面的信息进行计算得到总页数等信息。这个时候查询某一页信息的时候需要返回两个数据类型,一个是list(当前也的数据记录),一个是int(记录总数)。当然,完全可以在两个方法、两次数据库连接中得到这两个值。事实上在查询list的时候,已经通过sql查询得到总计录数,如果再开一个方法,再做一次数据库连接来查询总计录数,不免有点多此一举、浪费时间、浪费代码、浪费生命。言重了~在这种情况下,我们就可以利用二元组,在一次数据库连接中,得到总计录数、当前页记录,并存储到其中,简单明了!

二、源码实例
二元组:
/** <p>Title: TwoTuple</p>
* <p>Description: 两个元素的元组,用于在一个方法里返回两种类型的值</p>
* @author Xewee.Zhiwei.Wang@gmail.com
* @site http://wzwahl36.net
* @version 2012-3-21 上午11:15:03
* @param <A>
* @param <B>
*/
public class TwoTuple<A, B> {
public final A first;
public final B second;

public TwoTuple(A a, B b) {
this.first = a;
this.second = b;
}
}扩展为三元组(按此可以任意扩展)
/**
* <p>Title: ThreeTuple</p>
* <p>Description: 三个元素的元组,用于在一个方法里返回三种类型的值</p>
* @author Xewee.Zhiwei.Wang@gmail.com
* @site http://wzwahl36.net
* @version 2012-3-21 上午11:15:50
* @param <A>
* @param <B>
* @param <C>
*/
public class ThreeTuple<A, B, C> extends TwoTuple<A, B> {
public final C third;

public ThreeTuple(A a, B b, C c) {
super(a, b);
this.third = c;
}
}元组操作工具类、测试类(可按需自定义)

import java.util.ArrayList;
import java.util.List;
 
import com.bluesea.bean.GoodsBean;
 
/**
 * <p>Title: TupleUtil</p>
 * <p>Description:
 * 元组辅助类,用于多种类型值的返回,如在分页的时候,后台存储过程既返回了查询得到的
 * 当页的数据(List类型),又得到了数据表中总共的数据总数(Integer类型),然后将这
 * 两个参数封装到该类中返回到action中使用
 * 使用泛型方法实现,利用参数类型推断,编译器可以找出具体的类型
 * </p>
 * @author Xewee.Zhiwei.Wang@gmail.com
 * @site http://wzwahl36.net
 * @version 2012-3-21 上午09:59:39
 * @param <A>
 * @param <B>
 */
public class TupleUtil {
     
    public static <A, B> TwoTuple<A, B> tuple(A a, B b) {
        return new TwoTuple<A, B>(a, b);
    }
     
    public static <A, B, C> ThreeTuple<A, B, C> tuple(A a, B b, C c) {
        return new ThreeTuple<A, B, C>(a, b, c);
    }
 
    // 测试
    public static void main(String[] args) {
        List<GoodsBean> goodsBeans = new ArrayList<GoodsBean>();
        for(int i = 1; i < 26; i++) {
            GoodsBean goodsBean = new GoodsBean();
            goodsBean.setGoodsId(i);
            goodsBeans.add(goodsBean);
        }
        Integer totalProperty = 47;
//      TupleUtil<List<GoodsBean>, Integer> tupleUtil = new TupleUtil<List<GoodsBean>, Integer>(goodsBeans, totalProperty);
        TwoTuple<List<GoodsBean>, Integer> twoTuple = TupleUtil.tuple(goodsBeans, totalProperty);
        List<GoodsBean> list = twoTuple.first;
        System.out.println(list);
        System.out.println(twoTuple.second);
    }
}
三、Demo下载
搬到SAE上之后,链接丢失,Demo为以上几个文件打包,请自行处理。 查看全部
一、为什么使用元组tuple?
元组和列表list一样,都可能用于数据存储,包含多个数据;但是和列表不同的是:列表只能存储相同的数据类型,而元组不一样,它可以存储不同的数据类型,比如同时存储int、string、list等,并且可以根据需求无限扩展。
比如说在web应用中,经常会遇到一个问题就是数据分页问题,查询分页需要包含几点信息:当前页数、页大小;查询结果返回数据为:当前页的数据记录,但是如果需要在前台显示当前页、页大小、总页数等信息的时候,就必须有另外一个信息就是:数据记录总数,然后根据上面的信息进行计算得到总页数等信息。这个时候查询某一页信息的时候需要返回两个数据类型,一个是list(当前也的数据记录),一个是int(记录总数)。当然,完全可以在两个方法、两次数据库连接中得到这两个值。事实上在查询list的时候,已经通过sql查询得到总计录数,如果再开一个方法,再做一次数据库连接来查询总计录数,不免有点多此一举、浪费时间、浪费代码、浪费生命。言重了~在这种情况下,我们就可以利用二元组,在一次数据库连接中,得到总计录数、当前页记录,并存储到其中,简单明了!

二、源码实例
二元组:
/** <p>Title: TwoTuple</p>
* <p>Description: 两个元素的元组,用于在一个方法里返回两种类型的值</p>
* @author Xewee.Zhiwei.Wang@gmail.com
* @site http://wzwahl36.net
* @version 2012-3-21 上午11:15:03
* @param <A>
* @param <B>
*/
public class TwoTuple<A, B> {
public final A first;
public final B second;

public TwoTuple(A a, B b) {
this.first = a;
this.second = b;
}
}
扩展为三元组(按此可以任意扩展)
/**
* <p>Title: ThreeTuple</p>
* <p>Description: 三个元素的元组,用于在一个方法里返回三种类型的值</p>
* @author Xewee.Zhiwei.Wang@gmail.com
* @site http://wzwahl36.net
* @version 2012-3-21 上午11:15:50
* @param <A>
* @param <B>
* @param <C>
*/
public class ThreeTuple<A, B, C> extends TwoTuple<A, B> {
public final C third;

public ThreeTuple(A a, B b, C c) {
super(a, b);
this.third = c;
}
}
元组操作工具类、测试类(可按需自定义)

import java.util.ArrayList;
import java.util.List;
 
import com.bluesea.bean.GoodsBean;
 
/**
 * <p>Title: TupleUtil</p>
 * <p>Description:
 * 元组辅助类,用于多种类型值的返回,如在分页的时候,后台存储过程既返回了查询得到的
 * 当页的数据(List类型),又得到了数据表中总共的数据总数(Integer类型),然后将这
 * 两个参数封装到该类中返回到action中使用
 * 使用泛型方法实现,利用参数类型推断,编译器可以找出具体的类型
 * </p>
 * @author Xewee.Zhiwei.Wang@gmail.com
 * @site http://wzwahl36.net
 * @version 2012-3-21 上午09:59:39
 * @param <A>
 * @param <B>
 */
public class TupleUtil {
     
    public static <A, B> TwoTuple<A, B> tuple(A a, B b) {
        return new TwoTuple<A, B>(a, b);
    }
     
    public static <A, B, C> ThreeTuple<A, B, C> tuple(A a, B b, C c) {
        return new ThreeTuple<A, B, C>(a, b, c);
    }
 
    // 测试
    public static void main(String[] args) {
        List<GoodsBean> goodsBeans = new ArrayList<GoodsBean>();
        for(int i = 1; i < 26; i++) {
            GoodsBean goodsBean = new GoodsBean();
            goodsBean.setGoodsId(i);
            goodsBeans.add(goodsBean);
        }
        Integer totalProperty = 47;
//      TupleUtil<List<GoodsBean>, Integer> tupleUtil = new TupleUtil<List<GoodsBean>, Integer>(goodsBeans, totalProperty);
        TwoTuple<List<GoodsBean>, Integer> twoTuple = TupleUtil.tuple(goodsBeans, totalProperty);
        List<GoodsBean> list = twoTuple.first;
        System.out.println(list);
        System.out.println(twoTuple.second);
    }
}
三、Demo下载
搬到SAE上之后,链接丢失,Demo为以上几个文件打包,请自行处理。

微信公众号消息接口开发——Java Servlet开发

编程语言atool 发表了文章 • 0 个评论 • 1206 次浏览 • 2016-04-22 11:02 • 来自相关话题

张小龙搞出来的微信真的很牛逼啊,短短两三年就2亿用户量,这个数据似乎在警告QQ部门,IM软件上,你们QQ的老大位置并不稳固,仍需努力。当然QQ和微信不是一个平台上的产品,并不存在很大的竞争问题。

微信公众号消息接口API只有相当于只有一个简单调用链接,但是却完全改变了最初微信公众号的概念。不过说实话,这个接口真的设计的不怎么的...验证过程个字符处理啊,加密啊,拼接啊毫无用处,在申请页面填写的token也毫无用处,这些都是题外话了。不管这个接口腾讯设计得好不好,我们需要关心的是我们利用这个接口能够做什么,怎么做?

废话少说,言归正传,微信官网给我们提供了PHP的例子,所以做PHP的同学只需要画瓢即可,对于Java平台,网上还没有人说起,欲知Java平台怎么开发微信公众号接口,请看下文:

下面列出使用Java Servlet开发的一个简单的微信公众号接口调用的例子,如果有疑问,可以参见我本博的微信公众号:红色石头。

另外,我想大家一定很想知道《模拟登录微信公众平台,主动推送图文消息给用户》的有关信息。点开即可看到了~~~




 
package com.wzwcxl.pubwx.hustac.pubwx;

import java.io.IOException;
import java.io.InputStream;

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

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import com.wzwcxl.pubwx.hustac.util.StringUtil;

/**
* 微信公众号接口调用Java版
* @author Xewee.Zhiwei.Wang
* @version 2012-12-17 上午9:16:02
* @Contract wzwahl36@QQ.com or http://wzwahl36.net/
*/
public class Test extends HttpServlet {
private static final long serialVersionUID = 1L;

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("----------get---------------");
// response.getWriter().write(request.getParameter("echostr"));
doPost(request, response);
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("----------post---------------");
try {
InputStream is = request.getInputStream();
// 取HTTP请求流长度
int size = request.getContentLength();
// 用于缓存每次读取的数据
byte[] buffer = new byte[size];
// 用于存放结果的数组
byte[] xmldataByte = new byte[size];
int count = 0;
int rbyte = 0;
// 循环读取
while (count < size) {
// 每次实际读取长度存于rbyte中
rbyte = is.read(buffer);
for(int i=0;i<rbyte;i++) {
xmldataByte[count + i] = buffer[i];
}
count += rbyte;
}
is.close();
String requestStr = new String(xmldataByte, "UTF-8");
Document doc = DocumentHelper.parseText(requestStr);
Element rootElt = doc.getRootElement();
String content = rootElt.elementText("Content");
String toUserName = rootElt.elementText("ToUserName");
String fromUserName = rootElt.elementText("FromUserName");
//得到所有的有用数据
System.out.println(content+ ":" + toUserName + ":" + fromUserName);
//文本消息
if (! StringUtil.isBlank(content) && "text".equals(content)) {
String responseStr = "<xml>";
responseStr += "<ToUserName><![CDATA[" + fromUserName
+ "]]></ToUserName>";
responseStr += "<FromUserName><![CDATA[" + toUserName
+ "]]></FromUserName>";
responseStr += "<CreateTime>" + System.currentTimeMillis()
+ "</CreateTime>";
responseStr += "<MsgType><![CDATA[text]]></MsgType>";
responseStr += "<Content>输入text或者news返回相应类型的消息,另外推荐你关注 '红色石头'(完全采用Java完成),反馈和建议请到http://wzwahl36.net</Content>";
responseStr += "<FuncFlag>0</FuncFlag>";
responseStr += "</xml>";
response.getWriter().write(responseStr);
}
//图文消息
else if (! StringUtil.isBlank(content) && "news".equals(content)) {
String responseStr = "<xml>";
responseStr += "<ToUserName><![CDATA[" + fromUserName
+ "]]></ToUserName>";
responseStr += "<FromUserName><![CDATA[" + toUserName
+ "]]></FromUserName>";
responseStr += "<CreateTime>" + System.currentTimeMillis()
+ "</CreateTime>";
responseStr += "<MsgType><![CDATA[news]]></MsgType>";
responseStr += "<Content><![CDATA[]]></Content>";

responseStr += "<ArticleCount>2</ArticleCount>";

responseStr += "<Articles>";
responseStr += "<item>";
responseStr += "<Title><![CDATA[图文消息——红色石头]]></Title>";
responseStr += "<Discription><![CDATA[图文消息正文——红色石头]]></Discription>";
responseStr += "<PicUrl><![CDATA[http://redstones.sinaapp.com/res/images/redstones_wx_258.jpg]]></PicUrl>";
responseStr += "<Url><![CDATA[http://redstones.sinaapp.com/]]></Url>";
responseStr += "</item>";

responseStr += "<item>";
responseStr += "<Title><![CDATA[图文消息——红色石头]]></Title>";
responseStr += "<Discription><![CDATA[图文消息正文——红色石头]]></Discription>";
responseStr += "<PicUrl><![CDATA[http://redstones.sinaapp.com/res/images/redstones_wx_258.jpg]]></PicUrl>";
responseStr += "<Url><![CDATA[http://redstones.sinaapp.com/]]></Url>";
responseStr += "</item>";

responseStr += "</Articles>";
responseStr += "<FuncFlag>1</FuncFlag>";
responseStr += "</xml>";
response.getWriter().write(responseStr);
}
//不能识别
else {
String responseStr = "<xml>";
responseStr += "<ToUserName><![CDATA[" + fromUserName
+ "]]></ToUserName>";
responseStr += "<FromUserName><![CDATA[" + toUserName
+ "]]></FromUserName>";
responseStr += "<CreateTime>" + System.currentTimeMillis()
+ "</CreateTime>";
responseStr += "<MsgType><![CDATA[text]]></MsgType>";
responseStr += "<Content>输入text或者news返回相应类型的消息,另外推荐你关注 '红色石头'(完全采用Java完成),反馈和建议请到http://wzwahl36.net</Content>";
responseStr += "<FuncFlag>0</FuncFlag>";
responseStr += "</xml>";
response.getWriter().write(responseStr);
}

} catch (Exception e) {
e.printStackTrace();
}
}
}需要注意是一点是:在验证链接时,将get方法写为以下:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("----------get---------------");
response.getWriter().write(request.getParameter("echostr"));
// doPost(request, response);
}
验证通过之后,将get方法和post方法写成一样的。
另外注意servlet的编码问题,我这个servlet里面没有写编码是因为我设置了编码过滤器:
package com.wzwcxl.pubwx.hustac.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
* Servlet Filter implementation class EncodingFilter
*/
public class EncodingFilter implements Filter {

/**
* Default constructor.
*/
public EncodingFilter() {
// TODO Auto-generated constructor stub
}

/**
* @see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}

/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
System.out.println("EncodingFilter: UTF-8");

chain.doFilter(request, response);
}

/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
}
}附加:很多人问到代码中的StringUtil类中的isBlank方法是什么?然后要我发给他,其实StringUtil只有isBlank方法,这个方法就是用来判断字符串是不是空,所谓字符串为空,就是等于null或者trim之后为"",每次问到这个我都不知道怎么回答,所以在这里附加说明一下~

Enjoy~有空点点广告,感谢~~~ 查看全部
张小龙搞出来的微信真的很牛逼啊,短短两三年就2亿用户量,这个数据似乎在警告QQ部门,IM软件上,你们QQ的老大位置并不稳固,仍需努力。当然QQ和微信不是一个平台上的产品,并不存在很大的竞争问题。

微信公众号消息接口API只有相当于只有一个简单调用链接,但是却完全改变了最初微信公众号的概念。不过说实话,这个接口真的设计的不怎么的...验证过程个字符处理啊,加密啊,拼接啊毫无用处,在申请页面填写的token也毫无用处,这些都是题外话了。不管这个接口腾讯设计得好不好,我们需要关心的是我们利用这个接口能够做什么,怎么做?

废话少说,言归正传,微信官网给我们提供了PHP的例子,所以做PHP的同学只需要画瓢即可,对于Java平台,网上还没有人说起,欲知Java平台怎么开发微信公众号接口,请看下文:

下面列出使用Java Servlet开发的一个简单的微信公众号接口调用的例子,如果有疑问,可以参见我本博的微信公众号:红色石头。

另外,我想大家一定很想知道《模拟登录微信公众平台,主动推送图文消息给用户》的有关信息。点开即可看到了~~~
redstones_wx_430.jpg

 
package com.wzwcxl.pubwx.hustac.pubwx;

import java.io.IOException;
import java.io.InputStream;

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

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import com.wzwcxl.pubwx.hustac.util.StringUtil;

/**
* 微信公众号接口调用Java版
* @author Xewee.Zhiwei.Wang
* @version 2012-12-17 上午9:16:02
* @Contract wzwahl36@QQ.com or http://wzwahl36.net/
*/
public class Test extends HttpServlet {
private static final long serialVersionUID = 1L;

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("----------get---------------");
// response.getWriter().write(request.getParameter("echostr"));
doPost(request, response);
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("----------post---------------");
try {
InputStream is = request.getInputStream();
// 取HTTP请求流长度
int size = request.getContentLength();
// 用于缓存每次读取的数据
byte[] buffer = new byte[size];
// 用于存放结果的数组
byte[] xmldataByte = new byte[size];
int count = 0;
int rbyte = 0;
// 循环读取
while (count < size) {
// 每次实际读取长度存于rbyte中
rbyte = is.read(buffer);
for(int i=0;i<rbyte;i++) {
xmldataByte[count + i] = buffer[i];
}
count += rbyte;
}
is.close();
String requestStr = new String(xmldataByte, "UTF-8");
Document doc = DocumentHelper.parseText(requestStr);
Element rootElt = doc.getRootElement();
String content = rootElt.elementText("Content");
String toUserName = rootElt.elementText("ToUserName");
String fromUserName = rootElt.elementText("FromUserName");
//得到所有的有用数据
System.out.println(content+ ":" + toUserName + ":" + fromUserName);
//文本消息
if (! StringUtil.isBlank(content) && "text".equals(content)) {
String responseStr = "<xml>";
responseStr += "<ToUserName><![CDATA[" + fromUserName
+ "]]></ToUserName>";
responseStr += "<FromUserName><![CDATA[" + toUserName
+ "]]></FromUserName>";
responseStr += "<CreateTime>" + System.currentTimeMillis()
+ "</CreateTime>";
responseStr += "<MsgType><![CDATA[text]]></MsgType>";
responseStr += "<Content>输入text或者news返回相应类型的消息,另外推荐你关注 '红色石头'(完全采用Java完成),反馈和建议请到http://wzwahl36.net</Content>";
responseStr += "<FuncFlag>0</FuncFlag>";
responseStr += "</xml>";
response.getWriter().write(responseStr);
}
//图文消息
else if (! StringUtil.isBlank(content) && "news".equals(content)) {
String responseStr = "<xml>";
responseStr += "<ToUserName><![CDATA[" + fromUserName
+ "]]></ToUserName>";
responseStr += "<FromUserName><![CDATA[" + toUserName
+ "]]></FromUserName>";
responseStr += "<CreateTime>" + System.currentTimeMillis()
+ "</CreateTime>";
responseStr += "<MsgType><![CDATA[news]]></MsgType>";
responseStr += "<Content><![CDATA[]]></Content>";

responseStr += "<ArticleCount>2</ArticleCount>";

responseStr += "<Articles>";
responseStr += "<item>";
responseStr += "<Title><![CDATA[图文消息——红色石头]]></Title>";
responseStr += "<Discription><![CDATA[图文消息正文——红色石头]]></Discription>";
responseStr += "<PicUrl><![CDATA[http://redstones.sinaapp.com/res/images/redstones_wx_258.jpg]]></PicUrl>";
responseStr += "<Url><![CDATA[http://redstones.sinaapp.com/]]></Url>";
responseStr += "</item>";

responseStr += "<item>";
responseStr += "<Title><![CDATA[图文消息——红色石头]]></Title>";
responseStr += "<Discription><![CDATA[图文消息正文——红色石头]]></Discription>";
responseStr += "<PicUrl><![CDATA[http://redstones.sinaapp.com/res/images/redstones_wx_258.jpg]]></PicUrl>";
responseStr += "<Url><![CDATA[http://redstones.sinaapp.com/]]></Url>";
responseStr += "</item>";

responseStr += "</Articles>";
responseStr += "<FuncFlag>1</FuncFlag>";
responseStr += "</xml>";
response.getWriter().write(responseStr);
}
//不能识别
else {
String responseStr = "<xml>";
responseStr += "<ToUserName><![CDATA[" + fromUserName
+ "]]></ToUserName>";
responseStr += "<FromUserName><![CDATA[" + toUserName
+ "]]></FromUserName>";
responseStr += "<CreateTime>" + System.currentTimeMillis()
+ "</CreateTime>";
responseStr += "<MsgType><![CDATA[text]]></MsgType>";
responseStr += "<Content>输入text或者news返回相应类型的消息,另外推荐你关注 '红色石头'(完全采用Java完成),反馈和建议请到http://wzwahl36.net</Content>";
responseStr += "<FuncFlag>0</FuncFlag>";
responseStr += "</xml>";
response.getWriter().write(responseStr);
}

} catch (Exception e) {
e.printStackTrace();
}
}
}
需要注意是一点是:在验证链接时,将get方法写为以下:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("----------get---------------");
response.getWriter().write(request.getParameter("echostr"));
// doPost(request, response);
}
验证通过之后,将get方法和post方法写成一样的。
另外注意servlet的编码问题,我这个servlet里面没有写编码是因为我设置了编码过滤器:
package com.wzwcxl.pubwx.hustac.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
* Servlet Filter implementation class EncodingFilter
*/
public class EncodingFilter implements Filter {

/**
* Default constructor.
*/
public EncodingFilter() {
// TODO Auto-generated constructor stub
}

/**
* @see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}

/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
System.out.println("EncodingFilter: UTF-8");

chain.doFilter(request, response);
}

/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
}
}
附加:很多人问到代码中的StringUtil类中的isBlank方法是什么?然后要我发给他,其实StringUtil只有isBlank方法,这个方法就是用来判断字符串是不是空,所谓字符串为空,就是等于null或者trim之后为"",每次问到这个我都不知道怎么回答,所以在这里附加说明一下~

Enjoy~有空点点广告,感谢~~~

小黄鸡SimSimi API以及小i机器人的说明——如何免费使用?

移动开发atool 发表了文章 • 0 个评论 • 2880 次浏览 • 2016-04-22 12:57 • 来自相关话题

一、什么是Simsimi?

simsimi公司是提供智能服务,其中一个服务是simsimi聊天机器人服务,每天有超过百万的用户聊天,国内最大的搜索引擎——百度的产品siri使用的就是simsimi提供的api。

你可以在网址http://www.simsimi.com/talk.htm# 进行体验

SimSimi inc. is specialized in collective intelligence service. All kinds of services we provide generates unique entertainment and values through systemized collective intelligence.

One of our services, a chatting robot SimSimi exceeds the limitation of technology of natural-language processing system by collective intelligence and it has a chat with over millions user per day. Our Premium knowledge providing service “Jisikman” creates millions of valuable knowledges a day.

We invite you to our realm of service which is available through our cloud of collective intelligence, Crowd Cloud that SimSimi inc. creates.

二、Simsimi小黄鸡API

在去年的这个时候,小黄鸡的非官方api一度被大家疯狂的在微信公众号上使用,一时间不知道成就了多少微信营销号,同时,华科某位大四学生利用这个api,结合人人网开发平台,制作了一个小黄鸡的人人号,@小黄鸡之后,就可以利用api自动进行回复,是的这个人人号瞬间粉丝陡增。

然而大家使用的都是非官方的API,所谓非官方,就是不是simsimi公司提供的合法使用途径,API大致的原理是利用编程语言,模拟浏览器发送post请求到http://www.simsimi.com/talk.htm# 链接,解析响应,然后作成相关的小黄鸡API。这个方法后来被我在本博客中在博文中发布,导致使用人数激增,simsimi公司似乎察觉了什么,立马对这种模拟请求的方式做出了屏蔽,一旦某ip请求数量和频率超过限制,则终端对它的请求。正式官方对非法API的封锁,也使用国内的开发这关注到之前并不出名的小i机器人,同样使用语言模拟请求web聊天界面,时间没有过很久,这个页面就加入了图片验证码防止程序模拟。

至此,两个聊天机器人都走上了收费的道路...准确的说,应该是被这帮子开发者赶上了收费的道路,因为他们给它带来了知名度。

三、SimsimiAPI使用




目前,小黄鸡API已经公然收费(http://developer.simsimi.com/api)
不过,和之前一样,会给注册用户提供30天的试用API。
API请求链接为:
Trial-key    http://sandbox.api.simsimi.com/request.p
Paid-key    http://api.simsimi.com/request.p

API请求参数见官网。
 
API返回格式为:

result:100-ok. 400-Bad Request. 401-Unauthorized. 404-Not found. 500-Server Error.    返回的code

id:Response id. (you can get only if returning result is 100)回复的id,由系统生成,当请求成功返回时才有这个字段。 

response:Response message(you can get only if returning result is 100)返回的回复内容。

msg:Result  msg(Description of result code) 返回的code对应的含义

四、Simsimi使用举例

请求举例:

Trial-key    http://sandbox.api.simsimi.com ... %3Dhi   
Paid-key    http://api.simsimi.com/request ... %3Dhi

响应举例:

{ "result": 100, "response": "Who are you?!", "id": 13185569, "msg": "OK." }

五、如何免费的使用Simsimi API

我想,大家都懂了,写这篇文章的原因就是很多人搜索小黄鸡 api到我的博客,我想大家都是要找免费的小黄鸡API。这里提供给大家一个思路:
 
合作伙伴中,有人人网,为什么?本博文前面提高某大四学生做了一个人人号,@小黄鸡之后,会自动进行回复,他使用的就是simsimi的官方正版付费API,既然人人网提供开发平台,可以对帐号进行回复,获得回复等等操作,为什么不能使用程序,登录帐号,然后@小黄鸡,然后获得它的回复,再返回给你自己的用户呢?答案当然是可以的!!!

下面贴出一段可供参考的Java代码,之所以为仅供参考,就是说只能参考思路,代码运行是运行不起来的!!!如果能够帮助到你,希望回复点评一下,并点点广告,你懂的...
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
/**
* 利用httpclient操作人人网 比如登陆,发状态,模拟你访问任何人主页等等
* @author: http://50vip.com
*
*/
public class RenRen {
private String userName = "";
private String password = "";

private static String redirectURL = "http://www.renren.com/home";
private static String renRenLoginURL = "http://www.renren.com/PLogin.do";
private static String talkUrl = "http://photo.renren.com/photo/ ... 3B%3B
private HttpResponse response;
private DefaultHttpClient httpclient = null;
private String requestToken = null;
private String _rtk = null;

public RenRen(String userName, String password) {
this.userName = userName;
this.password = password;
}

public static void main(String[] args) {
RenRen rr = null;
rr = new RenRen("xxxxx@hotmail.com", "yyyyy");
rr.login();
System.out.println(rr.talk("820"));
}
/**
* 登陆
* @author: http://50vip.com
* @return
*/
public boolean login() {
if (httpclient != null) {
return true;
}
httpclient = null;
httpclient = new DefaultHttpClient();
HttpPost httpost = new HttpPost(renRenLoginURL);
// All the parameters post to the web site
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair("origURL", redirectURL));
nvps.add(new BasicNameValuePair("domain", "renren.com"));
nvps.add(new BasicNameValuePair("autoLogin", "true"));
nvps.add(new BasicNameValuePair("formName", ""));
nvps.add(new BasicNameValuePair("method", ""));
nvps.add(new BasicNameValuePair("submit", "登录"));
nvps.add(new BasicNameValuePair("email", userName));
nvps.add(new BasicNameValuePair("password", password));
try {
httpost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
response = httpclient.execute(httpost);
//System.out.println(response);
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
httpost.abort();
}

String redirectLocation = getRedirectLocation();
if (redirectLocation != null) {
// 跳到首页,登录完成
String indexHtml=getText(redirectLocation);

//获取requestToken get_check:'-2062261917'
Pattern pattern1 = Pattern.compile("get_check:'(.*)',get_check_x");
Matcher m1 = pattern1.matcher(indexHtml);
if (m1.find()) {
requestToken=m1.group(1);
} else {
System.out.println("获取requestToken失败!");
}

//"获取_rtk失败!"get_check_x:'50d55fbd'
Pattern pattern2 = Pattern.compile("get_check_x:'(.*)',env:");
Matcher m2 = pattern2.matcher(indexHtml);
if (m2.find()) {
_rtk=m2.group(1);
} else {
System.out.println("获取_rtk失败!");
}
}
return true;
}

/**
* 和人人的小黄鸡交谈
* @author: http://50vip.com
* @param msg
* @return
*/
public String talk(String msg) {
String repMsg="";//小黄的回复

HttpPost httpost = new HttpPost(talkUrl);
// All the parameters post to the web site
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair("_rtk", _rtk));
nvps.add(new BasicNameValuePair("requestToken", requestToken));
nvps.add(new BasicNameValuePair("message", msg));

try {
ResponseHandler<String> responseHandler = new BasicResponseHandler();
httpost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
repMsg=httpclient.execute(httpost, responseHandler);
} catch (Exception e) {
e.printStackTrace();
} finally {
httpost.abort();
}
return repMsg;
}

/**
* 此处人人网会302跳转
* @author: http://50vip.com
* @return
*/
private String getRedirectLocation() {
Header locationHeader = response.getFirstHeader("Location");
if (locationHeader == null) {
return null;
}
return locationHeader.getValue();
}

/**
* 读取首页内容
* @author: http://50vip.com
* @param redirectLocation
* @return
*/
private String getText(String redirectLocation) {
HttpGet httpget = new HttpGet(redirectLocation);
// Create a response handler
ResponseHandler<String> responseHandler = new BasicResponseHandler();
String responseBody = "";
try {
responseBody = httpclient.execute(httpget, responseHandler);
} catch (Exception e) {
e.printStackTrace();
responseBody = null;
} finally {
httpget.abort();
}
return responseBody;
}
} 查看全部
一、什么是Simsimi?

simsimi公司是提供智能服务,其中一个服务是simsimi聊天机器人服务,每天有超过百万的用户聊天,国内最大的搜索引擎——百度的产品siri使用的就是simsimi提供的api。

你可以在网址http://www.simsimi.com/talk.htm# 进行体验

SimSimi inc. is specialized in collective intelligence service. All kinds of services we provide generates unique entertainment and values through systemized collective intelligence.

One of our services, a chatting robot SimSimi exceeds the limitation of technology of natural-language processing system by collective intelligence and it has a chat with over millions user per day. Our Premium knowledge providing service “Jisikman” creates millions of valuable knowledges a day.

We invite you to our realm of service which is available through our cloud of collective intelligence, Crowd Cloud that SimSimi inc. creates.

二、Simsimi小黄鸡API

在去年的这个时候,小黄鸡的非官方api一度被大家疯狂的在微信公众号上使用,一时间不知道成就了多少微信营销号,同时,华科某位大四学生利用这个api,结合人人网开发平台,制作了一个小黄鸡的人人号,@小黄鸡之后,就可以利用api自动进行回复,是的这个人人号瞬间粉丝陡增。

然而大家使用的都是非官方的API,所谓非官方,就是不是simsimi公司提供的合法使用途径,API大致的原理是利用编程语言,模拟浏览器发送post请求到http://www.simsimi.com/talk.htm# 链接,解析响应,然后作成相关的小黄鸡API。这个方法后来被我在本博客中在博文中发布,导致使用人数激增,simsimi公司似乎察觉了什么,立马对这种模拟请求的方式做出了屏蔽,一旦某ip请求数量和频率超过限制,则终端对它的请求。正式官方对非法API的封锁,也使用国内的开发这关注到之前并不出名的小i机器人,同样使用语言模拟请求web聊天界面,时间没有过很久,这个页面就加入了图片验证码防止程序模拟。

至此,两个聊天机器人都走上了收费的道路...准确的说,应该是被这帮子开发者赶上了收费的道路,因为他们给它带来了知名度。

三、SimsimiAPI使用
13845160832840.jpg

目前,小黄鸡API已经公然收费(http://developer.simsimi.com/api
不过,和之前一样,会给注册用户提供30天的试用API。
API请求链接为:
Trial-key    http://sandbox.api.simsimi.com/request.p
Paid-key    http://api.simsimi.com/request.p

API请求参数见官网。
 
API返回格式为:

result:100-ok. 400-Bad Request. 401-Unauthorized. 404-Not found. 500-Server Error.    返回的code

id:Response id. (you can get only if returning result is 100)回复的id,由系统生成,当请求成功返回时才有这个字段。 

response:Response message(you can get only if returning result is 100)返回的回复内容。

msg:Result  msg(Description of result code) 返回的code对应的含义

四、Simsimi使用举例

请求举例:

Trial-key    http://sandbox.api.simsimi.com ... %3Dhi   
Paid-key    http://api.simsimi.com/request ... %3Dhi

响应举例:

{ "result": 100, "response": "Who are you?!", "id": 13185569, "msg": "OK." }

五、如何免费的使用Simsimi API

我想,大家都懂了,写这篇文章的原因就是很多人搜索小黄鸡 api到我的博客,我想大家都是要找免费的小黄鸡API。这里提供给大家一个思路:
 
合作伙伴中,有人人网,为什么?本博文前面提高某大四学生做了一个人人号,@小黄鸡之后,会自动进行回复,他使用的就是simsimi的官方正版付费API,既然人人网提供开发平台,可以对帐号进行回复,获得回复等等操作,为什么不能使用程序,登录帐号,然后@小黄鸡,然后获得它的回复,再返回给你自己的用户呢?答案当然是可以的!!!

下面贴出一段可供参考的Java代码,之所以为仅供参考,就是说只能参考思路,代码运行是运行不起来的!!!如果能够帮助到你,希望回复点评一下,并点点广告,你懂的...
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
/**
* 利用httpclient操作人人网 比如登陆,发状态,模拟你访问任何人主页等等
* @author: http://50vip.com
*
*/
public class RenRen {
private String userName = "";
private String password = "";

private static String redirectURL = "http://www.renren.com/home";
private static String renRenLoginURL = "http://www.renren.com/PLogin.do";
private static String talkUrl = "http://photo.renren.com/photo/ ... 3B%3B
private HttpResponse response;
private DefaultHttpClient httpclient = null;
private String requestToken = null;
private String _rtk = null;

public RenRen(String userName, String password) {
this.userName = userName;
this.password = password;
}

public static void main(String[] args) {
RenRen rr = null;
rr = new RenRen("xxxxx@hotmail.com", "yyyyy");
rr.login();
System.out.println(rr.talk("820"));
}
/**
* 登陆
* @author: http://50vip.com
* @return
*/
public boolean login() {
if (httpclient != null) {
return true;
}
httpclient = null;
httpclient = new DefaultHttpClient();
HttpPost httpost = new HttpPost(renRenLoginURL);
// All the parameters post to the web site
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair("origURL", redirectURL));
nvps.add(new BasicNameValuePair("domain", "renren.com"));
nvps.add(new BasicNameValuePair("autoLogin", "true"));
nvps.add(new BasicNameValuePair("formName", ""));
nvps.add(new BasicNameValuePair("method", ""));
nvps.add(new BasicNameValuePair("submit", "登录"));
nvps.add(new BasicNameValuePair("email", userName));
nvps.add(new BasicNameValuePair("password", password));
try {
httpost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
response = httpclient.execute(httpost);
//System.out.println(response);
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
httpost.abort();
}

String redirectLocation = getRedirectLocation();
if (redirectLocation != null) {
// 跳到首页,登录完成
String indexHtml=getText(redirectLocation);

//获取requestToken get_check:'-2062261917'
Pattern pattern1 = Pattern.compile("get_check:'(.*)',get_check_x");
Matcher m1 = pattern1.matcher(indexHtml);
if (m1.find()) {
requestToken=m1.group(1);
} else {
System.out.println("获取requestToken失败!");
}

//"获取_rtk失败!"get_check_x:'50d55fbd'
Pattern pattern2 = Pattern.compile("get_check_x:'(.*)',env:");
Matcher m2 = pattern2.matcher(indexHtml);
if (m2.find()) {
_rtk=m2.group(1);
} else {
System.out.println("获取_rtk失败!");
}
}
return true;
}

/**
* 和人人的小黄鸡交谈
* @author: http://50vip.com
* @param msg
* @return
*/
public String talk(String msg) {
String repMsg="";//小黄的回复

HttpPost httpost = new HttpPost(talkUrl);
// All the parameters post to the web site
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair("_rtk", _rtk));
nvps.add(new BasicNameValuePair("requestToken", requestToken));
nvps.add(new BasicNameValuePair("message", msg));

try {
ResponseHandler<String> responseHandler = new BasicResponseHandler();
httpost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
repMsg=httpclient.execute(httpost, responseHandler);
} catch (Exception e) {
e.printStackTrace();
} finally {
httpost.abort();
}
return repMsg;
}

/**
* 此处人人网会302跳转
* @author: http://50vip.com
* @return
*/
private String getRedirectLocation() {
Header locationHeader = response.getFirstHeader("Location");
if (locationHeader == null) {
return null;
}
return locationHeader.getValue();
}

/**
* 读取首页内容
* @author: http://50vip.com
* @param redirectLocation
* @return
*/
private String getText(String redirectLocation) {
HttpGet httpget = new HttpGet(redirectLocation);
// Create a response handler
ResponseHandler<String> responseHandler = new BasicResponseHandler();
String responseBody = "";
try {
responseBody = httpclient.execute(httpget, responseHandler);
} catch (Exception e) {
e.printStackTrace();
responseBody = null;
} finally {
httpget.abort();
}
return responseBody;
}
}

使用Java给微信公众号创建自定义的菜单

编程语言atool 发表了文章 • 0 个评论 • 1318 次浏览 • 2016-04-22 12:53 • 来自相关话题

最近一段时间,微信公众平台做了很多的改进啊~

微信目前将公众帐号分成服务号和订阅号两种,之前的微信公众号默认为订阅号,不过有一次机会可以自由选择,两者之间各有优劣:

服务号每月只能推送一条消息,不过消息是显示在消息列表中,并有消息提示;订阅号每天有一条消息推送,不过消息不显示在消息列表,没有消息提示。

除此之外,目前微信公众号可以自定义菜单,下面将介绍如果使用Java作一个微信公众号的菜单,参考API可到官网查看:http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E6%8E%A5%E5%8F%A3
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import org.json.JSONObject;

public class MenuUtil {
/**
* 获得ACCESS_TOKEN
* @Title: getAccess_token
* @Description: 获得ACCESS_TOKEN
* @param @return 设定文件
* @return String 返回类型
* @throws
*/
private static String getAccess_token(){

String APPID="";
String APPSECRET="";

String url = "https://api.weixin.qq.com/cgi- ... 3B%2B APPID + "&secret=" +APPSECRET;
String accessToken = null;
try {
URL urlGet = new URL(url);
HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();

http.setRequestMethod("GET"); //必须是get方式请求
http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");//连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); //读取超时30秒

http.connect();

InputStream is =http.getInputStream();
int size =is.available();
byte[] jsonBytes =new byte[size];
is.read(jsonBytes);
String message=new String(jsonBytes,"UTF-8");

JSONObject demoJson = new JSONObject(message);
accessToken = demoJson.getString("access_token");

System.out.println(message);
} catch (Exception e) {
e.printStackTrace();
}
return accessToken;
}

/**
* 创建Menu
* @Title: createMenu
* @Description: 创建Menu
* @param @return
* @param @throws IOException 设定文件
* @return int 返回类型
* @throws
*/
public static String createMenu() {
String menu = "{\"button\":[{\"type\":\"click\",\"name\":\"MENU01\",\"key\":\"1\"},{\"type\":\"click\",\"name\":\"天气查询\",\"key\":\"西安\"},{\"name\":\"日常工作\",\"sub_button\":[{\"type\":\"click\",\"name\":\"待办工单\",\"key\":\"01_WAITING\"},{\"type\":\"click\",\"name\":\"已办工单\",\"key\":\"02_FINISH\"},{\"type\":\"click\",\"name\":\"我的工单\",\"key\":\"03_MYJOB\"},{\"type\":\"click\",\"name\":\"公告消息箱\",\"key\":\"04_MESSAGEBOX\"},{\"type\":\"click\",\"name\":\"签到\",\"key\":\"05_SIGN\"}]}]}";

//此处改为自己想要的结构体,替换即可
String access_token= getAccess_token();

String action = "https://api.weixin.qq.com/cgi- ... en%3B
try {
URL url = new URL(action);
HttpURLConnection http = (HttpURLConnection) url.openConnection();

http.setRequestMethod("POST");
http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");//连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); //读取超时30秒

http.connect();
OutputStream os= http.getOutputStream();
os.write(menu.getBytes("UTF-8"));//传入参数
os.flush();
os.close();

InputStream is =http.getInputStream();
int size =is.available();
byte[] jsonBytes =new byte[size];
is.read(jsonBytes);
String message=new String(jsonBytes,"UTF-8");
return "返回信息"+message;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "createMenu 失败";
}

/**
* 删除当前Menu
* @Title: deleteMenu
* @Description: 删除当前Menu
* @param @return 设定文件
* @return String 返回类型
* @throws
*/
public static String deleteMenu()
{
String access_token= getAccess_token();
String action = "https://api.weixin.qq.com/cgi-bin/menu/delete? access_token="+access_token;
try {
URL url = new URL(action);
HttpURLConnection http = (HttpURLConnection) url.openConnection();

http.setRequestMethod("GET");
http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");//连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); //读取超时30秒

http.connect();
OutputStream os= http.getOutputStream();
os.flush();
os.close();

InputStream is =http.getInputStream();
int size =is.available();
byte[] jsonBytes =new byte[size];
is.read(jsonBytes);
String message=new String(jsonBytes,"UTF-8");
return "deleteMenu返回信息:"+message;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "deleteMenu 失败";
}

public static void main(String[] args) {
System.out.println(createMenu());
}
}代码来源于:http://www.oschina.net/code/snippet_945711_24355 ,后续会做PHP版,并加入到自己的微信公众号上面,我的微信公众号二维码见右侧。Enjoy~ 查看全部
最近一段时间,微信公众平台做了很多的改进啊~

微信目前将公众帐号分成服务号和订阅号两种,之前的微信公众号默认为订阅号,不过有一次机会可以自由选择,两者之间各有优劣:

服务号每月只能推送一条消息,不过消息是显示在消息列表中,并有消息提示;订阅号每天有一条消息推送,不过消息不显示在消息列表,没有消息提示。

除此之外,目前微信公众号可以自定义菜单,下面将介绍如果使用Java作一个微信公众号的菜单,参考API可到官网查看:http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E6%8E%A5%E5%8F%A3
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import org.json.JSONObject;

public class MenuUtil {
/**
* 获得ACCESS_TOKEN
* @Title: getAccess_token
* @Description: 获得ACCESS_TOKEN
* @param @return 设定文件
* @return String 返回类型
* @throws
*/
private static String getAccess_token(){

String APPID="";
String APPSECRET="";

String url = "https://api.weixin.qq.com/cgi- ... 3B%2B APPID + "&secret=" +APPSECRET;
String accessToken = null;
try {
URL urlGet = new URL(url);
HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();

http.setRequestMethod("GET"); //必须是get方式请求
http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");//连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); //读取超时30秒

http.connect();

InputStream is =http.getInputStream();
int size =is.available();
byte[] jsonBytes =new byte[size];
is.read(jsonBytes);
String message=new String(jsonBytes,"UTF-8");

JSONObject demoJson = new JSONObject(message);
accessToken = demoJson.getString("access_token");

System.out.println(message);
} catch (Exception e) {
e.printStackTrace();
}
return accessToken;
}

/**
* 创建Menu
* @Title: createMenu
* @Description: 创建Menu
* @param @return
* @param @throws IOException 设定文件
* @return int 返回类型
* @throws
*/
public static String createMenu() {
String menu = "{\"button\":[{\"type\":\"click\",\"name\":\"MENU01\",\"key\":\"1\"},{\"type\":\"click\",\"name\":\"天气查询\",\"key\":\"西安\"},{\"name\":\"日常工作\",\"sub_button\":[{\"type\":\"click\",\"name\":\"待办工单\",\"key\":\"01_WAITING\"},{\"type\":\"click\",\"name\":\"已办工单\",\"key\":\"02_FINISH\"},{\"type\":\"click\",\"name\":\"我的工单\",\"key\":\"03_MYJOB\"},{\"type\":\"click\",\"name\":\"公告消息箱\",\"key\":\"04_MESSAGEBOX\"},{\"type\":\"click\",\"name\":\"签到\",\"key\":\"05_SIGN\"}]}]}";

//此处改为自己想要的结构体,替换即可
String access_token= getAccess_token();

String action = "https://api.weixin.qq.com/cgi- ... en%3B
try {
URL url = new URL(action);
HttpURLConnection http = (HttpURLConnection) url.openConnection();

http.setRequestMethod("POST");
http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");//连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); //读取超时30秒

http.connect();
OutputStream os= http.getOutputStream();
os.write(menu.getBytes("UTF-8"));//传入参数
os.flush();
os.close();

InputStream is =http.getInputStream();
int size =is.available();
byte[] jsonBytes =new byte[size];
is.read(jsonBytes);
String message=new String(jsonBytes,"UTF-8");
return "返回信息"+message;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "createMenu 失败";
}

/**
* 删除当前Menu
* @Title: deleteMenu
* @Description: 删除当前Menu
* @param @return 设定文件
* @return String 返回类型
* @throws
*/
public static String deleteMenu()
{
String access_token= getAccess_token();
String action = "https://api.weixin.qq.com/cgi-bin/menu/delete? access_token="+access_token;
try {
URL url = new URL(action);
HttpURLConnection http = (HttpURLConnection) url.openConnection();

http.setRequestMethod("GET");
http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");//连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); //读取超时30秒

http.connect();
OutputStream os= http.getOutputStream();
os.flush();
os.close();

InputStream is =http.getInputStream();
int size =is.available();
byte[] jsonBytes =new byte[size];
is.read(jsonBytes);
String message=new String(jsonBytes,"UTF-8");
return "deleteMenu返回信息:"+message;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "deleteMenu 失败";
}

public static void main(String[] args) {
System.out.println(createMenu());
}
}
代码来源于:http://www.oschina.net/code/snippet_945711_24355 ,后续会做PHP版,并加入到自己的微信公众号上面,我的微信公众号二维码见右侧。Enjoy~

Java模拟登录微信公众平台,主动推送图文消息给用户

服务端atool 发表了文章 • 0 个评论 • 1333 次浏览 • 2016-04-22 11:37 • 来自相关话题

@2013-11-25,对博文进行说明,由于2013年10月底,微信公众平台界面完全改版,所以本博文的所有代码几乎全部不能使用,不过有网友对本博的代码进行修改并授权于我共享给大家,因此大家可以去看博文《【微信公众平台改版后】Java模拟登录微信平台,主动推送消息给用户》,本博文的思路,大家也可以看看进行参考。

很早之前,在博客中发表了关于使用java开发微信公众号接口的程序代码,详细见《微信公众号消息接口开发——Java Servlet开发》,例外利用java做了小黄鸡,小i机器人的微信聊天开发,所以之前很多人问我有关于java开发微信接口的东西~

除此之外,更重要的是:很多人还问我关于微信主动推送消息给用户的问题,我所给出的所有答案都是:微信官方没有给出主动推送的api,所有采用程序记录用户微信id,然后模拟微信接口的请求数据,去请求微信接口中设置的url,这些方法都是不可行的~

不过,要实现主动推送不是不可能的,最简单的一个思路就是使用java模拟登录微信公众平台,然后推送消息消息给用户,不过这种方式有推送限制。

由于问的人比较多,决定把代码放出来,代码还未整理,里面有解析数据可以用正则表达式替换也没做,有需要的可以自己在此基础上修改。如果你觉得有用,并帮助了你,感谢你对我的赞助和支持。
public boolean msgSend(MsgForm form, MsgType type) {
try {
if (!this.isLogin) {
this._login();
}
if (this.isLogin) {
form.setToken(this.token);
PostMethod post = new PostMethod(POST_MSG);
post.setRequestHeader(USER_AGENT_H, USER_AGENT);
post.setRequestHeader(REFERER_H, INDEX_URL);
post.setRequestHeader("Cookie", this.cookiestr);
NameValuePair[] params = null;
Part[] parts = null;
switch (type) {
case TEXT:

parts = new Part[]{
new StringPart("content", form.getContent(),
"UTF-8"),
new StringPart("type", form.getType()),
new StringPart("error", form.getError()),
new StringPart("needcomment", form.getNeedcomment()),
new StringPart("groupid", form.getGroupid()),
new StringPart("sex", form.getSex()),
new StringPart("country", form.getCountry()),
new StringPart("province", form.getProvince()),
new StringPart("city", form.getCity()),
new StringPart("token", form.getToken()),
new StringPart("ajax", form.getAjax()),
new StringPart("t", "ajax-response")};
break;
case IMAGE_TEXT:
parts = new Part[]{
new StringPart("content", form.getContent(),
"UTF-8"),
new StringPart("type", form.getType()),
new StringPart("error", form.getError()),
new StringPart("needcomment", form.getNeedcomment()),
new StringPart("groupid", form.getGroupid()),
new StringPart("sex", form.getSex()),
new StringPart("country", form.getCountry()),
new StringPart("province", form.getProvince()),
new StringPart("city", form.getCity()),
new StringPart("token", form.getToken()),
new StringPart("ajax", form.getAjax()),
new StringPart("t", "ajax-response")};
break;
default:
parts = new Part[]{
new StringPart("content", form.getContent(),
"UTF-8"),
new StringPart("type", form.getType()),
new StringPart("error", form.getError()),
new StringPart("needcomment", form.getNeedcomment()),
new StringPart("groupid", form.getGroupid()),
new StringPart("sex", form.getSex()),
new StringPart("country", form.getCountry()),
new StringPart("province", form.getProvince()),
new StringPart("city", form.getCity()),
new StringPart("token", form.getToken()),
new StringPart("ajax", form.getAjax()),
new StringPart("t", "ajax-response")};
break;
}
RequestEntity entity = new MultipartRequestEntity(parts,
post.getParams());
post.setRequestEntity(entity);
int status;
status = client.executeMethod(post);
if (status == HttpStatus.SC_OK) {
String text = post.getResponseBodyAsString();
try {
MsgJson ret = JSON.parseObject(text, MsgJson.class);
this.msgSendCode = ret.getRet();
switch (this.msgSendCode) {
case 0:
this.msgSendMsg = "发送成功";
return true;
case -2:
this.msgSendMsg = "参数错误,请仔细检查";
return false;
case 64004:
this.msgSendMsg = "今天的群发数量已到,无法群发";
return false;
case -20000:
this.msgSendMsg = "请求被禁止,请仔细检查token是否合法";
return false;
default:
this.msgSendMsg = "未知错误!";
return false;
}
} catch (Exception e) {
String info = "【群发信息失败】【解析json错误】" + e.getMessage()
+ "
【文本:】
" + text;
System.err.println(info);
log.debug(info);
log.info(info);
return false;
}
}
}
} catch (Exception e) {
String info = "【群发信息失败】" + e.getMessage();
System.err.println(info);
log.debug(info);
log.info(info);
return false;
}
return false;
} 查看全部
@2013-11-25,对博文进行说明,由于2013年10月底,微信公众平台界面完全改版,所以本博文的所有代码几乎全部不能使用,不过有网友对本博的代码进行修改并授权于我共享给大家,因此大家可以去看博文《【微信公众平台改版后】Java模拟登录微信平台,主动推送消息给用户》,本博文的思路,大家也可以看看进行参考。

很早之前,在博客中发表了关于使用java开发微信公众号接口的程序代码,详细见《微信公众号消息接口开发——Java Servlet开发》,例外利用java做了小黄鸡,小i机器人的微信聊天开发,所以之前很多人问我有关于java开发微信接口的东西~

除此之外,更重要的是:很多人还问我关于微信主动推送消息给用户的问题,我所给出的所有答案都是:微信官方没有给出主动推送的api,所有采用程序记录用户微信id,然后模拟微信接口的请求数据,去请求微信接口中设置的url,这些方法都是不可行的~

不过,要实现主动推送不是不可能的,最简单的一个思路就是使用java模拟登录微信公众平台,然后推送消息消息给用户,不过这种方式有推送限制。

由于问的人比较多,决定把代码放出来,代码还未整理,里面有解析数据可以用正则表达式替换也没做,有需要的可以自己在此基础上修改。如果你觉得有用,并帮助了你,感谢你对我的赞助和支持。
public boolean msgSend(MsgForm form, MsgType type) {
try {
if (!this.isLogin) {
this._login();
}
if (this.isLogin) {
form.setToken(this.token);
PostMethod post = new PostMethod(POST_MSG);
post.setRequestHeader(USER_AGENT_H, USER_AGENT);
post.setRequestHeader(REFERER_H, INDEX_URL);
post.setRequestHeader("Cookie", this.cookiestr);
NameValuePair[] params = null;
Part[] parts = null;
switch (type) {
case TEXT:

parts = new Part[]{
new StringPart("content", form.getContent(),
"UTF-8"),
new StringPart("type", form.getType()),
new StringPart("error", form.getError()),
new StringPart("needcomment", form.getNeedcomment()),
new StringPart("groupid", form.getGroupid()),
new StringPart("sex", form.getSex()),
new StringPart("country", form.getCountry()),
new StringPart("province", form.getProvince()),
new StringPart("city", form.getCity()),
new StringPart("token", form.getToken()),
new StringPart("ajax", form.getAjax()),
new StringPart("t", "ajax-response")};
break;
case IMAGE_TEXT:
parts = new Part[]{
new StringPart("content", form.getContent(),
"UTF-8"),
new StringPart("type", form.getType()),
new StringPart("error", form.getError()),
new StringPart("needcomment", form.getNeedcomment()),
new StringPart("groupid", form.getGroupid()),
new StringPart("sex", form.getSex()),
new StringPart("country", form.getCountry()),
new StringPart("province", form.getProvince()),
new StringPart("city", form.getCity()),
new StringPart("token", form.getToken()),
new StringPart("ajax", form.getAjax()),
new StringPart("t", "ajax-response")};
break;
default:
parts = new Part[]{
new StringPart("content", form.getContent(),
"UTF-8"),
new StringPart("type", form.getType()),
new StringPart("error", form.getError()),
new StringPart("needcomment", form.getNeedcomment()),
new StringPart("groupid", form.getGroupid()),
new StringPart("sex", form.getSex()),
new StringPart("country", form.getCountry()),
new StringPart("province", form.getProvince()),
new StringPart("city", form.getCity()),
new StringPart("token", form.getToken()),
new StringPart("ajax", form.getAjax()),
new StringPart("t", "ajax-response")};
break;
}
RequestEntity entity = new MultipartRequestEntity(parts,
post.getParams());
post.setRequestEntity(entity);
int status;
status = client.executeMethod(post);
if (status == HttpStatus.SC_OK) {
String text = post.getResponseBodyAsString();
try {
MsgJson ret = JSON.parseObject(text, MsgJson.class);
this.msgSendCode = ret.getRet();
switch (this.msgSendCode) {
case 0:
this.msgSendMsg = "发送成功";
return true;
case -2:
this.msgSendMsg = "参数错误,请仔细检查";
return false;
case 64004:
this.msgSendMsg = "今天的群发数量已到,无法群发";
return false;
case -20000:
this.msgSendMsg = "请求被禁止,请仔细检查token是否合法";
return false;
default:
this.msgSendMsg = "未知错误!";
return false;
}
} catch (Exception e) {
String info = "【群发信息失败】【解析json错误】" + e.getMessage()
+ "
【文本:】
" + text;
System.err.println(info);
log.debug(info);
log.info(info);
return false;
}
}
}
} catch (Exception e) {
String info = "【群发信息失败】" + e.getMessage();
System.err.println(info);
log.debug(info);
log.info(info);
return false;
}
return false;
}

dom4j解析创建Xml:org.dom4j.DocumentException: 2字节的UTF-8序列的2无效

编程语言atool 发表了文章 • 0 个评论 • 2217 次浏览 • 2016-04-22 11:26 • 来自相关话题

最近刚刚做完Java版Dota改键软件KeyHelper的界面配置操作,配置信息保存到xml中,采用dom4j进行解析和创建,基本做的差不多,并导出为jar自己在使用测试。

在Eclipse中运行时没有任何异常和错误,但是导出jar包之后使用start java -jar keyHelper.jar运行的时候,报异常:org.dom4j.DocumentException: 2字节的UTF-8序列的2无效...后面是一大串错误stack信息。

搜索了一下,网上关于dom4j解析xml汉字乱码问题一大堆,其中解决办法基本没有,大都是在网上发发问题,但是没有人解决,只有一个提到说将xml的编码改成为GBK或者GB2312,这个测试了,基本上是可行的,但是一般的软件开发都是采用UTF-8,将配置换成其他编码,会导致软件界面上是乱码,所以这个解决办法其实有一点鸡肋。自己尝试过在创建保存xml的时候,利用构造的domcument,调用asXml()方法得到document的string字符串,然后采用java io利用utf-8编码写入文件中,但是到读取的时候依然会报错。

再三折腾之下,发现了一个既不用修改xml编码,又可以解决这个中文解析的异常,贴出我的解析的创建xml的代码。

一、解析Config.xml配置信息
private void loadFromXml() {
try {
AXReader reader = new SAXReader();
File file = new File(CONFIG_FILE);
Document document = reader.read(new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8")));// 读取XML文件
Element xmlRoot = document.getRootElement();// 得到根节点
lastKeySet = xmlRoot.elementText("lastKeySet");
lastLocationX = Integer.valueOf(xmlRoot.elementText("lastLocationX"));
lastLocationY = Integer.valueOf(xmlRoot.elementText("lastLocationY"));
} catch (Exception e) {
e.printStackTrace();
lastKeySet = "";//上次选择的改键方案
lastLocationX = 500;//上次窗口位置
lastLocationY = 100;//上次窗口位置
}
}其中代码:Document document = reader.read(newBufferedReader(newInputStreamReader(newFileInputStream(file), "UTF-8")));是关键。

二、创建Config.xml配置信息
public void saveToXml() {
/** 建立document对象 */
Document document = DocumentHelper.createDocument();
/** 建立config根节点 */
Element configElement = document.addElement("config");
configElement.addElement("lastKeySet").setText(lastKeySet);
configElement.addElement("lastLocationX").setText(lastLocationX + "");
configElement.addElement("lastLocationY").setText(lastLocationY + "");
try{
/* 将document中的内容写入文件中 */
OutputFormat format = new OutputFormat();
format.setEncoding("UTF-8");
XMLWriter writer = new XMLWriter(new FileOutputStream(new File(CONFIG_FILE)), format);
writer.write(document);
writer.close();
} catch(Exception ex) {
ex.printStackTrace();
}
}其中代码:OutputFormat format = newOutputFormat();
format.setEncoding("UTF-8");
XMLWriter writer = newXMLWriter(newFileOutputStream(newFile(CONFIG_FILE)), format);是关键,请务必按照这个写法进行。具体为什么,我自己也不知道,唉~
Enjoy~ 查看全部
最近刚刚做完Java版Dota改键软件KeyHelper的界面配置操作,配置信息保存到xml中,采用dom4j进行解析和创建,基本做的差不多,并导出为jar自己在使用测试。

在Eclipse中运行时没有任何异常和错误,但是导出jar包之后使用start java -jar keyHelper.jar运行的时候,报异常:org.dom4j.DocumentException: 2字节的UTF-8序列的2无效...后面是一大串错误stack信息。

搜索了一下,网上关于dom4j解析xml汉字乱码问题一大堆,其中解决办法基本没有,大都是在网上发发问题,但是没有人解决,只有一个提到说将xml的编码改成为GBK或者GB2312,这个测试了,基本上是可行的,但是一般的软件开发都是采用UTF-8,将配置换成其他编码,会导致软件界面上是乱码,所以这个解决办法其实有一点鸡肋。自己尝试过在创建保存xml的时候,利用构造的domcument,调用asXml()方法得到document的string字符串,然后采用java io利用utf-8编码写入文件中,但是到读取的时候依然会报错。

再三折腾之下,发现了一个既不用修改xml编码,又可以解决这个中文解析的异常,贴出我的解析的创建xml的代码。

一、解析Config.xml配置信息
private void loadFromXml() {
try {
AXReader reader = new SAXReader();
File file = new File(CONFIG_FILE);
Document document = reader.read(new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8")));// 读取XML文件
Element xmlRoot = document.getRootElement();// 得到根节点
lastKeySet = xmlRoot.elementText("lastKeySet");
lastLocationX = Integer.valueOf(xmlRoot.elementText("lastLocationX"));
lastLocationY = Integer.valueOf(xmlRoot.elementText("lastLocationY"));
} catch (Exception e) {
e.printStackTrace();
lastKeySet = "";//上次选择的改键方案
lastLocationX = 500;//上次窗口位置
lastLocationY = 100;//上次窗口位置
}
}
其中代码:Document document = reader.read(newBufferedReader(newInputStreamReader(newFileInputStream(file), "UTF-8")));是关键。

二、创建Config.xml配置信息
public void saveToXml() {
/** 建立document对象 */
Document document = DocumentHelper.createDocument();
/** 建立config根节点 */
Element configElement = document.addElement("config");
configElement.addElement("lastKeySet").setText(lastKeySet);
configElement.addElement("lastLocationX").setText(lastLocationX + "");
configElement.addElement("lastLocationY").setText(lastLocationY + "");
try{
/* 将document中的内容写入文件中 */
OutputFormat format = new OutputFormat();
format.setEncoding("UTF-8");
XMLWriter writer = new XMLWriter(new FileOutputStream(new File(CONFIG_FILE)), format);
writer.write(document);
writer.close();
} catch(Exception ex) {
ex.printStackTrace();
}
}
其中代码:
OutputFormat format = newOutputFormat();
format.setEncoding("UTF-8");
XMLWriter writer = newXMLWriter(newFileOutputStream(newFile(CONFIG_FILE)), format);
是关键,请务必按照这个写法进行。具体为什么,我自己也不知道,唉~
Enjoy~

【错误】新浪SinaSAE 上传Java WAR包出现is not a javax.servlet.Filter

云计算atool 发表了文章 • 0 个评论 • 1199 次浏览 • 2016-04-22 11:22 • 来自相关话题

使用Java Web做了一个签到系统,使用的是Struts2 + ExtJs4 + BoneCP + Mysql。

准备部署到Sina SAE上面,之前部署微信公众号开发的的Java程序一点问题都没有,但是部署这个应用问题一堆。不过之前的应用使用的是Servlet,没有使用任何框架。

先说一个部署问题,大致是将war包上传之后,在SAE中的日志系统中的JVM日志有以下错误:

java.lang.IllegalStateException: class com.cxl.signin.filter.AuthFilter is not a javax.servlet.Filter

然后输入二级域名,发现前台显示也是报错的:

Error 404 - Not Found.No context on this server matched or handled this request.
Contexts known to this server are:...(后面是关于个人应用的一些乱鸡巴遭的东西)

最终在一个英文的讨论论坛找到了一个相关的回答:
My top-of-the-brain guess would be that you have two servlet JARs in your classpath, and jetty is using one but your WAR is using another.
Really weird error though, for sure.

大致意思是那哥们看到这个问题,第一感觉就是项目classpath里面有两个servlet jar包,服务器jetty使用一个,你的war包使用的另一个。

我想应该是sina的服务器classpath里面就有了servlet-api.jar包了,于是我删掉了web-INF/lib下面的这个包,上传,不报错,首页可以打开。我的二级域名为sign.sinaapp.com/login.jsp,大家测试。

另外还有一个需要注意的是:请不要用jre7的版本去编译你的项目...

除此之外,项目还有其他的问题,就是session问题,我Java开的是4个虚拟机,登陆的时候明明已经运行到登陆成功,session写入的那一步,然后该进入主界面了,但后面被登陆验证的过滤器拦截,得不到登陆时写入session,判定为没有登录,返回登陆页面.

有部署过类似Java项目到SAE上的同学帮个忙啊~~~ 查看全部
使用Java Web做了一个签到系统,使用的是Struts2 + ExtJs4 + BoneCP + Mysql。

准备部署到Sina SAE上面,之前部署微信公众号开发的的Java程序一点问题都没有,但是部署这个应用问题一堆。不过之前的应用使用的是Servlet,没有使用任何框架。

先说一个部署问题,大致是将war包上传之后,在SAE中的日志系统中的JVM日志有以下错误:

java.lang.IllegalStateException: class com.cxl.signin.filter.AuthFilter is not a javax.servlet.Filter

然后输入二级域名,发现前台显示也是报错的:

Error 404 - Not Found.No context on this server matched or handled this request.
Contexts known to this server are:...(后面是关于个人应用的一些乱鸡巴遭的东西)

最终在一个英文的讨论论坛找到了一个相关的回答:
My top-of-the-brain guess would be that you have two servlet JARs in your classpath, and jetty is using one but your WAR is using another.
Really weird error though, for sure.

大致意思是那哥们看到这个问题,第一感觉就是项目classpath里面有两个servlet jar包,服务器jetty使用一个,你的war包使用的另一个。

我想应该是sina的服务器classpath里面就有了servlet-api.jar包了,于是我删掉了web-INF/lib下面的这个包,上传,不报错,首页可以打开。我的二级域名为sign.sinaapp.com/login.jsp,大家测试。

另外还有一个需要注意的是:请不要用jre7的版本去编译你的项目...

除此之外,项目还有其他的问题,就是session问题,我Java开的是4个虚拟机,登陆的时候明明已经运行到登陆成功,session写入的那一步,然后该进入主界面了,但后面被登陆验证的过滤器拦截,得不到登陆时写入session,判定为没有登录,返回登陆页面.

有部署过类似Java项目到SAE上的同学帮个忙啊~~~

使用Java JMF技术编写视频播放器

图像/多媒体atool 发表了文章 • 0 个评论 • 698 次浏览 • 2016-04-22 11:21 • 来自相关话题

Java JMF意为Java媒体框架(JMF)。该核心框架支持不同媒体(如:音频输出和视频输出)间的时钟同步。它是一个标准的扩展框架,允许用户制作纯音频流和视频流。
下面的代码展示的是利用JMF和Java Swing编写的一个简单的视频播放器,因此运行这段代码,首先请安装JMF,安装地址,自己百度Google,完整代码如下:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.media.CannotRealizeException;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.EndOfMediaEvent;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.NoPlayerException;
import javax.media.Player;
import javax.media.PrefetchCompleteEvent;
import javax.media.RealizeCompleteEvent;
import javax.media.Time;
@SuppressWarnings({ "restriction", "unused" })
public class JMFSample implements ControllerListener {
public static void main(String[] args) {
JMFSample sp = new JMFSample();
sp.play();
}

private Player mediaPlayer;
private Frame f;
private Player player;
private Panel panel;
private Component visual;
private Component control = null;

public void play(){
f = new Frame("JMF Sample1");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
if(player != null) {
player.close();
}
System.exit(0);
}
});
f.setSize(500,400);
f.setVisible(true);
URL url = null;
try {
//准备一个要播放的视频文件的URL
url = new URL("file:/d:/2.mpg");
} catch (MalformedURLException e) {
e.printStackTrace();
}
try {
//通过调用Manager的createPlayer方法来创建一个Player的对象
//这个对象是媒体播放的核心控制对象
player = Manager.createPlayer(url);
} catch (NoPlayerException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
//对player对象注册监听器,能噶偶在相关事件发生的时候执行相关的动作
player.addControllerListener(this);

//让player对象进行相关的资源分配
player.realize();
}

private int videoWidth = 0;
private int videoHeight = 0;
private int controlHeight = 30;
private int insetWidth = 10;
private int insetHeight = 30;

//监听player的相关事件
public void controllerUpdate(ControllerEvent ce) {
if (ce instanceof RealizeCompleteEvent) {
//player实例化完成后进行player播放前预处理
player.prefetch();
} else if (ce instanceof PrefetchCompleteEvent) {
if (visual != null)
return;
//取得player中的播放视频的组件,并得到视频窗口的大小
//然后把视频窗口的组件添加到Frame窗口中,
if ((visual = player.getVisualComponent()) != null) {
Dimension size = visual.getPreferredSize();
videoWidth = size.width;
videoHeight = size.height;
f.add(visual);
} else {
videoWidth = 320;
}

//取得player中的视频播放控制条组件,并把该组件添加到Frame窗口中
if ((control = player.getControlPanelComponent()) != null) {
controlHeight = control.getPreferredSize().height;
f.add(control, BorderLayout.SOUTH);
}

//设定Frame窗口的大小,使得满足视频文件的默认大小
f.setSize(videoWidth + insetWidth, videoHeight + controlHeight + insetHeight);
f.validate();

//启动视频播放组件开始播放
player.start();
mediaPlayer.start();
} else if (ce instanceof EndOfMediaEvent) {
//当播放视频完成后,把时间进度条恢复到开始,并再次重新开始播放
player.setMediaTime(new Time(0));
player.start();
}
}
}JMF是专门用于做Java多媒体开发的。对于视频播放就是支持的格式少了一些,这个视频播放器可以播放mpg,avi,flv等等,想播放其他的请开发自己的插件。另外需要注明的是,有些不规范的avi格式的视频播放可能也会有问题。
下图是基于JMF和FFMPEG做的视频播放以及车牌识别定位的截图: 查看全部
Java JMF意为Java媒体框架(JMF)。该核心框架支持不同媒体(如:音频输出和视频输出)间的时钟同步。它是一个标准的扩展框架,允许用户制作纯音频流和视频流。
下面的代码展示的是利用JMF和Java Swing编写的一个简单的视频播放器,因此运行这段代码,首先请安装JMF,安装地址,自己百度Google,完整代码如下:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.media.CannotRealizeException;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.EndOfMediaEvent;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.NoPlayerException;
import javax.media.Player;
import javax.media.PrefetchCompleteEvent;
import javax.media.RealizeCompleteEvent;
import javax.media.Time;
@SuppressWarnings({ "restriction", "unused" })
public class JMFSample implements ControllerListener {
public static void main(String[] args) {
JMFSample sp = new JMFSample();
sp.play();
}

private Player mediaPlayer;
private Frame f;
private Player player;
private Panel panel;
private Component visual;
private Component control = null;

public void play(){
f = new Frame("JMF Sample1");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
if(player != null) {
player.close();
}
System.exit(0);
}
});
f.setSize(500,400);
f.setVisible(true);
URL url = null;
try {
//准备一个要播放的视频文件的URL
url = new URL("file:/d:/2.mpg");
} catch (MalformedURLException e) {
e.printStackTrace();
}
try {
//通过调用Manager的createPlayer方法来创建一个Player的对象
//这个对象是媒体播放的核心控制对象
player = Manager.createPlayer(url);
} catch (NoPlayerException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
//对player对象注册监听器,能噶偶在相关事件发生的时候执行相关的动作
player.addControllerListener(this);

//让player对象进行相关的资源分配
player.realize();
}

private int videoWidth = 0;
private int videoHeight = 0;
private int controlHeight = 30;
private int insetWidth = 10;
private int insetHeight = 30;

//监听player的相关事件
public void controllerUpdate(ControllerEvent ce) {
if (ce instanceof RealizeCompleteEvent) {
//player实例化完成后进行player播放前预处理
player.prefetch();
} else if (ce instanceof PrefetchCompleteEvent) {
if (visual != null)
return;
//取得player中的播放视频的组件,并得到视频窗口的大小
//然后把视频窗口的组件添加到Frame窗口中,
if ((visual = player.getVisualComponent()) != null) {
Dimension size = visual.getPreferredSize();
videoWidth = size.width;
videoHeight = size.height;
f.add(visual);
} else {
videoWidth = 320;
}

//取得player中的视频播放控制条组件,并把该组件添加到Frame窗口中
if ((control = player.getControlPanelComponent()) != null) {
controlHeight = control.getPreferredSize().height;
f.add(control, BorderLayout.SOUTH);
}

//设定Frame窗口的大小,使得满足视频文件的默认大小
f.setSize(videoWidth + insetWidth, videoHeight + controlHeight + insetHeight);
f.validate();

//启动视频播放组件开始播放
player.start();
mediaPlayer.start();
} else if (ce instanceof EndOfMediaEvent) {
//当播放视频完成后,把时间进度条恢复到开始,并再次重新开始播放
player.setMediaTime(new Time(0));
player.start();
}
}
}
JMF是专门用于做Java多媒体开发的。对于视频播放就是支持的格式少了一些,这个视频播放器可以播放mpg,avi,flv等等,想播放其他的请开发自己的插件。另外需要注明的是,有些不规范的avi格式的视频播放可能也会有问题。
下图是基于JMF和FFMPEG做的视频播放以及车牌识别定位的截图:
13659471585430.jpg

Java中java.util.PriorityQueue优先级队列使用方法

编程语言atool 发表了文章 • 0 个评论 • 463 次浏览 • 2016-04-22 11:10 • 来自相关话题

PriorityQueue是个基于优先级堆的极大优先级队列。
此队列按照在构造时所指定的顺序对元素排序,既可以根据元素的自然顺序来指定排序(参阅 Comparable),也可以根据 Comparator 来指定,这取决于使用哪种构造方法。优先级队列不允许 null 元素。依靠自然排序的优先级队列还不允许插入不可比较的对象(这样做可能导致 ClassCastException)。比如队列 1 3 5 10 2 自动会被排列 1 2 3 5 10。测试代码如下:
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;

public class PriorityQueueExample {
public static void main(String[] args) {
Queue<Integer> qi = new PriorityQueue<Integer>();

qi.add(5);
qi.add(2);
qi.add(1);
qi.add(10);
qi.add(3);

while (!qi.isEmpty()){
System.out.print(qi.poll() + ",");
}
System.out.println();
System.out.println("-----------------------------");
//自定义比较器
Comparator<Integer> cmp;
cmp = new Comparator<Integer>() {
public int compare(Integer e1, Integer e2) {
return e2 - e1;
}
};
Queue<Integer> q2 = new PriorityQueue<Integer>(5,cmp);
q2.add(2);
q2.add(8);
q2.add(9);
q2.add(1);
while (!q2.isEmpty()){
System.out.print(q2.poll() + ",");
}
}
}输出结果如下:
output

1,2,3,5,10,
-----------------------------
9,8,2,1,

代码中的自定义的比较器,可以让我们自由定义比较的顺序:
//自定义比较器
Comparator<Integer> cmp;
cmp = new Comparator<Integer>() {
public int compare(Integer e1, Integer e2) {
return e2 - e1;
}
};

此队列的头是按指定排序方式的最小元素。如果多个元素都是最小值,则头是其中一个元素——选择方法是任意的。队列检索操作 poll、remove、peek 和 element 访问处于队列头的元素。优先级队列是无界的,但是有一个内部容量,控制着用于存储队列元素的数组的大小。它总是至少与队列的大小相同。随着不断向优先级队列添加元素,其容量会自动增加。无需指定容量增加策略的细节。

注意1:该队列是用数组实现,但是数组大小可以动态增加,容量无限。

注意2:此实现不是同步的。不是线程安全的。如果多个线程中的任意线程从结构上修改了列表, 则这些线程不应同时访问 PriorityQueue。实例,这时请使用线程安全的PriorityBlockingQueue 类。

注意3:不允许使用 null 元素。

注意4:此实现为插入方法(offer、poll、remove() 和 add 方法)提供 O(log(n)) 时间;为 remove(Object) 和 contains(Object)方法提供线性时间;为检索方法(peek、element 和 size)提供固定时间。

注意5:方法iterator()中提供的迭代器并不保证以有序的方式遍历优先级队列中的元素。至于原因可参考下面关于PriorityQueue的内部实现如果需要按顺序遍历,请考虑使用 Arrays.sort(pq.toArray())。

注意6:可以在构造函数中指定如何排序。如:PriorityQueue()使用默认的初始容量(11)创建一个 PriorityQueue,并根据其自然顺序来排序其元素(使用 Comparable)。PriorityQueue(int initialCapacity)使用指定的初始容量创建一个 PriorityQueue,并根据其自然顺序来排序其元素(使用 Comparable)。PriorityQueue(int initialCapacity, Comparator comparator)。使用指定的初始容量创建一个PriorityQueue,并根据指定的比较器comparator来排序其元素。

注意7:此类及其迭代器实现了 Collection 和 Iterator 接口的所有可选 方法。PriorityQueue的内部实现。PriorityQueue对元素采用的是堆排序,头是按指定排序方式的最小元素。堆排序只能保证根是最大(最小),整个堆并不是有序的。方法iterator()中提供的迭代器可能只是对整个数组的依次遍历。也就只能保证数组的第一个元素是最小的。实例1的结果也正好与此相符。 查看全部
PriorityQueue是个基于优先级堆的极大优先级队列。
此队列按照在构造时所指定的顺序对元素排序,既可以根据元素的自然顺序来指定排序(参阅 Comparable),也可以根据 Comparator 来指定,这取决于使用哪种构造方法。优先级队列不允许 null 元素。依靠自然排序的优先级队列还不允许插入不可比较的对象(这样做可能导致 ClassCastException)。比如队列 1 3 5 10 2 自动会被排列 1 2 3 5 10。测试代码如下:
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;

public class PriorityQueueExample {
public static void main(String[] args) {
Queue<Integer> qi = new PriorityQueue<Integer>();

qi.add(5);
qi.add(2);
qi.add(1);
qi.add(10);
qi.add(3);

while (!qi.isEmpty()){
System.out.print(qi.poll() + ",");
}
System.out.println();
System.out.println("-----------------------------");
//自定义比较器
Comparator<Integer> cmp;
cmp = new Comparator<Integer>() {
public int compare(Integer e1, Integer e2) {
return e2 - e1;
}
};
Queue<Integer> q2 = new PriorityQueue<Integer>(5,cmp);
q2.add(2);
q2.add(8);
q2.add(9);
q2.add(1);
while (!q2.isEmpty()){
System.out.print(q2.poll() + ",");
}
}
}
输出结果如下:
output

1,2,3,5,10,
-----------------------------
9,8,2,1,

代码中的自定义的比较器,可以让我们自由定义比较的顺序:
//自定义比较器
Comparator<Integer> cmp;
cmp = new Comparator<Integer>() {
public int compare(Integer e1, Integer e2) {
return e2 - e1;
}
};

此队列的头是按指定排序方式的最小元素。如果多个元素都是最小值,则头是其中一个元素——选择方法是任意的。队列检索操作 poll、remove、peek 和 element 访问处于队列头的元素。优先级队列是无界的,但是有一个内部容量,控制着用于存储队列元素的数组的大小。它总是至少与队列的大小相同。随着不断向优先级队列添加元素,其容量会自动增加。无需指定容量增加策略的细节。

注意1:该队列是用数组实现,但是数组大小可以动态增加,容量无限。

注意2:此实现不是同步的。不是线程安全的。如果多个线程中的任意线程从结构上修改了列表, 则这些线程不应同时访问 PriorityQueue。实例,这时请使用线程安全的PriorityBlockingQueue 类。

注意3:不允许使用 null 元素。

注意4:此实现为插入方法(offer、poll、remove() 和 add 方法)提供 O(log(n)) 时间;为 remove(Object) 和 contains(Object)方法提供线性时间;为检索方法(peek、element 和 size)提供固定时间。

注意5:方法iterator()中提供的迭代器并不保证以有序的方式遍历优先级队列中的元素。至于原因可参考下面关于PriorityQueue的内部实现如果需要按顺序遍历,请考虑使用 Arrays.sort(pq.toArray())。

注意6:可以在构造函数中指定如何排序。如:PriorityQueue()使用默认的初始容量(11)创建一个 PriorityQueue,并根据其自然顺序来排序其元素(使用 Comparable)。PriorityQueue(int initialCapacity)使用指定的初始容量创建一个 PriorityQueue,并根据其自然顺序来排序其元素(使用 Comparable)。PriorityQueue(int initialCapacity, Comparator comparator)。使用指定的初始容量创建一个PriorityQueue,并根据指定的比较器comparator来排序其元素。

注意7:此类及其迭代器实现了 Collection 和 Iterator 接口的所有可选 方法。PriorityQueue的内部实现。PriorityQueue对元素采用的是堆排序,头是按指定排序方式的最小元素。堆排序只能保证根是最大(最小),整个堆并不是有序的。方法iterator()中提供的迭代器可能只是对整个数组的依次遍历。也就只能保证数组的第一个元素是最小的。实例1的结果也正好与此相符。

Java元组Tuple使用实例

编程语言atool 发表了文章 • 0 个评论 • 2228 次浏览 • 2016-04-22 11:07 • 来自相关话题

一、为什么使用元组tuple?
元组和列表list一样,都可能用于数据存储,包含多个数据;但是和列表不同的是:列表只能存储相同的数据类型,而元组不一样,它可以存储不同的数据类型,比如同时存储int、string、list等,并且可以根据需求无限扩展。
比如说在web应用中,经常会遇到一个问题就是数据分页问题,查询分页需要包含几点信息:当前页数、页大小;查询结果返回数据为:当前页的数据记录,但是如果需要在前台显示当前页、页大小、总页数等信息的时候,就必须有另外一个信息就是:数据记录总数,然后根据上面的信息进行计算得到总页数等信息。这个时候查询某一页信息的时候需要返回两个数据类型,一个是list(当前也的数据记录),一个是int(记录总数)。当然,完全可以在两个方法、两次数据库连接中得到这两个值。事实上在查询list的时候,已经通过sql查询得到总计录数,如果再开一个方法,再做一次数据库连接来查询总计录数,不免有点多此一举、浪费时间、浪费代码、浪费生命。言重了~在这种情况下,我们就可以利用二元组,在一次数据库连接中,得到总计录数、当前页记录,并存储到其中,简单明了!

二、源码实例
二元组:
/** <p>Title: TwoTuple</p>
* <p>Description: 两个元素的元组,用于在一个方法里返回两种类型的值</p>
* @author Xewee.Zhiwei.Wang@gmail.com
* @site http://wzwahl36.net
* @version 2012-3-21 上午11:15:03
* @param <A>
* @param <B>
*/
public class TwoTuple<A, B> {
public final A first;
public final B second;

public TwoTuple(A a, B b) {
this.first = a;
this.second = b;
}
}扩展为三元组(按此可以任意扩展)
/**
* <p>Title: ThreeTuple</p>
* <p>Description: 三个元素的元组,用于在一个方法里返回三种类型的值</p>
* @author Xewee.Zhiwei.Wang@gmail.com
* @site http://wzwahl36.net
* @version 2012-3-21 上午11:15:50
* @param <A>
* @param <B>
* @param <C>
*/
public class ThreeTuple<A, B, C> extends TwoTuple<A, B> {
public final C third;

public ThreeTuple(A a, B b, C c) {
super(a, b);
this.third = c;
}
}元组操作工具类、测试类(可按需自定义)

import java.util.ArrayList;
import java.util.List;
 
import com.bluesea.bean.GoodsBean;
 
/**
 * <p>Title: TupleUtil</p>
 * <p>Description:
 * 元组辅助类,用于多种类型值的返回,如在分页的时候,后台存储过程既返回了查询得到的
 * 当页的数据(List类型),又得到了数据表中总共的数据总数(Integer类型),然后将这
 * 两个参数封装到该类中返回到action中使用
 * 使用泛型方法实现,利用参数类型推断,编译器可以找出具体的类型
 * </p>
 * @author Xewee.Zhiwei.Wang@gmail.com
 * @site http://wzwahl36.net
 * @version 2012-3-21 上午09:59:39
 * @param <A>
 * @param <B>
 */
public class TupleUtil {
     
    public static <A, B> TwoTuple<A, B> tuple(A a, B b) {
        return new TwoTuple<A, B>(a, b);
    }
     
    public static <A, B, C> ThreeTuple<A, B, C> tuple(A a, B b, C c) {
        return new ThreeTuple<A, B, C>(a, b, c);
    }
 
    // 测试
    public static void main(String[] args) {
        List<GoodsBean> goodsBeans = new ArrayList<GoodsBean>();
        for(int i = 1; i < 26; i++) {
            GoodsBean goodsBean = new GoodsBean();
            goodsBean.setGoodsId(i);
            goodsBeans.add(goodsBean);
        }
        Integer totalProperty = 47;
//      TupleUtil<List<GoodsBean>, Integer> tupleUtil = new TupleUtil<List<GoodsBean>, Integer>(goodsBeans, totalProperty);
        TwoTuple<List<GoodsBean>, Integer> twoTuple = TupleUtil.tuple(goodsBeans, totalProperty);
        List<GoodsBean> list = twoTuple.first;
        System.out.println(list);
        System.out.println(twoTuple.second);
    }
}
三、Demo下载
搬到SAE上之后,链接丢失,Demo为以上几个文件打包,请自行处理。 查看全部
一、为什么使用元组tuple?
元组和列表list一样,都可能用于数据存储,包含多个数据;但是和列表不同的是:列表只能存储相同的数据类型,而元组不一样,它可以存储不同的数据类型,比如同时存储int、string、list等,并且可以根据需求无限扩展。
比如说在web应用中,经常会遇到一个问题就是数据分页问题,查询分页需要包含几点信息:当前页数、页大小;查询结果返回数据为:当前页的数据记录,但是如果需要在前台显示当前页、页大小、总页数等信息的时候,就必须有另外一个信息就是:数据记录总数,然后根据上面的信息进行计算得到总页数等信息。这个时候查询某一页信息的时候需要返回两个数据类型,一个是list(当前也的数据记录),一个是int(记录总数)。当然,完全可以在两个方法、两次数据库连接中得到这两个值。事实上在查询list的时候,已经通过sql查询得到总计录数,如果再开一个方法,再做一次数据库连接来查询总计录数,不免有点多此一举、浪费时间、浪费代码、浪费生命。言重了~在这种情况下,我们就可以利用二元组,在一次数据库连接中,得到总计录数、当前页记录,并存储到其中,简单明了!

二、源码实例
二元组:
/** <p>Title: TwoTuple</p>
* <p>Description: 两个元素的元组,用于在一个方法里返回两种类型的值</p>
* @author Xewee.Zhiwei.Wang@gmail.com
* @site http://wzwahl36.net
* @version 2012-3-21 上午11:15:03
* @param <A>
* @param <B>
*/
public class TwoTuple<A, B> {
public final A first;
public final B second;

public TwoTuple(A a, B b) {
this.first = a;
this.second = b;
}
}
扩展为三元组(按此可以任意扩展)
/**
* <p>Title: ThreeTuple</p>
* <p>Description: 三个元素的元组,用于在一个方法里返回三种类型的值</p>
* @author Xewee.Zhiwei.Wang@gmail.com
* @site http://wzwahl36.net
* @version 2012-3-21 上午11:15:50
* @param <A>
* @param <B>
* @param <C>
*/
public class ThreeTuple<A, B, C> extends TwoTuple<A, B> {
public final C third;

public ThreeTuple(A a, B b, C c) {
super(a, b);
this.third = c;
}
}
元组操作工具类、测试类(可按需自定义)

import java.util.ArrayList;
import java.util.List;
 
import com.bluesea.bean.GoodsBean;
 
/**
 * <p>Title: TupleUtil</p>
 * <p>Description:
 * 元组辅助类,用于多种类型值的返回,如在分页的时候,后台存储过程既返回了查询得到的
 * 当页的数据(List类型),又得到了数据表中总共的数据总数(Integer类型),然后将这
 * 两个参数封装到该类中返回到action中使用
 * 使用泛型方法实现,利用参数类型推断,编译器可以找出具体的类型
 * </p>
 * @author Xewee.Zhiwei.Wang@gmail.com
 * @site http://wzwahl36.net
 * @version 2012-3-21 上午09:59:39
 * @param <A>
 * @param <B>
 */
public class TupleUtil {
     
    public static <A, B> TwoTuple<A, B> tuple(A a, B b) {
        return new TwoTuple<A, B>(a, b);
    }
     
    public static <A, B, C> ThreeTuple<A, B, C> tuple(A a, B b, C c) {
        return new ThreeTuple<A, B, C>(a, b, c);
    }
 
    // 测试
    public static void main(String[] args) {
        List<GoodsBean> goodsBeans = new ArrayList<GoodsBean>();
        for(int i = 1; i < 26; i++) {
            GoodsBean goodsBean = new GoodsBean();
            goodsBean.setGoodsId(i);
            goodsBeans.add(goodsBean);
        }
        Integer totalProperty = 47;
//      TupleUtil<List<GoodsBean>, Integer> tupleUtil = new TupleUtil<List<GoodsBean>, Integer>(goodsBeans, totalProperty);
        TwoTuple<List<GoodsBean>, Integer> twoTuple = TupleUtil.tuple(goodsBeans, totalProperty);
        List<GoodsBean> list = twoTuple.first;
        System.out.println(list);
        System.out.println(twoTuple.second);
    }
}
三、Demo下载
搬到SAE上之后,链接丢失,Demo为以上几个文件打包,请自行处理。

微信公众号消息接口开发——Java Servlet开发

编程语言atool 发表了文章 • 0 个评论 • 1206 次浏览 • 2016-04-22 11:02 • 来自相关话题

张小龙搞出来的微信真的很牛逼啊,短短两三年就2亿用户量,这个数据似乎在警告QQ部门,IM软件上,你们QQ的老大位置并不稳固,仍需努力。当然QQ和微信不是一个平台上的产品,并不存在很大的竞争问题。

微信公众号消息接口API只有相当于只有一个简单调用链接,但是却完全改变了最初微信公众号的概念。不过说实话,这个接口真的设计的不怎么的...验证过程个字符处理啊,加密啊,拼接啊毫无用处,在申请页面填写的token也毫无用处,这些都是题外话了。不管这个接口腾讯设计得好不好,我们需要关心的是我们利用这个接口能够做什么,怎么做?

废话少说,言归正传,微信官网给我们提供了PHP的例子,所以做PHP的同学只需要画瓢即可,对于Java平台,网上还没有人说起,欲知Java平台怎么开发微信公众号接口,请看下文:

下面列出使用Java Servlet开发的一个简单的微信公众号接口调用的例子,如果有疑问,可以参见我本博的微信公众号:红色石头。

另外,我想大家一定很想知道《模拟登录微信公众平台,主动推送图文消息给用户》的有关信息。点开即可看到了~~~




 
package com.wzwcxl.pubwx.hustac.pubwx;

import java.io.IOException;
import java.io.InputStream;

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

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import com.wzwcxl.pubwx.hustac.util.StringUtil;

/**
* 微信公众号接口调用Java版
* @author Xewee.Zhiwei.Wang
* @version 2012-12-17 上午9:16:02
* @Contract wzwahl36@QQ.com or http://wzwahl36.net/
*/
public class Test extends HttpServlet {
private static final long serialVersionUID = 1L;

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("----------get---------------");
// response.getWriter().write(request.getParameter("echostr"));
doPost(request, response);
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("----------post---------------");
try {
InputStream is = request.getInputStream();
// 取HTTP请求流长度
int size = request.getContentLength();
// 用于缓存每次读取的数据
byte[] buffer = new byte[size];
// 用于存放结果的数组
byte[] xmldataByte = new byte[size];
int count = 0;
int rbyte = 0;
// 循环读取
while (count < size) {
// 每次实际读取长度存于rbyte中
rbyte = is.read(buffer);
for(int i=0;i<rbyte;i++) {
xmldataByte[count + i] = buffer[i];
}
count += rbyte;
}
is.close();
String requestStr = new String(xmldataByte, "UTF-8");
Document doc = DocumentHelper.parseText(requestStr);
Element rootElt = doc.getRootElement();
String content = rootElt.elementText("Content");
String toUserName = rootElt.elementText("ToUserName");
String fromUserName = rootElt.elementText("FromUserName");
//得到所有的有用数据
System.out.println(content+ ":" + toUserName + ":" + fromUserName);
//文本消息
if (! StringUtil.isBlank(content) && "text".equals(content)) {
String responseStr = "<xml>";
responseStr += "<ToUserName><![CDATA[" + fromUserName
+ "]]></ToUserName>";
responseStr += "<FromUserName><![CDATA[" + toUserName
+ "]]></FromUserName>";
responseStr += "<CreateTime>" + System.currentTimeMillis()
+ "</CreateTime>";
responseStr += "<MsgType><![CDATA[text]]></MsgType>";
responseStr += "<Content>输入text或者news返回相应类型的消息,另外推荐你关注 '红色石头'(完全采用Java完成),反馈和建议请到http://wzwahl36.net</Content>";
responseStr += "<FuncFlag>0</FuncFlag>";
responseStr += "</xml>";
response.getWriter().write(responseStr);
}
//图文消息
else if (! StringUtil.isBlank(content) && "news".equals(content)) {
String responseStr = "<xml>";
responseStr += "<ToUserName><![CDATA[" + fromUserName
+ "]]></ToUserName>";
responseStr += "<FromUserName><![CDATA[" + toUserName
+ "]]></FromUserName>";
responseStr += "<CreateTime>" + System.currentTimeMillis()
+ "</CreateTime>";
responseStr += "<MsgType><![CDATA[news]]></MsgType>";
responseStr += "<Content><![CDATA[]]></Content>";

responseStr += "<ArticleCount>2</ArticleCount>";

responseStr += "<Articles>";
responseStr += "<item>";
responseStr += "<Title><![CDATA[图文消息——红色石头]]></Title>";
responseStr += "<Discription><![CDATA[图文消息正文——红色石头]]></Discription>";
responseStr += "<PicUrl><![CDATA[http://redstones.sinaapp.com/res/images/redstones_wx_258.jpg]]></PicUrl>";
responseStr += "<Url><![CDATA[http://redstones.sinaapp.com/]]></Url>";
responseStr += "</item>";

responseStr += "<item>";
responseStr += "<Title><![CDATA[图文消息——红色石头]]></Title>";
responseStr += "<Discription><![CDATA[图文消息正文——红色石头]]></Discription>";
responseStr += "<PicUrl><![CDATA[http://redstones.sinaapp.com/res/images/redstones_wx_258.jpg]]></PicUrl>";
responseStr += "<Url><![CDATA[http://redstones.sinaapp.com/]]></Url>";
responseStr += "</item>";

responseStr += "</Articles>";
responseStr += "<FuncFlag>1</FuncFlag>";
responseStr += "</xml>";
response.getWriter().write(responseStr);
}
//不能识别
else {
String responseStr = "<xml>";
responseStr += "<ToUserName><![CDATA[" + fromUserName
+ "]]></ToUserName>";
responseStr += "<FromUserName><![CDATA[" + toUserName
+ "]]></FromUserName>";
responseStr += "<CreateTime>" + System.currentTimeMillis()
+ "</CreateTime>";
responseStr += "<MsgType><![CDATA[text]]></MsgType>";
responseStr += "<Content>输入text或者news返回相应类型的消息,另外推荐你关注 '红色石头'(完全采用Java完成),反馈和建议请到http://wzwahl36.net</Content>";
responseStr += "<FuncFlag>0</FuncFlag>";
responseStr += "</xml>";
response.getWriter().write(responseStr);
}

} catch (Exception e) {
e.printStackTrace();
}
}
}需要注意是一点是:在验证链接时,将get方法写为以下:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("----------get---------------");
response.getWriter().write(request.getParameter("echostr"));
// doPost(request, response);
}
验证通过之后,将get方法和post方法写成一样的。
另外注意servlet的编码问题,我这个servlet里面没有写编码是因为我设置了编码过滤器:
package com.wzwcxl.pubwx.hustac.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
* Servlet Filter implementation class EncodingFilter
*/
public class EncodingFilter implements Filter {

/**
* Default constructor.
*/
public EncodingFilter() {
// TODO Auto-generated constructor stub
}

/**
* @see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}

/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
System.out.println("EncodingFilter: UTF-8");

chain.doFilter(request, response);
}

/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
}
}附加:很多人问到代码中的StringUtil类中的isBlank方法是什么?然后要我发给他,其实StringUtil只有isBlank方法,这个方法就是用来判断字符串是不是空,所谓字符串为空,就是等于null或者trim之后为"",每次问到这个我都不知道怎么回答,所以在这里附加说明一下~

Enjoy~有空点点广告,感谢~~~ 查看全部
张小龙搞出来的微信真的很牛逼啊,短短两三年就2亿用户量,这个数据似乎在警告QQ部门,IM软件上,你们QQ的老大位置并不稳固,仍需努力。当然QQ和微信不是一个平台上的产品,并不存在很大的竞争问题。

微信公众号消息接口API只有相当于只有一个简单调用链接,但是却完全改变了最初微信公众号的概念。不过说实话,这个接口真的设计的不怎么的...验证过程个字符处理啊,加密啊,拼接啊毫无用处,在申请页面填写的token也毫无用处,这些都是题外话了。不管这个接口腾讯设计得好不好,我们需要关心的是我们利用这个接口能够做什么,怎么做?

废话少说,言归正传,微信官网给我们提供了PHP的例子,所以做PHP的同学只需要画瓢即可,对于Java平台,网上还没有人说起,欲知Java平台怎么开发微信公众号接口,请看下文:

下面列出使用Java Servlet开发的一个简单的微信公众号接口调用的例子,如果有疑问,可以参见我本博的微信公众号:红色石头。

另外,我想大家一定很想知道《模拟登录微信公众平台,主动推送图文消息给用户》的有关信息。点开即可看到了~~~
redstones_wx_430.jpg

 
package com.wzwcxl.pubwx.hustac.pubwx;

import java.io.IOException;
import java.io.InputStream;

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

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import com.wzwcxl.pubwx.hustac.util.StringUtil;

/**
* 微信公众号接口调用Java版
* @author Xewee.Zhiwei.Wang
* @version 2012-12-17 上午9:16:02
* @Contract wzwahl36@QQ.com or http://wzwahl36.net/
*/
public class Test extends HttpServlet {
private static final long serialVersionUID = 1L;

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("----------get---------------");
// response.getWriter().write(request.getParameter("echostr"));
doPost(request, response);
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("----------post---------------");
try {
InputStream is = request.getInputStream();
// 取HTTP请求流长度
int size = request.getContentLength();
// 用于缓存每次读取的数据
byte[] buffer = new byte[size];
// 用于存放结果的数组
byte[] xmldataByte = new byte[size];
int count = 0;
int rbyte = 0;
// 循环读取
while (count < size) {
// 每次实际读取长度存于rbyte中
rbyte = is.read(buffer);
for(int i=0;i<rbyte;i++) {
xmldataByte[count + i] = buffer[i];
}
count += rbyte;
}
is.close();
String requestStr = new String(xmldataByte, "UTF-8");
Document doc = DocumentHelper.parseText(requestStr);
Element rootElt = doc.getRootElement();
String content = rootElt.elementText("Content");
String toUserName = rootElt.elementText("ToUserName");
String fromUserName = rootElt.elementText("FromUserName");
//得到所有的有用数据
System.out.println(content+ ":" + toUserName + ":" + fromUserName);
//文本消息
if (! StringUtil.isBlank(content) && "text".equals(content)) {
String responseStr = "<xml>";
responseStr += "<ToUserName><![CDATA[" + fromUserName
+ "]]></ToUserName>";
responseStr += "<FromUserName><![CDATA[" + toUserName
+ "]]></FromUserName>";
responseStr += "<CreateTime>" + System.currentTimeMillis()
+ "</CreateTime>";
responseStr += "<MsgType><![CDATA[text]]></MsgType>";
responseStr += "<Content>输入text或者news返回相应类型的消息,另外推荐你关注 '红色石头'(完全采用Java完成),反馈和建议请到http://wzwahl36.net</Content>";
responseStr += "<FuncFlag>0</FuncFlag>";
responseStr += "</xml>";
response.getWriter().write(responseStr);
}
//图文消息
else if (! StringUtil.isBlank(content) && "news".equals(content)) {
String responseStr = "<xml>";
responseStr += "<ToUserName><![CDATA[" + fromUserName
+ "]]></ToUserName>";
responseStr += "<FromUserName><![CDATA[" + toUserName
+ "]]></FromUserName>";
responseStr += "<CreateTime>" + System.currentTimeMillis()
+ "</CreateTime>";
responseStr += "<MsgType><![CDATA[news]]></MsgType>";
responseStr += "<Content><![CDATA[]]></Content>";

responseStr += "<ArticleCount>2</ArticleCount>";

responseStr += "<Articles>";
responseStr += "<item>";
responseStr += "<Title><![CDATA[图文消息——红色石头]]></Title>";
responseStr += "<Discription><![CDATA[图文消息正文——红色石头]]></Discription>";
responseStr += "<PicUrl><![CDATA[http://redstones.sinaapp.com/res/images/redstones_wx_258.jpg]]></PicUrl>";
responseStr += "<Url><![CDATA[http://redstones.sinaapp.com/]]></Url>";
responseStr += "</item>";

responseStr += "<item>";
responseStr += "<Title><![CDATA[图文消息——红色石头]]></Title>";
responseStr += "<Discription><![CDATA[图文消息正文——红色石头]]></Discription>";
responseStr += "<PicUrl><![CDATA[http://redstones.sinaapp.com/res/images/redstones_wx_258.jpg]]></PicUrl>";
responseStr += "<Url><![CDATA[http://redstones.sinaapp.com/]]></Url>";
responseStr += "</item>";

responseStr += "</Articles>";
responseStr += "<FuncFlag>1</FuncFlag>";
responseStr += "</xml>";
response.getWriter().write(responseStr);
}
//不能识别
else {
String responseStr = "<xml>";
responseStr += "<ToUserName><![CDATA[" + fromUserName
+ "]]></ToUserName>";
responseStr += "<FromUserName><![CDATA[" + toUserName
+ "]]></FromUserName>";
responseStr += "<CreateTime>" + System.currentTimeMillis()
+ "</CreateTime>";
responseStr += "<MsgType><![CDATA[text]]></MsgType>";
responseStr += "<Content>输入text或者news返回相应类型的消息,另外推荐你关注 '红色石头'(完全采用Java完成),反馈和建议请到http://wzwahl36.net</Content>";
responseStr += "<FuncFlag>0</FuncFlag>";
responseStr += "</xml>";
response.getWriter().write(responseStr);
}

} catch (Exception e) {
e.printStackTrace();
}
}
}
需要注意是一点是:在验证链接时,将get方法写为以下:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("----------get---------------");
response.getWriter().write(request.getParameter("echostr"));
// doPost(request, response);
}
验证通过之后,将get方法和post方法写成一样的。
另外注意servlet的编码问题,我这个servlet里面没有写编码是因为我设置了编码过滤器:
package com.wzwcxl.pubwx.hustac.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
* Servlet Filter implementation class EncodingFilter
*/
public class EncodingFilter implements Filter {

/**
* Default constructor.
*/
public EncodingFilter() {
// TODO Auto-generated constructor stub
}

/**
* @see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}

/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
System.out.println("EncodingFilter: UTF-8");

chain.doFilter(request, response);
}

/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
}
}
附加:很多人问到代码中的StringUtil类中的isBlank方法是什么?然后要我发给他,其实StringUtil只有isBlank方法,这个方法就是用来判断字符串是不是空,所谓字符串为空,就是等于null或者trim之后为"",每次问到这个我都不知道怎么回答,所以在这里附加说明一下~

Enjoy~有空点点广告,感谢~~~