java实现微信公众号API服务端调用封装

背景

在进行微信公众号开发时,我们经常会在java服务端调用微信公众号的相关接口,如比
验证服务器接口地址、检验消息的真实性、获取AccessToken、消息加密、发送消息、创建菜单、获取或下载临时素材、获取用户列表、获取用户基本信息。为了简化接口的调用,我把常用接口的调用进行了封装。具体如下:

代码封装

对基本的微信公众号API调用封装如下:

基础方法:在回调模式下验证服务器接口地址

	/**
	 * 功能说明:基础方法:在回调模式下验证服务器接口地址
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 上午11:03:15
	 * @param token 公众号号的全局唯一票据
	 * @param sEncodingAESKey 微信公众号EncodingAESKey
	 * @param appId 微信公众号AppId
	 * @param msg_signature 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
	 * @param timestamp 时间戳
	 * @param nonce 随机串,对应URL参数的nonce
	 * @return 验证成功返回true,否则返回false
	 * @throws AesException
	 */
	public static boolean checkSignature(String token, String sEncodingAESKey, String appId, String msg_signature, String timestamp, String nonce) throws AesException
    {
        WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, sEncodingAESKey, appId);
        boolean result = wxcpt.verifyUrl(msg_signature, timestamp, nonce);
        return result;
    }

基础方法:检验消息的真实性,并且获取解密后的明文.

	/**
	 * 功能说明:基础方法:检验消息的真实性,并且获取解密后的明文.
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 上午11:09:17
	 * @param token 应用的回调接口票证
	 * @param sEncodingAESKey 应用的回调接口密钥
	 * @param appId AppId
	 * @param msg_signature 微信加密签名,msg_signature结合了企业填写的token、请求中的timestamp、nonce参数、加密的消息体,必填参数
	 * @param timestamp 时间戳,必填参数
	 * @param nonce 随机数,必填参数
	 * @param postData 加密的随机字符串,以msg_encrypt格式提供。需要解密并返回echostr明文,解密后有random、msg_len、msg、$CorpID四个字段,其中msg即为echostr明文。首次校验时必填
	 * @return 返回解密后字符串
	 * @throws AesException
	 */
	public static String serverDecryptMsg(String token, String sEncodingAESKey, String appId, String msg_signature, String timestamp, String nonce, String postData) throws AesException
    {
        WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, sEncodingAESKey, appId);
        String sEchoStr = wxcpt.decryptMsg(msg_signature, timestamp, nonce, postData);
        return sEchoStr;
    }

基础方法:将公众平台回复用户的消息加密打包.

/**
	 * 功能说明:基础方法:将公众平台回复用户的消息加密打包.
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 上午11:28:04
	 * @param token 应用的回调接口票证
	 * @param sEncodingAESKey 应用的回调接口密钥
	 * @param appId AppId
	 * @param msg_signature 微信加密签名,msg_signature结合了企业填写的token、请求中的timestamp、nonce参数、加密的消息体,必填参数
	 * @param timestamp 时间戳,必填参数
	 * @param nonce 随机数,必填参数
	 * @param replyMsg 要加密的回复消息
	 * @return 返回加密后的密文
	 * @throws AesException
	 */
	public static String ServerEncryptMsg(String token, String sEncodingAESKey, String appId, String msg_signature, String timestamp, String nonce, String replyMsg) throws AesException
    {
        WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, sEncodingAESKey, appId);
        String sEchoStr = wxcpt.encryptMsg(replyMsg, timestamp, nonce);
        return sEchoStr;
    }

基础方法:获取AccessToken

	/**
	 * 功能说明:基础方法:获取AccessToken
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 上午11:32:50
	 * @param appid 微信公众号AppId
	 * @param secret 凭证密钥
	 * @return 返回公众号号的全局唯一票据
	 * @throws IOException
	 */
	public static String getAccessToken(String appid, String secret) throws IOException
    {
        String param = "grant_type=client_credential&appid=%s&secret=%s";
        param = String.format(param, appid, secret);
        String jsonAccessToken = HttpRequestUtil.sendGet(Global.ACCESSTOKENURL, param);
        return jsonAccessToken;
    }
	
	/**
	 * 功能说明:基础方法:获取AccessToken实体
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 上午11:34:44
	 * @param appid 微信公众号AppId
	 * @param secret 凭证密钥
	 * @return 返回公众号的全局唯一票据实体
	 * @throws IOException
	 */
	public static AccessToken getAccessTokenEntity(String appid, String secret) throws IOException
    {
        String jsonResult = getAccessToken(appid, secret);
        AccessToken result = JSON.parseObject(jsonResult, AccessToken.class);
        return result;
    }
	
	/**
	 * 功能说明:基础方法,获取网页授权access_token
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月15日 上午9:16:42
	 * @param appid 微信公众号AppId
	 * @param secret 凭证密码
	 * @param code 引导网页授权的code码
	 * @return 返回网页授权json字符串
	 * @throws IOException
	 */
	public static String getPageAccessToken(String appid, String secret, String code) throws IOException {
		String param = "appid=%s&secret=%s&code=%s&grant_type=authorization_code";
		param = String.format(param, appid, secret, code);
		String jsonResult = HttpRequestUtil.sendGet(Global.GETPAGEACCESSTOKENURL, param);
		return jsonResult;
	}
	
	/**
	 * 功能说明:基础方法,获取网页授权access_token
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月15日 上午9:18:30
	 * @param appid 微信公众号AppId
	 * @param secret 凭证密码
	 * @param code 引导网页授权的code码
	 * @return 返回网页授权json字符串
	 * @throws IOException
	 */
	public static PageAccessToken getPageAccessTokenEntity(String appid, String secret, String code) throws IOException {
		String jsonResult = getPageAccessToken(appid, secret, code);
		PageAccessToken result = JSON.parseObject(jsonResult, PageAccessToken.class);
		return result;
	}

