mirror of
https://gitee.com/hotlcc/wechat4j.git
synced 2025-06-06 10:34:07 +08:00
init code
This commit is contained in:
parent
0ddb01be72
commit
bd6c61b3c3
4
.gitignore
vendored
4
.gitignore
vendored
@ -20,3 +20,7 @@
|
|||||||
|
|
||||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
hs_err_pid*
|
hs_err_pid*
|
||||||
|
|
||||||
|
.idea
|
||||||
|
*/target/*
|
||||||
|
*.iml
|
||||||
|
112
pom.xml
Normal file
112
pom.xml
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.hotlcc</groupId>
|
||||||
|
<artifactId>wechat4j</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<name>wechat4j</name>
|
||||||
|
<description>Wechat client for Java.</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
|
<java.version>1.7</java.version>
|
||||||
|
<maven.compiler.source>1.7</maven.compiler.source>
|
||||||
|
<maven.compiler.target>1.7</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpclient</artifactId>
|
||||||
|
<version>4.5.3</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpmime</artifactId>
|
||||||
|
<version>4.5</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>fastjson</artifactId>
|
||||||
|
<version>1.2.31</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>3.0</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<version>1.7.25</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<version>1.2.3</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- emoji -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.vdurmont</groupId>
|
||||||
|
<artifactId>emoji-java</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.antlr</groupId>
|
||||||
|
<artifactId>ST4</artifactId>
|
||||||
|
<version>4.0.8</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/junit/junit -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.12</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/com.google.zxing/javase -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.zxing</groupId>
|
||||||
|
<artifactId>javase</artifactId>
|
||||||
|
<version>3.3.3</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>${java.version}</source>
|
||||||
|
<target>${java.version}</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-resources-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<encoding>${project.build.sourceEncoding}</encoding>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<skip>true</skip>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
44
src/main/java/com/hotlcc/wechat4j/Wechat.java
Normal file
44
src/main/java/com/hotlcc/wechat4j/Wechat.java
Normal file
@ -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() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
582
src/main/java/com/hotlcc/wechat4j/api/WebWeixinApi.java
Normal file
582
src/main/java/com/hotlcc/wechat4j/api/WebWeixinApi.java
Normal file
@ -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<NameValuePair> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
56
src/main/java/com/hotlcc/wechat4j/util/PropertiesUtil.java
Normal file
56
src/main/java/com/hotlcc/wechat4j/util/PropertiesUtil.java
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
230
src/main/java/com/hotlcc/wechat4j/util/QRCodeUtil.java
Normal file
230
src/main/java/com/hotlcc/wechat4j/util/QRCodeUtil.java
Normal file
@ -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<Integer, Integer> 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<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
|
||||||
|
Integer k = null, v = null;
|
||||||
|
int flag = 0;
|
||||||
|
for (Map.Entry<Integer, Integer> 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, " ", "██");
|
||||||
|
}
|
||||||
|
}
|
34
src/main/java/com/hotlcc/wechat4j/util/StringUtil.java
Normal file
34
src/main/java/com/hotlcc/wechat4j/util/StringUtil.java
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
94
src/main/java/com/hotlcc/wechat4j/util/WechatUtil.java
Normal file
94
src/main/java/com/hotlcc/wechat4j/util/WechatUtil.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
4
src/main/resources/config/app.properties
Normal file
4
src/main/resources/config/app.properties
Normal file
@ -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
|
28
src/main/resources/config/webwx-url.properties
Normal file
28
src/main/resources/config/webwx-url.properties
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# 1、登录
|
||||||
|
## 1.1、获取微信uuid
|
||||||
|
webwx-url.uuid_url=https://login.wx2.qq.com/jslogin?appid=<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/<uuid>
|
||||||
|
## 1.3、等待扫码登录并获取跳转url
|
||||||
|
webwx-url.redirect_uri=https://login.wx2.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=<uuid>&tip=0&r=<r>&_=<_>
|
||||||
|
## 1.4、获取登录认证码
|
||||||
|
webwx-url.newlogin_url=<redirectUri>&fun=new&version=v2
|
||||||
|
## 1.5、退出登录
|
||||||
|
webwx-url.logout_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxlogout?redirect=1&type=<type>&skey=<skey>
|
||||||
|
# 2、数据同步
|
||||||
|
## 2.1、页面初始化
|
||||||
|
webwx-url.webwxinit_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=<r>&lang=zh_CN&pass_ticket=<pass_ticket>
|
||||||
|
## 2.2、开启消息状态通知
|
||||||
|
webwx-url.statusnotify_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxstatusnotify?lang=zh_CN&pass_ticket=<pass_ticket>
|
||||||
|
## 2.3、服务端状态同步
|
||||||
|
webwx-url.synccheck_url=https://webpush.wx2.qq.com/cgi-bin/mmwebwx-bin/synccheck?r=<r>&skey=<skey>&sid=<sid>&uin=<uin>&deviceid=<deviceid>&synckey=<synckey>&_=<_>
|
||||||
|
# 3、联系人管理
|
||||||
|
## 3.1、获取全部联系人列表
|
||||||
|
webwx-url.getcontact_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=zh_CN&pass_ticket=<pass_ticket>&r=<r>&seq=0&skey=<skey>
|
||||||
|
## 3.2、批量获取指定联系人列表
|
||||||
|
webwx-url.batchgetcontact_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxbatchgetcontact?type=ex&r=<r>&lang=zh_CN&pass_ticket=<pass_ticket>
|
||||||
|
# 4、收发消息
|
||||||
|
## 4.1、从服务端拉取新消息
|
||||||
|
webwx-url.webwxsync_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=<sid>&skey=<skey>&pass_ticket=<pass_ticket>
|
||||||
|
## 4.2、发送消息
|
||||||
|
webwx-url.webwxsendmsg_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket=<pass_ticket>
|
133
src/test/java/TestClass.java
Normal file
133
src/test/java/TestClass.java
Normal file
@ -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);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
159
src/test/resources/logback.xml
Normal file
159
src/test/resources/logback.xml
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration debug="false" scan="true" scanPeriod="30 second">
|
||||||
|
|
||||||
|
<property name="APP_NAME" value="emall-admin"/>
|
||||||
|
<property name="LOG_DIRECTORY" value="${user.home}/logs/${APP_NAME}/"/>
|
||||||
|
<property name="FILE_SIZE" value="20MB"/>
|
||||||
|
<property name="MAX_HISTORY" value="100"/>
|
||||||
|
<property name="TOTAL_SIZE" value="1GB"/>
|
||||||
|
<property name="LOG_LEVEL" value="INFO"/>
|
||||||
|
|
||||||
|
<!-- 控制台打印 -->
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>[%-5level] %date{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{36} - %m%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- INFO 输入到文件,按文件大小 -->
|
||||||
|
<appender name="INFO-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>INFO</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
<file>${LOG_DIRECTORY}/info.log</file>
|
||||||
|
<append>true</append>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOG_DIRECTORY}%d/info%i.log</fileNamePattern>
|
||||||
|
<maxHistory>${MAX_HISTORY}</maxHistory>
|
||||||
|
<maxFileSize>${FILE_SIZE}</maxFileSize>
|
||||||
|
<totalSizeCap>${TOTAL_SIZE}</totalSizeCap>
|
||||||
|
</rollingPolicy>
|
||||||
|
<encoder>
|
||||||
|
<pattern>[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{36} - %m%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- ERROR 输入到文件,按文件大小 -->
|
||||||
|
<appender name="ERROR-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{36} - %m%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>ERROR</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
<file>${LOG_DIRECTORY}/error.log</file>
|
||||||
|
<append>true</append>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOG_DIRECTORY}%d/error%i.log</fileNamePattern>
|
||||||
|
<maxHistory>${MAX_HISTORY}</maxHistory>
|
||||||
|
<maxFileSize>${FILE_SIZE}</maxFileSize>
|
||||||
|
<totalSizeCap>${TOTAL_SIZE}</totalSizeCap>
|
||||||
|
</rollingPolicy>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- WARN 输入到文件,按文件大小 -->
|
||||||
|
<appender name="WARN-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{36} - %m%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>WARN</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
<file>${LOG_DIRECTORY}/warn.log</file>
|
||||||
|
<append>true</append>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOG_DIRECTORY}%d/warn%i.log</fileNamePattern>
|
||||||
|
<maxHistory>${MAX_HISTORY}</maxHistory>
|
||||||
|
<maxFileSize>${FILE_SIZE}</maxFileSize>
|
||||||
|
<totalSizeCap>${TOTAL_SIZE}</totalSizeCap>
|
||||||
|
</rollingPolicy>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- DEBUG 输入到文件,按文件大小 -->
|
||||||
|
<appender name="DEBUG-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{36} - %m%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>DEBUG</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
<file>${LOG_DIRECTORY}/debug.log</file>
|
||||||
|
<append>true</append>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOG_DIRECTORY}%d/debug%i.log</fileNamePattern>
|
||||||
|
<maxHistory>${MAX_HISTORY}</maxHistory>
|
||||||
|
<maxFileSize>${FILE_SIZE}</maxFileSize>
|
||||||
|
</rollingPolicy>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- TRACE 输入到文件,按日期和文件大小 -->
|
||||||
|
<appender name="TRACE-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{36} - %m%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>TRACE</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
<file>${LOG_DIRECTORY}/trace.log</file>
|
||||||
|
<append>true</append>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOG_DIRECTORY}%d/trace%i.log</fileNamePattern>
|
||||||
|
<maxHistory>${MAX_HISTORY}</maxHistory>
|
||||||
|
<maxFileSize>${FILE_SIZE}</maxFileSize>
|
||||||
|
</rollingPolicy>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<appender name="${APP_NAME}" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{36} - %m%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
<!-- 过滤日志级别 -->
|
||||||
|
<!--<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>DEBUG</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>-->
|
||||||
|
<file>${LOG_DIRECTORY}/${APP_NAME}.log</file>
|
||||||
|
<append>true</append>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOG_DIRECTORY}%d/${APP_NAME}%i.log</fileNamePattern>
|
||||||
|
<maxHistory>${MAX_HISTORY}</maxHistory>
|
||||||
|
<maxFileSize>${FILE_SIZE}</maxFileSize>
|
||||||
|
</rollingPolicy>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- 包级别的日志 additivity="false" -->
|
||||||
|
<logger name="com.aaron.springcloud.consumer.controller" additivity="false">
|
||||||
|
<level value="{LOG_LEVEL}"/>
|
||||||
|
<appender-ref ref="${APP_NAME}"/>
|
||||||
|
|
||||||
|
<!-- 还是要输出到控制台中-->
|
||||||
|
<appender-ref ref="STDOUT"/>
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
<!-- org包下面设置日志级别为Error-->
|
||||||
|
<!--<logger name="org" level="ERROR"/>-->
|
||||||
|
|
||||||
|
<!-- org包下面设置日志级别为Error-->
|
||||||
|
<!--<logger name="com.netflix" level="ERROR"/>-->
|
||||||
|
|
||||||
|
<!-- Logger 根目录 -->
|
||||||
|
<root level="${LOG_LEVEL}">
|
||||||
|
<appender-ref ref="STDOUT"/>
|
||||||
|
<!--<appender-ref ref="ERROR-OUT"/>
|
||||||
|
<appender-ref ref="WARN-OUT"/>
|
||||||
|
<appender-ref ref="INFO-OUT"/>
|
||||||
|
<appender-ref ref="DEBUG-OUT"/>
|
||||||
|
<appender-ref ref="TRACE-OUT"/>-->
|
||||||
|
</root>
|
||||||
|
</configuration>
|
Loading…
x
Reference in New Issue
Block a user