微信测试号接口配置,公众号自动回复,关注/取消关注回复,自定义菜单https

master
jyx 7 years ago
parent 762a921ecc
commit 5c23b5d88d

@ -55,6 +55,40 @@
<version>1.2.37</version>
</dependency>
<!-- JSONObject对象依赖的jar包 -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>net.sf.ezmorph</groupId>
<artifactId>ezmorph</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.2.3</version>
<classifier>jdk15</classifier><!-- 指定jdk版本 -->
</dependency>
<!-- Json依赖架包下载 -->
<dependency>
@ -89,11 +123,11 @@
<optional>true</optional>
</dependency>
<!-- servlet依赖. -->
<!--<dependency>-->
<!--<groupId>javax.servlet</groupId>-->
<!--<artifactId>javax.servlet-api</artifactId>-->
<!--<scope>provided</scope>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>javax.servlet</groupId>-->
<!--<artifactId>javax.servlet-api</artifactId>-->
<!--<scope>provided</scope>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>javax.servlet</groupId>-->
<!--<artifactId>jstl</artifactId>-->
@ -114,6 +148,16 @@
<artifactId>spring-session</artifactId>
<!--<version>RELEASE</version>-->
</dependency>
<!--XStream包的依赖java对象到xml的处理扩展xstream使其支持CDATA块-->
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.9</version>
</dependency>
</dependencies>
<build>

@ -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) {

@ -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;

@ -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 + "]";
}
}

@ -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;
}

@ -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;
}

@ -0,0 +1,17 @@
package com.example.demo.weixin.bean.menu;
import lombok.Getter;
import lombok.Setter;
/**
* @Description: clicktypenamekey3
* @Parameters:
* @Return:
*/
@Setter
@Getter
public class ClickButton extends Button{
private String type;
private String key;
}

@ -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;
}

@ -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;
}

@ -0,0 +1,17 @@
package com.example.demo.weixin.bean.menu;
import lombok.Getter;
import lombok.Setter;
/**
* @Description: view(typenameurl)
* @Parameters:
* @Return:
*/
@Getter
@Setter
public class ViewButton extends Button {
public String type;
public String url;
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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<Article> Articles;
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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;
}
}
}

@ -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;
}
}
}

@ -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);
}

@ -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<String, String> 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;
}
}

@ -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 httpwww.baidu.com
* requestMethod GETPOST
* outputStr
* jsonxml.
* @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;
}
}

@ -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;
}
}

@ -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};
//将tokectimestamp,nonce三个参数进行字典序排序
Arrays.sort(arr);
StringBuilder content = new StringBuilder();
for(int i = 0 ; i<arr.length; i++){
content.append(arr[i]);
}
//MessageDigest类为应用程序提供信息摘要算法的功能
MessageDigest md = null;
String tmpStr = null;
try {
//MessageDigest通过getIntance函数进行sha-加密
md = MessageDigest.getInstance("SHA-1");
byte[] digest = md.digest(content.toString().getBytes());
tmpStr = byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
logger.info("------正在微信签名加密认证-----");
content = null;
//将sha1加密后的字符串与signature对比标识该请求来自于微信
return tmpStr !=null ? tmpStr.equals(signature.toUpperCase()) : false ;
}
//将字节数组转变为十六进制字符串
public static String byteToStr(byte [] digest){
String tmpStr = "";
for (int i = 0 ;i < digest.length ; i++){
tmpStr += byteToHexStr(digest[i]);
}
return tmpStr;
}
//将字节转变为十六进制字符串
public static String byteToHexStr(byte c){
char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
char[] tempArr = new char[2];
tempArr[0] = Digit[(c >>> 4) & 0X0F];
tempArr[1] = Digit[c & 0X0F];
String s = new String(tempArr);
return s;
}
}

@ -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;
}
}

@ -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";
}

@ -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为空");
}
}
}

@ -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;
}
}

@ -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;
}
}

@ -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<Article> articleList=new ArrayList<Article>();
// 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+"还未绑定");
// }
// }
}

@ -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: xmlmap
* @Parameters: WeixinMessageUtil
* @Return: Map<String, String>
*/
public Map<String, String> parseXml(HttpServletRequest request)throws Exception{
// 将解析结果存储在HashMap中
Map<String, String>map =new HashMap<String, String>();
// 从request中得到输入流
InputStream inputStream=request.getInputStream();
//用SAXReader解析xml文档
SAXReader reader = new SAXReader();
// 读取输入流
Document document = reader.read(inputStream);
// 得到XML的根元素
Element root = document.getRootElement();
// 得到根元素的所有子节点
@SuppressWarnings("unchecked") //忽略黄色警告
List<Element> 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("<![CDATA[");
writer.write(text);
writer.write("]]>");
} else {
writer.write(text);
}
}
};
}
});
}
Loading…
Cancel
Save