微信公共平台 java api 实现


package cn.com.softvan.common.wechat;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.log4j.Logger;

import cn.com.softvan.bean.wechat.TcWxMenuBean;
import cn.com.softvan.bean.wechat.TcWxUserBean;
import cn.com.softvan.common.CommonConstant;
import cn.com.softvan.common.IdUtils;
import cn.com.softvan.common.JedisHelper;
import cn.com.softvan.common.Resources;
import cn.com.softvan.common.Validator;
import cn.com.softvan.common.WebUtils;

/**
* <p>微信服务号 开放接口API</p>
* <ol>[提供机能]
* <li>List<String> getCallbackIp(String access_token) 获得微信服务器IP地址列表</li>
* <li>public String getAccessToken(Boolean falg,JedisHelper jedisHelper,String appid, String secret) 获取认证信息 access_token 缓存时间7150秒</li>
* <li>public String getAccessToken(String appid, String secret) 获取认证信息 access_token [直接访问微信服务api]不建议 会引起混乱</li>
* <li>uploadMedia 上传多媒体文件</li>
* <li>downMedia 下载多媒体文件</li>
* <li>getMenu 获取微信自定义菜单</li>
* <li>getUserList 获取帐号的关注者列表</li>
* <li>getUser 根据OpenID获取用户基本信息</li>
* <li>isErrAccessToken 验证是否认证码问题 认证码有问题返回true 认证码正确返回false</li>
* <li>sendCustomerService 通过POST一个JSON数据包来发送消息给普通用户,在48小时内不限制发送次数。此接口主要用于客服等有人工消息处理环节的功能,方便开发者为用户提供更加优质的服务。</li>
* <li>getQR_SCENE 生成带参数的二维码 临时二维码 </li>
* <li>getQR_LIMIT_SCENE 生成带参数的二维码 永久二维码 </li>
* </ol>
*/
public final class WxApiUtil {
/** 日志 */
private static final transient Logger log = Logger.getLogger("weixin");
/**公众号每次调用接口时,可能获得正确或错误的返回码,开发者可以根据返回码信息调试接口,排查错误。*/
private static final Map<String,String> errCodeMap=Collections.unmodifiableMap(new HashMap<String,String>(){
private static final long serialVersionUID = -906268846628152015L;
{
Properties prop = new Properties();
InputStream in = null;
try {
in=Resources.getResourceAsStream("wxcode.properties");
} catch (Exception e) {
log.error("读取微信全局返回码资源文件1异常.", e);
}
if(in!=null){
try {
prop.load(in);
Set<Object> keyset = prop.keySet();
for (Object object : keyset) {
if(object!=null){
String propValue= prop.getProperty(object.toString());
if(propValue!=null){
put(object.toString(), propValue.trim());
}
}
}
} catch (Exception e) {
log.error("读取微信全局返回码说明文件2信息异常.", e);
}
}
}
});
/**
* 获得微信服务器IP地址列表
* @param access_token 公众号的access_token
* @return IP地址列表
*/
public List<String> getCallbackIp(String access_token){
//如果公众号基于安全等考虑,需要获知微信服务器的IP地址列表,以便进行相关限制,可以通过该接口获得微信服务器IP地址列表。
String apizhname="【获得微信服务器IP地址列表】";
//错误标记
boolean error_flag=false;
List<String> ips=new ArrayList<String>();
String url = "https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=" + access_token;
log.debug("=向微信服务器发起"+apizhname+"="+url);
HttpClient client = new HttpClient();
GetMethod method = new GetMethod(url);
method.getParams().setContentCharset("utf-8");
// 发送http请求
String respStr = "";
try {
client.executeMethod(method);
respStr = method.getResponseBodyAsString();
log.debug("=获得"+apizhname+"反馈消息="+respStr);
JSONObject dataJson = JSONObject.fromObject(respStr);
if(dataJson!=null && null!=getJsonInfo(dataJson,"errcode")){
error_flag=true;
log.error("="+apizhname+"="+getJsonInfo(dataJson,"errcode")+":"+getErrMsg(dataJson,getJsonInfo(dataJson,"errcode")));
}
if(!error_flag){
//{"ip_list":["127.0.0.1","127.0.0.1"]}
JSONArray jsonArray=(dataJson.getJSONArray("ip_list"));
if(jsonArray!=null){
for(int i=0;i<jsonArray.size();i++){
String ip=jsonArray.getString(i);
ips.add(ip);
}
}
}
} catch (Exception e) {
log.error("=向微信服务器发起"+apizhname+"接口访问异常="+respStr,e);
}finally{
try {method.releaseConnection();} catch (Exception e) {}
try {client.getHttpConnectionManager().closeIdleConnections(0);} catch (Exception e) {}
}
return ips;
}
/**
* 获取认证信息 access_token 缓存时间7150秒
* @param falg [true:重新获取 flase:缓存中读取]
* @param jedisHelper 缓存服务工具类
* @param appid 第三方用户唯一凭证
* @param secret 第三方用户唯一凭证密钥,即appsecret
* @return 获取到的凭证
*/
public String getAccessToken(Boolean falg,JedisHelper jedisHelper,String appid, String secret){
//公众号可以使用AppID和AppSecret调用本接口来获取access_token。AppID和AppSecret可在微信公众平台官网-开发者中心页中获得(需要已经成为开发者,且帐号没有异常状态)。注意调用所有微信接口时均需使用https协议。
String access_token=null;
if(jedisHelper!=null && !falg){
access_token=(String) jedisHelper.get(CommonConstant.SESSION_KEY_USER_WECHAT_ACCESS_TOKEN);
}
if(null==access_token||falg){
access_token=getAccessToken(appid, secret);
if(jedisHelper!=null && access_token!=null){
//认证信息缓存7150秒
jedisHelper.set(CommonConstant.SESSION_KEY_USER_WECHAT_ACCESS_TOKEN,access_token,7150);
}
}
return access_token;
}
/**
* 获取认证信息 access_token [直接访问微信服务api]
* @param appid 第三方用户唯一凭证
* @param secret 第三方用户唯一凭证密钥,即appsecret
* @return 获取到的凭证
*/
public String getAccessToken(String appid, String secret) {
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret;
String apizhname="【获取认证信息 access_token】";
//错误标记
boolean error_flag=false;
HttpClient client = new HttpClient();
GetMethod method = new GetMethod(url);
method.getParams().setContentCharset("utf-8");
// 发送http请求
String respStr = "";
try {
client.executeMethod(method);
respStr = method.getResponseBodyAsString();
JSONObject dataJson = JSONObject.fromObject(respStr);
if(dataJson!=null && null!=getJsonInfo(dataJson,"errcode")){
error_flag=true;
log.error("="+apizhname+"="+getJsonInfo(dataJson,"errcode")+":"+getErrMsg(dataJson,getJsonInfo(dataJson,"errcode")));
}
if(!error_flag){
return getJsonInfo(dataJson,"access_token");
}
} catch (Exception e) {
log.error("="+apizhname+"接口访问异常="+respStr,e);
}finally{
try {method.releaseConnection();} catch (Exception e) {}
try {client.getHttpConnectionManager().closeIdleConnections(0);} catch (Exception e) {}
}
return null;
}
/**
* 上传多媒体文件
* 注意事项 上传的多媒体文件有格式和大小限制,如下: 图片(image): 128K,支持JPG格式
* 语音(voice):256K,播放长度不超过60s,支持AMRMP3格式 视频(video):1MB,支持MP4格式
* 缩略图(thumb):64KB,支持JPG格式
* 媒体文件在后台保存时间为3天,即3天后media_id失效。对于需要重复使用的多媒体文件,可以每3天循环上传一次,更新media_id。
* @param access_token 调用接口凭证
* @param type 媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb)
* @param localFile 文件本地路径
* @return 媒体文件上传后,获取时的唯一标识
*/
public String uploadMedia(String access_token,String type, String localFile) {
//公众号可调用本接口来上传图片、语音、视频等文件到微信服务器,上传后服务器会返回对应的media_id,公众号此后可根据该media_id来获取多媒体。请注意,media_id是可复用的,调用该接口需http协议。
String apizhname="【上传多媒体文件】";
//错误标记
boolean error_flag=false;
String media_id = null;
String url = "http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token=" + access_token + "&type=" + type;
//将服务器相对地址转为物理地址
String local_url = StrUtil.escapeRemoteToLocal(localFile);
OutputStream out =null;
DataInputStream in =null;
BufferedReader reader =null;
try {
File file = new File(local_url);
if (!file.exists() || !file.isFile()) {
log.error("文件路径错误==" + local_url);
return null;
}
URL urlObj = new URL(url);
HttpURLConnection con = (HttpURLConnection) urlObj.openConnection();
con.setRequestMethod("POST"); // 以Post方式提交表单,默认get方式
con.setDoInput(true);
con.setDoOutput(true);
con.setUseCaches(false); // post方式不能使用缓存
// 设置请求头信息
con.setRequestProperty("Connection", "Keep-Alive");
con.setRequestProperty("Charset", "UTF-8");
// 设置边界
String BOUNDARY = "----------" + System.currentTimeMillis();
con.setRequestProperty("content-type","multipart/form-data; boundary=" + BOUNDARY);
// 请求正文信息
// 第一部分:
StringBuilder sb = new StringBuilder();
sb.append("--"); //必须多两道线
sb.append(BOUNDARY);
sb.append("\r\n");
sb.append("Content-Disposition: form-data;name=\"file\";filename=\"" + file.getName() + "\"\r\n");
sb.append("Content-Type:application/octet-stream\r\n\r\n");
byte[] head = sb.toString().getBytes("utf-8");
// 获得输出流
out = new DataOutputStream(con.getOutputStream());
out.write(head);
// 文件正文部分
in = new DataInputStream(new FileInputStream(file));
int bytes = 0;
byte[] bufferOut = new byte[1024];
while ((bytes = in.read(bufferOut)) != -1) {
out.write(bufferOut, 0, bytes);
}
in.close();
// 结尾部分
byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 定义最后数据分隔线
out.write(foot);
out.flush();
out.close();
/**
* 读取服务器响应,必须读取,否则提交不成功
*/
// con.getResponseCode();
try {
// 定义BufferedReader输入流来读取URL的响应
StringBuffer buffer = new StringBuffer();
reader = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
String line = null;
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
String respStr =buffer.toString();
log.debug("==respStr==" + respStr);
JSONObject dataJson = JSONObject.fromObject(respStr);
if(dataJson!=null && null!=getJsonInfo(dataJson,"errcode")){
error_flag=true;
logErrCode(apizhname, getJsonInfo(dataJson,"errcode"));
return getJsonInfo(dataJson,"errcode");
}
if(!error_flag){
media_id = getJsonInfo(dataJson,"media_id");
}
reader.close();
} catch (Exception e) {
log.error("发送POST请求出现异常!" + e);
}
} catch (Exception e) {
log.error("调用微信"+apizhname+"接口上传文件失败!文件路径="+local_url,e);
} finally {
try {if(in!=null){in.close();}} catch (IOException e) {}
try {if(out!=null){ out.close();}} catch (IOException e) {}
try {if(reader!=null){reader.close();}} catch (IOException e) {}
}
return media_id;
}
/**
* 下载多媒体文件 请注意,视频文件不支持下载,调用该接口需http协议。
* @param access_token 调用接口凭证
* @param type 媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb)
* @param media_id 媒体文件上传后,获取时的唯一标识
* @return 文件下载后保存的本地路径
*/
public Map<String,String> downMedia(String access_token,String type, String media_id) {
Map<String,String> map=new HashMap<String,String>();
String localFile = null;
String apizhname="【下载多媒体文件】";
//错误标记
boolean error_flag=false;
SimpleDateFormat df = new SimpleDateFormat("/yyyyMM/");
InputStream in=null;
FileOutputStream outStream =null;
InputStream inputStream=null;
try {
String url = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=" + access_token + "&media_id=" + media_id;
//相对路径
String relative_path="/"+type+"/weixin"+df.format(new Date());
// log.error(path);
// 图片未保存 下载保存
URL urlObj = new URL(url);
HttpURLConnection conn = (HttpURLConnection) urlObj.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
String respStr=conn.getHeaderField("Content-disposition");
try {
log.debug("===调用微信公共平台 "+apizhname+"==返回文件信息=="+respStr);
if(respStr==null){
in=conn.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in, "utf-8"));
String line = null;
StringBuffer result = new StringBuffer();
while ((line = reader.readLine()) != null) {
result.append(line);
}
log.debug(result);
JSONObject dataJson = JSONObject.fromObject(result);
if(dataJson!=null && null!=getJsonInfo(dataJson,"errcode")){
error_flag=true;
logErrCode(apizhname, getJsonInfo(dataJson,"errcode"));
map.put("errcode",getJsonInfo(dataJson,"errcode"));
}
}
} catch (Exception e) {
}finally{
try {if(in!=null){in.close();}} catch (Exception e) {}
}
if (!error_flag && conn.getResponseCode() == 200) {
String Content_disposition=conn.getHeaderField("Content-disposition");
inputStream = conn.getInputStream();
// 文件类型
String fileType = conn.getContentType();
map.put("fileType",fileType);
// // 文件大小
Long fileSize = conn.getContentLengthLong();
map.put("fileSize",""+fileSize);
//文件夹 根目录+相对路径
String savePath = Resources.getData("UPLOAD_ROOT_FOLDER")+relative_path;
// 文件名
String fileName = WebUtils.getTime("yyyyMMddHHmmss")+WebUtils.getRandomString(5)+"."+WebUtils.getFileExt(Content_disposition);
map.put("fileName",fileName);
// 创建文件夹
File saveDirFile = new File(savePath);
if (!saveDirFile.exists()) {
saveDirFile.mkdirs();
}
// 检查目录写权限
if (!saveDirFile.canWrite()) {
log.error("目录没有写权限,写入文件失败");
throw new Exception("目录没有写权限,写入文件失败");
}
// 文件保存目录路径
File file = new File(saveDirFile, fileName);
outStream = new FileOutputStream(file);
int len = -1;
byte[] b = new byte[1024];
while ((len = inputStream.read(b)) != -1) {
outStream.write(b, 0, len);
}
outStream.flush();
outStream.close();
inputStream.close();
//服务器访问路径
localFile=Resources.getData("UPLOAD_ROOT_FOLDER_URL")+relative_path+fileName;
map.put("fileUrl",localFile);
}
} catch (Exception e) {
log.error("="+apizhname+"接口访问异常=", e);
} finally {
try {if(in!=null){in.close();}} catch (IOException e) {}
try {if(outStream!=null){outStream.close();}} catch (IOException e) {}
try {if(inputStream!=null){inputStream.close();}} catch (IOException e) {}
}
return map;
}
/**
* 下载微信图片 如果微信号没有多媒体接口权限 替换方案
* @param remote_url 图片远程路径
* @return
*/
public String downImg(String remote_url){
String local_path=null;
//
SimpleDateFormat df = new SimpleDateFormat("/yyyyMM/");
try {
//相对路径
String relative_path="/image/weixin"+df.format(new Date());
// log.error(path);
// 图片未保存 下载保存
URL url = new URL(remote_url);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
if (conn.getResponseCode() == 200) {
InputStream inputStream = conn.getInputStream();
// // 文件大小
// Long fileSize = conn.getContentLengthLong();
//文件夹 根目录+相对路径
String savePath = Resources.getData("UPLOAD_ROOT_FOLDER")+relative_path;
// 文件名
String fileName = WebUtils.getTime("yyyyMMddHHmmss") + WebUtils.getRandomString(5) + ".jpg";
// 创建文件夹
File saveDirFile = new File(savePath);
if (!saveDirFile.exists()) {
saveDirFile.mkdirs();
}
// 检查目录写权限
if (!saveDirFile.canWrite()) {
log.error("目录没有写权限,写入文件失败");
throw new Exception();
}
// 文件保存目录路径
File file = new File(saveDirFile, fileName);
FileOutputStream outStream = new FileOutputStream(file);
int len = -1;
byte[] b = new byte[1024];
while ((len = inputStream.read(b)) != -1) {
outStream.write(b, 0, len);
}
outStream.flush();
outStream.close();
inputStream.close();
//服务器访问路径
local_path=Resources.getData("UPLOAD_ROOT_FOLDER_URL")+relative_path+fileName;
}
} catch (Exception e) {
log.error("微信上传图片保存失败!",e);
}

return local_path;
}
/**
* 获取微信自定义菜单
* @param access_token 调用接口凭证
* @return 微信自定义菜单 列表
*/
public List<TcWxMenuBean> getMenu(String access_token) {
//---------beans-------------
List<TcWxMenuBean> beans=new ArrayList<TcWxMenuBean>();
String url = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=" + access_token;
String apizhname="【获取微信自定义菜单】";
log.debug("=向微信服务器发起"+apizhname+"="+url);
boolean error_flag=false;

HttpClient client = new HttpClient();
GetMethod method = new GetMethod(url);
method.getParams().setContentCharset("utf-8");
// 发送http请求
String respStr = "";
try {
client.executeMethod(method);
respStr = method.getResponseBodyAsString();
log.debug("=获得"+apizhname+"反馈消息="+respStr);
JSONObject dataJson = JSONObject.fromObject(respStr);
try {
if(dataJson!=null && null!=getJsonInfo(dataJson,"errcode")){
error_flag=true;
log.error("="+apizhname+"="+getJsonInfo(dataJson,"errcode")+":"+getErrMsg(dataJson,getJsonInfo(dataJson,"errcode")));
TcWxMenuBean bean=new TcWxMenuBean();
bean.setErrcode(getJsonInfo(dataJson,"errcode"));
bean.setErrmsg(getErrMsg(dataJson,getJsonInfo(dataJson,"errcode")));
beans.add(bean);
}
} catch (Exception e) {
}
if(!error_flag){
log.debug(dataJson);
//{"menu":{"button":[{"type":"click","name":"今日歌曲","key":"V1001_TODAY_MUSIC","sub_button":[]},{"type":"click","name":"歌手简介","key":"V1001_TODAY_SINGER","sub_button":[]},{"name":"菜单","sub_button":[{"type":"view","name":"搜索","url":"http://www.soso.com/","sub_button":[]},{"type":"view","name":"视频","url":"http://v.qq.com/","sub_button":[]},{"type":"click","name":"赞一下我们","key":"V1001_GOOD","sub_button":[]}]}]}}
JSONArray jsonArray=(dataJson.getJSONObject("menu").getJSONArray("button"));
if(jsonArray!=null){
//1.获取一级菜单
for(int i=0;i<jsonArray.size();i++){
String s1=jsonArray.getString(i);
log.debug("==s1=="+s1);
JSONObject j1=JSONObject.fromObject(s1);
String uuid=IdUtils.createUUID(32);
//TODO--
TcWxMenuBean bean=new TcWxMenuBean();
bean.setId(uuid);//主键id
bean.setMenu_name(j1.getString("name"));
JSONArray j2Array=j1.getJSONArray("sub_button");
bean.setBeans(new ArrayList<TcWxMenuBean>());
bean.setSort_num((i+1)*10);
//判断是否有子菜单
if(j2Array!=null && j2Array.size()>0){
for(int n=0;n<j2Array.size();n++){
String s2=j2Array.getString(n);
log.debug("==s2=="+s2);
JSONObject j2=JSONObject.fromObject(s2);
//TODO--
TcWxMenuBean bean2=new TcWxMenuBean();
bean2.setId(IdUtils.createUUID(32));//主键id
bean2.setParent_id(bean.getId());//父菜单id
bean2.setMenu_name(j2.getString("name"));
try {
bean2.setMenu_type(j2.getString("type"));
} catch (Exception e1) {
}
try {
bean2.setMenu_key(j2.getString("key"));
} catch (Exception e) {
}
try {
bean2.setMenu_url(j2.getString("url"));
} catch (Exception e) {
}
bean2.setSort_num(n+1);
bean.getBeans().add(bean2);
}
}else{
try {
bean.setMenu_type(j1.getString("type"));
} catch (Exception e) {
}
try {
bean.setMenu_key(j1.getString("key"));
} catch (Exception e) {
}
try {
bean.setMenu_url(j1.getString("url"));
} catch (Exception e) {
}
}
//add
beans.add(bean);
}
}
}

} catch (Exception e) {
log.error("=向微信服务器发起"+apizhname+"接口访问异常="+respStr,e);
}finally{
try {method.releaseConnection();} catch (Exception e) {}
try {client.getHttpConnectionManager().closeIdleConnections(0);} catch (Exception e) {}
}
return beans;
}
/**
* 公众号可通过本接口来获取帐号的关注者列表,关注者列表由一串OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的)组成。一次拉取调用最多拉取10000个关注者的OpenID,可以通过多次拉取的方式来满足需求。
* @param access_token
* @param next_openid 第一个拉取的OPENID,不填默认从头开始拉取
* @return
*/
public List<TcWxUserBean> getUserList(String access_token,String next_openid){
/*
* total 关注该公众账号的总用户数
* count 拉取的OPENID个数,最大值为10000
* data 列表数据,OPENID的列表
* next_openid 拉取列表的后一个用户的OPENID
*/
String apizhname="【获取帐号的关注者列表】";
boolean error_flag=false;
List<TcWxUserBean> beans=new ArrayList<TcWxUserBean>();
String url="https://api.weixin.qq.com/cgi-bin/user/get?access_token="+access_token;
if(Validator.notEmpty(next_openid)){
url+="&next_openid="+next_openid;
}
log.debug("=向微信服务器发起"+apizhname+"="+url);
HttpClient client = new HttpClient();
GetMethod method = new GetMethod(url);
method.getParams().setContentCharset("utf-8");
// 发送http请求
String respStr = "";
try {
client.executeMethod(method);
respStr = method.getResponseBodyAsString();
log.debug("=获得"+apizhname+"反馈消息="+respStr);
JSONObject dataJson = JSONObject.fromObject(respStr);
try {
if(dataJson!=null && null!=getJsonInfo(dataJson,"errcode")){
error_flag=true;
log.error("="+apizhname+"="+getJsonInfo(dataJson,"errcode")+":"+getErrMsg(dataJson,getJsonInfo(dataJson,"errcode")));
TcWxUserBean bean=new TcWxUserBean();
bean.setErrcode(getJsonInfo(dataJson,"errcode"));
bean.setErrmsg(getErrMsg(dataJson,getJsonInfo(dataJson,"errcode")));
beans.add(bean);
}
} catch (Exception e) {
}
if(!error_flag){
Long total=dataJson.getLong("total");
Integer count=dataJson.getInt("count");
String next_oid=dataJson.getString("next_openid");
log.debug("=====next_oid==="+next_oid+"===2==");
JSONObject data=dataJson.getJSONObject("data");
JSONArray array=data.getJSONArray("openid");
Object[] oIdArray=array.toArray();
if(oIdArray!=null){
TcWxUserBean bean=null;
for(Object oid:oIdArray){
bean=getUser(access_token,oid.toString());
if(bean!=null){
bean.setTotal(total);
bean.setCount(count);
bean.setNext_openid(next_oid);
//add
beans.add(bean);
}
}
}
}
} catch (Exception e) {
log.error("=向微信服务器发起"+apizhname+"接口访问异常="+respStr,e);
}finally{
try {method.releaseConnection();} catch (Exception e) {}
try {client.getHttpConnectionManager().closeIdleConnections(0);} catch (Exception e) {}
}
return beans;
}
/**
* 在关注者与公众号产生消息交互后,公众号可获得关注者的OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的。对于不同公众号,同一用户的openid不同)。公众号可通过本接口来根据OpenID获取用户基本信息,包括昵称、头像、性别、所在城市、语言和关注时间。
* @param access_token 是 调用接口凭证
* @param openid 是 普通用户的标识,对当前公众号唯一
* @return
*/
public TcWxUserBean getUser(String access_token,String openid){
/*
* access_token 是 调用接口凭证
openid 是 普通用户的标识,对当前公众号唯一
lang 否 返回国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语
*/
String apizhname="【获取用户基本信息】";
boolean error_flag=false;
TcWxUserBean bean=new TcWxUserBean();
bean.setOpenid(openid);
String url="https://api.weixin.qq.com/cgi-bin/user/info?access_token="+access_token+"&openid="+openid+"&lang=zh_CN";
log.debug("=向微信服务器发起"+apizhname+"="+url);
HttpClient client = new HttpClient();
GetMethod method = new GetMethod(url);
method.getParams().setContentCharset("utf-8");
// 发送http请求
String respStr = "";
try {
client.executeMethod(method);
respStr = method.getResponseBodyAsString();
log.debug("=获得"+apizhname+"反馈消息="+respStr);
JSONObject dataJson = JSONObject.fromObject(respStr);
try {
if(dataJson!=null && null!=getJsonInfo(dataJson,"errcode")){
error_flag=true;
log.error("="+apizhname+"="+getJsonInfo(dataJson,"errcode")+":"+getErrMsg(dataJson,getJsonInfo(dataJson,"errcode")));
bean.setErrcode(getJsonInfo(dataJson,"errcode"));
bean.setErrmsg(getErrMsg(dataJson,getJsonInfo(dataJson,"errcode")));
}
} catch (Exception e) {
}
if(!error_flag){
// subscribe 用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息。
bean.setSubscribe(dataJson.getString("subscribe"));
// openid 用户的标识,对当前公众号唯一
//=-------------
// nickname 用户的昵称
bean.setNickname(dataJson.getString("nickname"));
// sex 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
bean.setSex(dataJson.getString("sex"));
// city 用户所在城市
bean.setCity(dataJson.getString("city"));
// country 用户所在国家
bean.setCountry(dataJson.getString("country"));
// province 用户所在省份
bean.setProvince(dataJson.getString("province"));
// language 用户的语言,简体中文为zh_CN
bean.setLanguage(dataJson.getString("language"));
// headimgurl 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空
bean.setHeadimgurl(dataJson.getString("headimgurl"));
// subscribe_time 用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间
bean.setSubscribe_time(dataJson.getString("subscribe_time"));
}
} catch (Exception e) {
log.error("=向微信服务器发起"+apizhname+"接口访问异常="+respStr,e);
}finally{
try {method.releaseConnection();} catch (Exception e) {}
try {client.getHttpConnectionManager().closeIdleConnections(0);} catch (Exception e) {}
}
return bean;
}
/**
* 验证是否认证码问题 认证码有问题返回true 认证码正确返回false
* @param errorCode
* @return
*/
public boolean isErrAccessToken(String errorCode){
if(errorCode!=null && ("40001".equals(errorCode)||"40014".equals(errorCode)||"42001".equals(errorCode))){
return true;
}
return false;
}
/**
* 通过POST一个JSON数据包来发送消息给普通用户,在48小时内不限制发送次数。此接口主要用于客服等有人工消息处理环节的功能,方便开发者为用户提供更加优质的服务。
* @param access_token 是 调用接口凭证
* @param openid 是 普通用户的标识,对当前公众号唯一
* @return
*/
public String sendCustomerService(String access_token,String openid,String json){
String apizhname="【发送消息给普通用户】";
boolean error_flag=false;
String msg="1";
String url="https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token="+access_token;
log.debug("=向微信服务器发起"+apizhname+"="+url);
HttpClient client = new HttpClient();
PostMethod method = new PostMethod(url);
method.getParams().setContentCharset("utf-8");
// 发送http请求
String respStr = "";
try {
// method.setRequestBody(json);
RequestEntity entity = new StringRequestEntity(json, "text/xml", "utf-8");
method.setRequestEntity(entity);
client.executeMethod(method);
respStr = method.getResponseBodyAsString();
log.debug("=获得"+apizhname+"反馈消息="+respStr);
JSONObject dataJson = JSONObject.fromObject(respStr);
if(dataJson!=null && null!=getJsonInfo(dataJson,"errcode")){
error_flag=true;
log.error("="+apizhname+"="+getJsonInfo(dataJson,"errcode")+":"+getErrMsg(dataJson,getJsonInfo(dataJson,"errcode")));
msg=getJsonInfo(dataJson,"errcode");
}
if(!error_flag){
log.debug("信息发送完成!");
}
} catch (Exception e) {
log.error("=向微信服务器发起"+apizhname+"接口访问异常="+respStr,e);
}finally{
try {method.releaseConnection();} catch (Exception e) {}
try {client.getHttpConnectionManager().closeIdleConnections(0);} catch (Exception e) {}
}
return msg;
}
/**
* 生成带参数的二维码 临时二维码
* @param access_token 该二维码有效时间,以秒为单位。 最大不超过1800。
* @param expire_seconds
* @param scene_id 场景值ID,临时二维码时为32位非0整型
* @return
*/
public String getQRScene(String access_token,int expire_seconds,String scene_id){
String apizhname="【生成带参数的二维码 临时二维码】";
boolean error_flag=false;
String msg=null;
String json="{\"expire_seconds\": "+expire_seconds+", \"action_name\": \"QR_SCENE\", \"action_info\": {\"scene\": {\"scene_id\": "+scene_id+"}}}";
String url="https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token="+access_token;
log.debug("=向微信服务器发起"+apizhname+"="+url);
HttpClient client = new HttpClient();
PostMethod method = new PostMethod(url);
method.getParams().setContentCharset("utf-8");
// 发送http请求
String respStr = "";
try {
// method.setRequestBody(json);
RequestEntity entity = new StringRequestEntity(json, "text/xml", "utf-8");
method.setRequestEntity(entity);
client.executeMethod(method);
respStr = method.getResponseBodyAsString();
log.debug("=获得"+apizhname+"反馈消息="+respStr);
JSONObject dataJson = JSONObject.fromObject(respStr);
if(dataJson!=null && null!=getJsonInfo(dataJson,"errcode")){
error_flag=true;
log.error("="+apizhname+"="+getJsonInfo(dataJson,"errcode")+":"+getErrMsg(dataJson,getJsonInfo(dataJson,"errcode")));
msg=getJsonInfo(dataJson,"errcode");
}
if(!error_flag){
msg=getJsonInfo(dataJson,"ticket");
}
} catch (Exception e) {
log.error("=向微信服务器发起"+apizhname+"接口访问异常="+respStr,e);
}finally{
try {method.releaseConnection();} catch (Exception e) {}
try {client.getHttpConnectionManager().closeIdleConnections(0);} catch (Exception e) {}
}
return msg;
}
/**
* 生成带参数的二维码 永久二维码
* @param access_token
* @param scene_id 永久二维码时最大值为100000(目前参数只支持1--100000)
* @return
*/
public String getQRSceneLimit(String access_token,String scene_id){
String apizhname="【生成带参数的二维码 永久二维码】";
boolean error_flag=false;
String msg=null;
String json="{\"action_name\": \"QR_LIMIT_SCENE\", \"action_info\": {\"scene\": {\"scene_id\": "+scene_id+"}}}";
String url="https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token="+access_token;
log.debug("=向微信服务器发起"+apizhname+"="+url);
HttpClient client = new HttpClient();
PostMethod method = new PostMethod(url);
method.getParams().setContentCharset("utf-8");
// 发送http请求
String respStr = "";
try {
// method.setRequestBody(json);
RequestEntity entity = new StringRequestEntity(json, "text/xml", "utf-8");
method.setRequestEntity(entity);
client.executeMethod(method);
respStr = method.getResponseBodyAsString();
log.debug("=获得"+apizhname+"反馈消息="+respStr);
JSONObject dataJson = JSONObject.fromObject(respStr);
if(dataJson!=null && null!=getJsonInfo(dataJson,"errcode")){
error_flag=true;
log.error("="+apizhname+"="+getJsonInfo(dataJson,"errcode")+":"+getErrMsg(dataJson,getJsonInfo(dataJson,"errcode")));
msg=getJsonInfo(dataJson,"errcode");
}
if(!error_flag){
msg=getJsonInfo(dataJson,"ticket");
}
} catch (Exception e) {
log.error("=向微信服务器发起"+apizhname+"接口访问异常="+respStr,e);
}finally{
try {method.releaseConnection();} catch (Exception e) {}
try {client.getHttpConnectionManager().closeIdleConnections(0);} catch (Exception e) {}
}
return msg;
}
/**
* 获取json对象的具体数据
* @param jsonObject
* @param key
* @return
*/
private String getJsonInfo(JSONObject jsonObject,String key){
String info=null;
try {
if(jsonObject!=null){
info=jsonObject.getString(key);
if(info!=null){
info=StringUtils.trim(info);
}
}
} catch (Exception e) {
}
return info;
}
/**
* 获取错误代码 描述信息
* @param dataJson
* @param errcode
* @return
*/
private String getErrMsg(JSONObject dataJson,String errcode){
String errmsg=errCodeMap.get(errcode);
if(errmsg==null){
errmsg= getJsonInfo(dataJson,"errmsg");
}
return errmsg;
}
/**
* 记录微信接口反馈的错误信息
* @param apizhname 接口描述
* @param errcode 错误code
*/
private void logErrCode(String apizhname,String errcode){
log.error("="+apizhname+"="+errcode+":"+errCodeMap.get(errcode));
}
// http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html
// 1 上传图文消息素材【订阅号与服务号认证后均可用】
// 2 根据分组进行群发【订阅号与服务号认证后均可用】
// 3 根据OpenID列表群发【订阅号不可用,服务号认证后可用】
// 4 删除群发【订阅号与服务号认证后均可用】
// 5 预览接口【订阅号与服务号认证后均可用】
// 6 查询群发消息发送状态【订阅号与服务号认证后均可用】
// http://mp.weixin.qq.com/wiki/17/304c1885ea66dbedf7dc170d84999a9d.html
// 7 事件推送群发结果
// 1 设置所属行业
// 2 获得模板ID
// 3 发送模板消息
// 4 事件推送
// http://mp.weixin.qq.com/wiki/1/70a29afed17f56d537c833f89be979c9.html
// 1 客服帐号管理
// 1.1 添加客服帐号
// 1.2 修改客服帐号
// 1.3 删除客服帐号
// 1.4 设置客服帐号的头像
// 1.5 获取所有客服账号
// 1.6 接口的统一参数说明
// 2 客服接口-发消息
// http://mp.weixin.qq.com/wiki/0/56d992c605a97245eb7e617854b169fc.html
// -用户分组管理-
// 1 创建分组
// 2 查询所有分组
// 3 查询用户所在分组
// 4 修改分组名
// 5 移动用户分组
// 6 批量移动用户分组
// http://mp.weixin.qq.com/wiki/1/4a566d20d67def0b3c1afc55121d2419.html
// 设置用户备注名
// 获取用户基本信息(UnionID机制)
// 获取用户列表
// 获取用户地理位置
// 网页授权获取用户基本信息
// 网页获取用户网络状态(JS接口)
// http://mp.weixin.qq.com/wiki/13/43de8269be54a0a6f64413e4dfa94f39.html
// 自定义菜单创建接口
// 自定义菜单查询接口
// 自定义菜单删除接口
// 自定义菜单事件推送
// http://mp.weixin.qq.com/wiki/10/165c9b15eddcfbd8699ac12b0bd89ae6.html
// 长链接转短链接接口
// http://mp.weixin.qq.com/wiki/5/ae230189c9bd07a6b221f48619aeef35.html
// 将消息转发到多客服
// 客服管理
// 获取客服聊天记录
// PC客户端自定义插件接口
// http://mp.weixin.qq.com/wiki/0/0ce78b3c9524811fee34aba3e33f3448.html
// 语义理解
/**
* 微信认证
* @param token
* @param signature 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
* @param timestamp 时间戳
* @param nonce 随机数
* @return
*/
public boolean checkSignature(String token,String signature,String timestamp,String nonce){
String[] arr = new String[]{token,timestamp,nonce};
Arrays.sort(arr);
StringBuilder content = new StringBuilder();
for(int i=0;i<arr.length;i++){
content.append(arr[i]);
}
MessageDigest md = null;
String tmpStr = null;
try {
md = MessageDigest.getInstance("SHA-1");
byte[] digest = md.digest(content.toString().getBytes());
tmpStr = byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
log.error("微信认证错误!", e);
}
content = null;
return tmpStr!=null?tmpStr.equals(signature.toUpperCase()):false;
}

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

String s = new String(ob);
return s;
}
/**
* 将字节数组转换为十六进制字符串
* @param bytearray
* @return
*/
private String byteToStr(byte[] bytearray) {
String strDigest = "";
for (int i = 0; i < bytearray.length; i++) {
strDigest += byteToHexStr(bytearray[i]);
}
return strDigest;
}
// test
public static void main(String[] args) throws Exception {
// WxApiMpUtil api=new WxApiMpUtil();
System.out.println(errCodeMap.get("-1"));
// System.out.println(StrUtil.escapeRemoteToLocal("/upload/image/1.jpg"));
// System.out.println(StrUtil.escapeLocalToRemote("/home/baseos/upload/image/1.jpg"));
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值