SpringBoot和微信二维码相关的部分

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq1782/article/details/75126593

水平有限 部分代码还是参考了网上大神的代码 主要是为了纪念一下自己的码代码过程 不足之处忘多多包涵。


1.springboot项目就不多说了,然后配置一下server.port=80,因为微信公众平台的服务器配置要求支持80或43端口,然后映射一下自己的127.0.0.1:80一下,就可以在本地调试事件推送了。映射方法:http://ngrok.ciqiuwl.cn/ 这是一位前辈提供的服务器,这样很方便的能在本地进行各种debug,大大方便了开发;



2.微信公众号的服务器配置要验证token的代码如下:因为这是一个get方法,后面的事件推送则是post,所以随便新建个controller 再在里面新建2个方法一个处理get用于token验证 一个用于post负责事件推送;
get部分代码如下:@api以及@apiOperation是swagger2,有了它就可以不用写开发文档了,很棒的发明!再推荐一个好用的 http://www.fangbei.org/tool/message 微信调试器 能方便调试各种接口。


@Api(tags = "微信相关模块")
@RestController
@RequestMapping(value = "/wx")
public class WXController extends BaseController {

	Logger logger = LoggerFactory.getLogger(WXController.class);

	@ApiOperation("get用于微信配置服务器的验证")
	@RequestMapping(value = "security", method = RequestMethod.GET)
	public void doGet(HttpServletRequest request, HttpServletResponse response,
			@RequestParam(value = "signature", required = true) String signature,
			@RequestParam(value = "timestamp", required = true) String timestamp,
			@RequestParam(value = "nonce", required = true) String nonce,
			@RequestParam(value = "echostr", required = true) String echostr) {
		try {
			if (SignUtil.checkSignature(signature, timestamp, nonce)) {
				PrintWriter out = response.getWriter();
				out.print(echostr);
				out.close();
			} else {
				logger.info("这里存在非法请求!");
			}
		} catch (Exception e) {
			logger.error("" + e.getMessage());
	}

        下面是验证签名的类,然后微信平台测试账号那里填上你之前用ngrok映射的域名/wx/security    token填你在下面接口里面设置的 看能否设置成功 不成功的话看127.0.0.1/wx/security 这个你能否成功访问 可能需要加上你的项目名称什么的 反正我是可以的。

package soke.home.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.apache.commons.codec.digest.DigestUtils;

public class SignUtil {

	// TODO 与接口配置信息中的 Token 要一致

	/** * 验证签名 * @param signature * @param timestamp * @param nonce * @return */
	public static boolean checkSignature(String signature, String timestamp, String nonce) {
		// 将token、timestamp、nonce三个参数进行字典序排序
		String[] arr = new String[] { WeixinUtil.token, timestamp, nonce }; 
		Arrays.sort(arr);
		StringBuilder content = new StringBuilder();
		for (int i = 0; i < arr.length; i++) {
			content.append(arr[i]);
		}
		MessageDigest md = null;
		String tmpStr = null;
		try {
			md = MessageDigest.getInstance("SHA-1");
			// 将三个参数字符串拼接成一个字符串进行 sha1 加密 byte[]
			byte[] digest = md.digest(content.toString().getBytes());
			tmpStr = byteToStr(digest);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		content = null;
		// 将 sha1 加密后的字符串可与 signature 对比,标识该请求来源于微信
		return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
	}

	/** * 将字节数组转换为十六进制字符串 * @param byteArray * @return */
	public static String byteToStr(byte[] byteArray) {
		String strDigest = "";
		for (int i = 0; i < byteArray.length; i++) {
			strDigest += byteToHexStr(byteArray[i]);
		}
		return strDigest;
	}

	/** * 将字节转换为十六进制字符串 * @param mByte * @return */
	private static String byteToHexStr(byte mByte) {
		char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
		char[] tempArr = new char[2];
		tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
		tempArr[1] = Digit[mByte & 0X0F];
		String s = new String(tempArr);
		return s;
	}

	/**
	 * 
	 * @param params
	 *            Map数组,里面需要 appid//appId mch_id//商户号 device_info//设备信息
	 *            body//商品描述 nonce_str//随机字符串
	 * @param key
	 * @return String(签名)
	 */
	public static String WeChatPay(Map<String, String> params, String key) {
		List<String> list = new ArrayList<String>(params.keySet());
		Collections.sort(list);
		StringBuffer sb = new StringBuffer();
		for (String keyVal : list) {
			sb.append(keyVal + "=" + params.get(keyVal) + "&");
		}
		sb.append("key=" + key);
//		System.err.println(sb.toString());
		return DigestUtils.md5Hex(sb.toString()).toUpperCase();
	}

	/**
	 * 获得随机字符串
	 * 
	 * @return
	 */
	public static String getNonceStr() {
		Random random = new Random();
		long val = random.nextLong();
		String res = DigestUtils.md5Hex(val + "yzx").toUpperCase();
		if (32 < res.length()) {
			return res.substring(0, 32);
		} else {
			return res;
		}
	}

}

    服务器配置完就可以进行推送事件处理了。。。第一次关注,再次关注,发送各种消息都会触发里面的各种条件,可以在里面进行各种逻辑处理,另外注意返回的hml格式的响应中createTime是和其余的返回字段不一样,所以需要进行额外的处理,这部分的代码也参考了网上前辈的;

	@ApiOperation("用于推送事件的回调")
	@Anonymous
	@RequestMapping(value = "security", method = RequestMethod.POST)
	/**
	 * 
	 * @param request
	 * @param response
	 * @throws IOException
	 */
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, DocumentException {
		// 将请求、响应的编码均设置为UTF-8(防止中文乱码)
		request.setCharacterEncoding("UTF-8");
		response.setCharacterEncoding("UTF-8");
		// 调用核心业务类接收消息、处理消息
		String respMessage = processRequest(request);
		// 响应消息
		PrintWriter out = response.getWriter();
		out.print(respMessage);
		out.flush();
		out.close();
	}

	private String processRequest(HttpServletRequest request) throws IOException, DocumentException {
		String respMessage = "", respContent = "", respContentBussiness = "";
		// xml请求解析
		Map<String, String> requestMap = WeixinUtil.parseXml(request, null);
		// 发送方帐号(open_id)
		String fromUserName = requestMap.get("FromUserName");
		// 公众帐号
		String toUserName = requestMap.get("ToUserName");
		// 消息类型
		String msgType = requestMap.get("MsgType");

		TextMessage textMessage = new TextMessage();
		// FromUserName 发送方帐号
		textMessage.setToUserName(fromUserName);
		// ToUserName 开发者微信号
		textMessage.setFromUserName(toUserName);
		// MsgType-消息类型
		textMessage.setMsgType(WeiXinConstants.RESP_MESSAGE_TYPE_TEXT);
		// CreateTime-消息创建时间-(整型)
		textMessage.setCreateTime(System.currentTimeMillis());

		if (msgType.equals(WeiXinConstants.REQ_MESSAGE_TYPE_TEXT)) {
			// 回复任何文字发送图文消息(这个设计,我也很绝望啊。。。)
			// 这里用枚举的设计会不会好一点
			respContent = WeixinUtil.getFocusOnPushTest(fromUserName, toUserName);
		} else if (msgType.equals(WeiXinConstants.REQ_MESSAGE_TYPE_IMAGE)) {
		} else if (msgType.equals(WeiXinConstants.REQ_MESSAGE_TYPE_LOCATION)) {
		} else if (msgType.equals(WeiXinConstants.REQ_MESSAGE_TYPE_LINK)) {
		} else if (msgType.equals(WeiXinConstants.REQ_MESSAGE_TYPE_VOICE)) {
		} else if (msgType.equals(WeiXinConstants.REQ_MESSAGE_TYPE_EVENT)) {
			String eventType = requestMap.get("Event");
			// 这里获取用户的基本信息
			JSONObject jsonObject = WeixinUtil.getUserInfoFromWX(fromUserName);
			String unionid = jsonObject.getString("unionid");
			String headimgurl = jsonObject.getString("headimgurl");

			// 更新頭像
			User user1 = User.findByWX(unionid);
			if (user1 != null) {
				if (!headimgurl.equals(user1.getAvatar())) {
					user1.setAvatar(headimgurl);
					user1.save();
				}
			}

			if (eventType.equals(WeiXinConstants.EVENT_TYPE_SUBSCRIBE)) {
				respContent = WeixinUtil.getFocusOnPushTest(fromUserName, toUserName);
				String eventKey = requestMap.get("EventKey");
				// 说明是带参数的二维码进入的
				if (eventKey != null) {
					// 第一次关注前面有这个需要截一下
					String id = requestMap.get("EventKey").replace("qrscene_", "");
					//内部逻辑
					respContentBussiness = WeixinUtil.join(id, request, fromUserName, respContentBussiness);
				}
			} else if (eventType.equals(WeiXinConstants.EVENT_TYPE_SCAN)) {
				
			} else if (eventType.equals(WeiXinConstants.EVENT_TYPE_UNSUBSCRIBE)) {
			
			} else if (eventType.equals(WeiXinConstants.EVENT_TYPE_CLICK)) {
			}
		}

		// 空白字符串
		String blank = " ";
		if (respContentBussiness != null && respContentBussiness != blank && respContentBussiness != "") {
			respContentBussiness = "<![CDATA[" + respContentBussiness + "]]>";
			textMessage.setContent(respContentBussiness);
			respMessage = WeixinUtil.objectToXml(textMessage);
		} else if (respContent != null && respContent != blank && respContent != "") {
			respMessage = respContent;
		}

		System.err.println("微信触发事件回调,传递过去的信息是:" + respMessage);
		return respMessage;
	}

下面的对xml的处理内容 解析微信传过来的xml内容 以及把自己的内容转换成xml文件传过去 以及一些基本常量和一些基本方法的配置(比如结合里面的获取二维码地址和ticket可以获取带参数的二维码 然后扫描就会触发post事件 会接收到传过去的secen_id 然后就可以对这个id进行惨无人道的操作)


package soke.home.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.security.KeyStore;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import com.alibaba.fastjson.JSONObject;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import com.typesafe.config.ConfigFactory;

import soke.common.util.GetPostUtil;
import soke.home.classes.domain.model.CpClass;
import soke.home.classes.domain.model.CpClassMember;
import soke.home.family.domain.model.CpFamily;
import soke.home.message.domain.model.CpMsg;
import soke.home.message.domain.model.CpMsgDnd;
import soke.home.message.domain.model.CpMsgInbox;
import soke.home.message.domain.model.Message;
import soke.home.message.domain.model.MessageManagerPool;
import soke.home.org.domain.model.OrgMember;
import soke.home.org.domain.model.Organization;
import soke.home.user.domain.model.User;
import soke.home.user.enums.JFTRole;
import soke.home.wx.annotation.XStreamCDATA;
import soke.home.wx.constants.WeiXinConstants;
import soke.home.wx.thread.HomeVisitThread;
import soke.memory.redis.RedisDb;

@SuppressWarnings("deprecation")
@Component
/**
 * 
 * @author 15293
 *
 */
public class WeixinUtil {
	static Logger logger = LoggerFactory.getLogger(WeixinUtil.class);

	/*-------------------------WX---------------------------*/

	/** appId 微信的正式环境 */
	public static String appID = ConfigFactory.load().getString("weixin.appId");
	public static String appsecret = ConfigFactory.load().getString("weixin.appsecret");
	/** 商品号 */
	public static String mch_id = ConfigFactory.load().getString("weixin.mchId");
	/** 付款回调地址 */
	public static String notify_url = ConfigFactory.load().getString("weixin.notifyUrl");
	/** 微信公众号Key */
	public static String key = ConfigFactory.load().getString("weixin.key");
	/** 微信公众号校验的字段 */
	public static String token = ConfigFactory.load().getString("weixin.token");
	/** 项目路径 **/
	public static String applyaddress = ConfigFactory.load().getString("weixin.applyaddress");
	/** 发送红包的证书路径 **/
	public static String redPaperPath = ConfigFactory.load().getString("wexin.redPaperPath");

	/**
	 * 获取微信的access_token(redis里面获取不到就自己去取)
	 * 
	 * @return String(null)
	 * 
	 **/
	public static String getAccessToken() {
		String accessToken = null;
		if (RedisDb.exists(WeiXinConstants.ACCESSTOKEN_IN_REDIS)) {
			accessToken = RedisDb.getString("access_token");
		}

		String aString = GetPostUtil.sendGet("https://api.weixin.qq.com/cgi-bin/token",
				"grant_type=client_credential&appid=" + appID + "&secret=" + appsecret);
		JSONObject jsonObject = JSONObject.parseObject(aString);

		if (jsonObject.get("access_token") != null) {
			accessToken = (String) jsonObject.get("access_token");
			RedisDb.setAccessToken("access_token", accessToken, WeiXinConstants.EXPIRETIME);
		} else {
			logger.error("access_token的获取有问题" + jsonObject);
		}

		return accessToken;
	}

	/**
	 * 获取生成临时二维码需要的ticket
	 * 
	 * 1.设置了过期时间为2592000---即30天 2.如果报40001(access_token无效)的错误
	 * 就移除Redis里面的access_token重新生成
	 * 
	 * @param l:传入的带参数的二维码里面存的参数值
	 * 
	 * @return String(null)
	 *
	 */
	public static String getTicket(long l) {
		String accessToken = getAccessToken();
		JSONObject jsonObject = JSONObject.parseObject(
				"{\"expire_seconds\":2592000,\"action_name\": \"QR_SCENE\", \"action_info\": {\"scene\": {\"scene_id\":"
						+ l + "}}}");
		String aString2 = GetPostUtil
				.post("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + accessToken, jsonObject);
		JSONObject jsonObject2 = JSONObject.parseObject(aString2);

		// 当出现access_token出现40001异常的时候 从redis里面移除
		String errcode = (String) jsonObject2.get("errcode");
		if (errcode != null && errcode.equals("40001")) {
			RedisDb.delString("access_token");
			accessToken = getAccessToken();
			GetPostUtil.post("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + accessToken, jsonObject);
		}

		String ticket = (String) jsonObject2.get("ticket");
		return ticket;
	}

	/**
	 * 解析微信发来的请求或者XML为键值对,方便取值(因为有request和xml2种情况 ,所以合并成一个接口,传入2个参数 )
	 * 
	 * @param request:requset请求
	 * @param xml:String的xml语句
	 * 
	 * @return HashMap<Sring,String>
	 * 
	 * @throws IOException
	 * @throws DocumentException
	 * 
	 */
	public static Map<String, String> parseXml(HttpServletRequest request, String xml)
			throws IOException, DocumentException {
		// 将解析结果存储在HashMap中
		Map<String, String> map = new HashMap<String, String>();
		InputStream inputStream = null;
		Document document = null;

		if (request != null) {
			inputStream = request.getInputStream();
			SAXReader reader = new SAXReader();
			document = reader.read(inputStream);
		}

		if (xml != null) {
			document = DocumentHelper.parseText(xml);
		}

		Element rootElement = document.getRootElement();
		ele2map(map, rootElement);
		if (inputStream != null) {
			inputStream.close();
			inputStream = null;
		}
		return map;
	}

	/**
	 * 解析xml文件
	 */
	static void ele2map(Map<String, String> map, Element ele) {
		// 获得当前节点的子节点
		List<Element> elements = ele.elements();
		if (elements.size() == 0) {
			// 没有子节点说明当前节点是叶子节点,直接取值即可
			if (ele.getText() != null) {
				map.put(ele.getName(), ele.getText());
			}
		} else if (elements.size() == 1) {
			// 只有一个子节点说明不用考虑list的情况,直接继续递归即可
			Map<String, String> tempMap = new HashMap<String, String>();
			ele2map(map, elements.get(0));
			if (tempMap.get(ele.getName()) != null) {
				map.put(ele.getName(), tempMap.get(ele.getName()));
			}
		} else {
			// 多个子节点的话就得考虑list的情况了,比如多个子节点有节点名称相同的
			// 构造一个map用来去重
			Map<String, String> tempMap = new HashMap<String, String>();
			for (Element element : elements) {
				tempMap.put(element.getName(), null);
			}
			Set<String> keySet = tempMap.keySet();
			for (String string : keySet) {
				Namespace namespace = elements.get(0).getNamespace();
				List<Element> elements2 = ele.elements(new QName(string, namespace));
				// 如果同名的数目大于1则表示要构建list 现在假设不可能重名
				if (elements2.size() > 1) {

				} else {
					// 同名的数量不大于1则直接递归去
					ele2map(map, elements2.get(0));
				}
			}
		}
	}

	/**
	 * 根据access和OpenId获取用户基本信息
	 * 
	 * @param openid
	 * 
	 * @return JsonObject(null)
	 */
	public static JSONObject getUserInfoFromWX(String openid) {
		if (openid == null) {
			return null;
		}

		String url = "https://api.weixin.qq.com/cgi-bin/user/info";
		String accessToken = getAccessToken();
		String info = GetPostUtil.sendGet(url, "access_token=" + accessToken + "&openid=" + openid + "&lang=zh_CN");
		JSONObject jsonObject = JSONObject.parseObject(info);
		return jsonObject;
	}

	/**
	 * 把object转换成xml对象
	 * 
	 * @param object
	 * 
	 * @return String
	 */
	public static String objectToXml(Object object) {
		XStream xstream = createXstream();
		xstream.alias("xml", object.getClass());
		return xstream.toXML(object);
	}

	/**
	 * 利用Xstream来把Object转换成xml文件(匿名内部类)
	 * 
	 * @return
	 */
	public static XStream createXstream() {
		return new XStream(new XppDriver() {

			@Override
			public HierarchicalStreamWriter createWriter(Writer out) {
				return new PrettyPrintWriter(out) {
					boolean cdata = false;
					Class<?> targetClass = null;

					@Override
					public void startNode(String name, @SuppressWarnings("rawtypes") Class clazz) {
						super.startNode(name, clazz);
						// 业务处理,对于用XStreamCDATA标记的Field,需要加上CDATA标签
						if (!"xml".equals(name)) {
							cdata = needCDATA(targetClass, name);
						} else {
							targetClass = clazz;
						}
					}

					@Override
					protected void writeText(QuickWriter writer, String text) {
						if (cdata) {
							writer.write("<![CDATA[");
							writer.write(text);
							writer.write("]]>");
						} else {
							writer.write(text);
						}
					}
				};
			}
		});
	}

	/**
	 * 循环往上面遍历,看域上面是否有注解
	 * 
	 * @param targetClass
	 * @param fieldAlias
	 * @return
	 */
	private static boolean needCDATA(Class<?> targetClass, String fieldAlias) {
		boolean cdata = false;
		cdata = existsCDATA(targetClass, fieldAlias);
		if (cdata) {
			return cdata;
		}
		Class<?> superClass = targetClass.getSuperclass();
		while (!superClass.equals(Object.class)) {
			cdata = existsCDATA(superClass, fieldAlias);
			if (cdata) {
				return cdata;
			}
			superClass = superClass.getClass().getSuperclass();
		}
		return false;
	}

	private static boolean existsCDATA(Class<?> clazz, String fieldAlias) {
		// 特例添加
		if ("MediaId".equals(fieldAlias)) {
			return true;
		}

		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			if (field.getAnnotation(XStreamCDATA.class) != null) {
				XStreamAlias xStreamAlias = field.getAnnotation(XStreamAlias.class);
				if (null != xStreamAlias) {
					if (fieldAlias.equals(xStreamAlias.value())) {
						return true;
					}
				} else {
					// 如果传入的xml节点的名称和@xstreamAlias的相等也返回true
					if (fieldAlias.equals(field.getName())) {
						return true;
					}
				}
			}
		}
		return false;
	}

	/**
	 * 判断是否是QQ表情
	 * 
	 * @param content
	 * @return
	 */
	public static boolean isQqFace(String content) {
		boolean result = false;

		// 判断QQ表情的正则表达式
		String qqfaceRegex = "/::\\)|/::~|/::B|/::\\||/:8-\\)|/::<|/::$|/::X|/::Z|/::'\\(|/::-\\||/::@|"
				+ "/::P|/::D|/::O|/::\\(|/::\\+|/:--b|/::Q|/::T|/:,@P|/:,@-D|/::d|/:,@o|/::g|/:\\|-\\)|"
				+ "/::!|/::L|/::>|/::,@|/:,@f|/::-S|/:\\?|/:,@x|/:,@@|/::8|/:,@!|/:!!!|/:xx|/:bye|/:wipe|"
				+ "/:dig|/:handclap|/:&-\\(|/:B-\\)|/:<@|/:@>|/::-O|/:>-\\||/:P-\\(|/::'\\||/:X-\\)|/::\\*|"
				+ "/:@x|/:8\\*|/:pd|/:<W>|/:beer|/:basketb|/:oo|/:coffee|/:eat|/:pig|/:rose|/:fade|/:showlove|"
				+ "/:heart|/:break|/:cake|/:li|/:bome|/:kn|/:footb|/:ladybug|/:shit|/:moon|/:sun|/:gift|/:hug|"
				+ "/:strong|/:weak|/:share|/:v|/:@\\)|/:jj|/:@@|/:bad|/:lvu|/:no|/:ok|/:love|/:<L>|/:jump|/:shake|"
				+ "/:<O>|/:circle|/:kotow|/:turn|/:skip|/:oY|/:#-0|/:hiphot|/:kiss|/:<&|/:&>"
				+ "|\\[Smart\\]|\\[Hey\\]|\\[Facepalm\\]|\\[Smirk\\]|\\[Concerned\\]|\\[Yeah!\\]|\\[Packet\\]|\\[Chick\\]";
		Pattern p = Pattern.compile(qqfaceRegex);
		Matcher m = p.matcher(content);
		if (m.matches()) {
			result = true;
		}
		return result;
	}

	
	/**
	 * 调起Js
	 * 
	 * @return
	 */
	public static String getJsSdkConfigTicket() {
		String ticket = null;
		if (RedisDb.exists("jsapi_ticket")) {
			ticket = RedisDb.getString("jsapi_ticket");
		}

		if (ticket != null) {
			System.err.println("jsapi_ticket是从Redis里面取得,值为:");
			return ticket;
		}

		String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";
		String accessToken = getAccessToken();
		String info = GetPostUtil.sendGet(url, "access_token=" + accessToken + "&type=jsapi");
		JSONObject jsonObject = JSONObject.parseObject(info);
		System.err.print("获取JsApiTicket的值:ticket是手动获取的:" + jsonObject);
		ticket = jsonObject.getString("ticket");
		RedisDb.setAccessToken("jsapi_ticket", ticket, WeiXinConstants.EXPIRETIME);
		return ticket;
	}

	/**
	 * 生成内部订单号
	 */
	public static String createOutTradeNo(Integer uid) {
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
		String date = LocalDateTime.now().format(formatter);
		Random random = new Random();
		String uuid = uid + "";
		int rannum = (int) (random.nextDouble() * (99999 - 10000 + 1)) + 10000;
		if (uid == null) {
			uuid = "00";
		} else if (uid < 10) {
			uuid = "0" + uid;
		}
		return date + uuid + rannum;
	}

	
	/**
	 * 因为微信授权的特殊性 同一code只能获取一次信息 所以用redis来处理一下;
	 * 
	 * @param code
	 *            微信网页授权码
	 * 
	 * @param openId
	 *            openId
	 */
	public static String opreateOpenId(String code, String openId) {
		if (code == null) {
			logger.info("WeixinUtil的opreateOpenId传入的code为null");
			return null;
		}

		if (openId != null) {
			RedisDb.setString(code, openId);
			return null;
		} else {
			openId = RedisDb.getString(code);
			return openId;
		}

	}

	/**
	 * @param mchId
	 *            ----商户Id
	 * 
	 * @param xml
	 *            ----包含签名的xml文件
	 * 
	 * @param url
	 *            ----需要post数据的url地址
	 * 
	 * @return String
	 * 
	 */
	public static String WxRedPaperSend(String mchId, String xml, String url) {
		try {
			KeyStore keyStore = KeyStore.getInstance("PKCS12");
			FileInputStream instream = new FileInputStream(new File(redPaperPath));
			try {
				keyStore.load(instream, mchId.toCharArray());
			} finally {
				instream.close();
			}

			// Trust own CA and all self-signed certs
			SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchId.toCharArray()).build();
			// Allow TLSv1 protocol only
			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" },
					null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
			CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
			StringBuffer result = new StringBuffer();
			try {
				HttpPost httpPost = new HttpPost(url);
				// 构造HttpClient的HttpPost请求
				httpPost.addHeader("Connection", "keep-alive");
				httpPost.addHeader("Accept", "*/*");
				httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
				httpPost.addHeader("Host", "api.mch.weixin.qq.com");
				httpPost.addHeader("X-Requested-With", "XMLHttpRequest");
				httpPost.addHeader("Cache-Control", "max-age=0");
				httpPost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
				httpPost.setEntity(new StringEntity(xml, "UTF-8"));
				CloseableHttpResponse response = httpclient.execute(httpPost);

				try {
					HttpEntity entity = response.getEntity();
					System.out.println(response.getStatusLine());
					if (entity != null) {
						System.out.println("Response content length: " + entity.getContentLength());
						BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
						String text;
						while ((text = bufferedReader.readLine()) != null) {
							result.append(text);
							result.append("\n");
						}
					}
					EntityUtils.consume(entity);
				} finally {
					response.close();
				}
			} finally {
				httpclient.close();
			}

			return result.toString();
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("发送现金红包的封装接口出错:" + e.getMessage());
			return null;
		}

	}

}



还有一个关于注解的类和文本信息类,注解主要是为了有的字段返回去的xml不加上><![CDATA[]]>的标识,文本信息类用于返回文本信息;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD })
public @interface XStreamCDATA {

}
import com.thoughtworks.xstream.annotations.XStreamAlias;


public class TextMessage {
	// 接收方帐号(收到的OpenID)
	@XStreamAlias("ToUserName")
	private String ToUserName;
	// 开发者微信号
	@XStreamAlias("FromUserName")
	private String FromUserName;
	// 消息创建时间 (整型)
	private long CreateTime;
	// 消息类型(text/music/news)
	@XStreamAlias("MsgType")
	private String MsgType;
	// 位0x0001被标志时,星标刚收到的消息

	@XStreamAlias("Context")
	private String Content;

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

	public String getContent() {
		return Content;
	}

	public void setContent(String content) {
		Content = content;
	}



}



顺便加上几个需要的注释(关于xml的),顺便吐槽一下:没有认证的话获取不到unionId,很坑,scene_str的话EventKey获取不到:因为有些代码是项目里面的逻辑调用,所以手动删了一点,希望不会报错哈哈。。。。无聊的话可以随便接个机器人来玩玩。。。。

<dependency>
			<groupId>org.dom4j</groupId>
			<artifactId>dom4j</artifactId>
			<version>2.0.1</version>
		</dependency>
		<dependency>
			<groupId>com.thoughtworks.xstream</groupId>
			<artifactId>xstream</artifactId>
			<version>1.4.10</version>
		</dependency>


猜你喜欢

转载自blog.csdn.net/qq1782/article/details/75126593
今日推荐