邮件模块开发完成版本

master
土豆兄弟 4 years ago
parent 2d7aca22d2
commit 286145e1cd

@ -0,0 +1,2 @@
## 生成代码配置
pom 注释 sharding相关的依赖,切换druid依赖,配置环境用 single

@ -18,6 +18,7 @@ public enum ResponseCode {
ILLEGAL_ARGUMENT(1,"请求参数格式错误"),
EMPTY_ARGUMENT(1,"请求参数为空"),
NO_MATCH_ARGUMENT_SET(1,"不能满足要求的参数设置"),
NO_FILE_INPUT(1,"没有文件输入"),
// 特殊需要进行前端返回说明的参数定义
TASK_NAME_IS_EXIST(1,"任务名称已经存在"),
// 请求结果性的错误

@ -0,0 +1,23 @@
package me.zhengjie.common.json;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* Json
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OnceLinkMsgJsonContent implements Serializable {
/**
*
*/
private String onceLink;
}

@ -229,6 +229,27 @@ public class FileUtil extends cn.hutool.core.io.FileUtil {
IoUtil.close(out);
}
/**
* excel
*
* @param file
* @param response
* @throws IOException
*/
public static void downloadExcel(File file, HttpServletResponse response) throws IOException {
BigExcelWriter writer = ExcelUtil.getBigWriter(file);
//response为HttpServletResponse对象
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
//test.xls是弹出下载对话框的文件名不能为中文中文请自行编码
response.setHeader("Content-Disposition", "attachment;filename=file.xlsx");
ServletOutputStream out = response.getOutputStream();
// 终止后删除临时文件
file.deleteOnExit();
writer.flush(out, true);
//此处记得关闭输出Servlet流
IoUtil.close(out);
}
public static String getFileType(String type) {
String documents = "txt doc pdf ppt pps xlsx xls docx";
String music = "mp3 wav wma mpa ram ra aac aif m4a";

@ -29,7 +29,6 @@ import me.zhengjie.modules.buildrecord.service.dto.BuildRecordQueryCriteria;
import me.zhengjie.modules.buildrecord.task.ProduceBigDataTask;
import me.zhengjie.modules.buildrecord.task.SendBigDataTask;
import me.zhengjie.modules.buildrecord.task.dto.SendBigDataDTO;
import me.zhengjie.modules.taskrecord.service.dto.TaskRecordDto;
import me.zhengjie.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;

@ -16,7 +16,6 @@ import me.zhengjie.modules.tag.domain.Tag;
import me.zhengjie.modules.tag.service.TagService;
import me.zhengjie.modules.tag.service.dto.TagDto;
import me.zhengjie.modules.tag.service.dto.TagQueryCriteria;
import me.zhengjie.modules.taskrecord.domain.TaskRecord;
import me.zhengjie.modules.taskrecord.service.TaskRecordService;
import me.zhengjie.modules.taskrecord.service.dto.TaskRecordDto;
import me.zhengjie.modules.taskrecord.service.dto.TaskRecordQueryCriteria;
@ -26,6 +25,8 @@ import me.zhengjie.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@ -34,10 +35,8 @@ import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
@Component
@ -53,7 +52,7 @@ public class SendBigDataTask {
/**
*
*/
private static final int SEND_LIMIT = 500;
private static final int SEND_LIMIT = 5000;
/**
*
@ -63,7 +62,7 @@ public class SendBigDataTask {
/**
* ,
*/
public static final String BASE_URL_CHAR_NUMBER = "12345";
public static final String BASE_URL_CHAR_NUMBER = "123456";
/**
* url
@ -97,20 +96,23 @@ public class SendBigDataTask {
private void runTask(BuildRecord resource, SendBigDataDTO sendBigDataDTO) {
// 根据发送任务的Id来读取发送号码表
Integer id = resource.getId();
if (id <= 0 ){
log.info("id: {} ", id);
if (id == null || id <= 0 ){
log.error("====== { ERROR , resource body is {} } =======" , resource.toString());
return;
}
BuildRecordDto buildRecordDto = buildRecordService.findById(id);
buildRecordDto.setTaskBuildId(resource.getTaskBuildId());
// 查询记录表,返回这个id去发送记录表中进行查找 - 构建发送体
TagQueryCriteria tagQueryCriteria = new TagQueryCriteria();
tagQueryCriteria.setTaskId(Long.valueOf(id));
// fixme 这里可以分页进行查询 - 目前不进行优化 - 为全查
List<TagDto> tagDtos = tagService.queryAll(tagQueryCriteria);
tagQueryCriteria.setPushStatus(NON_FINISH_SEND_STATATUS);
// 加入分页防止查不动的情况 这里可以分页进行查询 - 目前不进行优化 - 为全查
Pageable pageable = PageRequest.of(0, sendBigDataDTO.getLimit().intValue());
List<Tag> backContent = tagService.queryAllBySlice(tagQueryCriteria, pageable);
// 遍历查询等待发送的列表
List<TagDto> collect = tagDtos.stream()
.filter(one -> one.getPushStatus() == NON_FINISH_SEND_STATATUS)
List<Tag> collect = backContent.stream()
.distinct()
.limit(sendBigDataDTO.getLimit())
.collect(Collectors.toList());
// 进行去重
String resultFilePath = null;
@ -132,30 +134,34 @@ public class SendBigDataTask {
log.error("================== {read file error , please check is , file path is : {} } ================================", resultFilePath, e);
}
// 过滤的集合
Set<String> filterCollect = collect.stream().map(TagDto::getUid).filter(fileLines::contains).collect(Collectors.toSet());
Set<String> filterCollect = collect.stream().map(Tag::getUid).filter(fileLines::contains).collect(Collectors.toSet());
collect = collect.stream().filter(one -> !filterCollect.contains(one.getUid())).collect(Collectors.toList());
}
// 乱序
// Collections.shuffle(collect);
// 对需要发送的字段进行发送
batchSend(collect, sendBigDataDTO, buildRecordDto);
AtomicLong atomicLong = batchSend(collect, sendBigDataDTO, buildRecordDto);
// 对发送后的状态进行更新
resource.setIsSend(FINISH_SEND_TAG);
buildRecordDto.setIsSend(FINISH_SEND_TAG);
BuildRecord buildRecord = new BuildRecord();
try{
Long sendTotal = buildRecordDto.getSendTotal();
if (sendTotal == null){
sendTotal = 0L;
}
Long sendTotal = atomicLong.get();
// 之前要进行校验
resource.setSendTotal( sendTotal + sendBigDataDTO.getLimit());
buildRecordService.update(resource);
Long dbCount = buildRecordDto.getSendTotal();
if (dbCount == null){
dbCount = 0L;
}
buildRecordDto.setSendTotal( sendTotal + dbCount);
BeanUtil.copyProperties(buildRecordDto, buildRecord);
buildRecordService.update(buildRecord);
}catch (Exception e){
log.error("==== [ update buildRecord fail, please check ] ====",e);
log.error("==== [ update buildRecord fail, buildRecord is {}, please check ] ====", buildRecord.toString() ,e);
}
}
private void batchSend(List<TagDto> collect, SendBigDataDTO sendRecordDTO, BuildRecordDto buildRecordDto) {
List<List<TagDto>> partition = Lists.partition(collect, SEND_LIMIT);
private AtomicLong batchSend(List<Tag> collect, SendBigDataDTO sendRecordDTO, BuildRecordDto buildRecordDto) {
AtomicLong successCount = new AtomicLong(0L);
List<List<Tag>> partition = Lists.partition(collect, SEND_LIMIT);
partition.forEach(
list->{
// 调用推送地址进行推送
@ -169,8 +175,6 @@ public class SendBigDataTask {
PushDBJsonContent.Client client = new PushDBJsonContent.Client();
client.setCellphone(each.getUid());
clientList.add(client);
// 推送完成后修改状态为 已经推送
each.setPushStatus(FINISH_SEND_TAG);
}
);
pushDBJsonContent.setClientList(clientList);
@ -180,10 +184,10 @@ public class SendBigDataTask {
log.info("============ [ Pre send Json is : {} ] ============", jsonStr);
int count = 1;
// 失败重发请求3次
String address ="";
while (count <= 3){
// 对发送请求地址进行准备
String addressTag = sendRecordDTO.getAddressTag();
String address ="";
if (StringUtils.isNotBlank(addressTag)){
address = preSendReqAddress(addressTag);
log.info("========== [DB request address is {} ] =========", address);
@ -192,6 +196,14 @@ public class SendBigDataTask {
HttpResponse httpResponse = HttpUtil.sendPostReq(address, jsonStr);
if (httpResponse.isOk() && httpResponse.body().contains("true")){
log.info("========== [DB request success, response is {} ] ==========", httpResponse.body());
successCount.addAndGet(list.size());
// 把修改完状态的进行更新
List<Long> pushIds = list.stream().map(Tag::getId).collect(Collectors.toList());
Long taskId = list.get(0).getTaskId();
Integer aLong = tagService.updateAllPushStatus(pushIds, taskId);
if (aLong <= 0){
log.error("================= [update data fail , please check it .] =================");
}
break;
}else{
count ++;
@ -199,25 +211,12 @@ public class SendBigDataTask {
}
}
if (count > 3) {
log.error("========== [DB update send status fail, url is {} ] ==========", url);
return;
}
log.error("========== [DB update send status fail, url is {} ] ==========", address);
}
List<Tag> tags = new ArrayList<>();
collect.forEach(
one ->{
Tag tag = new Tag();
BeanUtil.copyProperties(one, tag);
tags.add(tag);
}
);
// 把修改完状态的进行更新
Integer aLong = tagService.saveAll(tags);
if (aLong <= 0){
log.error("================= [update data fail , please check it .] =================");
}
}
);
return successCount;
}
private String preSendReqAddress(String tag) {

@ -0,0 +1,80 @@
package me.zhengjie.modules.mailtask.rest;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import me.zhengjie.annotation.Log;
import me.zhengjie.common.http.CommonResponse;
import me.zhengjie.common.http.ResponseCode;
import me.zhengjie.common.json.OnceLinkMsgJsonContent;
import me.zhengjie.modules.mailtask.service.MailTaskService;
import me.zhengjie.modules.tmpfilerecord.service.TempFileRecordService;
import me.zhengjie.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@RestController
@RequiredArgsConstructor
@Api(tags = "tmpfilerecord管理")
@RequestMapping("/api/temp/file/")
public class MailTaskController {
private final MailTaskService mailTaskService;
@Autowired
private TempFileRecordService tempFileRecordService;
/**
* ,
*/
@Log("生成文件一次性链接")
@PostMapping("link")
@ApiOperation("生成一次性链接")
public ResponseEntity<Object> buildRequest(@RequestParam(value = "files") MultipartFile[] files){
// 校验上传是否有文件
if (files!= null && files.length<= 0){
return new ResponseEntity<>(CommonResponse.createByError(ResponseCode.NO_FILE_INPUT), HttpStatus.OK);
}
// 构建一次性链接
String result = mailTaskService.buildOnceLinkForInputFile(files);
// String jsonResult = null;
OnceLinkMsgJsonContent content = new OnceLinkMsgJsonContent();
if (StringUtils.isNotBlank(result)){
// 进行json相关的转换
content.setOnceLink(result);
// JSON parse = JSONUtil.parse(content);
//// if (parse != null){
//// jsonResult = JSONUtil.toJsonStr(parse);
//// }
}else {
return new ResponseEntity<>(CommonResponse.createByError(ResponseCode.NO_MATCH_ARGUMENT_SET), HttpStatus.OK);
}
return new ResponseEntity<>(CommonResponse.createBySuccess(content), HttpStatus.OK);
}
/**
* ,
*/
@Log("下载文件")
@GetMapping("download")
@ApiOperation("下载文件")
public ResponseEntity<Object> downLoadFile(HttpServletResponse response, HttpServletRequest request, @RequestParam(value = "rand")String rand){
// 校验参数,进行下载文件
if (StringUtils.isBlank(rand)){
return new ResponseEntity<>(CommonResponse.createByError(ResponseCode.EMPTY_ARGUMENT), HttpStatus.OK);
}
mailTaskService.downloadFilesByRandCode(rand, response, request);
return new ResponseEntity<>(CommonResponse.createBySuccess(), HttpStatus.OK);
}
}

@ -0,0 +1,25 @@
package me.zhengjie.modules.mailtask.service;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface MailTaskService {
/**
*
*
* @param files
* @return
*/
String buildOnceLinkForInputFile(MultipartFile[] files);
/**
*
*
* @param rand
*/
void downloadFilesByRandCode(String rand, HttpServletResponse response, HttpServletRequest request);
}

@ -0,0 +1,159 @@
package me.zhengjie.modules.mailtask.service.impl;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.system.OsInfo;
import cn.hutool.system.SystemUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.modules.mailtask.service.MailTaskService;
import me.zhengjie.modules.tmpfilerecord.domain.TempFileRecord;
import me.zhengjie.modules.tmpfilerecord.service.TempFileRecordService;
import me.zhengjie.modules.tmpfilerecord.service.dto.TempFileRecordDto;
import me.zhengjie.utils.FileUtil;
import me.zhengjie.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Paths;
import java.util.List;
@Service
@RequiredArgsConstructor
@Slf4j
public class MailTaskServiceImpl implements MailTaskService {
/**
*
*/
private static final String FILE_END = ".xlsx";
/**
*
*/
private static final String FILE_SPLIT = ",";
/**
*
*/
@Value("${remote.link.address}")
private String remoteFileServerAddress;
/**
* - linux
*/
@Value("${remote.link.file-base-path-linux}")
private String remoteLinkFileBasePathLinux;
/**
* - linux
*/
@Value("${remote.link.file-base-path-windows}")
private String remoteLinkFileBasePathWindows;
/**
* - linux
*/
@Value("${remote.link.file-base-path-mac}")
private String remoteLinkFileBasePathMac;
@Autowired
private TempFileRecordService tempFileRecordService;
@Override
public String buildOnceLinkForInputFile(MultipartFile[] files) {
// 路径build
StringBuilder pathBuilder = new StringBuilder();
for (MultipartFile file : files) {
String eachFilePath = buildFileWritePath();
pathBuilder.append(eachFilePath);
pathBuilder.append(FILE_SPLIT);
if (StringUtils.isBlank(eachFilePath)){
return null;
}
try {
file.transferTo(Paths.get(eachFilePath));
} catch (IOException e) {
log.error("============== [transferTo file fail, path is {} ] ==============", eachFilePath);
}
}
// 任务记录
TempFileRecord tempFileRecord = new TempFileRecord();
// 保存当次任务生成的所有日志地址,然后保存在一次,用逗号分隔
tempFileRecord.setFilePaths(pathBuilder.toString().substring(0, pathBuilder.length() - 1));
// 默认保存7天
tempFileRecord.setDays(7);
// 生成验证码
tempFileRecord.setVerificationCode(RandomUtil.randomString(11));
// 文件标记 - 生成但是未读
tempFileRecord.setFileStatus(0);
TempFileRecordDto tempFileRecordDto = tempFileRecordService.create(tempFileRecord);
if (tempFileRecordDto == null){
log.error(" ====== [ create TempFileRecordDto fail, please check it. tempFileRecord is {} ] =====", tempFileRecord.toString());
return "";
}
// 生成需要请求的接口地址
String verificationCode = tempFileRecordDto.getVerificationCode();
if (StringUtils.isBlank(verificationCode)){
log.error(" ====== [make verificationCode fail. please check .tempFileRecord is {} ] ======", tempFileRecord.toString());
return "";
}
return remoteFileServerAddress + "?" + "rand=" + verificationCode;
}
/**
*
*/
private String buildFileWritePath(){
// 获取环境配置信息
OsInfo osInfo = SystemUtil.getOsInfo();
if (osInfo.isWindows()){
FileUtil.mkdir(remoteLinkFileBasePathWindows);
// 构建存储文件
return remoteLinkFileBasePathWindows + RandomUtil.randomString(11) + FILE_END;
}else if (osInfo.isLinux()){
FileUtil.mkdir(remoteLinkFileBasePathLinux);
// 构建存储文件
return remoteLinkFileBasePathLinux + RandomUtil.randomString(11) + FILE_END;
}else if (osInfo.isMac()){
FileUtil.mkdir(remoteLinkFileBasePathMac);
// 构建存储文件
return remoteLinkFileBasePathMac + RandomUtil.randomString(11) + FILE_END;
}else {
return "";
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void downloadFilesByRandCode(String rand, HttpServletResponse response,HttpServletRequest request) {
// 根据验证码查出需要的信息
TempFileRecord tempFileRecord = tempFileRecordService.findByVerificationCode(rand.trim());
// 切分需要的文件地址
if (tempFileRecord!= null){
String filePaths = tempFileRecord.getFilePaths();
if (StringUtils.isNotBlank(filePaths)){
String[] split = filePaths.split(FILE_SPLIT);
if (split.length > 0){
for (String eachPath : split) {
// 每天一个文件写入要下载的请求中
File file = new File(eachPath);
FileUtil.downloadFile(request, response, file, false);
}
}
}
}
}
}

@ -27,6 +27,7 @@ import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
/**
@ -119,12 +120,12 @@ public class SendRecordTask {
.collect(Collectors.toList());
// 分批进行发送
batchSend(collect, sendRecordDTO, taskRecordDto);
Long aLong = batchSend(collect, sendRecordDTO, taskRecordDto);
// 对发送后的记录进行更新
TaskRecord taskRecord = new TaskRecord();
BeanUtils.copyProperties(taskRecordDto, taskRecord);
taskRecord.setId(id);
taskRecord.setSendTotal(sendTotal + limit);
taskRecord.setSendTotal(sendTotal + aLong);
taskRecord.setIsSend(FINISH_SEND_TAG);
taskRecordService.update(taskRecord);
} catch (IOException e) {
@ -133,11 +134,12 @@ public class SendRecordTask {
}
}
private void batchSend(List<String> collect, SendRecordDTO sendRecordDTO, TaskRecordDto taskRecordDto) {
private Long batchSend(List<String> collect, SendRecordDTO sendRecordDTO, TaskRecordDto taskRecordDto) {
AtomicLong successCount = new AtomicLong(0L);
List<List<String>> partition = Lists.partition(collect, SEND_LIMIT);
partition.forEach(
list->{
// TODO: 2020/9/10 0010 调用推送地址进行推送
// 调用推送地址进行推送
PushDBJsonContent pushDBJsonContent = new PushDBJsonContent();
pushDBJsonContent.setActId(sendRecordDTO.getTaskId());
pushDBJsonContent.setActName(sendRecordDTO.getSendName());
@ -169,6 +171,7 @@ public class SendRecordTask {
HttpResponse httpResponse = HttpUtil.sendPostReq(address, jsonStr);
if (httpResponse.isOk() && httpResponse.body().contains("true")){
log.info("========== [DB request success, response is {} ] ==========", httpResponse.body());
successCount.addAndGet(list.size());
break;
}else{
count ++;
@ -177,11 +180,11 @@ public class SendRecordTask {
}
if (count > 3) {
log.error("========== [DB update send status fail, url is {} ] ==========", url);
return;
}
}
}
);
return successCount.get();
}
private String preSendReqAddress(String tag) {

@ -2,7 +2,7 @@
spring:
shardingsphere:
datasource:
names: eladmin
names: eladmin,schema
eladmin:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
@ -45,6 +45,48 @@ spring:
wall:
config:
multi-statement-allow: true
schema:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
url: jdbc:log4jdbc:mysql://localhost:3306/information_schema?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&rewriteBatchedStatements=true
username: root
password: root
# 初始连接数
initial-size: 5
# 最小连接数
min-idle: 10
# 最大连接数
max-active: 20
# 获取连接超时时间
max-wait: 5000
# 连接有效性检测时间
time-between-eviction-runs-millis: 60000
# 连接在池中最小生存的时间
min-evictable-idle-time-millis: 300000
# 连接在池中最大生存的时间
max-evictable-idle-time-millis: 900000
test-while-idle: true
test-on-borrow: false
test-on-return: false
# 检测连接是否有效
validation-query: select 1
# 配置监控统计
webStatFilter:
enabled: true
stat-view-servlet:
enabled: true
url-pattern: /druid/*
reset-enable: false
filter:
stat:
enabled: true
# 记录慢SQL
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true
sharding:
# 默认数据源
default-data-source-name: eladmin
@ -180,3 +222,9 @@ logging:
tag:
split-table:
sum: 10
remote:
link:
address: 'http://116.62.197.152:8000/api/temp/file/download'
file-base-path-linux: /home/eladmin/file/temp/
file-base-path-windows: C:\eladmin\file\temp\
file-base-path-mac: ~/file/eladmin/temp/

@ -180,3 +180,9 @@ logging:
tag:
split-table:
sum: 10
remote:
link:
address: 'http://116.62.197.152:8000/api/temp/file/download'
file-base-path-linux: /home/eladmin/file/temp/
file-base-path-windows: C:\eladmin\file\temp\
file-base-path-mac: ~/file/eladmin/temp/

@ -0,0 +1,175 @@
#配置数据源
spring:
datasource:
druid:
db-type: com.alibaba.druid.pool.DruidDataSource
driverClassName: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
url: jdbc:log4jdbc:mysql://47.99.218.9:3306/eladmin?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false
username: root
password: Yuyou@2020
# 初始连接数
initial-size: 5
# 最小连接数
min-idle: 10
# 最大连接数
max-active: 20
# 获取连接超时时间
max-wait: 5000
# 连接有效性检测时间
time-between-eviction-runs-millis: 60000
# 连接在池中最小生存的时间
min-evictable-idle-time-millis: 300000
# 连接在池中最大生存的时间
max-evictable-idle-time-millis: 900000
test-while-idle: true
test-on-borrow: false
test-on-return: false
# 检测连接是否有效
validation-query: select 1
# 配置监控统计
webStatFilter:
enabled: true
stat-view-servlet:
enabled: true
url-pattern: /druid/*
reset-enable: false
filter:
stat:
enabled: true
# 记录慢SQL
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true
# 登录相关配置
login:
# 登录缓存
cache-enable: true
# 是否限制单用户登录
single: false
# 验证码
login-code:
# 验证码类型配置 查看 LoginProperties 类
code-type: arithmetic
# 登录图形验证码有效时间/分钟
expiration: 2
# 验证码高度
width: 111
# 验证码宽度
heigth: 36
# 内容长度
length: 2
# 字体名称,为空则使用默认字体
font-name:
# 字体大小
font-size: 25
#jwt
jwt:
header: Authorization
# 令牌前缀
token-start-with: Bearer
# 必须使用最少88位的Base64对该令牌进行编码
base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI=
# 令牌过期时间 此处单位/毫秒 默认4小时可在此网站生成 https://www.convertworld.com/zh-hans/time/milliseconds.html
token-validity-in-seconds: 14400000
# 在线用户key
online-key: online-token-
# 验证码
code-key: code-key-
# token 续期检查时间范围默认30分钟单位毫秒在token即将过期的一段时间内用户操作了则给用户的token续期
detect: 1800000
# 续期时间范围默认1小时单位毫秒
renew: 3600000
#是否允许生成代码生产环境设置为false
generator:
enabled: true
#是否开启 swagger-ui
swagger:
enabled: true
# IP 本地解析
ip:
local-parsing: true
# 文件存储路径
file:
mac:
path: ~/file/
avatar: ~/avatar/
linux:
path: /home/eladmin/file/
avatar: /home/eladmin/avatar/
windows:
path: C:\eladmin\file\
avatar: C:\eladmin\avatar\
# 文件大小 /M
maxSize: 100
avatarMaxSize: 5
# 配置请求发送路径
req:
db:
# 设置给大坝回传号码的地址
host: http://api.hzdaba.cn/aibot
url: /api/activity/addclient
# 线程池的相关配置
produce:
task:
thread_pool:
corePoolSize: 2
maxPoolSize: 16
queueCapacity: 3
ThreadNamePrefix: 'ProduceLocalFileTaskExecutor-'
send:
task:
thread_pool:
corePoolSize: 2
maxPoolSize: 16
queueCapacity: 3
ThreadNamePrefix: 'SendLocalFileTaskExecutor-'
merge:
task:
thread_pool:
corePoolSize: 2
maxPoolSize: 16
queueCapacity: 3
ThreadNamePrefix: 'MergeFileTaskExecutor-'
producebigdata:
task:
thread_pool:
corePoolSize: 2
maxPoolSize: 16
queueCapacity: 3
ThreadNamePrefix: 'ProduceBigDataTaskExecutor-'
SendBigData:
task:
thread_pool:
corePoolSize: 2
maxPoolSize: 16
queueCapacity: 3
ThreadNamePrefix: 'SendBigDataTaskExecutor-'
# 增加日志相关的配置
logging:
level:
org.springframework.security:
- debug
- info
org.springframework.web: error
org.hibernate.SQL: debug
org.hibernate.engine.QueryParameters: debug
org.hibernate.engine.query.HQLQueryPlan: debug
org.hibernate.type.descriptor.sql.BasicBinder: trace
tag:
split-table:
sum: 10
remote:
link:
address: 'http://116.62.197.152:8000/api/temp/file/download'
file-base-path-linux: /home/eladmin/file/temp/
file-base-path-windows: C:\eladmin\file\temp\
file-base-path-mac: ~/file/eladmin/temp/

@ -2,7 +2,7 @@
spring:
shardingsphere:
datasource:
names: eladmin
names: eladmin,schema
eladmin:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
@ -45,6 +45,48 @@ spring:
wall:
config:
multi-statement-allow: true
schema:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
url: jdbc:log4jdbc:mysql://rm-bp1693kl5d490o5cn.mysql.rds.aliyuncs.com:3306/information_schema?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false
username: prod
password: yuyou@RDS9495
# 初始连接数
initial-size: 5
# 最小连接数
min-idle: 10
# 最大连接数
max-active: 20
# 获取连接超时时间
max-wait: 5000
# 连接有效性检测时间
time-between-eviction-runs-millis: 60000
# 连接在池中最小生存的时间
min-evictable-idle-time-millis: 300000
# 连接在池中最大生存的时间
max-evictable-idle-time-millis: 900000
test-while-idle: true
test-on-borrow: false
test-on-return: false
# 检测连接是否有效
validation-query: select 1
# 配置监控统计
webStatFilter:
enabled: true
stat-view-servlet:
enabled: true
url-pattern: /druid/*
reset-enable: false
filter:
stat:
enabled: true
# 记录慢SQL
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true
sharding:
# 默认数据源
default-data-source-name: eladmin
@ -180,3 +222,9 @@ logging:
tag:
split-table:
sum: 10
remote:
link:
address: 'http://116.62.197.152:8000/api/temp/file/download'
file-base-path-linux: /home/eladmin/file/temp/
file-base-path-windows: C:\eladmin\file\temp\
file-base-path-mac: ~/file/eladmin/temp/

@ -5,7 +5,7 @@ spring:
freemarker:
check-template-location: false
profiles:
active: test
active: prod
jackson:
time-zone: GMT+8
data:

@ -1,45 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds" debug="false">
<contextName>elAdmin</contextName>
<property name="log.charset" value="utf-8" />
<property name="log.pattern" value="%white(%contextName-) %red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}) - %white(%msg%n)" />
<!-- 定义日志格式基础信息 -->
<property name="LOG_DIR" value="./log/" />
<property name="LOG_PATTERN" value="%white(%contextName-) %d{yyyy-MM-dd HH:mm:ss:SS} %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{50}) - %cyan(%msg%n)" />
<property name="LOG_CHARSET" value="utf-8" />
<!--输出到控制台-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<appender name="stdAppender" class="ch.qos.logback.core.ConsoleAppender">
<!--<withJansi>true</withJansi> &lt;!&ndash; 如果是UTF-8的环境这句要注释掉 &ndash;&gt;-->
<encoder>
<pattern>${log.pattern}</pattern>
<charset>${log.charset}</charset>
<pattern>%highlight([%-5level]) %cyan(%d{yyyy-MM-dd#HH:mm:ss.SSS}) %yellow([Thread:%thread]) %magenta([Logger:%logger]) -> %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<!-- 输出到文件,并按天进行归档 -->
<appender name="fileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/log.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天归档,如果按小时后面加-hh -->
<fileNamePattern>${LOG_DIR}/history/%d{yyyy-MM-dd}.gz</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<append>true</append>
<encoder>
<pattern>${LOG_PATTERN}</pattern>
<charset>utf-8</charset>
</encoder>
<!-- 不写TRACE DEBUG -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
</appender>
<!--普通日志输出到控制台-->
<root level="info">
<appender-ref ref="console" />
<appender-ref ref="stdAppender" />
</root>
<!--监控sql日志输出 -->
<logger name="jdbc.sqlonly" level="INFO" additivity="false">
<appender-ref ref="console" />
<appender-ref ref="stdAppender" />
<appender-ref ref="fileAppender"/>
</logger>
<logger name="jdbc.resultset" level="ERROR" additivity="false">
<appender-ref ref="console" />
<appender-ref ref="stdAppender" />
<appender-ref ref="fileAppender"/>
</logger>
<!-- 如想看到表格数据将OFF改为INFO -->
<logger name="jdbc.resultsettable" level="OFF" additivity="false">
<appender-ref ref="console" />
<appender-ref ref="stdAppender" />
<appender-ref ref="fileAppender"/>
</logger>
<logger name="jdbc.connection" level="OFF" additivity="false">
<appender-ref ref="console" />
<appender-ref ref="stdAppender" />
<appender-ref ref="fileAppender"/>
</logger>
<logger name="jdbc.sqltiming" level="OFF" additivity="false">
<appender-ref ref="console" />
<appender-ref ref="stdAppender" />
<appender-ref ref="fileAppender"/>
</logger>
<logger name="jdbc.audit" level="OFF" additivity="false">
<appender-ref ref="console" />
<appender-ref ref="stdAppender" />
<appender-ref ref="fileAppender"/>
</logger>
<root level="INFO">
<!-- TODO prod 环境去掉std -->
<appender-ref ref="stdAppender"/>
<!--<appender-ref ref="fileAppender"/>-->
</root>
</configuration>

@ -0,0 +1,63 @@
package me.zhengjie;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.domain.EmailConfig;
import me.zhengjie.domain.vo.EmailVo;
import me.zhengjie.service.EmailService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Arrays;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Slf4j
public class MailTest {
@Autowired
private EmailService emailService;
private EmailConfig initConfig(){
EmailConfig emailConfig = new EmailConfig();
emailConfig.setHost("smtp.163.com"); // 邮件服务器SMTP地址
emailConfig.setPort("465"); // 465
emailConfig.setUser("qyxtoplink666"); // 用户名
emailConfig.setPass("QGCUIPZVWZIDMWNG"); // 密码
emailConfig.setFromUser("qyxtoplink666@163.com"); // 发件人邮箱
return emailConfig;
}
/**
* -
*/
@Test
public void testEmailConfig() throws Exception {
EmailConfig emailConfig = initConfig();
EmailConfig old = new EmailConfig();
old.setPass("xxx");
emailService.config(emailConfig,old);
}
/**
* -
*/
@Test
public void testEmailSend(){
EmailConfig emailConfig = emailService.find();
EmailVo emailVo = new EmailVo();
emailVo.setTos(Arrays.asList("496186310@qq.com", "15158080631@163.com"));
emailVo.setSubject("测试主题");
emailVo.setContent("测试发送内容1");
emailService.send(emailVo, emailConfig);
}
}

@ -13,6 +13,7 @@ import me.zhengjie.modules.student.repository.StudentRepository;
import me.zhengjie.modules.student.service.StudentService;
import me.zhengjie.modules.tag.service.TagService;
import me.zhengjie.utils.FileUtil;
import org.apache.commons.lang3.builder.ToStringExclude;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
@ -289,4 +290,12 @@ public class SpringJPATest {
System.out.println(integer);
}
@Test
public void testUpdateAllPushStatus(){
List<Long> pushIds = Arrays.asList(1L, 2L, 3L, 4L, 5L);
Long taskId = 26L;
Integer aLong = tagService.updateAllPushStatus(pushIds, taskId);
System.out.println(aLong);
}
}

@ -73,9 +73,11 @@ public class TempTest {
*/
@Test
public void testList1(){
List<Integer> list = Arrays.asList(1, 2, 3, 4);
List<Integer> list = Arrays.asList(1, 2, 3, 4, 6, 8, 9, 10);
List<Integer> list1 = Arrays.asList(3, 4, 5);
Set<Integer> collect = list.stream().filter(list1::contains).collect(Collectors.toSet());
Set<Integer> collect1 = list.stream().filter(item->!collect.contains(item)).collect(Collectors.toSet());

@ -15,17 +15,27 @@
*/
package me.zhengjie.rest;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import me.zhengjie.annotation.Log;
import me.zhengjie.common.http.CommonResponse;
import me.zhengjie.common.http.ResponseCode;
import me.zhengjie.common.json.OnceLinkMsgJsonContent;
import me.zhengjie.domain.vo.EmailVo;
import me.zhengjie.domain.EmailConfig;
import me.zhengjie.service.EmailService;
import me.zhengjie.utils.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
/**
*

@ -18,6 +18,7 @@ package me.zhengjie.service;
import me.zhengjie.domain.vo.EmailVo;
import me.zhengjie.domain.EmailConfig;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.multipart.MultipartFile;
/**
* @author Zheng Jie
@ -47,4 +48,6 @@ public interface EmailService {
* @throws Exception /
*/
void send(EmailVo emailVo, EmailConfig emailConfig);
}

@ -15,20 +15,32 @@
*/
package me.zhengjie.service.impl;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.extra.mail.Mail;
import cn.hutool.extra.mail.MailAccount;
import cn.hutool.system.OsInfo;
import cn.hutool.system.SystemUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.domain.EmailConfig;
import me.zhengjie.domain.vo.EmailVo;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.repository.EmailRepository;
import me.zhengjie.service.EmailService;
import me.zhengjie.utils.EncryptUtils;
import me.zhengjie.utils.FileUtil;
import me.zhengjie.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Optional;
/**
@ -38,6 +50,7 @@ import java.util.Optional;
@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = "email")
@Slf4j
public class EmailServiceImpl implements EmailService {
private final EmailRepository emailRepository;

@ -125,6 +125,8 @@
<artifactId>swagger-models</artifactId>
<version>1.5.21</version>
</dependency>
<!-- 生成代码时候进行注释 -->
<dependency>
<groupId>org.apache.shardingSphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>

Loading…
Cancel
Save