写这篇博客时犹豫了好久,因为步骤太多了,上班了也没时间,但是我依然记得当时实现公众号自动回复时的场景,找个案例好

难,也没有一个完整的案例,想了想还是写出来吧,希望能让实现这功能的人少走弯路。

微信公众号平台也有自定义回复消息,比如我在公众号里发送关注你,我们在微信公众号平台设置关键字关注你(就是

有人发送这个关键字就要回复什么内容)设置成回复:**你好,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.

现在去你的公众号测试一下就行了,有什么问题或者建议欢迎评论,确保一天之内回复,不算星期天哦。

java开发微信公众号接受并回复消息[工程代码+图片全解]相关推荐

  1. Java开发微信公众号之被动回复用户消息-回复图片消息

    一.前言 hello小伙伴们,大家好,做微信开发两年了,最近看到微信方面的文章阅读量和关注量上升的比较快速,激发了我满满的动力啊,所以就滋生了一个想法,从头开始整理一下微信公众号开发,写一个简易的教程 ...

  2. Java开发微信公众号(四)---微信服务器post消息体的接收及消息的处理

    在前几节文章中我们讲述了微信公众号环境的搭建.如何接入微信公众平台.以及微信服务器请求消息,响应消息,事件消息以及工具处理类的封装:接下来我们重点说一下-微信服务器post消息体的接收及消息的处理,这 ...

  3. Java开发微信公众号(二)---开启开发者模式,接入微信公众平台开发

    接入微信公众平台开发,开发者需要按照如下步骤完成: 1.填写服务器配置 2.验证服务器地址的有效性 3.依据接口文档实现业务逻辑 资料准备: 1.一个可以访问的外网,即80的访问端口,因为微信公众号接 ...

  4. Java开发微信公众号之整合weixin-java-tools框架开发微信公众号

    微信开发者接入文档 : https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319 微信公众平台测试账号申请: http ...

  5. java开发微信公众号支付

    这篇文章主要给大家结合微信支付接口开发的实践,从获取用户授权到各主要接口的使用方法等方面介绍微信支付的关键点技术,有需要的小伙伴可以参考下 最近做了微信公众号支付的开发,由于是第一次做也摸索了几天的时 ...

  6. java开发微信公众号(SpringMVC)2-消息管理功能

    微信移动端软件,可以向公众号发送消息,如文字,语音,图片等等,在这个过程中,微信端服务器首先要接受到你发送的消息,然后根据你发送的消息会产生不同的回应. 这个回应要想自己设定内容(微信公众号管理界面可 ...

  7. java开发微信公众号:微信公众号对接

    一.填写服务器配置信息的介绍 登录微信公众平台官网后,进入到公众平台后台管理页面. 选择 公众号基本设置->基本配置 ,点击"修改配置"按钮,填写服务器地址(URL).Tok ...

  8. java开发微信公众号(SpringMVC)1-简述

    很久之前就想了解并真正着手去做微信公众号的开发,在这一个多月终于有时间去看微信的开发文档,并利用自己的熟悉语言java去做这方面的一些东西. 要想真正去了解微信公众号的提供的接口的功能,开发文档虽然写 ...

  9. java开发微信公众号-订阅号-消息接收,及返回给用户信息

    创建java项目 1)导入依赖 pom.xml: <parent><groupId>org.springframework.boot</groupId><ar ...

最新文章

  1. break与continue
  2. python opencv 4.1.0 cv2.convertScaleAbs()函数 (通过线性变换将数据转换成8位[uint8])(用于Intel Realsense D435显示depth图像)
  3. ubuntu导入第三方库_在Ubuntu中,如何添加Apt存储库
  4. 云计算开发学习笔记:Python3迭代器与生成器
  5. 【kafka】Replication factor: 1 larger than available brokers:0
  6. websocket多客户端接收消息_WebSocket之消息接收发送
  7. R语言编程基础(2)
  8. js 实现ReplaceAll 的方法
  9. 我们为什么要学习JAVA编程语言
  10. 华为云文字识别关键技术和特别需要注意的事宜
  11. 打印机打印小票代码(附工具类,接口讲解和源码)
  12. Fedora 34 dnf 安装nvidia显卡驱动,支持rtx 2060 ,解决nouveau崩溃故障
  13. 鲁大师发布2022半年报手机UI排行榜,vivo OriginOS成为最流畅UI
  14. Excel 分组显示(COUNTIF 函数实现)
  15. 无人机专业实训室建设方案
  16. 计算机类专业知识pdf,事业单位计算机专业知识整理(全)(20210324075052).pdf
  17. 在HTML网页中怎样写大于号和小于号
  18. 地热能类毕业论文文献有哪些?
  19. yield 和 yield*
  20. 免费WebCamps-北美,亚洲和欧洲-*立即注册*

热门文章

  1. 【软件工程B】2021-2022(2)作业【一】
  2. 多重网络与计算机之间是感叹号,win10系统连接网络出现多重网络的设置教程
  3. 转--手电筒按钮变成灰色
  4. 腾讯云短信发送失败提示1038错误
  5. nodejs+vue+elementui校友会校友录社交网站系统-vscode
  6. 惠泉啤酒或与燕京啤酒正面交锋
  7. java字符串数组转json_java中字符串String格式转化成json格式
  8. 【golang】map,切片,数组转json格式(详细过程)
  9. Java 7 一个技术标准的商业咒语
  10. 原生JS实现移动端选择器插件