微信公众号java开发:验证消息的确来自微信服务器

微信公众号开发,微信服务需要认证服务,官方文档如下:
在这里插入图片描述

引入jar包如下:

<dependency>
	<groupId>com.github.binarywang</groupId>
	<artifactId>weixin-java-mp</artifactId>
	<version>3.6.0</version>
</dependency>
<dependency>
	<groupId>com.github.liyiorg</groupId>
	<artifactId>weixin-popular</artifactId>
	<version>2.8.24</version>
</dependency>
<dependency>
	<groupId>org.dom4j</groupId>
	<artifactId>dom4j</artifactId>
	<version>2.1.3</version>
</dependency>

代码如下:

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
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 com.alibaba.fastjson.JSONObject;
import com.cetcnav.lbs.pis.util.DateUtil;
import com.cetcnav.operations.Attention.service.AttentionService;
import com.cetcnav.operations.cache.CacheManger;
import com.cetcnav.operations.entity.UserApp;
import com.cetcnav.operations.user.service.UserAppService;
import com.cetcnav.operations.util.WXUtil;
import com.cetcnav.operations.util.WeixinUtil;
import com.cetcnav.operations.util.constant.OperationsConstant;
import com.cetcnav.operations.util.constant.WXConstant;
import com.cetcnav.operations.util.properties.RouteUrlPropertiesUtils;

import weixin.popular.bean.xmlmessage.XMLImageMessage;
import weixin.popular.bean.xmlmessage.XMLMessage;
import weixin.popular.support.ExpireKey;
import weixin.popular.support.expirekey.DefaultExpireKey;

/**
 * 1、验证消息的确来自微信服务器 2、接收微信服务器推送的时间信息
 * @author  2020年10月14日
 */
@RestController
@RequestMapping("/rest/wxauth")
public class WXAuthWebServiceController {
	private static Logger log = LoggerFactory.getLogger(WXAuthWebServiceController.class);


	@Autowired
	private UserAppService userAppService;
	
	
	// 重复通知过滤
	private static ExpireKey expireKey = new DefaultExpireKey();

	@RequestMapping(value = "", method = RequestMethod.GET)
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {

		// 1、验证消息的确来自微信服务器
		String signature = request.getParameter("signature");
		String timestamp = request.getParameter("timestamp");
		String nonce = request.getParameter("nonce");
		String echostr = request.getParameter("echostr");
		String token = OperationsConstant.WECHAT_TOKEN;
		String jiami = "";
		try {
			// 这里是对三个参数进行加密
			jiami = SHA1.getSHA1(token, timestamp, nonce, "");
		} catch (AesException e) {
			e.printStackTrace();
		}
		log.info("验证消息的确来自微信服务器 :加密" + jiami);
		log.info("验证消息的确来自微信服务器 :本身" + signature);
		if (jiami.equals(signature)) {
			// 返回echostr给微信服务器
			OutputStream os = response.getOutputStream();
			os.write(URLEncoder.encode(echostr, "UTF-8").getBytes());
			os.flush();
			os.close();
		}
	}
	
	@RequestMapping(value = "", method = RequestMethod.POST)
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		response.setCharacterEncoding("UTF-8");
		PrintWriter out = response.getWriter();
		// 2、接收微信服务器推送的时间信息
		// xml请求解析
		Map<String, String> requestMap = WXUtil.parseXml(request);