素材方法:获取临时素材文件与下载临时素材

	/**
	 * 功能说明:素材方法:获取临时素材文件(不包括视频)
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午1:32:02
	 * @param accessToken 微信公众号的全局唯一票据
	 * @param media_id 要获取的素材文件的media_id
	 * @return 返回对应素材文件的json字符串
	 * @throws IOException
	 */
	public static String getTempMedia(String accessToken, String media_id) throws IOException
    {
        String param = "access_token=%s&media_id=%s";
        param = String.format(param, accessToken, media_id);
        String jsonResult = HttpRequestUtil.sendGet(Global.GETTEMPMEDIAURL, param);
        return jsonResult;
    }
	
	/**
	 * 功能说明:素材方法:下载临时素材文件
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:10:05
	 * @param accessToken 微信公众号的全局唯一票据
	 * @param media_id 要下载的媒体文件的media_id
	 * @param outFileName 输出文件的完整路径包括文件名
	 * @return 成功返回文件名,失败返回“”
	 * @throws IOException
	 */
	public static String downloadTempMedia(String accessToken, String media_id, String outFileName) throws IOException
    {
        String param = "access_token=%s&media_id=%s";
        param = String.format(param, accessToken, media_id);
        boolean result = HttpRequestUtil.downloadFile(Global.GETTEMPMEDIAURL, param, outFileName);
        if (result)
        {
        	File file = new File(outFileName);
            return file.getName();
        }
        else
        {
            return "";
        }
    }

客服消息方法:发送文本消息

	/**
	 * 功能说明:客服消息方法:发送文本消息
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:12:50
	 * @param accessToken 企业号的全局唯一票据
	 * @param jsonData 要发送的json格式的消息
	 * @return 返回json结果字符串
	 * @throws IOException
	 */
	public static String sendTextMsg1(String accessToken, String jsonData) throws IOException
    {
        String url = Global.SENDMSGURL + "?access_token=%s";
        url = String.format(url, accessToken);
        String jsonResult = HttpRequestUtil.sendPost(url, jsonData);
        return jsonResult;
    }
	
	/**
	 * 功能说明:客服消息方法:发送文本消息
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:19:31
	 * @param accessToken 企业号的全局唯一票据
	 * @param jsonData 要发送的json格式的消息
	 * @return 返回ResultMsg结果对象
	 * @throws IOException
	 */
	public static ResultMsg sendTextMsg(String accessToken, String jsonData) throws IOException
    {
        String url = Global.SENDMSGURL + "?access_token=%s";
        url = String.format(url, accessToken);
        String jsonResult = HttpRequestUtil.sendPost(url, jsonData);
        ResultMsg result = JSON.parseObject(jsonResult, ResultMsg.class);
        return result;
    }
	
	/**
	 * 功能说明:客服消息方法:发消息(包括文本消息、图像、声音、视频、文件、图文、微信后台图文)
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:20:16
	 * @param accessToken 企业号的全局唯一票据
	 * @param msg 要发送的消息对象
	 * @return 返回ResultMsg结果对象
	 * @throws IOException
	 */
	public static ResultMsg sendMsg(String accessToken, SendMsg msg) throws IOException
    {
        ResultMsg result = sendTextMsg(accessToken, msg.toJsonString());
        return result;
    }

菜单方法

	/**
	 * 功能说明:菜单方法:创建菜单
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:24:10
	 * @param accessToken 公众号的唯一票据
	 * @param param 要创建的菜单参数
	 * @return 返回创建结果对象
	 * @throws IOException
	 */
	public static ResultMsg createMenu(String accessToken, MenuParam param) throws IOException
    {
        String url = Global.CREATEMENUURL + "?access_token=%s";
        url = String.format(url, accessToken);
        String jsonResult = HttpRequestUtil.sendPost(url, param.toJsonString());
        ResultMsg result = JSON.parseObject(jsonResult, ResultMsg.class);
        return result;
    }
	
	/**
	 * 功能说明:菜单方法:删除菜单
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:26:07
	 * @param accessToken 公众号的全局唯一票据
	 * @return 返回删除结果对象
	 * @throws IOException
	 */
	public static ResultMsg delMenu(String accessToken) throws IOException
    {
        String param = "access_token=%s";
        param = String.format(param, accessToken);
        String jsonResult = HttpRequestUtil.sendGet(Global.DELMENURUL, param);
        ResultMsg result = JSON.parseObject(jsonResult, ResultMsg.class);
        return result;
    }
	
	/**
	 * 功能说明:菜单方法:获取菜单列表
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:27:23
	 * @param accessToken 企业号的全局唯一票据
	 * @return 返回菜单列表
	 * @throws IOException
	 */
	public static String getMenu(String accessToken) throws IOException
    {
        String param = "access_token=%s";
        param = String.format(param, accessToken);
        String jsonResult = HttpRequestUtil.sendGet(Global.GETMENUURL, param);
        return jsonResult;
    }

