java开发微信公众号
1.接入微信公众号
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("接口测试开始!!!"); //微信加密签名 String signature = request.getParameter("signature"); //时间戳 String timestamp = request.getParameter("timestamp"); //随机数 String nonce = request.getParameter("nonce"); //随机字符串 String echostr = request.getParameter("echostr"); PrintWriter out = response.getWriter(); //通过校验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败 if(SignUtil.checkSignature(signature,timestamp,nonce)){ out.print(echostr); } out.close(); out = null; // response.encodeRedirectURL("success.jsp"); } /** * 处理微信服务器发来的消息 */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //消息的接受、处理、响应 request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); //调用核心业务类型接受消息、处理消息 String respMessage = EastnetService.processRequest(request); //响应消息 PrintWriter out = response.getWriter(); out.print(respMessage); out.close(); }
1 import java.security.MessageDigest; 2 import java.security.NoSuchAlgorithmException; 3 import java.util.Arrays; 4 import java.util.Iterator; 5 import java.util.Map; 6 import java.util.Set; 7 import java.util.concurrent.ConcurrentHashMap; 8 9 /** 10 * 请求校验工具类 11 * @author pengsong 12 * @date 2016.01.19 13 */ 14 public class SignUtil { 15 //与微信配置中的的Token一致 16 private static String token = "你的token"; 17 18 public static boolean checkSignature(String signature, String timestamp, 19 String nonce) { 20 String[] arra = new String[]{token,timestamp,nonce}; 21 //将signature,timestamp,nonce组成数组进行字典排序 22 Arrays.sort(arra); 23 StringBuilder sb = new StringBuilder(); 24 for(int i=0;i<arra.length;i++){ 25 sb.append(arra[i]); 26 } 27 MessageDigest md = null; 28 String stnStr = null; 29 try { 30 md = MessageDigest.getInstance("SHA-1"); 31 byte[] digest = md.digest(sb.toString().getBytes()); 32 stnStr = byteToStr(digest); 33 } catch (NoSuchAlgorithmException e) { 34 // TODO Auto-generated catch block 35 e.printStackTrace(); 36 } 37 //释放内存 38 sb = null; 39 //将sha1加密后的字符串与signature对比,标识该请求来源于微信 40 return stnStr!=null?stnStr.equals(signature.toUpperCase()):false; 41 } 42 /** 43 * 将字节数组转换成十六进制字符串 44 * @param digestArra 45 * @return 46 */ 47 private static String byteToStr(byte[] digestArra) { 48 // TODO Auto-generated method stub 49 String digestStr = ""; 50 for(int i=0;i<digestArra.length;i++){ 51 digestStr += byteToHexStr(digestArra[i]); 52 } 53 return digestStr; 54 } 55 /** 56 * 将字节转换成为十六进制字符串 57 */ 58 private static String byteToHexStr(byte dByte) { 59 // TODO Auto-generated method stub 60 char[] Digit = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; 61 char[] tmpArr = new char[2]; 62 tmpArr[0] = Digit[(dByte>>>4)&0X0F]; 63 tmpArr[1] = Digit[dByte&0X0F]; 64 String s = new String(tmpArr); 65 return s; 66 } 67 68 public static void main(String[] args) { 69 /*byte dByte = 'A'; 70 System.out.println(byteToHexStr(dByte));*/ 71 Map<String,String> map = new ConcurrentHashMap<String, String>(); 72 map.put("4", "zhangsan"); 73 map.put("100", "lisi"); 74 Set set = map.keySet(); 75 Iterator iter = set.iterator(); 76 while(iter.hasNext()){ 77 // String keyV = (String) iter.next(); 78 String key =(String)iter.next(); 79 System.out.println(map.get(key)); 80 // System.out.println(map.get(iter.next())); 81 } 82 /*for(int i=0;i<map.size();i++){ 83 84 }*/ 85 }
2.创建菜单
2.1获取Access_Token
import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.ConnectException; import java.net.URL; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import com.eastnet.wechat.pojo.AccessToken; import com.eastnet.wechat.pojo.Menu; import net.sf.json.JSONObject; public class WeixinUtil { // private static Logger log = LoggerFactory.getLogger(WeixinUtil.class); // 获取access_token的接口地址(GET) 限200(次/天) public final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"; // 菜单创建(POST) 限100(次/天) public static String menu_create_url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN"; /** * 发起https请求并获取结果 * * @param requestUrl 请求地址 * @param requestMethod 请求方式(GET、POST) * @param outputStr 提交的数据 * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值) */ public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) { JSONObject jsonObject = null; StringBuffer buffer = new StringBuffer(); try { // 创建SSLContext对象,并使用我们指定的信任管理器初始化 TrustManager[] tm = { new MyX509TrustManager() }; SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); sslContext.init(null, tm, new java.security.SecureRandom()); // 从上述SSLContext对象中得到SSLSocketFactory对象 SSLSocketFactory ssf = sslContext.getSocketFactory(); URL url = new URL(requestUrl); HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection(); httpUrlConn.setSSLSocketFactory(ssf); httpUrlConn.setDoOutput(true); httpUrlConn.setDoInput(true); httpUrlConn.setUseCaches(false); // 设置请求方式(GET/POST) httpUrlConn.setRequestMethod(requestMethod); if ("GET".equalsIgnoreCase(requestMethod)) httpUrlConn.connect(); // 当有数据需要提交时 if (null != outputStr) { OutputStream outputStream = httpUrlConn.getOutputStream(); // 注意编码格式,防止中文乱码 outputStream.write(outputStr.getBytes("UTF-8")); outputStream.close(); } // 将返回的输入流转换成字符串 InputStream inputStream = httpUrlConn.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String str = null; while ((str = bufferedReader.readLine()) != null) { buffer.append(str); } bufferedReader.close(); inputStreamReader.close(); // 释放资源 inputStream.close(); inputStream = null; httpUrlConn.disconnect(); System.out.println(buffer.toString()); jsonObject = JSONObject.fromObject(buffer.toString()); } catch (ConnectException ce) { System.out.println("Weixin server connection timed out."); } catch (Exception e) { System.err.println("https request error:{}"); // log.error("https request error:{}", e); } return jsonObject; } /** * 获取access_token * * @param appid 凭证 * @param appsecret 密钥 * @return */ public static AccessToken getAccessToken(String appid, String appsecret) { AccessToken accessToken = null; String requestUrl = access_token_url.replace("APPID", appid).replace("APPSECRET", appsecret); JSONObject jsonObject = httpRequest(requestUrl, "GET", null); // 如果请求成功 if (null != jsonObject) { try { accessToken = new AccessToken(); accessToken.setToken(jsonObject.getString("access_token")); accessToken.setExpiresIn(jsonObject.getInt("expires_in")); } catch (Exception e) { accessToken = null; // 获取token失败 System.out.println("获取token失败 errcode:"+jsonObject.getInt("errcode")+"errmsg:"+jsonObject.getString("errmsg")); // log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg")); } } return accessToken; } /** * 创建菜单 * * @param menu 菜单实例 * @param accessToken 有效的access_token * @return 0表示成功,其他值表示失败 */ public static int createMenu(Menu menu, String accessToken) { int result = 0; // 拼装创建菜单的url String url = menu_create_url.replace("ACCESS_TOKEN", accessToken); // 将菜单对象转换成json字符串 String jsonMenu = JSONObject.fromObject(menu).toString(); // 调用接口创建菜单 JSONObject jsonObject = httpRequest(url, "POST", jsonMenu); if (null != jsonObject) { if (0 != jsonObject.getInt("errcode")) { result = jsonObject.getInt("errcode"); System.out.println("创建菜单失败errcode:"+jsonObject.getInt("errcode")+"errmsg:"+jsonObject.getString("errmsg")); // log.error("创建菜单失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg")); } } return result; } }
public class AccessToken { // 获取到的凭证 private String token; // 凭证有效时间,单位:秒 private int expiresIn; public String getToken() { return token; } public void setToken(String token) { this.token = token; } public int getExpiresIn() { return expiresIn; } public void setExpiresIn(int expiresIn) { this.expiresIn = expiresIn; } }
import javax.net.ssl.X509TrustManager; /** * 证书信任管理器(用于https请求) * * @author steve * @date 2013-08-08 */ public class MyX509TrustManager implements X509TrustManager{ public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } }
import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.eastnet.wechat.pojo.AccessToken; import com.eastnet.wechat.pojo.Button; import com.eastnet.wechat.pojo.CommonButton; import com.eastnet.wechat.pojo.ComplexButton; import com.eastnet.wechat.pojo.Menu; import com.eastnet.wechat.pojo.ViewButton; import com.eastnet.wechat.utils.WeixinUtil; public class CreateMenuServlet extends HttpServlet { /** * Constructor of the object. */ public CreateMenuServlet() { super(); } /** * Destruction of the servlet. <br> */ public void destroy() { super.destroy(); // Just puts "destroy" string in log // Put your code here } /** * The doGet method of the servlet. <br> * * This method is called when a form has its tag value method equals to get. * * @param request the request send by the client to the server * @param response the response send by the server to the client * @throws ServletException if an error occurred * @throws IOException if an error occurred */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 第三方用户唯一凭证 String appId = "你的appId"; // 第三方用户唯一凭证密钥 String appSecret = "你的appSecret"; // 调用接口获取access_token AccessToken at = WeixinUtil.getAccessToken(appId, appSecret); if (null != at) { // 调用接口创建菜单 int result = WeixinUtil.createMenu(getMenu(), at.getToken()); // 判断菜单创建结果 if (0 == result){ response.setContentType("text/html;charset=UTF-8"); PrintWriter pw = response.getWriter(); pw.println("菜单创建成功!"); pw.flush(); }else{ response.setContentType("text/html;charset=UTF-8"); PrintWriter pw = response.getWriter(); pw.println("菜单创建失败,错误码:" + result); pw.flush(); } } } /** * The doPost method of the servlet. <br> * * This method is called when a form has its tag value method equals to post. * * @param request the request send by the client to the server * @param response the response send by the server to the client * @throws ServletException if an error occurred * @throws IOException if an error occurred */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } /** * Initialization of the servlet. <br> * * @throws ServletException if an error occurs */ public void init() throws ServletException { // Put your code here } /** * 组装菜单数据 * * @return */ private static Menu getMenu() { CommonButton btn11 = new CommonButton(); btn11.setName("个人信息查看"); btn11.setType("click"); btn11.setKey("stuInfoView"); CommonButton btn12 = new CommonButton(); btn12.setName("个人信息修改"); btn12.setType("click"); btn12.setKey("stuInfoEdit"); CommonButton btn21 = new CommonButton(); btn21.setName("行程查看"); btn21.setType("click"); btn21.setKey("stuTravelView"); CommonButton btn22 = new CommonButton(); btn22.setName("行程添加"); btn22.setType("click"); btn22.setKey("stuTravelAdd"); CommonButton btn23 = new CommonButton(); btn23.setName("行程修改"); btn23.setType("click"); btn23.setKey("stuTravelEdit"); CommonButton btn31 = new CommonButton(); btn31.setName("操作说明"); btn31.setType("click"); btn31.setKey("help"); CommonButton btn32 = new CommonButton(); btn32.setName("呼叫管理员"); btn32.setType("click"); btn32.setKey("callAdmin"); CommonButton btn33 = new CommonButton(); btn33.setName("意见反馈"); btn33.setType("click"); btn33.setKey("suggestions"); ComplexButton mainBtn1 = new ComplexButton(); mainBtn1.setName("个人信息"); mainBtn1.setSub_button(new Button[] { btn11, btn12}); ComplexButton mainBtn2 = new ComplexButton(); mainBtn2.setName("行程"); mainBtn2.setSub_button(new Button[] { btn21, btn22, btn23}); ComplexButton mainBtn3 = new ComplexButton(); mainBtn3.setName("帮助"); mainBtn3.setSub_button(new Button[] { btn31, btn32, btn33 }); /** * 这是公众号xiaoqrobot目前的菜单结构,每个一级菜单都有二级菜单项<br> * * 在某个一级菜单下没有二级菜单的情况,menu该如何定义呢?<br> * 比如,第三个一级菜单项不是“更多体验”,而直接是“幽默笑话”,那么menu应该这样定义:<br> * menu.setButton(new Button[] { mainBtn1, mainBtn2, btn33 }); */ Menu menu = new Menu(); menu.setButton(new Button[] { mainBtn1, mainBtn2, mainBtn3 }); return menu; }
public class CommonButton extends Button { private String type; private String key; public String getType() { return type; } public void setType(String type) { this.type = type; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } }
public class ComplexButton extends Button { private Button[] sub_button; public Button[] getSub_button() { return sub_button; } public void setSub_button(Button[] sub_button) { this.sub_button = sub_button; } }
public class Menu { private Button[] button; public Button[] getButton() { return button; } public void setButton(Button[] button) { this.button = button; } }