mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2026-03-10 00:13:40 +08:00
#193 增加小程序模块weixin-java-miniapp,支持小程序后台开发
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
package cn.binarywang.wx.miniapp.util.crypt;
|
||||
|
||||
import cn.binarywang.wx.miniapp.config.WxMaConfig;
|
||||
import me.chanjar.weixin.common.util.crypto.PKCS7Encoder;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.AlgorithmParameters;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
public class WxMaCryptUtils extends me.chanjar.weixin.common.util.crypto.WxCryptUtil {
|
||||
public WxMaCryptUtils(WxMaConfig config) {
|
||||
this.appidOrCorpid = config.getAppid();
|
||||
this.token = config.getToken();
|
||||
this.aesKey = Base64.decodeBase64(config.getAesKey() + "=");
|
||||
}
|
||||
|
||||
/**
|
||||
* AES解密
|
||||
*
|
||||
* @param encryptedData 消息密文
|
||||
* @param ivStr iv字符串
|
||||
*/
|
||||
public static String decrypt(String sessionKey, String encryptedData, String ivStr) {
|
||||
try {
|
||||
AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
|
||||
params.init(new IvParameterSpec(Base64.decodeBase64(ivStr)));
|
||||
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
|
||||
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(Base64.decodeBase64(sessionKey), "AES"), params);
|
||||
|
||||
return new String(PKCS7Encoder.decode(cipher.doFinal(Base64.decodeBase64(encryptedData))), StandardCharsets.UTF_8);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("AES解密失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package cn.binarywang.wx.miniapp.util.http;
|
||||
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaQrcode;
|
||||
import me.chanjar.weixin.common.bean.result.WxError;
|
||||
import me.chanjar.weixin.common.exception.WxErrorException;
|
||||
import me.chanjar.weixin.common.util.fs.FileUtils;
|
||||
import me.chanjar.weixin.common.util.http.RequestExecutor;
|
||||
import me.chanjar.weixin.common.util.http.RequestHttp;
|
||||
import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler;
|
||||
import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
public class QrCodeRequestExecutor implements RequestExecutor<File, WxMaQrcode> {
|
||||
protected RequestHttp<CloseableHttpClient, HttpHost> requestHttp;
|
||||
|
||||
public QrCodeRequestExecutor(RequestHttp requestHttp) {
|
||||
this.requestHttp = requestHttp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File execute(String uri, WxMaQrcode ticket) throws WxErrorException, IOException {
|
||||
HttpPost httpPost = new HttpPost(uri);
|
||||
if (requestHttp.getRequestHttpProxy() != null) {
|
||||
httpPost
|
||||
.setConfig(RequestConfig.custom()
|
||||
.setProxy(requestHttp.getRequestHttpProxy())
|
||||
.build()
|
||||
);
|
||||
}
|
||||
httpPost.setEntity(new StringEntity(ticket.toString()));
|
||||
|
||||
try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost);
|
||||
InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) {
|
||||
Header[] contentTypeHeader = response.getHeaders("Content-Type");
|
||||
if (contentTypeHeader != null && contentTypeHeader.length > 0
|
||||
&& ContentType.TEXT_PLAIN.getMimeType().equals(contentTypeHeader[0].getValue())) {
|
||||
String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
|
||||
throw new WxErrorException(WxError.fromJson(responseContent));
|
||||
}
|
||||
|
||||
return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg");
|
||||
} finally {
|
||||
httpPost.releaseConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package cn.binarywang.wx.miniapp.util.json;
|
||||
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
public class WxMaGsonBuilder {
|
||||
private static final GsonBuilder INSTANCE = new GsonBuilder();
|
||||
|
||||
static {
|
||||
INSTANCE.disableHtmlEscaping();
|
||||
INSTANCE.registerTypeAdapter(WxMaKefuMessage.class, new WxMaKefuMessageGsonAdapter());
|
||||
INSTANCE.registerTypeAdapter(WxMaTemplateMessage.class, new WxMaTemplateMessageGsonAdapter());
|
||||
}
|
||||
|
||||
public static Gson create() {
|
||||
return INSTANCE.create();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved.
|
||||
*
|
||||
* This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended
|
||||
* only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction
|
||||
* arose from modification of the original source, or other redistribution of this source
|
||||
* is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD.
|
||||
*/
|
||||
package cn.binarywang.wx.miniapp.util.json;
|
||||
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage;
|
||||
import cn.binarywang.wx.miniapp.constant.WxMaConstants;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
public class WxMaKefuMessageGsonAdapter implements JsonSerializer<WxMaKefuMessage> {
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(WxMaKefuMessage message, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject messageJson = new JsonObject();
|
||||
messageJson.addProperty("touser", message.getToUser());
|
||||
messageJson.addProperty("msgtype", message.getMsgType());
|
||||
|
||||
if (WxMaConstants.KefuMsgType.TEXT.equals(message.getMsgType())) {
|
||||
JsonObject text = new JsonObject();
|
||||
text.addProperty("content", message.getContent());
|
||||
messageJson.add("text", text);
|
||||
}
|
||||
|
||||
if (WxMaConstants.KefuMsgType.IMAGE.equals(message.getMsgType())) {
|
||||
JsonObject image = new JsonObject();
|
||||
image.addProperty("media_id", message.getMediaId());
|
||||
messageJson.add("image", image);
|
||||
}
|
||||
|
||||
return messageJson;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package cn.binarywang.wx.miniapp.util.json;
|
||||
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
public class WxMaTemplateMessageGsonAdapter implements JsonSerializer<WxMaTemplateMessage> {
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(WxMaTemplateMessage message, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject messageJson = new JsonObject();
|
||||
messageJson.addProperty("touser", message.getToUser());
|
||||
messageJson.addProperty("template_id", message.getTemplateId());
|
||||
if (message.getPage() != null) {
|
||||
messageJson.addProperty("page", message.getPage());
|
||||
}
|
||||
|
||||
if (message.getFormId() != null) {
|
||||
messageJson.addProperty("form_id", message.getFormId());
|
||||
}
|
||||
|
||||
if (message.getPage() != null) {
|
||||
messageJson.addProperty("page", message.getPage());
|
||||
}
|
||||
|
||||
if (message.getColor() != null) {
|
||||
messageJson.addProperty("color", message.getColor());
|
||||
}
|
||||
|
||||
if (message.getEmphasisKeyword() != null) {
|
||||
messageJson.addProperty("emphasis_keyword", message.getEmphasisKeyword());
|
||||
}
|
||||
|
||||
JsonObject data = new JsonObject();
|
||||
messageJson.add("data", data);
|
||||
|
||||
if (message.getData() == null) {
|
||||
return messageJson;
|
||||
}
|
||||
|
||||
for (WxMaTemplateMessage.Data datum : message.getData()) {
|
||||
JsonObject dataJson = new JsonObject();
|
||||
dataJson.addProperty("value", datum.getValue());
|
||||
if (datum.getColor() != null) {
|
||||
dataJson.addProperty("color", datum.getColor());
|
||||
}
|
||||
data.add(datum.getName(), dataJson);
|
||||
}
|
||||
|
||||
return messageJson;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package cn.binarywang.wx.miniapp.util.xml;
|
||||
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaMessage;
|
||||
import com.thoughtworks.xstream.XStream;
|
||||
import me.chanjar.weixin.common.util.xml.XStreamInitializer;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
public class XStreamTransformer {
|
||||
private static final Map<Class<?>, XStream> CLASS_2_XSTREAM_INSTANCE = new HashMap<>();
|
||||
|
||||
static {
|
||||
registerClass(WxMaMessage.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* xml -> pojo
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T fromXml(Class<T> clazz, String xml) {
|
||||
T object = (T) CLASS_2_XSTREAM_INSTANCE.get(clazz).fromXML(xml);
|
||||
return object;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T fromXml(Class<T> clazz, InputStream is) {
|
||||
T object = (T) CLASS_2_XSTREAM_INSTANCE.get(clazz).fromXML(is);
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* pojo -> xml
|
||||
*/
|
||||
public static <T> String toXml(Class<T> clazz, T object) {
|
||||
return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册扩展消息的解析器
|
||||
*
|
||||
* @param clz 类型
|
||||
* @param xStream xml解析器
|
||||
*/
|
||||
private static void register(Class<?> clz, XStream xStream) {
|
||||
CLASS_2_XSTREAM_INSTANCE.put(clz, xStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* 会自动注册该类及其子类
|
||||
*
|
||||
* @param clz 要注册的类
|
||||
*/
|
||||
private static void registerClass(Class<?> clz) {
|
||||
XStream xstream = XStreamInitializer.getInstance();
|
||||
xstream.processAnnotations(clz);
|
||||
xstream.processAnnotations(getInnerClasses(clz));
|
||||
if (clz.equals(WxMaMessage.class)) {
|
||||
// 操蛋的微信,模板消息推送成功的消息是MsgID,其他消息推送过来是MsgId
|
||||
xstream.aliasField("MsgID", WxMaMessage.class, "msgId");
|
||||
}
|
||||
|
||||
register(clz, xstream);
|
||||
}
|
||||
|
||||
private static Class<?>[] getInnerClasses(Class<?> clz) {
|
||||
Class<?>[] innerClasses = clz.getClasses();
|
||||
if (innerClasses == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<Class<?>> result = new ArrayList<>();
|
||||
result.addAll(Arrays.asList(innerClasses));
|
||||
for (Class<?> inner : innerClasses) {
|
||||
Class<?>[] innerClz = getInnerClasses(inner);
|
||||
if (innerClz == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result.addAll(Arrays.asList(innerClz));
|
||||
}
|
||||
|
||||
return result.toArray(new Class<?>[0]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user