用户信息方法

	/**
	 * 功能说明:用户管理方法:获取用户列表
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:30:50
	 * @param accessToken 公众号的全局唯一票据
	 * @param next_openid 第一个拉取的OPENID,不填默认从头开始拉取
	 * @return 返回json结果字符串
	 * @throws IOException
	 */
	public static String getUserJsonStr(String accessToken, String next_openid) throws IOException
    {
        String param = "access_token=%s&next_openid=%s";
        param = String.format(param, accessToken, next_openid);
        String jsonResult = HttpRequestUtil.sendGet(Global.GETUSERURL, param);
        return jsonResult;
    }
	
	/**
	 * 功能说明:用户管理方法:获取用户列表
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:32:54
	 * @param accessToken 公众号的全局唯一票据
	 * @param next_openid 第一个拉取的OPENID,不填默认从头开始拉取
	 * @return 返回结果对象
	 * @throws IOException
	 */
	public static ResultMsg getUser(String accessToken, String next_openid) throws IOException
    {
        String jsonResult = getUserJsonStr(accessToken, next_openid);
        ResultMsg result = JSON.parseObject(jsonResult, ResultMsg.class);
        return result;
    }
	
	/**
	 * 功能说明:用户管理方法:获取用户基本信息(包括UnionID机制)
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:34:40
	 * @param accessToken 公众号的全局唯一票据
	 * @param openid 普通用户的标识,对当前公众号唯一
	 * @param lang 国家地区语言版本,zh_CN简体,zh_TW繁体,en英语
	 * @return 返回json结果字符串
	 * @throws IOException
	 */
	public static String getUserInfoJsonStr(String accessToken, String openid, String lang) throws IOException
    {
        String param = "access_token=%s&openid=%s&lang=%s";
        param = String.format(param, accessToken, openid, lang);
        String jsonResult = HttpRequestUtil.sendGet(Global.GETUSERINFOURL, param);
        return jsonResult;
    }
	
	/**
	 * 功能说明:用户管理方法:获取用户基本信息(包括UnionID机制)
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:36:39
	 * @param accessToken 公众号的全局唯一票据
	 * @param openId 普通用户的标识,对当前公众号唯一
	 * @param lang 国家地区语言版本,zh_CN简体,zh_TW繁体,en英语
	 * @return 返回UserInfo实体对象
	 * @throws IOException
	 */
	public static UserInfo getUserInfo(String accessToken, String openId, String lang) throws IOException
    {
        String jsonResult = getUserInfoJsonStr(accessToken, openId, lang);
        UserInfo result = JSON.parseObject(jsonResult, UserInfo.class);
        return result;
    }
	
	/**
	 * 功能说明:用户管理方法:获取用户基本信息(包括UnionID机制)
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:38:00
	 * @param accessToken 公众号的全局唯一票据
	 * @param openId 普通用户的标识,对当前公众号唯一
	 * @return 返回UserInfo实体对象
	 * @throws IOException
	 */
	public static UserInfo getUserInfo(String accessToken, String openId) throws IOException
    {
        UserInfo result = getUserInfo(accessToken, openId, "zh_CN");
        return result;
    }

主代码清单

HttpRequestUtil.java

package com.wongoing.api;

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.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
 * 功能说明:封装http请求:GET/POST/PUT/DELETE等方法
 * 修改说明:
 * @author 郑立兵
 * @date 2017年10月17日 上午8:42:30
 * @version V0.1
 * @param <T>
 */
public class HttpRequestUtil {
	/**
	 * 定义全局默认编码格式
	 */
	private static final String CHARSET_NAME = "UTF-8";
	/**
	 * 定义全局OkHttpClient对象
	 */
	private static final OkHttpClient httpClient = new OkHttpClient();
	
	/**
	 * 功能说明:同步调用
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月8日 上午10:20:55
	 * @param request
	 * @return
	 * @throws IOException
	 */
	public static Response execute(Request request) throws IOException {
		return httpClient.newCall(request).execute();
	}
	
	/**
	 * 功能说明:开启异步线程调用
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月8日 上午10:23:00
	 * @param request
	 * @param responseCallback
	 */
	public static void enqueue(Request request, Callback responseCallback) {
		httpClient.newCall(request).enqueue(responseCallback);
	}
	
	/**
	 * 功能说明:开启异步线程调用,且不在意返回结果(实现空callback)
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月8日 上午10:24:53
	 * @param request
	 */
	public static void enqueue(Request request) {
		httpClient.newCall(request).enqueue(new Callback() {

			@Override
			public void onFailure(Call arg0, IOException arg1) {
				
			}

			@Override
			public void onResponse(Call arg0, Response arg1) throws IOException {
				
			}
			
		});
	}
	
	/**
	 * 功能说明:向指定URL发送GET方法的请求
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月8日 上午10:19:11
	 * @param url 发送请求的URL
	 * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
	 * @return URL所代表远程资源的响应结果
	 * @throws IOException
	 */
	public static String sendGet(String url, String param) throws IOException {
		String result = "";
		String urlNameString = url + "?" + param;
		
		Request req = new Request.Builder().url(urlNameString).build(); 
		Response response = httpClient.newCall(req).execute();
		if (!response.isSuccessful())
		{
			throw new IOException("Unexpected code " + response);
		}
		result = response.body().string();
		
		return result;
	}
	
