diff --git a/demo/pom.xml b/demo/pom.xml index f71e8f5..899cb2c 100644 --- a/demo/pom.xml +++ b/demo/pom.xml @@ -55,6 +55,40 @@ 1.2.37 + + + commons-beanutils + commons-beanutils + 1.9.3 + + + commons-collections + commons-collections + 3.2.1 + + + commons-lang + commons-lang + 2.6 + + + commons-logging + commons-logging + 1.1.1 + + + net.sf.ezmorph + ezmorph + 1.0.6 + + + net.sf.json-lib + json-lib + 2.2.3 + jdk15 + + + @@ -89,11 +123,11 @@ true - - - - - + + + + + @@ -114,6 +148,16 @@ spring-session + + + + com.thoughtworks.xstream + xstream + 1.4.9 + + + + diff --git a/demo/src/main/java/com/example/demo/DemoApplication.java b/demo/src/main/java/com/example/demo/DemoApplication.java index d95cf7a..c82d15a 100644 --- a/demo/src/main/java/com/example/demo/DemoApplication.java +++ b/demo/src/main/java/com/example/demo/DemoApplication.java @@ -2,10 +2,9 @@ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.web.servlet.ServletComponentScan; @SpringBootApplication -@ServletComponentScan("com.example.demo") +//@ServletComponentScan("com.example.demo") //@MapperScan("com.example.demo.Dao") public class DemoApplication { public static void main(String[] args) { diff --git a/demo/src/main/java/com/example/demo/loginService/SessionFilter.java b/demo/src/main/java/com/example/demo/loginService/SessionFilter.java index dafd5a3..ff1ad50 100644 --- a/demo/src/main/java/com/example/demo/loginService/SessionFilter.java +++ b/demo/src/main/java/com/example/demo/loginService/SessionFilter.java @@ -11,7 +11,8 @@ import java.io.IOException; @WebFilter(filterName = "sessionFilter",urlPatterns = {"/*"}) public class SessionFilter implements Filter { String NO_LOGIN="/Login.html"; - String[] includeUrls=new String[]{"/Login.html","/Register.html","/login","/register","/userExisted.html","/userPwdError.html","/userNotExist.html","/userPwdNotSame.html"}; + String[] includeUrls=new String[]{"/Login.html","/Register.html","/login","/register","/userExisted.html","/userPwdError.html","/userNotExist.html","/userPwdNotSame.html", + "/wechat","/access","/wechat/access"}; // @Override // public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws ServletException,IOException{ // HttpServletRequest request=(HttpServletRequest) servletRequest; diff --git a/demo/src/main/java/com/example/demo/weixin/bean/WeixinMessageInfo.java b/demo/src/main/java/com/example/demo/weixin/bean/WeixinMessageInfo.java new file mode 100644 index 0000000..125fdc6 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/bean/WeixinMessageInfo.java @@ -0,0 +1,32 @@ +package com.example.demo.weixin.bean; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.stereotype.Component; + +import java.io.Serializable; + +@Component +@Getter +@Setter +public class WeixinMessageInfo implements Serializable { + + //序列化版本号 + //默认会根据对象结构自动生成。 + //如果对象结构发生变化,序列号就会变化,导致不能正常调用。 + //这样直接声明出来,就是一个定值了,即使构造方法发生了变化,仍然可以调用,只不过发生改动的属性会变成null + private static final long serialVersionUID = 1L; + + private String fromUserName; //发送方微信账号 + private String toUserName; //接收方微信账号 + private String weixinUserName; //微信用户名 + private String messageType; //消息类型 + + @Override + public String toString(){ + return "WeixinMessageInfo [fromUserName=" + fromUserName + + ", toUserName=" + toUserName +", weixinUserName=" + + weixinUserName + ", messageType=" + messageType + "]"; + + } +} diff --git a/demo/src/main/java/com/example/demo/weixin/bean/menu/AccessToken.java b/demo/src/main/java/com/example/demo/weixin/bean/menu/AccessToken.java new file mode 100644 index 0000000..411d160 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/bean/menu/AccessToken.java @@ -0,0 +1,11 @@ +package com.example.demo.weixin.bean.menu; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class AccessToken { + private String Access_token; + private int Expires_in; +} diff --git a/demo/src/main/java/com/example/demo/weixin/bean/menu/Button.java b/demo/src/main/java/com/example/demo/weixin/bean/menu/Button.java new file mode 100644 index 0000000..69faf77 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/bean/menu/Button.java @@ -0,0 +1,17 @@ +package com.example.demo.weixin.bean.menu; + +import lombok.Getter; +import lombok.Setter; + +/** + * @Description: 按钮的基类(每个按钮对象都有一个共同的name属性, + * 因此需要定义一个按钮对象的基类,所有按钮对象都需要继承该类) + * @Parameters: + * @Return: +*/ + +@Setter +@Getter +public class Button { + private String name; +} diff --git a/demo/src/main/java/com/example/demo/weixin/bean/menu/ClickButton.java b/demo/src/main/java/com/example/demo/weixin/bean/menu/ClickButton.java new file mode 100644 index 0000000..36d6658 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/bean/menu/ClickButton.java @@ -0,0 +1,17 @@ +package com.example.demo.weixin.bean.menu; + +import lombok.Getter; +import lombok.Setter; + +/** + * @Description: click类型的按钮(有type、name和key3个属性) + * @Parameters: + * @Return: + */ + +@Setter +@Getter +public class ClickButton extends Button{ + private String type; + private String key; +} diff --git a/demo/src/main/java/com/example/demo/weixin/bean/menu/ComplexButton.java b/demo/src/main/java/com/example/demo/weixin/bean/menu/ComplexButton.java new file mode 100644 index 0000000..84cba66 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/bean/menu/ComplexButton.java @@ -0,0 +1,17 @@ +package com.example.demo.weixin.bean.menu; + + +import lombok.Getter; +import lombok.Setter; + +/** + * @Description: 复合类型的按钮(也就是含有子菜单的一级菜单) + * @Parameters: + * @Return: + */ + +@Getter +@Setter +public class ComplexButton extends Button { + private Button[] sub_button; +} diff --git a/demo/src/main/java/com/example/demo/weixin/bean/menu/Menu.java b/demo/src/main/java/com/example/demo/weixin/bean/menu/Menu.java new file mode 100644 index 0000000..1ba74e0 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/bean/menu/Menu.java @@ -0,0 +1,16 @@ +package com.example.demo.weixin.bean.menu; + +import lombok.Getter; +import lombok.Setter; + +/** + * @Description: 菜单 + * @Parameters: + * @Return: + */ + +@Setter +@Getter +public class Menu { + private Button[] button; +} diff --git a/demo/src/main/java/com/example/demo/weixin/bean/menu/ViewButton.java b/demo/src/main/java/com/example/demo/weixin/bean/menu/ViewButton.java new file mode 100644 index 0000000..029fe89 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/bean/menu/ViewButton.java @@ -0,0 +1,17 @@ +package com.example.demo.weixin.bean.menu; + +import lombok.Getter; +import lombok.Setter; + +/** + * @Description: view类型的按钮(有type、name、url三个属性) + * @Parameters: + * @Return: +*/ + +@Getter +@Setter +public class ViewButton extends Button { + public String type; + public String url; +} diff --git a/demo/src/main/java/com/example/demo/weixin/bean/message/Article.java b/demo/src/main/java/com/example/demo/weixin/bean/message/Article.java new file mode 100644 index 0000000..0b82e0b --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/bean/message/Article.java @@ -0,0 +1,18 @@ +package com.example.demo.weixin.bean.message; + +import lombok.Getter; +import lombok.Setter; + +@Setter +@Getter +public class Article { + //图文消息名称 + private String Title; + //图文消息描述 + private String Description; + //图片链接,支持JPG、PNG格式,较好的效果为大图640像素*320像素,小图80像素*80像素 + private String PicUrl; + //点击图文消息跳转链接 + private String Url; + +} diff --git a/demo/src/main/java/com/example/demo/weixin/bean/message/Image.java b/demo/src/main/java/com/example/demo/weixin/bean/message/Image.java new file mode 100644 index 0000000..43a4a33 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/bean/message/Image.java @@ -0,0 +1,11 @@ +package com.example.demo.weixin.bean.message; + +import lombok.Getter; +import lombok.Setter; + +@Setter +@Getter +public class Image { + //媒体文件ID + private String MediaId; +} diff --git a/demo/src/main/java/com/example/demo/weixin/bean/message/Music.java b/demo/src/main/java/com/example/demo/weixin/bean/message/Music.java new file mode 100644 index 0000000..0294564 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/bean/message/Music.java @@ -0,0 +1,19 @@ +package com.example.demo.weixin.bean.message; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class Music { + private String Title; + //音乐描述 + private String Description; + //音乐链接 + private String MusicUrl; + //高品质音乐链接,Wi-Fi环境优先使用该链接播放音乐 + private String HQMusicUrl; + //缩略图的媒体ID,通过上传多媒体文件得到的ID + private String ThumbMediaId; + +} diff --git a/demo/src/main/java/com/example/demo/weixin/bean/message/Video.java b/demo/src/main/java/com/example/demo/weixin/bean/message/Video.java new file mode 100644 index 0000000..a100d70 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/bean/message/Video.java @@ -0,0 +1,13 @@ +package com.example.demo.weixin.bean.message; + +import lombok.Getter; +import lombok.Setter; + +@Setter +@Getter +public class Video { + //媒体文件ID + private String MediaId; + //视频消息缩略图的媒体ID + private String ThumbMediaId; +} diff --git a/demo/src/main/java/com/example/demo/weixin/bean/message/Voice.java b/demo/src/main/java/com/example/demo/weixin/bean/message/Voice.java new file mode 100644 index 0000000..eb55ac1 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/bean/message/Voice.java @@ -0,0 +1,11 @@ +package com.example.demo.weixin.bean.message; + +import lombok.Getter; +import lombok.Setter; + +@Setter +@Getter +public class Voice { + //语音消息媒体ID + private String mediaId; +} diff --git a/demo/src/main/java/com/example/demo/weixin/bean/response/BaseMessage.java b/demo/src/main/java/com/example/demo/weixin/bean/response/BaseMessage.java new file mode 100644 index 0000000..e468607 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/bean/response/BaseMessage.java @@ -0,0 +1,20 @@ +package com.example.demo.weixin.bean.response; + +import lombok.Getter; +import lombok.Setter; + +@Setter +@Getter +public class BaseMessage { + //接收方账号(收到的OpenID) + private String ToUserName; + //开发者微信号 + private String FromUserName; + //消息创建时间(整型) + private long CreateTime; + //消息类型(text/music/news) + private String MsgType; + //星标刚收到的消息 + private int FuncFlag; + +} diff --git a/demo/src/main/java/com/example/demo/weixin/bean/response/ImageMessage.java b/demo/src/main/java/com/example/demo/weixin/bean/response/ImageMessage.java new file mode 100644 index 0000000..44db7ac --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/bean/response/ImageMessage.java @@ -0,0 +1,12 @@ +package com.example.demo.weixin.bean.response; + + +import com.example.demo.weixin.bean.message.Image; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class ImageMessage extends BaseMessage { + private Image image; +} diff --git a/demo/src/main/java/com/example/demo/weixin/bean/response/MusicMessage.java b/demo/src/main/java/com/example/demo/weixin/bean/response/MusicMessage.java new file mode 100644 index 0000000..d89e186 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/bean/response/MusicMessage.java @@ -0,0 +1,11 @@ +package com.example.demo.weixin.bean.response; + +import com.example.demo.weixin.bean.message.Music; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class MusicMessage extends BaseMessage { + private Music music; +} diff --git a/demo/src/main/java/com/example/demo/weixin/bean/response/NewsMessage.java b/demo/src/main/java/com/example/demo/weixin/bean/response/NewsMessage.java new file mode 100644 index 0000000..57ba879 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/bean/response/NewsMessage.java @@ -0,0 +1,16 @@ +package com.example.demo.weixin.bean.response; + +import com.example.demo.weixin.bean.message.Article; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +public class NewsMessage extends BaseMessage { + //图文消息个数,限制为10条以内 + private int ArticleCount; + //多条图文消息信息,默认第一个item为大图 + private List
Articles; +} diff --git a/demo/src/main/java/com/example/demo/weixin/bean/response/TextMessage.java b/demo/src/main/java/com/example/demo/weixin/bean/response/TextMessage.java new file mode 100644 index 0000000..7b7da3d --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/bean/response/TextMessage.java @@ -0,0 +1,11 @@ +package com.example.demo.weixin.bean.response; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class TextMessage extends BaseMessage { + //回复的消息内容 + private String Content; +} diff --git a/demo/src/main/java/com/example/demo/weixin/bean/response/VideoMessage.java b/demo/src/main/java/com/example/demo/weixin/bean/response/VideoMessage.java new file mode 100644 index 0000000..6f60692 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/bean/response/VideoMessage.java @@ -0,0 +1,12 @@ +package com.example.demo.weixin.bean.response; + +import com.example.demo.weixin.bean.message.Video; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class VideoMessage extends BaseMessage { + private Video video; + +} diff --git a/demo/src/main/java/com/example/demo/weixin/bean/response/VoiceMessage.java b/demo/src/main/java/com/example/demo/weixin/bean/response/VoiceMessage.java new file mode 100644 index 0000000..68b6d86 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/bean/response/VoiceMessage.java @@ -0,0 +1,11 @@ +package com.example.demo.weixin.bean.response; + +import com.example.demo.weixin.bean.message.Voice; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class VoiceMessage extends BaseMessage{ + private Voice voice; +} diff --git a/demo/src/main/java/com/example/demo/weixin/controller/WeixinCoreController.java b/demo/src/main/java/com/example/demo/weixin/controller/WeixinCoreController.java new file mode 100644 index 0000000..6097fcf --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/controller/WeixinCoreController.java @@ -0,0 +1,72 @@ +package com.example.demo.weixin.controller; + +import com.example.demo.weixin.service.DataProcess; +import com.example.demo.weixin.service.WeixinCoreService; +import com.example.demo.weixin.util.WeixinSignUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@RestController +@RequestMapping(value = "/wechat") +public class WeixinCoreController { + + //控制台输出日志信息所在的类 + private static Logger logger = LoggerFactory.getLogger(WeixinCoreController.class); + + @Autowired + private WeixinSignUtil weixinSignUtil; + @Autowired + private DataProcess dataProcess; + @Autowired + private WeixinCoreService weixinCoreService; + + @RequestMapping(value = "/access",method = RequestMethod.GET) + public String WeChatInterface(HttpServletRequest request)/*throws Exception*/{ + System.out.println("-----验证微信服务号开始-----"); + //微信加密签名 + String signature = request.getParameter("signature"); + //时间戳 + String timestamp = request.getParameter("timestamp"); + //随机数 + String nonce = request.getParameter("nonce"); + //随机字符串 + String echostr = request.getParameter("echostr"); + + logger.info("signature is :"+signature+" timestamp is :"+timestamp+" nonce is :"+nonce); + if(weixinSignUtil.checkSignature(signature,timestamp,nonce)){ + System.out.println("------验证微信服务号结束-------"); + return echostr; + }else{ + + //此处可以实现其他逻辑 + logger.warn("不是微信服务器的请求,小心!!"); + return null; + } + } + + + @RequestMapping(value="/access", method=RequestMethod.POST) + public String getWeiXinMessage(HttpServletRequest request, HttpServletResponse response)throws Exception{ + logger.info("----------------开始处理微信发过来的消息------------------"); + // 微信服务器POST消息时用的是UTF-8编码,在接收时也要用同样的编码,否则中文会乱码; + request.setCharacterEncoding("UTF-8"); + // 在响应消息(回复消息给用户)时,也将编码方式设置为UTF-8,原理同上; + response.setCharacterEncoding("UTF-8"); + String respXml = weixinCoreService.weixinMessageHandelCoreService(request, response); + if (dataProcess.dataIsNull(respXml)){ + logger.error("-------------处理微信消息失败-----------------------"); + return null; + }else { + logger.info("----------返回微信消息处理结果-----------------------:"+respXml); + return respXml; + } + } + +} diff --git a/demo/src/main/java/com/example/demo/weixin/service/DataProcess.java b/demo/src/main/java/com/example/demo/weixin/service/DataProcess.java new file mode 100644 index 0000000..7afcfc0 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/service/DataProcess.java @@ -0,0 +1,14 @@ +package com.example.demo.weixin.service; + +import org.springframework.stereotype.Service; + +@Service +public class DataProcess { + public boolean dataIsNull(String respXml){ + if(respXml.isEmpty()){ + return true; + }else{ + return false; + } + } +} diff --git a/demo/src/main/java/com/example/demo/weixin/service/WeixinCoreService.java b/demo/src/main/java/com/example/demo/weixin/service/WeixinCoreService.java new file mode 100644 index 0000000..5dab8cd --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/service/WeixinCoreService.java @@ -0,0 +1,8 @@ +package com.example.demo.weixin.service; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public interface WeixinCoreService { + public abstract String weixinMessageHandelCoreService(HttpServletRequest request,HttpServletResponse response); +} diff --git a/demo/src/main/java/com/example/demo/weixin/service/WeixinCoreServiceImpl.java b/demo/src/main/java/com/example/demo/weixin/service/WeixinCoreServiceImpl.java new file mode 100644 index 0000000..7402bc2 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/service/WeixinCoreServiceImpl.java @@ -0,0 +1,165 @@ +package com.example.demo.weixin.service; + +import com.example.demo.weixin.bean.WeixinMessageInfo; +import com.example.demo.weixin.bean.response.TextMessage; +import com.example.demo.weixin.util.message.WeixinMessageModelUtil; +import com.example.demo.weixin.util.message.WeixinMessageUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Date; +import java.util.Map; + +@Service("weixinCoreService") +public class WeixinCoreServiceImpl implements WeixinCoreService { + + private static Logger logger = LoggerFactory.getLogger(WeixinCoreServiceImpl.class); + + @Autowired + private WeixinMessageUtil weixinMessageUtil; + @Autowired + private WeixinMessageInfo weixinMessageInfo; + @Autowired + private WeixinMessageModelUtil weixinMessageModelUtil; +// @Autowired +// private UserDao userDao; +// @Autowired +// private DataProcess dataProcess; + + @Override + public String weixinMessageHandelCoreService(HttpServletRequest request, + HttpServletResponse response) { + + logger.info("------------微信消息开始处理-------------"); + // 返回给微信服务器的消息,默认为null + + String respMessage = null; + + try { + + // 默认返回的文本消息内容 + String respContent = null; + // xml分析 + // 调用消息工具类MessageUtil解析微信发来的xml格式的消息,解析的结果放在HashMap里; + Map map = weixinMessageUtil.parseXml(request); + // 发送方账号 + String fromUserName = map.get("FromUserName"); + weixinMessageInfo.setFromUserName(fromUserName); + System.out.println("fromUserName--->"+fromUserName); + // 接受方账号(公众号) + String toUserName = map.get("ToUserName"); + weixinMessageInfo.setToUserName(toUserName); + System.out.println("toUserName----->"+toUserName); + // 消息类型 + String msgType = map.get("MsgType"); + weixinMessageInfo.setMessageType(msgType); + logger.info("fromUserName is:" +fromUserName+" toUserName is:" +toUserName+" msgType is:" +msgType); + + // 默认回复文本消息 + TextMessage textMessage = new TextMessage(); + textMessage.setToUserName(fromUserName); + textMessage.setFromUserName(toUserName); + textMessage.setCreateTime(new Date().getTime()); + textMessage.setMsgType(weixinMessageUtil.RESP_MESSAGE_TYPE_TEXT); + textMessage.setFuncFlag(0); + + // 分析用户发送的消息类型,并作出相应的处理 + + // 文本消息 + if (msgType.equals(weixinMessageUtil.REQ_MESSAGE_TYPE_TEXT)){ + respContent = "亲,这是文本消息!"; + textMessage.setContent(respContent); + respMessage = weixinMessageUtil.textMessageToXml(textMessage); + } + + // 图片消息 + else if (msgType.equals(weixinMessageUtil.REQ_MESSAGE_TYPE_IMAGE)) { + respContent = "您发送的是图片消息!"; + textMessage.setContent(respContent); + respMessage = weixinMessageUtil.textMessageToXml(textMessage); + } + + // 语音消息 + else if (msgType.equals(weixinMessageUtil.REQ_MESSAGE_TYPE_VOICE)) { + respContent = "您发送的是语音消息!"; + textMessage.setContent(respContent); + respMessage = weixinMessageUtil.textMessageToXml(textMessage); + } + + // 视频消息 + else if (msgType.equals(weixinMessageUtil.REQ_MESSAGE_TYPE_VIDEO)) { + respContent = "您发送的是视频消息!"; + textMessage.setContent(respContent); + respMessage = weixinMessageUtil.textMessageToXml(textMessage); + } + + // 地理位置消息 + else if (msgType.equals(weixinMessageUtil.REQ_MESSAGE_TYPE_LOCATION)) { + respContent = "您发送的是地理位置消息!"; + textMessage.setContent(respContent); + respMessage = weixinMessageUtil.textMessageToXml(textMessage); + } + + // 链接消息 + else if (msgType.equals(weixinMessageUtil.REQ_MESSAGE_TYPE_LINK)) { + respContent = "您发送的是链接消息!"; + textMessage.setContent(respContent); + respMessage = weixinMessageUtil.textMessageToXml(textMessage); + } + + // 事件推送(当用户主动点击菜单,或者扫面二维码等事件) + else if (msgType.equals(weixinMessageUtil.REQ_MESSAGE_TYPE_EVENT)) { + + // 事件类型 + String eventType =map.get("Event"); + System.out.println("eventType------>"+eventType); + // 关注 + if (eventType.equals(weixinMessageUtil.EVENT_TYPE_SUBSCRIBE)){ + respMessage = weixinMessageModelUtil.followResponseMessageModel(weixinMessageInfo); + } + // 取消关注 + else if (eventType.equals(weixinMessageUtil.EVENT_TYPE_UNSUBSCRIBE)) { + System.out.println("取消关注"); + //weixinMessageModelUtil.cancelAttention(fromUserName); + } + // 扫描带参数二维码 + else if (eventType.equals(weixinMessageUtil.EVENT_TYPE_SCAN)) { + System.out.println("扫描带参数二维码"); + } + // 上报地理位置 + else if (eventType.equals(weixinMessageUtil.EVENT_TYPE_LOCATION)) { + System.out.println("上报地理位置"); + } + // 自定义菜单(点击菜单拉取消息) + else if (eventType.equals(weixinMessageUtil.EVENT_TYPE_CLICK)) { + + // 事件KEY值,与创建自定义菜单时指定的KEY值对应 + String eventKey=map.get("EventKey"); + System.out.println("eventKey------->"+eventKey); + + } + // 自定义菜单((自定义菜单URl视图)) + else if (eventType.equals(weixinMessageUtil.EVENT_TYPE_VIEW)) { + System.out.println("处理自定义菜单URI视图"); + } + + } + } catch (Exception e) { + e.printStackTrace(); + logger.error("系统出错"); + System.err.println("系统出错"); + respMessage = null; + } finally{ + if (null == respMessage) { + respMessage = weixinMessageModelUtil.systemErrorResponseMessageModel(weixinMessageInfo); + } + } + + return respMessage; + } + +} \ No newline at end of file diff --git a/demo/src/main/java/com/example/demo/weixin/service/https/HttpRequestUtil.java b/demo/src/main/java/com/example/demo/weixin/service/https/HttpRequestUtil.java new file mode 100644 index 0000000..bc3f925 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/service/https/HttpRequestUtil.java @@ -0,0 +1,87 @@ +package com.example.demo.weixin.service.https; + +import net.sf.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.ConnectException; +import java.net.URL; + +/** + * + * @Description: 发起https请求并获取结果 + * @Parameters: requestUrl 请求地址。 需要写全地址,即前边的http必须写上,不能只写www.baidu.com这样的。 + * requestMethod 请求方式(GET、POST) + * outputStr 我们在发起请求的时候传递参数到所要请求的服务器, + * 要传递的参数也要看接口文档确定格式,一般是封装成json或xml. + * @Return: JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值) + */ +@Component +public class HttpRequestUtil { + Logger logger = LoggerFactory.getLogger(HttpRequestUtil.class); + public JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr){ + //初始化一个json对象 + JSONObject jsonObject = null; + try { + //创建SSLContext对象,并使用我们指定的信任管理器初始化 + TrustManager[] tmManagers = {new MyX509TrustManager()}; + SSLContext sslContext = SSLContext.getInstance("SSL","SunJSSE"); + sslContext.init(null, tmManagers, new java.security.SecureRandom()); + //从上述SSLContext对象中得到SSLSocketFactory对象 + SSLSocketFactory sslSocket = sslContext.getSocketFactory(); + + URL url = new URL(requestUrl); + HttpsURLConnection httpsURLConnection = (HttpsURLConnection)url.openConnection(); + httpsURLConnection.setSSLSocketFactory(sslSocket); + + httpsURLConnection.setDoOutput(true); /*httpUrlConnection.setDoOutput(true);以后就可以使用conn.getOutputStream().write() httpUrlConnection.setDoInput(true);以后就可以使用conn.getInputStream().read(); get请求用不到conn.getOutputStream(),因为参数直接追加在地址后面,因此默认是false。 post请求(比如:文件上传)需要往服务区传输大量的数据,这些数据是放在http的body里面的,因此需要在建立连接以后,往服务端写数据。 因为总是使用conn.getInputStream()获取服务端的响应,因此默认值是true。 */ + httpsURLConnection.setDoInput(true); + httpsURLConnection.setUseCaches(false); + //设置请求方式 GET/POST + httpsURLConnection.setRequestMethod(requestMethod); + if ("GET".equalsIgnoreCase(requestMethod)) { //不考虑大小写。如果两个字符串的长度相等,并且两个字符串中的相应字符都相等(忽略大小写),则认为这两个字符串是相等的。 + httpsURLConnection.connect(); + } + //当有数据需要提交时,往服务器端写内容 也就是发起http请求需要带的参数 + if (null != outputStr) { + OutputStream outputStream = httpsURLConnection.getOutputStream(); + //注意编码格式,防止中文乱码 + outputStream.write(outputStr.getBytes("UTF-8")); + outputStream.close(); + } + + //获得输入流 读取服务器端返回的内容 + InputStream inputStream = httpsURLConnection.getInputStream(); + InputStreamReader inputStreamReader = new InputStreamReader(inputStream,"utf-8"); + BufferedReader bufferedReader = new BufferedReader(inputStreamReader); + String str = null; + StringBuffer stringBuffer = new StringBuffer(); + while((str = bufferedReader.readLine()) != null){ + stringBuffer.append(str); + } + //释放资源 + bufferedReader.close(); + inputStreamReader.close(); + inputStream.close(); + inputStream = null; + httpsURLConnection.disconnect(); + //将字符串转换为json对象 + jsonObject = JSONObject.fromObject(stringBuffer.toString()); + System.out.println("JSONObject---------------------->"+jsonObject); + } catch (ConnectException ce) { + logger.error("Weixin server connection timed out."); + } catch(Exception e){ + logger.error("https request error:{}",e); + } + return jsonObject; + } +} diff --git a/demo/src/main/java/com/example/demo/weixin/service/https/MyX509TrustManager.java b/demo/src/main/java/com/example/demo/weixin/service/https/MyX509TrustManager.java new file mode 100644 index 0000000..965ea59 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/service/https/MyX509TrustManager.java @@ -0,0 +1,42 @@ +/** + * 对于https请求,我们需要一个证书信任管理器, 这个管理器类需要自己定义,需要实现X509TrustManager接口代码 + */ + +package com.example.demo.weixin.service.https; + +import javax.net.ssl.X509TrustManager; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; + + +public class MyX509TrustManager implements X509TrustManager { + /** + * 该方法用于检查客户端的证书,若不信则抛出异常 + * 由于我们不需要对客户端进行认证,可以不做任何处理 + */ + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateEncodingException { + + } + + /** + * 该方法用于检验服务器端的证书,若不信任则抛出异常 + * 通过自己实现该方法,可以使之信任我们指定的任何证书 + * 在实现该方法时,也可以不做任何处理,即一个空的方法实现 + * 由于不会抛出异常,它就会信任任何证书 + */ + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateEncodingException { + + } + + /** + * 返回收信任的X509证书数组 + */ + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; + } +} \ No newline at end of file diff --git a/demo/src/main/java/com/example/demo/weixin/util/WeixinSignUtil.java b/demo/src/main/java/com/example/demo/weixin/util/WeixinSignUtil.java new file mode 100644 index 0000000..ae73ef4 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/util/WeixinSignUtil.java @@ -0,0 +1,70 @@ +/** + * 检测signature,标识该请求来自于微信 + */ + +package com.example.demo.weixin.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; + +@Component +public class WeixinSignUtil { + + //控制台输出日志信息所在的类 + public static Logger logger = LoggerFactory.getLogger(WeixinSignUtil.class); + //与微信公众号号中配置的token相同 + public static String token = "weixin"; + + public boolean checkSignature(String signature,String timestamp,String nonce){ + String[] arr = new String[]{token,timestamp,nonce}; + //将tokec,timestamp,nonce三个参数进行字典序排序 + Arrays.sort(arr); + StringBuilder content = new StringBuilder(); + for(int i = 0 ; i>> 4) & 0X0F]; + tempArr[1] = Digit[c & 0X0F]; + + String s = new String(tempArr); + return s; + } +} diff --git a/demo/src/main/java/com/example/demo/weixin/util/menu/WechatCommonUtil.java b/demo/src/main/java/com/example/demo/weixin/util/menu/WechatCommonUtil.java new file mode 100644 index 0000000..3caba1f --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/util/menu/WechatCommonUtil.java @@ -0,0 +1,52 @@ +package com.example.demo.weixin.util.menu; + +import com.example.demo.weixin.bean.menu.AccessToken; +import com.example.demo.weixin.service.https.HttpRequestUtil; +import net.sf.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + + +/** + * 编写获取access_token的工具类 + */ + + +@Component +public class WechatCommonUtil { + Logger logger = LoggerFactory.getLogger(WechatCommonUtil.class); + + //获取access_token接口 + private static String token_url = WechatConstants.ACCESS_TOKEN_URL; + //@Autowired + HttpRequestUtil httpRequestUtil = new HttpRequestUtil(); + + /** + * @Description: 获取微信调用高级接口的凭证(access_token) + * @Parameters: + * @Return: + */ + public AccessToken getAccessToken(String appid,String appsecret){ + //将公众号的appid和appsecret替换进url + //String.replace()替换原字符串中的子串 + String url = token_url.replace("APPID", appid).replace("APPSECRET", appsecret); + AccessToken accessToken = new AccessToken(); + //发起get请求获取凭证 + JSONObject jsonObject = httpRequestUtil.httpsRequest(url,"GET",null); + logger.info("获取到的json格式的Token为:"+jsonObject); + if (jsonObject!=null) { + try { + accessToken.setAccess_token(jsonObject.getString("access_token")); + accessToken.setExpires_in(jsonObject.getInt("expires_in")); + } catch (Exception e) { + accessToken = null; + //获取token失败 + logger.error("获取token失败 errcode:{} errmsg:{}", + jsonObject.getInt("errcode"), + jsonObject.getString("errmsg")); + } + } + return accessToken; + } +} diff --git a/demo/src/main/java/com/example/demo/weixin/util/menu/WechatConstants.java b/demo/src/main/java/com/example/demo/weixin/util/menu/WechatConstants.java new file mode 100644 index 0000000..d0fa716 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/util/menu/WechatConstants.java @@ -0,0 +1,8 @@ +package com.example.demo.weixin.util.menu; + +public class WechatConstants { + public static String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"; + public static String MENU_CREATE_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN"; + public static String MENU_GET_URL = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN"; + public static String MENU_DELETE_URL = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN"; +} diff --git a/demo/src/main/java/com/example/demo/weixin/util/menu/WechatCreatDefaultMenu.java b/demo/src/main/java/com/example/demo/weixin/util/menu/WechatCreatDefaultMenu.java new file mode 100644 index 0000000..1c63afa --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/util/menu/WechatCreatDefaultMenu.java @@ -0,0 +1,35 @@ +package com.example.demo.weixin.util.menu; + + +import com.example.demo.weixin.bean.menu.Menu; + +/** + * @Description: 创建自定义菜单主方法 + * @Parameters: + * @Return: + */ +public class WechatCreatDefaultMenu { + public static void main(String[] args){ + WechatCommonUtil wechatCommonUtil = new WechatCommonUtil(); + WechatMenuUtil wechatMenuUtil = new WechatMenuUtil(); + WechatMenuManagerUtil wechatMenuManagerUtil = new WechatMenuManagerUtil(); + String appid = "wx473235c6be5c945a"; + String appsecret = "69a0c7bcccf20833fd549ae9a530d299"; + + //获取access_token + String accessToken = wechatCommonUtil.getAccessToken(appid, appsecret).getAccess_token(); + //获取菜单结构 + Menu menu = wechatMenuManagerUtil.getMenu(); + if (accessToken!=null) { + //生成菜单 + boolean result = wechatMenuUtil.creatMenu(menu, accessToken); + if (result) { + System.out.println("菜单创建成功"); + }else { + System.out.println("菜单创建失败"); + } + }else { + System.out.println("token为空"); + } + } +} diff --git a/demo/src/main/java/com/example/demo/weixin/util/menu/WechatMenuManagerUtil.java b/demo/src/main/java/com/example/demo/weixin/util/menu/WechatMenuManagerUtil.java new file mode 100644 index 0000000..16324b8 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/util/menu/WechatMenuManagerUtil.java @@ -0,0 +1,55 @@ +package com.example.demo.weixin.util.menu; + +import com.example.demo.weixin.bean.menu.*; + + +/** + * @Description: 菜单管理器类 + * @Parameters: + * @Return: + */ +public class WechatMenuManagerUtil { + /** + * @Description: 定义菜单结构 + * @Parameters: + * @Return: + */ + public Menu getMenu(){ +// ClickButton firstClickButton = new ClickButton(); +// firstClickButton.setName("功能图文"); +// firstClickButton.setKey("function"); +// firstClickButton.setType("click"); + + ViewButton firstViewButton = new ViewButton(); + firstViewButton.setName("业务介绍"); + firstViewButton.setType("view"); + firstViewButton.setUrl("http://loan.ngrok.xiaomiqiu.cn/personalCenter.html"); + + ViewButton secondViewButton = new ViewButton(); + secondViewButton.setName("我要贷款"); + secondViewButton.setType("view"); + secondViewButton.setUrl("http://loan.ngrok.xiaomiqiu.cn/personalCenter.html"); + + ComplexButton complexButton = new ComplexButton(); + + ViewButton viewButton1 = new ViewButton(); + viewButton1.setType("view"); + viewButton1.setName("个人中心"); + viewButton1.setUrl("http://loan.ngrok.xiaomiqiu.cn/personalCenter.html"); + + ViewButton viewButton2 = new ViewButton(); + viewButton2.setType("view"); + viewButton2.setName("网页授权"); + viewButton2.setUrl("http://loan.ngrok.xiaomiqiu.cn/personalCenter.html"); //http://loan.ngrok.xiaomiqiu.cn/WeChat/login.php + ViewButton[] viewButton = {viewButton1,viewButton2}; + complexButton.setSub_button(viewButton); + complexButton.setName("我的服务"); + + Menu menu = new Menu(); + Button[] boButtons = {firstViewButton,secondViewButton,complexButton}; + menu.setButton(boButtons); + + return menu; + } +} + diff --git a/demo/src/main/java/com/example/demo/weixin/util/menu/WechatMenuUtil.java b/demo/src/main/java/com/example/demo/weixin/util/menu/WechatMenuUtil.java new file mode 100644 index 0000000..0d23295 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/util/menu/WechatMenuUtil.java @@ -0,0 +1,89 @@ +package com.example.demo.weixin.util.menu; + +import com.example.demo.weixin.bean.menu.Menu; +import com.example.demo.weixin.service.https.HttpRequestUtil; +import net.sf.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + + +/** + * @Description: 自定义菜单工具类,包括菜单的创建、查询、删除 + * @Parameters: + * @Return: + */ + +public class WechatMenuUtil { + Logger logger = LoggerFactory.getLogger(WechatMenuUtil.class); + //@Autowired + private HttpRequestUtil httpRequestUtil = new HttpRequestUtil(); + + /** + * @Parameters: menu 菜单实例 + * accessToken 凭证 + * @Return: true false + * @Return: + */ + public boolean creatMenu(Menu menu, String accessToken){ + boolean result = false; + String url = WechatConstants.MENU_CREATE_URL.replace("ACCESS_TOKEN", accessToken); + //将菜单对象转换成JSON字符串 + String jsonMenu = JSONObject.fromObject(menu).toString(); + //发起POST请求创建菜单 + JSONObject jsonObject = httpRequestUtil.httpsRequest(url, "POST", jsonMenu); + + if (null != jsonObject) { + int errorCode = jsonObject.getInt("errcode"); + String errorMsg = jsonObject.getString("errmsg"); + if (0== errorCode) { + result = true; + } else { + result = false; + logger.error("创建菜单失败 errcode:{} errmsg:{} ",errorCode,errorMsg); + } + } + return result; + } + /** + * + * @Description: 查询菜单 + * @Parameters: + * @Return: + */ + public String getMenu(String accessToken){ + String result = null; + String requestUrl = WechatConstants.MENU_GET_URL.replace("ACCESS_TOKEN", accessToken); + //发起GET请求查询菜单 + JSONObject jsonObject = httpRequestUtil.httpsRequest(requestUrl, "GET", null); + + if (null != jsonObject) { + result = jsonObject.toString(); + } + return result; + } + /** + * + * @Description: 删除菜单 + * @Parameters: + * @Return: + */ + public boolean deleteMenu(String accessToken){ + boolean result = false; + String requestUrl = WechatConstants.MENU_DELETE_URL.replace("ACCESS_TOKEN", accessToken); + //发起GET请求删除菜单 + JSONObject jsonObject = httpRequestUtil.httpsRequest(requestUrl, "GET", null); + + if (null != jsonObject) { + int errorCode = jsonObject.getInt("errcode"); + String errorMsg = jsonObject.getString("errmsg"); + if (0== errorCode) { + result = true; + } else { + result = false; + logger.error("创建菜单失败 errcode:{} errmsg:{} ",errorCode,errorMsg); + } + } + return result; + } +} diff --git a/demo/src/main/java/com/example/demo/weixin/util/message/WeixinMessageModelUtil.java b/demo/src/main/java/com/example/demo/weixin/util/message/WeixinMessageModelUtil.java new file mode 100644 index 0000000..6792e88 --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/util/message/WeixinMessageModelUtil.java @@ -0,0 +1,113 @@ +/** + * 微信消息处理,将关注回复消息等写成方法 + */ + +package com.example.demo.weixin.util.message; + +import com.example.demo.loginService.API.impl.UserService; +import com.example.demo.weixin.bean.WeixinMessageInfo; +import com.example.demo.weixin.bean.response.TextMessage; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Date; + +@Component +public class WeixinMessageModelUtil { + /** + * @Description: 封装微信回复消息,各种回复消息对应不同的方法 + */ + @Autowired + private WeixinMessageUtil weixinMessageUtil; +// @Autowired +// private WebConfigBean webConfigBean; + @Autowired + private UserService userService; +// @Autowired +// private EncodeUTF8 encodeUT8; + + /** + * @Description: 当系统出错时,默认回复的文本消息 + * @Parameters: WeixinMessageModelUtil + * @Return: 系统出错回复的消息 + */ + public String systemErrorResponseMessageModel(WeixinMessageInfo weixinMessageInfo ){ + + // 回复文本消息 + TextMessage textMessage = new TextMessage(); + textMessage.setToUserName(weixinMessageInfo.getFromUserName()); + textMessage.setFromUserName(weixinMessageInfo.getToUserName()); + textMessage.setCreateTime(new Date().getTime()); + textMessage.setMsgType(weixinMessageUtil.RESP_MESSAGE_TYPE_TEXT); + textMessage.setFuncFlag(0); + textMessage.setContent("系统出错啦,请稍后再试"); + return weixinMessageUtil.textMessageToXml(textMessage); + } + +// /** +// * @Description: 用户关注时发送的图文消息 +// * @Parameters: WeixinMessageModelUtil +// * @Return: 用户关注后发送的提示绑定用户的图文消息 +// */ +// public String followResponseMessageModel(WeixinMessageInfo weixinMessageInfo){ +// +// // 关注时发送图文消息 +// NewsMessage newsMessage = new NewsMessage(); +// newsMessage.setToUserName(weixinMessageInfo.getFromUserName()); +// newsMessage.setFromUserName(weixinMessageInfo.getToUserName()); +// newsMessage.setCreateTime(new Date().getTime()); +// newsMessage.setMsgType(weixinMessageUtil.RESP_MESSAGE_TYPE_NEWS); +// newsMessage.setFuncFlag(0); +// +// // 图文消息 +// List
articleList=new ArrayList
(); +// Article article = new Article(); +// // 设置图文消息的标题 +// String string = "欢迎关注借贷平台"; +// article.setTitle(string); +// article.setPicUrl(webConfigBean.getWeixinPicture()+"meetingLogo2.png"); +// article.setUrl(webConfigBean.getDoMainNameurl()+"/WeixinParticipantFouce"); +// articleList.add(article); +// newsMessage.setArticleCount(articleList.size()); +// newsMessage.setArticles(articleList); +// return weixinMessageUtil.newsMessageToXml(newsMessage); +// } + + + /** + * @Description: 用户关注时发送的文本消息 + * @Parameters: WeixinMessageModelUtil + * @Return: 用户关注后发送的提示绑定用户的文本消息 + */ + public String followResponseMessageModel(WeixinMessageInfo weixinMessageInfo){ + + // 关注时发送文本消息 + TextMessage textMessage = new TextMessage(); + textMessage.setFromUserName(weixinMessageInfo.getToUserName()); + textMessage.setToUserName(weixinMessageInfo.getFromUserName()); + textMessage.setCreateTime(new Date().getTime()); + textMessage.setMsgType(weixinMessageUtil.REQ_MESSAGE_TYPE_TEXT); + textMessage.setFuncFlag(0); + + // 设置文本内容 + String string = "欢迎关注借贷平台"; + textMessage.setContent(string); + return weixinMessageUtil.textMessageToXml(textMessage); + } + + +// /** +// * @Description: 用户取消关注,先判断用户是否绑定,如果已经绑定则解除绑定 +// * @Parameters: WeixinMessageModelUtil +// * @Return: void +// */ +// public void cancelAttention(String fromUserName){ +// +// if (userService.isAlreadyBinding(fromUserName)) { +// userService.userUnbinding(fromUserName); +// }else { +// System.out.println("取消关注用户{}"+fromUserName+"还未绑定"); +// } +// } +} + diff --git a/demo/src/main/java/com/example/demo/weixin/util/message/WeixinMessageUtil.java b/demo/src/main/java/com/example/demo/weixin/util/message/WeixinMessageUtil.java new file mode 100644 index 0000000..6888ebd --- /dev/null +++ b/demo/src/main/java/com/example/demo/weixin/util/message/WeixinMessageUtil.java @@ -0,0 +1,263 @@ +/** + *封装微信消息类型,有一个解析微信发过的xml消息的工具 + */ +package com.example.demo.weixin.util.message; + +import com.example.demo.weixin.bean.message.Article; +import com.example.demo.weixin.bean.response.*; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.core.util.QuickWriter; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; +import com.thoughtworks.xstream.io.xml.XppDriver; +import org.dom4j.Document; +import org.dom4j.Element; +import org.dom4j.io.SAXReader; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import java.io.InputStream; +import java.io.Writer; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +@Component +public class WeixinMessageUtil { + /** + * 请求消息类型:文本 + */ + public final String REQ_MESSAGE_TYPE_TEXT = "text"; + + /** + * 请求消息类型:图片 + */ + public final String REQ_MESSAGE_TYPE_IMAGE="image"; + + /** + * 请求消息类型:语音 + */ + public final String REQ_MESSAGE_TYPE_VOICE="voice"; + + /** + * 请求消息类型:视频 + */ + public final String REQ_MESSAGE_TYPE_VIDEO="video"; + + /** + * 请求消息类型:链接 + */ + public final String REQ_MESSAGE_TYPE_LINK = "link"; + + /** + * 请求消息类型:地理位置 + */ + public final String REQ_MESSAGE_TYPE_LOCATION="location"; + + /** + * 请求消息类型:小视频 + */ + public final String REQ_MESSAGE_TYPE_SHORTVIDEO="shortvideo"; + + /** + *请求消息类型:事件推送 + */ + public final String REQ_MESSAGE_TYPE_EVENT = "event"; + + /** + * 返回消息类型:文本 + */ + public final String RESP_MESSAGE_TYPE_TEXT = "text"; + + /** + * 消息返回类型:图片 + */ + public final String RESP_MESSAGE_TYPE_IMAGE="image"; + + /** + * 消息返回类型:语音 + */ + public final String RESP_MESSAGE_TYPE_VOICE = "voice"; + + /** + * 消息返回类型:音乐 + */ + public final String RESP_MESSAGE_TYPE_MUSIC = "music"; + + /** + * 消息返回类型:图文 + */ + public final String RESP_MESSAGE_TYPE_NEWS = "news"; + + /** + * 消息返回类型:视频 + */ + public final String RESP_MESSAGE_TYPE_VIDEO="video"; + + /** + * 事件类型:订阅 + */ + public final String EVENT_TYPE_SUBSCRIBE = "subscribe"; + + /** + * 事件类型:取消订阅 + */ + public final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe"; + + /** + * 事件类型:scan(关注用户扫描带参二维码) + */ + public final String EVENT_TYPE_SCAN = "scan"; + + /** + * 事件类型:location(上报地理位置) + */ + public final String EVENT_TYPE_LOCATION = "location"; + + /** + * 事件类型:CLICK(点击菜单拉取消息) + */ + public final String EVENT_TYPE_CLICK ="CLICK"; + + /** + * 事件类型:VIEW(自定义菜单URl视图) + */ + public final String EVENT_TYPE_VIEW ="VIEW"; + + /** + * 事件类型:TEMPLATESENDJOBFINISH(模板消息送达情况提醒) + */ + public final String EVENT_TYPE_TEMPLATESENDJOBFINISH="TEMPLATESENDJOBFINISH"; + + + /** + * @Description: 解析微信服务器发过来的xml格式的消息将其转换为map + * @Parameters: WeixinMessageUtil + * @Return: Map + */ + public Map parseXml(HttpServletRequest request)throws Exception{ + + // 将解析结果存储在HashMap中 + Mapmap =new HashMap(); + // 从request中得到输入流 + InputStream inputStream=request.getInputStream(); + + //用SAXReader解析xml文档 + SAXReader reader = new SAXReader(); + // 读取输入流 + Document document = reader.read(inputStream); + // 得到XML的根元素 + Element root = document.getRootElement(); + // 得到根元素的所有子节点 + @SuppressWarnings("unchecked") //忽略黄色警告 + List elementList = root.elements(); + // 判断有没有子元素列表 + if (elementList.size()==0){ + map.put(root.getName(), root.getText()); + }else { + for (Element e : elementList) + map.put(e.getName(), e.getText()); + } + // 释放资源 + inputStream.close(); + inputStream = null; + System.out.println("---------xml转换为map-----:"+map); + return map; + } + + /** + * @Description: 文本消息对象转换成xml + * @param textMessage + * @return xml + */ + public String textMessageToXml(TextMessage textMessage) { + xstream.alias("xml", textMessage.getClass()); + return xstream.toXML(textMessage); + } + + /** + * @Description: 图文消息对象转换成xml + * @param newsMessage + * @return xml + */ + + public String newsMessageToXml(NewsMessage newsMessage) { + xstream.alias("xml", newsMessage.getClass()); + xstream.alias("item", new Article().getClass()); + return xstream.toXML(newsMessage); + } + + /** + * @Description: 图片消息对象转换成xml + * @param imageMessage + * @return xml + */ + public String imageMessageToXml(ImageMessage imageMessage) { + xstream.alias("xml", imageMessage.getClass()); + return xstream.toXML(imageMessage); + } + + + /** + * @Description: 语音消息对象转换成xml + * @param voiceMessage + * @return xml + */ + public String voiceMessageToXml(VoiceMessage voiceMessage) { + xstream.alias("xml", voiceMessage.getClass()); + return xstream.toXML(voiceMessage); + } + + /** + * @Description: 视频消息对象转换成xml + * @param videoMessage + * @return xml + */ + public String videoMessageToXml(VideoMessage videoMessage) { + xstream.alias("xml", videoMessage.getClass()); + return xstream.toXML(videoMessage); + } + + /** + * @Description: 音乐消息对象转换成xml + * @param musicMessage + * @return xml + */ + public String musicMessageToXml(MusicMessage musicMessage) { + xstream.alias("xml", musicMessage.getClass()); + return xstream.toXML(musicMessage); + } + + /** + * 对象到xml的处理 + * 扩展xstream,使其支持CDATA块 + */ + private XStream xstream = new XStream(new XppDriver() { + @Override + public HierarchicalStreamWriter createWriter(Writer out) { + return new PrettyPrintWriter(out) { + // 对所有xml节点的转换都增加CDATA标记 + boolean cdata = true; + + @Override + @SuppressWarnings("rawtypes") + public void startNode(String name, Class clazz) { + super.startNode(name, clazz); + } + + @Override + protected void writeText(QuickWriter writer, String text) { + if (cdata) { + writer.write(""); + } else { + writer.write(text); + } + } + }; + } + }); + +}