		if (requestMap.get("MsgType") != null) {
			// 发送方帐号(open_id)
			String fromUserName = requestMap.get("FromUserName");
			// 公众帐号
			String toUserName = requestMap.get("ToUserName");
			// 消息类型
			String msgType = requestMap.get("MsgType");
			// 消息创建时间 (整型)
			String createTime = requestMap.get("CreateTime");

			String key = fromUserName + "-" + toUserName + "-" + createTime;
			// 重复通知不作处理
			if (expireKey.exists(key)) {
				log.info("重复通知了");
				return;
			}
			// 事件处理开始
			if (msgType.equals(WXConstant.REQ_MESSAGE_TYPE_EVENT)) {
				// 事件类型
				String eventType = requestMap.get("Event");
				// 微信关注事件
				if (eventType.equals(WXConstant.EVENT_TYPE_SUBSCRIBE)) {
					String unionid = CacheManger.getUnionId(fromUserName);
					if (StringUtils.isBlank(unionid)) {
						log.error("公众号关注,unionid获取为空。");
						return;
					}
					// 关注时触发 * 累加关注积分
					attentionService.attentionInterface(unionid);

					UserApp userApp = userAppService.getUserAppByUnionIdAndType(unionid,
							OperationsConstant.APP_TYPE_OPERATIONS);
					if (userApp == null) {
						// userapp里存储公众号账号信息
						UserApp ua = new UserApp();
						ua.setApptype(OperationsConstant.APP_TYPE_OPERATIONS);
						ua.setOpenid(fromUserName);
						ua.setUnionId(unionid);
						ua.setUpdatetime(DateUtil.getCurrentTime());
						ua.setDeleted(false);
						userAppService.add(ua);
					}
					// XMLMessage xmlTextMessage = new
					// XMLTextMessage(fromUserName,toUserName,"积分兑换流程如下:\n");
					// String textMessage = xmlTextMessage.toXML();
					// out.print(textMessage);

					// 调用客服接口 客服接口-发消息
					String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN"
							.replace("ACCESS_TOKEN", CacheManger.ACCESS_TOKEN);
					String json = "{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"DATA\"}}"
							.replace("OPENID", fromUserName)
							.replace("DATA", "欢迎关注图:\n");
					JSONObject jsonStr = WeixinUtil.httpRequest(url, "POST", json);
					log.info(jsonStr.toString());

					XMLMessage xmlImageMessage = new XMLImageMessage(fromUserName, toUserName,
							RouteUrlPropertiesUtils.getString("attention.image.id"));
					String imageMessage = xmlImageMessage.toXML();
					out.print(imageMessage);
				} else if (eventType.equals(WXConstant.EVENT_TYPE_UNSUBSCRIBE)) {
					// 取消关注,用户接受不到我们发送的消息了,可以在这里记录用户取消关注的日志信息
				}
			}
		}
		out.close();
	}
}

微信推送信息类型:

public class WXConstant {
	/**
	 * 请求消息类型:事件
	 */
	public static final String REQ_MESSAGE_TYPE_EVENT = "event";
	/**
	 * 请求消息类型:事件
	 */
	public static final String REQ_MESSAGE_TYPE_TEXT = "text";
 
	/**
	 * 事件类型:subscribe(关注)
	 */
	public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";
 
	/**
	 * 事件类型:unsubscribe(取消关注)
	 */
	public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";
 
	/**
	 * 事件类型:CLICK(自定义菜单点击事件)
	 */
	public static final String EVENT_TYPE_CLICK = "CLICK";
	
	
	public static final String MESSAGE_SCAN="SCAN";//未关注公众号扫描二维码
	public static final String MESSAGE_TEXT="text";//文本
	public static final String MESSAGE_IMAGE="image";//图片
	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";//t跳转链接url
}

SHA1加密方法:

import java.security.MessageDigest;
import java.util.Arrays;

/**
 * SHA1 class
 *
 * 计算公众平台的消息签名接口.
 */
public class SHA1 {