	/**
	 * 功能说明:向指定URL发送GET方法的请求
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月8日 上午10:54:55
	 * @param url 发送请求的URL
	 * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
	 * @param encoding 设置响应信息的编码格式,如utf-8
	 * @return URL所代表远程资源的响应结果
	 * @throws IOException
	 */
	public static String sendGet(String url, String param, String encoding) throws IOException {
		String result = "";
		String urlNameString = url + "?" + param;
		
		Request req = new Request.Builder().url(urlNameString).build(); 
		Response response = httpClient.newCall(req).execute();
		if (!response.isSuccessful())
		{
			throw new IOException("Unexpected code " + response);
		}
		result = response.body().string();
		
		if (null == encoding || encoding.equals("")) {
			return result;
		}
		byte[] bresult = result.getBytes();
		result = new String(bresult, encoding);
		
		return result;
	}
	
	/**
	 * 功能说明:向指定URL发送POST方法的请求
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月8日 上午10:54:55
	 * @param url 发送请求的URL
	 * @param jsonData 请求参数,请求参数应该是Json格式字符串的形式。
	 * @return URL所代表远程资源的响应结果
	 * @throws IOException
	 */
	public static String sendPost(String url, String jsonData) throws IOException {
		String result = "";
		RequestBody body = RequestBody.create(MediaType.parse("application/json;charset=utf-8"), jsonData);
		Request req = new Request.Builder().url(url).header("Content-Type", "application/json").post(body).build(); 
		Response response = httpClient.newCall(req).execute();
		if (!response.isSuccessful())
		{
			throw new IOException("Unexpected code " + response);
		}
		result = response.body().string();
		
		return result;
	}
	
