commit
415d8f738d
@ -0,0 +1,20 @@
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
/.idea
|
||||
*.iml
|
||||
/.settings
|
||||
/bin
|
||||
/gen
|
||||
/build
|
||||
/gradle
|
||||
/classes
|
||||
.classpath
|
||||
.project
|
||||
*.gradle
|
||||
gradlew
|
||||
local.properties
|
||||
node_modules/
|
@ -0,0 +1,33 @@
|
||||
package cn.zhouyafeng.itchat4j;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import cn.zhouyafeng.itchat4j.controller.LoginController;
|
||||
import cn.zhouyafeng.itchat4j.core.MsgCenter;
|
||||
import cn.zhouyafeng.itchat4j.face.IMsgHandlerFace;
|
||||
|
||||
public class Wechat {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Wechat.class);
|
||||
private IMsgHandlerFace msgHandler;
|
||||
|
||||
public Wechat(IMsgHandlerFace msgHandler, String qrPath) {
|
||||
System.setProperty("jsse.enableSNIExtension", "false"); // 防止SSL错误
|
||||
this.msgHandler = msgHandler;
|
||||
|
||||
// 登陆
|
||||
LoginController login = new LoginController();
|
||||
login.login(qrPath);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
LOG.info("+++++++++++++++++++开始消息处理+++++++++++++++++++++");
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
MsgCenter.handleMsg(msgHandler);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package cn.zhouyafeng.itchat4j.utils;
|
||||
|
||||
public class MsgKeywords {
|
||||
public static String newFriendStr = "我通过了你的朋友验证请求";
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package cn.zhouyafeng.itchat4j.utils;
|
||||
|
||||
/**
|
||||
* Created by xiaoxiaomo on 2017/5/6.
|
||||
*/
|
||||
public class SleepUtils {
|
||||
|
||||
/**
|
||||
* 毫秒为单位
|
||||
* @param time
|
||||
*/
|
||||
public static void sleep( long time ){
|
||||
try {
|
||||
Thread.sleep( time );
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package cn.zhouyafeng.itchat4j.utils.enums;
|
||||
|
||||
/**
|
||||
* 返回结构枚举类
|
||||
* <p>
|
||||
* Created by xiaoxiaomo on 2017/5/6.
|
||||
*/
|
||||
public enum ResultEnum {
|
||||
|
||||
SUCCESS("200", "成功"),
|
||||
WAIT_CONFIRM("201", "请在手机上点击确认"),
|
||||
WAIT_SCAN("400", "请扫描二维码");
|
||||
|
||||
private String code;
|
||||
private String msg;
|
||||
|
||||
ResultEnum(String code, String msg) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
// public static MsgInfoEnum getCode(String code) {
|
||||
// switch (code) {
|
||||
// case "Text":
|
||||
// return MsgInfoEnum.TEXT;
|
||||
// default:
|
||||
// return MsgInfoEnum.VIDEO;
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package cn.zhouyafeng.itchat4j.utils.enums;
|
||||
|
||||
public enum RetCodeEnum {
|
||||
|
||||
NORMAL("0", "普通"),
|
||||
LOGIN_OUT("1102", "退出"),
|
||||
LOGIN_OTHERWHERE("1101", "其它地方登陆"),
|
||||
MOBILE_LOGIN_OUT("1102", "移动端退出"),
|
||||
UNKOWN("9999", "未知")
|
||||
|
||||
;
|
||||
|
||||
|
||||
private String code;
|
||||
private String type;
|
||||
|
||||
RetCodeEnum(String code, String type) {
|
||||
this.code = code;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package cn.zhouyafeng.itchat4j.utils.enums;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by xiaoxiaomo on 2017/5/7.
|
||||
*/
|
||||
public enum StorageLoginInfoEnum {
|
||||
|
||||
//URL
|
||||
url("url",new String()),
|
||||
fileUrl("fileUrl",new String()),
|
||||
syncUrl("syncUrl",new String()),
|
||||
|
||||
deviceid("deviceid",new String()), //生成15位随机数
|
||||
|
||||
//baseRequest
|
||||
skey("skey",new String()),
|
||||
wxsid("wxsid",new String()),
|
||||
wxuin("wxuin",new String()),
|
||||
pass_ticket("pass_ticket",new String()),
|
||||
|
||||
|
||||
InviteStartCount("InviteStartCount",new Integer(0)),
|
||||
User("User",new JSONObject()),
|
||||
SyncKey("SyncKey",new JSONObject()),
|
||||
synckey("synckey",new String()),
|
||||
|
||||
|
||||
|
||||
MemberCount("MemberCount",new String()),
|
||||
MemberList("MemberList",new JSONArray()),
|
||||
|
||||
|
||||
|
||||
;
|
||||
|
||||
private String key;
|
||||
private Object type;
|
||||
|
||||
StorageLoginInfoEnum(String key, Object type) {
|
||||
this.key = key;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
public Object getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package cn.zhouyafeng.itchat4j.utils.enums;
|
||||
|
||||
/**
|
||||
* URL
|
||||
* Created by xiaoxiaomo on 2017/5/6.
|
||||
*/
|
||||
public enum URLEnum {
|
||||
|
||||
|
||||
|
||||
BASE_URL("https://login.weixin.qq.com","基本的URL"),
|
||||
UUID_URL(BASE_URL.url+"/jslogin","UUIDLURL"),
|
||||
QRCODE_URL(BASE_URL.url+"/qrcode/","初始化URL"),
|
||||
STATUS_NOTIFY_URL(BASE_URL.url+"/webwxstatusnotify?lang=zh_CN&pass_ticket=%s","微信状态通知"),
|
||||
LOGIN_URL(BASE_URL.url+"/cgi-bin/mmwebwx-bin/login","登陆URL"),
|
||||
INIT_URL("%s/webwxinit?r=%s&pass_ticket=%s","初始化URL"),
|
||||
SYNC_CHECK_URL("/synccheck","检查心跳URL"),
|
||||
WEB_WX_SYNC_URL("%s/webwxsync?sid=%s&skey=%s&pass_ticket=%s","web微信消息同步URL"),
|
||||
WEB_WX_GET_CONTACT("%s/webwxgetcontact","web微信获取联系人信息URL"),
|
||||
WEB_WX_SEND_MSG("%s/webwxsendmsg","发送消息URL"),
|
||||
WEB_WX_UPLOAD_MEDIA("%s/webwxuploadmedia?f=json", "上传文件到服务器"),
|
||||
WEB_WX_GET_MSG_IMG("%s/webwxgetmsgimg", "下载图片消息"),
|
||||
WEB_WX_GET_VOICE("%s/webwxgetvoice", "下载语音消息"),
|
||||
WEB_WX_GET_VIEDO("%s/webwxgetvideo", "下载语音消息"),
|
||||
WEB_WX_PUSH_LOGIN("%s/webwxpushloginurl", "不扫码登陆"),
|
||||
WEB_WX_LOGOUT("%s/webwxlogout", "退出微信"),
|
||||
WEB_WX_BATCH_GET_CONTACT("%s/webwxbatchgetcontact?type=ex&r=%s&lang=zh_CN&pass_ticket=%s", "查询群信息"),
|
||||
WEB_WX_REMARKNAME("%s/webwxoplog?lang=zh_CN&pass_ticket=%s", "修改好友备注"),
|
||||
WEB_WX_VERIFYUSER("%s/webwxverifyuser?r=%s&lang=zh_CN&pass_ticket=%s", "被动添加好友"),
|
||||
WEB_WX_GET_MEDIA("%s/webwxgetmedia", "下载文件")
|
||||
|
||||
|
||||
|
||||
|
||||
;
|
||||
|
||||
private String url;
|
||||
private String msg;
|
||||
|
||||
URLEnum(String url, String msg) {
|
||||
this.url = url;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package cn.zhouyafeng.itchat4j.utils.enums.parameters;
|
||||
|
||||
/**
|
||||
*
|
||||
* 基本请求参数
|
||||
* 1. webWxInit 初始化
|
||||
* 2. wxStatusNotify 微信状态通知
|
||||
*
|
||||
* <p>
|
||||
* Created by xiaoxiaomo on 2017/5/7.
|
||||
*/
|
||||
public enum BaseParaEnum {
|
||||
|
||||
Uin("Uin", "wxuin"),
|
||||
Sid("Sid", "wxsid"),
|
||||
Skey("Skey", "skey"),
|
||||
DeviceID("DeviceID", "pass_ticket");
|
||||
|
||||
private String para;
|
||||
private String value;
|
||||
|
||||
BaseParaEnum(String para, String value) {
|
||||
this.para = para;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String para() {
|
||||
return para;
|
||||
}
|
||||
|
||||
|
||||
public Object value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package cn.zhouyafeng.itchat4j.utils.enums.parameters;
|
||||
|
||||
/**
|
||||
* 登陆
|
||||
* <p>
|
||||
* Created by xiaoxiaomo on 2017/5/7.
|
||||
*/
|
||||
public enum LoginParaEnum {
|
||||
|
||||
LOGIN_ICON("loginicon", "true"),
|
||||
UUID("uuid", ""),
|
||||
TIP("tip", "0"),
|
||||
R("r", ""),
|
||||
_("_", "");
|
||||
|
||||
private String para;
|
||||
private String value;
|
||||
|
||||
LoginParaEnum(String para, String value) {
|
||||
this.para = para;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String para() {
|
||||
return para;
|
||||
}
|
||||
|
||||
public String value() {
|
||||
return value;
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package cn.zhouyafeng.itchat4j.utils.enums.parameters;
|
||||
|
||||
/**
|
||||
* 状态通知
|
||||
* <p>
|
||||
* Created by xiaoxiaomo on 2017/5/7.
|
||||
*/
|
||||
public enum StatusNotifyParaEnum {
|
||||
|
||||
CODE("Code", "3"),
|
||||
FROM_USERNAME("FromUserName", ""),
|
||||
TO_USERNAME("ToUserName", ""),
|
||||
CLIENT_MSG_ID("ClientMsgId", ""); //时间戳
|
||||
|
||||
private String para;
|
||||
private String value;
|
||||
|
||||
StatusNotifyParaEnum(String para, String value) {
|
||||
this.para = para;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String para() {
|
||||
return para;
|
||||
}
|
||||
|
||||
public String value() {
|
||||
return value;
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package cn.zhouyafeng.itchat4j.utils.enums.parameters;
|
||||
|
||||
/**
|
||||
* UUID
|
||||
* <p>
|
||||
* Created by xiaoxiaomo on 2017/5/7.
|
||||
*/
|
||||
public enum UUIDParaEnum {
|
||||
|
||||
APP_ID("appid", "wx782c26e4c19acffb"),
|
||||
FUN("fun", "new"),
|
||||
LANG("lang", "zh_CN"),
|
||||
_("_", "时间戳");
|
||||
|
||||
private String para;
|
||||
private String value;
|
||||
|
||||
UUIDParaEnum(String para, String value) {
|
||||
this.para = para;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String para() {
|
||||
return para;
|
||||
}
|
||||
|
||||
public String value() {
|
||||
return value;
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package xyz.wbsite.itchat4j;
|
||||
|
||||
import cn.zhouyafeng.itchat4j.beans.BaseMsg;
|
||||
import cn.zhouyafeng.itchat4j.face.IMsgHandlerFace;
|
||||
|
||||
public class JMsgHandler implements IMsgHandlerFace {
|
||||
@Override
|
||||
public String textMsgHandle(BaseMsg baseMsg) {
|
||||
return baseMsg.getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String picMsgHandle(BaseMsg baseMsg) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String voiceMsgHandle(BaseMsg baseMsg) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String viedoMsgHandle(BaseMsg baseMsg) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String nameCardMsgHandle(BaseMsg baseMsg) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sysMsgHandle(BaseMsg baseMsg) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String verifyAddFriendMsgHandle(BaseMsg baseMsg) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mediaMsgHandle(BaseMsg baseMsg) {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
package xyz.wbsite.itchat4j;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.setting.dialect.Props;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* 首选项配置
|
||||
*/
|
||||
public class JProp {
|
||||
|
||||
private static final JProp instance = new JProp();
|
||||
|
||||
private final File propFile;
|
||||
|
||||
private final Props props;
|
||||
|
||||
public static JProp getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private JProp() {
|
||||
this.propFile = new File("prop.ini");
|
||||
if (!propFile.exists()) {
|
||||
FileUtil.touch(propFile.getAbsolutePath());
|
||||
this.props = new Props(propFile, StandardCharsets.UTF_8);
|
||||
// 做一些初始化操作
|
||||
} else {
|
||||
this.props = new Props(propFile, StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
|
||||
private void save() {
|
||||
this.props.store(propFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
public String getString(String key, String defaultValue) {
|
||||
return this.props.getStr(key, defaultValue);
|
||||
}
|
||||
|
||||
public String[] getStringArray(String key, String[] defaultValue) {
|
||||
return this.props.getStr(key, "").split(",");
|
||||
}
|
||||
|
||||
public int getInt(String key, int defaultValue) {
|
||||
return this.props.getInt(key, defaultValue);
|
||||
}
|
||||
|
||||
public long getLong(String key, long defaultValue) {
|
||||
return this.props.getLong(key, defaultValue);
|
||||
}
|
||||
|
||||
public float getFloat(String key, float defaultValue) {
|
||||
return this.props.getFloat(key, defaultValue);
|
||||
}
|
||||
|
||||
public double getDouble(String key, double defaultValue) {
|
||||
return this.props.getDouble(key, defaultValue);
|
||||
}
|
||||
|
||||
public void setString(String key, String value) {
|
||||
this.props.setProperty(key, value);
|
||||
this.save();
|
||||
}
|
||||
|
||||
public void setStringArray(String key, String[] value) {
|
||||
this.props.setProperty(key, String.join(",", value));
|
||||
this.save();
|
||||
}
|
||||
|
||||
public void setInt(String key, int value) {
|
||||
this.props.setProperty(key, String.valueOf(value));
|
||||
this.save();
|
||||
}
|
||||
|
||||
public void setLong(String key, long value) {
|
||||
this.props.setProperty(key, String.valueOf(value));
|
||||
this.save();
|
||||
}
|
||||
|
||||
public void setFloat(String key, float value) {
|
||||
this.props.setProperty(key, String.valueOf(value));
|
||||
this.save();
|
||||
}
|
||||
|
||||
public void setDouble(String key, double value) {
|
||||
this.props.setProperty(key, String.valueOf(value));
|
||||
this.save();
|
||||
}
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
package xyz.wbsite.itchat4j.db;
|
||||
|
||||
import java.io.File;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Date;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Time;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* xyz.wbsite.wsqlite.Client
|
||||
*
|
||||
* @author wangbing
|
||||
*/
|
||||
public class Client {
|
||||
|
||||
Connection connection;
|
||||
ResultSet resultSet;
|
||||
String dbFilePath;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param dbFile 文件
|
||||
* @throws ClassNotFoundException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public Client(File dbFile) throws ClassNotFoundException, SQLException {
|
||||
this.dbFilePath = dbFile.getAbsolutePath();
|
||||
if (!dbFile.exists()) {
|
||||
connection = getConnection();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行sql语句
|
||||
*
|
||||
* @param sql
|
||||
* @throws SQLException
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
public void execute(String sql) throws SQLException, ClassNotFoundException {
|
||||
try {
|
||||
executeUpdate(sql);
|
||||
} finally {
|
||||
destroyed();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行sql查询语句
|
||||
*
|
||||
* @param sql
|
||||
* @throws SQLException
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
public ResultSet executeQuery(String sql, Object... args) throws SQLException, ClassNotFoundException {
|
||||
PreparedStatement preparedStatement = getConnection().prepareStatement(sql);
|
||||
setArg(preparedStatement, args);
|
||||
return preparedStatement.executeQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行sql语句
|
||||
*
|
||||
* @param sql
|
||||
* @throws SQLException
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
public int executeUpdate(String sql, Object... args) throws SQLException, ClassNotFoundException {
|
||||
try {
|
||||
PreparedStatement preparedStatement = getConnection().prepareStatement(sql);
|
||||
setArg(preparedStatement, args);
|
||||
return preparedStatement.executeUpdate();
|
||||
} finally {
|
||||
destroyed();
|
||||
}
|
||||
}
|
||||
|
||||
private void setArg(PreparedStatement ps, Object... args) throws SQLException {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
Object arg = args[i];
|
||||
|
||||
if (arg == null) {
|
||||
ps.setNull(i + 1, Types.NULL);
|
||||
} else if (arg instanceof String) {
|
||||
ps.setString(i + 1, (String) arg);
|
||||
} else if (arg instanceof Date) {
|
||||
ps.setDate(i + 1, (Date) arg);
|
||||
} else if (arg instanceof Time) {
|
||||
ps.setTime(i + 1, (Time) arg);
|
||||
} else if (arg instanceof java.util.Date) {
|
||||
ps.setLong(i + 1, ((java.util.Date) arg).getTime());
|
||||
} else if (arg instanceof Boolean) {
|
||||
ps.setBoolean(i + 1, (Boolean) arg);
|
||||
} else if (arg instanceof Byte) {
|
||||
ps.setByte(i + 1, (Byte) arg);
|
||||
} else if (arg instanceof Short) {
|
||||
ps.setShort(i + 1, (Short) arg);
|
||||
} else if (arg instanceof Integer) {
|
||||
ps.setInt(i + 1, (int) arg);
|
||||
} else if (arg instanceof Long) {
|
||||
ps.setLong(i + 1, (long) arg);
|
||||
} else if (arg instanceof Float) {
|
||||
ps.setFloat(i + 1, (float) arg);
|
||||
} else if (arg instanceof Double) {
|
||||
ps.setDouble(i + 1, (double) arg);
|
||||
} else if (arg instanceof byte[]) {
|
||||
ps.setBytes(i + 1, (byte[]) arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据库连接
|
||||
*
|
||||
* @return 数据库连接
|
||||
* @throws ClassNotFoundException
|
||||
* @throws SQLException
|
||||
*/
|
||||
Connection getConnection() throws ClassNotFoundException, SQLException {
|
||||
if (null == connection) {
|
||||
Class.forName("org.sqlite.JDBC");
|
||||
connection = DriverManager.getConnection("jdbc:sqlite:" + dbFilePath);
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据库资源关闭和释放
|
||||
*/
|
||||
public void destroyed() {
|
||||
try {
|
||||
if (null != resultSet) {
|
||||
resultSet.close();
|
||||
resultSet = null;
|
||||
}
|
||||
|
||||
if (null != connection) {
|
||||
connection.close();
|
||||
connection = null;
|
||||
}
|
||||
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
package xyz.wbsite.itchat4j.db;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Where {
|
||||
private String sql;
|
||||
private Object[] args;
|
||||
|
||||
private Where() {
|
||||
}
|
||||
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
public void setSql(String sql) {
|
||||
this.sql = sql;
|
||||
}
|
||||
|
||||
public Object[] getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
public void setArgs(Object[] args) {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public Where(String sql, Object[] args) {
|
||||
this.sql = sql;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private StringBuilder sb = new StringBuilder();
|
||||
private List<Object> argsList = new ArrayList<>();
|
||||
|
||||
public Builder eq(String name, Object value) {
|
||||
return eq(true, name, value);
|
||||
}
|
||||
|
||||
public Builder like(String name, Object value) {
|
||||
return like(true, name, value);
|
||||
}
|
||||
|
||||
public Builder isNull(String name, Object value) {
|
||||
return isNull(true, name, value);
|
||||
}
|
||||
|
||||
public Builder isNotNull(String name, Object value) {
|
||||
return isNotNull(true, name, value);
|
||||
}
|
||||
|
||||
public Builder eq(boolean condition, String name, Object value) {
|
||||
if (condition) {
|
||||
sb.append(sb.length() > 0 ? " and " : " where ").append(name).append(" = ? ");
|
||||
argsList.add(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder like(boolean condition, String name, Object value) {
|
||||
if (condition) {
|
||||
sb.append(sb.length() > 0 ? " and " : " where ").append(name).append("like ?");
|
||||
argsList.add(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder isNull(boolean condition, String name, Object value) {
|
||||
if (condition) {
|
||||
sb.append(sb.length() > 0 ? " and " : " where ").append(name).append("is null");
|
||||
argsList.add(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder isNotNull(boolean condition, String name, Object value) {
|
||||
if (condition) {
|
||||
sb.append(sb.length() > 0 ? " and " : " where ").append(name).append("is not null");
|
||||
argsList.add(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Where build() {
|
||||
return new Where(sb.toString(), argsList.toArray());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package xyz.wbsite.itchat4j.db.anonation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface TableField {
|
||||
|
||||
int value() default 20;
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
package xyz.wbsite.itchat4j.db.entity;
|
||||
|
||||
|
||||
import xyz.wbsite.itchat4j.db.anonation.TableField;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class Example {
|
||||
|
||||
@TableField(40)
|
||||
private String s;
|
||||
@TableField
|
||||
private boolean b;
|
||||
@TableField
|
||||
private byte[] bs;
|
||||
@TableField
|
||||
private byte b1;
|
||||
@TableField
|
||||
private short s1;
|
||||
@TableField
|
||||
private int age;
|
||||
@TableField
|
||||
private long id;
|
||||
@TableField
|
||||
private float f1;
|
||||
@TableField
|
||||
private double d1;
|
||||
@TableField
|
||||
private Date date;
|
||||
|
||||
public String getS() {
|
||||
return s;
|
||||
}
|
||||
|
||||
public void setS(String s) {
|
||||
this.s = s;
|
||||
}
|
||||
|
||||
public boolean isB() {
|
||||
return b;
|
||||
}
|
||||
|
||||
public void setB(boolean b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public byte[] getBs() {
|
||||
return bs;
|
||||
}
|
||||
|
||||
public void setBs(byte[] bs) {
|
||||
this.bs = bs;
|
||||
}
|
||||
|
||||
public byte getB1() {
|
||||
return b1;
|
||||
}
|
||||
|
||||
public void setB1(byte b1) {
|
||||
this.b1 = b1;
|
||||
}
|
||||
|
||||
public short getS1() {
|
||||
return s1;
|
||||
}
|
||||
|
||||
public void setS1(short s1) {
|
||||
this.s1 = s1;
|
||||
}
|
||||
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(int age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public float getF1() {
|
||||
return f1;
|
||||
}
|
||||
|
||||
public void setF1(float f1) {
|
||||
this.f1 = f1;
|
||||
}
|
||||
|
||||
public double getD1() {
|
||||
return d1;
|
||||
}
|
||||
|
||||
public void setD1(double d1) {
|
||||
this.d1 = d1;
|
||||
}
|
||||
|
||||
public Date getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(Date date) {
|
||||
this.date = date;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package xyz.wbsite.itchat4j.ui;
|
||||
|
||||
import xyz.wbsite.itchat4j.util.ResourceUtil;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* FXML工具
|
||||
*
|
||||
* @author wangbing
|
||||
* @version 0.0.1
|
||||
* @since 1.8
|
||||
*/
|
||||
public class FXMLUtil {
|
||||
|
||||
/**
|
||||
* 加载FXMLLoader
|
||||
*
|
||||
* @param fxml 资源路径
|
||||
* @return
|
||||
*/
|
||||
public static FXMLLoader load(String fxml) throws IOException {
|
||||
if (!fxml.startsWith("classpath:")) {
|
||||
fxml = "classpath:" + fxml;
|
||||
}
|
||||
URL resource = ResourceUtil.getURL(fxml);
|
||||
FXMLLoader fxmlLoader = new FXMLLoader(resource);
|
||||
fxmlLoader.load();
|
||||
return fxmlLoader;
|
||||
}
|
||||
}
|
@ -0,0 +1,269 @@
|
||||
package xyz.wbsite.itchat4j.util;
|
||||
|
||||
import cn.hutool.core.util.ClassUtil;
|
||||
import xyz.wbsite.itchat4j.JMainApplication;
|
||||
import javafx.animation.KeyFrame;
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ButtonBar;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ProgressIndicator;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.text.Font;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.util.Duration;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Optional;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
public class DialogUtil {
|
||||
|
||||
private static Stage popup;
|
||||
|
||||
public static void toast(String msg, long time) {
|
||||
Label label = new Label(msg);//默认信息
|
||||
label.setStyle("-fx-background: rgba(56,56,56,0.7);-fx-border-radius: 25;-fx-background-radius: 25");//label透明,圆角
|
||||
label.setTextFill(Color.rgb(225, 255, 226));//消息字体颜色
|
||||
label.setPrefHeight(50);
|
||||
label.setPadding(new Insets(15));
|
||||
label.setAlignment(Pos.CENTER);//居中
|
||||
label.setFont(new Font(20));//字体大小
|
||||
Scene scene = new Scene(label);
|
||||
scene.setFill(null);//场景透明
|
||||
Stage stage = new Stage();
|
||||
stage.initModality(Modality.WINDOW_MODAL);
|
||||
stage.setAlwaysOnTop(false);
|
||||
stage.setScene(scene);
|
||||
label.setText(msg);
|
||||
TimerTask task = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
Platform.runLater(stage::close);
|
||||
}
|
||||
};
|
||||
|
||||
Timer timer = new Timer();
|
||||
timer.schedule(task, time);
|
||||
stage.show();
|
||||
}
|
||||
|
||||
public static void showTimedDialog(final long time, String message) {
|
||||
popup = new Stage();
|
||||
popup.setAlwaysOnTop(true);
|
||||
popup.initModality(Modality.APPLICATION_MODAL);
|
||||
final Button closeBtn = new Button("知道了");
|
||||
closeBtn.setOnAction(event -> popup.close());
|
||||
VBox root = new VBox();
|
||||
root.setPadding(new Insets(10));
|
||||
root.setAlignment(Pos.BASELINE_CENTER);
|
||||
root.setSpacing(10);
|
||||
root.getChildren().addAll(new Label(message), closeBtn);
|
||||
Scene scene = new Scene(root);
|
||||
popup.setScene(scene);
|
||||
popup.setTitle("提示信息");
|
||||
popup.show();
|
||||
|
||||
Thread thread = new Thread(() -> {
|
||||
try {
|
||||
Thread.sleep(time);
|
||||
if (popup.isShowing()) {
|
||||
Platform.runLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
popup.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (Exception exp) {
|
||||
exp.printStackTrace();
|
||||
}
|
||||
});
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public static void alert(String message) {
|
||||
Platform.runLater(() -> {
|
||||
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
|
||||
Stage stage = (Stage) alert.getDialogPane().getScene().getWindow();
|
||||
stage.getIcons().add(new Image(ResourceUtil.getInput("icon.png")));
|
||||
stage.setAlwaysOnTop(true);
|
||||
alert.setHeaderText(null);
|
||||
alert.setTitle("提示");
|
||||
alert.setContentText(message);
|
||||
alert.getButtonTypes().remove(ButtonType.CANCEL);
|
||||
alert.setX(JMainApplication.primaryStage.getX() + JMainApplication.primaryStage.getWidth() / 2 - 213);
|
||||
alert.setY(JMainApplication.primaryStage.getY() + JMainApplication.primaryStage.getHeight() / 2 - 70);
|
||||
Optional<ButtonType> buttonType = alert.showAndWait();
|
||||
});
|
||||
}
|
||||
|
||||
public static void confirm(String message) {
|
||||
confirm("提示", message, null);
|
||||
}
|
||||
|
||||
public static void confirm(String title, String message) {
|
||||
confirm(title, message, null);
|
||||
}
|
||||
|
||||
public static void confirm(String title, String message, ConfirmCall call) {
|
||||
Platform.runLater(() -> {
|
||||
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
|
||||
Stage stage = (Stage) alert.getDialogPane().getScene().getWindow();
|
||||
stage.getIcons().add(new Image(ResourceUtil.getInput("icon.png")));
|
||||
stage.setAlwaysOnTop(true);
|
||||
alert.setHeaderText(null);
|
||||
alert.setTitle(title);
|
||||
alert.setContentText(message);
|
||||
alert.setX(JMainApplication.primaryStage.getX() + JMainApplication.primaryStage.getWidth() / 2 - 213);
|
||||
alert.setY(JMainApplication.primaryStage.getY() + JMainApplication.primaryStage.getHeight() / 2 - 70);
|
||||
Optional<ButtonType> buttonType = alert.showAndWait();
|
||||
if (call != null) {
|
||||
if (ButtonBar.ButtonData.OK_DONE.getTypeCode().equals(buttonType.get().getButtonData().getTypeCode())) {
|
||||
call.call(true);
|
||||
} else {
|
||||
call.call(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void error(String message) {
|
||||
Platform.runLater(() -> {
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
Stage stage = (Stage) alert.getDialogPane().getScene().getWindow();
|
||||
stage.setAlwaysOnTop(true);
|
||||
stage.getIcons().add(new Image(ResourceUtil.getInput("icon.png")));
|
||||
alert.setTitle("错误");
|
||||
alert.setX(JMainApplication.primaryStage.getX() + JMainApplication.primaryStage.getWidth() / 2 - 213);
|
||||
alert.setY(JMainApplication.primaryStage.getY() + JMainApplication.primaryStage.getHeight() / 2 - 70);
|
||||
alert.setHeaderText("");
|
||||
alert.setContentText(message);
|
||||
alert.show();
|
||||
});
|
||||
}
|
||||
|
||||
public static void success(String message) {
|
||||
Platform.runLater(() -> {
|
||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||
Stage stage = (Stage) alert.getDialogPane().getScene().getWindow();
|
||||
stage.getIcons().add(new Image(ResourceUtil.getInput("icon.png")));
|
||||
alert.setTitle("消息");
|
||||
alert.setX(JMainApplication.primaryStage.getX() + JMainApplication.primaryStage.getWidth() / 2 - 213);
|
||||
alert.setY(JMainApplication.primaryStage.getY() + JMainApplication.primaryStage.getHeight() / 2 - 70);
|
||||
alert.setHeaderText("");
|
||||
alert.setContentText(message);
|
||||
alert.show();
|
||||
});
|
||||
}
|
||||
|
||||
private static javafx.scene.control.Dialog dialog = null;
|
||||
|
||||
public static void loading(String message) {
|
||||
loading(message, null);
|
||||
}
|
||||
|
||||
public static void loading(String message, CancelCall cancelCall) {
|
||||
if (dialog != null) return;
|
||||
Platform.runLater(() -> {
|
||||
dialog = new javafx.scene.control.Dialog();
|
||||
dialog.setTitle("提示");
|
||||
Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow();
|
||||
stage.getIcons().add(new Image(ResourceUtil.getInput("icon.png")));
|
||||
dialog.setResult("1");
|
||||
dialog.setX(JMainApplication.primaryStage.getX() + JMainApplication.primaryStage.getWidth() / 2 - 68);
|
||||
dialog.setY(JMainApplication.primaryStage.getY() + JMainApplication.primaryStage.getHeight() / 2 - 70);
|
||||
GridPane gridPane = new GridPane();
|
||||
gridPane.setPrefWidth(200);
|
||||
gridPane.setHgap(10);
|
||||
gridPane.setVgap(10);
|
||||
gridPane.setAlignment(Pos.CENTER);
|
||||
gridPane.setPadding(new Insets(10, 10, 10, 10));
|
||||
dialog.getDialogPane().setContent(gridPane);
|
||||
|
||||
ProgressIndicator indicator = new ProgressIndicator();
|
||||
indicator.setPrefSize(30, 30);
|
||||
gridPane.add(indicator, 0, 0);
|
||||
gridPane.add(new Label(message), 0, 1);
|
||||
|
||||
if (cancelCall != null) {
|
||||
Button cancel = new Button("取消");
|
||||
gridPane.add(cancel, 0, 2);
|
||||
cancel.setOnMouseClicked(new EventHandler<MouseEvent>() {
|
||||
@Override
|
||||
public void handle(MouseEvent event) {
|
||||
cancelCall.call();
|
||||
}
|
||||
});
|
||||
}
|
||||
dialog.show();
|
||||
});
|
||||
}
|
||||
|
||||
public static void hideLoading() {
|
||||
if (dialog == null) return;
|
||||
Platform.runLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
dialog.close();
|
||||
dialog = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public interface InputCall {
|
||||
void call(String input);
|
||||
}
|
||||
|
||||
public interface ConfirmCall {
|
||||
void call(boolean result);
|
||||
}
|
||||
|
||||
public interface DirectoryCall {
|
||||
void call(File result);
|
||||
}
|
||||
|
||||
public interface CancelCall {
|
||||
void call();
|
||||
}
|
||||
|
||||
/**
|
||||
* 给组件增加鼠标悬浮提示
|
||||
*
|
||||
* @param node
|
||||
* @param tip
|
||||
*/
|
||||
public static void installTip(Node node, String tip) {
|
||||
Tooltip tooltip = new Tooltip(tip);
|
||||
try {
|
||||
java.lang.reflect.Field behavior = ClassUtil.getDeclaredField(Tooltip.class, "BEHAVIOR");
|
||||
behavior.setAccessible(true);
|
||||
Object o = behavior.get(tooltip);
|
||||
java.lang.reflect.Field activationTimer = ClassUtil.getDeclaredField(o.getClass(), "activationTimer");
|
||||
activationTimer.setAccessible(true);
|
||||
Timeline timeline = (Timeline) activationTimer.get(o);
|
||||
timeline.getKeyFrames().remove(0);
|
||||
timeline.getKeyFrames().add(new KeyFrame(new Duration(10)));
|
||||
} catch (Exception ignored) {
|
||||
|
||||
}
|
||||
Tooltip.install(node, tooltip);
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package xyz.wbsite.itchat4j.util;
|
||||
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.lang.caller.CallerUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.log.level.Level;
|
||||
import xyz.wbsite.itchat4j.JMainApplication;
|
||||
|
||||
/**
|
||||
* 日志记录器
|
||||
*
|
||||
* @author wangbing
|
||||
* @version 0.0.1
|
||||
* @since 1.8
|
||||
*/
|
||||
public class Logger {
|
||||
|
||||
public static void info(String format, Object... arg) {
|
||||
// 获取当前时间
|
||||
DateTime date = DateUtil.date();
|
||||
// 获取日志级别
|
||||
String level = Level.INFO.toString();
|
||||
// 格式化日志信息
|
||||
String log = StrUtil.format(format, arg);
|
||||
// 获取调用者类名
|
||||
String name = CallerUtil.getCallerCaller().getSimpleName();
|
||||
// 获取当前线程的堆栈追踪
|
||||
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||
// 通常堆栈追踪数组的第三个元素是logMessage方法的调用者
|
||||
int lineNumber = stackTrace[2].getLineNumber();
|
||||
// 打印日志信息
|
||||
JMainApplication.mainController.println("[{}] [{}] {} [{}:{}]", date, level, log, name, lineNumber);
|
||||
}
|
||||
|
||||
public static void error(String format, Object... arg) {
|
||||
// 获取当前时间
|
||||
DateTime date = DateUtil.date();
|
||||
// 获取日志级别
|
||||
String level = Level.ERROR.toString();
|
||||
// 格式化日志信息
|
||||
String log = StrUtil.format(format, arg);
|
||||
// 获取调用者类名
|
||||
String name = CallerUtil.getCallerCaller().getSimpleName();
|
||||
// 获取当前线程的堆栈追踪
|
||||
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||
// 通常堆栈追踪数组的第三个元素是logMessage方法的调用者
|
||||
int lineNumber = stackTrace[2].getLineNumber();
|
||||
// 打印日志信息
|
||||
JMainApplication.mainController.println("[{}] [{}] {} [{}:{}]", date, level, log, name, lineNumber);
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package xyz.wbsite.itchat4j.util;
|
||||
|
||||
import cn.hutool.core.io.resource.ClassPathResource;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* 资源工具
|
||||
*
|
||||
* @author wangbing
|
||||
* @version 0.0.1
|
||||
* @since 1.8
|
||||
*/
|
||||
public class ResourceUtil extends cn.hutool.core.io.resource.ResourceUtil {
|
||||
|
||||
/**
|
||||
* 获取资源输入流,以/开始
|
||||
*
|
||||
* @return 资源路径
|
||||
*/
|
||||
public static InputStream getInput(String resourceLocation) {
|
||||
if (resourceLocation.startsWith("/")) {
|
||||
resourceLocation = "/" + resourceLocation;
|
||||
}
|
||||
ClassPathResource classPathResource = new ClassPathResource(resourceLocation);
|
||||
return classPathResource.getStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取资源路径
|
||||
*
|
||||
* @param resourceLocation 资源
|
||||
*/
|
||||
public static URL getURL(String resourceLocation) throws FileNotFoundException {
|
||||
if (resourceLocation.startsWith("classpath:")) {
|
||||
String path = resourceLocation.substring("classpath:".length());
|
||||
ClassLoader cl = FXMLLoader.getDefaultClassLoader();
|
||||
URL url = cl != null ? cl.getResource(path) : ClassLoader.getSystemResource(path);
|
||||
if (url == null) {
|
||||
String description = "class path resource [" + path + "]";
|
||||
throw new FileNotFoundException(description + " cannot be resolved to URL because it does not exist");
|
||||
} else {
|
||||
return url;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
return new URL(resourceLocation);
|
||||
} catch (MalformedURLException var6) {
|
||||
try {
|
||||
return (new File(resourceLocation)).toURI().toURL();
|
||||
} catch (MalformedURLException var5) {
|
||||
throw new FileNotFoundException("Resource location [" + resourceLocation + "] is neither a URL not a well-formed file path");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 1.0 KiB |
@ -0,0 +1,12 @@
|
||||
/* styles.css */
|
||||
.text-area,
|
||||
.text-area:focused,
|
||||
.text-area:unfocused,
|
||||
.text-area:disabled {
|
||||
-fx-control-inner-background: transparent;
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
|
||||
.text-area .content {
|
||||
-fx-background-color: transparent;
|
||||
}
|
Loading…
Reference in new issue