目錄結構:html
isa.qa.core.weixin.message.resp包和isa.qa.core.weixin.util包中爲微信綁定的工具類,就不一一貼出代碼,詳見附件,下載地址:java
http://files.cnblogs.com/files/007sx/weixin_util.zipweb
jar包(包括了微信支付所需jar此處一塊兒列出) pom.xmlspring
<!-- weixin --> <dependency> <groupId>com.ning</groupId> <artifactId>async-http-client</artifactId> <version>1.8.13</version> </dependency> <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>xstream</artifactId> <version>1.4.7</version> </dependency> <dependency> <groupId>com.gson</groupId> <artifactId>wechat</artifactId> <version>1.0.8</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.14.4</version> </dependency> <dependency> <groupId>com.squareup.okhttp</groupId> <artifactId>okhttp</artifactId> <version>2.7.5</version> </dependency> <dependency> <groupId>net.sf.json-lib</groupId> <artifactId>json-lib</artifactId> <version>2.3</version> </dependency> <dependency> <groupId>commons-httpclient</groupId> <artifactId>commons-httpclient</artifactId> <version>3.1</version> </dependency> <dependency> <groupId>org.jdom</groupId> <artifactId>jdom</artifactId> <version>1.1</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.7</version> </dependency>
注意com.gson wechat 1.0.8 maven中央倉庫沒有,須要本身導入本地倉庫使用,wechat-1.0.8.jar下載地址:json
http://files.cnblogs.com/files/007sx/wechat-1.0.8.zipapi
WeixinResource.java-鏈接微信服務器代碼接口:xcode
package isa.qa.frame.controller; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.URL; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import isa.qa.frame.dao.UserDao; import isa.qa.frame.model.User; import isa.qa.frame.wechat.message.resp.TextMessage; import isa.qa.frame.wechat.util.MessageUtil; import isa.qa.frame.wechat.util.WeixinToken; import net.sf.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import com.gson.util.SHA1; /** * REST controller for managing WorkOrder. */ @Controller @RequestMapping("/api/wechat") public class WeixinResource { @Autowired private UserDao userDao; private final Logger log = LoggerFactory.getLogger(this.getClass()); // @Resource(name = "memberServiceImpl") // public MemberService memberService; private static Map<String,String> TIME_OPENID_MAP = new HashMap<String,String>(); /** * POST /menus -> Create weixin menus. */ //http://localhost:8080/api/wechat/gateway?signature=123432×tamp=12343&nonce=1234&echostr=1223434 @RequestMapping(value = "/gateway", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) @ResponseBody public String weChatValidate(HttpServletRequest request,HttpServletResponse response) throws Exception { System.out.println("enter weChatValidate!"); String _token = "mylng"; String outPut = "error"; String signature = request.getParameter("signature");// 微信加密簽名 String timestamp = request.getParameter("timestamp");// 時間戳 TIME_OPENID_MAP.put(timestamp, ""); String nonce = request.getParameter("nonce");// 隨機數 1413789908 String echostr = request.getParameter("echostr");// System.out.println("in get nonce: "+nonce); String[] str = { _token, timestamp, nonce }; Arrays.sort(str); // 字典序排序 String bigStr = str[0] + str[1] + str[2]; // SHA1加密 String digest = SHA1.encode(bigStr); if (digest.equals(signature)) { outPut = echostr; System.out.println("check success!"); } System.out.println("write response:"+outPut); PrintWriter writer = response.getWriter(); writer.write(outPut); writer.flush(); writer.close(); return null; } @RequestMapping(value = "/gateway", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) @ResponseBody public void handleWechatMessage(HttpServletRequest request,HttpServletResponse response) throws Exception { System.out.println("received wechat event!"); request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); String nonce = request.getParameter("nonce"); System.out.println("in post nonce: "+nonce); request.getSession().setAttribute("nonce", nonce); // 調用核心業務類接收消息、處理消息 String respMessage = processRequest(request,response); // 響應消息 PrintWriter out = response.getWriter(); out.print(respMessage); out.close(); } /** * 處理微信發來的請求 * * @param request * @return */ public String processRequest(HttpServletRequest request,HttpServletResponse response) { String respMessage = null; try { // 默認返回的文本消息內容 String respContent = "請求處理異常,請稍候嘗試!"; // xml請求解析 Map<String, String> requestMap = MessageUtil.parseXml(request); // 發送方賬號(open_id) String fromUserName = requestMap.get("FromUserName"); request.setAttribute("openId", fromUserName); HttpSession session=request.getSession(); session.setAttribute("openId", fromUserName); System.out.println("from:"+fromUserName); // 公衆賬號 String toUserName = requestMap.get("ToUserName"); // 消息類型 String msgType = requestMap.get("MsgType"); System.out.println("MsgType:"+msgType); // 回覆文本消息 TextMessage textMessage = new TextMessage(); textMessage.setToUserName(fromUserName); textMessage.setFromUserName(toUserName); textMessage.setCreateTime(new Date().getTime()); textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT); textMessage.setFuncFlag(0); // 文本消息 if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) { respContent = "您發送的是文本消息!"; } // 圖片消息 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)) { respContent = "您發送的是圖片消息!"; } // 地理位置消息 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)) { respContent = "您發送的是地理位置消息!"; } // 連接消息 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)) { respContent = "您發送的是連接消息!"+requestMap.get("EventKey"); } // 音頻消息 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)) { respContent = "您發送的是音頻消息!"; } // 事件推送 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) { // 事件類型 String eventType = requestMap.get("Event"); // 訂閱 if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) { String access_token = WeixinToken.getRecentToken(); String urlStr = "https://api.weixin.qq.com/cgi-bin/user/info?access_token="+access_token+"&openid="+fromUserName; URL url = new URL(urlStr); BufferedReader bufr = new BufferedReader(new InputStreamReader(new BufferedInputStream(url.openStream()), "utf-8")); String line; StringBuffer sb=new StringBuffer(); while((line=bufr.readLine())!=null){ sb.append(line); } bufr.close(); JSONObject jsonObject = JSONObject.fromObject(sb.toString()); if(jsonObject.get("errcode") != null){ throw new Exception(jsonObject.getString("errmsg")); } String nick = String.valueOf(jsonObject.get("nickname")); String sex = String.valueOf(jsonObject.get("sex")); if (sex.equals("1")) { sex = "男"; } else if(sex.equals("2")) { sex = "女"; } else if(sex.equals("0")) { sex = "未知"; } String city = String.valueOf(jsonObject.get("city")); String province = String.valueOf(jsonObject.get("province")); String country = String.valueOf(jsonObject.get("country")); String headimgurl = String.valueOf(jsonObject.get("headimgurl")); User user = new User(); user.setOpenId(fromUserName); user.setNick(nick); user.setSex(sex); user.setCity(city); user.setProvince(province); user.setCountry(country); user.setHeadimgurl(headimgurl); userDao.save(user); respContent = "謝謝您的關注!"; log.debug("關注成功"); } // 取消訂閱 else if (eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)) { // TODO 取消訂閱後用戶再收不到公衆號發送的消息,所以不須要回復消息 } // 自定義菜單點擊事件 else if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)) { // TODO 自定義菜單權沒有開放,暫不處理該類消息 String key = requestMap.get("EventKey"); if(key.equals("MAINTAIN")){ respContent = "服務熱線:400-008-7070"; } if(key.equals("INFO")){ respContent = "我是愛車,我爲主人服務!"; } System.out.println("event key:"+key); } // 自定義view界面 else if (eventType.equals(MessageUtil.EVENT_TYPE_VIEW)){ String url = requestMap.get("EventKey"); System.out.println("url:"+url); // String[] urls = url.split("&redirect_uri="); // String lastUrl = ""; // String lastUrl2 = ""; // Member user = memberService.findByWeixinOpenId(fromUserName); /*if (user == null) { lastUrl = urls[1]; String[] urls1 = lastUrl.split("&response_type="); String str1 = urls1[0] + "?openId=" + fromUserName; String url0 = URLEncoder.encode(str1,"UTF-8"); lastUrl2 = urls[0] + "&redirect_uri=" + url0 + "&response_type=" + urls1[1]; } else { // JsonConfig config = new JsonConfig(); // config.setIgnoreDefaultExcludes(false); // config.setCycleDetectionStrategy(CycleDetectionStrategy.LENIENT); //這裏是核心,過濾掉不想使用的屬性 // config .setExcludes(filterNames) ; // JsonConfig config = new JsonConfig(); // config.setJsonPropertyFilter(new PropertyFilter(){ // public boolean apply(Object source, String name, Object value) { // if(name.equals("lockedDate") || name.equals("loginDate") || name.equals("loginPhoneDate") || name.equals("birth") || name.equals("loginDate")) { // loginPhoneDate checkDate birth // return true; // } else { // return false; // } // } // }); // JSONObject json = JSONObject.fromObject(user, config);//將java對象轉換爲json對象 // String userJson = json.toString();//將json對象轉換爲字符串 // System.out.println("userJson:"+userJson); lastUrl = urls[0] + "&member=" + user.toString() + "#w" + urls[1]; }*/ } } textMessage.setContent(respContent); respMessage = MessageUtil.textMessageToXml(textMessage); } catch (Exception e) { e.printStackTrace(); } return respMessage; } }
wechat.properties-配置微信AppId和AppSecret (注意該文件所在位置爲ConfKit.java所在包所在的src/main/java下)服務器
#ht
AppId = wxd5609f7b5b4dd051
AppSecret = 2d1c183c1e99c378c7a60b595c825e03
MessageProcessingHandlerImpl=com.gson.MessageProcessingHandlerImpl
WeixinLoginController.java微信
openId綁定用戶的代碼,根據實際項目綁定代碼按需修改,注意項目中若是使用了權限管理,注意把微信相關接口不攔截。session
package isa.qa.blep.admin.controller; import java.util.HashMap; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.security.authentication.encoding.Md5PasswordEncoder; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import isa.qa.core.common.BoqumaConstant; import isa.qa.core.dao.EcshopUserDao; import isa.qa.core.dto.EcshopUserDto; import isa.qa.core.model.EcshopUsers; import isa.qa.core.weixin.util.WeixinToken; @CrossOrigin @Controller @RequestMapping(value = "/api") public class WeixinLoginController { @Autowired private EcshopUserDao userDao; /** * 獲取openId * @param wxCode * @param req * @return */ @RequestMapping(value = "/weixin/code/{wxCode}/wxcode", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) @ResponseBody public Object getWeiXinOpenId(@PathVariable String wxCode){ System.out.println("wxCode--》》》:"+wxCode); if ("undefined".equals(wxCode)) { return null; } String wxOpenId = ""; EcshopUsers user = null; try { wxOpenId = WeixinToken.getWeChatId(wxCode); System.out.println("根據code獲取得的wxOpenId:"+wxOpenId); user = userDao.findOneByOpenId(wxOpenId); if (user == null) { System.out.println("返回的openid:"+wxOpenId); Map<String, String> map = new HashMap<String, String>(); map.put("openId", wxOpenId); return map; } } catch (Exception e) { e.printStackTrace(); } return user; } /** * 微信登錄(綁定) * @param ecshopUserDto * @param openId * @return */ @RequestMapping(value = "/weixin/{openId}/member", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) @ResponseBody public Object checkMember(@RequestBody EcshopUserDto ecshopUserDto, @PathVariable String openId){ String userName = ecshopUserDto.getUserName(); Md5PasswordEncoder md5 = new Md5PasswordEncoder(); md5.setEncodeHashAsBase64(true); String encryptedPassword = md5.encodePassword(ecshopUserDto.getPassword(),BoqumaConstant.SALT); System.out.println("微信登陸用戶--UserName:"+userName); EcshopUsers user = userDao.findOneByUserNameAndPassword(userName,encryptedPassword); if (user == null) { System.out.println("用戶名或密碼錯誤!"); Map<String, String> map = new HashMap<String, String>(); map.put("hint", "用戶名或密碼錯誤!"); return map; } else { user.setOpenId(openId); userDao.save(user); System.out.println("綁定成功!"); return user; } } }
補充:
微信菜單的配置示例:
{ "button":[ { "name" : "優惠活動", "sub_button" : [ { "type": "view", "name": "最新促銷", "url": "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx195166055e5eddb2&redirect_uri=http://carowl.cn/app/index.html#/sales-list&response_type=code&scope=snsapi_base&state=wx&connect_redirect=1#wechat_redirect" },{ "type": "view", "name": "近期活動", "url": "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx195166055e5eddb2&redirect_uri=http://carowl.cn/app/index.html#/near-activities&response_type=code&scope=snsapi_base&state=wx&connect_redirect=1#wechat_redirect" },{ "type": "view", "name": "產品展廳", "url": "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx195166055e5eddb2&redirect_uri=http://carowl.cn/app/index.html#/products&response_type=code&scope=snsapi_base&state=wx&connect_redirect=1#wechat_redirect" } ] }, { "name" : "預定服務", "sub_button" : [ { "type": "view", "name": "試駕預定", "url": "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx195166055e5eddb2&redirect_uri=http://carowl.cn/app/index.html#/repairAppointment/try///carId//&response_type=code&scope=snsapi_base&state=wx&connect_redirect=1#wechat_redirect" },{ "type": "view", "name": "維修預定", "url": "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx195166055e5eddb2&redirect_uri=http://carowl.cn/app/index.html#/repairAppointment////carId//&response_type=code&scope=snsapi_base&state=wx&connect_redirect=1#wechat_redirect" },{ "type": "view", "name": "保養預定", "url": "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx195166055e5eddb2&redirect_uri=http://carowl.cn/app/index.html#/repairAppointment/protect///carId//&response_type=code&scope=snsapi_base&state=wx&connect_redirect=1#wechat_redirect" } ] }, { "name" : "個人地盤", "sub_button" : [ { "type": "view", "name": "一鍵救援", "url": "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx195166055e5eddb2&redirect_uri=http://carowl.cn/app/index.html#/oneKey&response_type=code&scope=snsapi_base&state=wx&connect_redirect=1#wechat_redirect" },{ "type": "view", "name": "在線客服", "url": "http://kefu.easemob.com/webim/im.html?tenantId=6137" },{ "type": "view", "name": "優惠券", "url": "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx195166055e5eddb2&redirect_uri=http://carowl.cn/app/index.html#/packetlist&response_type=code&scope=snsapi_base&state=wx&connect_redirect=1#wechat_redirect" },{ "type": "view", "name": "會員中心", "url": "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx195166055e5eddb2&redirect_uri=http://carowl.cn/app/index.html#/member-center&response_type=code&scope=snsapi_base&state=wx&connect_redirect=1#wechat_redirect" },{ "type": "view", "name": "APP下載", "url": "http://carowl.cn/download_page/index.html" } ] } ] }
公衆號配置的一些流程:
1.登陸公衆號 https://mp.weixin.qq.com/
2.啓用開發者模式
3.進入開發-基本配置
4.填入相關信息,之一URL和Token都要對應上上面所配置的接口和設置的Token
5.網頁受權獲取用戶信息 修改 修改成上一部URL中的 wechat.htib.com.cn
6.微信菜單的配置:
(1).進入在線接口調試工具
(2).配置菜單(先基礎配置獲得access_token,再使用access_token配置菜單)