	/**
	 * 功能说明:向指定URL发送POST方法的请求
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月8日 上午10:54:55
	 * @param url 发送请求的URL
	 * @param jsonData 请求参数,请求参数应该是Json格式字符串的形式。
	 * @param encoding 设置响应信息的编码格式,如utf-8
	 * @param authorization 授权
	 * @param postmanToken 票证
	 * @return URL所代表远程资源的响应结果
	 * @throws IOException
	 */
	public static String sendPost(String url, String jsonData, String encoding, String authorization, String postmanToken) {
		PrintWriter out = null;
		BufferedReader in = null;
		String result = "";
		try {
			URL realUrl = new URL(url);
			// 打开和URL之间的连接
			URLConnection con = realUrl.openConnection();
			HttpURLConnection conn = (HttpURLConnection) con;
			// 设置通用的请求属性
			conn.setRequestMethod("POST"); // 设置Post请求
			conn.setConnectTimeout(5 * 1000);
			conn.setRequestProperty("accept", "*/*");
			conn.setRequestProperty("connection", "Keep-Alive");
			conn.setRequestProperty("user-agent",
					"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
			conn.setRequestProperty("Content-Type",
					"application/x-www-form-urlencoded"); // 设置内容类型
			conn.setRequestProperty("authorization", authorization);
			conn.setRequestProperty("postman-token", postmanToken);
			
			// conn.setRequestProperty("Content-Length",
			// String.valueOf(param.length())); //设置长度
			// 发送POST请求必须设置如下两行
			conn.setDoOutput(true);
			conn.setDoInput(true);
			conn.setUseCaches(false);
			// 获取URLConnection对象对应的输出流
			out = new PrintWriter(new OutputStreamWriter(
					conn.getOutputStream(), encoding));
			// 发送请求参数
			// out.print(param);
			out.write(jsonData);
			// flush输出流的缓冲
			out.flush();
			// 定义BufferedReader输入流来读取URL的响应
			in = new BufferedReader(
					new InputStreamReader(conn.getInputStream()));
			String line;
			while ((line = in.readLine()) != null) {
				result += line;
			}
			byte[] bresult = result.getBytes();
			result = new String(bresult, encoding);
		} catch (Exception e) {
			System.out.println("发送 POST 请求出现异常!" + e);
			e.printStackTrace();
		}
		// 使用finally块来关闭输出流、输入流
		finally {
			try {
				if (out != null) {
					out.close();
				}
				if (in != null) {
					in.close();
				}
			} 
			catch (IOException ex) {
				ex.printStackTrace();
			}
		}
		return result;
	}
	
	/**
	 * 功能说明:向指定 URL 发送POST方法的请求
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月8日 下午2:17:06
	 * @param url 发送请求的 URL
	 * @param jsonData 请求参数,请求参数应该是Json格式字符串的形式。
	 * @param encoding 设置响应信息的编码格式,如utf-8
	 * @return url所代表远程资源的响应结果
	 * @throws IOException
	 */
	public static String sendPost(String url, String jsonData, String encoding) throws IOException {
		String result = "";
		RequestBody body = RequestBody.create(MediaType.parse("application/json;charset=utf-8"), jsonData);
		Request req = new Request.Builder().url(url).header("Content-Type", "application/json").post(body).build(); 
		Response response = httpClient.newCall(req).execute();
		if (!response.isSuccessful())
		{
			throw new IOException("Unexpected code " + response);
		}
		result = response.body().string();
		
		if (null == encoding || encoding.equals("")) {
			return result;
		}
		byte[] bresult = result.getBytes();
		result = new String(bresult, encoding);
		
		return result;
	}
	
	/**
	 * 功能说明:上传文件
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月8日 下午2:15:51
	 * @param url 上传url
	 * @param file 要上传的文件对象
	 * @return 返回上传的结果
	 */
	public static String uploadPost(String url, File file) {
		DataOutputStream dos = null;
		FileInputStream fis = null;
		DataInputStream dis = null;
		BufferedReader in = null;
		String result = "";
		String end = "\r\n";
		String twoHyphens = "--"; // 用于拼接
		String boundary = "*****"; // 用于拼接 可自定义
		try {
			URL realUrl = new URL(url);
			// 打开和URL之间的连接
			URLConnection con = realUrl.openConnection();
			HttpURLConnection conn = (HttpURLConnection) con;
			// 设置通用的请求属性
			conn.setRequestMethod("POST"); // 设置Post请求
			// 发送POST请求必须设置如下两行
			conn.setDoOutput(true);
			conn.setDoInput(true);
			conn.setUseCaches(false);
			conn.setConnectTimeout(5 * 1000);
			conn.setRequestProperty("connection", "Keep-Alive");
			conn.setRequestProperty("Charset", "UTF-8");
			conn.setRequestProperty("Content-Type",
					"multipart/form-data; boundary=" + boundary); // 设置内容类型
			
			// 获取URLConnection对象对应的输出流
			dos = new DataOutputStream(conn.getOutputStream());
			//1、写入媒体头部分
			StringBuilder sb = new StringBuilder();
			sb.append(twoHyphens).append(boundary).append(end);
			sb.append("Content-Disposition: form-data;name=\"file\";filename=\"" + file.getName() + "\"").append(end);
			sb.append("Content-Type:application/octet-stream").append(end).append(end);
			byte[] head = sb.toString().getBytes("utf-8");
			dos.write(head);
			
			//2、写入媒体正文部分, 对文件进行传输
			fis = new FileInputStream(file);
			dis = new DataInputStream(fis);
			byte[] buffer = new byte[8192]; // 8K
			int count = 0;
			while ((count = dis.read(buffer)) != -1) {
				dos.write(buffer, 0, count);
			}
			
			//3、写入媒体结尾部分。
			byte[] foot = (end + twoHyphens + boundary + twoHyphens + end).getBytes("utf-8");
			dos.write(foot);
			dos.flush();
			// 定义BufferedReader输入流来读取URL的响应
			in = new BufferedReader(
					new InputStreamReader(conn.getInputStream()));
			String line;
			while ((line = in.readLine()) != null) {
				result += line;
			}
			byte[] bresult = result.getBytes();
			result = new String(bresult, "utf-8");
		} catch (Exception e) {
			System.out.println("发送 POST 请求出现异常!" + e);
			e.printStackTrace();
		}
		// 使用finally块来关闭输出流、输入流
		finally {
			try {
				if (dos != null) {
					dos.close();
				}
				if (dis != null) {
					dis.close();
				}
				if (fis != null) {
					fis.close();
				}
				if (in != null) {
					in.close();
				}
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}
		return result;
	}
	
	/**
	 * 功能说明:下载素材文件
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:06:56
	 * @param url 下载的接口地址
	 * @param param 参数
	 * @param outFileName 输出文件
	 * @return 成功返回true,失败返回false
	 * @throws IOException
	 */
	public static boolean downloadFile(String url, String param, String outFileName) throws IOException
    {
		boolean result = false;
		String urlNameString = url + "?" + param;
		Request req = new Request.Builder().url(url).build(); 
		Response response = httpClient.newCall(req).execute();
		if (!response.isSuccessful())
		{
			throw new IOException("Unexpected code " + response);
		}
		if (response.body().contentType().toString().toLowerCase().contains("application/json") || response.body().contentType().toString().toLowerCase().contains("text/plain")) {
			throw new IOException("下载资源失败,下载地址为=" + urlNameString);
		} 
		else 
		{
			InputStream in = response.body().byteStream();
			FileOutputStream out = new FileOutputStream(outFileName);
			int bufferSize = 2048;
			byte[] data = new byte[bufferSize];
            int length = 0;
            while ((length = in.read(data, 0, bufferSize)) > 0)
            {
                out.write(data, 0, length);
            }
            out.close();
            in.close();
            result = true;
		}
        return result;
    }
}

Global.java

package com.wongoing.webchat.pub;

/**
 * 功能说明:微信公众号全局接口地址
 * 修改说明:
 * @author zhenglibing
 * @date 2018年1月8日 下午2:27:30
 * @version 0.1
 */
public interface Global {
	/**
	 * 微信公众平台全局唯一票据接口
	 */
	public static final String ACCESSTOKENURL = "https://api.weixin.qq.com/cgi-bin/token";
	
	/**
	 * 微信公众平台,通过media_id获取临时图片、语音、视频等文件的接口地址,Https请求方式:GET
	 * 请求示例 <![CDATA[https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID]]>
	 * 注意 视频文件不支持https下载,调用该接口需http协议
	 */
	public static final String GETTEMPMEDIAURL = "https://api.weixin.qq.com/cgi-bin/media/get";
	
	/**
	 * 微信公众平台,客服发送消息接口地址,Https请求方式::POST
	 * 接口地址示例:<![CDATA[https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN]]>
	 */
	public static final String SENDMSGURL = "https://api.weixin.qq.com/cgi-bin/message/custom/send";
	
	/**
	 * 微信公众平台,创建菜单接口地址,Https请求方式:POST
	 * 接口地址示例:<![CDATA[https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN]]>
	 */
	public static final String CREATEMENUURL = "https://api.weixin.qq.com/cgi-bin/menu/create";
	/**
	 * 微信公众平台,删除菜单接口地址,Https请求方式:GET
	 * 接口地址示例:<![CDATA[https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN]]>
	 */
	public static final String DELMENURUL = "https://api.weixin.qq.com/cgi-bin/menu/delete";
	/**
	 * 微信公众平台,获取菜单列表接口地址,Https请求方式:GET
	 * 接口地址示例:<![CDATA[https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN]]>
	 */
	public static final String GETMENUURL = "https://api.weixin.qq.com/cgi-bin/menu/get";
	
	/**
	 * 微信公众平台,获取用户列表接口地址,Https请求方式:GET
	 * 接口地址示例:<![CDATA[https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID]]>
	 */
	public static final String GETUSERURL = "https://api.weixin.qq.com/cgi-bin/user/get";
	/**
	 * 微信公众平台,获取用户基本信息(包括UnionID机制)
	 * 接口地址示例:<![CDATA[https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN]]>
	 */
	public static final String GETUSERINFOURL = "https://api.weixin.qq.com/cgi-bin/user/info";
	
	/**
	 * 微信公众平台,微信网页授权,通过code换取access_token,Https请求方式:GET
	 * 接口地址示例:<![CDATA[https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code]]>
	 */
	public static final String GETPAGEACCESSTOKENURL = "https://api.weixin.qq.com/sns/oauth2/access_token";
}

WebChat.java

package com.wongoing.webchat.pub;

import java.io.File;
import java.io.IOException;

import com.alibaba.fastjson.JSON;
import com.qq.weixin.mp.aes.AesException;
import com.qq.weixin.mp.aes.WXBizMsgCrypt;
import com.wongoing.api.HttpRequestUtil;
import com.wongoing.webchat.pub.entity.AccessToken;
import com.wongoing.webchat.pub.entity.MenuParam;
import com.wongoing.webchat.pub.entity.PageAccessToken;
import com.wongoing.webchat.pub.entity.ResultMsg;
import com.wongoing.webchat.pub.entity.SendMsg;
import com.wongoing.webchat.pub.entity.UserInfo;

/**
 * 功能说明:微信公众号接口调用封装类,封装所有微信公众号接口调用方法
 * 修改说明:
 * @author zhenglibing
 * @date 2018年1月9日 上午9:04:34
 * @version 0.1
 */
public class WebChat {
	
	/**
	 * 功能说明:基础方法:在回调模式下验证服务器接口地址
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 上午11:03:15
	 * @param token 公众号号的全局唯一票据
	 * @param sEncodingAESKey 微信公众号EncodingAESKey
	 * @param appId 微信公众号AppId
	 * @param msg_signature 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
	 * @param timestamp 时间戳
	 * @param nonce 随机串,对应URL参数的nonce
	 * @return 验证成功返回true,否则返回false
	 * @throws AesException
	 */
	public static boolean checkSignature(String token, String sEncodingAESKey, String appId, String msg_signature, String timestamp, String nonce) throws AesException
    {
        WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, sEncodingAESKey, appId);
        boolean result = wxcpt.verifyUrl(msg_signature, timestamp, nonce);
        return result;
    }
	
	/**
	 * 功能说明:基础方法:检验消息的真实性,并且获取解密后的明文.
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 上午11:09:17
	 * @param token 应用的回调接口票证
	 * @param sEncodingAESKey 应用的回调接口密钥
	 * @param appId AppId
	 * @param msg_signature 微信加密签名,msg_signature结合了企业填写的token、请求中的timestamp、nonce参数、加密的消息体,必填参数
	 * @param timestamp 时间戳,必填参数
	 * @param nonce 随机数,必填参数
	 * @param postData 加密的随机字符串,以msg_encrypt格式提供。需要解密并返回echostr明文,解密后有random、msg_len、msg、$CorpID四个字段,其中msg即为echostr明文。首次校验时必填
	 * @return 返回解密后字符串
	 * @throws AesException
	 */
	public static String serverDecryptMsg(String token, String sEncodingAESKey, String appId, String msg_signature, String timestamp, String nonce, String postData) throws AesException
    {
        WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, sEncodingAESKey, appId);
        String sEchoStr = wxcpt.decryptMsg(msg_signature, timestamp, nonce, postData);
        return sEchoStr;
    }
	
