diff --git a/READ_OPRATION.md b/READ_OPRATION.md new file mode 100644 index 0000000..aafc632 --- /dev/null +++ b/READ_OPRATION.md @@ -0,0 +1,2 @@ +## 生成代码配置 +pom 注释 sharding相关的依赖,切换druid依赖,配置环境用 single diff --git a/eladmin-system/src/main/java/me/zhengjie/common/http/CommonResponse.java b/eladmin-common/src/main/java/me/zhengjie/common/http/CommonResponse.java similarity index 100% rename from eladmin-system/src/main/java/me/zhengjie/common/http/CommonResponse.java rename to eladmin-common/src/main/java/me/zhengjie/common/http/CommonResponse.java diff --git a/eladmin-system/src/main/java/me/zhengjie/common/http/ResponseCode.java b/eladmin-common/src/main/java/me/zhengjie/common/http/ResponseCode.java similarity index 96% rename from eladmin-system/src/main/java/me/zhengjie/common/http/ResponseCode.java rename to eladmin-common/src/main/java/me/zhengjie/common/http/ResponseCode.java index f5507b9..1bd3226 100644 --- a/eladmin-system/src/main/java/me/zhengjie/common/http/ResponseCode.java +++ b/eladmin-common/src/main/java/me/zhengjie/common/http/ResponseCode.java @@ -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,"任务名称已经存在"), // 请求结果性的错误 diff --git a/eladmin-common/src/main/java/me/zhengjie/common/json/OnceLinkMsgJsonContent.java b/eladmin-common/src/main/java/me/zhengjie/common/json/OnceLinkMsgJsonContent.java new file mode 100644 index 0000000..3fddec0 --- /dev/null +++ b/eladmin-common/src/main/java/me/zhengjie/common/json/OnceLinkMsgJsonContent.java @@ -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; + + +} diff --git a/eladmin-system/src/main/java/me/zhengjie/common/json/PushDBJsonContent.java b/eladmin-common/src/main/java/me/zhengjie/common/json/PushDBJsonContent.java similarity index 100% rename from eladmin-system/src/main/java/me/zhengjie/common/json/PushDBJsonContent.java rename to eladmin-common/src/main/java/me/zhengjie/common/json/PushDBJsonContent.java diff --git a/eladmin-common/src/main/java/me/zhengjie/utils/FileUtil.java b/eladmin-common/src/main/java/me/zhengjie/utils/FileUtil.java index 4cc665f..8d1a90a 100644 --- a/eladmin-common/src/main/java/me/zhengjie/utils/FileUtil.java +++ b/eladmin-common/src/main/java/me/zhengjie/utils/FileUtil.java @@ -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"; diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/buildrecord/rest/BuildRecordController.java b/eladmin-system/src/main/java/me/zhengjie/modules/buildrecord/rest/BuildRecordController.java index 87a713c..1be201f 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/buildrecord/rest/BuildRecordController.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/buildrecord/rest/BuildRecordController.java @@ -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; diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/buildrecord/task/SendBigDataTask.java b/eladmin-system/src/main/java/me/zhengjie/modules/buildrecord/task/SendBigDataTask.java index fe62933..21b798c 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/buildrecord/task/SendBigDataTask.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/buildrecord/task/SendBigDataTask.java @@ -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 tagDtos = tagService.queryAll(tagQueryCriteria); + tagQueryCriteria.setPushStatus(NON_FINISH_SEND_STATATUS); + // 加入分页防止查不动的情况 这里可以分页进行查询 - 目前不进行优化 - 为全查 + Pageable pageable = PageRequest.of(0, sendBigDataDTO.getLimit().intValue()); + List backContent = tagService.queryAllBySlice(tagQueryCriteria, pageable); // 遍历查询等待发送的列表 - List collect = tagDtos.stream() - .filter(one -> one.getPushStatus() == NON_FINISH_SEND_STATATUS) + List 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 filterCollect = collect.stream().map(TagDto::getUid).filter(fileLines::contains).collect(Collectors.toSet()); + Set 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 collect, SendBigDataDTO sendRecordDTO, BuildRecordDto buildRecordDto) { - List> partition = Lists.partition(collect, SEND_LIMIT); + private AtomicLong batchSend(List collect, SendBigDataDTO sendRecordDTO, BuildRecordDto buildRecordDto) { + AtomicLong successCount = new AtomicLong(0L); + List> 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 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 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) { diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/mailtask/rest/MailTaskController.java b/eladmin-system/src/main/java/me/zhengjie/modules/mailtask/rest/MailTaskController.java new file mode 100644 index 0000000..626ee6b --- /dev/null +++ b/eladmin-system/src/main/java/me/zhengjie/modules/mailtask/rest/MailTaskController.java @@ -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 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 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); + } +} diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/mailtask/service/MailTaskService.java b/eladmin-system/src/main/java/me/zhengjie/modules/mailtask/service/MailTaskService.java new file mode 100644 index 0000000..7f79939 --- /dev/null +++ b/eladmin-system/src/main/java/me/zhengjie/modules/mailtask/service/MailTaskService.java @@ -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); +} diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/mailtask/service/impl/MailTaskServiceImpl.java b/eladmin-system/src/main/java/me/zhengjie/modules/mailtask/service/impl/MailTaskServiceImpl.java new file mode 100644 index 0000000..6a056ae --- /dev/null +++ b/eladmin-system/src/main/java/me/zhengjie/modules/mailtask/service/impl/MailTaskServiceImpl.java @@ -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); + } + } + } + } + } +} diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/taskrecord/task/SendRecordTask.java b/eladmin-system/src/main/java/me/zhengjie/modules/taskrecord/task/SendRecordTask.java index 40d49e8..9880468 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/taskrecord/task/SendRecordTask.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/taskrecord/task/SendRecordTask.java @@ -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 collect, SendRecordDTO sendRecordDTO, TaskRecordDto taskRecordDto) { + private Long batchSend(List collect, SendRecordDTO sendRecordDTO, TaskRecordDto taskRecordDto) { + AtomicLong successCount = new AtomicLong(0L); List> 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) { diff --git a/eladmin-system/src/main/resources/config/application-dev.yml b/eladmin-system/src/main/resources/config/application-dev.yml index 2077d12..d441816 100644 --- a/eladmin-system/src/main/resources/config/application-dev.yml +++ b/eladmin-system/src/main/resources/config/application-dev.yml @@ -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 @@ -179,4 +221,10 @@ logging: org.hibernate.type.descriptor.sql.BasicBinder: trace tag: split-table: - sum: 10 \ No newline at end of file + 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/ \ No newline at end of file diff --git a/eladmin-system/src/main/resources/config/application-prod.yml b/eladmin-system/src/main/resources/config/application-prod.yml index d4c7e2e..51d325c 100644 --- a/eladmin-system/src/main/resources/config/application-prod.yml +++ b/eladmin-system/src/main/resources/config/application-prod.yml @@ -179,4 +179,10 @@ logging: org.hibernate.type.descriptor.sql.BasicBinder: trace tag: split-table: - sum: 10 \ No newline at end of file + 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/ \ No newline at end of file diff --git a/eladmin-system/src/main/resources/config/application-single.yml b/eladmin-system/src/main/resources/config/application-single.yml new file mode 100644 index 0000000..dfb10f9 --- /dev/null +++ b/eladmin-system/src/main/resources/config/application-single.yml @@ -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/ \ No newline at end of file diff --git a/eladmin-system/src/main/resources/config/application-test.yml b/eladmin-system/src/main/resources/config/application-test.yml index 241fd19..ad33ab4 100644 --- a/eladmin-system/src/main/resources/config/application-test.yml +++ b/eladmin-system/src/main/resources/config/application-test.yml @@ -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 @@ -179,4 +221,10 @@ logging: org.hibernate.type.descriptor.sql.BasicBinder: trace tag: split-table: - sum: 10 \ No newline at end of file + 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/ \ No newline at end of file diff --git a/eladmin-system/src/main/resources/config/application.yml b/eladmin-system/src/main/resources/config/application.yml index 6a02dab..793279d 100644 --- a/eladmin-system/src/main/resources/config/application.yml +++ b/eladmin-system/src/main/resources/config/application.yml @@ -5,7 +5,7 @@ spring: freemarker: check-template-location: false profiles: - active: test + active: prod jackson: time-zone: GMT+8 data: diff --git a/eladmin-system/src/main/resources/logback.xml b/eladmin-system/src/main/resources/logback.xml index 1e87d84..30ccc85 100644 --- a/eladmin-system/src/main/resources/logback.xml +++ b/eladmin-system/src/main/resources/logback.xml @@ -1,45 +1,83 @@ elAdmin - - + + + + - + + - ${log.pattern} - ${log.charset} + %highlight([%-5level]) %cyan(%d{yyyy-MM-dd#HH:mm:ss.SSS}) %yellow([Thread:%thread]) %magenta([Logger:%logger]) -> %msg%n + utf-8 + + + ${LOG_DIR}/log.log + + + + ${LOG_DIR}/history/%d{yyyy-MM-dd}.gz + 30 + + + true + + + ${LOG_PATTERN} + utf-8 + + + + + INFO + + + - + - + + - + + - + + - + + - + + - + + + + + + + + \ No newline at end of file diff --git a/eladmin-system/src/test/java/me/zhengjie/MailTest.java b/eladmin-system/src/test/java/me/zhengjie/MailTest.java new file mode 100644 index 0000000..54c4a41 --- /dev/null +++ b/eladmin-system/src/test/java/me/zhengjie/MailTest.java @@ -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); + } + +} diff --git a/eladmin-system/src/test/java/me/zhengjie/SpringJPATest.java b/eladmin-system/src/test/java/me/zhengjie/SpringJPATest.java index 99c041c..fedbb75 100644 --- a/eladmin-system/src/test/java/me/zhengjie/SpringJPATest.java +++ b/eladmin-system/src/test/java/me/zhengjie/SpringJPATest.java @@ -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 pushIds = Arrays.asList(1L, 2L, 3L, 4L, 5L); + Long taskId = 26L; + Integer aLong = tagService.updateAllPushStatus(pushIds, taskId); + System.out.println(aLong); + } } diff --git a/eladmin-system/src/test/java/me/zhengjie/TempTest.java b/eladmin-system/src/test/java/me/zhengjie/TempTest.java index 2167ef2..2096f12 100644 --- a/eladmin-system/src/test/java/me/zhengjie/TempTest.java +++ b/eladmin-system/src/test/java/me/zhengjie/TempTest.java @@ -73,9 +73,11 @@ public class TempTest { */ @Test public void testList1(){ - List list = Arrays.asList(1, 2, 3, 4); + List list = Arrays.asList(1, 2, 3, 4, 6, 8, 9, 10); List list1 = Arrays.asList(3, 4, 5); + + Set collect = list.stream().filter(list1::contains).collect(Collectors.toSet()); Set collect1 = list.stream().filter(item->!collect.contains(item)).collect(Collectors.toSet()); diff --git a/eladmin-tools/src/main/java/me/zhengjie/rest/EmailController.java b/eladmin-tools/src/main/java/me/zhengjie/rest/EmailController.java index 974de99..68528b2 100644 --- a/eladmin-tools/src/main/java/me/zhengjie/rest/EmailController.java +++ b/eladmin-tools/src/main/java/me/zhengjie/rest/EmailController.java @@ -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; /** * 发送邮件 diff --git a/eladmin-tools/src/main/java/me/zhengjie/service/EmailService.java b/eladmin-tools/src/main/java/me/zhengjie/service/EmailService.java index 2c61a53..94f5b05 100644 --- a/eladmin-tools/src/main/java/me/zhengjie/service/EmailService.java +++ b/eladmin-tools/src/main/java/me/zhengjie/service/EmailService.java @@ -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); + + } diff --git a/eladmin-tools/src/main/java/me/zhengjie/service/impl/EmailServiceImpl.java b/eladmin-tools/src/main/java/me/zhengjie/service/impl/EmailServiceImpl.java index 3386500..668253c 100644 --- a/eladmin-tools/src/main/java/me/zhengjie/service/impl/EmailServiceImpl.java +++ b/eladmin-tools/src/main/java/me/zhengjie/service/impl/EmailServiceImpl.java @@ -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; diff --git a/pom.xml b/pom.xml index 58f35b0..fa76a0e 100644 --- a/pom.xml +++ b/pom.xml @@ -125,6 +125,8 @@ swagger-models 1.5.21 + + org.apache.shardingSphere sharding-jdbc-spring-boot-starter