写这篇博客时犹豫了好久,因为步骤太多了,上班了也没时间,但是我依然记得当时实现公众号自动回复时的场景,找个案例好
难,也没有一个完整的案例,想了想还是写出来吧,希望能让实现这功能的人少走弯路。
微信公众号平台也有自定义回复消息,比如我在公众号里发送关注你,我们在微信公众号平台设置关键字关注你(就是
有人发送这个关键字就要回复什么内容)设置成回复:**你好,java!**适用于这种固定信息,如果我发送 获取个人信息、我的积
分这种内容就需要动态的数据了,所以要使用我们自己的接口往数据库中进行查询信息。
这个项目实现了简单的回复文字消息,没有 图片、音频等类型的发送、推荐看微信API文档实现,我这也有实现的案例需要的可加我QQ 930496909
首先:
先整理一下大致流程
1.编写java代码,要按照微信公众号提供的API文档来做。
2.下载ngrok工具,假设编写的Java都不会部署到网上(本地运行项目),那我们要想微信能访问我们的java接口我们需要一个工
具(就是将我们本地电脑变成服务器,让别人能来访问我们本地运行的项目说的比较通俗具体可百度~),如果编写的java程序
部署到服务器上就不用啦。
3.在微信公众号平台注册服务号或者订阅号[两者的区别在于服务号收钱功能多,其他区别可自行百度~]我注册的是订阅号,然
后在微信平台进行一些配置,(其实就是让关注公众号的人发送消息后能够对接我们的java接口)
4.进行测试。(我会把源码贴到码云上,可以下载源码https://gitee.com/it_qin/weixintest.git)
接下来就是步骤了。
看一下java结构目录
jar包(因为当时在学校做的还不太会用MAVEN管理,无奈啊,jar包主要就是ssm框架jar包和微信的几个包,我把截图发下,上面
我提供的码云链接上也有jar包)
下面就是每个文件了
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"><!-- 配置编码(解决中文乱码)过滤器 --><filter><filter-name>encodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param><init-param><param-name>forceEncoding</param-name><param-value>true</param-value></init-param></filter><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern> </filter-mapping>
<!-- log4j日志文件 --><context-param><param-name>log4jConfigLocation</param-name><param-value>classpath:log4j.properties</param-value></context-param> <listener><listener-class>org.springframework.web.util.Log4jConfigListener</listener-class></listener><!-- 创建springMvc的 dispathServlet --><servlet><servlet-name>springMvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc-servlet.xml</param-value></init-param><load-on-startup>1</load-on-startup><!-- 服务器一启动就加载 --></servlet><!--拦截后缀是.do--><servlet-mapping><servlet-name>springMvc</servlet-name><url-pattern>*.do</url-pattern></servlet-mapping><!-- 启动spring容器 spring配置文件的位置--><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext-mybatis.xml</param-value></context-param> <!-- 监听spring容器的启动 --><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>
</web-app>
springmvc-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd"><context:component-scan base-package="com.qhk.controller"/><mvc:annotation-driven><mvc:message-converters><bean class="org.springframework.http.converter.StringHttpMessageConverter"><property name="supportedMediaTypes"><list><value>application/json;charset=UTF-8</value></list></property></bean><bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"><property name="supportedMediaTypes"><list><value>text/html;charset=UTF-8</value><value>application/json</value></list></property><property name="features"><list><value>WriteDateUseDateFormat</value></list></property></bean></mvc:message-converters></mvc:annotation-driven><!-- 配置多视图解析器 --><bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"><property name="favorParameter" value="true"/> <property name="defaultContentType" value="text/html" /> <property name="mediaTypes"><map><entry key="html" value="text/html; charset=UTF-8"/><entry key="json" value="application/json; charset=UTF-8"/><entry key="xml" value="application/xml; charset=UTF-8"/></map></property><property name="viewResolvers"><list><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/"/><property name="suffix" value=".jsp"/></bean></list></property></bean><!-- 配置interceptors --><!-- <mvc:interceptors><mvc:interceptor><mvc:mapping path="/main/**"/><bean class="com.ktv.interceptor.SysInterceptor"/></mvc:interceptor> </mvc:interceptors> --><!-- 配置文件上传 MultipartResolver--><bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><property name="maxUploadSize" value="500000000"/><property name="defaultEncoding" value="UTF-8"/></bean>
</beans>
applicationContext-mybatis.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.qhk.service" /><context:annotation-config /><context:property-placeholder location="classpath:database.properties" /><!-- JNDI获取数据源(使用dbcp连接池) --><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close" scope="singleton"><property name="driverClassName" value="${driver}" /><property name="url" value="${url}" /><property name="username" value="${user}" /><property name="password" value="${password}" /><property name="initialSize" value="${initialSize}" /><property name="maxActive" value="${maxActive}" /><property name="maxIdle" value="${maxIdle}" /><property name="minIdle" value="${minIdle}" /><property name="maxWait" value="${maxWait}" /><property name="removeAbandoned" value="${removeAbandoned}" /><property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" /><property name="testWhileIdle" value="true" /><property name="timeBetweenEvictionRunsMillis" value="60000" /><property name="testOnBorrow" value="false" /><property name="testOnReturn" value="false" /><property name="validationQuery" value="select 1" /><property name="numTestsPerEvictionRun" value="${maxActive}" /></bean><!-- 事务管理 --><bean id="txManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /></bean><!-- 配置mybatis SqlSessionFactoryBean --><bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource" /><property name="configLocation" value="classpath:mybatis-config.xml" /></bean><aop:aspectj-autoproxy /><aop:config proxy-target-class="true"><aop:pointcut expression="execution(* *com.qhk.service..*(..))"id="transService" /><aop:advisor advice-ref="myAdvice" pointcut-ref="transService" /></aop:config><tx:advice id="myAdvice" transaction-manager="txManager"><tx:attributes><tx:method name="find*" read-only="true" propagation="SUPPORTS" /><tx:method name="add*" propagation="REQUIRED" /><tx:method name="update*" propagation="REQUIRED" /><tx:method name="del*" propagation="REQUIRED" /><tx:method name="*" /></tx:attributes></tx:advice><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer" ><property name="basePackage" value="com.qhk.dao" /></bean></beans>
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration> <settings> <!-- changes from the defaults --> <setting name="lazyLoadingEnabled" value="false" /> </settings> <typeAliases> <!--这里给实体类取别名,方便在mapper配置文件中使用--> <package name="com.qhk.entity"/></typeAliases>
</configuration>
database.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/ktvsystem?useUnicode=true&characterEncoding=utf-8
user=root
password=admin
minIdle=45
maxIdle=50
initialSize=5
maxActive=100
maxWait=100
removeAbandonedTimeout=240
removeAbandoned=true
log4j.properties
log4j.rootLogger=debug,CONSOLE,file
#log4j.rootLogger=ERROR,ROLLING_FILElog4j.logger.cn.smbms=debug
log4j.logger.org.apache.ibatis=debug
log4j.logger.org.mybatis.spring=debug
log4j.logger.java.sql.Connection=debug
log4j.logger.java.sql.Statement=debug
log4j.logger.java.sql.PreparedStatement=debug
log4j.logger.java.sql.ResultSet=debug######################################################################################
# Console Appender \u65e5\u5fd7\u5728\u63a7\u5236\u8f93\u51fa\u914d\u7f6e
######################################################################################
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.Threshold=debug
log4j.appender.CONSOLE.DatePattern=yyyy-MM-dd
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern= - (%r ms) - %d{yyyy-M-d HH:mm:ss}%x[%5p](%F:%L) %m%n######################################################################################
# Rolling File \u6587\u4ef6\u5927\u5c0f\u5230\u8fbe\u6307\u5b9a\u5c3a\u5bf8\u7684\u65f6\u5019\u4ea7\u751f\u4e00\u4e2a\u65b0\u7684\u6587\u4ef6
######################################################################################
#log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender
#log4j.appender.ROLLING_FILE.Threshold=INFO
#log4j.appender.ROLLING_FILE.File=${baojia.root}/logs/log.log
#log4j.appender.ROLLING_FILE.Append=true
#log4j.appender.ROLLING_FILE.MaxFileSize=5000KB
#log4j.appender.ROLLING_FILE.MaxBackupIndex=100
#log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout
#log4j.appender.ROLLING_FILE.layout.ConversionPattern=%d{yyyy-M-d HH:mm:ss}%x[%5p](%F:%L) %m%n######################################################################################
# DailyRolling File \u6bcf\u5929\u4ea7\u751f\u4e00\u4e2a\u65e5\u5fd7\u6587\u4ef6\uff0c\u6587\u4ef6\u540d\u683c\u5f0f:log2009-09-11
######################################################################################
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.DatePattern=yyyy-MM-dd
log4j.appender.file.File=${AppInfoSystem.root}/logs/log.log
log4j.appender.file.Append=true
log4j.appender.file.Threshold=debug
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern= - (%r ms) - %d{yyyy-M-d HH:mm:ss}%x[%5p](%F:%L) %m%n#DWR \u65e5\u5fd7
#log4j.logger.org.directwebremoting = ERROR#\u663e\u793aHibernate\u5360\u4f4d\u7b26\u7ed1\u5b9a\u503c\u53ca\u8fd4\u56de\u503c
#log4j.logger.org.hibernate.type=DEBUG,CONSOLE #log4j.logger.org.springframework.transaction=DEBUG
#log4j.logger.org.hibernate=DEBUG
#log4j.logger.org.acegisecurity=DEBUG
#log4j.logger.org.apache.myfaces=TRACE
#log4j.logger.org.quartz=DEBUG#log4j.logger.com.opensymphony=INFO
#log4j.logger.org.apache.struts2=DEBUG
log4j.logger.com.opensymphony.xwork2=debug
WeiXinController.java
package com.qhk.controller;import java.util.Map;
import java.util.Random;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;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.qhk.util.CheckUtil;
import com.qhk.util.MessageFormat;
import com.qhk.util.MessageUtil;@Controller
@RequestMapping("/weixin")
public class WeiXinController {/*** <h4>功能:[微信验证 ][2018年2月9日 下午10:01:14][创建人: HongKun.Qin]</h4>* <h4></h4>* @param request* @param response* @return*/@ResponseBody@RequestMapping(value = "/message.do",method =RequestMethod.GET)public String getMessageValidate(HttpServletRequest request, HttpServletResponse response){String signature = request.getParameter("signature");//微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。String timestamp = request.getParameter("timestamp");// 时间戳String nonce = request.getParameter("nonce");// 随机数String echostr = request.getParameter("echostr");// 随机字符串if(CheckUtil.checkSignature(signature, timestamp, nonce)){return echostr;}return "";}/*** <h4>功能:[接受消息,并返回消息 ][2018年2月9日 下午10:02:00][创建人: HongKun.Qin]</h4>* <h4></h4>* @param request* @param response* @return* @throws Exception*/@ResponseBody@RequestMapping(value = "/message.do",method =RequestMethod.POST)public String getMessage(HttpServletRequest request, HttpServletResponse response) throws Exception{Map<String,String> map = new MessageFormat().xmlToMap(request);String fromUserName = map.get("FromUserName");//公众号String toUserName = map.get("ToUserName");//粉丝号String msgType = map.get("MsgType");//发送的消息类型[比如 文字,图片,语音。。。]String content = map.get("Content");//发送的消息内容String message = null;System.out.println("fromUserName:"+fromUserName+" ToUserName:"+toUserName+" MsgType:"+msgType+" "+content);//判断发送的类型是文本if(MessageUtil.MESSAGE_TEXT.equals(msgType)){//发送的内容为???时if("0".equals(content)){message = MessageFormat.initText(toUserName, fromUserName, MessageUtil.menuText());}else if("1".equals(content)) {Random random = new Random();message = MessageFormat.initText(toUserName, fromUserName, String.format("您本次的验证码为:%s%s%s%s", random.nextInt(10),random.nextInt(10),random.nextInt(10),random.nextInt(10)));//模拟验证码}else{message = MessageFormat.initText(toUserName, fromUserName, "功能正在完善中,请按提示信息操作[回复'0'显示主菜单]。");}}else if(MessageUtil.MESSAGE_EVENT.equals(msgType)){//验证是关注/取消事件String eventType = map.get("Event");//获取是关注还是取消//关注if(MessageUtil.MESSAGE_SUBSCRIBE.equals(eventType)){message = MessageFormat.initText(toUserName, fromUserName, "欢迎关注青鸟ktv,回复[0]即可调出功能菜单");}}return message;}}
AccessToken.java
package com.qhk.entity;public class AccessToken {private String token;private int expiresIn;public String getToken() {return token;}public void setToken(String token) {this.token = token;}public int getExpiresIn() {return expiresIn;}public void setExpiresIn(int expiresIn) {this.expiresIn = expiresIn;}
}
BaseMessage.java
package com.qhk.entity;public class BaseMessage {private String ToUserName;private String FromUserName;private long CreateTime;private String MsgType;public String getToUserName() {return ToUserName;}public void setToUserName(String toUserName) {ToUserName = toUserName;}public String getFromUserName() {return FromUserName;}public void setFromUserName(String fromUserName) {FromUserName = fromUserName;}public long getCreateTime() {return CreateTime;}public void setCreateTime(long createTime) {CreateTime = createTime;}public String getMsgType() {return MsgType;}public void setMsgType(String msgType) {MsgType = msgType;}
}
TextMessage.java
package com.qhk.entity;public class TextMessage extends BaseMessage{private String Content;private String MsgId;public String getContent() {return Content;}public void setContent(String content) {Content = content;}public String getMsgId() {return MsgId;}public void setMsgId(String msgId) {MsgId = msgId;}
}
CheckUtil.java(token注意,我现在是qhk后面微信公众号平台配置也要用这个,自己改了的话就填自己改的)
package com.qhk.util;import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;public class CheckUtil {public static final String token = "qhk";//这个地方也要注意public static boolean checkSignature(String signature,String timestamp,String nonce){String[] arr=new String[]{token,timestamp,nonce};//排序Arrays.sort(arr);//生成字符串StringBuffer content = new StringBuffer();for (int i = 0; i < arr.length; i++) {content.append(arr[i]);}//sha1加密String temp = getSha1(content.toString());return temp.equals(signature);}public static String getSha1(String str){if (null == str || 0 == str.length()){return null;}char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};try {MessageDigest mdTemp = MessageDigest.getInstance("SHA1");mdTemp.update(str.getBytes("UTF-8"));byte[] md = mdTemp.digest();int j = md.length;char[] buf = new char[j * 2];int k = 0;for (int i = 0; i < j; i++) {byte byte0 = md[i];buf[k++] = hexDigits[byte0 >>> 4 & 0xf];buf[k++] = hexDigits[byte0 & 0xf];}return new String(buf);} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (UnsupportedEncodingException e) {e.printStackTrace();}return null;}}
MessageFormat.java
package com.qhk.util;import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;import javax.servlet.http.HttpServletRequest;import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;import com.qhk.entity.TextMessage;
import com.thoughtworks.xstream.XStream;/*** <p>将发送的消息进行转换</p>* @author HongKun.Qin*/
public class MessageFormat {/*** xml 转 map* * @param request* @return* @throws IOException* @throws DocumentException*/public static Map<String, String> xmlToMap(HttpServletRequest request)throws IOException, DocumentException {Map<String, String> map = new HashMap<String, String>();SAXReader reader = new SAXReader();InputStream ins = request.getInputStream();Document doc = reader.read(ins);Element root = doc.getRootElement();List<Element> list = root.elements();for (Element e : list) {map.put(e.getName(), e.getText());}ins.close();return map;}/*** 将文本消息转换为xml* * @param textMessage* @return*/public static String textMessageToXml(TextMessage textMessage) {XStream xStream = new XStream();xStream.alias("xml", textMessage.getClass());return xStream.toXML(textMessage);}public static String initText(String toUserName, String fromUserName,String content) {TextMessage text = new TextMessage();text.setFromUserName(toUserName);text.setToUserName(fromUserName);text.setMsgType(MessageUtil.MESSAGE_TEXT);text.setCreateTime(new Date().getTime());text.setContent(content);return textMessageToXml(text);}
}
MessageUtil.java
package com.qhk.util;public class MessageUtil {/*** 类型*/public static final String MESSAGE_TEXT = "text";//文本public static final String MESSAGE_NEWS = "news";public static final String MESSAGE_IMAGE = "image";public static final String MESSAGE_MUSIC = "music";public static final String MESSAGE_VOICE = "voice";public static final String MESSAGE_VIDEO = "video";public static final String MESSAGE_LINK = "link";public static final String MESSAGE_LOCATION = "location";public static final String MESSAGE_EVENT = "event";public static final String MESSAGE_SUBSCRIBE = "subscribe";public static final String MESSAGE_UNSUBSCRIBE = "unsubscribe";public static final String MESSAGE_CLICK = "CLICK";public static final String MESSAGE_VIEW = "VIEW";public static final String MESSAGE_SCANCODE = "scancode_push";/*** <h4>功能:[显示的主菜单 ][2018年2月9日 下午9:37:56][创建人: HongKun.Qin]</h4>* <h4></h4>* @return*/public static String menuText() {StringBuffer sb = new StringBuffer();sb.append("欢迎您关注青鸟KTV,请按照菜单提示进行操作:\n\n");sb.append("[1].显示短信验证码\n");sb.append("[2].显示个人信息\n");sb.append("[3].关于青鸟KTV\n");sb.append("[4].关于注册成为会员\n\n");sb.append("回复 \"[0]\" 调出此菜单。");return sb.toString();}
}
WeixinUtil.java(APPID、APPSECRET)别忘改成自己的,不然项目也没法运行
package com.qhk.util;import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;import com.qhk.entity.AccessToken;import net.sf.json.JSONObject;public class WeixinUtil {private static final String APPID="";//在基础配置中可查看自己APPIDprivate static final String APPSECRET="";//在基础配置中可查看自己APPSECRETprivate static final String ACCESS_TOKEN_URL="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";private static final String UPLOAD_URL = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE";public static JSONObject doGetStr(String url){DefaultHttpClient httpClient = new DefaultHttpClient();HttpGet httpGet=new HttpGet(url); JSONObject jsonObject = null;try {HttpResponse response=httpClient.execute(httpGet);HttpEntity entity = response.getEntity();if(entity!=null){String result = EntityUtils.toString(entity,"UTF-8");jsonObject = JSONObject.fromObject(result);}} catch (ClientProtocolException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}System.out.println(jsonObject);return jsonObject;}/*** * @Description: TODO 获取AccessToken* @param @return * @return AccessToken * @throws* @author qinhongkun* @date 2017-12-18*/public static AccessToken getAccessToken(){AccessToken token = new AccessToken();String url = ACCESS_TOKEN_URL.replace("APPID", APPID).replace("APPSECRET", APPSECRET);JSONObject jsonObject = doGetStr(url);if(jsonObject!=null){token.setToken(jsonObject.getString("access_token"));token.setExpiresIn(jsonObject.getInt("expires_in"));}return token;}/** 文件上传*/public static String upload(String filePath, String accessToken,String type) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException {System.out.println("filePath:"+filePath);File file = new File(filePath);if (!file.exists() || !file.isFile()) {throw new IOException("文件不存在");}String url = UPLOAD_URL.replace("ACCESS_TOKEN", accessToken).replace("TYPE",type);URL urlObj = new URL(url);//连接HttpURLConnection con = (HttpURLConnection) urlObj.openConnection();con.setRequestMethod("POST"); con.setDoInput(true);con.setDoOutput(true);con.setUseCaches(false); //设置请求头信息con.setRequestProperty("Connection", "Keep-Alive");con.setRequestProperty("Charset", "UTF-8");//设置边界String BOUNDARY = "----------" + System.currentTimeMillis();con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);StringBuilder sb = new StringBuilder();sb.append("--");sb.append(BOUNDARY);sb.append("\r\n");sb.append("Content-Disposition: form-data;name=\"file\";filename=\"" + file.getName() + "\"\r\n");sb.append("Content-Type:application/octet-stream\r\n\r\n");byte[] head = sb.toString().getBytes("utf-8");//获得输出流OutputStream out = new DataOutputStream(con.getOutputStream());//输出表头out.write(head);//文件正文部分//把文件已流文件的方式 推入到url中DataInputStream in = new DataInputStream(new FileInputStream(file));int bytes = 0;byte[] bufferOut = new byte[1024];while ((bytes = in.read(bufferOut)) != -1) {out.write(bufferOut, 0, bytes);}in.close();//结尾部分byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");//定义最后数据分隔线out.write(foot);out.flush();out.close();StringBuffer buffer = new StringBuffer();BufferedReader reader = null;String result = null;try {//定义BufferedReader输入流来读取URL的响应reader = new BufferedReader(new InputStreamReader(con.getInputStream()));String line = null;while ((line = reader.readLine()) != null) {buffer.append(line);}if (result == null) {result = buffer.toString();}} catch (IOException e) {e.printStackTrace();} finally {if (reader != null) {reader.close();}}JSONObject jsonObj = JSONObject.fromObject(result);System.out.println(jsonObj);String typeName = "media_id";if(!"image".equals(type)){typeName = type + "_media_id";}String mediaId = jsonObj.getString(typeName);return mediaId;}}
2.大家现在就是关心ngrok下载地址:https://ngrok.com/download
还有人会问:哎哟我靠,什么是ngrok?
其实不用纠结这是个啥,如果你作为一个Java开发人员是第一次接触微信公众号后台开发,我建议你千万别纠结这到底是个
啥,简单明了的告诉你:微信公众号开发文档中 要求 有服务器 (自己的域名、也可以理解为自己的空间 当然 不是QQ空
间),然后呢,那你就想百度一下了,怎么拥有自己的域名或者说空间,有人推荐你使用百度BEA(好像是,不知道名字有
没有记错),然后微信公众号的技术文档里面推荐你用腾讯的什么什么,总之,收费。诶,对 就是收费。
所以呢,这个ngrok就是免费的。而且运行极其简单,对,不费劲哈。
这个下载之后,暂时放那,别动。
3.注册订阅号 去微信公众号平台注册一个个人的订阅号就行,登录进去,三个箭头分别点击一下将最下面红箭头标出的地方进
行关闭
关闭后
看图操作
此时 我们还需要配置下图
配置你的服务器地址 (这是问题1)
配置你的token (这是问题2)
配置你的EncodingAESkey (这不是问题!!)
问题1:
然后你肯定进入了死胡同,想说URL怎么填呢?
你还记得你的ngrok吗?
首先我们先在本地启动项目,(注意代码中需要修改的地方上面我已经写出来,填写自己的APPID和密码)必须是tomcat的8080
端口
这时候就要用到ngrok了
打开你的ngrok文件夹,在包涵ngrok.exe文件的文件夹中运行cmd,然后输入指令:
ngrok -config ngrok.cfg -subdomain qinhongkun 8080
qinhongkun可以随便改,自己填写服务器地址别写错了就行。
如果没有什么问题的话下面这张图就是启动成功的(别关掉这dos窗口)
转回来微信公众号,你的URL就填写ngrok运行后的生成的网址(我已经用红色标记出来了用哪一个都行有两个)/项目名称/控
制器名 比如我的就是 https://qinhongkun.tunnel.echomod.cn/weixintest/weixin/message.do
至于为什么我的项目名是weixintest而不是weixin-demo 那是我之前在eclipse中改了项目名,而tomcat中没有修改过来,
weixin/message.do这控制器方法上面有。
问题2:
token 就要填我们在项目中写的那个,上面我也重点标记了,如果项目中更改了的话,这别忘了修改!
问题3:直接点击随机生成一个就ok了
如果没有问题现在已经能保存了。
我将项目上传到码云,https://gitee.com/it_qin/weixintest.git。
注:因为当时用作项目中有很多功能,所以这是个完整的ssm框架,只不过我把那些都删了,只留下一个简单的微信Demo.
现在去你的公众号测试一下就行了,有什么问题或者建议欢迎评论,确保一天之内回复,不算星期天哦。