Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop #180

Merged
merged 20 commits into from
Jul 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
99db139
first step boost mode
rememberber Jul 7, 2019
6f609a3
first step boost mode
rememberber Jul 8, 2019
d06ef4c
test:boost mode test
rememberber Jul 9, 2019
e794b47
test:boost mode test
rememberber Jul 9, 2019
006ad2e
test:boost mode test
rememberber Jul 11, 2019
0e7b37f
feature:性能模式按计划执行
rememberber Jul 12, 2019
b2d5173
feature:性能模式停止按钮
rememberber Jul 12, 2019
df29e60
bug fix:修复计划任务保存提示最近5次运行时间提示问题,修复性能模式计划任务执行为普通模式的问题
rememberber Jul 13, 2019
07237be
bug fix:修复性能模式控制台log输出有误的问题
rememberber Jul 13, 2019
2564656
bug fix:空跑时不应该提示正在保存数据
rememberber Jul 13, 2019
3a8081e
feature:模板消息性能模式初版
rememberber Jul 13, 2019
94abd0e
feature:邮件消息表增加抄送字段
rememberber Jul 13, 2019
82cf4ab
feature:e-mail消息支持抄送
rememberber Jul 13, 2019
76590a2
optimization:更新版本号,优化平滑升级时sql执行幂等
rememberber Jul 13, 2019
511b7a9
feature:企业微信消息增加对文本卡片和markdown类型的支持
rememberber Jul 13, 2019
50b5144
release:v_3.5.0_190713
rememberber Jul 13, 2019
f2f4ef2
optimization:修改发送结果报告邮件中的二维码链接
rememberber Jul 14, 2019
a70faca
feature:性能模式 停止功能 第一阶段
rememberber Jul 14, 2019
4a5f839
feature:性能模式 停止功能 完毕
rememberber Jul 14, 2019
44a32f3
update:更新下载地址
rememberber Jul 14, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions download.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
<details>
<summary>Windows</summary>