	/**
	 * 用SHA1算法生成安全签名
	 * 
	 * @param token
	 *            票据
	 * @param timestamp
	 *            时间戳
	 * @param nonce
	 *            随机字符串
	 * @param encrypt
	 *            密文
	 * @return 安全签名
	 * @throws AesException
	 */
	public static String getSHA1(String token, String timestamp, String nonce, String encrypt) throws AesException {
		try {
			String[] array = new String[] { token, timestamp, nonce, encrypt };
			StringBuffer sb = new StringBuffer();
			// 字符串排序
			Arrays.sort(array);
			for (int i = 0; i < 4; i++) {
				sb.append(array[i]);
			}
			String str = sb.toString();
			// SHA1签名生成
			MessageDigest md = MessageDigest.getInstance("SHA-1");
			md.update(str.getBytes());
			byte[] digest = md.digest();

			StringBuffer hexstr = new StringBuffer();
			String shaHex = "";
			for (int i = 0; i < digest.length; i++) {
				shaHex = Integer.toHexString(digest[i] & 0xFF);
				if (shaHex.length() < 2) {
					hexstr.append(0);
				}
				hexstr.append(shaHex);
			}
			return hexstr.toString();
		} catch (Exception e) {
			e.printStackTrace();
			throw new AesException(AesException.ComputeSignatureError);
		}
	}
}

AesException

@SuppressWarnings("serial")
public class AesException extends Exception {

	public final static int OK = 0;
	public final static int ValidateSignatureError = -40001;
	public final static int ParseXmlError = -40002;
	public final static int ComputeSignatureError = -40003;
	public final static int IllegalAesKey = -40004;
	public final static int ValidateAppidError = -40005;
	public final static int EncryptAESError = -40006;
	public final static int DecryptAESError = -40007;
	public final static int IllegalBuffer = -40008;
	// public final static int EncodeBase64Error = -40009;
	// public final static int DecodeBase64Error = -40010;
	// public final static int GenReturnXmlError = -40011;

	private int code;

	private static String getMessage(int code) {
		switch (code) {
		case ValidateSignatureError:
			return "签名验证错误";
		case ParseXmlError:
			return "xml解析失败";
		case ComputeSignatureError:
			return "sha加密生成签名失败";
		case IllegalAesKey:
			return "SymmetricKey非法";
		case ValidateAppidError:
			return "appid校验失败";
		case EncryptAESError:
			return "aes加密失败";
		case DecryptAESError:
			return "aes解密失败";
		case IllegalBuffer:
			return "解密后得到的buffer非法";
		// case EncodeBase64Error:
		// return "base64加密错误";
		// case DecodeBase64Error:
		// return "base64解密错误";
		// case GenReturnXmlError:
		// return "xml生成失败";
		default:
			return null; // cannot be
		}
	}

	public int getCode() {
		return code;
	}

	AesException(int code) {
		super(getMessage(code));
		this.code = code;
	}

}

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
您好!关于Java微信公众号开发,我可以为您提供一些基本的信息和指导。 首先,微信公众号开发要有两种类型:订阅号和服务号。订阅号主要用于信息传达和内容分享,而服务号则更加注重业务功能和用户交互。 在Java开发中,您可以使用微信公众平台提供的开发接口进行开发。以下是一些常用的开发步骤和技术: 1. 注册微信公众平台账号:前往微信公众平台(https://mp.weixin.qq.com/)注册一个账号,并完成开发者认证。 2. 配置服务器:在公众号设置中,配置服务器URL和Token。Token用于验证消息的真实性。 3. 接入消息接口:通过开发接口,将用户发送的消息和事件推送到您的服务器。您可以使用Java框架(如Spring Boot)搭建服务器,并使用接口进行消息的处理和回复。 4. 实现功能:根据您的需求,可以实现一些常见的功能,如自动回复、菜单管理、用户管理、消息模板等。您可以使用Java的相关库和工具来简化开发过程。 5. 公众号运营:在开发完成后,可以进行公众号的运营和推广。您可以通过素材管理、群发消息、数据统计等功能来提升用户体验和运营效果。 需要注意的是,微信公众号开发涉及到用户隐私和信息安全,建议您在开发过程中遵守相关规定,并进行必要的数据加密和安全防护。 希望以上信息对您有所帮助!如果您有任何进一步的问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值