diff --git a/.gitignore b/.gitignore
index 6143e53..efffed2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,3 +20,7 @@
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
+
+.idea
+*/target/*
+*.iml
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..df95792
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,112 @@
+
+
+ 4.0.0
+
+ com.hotlcc
+ wechat4j
+ 1.0-SNAPSHOT
+
+ wechat4j
+ Wechat client for Java.
+
+
+ UTF-8
+ UTF-8
+ 1.7
+ 1.7
+ 1.7
+
+
+
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.3
+
+
+ org.apache.httpcomponents
+ httpmime
+ 4.5
+
+
+
+ com.alibaba
+ fastjson
+ 1.2.31
+
+
+
+ org.apache.commons
+ commons-lang3
+ 3.0
+
+
+
+ org.slf4j
+ slf4j-api
+ 1.7.25
+
+
+ ch.qos.logback
+ logback-classic
+ 1.2.3
+
+
+
+ com.vdurmont
+ emoji-java
+ 3.2.0
+
+
+
+ org.antlr
+ ST4
+ 4.0.8
+ compile
+
+
+
+ junit
+ junit
+ 4.12
+
+
+
+ com.google.zxing
+ javase
+ 3.3.3
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ ${java.version}
+ ${java.version}
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+
+ ${project.build.sourceEncoding}
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+ true
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/hotlcc/wechat4j/Wechat.java b/src/main/java/com/hotlcc/wechat4j/Wechat.java
new file mode 100644
index 0000000..c206707
--- /dev/null
+++ b/src/main/java/com/hotlcc/wechat4j/Wechat.java
@@ -0,0 +1,44 @@
+package com.hotlcc.wechat4j;
+
+import com.hotlcc.wechat4j.api.WebWeixinApi;
+import org.apache.http.client.CookieStore;
+import org.apache.http.client.HttpClient;
+import org.apache.http.impl.client.BasicCookieStore;
+import org.apache.http.impl.client.HttpClients;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 微信客户端
+ *
+ * @author Allen
+ */
+public class Wechat {
+ private static Logger logger = LoggerFactory.getLogger(Wechat.class);
+
+ private CookieStore cookieStore;
+ private HttpClient httpClient;
+
+ private WebWeixinApi webWeixinApi;
+
+ public void setWebWeixinApi(WebWeixinApi webWeixinApi) {
+ this.webWeixinApi = webWeixinApi;
+ }
+
+ public Wechat(CookieStore cookieStore) {
+ this.cookieStore = cookieStore;
+ this.httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
+ }
+
+ public Wechat() {
+ this.cookieStore = new BasicCookieStore();
+ this.httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
+ }
+
+ /**
+ * 自动登录
+ */
+ public void autoLogin() {
+
+ }
+}
diff --git a/src/main/java/com/hotlcc/wechat4j/api/WebWeixinApi.java b/src/main/java/com/hotlcc/wechat4j/api/WebWeixinApi.java
new file mode 100644
index 0000000..bafe99f
--- /dev/null
+++ b/src/main/java/com/hotlcc/wechat4j/api/WebWeixinApi.java
@@ -0,0 +1,582 @@
+package com.hotlcc.wechat4j.api;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.hotlcc.wechat4j.util.PropertiesUtil;
+import com.hotlcc.wechat4j.util.StringUtil;
+import com.hotlcc.wechat4j.util.WechatUtil;
+import org.apache.http.*;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+import org.json.XML;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.stringtemplate.v4.ST;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * web微信接口封装
+ *
+ * @author Allen
+ */
+@SuppressWarnings("Duplicates")
+public class WebWeixinApi {
+ private static Logger logger = LoggerFactory.getLogger(WebWeixinApi.class);
+
+ private static Pattern PATTERN_UUID_1 = Pattern.compile("window.QRLogin.code = (\\d+);");
+ private static Pattern PATTERN_UUID_2 = Pattern.compile("window.QRLogin.code = (\\d+); window.QRLogin.uuid = \"(\\S+?)\";");
+ private static Pattern PATTERN_REDIRECT_URI_1 = Pattern.compile("window.code=(\\d+);");
+ private static Pattern PATTERN_REDIRECT_URI_2 = Pattern.compile("window.code=(\\d+);\\s*window.redirect_uri=\"(\\S+?)\";");
+
+ /**
+ * 获取微信uuid
+ */
+ public JSONObject getWxUuid(HttpClient httpClient) {
+ String url = new ST(PropertiesUtil.getProperty("webwx-url.uuid_url"))
+ .add("appid", PropertiesUtil.getProperty("webwx.appid"))
+ .add("_", System.currentTimeMillis())
+ .render();
+
+ HttpGet httpGet = new HttpGet(url);
+ httpGet.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent"));
+ httpGet.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build());
+
+ JSONObject result = new JSONObject();
+
+ try {
+ HttpResponse response = httpClient.execute(httpGet);
+ if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
+ throw new RuntimeException("请求错误");
+ }
+
+ HttpEntity entity = response.getEntity();
+ String res = EntityUtils.toString(entity);
+
+ Matcher matcher = PATTERN_UUID_1.matcher(res);
+ if (!matcher.find()) {
+ throw new RuntimeException("获取登录uuid失败");
+ }
+
+ String code = matcher.group(1);
+ result.put("code", code);
+ if (!"200".equals(code)) {
+ result.put("code", code);
+ result.put("msg", "获取登录uuid失败,请确认appid是否有效");
+ return result;
+ }
+
+ matcher = PATTERN_UUID_2.matcher(res);
+ if (!matcher.find()) {
+ throw new RuntimeException("获取登录uuid失败");
+ }
+
+ String uuid = matcher.group(2);
+ result.put("uuid", uuid);
+ if (StringUtil.isEmpty(uuid)) {
+ throw new RuntimeException("获取登录uuid失败");
+ }
+
+ return result;
+ } catch (IOException e) {
+ logger.error("获取登录uuid异常", e);
+ result.put("code", "-1");
+ result.put("msg", "获取登录uuid异常");
+ return result;
+ }
+ }
+
+ /**
+ * 获取二维码
+ *
+ * @param uuid
+ */
+ public JSONObject getQR(HttpClient httpClient,
+ String uuid) {
+ String url = new ST(PropertiesUtil.getProperty("webwx-url.qrcode_url"))
+ .add("uuid", uuid)
+ .render();
+
+ HttpGet httpGet = new HttpGet(url);
+ httpGet.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent"));
+ httpGet.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build());
+
+ JSONObject result = new JSONObject();
+
+ try {
+ HttpResponse response = httpClient.execute(httpGet);
+ if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
+ throw new RuntimeException("请求错误");
+ }
+
+ HttpEntity entity = response.getEntity();
+ byte[] data = EntityUtils.toByteArray(entity);
+ if (data == null || data.length <= 0) {
+ throw new RuntimeException("获取二维码失败");
+ }
+
+ result.put("code", "200");
+ result.put("data", data);
+ return result;
+ } catch (IOException e) {
+ logger.error("获取二维码异常", e);
+ result.put("code", "-1");
+ result.put("msg", "获取二维码异常");
+ return result;
+ }
+ }
+
+ /**
+ * 获取跳转uri(等待扫码认证)
+ *
+ * @return
+ */
+ public JSONObject getRedirectUri(HttpClient httpClient,
+ String uuid) {
+ long millis = System.currentTimeMillis();
+ String url = new ST(PropertiesUtil.getProperty("webwx-url.redirect_uri"))
+ .add("uuid", uuid)
+ .add("r", millis / 1252L)
+ .add("_", millis)
+ .render();
+
+ HttpGet httpGet = new HttpGet(url);
+ httpGet.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent"));
+ httpGet.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build());
+
+ JSONObject result = new JSONObject();
+
+ try {
+ HttpResponse response = httpClient.execute(httpGet);
+ if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
+ throw new RuntimeException("请求错误");
+ }
+
+ HttpEntity entity = response.getEntity();
+ String res = EntityUtils.toString(entity);
+
+ Matcher matcher = PATTERN_REDIRECT_URI_1.matcher(res);
+ if (!matcher.find()) {
+ throw new RuntimeException("获取跳转uri失败");
+ }
+
+ String code = matcher.group(1);
+ result.put("code", code);
+ if ("408".equals(code)) {
+ result.put("msg", "请扫描二维码");
+ } else if ("400".equals(code)) {
+ result.put("msg", "二维码失效");
+ } else if ("201".equals(code)) {
+ result.put("msg", "请在手机上点击确认");
+ } else if ("200".equals(code)) {
+ matcher = PATTERN_REDIRECT_URI_2.matcher(res);
+ if (!matcher.find()) {
+ throw new RuntimeException("获取跳转uri失败");
+ }
+ result.put("msg", "手机确认成功");
+ result.put("redirectUri", matcher.group(2));
+ } else {
+ result.put("msg", "扫码失败");
+ }
+
+ return result;
+ } catch (IOException e) {
+ logger.error("获取跳转uri异常", e);
+ result.put("code", "-3");
+ result.put("msg", "获取跳转uri异常");
+ return result;
+ }
+ }
+
+ /**
+ * 获取登录认证码
+ * 此方法执行后,其它web端微信、pc端都会下线
+ */
+ public JSONObject getLoginCode(HttpClient httpClient,
+ String redirectUri) {
+ String url = new ST(PropertiesUtil.getProperty("webwx-url.newlogin_url"))
+ .add("redirectUri", redirectUri)
+ .render();
+
+ HttpGet httpGet = new HttpGet(url);
+ httpGet.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent"));
+ httpGet.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build());
+
+ JSONObject result = new JSONObject();
+
+ try {
+ HttpResponse response = httpClient.execute(httpGet);
+ if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
+ throw new RuntimeException("请求错误");
+ }
+
+ HttpEntity entity = response.getEntity();
+ String res = EntityUtils.toString(entity);
+
+ JSONObject json = JSONObject.parseObject(XML.toJSONObject(res).toString()).getJSONObject("error");
+ result.putAll(json);
+ result.put("msg", result.getString("message"));
+ if (result.getIntValue("ret") == 0) {
+ result.put("code", "200");
+ }
+
+ return result;
+ } catch (IOException e) {
+ logger.error("获取登录认证码异常", e);
+ result.put("code", "-1");
+ result.put("msg", "获取登录认证码异常");
+ return result;
+ }
+ }
+
+ /**
+ * 退出登录
+ */
+ public void logout(HttpClient httpClient,
+ String wxsid,
+ String skey,
+ String wxuin) {
+ //type=0
+ String url = new ST(PropertiesUtil.getProperty("webwx-url.logout_url"))
+ .add("type", 0)
+ .add("skey", StringUtil.encodeURL(skey, "UTF-8"))
+ .render();
+
+ HttpPost httpPost = new HttpPost(url);
+ httpPost.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent"));
+ httpPost.setHeader("Content-type", ContentType.APPLICATION_FORM_URLENCODED.toString());
+
+ List pairList = new ArrayList<>();
+ pairList.add(new BasicNameValuePair("sid", wxsid));
+ pairList.add(new BasicNameValuePair("uin", wxuin));
+
+ try {
+ HttpEntity paramEntity = new UrlEncodedFormEntity(pairList);
+ httpPost.setEntity(paramEntity);
+
+ httpClient.execute(httpPost);
+ } catch (IOException e) {
+ logger.error("退出登录异常", e);
+ }
+
+ //type=1
+ String url1 = new ST(PropertiesUtil.getProperty("webwx-url.logout_url"))
+ .add("type", 1)
+ .add("skey", StringUtil.encodeURL(skey, "UTF-8"))
+ .render();
+
+ HttpPost httpPost1 = new HttpPost(url1);
+ httpPost.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent"));
+ httpPost.setHeader("Content-type", ContentType.APPLICATION_FORM_URLENCODED.toString());
+
+ try {
+ HttpEntity paramEntity = new UrlEncodedFormEntity(pairList);
+ httpPost.setEntity(paramEntity);
+
+ httpClient.execute(httpPost1);
+ } catch (IOException e) {
+ logger.error("退出登录异常", e);
+ }
+ }
+
+ /**
+ * 数据初始化
+ */
+ public JSONObject webWeixinInit(HttpClient httpClient,
+ String passticket,
+ String wxsid,
+ String skey,
+ String wxuin) {
+ String url = new ST(PropertiesUtil.getProperty("webwx-url.webwxinit_url"))
+ .add("pass_ticket", passticket)
+ .add("r", System.currentTimeMillis() / 1252L)
+ .render();
+
+ HttpPost httpPost = new HttpPost(url);
+ httpPost.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent"));
+ httpPost.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
+
+ JSONObject paramJson = new JSONObject();
+ paramJson.put("BaseRequest", WechatUtil.createBaseRequest(wxsid, skey, wxuin));
+ HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8);
+ httpPost.setEntity(paramEntity);
+
+ try {
+ HttpResponse response = httpClient.execute(httpPost);
+ if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
+ throw new RuntimeException("请求错误");
+ }
+
+ HttpEntity entity = response.getEntity();
+ String res = EntityUtils.toString(entity, Consts.UTF_8);
+
+ return JSONObject.parseObject(res);
+ } catch (IOException e) {
+ logger.error("数据初始化异常", e);
+ return null;
+ }
+ }
+
+ /**
+ * 开启消息状态通知
+ *
+ * @return
+ */
+ public JSONObject statusNotify(HttpClient httpClient,
+ String passticket,
+ String wxsid,
+ String skey,
+ String wxuin,
+ String loginUserName) {
+ String url = new ST(PropertiesUtil.getProperty("webwx-url.statusnotify_url"))
+ .add("pass_ticket", passticket)
+ .render();
+
+ HttpPost httpPost = new HttpPost(url);
+ httpPost.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent"));
+ httpPost.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
+
+ JSONObject paramJson = new JSONObject();
+ paramJson.put("BaseRequest", WechatUtil.createBaseRequest(wxsid, skey, wxuin));
+ paramJson.put("ClientMsgId", System.currentTimeMillis());
+ paramJson.put("Code", 3);
+ paramJson.put("FromUserName", loginUserName);
+ paramJson.put("ToUserName", loginUserName);
+ HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8);
+ httpPost.setEntity(paramEntity);
+
+ try {
+ HttpResponse response = httpClient.execute(httpPost);
+ if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
+ throw new RuntimeException("请求错误");
+ }
+
+ HttpEntity entity = response.getEntity();
+ String res = EntityUtils.toString(entity, Consts.UTF_8);
+
+ return JSONObject.parseObject(res);
+ } catch (IOException e) {
+ logger.error("开启消息状态通知异常", e);
+ return null;
+ }
+ }
+
+ /**
+ * 服务端状态同步心跳
+ */
+ public JSONObject syncCheck(HttpClient httpClient,
+ String wxsid,
+ String skey,
+ String wxuin,
+ JSONArray SyncKeyList) {
+ long millis = System.currentTimeMillis();
+ String url = new ST(PropertiesUtil.getProperty("webwx-url.synccheck_url"))
+ .add("r", millis)
+ .add("skey", StringUtil.encodeURL(skey, "UTF-8"))
+ .add("sid", wxsid)
+ .add("uin", wxuin)
+ .add("deviceid", WechatUtil.createDeviceID())
+ .add("synckey", StringUtil.encodeURL(WechatUtil.syncKeyListToString(SyncKeyList), "UTF-8"))
+ .add("_", millis)
+ .render();
+
+ HttpGet httpGet = new HttpGet(url);
+ httpGet.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent"));
+ httpGet.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build());
+
+ try {
+ HttpResponse response = httpClient.execute(httpGet);
+ if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
+ throw new RuntimeException("请求错误");
+ }
+
+ HttpEntity entity = response.getEntity();
+ String res = EntityUtils.toString(entity);
+
+ String regExp = "window.synccheck=\\{retcode:\"(\\d+)\",selector:\"(\\d+)\"}";
+ Matcher matcher = Pattern.compile(regExp).matcher(res);
+ if (!matcher.find()) {
+ throw new RuntimeException("服务端状态同步失败");
+ }
+
+ JSONObject result = new JSONObject();
+ result.put("retcode", matcher.group(1));
+ result.put("selector", matcher.group(2));
+
+ return result;
+ } catch (IOException e) {
+ logger.error("服务端状态同步异常", e);
+ return null;
+ }
+ }
+
+ /**
+ * 获取全部联系人列表
+ */
+ public JSONObject getContact(HttpClient httpClient,
+ String passticket,
+ String skey) {
+ String url = new ST(PropertiesUtil.getProperty("webwx-url.getcontact_url"))
+ .add("pass_ticket", StringUtil.encodeURL(passticket, "UTF-8"))
+ .add("r", System.currentTimeMillis())
+ .add("skey", StringUtil.encodeURL(skey, "UTF-8"))
+ .render();
+
+ HttpGet httpGet = new HttpGet(url);
+ httpGet.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent"));
+ httpGet.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build());
+
+ try {
+ HttpResponse response = httpClient.execute(httpGet);
+ if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
+ throw new RuntimeException("请求错误");
+ }
+
+ HttpEntity entity = response.getEntity();
+ String res = EntityUtils.toString(entity);
+
+ return JSONObject.parseObject(res);
+ } catch (IOException e) {
+ logger.error("获取全部联系人列表异常", e);
+ return null;
+ }
+ }
+
+ /**
+ * 批量获取指定用户信息
+ */
+ public JSONObject batchGetContact(HttpClient httpClient,
+ String passticket,
+ String wxsid,
+ String skey,
+ String wxuin,
+ JSONArray batchContactList) {
+ String url = new ST(PropertiesUtil.getProperty("webwx-url.batchgetcontact_url"))
+ .add("pass_ticket", StringUtil.encodeURL(passticket, "UTF-8"))
+ .add("r", System.currentTimeMillis())
+ .render();
+
+ HttpPost httpPost = new HttpPost(url);
+ httpPost.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent"));
+ httpPost.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
+
+ JSONObject paramJson = new JSONObject();
+ paramJson.put("BaseRequest", WechatUtil.createBaseRequest(wxsid, skey, wxuin));
+ paramJson.put("Count", batchContactList.size());
+ paramJson.put("List", batchContactList);
+ HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8);
+ httpPost.setEntity(paramEntity);
+
+ try {
+ HttpResponse response = httpClient.execute(httpPost);
+ if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
+ throw new RuntimeException("请求错误");
+ }
+
+ HttpEntity entity = response.getEntity();
+ String res = EntityUtils.toString(entity);
+
+ return JSONObject.parseObject(res);
+ } catch (IOException e) {
+ logger.error("批量获取指定联系人信息异常", e);
+ return null;
+ }
+ }
+
+ /**
+ * 从服务端拉取新消息
+ */
+ public JSONObject pullNewMsg(HttpClient httpClient,
+ String passticket,
+ String wxsid,
+ String skey,
+ String wxuin,
+ JSONObject SyncKey) {
+ String url = new ST(PropertiesUtil.getProperty("webwx-url.webwxsync_url"))
+ .add("skey", skey)
+ .add("sid", wxsid)
+ .add("pass_ticket", passticket)
+ .render();
+
+ HttpPost httpPost = new HttpPost(url);
+ httpPost.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent"));
+ httpPost.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
+
+ JSONObject paramJson = new JSONObject();
+ paramJson.put("BaseRequest", WechatUtil.createBaseRequest(wxsid, skey, wxuin));
+ paramJson.put("SyncKey", SyncKey);
+ HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8);
+ httpPost.setEntity(paramEntity);
+
+ try {
+ HttpResponse response = httpClient.execute(httpPost);
+ if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
+ throw new RuntimeException("请求错误");
+ }
+
+ HttpEntity entity = response.getEntity();
+ String res = EntityUtils.toString(entity, Consts.UTF_8);
+
+ return JSONObject.parseObject(res);
+ } catch (IOException e) {
+ logger.error("开启消息状态通知异常", e);
+ return null;
+ }
+ }
+
+ /**
+ * 发送消息
+ */
+ public JSONObject sendMsg(HttpClient httpClient,
+ String passticket,
+ String wxsid,
+ String skey,
+ String wxuin,
+ String Content,
+ int Type,
+ String FromUserName,
+ String ToUserName) {
+ String url = new ST(PropertiesUtil.getProperty("webwx-url.webwxsendmsg_url"))
+ .add("pass_ticket", passticket)
+ .render();
+
+ HttpPost httpPost = new HttpPost(url);
+ httpPost.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent"));
+ httpPost.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
+
+ JSONObject paramJson = new JSONObject();
+ paramJson.put("BaseRequest", WechatUtil.createBaseRequest(wxsid, skey, wxuin));
+ paramJson.put("Msg", WechatUtil.createSendMsg(Content, Type, FromUserName, ToUserName));
+ paramJson.put("Scene", 0);
+ HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8);
+ httpPost.setEntity(paramEntity);
+
+ try {
+ HttpResponse response = httpClient.execute(httpPost);
+ if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
+ throw new RuntimeException("请求错误");
+ }
+
+ HttpEntity entity = response.getEntity();
+ String res = EntityUtils.toString(entity, Consts.UTF_8);
+
+ JSONObject result = JSONObject.parseObject(res);
+
+ return result;
+ } catch (IOException e) {
+ logger.error("开启消息状态通知异常", e);
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/com/hotlcc/wechat4j/util/PropertiesUtil.java b/src/main/java/com/hotlcc/wechat4j/util/PropertiesUtil.java
new file mode 100644
index 0000000..75a50a7
--- /dev/null
+++ b/src/main/java/com/hotlcc/wechat4j/util/PropertiesUtil.java
@@ -0,0 +1,56 @@
+package com.hotlcc.wechat4j.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+public final class PropertiesUtil {
+ private static Logger logger = LoggerFactory.getLogger(PropertiesUtil.class);
+
+ private PropertiesUtil() {
+ }
+
+ private static final Properties prop = new Properties();
+
+ static {
+ loadProperties(new String[]{
+ "config/app.properties",
+ "config/webwx-url.properties"
+ });
+ }
+
+ private static void loadProperties(String[] paths) {
+ if (paths == null) {
+ return;
+ }
+
+ for (String path : paths) {
+ InputStream is = null;
+ try {
+ is = PropertiesUtil.class.getClassLoader().getResourceAsStream(path);
+ prop.load(is);
+ } catch (Exception e) {
+ logger.error("Loading properties file \"" + path + "\" error.", e);
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+
+ public static String getProperty(String key) {
+ return prop.getProperty(key);
+ }
+
+ public static String getProperty(String key, String defaultValue) {
+ return prop.getProperty(key, defaultValue);
+ }
+}
diff --git a/src/main/java/com/hotlcc/wechat4j/util/QRCodeUtil.java b/src/main/java/com/hotlcc/wechat4j/util/QRCodeUtil.java
new file mode 100644
index 0000000..c9ac534
--- /dev/null
+++ b/src/main/java/com/hotlcc/wechat4j/util/QRCodeUtil.java
@@ -0,0 +1,230 @@
+package com.hotlcc.wechat4j.util;
+
+import com.google.zxing.Binarizer;
+import com.google.zxing.LuminanceSource;
+import com.google.zxing.NotFoundException;
+import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
+import com.google.zxing.common.BitMatrix;
+import com.google.zxing.common.HybridBinarizer;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 二维码工具类
+ *
+ * @author Allen
+ */
+public final class QRCodeUtil {
+ private QRCodeUtil() {
+ }
+
+ /**
+ * 从BitMatrix中得到boolean矩阵(不去除周围空白部分)
+ *
+ * @return
+ */
+ private static boolean[][] toBoolMatrix(BitMatrix matrix) {
+ return toBoolMatrix(matrix, false);
+ }
+
+ /**
+ * 从BitMatrix中得到boolean矩阵
+ *
+ * @param matrix
+ * @param noMargin 是否去除周围空白
+ * @return
+ */
+ private static boolean[][] toBoolMatrix(BitMatrix matrix, boolean noMargin) {
+ int width = matrix.getWidth();
+ int height = matrix.getHeight();
+ int top = 0, left = 0, bottom = 0, right = 0;
+ if (noMargin) {
+ int[] tl = matrix.getTopLeftOnBit();
+ top = tl[0];
+ left = tl[1];
+ int[] br = matrix.getBottomRightOnBit();
+ bottom = height - br[0] - 1;
+ right = width - br[1] - 1;
+ }
+ boolean[][] m = new boolean[height - top - bottom][width - left - right];
+ for (int h = 0 + top, i = 0; h < height - bottom; h++, i++) {
+ for (int w = 0 + left, j = 0; w < width - right; w++, j++) {
+ m[i][j] = matrix.get(w, h);
+ }
+ }
+ return m;
+ }
+
+ /**
+ * 将矩阵逆时针转90度
+ *
+ * @param matrix
+ * @return
+ */
+ private static boolean[][] reverseMatrix(boolean[][] matrix) {
+ if (matrix == null) {
+ return null;
+ }
+
+ int height = matrix.length;
+ int width = matrix[0].length;
+
+ boolean[][] matrix2 = new boolean[width][height];
+ for (int h = 0; h < height; h++) {
+ for (int w = 0; w < width; w++) {
+ matrix2[width - 1 - w][h] = matrix[h][w];
+ }
+ }
+
+ return matrix2;
+ }
+
+ /**
+ * 从boolMatrix左上角判断二维码定位标记的大小
+ *
+ * @param boolMatrix
+ * @return
+ */
+ private static int getBitCharSize(boolean[][] boolMatrix) {
+ int a = 0, b = 0;
+ out:
+ for (int i = 0, len = boolMatrix.length; i < len; i++) {
+ boolean find = false;
+ boolean[] boolArr = boolMatrix[i];
+ for (int i2 = 0, len2 = boolArr.length; i2 < len2; i2++) {
+ if (!find && boolArr[i2]) {
+ find = true;
+ a = i2;
+ }
+ if (find && !boolArr[i2]) {
+ b = i2;
+ break out;
+ }
+ }
+ }
+
+ return (b - a);
+ }
+
+ /**
+ * 从boolMatrix判断bit-char占位比
+ *
+ * @param boolMatrix
+ * @return
+ */
+ private static int getBitCharRatio(boolean[][] boolMatrix) {
+ int[] size = new int[4];
+ size[0] = getBitCharSize(boolMatrix);
+ for (int i = 1; i < 4; i++) {
+ boolMatrix = reverseMatrix(boolMatrix);
+ size[i] = getBitCharSize(boolMatrix);
+ }
+
+ Map map = new HashMap<>();
+ for (int s : size) {
+ Integer count = map.get(s);
+ if (count == null) {
+ map.put(s, 1);
+ } else {
+ map.put(s, count + 1);
+ }
+ }
+ Set> entrySet = map.entrySet();
+ Integer k = null, v = null;
+ int flag = 0;
+ for (Map.Entry entry : entrySet) {
+ if (flag++ == 0) {
+ k = entry.getKey();
+ v = entry.getValue();
+ continue;
+ }
+ if (entry.getValue() > v) {
+ k = entry.getKey();
+ v = entry.getValue();
+ }
+ }
+
+ return k.intValue() / 7;
+ }
+
+ /**
+ * 将二维码图片转为字符矩阵
+ *
+ * @param image
+ * @return
+ */
+ public static String toCharMatrix(BufferedImage image, String onStr, String offStr) {
+ LuminanceSource source = new BufferedImageLuminanceSource(image);
+ Binarizer binarizer = new HybridBinarizer(source);
+ BitMatrix matrix = null;
+ try {
+ matrix = binarizer.getBlackMatrix();
+ boolean[][] boolMatrix = toBoolMatrix(matrix, true);
+ int ratio = getBitCharRatio(boolMatrix);
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0, len = boolMatrix.length; i < len; i += ratio) {
+ boolean[] boolArr = boolMatrix[i];
+ for (int i2 = 0, len2 = boolArr.length; i2 < len2; i2 += ratio) {
+ sb.append(boolArr[i2] ? onStr : offStr);
+ }
+ sb.append("\n");
+ }
+
+ return sb.toString();
+ } catch (NotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * 将二维码图片转为字符矩阵
+ *
+ * @param image
+ * @return
+ */
+ public static String toCharMatrix(BufferedImage image) {
+ return toCharMatrix(image, " ", "██");
+ }
+
+ /**
+ * 将二维码图片转为字符矩阵
+ *
+ * @param data
+ * @return
+ */
+ public static String toCharMatrix(byte[] data, String onStr, String offStr) {
+ ByteArrayInputStream bais = null;
+ try {
+ bais = new ByteArrayInputStream(data);
+ BufferedImage image = ImageIO.read(bais);
+ return QRCodeUtil.toCharMatrix(image, onStr, offStr);
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ } finally {
+ if (bais != null) {
+ try {
+ bais.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * 将二维码图片转为字符矩阵
+ *
+ * @param data
+ * @return
+ */
+ public static String toCharMatrix(byte[] data) {
+ return toCharMatrix(data, " ", "██");
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/hotlcc/wechat4j/util/StringUtil.java b/src/main/java/com/hotlcc/wechat4j/util/StringUtil.java
new file mode 100644
index 0000000..20b0e06
--- /dev/null
+++ b/src/main/java/com/hotlcc/wechat4j/util/StringUtil.java
@@ -0,0 +1,34 @@
+package com.hotlcc.wechat4j.util;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+
+public final class StringUtil {
+ private StringUtil() {
+ }
+
+ public static boolean isEmpty(String str) {
+ return str == null || "".equals(str);
+ }
+
+ public static boolean isNotEmpty(String str) {
+ return !isEmpty(str);
+ }
+
+ public static String encodeURL(String str, String enc) {
+ try {
+ return URLEncoder.encode(str, enc);
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static String decodeURL(String str, String enc) {
+ try {
+ return URLDecoder.decode(str, enc);
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/main/java/com/hotlcc/wechat4j/util/WechatUtil.java b/src/main/java/com/hotlcc/wechat4j/util/WechatUtil.java
new file mode 100644
index 0000000..25c3ef2
--- /dev/null
+++ b/src/main/java/com/hotlcc/wechat4j/util/WechatUtil.java
@@ -0,0 +1,94 @@
+package com.hotlcc.wechat4j.util;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.commons.lang3.RandomStringUtils;
+
+public final class WechatUtil {
+ private WechatUtil() {
+ }
+
+ private static String STRING_CHARS_1 = "123456789";
+ private static String STRING_CHARS_2 = "1234567890";
+
+ /**
+ * 创建一个设备ID
+ *
+ * @return
+ */
+ public static String createDeviceID() {
+ return "e" + RandomStringUtils.random(15, STRING_CHARS_1);
+ }
+
+ /**
+ * 创建一个消息ID
+ *
+ * @return
+ */
+ public static String createMsgId() {
+ return System.currentTimeMillis() + RandomStringUtils.random(4, STRING_CHARS_2);
+ }
+
+ /**
+ * 创建BaseRequest
+ *
+ * @return
+ */
+ public static JSONObject createBaseRequest(String DeviceID, String wxsid, String skey, String wxuin) {
+ JSONObject BaseRequest = new JSONObject();
+ BaseRequest.put("DeviceID", DeviceID);
+ BaseRequest.put("Sid", wxsid);
+ BaseRequest.put("Skey", skey);
+ BaseRequest.put("Uin", wxuin);
+ return BaseRequest;
+ }
+
+ /**
+ * 创建BaseRequest
+ *
+ * @return
+ */
+ public static JSONObject createBaseRequest(String wxsid, String skey, String wxuin) {
+ return createBaseRequest(createDeviceID(), wxsid, skey, wxuin);
+ }
+
+ /**
+ * 把SyncKeyList转为字符串格式
+ *
+ * @param SyncKeyList
+ * @return
+ */
+ public static String syncKeyListToString(JSONArray SyncKeyList) {
+ if (SyncKeyList == null) {
+ return null;
+ }
+ StringBuffer synckey = new StringBuffer();
+ for (int i = 0, len = SyncKeyList.size(); i < len; i++) {
+ JSONObject json = SyncKeyList.getJSONObject(i);
+ if (i > 0) {
+ synckey.append("|");
+ }
+ synckey.append(json.getString("Key"))
+ .append("_")
+ .append(json.getString("Val"));
+ }
+ return synckey.toString();
+ }
+
+ /**
+ * 创建要发送的Msg
+ *
+ * @return
+ */
+ public static JSONObject createSendMsg(String Content, int Type, String FromUserName, String ToUserName) {
+ JSONObject Msg = new JSONObject();
+ String msgId = WechatUtil.createMsgId();
+ Msg.put("ClientMsgId", msgId);
+ Msg.put("Content", Content);
+ Msg.put("FromUserName", FromUserName);
+ Msg.put("LocalID", msgId);
+ Msg.put("ToUserName", ToUserName);
+ Msg.put("Type", Type);
+ return Msg;
+ }
+}
diff --git a/src/main/resources/config/app.properties b/src/main/resources/config/app.properties
new file mode 100644
index 0000000..d8eca08
--- /dev/null
+++ b/src/main/resources/config/app.properties
@@ -0,0 +1,4 @@
+# web微信对应的appid
+webwx.appid=wx782c26e4c19acffb
+# httpclient的UserAgent
+wechat4j.userAgent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36
\ No newline at end of file
diff --git a/src/main/resources/config/webwx-url.properties b/src/main/resources/config/webwx-url.properties
new file mode 100644
index 0000000..f81c1de
--- /dev/null
+++ b/src/main/resources/config/webwx-url.properties
@@ -0,0 +1,28 @@
+# 1、登录
+## 1.1、获取微信uuid
+webwx-url.uuid_url=https://login.wx2.qq.com/jslogin?appid=&redirect_uri=https%3A%2F%2Fwx2.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_=<_>
+## 1.2、获取二维码
+webwx-url.qrcode_url=https://login.weixin.qq.com/qrcode/
+## 1.3、等待扫码登录并获取跳转url
+webwx-url.redirect_uri=https://login.wx2.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=&tip=0&r=&_=<_>
+## 1.4、获取登录认证码
+webwx-url.newlogin_url=&fun=new&version=v2
+## 1.5、退出登录
+webwx-url.logout_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxlogout?redirect=1&type=&skey=
+# 2、数据同步
+## 2.1、页面初始化
+webwx-url.webwxinit_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=&lang=zh_CN&pass_ticket=
+## 2.2、开启消息状态通知
+webwx-url.statusnotify_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxstatusnotify?lang=zh_CN&pass_ticket=
+## 2.3、服务端状态同步
+webwx-url.synccheck_url=https://webpush.wx2.qq.com/cgi-bin/mmwebwx-bin/synccheck?r=&skey=&sid=&uin=&deviceid=&synckey=&_=<_>
+# 3、联系人管理
+## 3.1、获取全部联系人列表
+webwx-url.getcontact_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=zh_CN&pass_ticket=&r=&seq=0&skey=
+## 3.2、批量获取指定联系人列表
+webwx-url.batchgetcontact_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxbatchgetcontact?type=ex&r=&lang=zh_CN&pass_ticket=
+# 4、收发消息
+## 4.1、从服务端拉取新消息
+webwx-url.webwxsync_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=&skey=&pass_ticket=
+## 4.2、发送消息
+webwx-url.webwxsendmsg_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket=
diff --git a/src/test/java/TestClass.java b/src/test/java/TestClass.java
new file mode 100644
index 0000000..0bff038
--- /dev/null
+++ b/src/test/java/TestClass.java
@@ -0,0 +1,133 @@
+import com.alibaba.fastjson.JSONObject;
+import com.hotlcc.wechat4j.Wechat;
+import com.hotlcc.wechat4j.api.WebWeixinApi;
+import com.hotlcc.wechat4j.util.QRCodeUtil;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+public class TestClass {
+ private static Logger logger = LoggerFactory.getLogger(TestClass.class);
+
+ //@Test
+// public void test01() {
+// JSONObject result = null;
+//
+// String redirectUri = null;
+// login:
+// while (true) {
+// //1、获取uuid
+// logger.info("开始获取uuid...");
+// String uuid = null;
+// while (uuid == null || "".equals(uuid)) {
+// result = webWeixinApi.getWxUuid();
+// if (result != null) {
+// uuid = result.getString("uuid");
+// }
+// if (uuid == null || "".equals(uuid)) {
+// logger.info("获取uuid失败,将自动重试");
+// try {
+// Thread.sleep(2000);
+// } catch (InterruptedException e) {
+// e.printStackTrace();
+// }
+// } else {
+// break;
+// }
+// }
+// logger.info("获取uuid成功,值为:{}", uuid);
+//
+// //2、获取二维码
+// logger.info("开始获取二维码...");
+// result = webWeixinApi.getQR(uuid);
+// logger.info("获取二维码成功,请扫描二维码:\n{}", QRCodeUtil.toCharMatrix(result.getBytes("data")));
+//
+// //3、轮询
+// String code = null;
+// while (!"200".equals(code)) {
+// result = webWeixinApi.getRedirectUri(uuid);
+// code = result.getString("code");
+// if ("408".equals(code)) {
+// continue;
+// } else if ("400".equals(code)) {
+// logger.info("二维码失效,将自动获取新的二维码");
+// continue login;
+// } else if ("201".equals(code)) {
+// logger.info("请在手机上确认");
+// continue;
+// } else if ("200".equals(code)) {
+// redirectUri = result.getString("redirectUri");
+// logger.info("手机端认证成功");
+// break login;
+// } else {
+// break login;
+// }
+// }
+// }
+// //4、获取登录认证码
+// logger.info("开始获取登录认证码");
+// result = webWeixinApi.getLoginCode(redirectUri);
+// String wxsid = result.getString("wxsid");
+// String passTicket = result.getString("pass_ticket");
+// String skey = result.getString("skey");
+// String wxuin = result.getString("wxuin");
+// logger.info("获取登录认证码成功");
+// //5、初始化数据
+// logger.info("开始初始化数据");
+// result = webWeixinApi.webWeixinInit(passTicket, wxsid, skey, wxuin);
+// JSONObject loginUser = result.getJSONObject("User");
+// logger.info("欢迎回来,{}", loginUser.getString("NickName"));
+// JSONObject SyncKey = result.getJSONObject("SyncKey");
+// logger.info("初始化数据完成");
+// //6、开启消息状态通知
+// logger.info("开始开启消息状态通知");
+// result = webWeixinApi.statusNotify(passTicket, wxsid, skey, wxuin, loginUser.getString("UserName"));
+// logger.info("开启消息状态通知完成");
+// //7、服务端状态同步
+// logger.info("开始轮询服务端状态");
+// while (true) {
+// result = webWeixinApi.syncCheck(wxsid, skey, wxuin, SyncKey.getJSONArray("List"));
+// int retcode = result.getIntValue("retcode");
+// if (retcode != 0) {
+// logger.info("微信已退出登录");
+// break;
+// } else {
+// int selector = result.getIntValue("selector");
+// if (selector == 2) {
+// logger.info("收到新消息");
+// //8、获取新消息内容
+// result = webWeixinApi.pullNewMsg(passTicket, wxsid, skey, wxuin, SyncKey);
+// SyncKey = result.getJSONObject("SyncKey");
+// JSONObject Msg = result.getJSONArray("AddMsgList").getJSONObject(0);
+// String Content = Msg.getString("Content");
+// int MsgType = Msg.getIntValue("MsgType");
+// String FromUserName = Msg.getString("FromUserName");
+// String ToUserName = Msg.getString("ToUserName");
+// logger.info("消息类型:{},消息内容:{},发送方:{},接收方:{}", MsgType, Content, FromUserName, ToUserName);
+// result = webWeixinApi.sendMsg(passTicket, wxsid, skey, wxuin, Content, MsgType, ToUserName, FromUserName);
+// logger.info("自动回复消息完成,返回:{}", result);
+// }
+// }
+// }
+// }
+
+ public void test03() throws IOException {
+ BufferedImage image = ImageIO.read(new FileInputStream("D:/2.jpg"));
+ System.out.println(QRCodeUtil.toCharMatrix(image));
+ }
+
+ @Test
+ public void test04() {
+ WebWeixinApi api = new WebWeixinApi();
+ Wechat wechat = new Wechat();
+ wechat.setWebWeixinApi(api);
+
+
+ }
+}
diff --git a/src/test/resources/logback.xml b/src/test/resources/logback.xml
new file mode 100644
index 0000000..3cdec0c
--- /dev/null
+++ b/src/test/resources/logback.xml
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ [%-5level] %date{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{36} - %m%n
+
+
+
+
+
+
+ INFO
+ ACCEPT
+ DENY
+
+ ${LOG_DIRECTORY}/info.log
+ true
+
+ ${LOG_DIRECTORY}%d/info%i.log
+ ${MAX_HISTORY}
+ ${FILE_SIZE}
+ ${TOTAL_SIZE}
+
+
+ [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{36} - %m%n
+
+
+
+
+
+
+ [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{36} - %m%n
+
+
+ ERROR
+ ACCEPT
+ DENY
+
+ ${LOG_DIRECTORY}/error.log
+ true
+
+ ${LOG_DIRECTORY}%d/error%i.log
+ ${MAX_HISTORY}
+ ${FILE_SIZE}
+ ${TOTAL_SIZE}
+
+
+
+
+
+
+ [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{36} - %m%n
+
+
+ WARN
+ ACCEPT
+ DENY
+
+ ${LOG_DIRECTORY}/warn.log
+ true
+
+ ${LOG_DIRECTORY}%d/warn%i.log
+ ${MAX_HISTORY}
+ ${FILE_SIZE}
+ ${TOTAL_SIZE}
+
+
+
+
+
+
+ [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{36} - %m%n
+
+
+ DEBUG
+ ACCEPT
+ DENY
+
+ ${LOG_DIRECTORY}/debug.log
+ true
+
+ ${LOG_DIRECTORY}%d/debug%i.log
+ ${MAX_HISTORY}
+ ${FILE_SIZE}
+
+
+
+
+
+
+ [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{36} - %m%n
+
+
+ TRACE
+ ACCEPT
+ DENY
+
+ ${LOG_DIRECTORY}/trace.log
+ true
+
+ ${LOG_DIRECTORY}%d/trace%i.log
+ ${MAX_HISTORY}
+ ${FILE_SIZE}
+
+
+
+
+
+ [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{36} - %m%n
+
+
+
+ ${LOG_DIRECTORY}/${APP_NAME}.log
+ true
+
+ ${LOG_DIRECTORY}%d/${APP_NAME}%i.log
+ ${MAX_HISTORY}
+ ${FILE_SIZE}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file