	/**
	 * 功能说明:基础方法:将公众平台回复用户的消息加密打包.
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 上午11:28:04
	 * @param token 应用的回调接口票证
	 * @param sEncodingAESKey 应用的回调接口密钥
	 * @param appId AppId
	 * @param msg_signature 微信加密签名,msg_signature结合了企业填写的token、请求中的timestamp、nonce参数、加密的消息体,必填参数
	 * @param timestamp 时间戳,必填参数
	 * @param nonce 随机数,必填参数
	 * @param replyMsg 要加密的回复消息
	 * @return 返回加密后的密文
	 * @throws AesException
	 */
	public static String ServerEncryptMsg(String token, String sEncodingAESKey, String appId, String msg_signature, String timestamp, String nonce, String replyMsg) throws AesException
    {
        WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, sEncodingAESKey, appId);
        String sEchoStr = wxcpt.encryptMsg(replyMsg, timestamp, nonce);
        return sEchoStr;
    }
	
	/**
	 * 功能说明:基础方法:获取AccessToken
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 上午11:32:50
	 * @param appid 微信公众号AppId
	 * @param secret 凭证密钥
	 * @return 返回公众号号的全局唯一票据
	 * @throws IOException
	 */
	public static String getAccessToken(String appid, String secret) throws IOException
    {
        String param = "grant_type=client_credential&appid=%s&secret=%s";
        param = String.format(param, appid, secret);
        String jsonAccessToken = HttpRequestUtil.sendGet(Global.ACCESSTOKENURL, param);
        return jsonAccessToken;
    }
	
	/**
	 * 功能说明:基础方法:获取AccessToken实体
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 上午11:34:44
	 * @param appid 微信公众号AppId
	 * @param secret 凭证密钥
	 * @return 返回公众号的全局唯一票据实体
	 * @throws IOException
	 */
	public static AccessToken getAccessTokenEntity(String appid, String secret) throws IOException
    {
        String jsonResult = getAccessToken(appid, secret);
        AccessToken result = JSON.parseObject(jsonResult, AccessToken.class);
        return result;
    }
	
	/**
	 * 功能说明:基础方法,获取网页授权access_token
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月15日 上午9:16:42
	 * @param appid 微信公众号AppId
	 * @param secret 凭证密码
	 * @param code 引导网页授权的code码
	 * @return 返回网页授权json字符串
	 * @throws IOException
	 */
	public static String getPageAccessToken(String appid, String secret, String code) throws IOException {
		String param = "appid=%s&secret=%s&code=%s&grant_type=authorization_code";
		param = String.format(param, appid, secret, code);
		String jsonResult = HttpRequestUtil.sendGet(Global.GETPAGEACCESSTOKENURL, param);
		return jsonResult;
	}
	
	/**
	 * 功能说明:基础方法,获取网页授权access_token
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月15日 上午9:18:30
	 * @param appid 微信公众号AppId
	 * @param secret 凭证密码
	 * @param code 引导网页授权的code码
	 * @return 返回网页授权json字符串
	 * @throws IOException
	 */
	public static PageAccessToken getPageAccessTokenEntity(String appid, String secret, String code) throws IOException {
		String jsonResult = getPageAccessToken(appid, secret, code);
		PageAccessToken result = JSON.parseObject(jsonResult, PageAccessToken.class);
		return result;
	}
	
	/**
	 * 功能说明:素材方法:获取临时素材文件(不包括视频)
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午1:32:02
	 * @param accessToken 微信公众号的全局唯一票据
	 * @param media_id 要获取的素材文件的media_id
	 * @return 返回对应素材文件的json字符串
	 * @throws IOException
	 */
	public static String getTempMedia(String accessToken, String media_id) throws IOException
    {
        String param = "access_token=%s&media_id=%s";
        param = String.format(param, accessToken, media_id);
        String jsonResult = HttpRequestUtil.sendGet(Global.GETTEMPMEDIAURL, param);
        return jsonResult;
    }
	
	/**
	 * 功能说明:素材方法:下载临时素材文件
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:10:05
	 * @param accessToken 微信公众号的全局唯一票据
	 * @param media_id 要下载的媒体文件的media_id
	 * @param outFileName 输出文件的完整路径包括文件名
	 * @return 成功返回文件名,失败返回“”
	 * @throws IOException
	 */
	public static String downloadTempMedia(String accessToken, String media_id, String outFileName) throws IOException
    {
        String param = "access_token=%s&media_id=%s";
        param = String.format(param, accessToken, media_id);
        boolean result = HttpRequestUtil.downloadFile(Global.GETTEMPMEDIAURL, param, outFileName);
        if (result)
        {
        	File file = new File(outFileName);
            return file.getName();
        }
        else
        {
            return "";
        }
    }
	
	/**
	 * 功能说明:客服消息方法:发送文本消息
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:12:50
	 * @param accessToken 企业号的全局唯一票据
	 * @param jsonData 要发送的json格式的消息
	 * @return 返回json结果字符串
	 * @throws IOException
	 */
	public static String sendTextMsg1(String accessToken, String jsonData) throws IOException
    {
        String url = Global.SENDMSGURL + "?access_token=%s";
        url = String.format(url, accessToken);
        String jsonResult = HttpRequestUtil.sendPost(url, jsonData);
        return jsonResult;
    }
	
	/**
	 * 功能说明:客服消息方法:发送文本消息
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:19:31
	 * @param accessToken 企业号的全局唯一票据
	 * @param jsonData 要发送的json格式的消息
	 * @return 返回ResultMsg结果对象
	 * @throws IOException
	 */
	public static ResultMsg sendTextMsg(String accessToken, String jsonData) throws IOException
    {
        String url = Global.SENDMSGURL + "?access_token=%s";
        url = String.format(url, accessToken);
        String jsonResult = HttpRequestUtil.sendPost(url, jsonData);
        ResultMsg result = JSON.parseObject(jsonResult, ResultMsg.class);
        return result;
    }
	
	/**
	 * 功能说明:客服消息方法:发消息(包括文本消息、图像、声音、视频、文件、图文、微信后台图文)
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:20:16
	 * @param accessToken 企业号的全局唯一票据
	 * @param msg 要发送的消息对象
	 * @return 返回ResultMsg结果对象
	 * @throws IOException
	 */
	public static ResultMsg sendMsg(String accessToken, SendMsg msg) throws IOException
    {
        ResultMsg result = sendTextMsg(accessToken, msg.toJsonString());
        return result;
    }
	
	/**
	 * 功能说明:菜单方法:创建菜单
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:24:10
	 * @param accessToken 公众号的唯一票据
	 * @param param 要创建的菜单参数
	 * @return 返回创建结果对象
	 * @throws IOException
	 */
	public static ResultMsg createMenu(String accessToken, MenuParam param) throws IOException
    {
        String url = Global.CREATEMENUURL + "?access_token=%s";
        url = String.format(url, accessToken);
        String jsonResult = HttpRequestUtil.sendPost(url, param.toJsonString());
        ResultMsg result = JSON.parseObject(jsonResult, ResultMsg.class);
        return result;
    }
	
	/**
	 * 功能说明:菜单方法:删除菜单
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:26:07
	 * @param accessToken 公众号的全局唯一票据
	 * @return 返回删除结果对象
	 * @throws IOException
	 */
	public static ResultMsg delMenu(String accessToken) throws IOException
    {
        String param = "access_token=%s";
        param = String.format(param, accessToken);
        String jsonResult = HttpRequestUtil.sendGet(Global.DELMENURUL, param);
        ResultMsg result = JSON.parseObject(jsonResult, ResultMsg.class);
        return result;
    }
	
	/**
	 * 功能说明:菜单方法:获取菜单列表
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:27:23
	 * @param accessToken 企业号的全局唯一票据
	 * @return 返回菜单列表
	 * @throws IOException
	 */
	public static String getMenu(String accessToken) throws IOException
    {
        String param = "access_token=%s";
        param = String.format(param, accessToken);
        String jsonResult = HttpRequestUtil.sendGet(Global.GETMENUURL, param);
        return jsonResult;
    }
	
	/**
	 * 功能说明:用户管理方法:获取用户列表
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:30:50
	 * @param accessToken 公众号的全局唯一票据
	 * @param next_openid 第一个拉取的OPENID,不填默认从头开始拉取
	 * @return 返回json结果字符串
	 * @throws IOException
	 */
	public static String getUserJsonStr(String accessToken, String next_openid) throws IOException
    {
        String param = "access_token=%s&next_openid=%s";
        param = String.format(param, accessToken, next_openid);
        String jsonResult = HttpRequestUtil.sendGet(Global.GETUSERURL, param);
        return jsonResult;
    }
	
	/**
	 * 功能说明:用户管理方法:获取用户列表
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:32:54
	 * @param accessToken 公众号的全局唯一票据
	 * @param next_openid 第一个拉取的OPENID,不填默认从头开始拉取
	 * @return 返回结果对象
	 * @throws IOException
	 */
	public static ResultMsg getUser(String accessToken, String next_openid) throws IOException
    {
        String jsonResult = getUserJsonStr(accessToken, next_openid);
        ResultMsg result = JSON.parseObject(jsonResult, ResultMsg.class);
        return result;
    }
	
	/**
	 * 功能说明:用户管理方法:获取用户基本信息(包括UnionID机制)
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:34:40
	 * @param accessToken 公众号的全局唯一票据
	 * @param openid 普通用户的标识,对当前公众号唯一
	 * @param lang 国家地区语言版本,zh_CN简体,zh_TW繁体,en英语
	 * @return 返回json结果字符串
	 * @throws IOException
	 */
	public static String getUserInfoJsonStr(String accessToken, String openid, String lang) throws IOException
    {
        String param = "access_token=%s&openid=%s&lang=%s";
        param = String.format(param, accessToken, openid, lang);
        String jsonResult = HttpRequestUtil.sendGet(Global.GETUSERINFOURL, param);
        return jsonResult;
    }
	
	/**
	 * 功能说明:用户管理方法:获取用户基本信息(包括UnionID机制)
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:36:39
	 * @param accessToken 公众号的全局唯一票据
	 * @param openId 普通用户的标识,对当前公众号唯一
	 * @param lang 国家地区语言版本,zh_CN简体,zh_TW繁体,en英语
	 * @return 返回UserInfo实体对象
	 * @throws IOException
	 */
	public static UserInfo getUserInfo(String accessToken, String openId, String lang) throws IOException
    {
        String jsonResult = getUserInfoJsonStr(accessToken, openId, lang);
        UserInfo result = JSON.parseObject(jsonResult, UserInfo.class);
        return result;
    }
	
	/**
	 * 功能说明:用户管理方法:获取用户基本信息(包括UnionID机制)
	 * 修改说明:
	 * @author zhenglibing
	 * @date 2018年1月9日 下午2:38:00
	 * @param accessToken 公众号的全局唯一票据
	 * @param openId 普通用户的标识,对当前公众号唯一
	 * @return 返回UserInfo实体对象
	 * @throws IOException
	 */
	public static UserInfo getUserInfo(String accessToken, String openId) throws IOException
    {
        UserInfo result = getUserInfo(accessToken, openId, "zh_CN");
        return result;
    }
}

完整代码下载

完整代码下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值