Java development WeChat public account to accept and reply to the message [engineering code + picture full solution]

I hesitated for a long time when I wrote this blog, because there are too many steps, and I don’t have time to go to work, but I still remember the scene when the official account was automatically responded to. Find a case.

It is difficult, and there is no complete case. After thinking about it, write it down, hoping that people who realize this function can avoid detours.

The WeChat official account platform also has custom reply messages. For example, if I send follow you in the official account, we set keywords on the WeChat official account platform to follow you (that is

If someone sends this keyword to reply what content) is set to reply: **Hello, java!**Applicable to this kind of fixed information, if I send to get personal information, my accumulation

To divide this kind of content requires dynamic data, so we have to use our own interface to query information in the database.

This project implements a simple reply to text messages, no pictures, audio and other types of sending, it is recommended to see the WeChat API document implementation, I also have the implementation of the case, you can add me QQ 930496909

First of all:

First sort out the general process

1. To write java code, follow the API documentation provided by the WeChat official account.

2. Download the ngrok tool, assuming that the written Java will not be deployed to the Internet (locally run the project), then if we want WeChat to be able to access our java interface, we need a tool

Tool (that is, to turn our local computer into a server, so that others can visit our locally running projects, which is more popular and specific to Baidu~), if you write a java program

No need to deploy to the server.

3. Register the service account or subscription account on the WeChat official account platform [The difference between the two is that the service account has multiple functions for collecting money, and other differences can be Baidu by yourself~] I registered a subscription account, but

Then perform some configuration on the WeChat platform, (actually, let people who follow the official account send a message to connect to our java interface)

4. Perform the test. (I will post the source code on Code Cloud, you can download the source code https://gitee.com/it_qin/weixintest.git)

Next comes the steps.

Take a look at the

jar package of the java structure directory (because I was not able to manage it with MAVEN at the time, I am helpless, the jar package is mainly the ssm framework jar package and several packages of WeChat. I will post the screenshot, above

There is also a jar package on the code cloud link I provided)
Write picture description here
The following is each file

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/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://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_FILE

log4j.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 note, I am now using this for the configuration of the WeChat official account platform behind qhk, and if I change it myself, I will fill it in by myself )

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) don't forget to change to your own, otherwise the project will not run

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="";//在基础配置中可查看自己APPID
	private static final String APPSECRET="";//在基础配置中可查看自己APPSECRET
	private 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. Now everyone is concerned about the ngrok download address: https://ngrok.com/download

Others will ask: Ouch, what is ngrok?

In fact, don’t worry about what this is. If you, as a Java developer, it’s your first contact with WeChat official account backend development, I suggest you don’t worry about it.

What, let me tell you in a simple and clear way: the WeChat official account development document requires a server (your own domain name can also be understood as your own space is certainly not QQ space

Between), and then, you want to Baidu, how to have your own domain name or space, someone recommended you to use Baidu BEA (it seems to be, I don’t know if the name has

I remember correctly), and the technical documents of the WeChat official account recommend you to use Tencent. In short, there is a charge. Yeah, yes, it's a charge.

So, this ngrok is free. And the operation is extremely simple, yes, no effort.

After this download, put it there temporarily, don't move.

3. To register a subscription account, go to the WeChat official account platform to register a personal subscription account, log in, and click on the three arrows to enter the place marked by the bottom red arrow.

After the line is closed
Write picture description here
, look at the
Write picture description here
picture operation.
Write picture description hereWrite picture description hereWrite picture description here
At this time, we also need to configure the following picture

Configure your server address (this is question 1)

Configure your token (this is question 2)

Configure your EncodingAESkey (this is not a problem!!)
Write picture description here
Question 1:

Then you must have entered a dead end. How to fill in the URL?

Do you remember your ngrok?

First of all, let's start the project locally, (note the places that need to be modified in the code I have written above, fill in my own APPID and password) must be 8080 of tomcat

port

Ngrok will be used at this time

Open your ngrok folder, run cmd in the folder containing the ngrok.exe file, and enter the command:

ngrok -config ngrok.cfg -subdomain qinhongkun 8080

Qinhongkun can be changed at will, just fill in the server address by yourself and don't make a mistake.
Write picture description here

If there is no problem, the following picture is successfully launched (don't close the dos window)
Write picture description here
and return to the WeChat official account, and fill in the URL generated by ngrok after running (I have already marked which one to use) There are two)/project name/control

The controller name such as mine is https://qinhongkun.tunnel.echomod.cn/weixintest/weixin/message.do

As for why my project name is weixintest instead of weixin-demo, it is because I changed the project name in eclipse, but not in tomcat.

Weixin/message.do is on the controller method.

Question 2:

The token is to fill in the one we wrote in the project. I also highlighted it above. If the project changes, don’t forget to modify it!

Question 3: Click to generate one randomly and it will be ok

If there is no problem, it can be saved now.

I uploaded the project to Code Cloud, https://gitee.com/it_qin/weixintest.git.

Note: Because there are many functions in the project at that time, this is a complete ssm framework, but I deleted all of them, leaving only a simple WeChat Demo.

Go to your official account and test it now. If you have any questions or suggestions, please comment. Make sure to reply within one day, not Sunday.

Guess you like

Origin blog.csdn.net/Qin_HongKun/article/details/79293585