目录结构:
isa.qa.core.weixin.message.resp包和isa.qa.core.weixin.util包中为微信绑定的工具类,就不一一贴出代码,详见附件,下载地址:
http://files.cnblogs.com/files/007sx/weixin_util.zip
jar包(包括了微信支付所需jar此处一起列出) pom.xml
<!-- 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>
WeixinResource.java-连接微信服务器代码接口:
package isa.qa.blep.admin.controller; import java.io.PrintWriter; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.Resource; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import isa.qa.core.weixin.message.resp.TextMessage; import isa.qa.core.weixin.util.MessageUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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.google.gson.Gson; import com.gson.util.SHA1; /** * REST controller for managing WorkOrder. */ @Controller @RequestMapping("/api/wechat") public class WeixinResource { private final Logger log = LoggerFactory.getLogger(WeixinResource.class); // @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)) { respContent = "谢谢您的关注!"; } // 取消订阅 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绑定用户的代码,根据实际项目绑定代码按需修改,注意项目中如果使用了权限管理,注意把微信相关接口不拦截。
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配置菜单)