[WePush-v3.5.0_190713-x64-Setup.exe](http://download.zhoubochina.com/exe/WePush-v3.5.0_190713-x64-Setup.exe)
[WePush-with-jre-v3.5.0_190713-x64-Setup.exe](http://download.zhoubochina.com/exe/WePush-with-jre-v3.5.0_190713-x64-Setup.exe)
[WePush-v3.4.2_190630-x64-Setup.exe](http://download.zhoubochina.com/exe/WePush-v3.4.2_190630-x64-Setup.exe)
[WePush-with-jre-v3.4.2_190630-x64-Setup.exe](http://download.zhoubochina.com/exe/WePush-with-jre-v3.4.2_190630-x64-Setup.exe)
[WePush-v3.4.1_190624-x64-Setup.exe](http://download.zhoubochina.com/exe/WePush-v3.4.1_190624-x64-Setup.exe)
Expand Down Expand Up @@ -59,6 +61,7 @@
<details>
<summary>Mac OS</summary>

[v_3.5.0_190713.app](http://download.zhoubochina.com/mac/3.5.0.zip)
[v_3.4.1_190624.app](http://download.zhoubochina.com/mac/3.4.1.zip)
[v_3.4.2_190630.app](http://download.zhoubochina.com/mac/3.4.2.zip)
[v_3.4.0_190619.app](http://download.zhoubochina.com/mac/3.4.0.zip)
Expand Down Expand Up @@ -95,6 +98,7 @@
<details>
<summary>Linux</summary>

[v3.5.0_190713](http://download.zhoubochina.com/linux/WePush-3.5.0.zip)
[v3.4.2_190630](http://download.zhoubochina.com/linux/WePush-3.4.2.zip)
[v3.4.1_190624](http://download.zhoubochina.com/linux/WePush-3.4.1.zip)
[v3.4.0_190619](http://download.zhoubochina.com/linux/WePush-3.4.0.zip)
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/com/fangxuele/tool/push/bean/MailMsg.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ public class MailMsg implements Serializable {
*/
private String mailTitle;

/**
* 抄送
*/
private String mailCc;

/**
* 附件
*/
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/com/fangxuele/tool/push/domain/TMsgMail.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public class TMsgMail implements Serializable {

private String modifiedTime;

private String cc;

private static final long serialVersionUID = 1L;

public Integer getId() {
Expand Down Expand Up @@ -84,4 +86,12 @@ public String getModifiedTime() {
public void setModifiedTime(String modifiedTime) {
this.modifiedTime = modifiedTime == null ? null : modifiedTime.trim();
}

public String getCc() {
return cc;
}

public void setCc(String cc) {
this.cc = cc == null ? null : cc.trim();
}
}
10 changes: 10 additions & 0 deletions src/main/java/com/fangxuele/tool/push/domain/TMsgWxCp.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public class TMsgWxCp implements Serializable {

private String modifiedTime;

private String btnTxt;

private static final long serialVersionUID = 1L;

public Integer getId() {
Expand Down Expand Up @@ -124,4 +126,12 @@ public String getModifiedTime() {
public void setModifiedTime(String modifiedTime) {
this.modifiedTime = modifiedTime == null ? null : modifiedTime.trim();
}

public String getBtnTxt() {
return btnTxt;
}

public void setBtnTxt(String btnTxt) {
this.btnTxt = btnTxt == null ? null : btnTxt.trim();
}
}
178 changes: 178 additions & 0 deletions src/main/java/com/fangxuele/tool/push/logic/BoostPushRunThread.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package com.fangxuele.tool.push.logic;

import cn.hutool.core.date.BetweenFormater;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.cron.pattern.CronPattern;
import cn.hutool.cron.pattern.CronPatternUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.fangxuele.tool.push.App;
import com.fangxuele.tool.push.logic.msgsender.IMsgSender;
import com.fangxuele.tool.push.logic.msgsender.MsgSenderFactory;
import com.fangxuele.tool.push.logic.msgthread.MsgAsyncSendThread;
import com.fangxuele.tool.push.ui.form.BoostForm;
import com.fangxuele.tool.push.util.ConsoleUtil;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.http.HttpResponse;

import javax.swing.*;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Future;

/**
* <pre>
* 性能模式推送执行控制线程
* </pre>
*
* @author <a href="https://github.com/rememberber">RememBerBer</a>
* @since 2019/7/7.
*/
public class BoostPushRunThread extends Thread {

private static final Log logger = LogFactory.get();

public static List<Future<HttpResponse>> futureList = Lists.newArrayList();

@Override
public void run() {
BoostForm.boostForm.getProcessedProgressBar().setIndeterminate(true);
BoostForm.boostForm.getCompletedProgressBar().setIndeterminate(true);
// 准备推送
preparePushRun();
BoostForm.boostForm.getProcessedProgressBar().setIndeterminate(false);
BoostForm.boostForm.getCompletedProgressBar().setIndeterminate(false);
ConsoleUtil.boostConsoleWithLog("推送开始……");
// 消息数据分片以及线程纷发
shardingAndMsgThread();
// 时间监控
timeMonitor();
}

/**
* 准备推送
*/
private void preparePushRun() {
// 按钮状态
BoostForm.boostForm.getScheduledRunButton().setEnabled(false);
BoostForm.boostForm.getStartButton().setEnabled(false);
BoostForm.boostForm.getStopButton().setEnabled(true);

BoostForm.boostForm.getStopButton().setText("停止");
// 初始化
BoostForm.boostForm.getProcessedCountLabel().setText("0");
BoostForm.boostForm.getSuccessCountLabel().setText("0");
BoostForm.boostForm.getFailCountLabel().setText("0");

// 设置是否空跑
PushControl.dryRun = BoostForm.boostForm.getDryRunCheckBox().isSelected();

// 执行前重新导入目标用户
PushControl.reimportMembers();

// 重置推送数据
PushData.reset();
PushData.startTime = System.currentTimeMillis();

// 拷贝准备的目标用户
PushData.toSendList.addAll(PushData.allUser);
PushData.toSendCount.set(PushData.allUser.size());
// 总记录数
PushData.totalRecords = PushData.toSendList.size();

BoostForm.boostForm.getMemberCountLabel().setText("消息总数:" + PushData.totalRecords);
BoostForm.boostForm.getProcessedProgressBar().setMaximum((int) PushData.totalRecords);
BoostForm.boostForm.getCompletedProgressBar().setMaximum((int) PushData.totalRecords);
ConsoleUtil.boostConsoleWithLog("消息总数:" + PushData.totalRecords);
// 可用处理器核心数量
BoostForm.boostForm.getProcessorCountLabel().setText("可用处理器核心:" + Runtime.getRuntime().availableProcessors());
ConsoleUtil.boostConsoleWithLog("可用处理器核心:" + Runtime.getRuntime().availableProcessors());

// 准备消息构造器
PushControl.prepareMsgMaker();
}

/**
* 消息数据分片以及线程纷发
*/
private static void shardingAndMsgThread() {

MsgAsyncSendThread msgAsyncSendThread;

IMsgSender msgSender = MsgSenderFactory.getMsgSender();
msgAsyncSendThread = new MsgAsyncSendThread(msgSender);

ThreadUtil.execute(msgAsyncSendThread);
ConsoleUtil.boostConsoleWithLog("线程启动完毕……");
}

/**
* 时间监控
*/
private void timeMonitor() {
long startTimeMillis = System.currentTimeMillis();
// 计时
while (true) {
if (PushData.toSendCount.get() <= PushData.successRecords.longValue() + PushData.failRecords.longValue()) {
if (!PushData.fixRateScheduling) {
BoostForm.boostForm.getStopButton().setEnabled(false);
BoostForm.boostForm.getStopButton().updateUI();
BoostForm.boostForm.getStartButton().setEnabled(true);
BoostForm.boostForm.getStartButton().updateUI();
BoostForm.boostForm.getScheduledRunButton().setEnabled(true);
BoostForm.boostForm.getScheduledRunButton().updateUI();
BoostForm.boostForm.getScheduledTaskLabel().setText("");
String finishTip = "发送完毕!\n";
JOptionPane.showMessageDialog(BoostForm.boostForm.getBoostPanel(), finishTip, "提示",
JOptionPane.INFORMATION_MESSAGE);
BoostForm.boostForm.getScheduledTaskLabel().setVisible(false);
} else {
if (App.config.isRadioCron()) {
Date nextDate = CronPatternUtil.nextDateAfter(new CronPattern(App.config.getTextCron()), new Date(), true);
BoostForm.boostForm.getScheduledTaskLabel().setText("计划任务执行中,下一次执行时间:" + DateFormatUtils.format(nextDate, "yyyy-MM-dd HH:mm:ss"));
}
BoostForm.boostForm.getStopButton().setText("停止计划任务");
}

PushData.endTime = System.currentTimeMillis();

// 保存停止前的数据
try {
// 空跑控制
if (!BoostForm.boostForm.getDryRunCheckBox().isSelected()) {
ConsoleUtil.boostConsoleWithLog("正在保存结果数据……");
BoostForm.boostForm.getCompletedProgressBar().setIndeterminate(true);
PushControl.savePushData();
ConsoleUtil.boostConsoleWithLog("结果数据保存完毕!");
}
} catch (IOException e) {
logger.error(e);
} finally {
BoostForm.boostForm.getCompletedProgressBar().setIndeterminate(false);
}
break;
}

long currentTimeMillis = System.currentTimeMillis();
long lastTimeMillis = currentTimeMillis - startTimeMillis;
long leftTimeMillis = (long) ((double) lastTimeMillis / (PushData.sendSuccessList.size() + PushData.sendFailList.size()) * (PushData.allUser.size() - PushData.sendSuccessList.size() - PushData.sendFailList.size()));

// 耗时
String formatBetweenLast = DateUtil.formatBetween(lastTimeMillis, BetweenFormater.Level.SECOND);
BoostForm.boostForm.getLastTimeLabel().setText("".equals(formatBetweenLast) ? "0s" : formatBetweenLast);

// 预计剩余
String formatBetweenLeft = DateUtil.formatBetween(leftTimeMillis, BetweenFormater.Level.SECOND);
BoostForm.boostForm.getLeftTimeLabel().setText("".equals(formatBetweenLeft) ? "0s" : formatBetweenLeft);

BoostForm.boostForm.getJvmMemoryLabel().setText("JVM内存占用:" + FileUtil.readableFileSize(Runtime.getRuntime().totalMemory()) + "/" + FileUtil.readableFileSize(Runtime.getRuntime().maxMemory()));

ThreadUtil.safeSleep(100);
}
}

}
69 changes: 66 additions & 3 deletions src/main/java/com/fangxuele/tool/push/logic/PushControl.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
import com.fangxuele.tool.push.logic.msgsender.MailMsgSender;
import com.fangxuele.tool.push.logic.msgsender.MsgSenderFactory;
import com.fangxuele.tool.push.logic.msgsender.SendResult;
import com.fangxuele.tool.push.ui.UiConsts;
import com.fangxuele.tool.push.ui.form.MainWindow;
import com.fangxuele.tool.push.ui.form.MessageEditForm;
import com.fangxuele.tool.push.ui.form.PushForm;
import com.fangxuele.tool.push.ui.form.PushHisForm;
import com.fangxuele.tool.push.ui.form.ScheduleForm;
import com.fangxuele.tool.push.ui.form.SettingForm;
Expand Down Expand Up @@ -68,7 +71,7 @@ public class PushControl {
*/
public static List<SendResult> preview() {
List<SendResult> sendResultList = new ArrayList<>();
if (!pushCheck()) {
if (!configCheck()) {
return null;
}
List<String[]> msgDataList = new ArrayList<>();
Expand Down Expand Up @@ -97,7 +100,44 @@ public static List<SendResult> preview() {
*
* @return boolean
*/
static boolean pushCheck() {
public static boolean pushCheck() {
if (StringUtils.isEmpty(MessageEditForm.messageEditForm.getMsgNameField().getText())) {
JOptionPane.showMessageDialog(MainWindow.mainWindow.getMainPanel(), "请先选择一条消息!", "提示",
JOptionPane.INFORMATION_MESSAGE);
MainWindow.mainWindow.getTabbedPane().setSelectedIndex(2);

return false;
}
if (PushData.allUser == null || PushData.allUser.size() == 0) {
JOptionPane.showMessageDialog(MainWindow.mainWindow.getMainPanel(), "请先准备目标用户!", "提示",
JOptionPane.INFORMATION_MESSAGE);

return false;
}
if (!PushData.boostMode) {
if ("0".equals(PushForm.pushForm.getMaxThreadPoolTextField().getText()) || StringUtils.isEmpty(PushForm.pushForm.getMaxThreadPoolTextField().getText())) {
JOptionPane.showMessageDialog(PushForm.pushForm.getPushPanel(), "请设置每页分配用户数!", "提示",
JOptionPane.INFORMATION_MESSAGE);

return false;
}
if ("0".equals(PushForm.pushForm.getThreadCountTextField().getText()) || StringUtils.isEmpty(PushForm.pushForm.getThreadCountTextField().getText())) {
JOptionPane.showMessageDialog(PushForm.pushForm.getPushPanel(), "请设置每个线程分配的页数!", "提示",
JOptionPane.INFORMATION_MESSAGE);

return false;
}
}

return configCheck();
}

/**
* 配置检查
*
* @return
*/
public static boolean configCheck() {
int msgType = App.config.getMsgType();
switch (msgType) {
case MessageTypeEnum.MP_TEMPLATE_CODE:
Expand Down Expand Up @@ -293,7 +333,7 @@ static void savePushData() throws IOException {
contentBuilder.append("<br/>");
contentBuilder.append("<hr/>");
contentBuilder.append("<p>来自WePush,一款专注于批量推送的小而美的工具</p>");
contentBuilder.append("<img alt=\"WePush\" src=\"http://download.zhoubochina.com/file/wx-zanshang.jpg\">");
contentBuilder.append("<img alt=\"WePush\" src=\"" + UiConsts.INTRODUCE_QRCODE_URL + "\">");

File[] files = new File[fileList.size()];
fileList.toArray(files);
Expand Down Expand Up @@ -363,4 +403,27 @@ static void prepareMsgMaker() {
}
}

/**
* 重新导入目标用户(定时任务)
*/
public static void reimportMembers() {
if (PushData.fixRateScheduling && ScheduleForm.scheduleForm.getReimportCheckBox().isSelected()) {
switch ((String) ScheduleForm.scheduleForm.getReimportComboBox().getSelectedItem()) {
case "通过SQL导入":
MemberListener.importFromSql();
break;
case "通过文件导入":
MemberListener.importFromFile();
break;
case "导入所有关注公众号的用户":
MemberListener.importWxAll();
break;
case "导入企业通讯录中所有用户":
MemberListener.importWxCpAll();
break;
default:
}
}
}

}
Loading