commit 1e73fa59dbe30fb9a3d346af7a0a6003c89ffaa0 Author: 583641232@qq.com <583641232@qq.com> Date: Mon Jul 29 00:02:45 2024 +0800 first commit diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..25b312e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +# http://editorconfig.org +root = true + +# 空格替代Tab缩进在各种编辑工具下效果一致 +[*] +indent_style = space +indent_size = 4 +charset = utf-8 +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{json,yml,yaml}] +indent_size = 2 + +[*.md] +insert_final_newline = false +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9e33968 --- /dev/null +++ b/.gitignore @@ -0,0 +1,46 @@ +###################################################################### +# Build Tools + +.gradle +/build/ +!gradle/wrapper/gradle-wrapper.jar + +target/ +!.mvn/wrapper/maven-wrapper.jar + +###################################################################### +# IDE + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### JRebel ### +rebel.xml + +### NetBeans ### +nbproject/private/ +build/* +nbbuild/ +nbdist/ +.nb-gradle/ + +###################################################################### +# Others +*.log +*.xml.versionsBackup +*.swp + +!*/build/*.java +!*/build/*.html +!*/build/*.xml diff --git a/README.md b/README.md new file mode 100644 index 0000000..139597f --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ + + diff --git a/cas-admin/pom.xml b/cas-admin/pom.xml new file mode 100644 index 0000000..5aa7eb2 --- /dev/null +++ b/cas-admin/pom.xml @@ -0,0 +1,117 @@ + + + + cas-server + com.inscloudtech + 4.7.0 + + 4.0.0 + jar + cas-admin + + + web服务入口 + + + + + + + org.springframework.boot + spring-boot-devtools + true + + + + + com.mysql + mysql-connector-j + + + + com.microsoft.sqlserver + mssql-jdbc + + + + + com.inscloudtech + cas-framework + + + + com.inscloudtech + cas-system + + + + com.inscloudtech + cas-generator + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + true + + + + + repackage + + + + + + org.apache.maven.plugins + maven-war-plugin + 3.2.2 + + false + ${project.artifactId} + + + + + net.roseboy + classfinal-maven-plugin + 1.2.1 + + # + org.spring + com.inscloudtech + application.yml,application-dev.yml,application-prod.yml,application-soft.yml + cas-system-4.7.0.jar + + + + + package + + classFinal + + + + + + + + diff --git a/cas-admin/src/main/java/com/inscloudtech/CasApplication.java b/cas-admin/src/main/java/com/inscloudtech/CasApplication.java new file mode 100644 index 0000000..93ce7a6 --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/CasApplication.java @@ -0,0 +1,30 @@ +package com.inscloudtech; + +import org.dromara.easyes.starter.register.EsMapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.scheduling.annotation.EnableScheduling; + +/** + * 启动程序 + * + * @author + */ + +@EsMapperScan("com.inscloudtech.*.mapper") +@SpringBootApplication(scanBasePackages = {"com.inscloudtech"}) +@EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true) +@EnableScheduling +public class CasApplication { + + public static void main(String[] args) { + System.setProperty("spring.devtools.restart.enabled", "false"); + SpringApplication application = new SpringApplication(CasApplication.class); + application.setApplicationStartup(new BufferingApplicationStartup(2048)); + application.run(args); + System.out.println(">>>cas服务启动成功<<<"); + } + +} diff --git a/cas-admin/src/main/java/com/inscloudtech/CasServletInitializer.java b/cas-admin/src/main/java/com/inscloudtech/CasServletInitializer.java new file mode 100644 index 0000000..9638c69 --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/CasServletInitializer.java @@ -0,0 +1,18 @@ +package com.inscloudtech; + +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; + +/** + * web容器中进行部署 + * + * @author inscloudtech + */ +public class CasServletInitializer extends SpringBootServletInitializer { + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + return application.sources(CasApplication.class); + } + +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/analysiscenter/AnalysisReportController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/analysiscenter/AnalysisReportController.java new file mode 100644 index 0000000..7387116 --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/analysiscenter/AnalysisReportController.java @@ -0,0 +1,88 @@ +package com.inscloudtech.web.controller.analysiscenter; + +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.analysiscenter.domain.AnalysisReport; +import com.inscloudtech.analysiscenter.mapper.AnalysisReportMapper; +import com.inscloudtech.analysiscenter.service.IAnalysisReportService; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.annotation.RepeatSubmit; +import com.inscloudtech.common.annotation.UpdateLog; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.enums.BusinessType; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.io.IOException; +import java.util.Arrays; +import java.util.Date; + +/** + * 分析中心-分析报告对象 + * + * @author inscloudtech + * @date 2023-11-10 + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/ac/analysisReport") +public class AnalysisReportController extends BaseController { + + private final IAnalysisReportService iAnalysisReportService; + + //"OSS对象word格式转化为pdf格式") + @GetMapping("/download/{ossId}") + public void wordToPdf(@PathVariable String ossId, HttpServletResponse response) throws IOException { + iAnalysisReportService.download(ossId, response); + } + + //"查询分析报告对象列表") + @GetMapping("/list") + public TableDataInfo list(AnalysisReport bo, PageQuery pageQuery) { + return iAnalysisReportService.queryPageList(bo, pageQuery); + } + + //"获取分析报告对象") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") @PathVariable String id) { + return R.ok(iAnalysisReportService.queryById(id)); + } + + //"新增分析报告对象") + @Log(title = "分析报告对象", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@RequestBody AnalysisReport bo) { + bo.setCreateBy(getUsername()); + bo.setCreateTime(new Date()); + iAnalysisReportService.insert(bo); + return R.ok("分析报告生成成功",bo); + } + + //"修改分析报告对象") + @UpdateLog(title = "分析报告对象", mapperClass = AnalysisReportMapper.class, businessType = BusinessType.UPDATE) + @PutMapping() + public R edit(@RequestBody AnalysisReport bo) { + return R.ok(iAnalysisReportService.update(bo)); + } + + //"删除分析报告对象") + @Log(title = "分析报告对象", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") @PathVariable String[] ids) { + return R.ok(iAnalysisReportService.deleteWithValidByIds(Arrays.asList(ids))); + } + + //"保存至分析成果") + @PostMapping("/save2AnalysisResult") + public R save2AnalysisResult(@RequestBody AnalysisDto dto) { + iAnalysisReportService.save2AnalysisResult(dto); + return R.ok(); + } + +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/analysiscenter/AnalysisResultController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/analysiscenter/AnalysisResultController.java new file mode 100644 index 0000000..63e6989 --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/analysiscenter/AnalysisResultController.java @@ -0,0 +1,98 @@ +package com.inscloudtech.web.controller.analysiscenter; + +import com.inscloudtech.analysiscenter.domain.AnalysisResult; +import com.inscloudtech.analysiscenter.mapper.AnalysisResultMapper; +import com.inscloudtech.analysiscenter.service.IAnalysisResultService; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.annotation.RepeatSubmit; +import com.inscloudtech.common.annotation.UpdateLog; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.datacenter.service.QueryCenterService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Arrays; +import java.util.Date; + +/** + * 分析中心-分析成果对象 + * + * @author inscloudtech + * @date 2023-11-10 + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/ac/analysisResult") +public class AnalysisResultController extends BaseController { + + private final IAnalysisResultService iAnalysisResultService; + + private final QueryCenterService queryCenterService; + + //"查询分析成果对象列表") + @GetMapping("/list") + public TableDataInfo list(AnalysisResult bo, PageQuery pageQuery) { + return iAnalysisResultService.queryPageList(bo, pageQuery); + } + + + //"获取分析成果对象") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable String id) { + return R.ok(iAnalysisResultService.queryById(id)); + } + + + //"新增分析成果对象") + @Log(title = "分析成果对象", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add( @RequestBody AnalysisResult bo) { + bo.setCreateBy(getUsername()); + bo.setCreateTime(new Date()); + iAnalysisResultService.insert(bo); + return R.ok(bo.getId()); + } + + + //"修改分析成果对象") + @UpdateLog(title = "分析成果对象",mapperClass = AnalysisResultMapper.class, businessType = BusinessType.UPDATE) + @PutMapping() + public R edit(@RequestBody AnalysisResult bo) { + return R.ok(iAnalysisResultService.update(bo)); + } + + //"删除分析成果对象") + @Log(title = "分析成果对象", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable String[] ids) { + return R.ok(iAnalysisResultService.deleteWithValidByIds(Arrays.asList(ids))); + } + + + //"下载分析成果对象") + @PostMapping("/export") + public void export(AnalysisResult bo, HttpServletResponse response) { + queryCenterService.excelExport(response,bo); + } + + //"导入分析成果对象") + @PostMapping(value = "/import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R importData(@RequestPart("file") MultipartFile file, String caseId, String analysisResultId) { + iAnalysisResultService.importData(file,caseId,analysisResultId); + return R.ok(); + } + +} + diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/analysiscenter/PlateNumberInfoController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/analysiscenter/PlateNumberInfoController.java new file mode 100644 index 0000000..04dd8b5 --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/analysiscenter/PlateNumberInfoController.java @@ -0,0 +1,192 @@ +package com.inscloudtech.web.controller.analysiscenter; + +import cn.hutool.core.collection.CollectionUtil; +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.annotation.UpdateLog; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.excel.ExcelResult; +import com.inscloudtech.common.utils.BeanCopyUtils; +import com.inscloudtech.common.utils.poi.ExcelUtil; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.mapper.es.PlateNumberEsMapper; +import com.inscloudtech.system.service.ISysOssService; +import com.inscloudtech.datacenter.service.PlateNumberService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.*; + +/** + * 车牌抓取 + * + * @author inscloudtech + * @date 2023-11-10 + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/ac/plateNumberInfo") +public class PlateNumberInfoController extends BaseController { + + private final PlateNumberService iPlateNumberInfoService; + + private final ISysOssService iSysOssService; + + //"保存至分析成果") + @PostMapping("/save2AnalysisResult") + public R save2AnalysisResult(@RequestBody AnalysisDto dto) { + iPlateNumberInfoService.save2AnalysisResult(dto); + return R.ok(); + } + + /** + * 查询车牌抓取列表 + */ + //"查询车牌抓取列表") + @GetMapping("/list") + public TableDataInfo list(PlateNumberInfo bo, PageQuery pageQuery) { + return iPlateNumberInfoService.queryPageList(bo, pageQuery); + } + + /** + * 获取车牌抓取详细信息 + * + * @param id 主键 + */ + //"获取车牌抓取") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable String id) { + return R.ok(iPlateNumberInfoService.queryById(id)); + } + + /** + * 新增车牌抓取 + */ + //"新增车牌抓取") + @Log(title = "车牌抓取", businessType = BusinessType.INSERT) + @PostMapping() + public R add( @RequestBody PlateNumberInfo bo) { + bo.setCreateBy(getUsername()); + return R.ok(iPlateNumberInfoService.insertByBo(bo)); + } + + /** + * 修改车牌抓取 + */ + //"修改车牌抓取") + @UpdateLog(title = "车牌抓取",mapperClass = PlateNumberEsMapper.class, businessType = BusinessType.UPDATE) + @PutMapping() + public R edit(@RequestBody PlateNumberInfo bo) { + return R.ok(iPlateNumberInfoService.updateByBo(bo)); + } + + /** + * 删除车牌抓取 + * + * @param ids 主键串 + */ + //"删除车牌抓取") + @Log(title = "车牌抓取", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable String[] ids) { + return R.ok(iPlateNumberInfoService.deleteWithValidByIds(Arrays.asList(ids), true)); + } + + //"批量修改车牌抓取") + @PutMapping("/updateBatch") + public R updateBatch(@RequestBody PlateNumberInfo bo) { + List ids = bo.getIds(); + List list = new ArrayList<>(); + ids.stream().forEach(id ->{ + PlateNumberInfo update = BeanCopyUtils.copy(bo,PlateNumberInfo.class); + update.setId(id); + update.setUpdateBy(getUsername()); + update.setUpdateTime(new Date()); + list.add(update); + }); + return R.ok(iPlateNumberInfoService.updateBatch(list)); + } + + //"批量修改车牌抓取对象集合") + @PutMapping("/updateBatchByList") + public R updateBatch(@RequestBody List list) { + list.stream().forEach(update ->{ + update.setUpdateBy(getUsername()); + update.setUpdateTime(new Date()); + }); + return R.ok(iPlateNumberInfoService.updateBatch(list)); + } + + //"导入车牌抓取") + @PostMapping(value = "/import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R importData(@RequestPart("file") MultipartFile file, String caseId) { + boolean result = false; + String importResultStr = ""; + int importCount = 0; + try { + ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), PlateNumberInfo.class, true); + List list = excelResult.getList(); + if(CollectionUtil.isNotEmpty(list)){ + list = iPlateNumberInfoService.dataTrimAndDeduplication(list,caseId,getUsername()); + result = iPlateNumberInfoService.importData(list,caseId,null); + importCount = list.size(); + }else { + throw new RuntimeException("未解析到数据!"); + } + }catch (Exception e){ + importResultStr = e.getMessage(); + } + iSysOssService.upload2Local(importCount,importResultStr,file,caseId,"PLATE_NUMBER_INFO"); + return result ? R.ok() : R.fail(importResultStr); + } + + //"分析成果-车牌抓取导入") + @PostMapping(value = "/import4AnalysisResult", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R importAnalysisResult(@RequestPart("file") MultipartFile file, String caseId, String analysisResultId) { + boolean result = false; + String importResultStr = ""; + int importCount = 0; + try { + ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), PlateNumberInfo.class, true); + List list = excelResult.getList(); + if(CollectionUtil.isNotEmpty(list)){ + result = iPlateNumberInfoService.importAnalysisResult(list,analysisResultId,getUsername()); + importCount = list.size(); + }else { + throw new RuntimeException("未解析到数据!"); + } + }catch (Exception e){ + e.printStackTrace(); + importResultStr = e.getMessage(); + } + + iSysOssService.upload2Local(importCount,importResultStr,file,caseId,"ANALYSIS_RESULT"); + return result ? R.ok() : R.fail(importResultStr); + } + + /** + * 导出交易对象列表 + */ + //"导出车牌抓取") + @PostMapping("/export") + public void export(PlateNumberInfo bo, HttpServletResponse response) { + List list = Collections.EMPTY_LIST; + if(bo.getDownloadTemplate() == null){ + list = iPlateNumberInfoService.queryList(bo); + } + ExcelUtil.exportExcel(list, "车牌抓取", PlateNumberInfo.class, response); + } + +} + diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/common/CaptchaController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/common/CaptchaController.java new file mode 100644 index 0000000..7f642ab --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/common/CaptchaController.java @@ -0,0 +1,134 @@ +package com.inscloudtech.web.controller.common; + +import cn.dev33.satoken.annotation.SaIgnore; +import cn.hutool.captcha.AbstractCaptcha; +import cn.hutool.captcha.generator.CodeGenerator; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.RandomUtil; +import com.inscloudtech.common.constant.CacheConstants; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.enums.CaptchaType; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.email.MailUtils; +import com.inscloudtech.common.utils.redis.RedisUtils; +import com.inscloudtech.common.utils.reflect.ReflectUtils; +import com.inscloudtech.common.utils.spring.SpringUtils; +import com.inscloudtech.framework.config.properties.CaptchaProperties; +import com.inscloudtech.framework.config.properties.MailProperties; +//import com.inscloudtech.sms.config.properties.SmsProperties; +//import com.inscloudtech.sms.core.SmsTemplate; +//import com.inscloudtech.sms.entity.SmsResult; +import com.inscloudtech.system.service.ISysConfigService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.constraints.NotBlank; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; + +/** + * 验证码操作处理 + * + * @author inscloudtech + */ +@SaIgnore +@Slf4j +@Validated +@RequiredArgsConstructor +@RestController +public class CaptchaController { + + private final CaptchaProperties captchaProperties; +// private final SmsProperties smsProperties; + private final ISysConfigService configService; + private final MailProperties mailProperties; + +// /** +// * 短信验证码 +// * +// * @param phonenumber 用户手机号 +// */ +// @GetMapping("/captchaSms") +// public R smsCaptcha(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) { +// if (!smsProperties.getEnabled()) { +// return R.fail("当前系统没有开启短信功能!"); +// } +// String key = CacheConstants.CAPTCHA_CODE_KEY + phonenumber; +// String code = RandomUtil.randomNumbers(4); +// RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); +// // 验证码模板id 自行处理 (查数据库或写死均可) +// String templateId = ""; +// Map map = new HashMap<>(1); +// map.put("code", code); +// SmsTemplate smsTemplate = SpringUtils.getBean(SmsTemplate.class); +// SmsResult result = smsTemplate.send(phonenumber, templateId, map); +// if (!result.isSuccess()) { +// log.error("验证码短信发送异常 => {}", result); +// return R.fail(result.getMessage()); +// } +// return R.ok(); +// } + /** + * 邮箱验证码 + * + * @param email 邮箱 + */ + @GetMapping("/captchaEmail") + public R emailCode(@NotBlank(message = "{user.email.not.blank}") String email) { + if (!mailProperties.getEnabled()) { + return R.fail("当前系统没有开启邮箱功能!"); + } + String key = CacheConstants.CAPTCHA_CODE_KEY + email; + String code = RandomUtil.randomNumbers(4); + RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); + try { + MailUtils.sendText(email, "登录验证码", "您本次验证码为:" + code + ",有效性为" + Constants.CAPTCHA_EXPIRATION + "分钟,请尽快填写。"); + } catch (Exception e) { + log.error("验证码短信发送异常 => {}", e.getMessage()); + return R.fail(e.getMessage()); + } + return R.ok(); + } + /** + * 生成验证码 + */ + @GetMapping("/captchaImage") + public R> getCode() { + Map ajax = new HashMap<>(); + boolean captchaEnabled = configService.selectCaptchaEnabled(); + ajax.put("captchaEnabled", captchaEnabled); + if (!captchaEnabled) { + return R.ok(ajax); + } + // 保存验证码信息 + String uuid = IdUtil.simpleUUID(); + String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid; + // 生成验证码 + CaptchaType captchaType = captchaProperties.getType(); + boolean isMath = CaptchaType.MATH == captchaType; + Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength(); + CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length); + AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz()); + captcha.setGenerator(codeGenerator); + captcha.createCode(); + String code = captcha.getCode(); + if (isMath) { + ExpressionParser parser = new SpelExpressionParser(); + Expression exp = parser.parseExpression(StringUtils.remove(code, "=")); + code = exp.getValue(String.class); + } + RedisUtils.setCacheObject(verifyKey, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); + ajax.put("uuid", uuid); + ajax.put("img", captcha.getImageBase64()); + return R.ok(ajax); + } + +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/datacenter/BankController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/datacenter/BankController.java new file mode 100644 index 0000000..94f0edc --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/datacenter/BankController.java @@ -0,0 +1,399 @@ +package com.inscloudtech.web.controller.datacenter; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.IdUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.analysiscenter.domain.AnalysisPerson; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.constant.BankStatementConstants; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.excel.ExcelResult; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.common.utils.poi.ExcelUtil; +import com.inscloudtech.common.utils.redis.RedisUtils; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.ImportResult; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; +import com.inscloudtech.datacenter.domain.dto.QueryFailedMsgReq; +import com.inscloudtech.datacenter.domain.vo.GetBSFieldValueCountReq; +import com.inscloudtech.datacenter.domain.vo.GetBankStatementListReq; +import com.inscloudtech.datacenter.domain.vo.GetOpeningAccountInfoListReq; +import com.inscloudtech.datacenter.domain.vo.GetPersonReq; +import com.inscloudtech.datacenter.mapper.es.ESBankStatementMapper; +import com.inscloudtech.datacenter.service.*; +import com.inscloudtech.system.service.ISysOssService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 银行流水 + * + * @author inscloudtech + */ +@Slf4j +@RestController +@RequiredArgsConstructor +@RequestMapping("/bank_statement") +public class BankController extends BaseController { + + private final BankService bankService; + private final ISysOssService ossService; + private final ImportResultService importResultService; + private final OpeningAccountInfoService openingAccountInfoService; + private final ESBankStatementMapper esBsMapper; + private final PlateNumberService plateNumberService; + + + //"获取导入银行流水模板") + @GetMapping("/template") + public void getTemplateFile(HttpServletResponse response) { + String sourceFolderPath = "/template/银行流水/"; // 源文件夹路径 + String zipFilePath = "银行流水导入模板.zip"; // 压缩文件路径 + bankService.createTemplate(sourceFolderPath,zipFilePath); + ossService.downloadLocal("/template/" + zipFilePath,zipFilePath, response); + } + + /** + * 返回银行信息 + */ + //"获取银行信息") + @GetMapping("/bank/list") + public R getBankList() { + return R.ok(bankService.getBankList()); + } + + //"查询导入失败原因") + @PostMapping("/queryFailedMsg") + public R queryFailedPromptMsg(@RequestBody QueryFailedMsgReq req) { + List importResults = importResultService.getResultListByCaseId(req.getCaseId(),req.getBatchId()); + return R.ok(importResults); + } + + //"导入银行流水4Excel") + @PostMapping(value = "/importExcel", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R importData(@RequestPart("file") MultipartFile file,String caseId) { + boolean result = false; + String importResultStr = ""; + int importCount = 0; + try { + ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), BankStatement.class, true); + List list = excelResult.getList(); + if(CollectionUtil.isNotEmpty(list)){ + result = bankService.importData(list,caseId,file.getOriginalFilename()); + importCount = list.size(); + }else { + throw new RuntimeException("未解析到数据!"); + } + }catch (Exception e){ + importResultStr = e.getMessage(); + } + ossService.upload2Local(importCount,importResultStr,file,caseId,"BANK_STATEMENT"); + return result ? R.ok() : R.fail(importResultStr); + } + + + /** + * 导入银行流水 + */ + //"导入银行流水V2") + @Log(title = "导入银行流水", businessType = BusinessType.IMPORT) + @PostMapping("/import/v2") + public R importBankStatementsV2(MultipartFile file, String caseId) { + try { + //批次号 + String batchId = IdUtil.getSnowflakeNextIdStr(); + RedisUtils.setCacheObject(BankStatementConstants.USERID_4_IMPORT+caseId, LoginHelper.getUsername()); + RedisUtils.setCacheObject(BankStatementConstants.BATCH_ID_4_IMPORT+caseId, batchId); + int total = bankService.importBankStatements(file, caseId); + List importResults = importResultService.getResultListByCaseId(caseId,batchId); + Map> collect = importResults.stream().collect(Collectors.groupingBy(ImportResult::getBankName)); + int failCount = collect.keySet().size(); + int successCount = total - failCount; + Integer uploadResult = 1; + if (importResults.size() > 0) { + uploadResult = 0; + } + Map result = new HashMap<>(); + result.put("total",total); + result.put("failCount",failCount); + result.put("successCount",successCount); + result.put("errorInfoList",importResults); + + // 处理结果 + ossService.upload2LocalWithBatchId(file,caseId,"BANK_STATEMENT",batchId,uploadResult); + + //处理车牌信息 + plateNumberService.invoke(caseId); + + return R.ok(result); + } catch (Exception e) { + e.printStackTrace(); + return R.fail(e.getMessage()); + } finally { + checkIsImportComplete(caseId); + esBsMapper.refresh("dc_bank_statement"); + } + } + + /** + * 查询流水导入结果 + */ + //"查询流水导入结果") + @GetMapping("/listImportResult") + public TableDataInfo listImportResult(ImportResult bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(ImportResult::getCaseId,bo.getCaseId()); + lqw.eq(ImportResult::getBatchId,bo.getBatchId()); + lqw.eq(bo.getSuccess() != null,ImportResult::getSuccess,bo.getSuccess()); + Page page = pageQuery.build(); + page = importResultService.page(page,lqw); + TableDataInfo tableDataInfo = new TableDataInfo(); + tableDataInfo.setTotal(page.getTotal()); + tableDataInfo.setRows(page.getRecords()); + return tableDataInfo; + } + + /** + * 导出流水导入失败结果 + */ + //"导出流水导入失败结果") + @PostMapping("/exportImportResult") + public void export(ImportResult bo, HttpServletResponse response) { + List importResults = importResultService.getResultListByCaseId(bo.getCaseId(),bo.getBatchId()); + + ExcelUtil.exportExcel(importResults, "流水导入失败结果", ImportResult.class, response); + } + + + //"分析成果-流水信息导入") + @PostMapping(value = "/import4AnalysisResult", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R importAnalysisResult(@RequestPart("file") MultipartFile file, String caseId, String analysisResultId) { + boolean result = false; + String importResultStr = ""; + int importCount = 0; + try { + ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), BankStatement.class, true); + List list = excelResult.getList(); + if(CollectionUtil.isNotEmpty(list)){ + result = bankService.importAnalysisResult(list,analysisResultId,getUsername()); + importCount = list.size(); + }else { + throw new RuntimeException("未解析到数据!"); + } + }catch (Exception e){ + e.printStackTrace(); + importResultStr = e.getMessage(); + } + if(!result){ + return R.fail(importResultStr); + }else { + ossService.upload2Local(importCount,importResultStr,file,caseId,"ANALYSIS_RESULT"); + return R.ok(); + } + } + + + //"分析成果-开户信息导入") + @PostMapping(value = "/oai/import4AnalysisResult", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R oaiImportAnalysisResult(@RequestPart("file") MultipartFile file, String caseId, String analysisResultId) { + boolean result = false; + String importResultStr = ""; + int importCount = 0; + try { + ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), OpeningAccountInfo.class, true); + List list = excelResult.getList(); + if(CollectionUtil.isNotEmpty(list)){ + result = openingAccountInfoService.importAnalysisResult(list,analysisResultId,getUsername()); + importCount = list.size(); + }else { + throw new RuntimeException("未解析到数据!"); + } + }catch (Exception e){ + e.printStackTrace(); + importResultStr = e.getMessage(); + } + if(!result){ + return R.fail(importResultStr); + }else { + ossService.upload2Local(importCount,importResultStr,file,caseId,"ANALYSIS_RESULT"); + return R.ok(); + } + } + + + //"更新流水信息") + @Log(title = "流水信息", businessType = BusinessType.UPDATE) + @PostMapping("/updateBatch") + public R edit(@RequestBody BankStatement bs) { + + bankService.updateBatchBSEsVersion(bs); + + return R.ok(null); + } + + //"保存至分析成果-流水") + @PostMapping("/save2AnalysisResult") + public R save2AnalysisResult(@RequestBody AnalysisDto dto) { + bankService.save2AnalysisResult(dto); + return R.ok(); + } + + //"保存至分析成果-开户") + @PostMapping("/save2AnalysisResultOai") + public R save2AnalysisResultOai(@RequestBody AnalysisDto dto) { + bankService.save2AnalysisResultOai(dto); + return R.ok(); + } + + + //"查询开户信息") + @PostMapping("/oai/list") + public TableDataInfo oaiPage(@RequestBody GetOpeningAccountInfoListReq req) throws Exception { + return bankService.oaiPage(req); + } + + //"导出银行开户信息") + @Log(title = "开户信息详情", businessType = BusinessType.EXPORT) + @PostMapping(value = "/oai/export") + public void exportOAI(GetOpeningAccountInfoListReq req, HttpServletResponse response) { + try { + bankService.exportOAI(req, response); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + //"查询银行流水列表") + @PostMapping("/list") + public TableDataInfo page(@RequestBody GetBankStatementListReq req) throws Exception { + return bankService.page(req); + } + + //"导出银行流水") + @Log(title = "流水信息", businessType = BusinessType.EXPORT) + @PostMapping(value = "/export") + public void export(GetBSFieldValueCountReq req, HttpServletResponse response) throws IOException { + bankService.exportBankStatement(req, response); + } + + //"删除流水") + @DeleteMapping("/del/{bsIds}") + @Log(title = "流水信息", businessType = BusinessType.DELETE) + public R del(@PathVariable String[] bsIds) { + return R.ok(bankService.deleteBSByIdsEsVersion(bsIds)); + } + + //"查询字段统计值") + @PostMapping("/getFieldsValueCount") + public R getFieldsValueCount(@RequestBody GetBSFieldValueCountReq req) throws IOException { + return R.ok(bankService.getFieldsValueCount(req)); + } + + //"查询字段统计值") + @PostMapping("/oai/getFieldsValueCount") + public R getFieldsValueCountForOAI(@RequestBody GetOpeningAccountInfoListReq req) throws IOException { + return R.ok(bankService.getFieldsValueCount4OAI(req)); + } + + //"更新开户信息") + @Log(title = "开户信息", businessType = BusinessType.UPDATE) + @PostMapping("/oai/updateBatch") + public R editOpeningAccountInfo(@RequestBody OpeningAccountInfo oai) { + + bankService.updateBatchOAIEsVersion(oai); + + return R.ok(null); + } + + //"删除开户") + @Log(title = "开户信息", businessType = BusinessType.DELETE) + @DeleteMapping("/oai/del/{oaiIds}") + public R delOAI(@PathVariable String[] oaiIds) { + return R.ok(bankService.deleteOAIByIdsEsVersion(oaiIds)); + } + + + + /** + * 人员统计 + */ + //"人员统计") + @GetMapping("/getPersonInfo") + public R getPersons(GetPersonReq req) throws Exception { + return R.ok(bankService.getPersonInfo(req)); + } + + /** + * 修改交易对象 + */ + //"修改分析人员类别") + @PutMapping("/editPersonInfo") + public R editPersonInfo(@RequestBody List updateList) { + return R.ok(bankService.editPersonInfo(updateList)); + } + + //"清空") + @Log(title = "流水信息", businessType = BusinessType.CLEAN) + @GetMapping("/clear/{caseId}") + public R clear(@PathVariable("caseId") String caseId) { + try { + bankService.clear(caseId); + return R.ok(); + } catch (Exception e) { + return R.fail(e.getMessage()); + } + } + + //"获取流水文件导入完成状态") + @GetMapping("/isImportComplete/{caseId}") + public R isImportComplete(@PathVariable String caseId) { + return R.ok(checkIsImportComplete(caseId)); + } + + public int checkIsImportComplete(String caseId) { + int flag = 0; + String importFileKey = "importFile-" + caseId; + Integer tempVar = RedisUtils.getCacheObject(importFileKey); + if(null != tempVar){ + flag = 1; + RedisUtils.deleteObject(importFileKey); + } + + String ckey = Constants.COMPLETE_BANK_COUNT + caseId; + String bankCountKey = Constants.IMPORT_BANK_COUNT + caseId; + long completeCount = RedisUtils.getAtomicValue(ckey); + long bankCount = RedisUtils.getAtomicValue(bankCountKey); + + if(bankCount == completeCount){ + RedisUtils.deleteObject(bankCountKey); + flag = 1; + RedisUtils.deleteObject(importFileKey); + RedisUtils.deleteObject(ckey); + } + + RedisUtils.deleteObject(BankStatementConstants.USERID_4_IMPORT+caseId); + RedisUtils.deleteObject(BankStatementConstants.BATCH_ID_4_IMPORT+caseId); + return flag; + } + + + +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/datacenter/CarInfoController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/datacenter/CarInfoController.java new file mode 100644 index 0000000..317535b --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/datacenter/CarInfoController.java @@ -0,0 +1,191 @@ +package com.inscloudtech.web.controller.datacenter; + +import cn.hutool.core.collection.CollectionUtil; +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.annotation.UpdateLog; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.excel.ExcelResult; +import com.inscloudtech.common.utils.BeanCopyUtils; +import com.inscloudtech.common.utils.poi.ExcelUtil; +import com.inscloudtech.datacenter.domain.CarInfo; +import com.inscloudtech.datacenter.mapper.CarInfoMapper; +import com.inscloudtech.datacenter.service.ICarInfoService; +import com.inscloudtech.system.service.ISysOssService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.*; + +/** + * 重点人员资产-车辆信息 + * + * @author inscloudtech + * @date 2023-11-10 + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/dc/carInfo") +public class CarInfoController extends BaseController { + + private final ICarInfoService iCarInfoService; + + private final ISysOssService iSysOssService; + + //"保存至分析成果") + @PostMapping("/save2AnalysisResult") + public R save2AnalysisResult(@RequestBody AnalysisDto dto) { + iCarInfoService.save2AnalysisResult(dto); + return R.ok(); + } + + /** + * 查询重点人员资产-车辆信息列表 + */ + //"查询车辆信息列表") + @GetMapping("/list") + public TableDataInfo list(CarInfo bo, PageQuery pageQuery) { + return iCarInfoService.queryPageList(bo, pageQuery); + } + + /** + * 获取重点人员资产-车辆信息详细信息 + * + * @param id 主键 + */ + //"获取车辆信息") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable String id) { + return R.ok(iCarInfoService.queryById(id)); + } + + /** + * 新增重点人员资产-车辆信息 + */ + //"新增车辆信息") + @Log(title = "重点人员资产-车辆信息", businessType = BusinessType.INSERT) + @PostMapping() + public R add( @RequestBody CarInfo bo) { + return R.ok(iCarInfoService.insertByBo(bo)); + } + + /** + * 修改重点人员资产-车辆信息 + */ + //"修改车辆信息") + @UpdateLog(title = "重点人员资产-车辆信息",mapperClass = CarInfoMapper.class, businessType = BusinessType.UPDATE) + @PutMapping() + public R edit(@RequestBody CarInfo bo) { + return R.ok(iCarInfoService.updateByBo(bo)); + } + + /** + * 删除重点人员资产-车辆信息 + * + * @param ids 主键串 + */ + //"删除车辆信息") + @Log(title = "重点人员资产-车辆信息", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable String[] ids) { + return R.ok(iCarInfoService.deleteWithValidByIds(Arrays.asList(ids), true)); + } + + //"批量修改车辆信息") + @PutMapping("/updateBatch") + public R updateBatch(@RequestBody CarInfo bo) { + List ids = bo.getIds(); + List list = new ArrayList<>(); + ids.stream().forEach(id ->{ + CarInfo update = BeanCopyUtils.copy(bo,CarInfo.class); + update.setId(id); + update.setUpdateBy(getUsername()); + update.setUpdateTime(new Date()); + list.add(update); + }); + return R.ok(iCarInfoService.updateBatch(list)); + } + + //"批量修改车辆信息对象集合") + @PutMapping("/updateBatchByList") + public R updateBatch(@RequestBody List list) { + list.stream().forEach(update ->{ + update.setUpdateBy(getUsername()); + update.setUpdateTime(new Date()); + }); + return R.ok(iCarInfoService.updateBatch(list)); + } + + //"导入车辆信息") + @PostMapping(value = "/import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R importData(@RequestPart("file") MultipartFile file, String caseId) { + boolean result = false; + String importResultStr = ""; + int importCount = 0; + try { + ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), CarInfo.class, true); + List list = excelResult.getList(); + if(CollectionUtil.isNotEmpty(list)){ + list = iCarInfoService.dataTrimAndDeduplication(list,caseId,getUsername()); + result = iCarInfoService.importData(list,caseId,null); + importCount = list.size(); + }else { + throw new RuntimeException("未解析到数据!"); + } + }catch (Exception e){ + importResultStr = e.getMessage(); + } + iSysOssService.upload2Local(importCount,importResultStr,file,caseId,"CAR_INFO"); + return result ? R.ok() : R.fail(importResultStr); + } + + //"分析成果-车辆信息导入") + @PostMapping(value = "/import4AnalysisResult", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R importAnalysisResult(@RequestPart("file") MultipartFile file, String caseId, String analysisResultId) { + boolean result = false; + String importResultStr = ""; + int importCount = 0; + try { + ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), CarInfo.class, true); + List list = excelResult.getList(); + if(CollectionUtil.isNotEmpty(list)){ + result = iCarInfoService.importAnalysisResult(list,analysisResultId,getUsername()); + importCount = list.size(); + }else { + throw new RuntimeException("未解析到数据!"); + } + }catch (Exception e){ + e.printStackTrace(); + importResultStr = e.getMessage(); + } + + iSysOssService.upload2Local(importCount,importResultStr,file,caseId,"CAR_INFO"); + return result ? R.ok() : R.fail(importResultStr); + } + + /** + * 导出交易对象列表 + */ + //"导出车辆信息") + @PostMapping("/export") + public void export(CarInfo bo, HttpServletResponse response) { + List list = Collections.EMPTY_LIST; + if(bo.getDownloadTemplate() == null){ + list = iCarInfoService.queryList(bo); + } + ExcelUtil.exportExcel(list, "车辆信息", CarInfo.class, response); + } + +} + diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/datacenter/OtherAssetsController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/datacenter/OtherAssetsController.java new file mode 100644 index 0000000..8a28192 --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/datacenter/OtherAssetsController.java @@ -0,0 +1,148 @@ +package com.inscloudtech.web.controller.datacenter; + + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.utils.BeanCopyUtils; +import com.inscloudtech.datacenter.domain.OtherAssets; +import com.inscloudtech.system.domain.SysOss; +import com.inscloudtech.datacenter.service.IOtherAssetsService; +import com.inscloudtech.system.service.ISysOssService; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.NotEmpty; +import java.io.IOException; +import java.util.*; + + +/** + * 重点人员资产-其他资产信息 + * + * @author inscloudtech + * @date 2023-11-09 + */ + +@RequiredArgsConstructor +@RestController +@RequestMapping("/dc/otherAssets") +public class OtherAssetsController extends BaseController { + + private final ISysOssService iSysOssService; + + private final IOtherAssetsService iOtherAssetsService; + + //"保存至分析成果") + @PostMapping("/save2AnalysisResult") + public R save2AnalysisResult(@RequestBody AnalysisDto dto) { + iOtherAssetsService.save2AnalysisResult(dto); + return R.ok(); + } + + + private static final String BUSINESS_MODULE = "OTHER_ASSETS"; + + //"查询其他资产信息文件列表") + @GetMapping("/listFile") + public TableDataInfo listFile(SysOss bo, PageQuery pageQuery) { + bo.setBusinessModule(BUSINESS_MODULE); + return iSysOssService.queryPageList(bo, pageQuery); + } + + + //"查询其他资产信息列表") + @GetMapping("/list") + public TableDataInfo list(OtherAssets bo, PageQuery pageQuery) { + return iOtherAssetsService.queryPageList(bo, pageQuery); + } + + //"导入其他资产信息") + @Log(title = "其他资产信息", businessType = BusinessType.IMPORT) + @PostMapping(value = "/import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R> importData(@RequestPart("file") MultipartFile file, String caseId) { + if (ObjectUtil.isNull(file)) { + return R.fail("上传文件不能为空"); + } + SysOss oss = iSysOssService.upload2Local(1,"",file,caseId,BUSINESS_MODULE); + Map map = new HashMap<>(2); + map.put("url", oss.getUrl()); + map.put("fileName", oss.getOriginalName()); + map.put("ossId", oss.getOssId()); + iOtherAssetsService.insertFileContent(oss.getOssId(),file,caseId,BUSINESS_MODULE); + return R.ok(map); + } + + /** + * 批量修改交易对象 + */ + //"批量修改其他资产") + @PutMapping("/updateBatch") + public R updateBatch(@RequestBody SysOss bo) { + List ids = bo.getIds(); + List list = new ArrayList<>(); + ids.stream().forEach(id ->{ + SysOss update = BeanCopyUtils.copy(bo,SysOss.class); + update.setOssId(id); + update.setUpdateBy(getUsername()); + update.setUpdateTime(new Date()); + list.add(update); + }); + return R.ok(iSysOssService.updateBatch(list)); + } + + //"批量修改其他资产集合") + @PutMapping("/updateBatchByList") + public R updateBatch(@RequestBody List list) { + list.stream().forEach(update ->{ + update.setUpdateBy(getUsername()); + update.setUpdateTime(new Date()); + }); + return R.ok(iSysOssService.updateBatch(list)); + } + + @SneakyThrows + //"导出其他资产信息") + @Log(title = "其他资产信息", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SysOss bo, HttpServletResponse response) { + if(CollectionUtil.isNotEmpty(bo.getIds())){ + bo.getIds().stream().forEach(id ->{ + try { + iSysOssService.download(id,response); + } catch (IOException e) { + e.printStackTrace(); + } + }); + }else { + List sysOsses = iSysOssService.queryList(bo); + if(CollectionUtil.isNotEmpty(sysOsses)){ + sysOsses.stream().forEach(oss ->{ + try { + iSysOssService.download(oss.getOssId(),response); + } catch (IOException e) { + e.printStackTrace(); + } + }); + } + } + } + + + //"删除其他资产信息") + @Log(title = "其他资产信息", businessType = BusinessType.DELETE) + @DeleteMapping("/{ossIds}") + public R remove(@NotEmpty(message = "主键不能为空") @PathVariable String[] ossIds) { + return R.ok(iOtherAssetsService.remove(Arrays.asList(ossIds))); + } +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/datacenter/OtherInformationController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/datacenter/OtherInformationController.java new file mode 100644 index 0000000..c35d92b --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/datacenter/OtherInformationController.java @@ -0,0 +1,148 @@ +package com.inscloudtech.web.controller.datacenter; + + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.utils.BeanCopyUtils; +import com.inscloudtech.datacenter.domain.OtherInformation; +import com.inscloudtech.system.domain.SysOss; +import com.inscloudtech.datacenter.service.IOtherInformationService; +import com.inscloudtech.system.service.ISysOssService; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.NotEmpty; +import java.io.IOException; +import java.util.*; + + +/** + * -其他信息 + * + * @author inscloudtech + * @date 2023-11-09 + */ + +@RequiredArgsConstructor +@RestController +@RequestMapping("/dc/otherInformation") +public class OtherInformationController extends BaseController { + + private final ISysOssService iSysOssService; + + private final IOtherInformationService otherInformationService; + + private static final String BUSINESS_MODULE = "OTHER_INFORMATION"; + + //"保存至分析成果") + @PostMapping("/save2AnalysisResult") + public R save2AnalysisResult(@RequestBody AnalysisDto dto) { + otherInformationService.save2AnalysisResult(dto); + return R.ok(); + } + /** + * 查询-其他信息列表 + */ + //"查询其他信息文件列表") + @GetMapping("/listFile") + public TableDataInfo listFile(SysOss bo, PageQuery pageQuery) { + bo.setBusinessModule(BUSINESS_MODULE); + return iSysOssService.queryPageList(bo, pageQuery); + } + + //"查询其他信息列表") + @GetMapping("/list") + public TableDataInfo list(OtherInformation bo, PageQuery pageQuery) { + return otherInformationService.queryPageList(bo, pageQuery); + } + + /** + * 批量修改交易对象 + */ + //"批量修改其他信息") + @PutMapping("/updateBatch") + public R updateBatch(@RequestBody SysOss bo) { + List ids = bo.getIds(); + List list = new ArrayList<>(); + ids.stream().forEach(id ->{ + SysOss update = BeanCopyUtils.copy(bo,SysOss.class); + update.setOssId(id); + update.setUpdateBy(getUsername()); + update.setUpdateTime(new Date()); + list.add(update); + }); + return R.ok(iSysOssService.updateBatch(list)); + } + + //"批量修改其他信息集合") + @PutMapping("/updateBatchByList") + public R updateBatch(@RequestBody List list) { + list.stream().forEach(update ->{ + update.setUpdateBy(getUsername()); + update.setUpdateTime(new Date()); + }); + return R.ok(iSysOssService.updateBatch(list)); + } + + //"导入其他信息") + @Log(title = "其他信息", businessType = BusinessType.IMPORT) + @PostMapping(value = "/import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R> importData(@RequestPart("file") MultipartFile file, String caseId) { + if (ObjectUtil.isNull(file)) { + return R.fail("上传文件不能为空"); + } + SysOss oss = iSysOssService.upload2Local(1,"",file,caseId,BUSINESS_MODULE); + Map map = new HashMap<>(2); + map.put("url", oss.getUrl()); + map.put("fileName", oss.getOriginalName()); + map.put("ossId", oss.getOssId()); + otherInformationService.insertFileContent(oss.getOssId(),file,caseId,BUSINESS_MODULE); + return R.ok(map); + } + + @SneakyThrows + //"导出其他信息") + @Log(title = "其他信息", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SysOss bo, HttpServletResponse response) { + if(CollectionUtil.isNotEmpty(bo.getIds())){ + bo.getIds().stream().forEach(id ->{ + try { + iSysOssService.download(id,response); + } catch (IOException e) { + e.printStackTrace(); + } + }); + }else { + List sysOsses = iSysOssService.queryList(bo); + if(CollectionUtil.isNotEmpty(sysOsses)){ + sysOsses.stream().forEach(oss ->{ + try { + iSysOssService.download(oss.getOssId(),response); + } catch (IOException e) { + e.printStackTrace(); + } + }); + } + } + } + + + //"删除其他信息") + @Log(title = "其他信息", businessType = BusinessType.EXPORT) + @DeleteMapping("/{ossIds}") + public R remove(@NotEmpty(message = "主键不能为空") @PathVariable String[] ossIds) { + return R.ok(otherInformationService.remove(Arrays.asList(ossIds))); + } +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/datacenter/PublicFamilyController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/datacenter/PublicFamilyController.java new file mode 100644 index 0000000..633341c --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/datacenter/PublicFamilyController.java @@ -0,0 +1,203 @@ +package com.inscloudtech.web.controller.datacenter; + +import cn.hutool.core.collection.CollectionUtil; +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.annotation.UpdateLog; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.excel.ExcelResult; +import com.inscloudtech.common.utils.BeanCopyUtils; +import com.inscloudtech.common.utils.poi.ExcelUtil; +import com.inscloudtech.datacenter.domain.PublicFamily; +import com.inscloudtech.datacenter.mapper.PublicFamilyMapper; +import com.inscloudtech.datacenter.service.IPublicFamilyService; +import com.inscloudtech.system.service.ISysOssService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.*; + + +/** + * 数据中心-职工家属 + * + * @author inscloudtech + * @date 2023-11-09 + */ +//"公职人员-职工家属") +@RequiredArgsConstructor +@RestController +@RequestMapping("/dc/publicFamily") +public class PublicFamilyController extends BaseController { + + private final IPublicFamilyService iPublicFamilyService; + + private final ISysOssService iSysOssService; + + //"保存至分析成果") + @PostMapping("/save2AnalysisResult") + public R save2AnalysisResult(@RequestBody AnalysisDto dto) { + iPublicFamilyService.save2AnalysisResult(dto); + return R.ok(); + } + + /** + * 查询数据中心-职工家属列表 + */ + //"查询职工家属列表") + @GetMapping("/list") + public TableDataInfo list(PublicFamily bo, PageQuery pageQuery) { + return iPublicFamilyService.queryPageList(bo, pageQuery); + } + + /** + * 查询交易对象列表 + */ + //"高亮查询职工家属列表") + @GetMapping("/highlightList") + public TableDataInfo highlightList(PublicFamily bo, PageQuery pageQuery) { + return iPublicFamilyService.highlightList(bo, pageQuery); + } + + + //"导出职工家属列表") + @Log(title = "职工家属", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(PublicFamily bo, HttpServletResponse response) { + List list = Collections.EMPTY_LIST; + if(bo.getDownloadTemplate() == null){ + list = iPublicFamilyService.queryList(bo); + } + ExcelUtil.exportExcel(list, "职工及家属名册", PublicFamily.class, response); + } + + /** + * 获取数据中心-职工家属详细信息 + * + * @param id 主键 + */ + //"获取职工家属信息") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable String id) { + return R.ok(iPublicFamilyService.queryById(id)); + } + + /** + * 新增数据中心-职工家属 + */ + //"新增职工家属信息") + @Log(title = "职工家属", businessType = BusinessType.INSERT) + @PostMapping() + public R add( @RequestBody PublicFamily bo) { + return R.ok(iPublicFamilyService.insertByBo(bo)); + } + + /** + * 修改数据中心-职工家属 + */ + //"修改职工家属信息") + @UpdateLog(title = "职工家属",mapperClass = PublicFamilyMapper.class, businessType = BusinessType.UPDATE) + @PutMapping() + public R edit(@RequestBody PublicFamily bo) { + return R.ok(iPublicFamilyService.updateByBo(bo)); + } + + //"批量修改职工家属信息") + @PutMapping("/updateBatch") + public R updateBatch(@RequestBody PublicFamily bo) { + List ids = bo.getIds(); + List list = new ArrayList<>(); + ids.stream().forEach(id ->{ + PublicFamily update = BeanCopyUtils.copy(bo,PublicFamily.class); + update.setId(id); + update.setUpdateBy(getUsername()); + update.setUpdateTime(new Date()); + list.add(update); + }); + return R.ok(iPublicFamilyService.updateBatch(list)); + } + //"批量修改职工家属信息集合") + @PutMapping("/updateBatchByList") + public R updateBatch(@RequestBody List list) { + list.stream().forEach(update ->{ + update.setUpdateBy(getUsername()); + update.setUpdateTime(new Date()); + }); + return R.ok(iPublicFamilyService.updateBatch(list)); + } + + + //"导入职工家属列表") + @PostMapping(value = "/import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R importData(@RequestPart("file") MultipartFile file, String caseId) { + boolean result = false; + String importResultStr = ""; + int importCount = 0; + try { + ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), PublicFamily.class, true); + List list = excelResult.getList(); + if(CollectionUtil.isNotEmpty(list)){ + list = iPublicFamilyService.dataTrimAndDeduplication(list,caseId,getUsername()); + result = iPublicFamilyService.importData(list,caseId,null); + importCount = list.size(); + }else { + throw new RuntimeException("未解析到数据!"); + } + }catch (Exception e){ + e.printStackTrace(); + importResultStr = e.getMessage(); + } + iSysOssService.upload2Local(importCount,importResultStr,file,caseId,"PUBLIC_FAMILY"); + return result ? R.ok() : R.fail(importResultStr); + } + + //"分析成果-不动产信息导入") + @PostMapping(value = "/import4AnalysisResult", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R importAnalysisResult(@RequestPart("file") MultipartFile file, String caseId, String analysisResultId) { + boolean result = false; + String importResultStr = ""; + int importCount = 0; + try { + ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), PublicFamily.class, true); + List list = excelResult.getList(); + if(CollectionUtil.isNotEmpty(list)){ + result = iPublicFamilyService.importAnalysisResult(list,analysisResultId,getUsername()); + importCount = list.size(); + }else { + throw new RuntimeException("未解析到数据!"); + } + }catch (Exception e){ + importResultStr = e.getMessage(); + } + + iSysOssService.upload2Local(importCount,importResultStr,file,caseId,"ANALYSIS_RESULT"); + return result ? R.ok() : R.fail(importResultStr); + } + + + + + /** + * 删除数据中心-职工家属 + * + * @param ids 主键串 + */ + + //"删除职工家属信息") + @Log(title = "职工家属", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable String[] ids) { + return R.ok(iPublicFamilyService.deleteWithValidByIds(Arrays.asList(ids), true)); + } +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/index/LeaderTaskController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/index/LeaderTaskController.java new file mode 100644 index 0000000..21086f7 --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/index/LeaderTaskController.java @@ -0,0 +1,316 @@ +package com.inscloudtech.web.controller.index; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.inscloudtech.bankStatementAnalysis.util.DesUtil; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.annotation.UpdateLog; +import com.inscloudtech.caseMange.domain.vo.*; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.domain.entity.SysDept; +import com.inscloudtech.common.core.domain.entity.SysUser; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.excel.ExcelResult; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.common.utils.poi.ExcelUtil; + +import com.inscloudtech.caseMange.domain.SysLawCase; +import com.inscloudtech.caseMange.mapper.SysLawCaseMapper; +import com.inscloudtech.system.domain.vo.LoginRecordEntity; +import com.inscloudtech.system.domain.vo.SysUserExportVo; +import com.inscloudtech.system.mapper.SysUserMapper; +import com.inscloudtech.caseMange.service.ILeaderTaskService; +import com.inscloudtech.caseMange.service.ISysLawCaseService; +import com.inscloudtech.system.service.ISysOperLogService; +import com.inscloudtech.system.service.ISysUserService; +import com.inscloudtech.system.service.LoginRecordHelper; +import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * 案管领导首页 + */ + +@RequiredArgsConstructor +@RestController +@RequestMapping("/leader/task") +public class LeaderTaskController { + + private final ISysUserService userService; + private final ILeaderTaskService taskService; + private final ISysLawCaseService lawCaseService; + private final ISysOperLogService operLogService; + private final LoginRecordHelper loginRecordHelper; + private final SysUserMapper userMapper; + + private final Logger log = LoggerFactory.getLogger(LeaderTaskController.class); + + //"案件删除") + @Log(title = "案管领导", businessType = BusinessType.DELETE) + @PostMapping("/lawCase/delete") + public R deleteLawCase(@RequestBody SysLawCase req) { + try { + taskService.deleteLawCase(req.getId()); + return R.ok(null); + } catch (Exception e) { + log.error("删除案件错误:" + e.getMessage(), e); + return R.fail(e.getMessage(), null); + } + } + + + /** + * 导出用户列表 + */ + @Log(title = "用户管理", businessType = BusinessType.EXPORT) + @PostMapping("/investigator/export") + public void export(SysUser user, HttpServletResponse response) { + user.setRoleId(Constants.INVESTIGATOR_ROLE_ID); + List list = userService.selectUserList(user); + List listVo = BeanUtil.copyToList(list, SysUserExportVo.class); + for (int i = 0; i < list.size(); i++) { + SysDept dept = list.get(i).getDept(); + SysUserExportVo vo = listVo.get(i); + if (ObjectUtil.isNotEmpty(dept)) { + vo.setDeptName(dept.getDeptName()); + vo.setLeader(dept.getLeader()); + } + } + ExcelUtil.exportExcel(listVo, "调查人员信息", SysUserExportVo.class, response); + } + + //"导入调查人员信息") + @PostMapping(value = "/investigator/import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R importData(@RequestPart("file") MultipartFile file, boolean updateSupport) { + try { + ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), MInvestigator.class, true); + List list = excelResult.getList(); + List users = BeanUtil.copyToList(list,SysUser.class); + String msg = taskService.importInvestigator(users, updateSupport); + return R.ok(msg); + } catch (Exception e) { + log.error("导入调查人员信息错误: " + e.getMessage(), e); + return R.fail(e.getMessage(), null); + } + } + + + /** + * 添加调查人员 + */ + //"添加调查人员") + @Log(title = "调查人员管理", businessType = BusinessType.INSERT) + @PostMapping("/investigator/add") + public R addInvestigator(@RequestBody AddInvestigatorReq req) { + try { + taskService.addInvestigator(req); + return R.ok(null); + } catch (Exception e) { + log.error("添加调查人员: " + e.getMessage(), e); + return R.fail(e.getMessage(), null); + } + } + + /** + * 调查人员信息编辑 + */ + //"调查人员信息编辑") + @UpdateLog( + title = "调查人员管理", + businessType = BusinessType.UPDATE, + mapperClass = SysUserMapper.class) + @PostMapping("/investigator/edit") + public R editInvestigator(@RequestBody EditInvestigatorReq req) { + try { + taskService.editInvestigator(req); + return R.ok(null); + } catch (Exception e) { + log.error("编辑调查人员信息: " + e.getMessage(), e); + return R.fail(e.getMessage(), null); + } + } + + /** + * 删除调查人员 + */ + //"删除调查人员") + @Log(title = "调查人员管理", businessType = BusinessType.DELETE) + @PostMapping("/investigator/delete") + public R deleteInvestigator(@RequestBody DeleteInvestigatorReq req) { + try { + // 删除调查人员的同时,操作记录也应该删除 + taskService.deleteInvestigator(req.getId()); + return R.ok(null); + } catch (Exception e) { + log.error("删除调查人员信息: " + e.getMessage(), e); + return R.fail(e.getMessage(), null); + } + } + + /** + * 调查人员列表 + */ + @GetMapping("/investigator/list") + public TableDataInfo investigatorList(SysUser user, PageQuery pageQuery) { + user.setRoleId(Constants.INVESTIGATOR_ROLE_ID); + return userService.selectPageUserList(user,pageQuery); + } + + /** + * 登录记录 + */ + //"登录记录") + @PostMapping("/queryOperateLog") + public TableDataInfo queryOperateLog(@RequestBody QueryOperateLogReq req) { + return operLogService.queryOperateLogV2(req); + } + + /** + * 案件编辑 + */ + @UpdateLog( + title = "案件管理", + businessType = BusinessType.UPDATE, + mapperClass = SysLawCaseMapper.class, + methodName = "selectById") + //"案件编辑") + @PostMapping("/lawCase/edit") + public R editLawCase(@RequestBody EditLawCaseReq req) { + try { + taskService.editLawCase(req); + return R.ok(null); + } catch (Exception e) { + log.error("案件编辑错误: " + e.getMessage(), e); + return R.fail(e.getMessage(), null); + } + } + + /** + * 案列列表 + */ + @PostMapping("/lawCase/list") + public TableDataInfo lawCaseList(@RequestBody LawCaseListReq req) { + + TableDataInfo page = lawCaseService.getLawCaseList(req); + + List records = new ArrayList<>(); + + for (SysLawCase lawCase : page.getRows()) { + LawCaseResp resp = new LawCaseResp(); + + String caseId = lawCase.getId(); + + resp.setId(caseId); + resp.setName(lawCase.getName()); + resp.setCreateTime(lawCase.getCreateTime()); + resp.setRemark(lawCase.getRemark()); + + // 根据案件Id,查询关联的调查人员 + String investigators = lawCase.getInvestigatorStr(); + if(StrUtil.isNotEmpty(investigators)){ + List idNoList; + if(investigators.contains(",")){ + idNoList = Arrays.asList(investigators.split(",")); + }else { + idNoList = Collections.singletonList(investigators); + } + if(CollectionUtil.isNotEmpty(idNoList)){ + LambdaQueryWrapper userLqw = Wrappers.lambdaQuery(); + userLqw.in(SysUser::getIdCardNo, idNoList); + List sysUsers = userMapper.selectList(userLqw); + // 根据案件Id,查询关联的调查人员 + List investigatorNames = new ArrayList<>(); + List investigatorIds = new ArrayList<>(); + for (SysUser user : sysUsers) { + investigatorNames.add(user.getUserName()); + investigatorIds.add(user.getUserId()); + } + resp.setInvestigators(String.join("、", investigatorNames)); + resp.setIds(investigatorIds); + } + } + + // 添加 + records.add(resp); + } + TableDataInfo tableDataInfo = TableDataInfo.build(); + tableDataInfo.setRows(records); + tableDataInfo.setTotal(page.getTotal()); + return tableDataInfo; + } + + /** + * 新增案件时,所有调查人员信息 + */ + @GetMapping("/addLawCase/investigator/list") + public R getInvestigatorsForAddLawCase() { + try { + SysUser user = new SysUser(); + user.setRoleId(Constants.INVESTIGATOR_ROLE_ID); + List investigators = userService.selectUserList(user); + return R.ok(investigators); + } catch (Exception e) { + log.error("新增案件,获取调查员人列表错误:" + e.getMessage(), e); + return R.fail(e.getMessage(), null); + } + } + + /** + * 新增案件 + */ + //"新增案件") + @Log(title = "新增案件", businessType = BusinessType.INSERT) + @PostMapping("/addLawCase") + public R addLawCase(@RequestBody AddLawCaseReq req) { + + lawCaseService.addLawCase(req); + + return R.ok(null); + } + + /** + * 领导权限转移 + */ + //"领导权限转移") + @Log(title = "领导权限转移", businessType = BusinessType.GRANT) + @PostMapping("/transfer") + public R transfer(@RequestBody LeaderTransferReq req) { + // 权限转移后,当前账号将失效且无法再登录 + // 创建账号,根据姓名和身份证号 + String name = req.getName(); + String encryptedIdCardNo = req.getIdCardNo(); + String idCardNo = DesUtil.decrypt(encryptedIdCardNo); + + taskService.transform(idCardNo, name); + + // 冻结当前案管领导账号 + userService.freezeUser(LoginHelper.getUserId()); + + return R.ok(); + } + + //"查询字段统计值") + @PostMapping("/getFieldsValueCount") + public R getFieldsValueCount(@RequestBody GetLoginRecordFieldValueCountReq req) throws Exception { + return R.ok(loginRecordHelper.getFieldsValueCount(req)); + } + +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/monitor/CacheController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/monitor/CacheController.java new file mode 100644 index 0000000..f98c289 --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/monitor/CacheController.java @@ -0,0 +1,161 @@ +package com.inscloudtech.web.controller.monitor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.collection.CollUtil; +import com.inscloudtech.common.constant.CacheConstants; +import com.inscloudtech.common.constant.CacheNames; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.utils.JsonUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.redis.CacheUtils; +import com.inscloudtech.common.utils.redis.RedisUtils; +import com.inscloudtech.system.domain.SysCache; +import lombok.RequiredArgsConstructor; +import org.redisson.spring.data.connection.RedissonConnectionFactory; +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 缓存监控 + * + * @author inscloudtech + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/cache") +public class CacheController { + + private final RedissonConnectionFactory connectionFactory; + + private final static List CACHES = new ArrayList<>(); + + static { + CACHES.add(new SysCache(CacheConstants.ONLINE_TOKEN_KEY, "在线用户")); + CACHES.add(new SysCache(CacheNames.SYS_CONFIG, "配置信息")); + CACHES.add(new SysCache(CacheNames.SYS_DICT, "数据字典")); + CACHES.add(new SysCache(CacheConstants.CAPTCHA_CODE_KEY, "验证码")); + CACHES.add(new SysCache(CacheConstants.REPEAT_SUBMIT_KEY, "防重提交")); + CACHES.add(new SysCache(CacheConstants.RATE_LIMIT_KEY, "限流处理")); + CACHES.add(new SysCache(CacheNames.SYS_OSS_CONFIG, "OSS配置")); + CACHES.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数")); + } + /** + * 获取缓存监控列表 + */ + @SaCheckPermission("monitor:cache:list") + @GetMapping() + public R> getInfo() throws Exception { + RedisConnection connection = connectionFactory.getConnection(); + Properties info = connection.info(); + Properties commandStats = connection.info("commandstats"); + Long dbSize = connection.dbSize(); + + Map result = new HashMap<>(3); + result.put("info", info); + result.put("dbSize", dbSize); + + List> pieList = new ArrayList<>(); + if (commandStats != null) { + commandStats.stringPropertyNames().forEach(key -> { + Map data = new HashMap<>(2); + String property = commandStats.getProperty(key); + data.put("name", StringUtils.removeStart(key, "cmdstat_")); + data.put("value", StringUtils.substringBetween(property, "calls=", ",usec")); + pieList.add(data); + }); + } + result.put("commandStats", pieList); + return R.ok(result); + } + /** + * 获取缓存监控缓存名列表 + */ + @SaCheckPermission("monitor:cache:list") + @GetMapping("/getNames") + public R> cache() { + return R.ok(CACHES); + } + /** + * 获取缓存监控Key列表 + * + * @param cacheName 缓存名 + */ + @SaCheckPermission("monitor:cache:list") + @GetMapping("/getKeys/{cacheName}") + public R> getCacheKeys(@PathVariable String cacheName) { + Collection cacheKeys = new HashSet<>(0); + if (isCacheNames(cacheName)) { + Set keys = CacheUtils.keys(cacheName); + if (CollUtil.isNotEmpty(keys)) { + cacheKeys = keys.stream().map(Object::toString).collect(Collectors.toList()); + } + } else { + cacheKeys = RedisUtils.keys(cacheName + "*"); + } + return R.ok(cacheKeys); + } + /** + * 获取缓存监控缓存值详情 + * + * @param cacheName 缓存名 + * @param cacheKey 缓存key + */ + @SaCheckPermission("monitor:cache:list") + @GetMapping("/getValue/{cacheName}/{cacheKey}") + public R getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey) { + Object cacheValue; + if (isCacheNames(cacheName)) { + cacheValue = CacheUtils.get(cacheName, cacheKey); + } else { + cacheValue = RedisUtils.getCacheObject(cacheKey); + } + SysCache sysCache = new SysCache(cacheName, cacheKey, JsonUtils.toJsonString(cacheValue)); + return R.ok(sysCache); + } + /** + * 清理缓存监控缓存名 + * + * @param cacheName 缓存名 + */ + @SaCheckPermission("monitor:cache:list") + @DeleteMapping("/clearCacheName/{cacheName}") + public R clearCacheName(@PathVariable String cacheName) { + if (isCacheNames(cacheName)) { + CacheUtils.clear(cacheName); + } else { + RedisUtils.deleteKeys(cacheName + "*"); + } + return R.ok(); + } + /** + * 清理缓存监控Key + * + * @param cacheKey key名 + */ + @SaCheckPermission("monitor:cache:list") + @DeleteMapping("/clearCacheKey/{cacheName}/{cacheKey}") + public R clearCacheKey(@PathVariable String cacheName, @PathVariable String cacheKey) { + if (isCacheNames(cacheName)) { + CacheUtils.evict(cacheName, cacheKey); + } else { + RedisUtils.deleteObject(cacheKey); + } + return R.ok(); + } + /** + * 清理全部缓存监控 + */ + @SaCheckPermission("monitor:cache:list") + @DeleteMapping("/clearCacheAll") + public R clearCacheAll() { + RedisUtils.deleteKeys("*"); + return R.ok(); + } + + private boolean isCacheNames(String cacheName) { + return !StringUtils.contains(cacheName, ":"); + } +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/monitor/SysLogininforController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/monitor/SysLogininforController.java new file mode 100644 index 0000000..46029c3 --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/monitor/SysLogininforController.java @@ -0,0 +1,84 @@ +package com.inscloudtech.web.controller.monitor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.constant.CacheConstants; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.utils.poi.ExcelUtil; +import com.inscloudtech.common.utils.redis.RedisUtils; +import com.inscloudtech.system.domain.SysLogininfor; +import com.inscloudtech.system.service.ISysLogininforService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 系统访问记录 + * + * @author inscloudtech + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/logininfor") +public class SysLogininforController extends BaseController { + + private final ISysLogininforService logininforService; + /** + * 获取系统访问记录列表 + */ + @SaCheckPermission("monitor:logininfor:list") + @GetMapping("/list") + public TableDataInfo list(SysLogininfor logininfor, PageQuery pageQuery) { + return logininforService.selectPageLogininforList(logininfor, pageQuery); + } + /** + * 导出系统访问记录列表 + */ + @Log(title = "登录日志", businessType = BusinessType.EXPORT) + @SaCheckPermission("monitor:logininfor:export") + @PostMapping("/export") + public void export(SysLogininfor logininfor, HttpServletResponse response) { + List list = logininforService.selectLogininforList(logininfor); + ExcelUtil.exportExcel(list, "登录日志", SysLogininfor.class, response); + } + /** + * 批量删除登录日志 + * @param infoIds 日志ids + */ + @SaCheckPermission("monitor:logininfor:remove") + @Log(title = "登录日志", businessType = BusinessType.DELETE) + @DeleteMapping("/{infoIds}") + public R remove(@PathVariable Long[] infoIds) { + return toAjax(logininforService.deleteLogininforByIds(infoIds)); + } + /** + * 清理系统访问记录 + */ + @SaCheckPermission("monitor:logininfor:remove") + @Log(title = "登录日志", businessType = BusinessType.CLEAN) + @DeleteMapping("/clean") + public R clean() { + logininforService.cleanLogininfor(); + return R.ok(); + } + + @SaCheckPermission("monitor:logininfor:unlock") + @Log(title = "账户解锁", businessType = BusinessType.OTHER) + @GetMapping("/unlock/{userName}") + public R unlock(@PathVariable("userName") String userName) { + String loginName = CacheConstants.PWD_ERR_CNT_KEY + userName; + if (RedisUtils.hasKey(loginName)) { + RedisUtils.deleteObject(loginName); + } + return R.ok(); + } + +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/monitor/SysOperUpdateLogController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/monitor/SysOperUpdateLogController.java new file mode 100644 index 0000000..f893c40 --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/monitor/SysOperUpdateLogController.java @@ -0,0 +1,101 @@ +package com.inscloudtech.web.controller.monitor; + +import java.util.List; +import java.util.Arrays; + +import lombok.RequiredArgsConstructor; +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import com.inscloudtech.common.annotation.RepeatSubmit; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.validate.AddGroup; +import com.inscloudtech.common.core.validate.EditGroup; +import com.inscloudtech.common.core.validate.QueryGroup; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.utils.poi.ExcelUtil; +import com.inscloudtech.system.domain.vo.SysOperUpdateLogVo; +import com.inscloudtech.system.domain.bo.SysOperUpdateLogBo; +import com.inscloudtech.system.service.ISysOperUpdateLogService; +import com.inscloudtech.common.core.page.TableDataInfo; + +/** + * 操作数据更新记录 + * + * @author cas + * @date 2023-05-18 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/operUpdateLog") +public class SysOperUpdateLogController extends BaseController { + + private final ISysOperUpdateLogService iSysOperUpdateLogService; + /** + * 查询操作日志记录列表 + */ +// @SaCheckPermission("system:operUpdateLog:list") + @GetMapping("/list") + public TableDataInfo list(SysOperUpdateLogBo bo, PageQuery pageQuery) { + return iSysOperUpdateLogService.queryPageList(bo, pageQuery); + } + /** + * 导出操作日志记录列表 + */ + @SaCheckPermission("system:operUpdateLog:export") + @Log(title = "操作日志记录", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SysOperUpdateLogBo bo, HttpServletResponse response) { + List list = iSysOperUpdateLogService.queryList(bo); + ExcelUtil.exportExcel(list, "操作日志记录", SysOperUpdateLogVo.class, response); + } + /** + * 获取操作日志记录详细信息 + * + * @param operId 主键 + */ + @SaCheckPermission("system:operUpdateLog:query") + @GetMapping("/{operId}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long operId) { + return R.ok(iSysOperUpdateLogService.queryById(operId)); + } + /** + * 新增操作日志记录 + */ + @SaCheckPermission("system:operUpdateLog:add") + @Log(title = "操作日志记录", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SysOperUpdateLogBo bo) { + return toAjax(iSysOperUpdateLogService.insertByBo(bo)); + } + /** + * 修改操作日志记录 + */ + @SaCheckPermission("system:operUpdateLog:edit") + @Log(title = "操作日志记录", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody SysOperUpdateLogBo bo) { + return toAjax(iSysOperUpdateLogService.updateByBo(bo)); + } + /** + * 删除操作日志记录 + * + * @param operIds 主键串 + */ + @SaCheckPermission("system:operUpdateLog:remove") + @Log(title = "操作日志记录", businessType = BusinessType.DELETE) + @DeleteMapping("/{operIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] operIds) { + return toAjax(iSysOperUpdateLogService.deleteWithValidByIds(Arrays.asList(operIds), true)); + } +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/monitor/SysOperlogController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/monitor/SysOperlogController.java new file mode 100644 index 0000000..3fef8e7 --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/monitor/SysOperlogController.java @@ -0,0 +1,70 @@ +package com.inscloudtech.web.controller.monitor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.utils.poi.ExcelUtil; +import com.inscloudtech.system.domain.SysOperLog; +import com.inscloudtech.system.service.ISysOperLogService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 操作日志记录 + * + * @author inscloudtech + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/operlog") +public class SysOperlogController extends BaseController { + + private final ISysOperLogService operLogService; + /** + * 获取操作日志记录列表 + */ + @SaCheckPermission("monitor:operlog:list") + @GetMapping("/list") + public TableDataInfo list(SysOperLog operLog, PageQuery pageQuery) { + return operLogService.selectPageOperLogList(operLog, pageQuery); + } + /** + * 导出操作日志记录列表 + */ + @Log(title = "操作日志", businessType = BusinessType.EXPORT) + @SaCheckPermission("monitor:operlog:export") + @PostMapping("/export") + public void export(SysOperLog operLog, HttpServletResponse response) { + List list = operLogService.selectOperLogList(operLog); + ExcelUtil.exportExcel(list, "操作日志", SysOperLog.class, response); + } + /** + * 批量删除操作日志记录 + * @param operIds 日志ids + */ + @Log(title = "操作日志", businessType = BusinessType.DELETE) + @SaCheckPermission("monitor:operlog:remove") + @DeleteMapping("/{operIds}") + public R remove(@PathVariable Long[] operIds) { + return toAjax(operLogService.deleteOperLogByIds(operIds)); + } + /** + * 清理操作日志记录 + */ + @Log(title = "操作日志", businessType = BusinessType.CLEAN) + @SaCheckPermission("monitor:operlog:remove") + @DeleteMapping("/clean") + public R clean() { + operLogService.cleanOperLog(); + return R.ok(); + } +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/monitor/SysUserOnlineController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/monitor/SysUserOnlineController.java new file mode 100644 index 0000000..e53f501 --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/monitor/SysUserOnlineController.java @@ -0,0 +1,88 @@ +package com.inscloudtech.web.controller.monitor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.bean.BeanUtil; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.constant.CacheConstants; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.domain.dto.UserOnlineDTO; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.utils.StreamUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.redis.RedisUtils; +import com.inscloudtech.system.domain.SysUserOnline; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * 在线用户监控 + * + * @author inscloudtech + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/online") +public class SysUserOnlineController extends BaseController { + /** + * 获取在线用户监控列表 + * + * @param ipaddr IP地址 + * @param userName 用户名 + */ + @SaCheckPermission("monitor:online:list") + @GetMapping("/list") + public TableDataInfo list(String ipaddr, String userName) { + // 获取所有未过期的 token + List keys = StpUtil.searchTokenValue("", 0, -1, false); + List userOnlineDTOList = new ArrayList<>(); + for (String key : keys) { + String token = StringUtils.substringAfterLast(key, ":"); + // 如果已经过期则跳过 + if (StpUtil.stpLogic.getTokenActivityTimeoutByToken(token) < -1) { + continue; + } + userOnlineDTOList.add(RedisUtils.getCacheObject(CacheConstants.ONLINE_TOKEN_KEY + token)); + } + if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) { + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> + StringUtils.equals(ipaddr, userOnline.getIpaddr()) && + StringUtils.equals(userName, userOnline.getUserName()) + ); + } else if (StringUtils.isNotEmpty(ipaddr)) { + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> + StringUtils.equals(ipaddr, userOnline.getIpaddr()) + ); + } else if (StringUtils.isNotEmpty(userName)) { + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> + StringUtils.equals(userName, userOnline.getUserName()) + ); + } + Collections.reverse(userOnlineDTOList); + userOnlineDTOList.removeAll(Collections.singleton(null)); + List userOnlineList = BeanUtil.copyToList(userOnlineDTOList, SysUserOnline.class); + return TableDataInfo.build(userOnlineList); + } + /** + * 强退用户 + * + * @param tokenId token值 + */ + @SaCheckPermission("monitor:online:forceLogout") + @Log(title = "在线用户", businessType = BusinessType.FORCE) + @DeleteMapping("/{tokenId}") + public R forceLogout(@PathVariable String tokenId) { + try { + StpUtil.kickoutByTokenValue(tokenId); + } catch (NotLoginException ignored) { + } + return R.ok(); + } +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysConfigController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysConfigController.java new file mode 100644 index 0000000..5921232 --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysConfigController.java @@ -0,0 +1,128 @@ +package com.inscloudtech.web.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.constant.UserConstants; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.utils.poi.ExcelUtil; +import com.inscloudtech.system.domain.SysConfig; +import com.inscloudtech.system.service.ISysConfigService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 参数配置 信息操作处理 + * + * @author inscloudtech + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/config") +public class SysConfigController extends BaseController { + + private final ISysConfigService configService; + /** + * 获取参数配置列表 + */ + @SaCheckPermission("system:config:list") + @GetMapping("/list") + public TableDataInfo list(SysConfig config, PageQuery pageQuery) { + return configService.selectPageConfigList(config, pageQuery); + } + /** + * 导出参数配置列表 + */ + @Log(title = "参数管理", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:config:export") + @PostMapping("/export") + public void export(SysConfig config, HttpServletResponse response) { + List list = configService.selectConfigList(config); + ExcelUtil.exportExcel(list, "参数数据", SysConfig.class, response); + } + /** + * 根据参数编号获取详细信息 + * + * @param configId 参数ID + */ + @SaCheckPermission("system:config:query") + @GetMapping(value = "/{configId}") + public R getInfo(@PathVariable Long configId) { + return R.ok(configService.selectConfigById(configId)); + } + /** + * 根据参数键名查询参数值 + * + * @param configKey 参数Key + */ + @GetMapping(value = "/configKey/{configKey}") + public R getConfigKey(@PathVariable String configKey) { + return R.ok(configService.selectConfigByKey(configKey)); + } + /** + * 新增参数配置 + */ + @SaCheckPermission("system:config:add") + @Log(title = "参数管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysConfig config) { + if (!configService.checkConfigKeyUnique(config)) { + return R.fail("新增参数'" + config.getConfigName() + "'失败,参数键名已存在"); + } + configService.insertConfig(config); + return R.ok(); + } + /** + * 修改参数配置 + */ + @SaCheckPermission("system:config:edit") + @Log(title = "参数管理", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysConfig config) { + if (!configService.checkConfigKeyUnique(config)) { + return R.fail("修改参数'" + config.getConfigName() + "'失败,参数键名已存在"); + } + configService.updateConfig(config); + return R.ok(); + } + /** + * 根据参数键名修改参数配置 + */ + @SaCheckPermission("system:config:edit") + @Log(title = "参数管理", businessType = BusinessType.UPDATE) + @PutMapping("/updateByKey") + public R updateByKey(@RequestBody SysConfig config) { + configService.updateConfig(config); + return R.ok(); + } + /** + * 删除参数配置 + * + * @param configIds 参数ID串 + */ + @SaCheckPermission("system:config:remove") + @Log(title = "参数管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{configIds}") + public R remove(@PathVariable Long[] configIds) { + configService.deleteConfigByIds(configIds); + return R.ok(); + } + /** + * 刷新参数缓存 + */ + @SaCheckPermission("system:config:remove") + @Log(title = "参数管理", businessType = BusinessType.CLEAN) + @DeleteMapping("/refreshCache") + public R refreshCache() { + configService.resetConfigCache(); + return R.ok(); + } +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysDeptController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysDeptController.java new file mode 100644 index 0000000..7c254ab --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysDeptController.java @@ -0,0 +1,116 @@ +package com.inscloudtech.web.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.convert.Convert; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.annotation.UpdateLog; +import com.inscloudtech.common.constant.UserConstants; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.domain.entity.SysDept; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.system.mapper.SysDeptMapper; +import com.inscloudtech.system.service.ISysDeptService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 部门信息 + * + * @author inscloudtech + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/dept") +public class SysDeptController extends BaseController { + + private final ISysDeptService deptService; + /** + * 获取部门列表 + */ +// @SaCheckPermission("system:dept:list") + @GetMapping("/list") + public R> list(SysDept dept) { + List depts = deptService.selectDeptList(dept); + return R.ok(depts); + } + /** + * 查询部门列表(排除节点) + * + * @param deptId 部门ID + */ +// @SaCheckPermission("system:dept:list") + @GetMapping("/list/exclude/{deptId}") + public R> excludeChild(@PathVariable(value = "deptId", required = false) Long deptId) { + List depts = deptService.selectDeptList(new SysDept()); + depts.removeIf(d -> d.getDeptId().equals(deptId) + || StringUtils.splitList(d.getAncestors()).contains(Convert.toStr(deptId))); + return R.ok(depts); + } + /** + * 根据部门编号获取详细信息 + * + * @param deptId 部门ID + */ + @SaCheckPermission("system:dept:query") + @GetMapping(value = "/{deptId}") + public R getInfo(@PathVariable Long deptId) { + deptService.checkDeptDataScope(deptId); + return R.ok(deptService.selectDeptById(deptId)); + } + /** + * 新增部门 + */ + @SaCheckPermission("system:dept:add") + @Log(title = "部门管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysDept dept) { + if (!deptService.checkDeptNameUnique(dept)) { + return R.fail("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在"); + } + return toAjax(deptService.insertDept(dept)); + } + /** + * 修改部门 + */ + @SaCheckPermission("system:dept:edit") +// @Log(title = "部门管理", businessType = BusinessType.UPDATE) + @UpdateLog(title = "组织机构",mapperClass = ISysDeptService.class,entityClass = SysDept.class,methodName = "selectDeptById", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysDept dept) { + Long deptId = dept.getDeptId(); + deptService.checkDeptDataScope(deptId); + if (!deptService.checkDeptNameUnique(dept)) { + return R.fail("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在"); + } else if (dept.getParentId().equals(deptId)) { + return R.fail("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己"); + } else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) + && deptService.selectNormalChildrenDeptById(deptId) > 0) { + return R.fail("该部门包含未停用的子部门!"); + } + return toAjax(deptService.updateDept(dept)); + } + /** + * 删除部门 + * + * @param deptId 部门ID + */ + @SaCheckPermission("system:dept:remove") + @Log(title = "部门管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{deptId}") + public R remove(@PathVariable Long deptId) { + if (deptService.hasChildByDeptId(deptId)) { + return R.warn("存在下级部门,不允许删除"); + } + if (deptService.checkDeptExistUser(deptId)) { + return R.warn("部门存在用户,不允许删除"); + } + deptService.checkDeptDataScope(deptId); + return toAjax(deptService.deleteDeptById(deptId)); + } +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysDictDataController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysDictDataController.java new file mode 100644 index 0000000..ada2fcc --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysDictDataController.java @@ -0,0 +1,107 @@ +package com.inscloudtech.web.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.annotation.UpdateLog; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.domain.entity.SysDictData; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.utils.poi.ExcelUtil; +import com.inscloudtech.system.mapper.SysDictDataMapper; +import com.inscloudtech.system.service.ISysDictDataService; +import com.inscloudtech.system.service.ISysDictTypeService; +import com.inscloudtech.system.service.ISysUserService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 数据字典信息 + * + * @author inscloudtech + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/dict/data") +public class SysDictDataController extends BaseController { + + private final ISysDictDataService dictDataService; + private final ISysDictTypeService dictTypeService; + /** + * 查询字典数据列表 + */ +// @SaCheckPermission("system:dict:list") + @GetMapping("/list") + public TableDataInfo list(SysDictData dictData, PageQuery pageQuery) { + return dictDataService.selectPageDictDataList(dictData, pageQuery); + } + /** + * 导出字典数据列表 + */ + @Log(title = "字典数据", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:dict:export") + @PostMapping("/export") + public void export(SysDictData dictData, HttpServletResponse response) { + List list = dictDataService.selectDictDataList(dictData); + ExcelUtil.exportExcel(list, "字典数据", SysDictData.class, response); + } + /** + * 查询字典数据详细 + * + * @param dictCode 字典code + */ + @SaCheckPermission("system:dict:query") + @GetMapping(value = "/{dictCode}") + public R getInfo(@PathVariable Long dictCode) { + return R.ok(dictDataService.selectDictDataById(dictCode)); + } + /** + * 根据字典类型查询字典数据信息 + * + * @param dictType 字典类型 + */ + @GetMapping(value = "/type/{dictType}") + public R> dictType(@PathVariable String dictType) { + List data = dictTypeService.selectDictDataByType(dictType); + return R.ok(data); + } + /** + * 新增字典类型 + */ + @SaCheckPermission("system:dict:add") + @Log(title = "字典数据", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysDictData dict) { + dictDataService.insertDictData(dict); + return R.ok(); + } + /** + * 修改保存字典类型 + */ + @SaCheckPermission("system:dict:edit") + @UpdateLog(title = "字典数据",mapperClass = SysDictDataMapper.class, businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysDictData dict) { + dictDataService.updateDictData(dict); + return R.ok(); + } + /** + * 删除字典类型 + * + * @param dictCodes 字典code串 + */ + @SaCheckPermission("system:dict:remove") + @Log(title = "字典类型", businessType = BusinessType.DELETE) + @DeleteMapping("/{dictCodes}") + public R remove(@PathVariable Long[] dictCodes) { + dictDataService.deleteDictDataByIds(dictCodes); + return R.ok(); + } +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysDictTypeController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysDictTypeController.java new file mode 100644 index 0000000..86b5403 --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysDictTypeController.java @@ -0,0 +1,119 @@ +package com.inscloudtech.web.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.annotation.UpdateLog; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.domain.entity.SysDictType; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.utils.poi.ExcelUtil; +import com.inscloudtech.system.mapper.SysDictTypeMapper; +import com.inscloudtech.system.service.ISysDictTypeService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 数据字典信息 + * + * @author inscloudtech + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/dict/type") +public class SysDictTypeController extends BaseController { + + private final ISysDictTypeService dictTypeService; + /** + * 查询字典类型列表 + */ +// @SaCheckPermission("system:dict:list") + @GetMapping("/list") + public TableDataInfo list(SysDictType dictType, PageQuery pageQuery) { + return dictTypeService.selectPageDictTypeList(dictType, pageQuery); + } + /** + * 导出字典类型列表 + */ + @Log(title = "字典管理", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:dict:export") + @PostMapping("/export") + public void export(SysDictType dictType, HttpServletResponse response) { + List list = dictTypeService.selectDictTypeList(dictType); + ExcelUtil.exportExcel(list, "字典管理", SysDictType.class, response); + } + /** + * 查询字典类型详细 + * + * @param dictId 字典ID + */ + @SaCheckPermission("system:dict:query") + @GetMapping(value = "/{dictId}") + public R getInfo(@PathVariable Long dictId) { + return R.ok(dictTypeService.selectDictTypeById(dictId)); + } + /** + * 新增字典类型 + */ + @SaCheckPermission("system:dict:add") + @Log(title = "字典管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysDictType dict) { + if (!dictTypeService.checkDictTypeUnique(dict)) { + return R.fail("新增字典'" + dict.getDictName() + "'失败,字典类型已存在"); + } + dictTypeService.insertDictType(dict); + return R.ok(); + } + /** + * 修改字典类型 + */ + @SaCheckPermission("system:dict:edit") +// @Log(title = "字典管理", businessType = BusinessType.UPDATE) + @UpdateLog(title = "字典管理",mapperClass = SysDictTypeMapper.class, businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysDictType dict) { + if (!dictTypeService.checkDictTypeUnique(dict)) { + return R.fail("修改字典'" + dict.getDictName() + "'失败,字典类型已存在"); + } + dictTypeService.updateDictType(dict); + return R.ok(); + } + /** + * 删除字典类型 + * + * @param dictIds 字典ID串 + */ + @SaCheckPermission("system:dict:remove") + @Log(title = "字典管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{dictIds}") + public R remove(@PathVariable Long[] dictIds) { + dictTypeService.deleteDictTypeByIds(dictIds); + return R.ok(); + } + /** + * 刷新字典缓存 + */ + @SaCheckPermission("system:dict:remove") + @Log(title = "字典管理", businessType = BusinessType.CLEAN) + @DeleteMapping("/refreshCache") + public R refreshCache() { + dictTypeService.resetDictCache(); + return R.ok(); + } + /** + * 获取字典选择框列表 + */ + @GetMapping("/optionselect") + public R> optionselect() { + List dictTypes = dictTypeService.selectDictTypeAll(); + return R.ok(dictTypes); + } +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysIndexController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysIndexController.java new file mode 100644 index 0000000..8569c65 --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysIndexController.java @@ -0,0 +1,27 @@ +package com.inscloudtech.web.controller.system; + +import cn.dev33.satoken.annotation.SaIgnore; +import cn.hutool.json.JSONObject; +import com.inscloudtech.common.config.ProjectConfig; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 首页 + * + * @author inscloudtech + */ +@RequiredArgsConstructor +@RestController +public class SysIndexController { + /** + * 系统基础配置 + */ + private final ProjectConfig wuziConfig; + +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysLoginController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysLoginController.java new file mode 100644 index 0000000..9f2adae --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysLoginController.java @@ -0,0 +1,155 @@ +package com.inscloudtech.web.controller.system; + +import cn.dev33.satoken.annotation.SaIgnore; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.domain.entity.SysMenu; +import com.inscloudtech.common.core.domain.entity.SysUser; +import com.inscloudtech.common.core.domain.model.EmailLoginBody; +import com.inscloudtech.common.core.domain.model.LoginBody; +import com.inscloudtech.common.core.domain.model.LoginUser; +import com.inscloudtech.common.core.domain.model.SmsLoginBody; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.system.domain.vo.RouterVo; +import com.inscloudtech.system.service.ISysMenuService; +import com.inscloudtech.system.service.ISysUserService; +import com.inscloudtech.system.service.SysLoginService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.constraints.NotBlank; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 登录验证 + * + * @author inscloudtech + */ +@Validated +@RequiredArgsConstructor +@RestController +public class SysLoginController { + + private final SysLoginService loginService; + private final ISysMenuService menuService; + private final ISysUserService userService; + /** + * 登录方法 + * + * @param loginBody 登录信息 + * @return 结果 + */ + @SaIgnore + @PostMapping("/login") + public R> login(@Validated @RequestBody LoginBody loginBody) { + Map ajax = new HashMap<>(); + // 生成令牌 + String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(), + loginBody.getUuid()); + ajax.put(Constants.TOKEN, token); + return R.ok(ajax); + } + /** + * 登录方法 + * + * @param loginBody 登录信息 + * @return 结果 + */ + @SaIgnore + @PostMapping("/usernameLogin") + public R> usernameLogin(@Validated @RequestBody LoginBody loginBody) { + Map ajax = new HashMap<>(); + // 生成令牌 + String token = loginService.usernameLogin(loginBody.getUsername(),loginBody.getRole()); + ajax.put(Constants.TOKEN, token); + ajax.put("username", loginBody.getUsername()); + return R.ok(ajax); + } + + + /** + * 短信登录 + * + * @param smsLoginBody 登录信息 + * @return 结果 + */ + @SaIgnore + @PostMapping("/smsLogin") + public R> smsLogin(@Validated @RequestBody SmsLoginBody smsLoginBody) { + Map ajax = new HashMap<>(); + // 生成令牌 + String token = loginService.smsLogin(smsLoginBody.getPhonenumber(), smsLoginBody.getSmsCode()); + ajax.put(Constants.TOKEN, token); + return R.ok(ajax); + } + /** + * 邮件登录 + * + * @param body 登录信息 + * @return 结果 + */ + @PostMapping("/emailLogin") + public R> emailLogin(@Validated @RequestBody EmailLoginBody body) { + Map ajax = new HashMap<>(); + // 生成令牌 + String token = loginService.emailLogin(body.getEmail(), body.getEmailCode()); + ajax.put(Constants.TOKEN, token); + return R.ok(ajax); + } + /** + * 小程序登录(示例) + * + * @param xcxCode 小程序code + * @return 结果 + */ + @SaIgnore + @PostMapping("/xcxLogin") + public R> xcxLogin(@NotBlank(message = "{xcx.code.not.blank}") String xcxCode) { + Map ajax = new HashMap<>(); + // 生成令牌 + String token = loginService.xcxLogin(xcxCode); + ajax.put(Constants.TOKEN, token); + return R.ok(ajax); + } + /** + * 退出登录 + */ + @SaIgnore + @PostMapping("/logout") + public R logout() { + loginService.logout(); + return R.ok("退出成功"); + } + /** + * 获取用户信息 + * + * @return 用户信息 + */ + @GetMapping("getInfo") + public R> getInfo() { + LoginUser loginUser = LoginHelper.getLoginUser(); + SysUser user = userService.selectUserById(loginUser.getUserId()); + Map ajax = new HashMap<>(); + ajax.put("user", user); + ajax.put("roles", loginUser.getRolePermission()); + ajax.put("permissions", loginUser.getMenuPermission()); + return R.ok(ajax); + } + /** + * 获取路由信息 + * + * @return 路由信息 + */ + @GetMapping("getRouters") + public R> getRouters() { + Long userId = LoginHelper.getUserId(); + List menus = menuService.selectMenuTreeByUserId(userId); + return R.ok(menuService.buildMenus(menus)); + } +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysMenuController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysMenuController.java new file mode 100644 index 0000000..c7cad81 --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysMenuController.java @@ -0,0 +1,120 @@ +package com.inscloudtech.web.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.lang.tree.Tree; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.constant.UserConstants; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.domain.entity.SysMenu; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.system.service.ISysMenuService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 菜单信息 + * + * @author inscloudtech + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/menu") +public class SysMenuController extends BaseController { + + private final ISysMenuService menuService; + /** + * 获取菜单列表 + */ + @SaCheckPermission("system:menu:list") + @GetMapping("/list") + public R> list(SysMenu menu) { + List menus = menuService.selectMenuList(menu, getUserId()); + return R.ok(menus); + } + /** + * 根据菜单编号获取详细信息 + * + * @param menuId 菜单ID + */ + @SaCheckPermission("system:menu:query") + @GetMapping(value = "/{menuId}") + public R getInfo(@PathVariable Long menuId) { + return R.ok(menuService.selectMenuById(menuId)); + } + /** + * 获取菜单下拉树列表 + */ + @GetMapping("/treeselect") + public R>> treeselect(SysMenu menu) { + List menus = menuService.selectMenuList(menu, getUserId()); + return R.ok(menuService.buildMenuTreeSelect(menus)); + } + /** + * 加载对应角色菜单列表树 + * + * @param roleId 角色ID + */ + @GetMapping(value = "/roleMenuTreeselect/{roleId}") + public R> roleMenuTreeselect(@PathVariable("roleId") Long roleId) { + List menus = menuService.selectMenuList(getUserId()); + Map ajax = new HashMap<>(); + ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId)); + ajax.put("menus", menuService.buildMenuTreeSelect(menus)); + return R.ok(ajax); + } + /** + * 新增菜单 + */ + @SaCheckPermission("system:menu:add") + @Log(title = "菜单管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysMenu menu) { + if (!menuService.checkMenuNameUnique(menu)) { + return R.fail("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); + } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) { + return R.fail("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); + } + return toAjax(menuService.insertMenu(menu)); + } + /** + * 修改菜单 + */ + @SaCheckPermission("system:menu:edit") + @Log(title = "菜单管理", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysMenu menu) { + if (!menuService.checkMenuNameUnique(menu)) { + return R.fail("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); + } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) { + return R.fail("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); + } else if (menu.getMenuId().equals(menu.getParentId())) { + return R.fail("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己"); + } + return toAjax(menuService.updateMenu(menu)); + } + /** + * 删除菜单 + * + * @param menuId 菜单ID + */ + @SaCheckPermission("system:menu:remove") + @Log(title = "菜单管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{menuId}") + public R remove(@PathVariable("menuId") Long menuId) { + if (menuService.hasChildByMenuId(menuId)) { + return R.warn("存在子菜单,不允许删除"); + } + if (menuService.checkMenuExistRole(menuId)) { + return R.warn("菜单已分配,不允许删除"); + } + return toAjax(menuService.deleteMenuById(menuId)); + } +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysNoticeController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysNoticeController.java new file mode 100644 index 0000000..37e906c --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysNoticeController.java @@ -0,0 +1,75 @@ +package com.inscloudtech.web.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.system.domain.SysNotice; +import com.inscloudtech.system.service.ISysNoticeService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +/** + * 公告 信息操作处理 + * + * @author inscloudtech + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/notice") +public class SysNoticeController extends BaseController { + + private final ISysNoticeService noticeService; + /** + * 获取通知公告列表 + */ + @SaCheckPermission("system:notice:list") + @GetMapping("/list") + public TableDataInfo list(SysNotice notice, PageQuery pageQuery) { + return noticeService.selectPageNoticeList(notice, pageQuery); + } + /** + * 根据通知公告编号获取详细信息 + * + * @param noticeId 公告ID + */ + @SaCheckPermission("system:notice:query") + @GetMapping(value = "/{noticeId}") + public R getInfo(@PathVariable Long noticeId) { + return R.ok(noticeService.selectNoticeById(noticeId)); + } + /** + * 新增通知公告 + */ + @SaCheckPermission("system:notice:add") + @Log(title = "通知公告", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysNotice notice) { + return toAjax(noticeService.insertNotice(notice)); + } + /** + * 修改通知公告 + */ + @SaCheckPermission("system:notice:edit") + @Log(title = "通知公告", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysNotice notice) { + return toAjax(noticeService.updateNotice(notice)); + } + /** + * 删除通知公告 + * + * @param noticeIds 公告ID串 + */ + @SaCheckPermission("system:notice:remove") + @Log(title = "通知公告", businessType = BusinessType.DELETE) + @DeleteMapping("/{noticeIds}") + public R remove(@PathVariable Long[] noticeIds) { + return toAjax(noticeService.deleteNoticeByIds(noticeIds)); + } +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysNotifyMessageController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysNotifyMessageController.java new file mode 100644 index 0000000..0559dbf --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysNotifyMessageController.java @@ -0,0 +1,144 @@ +package com.inscloudtech.web.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.annotation.RepeatSubmit; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.core.validate.AddGroup; +import com.inscloudtech.common.core.validate.EditGroup; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.utils.poi.ExcelUtil; +import com.inscloudtech.system.domain.SysNotifyMessage; +import com.inscloudtech.system.service.ISysNotifyMessageService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Arrays; +import java.util.List; + +/** + * 站内信消息 + * + * @author inscloudtech + * @date 2023-06-02 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/notifyMessage") +public class SysNotifyMessageController extends BaseController { + + private final ISysNotifyMessageService iSysNotifyMessageService; + /** + * 查询站内信消息列表 + */ + @SaCheckPermission("system:notifyMessage:list") + @GetMapping("/list") + public TableDataInfo list(SysNotifyMessage bo, PageQuery pageQuery) { + return iSysNotifyMessageService.queryPageList(bo, pageQuery); + } + /** + * 导出站内信消息列表 + */ + @SaCheckPermission("system:notifyMessage:export") + @Log(title = "站内信消息", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SysNotifyMessage bo, HttpServletResponse response) { + List list = iSysNotifyMessageService.queryList(bo); + ExcelUtil.exportExcel(list, "站内信消息", SysNotifyMessage.class, response); + } + /** + * 获取站内信消息详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("system:notifyMessage:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(iSysNotifyMessageService.queryById(id)); + } + /** + * 新增站内信消息 + */ + @SaCheckPermission("system:notifyMessage:add") + @Log(title = "站内信消息", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SysNotifyMessage bo) { + return toAjax(iSysNotifyMessageService.insert(bo)); + } + /** + * 修改站内信消息 + */ + @SaCheckPermission("system:notifyMessage:edit") + @Log(title = "站内信消息", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody SysNotifyMessage bo) { + return toAjax(iSysNotifyMessageService.update(bo)); + } + /** + * 删除站内信消息 + * + * @param ids 主键串 + */ + @SaCheckPermission("system:notifyMessage:remove") + @Log(title = "站内信消息", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(iSysNotifyMessageService.deleteWithValidByIds(Arrays.asList(ids), true)); + } + /** + * 查询站内信消息列表 + */ +// @SaCheckPermission("system:notifyMessage:list") + @GetMapping("/unreadCount") + public R unreadCount() { + return R.ok(getUnreadList().getTotal()); + } + + @GetMapping("/unreadList") + public TableDataInfo unreadList() { + return getUnreadList(); + } + + TableDataInfo getUnreadList(){ + SysNotifyMessage condition = new SysNotifyMessage(); + condition.setReadStatus(0); + PageQuery pageQuery = new PageQuery(); + pageQuery.setPageNum(1); + pageQuery.setPageSize(5); + pageQuery.setOrderByColumn("create_time"); + pageQuery.setIsAsc("desc"); + TableDataInfo tableDataInfo = iSysNotifyMessageService.queryPageList(condition, pageQuery); + return tableDataInfo; + } + + + @PutMapping("/updateRead") + @RepeatSubmit + @Log(title = "标记站内信为已读", businessType = BusinessType.UPDATE) + public R updateNotifyMessageRead(@RequestBody Long[] ids) { + return toAjax(iSysNotifyMessageService.updateNotifyMessageRead(ids,getUserId())); + } + + @PutMapping("/updateAllRead") + @RepeatSubmit + @Log(title = "标记所有站内信为已读", businessType = BusinessType.UPDATE) + public R updateAllNotifyMessageRead() { + iSysNotifyMessageService.updateAllNotifyMessageRead(getUserId()); + return toAjax(true); + } +} + diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysNotifyTemplateController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysNotifyTemplateController.java new file mode 100644 index 0000000..cbe3352 --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysNotifyTemplateController.java @@ -0,0 +1,111 @@ +package com.inscloudtech.web.controller.system; + +import java.util.List; +import java.util.Arrays; + +import com.inscloudtech.system.domain.SysNotifyTemplate; +import io.swagger.v3.oas.annotations.Operation; +import lombok.RequiredArgsConstructor; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import javax.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import com.inscloudtech.common.annotation.RepeatSubmit; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.validate.AddGroup; +import com.inscloudtech.common.core.validate.EditGroup; +import com.inscloudtech.common.core.validate.QueryGroup; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.utils.poi.ExcelUtil; +import com.inscloudtech.system.domain.vo.SysNotifyTemplateVo; +import com.inscloudtech.system.service.ISysNotifyTemplateService; +import com.inscloudtech.common.core.page.TableDataInfo; + +/** + * 站内信模板 + * + * @author inscloudtech + * @date 2023-06-07 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/notifyTemplate") +public class SysNotifyTemplateController extends BaseController { + + private final ISysNotifyTemplateService iSysNotifyTemplateService; + /** + * 查询站内信模板列表 + */ + @SaCheckPermission("system:notifyTemplate:list") + @GetMapping("/list") + public TableDataInfo list(SysNotifyTemplate bo, PageQuery pageQuery) { + return iSysNotifyTemplateService.queryPageList(bo, pageQuery); + } + /** + * 导出站内信模板列表 + */ + @SaCheckPermission("system:notifyTemplate:export") + @Log(title = "站内信模板", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SysNotifyTemplate bo, HttpServletResponse response) { + List list = iSysNotifyTemplateService.queryList(bo); + ExcelUtil.exportExcel(list, "站内信模板", SysNotifyTemplateVo.class, response); + } + /** + * 获取站内信模板详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("system:notifyTemplate:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(iSysNotifyTemplateService.queryById(id)); + } + /** + * 新增站内信模板 + */ + @SaCheckPermission("system:notifyTemplate:add") + @Log(title = "站内信模板", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SysNotifyTemplate bo) { + return toAjax(iSysNotifyTemplateService.insertByBo(bo)); + } + /** + * 修改站内信模板 + */ + @SaCheckPermission("system:notifyTemplate:edit") + @Log(title = "站内信模板", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody SysNotifyTemplate bo) { + return toAjax(iSysNotifyTemplateService.updateByBo(bo)); + } + /** + * 删除站内信模板 + * + * @param ids 主键串 + */ + @SaCheckPermission("system:notifyTemplate:remove") + @Log(title = "站内信模板", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(iSysNotifyTemplateService.deleteWithValidByIds(Arrays.asList(ids), true)); + } + + @PostMapping("/send") + @Operation(summary = "发送站内信") + @SaCheckPermission("system:notifyTemplate:send") + public R sendNotify(@Valid @RequestBody SysNotifyTemplate bo) { + return toAjax(iSysNotifyTemplateService.sendSingleNotify(null, + bo.getCode(),null)); + } +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysOssController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysOssController.java new file mode 100644 index 0000000..5516860 --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysOssController.java @@ -0,0 +1,107 @@ +package com.inscloudtech.web.controller.system; + + +import cn.hutool.core.util.ObjectUtil; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.system.domain.SysOss; +import com.inscloudtech.system.service.ISysOssService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.NotEmpty; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 文件上传 控制层 + * + * @author inscloudtech + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/oss") +public class SysOssController extends BaseController { + + private final ISysOssService iSysOssService; + /** + * 查询OSS对象存储列表 + */ + @GetMapping("/list") + public TableDataInfo list(SysOss bo, PageQuery pageQuery) { + return iSysOssService.queryPageList(bo, pageQuery); + } + /** + * 查询OSS对象基于id串 + * + * @param ossIds OSS对象ID串 + */ + @GetMapping("/listByIds/{ossIds}") + public R> listByIds(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ossIds) { + List list = iSysOssService.listByIds(Arrays.asList(ossIds)); + return R.ok(list); + } + /** + * 根据id获取详细信息 + * + * @param ossId 菜单ID + */ + @GetMapping(value = "/{ossId}") + public R getInfo(@PathVariable String ossId) { + return R.ok(iSysOssService.getById(ossId)); + } + /** + * 上传OSS对象存储 + * + * @param file 文件 + */ + + @Log(title = "OSS对象存储", businessType = BusinessType.INSERT) + @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R> upload(@RequestPart("file") MultipartFile file) { + if (ObjectUtil.isNull(file)) { + return R.fail("上传文件不能为空"); + } + SysOss oss = iSysOssService.upload(file); + Map map = new HashMap<>(2); + map.put("url", oss.getUrl()); + map.put("fileName", oss.getOriginalName()); + map.put("ossId", oss.getOssId()); + return R.ok(map); + } + /** + * 下载OSS对象 + * + * @param ossId OSS对象ID + */ + @GetMapping("/download/{ossId}") + public void download(@PathVariable String ossId, HttpServletResponse response) throws IOException { + iSysOssService.download(ossId,response); + } + /** + * 删除OSS对象存储 + * + * @param ossIds OSS对象ID串 + */ + @Log(title = "OSS对象存储", businessType = BusinessType.DELETE) + @DeleteMapping("/{ossIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable String[] ossIds) { + iSysOssService.deleteWithValidByIds(Arrays.asList(ossIds)); + return R.ok(); + } + +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysPostController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysPostController.java new file mode 100644 index 0000000..a3ec570 --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysPostController.java @@ -0,0 +1,108 @@ +package com.inscloudtech.web.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.constant.UserConstants; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.utils.poi.ExcelUtil; +import com.inscloudtech.system.domain.SysPost; +import com.inscloudtech.system.service.ISysPostService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 岗位信息操作处理 + * + * @author inscloudtech + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/post") +public class SysPostController extends BaseController { + + private final ISysPostService postService; + /** + * 获取岗位列表 + */ + @SaCheckPermission("system:post:list") + @GetMapping("/list") + public TableDataInfo list(SysPost post, PageQuery pageQuery) { + return postService.selectPagePostList(post, pageQuery); + } + /** + * 导出岗位列表 + */ + @Log(title = "岗位管理", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:post:export") + @PostMapping("/export") + public void export(SysPost post, HttpServletResponse response) { + List list = postService.selectPostList(post); + ExcelUtil.exportExcel(list, "岗位数据", SysPost.class, response); + } + /** + * 根据岗位编号获取详细信息 + * + * @param postId 岗位ID + */ + @SaCheckPermission("system:post:query") + @GetMapping(value = "/{postId}") + public R getInfo(@PathVariable Long postId) { + return R.ok(postService.selectPostById(postId)); + } + /** + * 新增岗位 + */ + @SaCheckPermission("system:post:add") + @Log(title = "岗位管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysPost post) { + if (!postService.checkPostNameUnique(post)) { + return R.fail("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在"); + } else if (!postService.checkPostCodeUnique(post)) { + return R.fail("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在"); + } + return toAjax(postService.insertPost(post)); + } + /** + * 修改岗位 + */ + @SaCheckPermission("system:post:edit") + @Log(title = "岗位管理", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysPost post) { + if (!postService.checkPostNameUnique(post)) { + return R.fail("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在"); + } else if (!postService.checkPostCodeUnique(post)) { + return R.fail("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在"); + } + return toAjax(postService.updatePost(post)); + } + /** + * 删除岗位 + * + * @param postIds 岗位ID串 + */ + @SaCheckPermission("system:post:remove") + @Log(title = "岗位管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{postIds}") + public R remove(@PathVariable Long[] postIds) { + return toAjax(postService.deletePostByIds(postIds)); + } + /** + * 获取岗位选择框列表 + */ + @GetMapping("/optionselect") + public R> optionselect() { + List posts = postService.selectPostAll(); + return R.ok(posts); + } +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysProfileController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysProfileController.java new file mode 100644 index 0000000..546fc56 --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysProfileController.java @@ -0,0 +1,138 @@ +package com.inscloudtech.web.controller.system; + +import cn.dev33.satoken.secure.BCrypt; +import cn.hutool.core.io.FileUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.constant.UserConstants; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.domain.entity.SysDept; +import com.inscloudtech.common.core.domain.entity.SysUser; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.file.MimeTypeUtils; +import com.inscloudtech.system.domain.SysOss; +import com.inscloudtech.system.domain.vo.SysOssVo; +import com.inscloudtech.system.service.ISysOssService; +import com.inscloudtech.system.service.ISysUserService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 个人信息 业务处理 + * + * @author inscloudtech + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/user/profile") +public class SysProfileController extends BaseController { + + private final ISysUserService userService; + private final ISysOssService iSysOssService; + /** + * 个人信息 + */ + @GetMapping + public R> profile() { + SysUser user = userService.selectUserById(getUserId()); + Map ajax = new HashMap<>(); + ajax.put("user", user); + ajax.put("roleGroup", userService.selectUserRoleGroup(user.getUserName())); + ajax.put("postGroup", userService.selectUserPostGroup(user.getUserName())); + return R.ok(ajax); + } + + /** + * 个人信息 + */ + @GetMapping("/getDZDept") + public R> getDZDept() { + SysDept dzDept = userService.getDzDept(); + Map ajax = new HashMap<>(); + ajax.put("dzDept", dzDept); + return R.ok(ajax); + } + /** + * 修改用户 + */ + @Log(title = "个人信息", businessType = BusinessType.UPDATE) + @PutMapping + public R updateProfile(@RequestBody SysUser user) { + if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) { + return R.fail("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); + } + if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) { + return R.fail("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); + } + user.setUserId(getUserId()); + user.setUserName(null); + user.setPassword(null); + user.setAvatar(null); + user.setDeptId(null); + if (userService.updateUserProfile(user) > 0) { + return R.ok(); + } + return R.fail("修改个人信息异常,请联系管理员"); + } + /** + * 重置密码 + * + * @param newPassword 旧密码 + * @param oldPassword 新密码 + */ + @Log(title = "个人信息", businessType = BusinessType.UPDATE) + @PutMapping("/updatePwd") + public R updatePwd(String oldPassword, String newPassword) { + SysUser user = userService.selectUserById(LoginHelper.getUserId()); + String userName = user.getUserName(); + String password = user.getPassword(); + if (!BCrypt.checkpw(oldPassword, password)) { + return R.fail("修改密码失败,旧密码错误"); + } + if (BCrypt.checkpw(newPassword, password)) { + return R.fail("新密码不能与旧密码相同"); + } + + if (userService.resetUserPwd(userName, BCrypt.hashpw(newPassword)) > 0) { + return R.ok(); + } + return R.fail("修改密码异常,请联系管理员"); + } + /** + * 头像上传 + * + * @param avatarfile 用户头像 + */ + @Log(title = "用户头像", businessType = BusinessType.UPDATE) + @PostMapping(value = "/avatar", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R> avatar(@RequestPart("avatarfile") MultipartFile avatarfile) { + Map ajax = new HashMap<>(); + if (!avatarfile.isEmpty()) { + String extension = FileUtil.extName(avatarfile.getOriginalFilename()); + if (!StringUtils.equalsAnyIgnoreCase(extension, MimeTypeUtils.IMAGE_EXTENSION)) { + return R.fail("文件格式不正确,请上传" + Arrays.toString(MimeTypeUtils.IMAGE_EXTENSION) + "格式"); + } + /* SysOssVo oss = iSysOssService.upload(avatarfile); + String avatar = oss.getUrl(); + if (userService.updateUserAvatar(getUsername(), avatar)) { + ajax.put("imgUrl", avatar); + return R.ok(ajax); + }*/ + } + return R.fail("上传图片异常,请联系管理员"); + } +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysRegisterController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysRegisterController.java new file mode 100644 index 0000000..1479535 --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysRegisterController.java @@ -0,0 +1,39 @@ +package com.inscloudtech.web.controller.system; + +import cn.dev33.satoken.annotation.SaIgnore; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.domain.model.RegisterBody; +import com.inscloudtech.system.service.ISysConfigService; +import com.inscloudtech.system.service.SysRegisterService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +/** + * 注册验证 + * + * @author inscloudtech + */ +@Validated +@RequiredArgsConstructor +@RestController +public class SysRegisterController extends BaseController { + + private final SysRegisterService registerService; + private final ISysConfigService configService; + /** + * 用户注册 + */ + @SaIgnore + @PostMapping("/register") + public R register(@Validated @RequestBody RegisterBody user) { + if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) { + return R.fail("当前系统没有开启注册功能!"); + } + registerService.register(user); + return R.ok(); + } +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysRoleController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysRoleController.java new file mode 100644 index 0000000..2062632 --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysRoleController.java @@ -0,0 +1,214 @@ +package com.inscloudtech.web.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.annotation.UpdateLog; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.domain.entity.SysDept; +import com.inscloudtech.common.core.domain.entity.SysRole; +import com.inscloudtech.common.core.domain.entity.SysUser; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.utils.poi.ExcelUtil; +import com.inscloudtech.system.domain.SysUserRole; +import com.inscloudtech.system.service.ISysDeptService; +import com.inscloudtech.system.service.ISysRoleService; +import com.inscloudtech.system.service.ISysUserService; +import com.inscloudtech.system.service.SysPermissionService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 角色信息 + * + * @author inscloudtech + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/role") +public class SysRoleController extends BaseController { + + private final ISysRoleService roleService; + private final ISysUserService userService; + private final ISysDeptService deptService; + private final SysPermissionService permissionService; + /** + * 获取角色信息列表 + */ + @SaCheckPermission("system:role:list") + @GetMapping("/list") + public TableDataInfo list(SysRole role, PageQuery pageQuery) { + return roleService.selectPageRoleList(role, pageQuery); + } + /** + * 导出角色信息列表 + */ + @Log(title = "角色权限", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:role:export") + @PostMapping("/export") + public void export(SysRole role, HttpServletResponse response) { + List list = roleService.selectRoleList(role); + ExcelUtil.exportExcel(list, "角色数据", SysRole.class, response); + } + /** + * 根据角色编号获取详细信息 + * + * @param roleId 角色ID + */ + @SaCheckPermission("system:role:query") + @GetMapping(value = "/{roleId}") + public R getInfo(@PathVariable Long roleId) { + roleService.checkRoleDataScope(roleId); + return R.ok(roleService.selectRoleById(roleId)); + } + /** + * 新增角色 + */ + @SaCheckPermission("system:role:add") + @Log(title = "角色权限", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysRole role) { + if (!roleService.checkRoleNameUnique(role)) { + return R.fail("新增角色'" + role.getRoleName() + "'失败,角色名称已存在"); + } else if (!roleService.checkRoleKeyUnique(role)) { + return R.fail("新增角色'" + role.getRoleName() + "'失败,角色权限已存在"); + } + return toAjax(roleService.insertRole(role)); + + } + /** + * 修改保存角色 + */ + @SaCheckPermission("system:role:edit") +// @Log(title = "角色权限", businessType = BusinessType.UPDATE) + @UpdateLog(title = "角色权限",mapperClass = ISysRoleService.class,methodName = "selectRoleInfoById",entityClass = SysRole.class, businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysRole role) { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + if (!roleService.checkRoleNameUnique(role)) { + return R.fail("修改角色'" + role.getRoleName() + "'失败,角色名称已存在"); + } else if (!roleService.checkRoleKeyUnique(role)) { + return R.fail("修改角色'" + role.getRoleName() + "'失败,角色权限已存在"); + } + + if (roleService.updateRole(role) > 0) { + roleService.cleanOnlineUserByRole(role.getRoleId()); + return R.ok(); + } + return R.fail("修改角色'" + role.getRoleName() + "'失败,请联系管理员"); + } + /** + * 修改保存数据权限 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色权限", businessType = BusinessType.UPDATE) + @PutMapping("/dataScope") + public R dataScope(@RequestBody SysRole role) { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + return toAjax(roleService.authDataScope(role)); + } + /** + * 状态修改 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色权限", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public R changeStatus(@RequestBody SysRole role) { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + return toAjax(roleService.updateRoleStatus(role)); + } + /** + * 删除角色 + * + * @param roleIds 角色ID串 + */ + @SaCheckPermission("system:role:remove") + @Log(title = "角色权限", businessType = BusinessType.DELETE) + @DeleteMapping("/{roleIds}") + public R remove(@PathVariable Long[] roleIds) { + return toAjax(roleService.deleteRoleByIds(roleIds)); + } + /** + * 获取角色选择框列表 + */ + @SaCheckPermission("system:role:query") + @GetMapping("/optionselect") + public R> optionselect() { + return R.ok(roleService.selectRoleAll()); + } + /** + * 查询已分配用户角色列表 + */ + @SaCheckPermission("system:role:list") + @GetMapping("/authUser/allocatedList") + public TableDataInfo allocatedList(SysUser user, PageQuery pageQuery) { + return userService.selectAllocatedList(user, pageQuery); + } + /** + * 查询未分配用户角色列表 + */ + @SaCheckPermission("system:role:list") + @GetMapping("/authUser/unallocatedList") + public TableDataInfo unallocatedList(SysUser user, PageQuery pageQuery) { + return userService.selectUnallocatedList(user, pageQuery); + } + /** + * 取消授权用户 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色权限", businessType = BusinessType.GRANT) + @PutMapping("/authUser/cancel") + public R cancelAuthUser(@RequestBody SysUserRole userRole) { + return toAjax(roleService.deleteAuthUser(userRole)); + } + /** + * 批量取消授权用户 + * + * @param roleId 角色ID + * @param userIds 用户ID串 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色权限", businessType = BusinessType.GRANT) + @PutMapping("/authUser/cancelAll") + public R cancelAuthUserAll(Long roleId, Long[] userIds) { + return toAjax(roleService.deleteAuthUsers(roleId, userIds)); + } + /** + * 批量选择用户授权 + * + * @param roleId 角色ID + * @param userIds 用户ID串 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色权限", businessType = BusinessType.GRANT) + @PutMapping("/authUser/selectAll") + public R selectAuthUserAll(Long roleId, Long[] userIds) { + roleService.checkRoleDataScope(roleId); + return toAjax(roleService.insertAuthUsers(roleId, userIds)); + } + /** + * 获取对应角色部门树列表 + * + * @param roleId 角色ID + */ + @SaCheckPermission("system:role:list") + @GetMapping(value = "/deptTree/{roleId}") + public R> roleDeptTreeselect(@PathVariable("roleId") Long roleId) { + Map ajax = new HashMap<>(); + ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId)); + ajax.put("depts", deptService.selectDeptTreeList(new SysDept())); + return R.ok(ajax); + } +} diff --git a/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysUserController.java b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysUserController.java new file mode 100644 index 0000000..1e260ac --- /dev/null +++ b/cas-admin/src/main/java/com/inscloudtech/web/controller/system/SysUserController.java @@ -0,0 +1,240 @@ +package com.inscloudtech.web.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.secure.BCrypt; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.annotation.UpdateLog; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.domain.entity.SysDept; +import com.inscloudtech.common.core.domain.entity.SysRole; +import com.inscloudtech.common.core.domain.entity.SysUser; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.excel.ExcelResult; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.common.utils.StreamUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.poi.ExcelUtil; +import com.inscloudtech.system.domain.vo.SysUserExportVo; +import com.inscloudtech.system.domain.vo.SysUserImportVo; +import com.inscloudtech.system.listener.SysUserImportListener; +import com.inscloudtech.system.mapper.SysUserMapper; +import com.inscloudtech.system.service.ISysDeptService; +import com.inscloudtech.system.service.ISysPostService; +import com.inscloudtech.system.service.ISysRoleService; +import com.inscloudtech.system.service.ISysUserService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.util.*; + +/** + * 用户信息 + * + * @author inscloudtech + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/user") +public class SysUserController extends BaseController { + + private final ISysUserService userService; + private final ISysRoleService roleService; + private final ISysPostService postService; + private final ISysDeptService deptService; + /** + * 获取用户列表 + */ +// @SaCheckPermission("system:user:list") + @GetMapping("/list") + public TableDataInfo list(SysUser user, PageQuery pageQuery) { + return userService.selectPageUserList(user, pageQuery); + } + /** + * 导出用户列表 + */ + @Log(title = "用户管理", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:user:export") + @PostMapping("/export") + public void export(SysUser user, HttpServletResponse response) { + List list = userService.selectUserList(user); + List listVo = BeanUtil.copyToList(list, SysUserExportVo.class); + for (int i = 0; i < list.size(); i++) { + SysDept dept = list.get(i).getDept(); + SysUserExportVo vo = listVo.get(i); + if (ObjectUtil.isNotEmpty(dept)) { + vo.setDeptName(dept.getDeptName()); + vo.setLeader(dept.getLeader()); + } + } + ExcelUtil.exportExcel(listVo, "用户数据", SysUserExportVo.class, response); + } + /** + * 导入数据 + * + * @param file 导入文件 + * @param updateSupport 是否更新已存在数据 + */ + @Log(title = "用户管理", businessType = BusinessType.IMPORT) + @SaCheckPermission("system:user:import") + @PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R importData(@RequestPart("file") MultipartFile file, boolean updateSupport, Long deptId) throws Exception { + if(null == deptId){ + return R.fail("所属机构不能为空!"); + } + ExcelResult result = ExcelUtil.importExcel(file.getInputStream(), SysUserImportVo.class, new SysUserImportListener(updateSupport,deptId)); + return R.ok(result.getAnalysis()); + } + /** + * 获取导入模板 + */ + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) { + ExcelUtil.exportExcel(new ArrayList<>(), "用户数据", SysUserImportVo.class, response); + } + /** + * 根据用户编号获取详细信息 + * + * @param userId 用户ID + */ + @SaCheckPermission("system:user:query") + @GetMapping(value = {"/", "/{userId}"}) + public R> getInfo(@PathVariable(value = "userId", required = false) Long userId) { + userService.checkUserDataScope(userId); + Map ajax = new HashMap<>(); + List roles = roleService.selectRoleAll(); + ajax.put("roles", LoginHelper.isAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isAdmin())); +// ajax.put("posts", postService.selectPostAll()); + ajax.put("posts", Collections.EMPTY_LIST); + if (ObjectUtil.isNotNull(userId)) { + SysUser sysUser = userService.selectUserById(userId); + ajax.put("user", sysUser); +// ajax.put("postIds", postService.selectPostListByUserId(userId)); + ajax.put("postIds", Collections.EMPTY_LIST); + ajax.put("roleIds", StreamUtils.toList(sysUser.getRoles(), SysRole::getRoleId)); + } + return R.ok(ajax); + } + /** + * 新增用户 + */ + @SaCheckPermission("system:user:add") + @Log(title = "用户管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysUser user) { + if (!userService.checkUserNameUnique(user)) { + return R.fail("新增用户'" + user.getUserName() + "'失败,登录账号已存在"); + } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) { + return R.fail("新增用户'" + user.getUserName() + "'失败,手机号码已存在"); + } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) { + return R.fail("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在"); + } + user.setPassword(BCrypt.hashpw(user.getPassword())); + return toAjax(userService.insertUser(user)); + } + /** + * 修改用户 + */ + @SaCheckPermission("system:user:edit") +// @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @UpdateLog(title = "用户管理",mapperClass = SysUserMapper.class,methodName = "selectUserById" ,businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysUser user) { + userService.checkUserAllowed(user); + userService.checkUserDataScope(user.getUserId()); + if (!userService.checkUserNameUnique(user)) { + return R.fail("修改用户'" + user.getUserName() + "'失败,登录账号已存在"); + } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) { + return R.fail("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); + } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) { + return R.fail("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); + } + return toAjax(userService.updateUser(user)); + } + /** + * 删除用户 + * + * @param userIds 角色ID串 + */ + @SaCheckPermission("system:user:remove") + @Log(title = "用户管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{userIds}") + public R remove(@PathVariable Long[] userIds) { + if (ArrayUtil.contains(userIds, getUserId())) { + return R.fail("当前用户不能删除"); + } + return toAjax(userService.deleteUserByIds(userIds)); + } + /** + * 重置密码 + */ + @SaCheckPermission("system:user:resetPwd") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PutMapping("/resetPwd") + public R resetPwd(@RequestBody SysUser user) { + userService.checkUserAllowed(user); + userService.checkUserDataScope(user.getUserId()); + user.setPassword(BCrypt.hashpw(user.getPassword())); + return toAjax(userService.resetPwd(user)); + } + /** + * 状态修改 + */ + @SaCheckPermission("system:user:edit") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public R changeStatus(@RequestBody SysUser user) { + userService.checkUserAllowed(user); + userService.checkUserDataScope(user.getUserId()); + return toAjax(userService.updateUserStatus(user)); + } + /** + * 根据用户编号获取授权角色 + * + * @param userId 用户ID + */ + @SaCheckPermission("system:user:query") + @GetMapping("/authRole/{userId}") + public R> authRole(@PathVariable Long userId) { + SysUser user = userService.selectUserById(userId); + List roles = roleService.selectRolesByUserId(userId); + Map ajax = new HashMap<>(); + ajax.put("user", user); + ajax.put("roles", LoginHelper.isAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isAdmin())); + return R.ok(ajax); + } + /** + * 用户授权角色 + * + * @param userId 用户Id + * @param roleIds 角色ID串 + */ + @SaCheckPermission("system:user:edit") + @Log(title = "用户管理", businessType = BusinessType.GRANT) + @PutMapping("/authRole") + public R insertAuthRole(Long userId, Long[] roleIds) { + userService.checkUserDataScope(userId); + userService.insertUserAuth(userId, roleIds); + return R.ok(); + } + /** + * 获取部门树列表 + */ +// @SaCheckPermission("system:user:list") + @GetMapping("/deptTree") + public R>> deptTree(SysDept dept) { + return R.ok(deptService.selectDeptTreeList(dept)); + } + +} diff --git a/cas-admin/src/main/resources/application-dev.yml b/cas-admin/src/main/resources/application-dev.yml new file mode 100644 index 0000000..3e2e224 --- /dev/null +++ b/cas-admin/src/main/resources/application-dev.yml @@ -0,0 +1,87 @@ +spring: + datasource: + type: com.zaxxer.hikari.HikariDataSource + # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content + dynamic: + # 性能分析插件(有性能损耗 不建议生产环境使用) + p6spy: false + # 设置默认的数据源或者数据源组,默认值即为 master + primary: master + # 严格模式 匹配不到数据源则报错 + strict: true + datasource: + # 主库数据源 + master: + type: ${spring.datasource.type} + driverClassName: com.mysql.cj.jdbc.Driver + # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 + # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) + url: jdbc:mysql://localhost:3306/chng_wuzi?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true + username: root + password: 123456 + # 从库数据源 + hikari: + # 最大连接池数量 + maxPoolSize: 20 + # 最小空闲线程数量 + minIdle: 10 + # 配置获取连接等待超时的时间 + connectionTimeout: 30000 + # 校验超时时间 + validationTimeout: 5000 + # 空闲连接存活最大时间,默认10分钟 + idleTimeout: 600000 + # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟 + maxLifetime: 1800000 + # 连接测试query(配置检测连接是否有效) + connectionTestQuery: SELECT 1 + # 多久检查一次连接的活性 + keepaliveTime: 30000 + +--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) +spring: + redis: + # 地址 + host: localhost + # 端口,默认为6379 + port: 6379 + # 数据库索引 + database: 0 + # 密码(如没有密码请注释掉) + password: 123456 + # 连接超时时间 + timeout: 10s + # 是否开启ssl + ssl: false + +redisson: + # redis key前缀 + keyPrefix: + # 线程池数量 + threads: 4 + # Netty线程池数量 + nettyThreads: 8 + # 单节点配置 + singleServerConfig: + # 客户端名称 + clientName: ${cas.name} + # 最小空闲连接数 + connectionMinimumIdleSize: 8 + # 连接池大小 + connectionPoolSize: 32 + # 连接空闲超时,单位:毫秒 + idleConnectionTimeout: 10000 + # 命令等待超时,单位:毫秒 + timeout: 3000 + # 发布和订阅连接池大小 + subscriptionConnectionPoolSize: 50 + +#elasticsearch +easy-es: + enable: true #默认为true,若为false则认为不启用本框架 + address: 192.168.3.20:9200 #es的连接地址,必须含端口 若为集群,则可以用逗号隔开 例如:127.0.0.1:9200,127.0.0.2:9200 + global-config: + distributed: false + print-dsl: false + password: ly123456 + username: elastic diff --git a/cas-admin/src/main/resources/application-prod.yml b/cas-admin/src/main/resources/application-prod.yml new file mode 100644 index 0000000..66cac28 --- /dev/null +++ b/cas-admin/src/main/resources/application-prod.yml @@ -0,0 +1,96 @@ +--- # 临时文件存储位置 避免临时文件被系统清理报错 +spring.servlet.multipart.location: /app/asb/uploadPath + + +--- # 数据源配置 +spring: + datasource: + type: com.zaxxer.hikari.HikariDataSource + # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content + dynamic: + # 性能分析插件(有性能损耗 不建议生产环境使用) + p6spy: false + # 设置默认的数据源或者数据源组,默认值即为 master + primary: master + # 严格模式 匹配不到数据源则报错 + strict: true + datasource: + # 主库数据源 + master: + type: ${spring.datasource.type} + driverClassName: com.mysql.cj.jdbc.Driver + # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 + # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) + url: jdbc:mysql://10.64.200.69:3306/chng_wuzi?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true + username: root + password: Wuzi!@5212 + # 从库数据源 + postgresql: + lazy: true + type: ${spring.datasource.type} + driverClassName: org.postgresql.Driver + url: jdbc:postgresql://10.64.203.136:8000/hnlcj_dws?currentSchema=dwi&useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true + username: lcj_wz + password: Lzx-wz*983$265 + hikari: + # 最大连接池数量 + maxPoolSize: 20 + # 最小空闲线程数量 + minIdle: 10 + # 配置获取连接等待超时的时间 + connectionTimeout: 30000 + # 校验超时时间 + validationTimeout: 5000 + # 空闲连接存活最大时间,默认10分钟 + idleTimeout: 600000 + # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟 + maxLifetime: 1800000 + # 连接测试query(配置检测连接是否有效) + connectionTestQuery: SELECT 1 + # 多久检查一次连接的活性 + keepaliveTime: 30000 + +--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) +spring: + redis: + # 地址 + host: 192.168.0.10 + # 端口,默认为6379 + port: 6379 + # 数据库索引 + database: 0 + # 密码(如没有密码请注释掉) + password: Wuzi!@5212 + # 连接超时时间 + timeout: 10s + # 是否开启ssl + ssl: false + +redisson: + # redis key前缀 + keyPrefix: + # 线程池数量 + threads: 16 + # Netty线程池数量 + nettyThreads: 32 + # 单节点配置 + singleServerConfig: + # 客户端名称 + clientName: ${cas.name} + # 最小空闲连接数 + connectionMinimumIdleSize: 32 + # 连接池大小 + connectionPoolSize: 64 + # 连接空闲超时,单位:毫秒 + idleConnectionTimeout: 10000 + # 命令等待超时,单位:毫秒 + timeout: 3000 + # 发布和订阅连接池大小 + subscriptionConnectionPoolSize: 50 +#elasticsearch +easy-es: + enable: true #默认为true,若为false则认为不启用本框架 + address: localhost:9200 #es的连接地址,必须含端口 若为集群,则可以用逗号隔开 例如:127.0.0.1:9200,127.0.0.2:9200 + global-config: + distributed: false + print-dsl: false diff --git a/cas-admin/src/main/resources/application.yml b/cas-admin/src/main/resources/application.yml new file mode 100644 index 0000000..9a69211 --- /dev/null +++ b/cas-admin/src/main/resources/application.yml @@ -0,0 +1,281 @@ +# 项目相关配置 +cas: + # 名称 + name: cas + # 版本 + version: ${cas-server.version} + # 版权年份 + copyrightYear: 2023 + # 实例演示开关 + demoEnabled: true + # 获取ip地址开关 + addressEnabled: true + # 缓存懒加载 + cacheLazy: false + profile: /app/asb/uploadPath + +captcha: + # 页面 <参数设置> 可开启关闭 验证码校验 + # 验证码类型 math 数组计算 char 字符验证 + type: MATH + # line 线段干扰 circle 圆圈干扰 shear 扭曲干扰 + category: CIRCLE + # 数字验证码位数 + numberLength: 1 + # 字符验证码长度 + charLength: 4 + +# 开发环境配置 +server: + # 服务器的HTTP端口,默认为8080 + port: 8080 + servlet: + # 应用的访问路径 + context-path: / + # undertow 配置 + undertow: + # HTTP post内容的最大大小。当值为-1时,默认值为大小是无限的 + max-http-post-size: -1 + # 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理 + # 每块buffer的空间大小,越小的空间被利用越充分 + buffer-size: 512 + # 是否分配的直接内存 + direct-buffers: true + threads: + # 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程 + io: 8 + # 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载 + worker: 256 + +# 日志配置 +logging: + level: + com.inscloudtech: @logging.level@ + org.springframework: warn + config: classpath:logback-plus.xml + +# 用户配置 +user: + password: + # 密码最大错误次数 + maxRetryCount: 55 + # 密码锁定时间(默认10分钟) + lockTime: 1 + +# Spring配置 +spring: + application: + name: ${cas.name} + # 资源信息 + messages: + # 国际化资源文件路径 + basename: i18n/messages + profiles: + active: @profiles.active@ + # 文件上传 + servlet: + multipart: + # 单个文件大小 + max-file-size: 10MB + # 设置总上传的文件大小 + max-request-size: 20MB + # 服务模块 + devtools: + restart: + # 热部署开关 + enabled: true + mvc: + format: + date-time: yyyy-MM-dd HH:mm:ss + jackson: + # 日期格式化 + date-format: yyyy-MM-dd HH:mm:ss + serialization: + # 格式化输出 + indent_output: false + # 忽略无法转换的对象 + fail_on_empty_beans: false + deserialization: + # 允许对象忽略json中不存在的属性 + fail_on_unknown_properties: false + +# Sa-Token配置 +sa-token: + # token名称 (同时也是cookie名称) + token-name: Authorization + # token有效期 设为一天 (必定过期) 单位: 秒 + timeout: 86400 + # token临时有效期 (指定时间无操作就过期) 单位: 秒 + activity-timeout: 28800 + # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) + is-concurrent: true + # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) + is-share: false + # 是否尝试从header里读取token + is-read-header: true + # 是否尝试从cookie里读取token + is-read-cookie: false + # token前缀 + token-prefix: "Bearer" + # jwt秘钥 + jwt-secret-key: abcdefghijklmnopqrstuvwxyz + +# security配置 +security: + # 排除路径 + excludes: + # 静态资源 + - /*.html + - /**/*.html + - /**/*.css + - /**/*.js + # 公共路径 + - /favicon.ico + - /error + # swagger 文档配置 + - /*/api-docs + - /*/api-docs/** + # actuator 监控配置 + - /actuator + - /actuator/** + - /jmreport/** + + +# MyBatisPlus配置 +# https://baomidou.com/config/ +mybatis-plus: + # 不支持多包, 如有需要可在注解配置 或 提升扫包等级 + # 例如 com.**.**.mapper + mapperPackage: com.inscloudtech.**.mapper + # 对应的 XML 文件位置 + mapperLocations: classpath*:mapper/**/*Mapper.xml + # 实体扫描,多个package用逗号或者分号分隔 + typeAliasesPackage: com.inscloudtech.**.domain + # 启动时是否检查 MyBatis XML 文件的存在,默认不检查 + checkConfigLocation: false + configuration: + # 自动驼峰命名规则(camel case)映射 + mapUnderscoreToCamelCase: true + # MyBatis 自动映射策略 + # NONE:不启用 PARTIAL:只对非嵌套 resultMap 自动映射 FULL:对所有 resultMap 自动映射 + autoMappingBehavior: PARTIAL + # MyBatis 自动映射时未知列或未知属性处理策 + # NONE:不做处理 WARNING:打印相关警告 FAILING:抛出异常和详细信息 + autoMappingUnknownColumnBehavior: NONE + # 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl + # 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl + # 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl + logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl + global-config: + # 是否打印 Logo banner + banner: false + dbConfig: + # 主键类型 + # AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID + idType: AUTO + # 逻辑已删除值 + logicDeleteValue: 2 + # 逻辑未删除值 + logicNotDeleteValue: 0 + # 字段验证策略之 insert,在 insert 的时候的字段验证策略 + # IGNORED 忽略 NOT_NULL 非NULL NOT_EMPTY 非空 DEFAULT 默认 NEVER 不加入 SQL + insertStrategy: NOT_NULL + # 字段验证策略之 update,在 update 的时候的字段验证策略 + updateStrategy: NOT_NULL + # 字段验证策略之 select,在 select 的时候的字段验证策略既 wrapper 根据内部 entity 生成的 where 条件 + where-strategy: NOT_NULL + +# 数据加密 +mybatis-encryptor: + # 是否开启加密 + enable: false + # 默认加密算法 + algorithm: BASE64 + # 编码方式 BASE64/HEX。默认BASE64 + encode: BASE64 + # 安全秘钥 对称算法的秘钥 如:AES,SM4 +# password: + # 公私钥 非对称算法的公私钥 如:SM2,RSA + publicKey: + privateKey: + +# Swagger配置 +swagger: + info: + # 标题 + title: '标题:${cas.name}后台管理系统_接口文档' + # 描述 + description: '描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...' + # 版本 + version: '版本号: ${cas-server.version}' + # 作者信息 + contact: + name: inscloudtech + email: inscloudtech@163.com + url: inscloudtech + components: + # 鉴权方式配置 + security-schemes: + apiKey: + type: APIKEY + in: HEADER + name: ${sa-token.token-name} + +springdoc: + api-docs: + # 是否开启接口文档 + enabled: true + swagger-ui: + # 持久化认证数据 + persistAuthorization: true + #这里定义了两个分组,可定义多个,也可以不定义 + group-configs: + - group: 1.演示模块 + packages-to-scan: com.inscloudtech.demo + - group: 2.系统模块 + packages-to-scan: com.inscloudtech.web + - group: 3.代码生成模块 + packages-to-scan: com.inscloudtech.generator + - group: 4.编码库存计划模块 + packages-to-scan: com.inscloudtech.code + +# 防止XSS攻击 +xss: + # 过滤开关 + enabled: true + # 排除链接(多个用逗号分隔) + excludes: /system/notice + # 匹配链接 + urlPatterns: /system/*,/monitor/*,/tool/* + +# 全局线程池相关配置 +thread-pool: + # 是否开启线程池 + enabled: false + # 队列最大长度 + queueCapacity: 128 + # 线程池维护线程所允许的空闲时间 + keepAliveSeconds: 300 + +--- # 分布式锁 lock4j 全局配置 +lock4j: + # 获取分布式锁超时时间,默认为 3000 毫秒 + acquire-timeout: 3000 + # 分布式锁的超时时间,默认为 30 秒 + expire: 30000 + +--- # Actuator 监控端点的配置项 +management: + endpoints: + web: + exposure: + include: '*' + endpoint: + health: + show-details: ALWAYS + logfile: + external-file: ./logs/sys-console.log + +minidao : + base-package: org.jeecg.modules.jmreport.desreport.dao* + db-type: mysql diff --git a/cas-admin/src/main/resources/banner.txt b/cas-admin/src/main/resources/banner.txt new file mode 100644 index 0000000..0890582 --- /dev/null +++ b/cas-admin/src/main/resources/banner.txt @@ -0,0 +1,2 @@ +Application Version: ${cas-server.version} +Spring Boot Version: ${spring-boot.version} diff --git a/cas-admin/src/main/resources/i18n/messages.properties b/cas-admin/src/main/resources/i18n/messages.properties new file mode 100644 index 0000000..ffdd8f3 --- /dev/null +++ b/cas-admin/src/main/resources/i18n/messages.properties @@ -0,0 +1,49 @@ +#错误消息 +not.null=* 必须填写 +user.jcaptcha.error=验证码错误 +user.jcaptcha.expire=验证码已失效 +user.not.exists=对不起, 您的账号:{0} 不存在. +user.password.not.match=用户不存在/密码错误 +user.password.retry.limit.count=密码输入错误{0}次 +user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟 +user.password.delete=对不起,您的账号:{0} 已被删除 +user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员 +role.blocked=角色已封禁,请联系管理员 +user.logout.success=退出成功 +length.not.valid=长度必须在{min}到{max}个字符之间 +user.username.not.blank=用户名不能为空 +user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 +user.username.length.valid=账户长度必须在{min}到{max}个字符之间 +user.password.not.blank=用户密码不能为空 +user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间 +user.password.not.valid=* 5-50个字符 +user.email.not.valid=邮箱格式错误 +user.email.not.blank=邮箱不能为空 +user.phonenumber.not.blank=用户手机号不能为空 +user.mobile.phone.number.not.valid=手机号格式错误 +user.login.success=登录成功 +user.register.success=注册成功 +user.register.save.error=保存用户 {0} 失败,注册账号已存在 +user.register.error=注册失败,请联系系统管理人员 +user.notfound=请重新登录 +user.forcelogout=管理员强制退出,请重新登录 +user.unknown.error=未知错误,请重新登录 +##文件上传消息 +upload.exceed.maxSize=上传的文件大小超出限制的文件大小!
允许的文件最大大小是:{0}MB! +upload.filename.exceed.length=上传的文件名最长{0}个字符 +##权限 +no.permission=您没有数据的权限,请联系管理员添加权限 [{0}] +no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}] +no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}] +no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] +no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] +no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] +repeat.submit.message=不允许重复提交,请稍候再试 +rate.limiter.message=访问过于频繁,请稍候再试 +sms.code.not.blank=短信验证码不能为空 +sms.code.retry.limit.count=短信验证码输入错误{0}次 +sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}分钟 +email.code.not.blank=邮箱验证码不能为空 +email.code.retry.limit.count=邮箱验证码输入错误{0}次 +email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟 +xcx.code.not.blank=小程序code不能为空 diff --git a/cas-admin/src/main/resources/i18n/messages_en_US.properties b/cas-admin/src/main/resources/i18n/messages_en_US.properties new file mode 100644 index 0000000..c1ca439 --- /dev/null +++ b/cas-admin/src/main/resources/i18n/messages_en_US.properties @@ -0,0 +1,49 @@ +#错误消息 +not.null=* Required fill in +user.jcaptcha.error=Captcha error +user.jcaptcha.expire=Captcha invalid +user.not.exists=Sorry, your account: {0} does not exist +user.password.not.match=User does not exist/Password error +user.password.retry.limit.count=Password input error {0} times +user.password.retry.limit.exceed=Password input error {0} times, account locked for {1} minutes +user.password.delete=Sorry, your account:{0} has been deleted +user.blocked=Sorry, your account: {0} has been disabled. Please contact the administrator +role.blocked=Role disabled,please contact administrators +user.logout.success=Exit successful +length.not.valid=The length must be between {min} and {max} characters +user.username.not.blank=Username cannot be blank +user.username.not.valid=* 2 to 20 chinese characters, letters, numbers or underscores, and must start with a non number +user.username.length.valid=Account length must be between {min} and {max} characters +user.password.not.blank=Password cannot be empty +user.password.length.valid=Password length must be between {min} and {max} characters +user.password.not.valid=* 5-50 characters +user.email.not.valid=Mailbox format error +user.email.not.blank=Mailbox cannot be blank +user.phonenumber.not.blank=Phone number cannot be blank +user.mobile.phone.number.not.valid=Phone number format error +user.login.success=Login successful +user.register.success=Register successful +user.register.save.error=Failed to save user {0}, The registered account already exists +user.register.error=Register failed, please contact system administrator +user.notfound=Please login again +user.forcelogout=The administrator is forced to exit,please login again +user.unknown.error=Unknown error, please login again +##文件上传消息 +upload.exceed.maxSize=The uploaded file size exceeds the limit file size!
the maximum allowed file size is:{0}MB! +upload.filename.exceed.length=The maximum length of uploaded file name is {0} characters +##权限 +no.permission=You do not have permission to the data,please contact your administrator to add permissions [{0}] +no.create.permission=You do not have permission to create data,please contact your administrator to add permissions [{0}] +no.update.permission=You do not have permission to modify data,please contact your administrator to add permissions [{0}] +no.delete.permission=You do not have permission to delete data,please contact your administrator to add permissions [{0}] +no.export.permission=You do not have permission to export data,please contact your administrator to add permissions [{0}] +no.view.permission=You do not have permission to view data,please contact your administrator to add permissions [{0}] +repeat.submit.message=Repeat submit is not allowed, please try again later +rate.limiter.message=Visit too frequently, please try again later +sms.code.not.blank=Sms code cannot be blank +sms.code.retry.limit.count=Sms code input error {0} times +sms.code.retry.limit.exceed=Sms code input error {0} times, account locked for {1} minutes +email.code.not.blank=Email code cannot be blank +email.code.retry.limit.count=Email code input error {0} times +email.code.retry.limit.exceed=Email code input error {0} times, account locked for {1} minutes +xcx.code.not.blank=Mini program code cannot be blank diff --git a/cas-admin/src/main/resources/i18n/messages_zh_CN.properties b/cas-admin/src/main/resources/i18n/messages_zh_CN.properties new file mode 100644 index 0000000..ffdd8f3 --- /dev/null +++ b/cas-admin/src/main/resources/i18n/messages_zh_CN.properties @@ -0,0 +1,49 @@ +#错误消息 +not.null=* 必须填写 +user.jcaptcha.error=验证码错误 +user.jcaptcha.expire=验证码已失效 +user.not.exists=对不起, 您的账号:{0} 不存在. +user.password.not.match=用户不存在/密码错误 +user.password.retry.limit.count=密码输入错误{0}次 +user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟 +user.password.delete=对不起,您的账号:{0} 已被删除 +user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员 +role.blocked=角色已封禁,请联系管理员 +user.logout.success=退出成功 +length.not.valid=长度必须在{min}到{max}个字符之间 +user.username.not.blank=用户名不能为空 +user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 +user.username.length.valid=账户长度必须在{min}到{max}个字符之间 +user.password.not.blank=用户密码不能为空 +user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间 +user.password.not.valid=* 5-50个字符 +user.email.not.valid=邮箱格式错误 +user.email.not.blank=邮箱不能为空 +user.phonenumber.not.blank=用户手机号不能为空 +user.mobile.phone.number.not.valid=手机号格式错误 +user.login.success=登录成功 +user.register.success=注册成功 +user.register.save.error=保存用户 {0} 失败,注册账号已存在 +user.register.error=注册失败,请联系系统管理人员 +user.notfound=请重新登录 +user.forcelogout=管理员强制退出,请重新登录 +user.unknown.error=未知错误,请重新登录 +##文件上传消息 +upload.exceed.maxSize=上传的文件大小超出限制的文件大小!
允许的文件最大大小是:{0}MB! +upload.filename.exceed.length=上传的文件名最长{0}个字符 +##权限 +no.permission=您没有数据的权限,请联系管理员添加权限 [{0}] +no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}] +no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}] +no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] +no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] +no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] +repeat.submit.message=不允许重复提交,请稍候再试 +rate.limiter.message=访问过于频繁,请稍候再试 +sms.code.not.blank=短信验证码不能为空 +sms.code.retry.limit.count=短信验证码输入错误{0}次 +sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}分钟 +email.code.not.blank=邮箱验证码不能为空 +email.code.retry.limit.count=邮箱验证码输入错误{0}次 +email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟 +xcx.code.not.blank=小程序code不能为空 diff --git a/cas-admin/src/main/resources/ip2region.xdb b/cas-admin/src/main/resources/ip2region.xdb new file mode 100644 index 0000000..31f96a1 Binary files /dev/null and b/cas-admin/src/main/resources/ip2region.xdb differ diff --git a/cas-admin/src/main/resources/logback-plus.xml b/cas-admin/src/main/resources/logback-plus.xml new file mode 100644 index 0000000..40fa33b --- /dev/null +++ b/cas-admin/src/main/resources/logback-plus.xml @@ -0,0 +1,129 @@ + + + + + + + + + + ${console.log.pattern} + utf-8 + + + + + + ${log.path}/sys-console.log + + + ${log.path}/sys-console.%d{yyyy-MM-dd}.log + + 1 + + + ${log.pattern} + utf-8 + + + + INFO + + + + + + ${log.path}/sys-info.log + + + + ${log.path}/sys-info.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + INFO + + ACCEPT + + DENY + + + + + ${log.path}/sys-error.log + + + + ${log.path}/sys-error.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + ERROR + + ACCEPT + + DENY + + + + + + + 0 + + 512 + + + + + + + + 0 + + 512 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cas-admin/src/main/resources/spy.properties b/cas-admin/src/main/resources/spy.properties new file mode 100644 index 0000000..abbd893 --- /dev/null +++ b/cas-admin/src/main/resources/spy.properties @@ -0,0 +1,28 @@ +# p6spy 性能分析插件配置文件 +modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory +# 自定义日志打印 +logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger +#日志输出到控制台 +appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger +# 使用日志系统记录 sql +#appender=com.p6spy.engine.spy.appender.Slf4JLogger +# 设置 p6spy driver 代理 +#deregisterdrivers=true +# 取消JDBC URL前缀 +useprefix=true +# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset. +excludecategories=info,debug,result,commit,resultset +# 日期格式 +dateformat=yyyy-MM-dd HH:mm:ss +# SQL语句打印时间格式 +databaseDialectTimestampFormat=yyyy-MM-dd HH:mm:ss +# 实际驱动可多个 +#driverlist=org.h2.Driver +# 是否开启慢SQL记录 +outagedetection=true +# 慢SQL记录标准 2 秒 +outagedetectioninterval=2 +# 是否过滤 Log +filter=true +# 过滤 Log 时所排除的 sql 关键字,以逗号分隔 +exclude=SELECT 1 diff --git a/cas-common/pom.xml b/cas-common/pom.xml new file mode 100644 index 0000000..4761df0 --- /dev/null +++ b/cas-common/pom.xml @@ -0,0 +1,206 @@ + + + + cas-server + com.inscloudtech + 4.7.0 + + 4.0.0 + + cas-common + + + common通用工具 + + + + + + + org.springframework + spring-context-support + + + + + org.springframework + spring-web + + + + + cn.dev33 + sa-token-spring-boot-starter + + + + cn.dev33 + sa-token-jwt + + + + + org.springframework.boot + spring-boot-starter-validation + + + + + org.apache.commons + commons-lang3 + + + + + com.fasterxml.jackson.core + jackson-databind + + + + com.alibaba + easyexcel + + + + + org.yaml + snakeyaml + + + + + javax.servlet + javax.servlet-api + + + + com.baomidou + mybatis-plus-boot-starter + + + + + com.baomidou + dynamic-datasource-spring-boot-starter + + + + cn.hutool + hutool-core + + + + cn.hutool + hutool-http + + + + cn.hutool + hutool-captcha + + + + cn.hutool + hutool-jwt + + + + cn.hutool + hutool-extra + + + + com.sun.mail + jakarta.mail + + + + org.projectlombok + lombok + + + + org.springdoc + springdoc-openapi-webmvc-core + + + + org.springdoc + springdoc-openapi-javadoc + + + + + org.springframework.boot + spring-boot-configuration-processor + + + + + org.redisson + redisson-spring-boot-starter + + + + org.redisson + redisson-spring-data-27 + + + + com.baomidou + lock4j-redisson-spring-boot-starter + + + + + org.bouncycastle + bcprov-jdk15to18 + + + + + org.lionsoul + ip2region + + + + org.apache.commons + commons-compress + 1.21 + + + + + commons-io + commons-io + ${commons.io.version} + + + + + com.github.axet + java-unrar + 1.7.0-8 + + + net.sf.sevenzipjbinding + sevenzipjbinding + 16.02-2.01 + + + net.sf.sevenzipjbinding + sevenzipjbinding-all-platforms + 16.02-2.01 + + + + org.dromara.easy-es + easy-es-annotation + 2.0.0-beta4 + + + + + diff --git a/cas-common/src/main/java/com/inscloudtech/common/annotation/CellMerge.java b/cas-common/src/main/java/com/inscloudtech/common/annotation/CellMerge.java new file mode 100644 index 0000000..47ccaf8 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/annotation/CellMerge.java @@ -0,0 +1,24 @@ +package com.inscloudtech.common.annotation; + +import com.inscloudtech.common.excel.CellMergeStrategy; + +import java.lang.annotation.*; + +/** + * excel 列单元格合并(合并列相同项) + * + * 需搭配 {@link CellMergeStrategy} 策略使用 + * + * @author inscloudtech + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface CellMerge { + + /** + * col index + */ + int index() default -1; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/annotation/DataColumn.java b/cas-common/src/main/java/com/inscloudtech/common/annotation/DataColumn.java new file mode 100644 index 0000000..d439d69 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/annotation/DataColumn.java @@ -0,0 +1,26 @@ +package com.inscloudtech.common.annotation; + +import java.lang.annotation.*; + +/** + * 数据权限 + * + * 一个注解只能对应一个模板 + * + * @author inscloudtech + * @version 3.5.0 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DataColumn { + /** + * 占位符关键字 + */ + String[] key() default "deptName"; + /** + * 占位符替换值 + */ + String[] value() default "dept_id"; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/annotation/DataPermission.java b/cas-common/src/main/java/com/inscloudtech/common/annotation/DataPermission.java new file mode 100644 index 0000000..b081b5a --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/annotation/DataPermission.java @@ -0,0 +1,18 @@ +package com.inscloudtech.common.annotation; + +import java.lang.annotation.*; + +/** + * 数据权限组 + * + * @author inscloudtech + * @version 3.5.0 + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DataPermission { + + DataColumn[] value(); + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/annotation/DeduplicationField.java b/cas-common/src/main/java/com/inscloudtech/common/annotation/DeduplicationField.java new file mode 100644 index 0000000..53b70eb --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/annotation/DeduplicationField.java @@ -0,0 +1,24 @@ +package com.inscloudtech.common.annotation; + + +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.inscloudtech.common.jackson.SensitiveJsonSerializer; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * name字段 + * + * @author inscloudtech + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@JacksonAnnotationsInside +@JsonSerialize(using = SensitiveJsonSerializer.class) +public @interface DeduplicationField { + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/annotation/DictDataMapper.java b/cas-common/src/main/java/com/inscloudtech/common/annotation/DictDataMapper.java new file mode 100644 index 0000000..acb4f1d --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/annotation/DictDataMapper.java @@ -0,0 +1,28 @@ +package com.inscloudtech.common.annotation; + +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.inscloudtech.common.jackson.DictDataJsonSerializer; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 字典数据映射注解 + * + * @author inscloudtech + * @deprecated 建议使用通用翻译注解 + */ +@Deprecated +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.METHOD}) +@JacksonAnnotationsInside +@JsonSerialize(using = DictDataJsonSerializer.class) +public @interface DictDataMapper { + /** + * 设置字典的type值 (如: sys_user_sex) + */ + String dictType() default ""; +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/annotation/EncryptField.java b/cas-common/src/main/java/com/inscloudtech/common/annotation/EncryptField.java new file mode 100644 index 0000000..d6b55d6 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/annotation/EncryptField.java @@ -0,0 +1,39 @@ +package com.inscloudtech.common.annotation; + +import com.inscloudtech.common.enums.AlgorithmType; +import com.inscloudtech.common.enums.EncodeType; + +import java.lang.annotation.*; + +/** + * 字段加密注解 + * + * @author inscloudtech + */ +@Documented +@Inherited +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface EncryptField { + /** + * 加密算法 + */ + AlgorithmType algorithm() default AlgorithmType.DEFAULT; + /** + * 秘钥。AES、SM4需要 + */ + String password() default ""; + /** + * 公钥。RSA、SM2需要 + */ + String publicKey() default ""; + /** + * 公钥。RSA、SM2需要 + */ + String privateKey() default ""; + /** + * 编码方式。对加密算法为BASE64的不起作用 + */ + EncodeType encode() default EncodeType.DEFAULT; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/annotation/ExcelDictFormat.java b/cas-common/src/main/java/com/inscloudtech/common/annotation/ExcelDictFormat.java new file mode 100644 index 0000000..42762ee --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/annotation/ExcelDictFormat.java @@ -0,0 +1,29 @@ +package com.inscloudtech.common.annotation; + +import com.inscloudtech.common.utils.StringUtils; + +import java.lang.annotation.*; + +/** + * 字典格式化 + * + * @author inscloudtech + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ExcelDictFormat { + /** + * 如果是字典类型,请设置字典的type值 (如: sys_user_sex) + */ + String dictType() default ""; + /** + * 读取内容转表达式 (如: 0=男,1=女,2=未知) + */ + String readConverterExp() default ""; + /** + * 分隔符,读取字符串组内容 + */ + String separator() default StringUtils.SEPARATOR; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/annotation/ExcelEnumFormat.java b/cas-common/src/main/java/com/inscloudtech/common/annotation/ExcelEnumFormat.java new file mode 100644 index 0000000..f9242e1 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/annotation/ExcelEnumFormat.java @@ -0,0 +1,27 @@ +package com.inscloudtech.common.annotation; + +import java.lang.annotation.*; + +/** + * 枚举格式化 + * + * @author inscloudtech + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ExcelEnumFormat { + /** + * 字典枚举类型 + */ + Class> enumClass(); + /** + * 字典枚举类中对应的code属性名称,默认为code + */ + String codeField() default "code"; + /** + * 字典枚举类中对应的text属性名称,默认为text + */ + String textField() default "text"; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/annotation/IdCardField.java b/cas-common/src/main/java/com/inscloudtech/common/annotation/IdCardField.java new file mode 100644 index 0000000..472582a --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/annotation/IdCardField.java @@ -0,0 +1,24 @@ +package com.inscloudtech.common.annotation; + + +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.inscloudtech.common.jackson.SensitiveJsonSerializer; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * name字段 + * + * @author inscloudtech + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@JacksonAnnotationsInside +@JsonSerialize(using = SensitiveJsonSerializer.class) +public @interface IdCardField { + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/annotation/Log.java b/cas-common/src/main/java/com/inscloudtech/common/annotation/Log.java new file mode 100644 index 0000000..8abbd19 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/annotation/Log.java @@ -0,0 +1,41 @@ +package com.inscloudtech.common.annotation; + +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.enums.OperatorType; + +import java.lang.annotation.*; + +/** + * 自定义操作日志记录注解 + * + * @author inscloudtech + */ +@Target({ElementType.PARAMETER, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Log { /** + * 模块 + */ + String title() default ""; + /** + * 功能 + */ + BusinessType businessType() default BusinessType.OTHER; + /** + * 操作人类别 + */ + OperatorType operatorType() default OperatorType.MANAGE; + /** + * 是否保存请求的参数 + */ + boolean isSaveRequestData() default true; + /** + * 是否保存响应的参数 + */ + boolean isSaveResponseData() default true; + /** + * 排除指定的请求参数 + */ + String[] excludeParamNames() default {}; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/annotation/NameField.java b/cas-common/src/main/java/com/inscloudtech/common/annotation/NameField.java new file mode 100644 index 0000000..fab7ee0 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/annotation/NameField.java @@ -0,0 +1,24 @@ +package com.inscloudtech.common.annotation; + + +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.inscloudtech.common.jackson.SensitiveJsonSerializer; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * name字段 + * + * @author inscloudtech + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@JacksonAnnotationsInside +@JsonSerialize(using = SensitiveJsonSerializer.class) +public @interface NameField { + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/annotation/PhoneField.java b/cas-common/src/main/java/com/inscloudtech/common/annotation/PhoneField.java new file mode 100644 index 0000000..a5f6adf --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/annotation/PhoneField.java @@ -0,0 +1,24 @@ +package com.inscloudtech.common.annotation; + + +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.inscloudtech.common.jackson.SensitiveJsonSerializer; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * name字段 + * + * @author inscloudtech + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@JacksonAnnotationsInside +@JsonSerialize(using = SensitiveJsonSerializer.class) +public @interface PhoneField { + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/annotation/RateLimiter.java b/cas-common/src/main/java/com/inscloudtech/common/annotation/RateLimiter.java new file mode 100644 index 0000000..5ad4846 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/annotation/RateLimiter.java @@ -0,0 +1,36 @@ +package com.inscloudtech.common.annotation; + +import com.inscloudtech.common.enums.LimitType; + +import java.lang.annotation.*; + +/** + * 限流注解 + * + * @author inscloudtech + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RateLimiter { /** + * 限流key,支持使用Spring el表达式来动态获取方法上的参数值 + * 格式类似于 #code.id #{#code} + */ + String key() default ""; + /** + * 限流时间,单位秒 + */ + int time() default 60; + /** + * 限流次数 + */ + int count() default 100; + /** + * 限流类型 + */ + LimitType limitType() default LimitType.DEFAULT; + /** + * 提示消息 支持国际化 格式为 {code} + */ + String message() default "{rate.limiter.message}"; +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/annotation/RepeatSubmit.java b/cas-common/src/main/java/com/inscloudtech/common/annotation/RepeatSubmit.java new file mode 100644 index 0000000..99a7251 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/annotation/RepeatSubmit.java @@ -0,0 +1,27 @@ +package com.inscloudtech.common.annotation; + +import java.lang.annotation.*; +import java.util.concurrent.TimeUnit; + +/** + * 自定义注解防止表单重复提交 + * + * @author inscloudtech + */ +@Inherited +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RepeatSubmit { + /** + * 间隔时间(ms),小于此时间视为重复提交 + */ + int interval() default 5000; + + TimeUnit timeUnit() default TimeUnit.MILLISECONDS; + /** + * 提示消息 支持国际化 格式为 {code} + */ + String message() default "{repeat.submit.message}"; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/annotation/Sensitive.java b/cas-common/src/main/java/com/inscloudtech/common/annotation/Sensitive.java new file mode 100644 index 0000000..5194903 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/annotation/Sensitive.java @@ -0,0 +1,24 @@ +package com.inscloudtech.common.annotation; + +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.inscloudtech.common.enums.SensitiveStrategy; +import com.inscloudtech.common.jackson.SensitiveJsonSerializer; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 数据脱敏注解 + * + * @author inscloudtech + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@JacksonAnnotationsInside +@JsonSerialize(using = SensitiveJsonSerializer.class) +public @interface Sensitive { + SensitiveStrategy strategy(); +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/annotation/Translation.java b/cas-common/src/main/java/com/inscloudtech/common/annotation/Translation.java new file mode 100644 index 0000000..eca626f --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/annotation/Translation.java @@ -0,0 +1,36 @@ +package com.inscloudtech.common.annotation; + +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.inscloudtech.common.translation.handler.TranslationHandler; + +import java.lang.annotation.*; + +/** + * 通用翻译注解 + * + * @author inscloudtech + */ +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.METHOD}) +@Documented +@JacksonAnnotationsInside +@JsonSerialize(using = TranslationHandler.class) +public @interface Translation { + /** + * 类型 (需与实现类上的 {@link com.inscloudtech.common.annotation.TranslationType} 注解type对应) + *

+ * 默认取当前字段的值 如果设置了 @{@link Translation#mapper()} 则取映射字段的值 + */ + String type(); + /** + * 映射字段 (如果不为空则取此字段的值) + */ + String mapper() default ""; + /** + * 其他条件 例如: 字典type(sys_user_sex) + */ + String other() default ""; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/annotation/TranslationType.java b/cas-common/src/main/java/com/inscloudtech/common/annotation/TranslationType.java new file mode 100644 index 0000000..10183e4 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/annotation/TranslationType.java @@ -0,0 +1,20 @@ +package com.inscloudtech.common.annotation; + +import java.lang.annotation.*; + +/** + * 翻译类型注解 (标注到{@link com.inscloudtech.common.translation.TranslationInterface} 的实现类) + * + * @author inscloudtech + */ +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +@Documented +public @interface TranslationType { + /** + * 类型 + */ + String type(); + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/annotation/UpdateLog.java b/cas-common/src/main/java/com/inscloudtech/common/annotation/UpdateLog.java new file mode 100644 index 0000000..bc69571 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/annotation/UpdateLog.java @@ -0,0 +1,54 @@ +package com.inscloudtech.common.annotation; + +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.enums.OperatorType; + +import java.lang.annotation.*; + +/** + * 自定义操作日志记录注解 + * + * @author zhouyl + */ +@Target({ElementType.PARAMETER, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface UpdateLog { /** + * 模块 + */ + String title() default ""; + /** + * 操作人类别 + */ + OperatorType operatorType() default OperatorType.MANAGE; + /** + * 功能 + */ + BusinessType businessType() default BusinessType.OTHER; + /** + * 是否保存请求的参数 + */ + boolean isSaveRequestData() default true; + /** + * 是否保存响应的参数 + */ + boolean isSaveResponseData() default true; + /** + * 排除指定的请求参数 + */ + String[] excludeParamNames() default {}; + /** + * 记录数据变化 + * 需要用到的mapper or service + */ + Class mapperClass() default Object.class; + + Class entityClass() default Object.class; + /** + * 用来获取数据修改前对象的方法 + * @return + */ + String methodName() default "selectById"; + + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/annotation/UpdateValueLog.java b/cas-common/src/main/java/com/inscloudtech/common/annotation/UpdateValueLog.java new file mode 100644 index 0000000..f473f18 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/annotation/UpdateValueLog.java @@ -0,0 +1,23 @@ +package com.inscloudtech.common.annotation; + +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.inscloudtech.common.jackson.SensitiveJsonSerializer; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 数值修改记录字段注解 + * + * @author inscloudtech + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@JacksonAnnotationsInside +@JsonSerialize(using = SensitiveJsonSerializer.class) +public @interface UpdateValueLog { + String fieldName() default ""; +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/captcha/UnsignedMathGenerator.java b/cas-common/src/main/java/com/inscloudtech/common/captcha/UnsignedMathGenerator.java new file mode 100644 index 0000000..f2e080b --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/captcha/UnsignedMathGenerator.java @@ -0,0 +1,80 @@ +package com.inscloudtech.common.captcha; + +import cn.hutool.captcha.generator.CodeGenerator; +import cn.hutool.core.math.Calculator; +import cn.hutool.core.util.CharUtil; +import cn.hutool.core.util.RandomUtil; +import com.inscloudtech.common.utils.StringUtils; + +/** + * 无符号计算生成器 + * + * @author inscloudtech + */ +public class UnsignedMathGenerator implements CodeGenerator { + + private static final long serialVersionUID = -5514819971774091076L; + + private static final String OPERATORS = "+-*"; + /** + * 参与计算数字最大长度 + */ + private final int numberLength; + /** + * 构造 + */ + public UnsignedMathGenerator() { + this(2); + } + /** + * 构造 + * + * @param numberLength 参与计算最大数字位数 + */ + public UnsignedMathGenerator(int numberLength) { + this.numberLength = numberLength; + } + + @Override + public String generate() { + final int limit = getLimit(); + int a = RandomUtil.randomInt(limit); + int b = RandomUtil.randomInt(limit); + String max = Integer.toString(Math.max(a,b)); + String min = Integer.toString(Math.min(a,b)); + max = StringUtils.rightPad(max, this.numberLength, CharUtil.SPACE); + min = StringUtils.rightPad(min, this.numberLength, CharUtil.SPACE); + + return max + RandomUtil.randomChar(OPERATORS) + min + '='; + } + + @Override + public boolean verify(String code, String userInputCode) { + int result; + try { + result = Integer.parseInt(userInputCode); + } catch (NumberFormatException e) { + // 用户输入非数字 + return false; + } + + final int calculateResult = (int) Calculator.conversion(code); + return result == calculateResult; + } + /** + * 获取验证码长度 + * + * @return 验证码长度 + */ + public int getLength() { + return this.numberLength * 2 + 2; + } + /** + * 根据长度获取参与计算数字最大值 + * + * @return 最大值 + */ + private int getLimit() { + return Integer.parseInt("1" + StringUtils.repeat('0', this.numberLength)); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/config/ProjectConfig.java b/cas-common/src/main/java/com/inscloudtech/common/config/ProjectConfig.java new file mode 100644 index 0000000..caa0568 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/config/ProjectConfig.java @@ -0,0 +1,130 @@ +package com.inscloudtech.common.config; + +import lombok.Data; +import lombok.Getter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 读取项目相关配置 + * + * @author inscloudtech + */ + +@Data +@Component +@ConfigurationProperties(prefix = "cas") +public class ProjectConfig { + /** + * 上传路径 + */ + private static String profile; + /** + * 获取地址开关 + */ + private static boolean addressEnabled; + /** + * 验证码类型 + */ + private static String captchaType; + /** + * 项目名称 + */ + private String name; + /** + * 版本 + */ + private String version; + /** + * 版权年份 + */ + private String copyrightYear; + /** + * 实例演示开关 + */ + private boolean demoEnabled; + + public static String getProfile() { + return profile; + } + + public void setProfile(String profile) { + ProjectConfig.profile = profile; + } + + public static boolean isAddressEnabled() { + return addressEnabled; + } + + public void setAddressEnabled(boolean addressEnabled) { + ProjectConfig.addressEnabled = addressEnabled; + } + + public static String getCaptchaType() { + return captchaType; + } + + public void setCaptchaType(String captchaType) { + ProjectConfig.captchaType = captchaType; + } + + /** + * 获取导入上传路径 + */ + public static String getImportPath() { + return getProfile() + "/import"; + } + + /** + * 获取头像上传路径 + */ + public static String getAvatarPath() { + return getProfile() + "/avatar"; + } + + /** + * 获取下载路径 + */ + public static String getDownloadPath() { + return getProfile() + "/download/"; + } + + /** + * 获取上传路径 + */ + public static String getUploadPath() { + return getProfile() + "/upload"; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getCopyrightYear() { + return copyrightYear; + } + + public void setCopyrightYear(String copyrightYear) { + this.copyrightYear = copyrightYear; + } + + public boolean isDemoEnabled() { + return demoEnabled; + } + + public void setDemoEnabled(boolean demoEnabled) { + this.demoEnabled = demoEnabled; + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/constant/BankStatementConstants.java b/cas-common/src/main/java/com/inscloudtech/common/constant/BankStatementConstants.java new file mode 100644 index 0000000..a3543f8 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/constant/BankStatementConstants.java @@ -0,0 +1,34 @@ +package com.inscloudtech.common.constant; + + + +/** + * + * + * @author + */ +public class BankStatementConstants { + + /** + * 批量操作 + */ + public static final int BATCH_SIZE = 1000; + + /** + * 导入银行流水开户信息模板索引 + */ + public static final String IMPORT_TEMPLATE_OPENING_ACCOUNT = "import_template_opening_account"; + + public static final String NAME_WITH_SHEET_NAME = "NAME_WITH_SHEET_NAME"; + + public static final String USERID_4_IMPORT = "importResult-"; + + public static final String BATCH_ID_4_IMPORT = "importBatchId-"; + + public static final String ANALYZE_TRANSACTION_AMOUNT_FAIL_TIPS = "解析交易金额失败,交易金额为:{}"; + + public static final String ANALYZE_BALANCE_FAIL_TIPS = "解析余额失败,余额为:{}"; + + public static final String ANALYZE_TRANSACTION_DATE_FAIL_TIPS = "解析交易日期失败,日期为:{}"; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/constant/CacheConstants.java b/cas-common/src/main/java/com/inscloudtech/common/constant/CacheConstants.java new file mode 100644 index 0000000..ec8d945 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/constant/CacheConstants.java @@ -0,0 +1,37 @@ +package com.inscloudtech.common.constant; + +/** + * 缓存的key 常量 + * + * @author inscloudtech + */ +public interface CacheConstants { + /** + * 在线用户 redis key + */ + String ONLINE_TOKEN_KEY = "online_tokens:"; + /** + * 验证码 redis key + */ + String CAPTCHA_CODE_KEY = "captcha_codes:"; + /** + * 参数管理 cache key + */ + String SYS_CONFIG_KEY = "sys_config:"; + /** + * 字典管理 cache key + */ + String SYS_DICT_KEY = "sys_dict:"; + /** + * 防重提交 redis key + */ + String REPEAT_SUBMIT_KEY = "repeat_submit:"; + /** + * 限流 redis key + */ + String RATE_LIMIT_KEY = "rate_limit:"; + /** + * 登录账户密码错误次数 redis key + */ + String PWD_ERR_CNT_KEY = "pwd_err_cnt:"; +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/constant/CacheNames.java b/cas-common/src/main/java/com/inscloudtech/common/constant/CacheNames.java new file mode 100644 index 0000000..fa8111f --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/constant/CacheNames.java @@ -0,0 +1,57 @@ +package com.inscloudtech.common.constant; + +/** + * 缓存组名称常量 + *

+ * key 格式为 cacheNames#ttl#maxIdleTime#maxSize + *

+ * ttl 过期时间 如果设置为0则不过期 默认为0 + * maxIdleTime 最大空闲时间 根据LRU算法清理空闲数据 如果设置为0则不检测 默认为0 + * maxSize 组最大长度 根据LRU算法清理溢出数据 如果设置为0则无限长 默认为0 + *

+ * 例子: test#60s、test#0#60s、test#0#1m#1000、test#1h#0#500 + * + * @author inscloudtech + */ +public interface CacheNames { + /** + * 演示案例 + */ + String DEMO_CACHE = "demo:cache#60s#10m#20"; + /** + * 系统配置 + */ + String SYS_CONFIG = "sys_config"; + /** + * 数据字典 + */ + String SYS_DICT = "sys_dict"; + /** + * 用户账户 + */ + String SYS_USER_ID = "sys_user_id#30d"; + /** + * 用户账户 + */ + String SYS_USER_NAME = "sys_user_name#30d"; + /** + * 部门 + */ + String SYS_DEPT = "sys_dept#30d"; + /** + * OSS内容 + */ + String SYS_OSS = "sys_oss#30d"; + /** + * OSS配置 + */ + String SYS_OSS_CONFIG = "sys_oss_config"; + /** + * 在线用户 + */ + String ONLINE_TOKEN = "online_tokens"; + + String STOCK_WARNING = "stock_Warning"; + + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/constant/CompanyConfig.java b/cas-common/src/main/java/com/inscloudtech/common/constant/CompanyConfig.java new file mode 100644 index 0000000..ace2ec0 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/constant/CompanyConfig.java @@ -0,0 +1,12 @@ +package com.inscloudtech.common.constant; + +import java.util.Arrays; +import java.util.List; + +public interface CompanyConfig { + List STOCK_DEPT_CODE_LIST = Arrays.asList("6330", "6351", "6361","6390", "63A0", "63B0", "63D0","63N0", "63R0", "63R2", "63R4"); + + List PLAN_DEPT_CODE_LIST = Arrays.asList("6300", "6330", "6351", "6361", "6370", "6380", "6390", "63A0", + "63B0", "63D0", "63F0", "63F1", "63H0", "63J0", "63N0", "63R0", "63R2", "63R4", "63R5", "63T0", "63U0", "63VD", "63W0", "63Z1", "63Z2", "6921", "6922"); + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/constant/Constants.java b/cas-common/src/main/java/com/inscloudtech/common/constant/Constants.java new file mode 100644 index 0000000..a954248 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/constant/Constants.java @@ -0,0 +1,670 @@ +package com.inscloudtech.common.constant; + +import java.nio.charset.StandardCharsets; + +/** + * 通用常量信息 + * + * @author ruoyi + */ +public class Constants { + + /** + * 批量操作 + */ + public static final int BATCH_SIZE = 1000; + + /** + * UTF-8 字符集 + */ + public static final String UTF8 = "UTF-8"; + + /** + * GBK 字符集 + */ + public static final String GBK = "GBK"; + + /** + * www主域 + */ + public static final String WWW = "www."; + + /** + * http请求 + */ + public static final String HTTP = "http://"; + + /** + * https请求 + */ + public static final String HTTPS = "https://"; + + /** + * 通用成功标识 + */ + public static final String SUCCESS = "0"; + + /** + * 通用失败标识 + */ + public static final String FAIL = "1"; + + /** + * 登录成功 + */ + public static final String LOGIN_SUCCESS = "Success"; + + /** + * 注销 + */ + public static final String LOGOUT = "Logout"; + + /** + * 注册 + */ + public static final String REGISTER = "Register"; + + /** + * 登录失败 + */ + public static final String LOGIN_FAIL = "Error"; + + /** + * 验证码有效期(分钟) + */ + public static final Integer CAPTCHA_EXPIRATION = 2; + + /** + * 令牌 + */ + public static final String TOKEN = "token"; + + /** + * 令牌前缀 + */ + public static final String TOKEN_PREFIX = "Bearer "; + + /** + * 令牌前缀 + */ + public static final String LOGIN_USER_KEY = "login_user_key"; + + /** + * 用户ID + */ + public static final String JWT_USERID = "userid"; + + /** + * 用户名称 + */ +// public static final String JWT_USERNAME = Claims.SUBJECT; + + /** + * 用户头像 + */ + public static final String JWT_AVATAR = "avatar"; + + /** + * 创建时间 + */ + public static final String JWT_CREATED = "created"; + + /** + * 用户权限 + */ + public static final String JWT_AUTHORITIES = "authorities"; + + /** + * 资源映射路径 前缀 + */ + public static final String RESOURCE_PREFIX = "/profile"; + + /** + * RMI 远程方法调用 + */ + public static final String LOOKUP_RMI = "rmi:"; + + /** + * LDAP 远程方法调用 + */ + public static final String LOOKUP_LDAP = "ldap:"; + + /** + * LDAPS 远程方法调用 + */ + public static final String LOOKUP_LDAPS = "ldaps:"; + + /** + * 自动识别json对象白名单配置(仅允许解析的包名,范围越小越安全) + */ + public static final String[] JSON_WHITELIST_STR = {"org.springframework", "com.ruoyi"}; + + /** + * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加) + */ + public static final String[] JOB_WHITELIST_STR = {"com.ruoyi"}; + + public static final byte[] AES_SEC_KEY = "managementAnalys".getBytes(StandardCharsets.UTF_8); + + public static final String DEFAULT_PASSWD = "123456"; + + public static final Long ADMIN_USER_ID = 1L; + public static final Long RY_USER_ID = 2L; + + public static final Long LEADER_ROLE_ID = 3L; + public static final String LEADER_NAME = "案管领导"; + public static final Long INVESTIGATOR_ROLE_ID = 4L; + public static final String INVESTIGATOR_NAME = "调查人员"; + + /** + * 用户类型,案管领导 + */ + public static final int USER_TYPE_LEADER = 1; + + /** + * 用户类型,调查人员 + */ + public static final int USER_TYPE_INVESTIGATOR = 2; + + /** + * 用户类型,其他 + */ + public static final int USER_TYPE_OTHER = 3; + + public static final String ORDER_ASC = "asc"; + public static final String ORDER_DESC = "desc"; + + public static final int CURRENCY_TYPE_CHINA = 1; + + /** + * MongoDB中集合名称-富滇银行流水信息-原始 + */ + public static final String ES_INDEX_NAME_FDB_STATEMENT = "fdb_statements"; + /** + * MongoDB中集合名称-中信银行流水信息 + */ + public static final String ES_INDEX_NAME_CITIC_STATEMENT = "citic_statements"; + /** + * MongoDB中集合名称-招商银行流水信息 + */ + public static final String ES_INDEX_NAME_CMB_STATEMENT = "cmb_statements"; + + /** + * MongoDB中集合名称-招商银行流水信息 + */ + public static final String ES_INDEX_NAME_CMB_RETAIL_STATEMENT = "cmb_retail_statements"; + /** + * MongoDB中集合名称-工商银行流水信息-储蓄卡 + */ + public static final String ES_INDEX_NAME_ICBC_STATEMENT = "icbc_statements"; + + /** + * MongoDB中集合名称-工商银行流水信息-信用卡 + */ + public static final String ES_INDEX_NAME_ICBC_STATEMENT_CREDIT_CARD = "icbc_credit_card_statements"; + + /** + * MongoDB中集合名称-农村信用社流水信息 + */ + public static final String ES_INDEX_NAME_RCC_STATEMENT = "rcc_statements"; + /** + * MongoDB中集合名称-中国银行流水信息-对私 + */ + public static final String ES_INDEX_NAME_BOC_STATEMENT_PRIVATE = "boc_statements_private"; + + /** + * MongoDB中集合名称-中国银行流水信息-对公 + */ + public static final String ES_INDEX_NAME_BOC_STATEMENT_PUBLIC = "boc_statements_public"; + + /** + * MongoDB中集合名称-农业银行流水信息 + */ + public static final String MONGO_COLLECTION_NAME_ABC_STATEMENT = "abc_statements"; + + /** + * MongoDB中集合名称-农业银行流水信息-公司 + */ + public static final String ES_INDEX_NAME_ABC_COMPANY_STATEMENT = "abc_company_statements"; + + /** + * MongoDB中集合名称-农业银行流水信息-个人 + */ + public static final String ES_INDEX_NAME_ABC_CUSTOMER_STATEMENT = "abc_customer_statements"; + + /** + * MongoDB中集合名称-浦发银行流水信息-个人流水 + */ + public static final String ES_INDEX_NAME_SPDB_CREDIT_CARD_CUSTOMER_STATEMENT = + "spdb_credit_card_customer_statements"; + + /** + * MongoDB中集合名称-浦发银行流水信息-公司流水 + */ + public static final String ES_INDEX_NAME_SPDB_CREDIT_CARD_COMPANY_STATEMENT = "spdb_credit_card_company_statements"; + + /** + * MongoDB中集合名称-浦发银行开户信息-个人 + */ + public static final String ES_INDEX_NAME_SPDB_CREDIT_CARD_CUSTOMER_INFO = "spdb_credit_card_customer_info"; + + /** + * MongoDB中集合名称-浦发银行开户信息-公司 + */ + public static final String ES_INDEX_NAME_SPDB_CREDIT_CARD_COMPANY_INFO = "spdb_credit_card_company_info"; + + /** + * MongoDB中集合名称-华夏银行流水信息 + */ + public static final String ES_INDEX_NAME_HUAXIA_STATEMENT = "huaxia_statements"; + + /** + * MongoDB中集合名称-华夏银行流水信息-个人 + */ + public static final String ES_INDEX_NAME_HUAXIA_STATEMENT_PERSONAL = "huaxia_statements_personal"; + + /** + * MongoDB中集合名称-华夏银行开户信息 + */ + public static final String ES_INDEX_NAME_HUAXIA_OPENING_ACCOUNT_INFO = "huaxia_opening_account_info"; + + /** + * MongoDB中集合名称-富滇银行开户信息-原始 + */ + public static final String MONGO_COLLECTION_NAME_FDB_OPENING_ACCOUNT_RAW = "fdb_opening_account_info_raw"; + + /** + * MongoDB中集合名称-富滇银行开户信息-个人 + */ + public static final String ES_INDEX_NAME_FDB_OPENING_ACCOUNT_PRIVATE = "fdb_opening_account_info_private"; + + /** + * MongoDB中集合名称-富滇银行开户信息-组织 + */ + public static final String ES_INDEX_NAME_FDB_OPENING_ACCOUNT_PUBLIC = "fdb_opening_account_info_public"; + + /** + * MongoDB中集合名称-中信银行开户信息 + */ + public static final String ES_INDEX_NAME_CITIC_OPENING_ACCOUNT = "citic_opening_account_info"; + + /** + * MongoDB中集合名称-平安开户信息-客户基本信息 + */ + public static final String ES_INDEX_NAME_PING_AN_CUSTOMER_INFO = "ping_an_customer_info"; + + /** + * MongoDB中集合名称-平安开户信息-账户信息 + */ + public static final String ES_INDEX_NAME_PING_AN_ACCOUNT_INFO = "ping_an_account_info"; + + /** + * MongoDB中集合名称-平安开户信息-账户信息-信用卡 + */ + public static final String ES_INDEX_NAME_PING_AN_CREDIT_CARD_ACCOUNT_INFO = "ping_an_credit_card_account_info"; + + /** + * MongoDB中集合名称-平安银行账户信息 + */ + public static final String MONGO_COLLECTION_NAME_PING_AN_ACCOUNT_INFO = "ping_an_account_info"; + + /** + * MongoDB中集合名称-民生银行开户信息-储蓄卡-个人 + */ + public static final String ES_INDEX_NAME_CMBC_SAVINGS_CARD_OPENING_ACCOUNT = + "cmbc_savings_card_opening_account_info"; + + /** + * MongoDB中集合名称-民生银行开户信息-储蓄卡-公司 + */ + public static final String ES_INDEX_NAME_CMBC_SAVINGS_CARD_COMPANY_INFO = "cmbc_savings_card_company_info"; + + /** + * MongoDB中集合名称-民生银行开户信息-信用卡 + */ + public static final String ES_INDEX_NAME_CMBC_CREDIT_CARD_OPENING_ACCOUNT = "cmbc_credit_card_opening_account_info"; + + /** + * MongoDB中集合名称-广发银行开户信息 + */ + public static final String ES_INDEX_NAME_CGBC_OPENING_ACCOUNT = "cgbc_opening_account_info"; + + /** + * MongoDB中集合名称-广发银行开户信息-客户信息 + */ + public static final String ES_INDEX_NAME_CGBC_CUSTOMER_INFO = "cgbc_customer_info"; + + /** + * MongoDB中集合名称-广发银行流水 + */ + public static final String ES_INDEX_NAME_CGBC_SAVINGS_CARD_STATEMENT = "cgbc_old_statements"; + + /** + * MongoDB中集合名称-广发银行流水 + */ + public static final String ES_INDEX_NAME_CGBC_SAVINGS_CARD_NEW_STATEMENT = "cgbc_new_statements"; + + /** + * MongoDB中集合名称-广发银行流水-信用卡 + */ + public static final String ES_INDEX_NAME_CGBC_CREDIT_CARD_STATEMENT = "cgbc_credit_card_statements"; + + /** + * MongoDB中集合名称-交通银行开户信息 + */ + public static final String ES_INDEX_NAME_BOCOM_OPENING_ACCOUNT = "bank_comm_opening_account_info"; + + /** + * MongoDB中集合名称-建设银行开户信息-定期、活期 + */ + public static final String ES_INDEX_NAME_CCB_OPENING_ACCOUNT = "ccb_opening_account_info"; + // 建设银行-公司-开户 + public static final String ES_INDEX_NAME_CCB_COMPANY_OPENING_ACCOUNT = "ccb_company_opening_account_info"; + + /** + * MongoDB中集合名称-建设银行开户信息-电子现金 + */ + public static final String ES_INDEX_NAME_CCB_ELECTRONIC_CASH_OPENING_ACCOUNT = + "ccb_electronic_cash_opening_account_info"; + + /** + * MongoDB中集合名称-兴业银行开户信息 + */ + public static final String ES_INDEX_NAME_CIB_OPENING_ACCOUNT = "cib_opening_account_info"; + + /** + * MongoDB中集合名称-农业银行开户信息-个人 + */ + public static final String ES_INDEX_NAME_ABC_CUSTOMER_OPENING_ACCOUNT = "abc_customer_opening_account_info"; + + /** + * MongoDB中集合名称-交通银行流水信息 + */ + public static final String ES_INDEX_NAME_BOCOM_STATEMENT = "bocom_statements"; + + /** + * MongoDB中集合名称-曲商行流水信息 + */ + public static final String ES_INDEX_NAME_QJCCB_STATEMENT = "qjccb_statements"; + + /** + * MongoDB中集合名称-曲商行开户信息 + */ + public static final String ES_INDEX_NAME_QJCCB_ACCOUNT_INFO = "qjccb_account_info"; + + /** + * MongoDB中集合名称-邮储银行流水信息 + */ + public static final String ES_INDEX_NAME_PSBC_STATEMENT = "psbc_statements"; + + /** + * MongoDB中集合名称-光大银行流水信息-信用卡 + */ + public static final String ES_INDEX_NAME_CEB_CREDIT_CARD_STATEMENT = "ceb_credit_card_statements"; + + /** + * MongoDB中集合名称-光大银行流水信息-储蓄卡 + */ + public static final String ES_INDEX_NAME_CEB_SAVINGS_CARD_STATEMENT = "ceb_savings_card_statements"; + + /** + * MongoDB中集合名称-广发银行流水信息-信用卡 + */ + public static final String ES_INDEX_NAME_CGBC_OTHER_CREDIT_CARD_STATEMENT = "ceb_other_credit_card_statements"; + + /** + * MongoDB中集合名称-邮储银行开户 + */ + public static final String ES_INDEX_NAME_PSBC_ACCOUNT_INFO = "psbc_account_info"; + + /** + * MongoDB中集合名称-民生银行流水信息-储蓄卡 + */ + public static final String ES_INDEX_NAME_CMBC_SAVINGS_CARD_STATEMENT = "cmbc_savings_card_statements"; + + /** + * MongoDB中集合名称-民生银行流水信息-信用卡 + */ + public static final String ES_INDEX_NAME_CMBC_CREDIT_CARD_STATEMENT = "cmbc_credit_card_statements"; + + /** + * MongoDB中集合名称-平安银行流水信息 + */ + public static final String ES_INDEX_NAME_PING_AN_STATEMENT = "ping_an_statements"; + + /** + * MongoDB中集合名称-平安银行流水信息-信用卡 + */ + public static final String ES_INDEX_NAME_PING_AN_CREDIT_CARD_STATEMENT = "ping_an_credit_card_statements"; + + /** + * MongoDB中集合名称-兴业银行流水信息 + */ + public static final String ES_INDEX_NAME_CIB_STATEMENT = "cib_statements"; + + /** + * MongoDB中集合名称-兴业银行流水信息-信用卡 + */ + public static final String ES_INDEX_NAME_CIB_CREDIT_CARD_STATEMENT = "cib_credit_card_statements"; + + /** + * MongoDB中集合名称-建设银行流水信息-活期流水 + */ + public static final String ES_INDEX_NAME_CCB_CURRENT_STATEMENT = "ccb_current_statements"; + // 建设银行流水信息-活期流水-公司 + public static final String ES_INDEX_NAME_CCB_COMPANY_CURRENT_STATEMENT = "ccb_company_current_statements"; + + /** + * MongoDB中集合名称-建设银行流水信息-定期流水 + */ + public static final String ES_INDEX_NAME_CCB_REGULAR_STATEMENT = "ccb_regular_statements"; + + /** + * MongoDB中集合名称-建设银行流水信息-电子现金 + */ + public static final String ES_INDEX_NAME_CCB_ELECTRONIC_CASH_STATEMENT = "ccb_electronic_cash_statements"; + + /** + * MongoDB中集合名称-招商银行开户信息 + */ + public static final String ES_INDEX_NAME_CMB_OPENING_ACCOUNT = "cmb_opening_account_info"; + /** + * 富滇银行开户信息-清洗之后 + */ + public static final String MONGO_COLLECTION_NAME_FUDIAN_OPENING_ACCOUNT_PURE = "fudian_opening_account_info_pure"; + + /** + * MongoDB中集合名称—工商银行开户信息 + */ + public static final String ES_INDEX_NAME_ICBC_OPENING_ACCOUNT = "icbc_opening_account_info"; + /** + * MongoDB中集合名称—农村信用社开户信息 + */ + public static final String MONGO_COLLECTION_NAME_RCC_OPENING_ACCOUNT = "rcc_opening_account_info"; + + /** + * MongoDB中集合名称—中国银行开户信息-公司开户信息 + */ + public static final String ES_INDEX_NAME_BOC_PUBLIC_OPENING_ACCOUNT = "boc_opening_company_account_info"; + + /** + * MongoDB中集合名称—中国银行开户信息-基本个人信息,不包含银行信息,一人一条数据 + */ + public static final String ES_INDEX_NAME_BOC_PRIVATE_BASIC_INFO = "boc_private_basic_info"; + + /** + * MongoDB中集合名称—中国银行开户信息-账户信息 + */ + public static final String ES_INDEX_NAME_BOC_PRIVATE_ACCOUNT_INFO = "boc_private_account_info"; + + /** + * MongoDB中集合名称—中国银行开户信息-开户信息,包含银行信息,一人多条数据 + */ + @Deprecated + public static final String MONGO_COLLECTION_NAME_BOC_CUSTOMER_OPENING_INFO = "boc_customer_opening_account_info"; + + public static final String DICT_TYPE_BANK = "sys_bank_type"; + + public static final String DICT_TYPE_TRANS_CURRENCY = "sys_trans_currency_type"; + + public static final int RANDOM_STRING_LENGTH = 20; + + /** + * 富滇银行 + */ + public static final String BANK_IMPORT_MODEL_BANK_FDB = "16"; + /** + * 中国银行 + */ + public static final String BANK_IMPORT_MODEL_BOC_BANK = "0"; + + /** + * 兴业银行 + */ + public static final String BANK_IMPORT_MODEL_INDUSTRIAL_BANK = "3"; + + /** + * 建设银行 + */ + public static final String BANK_IMPORT_MODEL_CCB_BANK = "5"; + + /** + * 曲靖商业银行 + */ + public static final String BANK_IMPORT_MODEL_QJCCB_BANK = "13"; + + /** + * 浦发银行 + */ + public static final String BANK_IMPORT_MODEL_SPDB_BANK = "14"; + + /** + * 华夏银行 + */ + public static final String BANK_IMPORT_MODEL_HUAXIA_BANK = "11"; + + /** + * 招商银行 + */ + public static final String BANK_IMPORT_MODEL_MERCHANTS_BANK = "4"; + + /** + * 中信银行 + */ + public static final String BANK_IMPORT_MODEL_CITIC_BANK = "1"; + /** + * 工商银行 + */ + public static final String BANK_IMPORT_MODEL_ICBC_BANK = "10"; + + /** + * 农村信用社 + */ + public static final String BANK_IMPORT_MODEL_RCC_BANK = "15"; + + /** + * 平安银行 + */ + public static final String BANK_IMPORT_MODEL_PING_AN_BANK = "2"; + + /** + * 邮储银行 + */ + public static final String BANK_IMPORT_MODEL_PSBC_BANK = "9"; + + /** + * 广发银行 + */ + public static final String BANK_IMPORT_MODEL_CGBC_BANK = "12"; + + /** + * 民生银行 + */ + public static final String BANK_IMPORT_MODEL_CMBC_BANK = "6"; + + /** + * 交通银行 + */ + public static final String BANK_IMPORT_MODEL_BANK_COMM_BANK = "8"; + + /** + * 光大银行 + */ + public static final String BANK_IMPORT_MODEL_BANK_CEB_BANK = "17"; + + /** + * 农业银行 + */ + public static final String BANK_IMPORT_MODEL_BANK_ABC_BANK = "7"; + + /** + * 央地系统 + */ + public static final String BANK_IMPORT_MODEL_BANK_CGS = "19"; + + /** + * 恒丰银行 + */ + public static final String BANK_IMPORT_MODEL_BANK_HFB_BANK = "18"; + + + /** + * 定时任务违规的字符 + */ + public static final String[] JOB_ERROR_STR = { + "java.net.URL", + "javax.naming.InitialContext", + "org.yaml.snakeyaml", + "org.springframework", + "org.apache", + "com.ruoyi.common.utils.file", + "com.ruoyi.common.config" + }; + + /** + * minio导入银行流水模板文件 + */ + public static final String IMPORT_BANK_STATEMENT_TEMPLATE_FILE_NAME = "bs_template/银行流水.zip"; + + public static final int DATE_FULL_FORMAT_LENGTH = "yyyyMMdd".length(); + public static final int TIME_FULL_FORMAT_LENGTH = "HHmmss".length(); + + public static final int DATE_TIME_FULL_FORMAT_LENGTH = "yyyyMMddHHmmss".length(); + + public static final String ID_TYPE_ID_CARD = "第二代居民身份证"; + + public static final String ID_TYPE_SOCIAL_CREDIT_CODE = "社会信用代码"; + + /** + * 工商银行流水类型-信用卡流水 + */ + public static final int ICBC_BS_TYPE_CREDIT_CARD = 1; + /** + * 工商银行流水类型-储蓄卡流水 + */ + public static final int ICBC_BS_TYPE_DEBIT_CARD = 2; + + public static final String ES_INDEX_NAME_ABC_COMPANY_OPENING_ACCOUNT = "abc_company_opening_account"; + + public static final String ES_INDEX_NAME_HF_COMPANY_STATEMENT = "hf_company_statements"; + + public static final String ES_INDEX_NAME_HF_COMPANY_STATEMENT_V2 = "hf_company_statements_v2"; + + public static final String REDIS_CACHE_BANK_LIST = "redis_cache_bank_list"; + + public static final String CENTRAL_GROUND_SYSTEM = "央地系统"; + + /** + * 银行流水处理完毕标识 + */ + public static final String COMPLETE_BANK_COUNT = "COMPLETE_BANK_COUNT-"; + public static final String IMPORT_BANK_COUNT = "IMPORT_BANK_COUNT-"; + + /** + * 央地系统银行流水 + */ + public static final String ES_INDEX_NAME_CGS_STATEMENT = "cgs_statements"; + + public static final String ES_INDEX_NAME_CGS_OPEN_ACCOUNT_INFO = "cgs_open_account_info"; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/constant/GenConstants.java b/cas-common/src/main/java/com/inscloudtech/common/constant/GenConstants.java new file mode 100644 index 0000000..14cb6d7 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/constant/GenConstants.java @@ -0,0 +1,157 @@ +package com.inscloudtech.common.constant; + +/** + * 代码生成通用常量 + * + * @author inscloudtech + */ +public interface GenConstants { /** + * 单表(增删改查) + */ + String TPL_CRUD = "crud"; + /** + * 树表(增删改查) + */ + String TPL_TREE = "tree"; + /** + * 主子表(增删改查) + */ + String TPL_SUB = "sub"; + /** + * 树编码字段 + */ + String TREE_CODE = "treeCode"; + /** + * 树父编码字段 + */ + String TREE_PARENT_CODE = "treeParentCode"; + /** + * 树名称字段 + */ + String TREE_NAME = "treeName"; + /** + * 上级菜单ID字段 + */ + String PARENT_MENU_ID = "parentMenuId"; + /** + * 上级菜单名称字段 + */ + String PARENT_MENU_NAME = "parentMenuName"; + /** + * 数据库字符串类型 + */ + String[] COLUMNTYPE_STR = {"char", "varchar", "nvarchar", "varchar2"}; + /** + * 数据库文本类型 + */ + String[] COLUMNTYPE_TEXT = {"tinytext", "text", "mediumtext", "longtext"}; + /** + * 数据库时间类型 + */ + String[] COLUMNTYPE_TIME = {"datetime", "time", "date", "timestamp"}; + /** + * 数据库数字类型 + */ + String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "number", "integer", + "bit", "bigint", "float", "double", "decimal"}; + /** + * BO对象 不需要添加字段 + */ + String[] COLUMNNAME_NOT_ADD = {"create_by", "create_time", "del_flag", "update_by", + "update_time", "version"}; + /** + * BO对象 不需要编辑字段 + */ + String[] COLUMNNAME_NOT_EDIT = {"create_by", "create_time", "del_flag", "update_by", + "update_time", "version"}; + /** + * VO对象 不需要返回字段 + */ + String[] COLUMNNAME_NOT_LIST = {"create_by", "create_time", "del_flag", "update_by", + "update_time", "version"}; + /** + * BO对象 不需要查询字段 + */ + String[] COLUMNNAME_NOT_QUERY = {"id", "create_by", "create_time", "del_flag", "update_by", + "update_time", "remark", "version"}; + /** + * Entity基类字段 + */ + String[] BASE_ENTITY = {"createBy", "createTime", "updateBy", "updateTime"}; + /** + * Tree基类字段 + */ + String[] TREE_ENTITY = {"parentName", "parentId", "children"}; + /** + * 文本框 + */ + String HTML_INPUT = "input"; + /** + * 文本域 + */ + String HTML_TEXTAREA = "textarea"; + /** + * 下拉框 + */ + String HTML_SELECT = "select"; + /** + * 单选框 + */ + String HTML_RADIO = "radio"; + /** + * 复选框 + */ + String HTML_CHECKBOX = "checkbox"; + /** + * 日期控件 + */ + String HTML_DATETIME = "datetime"; + /** + * 图片上传控件 + */ + String HTML_IMAGE_UPLOAD = "imageUpload"; + /** + * 文件上传控件 + */ + String HTML_FILE_UPLOAD = "fileUpload"; + /** + * 富文本控件 + */ + String HTML_EDITOR = "editor"; + /** + * 字符串类型 + */ + String TYPE_STRING = "String"; + /** + * 整型 + */ + String TYPE_INTEGER = "Integer"; + /** + * 长整型 + */ + String TYPE_LONG = "Long"; + /** + * 浮点型 + */ + String TYPE_DOUBLE = "Double"; + /** + * 高精度计算类型 + */ + String TYPE_BIGDECIMAL = "BigDecimal"; + /** + * 时间类型 + */ + String TYPE_DATE = "Date"; + /** + * 模糊查询 + */ + String QUERY_LIKE = "LIKE"; + /** + * 相等查询 + */ + String QUERY_EQ = "EQ"; + /** + * 需要 + */ + String REQUIRE = "1"; +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/constant/HttpStatus.java b/cas-common/src/main/java/com/inscloudtech/common/constant/HttpStatus.java new file mode 100644 index 0000000..df23219 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/constant/HttpStatus.java @@ -0,0 +1,76 @@ +package com.inscloudtech.common.constant; + +/** + * 返回状态码 + * + * @author inscloudtech + */ +public interface HttpStatus { /** + * 操作成功 + */ + int SUCCESS = 200; + /** + * 对象创建成功 + */ + int CREATED = 201; + /** + * 请求已经被接受 + */ + int ACCEPTED = 202; + /** + * 操作已经执行成功,但是没有返回数据 + */ + int NO_CONTENT = 204; + /** + * 资源已被移除 + */ + int MOVED_PERM = 301; + /** + * 重定向 + */ + int SEE_OTHER = 303; + /** + * 资源没有被修改 + */ + int NOT_MODIFIED = 304; + /** + * 参数列表错误(缺少,格式不匹配) + */ + int BAD_REQUEST = 400; + /** + * 未授权 + */ + int UNAUTHORIZED = 401; + /** + * 访问受限,授权过期 + */ + int FORBIDDEN = 403; + /** + * 资源,服务未找到 + */ + int NOT_FOUND = 404; + /** + * 不允许的http方法 + */ + int BAD_METHOD = 405; + /** + * 资源冲突,或者资源被锁 + */ + int CONFLICT = 409; + /** + * 不支持的数据,媒体类型 + */ + int UNSUPPORTED_TYPE = 415; + /** + * 系统内部错误 + */ + int ERROR = 500; + /** + * 接口未实现 + */ + int NOT_IMPLEMENTED = 501; + /** + * 系统警告消息 + */ + int WARN = 601; +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/constant/TransConstant.java b/cas-common/src/main/java/com/inscloudtech/common/constant/TransConstant.java new file mode 100644 index 0000000..e7b7ead --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/constant/TransConstant.java @@ -0,0 +1,28 @@ +package com.inscloudtech.common.constant; + +/** + * 翻译常量 + * + * @author inscloudtech + */ +public interface TransConstant { + /** + * 用户id转账号 + */ + String USER_ID_TO_NAME = "user_id_to_name"; + + String USERNAME_TO_NICKNAME = "username_to_nickname"; + /** + * 部门id转名称 + */ + String DEPT_ID_TO_NAME = "dept_id_to_name"; + /** + * 字典type转label + */ + String DICT_TYPE_TO_LABEL = "dict_type_to_label"; + /** + * ossId转url + */ + String OSS_ID_TO_URL = "oss_id_to_url"; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/constant/UserConstants.java b/cas-common/src/main/java/com/inscloudtech/common/constant/UserConstants.java new file mode 100644 index 0000000..3395e1d --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/constant/UserConstants.java @@ -0,0 +1,108 @@ +package com.inscloudtech.common.constant; + +/** + * 用户常量信息 + * + * @author inscloudtech + */ +public interface UserConstants { + /** + * 平台内系统用户的唯一标志 + */ + String SYS_USER = "SYS_USER"; + /** + * 正常状态 + */ + String NORMAL = "0"; + /** + * 异常状态 + */ + String EXCEPTION = "1"; + /** + * 用户正常状态 + */ + String USER_NORMAL = "0"; + /** + * 用户封禁状态 + */ + String USER_DISABLE = "1"; + /** + * 角色正常状态 + */ + String ROLE_NORMAL = "0"; + /** + * 角色封禁状态 + */ + String ROLE_DISABLE = "1"; + /** + * 部门正常状态 + */ + String DEPT_NORMAL = "0"; + /** + * 部门停用状态 + */ + String DEPT_DISABLE = "1"; + /** + * 字典正常状态 + */ + String DICT_NORMAL = "0"; + /** + * 是否为系统默认(是) + */ + String YES = "Y"; + /** + * 是否菜单外链(是) + */ + String YES_FRAME = "0"; + /** + * 是否菜单外链(否) + */ + String NO_FRAME = "1"; + /** + * 菜单正常状态 + */ + String MENU_NORMAL = "0"; + /** + * 菜单停用状态 + */ + String MENU_DISABLE = "1"; + /** + * 菜单类型(目录) + */ + String TYPE_DIR = "M"; + /** + * 菜单类型(菜单) + */ + String TYPE_MENU = "C"; + /** + * 菜单类型(按钮) + */ + String TYPE_BUTTON = "F"; + /** + * Layout组件标识 + */ + String LAYOUT = "Layout"; + /** + * ParentView组件标识 + */ + String PARENT_VIEW = "ParentView"; + /** + * InnerLink组件标识 + */ + String INNER_LINK = "InnerLink"; + /** + * 用户名长度限制 + */ + int USERNAME_MIN_LENGTH = 2; + int USERNAME_MAX_LENGTH = 20; + /** + * 密码长度限制 + */ + int PASSWORD_MIN_LENGTH = 5; + int PASSWORD_MAX_LENGTH = 20; + /** + * 管理员ID + */ + Long ADMIN_ID = 1L; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/convert/ExcelBigNumberConvert.java b/cas-common/src/main/java/com/inscloudtech/common/convert/ExcelBigNumberConvert.java new file mode 100644 index 0000000..76dd8d9 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/convert/ExcelBigNumberConvert.java @@ -0,0 +1,52 @@ +package com.inscloudtech.common.convert; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import lombok.extern.slf4j.Slf4j; + +import java.math.BigDecimal; + +/** + * 大数值转换 + * Excel 数值长度位15位 大于15位的数值转换位字符串 + * + * @author inscloudtech + */ +@Slf4j +public class ExcelBigNumberConvert implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Long.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public Long convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + return Convert.toLong(cellData.getData()); + } + + @Override + public WriteCellData convertToExcelData(Long object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (ObjectUtil.isNotNull(object)) { + String str = Convert.toStr(object); + if (str.length() > 15) { + return new WriteCellData<>(str); + } + } + WriteCellData cellData = new WriteCellData<>(new BigDecimal(object)); + cellData.setType(CellDataTypeEnum.NUMBER); + return cellData; + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/convert/ExcelDictConvert.java b/cas-common/src/main/java/com/inscloudtech/common/convert/ExcelDictConvert.java new file mode 100644 index 0000000..f037e6a --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/convert/ExcelDictConvert.java @@ -0,0 +1,73 @@ +package com.inscloudtech.common.convert; + +import cn.hutool.core.annotation.AnnotationUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.inscloudtech.common.annotation.ExcelDictFormat; +import com.inscloudtech.common.core.service.DictService; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.poi.ExcelUtil; +import com.inscloudtech.common.utils.spring.SpringUtils; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; + +/** + * 字典格式化转换处理 + * + * @author inscloudtech + */ +@Slf4j +public class ExcelDictConvert implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Object.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return null; + } + + @Override + public Object convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + ExcelDictFormat anno = getAnnotation(contentProperty.getField()); + String type = anno.dictType(); + String label = cellData.getStringValue(); + String value; + if (StringUtils.isBlank(type)) { + value = ExcelUtil.reverseByExp(label, anno.readConverterExp(), anno.separator()); + } else { + value = SpringUtils.getBean(DictService.class).getDictValue(type, label, anno.separator()); + } + return Convert.convert(contentProperty.getField().getType(), value); + } + + @Override + public WriteCellData convertToExcelData(Object object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (ObjectUtil.isNull(object)) { + return new WriteCellData<>(""); + } + ExcelDictFormat anno = getAnnotation(contentProperty.getField()); + String type = anno.dictType(); + String value = Convert.toStr(object); + String label; + if (StringUtils.isBlank(type)) { + label = ExcelUtil.convertByExp(value, anno.readConverterExp(), anno.separator()); + } else { + label = SpringUtils.getBean(DictService.class).getDictLabel(type, value, anno.separator()); + } + return new WriteCellData<>(label); + } + + private ExcelDictFormat getAnnotation(Field field) { + return AnnotationUtil.getAnnotation(field, ExcelDictFormat.class); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/convert/ExcelEnumConvert.java b/cas-common/src/main/java/com/inscloudtech/common/convert/ExcelEnumConvert.java new file mode 100644 index 0000000..55d0377 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/convert/ExcelEnumConvert.java @@ -0,0 +1,75 @@ +package com.inscloudtech.common.convert; + +import cn.hutool.core.annotation.AnnotationUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.inscloudtech.common.annotation.ExcelEnumFormat; +import com.inscloudtech.common.utils.reflect.ReflectUtils; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +/** + * 枚举格式化转换处理 + * + * @author inscloudtech + */ +@Slf4j +public class ExcelEnumConvert implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Object.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return null; + } + + @Override + public Object convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + Object codeValue = cellData.getData(); + // 如果是空值 + if (ObjectUtil.isNull(codeValue)) { + return null; + } + Map enumValueMap = beforeConvert(contentProperty); + String textValue = enumValueMap.get(codeValue); + return Convert.convert(contentProperty.getField().getType(), textValue); + } + + @Override + public WriteCellData convertToExcelData(Object object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (ObjectUtil.isNull(object)) { + return new WriteCellData<>(""); + } + Map enumValueMap = beforeConvert(contentProperty); + String value = Convert.toStr(enumValueMap.get(object), ""); + return new WriteCellData<>(value); + } + + private Map beforeConvert(ExcelContentProperty contentProperty) { + ExcelEnumFormat anno = getAnnotation(contentProperty.getField()); + Map enumValueMap = new HashMap<>(); + Enum[] enumConstants = anno.enumClass().getEnumConstants(); + for (Enum enumConstant : enumConstants) { + Object codeValue = ReflectUtils.invokeGetter(enumConstant, anno.codeField()); + String textValue = ReflectUtils.invokeGetter(enumConstant, anno.textField()); + enumValueMap.put(codeValue, textValue); + } + return enumValueMap; + } + + private ExcelEnumFormat getAnnotation(Field field) { + return AnnotationUtil.getAnnotation(field, ExcelEnumFormat.class); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/controller/BaseController.java b/cas-common/src/main/java/com/inscloudtech/common/core/controller/BaseController.java new file mode 100644 index 0000000..4fce10a --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/controller/BaseController.java @@ -0,0 +1,62 @@ +package com.inscloudtech.common.core.controller; + +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.domain.model.LoginUser; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.common.utils.StringUtils; + +/** + * web层通用数据处理 + * + * @author inscloudtech + */ +public class BaseController { + /** + * 响应返回结果 + * + * @param rows 影响行数 + * @return 操作结果 + */ + protected R toAjax(int rows) { + return rows > 0 ? R.ok() : R.fail(); + } + /** + * 响应返回结果 + * + * @param result 结果 + * @return 操作结果 + */ + protected R toAjax(boolean result) { + return result ? R.ok() : R.fail(); + } + /** + * 页面跳转 + */ + public String redirect(String url) { + return StringUtils.format("redirect:{}", url); + } + /** + * 获取用户缓存信息 + */ + public LoginUser getLoginUser() { + return LoginHelper.getLoginUser(); + } + /** + * 获取登录用户id + */ + public Long getUserId() { + return LoginHelper.getUserId(); + } + /** + * 获取登录部门id + */ + public Long getDeptId() { + return LoginHelper.getDeptId(); + } + /** + * 获取登录用户名 + */ + public String getUsername() { + return LoginHelper.getUsername(); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/domain/BaseEntity.java b/cas-common/src/main/java/com/inscloudtech/common/core/domain/BaseEntity.java new file mode 100644 index 0000000..00b3d15 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/domain/BaseEntity.java @@ -0,0 +1,83 @@ +package com.inscloudtech.common.core.domain; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.FieldStrategy; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; + +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Entity基类 + * + * @author inscloudtech + */ + +@Data +public class BaseEntity implements Serializable { + + private static final long serialVersionUID = 1L; + /** + * 搜索值 + */ + @JsonIgnore + @TableField(exist = false) + private String searchValue; + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private String createBy; + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + /** + * 更新者 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updateBy; + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; + /** + * 请求参数 + */ + @JsonInclude(JsonInclude.Include.NON_EMPTY) + @TableField(exist = false) + private Map params = new HashMap<>(); + + @TableField(exist = false) + @IndexField(exist = false) + private List ids; + + /** + * 备注 + */ + @TableField(updateStrategy = FieldStrategy.IGNORED) + @IndexField(strategy = org.dromara.easyes.annotation.rely.FieldStrategy.IGNORED) + private String remark; + + @JsonIgnore + @TableField(exist = false) + @IndexField(exist = false) + private Integer downloadTemplate; + + + @IndexField(exist = false) + @TableLogic + @JsonIgnore + private String delFlag; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/domain/ExportBaseEntity.java b/cas-common/src/main/java/com/inscloudtech/common/core/domain/ExportBaseEntity.java new file mode 100644 index 0000000..3e066eb --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/domain/ExportBaseEntity.java @@ -0,0 +1,48 @@ +package com.inscloudtech.common.core.domain; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * Entity基类 + * + * @author ruoyi + */ +@Data +public class ExportBaseEntity implements Serializable { + private static final long serialVersionUID = 1L; + + @ExcelProperty("id") + private String id; + + @ExcelProperty("创建者") + private String createBy; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @ExcelProperty("创建时间") + private Date createTime; + + @ExcelProperty("更新者") + private String updateBy; + + @ExcelProperty("更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + + @ExcelProperty("备注") + private String remark; + + + @ExcelProperty("bgc") + private String bgc; + + @ExcelProperty("caseId") + private String caseId; + + @ExcelProperty("analysisResultId") + private String analysisResultId; +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/domain/PageQuery.java b/cas-common/src/main/java/com/inscloudtech/common/core/domain/PageQuery.java new file mode 100644 index 0000000..d2a6f03 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/domain/PageQuery.java @@ -0,0 +1,105 @@ +package com.inscloudtech.common.core.domain; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.metadata.OrderItem; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.inscloudtech.common.exception.ServiceException; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.sql.SqlUtil; +import lombok.Data; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * 分页查询实体类 + * + * @author inscloudtech + */ + +@Data +public class PageQuery implements Serializable { + + private static final long serialVersionUID = 1L; + /** + * 分页大小 + */ + private Integer pageSize; + /** + * 当前页数 + */ + private Integer pageNum; + /** + * 排序列 + */ + private String orderByColumn; + /** + * 排序的方向desc或者asc + */ + private String isAsc; + /** + * 当前记录起始索引 默认值 + */ + public static final int DEFAULT_PAGE_NUM = 1; + /** + * 每页显示记录数 默认值 默认查全部 + */ + public static final int DEFAULT_PAGE_SIZE = 20; + + public Page build() { + Integer pageNum = ObjectUtil.defaultIfNull(getPageNum(), DEFAULT_PAGE_NUM); + Integer pageSize = ObjectUtil.defaultIfNull(getPageSize(), DEFAULT_PAGE_SIZE); + if (pageNum <= 0) { + pageNum = DEFAULT_PAGE_NUM; + } + Page page = new Page<>(pageNum, pageSize); + List orderItems = buildOrderItem(); + if (CollUtil.isNotEmpty(orderItems)) { + page.addOrder(orderItems); + } + return page; + } + /** + * 构建排序 + * + * 支持的用法如下: + * {isAsc:"asc",orderByColumn:"id"} order by id asc + * {isAsc:"asc",orderByColumn:"id,createTime"} order by id asc,create_time asc + * {isAsc:"desc",orderByColumn:"id,createTime"} order by id desc,create_time desc + * {isAsc:"asc,desc",orderByColumn:"id,createTime"} order by id asc,create_time desc + */ + private List buildOrderItem() { + if (StringUtils.isBlank(orderByColumn) || StringUtils.isBlank(isAsc)) { + return null; + } + String orderBy = SqlUtil.escapeOrderBySql(orderByColumn); + orderBy = StringUtils.toUnderScoreCase(orderBy); + + // 兼容前端排序类型 + isAsc = StringUtils.replaceEach(isAsc, new String[]{"ascending", "descending"}, new String[]{"asc", "desc"}); + + String[] orderByArr = orderBy.split(StringUtils.SEPARATOR); + String[] isAscArr = isAsc.split(StringUtils.SEPARATOR); + if (isAscArr.length != 1 && isAscArr.length != orderByArr.length) { + throw new ServiceException("排序参数有误"); + } + + List list = new ArrayList<>(); + // 每个字段各自排序 + for (int i = 0; i < orderByArr.length; i++) { + String orderByStr = orderByArr[i]; + String isAscStr = isAscArr.length == 1 ? isAscArr[0] : isAscArr[i]; + if ("asc".equals(isAscStr)) { + list.add(OrderItem.asc(orderByStr)); + } else if ("desc".equals(isAscStr)) { + list.add(OrderItem.desc(orderByStr)); + } else { + throw new ServiceException("排序参数有误"); + } + } + return list; + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/domain/R.java b/cas-common/src/main/java/com/inscloudtech/common/core/domain/R.java new file mode 100644 index 0000000..38496cf --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/domain/R.java @@ -0,0 +1,103 @@ +package com.inscloudtech.common.core.domain; + +import com.inscloudtech.common.constant.HttpStatus; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 响应信息主体 + * + * @author inscloudtech + */ +@Data +@NoArgsConstructor +public class R implements Serializable { + private static final long serialVersionUID = 1L; + /** + * 成功 + */ + public static final int SUCCESS = 200; + /** + * 失败 + */ + public static final int FAIL = 500; + + private int code; + + private String msg; + + private T data; + + public static R ok() { + return restResult(null, SUCCESS, "操作成功"); + } + + public static R ok(T data) { + return restResult(data, SUCCESS, "操作成功"); + } + + public static R ok(String msg) { + return restResult(null, SUCCESS, msg); + } + + public static R ok(String msg, T data) { + return restResult(data, SUCCESS, msg); + } + + public static R fail() { + return restResult(null, FAIL, "操作失败"); + } + + public static R fail(String msg) { + return restResult(null, FAIL, msg); + } + + public static R fail(T data) { + return restResult(data, FAIL, "操作失败"); + } + + public static R fail(String msg, T data) { + return restResult(data, FAIL, msg); + } + + public static R fail(int code, String msg) { + return restResult(null, code, msg); + } + /** + * 返回警告消息 + * + * @param msg 返回内容 + * @return 警告消息 + */ + public static R warn(String msg) { + return restResult(null, HttpStatus.WARN, msg); + } + /** + * 返回警告消息 + * + * @param msg 返回内容 + * @param data 数据对象 + * @return 警告消息 + */ + public static R warn(String msg, T data) { + return restResult(data, HttpStatus.WARN, msg); + } + + private static R restResult(T data, int code, String msg) { + R r = new R<>(); + r.setCode(code); + r.setData(data); + r.setMsg(msg); + return r; + } + + public static Boolean isError(R ret) { + return !isSuccess(ret); + } + + public static Boolean isSuccess(R ret) { + return R.SUCCESS == ret.getCode(); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/domain/TreeEntity.java b/cas-common/src/main/java/com/inscloudtech/common/core/domain/TreeEntity.java new file mode 100644 index 0000000..041b341 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/domain/TreeEntity.java @@ -0,0 +1,36 @@ +package com.inscloudtech.common.core.domain; + +import com.baomidou.mybatisplus.annotation.TableField; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.ArrayList; +import java.util.List; + +/** + * Tree基类 + * + * @author inscloudtech + */ + +@Data +@EqualsAndHashCode(callSuper = true) +public class TreeEntity extends BaseEntity { + + private static final long serialVersionUID = 1L; + /** + * 父菜单名称 + */ + @TableField(exist = false) + private String parentName; + /** + * 父菜单ID + */ + private Long parentId; + /** + * 子部门 + */ + @TableField(exist = false) + private List children = new ArrayList<>(); + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/domain/dto/RoleDTO.java b/cas-common/src/main/java/com/inscloudtech/common/core/domain/dto/RoleDTO.java new file mode 100644 index 0000000..55e811c --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/domain/dto/RoleDTO.java @@ -0,0 +1,34 @@ +package com.inscloudtech.common.core.domain.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 角色 + * + * @author inscloudtech + */ + +@Data +@NoArgsConstructor +public class RoleDTO implements Serializable { + /** + * 角色ID + */ + private Long roleId; + /** + * 角色名称 + */ + private String roleName; + /** + * 角色权限 + */ + private String roleKey; + /** + * 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限) + */ + private String dataScope; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/domain/dto/UserOnlineDTO.java b/cas-common/src/main/java/com/inscloudtech/common/core/domain/dto/UserOnlineDTO.java new file mode 100644 index 0000000..b2725fe --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/domain/dto/UserOnlineDTO.java @@ -0,0 +1,52 @@ +package com.inscloudtech.common.core.domain.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 当前在线会话 + * + * @author inscloudtech + */ + +@Data +@NoArgsConstructor +public class UserOnlineDTO implements Serializable { + + private static final long serialVersionUID = 1L; + /** + * 会话编号 + */ + private String tokenId; + /** + * 部门名称 + */ + private String deptName; + /** + * 用户名称 + */ + private String userName; + /** + * 登录IP地址 + */ + private String ipaddr; + /** + * 登录地址 + */ + private String loginLocation; + /** + * 浏览器类型 + */ + private String browser; + /** + * 操作系统 + */ + private String os; + /** + * 登录时间 + */ + private Long loginTime; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/domain/entity/SysDept.java b/cas-common/src/main/java/com/inscloudtech/common/core/domain/entity/SysDept.java new file mode 100644 index 0000000..7bc8abe --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/domain/entity/SysDept.java @@ -0,0 +1,110 @@ +package com.inscloudtech.common.core.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.inscloudtech.common.annotation.UpdateValueLog; +import com.inscloudtech.common.core.domain.TreeEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.List; + +/** + * 部门表 sys_dept + * + * @author inscloudtech + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_dept") +public class SysDept extends TreeEntity { + private static final long serialVersionUID = 1L; + /** + * 部门ID + */ + @TableId(value = "dept_id") + private Long deptId; + /** + * 部门名称 + */ + @NotBlank(message = "单位名称不能为空") + @Size(min = 0, max = 30, message = "单位名称长度不能超过{max}个字符") + @UpdateValueLog(fieldName = "单位名称") + private String deptName; + + private String shortName; + + @NotBlank(message = "单位编码不能为空") + @Size(min = 0, max = 30, message = "单位编码长度不能超过{max}个字符") + @UpdateValueLog(fieldName = "单位编码") + private String deptCode; + + /** + * 部门名称 + */ +// @NotBlank(message = "机构类别不能为空") + @Size(min = 0, max = 30, message = "机构类别长度不能超过{max}个字符") + @UpdateValueLog(fieldName = "机构类别") + private String deptType; + + @TableField(exist = false) + private List deptTypeList; + + @TableField(exist = false) + private List deptCodeList; + /** + * 显示顺序 + */ + @NotNull(message = "显示顺序不能为空") + private Integer orderNum; + /** + * 负责人 + */ + @UpdateValueLog(fieldName = "负责人") + private String leader; + /** + * 联系电话 + */ + @Size(min = 0, max = 11, message = "联系电话长度不能超过{max}个字符") + @UpdateValueLog(fieldName = "联系电话") + private String phone; + /** + * 邮箱 + */ + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过{max}个字符") + @UpdateValueLog(fieldName = "联系电话") + private String email; + /** + * 部门状态:0正常,1停用 + */ + @UpdateValueLog(fieldName = "部门状态") + private String status; + /** + * 删除标志(0代表存在 2代表删除) + */ + @TableLogic + private String delFlag; + /** + * 祖级列表 + */ + private String ancestors; + /** + * 父菜单名称 + */ + @UpdateValueLog(fieldName = "上级部门") + private String parentName; + + /** + * 是否是erp单位 + */ + @UpdateValueLog(fieldName = "是否是erp单位") + private String erp; +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/domain/entity/SysDictData.java b/cas-common/src/main/java/com/inscloudtech/common/core/domain/entity/SysDictData.java new file mode 100644 index 0000000..921623c --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/domain/entity/SysDictData.java @@ -0,0 +1,109 @@ +package com.inscloudtech.common.core.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.inscloudtech.common.annotation.ExcelDictFormat; +import com.inscloudtech.common.annotation.Translation; +import com.inscloudtech.common.annotation.UpdateValueLog; +import com.inscloudtech.common.constant.TransConstant; +import com.inscloudtech.common.constant.UserConstants; +import com.inscloudtech.common.convert.ExcelDictConvert; +import com.inscloudtech.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; + +/** + * 字典数据表 sys_dict_data + * + * @author inscloudtech + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_dict_data") +@ExcelIgnoreUnannotated +public class SysDictData extends BaseEntity { + /** + * 字典编码 + */ + @ExcelProperty(value = "字典编码") + @TableId(value = "dict_code") + private Long dictCode; + /** + * 字典排序 + */ + @ExcelProperty(value = "字典排序") + @UpdateValueLog(fieldName = "字典排序") + private Integer dictSort; + /** + * 字典标签 + */ + @ExcelProperty(value = "字典标签") + @NotBlank(message = "字典标签不能为空") + @Size(min = 0, max = 100, message = "字典标签长度不能超过{max}个字符") + @UpdateValueLog(fieldName = "字典排序") + private String dictLabel; + /** + * 字典键值 + */ + @ExcelProperty(value = "字典键值") + @NotBlank(message = "字典键值不能为空") + @Size(min = 0, max = 100, message = "字典键值长度不能超过{max}个字符") + @UpdateValueLog(fieldName = "字典键值") + private String dictValue; + /** + * 字典类型 + */ + @ExcelProperty(value = "字典类型") + @NotBlank(message = "字典类型不能为空") + @Size(min = 0, max = 100, message = "字典类型长度不能超过{max}个字符") + private String dictType; + /** + * 样式属性(其他样式扩展) + */ + @Size(min = 0, max = 100, message = "样式属性长度不能超过{max}个字符") + @UpdateValueLog(fieldName = "样式属性") + private String cssClass; + /** + * 表格字典样式 + */ + @UpdateValueLog(fieldName = "表格字典样式") + private String listClass; + /** + * 是否默认(Y是 N否) + */ + @ExcelProperty(value = "是否默认", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_yes_no") + private String isDefault; + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + @UpdateValueLog(fieldName = "状态") + private String status; + /** + * 备注 + */ + @UpdateValueLog(fieldName = "remark") + private String remark; + + @Translation(type = TransConstant.USERNAME_TO_NICKNAME,mapper = "createBy") + @TableField(exist = false) + private String createByNickname; + + @Translation(type = TransConstant.USERNAME_TO_NICKNAME,mapper = "updateBy") + @TableField(exist = false) + private String updateByNickname; + + public boolean getDefault() { + return UserConstants.YES.equals(this.isDefault); + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/domain/entity/SysDictType.java b/cas-common/src/main/java/com/inscloudtech/common/core/domain/entity/SysDictType.java new file mode 100644 index 0000000..5855edd --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/domain/entity/SysDictType.java @@ -0,0 +1,74 @@ +package com.inscloudtech.common.core.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.inscloudtech.common.annotation.ExcelDictFormat; +import com.inscloudtech.common.annotation.UpdateValueLog; +import com.inscloudtech.common.convert.ExcelDictConvert; +import com.inscloudtech.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; + +/** + * 字典类型表 sys_dict_type + * + * @author inscloudtech + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_dict_type") +@ExcelIgnoreUnannotated +public class SysDictType extends BaseEntity { + /** + * 字典主键 + */ + @ExcelProperty(value = "字典主键") + @TableId(value = "dict_id") + private Long dictId; + /** + * 字典名称 + */ + @ExcelProperty(value = "字典名称") + @NotBlank(message = "字典名称不能为空") + @Size(min = 0, max = 100, message = "字典类型名称长度不能超过{max}个字符") + @UpdateValueLog(fieldName = "字典名称") + private String dictName; + /** + * 字典类型 + */ + @ExcelProperty(value = "字典类型") + @NotBlank(message = "字典类型不能为空") + @Size(min = 0, max = 100, message = "字典类型类型长度不能超过{max}个字符") + @Pattern(regexp = "^[a-z][a-z0-9_]*$", message = "字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)") + @UpdateValueLog(fieldName = "字典类型") + private String dictType; + /** + * 字典组名值 + */ + @ExcelProperty(value = "字典组名值") +// @NotBlank(message = "字典组名值不能为空") + @Size(min = 0, max = 100, message = "字典组名值类型长度不能超过{max}个字符") +// @Pattern(regexp = "^[a-z][a-z0-9_]*$", message = "字典组名值必须以字母开头,且只能为(小写字母,数字,下滑线)") + @UpdateValueLog(fieldName = "字典组名值") + private String dictGroupValue; + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + @UpdateValueLog(fieldName = "状态") + private String status; + /** + * 备注 + */ + @UpdateValueLog(fieldName = "备注") + private String remark; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/domain/entity/SysMenu.java b/cas-common/src/main/java/com/inscloudtech/common/core/domain/entity/SysMenu.java new file mode 100644 index 0000000..acc2245 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/domain/entity/SysMenu.java @@ -0,0 +1,90 @@ +package com.inscloudtech.common.core.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.inscloudtech.common.core.domain.TreeEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +/** + * 菜单权限表 sys_menu + * + * @author inscloudtech + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_menu") +public class SysMenu extends TreeEntity { + /** + * 菜单ID + */ + @TableId(value = "menu_id") + private Long menuId; + /** + * 菜单名称 + */ + @NotBlank(message = "菜单名称不能为空") + @Size(min = 0, max = 50, message = "菜单名称长度不能超过{max}个字符") + private String menuName; + /** + * 显示顺序 + */ + @NotNull(message = "显示顺序不能为空") + private Integer orderNum; + /** + * 路由地址 + */ + @Size(min = 0, max = 200, message = "路由地址不能超过{max}个字符") + private String path; + /** + * 组件路径 + */ + @Size(min = 0, max = 200, message = "组件路径不能超过{max}个字符") + private String component; + /** + * 路由参数 + */ + private String queryParam; + /** + * 是否为外链(0是 1否) + */ + private String isFrame; + /** + * 是否缓存(0缓存 1不缓存) + */ + private String isCache; + /** + * 类型(M目录 C菜单 F按钮) + */ + @NotBlank(message = "菜单类型不能为空") + private String menuType; + /** + * 显示状态(0显示 1隐藏) + */ + private String visible; + /** + * 菜单状态(0正常 1停用) + */ + private String status; + /** + * 权限字符串 + */ + @JsonInclude(JsonInclude.Include.NON_NULL) + @Size(min = 0, max = 100, message = "权限标识长度不能超过{max}个字符") + private String perms; + /** + * 菜单图标 + */ + private String icon; + /** + * 备注 + */ + private String remark; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/domain/entity/SysRole.java b/cas-common/src/main/java/com/inscloudtech/common/core/domain/entity/SysRole.java new file mode 100644 index 0000000..a5159f1 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/domain/entity/SysRole.java @@ -0,0 +1,124 @@ +package com.inscloudtech.common.core.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.inscloudtech.common.annotation.ExcelDictFormat; +import com.inscloudtech.common.annotation.UpdateValueLog; +import com.inscloudtech.common.constant.UserConstants; +import com.inscloudtech.common.convert.ExcelDictConvert; +import com.inscloudtech.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.List; + +/** + * 角色表 sys_role + * + * @author inscloudtech + */ + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@TableName("sys_role") +@ExcelIgnoreUnannotated +public class SysRole extends BaseEntity { + /** + * 角色ID + */ + @ExcelProperty(value = "角色序号") + @TableId(value = "role_id") + private Long roleId; + /** + * 角色名称 + */ + @ExcelProperty(value = "角色名称") + @NotBlank(message = "角色名称不能为空") + @Size(min = 0, max = 30, message = "角色名称长度不能超过{max}个字符") + @UpdateValueLog(fieldName = "角色名称") + private String roleName; + /** + * 角色权限 + */ + @ExcelProperty(value = "角色权限") + @NotBlank(message = "权限字符不能为空") + @Size(min = 0, max = 100, message = "权限字符长度不能超过{max}个字符") + @UpdateValueLog(fieldName = "角色权限") + private String roleKey; + /** + * 角色排序 + */ + @ExcelProperty(value = "角色排序") + @NotNull(message = "显示顺序不能为空") + @UpdateValueLog(fieldName = "角色权限") + private Integer roleSort; + /** + * 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限) + */ + @ExcelProperty(value = "数据范围", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限") + private String dataScope; + /** + * 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示) + */ + private Boolean menuCheckStrictly; + /** + * 部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示 ) + */ + private Boolean deptCheckStrictly; + /** + * 角色状态(0正常 1停用) + */ + @ExcelProperty(value = "角色状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + @UpdateValueLog(fieldName = "角色状态") + private String status; + /** + * 删除标志(0代表存在 2代表删除) + */ + @TableLogic + private String delFlag; + /** + * 备注 + */ + @UpdateValueLog(fieldName = "备注") + private String remark; + /** + * 用户是否存在此角色标识 默认不存在 + */ + @TableField(exist = false) + private boolean flag = false; + /** + * 菜单组 + */ + @TableField(exist = false) + private Long[] menuIds; + /** + * 菜单组 + */ + @TableField(exist = false) + @UpdateValueLog(fieldName = "菜单组") + private List menuNames; + /** + * 部门组(数据权限) + */ + @TableField(exist = false) + private Long[] deptIds; + + public SysRole(Long roleId) { + this.roleId = roleId; + } + + public boolean isAdmin() { + return UserConstants.ADMIN_ID.equals(this.roleId); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/domain/entity/SysUser.java b/cas-common/src/main/java/com/inscloudtech/common/core/domain/entity/SysUser.java new file mode 100644 index 0000000..cd514d4 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/domain/entity/SysUser.java @@ -0,0 +1,172 @@ +package com.inscloudtech.common.core.domain.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.inscloudtech.common.annotation.Sensitive; +import com.inscloudtech.common.annotation.UpdateValueLog; +import com.inscloudtech.common.annotation.UpdateValueLog; +import com.inscloudtech.common.constant.UserConstants; +import com.inscloudtech.common.core.domain.BaseEntity; +import com.inscloudtech.common.enums.SensitiveStrategy; +import com.inscloudtech.common.xss.Xss; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; +import java.util.Date; +import java.util.List; +import java.util.List; +/** + * 用户对象 sys_user + * + * @author inscloudtech + */ + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@TableName("sys_user") +public class SysUser extends BaseEntity { + /** + * 用户ID + */ + @TableId(value = "user_id") + private Long userId; + /** + * 部门ID + */ + private Long deptId; + + @TableField(exist = false) + @UpdateValueLog(fieldName = "所属部门") + private String deptName; + /** + * 用户账号 + */ + @Xss(message = "用户账号不能包含脚本字符") + @NotBlank(message = "用户账号不能为空") + @Size(min = 0, max = 30, message = "用户账号长度不能超过{max}个字符") + private String userName; + /** + * 用户昵称 + */ + @Xss(message = "用户昵称不能包含脚本字符") + @Size(min = 0, max = 30, message = "用户昵称长度不能超过{max}个字符") + @UpdateValueLog(fieldName = "用户昵称") + private String nickName; + /** + * 用户类型(sys_user系统用户) + */ + private String userType; + /** + * 用户邮箱 + */ +// @Sensitive(strategy = SensitiveStrategy.EMAIL) + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过{max}个字符") + @UpdateValueLog(fieldName = "邮箱") + private String email; + /** + * 手机号码 + */ +// @Sensitive(strategy = SensitiveStrategy.PHONE) + @UpdateValueLog(fieldName = "手机号码") + private String phonenumber; + /** + * 用户性别 + */ + @UpdateValueLog(fieldName = "用户性别") + private String sex; + /** + * 用户头像 + */ + private String avatar; + + private String frRole; + + /** + * 密码 + */ + @TableField( + insertStrategy = FieldStrategy.NOT_EMPTY, + updateStrategy = FieldStrategy.NOT_EMPTY, + whereStrategy = FieldStrategy.NOT_EMPTY + ) + private String password; + + @JsonIgnore + @JsonProperty + public String getPassword() { + return password; + } + /** + * 帐号状态(0正常 1停用) + */ + @UpdateValueLog(fieldName = "状态") + private String status; + /** + * 删除标志(0代表存在 2代表删除) + */ + @TableLogic + private String delFlag; + /** + * 最后登录IP + */ + private String loginIp; + /** + * 最后登录时间 + */ + private Date loginDate; + /** + * 备注 + */ + @UpdateValueLog(fieldName = "备注") + private String remark; + /** + * 部门对象 + */ + @TableField(exist = false) + private SysDept dept; + /** + * 角色对象 + */ + @TableField(exist = false) + private List roles; + /** + * 角色组 + */ + @TableField(exist = false) + private Long[] roleIds; + + @TableField(exist = false) + @UpdateValueLog(fieldName = "角色组") + private List roleNames; + /** + * 岗位组 + */ + @TableField(exist = false) +// @UpdateValueLog(fieldName = "岗位") + private Long[] postIds; + /** + * 数据权限 当前角色ID + */ + @TableField(exist = false) + private Long roleId; + + public SysUser(Long userId) { + this.userId = userId; + } + + public boolean isAdmin() { + return UserConstants.ADMIN_ID.equals(this.userId); + } + + @UpdateValueLog(fieldName = "备注") + private String idCardNo; + + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/domain/event/LogininforEvent.java b/cas-common/src/main/java/com/inscloudtech/common/core/domain/event/LogininforEvent.java new file mode 100644 index 0000000..10dbd78 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/domain/event/LogininforEvent.java @@ -0,0 +1,39 @@ +package com.inscloudtech.common.core.domain.event; + +import lombok.Data; + +import javax.servlet.http.HttpServletRequest; +import java.io.Serializable; + +/** + * 登录事件 + * + * @author inscloudtech + */ + +@Data +public class LogininforEvent implements Serializable { + + private static final long serialVersionUID = 1L; + /** + * 用户账号 + */ + private String username; + /** + * 登录状态 0成功 1失败 + */ + private String status; + /** + * 提示消息 + */ + private String message; + /** + * 请求体 + */ + private HttpServletRequest request; + /** + * 其他参数 + */ + private Object[] args; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/domain/event/OperLogEvent.java b/cas-common/src/main/java/com/inscloudtech/common/core/domain/event/OperLogEvent.java new file mode 100644 index 0000000..53240e7 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/domain/event/OperLogEvent.java @@ -0,0 +1,100 @@ +package com.inscloudtech.common.core.domain.event; + +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * 操作日志事件 + * + * @author inscloudtech + */ + +@Data +public class OperLogEvent implements Serializable { + + private static final long serialVersionUID = 1L; + /** + * 日志主键 + */ + private Long operId; + /** + * 操作模块 + */ + private String title; + /** + * 业务类型(0其它 1新增 2修改 3删除) + */ + private Integer businessType; + /** + * 业务类型数组 + */ + private Integer[] businessTypes; + /** + * 请求方法 + */ + private String method; + /** + * 请求方式 + */ + private String requestMethod; + /** + * 操作类别(0其它 1后台用户 2手机端用户) + */ + private Integer operatorType; + /** + * 操作人员 + */ + private String operName; + /** + * 部门名称 + */ + private String deptName; + /** + * 请求url + */ + private String operUrl; + /** + * 操作地址 + */ + private String operIp; + /** + * 操作地点 + */ + private String operLocation; + /** + * 请求参数 + */ + private String operParam; + /** + * 返回参数 + */ + private String jsonResult; + /** + * 操作状态(0正常 1异常) + */ + private Integer status; + /** + * 错误消息 + */ + private String errorMsg; + /** + * 操作时间 + */ + private Date operTime; + /** + * 更新前值 + */ + private String beforeValue; + + /** + * 更新新后 + */ + private String afterValue; + + /** + * 更新新后 + */ + private Long businessId; +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/domain/model/EmailLoginBody.java b/cas-common/src/main/java/com/inscloudtech/common/core/domain/model/EmailLoginBody.java new file mode 100644 index 0000000..105ab55 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/domain/model/EmailLoginBody.java @@ -0,0 +1,28 @@ +package com.inscloudtech.common.core.domain.model; + +import lombok.Data; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; + +/** + * 短信登录对象 + * + * @author inscloudtech + */ + +@Data +public class EmailLoginBody { + /** + * 邮箱 + */ + @NotBlank(message = "{user.email.not.blank}") + @Email(message = "{user.email.not.valid}") + private String email; + /** + * 邮箱code + */ + @NotBlank(message = "{email.code.not.blank}") + private String emailCode; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/domain/model/LoginBody.java b/cas-common/src/main/java/com/inscloudtech/common/core/domain/model/LoginBody.java new file mode 100644 index 0000000..89a14fa --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/domain/model/LoginBody.java @@ -0,0 +1,42 @@ +package com.inscloudtech.common.core.domain.model; + +import com.inscloudtech.common.constant.UserConstants; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotBlank; + +/** + * 用户登录对象 + * + * @author inscloudtech + */ + +@Data +public class LoginBody { + /** + * 用户名 + */ + @NotBlank(message = "{user.username.not.blank}") + @Length(min = UserConstants.USERNAME_MIN_LENGTH, max = UserConstants.USERNAME_MAX_LENGTH, message = "{user.username.length.valid}") + private String username; + /** + * 用户密码 + */ +// @NotBlank(message = "{user.password.not.blank}") +// @Length(min = UserConstants.PASSWORD_MIN_LENGTH, max = UserConstants.PASSWORD_MAX_LENGTH, message = "{user.password.length.valid}") + private String password; + /** + * 验证码 + */ + private String code; + /** + * 唯一标识 + */ + private String uuid; + + private String role; + + + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/domain/model/LoginUser.java b/cas-common/src/main/java/com/inscloudtech/common/core/domain/model/LoginUser.java new file mode 100644 index 0000000..66c4464 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/domain/model/LoginUser.java @@ -0,0 +1,109 @@ +package com.inscloudtech.common.core.domain.model; + +import com.inscloudtech.common.core.domain.dto.RoleDTO; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; +import java.util.Set; + +/** + * 登录用户身份权限 + * + * @author inscloudtech + */ + +@Data +@NoArgsConstructor +public class LoginUser implements Serializable { + + private static final long serialVersionUID = 1L; + /** + * 用户ID + */ + private Long userId; + /** + * 部门ID + */ + private Long deptId; + + /** + * 部门ID + */ + private String deptCode; + + /** + * 部门名 + */ + private String deptName; + /** + * 用户唯一标识 + */ + private String token; + /** + * 用户类型 + */ + private String userType; + /** + * 登录时间 + */ + private Long loginTime; + /** + * 过期时间 + */ + private Long expireTime; + /** + * 登录IP地址 + */ + private String ipaddr; + /** + * 登录地点 + */ + private String loginLocation; + /** + * 浏览器类型 + */ + private String browser; + /** + * 操作系统 + */ + private String os; + /** + * 菜单权限 + */ + private Set menuPermission; + /** + * 角色权限 + */ + private Set rolePermission; + /** + * 用户名 + */ + private String username; + /** + * 角色对象 + */ + private List roles; + /** + * 数据权限 当前角色ID + */ + private Long roleId; + /** + * 获取登录id + */ + public String getLoginId() { + if (userType == null) { + throw new IllegalArgumentException("用户类型不能为空"); + } + if (userId == null) { + throw new IllegalArgumentException("用户ID不能为空"); + } + return userType + ":" + userId; + } + /** + * nickname + */ + private String nickname; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/domain/model/RegisterBody.java b/cas-common/src/main/java/com/inscloudtech/common/core/domain/model/RegisterBody.java new file mode 100644 index 0000000..1bd6f56 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/domain/model/RegisterBody.java @@ -0,0 +1,17 @@ +package com.inscloudtech.common.core.domain.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户注册对象 + * + * @author inscloudtech + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class RegisterBody extends LoginBody { + + private String userType; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/domain/model/SmsLoginBody.java b/cas-common/src/main/java/com/inscloudtech/common/core/domain/model/SmsLoginBody.java new file mode 100644 index 0000000..d4be8d7 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/domain/model/SmsLoginBody.java @@ -0,0 +1,26 @@ +package com.inscloudtech.common.core.domain.model; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/** + * 短信登录对象 + * + * @author inscloudtech + */ + +@Data +public class SmsLoginBody { + /** + * 手机号 + */ + @NotBlank(message = "{user.phonenumber.not.blank}") + private String phonenumber; + /** + * 短信code + */ + @NotBlank(message = "{sms.code.not.blank}") + private String smsCode; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/domain/model/XcxLoginUser.java b/cas-common/src/main/java/com/inscloudtech/common/core/domain/model/XcxLoginUser.java new file mode 100644 index 0000000..d8ee4f3 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/domain/model/XcxLoginUser.java @@ -0,0 +1,23 @@ +package com.inscloudtech.common.core.domain.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 小程序登录用户身份权限 + * + * @author inscloudtech + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +public class XcxLoginUser extends LoginUser { + + private static final long serialVersionUID = 1L; + /** + * openid + */ + private String openid; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/mapper/BaseMapperPlus.java b/cas-common/src/main/java/com/inscloudtech/common/core/mapper/BaseMapperPlus.java new file mode 100644 index 0000000..7aab49c --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/mapper/BaseMapperPlus.java @@ -0,0 +1,179 @@ +package com.inscloudtech.common.core.mapper; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.*; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.toolkit.Db; +import com.inscloudtech.common.utils.BeanCopyUtils; +import org.apache.ibatis.logging.Log; +import org.apache.ibatis.logging.LogFactory; + +import java.io.Serializable; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 自定义 Mapper 接口, 实现 自定义扩展 + * + * @param mapper 泛型 + * @param table 泛型 + * @param vo 泛型 + * @author inscloudtech + * @since 2021-05-13 + */ +@SuppressWarnings("unchecked") +public interface BaseMapperPlus extends BaseMapper { + + Log log = LogFactory.getLog(BaseMapperPlus.class); + + default Class currentVoClass() { + return (Class) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseMapperPlus.class, 2); + } + + default Class currentModelClass() { + return (Class) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseMapperPlus.class, 1); + } + + default Class currentMapperClass() { + return (Class) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseMapperPlus.class, 0); + } + + default List selectList() { + return this.selectList(new QueryWrapper<>()); + } + /** + * 批量插入 + */ + default boolean insertBatch(Collection entityList) { + return Db.saveBatch(entityList); + } + /** + * 批量更新 + */ + default boolean updateBatchById(Collection entityList) { + return Db.updateBatchById(entityList); + } + /** + * 批量插入或更新 + */ + default boolean insertOrUpdateBatch(Collection entityList) { + return Db.saveOrUpdateBatch(entityList); + } + /** + * 批量插入(包含限制条数) + */ + default boolean insertBatch(Collection entityList, int batchSize) { + return Db.saveBatch(entityList, batchSize); + } + /** + * 批量更新(包含限制条数) + */ + default boolean updateBatchById(Collection entityList, int batchSize) { + return Db.updateBatchById(entityList, batchSize); + } + /** + * 批量插入或更新(包含限制条数) + */ + default boolean insertOrUpdateBatch(Collection entityList, int batchSize) { + return Db.saveOrUpdateBatch(entityList, batchSize); + } + /** + * 插入或更新(包含限制条数) + */ + default boolean insertOrUpdate(T entity) { + return Db.saveOrUpdate(entity); + } + + default V selectVoById(Serializable id) { + return selectVoById(id, this.currentVoClass()); + } + /** + * 根据 ID 查询 + */ + default C selectVoById(Serializable id, Class voClass) { + T obj = this.selectById(id); + if (ObjectUtil.isNull(obj)) { + return null; + } + return BeanCopyUtils.copy(obj, voClass); + } + + default List selectVoBatchIds(Collection idList) { + return selectVoBatchIds(idList, this.currentVoClass()); + } + /** + * 查询(根据ID 批量查询) + */ + default List selectVoBatchIds(Collection idList, Class voClass) { + List list = this.selectBatchIds(idList); + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + return BeanCopyUtils.copyList(list, voClass); + } + + default List selectVoByMap(Map map) { + return selectVoByMap(map, this.currentVoClass()); + } + /** + * 查询(根据 columnMap 条件) + */ + default List selectVoByMap(Map map, Class voClass) { + List list = this.selectByMap(map); + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + return BeanCopyUtils.copyList(list, voClass); + } + + default V selectVoOne(Wrapper wrapper) { + return selectVoOne(wrapper, this.currentVoClass()); + } + /** + * 根据 entity 条件,查询一条记录 + */ + default C selectVoOne(Wrapper wrapper, Class voClass) { + T obj = this.selectOne(wrapper); + if (ObjectUtil.isNull(obj)) { + return null; + } + return BeanCopyUtils.copy(obj, voClass); + } + + default List selectVoList(Wrapper wrapper) { + return selectVoList(wrapper, this.currentVoClass()); + } + /** + * 根据 entity 条件,查询全部记录 + */ + default List selectVoList(Wrapper wrapper, Class voClass) { + List list = this.selectList(wrapper); + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + return BeanCopyUtils.copyList(list, voClass); + } + + default

> P selectVoPage(IPage page, Wrapper wrapper) { + return selectVoPage(page, wrapper, this.currentVoClass()); + } + /** + * 分页查询VO + */ + default > P selectVoPage(IPage page, Wrapper wrapper, Class voClass) { + IPage pageData = this.selectPage(page, wrapper); + IPage voPage = new Page<>(pageData.getCurrent(), pageData.getSize(), pageData.getTotal()); + if (CollUtil.isEmpty(pageData.getRecords())) { + return (P) voPage; + } + voPage.setRecords(BeanCopyUtils.copyList(pageData.getRecords(), voClass)); + return (P) voPage; + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/page/TableDataInfo.java b/cas-common/src/main/java/com/inscloudtech/common/core/page/TableDataInfo.java new file mode 100644 index 0000000..9a36644 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/page/TableDataInfo.java @@ -0,0 +1,73 @@ +package com.inscloudtech.common.core.page; + +import cn.hutool.http.HttpStatus; +import com.baomidou.mybatisplus.core.metadata.IPage; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; + +/** + * 表格分页数据对象 + * + * @author inscloudtech + */ + +@Data +@NoArgsConstructor +public class TableDataInfo implements Serializable { + private static final long serialVersionUID = 1L; + /** + * 总记录数 + */ + private long total; + /** + * 列表数据 + */ + private List rows; + /** + * 消息状态码 + */ + private int code; + /** + * 消息内容 + */ + private String msg; + /** + * 分页 + * + * @param list 列表数据 + * @param total 总记录数 + */ + public TableDataInfo(List list, long total) { + this.rows = list; + this.total = total; + } + + public static TableDataInfo build(IPage page) { + TableDataInfo rspData = new TableDataInfo<>(); + rspData.setCode(HttpStatus.HTTP_OK); + rspData.setMsg("查询成功"); + rspData.setRows(page.getRecords()); + rspData.setTotal(page.getTotal()); + return rspData; + } + + public static TableDataInfo build(List list) { + TableDataInfo rspData = new TableDataInfo<>(); + rspData.setCode(HttpStatus.HTTP_OK); + rspData.setMsg("查询成功"); + rspData.setRows(list); + rspData.setTotal(list.size()); + return rspData; + } + + public static TableDataInfo build() { + TableDataInfo rspData = new TableDataInfo<>(); + rspData.setCode(HttpStatus.HTTP_OK); + rspData.setMsg("查询成功"); + return rspData; + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/service/ConfigService.java b/cas-common/src/main/java/com/inscloudtech/common/core/service/ConfigService.java new file mode 100644 index 0000000..fd05ef0 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/service/ConfigService.java @@ -0,0 +1,17 @@ +package com.inscloudtech.common.core.service; + +/** + * 通用 参数配置服务 + * + * @author inscloudtech + */ +public interface ConfigService { + /** + * 根据参数 key 获取参数值 + * + * @param configKey 参数 key + * @return 参数值 + */ + String getConfigValue(String configKey); + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/service/DeptService.java b/cas-common/src/main/java/com/inscloudtech/common/core/service/DeptService.java new file mode 100644 index 0000000..3672aba --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/service/DeptService.java @@ -0,0 +1,17 @@ +package com.inscloudtech.common.core.service; + +/** + * 通用 部门服务 + * + * @author inscloudtech + */ +public interface DeptService { + /** + * 通过部门ID查询部门名称 + * + * @param deptIds 部门ID串逗号分隔 + * @return 部门名称串逗号分隔 + */ + String selectDeptNameByIds(String deptIds); + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/service/DictService.java b/cas-common/src/main/java/com/inscloudtech/common/core/service/DictService.java new file mode 100644 index 0000000..3b43375 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/service/DictService.java @@ -0,0 +1,52 @@ +package com.inscloudtech.common.core.service; + +/** + * 通用 字典服务 + * + * @author inscloudtech + */ +public interface DictService { + /** + * 分隔符 + */ + String SEPARATOR = ","; + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @return 字典标签 + */ + default String getDictLabel(String dictType, String dictValue) { + return getDictLabel(dictType, dictValue, SEPARATOR); + } + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @return 字典值 + */ + default String getDictValue(String dictType, String dictLabel) { + return getDictValue(dictType, dictLabel, SEPARATOR); + } + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @param separator 分隔符 + * @return 字典标签 + */ + String getDictLabel(String dictType, String dictValue, String separator); + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @param separator 分隔符 + * @return 字典值 + */ + String getDictValue(String dictType, String dictLabel, String separator); + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/service/OssService.java b/cas-common/src/main/java/com/inscloudtech/common/core/service/OssService.java new file mode 100644 index 0000000..4c7d575 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/service/OssService.java @@ -0,0 +1,17 @@ +package com.inscloudtech.common.core.service; + +/** + * 通用 OSS服务 + * + * @author inscloudtech + */ +public interface OssService { + /** + * 通过ossId查询对应的url + * + * @param ossIds ossId串逗号分隔 + * @return url串逗号分隔 + */ + String selectUrlByIds(String ossIds); + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/service/SensitiveService.java b/cas-common/src/main/java/com/inscloudtech/common/core/service/SensitiveService.java new file mode 100644 index 0000000..6a11e00 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/service/SensitiveService.java @@ -0,0 +1,17 @@ +package com.inscloudtech.common.core.service; + +/** + * 脱敏服务 + * 默认管理员不过滤 + * 需自行根据业务重写实现 + * + * @author inscloudtech + * @version 3.6.0 + */ +public interface SensitiveService { + /** + * 是否脱敏 + */ + boolean isSensitive(); + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/service/UserService.java b/cas-common/src/main/java/com/inscloudtech/common/core/service/UserService.java new file mode 100644 index 0000000..83b6068 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/service/UserService.java @@ -0,0 +1,20 @@ +package com.inscloudtech.common.core.service; + +/** + * 通用 用户服务 + * + * @author inscloudtech + */ +public interface UserService { + /** + * 通过用户ID查询用户账户 + * + * @param userId 用户ID + * @return 用户账户 + */ + String selectUserNameById(Long userId); + + + String selectNicknameByUserName(String username); + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/validate/AddGroup.java b/cas-common/src/main/java/com/inscloudtech/common/core/validate/AddGroup.java new file mode 100644 index 0000000..d77191a --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/validate/AddGroup.java @@ -0,0 +1,9 @@ +package com.inscloudtech.common.core.validate; + +/** + * 校验分组 add + * + * @author inscloudtech + */ +public interface AddGroup { +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/validate/EditGroup.java b/cas-common/src/main/java/com/inscloudtech/common/core/validate/EditGroup.java new file mode 100644 index 0000000..056481d --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/validate/EditGroup.java @@ -0,0 +1,9 @@ +package com.inscloudtech.common.core.validate; + +/** + * 校验分组 edit + * + * @author inscloudtech + */ +public interface EditGroup { +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/core/validate/QueryGroup.java b/cas-common/src/main/java/com/inscloudtech/common/core/validate/QueryGroup.java new file mode 100644 index 0000000..86a735b --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/core/validate/QueryGroup.java @@ -0,0 +1,9 @@ +package com.inscloudtech.common.core.validate; + +/** + * 校验分组 query + * + * @author inscloudtech + */ +public interface QueryGroup { +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/encrypt/EncryptContext.java b/cas-common/src/main/java/com/inscloudtech/common/encrypt/EncryptContext.java new file mode 100644 index 0000000..fbbf622 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/encrypt/EncryptContext.java @@ -0,0 +1,36 @@ +package com.inscloudtech.common.encrypt; + +import com.inscloudtech.common.enums.AlgorithmType; +import com.inscloudtech.common.enums.EncodeType; +import lombok.Data; + +/** + * 加密上下文 用于encryptor传递必要的参数。 + * + * @author inscloudtech + * @version 4.6.0 + */ +@Data +public class EncryptContext { + /** + * 默认算法 + */ + private AlgorithmType algorithm; + /** + * 安全秘钥 + */ + private String password; + /** + * 公钥 + */ + private String publicKey; + /** + * 私钥 + */ + private String privateKey; + /** + * 编码方式,base64/hex + */ + private EncodeType encode; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/encrypt/IEncryptor.java b/cas-common/src/main/java/com/inscloudtech/common/encrypt/IEncryptor.java new file mode 100644 index 0000000..6aabb96 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/encrypt/IEncryptor.java @@ -0,0 +1,32 @@ +package com.inscloudtech.common.encrypt; + +import com.inscloudtech.common.enums.AlgorithmType; +import com.inscloudtech.common.enums.EncodeType; + +/** + * 加解者 + * + * @author inscloudtech + * @version 4.6.0 + */ +public interface IEncryptor { + /** + * 获得当前算法 + */ + AlgorithmType algorithm(); + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + * @return 加密后的字符串 + */ + String encrypt(String value, EncodeType encodeType); + /** + * 解密 + * + * @param value 待加密字符串 + * @return 解密后的字符串 + */ + String decrypt(String value); +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/encrypt/encryptor/AbstractEncryptor.java b/cas-common/src/main/java/com/inscloudtech/common/encrypt/encryptor/AbstractEncryptor.java new file mode 100644 index 0000000..50cb143 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/encrypt/encryptor/AbstractEncryptor.java @@ -0,0 +1,18 @@ +package com.inscloudtech.common.encrypt.encryptor; + +import com.inscloudtech.common.encrypt.EncryptContext; +import com.inscloudtech.common.encrypt.IEncryptor; + +/** + * 所有加密执行者的基类 + * + * @author inscloudtech + * @version 4.6.0 + */ +public abstract class AbstractEncryptor implements IEncryptor { + + public AbstractEncryptor(EncryptContext context) { + // 用户配置校验与配置注入 + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/encrypt/encryptor/AesEncryptor.java b/cas-common/src/main/java/com/inscloudtech/common/encrypt/encryptor/AesEncryptor.java new file mode 100644 index 0000000..5d83f05 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/encrypt/encryptor/AesEncryptor.java @@ -0,0 +1,66 @@ +package com.inscloudtech.common.encrypt.encryptor; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.symmetric.AES; +import com.inscloudtech.common.encrypt.EncryptContext; +import com.inscloudtech.common.enums.AlgorithmType; +import com.inscloudtech.common.enums.EncodeType; + +import java.nio.charset.StandardCharsets; + +/** + * AES算法实现 + * + * @author inscloudtech + * @version 4.6.0 + */ +public class AesEncryptor extends AbstractEncryptor { + + private final AES aes; + + public AesEncryptor(EncryptContext context) { + super(context); + String password = context.getPassword(); + if (StrUtil.isBlank(password)) { + throw new IllegalArgumentException("AES没有获得秘钥信息"); + } + // aes算法的秘钥要求是16位、24位、32位 + int[] array = {16, 24, 32}; + if (!ArrayUtil.contains(array, password.length())) { + throw new IllegalArgumentException("AES秘钥长度应该为16位、24位、32位,实际为" + password.length() + "位"); + } + aes = SecureUtil.aes(context.getPassword().getBytes(StandardCharsets.UTF_8)); + } + /** + * 获得当前算法 + */ + @Override + public AlgorithmType algorithm() { + return AlgorithmType.AES; + } + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + */ + @Override + public String encrypt(String value, EncodeType encodeType) { + if (encodeType == EncodeType.HEX) { + return aes.encryptHex(value); + } else { + return aes.encryptBase64(value); + } + } + /** + * 解密 + * + * @param value 待加密字符串 + */ + @Override + public String decrypt(String value) { + return this.aes.decryptStr(value); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/encrypt/encryptor/Base64Encryptor.java b/cas-common/src/main/java/com/inscloudtech/common/encrypt/encryptor/Base64Encryptor.java new file mode 100644 index 0000000..a47f173 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/encrypt/encryptor/Base64Encryptor.java @@ -0,0 +1,45 @@ +package com.inscloudtech.common.encrypt.encryptor; + +import cn.hutool.core.codec.Base64; +import com.inscloudtech.common.encrypt.EncryptContext; +import com.inscloudtech.common.enums.AlgorithmType; +import com.inscloudtech.common.enums.EncodeType; + +/** + * Base64算法实现 + * + * @author inscloudtech + * @version 4.6.0 + */ +public class Base64Encryptor extends AbstractEncryptor { + + public Base64Encryptor(EncryptContext context) { + super(context); + } + /** + * 获得当前算法 + */ + @Override + public AlgorithmType algorithm() { + return AlgorithmType.BASE64; + } + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + */ + @Override + public String encrypt(String value, EncodeType encodeType) { + return Base64.encode(value); + } + /** + * 解密 + * + * @param value 待加密字符串 + */ + @Override + public String decrypt(String value) { + return Base64.decodeStr(value); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/encrypt/encryptor/RsaEncryptor.java b/cas-common/src/main/java/com/inscloudtech/common/encrypt/encryptor/RsaEncryptor.java new file mode 100644 index 0000000..24313fb --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/encrypt/encryptor/RsaEncryptor.java @@ -0,0 +1,62 @@ +package com.inscloudtech.common.encrypt.encryptor; + +import cn.hutool.core.codec.Base64; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.RSA; +import com.inscloudtech.common.encrypt.EncryptContext; +import com.inscloudtech.common.enums.AlgorithmType; +import com.inscloudtech.common.enums.EncodeType; +import com.inscloudtech.common.utils.StringUtils; + + +/** + * RSA算法实现 + * + * @author inscloudtech + * @version 4.6.0 + */ +public class RsaEncryptor extends AbstractEncryptor { + + private final RSA rsa; + + public RsaEncryptor(EncryptContext context) { + super(context); + String privateKey = context.getPrivateKey(); + String publicKey = context.getPublicKey(); + if (StringUtils.isAnyEmpty(privateKey, publicKey)) { + throw new IllegalArgumentException("RSA公私钥均需要提供,公钥加密,私钥解密。"); + } + this.rsa = SecureUtil.rsa(Base64.decode(privateKey), Base64.decode(publicKey)); + } + /** + * 获得当前算法 + */ + @Override + public AlgorithmType algorithm() { + return AlgorithmType.RSA; + } + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + */ + @Override + public String encrypt(String value, EncodeType encodeType) { + if (encodeType == EncodeType.HEX) { + return rsa.encryptHex(value, KeyType.PublicKey); + } else { + return rsa.encryptBase64(value, KeyType.PublicKey); + } + } + /** + * 解密 + * + * @param value 待加密字符串 + */ + @Override + public String decrypt(String value) { + return this.rsa.decryptStr(value, KeyType.PrivateKey); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/encrypt/encryptor/Sm2Encryptor.java b/cas-common/src/main/java/com/inscloudtech/common/encrypt/encryptor/Sm2Encryptor.java new file mode 100644 index 0000000..6f2e7fa --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/encrypt/encryptor/Sm2Encryptor.java @@ -0,0 +1,62 @@ +package com.inscloudtech.common.encrypt.encryptor; + + +import cn.hutool.core.codec.Base64; +import cn.hutool.crypto.SmUtil; +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.SM2; +import com.inscloudtech.common.encrypt.EncryptContext; +import com.inscloudtech.common.enums.AlgorithmType; +import com.inscloudtech.common.enums.EncodeType; +import com.inscloudtech.common.utils.StringUtils; + +/** + * sm2算法实现 + * + * @author inscloudtech + * @version 4.6.0 + */ +public class Sm2Encryptor extends AbstractEncryptor { + + private final SM2 sm2; + + public Sm2Encryptor(EncryptContext context) { + super(context); + String privateKey = context.getPrivateKey(); + String publicKey = context.getPublicKey(); + if (StringUtils.isAnyEmpty(privateKey, publicKey)) { + throw new IllegalArgumentException("SM2公私钥均需要提供,公钥加密,私钥解密。"); + } + this.sm2 = SmUtil.sm2(Base64.decode(privateKey), Base64.decode(publicKey)); + } + /** + * 获得当前算法 + */ + @Override + public AlgorithmType algorithm() { + return AlgorithmType.SM2; + } + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + */ + @Override + public String encrypt(String value, EncodeType encodeType) { + if (encodeType == EncodeType.HEX) { + return sm2.encryptHex(value, KeyType.PublicKey); + } else { + return sm2.encryptBase64(value, KeyType.PublicKey); + } + } + /** + * 解密 + * + * @param value 待加密字符串 + */ + @Override + public String decrypt(String value) { + return this.sm2.decryptStr(value, KeyType.PrivateKey); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/encrypt/encryptor/Sm4Encryptor.java b/cas-common/src/main/java/com/inscloudtech/common/encrypt/encryptor/Sm4Encryptor.java new file mode 100644 index 0000000..2c3cbe3 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/encrypt/encryptor/Sm4Encryptor.java @@ -0,0 +1,64 @@ +package com.inscloudtech.common.encrypt.encryptor; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SmUtil; +import cn.hutool.crypto.symmetric.SM4; +import com.inscloudtech.common.encrypt.EncryptContext; +import com.inscloudtech.common.enums.AlgorithmType; +import com.inscloudtech.common.enums.EncodeType; + +import java.nio.charset.StandardCharsets; + +/** + * sm4算法实现 + * + * @author inscloudtech + * @version 4.6.0 + */ +public class Sm4Encryptor extends AbstractEncryptor { + + private final SM4 sm4; + + public Sm4Encryptor(EncryptContext context) { + super(context); + String password = context.getPassword(); + if (StrUtil.isBlank(password)) { + throw new IllegalArgumentException("SM4没有获得秘钥信息"); + } + // sm4算法的秘钥要求是16位长度 + if (16 != password.length()) { + throw new IllegalArgumentException("SM4秘钥长度应该为16位,实际为" + password.length() + "位"); + } + this.sm4 = SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8)); + } + /** + * 获得当前算法 + */ + @Override + public AlgorithmType algorithm() { + return AlgorithmType.SM4; + } + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + */ + @Override + public String encrypt(String value, EncodeType encodeType) { + if (encodeType == EncodeType.HEX) { + return sm4.encryptHex(value); + } else { + return sm4.encryptBase64(value); + } + } + /** + * 解密 + * + * @param value 待加密字符串 + */ + @Override + public String decrypt(String value) { + return this.sm4.decryptStr(value); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/enums/AlgorithmType.java b/cas-common/src/main/java/com/inscloudtech/common/enums/AlgorithmType.java new file mode 100644 index 0000000..d74bd89 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/enums/AlgorithmType.java @@ -0,0 +1,42 @@ +package com.inscloudtech.common.enums; + +import com.inscloudtech.common.encrypt.encryptor.*; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 算法名称 + * + * @author inscloudtech + * @version 4.6.0 + */ +@Getter +@AllArgsConstructor +public enum AlgorithmType { + /** + * 默认走yml配置 + */ + DEFAULT(null), + /** + * base64 + */ + BASE64(Base64Encryptor.class), + /** + * aes + */ + AES(AesEncryptor.class), + /** + * rsa + */ + RSA(RsaEncryptor.class), + /** + * sm2 + */ + SM2(Sm2Encryptor.class), + /** + * sm4 + */ + SM4(Sm4Encryptor.class); + + private final Class clazz; +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/enums/BusinessStatus.java b/cas-common/src/main/java/com/inscloudtech/common/enums/BusinessStatus.java new file mode 100644 index 0000000..765a3fd --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/enums/BusinessStatus.java @@ -0,0 +1,16 @@ +package com.inscloudtech.common.enums; + +/** + * 操作状态 + * + * @author inscloudtech + */ +public enum BusinessStatus { /** + * 成功 + */ + SUCCESS, + /** + * 失败 + */ + FAIL, +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/enums/BusinessType.java b/cas-common/src/main/java/com/inscloudtech/common/enums/BusinessType.java new file mode 100644 index 0000000..bf7bd8a --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/enums/BusinessType.java @@ -0,0 +1,48 @@ +package com.inscloudtech.common.enums; + +/** + * 业务操作类型 + * + * @author inscloudtech + */ +public enum BusinessType { /** + * 其它 + */ + OTHER, + /** + * 新增 + */ + INSERT, + /** + * 修改 + */ + UPDATE, + /** + * 删除 + */ + DELETE, + /** + * 授权 + */ + GRANT, + /** + * 导出 + */ + EXPORT, + /** + * 导入 + */ + IMPORT, + /** + * 强退 + */ + FORCE, + /** + * 生成代码 + */ + GENCODE, + /** + * 清空数据 + */ + CLEAN, +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/enums/CaptchaCategory.java b/cas-common/src/main/java/com/inscloudtech/common/enums/CaptchaCategory.java new file mode 100644 index 0000000..fdbabf8 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/enums/CaptchaCategory.java @@ -0,0 +1,32 @@ +package com.inscloudtech.common.enums; + +import cn.hutool.captcha.AbstractCaptcha; +import cn.hutool.captcha.CircleCaptcha; +import cn.hutool.captcha.LineCaptcha; +import cn.hutool.captcha.ShearCaptcha; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 验证码类别 + * + * @author inscloudtech + */ +@Getter +@AllArgsConstructor +public enum CaptchaCategory { + /** + * 线段干扰 + */ + LINE(LineCaptcha.class), + /** + * 圆圈干扰 + */ + CIRCLE(CircleCaptcha.class), + /** + * 扭曲干扰 + */ + SHEAR(ShearCaptcha.class); + + private final Class clazz; +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/enums/CaptchaType.java b/cas-common/src/main/java/com/inscloudtech/common/enums/CaptchaType.java new file mode 100644 index 0000000..d45a136 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/enums/CaptchaType.java @@ -0,0 +1,27 @@ +package com.inscloudtech.common.enums; + +import cn.hutool.captcha.generator.CodeGenerator; +import cn.hutool.captcha.generator.RandomGenerator; +import com.inscloudtech.common.captcha.UnsignedMathGenerator; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 验证码类型 + * + * @author inscloudtech + */ +@Getter +@AllArgsConstructor +public enum CaptchaType { + /** + * 数字 + */ + MATH(UnsignedMathGenerator.class), + /** + * 字符 + */ + CHAR(RandomGenerator.class); + + private final Class clazz; +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/enums/DataBaseType.java b/cas-common/src/main/java/com/inscloudtech/common/enums/DataBaseType.java new file mode 100644 index 0000000..043642f --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/enums/DataBaseType.java @@ -0,0 +1,45 @@ +package com.inscloudtech.common.enums; + +import com.inscloudtech.common.utils.StringUtils; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 数据库类型 + * + * @author inscloudtech + */ +@Getter +@AllArgsConstructor +public enum DataBaseType { + /** + * MySQL + */ + MY_SQL("MySQL"), + /** + * Oracle + */ + ORACLE("Oracle"), + /** + * PostgreSQL + */ + POSTGRE_SQL("PostgreSQL"), + /** + * SQL Server + */ + SQL_SERVER("Microsoft SQL Server"); + + private final String type; + + public static DataBaseType find(String databaseProductName) { + if (StringUtils.isBlank(databaseProductName)) { + return null; + } + for (DataBaseType type : values()) { + if (type.getType().equals(databaseProductName)) { + return type; + } + } + return null; + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/enums/DataScopeType.java b/cas-common/src/main/java/com/inscloudtech/common/enums/DataScopeType.java new file mode 100644 index 0000000..eb0f849 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/enums/DataScopeType.java @@ -0,0 +1,65 @@ +package com.inscloudtech.common.enums; + +import com.inscloudtech.common.utils.StringUtils; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 数据权限类型 + *

+ * 语法支持 spel 模板表达式 + *

+ * 内置数据 user 当前用户 内容参考 LoginUser + * 如需扩展数据 可使用 {@link com.inscloudtech.common.helper.DataPermissionHelper} 操作 + * 内置服务 sdss 系统数据权限服务 内容参考 SysDataScopeService + * 如需扩展更多自定义服务 可以参考 sdss 自行编写 + * + * @author inscloudtech + * @version 3.5.0 + */ +@Getter +@AllArgsConstructor +public enum DataScopeType { + /** + * 全部数据权限 + */ + ALL("1", "", ""), + /** + * 自定数据权限 + */ + CUSTOM("2", " #{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} ) ", ""), + /** + * 部门数据权限 + */ + DEPT("3", " #{#deptName} = #{#user.deptId} ", ""), + /** + * 部门及以下数据权限 + */ + DEPT_AND_CHILD("4", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} )", ""), + /** + * 仅本人数据权限 + */ + SELF("5", " #{#userName} = #{#user.userId} ", " 1 = 0 "); + + private final String code; + /** + * 语法 采用 spel 模板表达式 + */ + private final String sqlTemplate; + /** + * 不满足 sqlTemplate 则填充 + */ + private final String elseSql; + + public static DataScopeType findCode(String code) { + if (StringUtils.isBlank(code)) { + return null; + } + for (DataScopeType type : values()) { + if (type.getCode().equals(code)) { + return type; + } + } + return null; + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/enums/DeviceType.java b/cas-common/src/main/java/com/inscloudtech/common/enums/DeviceType.java new file mode 100644 index 0000000..c4d08d1 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/enums/DeviceType.java @@ -0,0 +1,29 @@ +package com.inscloudtech.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 设备类型 + * 针对一套 用户体系 + * + * @author inscloudtech + */ +@Getter +@AllArgsConstructor +public enum DeviceType { + /** + * pc端 + */ + PC("pc"), + /** + * app端 + */ + APP("app"), + /** + * 小程序端 + */ + XCX("xcx"); + + private final String device; +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/enums/EncodeType.java b/cas-common/src/main/java/com/inscloudtech/common/enums/EncodeType.java new file mode 100644 index 0000000..04e57eb --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/enums/EncodeType.java @@ -0,0 +1,23 @@ +package com.inscloudtech.common.enums; + +/** + * 编码类型 + * + * @author inscloudtech + * @version 4.6.0 + */ +public enum EncodeType { + /** + * 默认使用yml配置 + */ + DEFAULT, + /** + * base64编码 + */ + BASE64, + /** + * 16进制编码 + */ + HEX; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/enums/HttpMethod.java b/cas-common/src/main/java/com/inscloudtech/common/enums/HttpMethod.java new file mode 100644 index 0000000..ac50936 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/enums/HttpMethod.java @@ -0,0 +1,32 @@ +package com.inscloudtech.common.enums; + +import org.springframework.lang.Nullable; + +import java.util.HashMap; +import java.util.Map; + +/** + * 请求方式 + * + * @author inscloudtech + */ +public enum HttpMethod { + GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE; + + private static final Map mappings = new HashMap<>(16); + + static { + for (HttpMethod httpMethod : values()) { + mappings.put(httpMethod.name(), httpMethod); + } + } + + @Nullable + public static HttpMethod resolve(@Nullable String method) { + return (method != null ? mappings.get(method) : null); + } + + public boolean matches(String method) { + return (this == resolve(method)); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/enums/LimitType.java b/cas-common/src/main/java/com/inscloudtech/common/enums/LimitType.java new file mode 100644 index 0000000..5a29737 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/enums/LimitType.java @@ -0,0 +1,21 @@ +package com.inscloudtech.common.enums; + +/** + * 限流类型 + * + * @author inscloudtech + */ + +public enum LimitType { /** + * 默认策略全局限流 + */ + DEFAULT, + /** + * 根据请求者IP进行限流 + */ + IP, + /** + * 实例限流(集群多后端实例) + */ + CLUSTER +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/enums/LoginType.java b/cas-common/src/main/java/com/inscloudtech/common/enums/LoginType.java new file mode 100644 index 0000000..eaf1781 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/enums/LoginType.java @@ -0,0 +1,38 @@ +package com.inscloudtech.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 登录类型 + * + * @author inscloudtech + */ +@Getter +@AllArgsConstructor +public enum LoginType { + /** + * 密码登录 + */ + PASSWORD("user.password.retry.limit.exceed", "user.password.retry.limit.count"), + /** + * 短信登录 + */ + SMS("sms.code.retry.limit.exceed", "sms.code.retry.limit.count"), + /** + * 邮箱登录 + */ + EMAIL("email.code.retry.limit.exceed", "email.code.retry.limit.count"), + /** + * 小程序登录 + */ + XCX("", ""); + /** + * 登录重试超出限制提示 + */ + final String retryLimitExceed; + /** + * 登录重试限制计数提示 + */ + final String retryLimitCount; +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/enums/OperatorType.java b/cas-common/src/main/java/com/inscloudtech/common/enums/OperatorType.java new file mode 100644 index 0000000..4f08595 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/enums/OperatorType.java @@ -0,0 +1,20 @@ +package com.inscloudtech.common.enums; + +/** + * 操作人类别 + * + * @author inscloudtech + */ +public enum OperatorType { /** + * 其它 + */ + OTHER, + /** + * 后台用户 + */ + MANAGE, + /** + * 手机端用户 + */ + MOBILE +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/enums/SensitiveStrategy.java b/cas-common/src/main/java/com/inscloudtech/common/enums/SensitiveStrategy.java new file mode 100644 index 0000000..9f8fcf7 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/enums/SensitiveStrategy.java @@ -0,0 +1,44 @@ +package com.inscloudtech.common.enums; + +import cn.hutool.core.util.DesensitizedUtil; +import lombok.AllArgsConstructor; + +import java.util.function.Function; + +/** + * 脱敏策略 + * + * @author Yjoioooo + * @version 3.6.0 + */ +@AllArgsConstructor +public enum SensitiveStrategy { + /** + * 身份证脱敏 + */ + ID_CARD(s -> DesensitizedUtil.idCardNum(s, 3, 4)), + /** + * 手机号脱敏 + */ + PHONE(DesensitizedUtil::mobilePhone), + /** + * 地址脱敏 + */ + ADDRESS(s -> DesensitizedUtil.address(s, 8)), + /** + * 邮箱脱敏 + */ + EMAIL(DesensitizedUtil::email), + /** + * 银行卡 + */ + BANK_CARD(DesensitizedUtil::bankCard); + + //可自行添加其他脱敏策略 + + private final Function desensitizer; + + public Function desensitizer() { + return desensitizer; + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/enums/UserStatus.java b/cas-common/src/main/java/com/inscloudtech/common/enums/UserStatus.java new file mode 100644 index 0000000..bc45c74 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/enums/UserStatus.java @@ -0,0 +1,26 @@ +package com.inscloudtech.common.enums; + +/** + * 用户状态 + * + * @author inscloudtech + */ +public enum UserStatus { + OK("0", "正常"), DISABLE("1", "停用"), DELETED("2", "删除"); + + private final String code; + private final String info; + + UserStatus(String code, String info) { + this.code = code; + this.info = info; + } + + public String getCode() { + return code; + } + + public String getInfo() { + return info; + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/enums/UserType.java b/cas-common/src/main/java/com/inscloudtech/common/enums/UserType.java new file mode 100644 index 0000000..257c1a9 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/enums/UserType.java @@ -0,0 +1,35 @@ +package com.inscloudtech.common.enums; + +import com.inscloudtech.common.utils.StringUtils; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 设备类型 + * 针对多套 用户体系 + * + * @author inscloudtech + */ +@Getter +@AllArgsConstructor +public enum UserType { + /** + * pc端 + */ + SYS_USER("sys_user"), + /** + * app端 + */ + APP_USER("app_user"); + + private final String userType; + + public static UserType getUserType(String str) { + for (UserType value : values()) { + if (StringUtils.contains(str, value.getUserType())) { + return value; + } + } + throw new RuntimeException("'UserType' not found By " + str); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/excel/CellMergeStrategy.java b/cas-common/src/main/java/com/inscloudtech/common/excel/CellMergeStrategy.java new file mode 100644 index 0000000..02eabe6 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/excel/CellMergeStrategy.java @@ -0,0 +1,393 @@ +package com.inscloudtech.common.excel; + +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.merge.AbstractMergeStrategy; +import com.inscloudtech.common.annotation.CellMerge; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.util.CellRangeAddress; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 列值重复合并策略 + * + * @author inscloudtech + */ +@AllArgsConstructor +@Slf4j +public class CellMergeStrategy extends AbstractMergeStrategy { + + private List list; + // 行合并开始下标 + private int mergeStartRowIndex; +// CellRangeAddress cellRangeAddress = new CellRangeAddress(1, 3, 4, 4); + //单元格合并区域,从第 2 行到第 4 行(起始行为 1,终止行为 3),第 5 列到第 5 列(起始列为 4,终止列也为 4)。 + + @Override + protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { + List cellList = handle4Json(list, mergeStartRowIndex); + // judge the list is not null + if (CollectionUtils.isNotEmpty(cellList)) { + // the judge is necessary + if (cell.getRowIndex() == mergeStartRowIndex + 1 && cell.getColumnIndex() == 0) { + /** + * 保证每个cell被合并一次,如果不加上面的判断,因为是一个cell一个cell操作的, + * 例如合并A2:A3,当cell为A2时,合并A2,A3,但是当cell为A3时,又是合并A2,A3, + * 但此时A2,A3已经是合并的单元格了 + */ + for (CellRangeAddress item : cellList) { + try { + sheet.addMergedRegion(item); + }catch (Exception e){ + e.printStackTrace(); + } + } + } + } + } + + @SneakyThrows + private static List handle(List rows,int mergeStartRowIndex) { + List cellList = new ArrayList<>(); + if (CollectionUtils.isEmpty(rows)) { + return cellList; + } + Class clazz = rows.get(0).getClass(); + Field[] fields = clazz.getDeclaredFields(); + // 有注解的字段 + List mergeFields = new ArrayList<>(); + List mergeFieldsIndex = new ArrayList<>(); + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + if (field.isAnnotationPresent(CellMerge.class)) { + CellMerge cm = field.getAnnotation(CellMerge.class); + mergeFields.add(field); + mergeFieldsIndex.add(cm.index() == -1 ? i : cm.index()); + } + } + // 行合并开始下标 + Map map = new HashMap<>(); + // 生成两两合并单元格 + for (int i = 0; i < rows.size(); i++) { + Map valueAndColNum = new HashMap<>(); + Object rowObj = rows.get(i); + for (int currentColNum = 0; currentColNum < mergeFields.size(); currentColNum++) { + Field field = mergeFields.get(currentColNum); + String name = field.getName(); + String methodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1); + Method readMethod = clazz.getMethod(methodName); + Object val = readMethod.invoke(rowObj); + + //不同行上下相邻单元格合并 + int colNum = mergeFieldsIndex.get(currentColNum); + if (!map.containsKey(field)) { + map.put(field, new RepeatCell(val, i)); + } else { + RepeatCell repeatCell = map.get(field); + Object historyValue = repeatCell.getValue(); + if (historyValue == null || "".equals(historyValue)) { + // 空值跳过不合并 + continue; + } +// CellRangeAddress(int firstRow, int lastRow, int firstCol, int lastCol) { + if (!historyValue.equals(val)) { + if (i - repeatCell.getCurrent() > 1) { + cellList.add(new CellRangeAddress(repeatCell.getCurrent() + mergeStartRowIndex, i + mergeStartRowIndex - 1, colNum, colNum)); + } + map.put(field, new RepeatCell(val, i)); + } else if (i == rows.size() - 1) { + if (i > repeatCell.getCurrent()) { + cellList.add(new CellRangeAddress(repeatCell.getCurrent() + mergeStartRowIndex, i + mergeStartRowIndex, colNum, colNum)); + } + } + } + + //同行相邻单元格合并 + if (valueAndColNum.containsKey(val.toString())) { + int preCol = valueAndColNum.get(val.toString()); + int currentRowIndex = i + mergeStartRowIndex; + boolean needAdd = true; + // 合并相同内容的单元格 + for (CellRangeAddress cellAddresses : cellList) { + if(cellAddresses.getFirstRow() == currentRowIndex + && cellAddresses.getLastColumn() == colNum -1){//如果是当前行,并且相邻那就一直替换 + cellAddresses.setLastColumn(colNum); + needAdd = false; + } + } + if(needAdd){ + cellList.add(new CellRangeAddress(currentRowIndex, currentRowIndex , preCol, colNum)); + } + } else { + valueAndColNum.put(val.toString(), currentColNum); + } + } + } + return cellList; + } + + @SneakyThrows + private static List handle4Json(List rows,int mergeStartRowIndex) { + List cellRowRangeList = new ArrayList<>(); + List cellColRangeList = new ArrayList<>(); + List cellJsonList = new ArrayList<>(); + if (CollectionUtils.isEmpty(rows)) { + return null; + } + + List tempRow = (List)rows.get(0); + // 有注解的字段 + List mergeFields = new ArrayList<>(); + for (JSONObject cell : tempRow) { + if(cell.containsKey("merge")){ + String field = cell.getStr("field"); + mergeFields.add(field); + } + } + + // 行合并开始下标 + Map rowMergeMap = new HashMap<>(); + //,会多次合并添加合计 + Set hasAdd = new HashSet<>(); + Map hasOther = new HashMap<>(); + // 生成两两合并单元格 + for (int currentRowNum = 0; currentRowNum < rows.size(); currentRowNum++) { + Map valueAndColNum = new HashMap<>(); + List row = (List)rows.get(currentRowNum); + for (int currentColNum = 0; currentColNum < mergeFields.size(); currentColNum++) { + String field = mergeFields.get(currentColNum); + String currentVal = ""; + for (JSONObject cell : row) { + if (cell.getStr("field").equals(field)) { + currentVal = cell.getStr("value"); + } + } + + //不同行上下相邻单元格合并 + //同行相邻单元格合并 + if (valueAndColNum.containsKey(currentVal)) { + int preCol = valueAndColNum.get(currentVal); + int currentRowIndex = currentRowNum + mergeStartRowIndex; + boolean needAdd = true; + // 合并相同内容的单元格 + for (CellRangeAddress cellAddresses : cellColRangeList) { + if(cellAddresses.getFirstRow() == currentRowIndex + && cellAddresses.getLastColumn() == currentColNum -1 ){//如果是当前行,并且相邻那就一直替换 + //再比较前后两列格子的值是否相等 + String lastColValue = row.get(currentColNum - 1).getStr("value"); + if(lastColValue.equals(currentVal)){ + cellAddresses.setLastColumn(currentColNum); + } + + needAdd = false; + } + } + if(needAdd && currentColNum >= preCol){ + cellColRangeList.add(new CellRangeAddress(currentRowIndex, currentRowIndex , preCol, currentColNum)); + } + } else { + valueAndColNum.put(currentVal, currentColNum); + } + + //行合并 + if (!rowMergeMap.containsKey(field) && !(currentVal.contains("合计") || currentVal.contains("小计"))) { + rowMergeMap.put(field, new RepeatCell(currentVal, currentRowNum)); + String key = field + currentVal; + hasOther.put(key,hasOther.getOrDefault(key,0) + 1); + } else { + if(!rowMergeMap.containsKey(field)){ + continue; + } + RepeatCell repeatCell = rowMergeMap.get(field); + Object historyValue = repeatCell.getValue(); + if (historyValue == null || "".equals(historyValue)) { + // 空值跳过不合并 + continue; + } + if (!historyValue.equals(currentVal)) { + boolean hasRemove = false; + if (currentRowNum - repeatCell.getCurrent() > 1) { + //要把这行给列合并,会多次添加合计 + //&& //记录至少有两行才合并 + if(!hasAdd.contains(field+historyValue+repeatCell.getCurrent()) && hasOther.getOrDefault(field+historyValue,0) > 1){ + int firstRow = repeatCell.getCurrent() + mergeStartRowIndex; + int lastRow = currentRowNum + mergeStartRowIndex - 1; + int firstCol = currentColNum; + int lastCol = currentColNum; + JSONObject cellJson = new JSONObject(); + cellJson.putOpt("firstRow",firstRow); + cellJson.putOpt("lastRow",lastRow); + cellJson.putOpt("firstCol",firstCol); + cellJson.putOpt("lastCol",lastCol); + cellJsonList.add(cellJson); + cellRowRangeList.add(new CellRangeAddress(firstRow ,lastRow, firstCol, lastCol)); + hasAdd.add(field+historyValue+repeatCell.getCurrent());//不同行,出现相同值情况解决 + hasOther.remove(field+historyValue);//合并了就移除相同计数 + rowMergeMap.remove(field); + hasRemove = true; + } + }else { + hasOther.remove(field+historyValue); + String key = field + currentVal; + hasOther.put(key,hasOther.getOrDefault(key,0) + 1); + } + //不包含 合计,小计 + if(!(currentVal.contains("合计") || currentVal.contains("小计"))){ + rowMergeMap.put(field, new RepeatCell(currentVal, currentRowNum)); + if(hasRemove){//放的必须上上一行发生或合并的 + String key = field + currentVal; + hasOther.put(key,hasOther.getOrDefault(key,0) + 1); + }else{ + hasOther.remove(field+historyValue);//上下行不一样,移除掉,不留 + } + }else{ + //出现小计,合计行,移除之前记录需要合并行信息 + rowMergeMap.remove(field); + hasOther.remove(field+historyValue);//上下行不一样,移除掉,不留 + } + } else if (currentRowNum == rows.size() - 1) { + if (currentRowNum > repeatCell.getCurrent()) { + int firstRow = repeatCell.getCurrent() + mergeStartRowIndex; + int lastRow = currentRowNum + mergeStartRowIndex; + int firstCol = currentColNum; + int lastCol = currentColNum; + JSONObject cellJson = new JSONObject(); + cellJson.putOpt("firstRow",firstRow); + cellJson.putOpt("lastRow",lastRow); + cellJson.putOpt("firstCol",firstCol); + cellJson.putOpt("lastCol",lastCol); + cellJsonList.add(cellJson); + cellRowRangeList.add(new CellRangeAddress(firstRow ,lastRow, firstCol, lastCol)); + } + }else {//记录至少有两行才合并 + String key = field + historyValue; + hasOther.put(key,hasOther.getOrDefault(key,0) + 1); + } + } + } + } + Map result = new HashMap(); + result.put("cellRowRangeList",cellRowRangeList); + result.put("cellColRangeList",cellColRangeList); + result.put("cellJsonList",cellJsonList); + List newRowRangeList = handleMergeList(cellRowRangeList); + List allCellRangeList = new ArrayList<>(); + allCellRangeList.addAll(cellColRangeList); + allCellRangeList.addAll(newRowRangeList); + return allCellRangeList; + } + + @Data + @AllArgsConstructor + static class RepeatCell { + + private Object value; + + private int current; + + } + + + static List handleMergeList(List cellAddressesList){ +// //按第一列排序 + List sortedList = cellAddressesList.stream().sorted(Comparator.comparingInt(CellRangeAddress::getFirstColumn)).collect(Collectors.toList()); + List newCAList = new ArrayList<>(); + Map> groupedByFirstCol = newCAList.stream().collect(Collectors.groupingBy(CellRangeAddress::getFirstColumn)); + for (CellRangeAddress currentCell : sortedList) { + int firstColumn = currentCell.getFirstColumn(); + if (firstColumn == 0) { + groupedByFirstCol = addAndGroupBy(newCAList,currentCell); + continue; + } + //从第二列开始需要判断,行合并,不能超过前一列的,超过就以前一列为准 + int currentLastRow = currentCell.getLastRow(); + + //当前的第一个,也必须小于等于前一个合并格子的第一行 + int currentFirstRow = currentCell.getFirstRow(); + //前一列 或着第一 + List parentCells = groupedByFirstCol.get(firstColumn -1); + if (CollectionUtils.isEmpty(parentCells)) { + continue; + } + + CellRangeAddress newCellRangeAddress = new CellRangeAddress(currentFirstRow,currentLastRow,firstColumn,currentCell.getLastColumn()); + for (CellRangeAddress parentCell : parentCells) { + Integer parentFirstRow = parentCell.getFirstRow(); + Integer parentLastRow = parentCell.getLastRow(); + if(currentFirstRow >= parentFirstRow && currentLastRow <= parentLastRow){//最后一行小于等于父级,是有效的合并格子 + groupedByFirstCol = addAndGroupBy(newCAList,newCellRangeAddress); + break; + } + + if(parentLastRow >= currentFirstRow && parentLastRow <= currentLastRow){//当前合并单元格的第一行,大于或者等于父级的第一行,最后一行小于等于父亲最后一行才是真的parent + if(currentLastRow <= parentLastRow){//最后一行小于等于父级,是有效的合并格子 + groupedByFirstCol = addAndGroupBy(newCAList,newCellRangeAddress); + break; + } + //当前的第一行,到最后一行要包含父级的最后一样才是父级 + if(currentLastRow > parentLastRow ){//最后一行大于父级 + int between = currentLastRow - parentLastRow; + newCellRangeAddress.setLastRow(currentLastRow); + groupedByFirstCol = addAndGroupBy(newCAList,newCellRangeAddress); + if(between == 1){//取父级的最后一行为当前行的lastRow,原来的下一个格子就一个,不需要新增合并格子 + break; + }else if(between > 1){//原来的合并格子多于1行,还需要再增加合并格子 + //新一个合并单元格开始,然后再找他的父亲看有没有合并单元 + int newFistRow = parentLastRow + 1; + int newLastRow = parentLastRow + between; + if (checkHasParent(parentCells,newFistRow,newLastRow)) { + CellRangeAddress other = new CellRangeAddress(newFistRow,newLastRow,firstColumn,currentCell.getLastColumn()); + groupedByFirstCol = addAndGroupBy(newCAList,other); + break; + }else{ + break; + } + } + } + } + } + } + return newCAList; + } + + static Map> addAndGroupBy(List newCAList,CellRangeAddress cellAddresses){ + newCAList.add(cellAddresses); + return newCAList.stream().collect(Collectors.groupingBy(CellRangeAddress::getFirstColumn)); + } + + static boolean checkHasParent(List parentCells,int currentFirstRow,int currentLastRow){ + for (CellRangeAddress parentCell : parentCells) { + Integer parentFirstRow = parentCell.getFirstRow(); + Integer parentLastRow = parentCell.getLastRow(); + if(currentFirstRow >= parentFirstRow && currentLastRow <= parentLastRow) {//当前合并单元格的第一行,大于或者等于父级的第一行,才是真的parent + return true; + } + } + return false; + } + public static void main(String[] args) { + String a = "[{\"firstRow\":3,\"lastRow\":4,\"firstCol\":1,\"lastCol\":1}, {\"firstRow\":3,\"lastRow\":4,\"firstCol\":2,\"lastCol\":2}, {\"firstRow\":3,\"lastRow\":4,\"firstCol\":3,\"lastCol\":3}, {\"firstRow\":3,\"lastRow\":4,\"firstCol\":5,\"lastCol\":5}, {\"firstRow\":3,\"lastRow\":5,\"firstCol\":0,\"lastCol\":0}, {\"firstRow\":3,\"lastRow\":5,\"firstCol\":7,\"lastCol\":7}, {\"firstRow\":6,\"lastRow\":8,\"firstCol\":0,\"lastCol\":0}, {\"firstRow\":6,\"lastRow\":8,\"firstCol\":1,\"lastCol\":1}, {\"firstRow\":7,\"lastRow\":8,\"firstCol\":2,\"lastCol\":2}, {\"firstRow\":7,\"lastRow\":8,\"firstCol\":3,\"lastCol\":3}, {\"firstRow\":3,\"lastRow\":7,\"firstCol\":4,\"lastCol\":4}]"; + List cellJsonList = JSONUtil.toList(a,JSONObject.class); + String b = "[{\"firstRow\":3,\"lastRow\":4,\"firstCol\":4,\"lastCol\":4}, {\"firstRow\":3,\"lastRow\":4,\"firstCol\":5,\"lastCol\":5}, {\"firstRow\":3,\"lastRow\":4,\"firstCol\":7,\"lastCol\":7}, {\"firstRow\":3,\"lastRow\":5,\"firstCol\":3,\"lastCol\":3}, {\"firstRow\":3,\"lastRow\":6,\"firstCol\":2,\"lastCol\":2}, {\"firstRow\":3,\"lastRow\":7,\"firstCol\":1,\"lastCol\":1}, {\"firstRow\":8,\"lastRow\":9,\"firstCol\":3,\"lastCol\":3}, {\"firstRow\":8,\"lastRow\":10,\"firstCol\":2,\"lastCol\":2}, {\"firstRow\":8,\"lastRow\":11,\"firstCol\":1,\"lastCol\":1}, {\"firstRow\":3,\"lastRow\":12,\"firstCol\":0,\"lastCol\":0}, {\"firstRow\":13,\"lastRow\":14,\"firstCol\":3,\"lastCol\":3}, {\"firstRow\":13,\"lastRow\":15,\"firstCol\":2,\"lastCol\":2}, {\"firstRow\":16,\"lastRow\":18,\"firstCol\":3,\"lastCol\":3}, {\"firstRow\":16,\"lastRow\":19,\"firstCol\":2,\"lastCol\":2}, {\"firstRow\":13,\"lastRow\":20,\"firstCol\":1,\"lastCol\":1}, {\"firstRow\":13,\"lastRow\":21,\"firstCol\":0,\"lastCol\":0}]"; + cellJsonList = JSONUtil.toList(b,JSONObject.class); + + List cellAddressesList = new ArrayList<>(); + for (JSONObject cellJson : cellJsonList) { + CellRangeAddress cellAddresses = new CellRangeAddress(cellJson.getInt("firstRow"),cellJson.getInt("lastRow"),cellJson.getInt("firstCol"),cellJson.getInt("lastCol")); + cellAddressesList.add(cellAddresses); + } + List newCAList = handleMergeList(cellAddressesList); + newCAList.size(); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/excel/DefaultExcelListener.java b/cas-common/src/main/java/com/inscloudtech/common/excel/DefaultExcelListener.java new file mode 100644 index 0000000..5eb8ad7 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/excel/DefaultExcelListener.java @@ -0,0 +1,102 @@ +package com.inscloudtech.common.excel; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.exception.ExcelDataConvertException; +import com.inscloudtech.common.utils.JsonUtils; +import com.inscloudtech.common.utils.StreamUtils; +import com.inscloudtech.common.utils.ValidatorUtils; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import java.util.Map; +import java.util.Set; + +/** + * Excel 导入监听 + * + * @author Yjoioooo + * @author inscloudtech + */ +@Slf4j +@NoArgsConstructor +public class DefaultExcelListener extends AnalysisEventListener implements ExcelListener { + /** + * 是否Validator检验,默认为是 + */ + private Boolean isValidate = Boolean.TRUE; + /** + * excel 表头数据 + */ + private Map headMap; + /** + * 导入回执 + */ + private ExcelResult excelResult; + + public DefaultExcelListener(boolean isValidate) { + this.excelResult = new DefaultExcelResult<>(); + this.isValidate = isValidate; + } + /** + * 处理异常 + * + * @param exception ExcelDataConvertException + * @param context Excel 上下文 + */ + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + String errMsg = null; + if (exception instanceof ExcelDataConvertException) { + // 如果是某一个单元格的转换异常 能获取到具体行号 + ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception; + Integer rowIndex = excelDataConvertException.getRowIndex(); + Integer columnIndex = excelDataConvertException.getColumnIndex(); + errMsg = StrUtil.format("第{}行-第{}列-表头{}: 解析异常
", + rowIndex + 1, columnIndex + 1, headMap.get(columnIndex)); + if (log.isDebugEnabled()) { + log.error(errMsg); + } + } + if (exception instanceof ConstraintViolationException) { + ConstraintViolationException constraintViolationException = (ConstraintViolationException) exception; + Set> constraintViolations = constraintViolationException.getConstraintViolations(); + String constraintViolationsMsg = StreamUtils.join(constraintViolations, ConstraintViolation::getMessage, ", "); + errMsg = StrUtil.format("第{}行数据校验异常: {}", context.readRowHolder().getRowIndex() + 1, constraintViolationsMsg); + if (log.isDebugEnabled()) { + log.error(errMsg); + } + } + excelResult.getErrorList().add(errMsg); + throw new ExcelAnalysisException(errMsg); + } + + @Override + public void invokeHeadMap(Map headMap, AnalysisContext context) { + this.headMap = headMap; + log.debug("解析到一条表头数据: {}", JsonUtils.toJsonString(headMap)); + } + + @Override + public void invoke(T data, AnalysisContext context) { + if (isValidate) { + ValidatorUtils.validate(data); + } + excelResult.getList().add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + log.debug("所有数据解析完成!"); + } + + @Override + public ExcelResult getExcelResult() { + return excelResult; + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/excel/DefaultExcelResult.java b/cas-common/src/main/java/com/inscloudtech/common/excel/DefaultExcelResult.java new file mode 100644 index 0000000..466fddf --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/excel/DefaultExcelResult.java @@ -0,0 +1,70 @@ +package com.inscloudtech.common.excel; + +import cn.hutool.core.util.StrUtil; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +/** + * 默认excel返回对象 + * + * @author Yjoioooo + * @author inscloudtech + */ +public class DefaultExcelResult implements ExcelResult { + /** + * 数据对象list + */ + @Setter + private List list; + /** + * 错误信息列表 + */ + @Setter + private List errorList; + + public DefaultExcelResult() { + this.list = new ArrayList<>(); + this.errorList = new ArrayList<>(); + } + + public DefaultExcelResult(List list, List errorList) { + this.list = list; + this.errorList = errorList; + } + + public DefaultExcelResult(ExcelResult excelResult) { + this.list = excelResult.getList(); + this.errorList = excelResult.getErrorList(); + } + + @Override + public List getList() { + return list; + } + + @Override + public List getErrorList() { + return errorList; + } + /** + * 获取导入回执 + * + * @return 导入回执 + */ + @Override + public String getAnalysis() { + int successCount = list.size(); + int errorCount = errorList.size(); + if (successCount == 0) { + return "读取失败,未解析到数据"; + } else { + if (errorCount == 0) { + return StrUtil.format("恭喜您,全部读取成功!共{}条", successCount); + } else { + return ""; + } + } + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/excel/ExcelListener.java b/cas-common/src/main/java/com/inscloudtech/common/excel/ExcelListener.java new file mode 100644 index 0000000..6a96a6f --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/excel/ExcelListener.java @@ -0,0 +1,14 @@ +package com.inscloudtech.common.excel; + +import com.alibaba.excel.read.listener.ReadListener; + +/** + * Excel 导入监听 + * + * @author inscloudtech + */ +public interface ExcelListener extends ReadListener { + + ExcelResult getExcelResult(); + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/excel/ExcelResult.java b/cas-common/src/main/java/com/inscloudtech/common/excel/ExcelResult.java new file mode 100644 index 0000000..25845db --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/excel/ExcelResult.java @@ -0,0 +1,23 @@ +package com.inscloudtech.common.excel; + +import java.util.List; + +/** + * excel返回对象 + * + * @author inscloudtech + */ +public interface ExcelResult { + /** + * 对象列表 + */ + List getList(); + /** + * 错误列表 + */ + List getErrorList(); + /** + * 导入回执 + */ + String getAnalysis(); +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/excel/MyLongestMatchColumnWidthStyleStrategy.java b/cas-common/src/main/java/com/inscloudtech/common/excel/MyLongestMatchColumnWidthStyleStrategy.java new file mode 100644 index 0000000..2aa3e8a --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/excel/MyLongestMatchColumnWidthStyleStrategy.java @@ -0,0 +1,91 @@ +package com.inscloudtech.common.excel; + +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.util.MapUtils; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.poi.ss.usermodel.Cell; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +public class MyLongestMatchColumnWidthStyleStrategy extends AbstractColumnWidthStyleStrategy { + private static final int MAX_COLUMN_WIDTH = 255; + private final Map> cache = MapUtils.newHashMapWithExpectedSize(8); + + public MyLongestMatchColumnWidthStyleStrategy() { + } + + protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList); + if (needSetWidth) { + Map maxColumnWidthMap = (Map)this.cache.computeIfAbsent(writeSheetHolder.getSheetNo(), (key) -> { + return new HashMap(16); + }); + Integer columnWidth = this.dataLength(cellDataList, cell, isHead); + if (columnWidth >= 0) { + if (columnWidth > 255) { + columnWidth = 255; + } + + Integer maxColumnWidth = (Integer)maxColumnWidthMap.get(cell.getColumnIndex()); + if (maxColumnWidth == null || columnWidth > maxColumnWidth) { + maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth); + writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), columnWidth * 256); + } + + } + } + } + + private Integer dataLength(List> cellDataList, Cell cell, Boolean isHead) { + if (isHead) { + return cell.getStringCellValue().getBytes().length; + } else { + Integer result = 0; + WriteCellData cellData = (WriteCellData)cellDataList.get(0); + CellDataTypeEnum type = cellData.getType(); + if (type == null) { + return -1; + } else { + switch(type) { + case STRING: + result = cellData.getStringValue().getBytes().length; + if(isInteger(cellData.getStringValue())){ + if(result > 10){ + result = (int)(result * 0.96); + } + }else { + if(result > 10){ + result = (int)(result * 0.68); + } + } + break; + case BOOLEAN: + result = cellData.getBooleanValue().toString().getBytes().length; + break; + case NUMBER: + result = cellData.getNumberValue().toString().getBytes().length; + break; + case DATE: + result = cellData.getDateValue().toString().getBytes().length; + break; + default: + break; + } + } + return result; //实际计算出来的宽度度在excel不适合 + } + } + + public static boolean isInteger(String str) { + Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$"); + return pattern.matcher(str).matches(); + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/exception/DemoModeException.java b/cas-common/src/main/java/com/inscloudtech/common/exception/DemoModeException.java new file mode 100644 index 0000000..f2ed023 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/exception/DemoModeException.java @@ -0,0 +1,13 @@ +package com.inscloudtech.common.exception; + +/** + * 演示模式异常 + * + * @author inscloudtech + */ +public class DemoModeException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public DemoModeException() { + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/exception/GlobalException.java b/cas-common/src/main/java/com/inscloudtech/common/exception/GlobalException.java new file mode 100644 index 0000000..185e7ed --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/exception/GlobalException.java @@ -0,0 +1,49 @@ +package com.inscloudtech.common.exception; + +/** + * 全局异常 + * + * @author inscloudtech + */ +public class GlobalException extends RuntimeException { + + private static final long serialVersionUID = 1L; + /** + * 错误提示 + */ + private String message; + /** + * 错误明细,内部调试错误 + *

+ * 和 {@link CommonResult#getDetailMessage()} 一致的设计 + */ + private String detailMessage; + /** + * 空构造方法,避免反序列化问题 + */ + public GlobalException() { + } + + public GlobalException(String message) { + this.message = message; + } + + public String getDetailMessage() { + return detailMessage; + } + + public GlobalException setDetailMessage(String detailMessage) { + this.detailMessage = detailMessage; + return this; + } + + @Override + public String getMessage() { + return message; + } + + public GlobalException setMessage(String message) { + this.message = message; + return this; + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/exception/ServiceException.java b/cas-common/src/main/java/com/inscloudtech/common/exception/ServiceException.java new file mode 100644 index 0000000..a0a430d --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/exception/ServiceException.java @@ -0,0 +1,61 @@ +package com.inscloudtech.common.exception; + +/** + * 业务异常 + * + * @author inscloudtech + */ +public final class ServiceException extends RuntimeException { + private static final long serialVersionUID = 1L; + /** + * 错误码 + */ + private Integer code; + /** + * 错误提示 + */ + private String message; + /** + * 错误明细,内部调试错误 + *

+ * 和 {@link CommonResult#getDetailMessage()} 一致的设计 + */ + private String detailMessage; + /** + * 空构造方法,避免反序列化问题 + */ + public ServiceException() { + } + + public ServiceException(String message) { + this.message = message; + } + + public ServiceException(String message, Integer code) { + this.message = message; + this.code = code; + } + + public String getDetailMessage() { + return detailMessage; + } + + @Override + public String getMessage() { + return message; + } + + public Integer getCode() { + return code; + } + + public ServiceException setMessage(String message) { + this.message = message; + return this; + } + + public ServiceException setDetailMessage(String detailMessage) { + this.detailMessage = detailMessage; + return this; + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/exception/UtilException.java b/cas-common/src/main/java/com/inscloudtech/common/exception/UtilException.java new file mode 100644 index 0000000..d63b69a --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/exception/UtilException.java @@ -0,0 +1,22 @@ +package com.inscloudtech.common.exception; + +/** + * 工具类异常 + * + * @author inscloudtech + */ +public class UtilException extends RuntimeException { + private static final long serialVersionUID = 8247610319171014183L; + + public UtilException(Throwable e) { + super(e.getMessage(), e); + } + + public UtilException(String message) { + super(message); + } + + public UtilException(String message, Throwable throwable) { + super(message, throwable); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/exception/base/BaseException.java b/cas-common/src/main/java/com/inscloudtech/common/exception/base/BaseException.java new file mode 100644 index 0000000..b042452 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/exception/base/BaseException.java @@ -0,0 +1,71 @@ +package com.inscloudtech.common.exception.base; + +import com.inscloudtech.common.utils.MessageUtils; +import com.inscloudtech.common.utils.StringUtils; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 基础异常 + * + * @author inscloudtech + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +public class BaseException extends RuntimeException { + private static final long serialVersionUID = 1L; + /** + * 所属模块 + */ + private String module; + /** + * 错误码 + */ + private String code; + /** + * 错误码对应的参数 + */ + private Object[] args; + /** + * 错误消息 + */ + private String defaultMessage; + + public BaseException(String module, String code, Object[] args, String defaultMessage) { + this.module = module; + this.code = code; + this.args = args; + this.defaultMessage = defaultMessage; + } + + public BaseException(String module, String code, Object[] args) { + this(module, code, args, null); + } + + public BaseException(String module, String defaultMessage) { + this(module, null, null, defaultMessage); + } + + public BaseException(String code, Object[] args) { + this(null, code, args, null); + } + + public BaseException(String defaultMessage) { + this(null, null, null, defaultMessage); + } + + @Override + public String getMessage() { + String message = null; + if (!StringUtils.isEmpty(code)) { + message = MessageUtils.message(code, args); + } + if (message == null) { + message = defaultMessage; + } + return message; + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/exception/dc/AnalyzeDataFailedException.java b/cas-common/src/main/java/com/inscloudtech/common/exception/dc/AnalyzeDataFailedException.java new file mode 100644 index 0000000..a81959b --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/exception/dc/AnalyzeDataFailedException.java @@ -0,0 +1,18 @@ +package com.inscloudtech.common.exception.dc; + +import lombok.Getter; + +@Getter +public class AnalyzeDataFailedException extends RuntimeException { + + private String relationFilename; + + public AnalyzeDataFailedException(String message, Exception e) { + super(message, e); + } + + public AnalyzeDataFailedException(String message, Throwable cause, String relationFilename) { + super(message, cause); + this.relationFilename = relationFilename; + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/exception/dc/GetIndexNameFailedException.java b/cas-common/src/main/java/com/inscloudtech/common/exception/dc/GetIndexNameFailedException.java new file mode 100644 index 0000000..a7f2405 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/exception/dc/GetIndexNameFailedException.java @@ -0,0 +1,15 @@ +package com.inscloudtech.common.exception.dc; + +public class GetIndexNameFailedException extends Exception{ + public GetIndexNameFailedException() { + super(); + } + + public GetIndexNameFailedException(String message) { + super(message); + } + + public GetIndexNameFailedException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/exception/dc/ImportDataFailedException.java b/cas-common/src/main/java/com/inscloudtech/common/exception/dc/ImportDataFailedException.java new file mode 100644 index 0000000..5f9cae4 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/exception/dc/ImportDataFailedException.java @@ -0,0 +1,21 @@ +package com.inscloudtech.common.exception.dc; + +import lombok.Getter; + +/** + * @description: 导入数据失败异常,用于记录导入数据失败原因,收集文件信息 + */ +@Getter +public class ImportDataFailedException extends RuntimeException { + + private final String filename; + + public ImportDataFailedException(String format) { + this(null, null); + } + + public ImportDataFailedException(String message, String filename) { + super(message); + this.filename = filename; + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/exception/dc/RegularFailureException.java b/cas-common/src/main/java/com/inscloudtech/common/exception/dc/RegularFailureException.java new file mode 100644 index 0000000..8c73d35 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/exception/dc/RegularFailureException.java @@ -0,0 +1,13 @@ +package com.inscloudtech.common.exception.dc; + +/** + * 常规失败异常,无法从其中获取文件信息 + */ +public class RegularFailureException extends RuntimeException { + + public RegularFailureException() {} + + public RegularFailureException(String message) { + super(message); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/exception/dc/TemplateNotFindException.java b/cas-common/src/main/java/com/inscloudtech/common/exception/dc/TemplateNotFindException.java new file mode 100644 index 0000000..a53b1b8 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/exception/dc/TemplateNotFindException.java @@ -0,0 +1,21 @@ +package com.inscloudtech.common.exception.dc; + +import lombok.Data; + +/** + * 模板未找到 + */ +@Data +public class TemplateNotFindException extends RuntimeException { + + public static final String TIPS = "该数据表格无对应解析模板"; + private String filename; + + + public TemplateNotFindException() {} + + public TemplateNotFindException(String filename) { + super(filename + TIPS); + this.filename = filename; + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/exception/file/FileException.java b/cas-common/src/main/java/com/inscloudtech/common/exception/file/FileException.java new file mode 100644 index 0000000..03c0a29 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/exception/file/FileException.java @@ -0,0 +1,17 @@ +package com.inscloudtech.common.exception.file; + +import com.inscloudtech.common.exception.base.BaseException; + +/** + * 文件信息异常类 + * + * @author inscloudtech + */ +public class FileException extends BaseException { + private static final long serialVersionUID = 1L; + + public FileException(String code, Object[] args) { + super("file", code, args, null); + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/exception/file/FileNameLengthLimitExceededException.java b/cas-common/src/main/java/com/inscloudtech/common/exception/file/FileNameLengthLimitExceededException.java new file mode 100644 index 0000000..2ab41d4 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/exception/file/FileNameLengthLimitExceededException.java @@ -0,0 +1,14 @@ +package com.inscloudtech.common.exception.file; + +/** + * 文件名称超长限制异常类 + * + * @author inscloudtech + */ +public class FileNameLengthLimitExceededException extends FileException { + private static final long serialVersionUID = 1L; + + public FileNameLengthLimitExceededException(int defaultFileNameLength) { + super("upload.filename.exceed.length", new Object[]{defaultFileNameLength}); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/exception/file/FileSizeLimitExceededException.java b/cas-common/src/main/java/com/inscloudtech/common/exception/file/FileSizeLimitExceededException.java new file mode 100644 index 0000000..9fc7cd3 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/exception/file/FileSizeLimitExceededException.java @@ -0,0 +1,14 @@ +package com.inscloudtech.common.exception.file; + +/** + * 文件名大小限制异常类 + * + * @author inscloudtech + */ +public class FileSizeLimitExceededException extends FileException { + private static final long serialVersionUID = 1L; + + public FileSizeLimitExceededException(long defaultMaxSize) { + super("upload.exceed.maxSize", new Object[]{defaultMaxSize}); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/exception/file/FileUploadException.java b/cas-common/src/main/java/com/inscloudtech/common/exception/file/FileUploadException.java new file mode 100644 index 0000000..c1ab754 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/exception/file/FileUploadException.java @@ -0,0 +1,52 @@ +package com.inscloudtech.common.exception.file; + +import java.io.PrintStream; +import java.io.PrintWriter; + +/** + * 文件上传异常类 + * + * @author ruoyi + */ +public class FileUploadException extends Exception { + + private static final long serialVersionUID = 1L; + + private final Throwable cause; + + public FileUploadException() { + this(null, null); + } + + public FileUploadException(final String msg) { + this(msg, null); + } + + public FileUploadException(String msg, Throwable cause) { + super(msg); + this.cause = cause; + } + + @Override + public void printStackTrace(PrintStream stream) { + super.printStackTrace(stream); + if (cause != null) { + stream.println("Caused by:"); + cause.printStackTrace(stream); + } + } + + @Override + public void printStackTrace(PrintWriter writer) { + super.printStackTrace(writer); + if (cause != null) { + writer.println("Caused by:"); + cause.printStackTrace(writer); + } + } + + @Override + public Throwable getCause() { + return cause; + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/exception/file/InvalidExtensionException.java b/cas-common/src/main/java/com/inscloudtech/common/exception/file/InvalidExtensionException.java new file mode 100644 index 0000000..c2b6c90 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/exception/file/InvalidExtensionException.java @@ -0,0 +1,67 @@ +package com.inscloudtech.common.exception.file; + +import java.util.Arrays; + +/** + * 文件上传 误异常类 + * + * @author ruoyi + */ +public class InvalidExtensionException extends FileUploadException { + private static final long serialVersionUID = 1L; + + private String[] allowedExtension; + private String extension; + private String filename; + + public InvalidExtensionException(String[] allowedExtension, String extension, String filename) { + super("文件[" + filename + "]后缀[" + extension + "]不正确,请上传" + Arrays.toString(allowedExtension) + "格式"); + this.allowedExtension = allowedExtension; + this.extension = extension; + this.filename = filename; + } + + public String[] getAllowedExtension() { + return allowedExtension; + } + + public String getExtension() { + return extension; + } + + public String getFilename() { + return filename; + } + + public static class InvalidImageExtensionException extends InvalidExtensionException { + private static final long serialVersionUID = 1L; + + public InvalidImageExtensionException(String[] allowedExtension, String extension, String filename) { + super(allowedExtension, extension, filename); + } + } + + public static class InvalidFlashExtensionException extends InvalidExtensionException { + private static final long serialVersionUID = 1L; + + public InvalidFlashExtensionException(String[] allowedExtension, String extension, String filename) { + super(allowedExtension, extension, filename); + } + } + + public static class InvalidMediaExtensionException extends InvalidExtensionException { + private static final long serialVersionUID = 1L; + + public InvalidMediaExtensionException(String[] allowedExtension, String extension, String filename) { + super(allowedExtension, extension, filename); + } + } + + public static class InvalidVideoExtensionException extends InvalidExtensionException { + private static final long serialVersionUID = 1L; + + public InvalidVideoExtensionException(String[] allowedExtension, String extension, String filename) { + super(allowedExtension, extension, filename); + } + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/exception/user/CaptchaException.java b/cas-common/src/main/java/com/inscloudtech/common/exception/user/CaptchaException.java new file mode 100644 index 0000000..b1bc9be --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/exception/user/CaptchaException.java @@ -0,0 +1,14 @@ +package com.inscloudtech.common.exception.user; + +/** + * 验证码错误异常类 + * + * @author inscloudtech + */ +public class CaptchaException extends UserException { + private static final long serialVersionUID = 1L; + + public CaptchaException() { + super("user.jcaptcha.error"); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/exception/user/CaptchaExpireException.java b/cas-common/src/main/java/com/inscloudtech/common/exception/user/CaptchaExpireException.java new file mode 100644 index 0000000..243a1ed --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/exception/user/CaptchaExpireException.java @@ -0,0 +1,14 @@ +package com.inscloudtech.common.exception.user; + +/** + * 验证码失效异常类 + * + * @author inscloudtech + */ +public class CaptchaExpireException extends UserException { + private static final long serialVersionUID = 1L; + + public CaptchaExpireException() { + super("user.jcaptcha.expire"); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/exception/user/UserException.java b/cas-common/src/main/java/com/inscloudtech/common/exception/user/UserException.java new file mode 100644 index 0000000..3af886f --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/exception/user/UserException.java @@ -0,0 +1,16 @@ +package com.inscloudtech.common.exception.user; + +import com.inscloudtech.common.exception.base.BaseException; + +/** + * 用户信息异常类 + * + * @author inscloudtech + */ +public class UserException extends BaseException { + private static final long serialVersionUID = 1L; + + public UserException(String code, Object... args) { + super("user", code, args, null); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/exception/user/UserPasswordNotMatchException.java b/cas-common/src/main/java/com/inscloudtech/common/exception/user/UserPasswordNotMatchException.java new file mode 100644 index 0000000..062b7aa --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/exception/user/UserPasswordNotMatchException.java @@ -0,0 +1,14 @@ +package com.inscloudtech.common.exception.user; + +/** + * 用户密码不正确或不符合规范异常类 + * + * @author inscloudtech + */ +public class UserPasswordNotMatchException extends UserException { + private static final long serialVersionUID = 1L; + + public UserPasswordNotMatchException() { + super("user.password.not.match"); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/exception/user/UserPasswordRetryLimitExceedException.java b/cas-common/src/main/java/com/inscloudtech/common/exception/user/UserPasswordRetryLimitExceedException.java new file mode 100644 index 0000000..76db095 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/exception/user/UserPasswordRetryLimitExceedException.java @@ -0,0 +1,16 @@ +package com.inscloudtech.common.exception.user; + +/** + * 用户错误最大次数异常类 + * + * @author inscloudtech + */ +public class UserPasswordRetryLimitExceedException extends UserException { + + private static final long serialVersionUID = 1L; + + public UserPasswordRetryLimitExceedException(int retryLimitCount, int lockTime) { + super("user.password.retry.limit.exceed", retryLimitCount, lockTime); + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/filter/RepeatableFilter.java b/cas-common/src/main/java/com/inscloudtech/common/filter/RepeatableFilter.java new file mode 100644 index 0000000..0adf54a --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/filter/RepeatableFilter.java @@ -0,0 +1,40 @@ +package com.inscloudtech.common.filter; + +import com.inscloudtech.common.utils.StringUtils; +import org.springframework.http.MediaType; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +/** + * Repeatable 过滤器 + * + * @author inscloudtech + */ +public class RepeatableFilter implements Filter { + @Override + public void init(FilterConfig filterConfig) throws ServletException { + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + ServletRequest requestWrapper = null; + if (request instanceof HttpServletRequest + && StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) { + requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response); + } + if (null == requestWrapper) { + chain.doFilter(request, response); + } else { + chain.doFilter(requestWrapper, response); + } + } + + @Override + public void destroy() { + + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/filter/RepeatedlyRequestWrapper.java b/cas-common/src/main/java/com/inscloudtech/common/filter/RepeatedlyRequestWrapper.java new file mode 100644 index 0000000..4ea8b71 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/filter/RepeatedlyRequestWrapper.java @@ -0,0 +1,67 @@ +package com.inscloudtech.common.filter; + +import cn.hutool.core.io.IoUtil; +import com.inscloudtech.common.constant.Constants; + +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; + +/** + * 构建可重复读取inputStream的request + * + * @author inscloudtech + */ +public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper { + private final byte[] body; + + public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException { + super(request); + request.setCharacterEncoding(Constants.UTF8); + response.setCharacterEncoding(Constants.UTF8); + + body = IoUtil.readBytes(request.getInputStream(), false); + } + + @Override + public BufferedReader getReader() throws IOException { + return new BufferedReader(new InputStreamReader(getInputStream())); + } + + @Override + public ServletInputStream getInputStream() throws IOException { + final ByteArrayInputStream bais = new ByteArrayInputStream(body); + return new ServletInputStream() { + @Override + public int read() throws IOException { + return bais.read(); + } + + @Override + public int available() throws IOException { + return body.length; + } + + @Override + public boolean isFinished() { + return false; + } + + @Override + public boolean isReady() { + return false; + } + + @Override + public void setReadListener(ReadListener readListener) { + + } + }; + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/filter/XssFilter.java b/cas-common/src/main/java/com/inscloudtech/common/filter/XssFilter.java new file mode 100644 index 0000000..9599b37 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/filter/XssFilter.java @@ -0,0 +1,61 @@ +package com.inscloudtech.common.filter; + +import com.inscloudtech.common.enums.HttpMethod; +import com.inscloudtech.common.utils.StringUtils; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * 防止XSS攻击的过滤器 + * + * @author inscloudtech + */ +public class XssFilter implements Filter { /** + * 排除链接 + */ + public List excludes = new ArrayList<>(); + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + String tempExcludes = filterConfig.getInitParameter("excludes"); + if (StringUtils.isNotEmpty(tempExcludes)) { + String[] url = tempExcludes.split(StringUtils.SEPARATOR); + for (int i = 0; url != null && i < url.length; i++) { + excludes.add(url[i]); + } + } + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + HttpServletRequest req = (HttpServletRequest) request; + HttpServletResponse resp = (HttpServletResponse) response; + if (handleExcludeURL(req, resp)) { + chain.doFilter(request, response); + return; + } + XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request); + chain.doFilter(xssRequest, response); + } + + private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) { + String url = request.getServletPath(); + String method = request.getMethod(); + // GET DELETE 不过滤 + if (method == null || HttpMethod.GET.matches(method) || HttpMethod.DELETE.matches(method)) { + return true; + } + return StringUtils.matches(url, excludes); + } + + @Override + public void destroy() { + + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/filter/XssHttpServletRequestWrapper.java b/cas-common/src/main/java/com/inscloudtech/common/filter/XssHttpServletRequestWrapper.java new file mode 100644 index 0000000..899d7d4 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/filter/XssHttpServletRequestWrapper.java @@ -0,0 +1,95 @@ +package com.inscloudtech.common.filter; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HtmlUtil; +import com.inscloudtech.common.utils.StringUtils; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; + +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +/** + * XSS过滤处理 + * + * @author inscloudtech + */ +public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { /** + * @param request + */ + public XssHttpServletRequestWrapper(HttpServletRequest request) { + super(request); + } + + @Override + public String[] getParameterValues(String name) { + String[] values = super.getParameterValues(name); + if (values != null) { + int length = values.length; + String[] escapesValues = new String[length]; + for (int i = 0; i < length; i++) { + // 防xss攻击和过滤前后空格 + escapesValues[i] = HtmlUtil.cleanHtmlTag(values[i]).trim(); + } + return escapesValues; + } + return super.getParameterValues(name); + } + + @Override + public ServletInputStream getInputStream() throws IOException { + // 非json类型,直接返回 + if (!isJsonRequest()) { + return super.getInputStream(); + } + + // 为空,直接返回 + String json = StrUtil.str(IoUtil.readBytes(super.getInputStream(), false), StandardCharsets.UTF_8); + if (StringUtils.isEmpty(json)) { + return super.getInputStream(); + } + + // xss过滤 + json = HtmlUtil.cleanHtmlTag(json).trim(); + byte[] jsonBytes = json.getBytes(StandardCharsets.UTF_8); + final ByteArrayInputStream bis = IoUtil.toStream(jsonBytes); + return new ServletInputStream() { + @Override + public boolean isFinished() { + return true; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public int available() throws IOException { + return jsonBytes.length; + } + + @Override + public void setReadListener(ReadListener readListener) { + } + + @Override + public int read() throws IOException { + return bis.read(); + } + }; + } + /** + * 是否是Json请求 + */ + public boolean isJsonRequest() { + String header = super.getHeader(HttpHeaders.CONTENT_TYPE); + return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/helper/DataBaseHelper.java b/cas-common/src/main/java/com/inscloudtech/common/helper/DataBaseHelper.java new file mode 100644 index 0000000..152c418 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/helper/DataBaseHelper.java @@ -0,0 +1,71 @@ +package com.inscloudtech.common.helper; + +import cn.hutool.core.convert.Convert; +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.inscloudtech.common.enums.DataBaseType; +import com.inscloudtech.common.exception.ServiceException; +import com.inscloudtech.common.utils.spring.SpringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; + +/** + * 数据库助手 + * + * @author inscloudtech + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class DataBaseHelper { + + private static final DynamicRoutingDataSource DS = SpringUtils.getBean(DynamicRoutingDataSource.class); + /** + * 获取当前数据库类型 + */ + public static DataBaseType getDataBaseType() { + DataSource dataSource = DS.determineDataSource(); + try (Connection conn = dataSource.getConnection()) { + DatabaseMetaData metaData = conn.getMetaData(); + String databaseProductName = metaData.getDatabaseProductName(); + return DataBaseType.find(databaseProductName); + } catch (SQLException e) { + throw new ServiceException(e.getMessage()); + } + } + + public static boolean isMySql() { + return DataBaseType.MY_SQL == getDataBaseType(); + } + + public static boolean isOracle() { + return DataBaseType.ORACLE == getDataBaseType(); + } + + public static boolean isPostgerSql() { + return DataBaseType.POSTGRE_SQL == getDataBaseType(); + } + + public static boolean isSqlServer() { + return DataBaseType.SQL_SERVER == getDataBaseType(); + } + + public static String findInSet(Object var1, String var2) { + DataBaseType dataBasyType = getDataBaseType(); + String var = Convert.toStr(var1); + if (dataBasyType == DataBaseType.SQL_SERVER) { + // charindex(',100,' , ',0,100,101,') <> 0 + return "charindex('," + var + ",' , ','+" + var2 + "+',') <> 0"; + } else if (dataBasyType == DataBaseType.POSTGRE_SQL) { + // (select position(',100,' in ',0,100,101,')) <> 0 + return "(select position('," + var + ",' in ','||" + var2 + "||',')) <> 0"; + } else if (dataBasyType == DataBaseType.ORACLE) { + // instr(',0,100,101,' , ',100,') <> 0 + return "instr(','||" + var2 + "||',' , '," + var + ",') <> 0"; + } + // find_in_set('100' , '0,100,101') + return "find_in_set('" + var + "' , " + var2 + ") <> 0"; + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/helper/DataPermissionHelper.java b/cas-common/src/main/java/com/inscloudtech/common/helper/DataPermissionHelper.java new file mode 100644 index 0000000..bb5a7c3 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/helper/DataPermissionHelper.java @@ -0,0 +1,89 @@ +package com.inscloudtech.common.helper; + +import cn.dev33.satoken.context.SaHolder; +import cn.dev33.satoken.context.model.SaStorage; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy; +import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Supplier; + +/** + * 数据权限助手 + * + * @author inscloudtech + * @version 3.5.0 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@SuppressWarnings("unchecked cast") +public class DataPermissionHelper { + + private static final String DATA_PERMISSION_KEY = "data:permission"; + + public static T getVariable(String key) { + Map context = getContext(); + return (T) context.get(key); + } + + + public static void setVariable(String key, Object value) { + Map context = getContext(); + context.put(key, value); + } + + public static Map getContext() { + SaStorage saStorage = SaHolder.getStorage(); + Object attribute = saStorage.get(DATA_PERMISSION_KEY); + if (ObjectUtil.isNull(attribute)) { + saStorage.set(DATA_PERMISSION_KEY, new HashMap<>()); + attribute = saStorage.get(DATA_PERMISSION_KEY); + } + if (attribute instanceof Map) { + return (Map) attribute; + } + throw new NullPointerException("data permission context type exception"); + } + /** + * 开启忽略数据权限(开启后需手动调用 {@link #disableIgnore()} 关闭) + */ + public static void enableIgnore() { + InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().dataPermission(true).build()); + } + /** + * 关闭忽略数据权限 + */ + public static void disableIgnore() { + InterceptorIgnoreHelper.clearIgnoreStrategy(); + } + /** + * 在忽略数据权限中执行 + * + * @param handle 处理执行方法 + */ + public static void ignore(Runnable handle) { + enableIgnore(); + try { + handle.run(); + } finally { + disableIgnore(); + } + } + /** + * 在忽略数据权限中执行 + * + * @param handle 处理执行方法 + */ + public static T ignore(Supplier handle) { + enableIgnore(); + try { + return handle.get(); + } finally { + disableIgnore(); + } + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/helper/LoginHelper.java b/cas-common/src/main/java/com/inscloudtech/common/helper/LoginHelper.java new file mode 100644 index 0000000..2abea1c --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/helper/LoginHelper.java @@ -0,0 +1,135 @@ +package com.inscloudtech.common.helper; + +import cn.dev33.satoken.context.SaHolder; +import cn.dev33.satoken.context.model.SaStorage; +import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.inscloudtech.common.constant.UserConstants; +import com.inscloudtech.common.core.domain.model.LoginUser; +import com.inscloudtech.common.enums.DeviceType; +import com.inscloudtech.common.enums.UserType; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +/** + * 登录鉴权助手 + *

+ * user_type 为 用户类型 同一个用户表 可以有多种用户类型 例如 pc,app + * deivce 为 设备类型 同一个用户类型 可以有 多种设备类型 例如 web,ios + * 可以组成 用户类型与设备类型多对多的 权限灵活控制 + *

+ * 多用户体系 针对 多种用户类型 但权限控制不一致 + * 可以组成 多用户类型表与多设备类型 分别控制权限 + * + * @author inscloudtech + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class LoginHelper { + + public static final String LOGIN_USER_KEY = "loginUser"; + public static final String USER_KEY = "userId"; + public static final String REPORT_ADMIN_PERMISSION = "report:admin"; + public static final String STOCK_VIEW_ADMIN = "stock:viewAdmin"; + public static final String PLAN_VIEW_ADMIN = "plan:viewAdmin"; + + /** + * 登录系统 + * + * @param loginUser 登录用户信息 + */ + public static void login(LoginUser loginUser) { + loginByDevice(loginUser, null); + } + /** + * 登录系统 基于 设备类型 + * 针对相同用户体系不同设备 + * + * @param loginUser 登录用户信息 + */ + public static void loginByDevice(LoginUser loginUser, DeviceType deviceType) { + SaStorage storage = SaHolder.getStorage(); + storage.set(LOGIN_USER_KEY, loginUser); + storage.set(USER_KEY, loginUser.getUserId()); + SaLoginModel model = new SaLoginModel(); + if (ObjectUtil.isNotNull(deviceType)) { + model.setDevice(deviceType.getDevice()); + } + StpUtil.login(loginUser.getLoginId(), model.setExtra(USER_KEY, loginUser.getUserId())); + StpUtil.getTokenSession().set(LOGIN_USER_KEY, loginUser); + } + /** + * 获取用户(多级缓存) + */ + public static LoginUser getLoginUser() { + LoginUser loginUser = (LoginUser) SaHolder.getStorage().get(LOGIN_USER_KEY); + if (loginUser != null) { + return loginUser; + } + loginUser = (LoginUser) StpUtil.getTokenSession().get(LOGIN_USER_KEY); + SaHolder.getStorage().set(LOGIN_USER_KEY, loginUser); + return loginUser; + } + /** + * 获取用户基于token + */ + public static LoginUser getLoginUser(String token) { + return (LoginUser) StpUtil.getTokenSessionByToken(token).get(LOGIN_USER_KEY); + } + /** + * 获取用户id + */ + public static Long getUserId() { + Long userId; + try { + userId = Convert.toLong(SaHolder.getStorage().get(USER_KEY)); + if (ObjectUtil.isNull(userId)) { + userId = Convert.toLong(StpUtil.getExtra(USER_KEY)); + SaHolder.getStorage().set(USER_KEY, userId); + } + } catch (Exception e) { + return null; + } + return userId; + } + /** + * 获取部门ID + */ + public static Long getDeptId() { + return getLoginUser().getDeptId(); + } + /** + * 获取用户账户 + */ + public static String getUsername() { + return getLoginUser().getUsername(); + } + /** + * + */ + public static String getNickname() { + return getLoginUser().getNickname(); + } + /** + * 获取用户类型 + */ + public static UserType getUserType() { + String loginId = StpUtil.getLoginIdAsString(); + return UserType.getUserType(loginId); + } + /** + * 是否为管理员 + * + * @param userId 用户ID + * @return 结果 + */ + public static boolean isAdmin(Long userId) { + return UserConstants.ADMIN_ID.equals(userId); + } + + public static boolean isAdmin() { + return isAdmin(getUserId()); + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/jackson/DictDataJsonSerializer.java b/cas-common/src/main/java/com/inscloudtech/common/jackson/DictDataJsonSerializer.java new file mode 100644 index 0000000..61a1524 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/jackson/DictDataJsonSerializer.java @@ -0,0 +1,58 @@ +package com.inscloudtech.common.jackson; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.ContextualSerializer; +import com.inscloudtech.common.annotation.DictDataMapper; +import com.inscloudtech.common.core.service.DictService; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.spring.SpringUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeansException; + +import java.io.IOException; +import java.util.Objects; + +/** + * 字典数据json序列化工具 + * + * @author inscloudtech + * @deprecated 建议使用通用翻译注解 + */ +@Deprecated +@Slf4j +public class DictDataJsonSerializer extends JsonSerializer implements ContextualSerializer { + + private String dictType; + + @Override + public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + try { + DictService dictService = SpringUtils.getBean(DictService.class); + if (ObjectUtil.isNotNull(dictService)) { + String label = dictService.getDictLabel(dictType, value); + gen.writeString(StringUtils.isNotBlank(label) ? label : value); + } else { + gen.writeString(value); + } + } catch (BeansException e) { + log.error("字典数据未查到, 采用默认处理 => {}", e.getMessage()); + gen.writeString(value); + } + } + + @Override + public JsonSerializer createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException { + DictDataMapper anno = property.getAnnotation(DictDataMapper.class); + if (Objects.nonNull(anno) && StrUtil.isNotBlank(anno.dictType())) { + this.dictType = anno.dictType(); + return this; + } + return prov.findValueSerializer(property.getType(), property); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/jackson/SensitiveJsonSerializer.java b/cas-common/src/main/java/com/inscloudtech/common/jackson/SensitiveJsonSerializer.java new file mode 100644 index 0000000..5997a86 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/jackson/SensitiveJsonSerializer.java @@ -0,0 +1,54 @@ +package com.inscloudtech.common.jackson; + +import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.ContextualSerializer; +import com.inscloudtech.common.annotation.Sensitive; +import com.inscloudtech.common.core.service.SensitiveService; +import com.inscloudtech.common.enums.SensitiveStrategy; +import com.inscloudtech.common.utils.spring.SpringUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeansException; + +import java.io.IOException; +import java.util.Objects; + +/** + * 数据脱敏json序列化工具 + * + * @author Yjoioooo + */ +@Slf4j +public class SensitiveJsonSerializer extends JsonSerializer implements ContextualSerializer { + + private SensitiveStrategy strategy; + + @Override + public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + try { + SensitiveService sensitiveService = SpringUtils.getBean(SensitiveService.class); + if (ObjectUtil.isNotNull(sensitiveService) && sensitiveService.isSensitive()) { + gen.writeString(strategy.desensitizer().apply(value)); + } else { + gen.writeString(value); + } + } catch (BeansException e) { + log.error("脱敏实现不存在, 采用默认处理 => {}", e.getMessage()); + gen.writeString(value); + } + } + + @Override + public JsonSerializer createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException { + Sensitive annotation = property.getAnnotation(Sensitive.class); + if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) { + this.strategy = annotation.strategy(); + return this; + } + return prov.findValueSerializer(property.getType(), property); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/translation/TranslationInterface.java b/cas-common/src/main/java/com/inscloudtech/common/translation/TranslationInterface.java new file mode 100644 index 0000000..dbf0d1d --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/translation/TranslationInterface.java @@ -0,0 +1,16 @@ +package com.inscloudtech.common.translation; + +/** + * 翻译接口 (实现类需标注 {@link com.inscloudtech.common.annotation.TranslationType} 注解标明翻译类型) + * + * @author inscloudtech + */ +public interface TranslationInterface { + /** + * 翻译 + * + * @param key 需要被翻译的键(不为空) + * @return 返回键对应的值 + */ + T translation(Object key, String other); +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/translation/handler/TranslationBeanSerializerModifier.java b/cas-common/src/main/java/com/inscloudtech/common/translation/handler/TranslationBeanSerializerModifier.java new file mode 100644 index 0000000..1794aba --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/translation/handler/TranslationBeanSerializerModifier.java @@ -0,0 +1,29 @@ +package com.inscloudtech.common.translation.handler; + +import com.fasterxml.jackson.databind.BeanDescription; +import com.fasterxml.jackson.databind.SerializationConfig; +import com.fasterxml.jackson.databind.ser.BeanPropertyWriter; +import com.fasterxml.jackson.databind.ser.BeanSerializerModifier; + +import java.util.List; + +/** + * Bean 序列化修改器 解决 Null 被单独处理问题 + * + * @author inscloudtech + */ +public class TranslationBeanSerializerModifier extends BeanSerializerModifier { + + @Override + public List changeProperties(SerializationConfig config, BeanDescription beanDesc, + List beanProperties) { + for (BeanPropertyWriter writer : beanProperties) { + // 如果序列化器为 TranslationHandler 的话 将 Null 值也交给他处理 + if (writer.getSerializer() instanceof TranslationHandler) { + writer.assignNullSerializer(writer.getSerializer()); + } + } + return beanProperties; + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/translation/handler/TranslationHandler.java b/cas-common/src/main/java/com/inscloudtech/common/translation/handler/TranslationHandler.java new file mode 100644 index 0000000..4ee51b9 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/translation/handler/TranslationHandler.java @@ -0,0 +1,64 @@ +package com.inscloudtech.common.translation.handler; + +import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.ContextualSerializer; +import com.inscloudtech.common.annotation.Translation; +import com.inscloudtech.common.translation.TranslationInterface; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.reflect.ReflectUtils; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 翻译处理器 + * + * @author inscloudtech + */ +@Slf4j +public class TranslationHandler extends JsonSerializer implements ContextualSerializer { + /** + * 全局翻译实现类映射器 + */ + public static final Map> TRANSLATION_MAPPER = new ConcurrentHashMap<>(); + + private Translation translation; + + @Override + public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + TranslationInterface trans = TRANSLATION_MAPPER.get(translation.type()); + if (ObjectUtil.isNotNull(trans)) { + // 如果映射字段不为空 则取映射字段的值 + if (StringUtils.isNotBlank(translation.mapper())) { + value = ReflectUtils.invokeGetter(gen.getCurrentValue(), translation.mapper()); + } + // 如果为 null 直接写出 + if (ObjectUtil.isNull(value)) { + gen.writeNull(); + return; + } + Object result = trans.translation(value, translation.other()); + gen.writeObject(result); + } else { + gen.writeObject(value); + } + } + + @Override + public JsonSerializer createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException { + Translation translation = property.getAnnotation(Translation.class); + if (Objects.nonNull(translation)) { + this.translation = translation; + return this; + } + return prov.findValueSerializer(property.getType(), property); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/translation/impl/DeptNameTranslationImpl.java b/cas-common/src/main/java/com/inscloudtech/common/translation/impl/DeptNameTranslationImpl.java new file mode 100644 index 0000000..72753e4 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/translation/impl/DeptNameTranslationImpl.java @@ -0,0 +1,26 @@ +package com.inscloudtech.common.translation.impl; + +import com.inscloudtech.common.annotation.TranslationType; +import com.inscloudtech.common.constant.TransConstant; +import com.inscloudtech.common.core.service.DeptService; +import com.inscloudtech.common.translation.TranslationInterface; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Component; + +/** + * 部门翻译实现 + * + * @author inscloudtech + */ +@Component +@AllArgsConstructor +@TranslationType(type = TransConstant.DEPT_ID_TO_NAME) +public class DeptNameTranslationImpl implements TranslationInterface { + + private final DeptService deptService; + + @Override + public String translation(Object key, String other) { + return deptService.selectDeptNameByIds(key.toString()); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/translation/impl/DictTypeTranslationImpl.java b/cas-common/src/main/java/com/inscloudtech/common/translation/impl/DictTypeTranslationImpl.java new file mode 100644 index 0000000..1718c78 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/translation/impl/DictTypeTranslationImpl.java @@ -0,0 +1,30 @@ +package com.inscloudtech.common.translation.impl; + +import com.inscloudtech.common.annotation.TranslationType; +import com.inscloudtech.common.constant.TransConstant; +import com.inscloudtech.common.core.service.DictService; +import com.inscloudtech.common.translation.TranslationInterface; +import com.inscloudtech.common.utils.StringUtils; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Component; + +/** + * 字典翻译实现 + * + * @author inscloudtech + */ +@Component +@AllArgsConstructor +@TranslationType(type = TransConstant.DICT_TYPE_TO_LABEL) +public class DictTypeTranslationImpl implements TranslationInterface { + + private final DictService dictService; + + @Override + public String translation(Object key, String other) { + if (key instanceof String && StringUtils.isNotBlank(other)) { + return dictService.getDictLabel(other, key.toString()); + } + return null; + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/translation/impl/OssUrlTranslationImpl.java b/cas-common/src/main/java/com/inscloudtech/common/translation/impl/OssUrlTranslationImpl.java new file mode 100644 index 0000000..07d47e5 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/translation/impl/OssUrlTranslationImpl.java @@ -0,0 +1,26 @@ +package com.inscloudtech.common.translation.impl; + +import com.inscloudtech.common.annotation.TranslationType; +import com.inscloudtech.common.constant.TransConstant; +import com.inscloudtech.common.core.service.OssService; +import com.inscloudtech.common.translation.TranslationInterface; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Component; + +/** + * OSS翻译实现 + * + * @author inscloudtech + */ +@Component +@AllArgsConstructor +@TranslationType(type = TransConstant.OSS_ID_TO_URL) +public class OssUrlTranslationImpl implements TranslationInterface { + + private final OssService ossService; + + @Override + public String translation(Object key, String other) { + return ossService.selectUrlByIds(key.toString()); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/translation/impl/UserNameTranslationImpl.java b/cas-common/src/main/java/com/inscloudtech/common/translation/impl/UserNameTranslationImpl.java new file mode 100644 index 0000000..fc660ca --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/translation/impl/UserNameTranslationImpl.java @@ -0,0 +1,29 @@ +package com.inscloudtech.common.translation.impl; + +import com.inscloudtech.common.annotation.TranslationType; +import com.inscloudtech.common.constant.TransConstant; +import com.inscloudtech.common.core.service.UserService; +import com.inscloudtech.common.translation.TranslationInterface; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Component; + +/** + * 用户名翻译实现 + * + * @author inscloudtech + */ +@Component +@AllArgsConstructor +@TranslationType(type = TransConstant.USER_ID_TO_NAME) +public class UserNameTranslationImpl implements TranslationInterface { + + private final UserService userService; + + @Override + public String translation(Object key, String other) { + if (key instanceof Long) { + return userService.selectUserNameById((Long) key); + } + return null; + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/translation/impl/UserNicknameTranslationImpl.java b/cas-common/src/main/java/com/inscloudtech/common/translation/impl/UserNicknameTranslationImpl.java new file mode 100644 index 0000000..93bcc76 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/translation/impl/UserNicknameTranslationImpl.java @@ -0,0 +1,29 @@ +package com.inscloudtech.common.translation.impl; + +import com.inscloudtech.common.annotation.TranslationType; +import com.inscloudtech.common.constant.TransConstant; +import com.inscloudtech.common.core.service.UserService; +import com.inscloudtech.common.translation.TranslationInterface; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Component; + +/** + * 用户名翻译实现 + * + * @author inscloudtech + */ +@Component +@AllArgsConstructor +@TranslationType(type = TransConstant.USERNAME_TO_NICKNAME) +public class UserNicknameTranslationImpl implements TranslationInterface { + + private final UserService userService; + + @Override + public String translation(Object key, String other) { + if (key instanceof String) { + return userService.selectNicknameByUserName((String) key); + } + return null; + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/BeanCopyUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/BeanCopyUtils.java new file mode 100644 index 0000000..03539a0 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/BeanCopyUtils.java @@ -0,0 +1,355 @@ +package com.inscloudtech.common.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.SimpleCache; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.inscloudtech.common.annotation.UpdateLog; +import com.inscloudtech.common.annotation.UpdateValueLog; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.SneakyThrows; +import org.springframework.cglib.beans.BeanCopier; +import org.springframework.cglib.beans.BeanMap; +import org.springframework.cglib.core.Converter; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.*; + +/** + * bean深拷贝工具(基于 cglib 性能优异) + *

+ * 重点 cglib 不支持 拷贝到链式对象 + * 例如: 源对象 拷贝到 目标(链式对象) + * 请区分好`浅拷贝`和`深拷贝`再做使用 + * + * @author inscloudtech + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class BeanCopyUtils { + /** + * 单对象基于class创建拷贝 + * + * @param source 数据来源实体 + * @param desc 描述对象 转换后的对象 + * @return desc + */ + public static V copy(T source, Class desc) { + if (ObjectUtil.isNull(source)) { + return null; + } + if (ObjectUtil.isNull(desc)) { + return null; + } + final V target = ReflectUtil.newInstanceIfPossible(desc); + return copy(source, target); + } + /** + * 单对象基于对象创建拷贝 + * + * @param source 数据来源实体 + * @param desc 转换后的对象 + * @return desc + */ + public static V copy(T source, V desc) { + if (ObjectUtil.isNull(source)) { + return null; + } + if (ObjectUtil.isNull(desc)) { + return null; + } + BeanCopier beanCopier = BeanCopierCache.INSTANCE.get(source.getClass(), desc.getClass(), null); + beanCopier.copy(source, desc, null); + return desc; + } + /** + * 列表对象基于class创建拷贝 + * + * @param sourceList 数据来源实体列表 + * @param desc 描述对象 转换后的对象 + * @return desc + */ + public static List copyList(List sourceList, Class desc) { + if (ObjectUtil.isNull(sourceList)) { + return null; + } + if (CollUtil.isEmpty(sourceList)) { + return CollUtil.newArrayList(); + } + return StreamUtils.toList(sourceList, source -> { + V target = ReflectUtil.newInstanceIfPossible(desc); + copy(source, target); + return target; + }); + } + /** + * bean拷贝到map + * + * @param bean 数据来源实体 + * @return map对象 + */ + @SuppressWarnings("unchecked") + public static Map copyToMap(T bean) { + if (ObjectUtil.isNull(bean)) { + return null; + } + return BeanMap.create(bean); + } + /** + * map拷贝到bean + * + * @param map 数据来源 + * @param beanClass bean类 + * @return bean对象 + */ + public static T mapToBean(Map map, Class beanClass) { + if (MapUtil.isEmpty(map)) { + return null; + } + if (ObjectUtil.isNull(beanClass)) { + return null; + } + T bean = ReflectUtil.newInstanceIfPossible(beanClass); + return mapToBean(map, bean); + } + /** + * map拷贝到bean + * + * @param map 数据来源 + * @param bean bean对象 + * @return bean对象 + */ + public static T mapToBean(Map map, T bean) { + if (MapUtil.isEmpty(map)) { + return null; + } + if (ObjectUtil.isNull(bean)) { + return null; + } + BeanMap.create(bean).putAll(map); + return bean; + } + /** + * map拷贝到map + * + * @param map 数据来源 + * @param clazz 返回的对象类型 + * @return map对象 + */ + public static Map mapToMap(Map map, Class clazz) { + if (MapUtil.isEmpty(map)) { + return null; + } + if (ObjectUtil.isNull(clazz)) { + return null; + } + Map copyMap = new LinkedHashMap<>(map.size()); + map.forEach((k, v) -> copyMap.put(k, copy(v, clazz))); + return copyMap; + } + /** + * BeanCopier属性缓存
+ * 缓存用于防止多次反射造成的性能问题 + * + * @author Looly + * @since 5.4.1 + */ + public enum BeanCopierCache { + /** + * BeanCopier属性缓存单例 + */ + INSTANCE; + + private final SimpleCache cache = new SimpleCache<>(); + + /** + * 获得类与转换器生成的key在{@link BeanCopier}的Map中对应的元素 + * + * @param srcClass 源Bean的类 + * @param targetClass 目标Bean的类 + * @param converter 转换器 + * @return Map中对应的BeanCopier + */ + public BeanCopier get(Class srcClass, Class targetClass, Converter converter) { + final String key = genKey(srcClass, targetClass, converter); + return cache.get(key, () -> BeanCopier.create(srcClass, targetClass, converter != null)); + } + + /** + * 获得类与转换器生成的key + * + * @param srcClass 源Bean的类 + * @param targetClass 目标Bean的类 + * @param converter 转换器 + * @return 属性名和Map映射的key + */ + private String genKey(Class srcClass, Class targetClass, Converter converter) { + final StringBuilder key = StrUtil.builder() + .append(srcClass.getName()).append('#').append(targetClass.getName()); + if (null != converter) { + key.append('#').append(converter.getClass().getName()); + } + return key.toString(); + } + } + /** + * 获取变更内容 + * @param oldBean 更改前的Bean + * @param newBean 更改后的Bean + * @param + * @return + */ + public static Map getChangedFields(T oldBean, T newBean){ + Field[] fields = newBean.getClass().getDeclaredFields(); + StringBuilder beforeBuilder = new StringBuilder(); + StringBuilder afterBuilder = new StringBuilder(); + String fieldName = ""; + for(Field field : fields) { + field.setAccessible(true); + if (!field.isAnnotationPresent(UpdateValueLog.class)) { + continue; + } + + try { + Object oldValue = field.get(oldBean); + Object newValue = field.get(newBean); + if(ObjectUtil.isNotNull(newValue) && !Objects.equals(newValue, oldValue)) { + fieldName = field.getAnnotation(UpdateValueLog.class).fieldName(); + beforeBuilder.append(fieldName); + beforeBuilder.append(": 【更改前:"); + beforeBuilder.append(oldValue); + beforeBuilder.append("】,"); + + afterBuilder.append(fieldName); + afterBuilder.append(": 【更改后:"); + afterBuilder.append(newValue); + afterBuilder.append("】,"); + + } + } catch (Exception e) { + System.out.println(e); + } + } + Map result = new HashMap<>(2); + result.put("before",beforeBuilder.toString()); + result.put("after",afterBuilder.toString()); + return result; + } + + + /** + * 利用反射通过get方法获取bean中字段fieldName的值 + * @param bean + * @param fieldName + * @return + * @throws Exception + */ + public static Object getFieldValue(Object bean, String fieldName) + throws Exception { + StringBuffer result = new StringBuffer(); + String methodName = result.append("get") + .append(fieldName.substring(0, 1).toUpperCase()) + .append(fieldName.substring(1)).toString(); + + Object rObject = null; + Method method = null; + + @SuppressWarnings("rawtypes") + Class[] classArr = new Class[0]; + method = bean.getClass().getMethod(methodName, classArr); + rObject = method.invoke(bean, new Object[0]); + + return rObject; + } + + /** + * 去掉bean中所有属性为字符串的空格 + * @param bean + * @throws Exception + */ + @SneakyThrows + public static void beanAttributeValueTrim(Object bean) { + if(bean!=null){ + //获取所有的字段包括public,private,protected,private + Field[] fields = bean.getClass().getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + Field f = fields[i]; + if (f.getType().getName().equals("java.lang.String")) { + String key = f.getName();//获取字段名 + Object value = getFieldValue(bean, key); + + if (value == null) + continue; + //全角空格 + setFieldValue(bean, key, value.toString().trim().replaceAll("([ ]|\\s|\\u00A0)+","")); + } + } + } + } + + + private static void setFieldValue(Object bean, String fieldName, Object value) + throws Exception { + StringBuffer result = new StringBuffer(); + String methodName = result.append("set") + .append(fieldName.substring(0, 1).toUpperCase()) + .append(fieldName.substring(1)).toString(); + + /** + * 利用发射调用bean.set方法将value设置到字段 + */ + Class[] classArr = new Class[1]; + classArr[0]="java.lang.String".getClass(); + Method method=bean.getClass().getMethod(methodName,classArr); + method.invoke(bean,value); + } + + public static Set getDiffProps(T oldBean, T newBean) { + Field[] fields = newBean.getClass().getDeclaredFields(); + + Set diffProps = new HashSet<>(); + + for (Field field : fields) { + field.setAccessible(true); + + try { + Object oldValue = field.get(oldBean); + Object newValue = field.get(newBean); + if (!Objects.equals(newValue, oldValue)) { + diffProps.add(field.getName()); + + } + } catch (Exception e) { +// log.error("{}", e.getMessage(), e); + } + } + + return diffProps; + } + + + public static T copy(T src, T dest, Class clazz) { + Set diffProps = getDiffProps(src, dest); + + String destStr = JSONUtil.toJsonStr(dest); + JSONObject destObj = JSONUtil.parseObj(destStr); + + String srcStr = JSONUtil.toJsonStr(src); + JSONObject srcObj = JSONUtil.parseObj(srcStr); + + + + for (String prop : diffProps) { + Object value = srcObj.get(prop); + + destObj.put(prop, value); + } + + return destObj.toBean(clazz); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/DateUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/DateUtils.java new file mode 100644 index 0000000..7d2671f --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/DateUtils.java @@ -0,0 +1,194 @@ +package com.inscloudtech.common.utils; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.time.DateFormatUtils; + +import java.lang.management.ManagementFactory; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Date; + +/** + * 时间工具类 + * + * @author inscloudtech + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class DateUtils extends org.apache.commons.lang3.time.DateUtils { + + public static final String YYYY = "yyyy"; + + public static final String YYYY_MM = "yyyy-MM"; + + public static final String YYYY_MM_DD = "yyyy-MM-dd"; + + public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss"; + + public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; + + private static final String[] PARSE_PATTERNS = { + "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", + "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", + "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"}; + /** + * 获取当前Date型日期 + * + * @return Date() 当前日期 + */ + public static Date getNowDate() { + return new Date(); + } + /** + * 获取当前日期, 默认格式为yyyy-MM-dd + * + * @return String + */ + public static String getDate() { + return dateTimeNow(YYYY_MM_DD); + } + + public static String getTime() { + return dateTimeNow(YYYY_MM_DD_HH_MM_SS); + } + + public static String dateTimeNow() { + return dateTimeNow(YYYYMMDDHHMMSS); + } + + public static String dateTimeNow(final String format) { + return parseDateToStr(format, new Date()); + } + + public static String dateTime(final Date date) { + return parseDateToStr(YYYY_MM_DD, date); + } + + public static String parseDateToStr(final String format, final Date date) { + return new SimpleDateFormat(format).format(date); + } + + public static Date dateTime(final String format, final String ts) { + try { + return new SimpleDateFormat(format).parse(ts); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + /** + * 日期路径 即年/月/日 如2018/08/08 + */ + public static String datePath() { + Date now = new Date(); + return DateFormatUtils.format(now, "yyyy/MM/dd"); + } + /** + * 日期路径 即年/月/日 如20180808 + */ + public static String dateTime() { + Date now = new Date(); + return DateFormatUtils.format(now, "yyyyMMdd"); + } + /** + * 日期型字符串转化为日期 格式 + */ + public static Date parseDate(Object str) { + if (str == null) { + return null; + } + try { + return parseDate(str.toString(), PARSE_PATTERNS); + } catch (ParseException e) { + return null; + } + } + /** + * 获取服务器启动时间 + */ + public static Date getServerStartDate() { + long time = ManagementFactory.getRuntimeMXBean().getStartTime(); + return new Date(time); + } + /** + * 计算相差天数 + */ + public static int differentDaysByMillisecond(Date date1, Date date2) { + return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24))); + } + /** + * 计算两个时间差 + */ + public static String getDatePoor(Date endDate, Date nowDate) { + long nd = 1000 * 24 * 60 * 60; + long nh = 1000 * 60 * 60; + long nm = 1000 * 60; + // long ns = 1000; + // 获得两个时间的毫秒时间差异 + long diff = endDate.getTime() - nowDate.getTime(); + // 计算差多少天 + long day = diff / nd; + // 计算差多少小时 + long hour = diff % nd / nh; + // 计算差多少分钟 + long min = diff % nd % nh / nm; + // 计算差多少秒//输出结果 + // long sec = diff % nd % nh % nm / ns; + return day + "天" + hour + "小时" + min + "分钟"; + } + /** + * 增加 LocalDateTime ==> Date + */ + public static Date toDate(LocalDateTime temporalAccessor) { + ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault()); + return Date.from(zdt.toInstant()); + } + /** + * 增加 LocalDate ==> Date + */ + public static Date toDate(LocalDate temporalAccessor) { + LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0)); + ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault()); + return Date.from(zdt.toInstant()); + } + + public static String toMonthStr(int monthIndex) { + switch (monthIndex){ + case 1: + return "一月"; + case 2: + return "二月"; + case 3: + return "三月"; + case 4: + return "四月"; + case 5: + return "五月"; + case 6: + return "六月"; + case 7: + return "七月"; + case 8: + return "八月"; + case 9: + return "九月"; + case 10: + return "十月"; + case 11: + return "十一月"; + case 12: + return "十二月"; + default: + return ""; + } + } + + public static Integer getQuarterByMonth(int monthIndex) { + return monthIndex % 3 == 0 ? monthIndex / 3 : monthIndex / 3 + 1; + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/EncryptUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/EncryptUtils.java new file mode 100644 index 0000000..68476eb --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/EncryptUtils.java @@ -0,0 +1,226 @@ +package com.inscloudtech.common.utils; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.SmUtil; +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.RSA; +import cn.hutool.crypto.asymmetric.SM2; + +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +/** + * 安全相关工具类 + * + * @author inscloudtech + */ +public class EncryptUtils { /** + * 公钥 + */ + public static final String PUBLIC_KEY = "publicKey"; /** + * 私钥 + */ + public static final String PRIVATE_KEY = "privateKey"; + /** + * Base64加密 + * + * @param data 待加密数据 + * @return 加密后字符串 + */ + public static String encryptByBase64(String data) { + return Base64.encode(data, StandardCharsets.UTF_8); + } + /** + * Base64解密 + * + * @param data 待解密数据 + * @return 解密后字符串 + */ + public static String decryptByBase64(String data) { + return Base64.decodeStr(data, StandardCharsets.UTF_8); + } + /** + * AES加密 + * + * @param data 待解密数据 + * @param password 秘钥字符串 + * @return 加密后字符串, 采用Base64编码 + */ + public static String encryptByAes(String data, String password) { + if (StrUtil.isBlank(password)) { + throw new IllegalArgumentException("AES需要传入秘钥信息"); + } + // aes算法的秘钥要求是16位、24位、32位 + int[] array = {16, 24, 32}; + if (!ArrayUtil.contains(array, password.length())) { + throw new IllegalArgumentException("AES秘钥长度要求为16位、24位、32位"); + } + return SecureUtil.aes(password.getBytes(StandardCharsets.UTF_8)).encryptBase64(data, StandardCharsets.UTF_8); + } + /** + * AES解密 + * + * @param data 待解密数据 + * @param password 秘钥字符串 + * @return 解密后字符串 + */ + public static String decryptByAes(String data, String password) { + if (StrUtil.isBlank(password)) { + throw new IllegalArgumentException("AES需要传入秘钥信息"); + } + // aes算法的秘钥要求是16位、24位、32位 + int[] array = {16, 24, 32}; + if (!ArrayUtil.contains(array, password.length())) { + throw new IllegalArgumentException("AES秘钥长度要求为16位、24位、32位"); + } + return SecureUtil.aes(password.getBytes(StandardCharsets.UTF_8)).decryptStr(data, StandardCharsets.UTF_8); + } + /** + * sm4加密 + * + * @param data 待加密数据 + * @param password 秘钥字符串 + * @return 加密后字符串, 采用Base64编码 + */ + public static String encryptBySm4(String data, String password) { + if (StrUtil.isBlank(password)) { + throw new IllegalArgumentException("SM4需要传入秘钥信息"); + } + // sm4算法的秘钥要求是16位长度 + int sm4PasswordLength = 16; + if (sm4PasswordLength != password.length()) { + throw new IllegalArgumentException("SM4秘钥长度要求为16位"); + } + return SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8)).encryptBase64(data, StandardCharsets.UTF_8); + } + /** + * sm4解密 + * + * @param data 待解密数据 + * @param password 秘钥字符串 + * @return 解密后字符串 + */ + public static String decryptBySm4(String data, String password) { + if (StrUtil.isBlank(password)) { + throw new IllegalArgumentException("SM4需要传入秘钥信息"); + } + // sm4算法的秘钥要求是16位长度 + int sm4PasswordLength = 16; + if (sm4PasswordLength != password.length()) { + throw new IllegalArgumentException("SM4秘钥长度要求为16位"); + } + return SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8)).decryptStr(data, StandardCharsets.UTF_8); + } + /** + * 产生sm2加解密需要的公钥和私钥 + * + * @return 公私钥Map + */ + public static Map generateSm2Key() { + Map keyMap = new HashMap<>(2); + SM2 sm2 = SmUtil.sm2(); + keyMap.put(PRIVATE_KEY, sm2.getPrivateKeyBase64()); + keyMap.put(PUBLIC_KEY, sm2.getPublicKeyBase64()); + return keyMap; + } + /** + * sm2公钥加密 + * + * @param data 待加密数据 + * @param publicKey 公钥 + * @return 加密后字符串, 采用Base64编码 + */ + public static String encryptBySm2(String data, String publicKey) { + if (StrUtil.isBlank(publicKey)) { + throw new IllegalArgumentException("SM2需要传入公钥进行加密"); + } + SM2 sm2 = SmUtil.sm2(null, publicKey); + return sm2.encryptBase64(data, StandardCharsets.UTF_8, KeyType.PublicKey); + } + /** + * sm2私钥解密 + * + * @param data 待加密数据 + * @param privateKey 私钥 + * @return 解密后字符串 + */ + public static String decryptBySm2(String data, String privateKey) { + if (StrUtil.isBlank(privateKey)) { + throw new IllegalArgumentException("SM2需要传入私钥进行解密"); + } + SM2 sm2 = SmUtil.sm2(privateKey, null); + return sm2.decryptStr(data, KeyType.PrivateKey, StandardCharsets.UTF_8); + } + /** + * 产生RSA加解密需要的公钥和私钥 + * + * @return 公私钥Map + */ + public static Map generateRsaKey() { + Map keyMap = new HashMap<>(2); + RSA rsa = SecureUtil.rsa(); + keyMap.put(PRIVATE_KEY, rsa.getPrivateKeyBase64()); + keyMap.put(PUBLIC_KEY, rsa.getPublicKeyBase64()); + return keyMap; + } + /** + * rsa公钥加密 + * + * @param data 待加密数据 + * @param publicKey 公钥 + * @return 加密后字符串, 采用Base64编码 + */ + public static String encryptByRsa(String data, String publicKey) { + if (StrUtil.isBlank(publicKey)) { + throw new IllegalArgumentException("RSA需要传入公钥进行加密"); + } + RSA rsa = SecureUtil.rsa(null, publicKey); + return rsa.encryptBase64(data, StandardCharsets.UTF_8, KeyType.PublicKey); + } + /** + * rsa私钥解密 + * + * @param data 待加密数据 + * @param privateKey 私钥 + * @return 解密后字符串 + */ + public static String decryptByRsa(String data, String privateKey) { + if (StrUtil.isBlank(privateKey)) { + throw new IllegalArgumentException("RSA需要传入私钥进行解密"); + } + RSA rsa = SecureUtil.rsa(privateKey, null); + return rsa.decryptStr(data, KeyType.PrivateKey, StandardCharsets.UTF_8); + } + /** + * md5加密 + * + * @param data 待加密数据 + * @return 加密后字符串, 采用Hex编码 + */ + public static String encryptByMd5(String data) { + return SecureUtil.md5(data); + } + /** + * sha256加密 + * + * @param data 待加密数据 + * @return 加密后字符串, 采用Hex编码 + */ + public static String encryptBySha256(String data) { + return SecureUtil.sha256(data); + } + /** + * sm3加密 + * + * @param data 待加密数据 + * @return 加密后字符串, 采用Hex编码 + */ + public static String encryptBySm3(String data) { + return SmUtil.sm3(data); + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/JsonUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/JsonUtils.java new file mode 100644 index 0000000..7c98cc7 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/JsonUtils.java @@ -0,0 +1,112 @@ +package com.inscloudtech.common.utils; + +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; +import com.inscloudtech.common.utils.spring.SpringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * JSON 工具类 + * + * @author 芋道源码 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class JsonUtils { + + private static final ObjectMapper OBJECT_MAPPER = SpringUtils.getBean(ObjectMapper.class); + + public static ObjectMapper getObjectMapper() { + return OBJECT_MAPPER; + } + + public static String toJsonString(Object object) { + if (ObjectUtil.isNull(object)) { + return null; + } + try { + return OBJECT_MAPPER.writeValueAsString(object); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + public static T parseObject(String text, Class clazz) { + if (StringUtils.isEmpty(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, clazz); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static T parseObject(byte[] bytes, Class clazz) { + if (ArrayUtil.isEmpty(bytes)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(bytes, clazz); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static T parseObject(String text, TypeReference typeReference) { + if (StringUtils.isBlank(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, typeReference); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static Dict parseMap(String text) { + if (StringUtils.isBlank(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructType(Dict.class)); + } catch (MismatchedInputException e) { + // 类型不匹配说明不是json + return null; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static List parseArrayMap(String text) { + if (StringUtils.isBlank(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, Dict.class)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static List parseArray(String text, Class clazz) { + if (StringUtils.isEmpty(text)) { + return new ArrayList<>(); + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, clazz)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/MessageUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/MessageUtils.java new file mode 100644 index 0000000..62e08fb --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/MessageUtils.java @@ -0,0 +1,28 @@ +package com.inscloudtech.common.utils; + +import com.inscloudtech.common.utils.spring.SpringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.springframework.context.MessageSource; +import org.springframework.context.i18n.LocaleContextHolder; + +/** + * 获取i18n资源文件 + * + * @author inscloudtech + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class MessageUtils { + + private static final MessageSource MESSAGE_SOURCE = SpringUtils.getBean(MessageSource.class); + /** + * 根据消息键和参数 获取消息 委托给spring messageSource + * + * @param code 消息键 + * @param args 参数 + * @return 获取国际化翻译值 + */ + public static String message(String code, Object... args) { + return MESSAGE_SOURCE.getMessage(code, args, LocaleContextHolder.getLocale()); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/Obj2DDL.java b/cas-common/src/main/java/com/inscloudtech/common/utils/Obj2DDL.java new file mode 100644 index 0000000..1421bba --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/Obj2DDL.java @@ -0,0 +1,129 @@ +package com.inscloudtech.common.utils; + +import java.lang.reflect.Field; +import java.util.*; + +/*** + * + * @author Brandon Leaf + * @date 2021/1/20 16:01 + * @description + * 生成器 + */ +public class Obj2DDL { + + private final Map, String> typeMap = new HashMap<>(); + /** + * 初始化类型映射表 + */ + private void initDefaultTypeMap() { + typeMap.put(String.class, "varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT ''"); + typeMap.put(Long.class, "int NULL DEFAULT 0"); + typeMap.put(Double.class, "double(*,6)"); + typeMap.put(Integer.class, "int NULL DEFAULT 0"); + typeMap.put(Date.class, "datetime NULL DEFAULT NULL "); + } + + + public Obj2DDL() { + if (typeMap.isEmpty()) { + initDefaultTypeMap(); + } + } + /** + * + * @param customTypeMap 自定义映射表 + */ + public Obj2DDL(Map, String> customTypeMap) { + typeMap.putAll(customTypeMap); + } + + /** + * + * @param classList 类列表 + * @param tablePrefix 表前缀 + * @return create sql + */ + public String genCreateSql(List> classList, String tablePrefix) { + + StringBuilder sb = new StringBuilder("-- =====entity to create sql=====\n"); + + for (Class c : classList) { + Field[] declaredFields = c.getDeclaredFields(); + List fieldList = new ArrayList<>(); + for(Field f : declaredFields){ + String type = typeMap.get(f.getType()); + if(type!=null){ + fieldList.add(f); + } + } + if(fieldList.isEmpty()){ + continue; + } + + //title + String tableName = c.getSimpleName(); + String sqlTableName = enCodeUnderlined(tableName,true); + if (tablePrefix != null) { + sqlTableName = tablePrefix + sqlTableName; + } + sb.append("-- =====").append(tableName).append("=====").append(sqlTableName).append("=====\n\n\t"); + sb.append("CREATE TABLE `").append(sqlTableName).append("` (\n\t"); + + //todo columns + + for (int i = 0; i < fieldList.size(); i++) { + Field f = fieldList.get(i); + String type = typeMap.get(f.getType()); + + String name = f.getName(); + sb.append("`").append(enCodeUnderlined(name,true)).append("` ").append(type); + if (i != (fieldList.size() - 1)) { + sb.append(" ,\n\t"); + } + } + sb.append("\n\t);\n\n"); + + //todo remark + + } + return sb.toString(); + } + + // 首字母转小写 + public static String toLowerCaseFirstOne(String s) { + if (Character.isLowerCase(s.charAt(0))) + return s; + else + return Character.toLowerCase(s.charAt(0)) + + s.substring(1); + } + + // 大写字母前面加上下划线并转为全小写 + public static String enCodeUnderlined(String s,boolean isTableName) { + char[] chars = toLowerCaseFirstOne(s).toCharArray(); + StringBuilder temp = new StringBuilder(); + for (char aChar : chars) { + if(isTableName){ + if (Character.isUpperCase(aChar)) { + temp.append("_"); + } + } + temp.append(Character.toLowerCase(aChar)); + } + return temp.toString(); + } + /** + * demo + */ + public static void main(String[] args) { +// Obj2DDL gener = new Obj2DDL(); +// String s = gener.genCreateSql(Arrays.asList(ExternalDept.class), "external_"); +// //打印sql +// System.out.println(s); + } + +} + + + diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/ServletUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/ServletUtils.java new file mode 100644 index 0000000..f7e5668 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/ServletUtils.java @@ -0,0 +1,188 @@ +package com.inscloudtech.common.utils; + +import cn.hutool.core.convert.Convert; +import cn.hutool.extra.servlet.ServletUtil; +import cn.hutool.http.HttpStatus; +import com.inscloudtech.common.constant.Constants; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * 客户端工具类 + * + * @author inscloudtech + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ServletUtils extends ServletUtil { + /** + * 获取String参数 + */ + public static String getParameter(String name) { + return getRequest().getParameter(name); + } + /** + * 获取String参数 + */ + public static String getParameter(String name, String defaultValue) { + return Convert.toStr(getRequest().getParameter(name), defaultValue); + } + /** + * 获取Integer参数 + */ + public static Integer getParameterToInt(String name) { + return Convert.toInt(getRequest().getParameter(name)); + } + /** + * 获取Integer参数 + */ + public static Integer getParameterToInt(String name, Integer defaultValue) { + return Convert.toInt(getRequest().getParameter(name), defaultValue); + } + /** + * 获取Boolean参数 + */ + public static Boolean getParameterToBool(String name) { + return Convert.toBool(getRequest().getParameter(name)); + } + /** + * 获取Boolean参数 + */ + public static Boolean getParameterToBool(String name, Boolean defaultValue) { + return Convert.toBool(getRequest().getParameter(name), defaultValue); + } + /** + * 获得所有请求参数 + * + * @param request 请求对象{@link ServletRequest} + * @return Map + */ + public static Map getParams(ServletRequest request) { + final Map map = request.getParameterMap(); + return Collections.unmodifiableMap(map); + } + /** + * 获得所有请求参数 + * + * @param request 请求对象{@link ServletRequest} + * @return Map + */ + public static Map getParamMap(ServletRequest request) { + Map params = new HashMap<>(); + for (Map.Entry entry : getParams(request).entrySet()) { + params.put(entry.getKey(), StringUtils.join(entry.getValue(), StringUtils.SEPARATOR)); + } + return params; + } + /** + * 获取request + */ + public static HttpServletRequest getRequest() { + return getRequestAttributes().getRequest(); + } + /** + * 获取response + */ + public static HttpServletResponse getResponse() { + return getRequestAttributes().getResponse(); + } + /** + * 获取session + */ + public static HttpSession getSession() { + return getRequest().getSession(); + } + + public static ServletRequestAttributes getRequestAttributes() { + RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); + return (ServletRequestAttributes) attributes; + } + /** + * 将字符串渲染到客户端 + * + * @param response 渲染对象 + * @param string 待渲染的字符串 + */ + public static void renderString(HttpServletResponse response, String string) { + try { + response.setStatus(HttpStatus.HTTP_OK); + response.setContentType(MediaType.APPLICATION_JSON_VALUE); + response.setCharacterEncoding(StandardCharsets.UTF_8.toString()); + response.getWriter().print(string); + } catch (IOException e) { + e.printStackTrace(); + } + } + /** + * 是否是Ajax异步请求 + * + * @param request + */ + public static boolean isAjaxRequest(HttpServletRequest request) { + + String accept = request.getHeader("accept"); + if (accept != null && accept.contains(MediaType.APPLICATION_JSON_VALUE)) { + return true; + } + + String xRequestedWith = request.getHeader("X-Requested-With"); + if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest")) { + return true; + } + + String uri = request.getRequestURI(); + if (StringUtils.equalsAnyIgnoreCase(uri, ".json", ".xml")) { + return true; + } + + String ajax = request.getParameter("__ajax"); + return StringUtils.equalsAnyIgnoreCase(ajax, "json", "xml"); + } + + public static String getClientIP() { + return getClientIP(getRequest()); + } + /** + * 内容编码 + * + * @param str 内容 + * @return 编码后的内容 + */ + public static String urlEncode(String str) { + try { + return URLEncoder.encode(str, Constants.UTF8); + } catch (UnsupportedEncodingException e) { + return StringUtils.EMPTY; + } + } + /** + * 内容解码 + * + * @param str 内容 + * @return 解码后的内容 + */ + public static String urlDecode(String str) { + try { + return URLDecoder.decode(str, Constants.UTF8); + } catch (UnsupportedEncodingException e) { + return StringUtils.EMPTY; + } + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/StreamUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/StreamUtils.java new file mode 100644 index 0000000..87859bf --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/StreamUtils.java @@ -0,0 +1,239 @@ +package com.inscloudtech.common.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.*; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +/** + * stream 流工具类 + * + * @author inscloudtech + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class StreamUtils { + /** + * 将collection过滤 + * + * @param collection 需要转化的集合 + * @param function 过滤方法 + * @return 过滤后的list + */ + public static List filter(Collection collection, Predicate function) { + if (CollUtil.isEmpty(collection)) { + return CollUtil.newArrayList(); + } + return collection.stream().filter(function).collect(Collectors.toList()); + } + /** + * 将collection拼接 + * + * @param collection 需要转化的集合 + * @param function 拼接方法 + * @return 拼接后的list + */ + public static String join(Collection collection, Function function) { + return join(collection, function, StringUtils.SEPARATOR); + } + /** + * 将collection拼接 + * + * @param collection 需要转化的集合 + * @param function 拼接方法 + * @param delimiter 拼接符 + * @return 拼接后的list + */ + public static String join(Collection collection, Function function, CharSequence delimiter) { + if (CollUtil.isEmpty(collection)) { + return StringUtils.EMPTY; + } + return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.joining(delimiter)); + } + /** + * 将collection排序 + * + * @param collection 需要转化的集合 + * @param comparing 排序方法 + * @return 排序后的list + */ + public static List sorted(Collection collection, Comparator comparing) { + if (CollUtil.isEmpty(collection)) { + return CollUtil.newArrayList(); + } + return collection.stream().sorted(comparing).collect(Collectors.toList()); + } + /** + * 将collection转化为类型不变的map
+ * {@code Collection ----> Map} + * + * @param collection 需要转化的集合 + * @param key V类型转化为K类型的lambda方法 + * @param collection中的泛型 + * @param map中的key类型 + * @return 转化后的map + */ + public static Map toIdentityMap(Collection collection, Function key) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection.stream().collect(Collectors.toMap(key, Function.identity(), (l, r) -> l)); + } + /** + * 将Collection转化为map(value类型与collection的泛型不同)
+ * {@code Collection -----> Map } + * + * @param collection 需要转化的集合 + * @param key E类型转化为K类型的lambda方法 + * @param value E类型转化为V类型的lambda方法 + * @param collection中的泛型 + * @param map中的key类型 + * @param map中的value类型 + * @return 转化后的map + */ + public static Map toMap(Collection collection, Function key, Function value) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection.stream().collect(Collectors.toMap(key, value, (l, r) -> l)); + } + /** + * 将collection按照规则(比如有相同的班级id)分类成map
+ * {@code Collection -------> Map> } + * + * @param collection 需要分类的集合 + * @param key 分类的规则 + * @param collection中的泛型 + * @param map中的key类型 + * @return 分类后的map + */ + public static Map> groupByKey(Collection collection, Function key) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection + .stream() + .collect(Collectors.groupingBy(key, LinkedHashMap::new, Collectors.toList())); + } + /** + * 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map
+ * {@code Collection ---> Map>> } + * + * @param collection 需要分类的集合 + * @param key1 第一个分类的规则 + * @param key2 第二个分类的规则 + * @param 集合元素类型 + * @param 第一个map中的key类型 + * @param 第二个map中的key类型 + * @return 分类后的map + */ + public static Map>> groupBy2Key(Collection collection, Function key1, Function key2) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection + .stream() + .collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.groupingBy(key2, LinkedHashMap::new, Collectors.toList()))); + } + /** + * 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map
+ * {@code Collection ---> Map> } + * + * @param collection 需要分类的集合 + * @param key1 第一个分类的规则 + * @param key2 第二个分类的规则 + * @param 第一个map中的key类型 + * @param 第二个map中的key类型 + * @param collection中的泛型 + * @return 分类后的map + */ + public static Map> group2Map(Collection collection, Function key1, Function key2) { + if (CollUtil.isEmpty(collection) || key1 == null || key2 == null) { + return MapUtil.newHashMap(); + } + return collection + .stream() + .collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.toMap(key2, Function.identity(), (l, r) -> l))); + } + /** + * 将collection转化为List集合,但是两者的泛型不同
+ * {@code Collection ------> List } + * + * @param collection 需要转化的集合 + * @param function collection中的泛型转化为list泛型的lambda表达式 + * @param collection中的泛型 + * @param List中的泛型 + * @return 转化后的list + */ + public static List toList(Collection collection, Function function) { + if (CollUtil.isEmpty(collection)) { + return CollUtil.newArrayList(); + } + return collection + .stream() + .map(function) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + /** + * 将collection转化为Set集合,但是两者的泛型不同
+ * {@code Collection ------> Set } + * + * @param collection 需要转化的集合 + * @param function collection中的泛型转化为set泛型的lambda表达式 + * @param collection中的泛型 + * @param Set中的泛型 + * @return 转化后的Set + */ + public static Set toSet(Collection collection, Function function) { + if (CollUtil.isEmpty(collection) || function == null) { + return CollUtil.newHashSet(); + } + return collection + .stream() + .map(function) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + } + + /** + * 合并两个相同key类型的map + * + * @param map1 第一个需要合并的 map + * @param map2 第二个需要合并的 map + * @param merge 合并的lambda,将key value1 value2合并成最终的类型,注意value可能为空的情况 + * @param map中的key类型 + * @param 第一个 map的value类型 + * @param 第二个 map的value类型 + * @param 最终map的value类型 + * @return 合并后的map + */ + public static Map merge(Map map1, Map map2, BiFunction merge) { + if (MapUtil.isEmpty(map1) && MapUtil.isEmpty(map2)) { + return MapUtil.newHashMap(); + } else if (MapUtil.isEmpty(map1)) { + map1 = MapUtil.newHashMap(); + } else if (MapUtil.isEmpty(map2)) { + map2 = MapUtil.newHashMap(); + } + Set key = new HashSet<>(); + key.addAll(map1.keySet()); + key.addAll(map2.keySet()); + Map map = new HashMap<>(); + for (K t : key) { + X x = map1.get(t); + Y y = map2.get(t); + V z = merge.apply(x, y); + if (z != null) { + map.put(t, z); + } + } + return map; + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/StringUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/StringUtils.java new file mode 100644 index 0000000..8cdd8bd --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/StringUtils.java @@ -0,0 +1,313 @@ +package com.inscloudtech.common.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Validator; +import cn.hutool.core.util.StrUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.springframework.util.AntPathMatcher; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 字符串工具类 + * + * @author inscloudtech + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class StringUtils extends org.apache.commons.lang3.StringUtils { + + public static final String SEPARATOR = ","; + /** + * 获取参数不为空值 + * + * @param str defaultValue 要判断的value + * @return value 返回值 + */ + public static String blankToDefault(String str, String defaultValue) { + return StrUtil.blankToDefault(str, defaultValue); + } + /** + * * 判断一个字符串是否为空串 + * + * @param str String + * @return true:为空 false:非空 + */ + public static boolean isEmpty(String str) { + return StrUtil.isEmpty(str); + } + /** + * * 判断一个字符串是否为非空串 + * + * @param str String + * @return true:非空串 false:空串 + */ + public static boolean isNotEmpty(String str) { + return !isEmpty(str); + } + /** + * 去空格 + */ + public static String trim(String str) { + return StrUtil.trim(str); + } + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @return 结果 + */ + public static String substring(final String str, int start) { + return substring(str, start, str.length()); + } + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @param end 结束 + * @return 结果 + */ + public static String substring(final String str, int start, int end) { + return StrUtil.sub(str, start, end); + } + /** + * 格式化文本, {} 表示占位符
+ * 此方法只是简单将占位符 {} 按照顺序替换为参数
+ * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可
+ * 例:
+ * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
+ * 转义{}: format("this is \\{} for {}", "a", "b") -> this is {} for a
+ * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
+ * + * @param template 文本模板,被替换的部分用 {} 表示 + * @param params 参数值 + * @return 格式化后的文本 + */ + public static String format(String template, Object... params) { + return StrUtil.format(template, params); + } + /** + * 是否为http(s)://开头 + * + * @param link 链接 + * @return 结果 + */ + public static boolean ishttp(String link) { + return Validator.isUrl(link); + } + /** + * 字符串转set + * + * @param str 字符串 + * @param sep 分隔符 + * @return set集合 + */ + public static Set str2Set(String str, String sep) { + return new HashSet<>(str2List(str, sep, true, false)); + } + /** + * 字符串转list + * + * @param str 字符串 + * @param sep 分隔符 + * @param filterBlank 过滤纯空白 + * @param trim 去掉首尾空白 + * @return list集合 + */ + public static List str2List(String str, String sep, boolean filterBlank, boolean trim) { + List list = new ArrayList<>(); + if (isEmpty(str)) { + return list; + } + + // 过滤空白字符串 + if (filterBlank && isBlank(str)) { + return list; + } + String[] split = str.split(sep); + for (String string : split) { + if (filterBlank && isBlank(string)) { + continue; + } + if (trim) { + string = trim(string); + } + list.add(string); + } + + return list; + } + /** + * 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写 + * + * @param cs 指定字符串 + * @param searchCharSequences 需要检查的字符串数组 + * @return 是否包含任意一个字符串 + */ + public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) { + return StrUtil.containsAnyIgnoreCase(cs, searchCharSequences); + } + /** + * 驼峰转下划线命名 + */ + public static String toUnderScoreCase(String str) { + return StrUtil.toUnderlineCase(str); + } + /** + * 是否包含字符串 + * + * @param str 验证字符串 + * @param strs 字符串组 + * @return 包含返回true + */ + public static boolean inStringIgnoreCase(String str, String... strs) { + return StrUtil.equalsAnyIgnoreCase(str, strs); + } + /** + * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld + * + * @param name 转换前的下划线大写方式命名的字符串 + * @return 转换后的驼峰式命名的字符串 + */ + public static String convertToCamelCase(String name) { + return StrUtil.upperFirst(StrUtil.toCamelCase(name)); + } + /** + * 驼峰式命名法 例如:user_name->userName + */ + public static String toCamelCase(String s) { + return StrUtil.toCamelCase(s); + } + /** + * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串 + * + * @param str 指定字符串 + * @param strs 需要检查的字符串数组 + * @return 是否匹配 + */ + public static boolean matches(String str, List strs) { + if (isEmpty(str) || CollUtil.isEmpty(strs)) { + return false; + } + for (String pattern : strs) { + if (isMatch(pattern, str)) { + return true; + } + } + return false; + } + /** + * 判断url是否与规则配置: + * ? 表示单个字符; + * * 表示一层路径内的任意字符串,不可跨层级; + * ** 表示任意层路径; + * + * @param pattern 匹配规则 + * @param url 需要匹配的url + */ + public static boolean isMatch(String pattern, String url) { + AntPathMatcher matcher = new AntPathMatcher(); + return matcher.match(pattern, url); + } + /** + * 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。 + * + * @param num 数字对象 + * @param size 字符串指定长度 + * @return 返回数字的字符串格式,该字符串为指定长度。 + */ + public static String padl(final Number num, final int size) { + return padl(num.toString(), size, '0'); + } + /** + * 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。 + * + * @param s 原始字符串 + * @param size 字符串指定长度 + * @param c 用于补齐的字符 + * @return 返回指定长度的字符串,由原字符串左补齐或截取得到。 + */ + public static String padl(final String s, final int size, final char c) { + final StringBuilder sb = new StringBuilder(size); + if (s != null) { + final int len = s.length(); + if (s.length() <= size) { + for (int i = size - len; i > 0; i--) { + sb.append(c); + } + sb.append(s); + } else { + return s.substring(len - size, len); + } + } else { + for (int i = size; i > 0; i--) { + sb.append(c); + } + } + return sb.toString(); + } + /** + * 切分字符串(分隔符默认逗号) + * + * @param str 被切分的字符串 + * @return 分割后的数据列表 + */ + public static List splitList(String str) { + return splitTo(str, Convert::toStr); + } + /** + * 切分字符串 + * + * @param str 被切分的字符串 + * @param separator 分隔符 + * @return 分割后的数据列表 + */ + public static List splitList(String str, String separator) { + return splitTo(str, separator, Convert::toStr); + } + /** + * 切分字符串自定义转换(分隔符默认逗号) + * + * @param str 被切分的字符串 + * @param mapper 自定义转换 + * @return 分割后的数据列表 + */ + public static List splitTo(String str, Function mapper) { + return splitTo(str, SEPARATOR, mapper); + } + /** + * 切分字符串自定义转换 + * + * @param str 被切分的字符串 + * @param separator 分隔符 + * @param mapper 自定义转换 + * @return 分割后的数据列表 + */ + public static List splitTo(String str, String separator, Function mapper) { + if (isBlank(str)) { + return new ArrayList<>(0); + } + return StrUtil.split(str, separator) + .stream() + .filter(Objects::nonNull) + .map(mapper) + .collect(Collectors.toList()); + } + + public static String firstCharToLowercase(String str) { + if (str == null || str.length() == 0) { + return str; + } + char[] chars = str.toCharArray(); + if (chars[0] >= 'A' && chars[0] <= 'Z') { + chars[0] += ('a' - 'A'); + } + return new String(chars); + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/Threads.java b/cas-common/src/main/java/com/inscloudtech/common/utils/Threads.java new file mode 100644 index 0000000..a4299b9 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/Threads.java @@ -0,0 +1,72 @@ +package com.inscloudtech.common.utils; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.*; + +/** + * 线程相关工具类. + * + * @author inscloudtech + */ +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class Threads { + /** + * sleep等待,单位为毫秒 + */ + public static void sleep(long milliseconds) { + try { + Thread.sleep(milliseconds); + } catch (InterruptedException e) { + return; + } + } + /** + * 停止线程池 + * 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务. + * 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数. + * 如果仍然超時,則強制退出. + * 另对在shutdown时线程本身被调用中断做了处理. + */ + public static void shutdownAndAwaitTermination(ExecutorService pool) { + if (pool != null && !pool.isShutdown()) { + pool.shutdown(); + try { + if (!pool.awaitTermination(120, TimeUnit.SECONDS)) { + pool.shutdownNow(); + if (!pool.awaitTermination(120, TimeUnit.SECONDS)) { + log.info("Pool did not terminate"); + } + } + } catch (InterruptedException ie) { + pool.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + } + /** + * 打印线程异常信息 + */ + public static void printException(Runnable r, Throwable t) { + if (t == null && r instanceof Future) { + try { + Future future = (Future) r; + if (future.isDone()) { + future.get(); + } + } catch (CancellationException ce) { + t = ce; + } catch (ExecutionException ee) { + t = ee.getCause(); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + } + if (t != null) { + log.error(t.getMessage(), t); + } + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/TreeBuildUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/TreeBuildUtils.java new file mode 100644 index 0000000..2d3ec8e --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/TreeBuildUtils.java @@ -0,0 +1,34 @@ +package com.inscloudtech.common.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.lang.tree.TreeNodeConfig; +import cn.hutool.core.lang.tree.TreeUtil; +import cn.hutool.core.lang.tree.parser.NodeParser; +import com.inscloudtech.common.utils.reflect.ReflectUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 扩展 hutool TreeUtil 封装系统树构建 + * + * @author inscloudtech + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class TreeBuildUtils extends TreeUtil { + /** + * 根据前端定制差异化字段 + */ + public static final TreeNodeConfig DEFAULT_CONFIG = TreeNodeConfig.DEFAULT_CONFIG.setNameKey("label"); + + public static List> build(List list, NodeParser nodeParser) { + if (CollUtil.isEmpty(list)) { + return null; + } + K k = ReflectUtils.invokeGetter(list.get(0), "parentId"); + return TreeUtil.build(list, k, DEFAULT_CONFIG, nodeParser); + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/ValidatorUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/ValidatorUtils.java new file mode 100644 index 0000000..8779a43 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/ValidatorUtils.java @@ -0,0 +1,29 @@ +package com.inscloudtech.common.utils; + +import com.inscloudtech.common.utils.spring.SpringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.validation.Validator; +import java.util.Set; + +/** + * Validator 校验框架工具 + * + * @author inscloudtech + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ValidatorUtils { + + private static final Validator VALID = SpringUtils.getBean(Validator.class); + + public static void validate(T object, Class... groups) { + Set> validate = VALID.validate(object, groups); + if (!validate.isEmpty()) { + throw new ConstraintViolationException("参数校验异常", validate); + } + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/bean/BeanUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/bean/BeanUtils.java new file mode 100644 index 0000000..81aebdc --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/bean/BeanUtils.java @@ -0,0 +1,224 @@ +package com.inscloudtech.common.utils.bean; + +import cn.hutool.core.util.StrUtil; +import com.inscloudtech.common.annotation.DeduplicationField; +import lombok.SneakyThrows; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Bean 工具类 + * + * @author ruoyi + */ +public class BeanUtils extends org.springframework.beans.BeanUtils { + /** + * Bean方法名中属性名开始的下标 + */ + private static final int BEAN_METHOD_PROP_INDEX = 3; + + /** + * 匹配getter方法的正则表达式 + */ + private static final Pattern GET_PATTERN = Pattern.compile("get(\\p{javaUpperCase}\\w*)"); + + /** + * 匹配setter方法的正则表达式 + */ + private static final Pattern SET_PATTERN = Pattern.compile("set(\\p{javaUpperCase}\\w*)"); + + /** + * Bean属性复制工具方法。 + * + * @param dest 目标对象 + * @param src 源对象 + */ + public static void copyBeanProp(Object dest, Object src) { + try { + copyProperties(src, dest); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 获取对象的setter方法。 + * + * @param obj 对象 + * @return 对象的setter方法列表 + */ + public static List getSetterMethods(Object obj) { + // setter方法列表 + List setterMethods = new ArrayList(); + + // 获取所有方法 + Method[] methods = obj.getClass().getMethods(); + + // 查找setter方法 + + for (Method method : methods) { + Matcher m = SET_PATTERN.matcher(method.getName()); + if (m.matches() && (method.getParameterTypes().length == 1)) { + setterMethods.add(method); + } + } + // 返回setter方法列表 + return setterMethods; + } + + /** + * 获取对象的getter方法。 + * + * @param obj 对象 + * @return 对象的getter方法列表 + */ + + public static List getGetterMethods(Object obj) { + // getter方法列表 + List getterMethods = new ArrayList(); + // 获取所有方法 + Method[] methods = obj.getClass().getMethods(); + // 查找getter方法 + for (Method method : methods) { + Matcher m = GET_PATTERN.matcher(method.getName()); + if (m.matches() && (method.getParameterTypes().length == 0)) { + getterMethods.add(method); + } + } + // 返回getter方法列表 + return getterMethods; + } + + /** + * 检查Bean方法名中的属性名是否相等。
+ * 如getName()和setName()属性名一样,getName()和setAge()属性名不一样。 + * + * @param m1 方法名1 + * @param m2 方法名2 + * @return 属性名一样返回true,否则返回false + */ + + public static boolean isMethodPropEquals(String m1, String m2) { + return m1.substring(BEAN_METHOD_PROP_INDEX).equals(m2.substring(BEAN_METHOD_PROP_INDEX)); + } + + public static T mergeObjects(T oldObj, T newObj) { + try { + // 获取类的所有字段 + Field[] fields = oldObj.getClass().getDeclaredFields(); + + // 遍历字段 + for (Field field : fields) { + field.setAccessible(true); + if(field.getName().contains("serialVersionUID")){ + continue; + } + // 如果新对象的属性值不为null,则覆盖旧对象的属性 + if (field.get(newObj) != null) { + field.set(oldObj, field.get(newObj)); + } + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + return oldObj; + } + + /** + * 利用发射调用bean.set方法将value设置到字段 + * @param bean + * @param fieldName + * @param value + * @throws Exception + */ + private static void setFieldValue(Object bean, String fieldName, Object value) + throws Exception { + StringBuffer result = new StringBuffer(); + String methodName = result.append("set") + .append(fieldName.substring(0, 1).toUpperCase()) + .append(fieldName.substring(1)).toString(); + + /** + * 利用发射调用bean.set方法将value设置到字段 + */ + Class[] classArr = new Class[1]; + classArr[0]="java.lang.String".getClass(); + Method method=bean.getClass().getMethod(methodName,classArr); + method.invoke(bean,value); + } + + /** + * 利用反射通过get方法获取bean中字段fieldName的值 + * @param bean + * @param fieldName + * @return + * @throws Exception + */ + public static Object getFieldValue(Object bean, String fieldName) + throws Exception { + StringBuffer result = new StringBuffer(); + String methodName = result.append("get") + .append(fieldName.substring(0, 1).toUpperCase()) + .append(fieldName.substring(1)).toString(); + + Object rObject = null; + Method method = null; + + @SuppressWarnings("rawtypes") + Class[] classArr = new Class[0]; + method = bean.getClass().getMethod(methodName, classArr); + rObject = method.invoke(bean, new Object[0]); + + return rObject; + } + + /** + * 去掉bean中所有属性为字符串的空格 + * @param bean + * @throws Exception + */ + @SneakyThrows + public static void beanAttributeValueTrim(Object bean) { + if(bean!=null){ + //获取所有的字段包括public,private,protected,private + Field[] fields = bean.getClass().getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + Field f = fields[i]; + if (f.getType().getName().equals("java.lang.String")) { + String key = f.getName();//获取字段名 + Object valueObj = getFieldValue(bean, key); + String value = valueObj == null?"":valueObj.toString(); + //全角空格 + setFieldValue(bean, key, value.trim().replaceAll("([ ]|\\s|\\u00A0)+","")); + } + } + } + } + + @SneakyThrows + public static String getUniqueKey(Object obj){ + Field[] fields = obj.getClass().getDeclaredFields(); + StringBuilder uniqueKeySb = new StringBuilder(); + for (Field field : fields) { + field.setAccessible(true); + if (!field.isAnnotationPresent(DeduplicationField.class)) { + continue; + } + Object value = BeanUtils.getFieldValue(obj, field.getName()); + if (field.getType().getName().equals("java.lang.String")) { + if(value == null){ + value = ""; + }else { + value = StrUtil.isEmpty(value.toString())?"":value.toString(); + } + } + uniqueKeySb.append(value); + } + return uniqueKeySb.toString(); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/bean/BeanValidators.java b/cas-common/src/main/java/com/inscloudtech/common/utils/bean/BeanValidators.java new file mode 100644 index 0000000..dc6e2a0 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/bean/BeanValidators.java @@ -0,0 +1,21 @@ +package com.inscloudtech.common.utils.bean; + +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.validation.Validator; +import java.util.Set; + +/** + * bean对象属性验证 + * + * @author ruoyi + */ +public class BeanValidators { + public static void validateWithException(Validator validator, Object object, Class... groups) + throws ConstraintViolationException { + Set> constraintViolations = validator.validate(object, groups); + if (!constraintViolations.isEmpty()) { + throw new ConstraintViolationException(constraintViolations); + } + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/email/MailUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/email/MailUtils.java new file mode 100644 index 0000000..73c9775 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/email/MailUtils.java @@ -0,0 +1,443 @@ +package com.inscloudtech.common.utils.email; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.CharUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.mail.*; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.spring.SpringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import javax.mail.Authenticator; +import javax.mail.Session; +import java.io.File; +import java.io.InputStream; +import java.util.Collection; +import java.util.List; +import java.util.Map; + + +/** + * 邮件工具类 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class MailUtils { + + private static final MailAccount ACCOUNT = SpringUtils.getBean(MailAccount.class); + /** + * 获取邮件发送实例 + */ + public static MailAccount getMailAccount() { + return ACCOUNT; + } + /** + * 获取邮件发送实例 (自定义发送人以及授权码) + * + * @param user 发送人 + * @param pass 授权码 + */ + public static MailAccount getMailAccount(String from, String user, String pass) { + ACCOUNT.setFrom(StringUtils.blankToDefault(from, ACCOUNT.getFrom())); + ACCOUNT.setUser(StringUtils.blankToDefault(user, ACCOUNT.getUser())); + ACCOUNT.setPass(StringUtils.blankToDefault(pass, ACCOUNT.getPass())); + return ACCOUNT; + } + /** + * 使用配置文件中设置的账户发送文本邮件,发送给单个或多个收件人
+ * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人 + * @param subject 标题 + * @param content 正文 + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String sendText(String to, String subject, String content, File... files) { + return send(to, subject, content, false, files); + } + /** + * 使用配置文件中设置的账户发送HTML邮件,发送给单个或多个收件人
+ * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人 + * @param subject 标题 + * @param content 正文 + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String sendHtml(String to, String subject, String content, File... files) { + return send(to, subject, content, true, files); + } + /** + * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人
+ * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + */ + public static String send(String to, String subject, String content, boolean isHtml, File... files) { + return send(splitAddress(to), subject, content, isHtml, files); + } + /** + * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人
+ * 多个收件人、抄送人、密送人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param cc 抄送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param bcc 密送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + * @since 4.0.3 + */ + public static String send(String to, String cc, String bcc, String subject, String content, boolean isHtml, File... files) { + return send(splitAddress(to), splitAddress(cc), splitAddress(bcc), subject, content, isHtml, files); + } + /** + * 使用配置文件中设置的账户发送文本邮件,发送给多人 + * + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param files 附件列表 + * @return message-id + */ + public static String sendText(Collection tos, String subject, String content, File... files) { + return send(tos, subject, content, false, files); + } + /** + * 使用配置文件中设置的账户发送HTML邮件,发送给多人 + * + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String sendHtml(Collection tos, String subject, String content, File... files) { + return send(tos, subject, content, true, files); + } + /** + * 使用配置文件中设置的账户发送邮件,发送给多人 + * + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + */ + public static String send(Collection tos, String subject, String content, boolean isHtml, File... files) { + return send(tos, null, null, subject, content, isHtml, files); + } + /** + * 使用配置文件中设置的账户发送邮件,发送给多人 + * + * @param tos 收件人列表 + * @param ccs 抄送人列表,可以为null或空 + * @param bccs 密送人列表,可以为null或空 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + * @since 4.0.3 + */ + public static String send(Collection tos, Collection ccs, Collection bccs, String subject, String content, boolean isHtml, File... files) { + return send(getMailAccount(), true, tos, ccs, bccs, subject, content, null, isHtml, files); + } + + // ------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件认证对象 + * @param to 收件人,多个收件人逗号或者分号隔开 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String send(MailAccount mailAccount, String to, String subject, String content, boolean isHtml, File... files) { + return send(mailAccount, splitAddress(to), subject, content, isHtml, files); + } + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件帐户信息 + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + */ + public static String send(MailAccount mailAccount, Collection tos, String subject, String content, boolean isHtml, File... files) { + return send(mailAccount, tos, null, null, subject, content, isHtml, files); + } + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件帐户信息 + * @param tos 收件人列表 + * @param ccs 抄送人列表,可以为null或空 + * @param bccs 密送人列表,可以为null或空 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 4.0.3 + */ + public static String send(MailAccount mailAccount, Collection tos, Collection ccs, Collection bccs, String subject, String content, boolean isHtml, File... files) { + return send(mailAccount, false, tos, ccs, bccs, subject, content, null, isHtml, files); + } + /** + * 使用配置文件中设置的账户发送HTML邮件,发送给单个或多个收件人
+ * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String sendHtml(String to, String subject, String content, Map imageMap, File... files) { + return send(to, subject, content, imageMap, true, files); + } + /** + * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人
+ * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + */ + public static String send(String to, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(splitAddress(to), subject, content, imageMap, isHtml, files); + } + /** + * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人
+ * 多个收件人、抄送人、密送人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param cc 抄送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param bcc 密送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + * @since 4.0.3 + */ + public static String send(String to, String cc, String bcc, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(splitAddress(to), splitAddress(cc), splitAddress(bcc), subject, content, imageMap, isHtml, files); + } + /** + * 使用配置文件中设置的账户发送HTML邮件,发送给多人 + * + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String sendHtml(Collection tos, String subject, String content, Map imageMap, File... files) { + return send(tos, subject, content, imageMap, true, files); + } + /** + * 使用配置文件中设置的账户发送邮件,发送给多人 + * + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + */ + public static String send(Collection tos, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(tos, null, null, subject, content, imageMap, isHtml, files); + } + /** + * 使用配置文件中设置的账户发送邮件,发送给多人 + * + * @param tos 收件人列表 + * @param ccs 抄送人列表,可以为null或空 + * @param bccs 密送人列表,可以为null或空 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + * @since 4.0.3 + */ + public static String send(Collection tos, Collection ccs, Collection bccs, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(getMailAccount(), true, tos, ccs, bccs, subject, content, imageMap, isHtml, files); + } + + // ------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件认证对象 + * @param to 收件人,多个收件人逗号或者分号隔开 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String send(MailAccount mailAccount, String to, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(mailAccount, splitAddress(to), subject, content, imageMap, isHtml, files); + } + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件帐户信息 + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 4.6.3 + */ + public static String send(MailAccount mailAccount, Collection tos, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(mailAccount, tos, null, null, subject, content, imageMap, isHtml, files); + } + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件帐户信息 + * @param tos 收件人列表 + * @param ccs 抄送人列表,可以为null或空 + * @param bccs 密送人列表,可以为null或空 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 4.6.3 + */ + public static String send(MailAccount mailAccount, Collection tos, Collection ccs, Collection bccs, String subject, String content, Map imageMap, + boolean isHtml, File... files) { + return send(mailAccount, false, tos, ccs, bccs, subject, content, imageMap, isHtml, files); + } + /** + * 根据配置文件,获取邮件客户端会话 + * + * @param mailAccount 邮件账户配置 + * @param isSingleton 是否单例(全局共享会话) + * @return {@link Session} + * @since 5.5.7 + */ + public static Session getSession(MailAccount mailAccount, boolean isSingleton) { + Authenticator authenticator = null; + if (mailAccount.isAuth()) { + authenticator = new UserPassAuthenticator(mailAccount.getUser(), mailAccount.getPass()); + } + + return isSingleton ? Session.getDefaultInstance(mailAccount.getSmtpProps(), authenticator) // + : Session.getInstance(mailAccount.getSmtpProps(), authenticator); + } + + // ------------------------------------------------------------------------------------------------------------------------ Private method start + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件帐户信息 + * @param useGlobalSession 是否全局共享Session + * @param tos 收件人列表 + * @param ccs 抄送人列表,可以为null或空 + * @param bccs 密送人列表,可以为null或空 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:${cid} + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 4.6.3 + */ + private static String send(MailAccount mailAccount, boolean useGlobalSession, Collection tos, Collection ccs, Collection bccs, String subject, String content, + Map imageMap, boolean isHtml, File... files) { + final Mail mail = Mail.create(mailAccount).setUseGlobalSession(useGlobalSession); + + // 可选抄送人 + if (CollUtil.isNotEmpty(ccs)) { + mail.setCcs(ccs.toArray(new String[0])); + } + // 可选密送人 + if (CollUtil.isNotEmpty(bccs)) { + mail.setBccs(bccs.toArray(new String[0])); + } + + mail.setTos(tos.toArray(new String[0])); + mail.setTitle(subject); + mail.setContent(content); + mail.setHtml(isHtml); + mail.setFiles(files); + + // 图片 + if (MapUtil.isNotEmpty(imageMap)) { + for (Map.Entry entry : imageMap.entrySet()) { + mail.addImage(entry.getKey(), entry.getValue()); + // 关闭流 + IoUtil.close(entry.getValue()); + } + } + + return mail.send(); + } + /** + * 将多个联系人转为列表,分隔符为逗号或者分号 + * + * @param addresses 多个联系人,如果为空返回null + * @return 联系人列表 + */ + private static List splitAddress(String addresses) { + if (StrUtil.isBlank(addresses)) { + return null; + } + + List result; + if (StrUtil.contains(addresses, CharUtil.COMMA)) { + result = StrUtil.splitTrim(addresses, CharUtil.COMMA); + } else if (StrUtil.contains(addresses, ';')) { + result = StrUtil.splitTrim(addresses, ';'); + } else { + result = CollUtil.newArrayList(addresses); + } + return result; + } + // ------------------------------------------------------------------------------------------------------------------------ Private method end + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/file/ExtractCallback.java b/cas-common/src/main/java/com/inscloudtech/common/utils/file/ExtractCallback.java new file mode 100644 index 0000000..638d303 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/file/ExtractCallback.java @@ -0,0 +1,129 @@ +package com.inscloudtech.common.utils.file; + +import net.sf.sevenzipjbinding.*; + +import java.io.*; + +public class ExtractCallback implements IArchiveExtractCallback { + + private int index; + private IInArchive inArchive; + private String ourDir; + + public ExtractCallback(IInArchive inArchive, String ourDir) { + this.inArchive = inArchive; + this.ourDir = ourDir; + } + + @Override + public void setCompleted(long arg0) throws SevenZipException { + } + + @Override + public void setTotal(long arg0) throws SevenZipException { + } + + @Override + public ISequentialOutStream getStream(int index, ExtractAskMode extractAskMode) throws SevenZipException { + this.index = index; + final String path = (String) inArchive.getProperty(index, PropID.PATH); + final boolean isFolder = (boolean) inArchive.getProperty(index, PropID.IS_FOLDER); + final String[] oldPath = {""}; + return new ISequentialOutStream() { + public int write(byte[] data) throws SevenZipException { + try { + if (!isFolder) { +// System.out.println(path); + File file = new File(ourDir+"\\" + path); + if (path.equals(oldPath[0])){ + save2File(file, data,true); + }else{ + save2File(file, data,false); + } + oldPath[0] = path; + } + } catch (Exception e) { + e.printStackTrace(); + } + return data.length; + } + }; + /*return data -> { + try { + if (!isFolder) { + File file = new File(ourDir + path); + save2File(file, data); + } + } catch (Exception e) { + e.printStackTrace(); + } + return data.length; + };*/ + + } + + @Override + public void prepareOperation(ExtractAskMode arg0) throws SevenZipException { + } + + @Override + public void setOperationResult(ExtractOperationResult extractOperationResult) throws SevenZipException { + + } + //解决字节丢失 未验证 + public boolean save2File(File file, byte[] msg,boolean append) { + OutputStream fos = null; + try { + File parent = file.getParentFile(); + boolean bool; + if ((!parent.exists()) && (!parent.mkdirs())) { + return false; + } + // fos = new FileOutputStream(file); + fos = new FileOutputStream(file,append);//是否追加 + fos.write(msg); + fos.flush(); + return true; + } catch (FileNotFoundException e) { + return false; + } catch (IOException e) { + File parent; + return false; + } finally { + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + } + } + } + } + + public static boolean save2File(File file, byte[] msg) { + OutputStream fos = null; + try { + File parent = file.getParentFile(); + if ((!parent.exists()) && (!parent.mkdirs())) { + return false; + } + fos = new FileOutputStream(file, true); + fos.write(msg); + fos.flush(); + return true; + } catch (FileNotFoundException e) { + e.printStackTrace(); + return false; + } catch (IOException e) { + e.printStackTrace(); + return false; + } finally { + try { + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +} + + diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/file/FileTypeUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/file/FileTypeUtils.java new file mode 100644 index 0000000..4d1b625 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/file/FileTypeUtils.java @@ -0,0 +1,64 @@ +package com.inscloudtech.common.utils.file; + +import org.apache.commons.lang3.StringUtils; + +import java.io.File; + +/** + * 文件类型工具类 + * + * @author ruoyi + */ +public class FileTypeUtils { + /** + * 获取文件类型 + *

+ * 例如: ruoyi.txt, 返回: txt + * + * @param file 文件名 + * @return 后缀(不含".") + */ + public static String getFileType(File file) { + if (null == file) { + return StringUtils.EMPTY; + } + return getFileType(file.getName()); + } + + /** + * 获取文件类型 + *

+ * 例如: ruoyi.txt, 返回: txt + * + * @param fileName 文件名 + * @return 后缀(不含".") + */ + public static String getFileType(String fileName) { + int separatorIndex = fileName.lastIndexOf("."); + if (separatorIndex < 0) { + return ""; + } + return fileName.substring(separatorIndex + 1).toLowerCase(); + } + + /** + * 获取文件类型 + * + * @param photoByte 文件字节码 + * @return 后缀(不含".") + */ + public static String getFileExtendName(byte[] photoByte) { + String strFileExtendName = "JPG"; + if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56) + && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97)) { + strFileExtendName = "GIF"; + } else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70)) { + strFileExtendName = "JPG"; + } else if ((photoByte[0] == 66) && (photoByte[1] == 77)) { + strFileExtendName = "BMP"; + } else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71)) { + strFileExtendName = "PNG"; + } + return strFileExtendName; + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/file/FileUploadUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/file/FileUploadUtils.java new file mode 100644 index 0000000..a606bdd --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/file/FileUploadUtils.java @@ -0,0 +1,212 @@ +package com.inscloudtech.common.utils.file; + +import cn.hutool.core.util.StrUtil; +import com.inscloudtech.common.utils.DateUtils; +import com.inscloudtech.common.config.ProjectConfig; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.exception.file.FileNameLengthLimitExceededException; +import com.inscloudtech.common.exception.file.FileSizeLimitExceededException; +import com.inscloudtech.common.exception.file.InvalidExtensionException; +import com.inscloudtech.common.utils.DateUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.uuid.Seq; +import lombok.Getter; +import org.apache.commons.io.FilenameUtils; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.Objects; + +/** + * 文件上传工具类 + * + * @author ruoyi + */ +public class FileUploadUtils { + /** + * 默认大小 50M + */ + public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024; + + /** + * 默认的文件名最大长度 100 + */ + public static final int DEFAULT_FILE_NAME_LENGTH = 100; + + /** + * 本地默认上传的地址 + */ + @Getter + private static String defaultBaseDir = ProjectConfig.getProfile(); + + /** + * Minio默认上传的地址 + */ + @Getter + private static final String bucketName = "asb"; + + static { +// ClassPathResource cpr = new ClassPathResource("application.yml"); +// +// BufferedReader reader = cpr.getReader(StandardCharsets.UTF_8); +// +// Dict dict = YamlUtil.load(reader); +// bucketName = dict.getStr("minio.bucketName"); + } + + public static void setDefaultBaseDir(String defaultBaseDir) { + FileUploadUtils.defaultBaseDir = defaultBaseDir; + } + + /** + * 以默认配置进行文件上传 + * + * @param file 上传的文件 + * @return 文件名称 + */ + public static String upload(MultipartFile file) throws IOException { + try { + return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); + } catch (Exception e) { + throw new IOException(e.getMessage(), e); + } + } + + /** + * 根据文件路径上传 + * + * @param baseDir 相对应用的基目录 + * @param file 上传的文件 + * @return 文件名称 + */ + public static String upload(String baseDir, MultipartFile file) throws IOException { + try { + return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); + } catch (Exception e) { + throw new IOException(e.getMessage(), e); + } + } + + /** + * 文件上传 + * + * @param baseDir 相对应用的基目录 + * @param file 上传的文件 + * @param allowedExtension 上传文件类型 + * @return 返回上传成功的文件名 + * @throws FileSizeLimitExceededException 如果超出最大大小 + * @throws FileNameLengthLimitExceededException 文件名太长 + * @throws IOException 比如读写文件出错时 + * @throws InvalidExtensionException 文件校验异常 + */ + public static String upload(String baseDir, MultipartFile file, String[] allowedExtension) + throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, + InvalidExtensionException { + int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length(); + if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) { + throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); + } + + assertAllowed(file, allowedExtension); + + String fileName = extractFilename(file); + + String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath(); + file.transferTo(Paths.get(absPath)); + File file1 = new File(absPath); +// // 设置文件权限,防止直接打开 +// if (file1.setReadable(false) && file1.setWritable(false) && file1.setExecutable(false)) { +// System.out.println("File permissions set successfully."); +// } + + return getPathFileName(baseDir, fileName); + } + + + /** + * 编码文件名 + */ + public static String extractFilename(MultipartFile file) { + return StrUtil.format("{}/{}_{}.{}", DateUtils.datePath(), + FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file)); + } + + public static File getAbsoluteFile(String uploadDir, String fileName) throws IOException { + File desc = new File(uploadDir + File.separator + fileName); + + if (!desc.exists()) { + if (!desc.getParentFile().exists()) { + desc.getParentFile().mkdirs(); + } + } + return desc; + } + + public static String getPathFileName(String uploadDir, String fileName) throws IOException { + int dirLastIndex = ProjectConfig.getProfile().length() + 1; + String currentDir = StringUtils.substring(uploadDir, dirLastIndex); + return Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName; + } + + /** + * 文件大小校验 + * + * @param file 上传的文件 + * @throws FileSizeLimitExceededException 如果超出最大大小 + */ + public static void assertAllowed(MultipartFile file, String[] allowedExtension) + throws FileSizeLimitExceededException, InvalidExtensionException { + long size = file.getSize(); + if (size > DEFAULT_MAX_SIZE) { + throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024); + } + + String fileName = file.getOriginalFilename(); + String extension = getExtension(file); + if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) { + if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) { + throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension, + fileName); + } else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION) { + throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension, + fileName); + } else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION) { + throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension, + fileName); + } else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION) { + throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension, + fileName); + } else { + throw new InvalidExtensionException(allowedExtension, extension, fileName); + } + } + } + + /** + * 判断MIME类型是否是允许的MIME类型 + */ + public static boolean isAllowedExtension(String extension, String[] allowedExtension) { + for (String str : allowedExtension) { + if (str.equalsIgnoreCase(extension)) { + return true; + } + } + return false; + } + + /** + * 获取文件名的后缀 + * + * @param file 表单文件 + * @return 后缀名 + */ + public static String getExtension(MultipartFile file) { + String extension = FilenameUtils.getExtension(file.getOriginalFilename()); + if (StringUtils.isEmpty(extension)) { + extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType())); + } + return extension; + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/file/FileUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/file/FileUtils.java new file mode 100644 index 0000000..4583ada --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/file/FileUtils.java @@ -0,0 +1,245 @@ +package com.inscloudtech.common.utils.file; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.core.util.ZipUtil; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.utils.StringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import net.sf.sevenzipjbinding.IInArchive; +import net.sf.sevenzipjbinding.SevenZip; +import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream; +import org.apache.commons.lang3.ArrayUtils; + +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.net.URLEncoder; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; + +/** + * 文件处理工具类 + * + * @author inscloudtech + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class FileUtils extends FileUtil { + + /** + * 删除文件 + * + * @param filePath 文件 + * @return + */ + public static boolean deleteFile(String filePath) { + boolean flag = false; + File file = new File(filePath); + // 路径为文件且不为空则进行删除 + if (file.isFile() && file.exists()) { + flag = file.delete(); + } + return flag; + } + + /** + * 输出指定文件的byte数组 + * + * @param filePath 文件路径 + * @param os 输出流 + * @return + */ + public static void writeBytes(String filePath, OutputStream os) throws IOException { + FileInputStream fis = null; + try { + File file = new File(filePath); + if (!file.exists()) { + throw new FileNotFoundException(filePath); + } + fis = new FileInputStream(file); + byte[] b = new byte[1024]; + int length; + while ((length = fis.read(b)) > 0) { + os.write(b, 0, length); + } + } catch (IOException e) { + throw e; + } finally { + IoUtil.close(os); + IoUtil.close(fis); + } + } + + /** + * 检查文件是否可下载 + * + * @param resource 需要下载的文件 + * @return true 正常 false 非法 + */ + public static boolean checkAllowDownload(String resource) { + // 禁止目录上跳级别 + if (StringUtils.contains(resource, "..")) { + return false; + } + + // 检查允许下载的文件规则 + if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource))) { + return true; + } + + // 不在允许下载的文件规则 + return false; + } + /** + * 下载文件名重新编码 + * + * @param response 响应对象 + * @param realFileName 真实文件名 + */ + public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException { + String percentEncodedFileName = percentEncode(realFileName); + + StringBuilder contentDispositionValue = new StringBuilder(); + contentDispositionValue.append("attachment; filename=") + .append(percentEncodedFileName) + .append(";") + .append("filename*=") + .append("utf-8''") + .append(percentEncodedFileName); + + response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename"); + response.setHeader("Content-disposition", contentDispositionValue.toString()); + response.setHeader("download-filename", percentEncodedFileName); + } + /** + * 百分号编码工具方法 + * + * @param s 需要百分号编码的字符串 + * @return 百分号编码后的字符串 + */ + public static String percentEncode(String s) throws UnsupportedEncodingException { + String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString()); + return encode.replaceAll("\\+", "%20"); + } + + /** + * 从文件中直接读取字节 + */ + public static ByteArrayOutputStream readByteArrayOutputStream(File file) throws IOException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + try (BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(file.toPath()))) { + byte[] byt = new byte[1024 * 4]; + int len; + + while ((len = bis.read(byt)) != -1) { + if (len < 1024 * 4) { + output.write(byt, 0, len); + } else output.write(byt); + } + } + + return output; + } + + /** + * 解压缩 + * + * @param zipFile zip文件 + */ + public static String unzip(String zipFile) throws Exception { + return unzip(new File(zipFile)).getAbsolutePath(); + } + + public static File unzip(File zipFile) throws Exception { + //解压缩 + return unzip(Files.newInputStream(zipFile.toPath())); + } + + public static File unzip(InputStream in) throws Exception { + File tmpDir = FileUtil.getTmpDir(); + //在临时目录下新建一个文件作为解压缩 + String newDirName = tmpDir.getAbsolutePath() + File.separator + RandomUtil.randomString(Constants.RANDOM_STRING_LENGTH); + + File zipTmpDir = FileUtil.newFile(newDirName); + //解压缩 + return ZipUtil.unzip(in, zipTmpDir, Charset.forName("GBK")); + } + + + /** + * 解压RAR压缩文件到指定路径 + */ + public static List unRar(File rarPath, String dstDirectoryPath) throws IOException { + IInArchive archive; + RandomAccessFile randomAccessFile; + // 第一个参数是需要解压的压缩包路径,第二个参数参考JdkAPI文档的RandomAccessFile + //r代表以只读的方式打开文本,也就意味着不能用write来操作文件 + randomAccessFile = new RandomAccessFile(rarPath, "r"); + archive = SevenZip.openInArchive(null, // null - autodetect + new RandomAccessFileInStream(randomAccessFile)); + int[] in = new int[archive.getNumberOfItems()]; + for (int i = 0; i < in.length; i++) { + in[i] = i; + } + archive.extract(in, false, new ExtractCallback(archive,dstDirectoryPath )); + archive.close(); + randomAccessFile.close(); + ///data/microService/data/offline_dzhd_pdf/pdf/1637724142062/ + System.out.println("rar文件电子回单解压目标文件夹为:"+dstDirectoryPath); + List allFileList = getAllFile(dstDirectoryPath, false); + + ArrayList resultFileList = new ArrayList<>(); + String startString; + String endString; + String fianllyString; + for (String s : allFileList) { + if(s.startsWith("/") || s.startsWith("\\")){ + startString = s.substring(0,s.lastIndexOf("\\")); + endString = s.substring(s.lastIndexOf("\\")+1); + fianllyString = startString+"\\"+endString; + }else { + //windows系统去掉盘符 + s =s.substring(2); + startString = s.substring(0,s.lastIndexOf("\\")); + endString = s.substring(s.lastIndexOf("\\")+1); + fianllyString = startString+"/"+endString; + } + System.out.println("rar文件电子回单解压前缀为:"+startString+"rar文件电子回单解压后缀为:"+endString); + //解决liunx路径出现//导致文件路径错误 + fianllyString = fianllyString.replaceAll("//","/"); + resultFileList.add(fianllyString); + } + System.out.println("rar电子回单解压文件路径为"+resultFileList); + return resultFileList; + } + /** + * 获取路径下的所有文件/文件夹 + * @param directoryPath 需要遍历的文件夹路径 + * @param isAddDirectory 是否将子文件夹的路径也添加到list集合中 + * @return + */ + public static List getAllFile(String directoryPath,boolean isAddDirectory) { + List list = new ArrayList(); + File baseFile = new File(directoryPath); + if (baseFile.isFile() || !baseFile.exists()) { + return list; + } + File[] files = baseFile.listFiles(); + for (File file : files) { + if (file.isDirectory()) { + if(isAddDirectory){ + list.add(file.getAbsolutePath()); + } + list.addAll(getAllFile(file.getAbsolutePath(),isAddDirectory)); + } else { + list.add(file.getAbsolutePath()); + } + } + return list; + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/file/ImageUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/file/ImageUtils.java new file mode 100644 index 0000000..8befcd3 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/file/ImageUtils.java @@ -0,0 +1,79 @@ +package com.inscloudtech.common.utils.file; + +import com.inscloudtech.common.config.ProjectConfig; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.utils.StringUtils; +import org.apache.poi.util.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayInputStream; +import java.io.FileInputStream; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.util.Arrays; + +/** + * 图片处理工具类 + * + * @author ruoyi + */ +public class ImageUtils { + private static final Logger log = LoggerFactory.getLogger(ImageUtils.class); + + public static byte[] getImage(String imagePath) { + InputStream is = getFile(imagePath); + try { + return IOUtils.toByteArray(is); + } catch (Exception e) { + log.error("图片加载异常 {}", e); + return null; + } finally { + IOUtils.closeQuietly(is); + } + } + + public static InputStream getFile(String imagePath) { + try { + byte[] result = readFile(imagePath); + result = Arrays.copyOf(result, result.length); + return new ByteArrayInputStream(result); + } catch (Exception e) { + log.error("获取图片异常 {}", e); + } + return null; + } + + /** + * 读取文件为字节数据 + * + * @param url 地址 + * @return 字节数据 + */ + public static byte[] readFile(String url) { + InputStream in = null; + try { + if (url.startsWith("http")) { + // 网络地址 + URL urlObj = new URL(url); + URLConnection urlConnection = urlObj.openConnection(); + urlConnection.setConnectTimeout(30 * 1000); + urlConnection.setReadTimeout(60 * 1000); + urlConnection.setDoInput(true); + in = urlConnection.getInputStream(); + } else { + // 本机地址 + String localPath = ProjectConfig.getProfile(); + String downloadPath = localPath + StringUtils.substringAfter(url, Constants.RESOURCE_PREFIX); + in = new FileInputStream(downloadPath); + } + return IOUtils.toByteArray(in); + } catch (Exception e) { + log.error("获取文件路径异常 {}", e); + return null; + } finally { + IOUtils.closeQuietly(in); + } + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/file/MimeTypeUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/file/MimeTypeUtils.java new file mode 100644 index 0000000..cb9aca7 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/file/MimeTypeUtils.java @@ -0,0 +1,56 @@ +package com.inscloudtech.common.utils.file; + +/** + * 媒体类型工具类 + * + * @author ruoyi + */ +public class MimeTypeUtils { + public static final String IMAGE_PNG = "image/png"; + + public static final String IMAGE_JPG = "image/jpg"; + + public static final String IMAGE_JPEG = "image/jpeg"; + + public static final String IMAGE_BMP = "image/bmp"; + + public static final String IMAGE_GIF = "image/gif"; + + public static final String[] IMAGE_EXTENSION = {"bmp", "gif", "jpg", "jpeg", "png"}; + + public static final String[] FLASH_EXTENSION = {"swf", "flv"}; + + public static final String[] MEDIA_EXTENSION = {"swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg", + "asf", "rm", "rmvb"}; + + public static final String[] VIDEO_EXTENSION = {"mp4", "avi", "rmvb"}; + + public static final String[] DEFAULT_ALLOWED_EXTENSION = { + // 图片 + "bmp", "gif", "jpg", "jpeg", "png", + // word excel powerpoint + "doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt", + // 压缩文件 + "rar", "zip", "gz", "bz2", + // 视频格式 + "mp4", "avi", "rmvb", + // pdf + "pdf"}; + + public static String getExtension(String prefix) { + switch (prefix) { + case IMAGE_PNG: + return "png"; + case IMAGE_JPG: + return "jpg"; + case IMAGE_JPEG: + return "jpeg"; + case IMAGE_BMP: + return "bmp"; + case IMAGE_GIF: + return "gif"; + default: + return ""; + } + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/file/RAR5Util.java b/cas-common/src/main/java/com/inscloudtech/common/utils/file/RAR5Util.java new file mode 100644 index 0000000..076b739 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/file/RAR5Util.java @@ -0,0 +1,91 @@ +package com.inscloudtech.common.utils.file; + + +import net.sf.sevenzipjbinding.IInArchive; +import net.sf.sevenzipjbinding.SevenZip; +import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.ArrayList; +import java.util.List; + +public class RAR5Util { + public static void main(String[] args) throws IOException { + String rarDir = "E:\\项目文件\\中合担保标准回单模板\\rar5压缩包\\银行回单.rar"; + String outDir = "E:\\12\\"; + unRar(new File(rarDir),outDir); + } + public static List unRar(File rarPath, String dstDirectoryPath) throws IOException { + IInArchive archive; + RandomAccessFile randomAccessFile; + // 第一个参数是需要解压的压缩包路径,第二个参数参考JdkAPI文档的RandomAccessFile + //r代表以只读的方式打开文本,也就意味着不能用write来操作文件 + randomAccessFile = new RandomAccessFile(rarPath, "r"); + archive = SevenZip.openInArchive(null, // null - autodetect + new RandomAccessFileInStream(randomAccessFile)); + int[] in = new int[archive.getNumberOfItems()]; + for (int i = 0; i < in.length; i++) { + in[i] = i; + } + archive.extract(in, false, new ExtractCallback(archive,dstDirectoryPath )); + archive.close(); + randomAccessFile.close(); + ///data/microService/data/offline_dzhd_pdf/pdf/1637724142062/ + System.out.println("rar文件电子回单解压目标文件夹为:"+dstDirectoryPath); + List allFileList = getAllFile(dstDirectoryPath, false); + + ArrayList resultFileList = new ArrayList<>(); + String startString; + String endString; + String fianllyString; + for (String s : allFileList) { + if(s.startsWith("/") || s.startsWith("\\")){ + startString = s.substring(0,s.lastIndexOf("\\")); + endString = s.substring(s.lastIndexOf("\\")+1); + fianllyString = startString+"\\"+endString; + }else { + //windows系统去掉盘符 + s =s.substring(2); + startString = s.substring(0,s.lastIndexOf("\\")); + endString = s.substring(s.lastIndexOf("\\")+1); + fianllyString = startString+"/"+endString; + } + System.out.println("rar文件电子回单解压前缀为:"+startString+"rar文件电子回单解压后缀为:"+endString); + //解决liunx路径出现//导致文件路径错误 + fianllyString = fianllyString.replaceAll("//","/"); + resultFileList.add(fianllyString); + } + System.out.println("rar电子回单解压文件路径为"+resultFileList); + return resultFileList; + } + /** + * 获取路径下的所有文件/文件夹 + * @param directoryPath 需要遍历的文件夹路径 + * @param isAddDirectory 是否将子文件夹的路径也添加到list集合中 + * @return + */ + public static List getAllFile(String directoryPath,boolean isAddDirectory) { + List list = new ArrayList(); + File baseFile = new File(directoryPath); + if (baseFile.isFile() || !baseFile.exists()) { + return list; + } + File[] files = baseFile.listFiles(); + for (File file : files) { + if (file.isDirectory()) { + if(isAddDirectory){ + list.add(file.getAbsolutePath()); + } + list.addAll(getAllFile(file.getAbsolutePath(),isAddDirectory)); + } else { + list.add(file.getAbsolutePath()); + } + } + return list; + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/ip/AddressUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/ip/AddressUtils.java new file mode 100644 index 0000000..e0ea908 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/ip/AddressUtils.java @@ -0,0 +1,33 @@ +package com.inscloudtech.common.utils.ip; + +import cn.hutool.core.net.NetUtil; +import cn.hutool.http.HtmlUtil; +import com.inscloudtech.common.utils.StringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * 获取地址类 + * + * @author inscloudtech + */ +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class AddressUtils { + + // 未知地址 + public static final String UNKNOWN = "XX XX"; + + public static String getRealAddressByIP(String ip) { + if (StringUtils.isBlank(ip)) { + return UNKNOWN; + } + // 内网不查询 + ip = "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : HtmlUtil.cleanHtmlTag(ip); + if (NetUtil.isInnerIP(ip)) { + return "内网IP"; + } + return RegionUtils.getCityInfo(ip); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/ip/RegionUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/ip/RegionUtils.java new file mode 100644 index 0000000..c618c98 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/ip/RegionUtils.java @@ -0,0 +1,65 @@ +package com.inscloudtech.common.utils.ip; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.resource.ClassPathResource; +import cn.hutool.core.util.ObjectUtil; +import com.inscloudtech.common.exception.ServiceException; +import com.inscloudtech.common.utils.file.FileUtils; +import lombok.extern.slf4j.Slf4j; +import org.lionsoul.ip2region.xdb.Searcher; + +import java.io.File; + +/** + * 根据ip地址定位工具类,离线方式 + * 参考地址:集成 ip2region 实现离线IP地址定位库 + * + * @author lishuyan + */ +@Slf4j +public class RegionUtils { + + private static final Searcher SEARCHER; + + static { + String fileName = "/ip2region.xdb"; + File existFile = FileUtils.file(FileUtil.getTmpDir() + FileUtil.FILE_SEPARATOR + fileName); + if (!FileUtils.exist(existFile)) { + ClassPathResource fileStream = new ClassPathResource(fileName); + if (ObjectUtil.isEmpty(fileStream.getStream())) { + throw new ServiceException("RegionUtils初始化失败,原因:IP地址库数据不存在!"); + } + FileUtils.writeFromStream(fileStream.getStream(), existFile); + } + + String dbPath = existFile.getPath(); + + // 1、从 dbPath 加载整个 xdb 到内存。 + byte[] cBuff; + try { + cBuff = Searcher.loadContentFromFile(dbPath); + } catch (Exception e) { + throw new ServiceException("RegionUtils初始化失败,原因:从ip2region.xdb文件加载内容失败!" + e.getMessage()); + } + // 2、使用上述的 cBuff 创建一个完全基于内存的查询对象。 + try { + SEARCHER = Searcher.newWithBuffer(cBuff); + } catch (Exception e) { + throw new ServiceException("RegionUtils初始化失败,原因:" + e.getMessage()); + } + } + /** + * 根据IP地址离线获取城市 + */ + public static String getCityInfo(String ip) { + try { + ip = ip.trim(); + // 3、执行查询 + String region = SEARCHER.search(ip); + return region.replace("0|", "").replace("|0", ""); + } catch (Exception e) { + log.error("IP地址离线获取城市异常 {}", ip); + return "未知"; + } + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/poi/CustomCellWriteHandler.java b/cas-common/src/main/java/com/inscloudtech/common/utils/poi/CustomCellWriteHandler.java new file mode 100644 index 0000000..954bb34 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/poi/CustomCellWriteHandler.java @@ -0,0 +1,115 @@ +package com.inscloudtech.common.utils.poi; + + + + +//在导出时注册registerWriteHandler(new CustomCellWriteHandler()) + +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.metadata.data.CellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy; +import org.apache.poi.ss.usermodel.Cell; +import org.springframework.util.CollectionUtils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CustomCellWriteHandler extends AbstractColumnWidthStyleStrategy { + private static final int MAX_COLUMN_WIDTH = 255; + private Map> CACHE = new HashMap(8); + private Map headWidthMap = new HashMap(); + private boolean firstRowHead;//第一行表头是否需要计算宽度,针对第一行类似标题那种表格 + public CustomCellWriteHandler(boolean firstRowHead) { + this.firstRowHead = firstRowHead; + } +// public void afterCellDispose(CellWriteHandlerContext context) { +// WriteCellData cellData = context.getFirstCellData(); +// int rowNum = context.getRow().getRowNum(); +// Integer columnIndex = context.getColumnIndex(); +// Sheet sheet = context.getWriteSheetHolder().getSheet(); +// Cell cell = context.getCell(); +// +// if (BooleanUtils.isTrue(context.getHead())) { +// WriteCellStyle writeCellStyle = cellData.getWriteCellStyle(); +// //字体 +// WriteFont writeFont = writeCellStyle.getWriteFont(); +// //背景颜色 +// writeCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex()); +// writeCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND); +// //字体大小 +// writeFont.setFontHeightInPoints((short) 14); +// //字体加粗 +// writeFont.setBold(true); +// writeCellStyle.setWriteFont(writeFont); +// //列宽,行高 +// sheet.setColumnWidth(cell.getColumnIndex(), 4000); +// sheet.setDefaultRowHeight((short) 400); +// }else{ +// +// } +// } + + + protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + if(relativeRowIndex == 0 && !firstRowHead){//ruo + return; + } + boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList); + + if (needSetWidth) { + Map maxColumnWidthMap = (Map)CACHE.get(writeSheetHolder.getSheetNo()); + if (maxColumnWidthMap == null) { + maxColumnWidthMap = new HashMap(16); + CACHE.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap); + } + WriteCellData writeCellData = cellDataList.get(0); + Integer dataWidth = this.dataLength(writeCellData) - 2; + //格子太大 太小 + dataWidth = dataWidth <10?10:dataWidth; + dataWidth = dataWidth >32?32:dataWidth; +// if(isHead){ +// headWidthMap.put(cell.getColumnIndex(),cell.getStringCellValue().getBytes().length); +// } + if (dataWidth >= 0) { + if (dataWidth > MAX_COLUMN_WIDTH) { + dataWidth = MAX_COLUMN_WIDTH; + } + + if(maxColumnWidthMap.getOrDefault(cell.getColumnIndex(),1) headWidthMap.get(cell.getColumnIndex())?dataWidth:headWidthMap.get(cell.getColumnIndex()); + + Integer finalWidth = dataWidth > maxWidth?dataWidth:maxWidth; +// } +// } + writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), finalWidth * 256); + } + } + } + + private Integer dataLength(CellData cellData) { + CellDataTypeEnum type = cellData.getType(); + if (type == null) { + return -1; + } else { + switch(type) { + case STRING: + return cellData.getStringValue().getBytes().length; + case BOOLEAN: + return cellData.getBooleanValue().toString().getBytes().length; + case NUMBER: + return cellData.getNumberValue().toString().getBytes().length; + default: + return -1; + } + } + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/poi/CustomRowHandler.java b/cas-common/src/main/java/com/inscloudtech/common/utils/poi/CustomRowHandler.java new file mode 100644 index 0000000..8d48a58 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/poi/CustomRowHandler.java @@ -0,0 +1,53 @@ +package com.inscloudtech.common.utils.poi; + + + + +//在导出时注册registerWriteHandler(new CustomCellWriteHandler()) + +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.metadata.data.CellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.util.StyleUtil; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; +import com.alibaba.excel.write.metadata.style.WriteCellStyle; +import com.alibaba.excel.write.metadata.style.WriteFont; +import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy; +import com.alibaba.excel.write.style.row.AbstractRowHeightStyleStrategy; +import org.apache.poi.ss.usermodel.*; +import org.springframework.util.CollectionUtils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CustomRowHandler extends AbstractRowHeightStyleStrategy { + private final Short firstHeadRowHeight; + private final Short headRowHeight; + private final Short contentRowHeight; + public CustomRowHandler(Short firstHeadRowHeight,Short headRowHeight, Short contentRowHeight) { + this.firstHeadRowHeight = firstHeadRowHeight; + this.headRowHeight = headRowHeight; + this.contentRowHeight = contentRowHeight; + } + + + @Override + protected void setHeadColumnHeight(Row row, int i) { + if(row.getRowNum() == 0){ + row.setHeightInPoints((float)this.firstHeadRowHeight); + }else { + row.setHeightInPoints((float)this.headRowHeight); + } + + } + + @Override + protected void setContentColumnHeight(Row row, int i) { + if (this.contentRowHeight != null) { + row.setHeightInPoints((float)this.contentRowHeight); + } + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/poi/ExcelUtil.java b/cas-common/src/main/java/com/inscloudtech/common/utils/poi/ExcelUtil.java new file mode 100644 index 0000000..bbdd248 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/poi/ExcelUtil.java @@ -0,0 +1,539 @@ +package com.inscloudtech.common.utils.poi; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.resource.ClassPathResource; +import cn.hutool.core.util.IdUtil; +import cn.hutool.json.JSONObject; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.fill.FillConfig; +import com.alibaba.excel.write.metadata.fill.FillWrapper; +import com.alibaba.excel.write.metadata.style.WriteCellStyle; +import com.alibaba.excel.write.metadata.style.WriteFont; +import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; +import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; +import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy; +import com.inscloudtech.common.convert.ExcelBigNumberConvert; +import com.inscloudtech.common.excel.CellMergeStrategy; +import com.inscloudtech.common.excel.DefaultExcelListener; +import com.inscloudtech.common.excel.ExcelListener; +import com.inscloudtech.common.excel.ExcelResult; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.file.FileUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.poi.ss.usermodel.BorderStyle; +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.usermodel.VerticalAlignment; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +/** + * Excel相关处理 + * + * @author inscloudtech + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ExcelUtil { + + private static WriteCellStyle headWriteCellStyle = new WriteCellStyle(); + + private static WriteCellStyle contentWriteCellStyle = new WriteCellStyle(); /** + * 同步导入(适用于小数据量) + * + * @param is 输入流 + * @return 转换后集合 + */ + public static List importExcel(InputStream is, Class clazz) { + return EasyExcel.read(is).head(clazz).autoCloseStream(false).sheet().doReadSync(); + } + + /** + * 使用校验监听器 异步导入 同步返回 + * + * @param is 输入流 + * @param clazz 对象类型 + * @param isValidate 是否 Validator 检验 默认为是 + * @return 转换后集合 + */ + public static ExcelResult importExcel(InputStream is, Class clazz, boolean isValidate) { + DefaultExcelListener listener = new DefaultExcelListener<>(isValidate); + EasyExcel.read(is, clazz, listener).sheet().doRead(); + return listener.getExcelResult(); + } + /** + * 使用自定义监听器 异步导入 自定义返回 + * + * @param is 输入流 + * @param clazz 对象类型 + * @param listener 自定义监听器 + * @return 转换后集合 + */ + public static ExcelResult importExcel(InputStream is, Class clazz, ExcelListener listener) { + EasyExcel.read(is, clazz, listener).sheet().doRead(); + return listener.getExcelResult(); + } + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param response 响应体 + */ +// public static void exportExcel(List list, String sheetName, Class clazz, HttpServletResponse response) { +// try { +// resetResponse(sheetName, response); +// ServletOutputStream os = response.getOutputStream(); +// exportExcel(list, sheetName, clazz, false,0, os); +// } catch (IOException e) { +// throw new RuntimeException("导出Excel异常"); +// } +// } + + public static void exportExcel(List list, String sheetName, Class clazz, HttpServletResponse response) { + try { + resetResponse(sheetName, response); + ServletOutputStream os = response.getOutputStream(); + ExcelWriterSheetBuilder builder = EasyExcel.write(os, clazz) + .autoCloseStream(false) + // 自动适配 + .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .sheet(sheetName); + builder.doWrite(list); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param merge 是否合并单元格 + * @param response 响应体 + */ + public static void exportExcel(List list, String sheetName, Class clazz, boolean merge,int rowIndex, HttpServletResponse response) { + try { + resetResponse(sheetName, response); + ServletOutputStream os = response.getOutputStream(); + exportExcel(list, sheetName, clazz, merge, rowIndex ,os); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param head 表头 + * @param merge 是否合并单元格 + * @param response 响应体 + */ + public static void exportExcel(List list, String sheetName, List> head, boolean merge,int rowIndex, HttpServletResponse response) { + try { + resetResponse(sheetName, response); + ServletOutputStream os = response.getOutputStream(); + exportExcel(list, sheetName,head, merge, rowIndex ,os); + + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + public static void exportExcel4Json(List valueList, List> fieldValueRows,String sheetName, List> head, boolean merge, int rowIndex, HttpServletResponse response) { + try { + styleConfig(); + resetResponse(sheetName, response); + ServletOutputStream os = response.getOutputStream(); + ExcelWriterSheetBuilder builder = EasyExcel.write(os) + .autoCloseStream(false) + .head(head) + // 自动适配 +// .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .registerWriteHandler(new CustomCellWriteHandler(true)) + .registerWriteHandler(new CustomRowHandler((short)22,(short)22,(short)22)) + .registerWriteHandler(new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle)) + .sheet(sheetName); + if (merge) { + // 合并处理器 + builder.registerWriteHandler(new CellMergeStrategy(fieldValueRows, rowIndex)); + } + builder.doWrite(valueList); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param merge 是否合并单元格 + * @param os 输出流 + */ + public static void exportExcel(List list, String sheetName, List> head, boolean merge,int rowIndex,OutputStream os) { + styleConfig(); + ExcelWriterSheetBuilder builder = EasyExcel.write(os) + .autoCloseStream(false) + .head(head) + // 自动适配 +// .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .registerWriteHandler(new CustomCellWriteHandler(true)) + .registerWriteHandler(new CustomRowHandler((short)40,(short)22,(short)22)) + .registerWriteHandler(new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle)) + .sheet(sheetName); + if (merge) { + // 合并处理器 + builder.registerWriteHandler(new CellMergeStrategy(list, rowIndex)); + } + builder.doWrite(list); + } + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param os 输出流 + */ + public static void exportExcel(List list, String sheetName, Class clazz, OutputStream os) { + exportExcel(list, sheetName, clazz, false,0, os); + } + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param merge 是否合并单元格 + * @param os 输出流 + */ + public static void exportExcel(List list, String sheetName, Class clazz, boolean merge,int rowIndex,OutputStream os) { + styleConfig(); + ExcelWriterSheetBuilder builder = EasyExcel.write(os, clazz) + .autoCloseStream(false) + // 自动适配 +// .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .registerWriteHandler(new CustomCellWriteHandler(true)) + .registerWriteHandler(new CustomRowHandler((short)40,(short)22,(short)22)) + .registerWriteHandler(new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle)) + .sheet(sheetName); + if (merge) { + // 合并处理器 + builder.registerWriteHandler(new CellMergeStrategy(list, rowIndex)); + } + builder.doWrite(list); + } + /** + * 单表多数据模板导出 模板格式为 {.属性} + * + * @param filename 文件名 + * @param templatePath 模板路径 resource 目录下的路径包括模板文件名 + * 例如: excel/temp.xlsx + * 重点: 模板文件必须放置到启动类对应的 resource 目录下 + * @param data 模板需要的数据 + * @param response 响应体 + */ + public static void exportTemplate(List data, String filename, String templatePath, HttpServletResponse response) { + try { + resetResponse(filename, response); + ServletOutputStream os = response.getOutputStream(); + exportTemplate(data, templatePath, os); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + /** + * 单表多数据模板导出 模板格式为 {.属性} + * + * @param templatePath 模板路径 resource 目录下的路径包括模板文件名 + * 例如: excel/temp.xlsx + * 重点: 模板文件必须放置到启动类对应的 resource 目录下 + * @param data 模板需要的数据 + * @param os 输出流 + */ + public static void exportTemplate(List data, String templatePath, OutputStream os) { + ClassPathResource templateResource = new ClassPathResource(templatePath); + ExcelWriter excelWriter = EasyExcel.write(os) + .withTemplate(templateResource.getStream()) + .autoCloseStream(false) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .build(); + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + if (CollUtil.isEmpty(data)) { + throw new IllegalArgumentException("数据为空"); + } + // 单表多数据导出 模板格式为 {.属性} + for (Object d : data) { + excelWriter.fill(d, writeSheet); + } + excelWriter.finish(); + } + /** + * 多表多数据模板导出 模板格式为 {key.属性} + * + * @param filename 文件名 + * @param templatePath 模板路径 resource 目录下的路径包括模板文件名 + * 例如: excel/temp.xlsx + * 重点: 模板文件必须放置到启动类对应的 resource 目录下 + * @param data 模板需要的数据 + * @param response 响应体 + */ + public static void exportTemplateMultiList(Map data, String filename, String templatePath, HttpServletResponse response) { + try { + resetResponse(filename, response); + ServletOutputStream os = response.getOutputStream(); + exportTemplateMultiList(data, templatePath, os); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + /** + * 多表多数据模板导出 模板格式为 {key.属性} + * + * @param templatePath 模板路径 resource 目录下的路径包括模板文件名 + * 例如: excel/temp.xlsx + * 重点: 模板文件必须放置到启动类对应的 resource 目录下 + * @param data 模板需要的数据 + * @param os 输出流 + */ + public static void exportTemplateMultiList(Map data, String templatePath, OutputStream os) { + ClassPathResource templateResource = new ClassPathResource(templatePath); + ExcelWriter excelWriter = EasyExcel.write(os) + .withTemplate(templateResource.getStream()) + .autoCloseStream(false) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .build(); + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + if (CollUtil.isEmpty(data)) { + throw new IllegalArgumentException("数据为空"); + } + for (Map.Entry map : data.entrySet()) { + // 设置列表后续还有数据 + FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(); + if (map.getValue() instanceof Collection) { + // 多表导出必须使用 FillWrapper + excelWriter.fill(new FillWrapper(map.getKey(), (Collection) map.getValue()), fillConfig, writeSheet); + } else { + excelWriter.fill(map.getValue(), writeSheet); + } + } + excelWriter.finish(); + } + /** + * 重置响应体 + */ + private static void resetResponse(String sheetName, HttpServletResponse response) throws UnsupportedEncodingException { + String filename = encodingFilename(sheetName); + FileUtils.setAttachmentResponseHeader(response, filename); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8"); + } + /** + * 解析导出值 0=男,1=女,2=未知 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + */ + public static String convertByExp(String propertyValue, String converterExp, String separator) { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(StringUtils.SEPARATOR); + for (String item : convertSource) { + String[] itemArray = item.split("="); + if (StringUtils.containsAny(propertyValue, separator)) { + for (String value : propertyValue.split(separator)) { + if (itemArray[0].equals(value)) { + propertyString.append(itemArray[1] + separator); + break; + } + } + } else { + if (itemArray[0].equals(propertyValue)) { + return itemArray[1]; + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + /** + * 反向解析值 男=0,女=1,未知=2 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + */ + public static String reverseByExp(String propertyValue, String converterExp, String separator) { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(StringUtils.SEPARATOR); + for (String item : convertSource) { + String[] itemArray = item.split("="); + if (StringUtils.containsAny(propertyValue, separator)) { + for (String value : propertyValue.split(separator)) { + if (itemArray[1].equals(value)) { + propertyString.append(itemArray[0] + separator); + break; + } + } + } else { + if (itemArray[1].equals(propertyValue)) { + return itemArray[0]; + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + /** + * 编码文件名 + */ + public static String encodingFilename(String filename) { + return IdUtil.fastSimpleUUID() + "_" + filename + ".xlsx"; + } + + + static void styleConfig(){ + //内容样式策略 +// WriteCellStyle contentWriteCellStyle = new WriteCellStyle(); + //垂直居中,水平居中 + contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); + contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); + contentWriteCellStyle.setBorderLeft(BorderStyle.THIN); + contentWriteCellStyle.setBorderTop(BorderStyle.THIN); + contentWriteCellStyle.setBorderRight(BorderStyle.THIN); + contentWriteCellStyle.setBorderBottom(BorderStyle.THIN); + + //设置 自动换行 +// contentWriteCellStyle.setWrapped(true); + // 字体策略 + WriteFont contentWriteFont = new WriteFont(); + // 字体大小 + contentWriteFont.setFontHeightInPoints((short) 12); + contentWriteFont.setFontName("宋体"); + contentWriteCellStyle.setWriteFont(contentWriteFont); + + //头策略使用默认 设置字体大小 +// WriteCellStyle headWriteCellStyle = new WriteCellStyle(); + WriteFont headWriteFont = new WriteFont(); + headWriteFont.setFontHeightInPoints((short) 14); + headWriteFont.setFontName("宋体"); + headWriteCellStyle.setWriteFont(headWriteFont); + headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.index); + } + public static void generateExcelFile4Json(String fileName,List> valueList, List> fieldValueRows,String sheetName, List> head, boolean merge, int mergeStartRowIndex) { + styleConfig(); + ExcelWriterSheetBuilder builder = EasyExcel.write(fileName) + .autoCloseStream(false) + .head(head) + // 自动适配 +// .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .registerWriteHandler(new CustomCellWriteHandler(false)) + .registerWriteHandler(new CustomRowHandler((short)44,(short)22,(short)22)) + .registerWriteHandler(new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle)) + .sheet(sheetName); + if (merge) { + // 合并处理器 + builder.registerWriteHandler(new CellMergeStrategy(fieldValueRows, mergeStartRowIndex)); + } + builder.doWrite(valueList); + + } + public static void generateExcelFile(String fileName,List> head,List> dataList){ + + styleConfig(); +// String fileName="数据汇总表"+getNowDate(); +// String fileName= LocalDateTime.now().toString(); + //将文件名称转码再使用 +// fileName = URLEncoder.encode(fileName, "UTF-8"); +// response.setHeader("Content-Disposition", "attachment;filename*= UTF-8''"+ URLEncoder.encode(fileName,"UTF-8")); +// response.setHeader("Content-Disposition", "attachment;filename=" + fileName+".xlsx") ; +// OutputStream out=response.getOutputStream(); +// ExcelWriter excelWriter = EasyExcel.write(out).registerWriteHandler(new CustomCellWriteHandler()). +// registerWriteHandler(new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle)) +// .registerWriteHandler(new SimpleRowHeightStyleStrategy((short)22,(short)22)) +//// .registerWriteHandler(new CustomCellWriteHandler()) +// .build(); + + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName).registerWriteHandler(new CustomCellWriteHandler(true)) + .registerWriteHandler(new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle)) + .registerWriteHandler(new SimpleRowHeightStyleStrategy((short)22,(short)22)) + .head(head).sheet().doWrite(dataList); + } + + public static void exportExcel(List list, Class clazz, ByteArrayOutputStream outputStream) { + styleConfig(); + ExcelWriterSheetBuilder builder = EasyExcel.write(outputStream, clazz) + .autoCloseStream(false) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .registerWriteHandler(new CustomCellWriteHandler(true)) + .registerWriteHandler(new CustomRowHandler((short)40,(short)22,(short)22)) + .registerWriteHandler(new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle)) + .sheet(""); + try { + builder.doWrite(list); + }catch (Exception e){ + e.printStackTrace(); + } + + } + + + /** + * 压缩单个excel文件的输出流 到zip输出流,注意zipOutputStream未关闭,需要交由调用者关闭之 + * @param zipOutputStream zip文件的输出流 + * @param excelOutputStream excel文件的输出流 + * @param excelFilename 文件名可以带目录,例如 TestDir/test1.xlsx + */ + public static void compressFileToZipStream(ZipOutputStream zipOutputStream, + ByteArrayOutputStream excelOutputStream, String excelFilename) { + byte[] buf = new byte[1024]; + try { + // Compress the files + byte[] content = excelOutputStream.toByteArray(); + ByteArrayInputStream is = new ByteArrayInputStream(content); + BufferedInputStream bis = new BufferedInputStream(is); + // Add ZIP entry to output stream. + zipOutputStream.putNextEntry(new ZipEntry(excelFilename)); + // Transfer bytes from the file to the ZIP file + int len; + while ((len = bis.read(buf)) > 0) { + zipOutputStream.write(buf, 0, len); + } + // Complete the entry + //excelOutputStream.close();//关闭excel输出流 + zipOutputStream.closeEntry(); + bis.close(); + is.close(); + // Complete the ZIP file + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/redis/CacheUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/redis/CacheUtils.java new file mode 100644 index 0000000..a0db9bb --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/redis/CacheUtils.java @@ -0,0 +1,70 @@ +package com.inscloudtech.common.utils.redis; + +import com.inscloudtech.common.utils.spring.SpringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.redisson.api.RMap; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; + +import java.util.Set; + +/** + * 缓存操作工具类 {@link } + * + * @author Michelle.Chung + * @date 2022/8/13 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@SuppressWarnings(value = {"unchecked"}) +public class CacheUtils { + + private static final CacheManager CACHE_MANAGER = SpringUtils.getBean(CacheManager.class); + /** + * 获取缓存组内所有的KEY + * + * @param cacheNames 缓存组名称 + */ + public static Set keys(String cacheNames) { + RMap rmap = (RMap) CACHE_MANAGER.getCache(cacheNames).getNativeCache(); + return rmap.keySet(); + } + /** + * 获取缓存值 + * + * @param cacheNames 缓存组名称 + * @param key 缓存key + */ + public static T get(String cacheNames, Object key) { + Cache.ValueWrapper wrapper = CACHE_MANAGER.getCache(cacheNames).get(key); + return wrapper != null ? (T) wrapper.get() : null; + } + /** + * 保存缓存值 + * + * @param cacheNames 缓存组名称 + * @param key 缓存key + * @param value 缓存值 + */ + public static void put(String cacheNames, Object key, Object value) { + CACHE_MANAGER.getCache(cacheNames).put(key, value); + } + /** + * 删除缓存值 + * + * @param cacheNames 缓存组名称 + * @param key 缓存key + */ + public static void evict(String cacheNames, Object key) { + CACHE_MANAGER.getCache(cacheNames).evict(key); + } + /** + * 清空缓存值 + * + * @param cacheNames 缓存组名称 + */ + public static void clear(String cacheNames) { + CACHE_MANAGER.getCache(cacheNames).clear(); + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/redis/QueueUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/redis/QueueUtils.java new file mode 100644 index 0000000..000d3ef --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/redis/QueueUtils.java @@ -0,0 +1,165 @@ +package com.inscloudtech.common.utils.redis; + +import com.inscloudtech.common.utils.spring.SpringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.redisson.api.*; + +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +/** + * 分布式队列工具 + * 轻量级队列 重量级数据量 请使用 MQ + * 要求 redis 5.X 以上 + * + * @author inscloudtech + * @version 3.6.0 新增 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class QueueUtils { + + private static final RedissonClient CLIENT = SpringUtils.getBean(RedissonClient.class); + + /** + * 获取客户端实例 + */ + public static RedissonClient getClient() { + return CLIENT; + } + /** + * 添加普通队列数据 + * + * @param queueName 队列名 + * @param data 数据 + */ + public static boolean addQueueObject(String queueName, T data) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + return queue.offer(data); + } + /** + * 通用获取一个队列数据 没有数据返回 null(不支持延迟队列) + * + * @param queueName 队列名 + */ + public static T getQueueObject(String queueName) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + return queue.poll(); + } + /** + * 通用删除队列数据(不支持延迟队列) + */ + public static boolean removeQueueObject(String queueName, T data) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + return queue.remove(data); + } + /** + * 通用销毁队列 所有阻塞监听 报错(不支持延迟队列) + */ + public static boolean destroyQueue(String queueName) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + return queue.delete(); + } + /** + * 添加延迟队列数据 默认毫秒 + * + * @param queueName 队列名 + * @param data 数据 + * @param time 延迟时间 + */ + public static void addDelayedQueueObject(String queueName, T data, long time) { + addDelayedQueueObject(queueName, data, time, TimeUnit.MILLISECONDS); + } + /** + * 添加延迟队列数据 + * + * @param queueName 队列名 + * @param data 数据 + * @param time 延迟时间 + * @param timeUnit 单位 + */ + public static void addDelayedQueueObject(String queueName, T data, long time, TimeUnit timeUnit) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + RDelayedQueue delayedQueue = CLIENT.getDelayedQueue(queue); + delayedQueue.offer(data, time, timeUnit); + } + /** + * 获取一个延迟队列数据 没有数据返回 null + * + * @param queueName 队列名 + */ + public static T getDelayedQueueObject(String queueName) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + RDelayedQueue delayedQueue = CLIENT.getDelayedQueue(queue); + return delayedQueue.poll(); + } + /** + * 删除延迟队列数据 + */ + public static boolean removeDelayedQueueObject(String queueName, T data) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + RDelayedQueue delayedQueue = CLIENT.getDelayedQueue(queue); + return delayedQueue.remove(data); + } + /** + * 销毁延迟队列 所有阻塞监听 报错 + */ + public static void destroyDelayedQueue(String queueName) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + RDelayedQueue delayedQueue = CLIENT.getDelayedQueue(queue); + delayedQueue.destroy(); + } + /** + * 添加优先队列数据 + * + * @param queueName 队列名 + * @param data 数据 + */ + public static boolean addPriorityQueueObject(String queueName, T data) { + RPriorityBlockingQueue priorityBlockingQueue = CLIENT.getPriorityBlockingQueue(queueName); + return priorityBlockingQueue.offer(data); + } + /** + * 尝试设置 有界队列 容量 用于限制数量 + * + * @param queueName 队列名 + * @param capacity 容量 + */ + public static boolean trySetBoundedQueueCapacity(String queueName, int capacity) { + RBoundedBlockingQueue boundedBlockingQueue = CLIENT.getBoundedBlockingQueue(queueName); + return boundedBlockingQueue.trySetCapacity(capacity); + } + /** + * 尝试设置 有界队列 容量 用于限制数量 + * + * @param queueName 队列名 + * @param capacity 容量 + * @param destroy 已存在是否销毁 + */ + public static boolean trySetBoundedQueueCapacity(String queueName, int capacity, boolean destroy) { + RBoundedBlockingQueue boundedBlockingQueue = CLIENT.getBoundedBlockingQueue(queueName); + if (boundedBlockingQueue.isExists() && destroy) { + destroyQueue(queueName); + } + return boundedBlockingQueue.trySetCapacity(capacity); + } + /** + * 添加有界队列数据 + * + * @param queueName 队列名 + * @param data 数据 + * @return 添加成功 true 已达到界限 false + */ + public static boolean addBoundedQueueObject(String queueName, T data) { + RBoundedBlockingQueue boundedBlockingQueue = CLIENT.getBoundedBlockingQueue(queueName); + return boundedBlockingQueue.offer(data); + } + /** + * 订阅阻塞队列(可订阅所有实现类 例如: 延迟 优先 有界 等) + */ + public static void subscribeBlockingQueue(String queueName, Consumer consumer) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + queue.subscribeOnElements(consumer); + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/redis/RedisUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/redis/RedisUtils.java new file mode 100644 index 0000000..48f8eda --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/redis/RedisUtils.java @@ -0,0 +1,426 @@ +package com.inscloudtech.common.utils.redis; + +import com.inscloudtech.common.utils.spring.SpringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.redisson.api.*; + +import java.time.Duration; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * redis 工具类 + * + * @author inscloudtech + * @version 3.1.0 新增 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@SuppressWarnings(value = {"unchecked", "rawtypes"}) +public class RedisUtils { + + private static final RedissonClient CLIENT = SpringUtils.getBean(RedissonClient.class); + /** + * 限流 + * + * @param key 限流key + * @param rateType 限流类型 + * @param rate 速率 + * @param rateInterval 速率间隔 + * @return -1 表示失败 + */ + public static long rateLimiter(String key, RateType rateType, int rate, int rateInterval) { + RRateLimiter rateLimiter = CLIENT.getRateLimiter(key); + rateLimiter.trySetRate(rateType, rate, rateInterval, RateIntervalUnit.SECONDS); + if (rateLimiter.tryAcquire()) { + return rateLimiter.availablePermits(); + } else { + return -1L; + } + } + /** + * 获取客户端实例 + */ + public static RedissonClient getClient() { + return CLIENT; + } + /** + * 发布通道消息 + * + * @param channelKey 通道key + * @param msg 发送数据 + * @param consumer 自定义处理 + */ + public static void publish(String channelKey, T msg, Consumer consumer) { + RTopic topic = CLIENT.getTopic(channelKey); + topic.publish(msg); + consumer.accept(msg); + } + + public static void publish(String channelKey, T msg) { + RTopic topic = CLIENT.getTopic(channelKey); + topic.publish(msg); + } + /** + * 订阅通道接收消息 + * + * @param channelKey 通道key + * @param clazz 消息类型 + * @param consumer 自定义处理 + */ + public static void subscribe(String channelKey, Class clazz, Consumer consumer) { + RTopic topic = CLIENT.getTopic(channelKey); + topic.addListener(clazz, (channel, msg) -> consumer.accept(msg)); + } + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + */ + public static void setCacheObject(final String key, final T value) { + setCacheObject(key, value, false); + } + /** + * 缓存基本的对象,保留当前对象 TTL 有效期 + * + * @param key 缓存的键值 + * @param value 缓存的值 + * @param isSaveTtl 是否保留TTL有效期(例如: set之前ttl剩余90 set之后还是为90) + * @since Redis 6.X 以上使用 setAndKeepTTL 兼容 5.X 方案 + */ + public static void setCacheObject(final String key, final T value, final boolean isSaveTtl) { + RBucket bucket = CLIENT.getBucket(key); + if (isSaveTtl) { + try { + bucket.setAndKeepTTL(value); + } catch (Exception e) { + long timeToLive = bucket.remainTimeToLive(); + setCacheObject(key, value, Duration.ofMillis(timeToLive)); + } + } else { + bucket.set(value); + } + } + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + * @param duration 时间 + */ + public static void setCacheObject(final String key, final T value, final Duration duration) { + RBatch batch = CLIENT.createBatch(); + RBucketAsync bucket = batch.getBucket(key); + bucket.setAsync(value); + bucket.expireAsync(duration); + batch.execute(); + } + /** + * 注册对象监听器 + *

+ * key 监听器需开启 `notify-keyspace-events` 等 redis 相关配置 + * + * @param key 缓存的键值 + * @param listener 监听器配置 + */ + public static void addObjectListener(final String key, final ObjectListener listener) { + RBucket result = CLIENT.getBucket(key); + result.addListener(listener); + } + /** + * 设置有效时间 + * + * @param key Redis键 + * @param timeout 超时时间 + * @return true=设置成功;false=设置失败 + */ + public static boolean expire(final String key, final long timeout) { + return expire(key, Duration.ofSeconds(timeout)); + } + /** + * 设置有效时间 + * + * @param key Redis键 + * @param duration 超时时间 + * @return true=设置成功;false=设置失败 + */ + public static boolean expire(final String key, final Duration duration) { + RBucket rBucket = CLIENT.getBucket(key); + return rBucket.expire(duration); + } + /** + * 获得缓存的基本对象。 + * + * @param key 缓存键值 + * @return 缓存键值对应的数据 + */ + public static T getCacheObject(final String key) { + RBucket rBucket = CLIENT.getBucket(key); + return rBucket.get(); + } + /** + * 获得key剩余存活时间 + * + * @param key 缓存键值 + * @return 剩余存活时间 + */ + public static long getTimeToLive(final String key) { + RBucket rBucket = CLIENT.getBucket(key); + return rBucket.remainTimeToLive(); + } + /** + * 删除单个对象 + * + * @param key 缓存的键值 + */ + public static boolean deleteObject(final String key) { + return CLIENT.getBucket(key).delete(); + } + /** + * 删除集合对象 + * + * @param collection 多个对象 + */ + public static void deleteObject(final Collection collection) { + RBatch batch = CLIENT.createBatch(); + collection.forEach(t -> { + batch.getBucket(t.toString()).deleteAsync(); + }); + batch.execute(); + } + /** + * 检查缓存对象是否存在 + * + * @param key 缓存的键值 + */ + public static boolean isExistsObject(final String key) { + return CLIENT.getBucket(key).isExists(); + } + /** + * 缓存List数据 + * + * @param key 缓存的键值 + * @param dataList 待缓存的List数据 + * @return 缓存的对象 + */ + public static boolean setCacheList(final String key, final List dataList) { + RList rList = CLIENT.getList(key); + return rList.addAll(dataList); + } + /** + * 注册List监听器 + *

+ * key 监听器需开启 `notify-keyspace-events` 等 redis 相关配置 + * + * @param key 缓存的键值 + * @param listener 监听器配置 + */ + public static void addListListener(final String key, final ObjectListener listener) { + RList rList = CLIENT.getList(key); + rList.addListener(listener); + } + /** + * 获得缓存的list对象 + * + * @param key 缓存的键值 + * @return 缓存键值对应的数据 + */ + public static List getCacheList(final String key) { + RList rList = CLIENT.getList(key); + return rList.readAll(); + } + /** + * 缓存Set + * + * @param key 缓存键值 + * @param dataSet 缓存的数据 + * @return 缓存数据的对象 + */ + public static boolean setCacheSet(final String key, final Set dataSet) { + RSet rSet = CLIENT.getSet(key); + return rSet.addAll(dataSet); + } + /** + * 注册Set监听器 + *

+ * key 监听器需开启 `notify-keyspace-events` 等 redis 相关配置 + * + * @param key 缓存的键值 + * @param listener 监听器配置 + */ + public static void addSetListener(final String key, final ObjectListener listener) { + RSet rSet = CLIENT.getSet(key); + rSet.addListener(listener); + } + /** + * 获得缓存的set + * + * @param key 缓存的key + * @return set对象 + */ + public static Set getCacheSet(final String key) { + RSet rSet = CLIENT.getSet(key); + return rSet.readAll(); + } + /** + * 缓存Map + * + * @param key 缓存的键值 + * @param dataMap 缓存的数据 + */ + public static void setCacheMap(final String key, final Map dataMap) { + if (dataMap != null) { + RMap rMap = CLIENT.getMap(key); + rMap.putAll(dataMap); + } + } + /** + * 注册Map监听器 + *

+ * key 监听器需开启 `notify-keyspace-events` 等 redis 相关配置 + * + * @param key 缓存的键值 + * @param listener 监听器配置 + */ + public static void addMapListener(final String key, final ObjectListener listener) { + RMap rMap = CLIENT.getMap(key); + rMap.addListener(listener); + } + /** + * 获得缓存的Map + * + * @param key 缓存的键值 + * @return map对象 + */ + public static Map getCacheMap(final String key) { + RMap rMap = CLIENT.getMap(key); + return rMap.getAll(rMap.keySet()); + } + /** + * 获得缓存Map的key列表 + * + * @param key 缓存的键值 + * @return key列表 + */ + public static Set getCacheMapKeySet(final String key) { + RMap rMap = CLIENT.getMap(key); + return rMap.keySet(); + } + /** + * 往Hash中存入数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @param value 值 + */ + public static void setCacheMapValue(final String key, final String hKey, final T value) { + RMap rMap = CLIENT.getMap(key); + rMap.put(hKey, value); + } + /** + * 获取Hash中的数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @return Hash中的对象 + */ + public static T getCacheMapValue(final String key, final String hKey) { + RMap rMap = CLIENT.getMap(key); + return rMap.get(hKey); + } + /** + * 删除Hash中的数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @return Hash中的对象 + */ + public static T delCacheMapValue(final String key, final String hKey) { + RMap rMap = CLIENT.getMap(key); + return rMap.remove(hKey); + } + /** + * 获取多个Hash中的数据 + * + * @param key Redis键 + * @param hKeys Hash键集合 + * @return Hash对象集合 + */ + public static Map getMultiCacheMapValue(final String key, final Set hKeys) { + RMap rMap = CLIENT.getMap(key); + return rMap.getAll(hKeys); + } + /** + * 设置原子值 + * + * @param key Redis键 + * @param value 值 + */ + public static void setAtomicValue(String key, long value) { + RAtomicLong atomic = CLIENT.getAtomicLong(key); + atomic.set(value); + } + /** + * 获取原子值 + * + * @param key Redis键 + * @return 当前值 + */ + public static long getAtomicValue(String key) { + RAtomicLong atomic = CLIENT.getAtomicLong(key); + return atomic.get(); + } + /** + * 递增原子值 + * + * @param key Redis键 + * @return 当前值 + */ + public static long incrAtomicValue(String key) { + RAtomicLong atomic = CLIENT.getAtomicLong(key); + return atomic.incrementAndGet(); + } + /** + * 递减原子值 + * + * @param key Redis键 + * @return 当前值 + */ + public static long decrAtomicValue(String key) { + RAtomicLong atomic = CLIENT.getAtomicLong(key); + return atomic.decrementAndGet(); + } + /** + * 获得缓存的基本对象列表 + * + * @param pattern 字符串前缀 + * @return 对象列表 + */ + public static Collection keys(final String pattern) { + Stream stream = CLIENT.getKeys().getKeysStreamByPattern(pattern); + return stream.collect(Collectors.toList()); + } + /** + * 删除缓存的基本对象列表 + * + * @param pattern 字符串前缀 + */ + public static void deleteKeys(final String pattern) { + CLIENT.getKeys().deleteByPattern(pattern); + } + /** + * 检查redis中是否存在key + * + * @param key 键 + */ + public static Boolean hasKey(String key) { + RKeys rKeys = CLIENT.getKeys(); + return rKeys.countExists(key) > 0; + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/reflect/ReflectUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/reflect/ReflectUtils.java new file mode 100644 index 0000000..de6e52a --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/reflect/ReflectUtils.java @@ -0,0 +1,54 @@ +package com.inscloudtech.common.utils.reflect; + +import cn.hutool.core.util.ReflectUtil; +import com.inscloudtech.common.utils.StringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.lang.reflect.Method; + +/** + * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数. + * + * @author inscloudtech + */ +@SuppressWarnings("rawtypes") +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ReflectUtils extends ReflectUtil { + + private static final String SETTER_PREFIX = "set"; + + private static final String GETTER_PREFIX = "get"; + /** + * 调用Getter方法. + * 支持多级,如:对象名.对象名.方法 + */ + @SuppressWarnings("unchecked") + public static E invokeGetter(Object obj, String propertyName) { + Object object = obj; + for (String name : StringUtils.split(propertyName, ".")) { + String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name); + object = invoke(object, getterMethodName); + } + return (E) object; + } + /** + * 调用Setter方法, 仅匹配方法名。 + * 支持多级,如:对象名.对象名.方法 + */ + public static void invokeSetter(Object obj, String propertyName, E value) { + Object object = obj; + String[] names = StringUtils.split(propertyName, "."); + for (int i = 0; i < names.length; i++) { + if (i < names.length - 1) { + String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]); + object = invoke(object, getterMethodName); + } else { + String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]); + Method method = getMethodByName(object.getClass(), setterMethodName); + invoke(object, method, value); + } + } + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/spring/SpringUtils.java b/cas-common/src/main/java/com/inscloudtech/common/utils/spring/SpringUtils.java new file mode 100644 index 0000000..e64fee6 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/spring/SpringUtils.java @@ -0,0 +1,68 @@ +package com.inscloudtech.common.utils.spring; + +import cn.hutool.extra.spring.SpringUtil; +import org.springframework.aop.framework.AopContext; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +/** + * spring工具类 + * + * @author inscloudtech + */ +@Component +public final class SpringUtils extends SpringUtil { + /** + * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true + * + * @param name + * @return boolean + */ + public static boolean containsBean(String name) { + return getBeanFactory().containsBean(name); + } + /** + * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 + * 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException) + * + * @param name + * @return boolean + */ + public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException { + return getBeanFactory().isSingleton(name); + } + /** + * @param name + * @return Class 注册对象的类型 + */ + public static Class getType(String name) throws NoSuchBeanDefinitionException { + return getBeanFactory().getType(name); + } + /** + * 如果给定的bean名字在bean定义中有别名,则返回这些别名 + * + * @param name + */ + public static String[] getAliases(String name) throws NoSuchBeanDefinitionException { + return getBeanFactory().getAliases(name); + } + /** + * 获取aop代理对象 + * + * @param invoker + * @return + */ + @SuppressWarnings("unchecked") + public static T getAopProxy(T invoker) { + return (T) AopContext.currentProxy(); + } + + /** + * 获取spring上下文 + */ + public static ApplicationContext context() { + return getApplicationContext(); + } + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/utils/sql/SqlUtil.java b/cas-common/src/main/java/com/inscloudtech/common/utils/sql/SqlUtil.java new file mode 100644 index 0000000..1146652 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/utils/sql/SqlUtil.java @@ -0,0 +1,52 @@ +package com.inscloudtech.common.utils.sql; + +import com.inscloudtech.common.exception.UtilException; +import com.inscloudtech.common.utils.StringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +/** + * sql操作工具类 + * + * @author inscloudtech + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class SqlUtil { + /** + * 定义常用的 sql关键字 + */ + public static final String SQL_REGEX = "select |insert |delete |update |drop |count |exec |chr |mid |master |truncate |char |and |declare "; + /** + * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序) + */ + public static final String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+"; + /** + * 检查字符,防止注入绕过 + */ + public static String escapeOrderBySql(String value) { + if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) { + throw new UtilException("参数不符合规范,不能进行查询"); + } + return value; + } + /** + * 验证 order by 语法是否符合规范 + */ + public static boolean isValidOrderBySql(String value) { + return value.matches(SQL_PATTERN); + } + /** + * SQL关键字检查 + */ + public static void filterKeyword(String value) { + if (StringUtils.isEmpty(value)) { + return; + } + String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|"); + for (String sqlKeyword : sqlKeywords) { + if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1) { + throw new UtilException("参数存在SQL注入风险"); + } + } + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/uuid/IdUtils.java b/cas-common/src/main/java/com/inscloudtech/common/uuid/IdUtils.java new file mode 100644 index 0000000..f1aadc3 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/uuid/IdUtils.java @@ -0,0 +1,44 @@ +package com.inscloudtech.common.uuid; + +/** + * ID生成器工具类 + * + * @author ruoyi + */ +public class IdUtils { + /** + * 获取随机UUID + * + * @return 随机UUID + */ + public static String randomUUID() { + return UUID.randomUUID().toString(); + } + + /** + * 简化的UUID,去掉了横线 + * + * @return 简化的UUID,去掉了横线 + */ + public static String simpleUUID() { + return UUID.randomUUID().toString(true); + } + + /** + * 获取随机UUID,使用性能更好的ThreadLocalRandom生成UUID + * + * @return 随机UUID + */ + public static String fastUUID() { + return UUID.fastUUID().toString(); + } + + /** + * 简化的UUID,去掉了横线,使用性能更好的ThreadLocalRandom生成UUID + * + * @return 简化的UUID,去掉了横线 + */ + public static String fastSimpleUUID() { + return UUID.fastUUID().toString(true); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/uuid/Seq.java b/cas-common/src/main/java/com/inscloudtech/common/uuid/Seq.java new file mode 100644 index 0000000..7e42177 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/uuid/Seq.java @@ -0,0 +1,79 @@ +package com.inscloudtech.common.uuid; + + + +import com.inscloudtech.common.utils.DateUtils; +import com.inscloudtech.common.utils.StringUtils; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author 序列生成类 + */ +public class Seq { + // 通用序列类型 + public static final String commSeqType = "COMMON"; + + // 上传序列类型 + public static final String uploadSeqType = "UPLOAD"; + // 机器标识 + private static final String machineCode = "A"; + // 通用接口序列数 + private static AtomicInteger commSeq = new AtomicInteger(1); + // 上传接口序列数 + private static AtomicInteger uploadSeq = new AtomicInteger(1); + + /** + * 获取通用序列号 + * + * @return 序列值 + */ + public static String getId() { + return getId(commSeqType); + } + + /** + * 默认16位序列号 yyMMddHHmmss + 一位机器标识 + 3长度循环递增字符串 + * + * @return 序列值 + */ + public static String getId(String type) { + AtomicInteger atomicInt = commSeq; + if (uploadSeqType.equals(type)) { + atomicInt = uploadSeq; + } + return getId(atomicInt, 3); + } + + /** + * 通用接口序列号 yyMMddHHmmss + 一位机器标识 + length长度循环递增字符串 + * + * @param atomicInt 序列数 + * @param length 数值长度 + * @return 序列值 + */ + public static String getId(AtomicInteger atomicInt, int length) { + String result = DateUtils.dateTimeNow(); + result += machineCode; + result += getSeq(atomicInt, length); + return result; + } + + /** + * 序列循环递增字符串[1, 10 的 (length)幂次方), 用0左补齐length位数 + * + * @return 序列值 + */ + private synchronized static String getSeq(AtomicInteger atomicInt, int length) { + // 先取值再+1 + int value = atomicInt.getAndIncrement(); + + // 如果更新后值>=10 的 (length)幂次方则重置为1 + int maxSeq = (int) Math.pow(10, length); + if (atomicInt.get() >= maxSeq) { + atomicInt.set(1); + } + // 转字符串,用0左补齐 + return StringUtils.padl(value, length); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/uuid/UUID.java b/cas-common/src/main/java/com/inscloudtech/common/uuid/UUID.java new file mode 100644 index 0000000..0d989cb --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/uuid/UUID.java @@ -0,0 +1,440 @@ +package com.inscloudtech.common.uuid; + + +import com.inscloudtech.common.exception.UtilException; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; + +/** + * 提供通用唯一识别码(universally unique identifier)(UUID)实现 + * + * @author + */ +public final class UUID implements java.io.Serializable, Comparable { + private static final long serialVersionUID = -1185015143654744140L; + /** + * 此UUID的最高64有效位 + */ + private final long mostSigBits; + /** + * 此UUID的最低64有效位 + */ + private final long leastSigBits; + + /** + * 私有构造 + * + * @param data 数据 + */ + private UUID(byte[] data) { + long msb = 0; + long lsb = 0; + assert data.length == 16 : "data must be 16 bytes in length"; + for (int i = 0; i < 8; i++) { + msb = (msb << 8) | (data[i] & 0xff); + } + for (int i = 8; i < 16; i++) { + lsb = (lsb << 8) | (data[i] & 0xff); + } + this.mostSigBits = msb; + this.leastSigBits = lsb; + } + + /** + * 使用指定的数据构造新的 UUID。 + * + * @param mostSigBits 用于 {@code UUID} 的最高有效 64 位 + * @param leastSigBits 用于 {@code UUID} 的最低有效 64 位 + */ + public UUID(long mostSigBits, long leastSigBits) { + this.mostSigBits = mostSigBits; + this.leastSigBits = leastSigBits; + } + + /** + * 获取类型 4(伪随机生成的)UUID 的静态工厂。 + * + * @return 随机生成的 {@code UUID} + */ + public static UUID fastUUID() { + return randomUUID(false); + } + + /** + * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。 + * + * @return 随机生成的 {@code UUID} + */ + public static UUID randomUUID() { + return randomUUID(true); + } + + /** + * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。 + * + * @param isSecure 是否使用{@link SecureRandom}如果是可以获得更安全的随机码,否则可以得到更好的性能 + * @return 随机生成的 {@code UUID} + */ + public static UUID randomUUID(boolean isSecure) { + final Random ng = isSecure ? Holder.numberGenerator : getRandom(); + + byte[] randomBytes = new byte[16]; + ng.nextBytes(randomBytes); + randomBytes[6] &= 0x0f; /* clear version */ + randomBytes[6] |= 0x40; /* set to version 4 */ + randomBytes[8] &= 0x3f; /* clear variant */ + randomBytes[8] |= 0x80; /* set to IETF variant */ + return new UUID(randomBytes); + } + + /** + * 根据指定的字节数组获取类型 3(基于名称的)UUID 的静态工厂。 + * + * @param name 用于构造 UUID 的字节数组。 + * @return 根据指定数组生成的 {@code UUID} + */ + public static UUID nameUUIDFromBytes(byte[] name) { + MessageDigest md; + try { + md = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException nsae) { + throw new InternalError("MD5 not supported"); + } + byte[] md5Bytes = md.digest(name); + md5Bytes[6] &= 0x0f; /* clear version */ + md5Bytes[6] |= 0x30; /* set to version 3 */ + md5Bytes[8] &= 0x3f; /* clear variant */ + md5Bytes[8] |= 0x80; /* set to IETF variant */ + return new UUID(md5Bytes); + } + + /** + * 根据 {@link #toString()} 方法中描述的字符串标准表示形式创建{@code UUID}。 + * + * @param name 指定 {@code UUID} 字符串 + * @return 具有指定值的 {@code UUID} + * @throws IllegalArgumentException 如果 name 与 {@link #toString} 中描述的字符串表示形式不符抛出此异常 + */ + public static UUID fromString(String name) { + String[] components = name.split("-"); + if (components.length != 5) { + throw new IllegalArgumentException("Invalid UUID string: " + name); + } + for (int i = 0; i < 5; i++) { + components[i] = "0x" + components[i]; + } + + long mostSigBits = Long.decode(components[0]).longValue(); + mostSigBits <<= 16; + mostSigBits |= Long.decode(components[1]).longValue(); + mostSigBits <<= 16; + mostSigBits |= Long.decode(components[2]).longValue(); + + long leastSigBits = Long.decode(components[3]).longValue(); + leastSigBits <<= 48; + leastSigBits |= Long.decode(components[4]).longValue(); + + return new UUID(mostSigBits, leastSigBits); + } + + /** + * 返回指定数字对应的hex值 + * + * @param val 值 + * @param digits 位 + * @return 值 + */ + private static String digits(long val, int digits) { + long hi = 1L << (digits * 4); + return Long.toHexString(hi | (val & (hi - 1))).substring(1); + } + + /** + * 获取{@link SecureRandom},类提供加密的强随机数生成器 (RNG) + * + * @return {@link SecureRandom} + */ + public static SecureRandom getSecureRandom() { + try { + return SecureRandom.getInstance("SHA1PRNG"); + } catch (NoSuchAlgorithmException e) { + throw new UtilException(e); + } + } + + /** + * 获取随机数生成器对象
+ * ThreadLocalRandom是JDK 7之后提供并发产生随机数,能够解决多个线程发生的竞争争夺。 + * + * @return {@link ThreadLocalRandom} + */ + public static ThreadLocalRandom getRandom() { + return ThreadLocalRandom.current(); + } + + /** + * 返回此 UUID 的 128 位值中的最低有效 64 位。 + * + * @return 此 UUID 的 128 位值中的最低有效 64 位。 + */ + public long getLeastSignificantBits() { + return leastSigBits; + } + + /** + * 返回此 UUID 的 128 位值中的最高有效 64 位。 + * + * @return 此 UUID 的 128 位值中最高有效 64 位。 + */ + public long getMostSignificantBits() { + return mostSigBits; + } + + /** + * 与此 {@code UUID} 相关联的版本号. 版本号描述此 {@code UUID} 是如何生成的。 + *

+ * 版本号具有以下含意: + *

    + *
  • 1 基于时间的 UUID + *
  • 2 DCE 安全 UUID + *
  • 3 基于名称的 UUID + *
  • 4 随机生成的 UUID + *
+ * + * @return 此 {@code UUID} 的版本号 + */ + public int version() { + // Version is bits masked by 0x000000000000F000 in MS long + return (int) ((mostSigBits >> 12) & 0x0f); + } + + /** + * 与此 {@code UUID} 相关联的变体号。变体号描述 {@code UUID} 的布局。 + *

+ * 变体号具有以下含意: + *

    + *
  • 0 为 NCS 向后兼容保留 + *
  • 2 IETF RFC 4122(Leach-Salz), 用于此类 + *
  • 6 保留,微软向后兼容 + *
  • 7 保留供以后定义使用 + *
+ * + * @return 此 {@code UUID} 相关联的变体号 + */ + public int variant() { + // This field is composed of a varying number of bits. + // 0 - - Reserved for NCS backward compatibility + // 1 0 - The IETF aka Leach-Salz variant (used by this class) + // 1 1 0 Reserved, Microsoft backward compatibility + // 1 1 1 Reserved for future definition. + return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62))) & (leastSigBits >> 63)); + } + + /** + * 与此 UUID 相关联的时间戳值。 + * + *

+ * 60 位的时间戳值根据此 {@code UUID} 的 time_low、time_mid 和 time_hi 字段构造。
+ * 所得到的时间戳以 100 毫微秒为单位,从 UTC(通用协调时间) 1582 年 10 月 15 日零时开始。 + * + *

+ * 时间戳值仅在在基于时间的 UUID(其 version 类型为 1)中才有意义。
+ * 如果此 {@code UUID} 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。 + * + * @throws UnsupportedOperationException 如果此 {@code UUID} 不是 version 为 1 的 UUID。 + */ + public long timestamp() throws UnsupportedOperationException { + checkTimeBase(); + return (mostSigBits & 0x0FFFL) << 48// + | ((mostSigBits >> 16) & 0x0FFFFL) << 32// + | mostSigBits >>> 32; + } + + /** + * 与此 UUID 相关联的时钟序列值。 + * + *

+ * 14 位的时钟序列值根据此 UUID 的 clock_seq 字段构造。clock_seq 字段用于保证在基于时间的 UUID 中的时间唯一性。 + *

+ * {@code clockSequence} 值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。 如果此 UUID 不是基于时间的 UUID,则此方法抛出 + * UnsupportedOperationException。 + * + * @return 此 {@code UUID} 的时钟序列 + * @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1 + */ + public int clockSequence() throws UnsupportedOperationException { + checkTimeBase(); + return (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48); + } + + /** + * 与此 UUID 相关的节点值。 + * + *

+ * 48 位的节点值根据此 UUID 的 node 字段构造。此字段旨在用于保存机器的 IEEE 802 地址,该地址用于生成此 UUID 以保证空间唯一性。 + *

+ * 节点值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。
+ * 如果此 UUID 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。 + * + * @return 此 {@code UUID} 的节点值 + * @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1 + */ + public long node() throws UnsupportedOperationException { + checkTimeBase(); + return leastSigBits & 0x0000FFFFFFFFFFFFL; + } + + /** + * 返回此{@code UUID} 的字符串表现形式。 + * + *

+ * UUID 的字符串表示形式由此 BNF 描述: + * + *

+     * {@code
+     * UUID                   = ----
+     * time_low               = 4*
+     * time_mid               = 2*
+     * time_high_and_version  = 2*
+     * variant_and_sequence   = 2*
+     * node                   = 6*
+     * hexOctet               = 
+     * hexDigit               = [0-9a-fA-F]
+     * }
+     * 
+ * + * + * + * @return 此{@code UUID} 的字符串表现形式 + * @see #toString(boolean) + */ + @Override + public String toString() { + return toString(false); + } + + /** + * 返回此{@code UUID} 的字符串表现形式。 + * + *

+ * UUID 的字符串表示形式由此 BNF 描述: + * + *

+     * {@code
+     * UUID                   = ----
+     * time_low               = 4*
+     * time_mid               = 2*
+     * time_high_and_version  = 2*
+     * variant_and_sequence   = 2*
+     * node                   = 6*
+     * hexOctet               = 
+     * hexDigit               = [0-9a-fA-F]
+     * }
+     * 
+ * + * + * + * @param isSimple 是否简单模式,简单模式为不带'-'的UUID字符串 + * @return 此{@code UUID} 的字符串表现形式 + */ + public String toString(boolean isSimple) { + final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36); + // time_low + builder.append(digits(mostSigBits >> 32, 8)); + if (!isSimple) { + builder.append('-'); + } + // time_mid + builder.append(digits(mostSigBits >> 16, 4)); + if (!isSimple) { + builder.append('-'); + } + // time_high_and_version + builder.append(digits(mostSigBits, 4)); + if (!isSimple) { + builder.append('-'); + } + // variant_and_sequence + builder.append(digits(leastSigBits >> 48, 4)); + if (!isSimple) { + builder.append('-'); + } + // node + builder.append(digits(leastSigBits, 12)); + + return builder.toString(); + } + + // Comparison Operations + + /** + * 返回此 UUID 的哈希码。 + * + * @return UUID 的哈希码值。 + */ + @Override + public int hashCode() { + long hilo = mostSigBits ^ leastSigBits; + return ((int) (hilo >> 32)) ^ (int) hilo; + } + + // ------------------------------------------------------------------------------------------------------------------- + // Private method start + + /** + * 将此对象与指定对象比较。 + *

+ * 当且仅当参数不为 {@code null}、而是一个 UUID 对象、具有与此 UUID 相同的 varriant、包含相同的值(每一位均相同)时,结果才为 {@code true}。 + * + * @param obj 要与之比较的对象 + * @return 如果对象相同,则返回 {@code true};否则返回 {@code false} + */ + @Override + public boolean equals(Object obj) { + if ((null == obj) || (obj.getClass() != UUID.class)) { + return false; + } + UUID id = (UUID) obj; + return (mostSigBits == id.mostSigBits && leastSigBits == id.leastSigBits); + } + + /** + * 将此 UUID 与指定的 UUID 比较。 + * + *

+ * 如果两个 UUID 不同,且第一个 UUID 的最高有效字段大于第二个 UUID 的对应字段,则第一个 UUID 大于第二个 UUID。 + * + * @param val 与此 UUID 比较的 UUID + * @return 在此 UUID 小于、等于或大于 val 时,分别返回 -1、0 或 1。 + */ + @Override + public int compareTo(UUID val) { + // The ordering is intentionally set up so that the UUIDs + // can simply be numerically compared as two numbers + return (this.mostSigBits < val.mostSigBits ? -1 : // + (this.mostSigBits > val.mostSigBits ? 1 : // + (this.leastSigBits < val.leastSigBits ? -1 : // + (this.leastSigBits > val.leastSigBits ? 1 : // + 0)))); + } + + /** + * 检查是否为time-based版本UUID + */ + private void checkTimeBase() { + if (version() != 1) { + throw new UnsupportedOperationException("Not a time-based UUID"); + } + } + + /** + * SecureRandom 的单例 + */ + private static class Holder { + static final SecureRandom numberGenerator = getSecureRandom(); + } +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/xss/Xss.java b/cas-common/src/main/java/com/inscloudtech/common/xss/Xss.java new file mode 100644 index 0000000..887fbb8 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/xss/Xss.java @@ -0,0 +1,26 @@ +package com.inscloudtech.common.xss; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 自定义xss校验注解 + * + * @author inscloudtech + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(value = {ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER}) +@Constraint(validatedBy = {XssValidator.class}) +public @interface Xss { + + String message() default "不允许任何脚本运行"; + + Class[] groups() default {}; + + Class[] payload() default {}; + +} diff --git a/cas-common/src/main/java/com/inscloudtech/common/xss/XssValidator.java b/cas-common/src/main/java/com/inscloudtech/common/xss/XssValidator.java new file mode 100644 index 0000000..97aa547 --- /dev/null +++ b/cas-common/src/main/java/com/inscloudtech/common/xss/XssValidator.java @@ -0,0 +1,21 @@ +package com.inscloudtech.common.xss; + +import cn.hutool.core.util.ReUtil; +import cn.hutool.http.HtmlUtil; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +/** + * 自定义xss校验注解实现 + * + * @author inscloudtech + */ +public class XssValidator implements ConstraintValidator { + + @Override + public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) { + return !ReUtil.contains(HtmlUtil.RE_HTML_MARK, value); + } + +} diff --git a/cas-framework/pom.xml b/cas-framework/pom.xml new file mode 100644 index 0000000..68ee6f8 --- /dev/null +++ b/cas-framework/pom.xml @@ -0,0 +1,72 @@ + + + + cas-server + com.inscloudtech + 4.7.0 + + 4.0.0 + + cas-framework + + + framework框架核心 + + + + + + + org.springframework.boot + spring-boot-starter-web + + + spring-boot-starter-tomcat + org.springframework.boot + + + + + + org.springframework.boot + spring-boot-starter-undertow + + + + + org.springframework.boot + spring-boot-starter-aop + + + + + p6spy + p6spy + + + + org.springframework.boot + spring-boot-starter-actuator + + + + de.codecentric + spring-boot-admin-starter-client + + + + com.alibaba + transmittable-thread-local + + + + + com.inscloudtech + cas-common + + + + + diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/aspectj/LogAspect.java b/cas-framework/src/main/java/com/inscloudtech/framework/aspectj/LogAspect.java new file mode 100644 index 0000000..67d314f --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/aspectj/LogAspect.java @@ -0,0 +1,188 @@ +package com.inscloudtech.framework.aspectj; + +import cn.hutool.core.lang.Dict; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.core.domain.event.OperLogEvent; +import com.inscloudtech.common.enums.BusinessStatus; +import com.inscloudtech.common.enums.HttpMethod; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.common.utils.JsonUtils; +import com.inscloudtech.common.utils.ServletUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.spring.SpringUtils; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.stereotype.Component; +import org.springframework.validation.BindingResult; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Collection; +import java.util.Map; + +/** + * 操作日志记录处理 + * + * @author Lion Li + */ +@Slf4j +@Aspect +@Component +public class LogAspect { + /** + * 排除敏感属性字段 + */ + public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" }; + /** + * 处理完请求后执行 + * + * @param joinPoint 切点 + */ + @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult") + public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) { + handleLog(joinPoint, controllerLog, null, jsonResult); + } + /** + * 拦截异常操作 + * + * @param joinPoint 切点 + * @param e 异常 + */ + @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e") + public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) { + handleLog(joinPoint, controllerLog, e, null); + } + + protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) { + try { + + // *========数据库日志=========*// + OperLogEvent operLog = new OperLogEvent(); + operLog.setStatus(BusinessStatus.SUCCESS.ordinal()); + // 请求的地址 + String ip = ServletUtils.getClientIP(); + operLog.setOperIp(ip); + operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255)); + operLog.setOperName(LoginHelper.getUsername()); + + if (e != null) { + operLog.setStatus(BusinessStatus.FAIL.ordinal()); + operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000)); + } + // 设置方法名称 + String className = joinPoint.getTarget().getClass().getName(); + String methodName = joinPoint.getSignature().getName(); + operLog.setMethod(className + "." + methodName + "()"); + // 设置请求方式 + operLog.setRequestMethod(ServletUtils.getRequest().getMethod()); + // 处理设置注解上的参数 + getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult); + // 发布事件保存数据库 + SpringUtils.context().publishEvent(operLog); + } catch (Exception exp) { + // 记录本地异常日志 + log.error("异常信息:{}", exp.getMessage()); + exp.printStackTrace(); + } + } + /** + * 获取注解中对方法的描述信息 用于Controller层注解 + * + * @param log 日志 + * @param operLog 操作日志 + * @throws Exception + */ + public void getControllerMethodDescription(JoinPoint joinPoint, Log log, OperLogEvent operLog, Object jsonResult) throws Exception { + // 设置action动作 + operLog.setBusinessType(log.businessType().ordinal()); + // 设置标题 + operLog.setTitle(log.title()); + // 设置操作人类别 + operLog.setOperatorType(log.operatorType().ordinal()); + // 是否需要保存request,参数和值 + if (log.isSaveRequestData()) { + // 获取参数的信息,传入到数据库中。 + setRequestValue(joinPoint, operLog, log.excludeParamNames()); + } + // 是否需要保存response,参数和值 + if (log.isSaveResponseData() && ObjectUtil.isNotNull(jsonResult)) { + operLog.setJsonResult(StringUtils.substring(JsonUtils.toJsonString(jsonResult), 0, 2000)); + } + } + /** + * 获取请求的参数,放到log中 + * + * @param operLog 操作日志 + * @throws Exception 异常 + */ + private void setRequestValue(JoinPoint joinPoint, OperLogEvent operLog, String[] excludeParamNames) throws Exception { + Map paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest()); + String requestMethod = operLog.getRequestMethod(); + if (MapUtil.isEmpty(paramsMap) + && HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) { + String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames); + operLog.setOperParam(StringUtils.substring(params, 0, 2000)); + } else { + MapUtil.removeAny(paramsMap, EXCLUDE_PROPERTIES); + MapUtil.removeAny(paramsMap, excludeParamNames); + operLog.setOperParam(StringUtils.substring(JsonUtils.toJsonString(paramsMap), 0, 2000)); + } + } + /** + * 参数拼装 + */ + private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames) { + StringBuilder params = new StringBuilder(); + if (paramsArray != null && paramsArray.length > 0) { + for (Object o : paramsArray) { + if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) { + try { + String str = JsonUtils.toJsonString(o); + Dict dict = JsonUtils.parseMap(str); + if (MapUtil.isNotEmpty(dict)) { + MapUtil.removeAny(dict, EXCLUDE_PROPERTIES); + MapUtil.removeAny(dict, excludeParamNames); + str = JsonUtils.toJsonString(dict); + } + params.append(str).append(" "); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + return params.toString().trim(); + } + /** + * 判断是否需要过滤的对象。 + * + * @param o 对象信息。 + * @return 如果是需要过滤的对象,则返回true;否则返回false。 + */ + @SuppressWarnings("rawtypes") + public boolean isFilterObject(final Object o) { + Class clazz = o.getClass(); + if (clazz.isArray()) { + return clazz.getComponentType().isAssignableFrom(MultipartFile.class); + } else if (Collection.class.isAssignableFrom(clazz)) { + Collection collection = (Collection) o; + for (Object value : collection) { + return value instanceof MultipartFile; + } + } else if (Map.class.isAssignableFrom(clazz)) { + Map map = (Map) o; + for (Object value : map.entrySet()) { + Map.Entry entry = (Map.Entry) value; + return entry.getValue() instanceof MultipartFile; + } + } + return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse + || o instanceof BindingResult; + } +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/aspectj/RateLimiterAspect.java b/cas-framework/src/main/java/com/inscloudtech/framework/aspectj/RateLimiterAspect.java new file mode 100644 index 0000000..7cf1d86 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/aspectj/RateLimiterAspect.java @@ -0,0 +1,125 @@ +package com.inscloudtech.framework.aspectj; + +import cn.hutool.core.util.ArrayUtil; +import com.inscloudtech.common.annotation.RateLimiter; +import com.inscloudtech.common.constant.CacheConstants; +import com.inscloudtech.common.enums.LimitType; +import com.inscloudtech.common.exception.ServiceException; +import com.inscloudtech.common.utils.MessageUtils; +import com.inscloudtech.common.utils.ServletUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.redis.RedisUtils; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.reflect.MethodSignature; +import org.redisson.api.RateType; +import org.springframework.core.DefaultParameterNameDiscoverer; +import org.springframework.core.ParameterNameDiscoverer; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.ParserContext; +import org.springframework.expression.common.TemplateParserContext; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; + +/** + * 限流处理 + * + * @author inscloudtech + */ +@Slf4j +@Aspect +@Component +public class RateLimiterAspect { + /** + * 定义spel表达式解析器 + */ + private final ExpressionParser parser = new SpelExpressionParser(); /** + * 定义spel解析模版 + */ + private final ParserContext parserContext = new TemplateParserContext(); /** + * 定义spel上下文对象进行解析 + */ + private final EvaluationContext context = new StandardEvaluationContext(); /** + * 方法参数解析器 + */ + private final ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer(); + + @Before("@annotation(rateLimiter)") + public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable { + int time = rateLimiter.time(); + int count = rateLimiter.count(); + String combineKey = getCombineKey(rateLimiter, point); + try { + RateType rateType = RateType.OVERALL; + if (rateLimiter.limitType() == LimitType.CLUSTER) { + rateType = RateType.PER_CLIENT; + } + long number = RedisUtils.rateLimiter(combineKey, rateType, count, time); + if (number == -1) { + String message = rateLimiter.message(); + if (StringUtils.startsWith(message, "{") && StringUtils.endsWith(message, "}")) { + message = MessageUtils.message(StringUtils.substring(message, 1, message.length() - 1)); + } + throw new ServiceException(message); + } + log.info("限制令牌 => {}, 剩余令牌 => {}, 缓存key => '{}'", count, number, combineKey); + } catch (Exception e) { + if (e instanceof ServiceException) { + throw e; + } else { + throw new RuntimeException("服务器限流异常,请稍候再试"); + } + } + } + + public String getCombineKey(RateLimiter rateLimiter, JoinPoint point) { + String key = rateLimiter.key(); + // 获取方法(通过方法签名来获取) + MethodSignature signature = (MethodSignature) point.getSignature(); + Method method = signature.getMethod(); + Class targetClass = method.getDeclaringClass(); + // 判断是否是spel格式 + if (StringUtils.containsAny(key, "#")) { + // 获取参数值 + Object[] args = point.getArgs(); + // 获取方法上参数的名称 + String[] parameterNames = pnd.getParameterNames(method); + if (ArrayUtil.isEmpty(parameterNames)) { + throw new ServiceException("限流key解析异常!请联系管理员!"); + } + for (int i = 0; i < parameterNames.length; i++) { + context.setVariable(parameterNames[i], args[i]); + } + // 解析返回给key + try { + Expression expression; + if (StringUtils.startsWith(key, parserContext.getExpressionPrefix()) + && StringUtils.endsWith(key, parserContext.getExpressionSuffix())) { + expression = parser.parseExpression(key, parserContext); + } else { + expression = parser.parseExpression(key); + } + key = expression.getValue(context, String.class) + ":"; + } catch (Exception e) { + throw new ServiceException("限流key解析异常!请联系管理员!"); + } + } + StringBuilder stringBuffer = new StringBuilder(CacheConstants.RATE_LIMIT_KEY); + stringBuffer.append(ServletUtils.getRequest().getRequestURI()).append(":"); + if (rateLimiter.limitType() == LimitType.IP) { + // 获取请求ip + stringBuffer.append(ServletUtils.getClientIP()).append(":"); + } else if (rateLimiter.limitType() == LimitType.CLUSTER) { + // 获取客户端实例id + stringBuffer.append(RedisUtils.getClient().getId()).append(":"); + } + return stringBuffer.append(key).toString(); + } +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/aspectj/RepeatSubmitAspect.java b/cas-framework/src/main/java/com/inscloudtech/framework/aspectj/RepeatSubmitAspect.java new file mode 100644 index 0000000..7bcf854 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/aspectj/RepeatSubmitAspect.java @@ -0,0 +1,155 @@ +package com.inscloudtech.framework.aspectj; + +import cn.dev33.satoken.SaManager; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.crypto.SecureUtil; +import com.inscloudtech.common.annotation.RepeatSubmit; +import com.inscloudtech.common.constant.CacheConstants; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.exception.ServiceException; +import com.inscloudtech.common.utils.JsonUtils; +import com.inscloudtech.common.utils.MessageUtils; +import com.inscloudtech.common.utils.ServletUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.redis.RedisUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.stereotype.Component; +import org.springframework.validation.BindingResult; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.time.Duration; +import java.util.Collection; +import java.util.Map; + +/** + * 防止重复提交(参考美团GTIS防重系统) + * + * @author inscloudtech + */ +@Slf4j +@RequiredArgsConstructor +@Aspect +@Component +public class RepeatSubmitAspect { + + private static final ThreadLocal KEY_CACHE = new ThreadLocal<>(); + + @Before("@annotation(repeatSubmit)") + public void doBefore(JoinPoint point, RepeatSubmit repeatSubmit) throws Throwable { + // 如果注解不为0 则使用注解数值 + long interval = 0; + if (repeatSubmit.interval() > 0) { + interval = repeatSubmit.timeUnit().toMillis(repeatSubmit.interval()); + } + if (interval < 1000) { + throw new ServiceException("重复提交间隔时间不能小于'1'秒"); + } + HttpServletRequest request = ServletUtils.getRequest(); + String nowParams = argsArrayToString(point.getArgs()); + + // 请求地址(作为存放cache的key值) + String url = request.getRequestURI(); + + // 唯一值(没有消息头则使用请求地址) + String submitKey = StringUtils.trimToEmpty(request.getHeader(SaManager.getConfig().getTokenName())); + + submitKey = SecureUtil.md5(submitKey + ":" + nowParams); + // 唯一标识(指定key + url + 消息头) + String cacheRepeatKey = CacheConstants.REPEAT_SUBMIT_KEY + url + submitKey; + String key = RedisUtils.getCacheObject(cacheRepeatKey); + if (key == null) { + RedisUtils.setCacheObject(cacheRepeatKey, "", Duration.ofMillis(interval)); + KEY_CACHE.set(cacheRepeatKey); + } else { + String message = repeatSubmit.message(); + if (StringUtils.startsWith(message, "{") && StringUtils.endsWith(message, "}")) { + message = MessageUtils.message(StringUtils.substring(message, 1, message.length() - 1)); + } + throw new ServiceException(message); + } + } + /** + * 处理完请求后执行 + * + * @param joinPoint 切点 + */ + @AfterReturning(pointcut = "@annotation(repeatSubmit)", returning = "jsonResult") + public void doAfterReturning(JoinPoint joinPoint, RepeatSubmit repeatSubmit, Object jsonResult) { + if (jsonResult instanceof R) { + try { + R r = (R) jsonResult; + // 成功则不删除redis数据 保证在有效时间内无法重复提交 + if (r.getCode() == R.SUCCESS) { + return; + } + RedisUtils.deleteObject(KEY_CACHE.get()); + } finally { + KEY_CACHE.remove(); + } + } + } + /** + * 拦截异常操作 + * + * @param joinPoint 切点 + * @param e 异常 + */ + @AfterThrowing(value = "@annotation(repeatSubmit)", throwing = "e") + public void doAfterThrowing(JoinPoint joinPoint, RepeatSubmit repeatSubmit, Exception e) { + RedisUtils.deleteObject(KEY_CACHE.get()); + KEY_CACHE.remove(); + } + /** + * 参数拼装 + */ + private String argsArrayToString(Object[] paramsArray) { + StringBuilder params = new StringBuilder(); + if (paramsArray != null && paramsArray.length > 0) { + for (Object o : paramsArray) { + if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) { + try { + params.append(JsonUtils.toJsonString(o)).append(" "); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + return params.toString().trim(); + } + /** + * 判断是否需要过滤的对象。 + * + * @param o 对象信息。 + * @return 如果是需要过滤的对象,则返回true;否则返回false。 + */ + @SuppressWarnings("rawtypes") + public boolean isFilterObject(final Object o) { + Class clazz = o.getClass(); + if (clazz.isArray()) { + return clazz.getComponentType().isAssignableFrom(MultipartFile.class); + } else if (Collection.class.isAssignableFrom(clazz)) { + Collection collection = (Collection) o; + for (Object value : collection) { + return value instanceof MultipartFile; + } + } else if (Map.class.isAssignableFrom(clazz)) { + Map map = (Map) o; + for (Object value : map.entrySet()) { + Map.Entry entry = (Map.Entry) value; + return entry.getValue() instanceof MultipartFile; + } + } + return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse + || o instanceof BindingResult; + } + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/aspectj/UpdateRecordAspect.java b/cas-framework/src/main/java/com/inscloudtech/framework/aspectj/UpdateRecordAspect.java new file mode 100644 index 0000000..a4ed477 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/aspectj/UpdateRecordAspect.java @@ -0,0 +1,255 @@ +package com.inscloudtech.framework.aspectj; + +import cn.hutool.core.lang.Dict; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.inscloudtech.common.annotation.UpdateLog; +import com.inscloudtech.common.core.domain.event.OperLogEvent; +import com.inscloudtech.common.enums.BusinessStatus; +import com.inscloudtech.common.enums.HttpMethod; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.common.utils.BeanCopyUtils; +import com.inscloudtech.common.utils.JsonUtils; +import com.inscloudtech.common.utils.ServletUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.spring.SpringUtils; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.stereotype.Component; +import org.springframework.validation.BindingResult; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 操作日志记录处理 + * + * @author inscloudtech + */ +@Slf4j +@Aspect +@Component +public class UpdateRecordAspect { + + + @Around("@annotation(controllerLog)") + public Object doAround(ProceedingJoinPoint joinPoint, UpdateLog controllerLog) throws Throwable { + Class clazz = controllerLog.mapperClass(); + if(ObjectUtil.isEmpty(clazz) || StringUtils.equals("Object",clazz.getSimpleName())){ + return null; + } + + //service,mapper对应的实体类 + Class entityClass = null; + boolean isMapperClass = BaseMapper.class.isAssignableFrom(clazz); + //不是service类 + if(isMapperClass){ + //获取Mapper对应的entity + Type superClass = clazz.getGenericInterfaces()[0]; + if (superClass instanceof ParameterizedType) { + // 获取类型参数数组,即 [<当前接口的 Class 对象>, , ] + Type[] typeArr = ((ParameterizedType) superClass).getActualTypeArguments(); + // 第二个类型参数就是 SysUser 的 Class 对象 + entityClass = (Class) typeArr[1]; + } + }else{ + entityClass = controllerLog.entityClass(); + } + + //获取tableId字段 + String tableIdField = ""; + Field[] fields = entityClass.getDeclaredFields(); + for(Field field : fields) { + field.setAccessible(true); + if (field.isAnnotationPresent(TableId.class)) { + tableIdField = field.getName(); + break; + } + } + + //获取方法参数 + Object[] args = joinPoint.getArgs(); + Object arg = args[0]; + + //获取tableId值 + String afterJsonStr = JsonUtils.toJsonString(arg); + Dict afterJson = JsonUtils.parseMap(afterJsonStr); + Long businessId = afterJson.getLong(tableIdField); + + //根据mapper查询一条修改前的数据 + Object serviceObj = SpringUtils.getBean(clazz); +// Method method = clazz.getMethod(methodName, Serializable.class);//Long.class + String methodName = controllerLog.methodName(); + List methodList = Arrays.stream(clazz.getMethods()).filter(method -> method.getName().equals(methodName)).collect(Collectors.toList()); + Method method = methodList.get(0);// + Object[] argsz = new Object[]{businessId}; + Object beforeEntity = method.invoke(serviceObj, argsz); + Object result; + try { + //执行方法 + result = joinPoint.proceed(args); + } catch (Exception e) { + throw e; + } + //比较两个对象字段变化 + Object afterEntity = JsonUtils.parseObject(afterJsonStr,entityClass); + Map changeMap = BeanCopyUtils.getChangedFields(beforeEntity,afterEntity); + String before = null == changeMap.get("before")?null:changeMap.get("before"); + String after = null == changeMap.get("after")?null:changeMap.get("after"); + OperLogEvent operLog = new OperLogEvent(); + //保存更新前后信息 + operLog.setBeforeValue(before); + operLog.setAfterValue(after); + operLog.setBusinessId(businessId); + handleLog(joinPoint, controllerLog, null, result,operLog); + return result; + } + /** + * 排除敏感属性字段 + */ + public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" }; + + protected void handleLog(final JoinPoint joinPoint, UpdateLog controllerLog, final Exception e, Object jsonResult,OperLogEvent operLog) { + try { + + // *========数据库日志=========*// + + operLog.setStatus(BusinessStatus.SUCCESS.ordinal()); + // 请求的地址 + String ip = ServletUtils.getClientIP(); + operLog.setOperIp(ip); + operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255)); + operLog.setOperName(LoginHelper.getUsername()); + + if (e != null) { + operLog.setStatus(BusinessStatus.FAIL.ordinal()); + operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000)); + } + // 设置方法名称 + String className = joinPoint.getTarget().getClass().getName(); + String methodName = joinPoint.getSignature().getName(); + operLog.setMethod(className + "." + methodName + "()"); + // 设置请求方式 + operLog.setRequestMethod(ServletUtils.getRequest().getMethod()); + // 处理设置注解上的参数 + getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult); + // 发布事件保存数据库 + SpringUtils.context().publishEvent(operLog); + } catch (Exception exp) { + // 记录本地异常日志 + log.error("异常信息:{}", exp.getMessage()); + exp.printStackTrace(); + } + } + /** + * 获取注解中对方法的描述信息 用于Controller层注解 + * + * @param log 日志 + * @param operLog 操作日志 + * @throws Exception + */ + public void getControllerMethodDescription(JoinPoint joinPoint, UpdateLog log, OperLogEvent operLog, Object jsonResult) throws Exception { + // 设置action动作 + operLog.setBusinessType(log.businessType().ordinal()); + // 设置标题 + operLog.setTitle(log.title()); + // 设置操作人类别 + operLog.setOperatorType(log.operatorType().ordinal()); + // 是否需要保存request,参数和值 + if (log.isSaveRequestData()) { + // 获取参数的信息,传入到数据库中。 + setRequestValue(joinPoint, operLog, log.excludeParamNames()); + } + // 是否需要保存response,参数和值 + if (log.isSaveResponseData() && ObjectUtil.isNotNull(jsonResult)) { + operLog.setJsonResult(StringUtils.substring(JsonUtils.toJsonString(jsonResult), 0, 2000)); + } + } + /** + * 获取请求的参数,放到log中 + * + * @param operLog 操作日志 + * @throws Exception 异常 + */ + private void setRequestValue(JoinPoint joinPoint, OperLogEvent operLog, String[] excludeParamNames) throws Exception { + Map paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest()); + String requestMethod = operLog.getRequestMethod(); + if (MapUtil.isEmpty(paramsMap) + && HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) { + String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames); + operLog.setOperParam(StringUtils.substring(params, 0, 2000)); + } else { + MapUtil.removeAny(paramsMap, EXCLUDE_PROPERTIES); + MapUtil.removeAny(paramsMap, excludeParamNames); + operLog.setOperParam(StringUtils.substring(JsonUtils.toJsonString(paramsMap), 0, 2000)); + } + } + /** + * 参数拼装 + */ + private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames) { + StringBuilder params = new StringBuilder(); + if (paramsArray != null && paramsArray.length > 0) { + for (Object o : paramsArray) { + if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) { + try { + String str = JsonUtils.toJsonString(o); + Dict dict = JsonUtils.parseMap(str); + if (MapUtil.isNotEmpty(dict)) { + MapUtil.removeAny(dict, EXCLUDE_PROPERTIES); + MapUtil.removeAny(dict, excludeParamNames); + str = JsonUtils.toJsonString(dict); + } + params.append(str).append(" "); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + return params.toString().trim(); + } + /** + * 判断是否需要过滤的对象。 + * + * @param o 对象信息。 + * @return 如果是需要过滤的对象,则返回true;否则返回false。 + */ + @SuppressWarnings("rawtypes") + public boolean isFilterObject(final Object o) { + Class clazz = o.getClass(); + if (clazz.isArray()) { + return clazz.getComponentType().isAssignableFrom(MultipartFile.class); + } else if (Collection.class.isAssignableFrom(clazz)) { + Collection collection = (Collection) o; + for (Object value : collection) { + return value instanceof MultipartFile; + } + } else if (Map.class.isAssignableFrom(clazz)) { + Map map = (Map) o; + for (Object value : map.entrySet()) { + Map.Entry entry = (Map.Entry) value; + return entry.getValue() instanceof MultipartFile; + } + } + return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse + || o instanceof BindingResult; + } + + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/ApplicationConfig.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/ApplicationConfig.java new file mode 100644 index 0000000..118d288 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/ApplicationConfig.java @@ -0,0 +1,16 @@ +package com.inscloudtech.framework.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.EnableAspectJAutoProxy; + +/** + * 程序注解配置 + * + * @author inscloudtech + */ +@Configuration +// 表示通过aop框架暴露该代理对象,AopContext能够访问 +@EnableAspectJAutoProxy(exposeProxy = true) +public class ApplicationConfig { + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/AsyncConfig.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/AsyncConfig.java new file mode 100644 index 0000000..c549ee5 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/AsyncConfig.java @@ -0,0 +1,52 @@ +package com.inscloudtech.framework.config; + +import cn.hutool.core.util.ArrayUtil; +import com.inscloudtech.common.exception.ServiceException; +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.AsyncConfigurerSupport; +import org.springframework.scheduling.annotation.EnableAsync; + +import java.util.Arrays; +import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; + +/** + * 异步配置 + * + * @author inscloudtech + */ +@EnableAsync(proxyTargetClass = true) +@Configuration +public class AsyncConfig extends AsyncConfigurerSupport { + + @Autowired + @Qualifier("scheduledExecutorService") + private ScheduledExecutorService scheduledExecutorService; + /** + * 自定义 @Async 注解使用系统线程池 + */ + @Override + public Executor getAsyncExecutor() { + return scheduledExecutorService; + } + /** + * 异步执行异常处理 + */ + @Override + public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { + return (throwable, method, objects) -> { + throwable.printStackTrace(); + StringBuilder sb = new StringBuilder(); + sb.append("Exception message - ").append(throwable.getMessage()) + .append(", Method name - ").append(method.getName()); + if (ArrayUtil.isNotEmpty(objects)) { + sb.append(", Parameter value - ").append(Arrays.toString(objects)); + } + throw new ServiceException(sb.toString()); + }; + } + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/CaptchaConfig.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/CaptchaConfig.java new file mode 100644 index 0000000..0d863aa --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/CaptchaConfig.java @@ -0,0 +1,59 @@ +package com.inscloudtech.framework.config; + +import cn.hutool.captcha.CaptchaUtil; +import cn.hutool.captcha.CircleCaptcha; +import cn.hutool.captcha.LineCaptcha; +import cn.hutool.captcha.ShearCaptcha; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; + +import java.awt.*; + +/** + * 验证码配置 + * + * @author inscloudtech + */ +@Configuration +public class CaptchaConfig { + + private static final int WIDTH = 160; + private static final int HEIGHT = 60; + private static final Color BACKGROUND = Color.PINK; + private static final Font FONT = new Font("Arial", Font.BOLD, 48); + /** + * 圆圈干扰验证码 + */ + @Lazy + @Bean + public CircleCaptcha circleCaptcha() { + CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(WIDTH, HEIGHT); + captcha.setBackground(BACKGROUND); + captcha.setFont(FONT); + return captcha; + } + /** + * 线段干扰的验证码 + */ + @Lazy + @Bean + public LineCaptcha lineCaptcha() { + LineCaptcha captcha = CaptchaUtil.createLineCaptcha(WIDTH, HEIGHT); + captcha.setBackground(BACKGROUND); + captcha.setFont(FONT); + return captcha; + } + /** + * 扭曲干扰验证码 + */ + @Lazy + @Bean + public ShearCaptcha shearCaptcha() { + ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(WIDTH, HEIGHT); + captcha.setBackground(BACKGROUND); + captcha.setFont(FONT); + return captcha; + } + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/EncryptorConfig.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/EncryptorConfig.java new file mode 100644 index 0000000..016f81e --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/EncryptorConfig.java @@ -0,0 +1,39 @@ +package com.inscloudtech.framework.config; + +import com.inscloudtech.framework.config.properties.EncryptorProperties; +import com.inscloudtech.framework.manager.EncryptorManager; +import com.inscloudtech.framework.encrypt.MybatisDecryptInterceptor; +import com.inscloudtech.framework.encrypt.MybatisEncryptInterceptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 加解密配置 + * + * @author inscloudtech + * @version 4.6.0 + */ +@Configuration +@ConditionalOnProperty(value = "mybatis-encryptor.enable", havingValue = "true") +public class EncryptorConfig { + + @Autowired + private EncryptorProperties properties; + + @Bean + public EncryptorManager encryptorManager() { + return new EncryptorManager(); + } + + @Bean + public MybatisEncryptInterceptor mybatisEncryptInterceptor(EncryptorManager encryptorManager) { + return new MybatisEncryptInterceptor(encryptorManager, properties); + } + + @Bean + public MybatisDecryptInterceptor mybatisDecryptInterceptor(EncryptorManager encryptorManager) { + return new MybatisDecryptInterceptor(encryptorManager, properties); + } +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/FilterConfig.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/FilterConfig.java new file mode 100644 index 0000000..92dfdb4 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/FilterConfig.java @@ -0,0 +1,55 @@ +package com.inscloudtech.framework.config; + +import com.inscloudtech.common.filter.RepeatableFilter; +import com.inscloudtech.common.filter.XssFilter; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.framework.config.properties.XssProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.servlet.DispatcherType; +import java.util.HashMap; +import java.util.Map; + +/** + * Filter配置 + * + * @author inscloudtech + */ +@Configuration +public class FilterConfig { + + @Autowired + private XssProperties xssProperties; + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Bean + @ConditionalOnProperty(value = "xss.enabled", havingValue = "true") + public FilterRegistrationBean xssFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setDispatcherTypes(DispatcherType.REQUEST); + registration.setFilter(new XssFilter()); + registration.addUrlPatterns(StringUtils.split(xssProperties.getUrlPatterns(), StringUtils.SEPARATOR)); + registration.setName("xssFilter"); + registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE); + Map initParameters = new HashMap(); + initParameters.put("excludes", xssProperties.getExcludes()); + registration.setInitParameters(initParameters); + return registration; + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Bean + public FilterRegistrationBean someFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(new RepeatableFilter()); + registration.addUrlPatterns("/*"); + registration.setName("repeatableFilter"); + registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE); + return registration; + } + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/I18nConfig.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/I18nConfig.java new file mode 100644 index 0000000..dcd49ea --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/I18nConfig.java @@ -0,0 +1,45 @@ +package com.inscloudtech.framework.config; + +import cn.hutool.core.util.StrUtil; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.LocaleResolver; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Locale; + +/** + * 国际化配置 + * + * @author inscloudtech + */ +@Configuration +public class I18nConfig { + + @Bean + public LocaleResolver localeResolver() { + return new I18nLocaleResolver(); + } + /** + * 获取请求头国际化信息 + */ + static class I18nLocaleResolver implements LocaleResolver { + + @Override + public Locale resolveLocale(HttpServletRequest httpServletRequest) { + String language = httpServletRequest.getHeader("content-language"); + Locale locale = Locale.getDefault(); + if (StrUtil.isNotBlank(language)) { + String[] split = language.split("_"); + locale = new Locale(split[0], split[1]); + } + return locale; + } + + @Override + public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) { + + } + } +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/JacksonConfig.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/JacksonConfig.java new file mode 100644 index 0000000..45540be --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/JacksonConfig.java @@ -0,0 +1,46 @@ +package com.inscloudtech.framework.config; + +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import com.inscloudtech.framework.jackson.BigNumberSerializer; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.TimeZone; + +/** + * jackson 配置 + * + * @author inscloudtech + */ +@Slf4j +@Configuration +public class JacksonConfig { + + @Bean + public Jackson2ObjectMapperBuilderCustomizer customizer() { + return builder -> { + // 全局配置序列化返回 JSON 处理 + JavaTimeModule javaTimeModule = new JavaTimeModule(); + javaTimeModule.addSerializer(Long.class, BigNumberSerializer.INSTANCE); + javaTimeModule.addSerializer(Long.TYPE, BigNumberSerializer.INSTANCE); + javaTimeModule.addSerializer(BigInteger.class, BigNumberSerializer.INSTANCE); + javaTimeModule.addSerializer(BigDecimal.class, ToStringSerializer.instance); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(formatter)); + javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter)); + builder.modules(javaTimeModule); + builder.timeZone(TimeZone.getDefault()); + log.info("初始化 jackson 配置"); + }; + } + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/MailConfig.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/MailConfig.java new file mode 100644 index 0000000..751b258 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/MailConfig.java @@ -0,0 +1,35 @@ +package com.inscloudtech.framework.config; + +import cn.hutool.extra.mail.MailAccount; +import com.inscloudtech.framework.config.properties.MailProperties; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * JavaMail 配置 + * + * @author Michelle.Chung + */ +@Configuration +public class MailConfig { + + @Bean + @ConditionalOnProperty(value = "mail.enabled", havingValue = "true") + public MailAccount mailAccount(MailProperties mailProperties) { + MailAccount account = new MailAccount(); + account.setHost(mailProperties.getHost()); + account.setPort(mailProperties.getPort()); + account.setAuth(mailProperties.getAuth()); + account.setFrom(mailProperties.getFrom()); + account.setUser(mailProperties.getUser()); + account.setPass(mailProperties.getPass()); + account.setSocketFactoryPort(mailProperties.getPort()); + account.setStarttlsEnable(mailProperties.getStarttlsEnable()); + account.setSslEnable(mailProperties.getSslEnable()); + account.setTimeout(mailProperties.getTimeout()); + account.setConnectionTimeout(mailProperties.getConnectionTimeout()); + return account; + } + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/MybatisPlusConfig.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/MybatisPlusConfig.java new file mode 100644 index 0000000..5af4b0b --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/MybatisPlusConfig.java @@ -0,0 +1,96 @@ +package com.inscloudtech.framework.config; + +import cn.hutool.core.net.NetUtil; +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator; +import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import com.inscloudtech.framework.handler.CreateAndUpdateMetaObjectHandler; +import com.inscloudtech.framework.interceptor.PlusDataPermissionInterceptor; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * mybatis-plus配置类(下方注释有插件介绍) + * + * @author inscloudtech + */ +@EnableTransactionManagement(proxyTargetClass = true) +@Configuration +@MapperScan("${mybatis-plus.mapperPackage}") +public class MybatisPlusConfig { + + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + // 数据权限处理 + interceptor.addInnerInterceptor(dataPermissionInterceptor()); + // 分页插件 + interceptor.addInnerInterceptor(paginationInnerInterceptor()); + // 乐观锁插件 + interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor()); + return interceptor; + } + /** + * 数据权限拦截器 + */ + public PlusDataPermissionInterceptor dataPermissionInterceptor() { + return new PlusDataPermissionInterceptor(); + } + /** + * 分页插件,自动识别数据库类型 + */ + public PaginationInnerInterceptor paginationInnerInterceptor() { + PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(); + // 设置最大单页限制数量,默认 500 条,-1 不受限制 + paginationInnerInterceptor.setMaxLimit(-1L); + // 分页合理化 + paginationInnerInterceptor.setOverflow(true); + return paginationInnerInterceptor; + } + /** + * 乐观锁插件 + */ + public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() { + return new OptimisticLockerInnerInterceptor(); + } + /** + * 元对象字段填充控制器 + */ + @Bean + public MetaObjectHandler metaObjectHandler() { + return new CreateAndUpdateMetaObjectHandler(); + } + /** + * 使用网卡信息绑定雪花生成器 + * 防止集群雪花ID重复 + */ + @Bean + public IdentifierGenerator idGenerator() { + return new DefaultIdentifierGenerator(NetUtil.getLocalhost()); + } + /** + * PaginationInnerInterceptor 分页插件,自动识别数据库类型 + * https://baomidou.com/pages/97710a/ + * OptimisticLockerInnerInterceptor 乐观锁插件 + * https://baomidou.com/pages/0d93c0/ + * MetaObjectHandler 元对象字段填充控制器 + * https://baomidou.com/pages/4c6bcf/ + * ISqlInjector sql注入器 + * https://baomidou.com/pages/42ea4a/ + * BlockAttackInnerInterceptor 如果是对全表的删除或更新操作,就会终止该操作 + * https://baomidou.com/pages/f9a237/ + * IllegalSQLInnerInterceptor sql性能规范插件(垃圾SQL拦截) + * IdentifierGenerator 自定义主键策略 + * https://baomidou.com/pages/568eb2/ + * TenantLineInnerInterceptor 多租户插件 + * https://baomidou.com/pages/aef2f2/ + * DynamicTableNameInnerInterceptor 动态表名插件 + * https://baomidou.com/pages/2a45ff/ + */ + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/RedisConfig.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/RedisConfig.java new file mode 100644 index 0000000..25db7f3 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/RedisConfig.java @@ -0,0 +1,128 @@ +package com.inscloudtech.framework.config; + +import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.inscloudtech.framework.config.properties.RedissonProperties; +import com.inscloudtech.framework.handler.KeyPrefixHandler; +import com.inscloudtech.framework.manager.PlusSpringCacheManager; +import lombok.extern.slf4j.Slf4j; +import org.redisson.codec.JsonJacksonCodec; +import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * redis配置 + * + * @author inscloudtech + */ +@Slf4j +@Configuration +@EnableCaching +@EnableConfigurationProperties(RedissonProperties.class) +public class RedisConfig { + + @Autowired + private RedissonProperties redissonProperties; + + @Autowired + private ObjectMapper objectMapper; + + @Bean + public RedissonAutoConfigurationCustomizer redissonCustomizer() { + return config -> { + config.setThreads(redissonProperties.getThreads()) + .setNettyThreads(redissonProperties.getNettyThreads()) + .setCodec(new JsonJacksonCodec(objectMapper)); + RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig(); + if (ObjectUtil.isNotNull(singleServerConfig)) { + // 使用单机模式 + config.useSingleServer() + //设置redis key前缀 + .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix())) + .setTimeout(singleServerConfig.getTimeout()) + .setClientName(singleServerConfig.getClientName()) + .setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout()) + .setSubscriptionConnectionPoolSize(singleServerConfig.getSubscriptionConnectionPoolSize()) + .setConnectionMinimumIdleSize(singleServerConfig.getConnectionMinimumIdleSize()) + .setConnectionPoolSize(singleServerConfig.getConnectionPoolSize()); + } + // 集群配置方式 参考下方注释 + RedissonProperties.ClusterServersConfig clusterServersConfig = redissonProperties.getClusterServersConfig(); + if (ObjectUtil.isNotNull(clusterServersConfig)) { + config.useClusterServers() + //设置redis key前缀 + .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix())) + .setTimeout(clusterServersConfig.getTimeout()) + .setClientName(clusterServersConfig.getClientName()) + .setIdleConnectionTimeout(clusterServersConfig.getIdleConnectionTimeout()) + .setSubscriptionConnectionPoolSize(clusterServersConfig.getSubscriptionConnectionPoolSize()) + .setMasterConnectionMinimumIdleSize(clusterServersConfig.getMasterConnectionMinimumIdleSize()) + .setMasterConnectionPoolSize(clusterServersConfig.getMasterConnectionPoolSize()) + .setSlaveConnectionMinimumIdleSize(clusterServersConfig.getSlaveConnectionMinimumIdleSize()) + .setSlaveConnectionPoolSize(clusterServersConfig.getSlaveConnectionPoolSize()) + .setReadMode(clusterServersConfig.getReadMode()) + .setSubscriptionMode(clusterServersConfig.getSubscriptionMode()); + } + log.info("初始化 redis 配置"); + }; + } + /** + * 自定义缓存管理器 整合spring-cache + */ + @Bean + public CacheManager cacheManager() { + return new PlusSpringCacheManager(); + } + /** + * redis集群配置 yml + * + * --- # redis 集群配置(单机与集群只能开启一个另一个需要注释掉) + * spring: + * redis: + * cluster: + * nodes: + * - 192.168.0.100:6379 + * - 192.168.0.101:6379 + * - 192.168.0.102:6379 + * # 密码 + * password: + * # 连接超时时间 + * timeout: 10s + * # 是否开启ssl + * ssl: false + * + * redisson: + * # 线程池数量 + * threads: 16 + * # Netty线程池数量 + * nettyThreads: 32 + * # 集群配置 + * clusterServersConfig: + * # 客户端名称 + * clientName: ${cas.name} + * # master最小空闲连接数 + * masterConnectionMinimumIdleSize: 32 + * # master连接池大小 + * masterConnectionPoolSize: 64 + * # slave最小空闲连接数 + * slaveConnectionMinimumIdleSize: 32 + * # slave连接池大小 + * slaveConnectionPoolSize: 64 + * # 连接空闲超时,单位:毫秒 + * idleConnectionTimeout: 10000 + * # 命令等待超时,单位:毫秒 + * timeout: 3000 + * # 发布和订阅连接池大小 + * subscriptionConnectionPoolSize: 50 + * # 读取模式 + * readMode: "SLAVE" + * # 订阅模式 + * subscriptionMode: "MASTER" + */ + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/ResourcesConfig.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/ResourcesConfig.java new file mode 100644 index 0000000..366abb2 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/ResourcesConfig.java @@ -0,0 +1,51 @@ +package com.inscloudtech.framework.config; + +import com.inscloudtech.framework.interceptor.PlusWebInvokeTimeInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * 通用配置 + * + * @author inscloudtech + */ +@Configuration +public class ResourcesConfig implements WebMvcConfigurer { + + @Override + public void addInterceptors(InterceptorRegistry registry) { + // 全局访问性能拦截 + registry.addInterceptor(new PlusWebInvokeTimeInterceptor()); + } + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + } + /** + * 跨域配置 + */ + @Bean + public CorsFilter corsFilter() { + CorsConfiguration config = new CorsConfiguration(); + config.setAllowCredentials(true); + // 设置访问源地址 + config.addAllowedOriginPattern("*"); + // 设置访问源请求头 + config.addAllowedHeader("*"); + // 设置访问源请求方法 + config.addAllowedMethod("*"); + // 有效期 1800秒 + config.setMaxAge(1800L); + // 添加映射路径,拦截一切请求 + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", config); + // 返回新的CorsFilter + return new CorsFilter(source); + } +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/SaTokenConfig.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/SaTokenConfig.java new file mode 100644 index 0000000..1848650 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/SaTokenConfig.java @@ -0,0 +1,82 @@ +package com.inscloudtech.framework.config; + +import cn.dev33.satoken.dao.SaTokenDao; +import cn.dev33.satoken.interceptor.SaInterceptor; +import cn.dev33.satoken.jwt.StpLogicJwtForSimple; +import cn.dev33.satoken.router.SaRouter; +import cn.dev33.satoken.stp.StpInterface; +import cn.dev33.satoken.stp.StpLogic; +import cn.dev33.satoken.stp.StpUtil; +import com.inscloudtech.common.utils.spring.SpringUtils; +import com.inscloudtech.framework.config.properties.SecurityProperties; +import com.inscloudtech.framework.handler.AllUrlHandler; +import com.inscloudtech.framework.satoken.dao.PlusSaTokenDao; +import com.inscloudtech.framework.satoken.service.SaPermissionImpl; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * sa-token 配置 + * + * @author inscloudtech + */ +@RequiredArgsConstructor +@Slf4j +@Configuration +public class SaTokenConfig implements WebMvcConfigurer { + + private final SecurityProperties securityProperties; + /** + * 注册sa-token的拦截器 + */ + @Override + public void addInterceptors(InterceptorRegistry registry) { + // 注册路由拦截器,自定义验证规则 + registry.addInterceptor(new SaInterceptor(handler -> { + AllUrlHandler allUrlHandler = SpringUtils.getBean(AllUrlHandler.class); + // 登录验证 -- 排除多个路径 + SaRouter + // 获取所有的 + .match(allUrlHandler.getUrls()) + // 对未排除的路径进行检查 + .check(() -> { + // 检查是否登录 是否有token + StpUtil.checkLogin(); + + // 有效率影响 用于临时测试 + // if (log.isDebugEnabled()) { + // log.debug("剩余有效时间: {}", StpUtil.getTokenTimeout()); + // log.debug("临时有效时间: {}", StpUtil.getTokenActivityTimeout()); + // } + + }); + })).addPathPatterns("/**") + // 排除不需要拦截的路径 + .excludePathPatterns(securityProperties.getExcludes()); + } + + @Bean + public StpLogic getStpLogicJwt() { + // Sa-Token 整合 jwt (简单模式) + return new StpLogicJwtForSimple(); + } + /** + * 权限接口实现(使用bean注入方便用户替换) + */ + @Bean + public StpInterface stpInterface() { + return new SaPermissionImpl(); + } + /** + * 自定义dao层存储 + */ + @Bean + public SaTokenDao saTokenDao() { + return new PlusSaTokenDao(); + } + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/SwaggerConfig.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/SwaggerConfig.java new file mode 100644 index 0000000..cce6453 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/SwaggerConfig.java @@ -0,0 +1,120 @@ +package com.inscloudtech.framework.config; + +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.framework.config.properties.SwaggerProperties; +import com.inscloudtech.framework.handler.OpenApiHandler; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import lombok.RequiredArgsConstructor; +import org.springdoc.core.*; +import org.springdoc.core.customizers.OpenApiBuilderCustomizer; +import org.springdoc.core.customizers.OpenApiCustomiser; +import org.springdoc.core.customizers.ServerBaseUrlCustomizer; +import org.springdoc.core.providers.JavadocProvider; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.web.ServerProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/** + * Swagger 文档配置 + * + * @author inscloudtech + */ +@RequiredArgsConstructor +@Configuration +@AutoConfigureBefore(SpringDocConfiguration.class) +@ConditionalOnProperty(name = "springdoc.api-docs.enabled", havingValue = "true", matchIfMissing = true) +public class SwaggerConfig { + + private final SwaggerProperties swaggerProperties; + private final ServerProperties serverProperties; + + @Bean + @ConditionalOnMissingBean(OpenAPI.class) + public OpenAPI openApi() { + OpenAPI openApi = new OpenAPI(); + // 文档基本信息 + SwaggerProperties.InfoProperties infoProperties = swaggerProperties.getInfo(); + Info info = convertInfo(infoProperties); + openApi.info(info); + // 扩展文档信息 + openApi.externalDocs(swaggerProperties.getExternalDocs()); + openApi.tags(swaggerProperties.getTags()); + openApi.paths(swaggerProperties.getPaths()); + openApi.components(swaggerProperties.getComponents()); + Set keySet = swaggerProperties.getComponents().getSecuritySchemes().keySet(); + List list = new ArrayList<>(); + SecurityRequirement securityRequirement = new SecurityRequirement(); + keySet.forEach(securityRequirement::addList); + list.add(securityRequirement); + openApi.security(list); + + return openApi; + } + + private Info convertInfo(SwaggerProperties.InfoProperties infoProperties) { + Info info = new Info(); + info.setTitle(infoProperties.getTitle()); + info.setDescription(infoProperties.getDescription()); + info.setContact(infoProperties.getContact()); + info.setLicense(infoProperties.getLicense()); + info.setVersion(infoProperties.getVersion()); + return info; + } + /** + * 自定义 openapi 处理器 + */ + @Bean + public OpenAPIService openApiBuilder(Optional openAPI, + SecurityService securityParser, + SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils, + Optional> openApiBuilderCustomisers, + Optional> serverBaseUrlCustomisers, Optional javadocProvider) { + return new OpenApiHandler(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers, serverBaseUrlCustomisers, javadocProvider); + } + /** + * 对已经生成好的 OpenApi 进行自定义操作 + */ + @Bean + public OpenApiCustomiser openApiCustomiser() { + String contextPath = serverProperties.getServlet().getContextPath(); + String finalContextPath; + if (StringUtils.isBlank(contextPath) || "/".equals(contextPath)) { + finalContextPath = ""; + } else { + finalContextPath = contextPath; + } + // 对所有路径增加前置上下文路径 + return openApi -> { + Paths oldPaths = openApi.getPaths(); + if (oldPaths instanceof PlusPaths) { + return; + } + PlusPaths newPaths = new PlusPaths(); + oldPaths.forEach((k,v) -> newPaths.addPathItem(finalContextPath + k, v)); + openApi.setPaths(newPaths); + }; + } + /** + * 单独使用一个类便于判断 解决springdoc路径拼接重复问题 + * + * @author inscloudtech + */ + static class PlusPaths extends Paths { + + public PlusPaths() { + super(); + } + } + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/ThreadPoolConfig.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/ThreadPoolConfig.java new file mode 100644 index 0000000..32ba6d4 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/ThreadPoolConfig.java @@ -0,0 +1,57 @@ +package com.inscloudtech.framework.config; + +import com.inscloudtech.common.utils.Threads; +import com.inscloudtech.framework.config.properties.ThreadPoolProperties; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * 线程池配置 + * + * @author inscloudtech + **/ +@Configuration +public class ThreadPoolConfig { + /** + * 核心线程数 = cpu 核心数 + 1 + */ + private final int core = Runtime.getRuntime().availableProcessors() + 1; + + @Autowired + private ThreadPoolProperties threadPoolProperties; + + @Bean(name = "threadPoolTaskExecutor") + @ConditionalOnProperty(prefix = "thread-pool", name = "enabled", havingValue = "true") + public ThreadPoolTaskExecutor threadPoolTaskExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(core); + executor.setMaxPoolSize(core * 2); + executor.setQueueCapacity(threadPoolProperties.getQueueCapacity()); + executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds()); + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + return executor; + } + /** + * 执行周期性或定时任务 + */ + @Bean(name = "scheduledExecutorService") + protected ScheduledExecutorService scheduledExecutorService() { + return new ScheduledThreadPoolExecutor(core, + new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(), + new ThreadPoolExecutor.CallerRunsPolicy()) { + @Override + protected void afterExecute(Runnable r, Throwable t) { + super.afterExecute(r, t); + Threads.printException(r, t); + } + }; + } +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/TranslationConfig.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/TranslationConfig.java new file mode 100644 index 0000000..dd1b508 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/TranslationConfig.java @@ -0,0 +1,50 @@ +package com.inscloudtech.framework.config; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.inscloudtech.common.annotation.TranslationType; +import com.inscloudtech.common.translation.TranslationInterface; +import com.inscloudtech.common.translation.handler.TranslationBeanSerializerModifier; +import com.inscloudtech.common.translation.handler.TranslationHandler; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; + +import javax.annotation.PostConstruct; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 翻译模块配置类 + * + * @author inscloudtech + */ +@Slf4j +@Configuration +public class TranslationConfig { + + @Autowired + private List> list; + + @Autowired + private ObjectMapper objectMapper; + + @PostConstruct + public void init() { + Map> map = new HashMap<>(list.size()); + for (TranslationInterface trans : list) { + if (trans.getClass().isAnnotationPresent(TranslationType.class)) { + TranslationType annotation = trans.getClass().getAnnotation(TranslationType.class); + map.put(annotation.type(), trans); + } else { + log.warn(trans.getClass().getName() + " 翻译实现类未标注 TranslationType 注解!"); + } + } + TranslationHandler.TRANSLATION_MAPPER.putAll(map); + // 设置 Bean 序列化修改器 + objectMapper.setSerializerFactory( + objectMapper.getSerializerFactory() + .withSerializerModifier(new TranslationBeanSerializerModifier())); + } + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/UndertowConfig.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/UndertowConfig.java new file mode 100644 index 0000000..7f0f828 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/UndertowConfig.java @@ -0,0 +1,29 @@ +package com.inscloudtech.framework.config; + +import io.undertow.server.DefaultByteBufferPool; +import io.undertow.websockets.jsr.WebSocketDeploymentInfo; +import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.context.annotation.Configuration; + +/** + * Undertow 自定义配置 + * + * @author inscloudtech + */ +@Configuration +public class UndertowConfig implements WebServerFactoryCustomizer { + /** + * 设置 Undertow 的 websocket 缓冲池 + */ + @Override + public void customize(UndertowServletWebServerFactory factory) { + // 默认不直接分配内存 如果项目中使用了 websocket 建议直接分配 + factory.addDeploymentInfoCustomizers(deploymentInfo -> { + WebSocketDeploymentInfo webSocketDeploymentInfo = new WebSocketDeploymentInfo(); + webSocketDeploymentInfo.setBuffers(new DefaultByteBufferPool(false, 512)); + deploymentInfo.addServletContextAttribute("io.undertow.websockets.jsr.WebSocketDeploymentInfo", webSocketDeploymentInfo); + }); + } + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/ValidatorConfig.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/ValidatorConfig.java new file mode 100644 index 0000000..a627c7f --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/ValidatorConfig.java @@ -0,0 +1,42 @@ +package com.inscloudtech.framework.config; + +import org.hibernate.validator.HibernateValidator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.MessageSource; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; + +import javax.validation.Validator; +import java.util.Properties; + +/** + * 校验框架配置类 + * + * @author inscloudtech + */ +@Configuration +public class ValidatorConfig { + + @Autowired + private MessageSource messageSource; + /** + * 配置校验框架 快速返回模式 + */ + @Bean + public Validator validator() { + LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean(); + // 国际化 + factoryBean.setValidationMessageSource(messageSource); + // 设置使用 HibernateValidator 校验器 + factoryBean.setProviderClass(HibernateValidator.class); + Properties properties = new Properties(); + // 设置 快速异常返回 + properties.setProperty("hibernate.validator.fail_fast", "true"); + factoryBean.setValidationProperties(properties); + // 加载配置 + factoryBean.afterPropertiesSet(); + return factoryBean.getValidator(); + } + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/CaptchaProperties.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/CaptchaProperties.java new file mode 100644 index 0000000..53b9e5d --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/CaptchaProperties.java @@ -0,0 +1,34 @@ +package com.inscloudtech.framework.config.properties; + +import com.inscloudtech.common.enums.CaptchaCategory; +import com.inscloudtech.common.enums.CaptchaType; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 验证码 配置属性 + * + * @author inscloudtech + */ +@Data +@Component +@ConfigurationProperties(prefix = "captcha") +public class CaptchaProperties { + /** + * 验证码类型 + */ + private CaptchaType type; + /** + * 验证码类别 + */ + private CaptchaCategory category; + /** + * 数字验证码位数 + */ + private Integer numberLength; + /** + * 字符验证码长度 + */ + private Integer charLength; +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/EncryptorProperties.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/EncryptorProperties.java new file mode 100644 index 0000000..6375a4e --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/EncryptorProperties.java @@ -0,0 +1,44 @@ +package com.inscloudtech.framework.config.properties; + +import com.inscloudtech.common.enums.AlgorithmType; +import com.inscloudtech.common.enums.EncodeType; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 加解密属性配置类 + * + * @author inscloudtech + * @version 4.6.0 + */ +@Data +@Component +@ConfigurationProperties(prefix = "mybatis-encryptor") +public class EncryptorProperties { + /** + * 过滤开关 + */ + private Boolean enable; + /** + * 默认算法 + */ + private AlgorithmType algorithm; + /** + * 安全秘钥 + */ + private String password; + /** + * 公钥 + */ + private String publicKey; + /** + * 私钥 + */ + private String privateKey; + /** + * 编码方式,base64/hex + */ + private EncodeType encode; + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/MailProperties.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/MailProperties.java new file mode 100644 index 0000000..546d157 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/MailProperties.java @@ -0,0 +1,60 @@ +package com.inscloudtech.framework.config.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * JavaMail 配置属性 + * + * @author Michelle.Chung + */ +@Data +@Component +@ConfigurationProperties(prefix = "mail") +public class MailProperties { + /** + * 过滤开关 + */ + private Boolean enabled; + /** + * SMTP服务器域名 + */ + private String host; + /** + * SMTP服务端口 + */ + private Integer port; + /** + * 是否需要用户名密码验证 + */ + private Boolean auth; + /** + * 用户名 + */ + private String user; + /** + * 密码 + */ + private String pass; + /** + * 发送方,遵循RFC-822标准 + */ + private String from; + /** + * 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。它将纯文本连接升级为加密连接(TLS或SSL), 而不是使用一个单独的加密通信端口。 + */ + private Boolean starttlsEnable; + /** + * 使用 SSL安全连接 + */ + private Boolean sslEnable; + /** + * SMTP超时时长,单位毫秒,缺省值不超时 + */ + private Long timeout; + /** + * Socket连接超时值,单位毫秒,缺省值不超时 + */ + private Long connectionTimeout; +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/RedissonProperties.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/RedissonProperties.java new file mode 100644 index 0000000..0d1f4b9 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/RedissonProperties.java @@ -0,0 +1,132 @@ +package com.inscloudtech.framework.config.properties; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.redisson.config.ReadMode; +import org.redisson.config.SubscriptionMode; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * Redisson 配置属性 + * + * @author inscloudtech + */ +@Data +@Component +@ConfigurationProperties(prefix = "redisson") +public class RedissonProperties { + /** + * redis缓存key前缀 + */ + private String keyPrefix; + /** + * 线程池数量,默认值 = 当前处理核数量 * 2 + */ + private int threads; + /** + * Netty线程池数量,默认值 = 当前处理核数量 * 2 + */ + private int nettyThreads; + /** + * 单机服务配置 + */ + private SingleServerConfig singleServerConfig; + /** + * 集群服务配置 + */ + private ClusterServersConfig clusterServersConfig; + + @Data + @NoArgsConstructor + public static class SingleServerConfig { + + /** + * 客户端名称 + */ + private String clientName; + + /** + * 最小空闲连接数 + */ + private int connectionMinimumIdleSize; + + /** + * 连接池大小 + */ + private int connectionPoolSize; + + /** + * 连接空闲超时,单位:毫秒 + */ + private int idleConnectionTimeout; + + /** + * 命令等待超时,单位:毫秒 + */ + private int timeout; + + /** + * 发布和订阅连接池大小 + */ + private int subscriptionConnectionPoolSize; + + } + + @Data + @NoArgsConstructor + public static class ClusterServersConfig { + + /** + * 客户端名称 + */ + private String clientName; + + /** + * master最小空闲连接数 + */ + private int masterConnectionMinimumIdleSize; + + /** + * master连接池大小 + */ + private int masterConnectionPoolSize; + + /** + * slave最小空闲连接数 + */ + private int slaveConnectionMinimumIdleSize; + + /** + * slave连接池大小 + */ + private int slaveConnectionPoolSize; + + /** + * 连接空闲超时,单位:毫秒 + */ + private int idleConnectionTimeout; + + /** + * 命令等待超时,单位:毫秒 + */ + private int timeout; + + /** + * 发布和订阅连接池大小 + */ + private int subscriptionConnectionPoolSize; + + /** + * 读取模式 + */ + private ReadMode readMode; + + /** + * 订阅模式 + */ + private SubscriptionMode subscriptionMode; + + } + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/SecurityProperties.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/SecurityProperties.java new file mode 100644 index 0000000..92213b3 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/SecurityProperties.java @@ -0,0 +1,22 @@ +package com.inscloudtech.framework.config.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * Security 配置属性 + * + * @author inscloudtech + */ +@Data +@Component +@ConfigurationProperties(prefix = "security") +public class SecurityProperties { + /** + * 排除路径 + */ + private String[] excludes; + + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/SwaggerProperties.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/SwaggerProperties.java new file mode 100644 index 0000000..b96c561 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/SwaggerProperties.java @@ -0,0 +1,90 @@ +package com.inscloudtech.framework.config.properties; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.ExternalDocumentation; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.License; +import io.swagger.v3.oas.models.tags.Tag; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.NestedConfigurationProperty; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * swagger 配置属性 + * + * @author inscloudtech + */ +@Data +@Component +@ConfigurationProperties(prefix = "swagger") +public class SwaggerProperties { + /** + * 文档基本信息 + */ + @NestedConfigurationProperty + private InfoProperties info = new InfoProperties(); + /** + * 扩展文档地址 + */ + @NestedConfigurationProperty + private ExternalDocumentation externalDocs; + /** + * 标签 + */ + private List tags = null; + /** + * 路径 + */ + @NestedConfigurationProperty + private Paths paths = null; + /** + * 组件 + */ + @NestedConfigurationProperty + private Components components = null; + /** + *

+ * 文档的基础属性信息 + *

+ * + * @see io.swagger.v3.oas.models.info.Info + * + * 为了 springboot 自动生产配置提示信息,所以这里复制一个类出来 + */ + @Data + public static class InfoProperties { + + /** + * 标题 + */ + private String title = null; + + /** + * 描述 + */ + private String description = null; + + /** + * 联系人信息 + */ + @NestedConfigurationProperty + private Contact contact = null; + + /** + * 许可证 + */ + @NestedConfigurationProperty + private License license = null; + + /** + * 版本 + */ + private String version = null; + + } + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/ThreadPoolProperties.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/ThreadPoolProperties.java new file mode 100644 index 0000000..2fe5b54 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/ThreadPoolProperties.java @@ -0,0 +1,29 @@ +package com.inscloudtech.framework.config.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 线程池 配置属性 + * + * @author inscloudtech + */ +@Data +@Component +@ConfigurationProperties(prefix = "thread-pool") +public class ThreadPoolProperties { + /** + * 是否开启线程池 + */ + private boolean enabled; + /** + * 队列最大长度 + */ + private int queueCapacity; + /** + * 线程池维护线程所允许的空闲时间 + */ + private int keepAliveSeconds; + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/XssProperties.java b/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/XssProperties.java new file mode 100644 index 0000000..631cbc8 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/config/properties/XssProperties.java @@ -0,0 +1,29 @@ +package com.inscloudtech.framework.config.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * xss过滤 配置属性 + * + * @author inscloudtech + */ +@Data +@Component +@ConfigurationProperties(prefix = "xss") +public class XssProperties { + /** + * 过滤开关 + */ + private String enabled; + /** + * 排除链接(多个用逗号分隔) + */ + private String excludes; + /** + * 匹配链接 + */ + private String urlPatterns; + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/encrypt/MybatisDecryptInterceptor.java b/cas-framework/src/main/java/com/inscloudtech/framework/encrypt/MybatisDecryptInterceptor.java new file mode 100644 index 0000000..d28aaf6 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/encrypt/MybatisDecryptInterceptor.java @@ -0,0 +1,114 @@ +package com.inscloudtech.framework.encrypt; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.inscloudtech.common.annotation.EncryptField; +import com.inscloudtech.common.encrypt.EncryptContext; +import com.inscloudtech.common.enums.AlgorithmType; +import com.inscloudtech.common.enums.EncodeType; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.framework.config.properties.EncryptorProperties; +import com.inscloudtech.framework.manager.EncryptorManager; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.executor.resultset.ResultSetHandler; +import org.apache.ibatis.plugin.*; + +import java.lang.reflect.Field; +import java.sql.Statement; +import java.util.*; + +/** + * 出参解密拦截器 + * + * @author inscloudtech + * @version 4.6.0 + */ +@Slf4j +@Intercepts({@Signature( + type = ResultSetHandler.class, + method = "handleResultSets", + args = {Statement.class}) +}) +@AllArgsConstructor +public class MybatisDecryptInterceptor implements Interceptor { + + private final EncryptorManager encryptorManager; + private final EncryptorProperties defaultProperties; + + @Override + public Object intercept(Invocation invocation) throws Throwable { + // 获取执行mysql执行结果 + Object result = invocation.proceed(); + if (result == null) { + return null; + } + decryptHandler(result); + return result; + } + /** + * 解密对象 + * + * @param sourceObject 待加密对象 + */ + private void decryptHandler(Object sourceObject) { + if (ObjectUtil.isNull(sourceObject)) { + return; + } + if (sourceObject instanceof Map) { + new HashSet<>(((Map) sourceObject).values()).forEach(this::decryptHandler); + return; + } + if (sourceObject instanceof List) { + List sourceList = (List) sourceObject; + if(CollUtil.isEmpty(sourceList)) { + return; + } + // 判断第一个元素是否含有注解。如果没有直接返回,提高效率 + Object firstItem = sourceList.get(0); + if (ObjectUtil.isNull(firstItem) || CollUtil.isEmpty(encryptorManager.getFieldCache(firstItem.getClass()))) { + return; + } + ((List) sourceObject).forEach(this::decryptHandler); + return; + } + Set fields = encryptorManager.getFieldCache(sourceObject.getClass()); + try { + for (Field field : fields) { + field.set(sourceObject, this.decryptField(String.valueOf(field.get(sourceObject)), field)); + } + } catch (Exception e) { + log.error("处理解密字段时出错", e); + } + } + /** + * 字段值进行加密。通过字段的批注注册新的加密算法 + * + * @param value 待加密的值 + * @param field 待加密字段 + * @return 加密后结果 + */ + private String decryptField(String value, Field field) { + if (ObjectUtil.isNull(value)) { + return null; + } + EncryptField encryptField = field.getAnnotation(EncryptField.class); + EncryptContext encryptContext = new EncryptContext(); + encryptContext.setAlgorithm(encryptField.algorithm() == AlgorithmType.DEFAULT ? defaultProperties.getAlgorithm() : encryptField.algorithm()); + encryptContext.setEncode(encryptField.encode() == EncodeType.DEFAULT ? defaultProperties.getEncode() : encryptField.encode()); + encryptContext.setPassword(StringUtils.isBlank(encryptField.password()) ? defaultProperties.getPassword() : encryptField.password()); + encryptContext.setPrivateKey(StringUtils.isBlank(encryptField.privateKey()) ? defaultProperties.getPrivateKey() : encryptField.privateKey()); + encryptContext.setPublicKey(StringUtils.isBlank(encryptField.publicKey()) ? defaultProperties.getPublicKey() : encryptField.publicKey()); + return this.encryptorManager.decrypt(value, encryptContext); + } + + @Override + public Object plugin(Object target) { + return Plugin.wrap(target, this); + } + + @Override + public void setProperties(Properties properties) { + + } +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/encrypt/MybatisEncryptInterceptor.java b/cas-framework/src/main/java/com/inscloudtech/framework/encrypt/MybatisEncryptInterceptor.java new file mode 100644 index 0000000..d90aa98 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/encrypt/MybatisEncryptInterceptor.java @@ -0,0 +1,119 @@ +package com.inscloudtech.framework.encrypt; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.inscloudtech.common.annotation.EncryptField; +import com.inscloudtech.common.encrypt.EncryptContext; +import com.inscloudtech.common.enums.AlgorithmType; +import com.inscloudtech.common.enums.EncodeType; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.framework.config.properties.EncryptorProperties; +import com.inscloudtech.framework.manager.EncryptorManager; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.executor.parameter.ParameterHandler; +import org.apache.ibatis.plugin.Interceptor; +import org.apache.ibatis.plugin.Intercepts; +import org.apache.ibatis.plugin.Invocation; +import org.apache.ibatis.plugin.Signature; + +import java.lang.reflect.Field; +import java.sql.PreparedStatement; +import java.util.*; + +/** + * 入参加密拦截器 + * + * @author inscloudtech + * @version 4.6.0 + */ +@Slf4j +@Intercepts({@Signature( + type = ParameterHandler.class, + method = "setParameters", + args = {PreparedStatement.class}) +}) +@AllArgsConstructor +public class MybatisEncryptInterceptor implements Interceptor { + + private final EncryptorManager encryptorManager; + private final EncryptorProperties defaultProperties; + + @Override + public Object intercept(Invocation invocation) throws Throwable { + return invocation; + } + + @Override + public Object plugin(Object target) { + if (target instanceof ParameterHandler) { + // 进行加密操作 + ParameterHandler parameterHandler = (ParameterHandler) target; + Object parameterObject = parameterHandler.getParameterObject(); + if (ObjectUtil.isNotNull(parameterObject) && !(parameterObject instanceof String)) { + this.encryptHandler(parameterObject); + } + } + return target; + } + /** + * 加密对象 + * + * @param sourceObject 待加密对象 + */ + private void encryptHandler(Object sourceObject) { + if (ObjectUtil.isNull(sourceObject)) { + return; + } + if (sourceObject instanceof Map) { + new HashSet<>(((Map) sourceObject).values()).forEach(this::encryptHandler); + return; + } + if (sourceObject instanceof List) { + List sourceList = (List) sourceObject; + if(CollUtil.isEmpty(sourceList)) { + return; + } + // 判断第一个元素是否含有注解。如果没有直接返回,提高效率 + Object firstItem = sourceList.get(0); + if (ObjectUtil.isNull(firstItem) || CollUtil.isEmpty(encryptorManager.getFieldCache(firstItem.getClass()))) { + return; + } + ((List) sourceObject).forEach(this::encryptHandler); + return; + } + Set fields = encryptorManager.getFieldCache(sourceObject.getClass()); + try { + for (Field field : fields) { + field.set(sourceObject, this.encryptField(String.valueOf(field.get(sourceObject)), field)); + } + } catch (Exception e) { + log.error("处理加密字段时出错", e); + } + } + /** + * 字段值进行加密。通过字段的批注注册新的加密算法 + * + * @param value 待加密的值 + * @param field 待加密字段 + * @return 加密后结果 + */ + private String encryptField(String value, Field field) { + if (ObjectUtil.isNull(value)) { + return null; + } + EncryptField encryptField = field.getAnnotation(EncryptField.class); + EncryptContext encryptContext = new EncryptContext(); + encryptContext.setAlgorithm(encryptField.algorithm() == AlgorithmType.DEFAULT ? defaultProperties.getAlgorithm() : encryptField.algorithm()); + encryptContext.setEncode(encryptField.encode() == EncodeType.DEFAULT ? defaultProperties.getEncode() : encryptField.encode()); + encryptContext.setPassword(StringUtils.isBlank(encryptField.password()) ? defaultProperties.getPassword() : encryptField.password()); + encryptContext.setPrivateKey(StringUtils.isBlank(encryptField.privateKey()) ? defaultProperties.getPrivateKey() : encryptField.privateKey()); + encryptContext.setPublicKey(StringUtils.isBlank(encryptField.publicKey()) ? defaultProperties.getPublicKey() : encryptField.publicKey()); + return this.encryptorManager.encrypt(value, encryptContext); + } + + + @Override + public void setProperties(Properties properties) { + } +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/handler/AllUrlHandler.java b/cas-framework/src/main/java/com/inscloudtech/framework/handler/AllUrlHandler.java new file mode 100644 index 0000000..5518da0 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/handler/AllUrlHandler.java @@ -0,0 +1,41 @@ +package com.inscloudtech.framework.handler; + +import cn.hutool.core.util.ReUtil; +import com.inscloudtech.common.utils.spring.SpringUtils; +import lombok.Data; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.mvc.method.RequestMappingInfo; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; + +import java.util.*; +import java.util.regex.Pattern; + +/** + * 获取所有Url配置 + * + * @author inscloudtech + */ +@Data +@Component +public class AllUrlHandler implements InitializingBean { + + private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}"); + + private List urls = new ArrayList<>(); + + @Override + public void afterPropertiesSet() { + Set set = new HashSet<>(); + RequestMappingHandlerMapping mapping = SpringUtils.getBean("requestMappingHandlerMapping", RequestMappingHandlerMapping.class); + Map map = mapping.getHandlerMethods(); + map.keySet().forEach(info -> { + // 获取注解上边的 path 替代 path variable 为 * + Objects.requireNonNull(info.getPathPatternsCondition().getPatterns()) + .forEach(url -> set.add(ReUtil.replaceAll(url.getPatternString(), PATTERN, "*"))); + }); + urls.addAll(set); + } + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/handler/CreateAndUpdateMetaObjectHandler.java b/cas-framework/src/main/java/com/inscloudtech/framework/handler/CreateAndUpdateMetaObjectHandler.java new file mode 100644 index 0000000..f509d96 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/handler/CreateAndUpdateMetaObjectHandler.java @@ -0,0 +1,78 @@ +package com.inscloudtech.framework.handler; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.http.HttpStatus; +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import com.inscloudtech.common.core.domain.BaseEntity; +import com.inscloudtech.common.core.domain.model.LoginUser; +import com.inscloudtech.common.exception.ServiceException; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.common.utils.StringUtils; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.reflection.MetaObject; + +import java.util.Date; + +/** + * MP注入处理器 + * + * @author inscloudtech + * @date 2021/4/25 + */ +@Slf4j +public class CreateAndUpdateMetaObjectHandler implements MetaObjectHandler { + + @Override + public void insertFill(MetaObject metaObject) { + try { + if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity) { + BaseEntity baseEntity = (BaseEntity) metaObject.getOriginalObject(); + Date current = ObjectUtil.isNotNull(baseEntity.getCreateTime()) + ? baseEntity.getCreateTime() : new Date(); + baseEntity.setCreateTime(current); + baseEntity.setUpdateTime(current); + String username = StringUtils.isNotBlank(baseEntity.getCreateBy()) + ? baseEntity.getCreateBy() : getLoginUsername(); + // 当前已登录 且 创建人为空 则填充 + baseEntity.setCreateBy(username); + // 当前已登录 且 更新人为空 则填充 + baseEntity.setUpdateBy(username); + } + } catch (Exception e) { + throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); + } + } + + @Override + public void updateFill(MetaObject metaObject) { + try { + if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity) { + BaseEntity baseEntity = (BaseEntity) metaObject.getOriginalObject(); + Date current = new Date(); + // 更新时间填充(不管为不为空) + baseEntity.setUpdateTime(current); + String username = getLoginUsername(); + // 当前已登录 更新人填充(不管为不为空) + if (StringUtils.isNotBlank(username)) { + baseEntity.setUpdateBy(username); + } + } + } catch (Exception e) { + throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); + } + } + /** + * 获取登录用户名 + */ + private String getLoginUsername() { + LoginUser loginUser; + try { + loginUser = LoginHelper.getLoginUser(); + } catch (Exception e) { + log.warn("自动注入警告 => 用户未登录"); + return null; + } + return ObjectUtil.isNotNull(loginUser) ? loginUser.getUsername() : null; + } + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/handler/KeyPrefixHandler.java b/cas-framework/src/main/java/com/inscloudtech/framework/handler/KeyPrefixHandler.java new file mode 100644 index 0000000..c22e7d8 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/handler/KeyPrefixHandler.java @@ -0,0 +1,48 @@ +package com.inscloudtech.framework.handler; + +import com.inscloudtech.common.utils.StringUtils; +import org.redisson.api.NameMapper; + +/** + * redis缓存key前缀处理 + * + * @author ye + * @date 2022/7/14 17:44 + * @since 4.3.0 + */ +public class KeyPrefixHandler implements NameMapper { + + private final String keyPrefix; + + public KeyPrefixHandler(String keyPrefix) { + //前缀为空 则返回空前缀 + this.keyPrefix = StringUtils.isBlank(keyPrefix) ? "" : keyPrefix + ":"; + } + /** + * 增加前缀 + */ + @Override + public String map(String name) { + if (StringUtils.isBlank(name)) { + return null; + } + if (StringUtils.isNotBlank(keyPrefix) && !name.startsWith(keyPrefix)) { + return keyPrefix + name; + } + return name; + } + /** + * 去除前缀 + */ + @Override + public String unmap(String name) { + if (StringUtils.isBlank(name)) { + return null; + } + if (StringUtils.isNotBlank(keyPrefix) && name.startsWith(keyPrefix)) { + return name.substring(keyPrefix.length()); + } + return name; + } + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/handler/OpenApiHandler.java b/cas-framework/src/main/java/com/inscloudtech/framework/handler/OpenApiHandler.java new file mode 100644 index 0000000..7446b08 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/handler/OpenApiHandler.java @@ -0,0 +1,256 @@ +package com.inscloudtech.framework.handler; + +import cn.hutool.core.io.IoUtil; +import io.swagger.v3.core.jackson.TypeNameResolver; +import io.swagger.v3.core.util.AnnotationsUtils; +import io.swagger.v3.oas.annotations.tags.Tags; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.tags.Tag; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springdoc.core.OpenAPIService; +import org.springdoc.core.PropertyResolverUtils; +import org.springdoc.core.SecurityService; +import org.springdoc.core.SpringDocConfigProperties; +import org.springdoc.core.customizers.OpenApiBuilderCustomizer; +import org.springdoc.core.customizers.ServerBaseUrlCustomizer; +import org.springdoc.core.providers.JavadocProvider; +import org.springframework.context.ApplicationContext; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.util.CollectionUtils; +import org.springframework.web.method.HandlerMethod; + +import java.io.StringReader; +import java.lang.reflect.Method; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 自定义 openapi 处理器 + * 对源码功能进行修改 增强使用 + */ +@SuppressWarnings("all") +public class OpenApiHandler extends OpenAPIService { + /** + * The constant LOGGER. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(OpenAPIService.class); + /** + * The Context. + */ + private ApplicationContext context; + /** + * The Security parser. + */ + private final SecurityService securityParser; + /** + * The Mappings map. + */ + private final Map mappingsMap = new HashMap<>(); + /** + * The Springdoc tags. + */ + private final Map springdocTags = new HashMap<>(); + /** + * The Open api builder customisers. + */ + private final Optional> openApiBuilderCustomisers; + /** + * The server base URL customisers. + */ + private final Optional> serverBaseUrlCustomizers; + /** + * The Spring doc config properties. + */ + private final SpringDocConfigProperties springDocConfigProperties; + /** + * The Open api. + */ + private OpenAPI openAPI; + /** + * The Cached open api map. + */ + private final Map cachedOpenAPI = new HashMap<>(); + /** + * The Is servers present. + */ + private boolean isServersPresent; + /** + * The Server base url. + */ + private String serverBaseUrl; + /** + * The Property resolver utils. + */ + private final PropertyResolverUtils propertyResolverUtils; + /** + * The javadoc provider. + */ + private final Optional javadocProvider; + /** + * The Basic error controller. + */ + private static Class basicErrorController; + + static { + try { + //spring-boot 2 + basicErrorController = Class.forName("org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController"); + } catch (ClassNotFoundException e) { + //spring-boot 1 + try { + basicErrorController = Class.forName("org.springframework.boot.autoconfigure.web.BasicErrorController"); + } catch (ClassNotFoundException classNotFoundException) { + //Basic error controller class not found + LOGGER.trace(classNotFoundException.getMessage()); + } + } + } + /** + * Instantiates a new Open api builder. + * + * @param openAPI the open api + * @param securityParser the security parser + * @param springDocConfigProperties the spring doc config properties + * @param propertyResolverUtils the property resolver utils + * @param openApiBuilderCustomizers the open api builder customisers + * @param serverBaseUrlCustomizers the server base url customizers + * @param javadocProvider the javadoc provider + */ + public OpenApiHandler(Optional openAPI, SecurityService securityParser, + SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils, + Optional> openApiBuilderCustomizers, + Optional> serverBaseUrlCustomizers, + Optional javadocProvider) { + super(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomizers, serverBaseUrlCustomizers, javadocProvider); + if (openAPI.isPresent()) { + this.openAPI = openAPI.get(); + if (this.openAPI.getComponents() == null) + this.openAPI.setComponents(new Components()); + if (this.openAPI.getPaths() == null) + this.openAPI.setPaths(new Paths()); + if (!CollectionUtils.isEmpty(this.openAPI.getServers())) + this.isServersPresent = true; + } + this.propertyResolverUtils = propertyResolverUtils; + this.securityParser = securityParser; + this.springDocConfigProperties = springDocConfigProperties; + this.openApiBuilderCustomisers = openApiBuilderCustomizers; + this.serverBaseUrlCustomizers = serverBaseUrlCustomizers; + this.javadocProvider = javadocProvider; + if (springDocConfigProperties.isUseFqn()) + TypeNameResolver.std.setUseFqn(true); + } + + @Override + public Operation buildTags(HandlerMethod handlerMethod, Operation operation, OpenAPI openAPI, Locale locale) { + + Set tags = new HashSet<>(); + Set tagsStr = new HashSet<>(); + + buildTagsFromMethod(handlerMethod.getMethod(), tags, tagsStr, locale); + buildTagsFromClass(handlerMethod.getBeanType(), tags, tagsStr, locale); + + if (!CollectionUtils.isEmpty(tagsStr)) + tagsStr = tagsStr.stream() + .map(str -> propertyResolverUtils.resolve(str, locale)) + .collect(Collectors.toSet()); + + if (springdocTags.containsKey(handlerMethod)) { + io.swagger.v3.oas.models.tags.Tag tag = springdocTags.get(handlerMethod); + tagsStr.add(tag.getName()); + if (openAPI.getTags() == null || !openAPI.getTags().contains(tag)) { + openAPI.addTagsItem(tag); + } + } + + if (!CollectionUtils.isEmpty(tagsStr)) { + if (CollectionUtils.isEmpty(operation.getTags())) + operation.setTags(new ArrayList<>(tagsStr)); + else { + Set operationTagsSet = new HashSet<>(operation.getTags()); + operationTagsSet.addAll(tagsStr); + operation.getTags().clear(); + operation.getTags().addAll(operationTagsSet); + } + } + + if (isAutoTagClasses(operation)) { + + + if (javadocProvider.isPresent()) { + String description = javadocProvider.get().getClassJavadoc(handlerMethod.getBeanType()); + if (StringUtils.isNotBlank(description)) { + io.swagger.v3.oas.models.tags.Tag tag = new io.swagger.v3.oas.models.tags.Tag(); + + // 自定义部分 修改使用java注释当tag名 + List list = IoUtil.readLines(new StringReader(description), new ArrayList<>()); + // tag.setName(tagAutoName); + tag.setName(list.get(0)); + operation.addTagsItem(list.get(0)); + + tag.setDescription(description); + if (openAPI.getTags() == null || !openAPI.getTags().contains(tag)) { + openAPI.addTagsItem(tag); + } + } + } else { + String tagAutoName = splitCamelCase(handlerMethod.getBeanType().getSimpleName()); + operation.addTagsItem(tagAutoName); + } + } + + if (!CollectionUtils.isEmpty(tags)) { + // Existing tags + List openApiTags = openAPI.getTags(); + if (!CollectionUtils.isEmpty(openApiTags)) + tags.addAll(openApiTags); + openAPI.setTags(new ArrayList<>(tags)); + } + + // Handle SecurityRequirement at operation level + io.swagger.v3.oas.annotations.security.SecurityRequirement[] securityRequirements = securityParser + .getSecurityRequirements(handlerMethod); + if (securityRequirements != null) { + if (securityRequirements.length == 0) + operation.setSecurity(Collections.emptyList()); + else + securityParser.buildSecurityRequirement(securityRequirements, operation); + } + + return operation; + } + + private void buildTagsFromMethod(Method method, Set tags, Set tagsStr, Locale locale) { + // method tags + Set tagsSet = AnnotatedElementUtils + .findAllMergedAnnotations(method, Tags.class); + Set methodTags = tagsSet.stream() + .flatMap(x -> Stream.of(x.value())).collect(Collectors.toSet()); + methodTags.addAll(AnnotatedElementUtils.findAllMergedAnnotations(method, io.swagger.v3.oas.annotations.tags.Tag.class)); + if (!CollectionUtils.isEmpty(methodTags)) { + tagsStr.addAll(methodTags.stream().map(tag -> propertyResolverUtils.resolve(tag.name(), locale)).collect(Collectors.toSet())); + List allTags = new ArrayList<>(methodTags); + addTags(allTags, tags, locale); + } + } + + private void addTags(List sourceTags, Set tags, Locale locale) { + Optional> optionalTagSet = AnnotationsUtils + .getTags(sourceTags.toArray(new io.swagger.v3.oas.annotations.tags.Tag[0]), true); + optionalTagSet.ifPresent(tagsSet -> { + tagsSet.forEach(tag -> { + tag.name(propertyResolverUtils.resolve(tag.getName(), locale)); + tag.description(propertyResolverUtils.resolve(tag.getDescription(), locale)); + if (tags.stream().noneMatch(t -> t.getName().equals(tag.getName()))) + tags.add(tag); + }); + }); + } + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/handler/PlusDataPermissionHandler.java b/cas-framework/src/main/java/com/inscloudtech/framework/handler/PlusDataPermissionHandler.java new file mode 100644 index 0000000..06ad7d6 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/handler/PlusDataPermissionHandler.java @@ -0,0 +1,193 @@ +package com.inscloudtech.framework.handler; + +import cn.hutool.core.annotation.AnnotationUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ConcurrentHashSet; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ClassUtil; +import cn.hutool.core.util.ObjectUtil; +import com.inscloudtech.common.annotation.DataColumn; +import com.inscloudtech.common.annotation.DataPermission; +import com.inscloudtech.common.core.domain.dto.RoleDTO; +import com.inscloudtech.common.core.domain.model.LoginUser; +import com.inscloudtech.common.enums.DataScopeType; +import com.inscloudtech.common.exception.ServiceException; +import com.inscloudtech.common.helper.DataPermissionHelper; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.common.utils.StreamUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.spring.SpringUtils; +import lombok.extern.slf4j.Slf4j; +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.Parenthesis; +import net.sf.jsqlparser.expression.operators.conditional.AndExpression; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import org.springframework.context.expression.BeanFactoryResolver; +import org.springframework.expression.BeanResolver; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.ParserContext; +import org.springframework.expression.common.TemplateParserContext; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; + +import java.lang.reflect.Method; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 数据权限过滤 + * + * @author inscloudtech + * @version 3.5.0 + */ +@Slf4j +public class PlusDataPermissionHandler { + /** + * 方法或类(名称) 与 注解的映射关系缓存 + */ + private final Map dataPermissionCacheMap = new ConcurrentHashMap<>(); + /** + * 无效注解方法缓存用于快速返回 + */ + private final Set invalidCacheSet = new ConcurrentHashSet<>(); + /** + * spel 解析器 + */ + private final ExpressionParser parser = new SpelExpressionParser(); + private final ParserContext parserContext = new TemplateParserContext(); /** + * bean解析器 用于处理 spel 表达式中对 bean 的调用 + */ + private final BeanResolver beanResolver = new BeanFactoryResolver(SpringUtils.getBeanFactory()); + + + public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) { + DataColumn[] dataColumns = findAnnotation(mappedStatementId); + if (ArrayUtil.isEmpty(dataColumns)) { + invalidCacheSet.add(mappedStatementId); + return where; + } + LoginUser currentUser = DataPermissionHelper.getVariable("user"); + if (ObjectUtil.isNull(currentUser)) { + currentUser = LoginHelper.getLoginUser(); + DataPermissionHelper.setVariable("user", currentUser); + } + // 如果是超级管理员,则不过滤数据 + if (LoginHelper.isAdmin()) { + return where; + } + String dataFilterSql = buildDataFilter(dataColumns, isSelect); + if (StringUtils.isBlank(dataFilterSql)) { + return where; + } + try { + Expression expression = CCJSqlParserUtil.parseExpression(dataFilterSql); + // 数据权限使用单独的括号 防止与其他条件冲突 + Parenthesis parenthesis = new Parenthesis(expression); + if (ObjectUtil.isNotNull(where)) { + return new AndExpression(where, parenthesis); + } else { + return parenthesis; + } + } catch (JSQLParserException e) { + throw new ServiceException("数据权限解析异常 => " + e.getMessage()); + } + } + /** + * 构造数据过滤sql + */ + private String buildDataFilter(DataColumn[] dataColumns, boolean isSelect) { + // 更新或删除需满足所有条件 + String joinStr = isSelect ? " OR " : " AND "; + LoginUser user = DataPermissionHelper.getVariable("user"); + StandardEvaluationContext context = new StandardEvaluationContext(); + context.setBeanResolver(beanResolver); + DataPermissionHelper.getContext().forEach(context::setVariable); + Set conditions = new HashSet<>(); + for (RoleDTO role : user.getRoles()) { + user.setRoleId(role.getRoleId()); + // 获取角色权限泛型 + DataScopeType type = DataScopeType.findCode(role.getDataScope()); + if (ObjectUtil.isNull(type)) { + throw new ServiceException("角色数据范围异常 => " + role.getDataScope()); + } + // 全部数据权限直接返回 + if (type == DataScopeType.ALL) { + return ""; + } + boolean isSuccess = false; + for (DataColumn dataColumn : dataColumns) { + if (dataColumn.key().length != dataColumn.value().length) { + throw new ServiceException("角色数据范围异常 => key与value长度不匹配"); + } + // 不包含 key 变量 则不处理 + if (!StringUtils.containsAny(type.getSqlTemplate(), + Arrays.stream(dataColumn.key()).map(key -> "#" + key).toArray(String[]::new) + )) { + continue; + } + // 设置注解变量 key 为表达式变量 value 为变量值 + for (int i = 0; i < dataColumn.key().length; i++) { + context.setVariable(dataColumn.key()[i], dataColumn.value()[i]); + } + + // 解析sql模板并填充 + String sql = parser.parseExpression(type.getSqlTemplate(), parserContext).getValue(context, String.class); + conditions.add(joinStr + sql); + isSuccess = true; + } + // 未处理成功则填充兜底方案 + if (!isSuccess && StringUtils.isNotBlank(type.getElseSql())) { + conditions.add(joinStr + type.getElseSql()); + } + } + + if (CollUtil.isNotEmpty(conditions)) { + String sql = StreamUtils.join(conditions, Function.identity(), ""); + return sql.substring(joinStr.length()); + } + return ""; + } + + private DataColumn[] findAnnotation(String mappedStatementId) { + StringBuilder sb = new StringBuilder(mappedStatementId); + int index = sb.lastIndexOf("."); + String clazzName = sb.substring(0, index); + String methodName = sb.substring(index + 1, sb.length()); + Class clazz = ClassUtil.loadClass(clazzName); + List methods = Arrays.stream(ClassUtil.getDeclaredMethods(clazz)) + .filter(method -> method.getName().equals(methodName)).collect(Collectors.toList()); + DataPermission dataPermission; + // 获取方法注解 + for (Method method : methods) { + dataPermission = dataPermissionCacheMap.get(mappedStatementId); + if (ObjectUtil.isNotNull(dataPermission)) { + return dataPermission.value(); + } + if (AnnotationUtil.hasAnnotation(method, DataPermission.class)) { + dataPermission = AnnotationUtil.getAnnotation(method, DataPermission.class); + dataPermissionCacheMap.put(mappedStatementId, dataPermission); + return dataPermission.value(); + } + } + dataPermission = dataPermissionCacheMap.get(clazz.getName()); + if (ObjectUtil.isNotNull(dataPermission)) { + return dataPermission.value(); + } + // 获取类注解 + if (AnnotationUtil.hasAnnotation(clazz, DataPermission.class)) { + dataPermission = AnnotationUtil.getAnnotation(clazz, DataPermission.class); + dataPermissionCacheMap.put(clazz.getName(), dataPermission); + return dataPermission.value(); + } + return null; + } + /** + * 是否为无效方法 无数据权限 + */ + public boolean isInvalid(String mappedStatementId) { + return invalidCacheSet.contains(mappedStatementId); + } +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/interceptor/PlusDataPermissionInterceptor.java b/cas-framework/src/main/java/com/inscloudtech/framework/interceptor/PlusDataPermissionInterceptor.java new file mode 100644 index 0000000..4424734 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/interceptor/PlusDataPermissionInterceptor.java @@ -0,0 +1,107 @@ +package com.inscloudtech.framework.interceptor; + +import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; +import com.baomidou.mybatisplus.core.toolkit.PluginUtils; +import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport; +import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; +import com.inscloudtech.framework.handler.PlusDataPermissionHandler; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.select.SelectBody; +import net.sf.jsqlparser.statement.select.SetOperationList; +import net.sf.jsqlparser.statement.update.Update; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.executor.statement.StatementHandler; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlCommandType; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.List; + +/** + * 数据权限拦截器 + * + * @author inscloudtech + * @version 3.5.0 + */ +public class PlusDataPermissionInterceptor extends JsqlParserSupport implements InnerInterceptor { + + private final PlusDataPermissionHandler dataPermissionHandler = new PlusDataPermissionHandler(); + + @Override + public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { + // 检查忽略注解 + if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) { + return; + } + // 检查是否无效 无数据权限注解 + if (dataPermissionHandler.isInvalid(ms.getId())) { + return; + } + // 解析 sql 分配对应方法 + PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql); + mpBs.sql(parserSingle(mpBs.sql(), ms.getId())); + } + + @Override + public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) { + PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh); + MappedStatement ms = mpSh.mappedStatement(); + SqlCommandType sct = ms.getSqlCommandType(); + if (sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) { + if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) { + return; + } + PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql(); + mpBs.sql(parserMulti(mpBs.sql(), ms.getId())); + } + } + + @Override + protected void processSelect(Select select, int index, String sql, Object obj) { + SelectBody selectBody = select.getSelectBody(); + if (selectBody instanceof PlainSelect) { + this.setWhere((PlainSelect) selectBody, (String) obj); + } else if (selectBody instanceof SetOperationList) { + SetOperationList setOperationList = (SetOperationList) selectBody; + List selectBodyList = setOperationList.getSelects(); + selectBodyList.forEach(s -> this.setWhere((PlainSelect) s, (String) obj)); + } + } + + @Override + protected void processUpdate(Update update, int index, String sql, Object obj) { + Expression sqlSegment = dataPermissionHandler.getSqlSegment(update.getWhere(), (String) obj, false); + if (null != sqlSegment) { + update.setWhere(sqlSegment); + } + } + + @Override + protected void processDelete(Delete delete, int index, String sql, Object obj) { + Expression sqlSegment = dataPermissionHandler.getSqlSegment(delete.getWhere(), (String) obj, false); + if (null != sqlSegment) { + delete.setWhere(sqlSegment); + } + } + /** + * 设置 where 条件 + * + * @param plainSelect 查询对象 + * @param mappedStatementId 执行方法id + */ + protected void setWhere(PlainSelect plainSelect, String mappedStatementId) { + Expression sqlSegment = dataPermissionHandler.getSqlSegment(plainSelect.getWhere(), mappedStatementId, true); + if (null != sqlSegment) { + plainSelect.setWhere(sqlSegment); + } + } + +} + diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/interceptor/PlusWebInvokeTimeInterceptor.java b/cas-framework/src/main/java/com/inscloudtech/framework/interceptor/PlusWebInvokeTimeInterceptor.java new file mode 100644 index 0000000..a9d931b --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/interceptor/PlusWebInvokeTimeInterceptor.java @@ -0,0 +1,93 @@ +package com.inscloudtech.framework.interceptor; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.map.MapUtil; +import com.alibaba.ttl.TransmittableThreadLocal; +import com.inscloudtech.common.filter.RepeatedlyRequestWrapper; +import com.inscloudtech.common.utils.JsonUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.spring.SpringUtils; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.time.StopWatch; +import org.springframework.http.MediaType; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.BufferedReader; +import java.util.Map; + +/** + * web的调用时间统计拦截器 + * dev环境有效 + * + * @author inscloudtech + * @since 3.3.0 + */ +@Slf4j +public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor { + + private final String prodProfile = "prod"; + + private final TransmittableThreadLocal invokeTimeTL = new TransmittableThreadLocal<>(); + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + if (!prodProfile.equals(SpringUtils.getActiveProfile())) { + String url = request.getMethod() + " " + request.getRequestURI(); + + // 打印请求参数 + if (isJsonRequest(request)) { + String jsonParam = ""; + if (request instanceof RepeatedlyRequestWrapper) { + BufferedReader reader = request.getReader(); + jsonParam = IoUtil.read(reader); + } + log.debug("[PLUS]开始请求 => URL[{}],参数类型[json],参数:[{}]", url, jsonParam); + } else { + Map parameterMap = request.getParameterMap(); + if (MapUtil.isNotEmpty(parameterMap)) { + String parameters = JsonUtils.toJsonString(parameterMap); + log.debug("[PLUS]开始请求 => URL[{}],参数类型[param],参数:[{}]", url, parameters); + } else { + log.debug("[PLUS]开始请求 => URL[{}],无参数", url); + } + } + + StopWatch stopWatch = new StopWatch(); + invokeTimeTL.set(stopWatch); + stopWatch.start(); + } + return true; + } + + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { + + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { + if (!prodProfile.equals(SpringUtils.getActiveProfile())) { + StopWatch stopWatch = invokeTimeTL.get(); + stopWatch.stop(); + log.debug("[PLUS]结束请求 => URL[{}],耗时:[{}]毫秒", request.getMethod() + " " + request.getRequestURI(), stopWatch.getTime()); + invokeTimeTL.remove(); + } + } + /** + * 判断本次请求的数据类型是否为json + * + * @param request request + * @return boolean + */ + private boolean isJsonRequest(HttpServletRequest request) { + String contentType = request.getContentType(); + if (contentType != null) { + return StringUtils.startsWithIgnoreCase(contentType, MediaType.APPLICATION_JSON_VALUE); + } + return false; + } + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/jackson/BigNumberSerializer.java b/cas-framework/src/main/java/com/inscloudtech/framework/jackson/BigNumberSerializer.java new file mode 100644 index 0000000..dad27d4 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/jackson/BigNumberSerializer.java @@ -0,0 +1,40 @@ +package com.inscloudtech.framework.jackson; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JacksonStdImpl; +import com.fasterxml.jackson.databind.ser.std.NumberSerializer; + +import java.io.IOException; + +/** + * 超出 JS 最大最小值 处理 + * + * @author inscloudtech + */ +@JacksonStdImpl +public class BigNumberSerializer extends NumberSerializer { + /** + * 根据 JS Number.MAX_SAFE_INTEGER 与 Number.MIN_SAFE_INTEGER 得来 + */ + private static final long MAX_SAFE_INTEGER = 9007199254740991L; + private static final long MIN_SAFE_INTEGER = -9007199254740991L; + /** + * 提供实例 + */ + public static final BigNumberSerializer INSTANCE = new BigNumberSerializer(Number.class); + + public BigNumberSerializer(Class rawType) { + super(rawType); + } + + @Override + public void serialize(Number value, JsonGenerator gen, SerializerProvider provider) throws IOException { + // 超出范围 序列化位字符串 + if (value.longValue() > MIN_SAFE_INTEGER && value.longValue() < MAX_SAFE_INTEGER) { + super.serialize(value, gen, provider); + } else { + gen.writeString(value.toString()); + } + } +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/listener/UserActionListener.java b/cas-framework/src/main/java/com/inscloudtech/framework/listener/UserActionListener.java new file mode 100644 index 0000000..426b8f6 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/listener/UserActionListener.java @@ -0,0 +1,128 @@ +package com.inscloudtech.framework.listener; + +import cn.dev33.satoken.config.SaTokenConfig; +import cn.dev33.satoken.listener.SaTokenListener; +import cn.dev33.satoken.stp.SaLoginModel; +import cn.hutool.http.useragent.UserAgent; +import cn.hutool.http.useragent.UserAgentUtil; +import com.inscloudtech.common.constant.CacheConstants; +import com.inscloudtech.common.core.domain.dto.UserOnlineDTO; +import com.inscloudtech.common.core.domain.model.LoginUser; +import com.inscloudtech.common.enums.UserType; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.common.utils.ServletUtils; +import com.inscloudtech.common.utils.ip.AddressUtils; +import com.inscloudtech.common.utils.redis.RedisUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.time.Duration; + +/** + * 用户行为 侦听器的实现 + * + * @author inscloudtech + */ +@RequiredArgsConstructor +@Component +@Slf4j +public class UserActionListener implements SaTokenListener { + + private final SaTokenConfig tokenConfig; + /** + * 每次登录时触发 + */ + @Override + public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) { + UserType userType = UserType.getUserType(loginId.toString()); + if (userType == UserType.SYS_USER) { + UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent")); + String ip = ServletUtils.getClientIP(); + LoginUser user = LoginHelper.getLoginUser(); + UserOnlineDTO dto = new UserOnlineDTO(); + dto.setIpaddr(ip); + dto.setLoginLocation(AddressUtils.getRealAddressByIP(ip)); + dto.setBrowser(userAgent.getBrowser().getName()); + dto.setOs(userAgent.getOs().getName()); + dto.setLoginTime(System.currentTimeMillis()); + dto.setTokenId(tokenValue); + dto.setUserName(user.getUsername()); + dto.setDeptName(user.getDeptName()); + if(tokenConfig.getTimeout() == -1) { + RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto); + } else { + RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(tokenConfig.getTimeout())); + } + log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue); + } else if (userType == UserType.APP_USER) { + // app端 自行根据业务编写 + } + } + /** + * 每次注销时触发 + */ + @Override + public void doLogout(String loginType, Object loginId, String tokenValue) { + RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); + log.info("user doLogout, userId:{}, token:{}", loginId, tokenValue); + } + /** + * 每次被踢下线时触发 + */ + @Override + public void doKickout(String loginType, Object loginId, String tokenValue) { + RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); + log.info("user doLogoutByLoginId, userId:{}, token:{}", loginId, tokenValue); + } + /** + * 每次被顶下线时触发 + */ + @Override + public void doReplaced(String loginType, Object loginId, String tokenValue) { + RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); + log.info("user doReplaced, userId:{}, token:{}", loginId, tokenValue); + } + /** + * 每次被封禁时触发 + */ + @Override + public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) { + } + /** + * 每次被解封时触发 + */ + @Override + public void doUntieDisable(String loginType, Object loginId, String service) { + } + /** + * 每次打开二级认证时触发 + */ + @Override + public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) { + } + /** + * 每次创建Session时触发 + */ + @Override + public void doCloseSafe(String loginType, String tokenValue, String service) { + } + /** + * 每次创建Session时触发 + */ + @Override + public void doCreateSession(String id) { + } + /** + * 每次注销Session时触发 + */ + @Override + public void doLogoutSession(String id) { + } + /** + * 每次Token续期时触发 + */ + @Override + public void doRenewTimeout(String tokenValue, Object loginId, long timeout) { + } +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/manager/EncryptorManager.java b/cas-framework/src/main/java/com/inscloudtech/framework/manager/EncryptorManager.java new file mode 100644 index 0000000..ab4a924 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/manager/EncryptorManager.java @@ -0,0 +1,89 @@ +package com.inscloudtech.framework.manager; + +import cn.hutool.core.util.ReflectUtil; +import com.inscloudtech.common.annotation.EncryptField; +import com.inscloudtech.common.encrypt.EncryptContext; +import com.inscloudtech.common.encrypt.IEncryptor; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +/** + * 加密管理类 + * + * @author inscloudtech + * @version 4.6.0 + */ +@Slf4j +public class EncryptorManager { + /** + * 缓存加密器 + */ + Map encryptorMap = new ConcurrentHashMap<>(); + /** + * 类加密字段缓存 + */ + Map, Set> fieldCache = new ConcurrentHashMap<>(); + /** + * 获取类加密字段缓存 + */ + public Set getFieldCache(Class sourceClazz) { + return fieldCache.computeIfAbsent(sourceClazz, clazz -> { + Field[] declaredFields = clazz.getDeclaredFields(); + Set fieldSet = Arrays.stream(declaredFields).filter(field -> + field.isAnnotationPresent(EncryptField.class) && field.getType() == String.class) + .collect(Collectors.toSet()); + for (Field field : fieldSet) { + field.setAccessible(true); + } + return fieldSet; + }); + } + /** + * 注册加密执行者到缓存 + * + * @param encryptContext 加密执行者需要的相关配置参数 + */ + public IEncryptor registAndGetEncryptor(EncryptContext encryptContext) { + if (encryptorMap.containsKey(encryptContext)) { + return encryptorMap.get(encryptContext); + } + IEncryptor encryptor = ReflectUtil.newInstance(encryptContext.getAlgorithm().getClazz(), encryptContext); + encryptorMap.put(encryptContext, encryptor); + return encryptor; + } + /** + * 移除缓存中的加密执行者 + * + * @param encryptContext 加密执行者需要的相关配置参数 + */ + public void removeEncryptor(EncryptContext encryptContext) { + this.encryptorMap.remove(encryptContext); + } + /** + * 根据配置进行加密。会进行本地缓存对应的算法和对应的秘钥信息。 + * + * @param value 待加密的值 + * @param encryptContext 加密相关的配置信息 + */ + public String encrypt(String value, EncryptContext encryptContext) { + IEncryptor encryptor = this.registAndGetEncryptor(encryptContext); + return encryptor.encrypt(value, encryptContext.getEncode()); + } + /** + * 根据配置进行解密 + * + * @param value 待解密的值 + * @param encryptContext 加密相关的配置信息 + */ + public String decrypt(String value, EncryptContext encryptContext) { + IEncryptor encryptor = this.registAndGetEncryptor(encryptContext); + return encryptor.decrypt(value); + } + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/manager/PlusSpringCacheManager.java b/cas-framework/src/main/java/com/inscloudtech/framework/manager/PlusSpringCacheManager.java new file mode 100644 index 0000000..03fba9f --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/manager/PlusSpringCacheManager.java @@ -0,0 +1,186 @@ +/** + * Copyright (c) 2013-2021 Nikita Koksharov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.inscloudtech.framework.manager; + +import com.inscloudtech.common.utils.redis.RedisUtils; +import org.redisson.api.RMap; +import org.redisson.api.RMapCache; +import org.redisson.spring.cache.CacheConfig; +import org.redisson.spring.cache.RedissonCache; +import org.springframework.boot.convert.DurationStyle; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.cache.transaction.TransactionAwareCacheDecorator; +import org.springframework.util.StringUtils; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * A {@link org.springframework.cache.CacheManager} implementation + * backed by Redisson instance. + *

+ * 修改 RedissonSpringCacheManager 源码 + * 重写 cacheName 处理方法 支持多参数 + * + * @author Nikita Koksharov + * + */ +@SuppressWarnings("unchecked") +public class PlusSpringCacheManager implements CacheManager { + + private boolean dynamic = true; + + private boolean allowNullValues = true; + + private boolean transactionAware = true; + + Map configMap = new ConcurrentHashMap<>(); + ConcurrentMap instanceMap = new ConcurrentHashMap<>(); + /** + * Creates CacheManager supplied by Redisson instance + */ + public PlusSpringCacheManager() { + } + + /** + * Defines possibility of storing {@code null} values. + *

+ * Default is true + * + * @param allowNullValues stores if true + */ + public void setAllowNullValues(boolean allowNullValues) { + this.allowNullValues = allowNullValues; + } + /** + * Defines if cache aware of Spring-managed transactions. + * If {@code true} put/evict operations are executed only for successful transaction in after-commit phase. + *

+ * Default is false + * + * @param transactionAware cache is transaction aware if true + */ + public void setTransactionAware(boolean transactionAware) { + this.transactionAware = transactionAware; + } + /** + * Defines 'fixed' cache names. + * A new cache instance will not be created in dynamic for non-defined names. + *

+ * `null` parameter setups dynamic mode + * + * @param names of caches + */ + public void setCacheNames(Collection names) { + if (names != null) { + for (String name : names) { + getCache(name); + } + dynamic = false; + } else { + dynamic = true; + } + } + /** + * Set cache config mapped by cache name + * + * @param config object + */ + public void setConfig(Map config) { + this.configMap = (Map) config; + } + + protected CacheConfig createDefaultConfig() { + return new CacheConfig(); + } + + @Override + public Cache getCache(String name) { + Cache cache = instanceMap.get(name); + if (cache != null) { + return cache; + } + if (!dynamic) { + return cache; + } + + CacheConfig config = configMap.get(name); + if (config == null) { + config = createDefaultConfig(); + configMap.put(name, config); + } + + // 重写 cacheName 支持多参数 + String[] array = StringUtils.delimitedListToStringArray(name, "#"); + name = array[0]; + if (array.length > 1) { + config.setTTL(DurationStyle.detectAndParse(array[1]).toMillis()); + } + if (array.length > 2) { + config.setMaxIdleTime(DurationStyle.detectAndParse(array[2]).toMillis()); + } + if (array.length > 3) { + config.setMaxSize(Integer.parseInt(array[3])); + } + + if (config.getMaxIdleTime() == 0 && config.getTTL() == 0 && config.getMaxSize() == 0) { + return createMap(name, config); + } + + return createMapCache(name, config); + } + + private Cache createMap(String name, CacheConfig config) { + RMap map = RedisUtils.getClient().getMap(name); + + Cache cache = new RedissonCache(map, allowNullValues); + if (transactionAware) { + cache = new TransactionAwareCacheDecorator(cache); + } + Cache oldCache = instanceMap.putIfAbsent(name, cache); + if (oldCache != null) { + cache = oldCache; + } + return cache; + } + + private Cache createMapCache(String name, CacheConfig config) { + RMapCache map = RedisUtils.getClient().getMapCache(name); + + Cache cache = new RedissonCache(map, config, allowNullValues); + if (transactionAware) { + cache = new TransactionAwareCacheDecorator(cache); + } + Cache oldCache = instanceMap.putIfAbsent(name, cache); + if (oldCache != null) { + cache = oldCache; + } else { + map.setMaxSize(config.getMaxSize()); + } + return cache; + } + + @Override + public Collection getCacheNames() { + return Collections.unmodifiableSet(configMap.keySet()); + } + + +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/manager/ShutdownManager.java b/cas-framework/src/main/java/com/inscloudtech/framework/manager/ShutdownManager.java new file mode 100644 index 0000000..f014345 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/manager/ShutdownManager.java @@ -0,0 +1,40 @@ +package com.inscloudtech.framework.manager; + +import com.inscloudtech.common.utils.Threads; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import javax.annotation.PreDestroy; +import java.util.concurrent.ScheduledExecutorService; + +/** + * 确保应用退出时能关闭后台线程 + * + * @author inscloudtech + */ +@Slf4j +@Component +public class ShutdownManager { + + @Autowired + @Qualifier("scheduledExecutorService") + private ScheduledExecutorService scheduledExecutorService; + + @PreDestroy + public void destroy() { + shutdownAsyncManager(); + } + /** + * 停止异步执行任务 + */ + private void shutdownAsyncManager() { + try { + log.info("====关闭后台任务任务线程池===="); + Threads.shutdownAndAwaitTermination(scheduledExecutorService); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/satoken/dao/PlusSaTokenDao.java b/cas-framework/src/main/java/com/inscloudtech/framework/satoken/dao/PlusSaTokenDao.java new file mode 100644 index 0000000..fb33884 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/satoken/dao/PlusSaTokenDao.java @@ -0,0 +1,163 @@ +package com.inscloudtech.framework.satoken.dao; + +import cn.dev33.satoken.dao.SaTokenDao; +import cn.dev33.satoken.util.SaFoxUtil; +import com.inscloudtech.common.utils.redis.RedisUtils; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Sa-Token持久层接口(使用框架自带RedisUtils实现 协议统一) + * + * @author inscloudtech + */ +public class PlusSaTokenDao implements SaTokenDao { + /** + * 获取Value,如无返空 + */ + @Override + public String get(String key) { + return RedisUtils.getCacheObject(key); + } + /** + * 写入Value,并设定存活时间 (单位: 秒) + */ + @Override + public void set(String key, String value, long timeout) { + if (timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } + // 判断是否为永不过期 + if (timeout == SaTokenDao.NEVER_EXPIRE) { + RedisUtils.setCacheObject(key, value); + } else { + RedisUtils.setCacheObject(key, value, Duration.ofSeconds(timeout)); + } + } + /** + * 修修改指定key-value键值对 (过期时间不变) + */ + @Override + public void update(String key, String value) { + long expire = getTimeout(key); + // -2 = 无此键 + if (expire == SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } + this.set(key, value, expire); + } + /** + * 删除Value + */ + @Override + public void delete(String key) { + RedisUtils.deleteObject(key); + } + /** + * 获取Value的剩余存活时间 (单位: 秒) + */ + @Override + public long getTimeout(String key) { + long timeout = RedisUtils.getTimeToLive(key); + return timeout < 0 ? timeout : timeout / 1000; + } + /** + * 修改Value的剩余存活时间 (单位: 秒) + */ + @Override + public void updateTimeout(String key, long timeout) { + // 判断是否想要设置为永久 + if (timeout == SaTokenDao.NEVER_EXPIRE) { + long expire = getTimeout(key); + if (expire == SaTokenDao.NEVER_EXPIRE) { + // 如果其已经被设置为永久,则不作任何处理 + } else { + // 如果尚未被设置为永久,那么再次set一次 + this.set(key, this.get(key), timeout); + } + return; + } + RedisUtils.expire(key, Duration.ofSeconds(timeout)); + } + + /** + * 获取Object,如无返空 + */ + @Override + public Object getObject(String key) { + return RedisUtils.getCacheObject(key); + } + /** + * 写入Object,并设定存活时间 (单位: 秒) + */ + @Override + public void setObject(String key, Object object, long timeout) { + if (timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } + // 判断是否为永不过期 + if (timeout == SaTokenDao.NEVER_EXPIRE) { + RedisUtils.setCacheObject(key, object); + } else { + RedisUtils.setCacheObject(key, object, Duration.ofSeconds(timeout)); + } + } + /** + * 更新Object (过期时间不变) + */ + @Override + public void updateObject(String key, Object object) { + long expire = getObjectTimeout(key); + // -2 = 无此键 + if (expire == SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } + this.setObject(key, object, expire); + } + /** + * 删除Object + */ + @Override + public void deleteObject(String key) { + RedisUtils.deleteObject(key); + } + /** + * 获取Object的剩余存活时间 (单位: 秒) + */ + @Override + public long getObjectTimeout(String key) { + long timeout = RedisUtils.getTimeToLive(key); + return timeout < 0 ? timeout : timeout / 1000; + } + /** + * 修改Object的剩余存活时间 (单位: 秒) + */ + @Override + public void updateObjectTimeout(String key, long timeout) { + // 判断是否想要设置为永久 + if (timeout == SaTokenDao.NEVER_EXPIRE) { + long expire = getObjectTimeout(key); + if (expire == SaTokenDao.NEVER_EXPIRE) { + // 如果其已经被设置为永久,则不作任何处理 + } else { + // 如果尚未被设置为永久,那么再次set一次 + this.setObject(key, this.getObject(key), timeout); + } + return; + } + RedisUtils.expire(key, Duration.ofSeconds(timeout)); + } + + /** + * 搜索数据 + */ + @Override + public List searchData(String prefix, String keyword, int start, int size, boolean sortType) { + Collection keys = RedisUtils.keys(prefix + "*" + keyword + "*"); + List list = new ArrayList<>(keys); + return SaFoxUtil.searchList(list, start, size, sortType); + } +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/satoken/service/SaPermissionImpl.java b/cas-framework/src/main/java/com/inscloudtech/framework/satoken/service/SaPermissionImpl.java new file mode 100644 index 0000000..60d7684 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/satoken/service/SaPermissionImpl.java @@ -0,0 +1,45 @@ +package com.inscloudtech.framework.satoken.service; + +import cn.dev33.satoken.stp.StpInterface; +import com.inscloudtech.common.core.domain.model.LoginUser; +import com.inscloudtech.common.enums.UserType; +import com.inscloudtech.common.helper.LoginHelper; + +import java.util.ArrayList; +import java.util.List; + +/** + * sa-token 权限管理实现类 + * + * @author inscloudtech + */ +public class SaPermissionImpl implements StpInterface { + /** + * 获取菜单权限列表 + */ + @Override + public List getPermissionList(Object loginId, String loginType) { + LoginUser loginUser = LoginHelper.getLoginUser(); + UserType userType = UserType.getUserType(loginUser.getUserType()); + if (userType == UserType.SYS_USER) { + return new ArrayList<>(loginUser.getMenuPermission()); + } else if (userType == UserType.APP_USER) { + // 其他端 自行根据业务编写 + } + return new ArrayList<>(); + } + /** + * 获取角色权限列表 + */ + @Override + public List getRoleList(Object loginId, String loginType) { + LoginUser loginUser = LoginHelper.getLoginUser(); + UserType userType = UserType.getUserType(loginUser.getUserType()); + if (userType == UserType.SYS_USER) { + return new ArrayList<>(loginUser.getRolePermission()); + } else if (userType == UserType.APP_USER) { + // 其他端 自行根据业务编写 + } + return new ArrayList<>(); + } +} diff --git a/cas-framework/src/main/java/com/inscloudtech/framework/web/exception/GlobalExceptionHandler.java b/cas-framework/src/main/java/com/inscloudtech/framework/web/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..a9b7f14 --- /dev/null +++ b/cas-framework/src/main/java/com/inscloudtech/framework/web/exception/GlobalExceptionHandler.java @@ -0,0 +1,155 @@ +package com.inscloudtech.framework.web.exception; + +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.exception.NotPermissionException; +import cn.dev33.satoken.exception.NotRoleException; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.http.HttpStatus; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.exception.DemoModeException; +import com.inscloudtech.common.exception.ServiceException; +import com.inscloudtech.common.utils.StreamUtils; +import lombok.extern.slf4j.Slf4j; +import org.mybatis.spring.MyBatisSystemException; +import org.springframework.context.support.DefaultMessageSourceResolvable; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.validation.BindException; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; + +/** + * 全局异常处理器 + * + * @author inscloudtech + */ +@Slf4j +@RestControllerAdvice +public class GlobalExceptionHandler { + /** + * 权限码异常 + */ + @ExceptionHandler(NotPermissionException.class) + public R handleNotPermissionException(NotPermissionException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',权限码校验失败'{}'", requestURI, e.getMessage()); + return R.fail(HttpStatus.HTTP_FORBIDDEN, "没有访问权限,请联系管理员授权"); + } + /** + * 角色权限异常 + */ + @ExceptionHandler(NotRoleException.class) + public R handleNotRoleException(NotRoleException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',角色权限校验失败'{}'", requestURI, e.getMessage()); + return R.fail(HttpStatus.HTTP_FORBIDDEN, "没有访问权限,请联系管理员授权"); + } + /** + * 认证失败 + */ + @ExceptionHandler(NotLoginException.class) + public R handleNotLoginException(NotLoginException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',认证失败'{}',无法访问系统资源", requestURI, e.getMessage()); + return R.fail(HttpStatus.HTTP_UNAUTHORIZED, "认证失败,无法访问系统资源"); + } + /** + * 请求方式不支持 + */ + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + public R handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e, + HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod()); + return R.fail(e.getMessage()); + } + /** + * 主键或UNIQUE索引,数据重复异常 + */ + @ExceptionHandler(DuplicateKeyException.class) + public R handleDuplicateKeyException(DuplicateKeyException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',数据库中已存在记录'{}'", requestURI, e.getMessage()); + return R.fail("数据库中已存在该记录,请联系管理员确认"); + } + /** + * Mybatis系统异常 通用处理 + */ + @ExceptionHandler(MyBatisSystemException.class) + public R handleCannotFindDataSourceException(MyBatisSystemException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + String message = e.getMessage(); + if (message.contains("CannotFindDataSourceException")) { + log.error("请求地址'{}', 未找到数据源", requestURI); + return R.fail("未找到数据源,请联系管理员确认"); + } + log.error("请求地址'{}', Mybatis系统异常", requestURI, e); + return R.fail(message); + } + /** + * 业务异常 + */ + @ExceptionHandler(ServiceException.class) + public R handleServiceException(ServiceException e, HttpServletRequest request) { + log.error(e.getMessage(), e); + Integer code = e.getCode(); + return ObjectUtil.isNotNull(code) ? R.fail(code, e.getMessage()) : R.fail(e.getMessage()); + } + /** + * 拦截未知的运行时异常 + */ + @ExceptionHandler(RuntimeException.class) + public R handleRuntimeException(RuntimeException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',发生未知异常.", requestURI, e); + return R.fail(e.getMessage()); + } + /** + * 系统异常 + */ + @ExceptionHandler(Exception.class) + public R handleException(Exception e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',发生系统异常.", requestURI, e); + return R.fail(e.getMessage()); + } + /** + * 自定义验证异常 + */ + @ExceptionHandler(BindException.class) + public R handleBindException(BindException e) { + log.error(e.getMessage(), e); + String message = StreamUtils.join(e.getAllErrors(), DefaultMessageSourceResolvable::getDefaultMessage, ", "); + return R.fail(message); + } + /** + * 自定义验证异常 + */ + @ExceptionHandler(ConstraintViolationException.class) + public R constraintViolationException(ConstraintViolationException e) { + log.error(e.getMessage(), e); + String message = StreamUtils.join(e.getConstraintViolations(), ConstraintViolation::getMessage, ", "); + return R.fail(message); + } + /** + * 自定义验证异常 + */ + @ExceptionHandler(MethodArgumentNotValidException.class) + public R handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { + log.error(e.getMessage(), e); + String message = e.getBindingResult().getFieldError().getDefaultMessage(); + return R.fail(message); + } + /** + * 演示模式异常 + */ + @ExceptionHandler(DemoModeException.class) + public R handleDemoModeException(DemoModeException e) { + return R.fail("演示模式,不允许操作"); + } +} diff --git a/cas-generator/pom.xml b/cas-generator/pom.xml new file mode 100644 index 0000000..a4d2027 --- /dev/null +++ b/cas-generator/pom.xml @@ -0,0 +1,34 @@ + + + + cas-server + com.inscloudtech + 4.7.0 + + 4.0.0 + + cas-generator + + + generator代码生成 + + + + + + + org.apache.velocity + velocity-engine-core + + + + + com.inscloudtech + cas-common + + + + + diff --git a/cas-generator/src/main/java/com/inscloudtech/generator/config/GenConfig.java b/cas-generator/src/main/java/com/inscloudtech/generator/config/GenConfig.java new file mode 100644 index 0000000..f498264 --- /dev/null +++ b/cas-generator/src/main/java/com/inscloudtech/generator/config/GenConfig.java @@ -0,0 +1,69 @@ +package com.inscloudtech.generator.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; + +/** + * 读取代码生成相关配置 + * + * @author inscloudtech + */ +@Component +@ConfigurationProperties(prefix = "gen") +@PropertySource(value = {"classpath:generator.yml"}, encoding = "UTF-8") +public class GenConfig { + /** + * 作者 + */ + public static String author; + /** + * 生成包路径 + */ + public static String packageName; + /** + * 自动去除表前缀,默认是false + */ + public static boolean autoRemovePre; + /** + * 表前缀(类名不会包含表前缀) + */ + public static String tablePrefix; + + public static String getAuthor() { + return author; + } + + @Value("${author}") + public void setAuthor(String author) { + GenConfig.author = author; + } + + public static String getPackageName() { + return packageName; + } + + @Value("${packageName}") + public void setPackageName(String packageName) { + GenConfig.packageName = packageName; + } + + public static boolean getAutoRemovePre() { + return autoRemovePre; + } + + @Value("${autoRemovePre}") + public void setAutoRemovePre(boolean autoRemovePre) { + GenConfig.autoRemovePre = autoRemovePre; + } + + public static String getTablePrefix() { + return tablePrefix; + } + + @Value("${tablePrefix}") + public void setTablePrefix(String tablePrefix) { + GenConfig.tablePrefix = tablePrefix; + } +} diff --git a/cas-generator/src/main/java/com/inscloudtech/generator/controller/GenController.java b/cas-generator/src/main/java/com/inscloudtech/generator/controller/GenController.java new file mode 100644 index 0000000..2b40a28 --- /dev/null +++ b/cas-generator/src/main/java/com/inscloudtech/generator/controller/GenController.java @@ -0,0 +1,194 @@ +package com.inscloudtech.generator.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.io.IoUtil; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.generator.domain.GenTable; +import com.inscloudtech.generator.domain.GenTableColumn; +import com.inscloudtech.generator.service.IGenTableService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 代码生成 操作处理 + * + * @author inscloudtech + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/tool/gen") +public class GenController extends BaseController { + + private final IGenTableService genTableService; + /** + * 查询代码生成列表 + */ + @SaCheckPermission("tool:gen:list") + @GetMapping("/list") + public TableDataInfo genList(GenTable genTable, PageQuery pageQuery) { + return genTableService.selectPageGenTableList(genTable, pageQuery); + } + /** + * 修改代码生成业务 + * + * @param tableId 表ID + */ + @SaCheckPermission("tool:gen:query") + @GetMapping(value = "/{tableId}") + public R> getInfo(@PathVariable Long tableId) { + GenTable table = genTableService.selectGenTableById(tableId); + List tables = genTableService.selectGenTableAll(); + List list = genTableService.selectGenTableColumnListByTableId(tableId); + Map map = new HashMap(); + map.put("info", table); + map.put("rows", list); + map.put("tables", tables); + return R.ok(map); + } + /** + * 查询数据库列表 + */ + @SaCheckPermission("tool:gen:list") + @GetMapping("/db/list") + public TableDataInfo dataList(GenTable genTable, PageQuery pageQuery) { + return genTableService.selectPageDbTableList(genTable, pageQuery); + } + /** + * 查询数据表字段列表 + * + * @param tableId 表ID + */ + @SaCheckPermission("tool:gen:list") + @GetMapping(value = "/column/{tableId}") + public TableDataInfo columnList(Long tableId) { + TableDataInfo dataInfo = new TableDataInfo<>(); + List list = genTableService.selectGenTableColumnListByTableId(tableId); + dataInfo.setRows(list); + dataInfo.setTotal(list.size()); + return dataInfo; + } + /** + * 导入表结构(保存) + * + * @param tables 表名串 + */ + @SaCheckPermission("tool:gen:import") +// @Log(title = "代码生成", businessType = BusinessType.IMPORT) + @PostMapping("/importTable") + public R importTableSave(String tables) { + String[] tableNames = Convert.toStrArray(tables); + // 查询表信息 + List tableList = genTableService.selectDbTableListByNames(tableNames); + genTableService.importGenTable(tableList); + return R.ok(); + } + /** + * 修改保存代码生成业务 + */ + @SaCheckPermission("tool:gen:edit") + @Log(title = "代码生成", businessType = BusinessType.UPDATE) + @PutMapping + public R editSave(@Validated @RequestBody GenTable genTable) { + genTableService.validateEdit(genTable); + genTableService.updateGenTable(genTable); + return R.ok(); + } + /** + * 删除代码生成 + * + * @param tableIds 表ID串 + */ + @SaCheckPermission("tool:gen:remove") + @Log(title = "代码生成", businessType = BusinessType.DELETE) + @DeleteMapping("/{tableIds}") + public R remove(@PathVariable Long[] tableIds) { + genTableService.deleteGenTableByIds(tableIds); + return R.ok(); + } + /** + * 预览代码 + * + * @param tableId 表ID + */ + @SaCheckPermission("tool:gen:preview") + @GetMapping("/preview/{tableId}") + public R> preview(@PathVariable("tableId") Long tableId) throws IOException { + Map dataMap = genTableService.previewCode(tableId); + return R.ok(dataMap); + } + /** + * 生成代码(下载方式) + * + * @param tableName 表名 + */ + @SaCheckPermission("tool:gen:code") + @Log(title = "代码生成", businessType = BusinessType.GENCODE) + @GetMapping("/download/{tableName}") + public void download(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException { + byte[] data = genTableService.downloadCode(tableName); + genCode(response, data); + } + /** + * 生成代码(自定义路径) + * + * @param tableName 表名 + */ + @SaCheckPermission("tool:gen:code") + @Log(title = "代码生成", businessType = BusinessType.GENCODE) + @GetMapping("/genCode/{tableName}") + public R genCode(@PathVariable("tableName") String tableName) { + genTableService.generatorCode(tableName); + return R.ok(); + } + /** + * 同步数据库 + * + * @param tableName 表名 + */ + @SaCheckPermission("tool:gen:edit") + @Log(title = "代码生成", businessType = BusinessType.UPDATE) + @GetMapping("/synchDb/{tableName}") + public R synchDb(@PathVariable("tableName") String tableName) { + genTableService.synchDb(tableName); + return R.ok(); + } + /** + * 批量生成代码 + * + * @param tables 表名串 + */ + @SaCheckPermission("tool:gen:code") + @Log(title = "代码生成", businessType = BusinessType.GENCODE) + @GetMapping("/batchGenCode") + public void batchGenCode(HttpServletResponse response, String tables) throws IOException { + String[] tableNames = Convert.toStrArray(tables); + byte[] data = genTableService.downloadCode(tableNames); + genCode(response, data); + } + /** + * 生成zip文件 + */ + private void genCode(HttpServletResponse response, byte[] data) throws IOException { + response.reset(); + response.addHeader("Access-Control-Allow-Origin", "*"); + response.addHeader("Access-Control-Expose-Headers", "Content-Disposition"); + response.setHeader("Content-Disposition", "attachment; filename=\"inscloudtech.zip\""); + response.addHeader("Content-Length", "" + data.length); + response.setContentType("application/octet-stream; charset=UTF-8"); + IoUtil.write(response.getOutputStream(), false, data); + } +} diff --git a/cas-generator/src/main/java/com/inscloudtech/generator/domain/GenTable.java b/cas-generator/src/main/java/com/inscloudtech/generator/domain/GenTable.java new file mode 100644 index 0000000..3448a0c --- /dev/null +++ b/cas-generator/src/main/java/com/inscloudtech/generator/domain/GenTable.java @@ -0,0 +1,182 @@ +package com.inscloudtech.generator.domain; + +import com.baomidou.mybatisplus.annotation.*; +import com.inscloudtech.common.constant.GenConstants; +import com.inscloudtech.common.core.domain.BaseEntity; +import com.inscloudtech.common.utils.StringUtils; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.commons.lang3.ArrayUtils; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import java.util.List; + +/** + * 业务表 gen_table + * + * @author inscloudtech + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("gen_table") +public class GenTable extends BaseEntity { + /** + * 编号 + */ + @TableId(value = "table_id") + private Long tableId; + /** + * 表名称 + */ + @NotBlank(message = "表名称不能为空") + private String tableName; + /** + * 表描述 + */ + @NotBlank(message = "表描述不能为空") + private String tableComment; + /** + * 关联父表的表名 + */ + private String subTableName; + /** + * 本表关联父表的外键名 + */ + private String subTableFkName; + /** + * 实体类名称(首字母大写) + */ + @NotBlank(message = "实体类名称不能为空") + private String className; + /** + * 使用的模板(crud单表操作 tree树表操作 sub主子表操作) + */ + private String tplCategory; + /** + * 生成包路径 + */ + @NotBlank(message = "生成包路径不能为空") + private String packageName; + /** + * 生成模块名 + */ + @NotBlank(message = "生成模块名不能为空") + private String moduleName; + /** + * 生成业务名 + */ + @NotBlank(message = "生成业务名不能为空") + private String businessName; + /** + * 生成功能名 + */ + @NotBlank(message = "生成功能名不能为空") + private String functionName; + /** + * 生成作者 + */ + @NotBlank(message = "作者不能为空") + private String functionAuthor; + /** + * 生成代码方式(0zip压缩包 1自定义路径) + */ + private String genType; + /** + * 生成路径(不填默认项目路径) + */ + @TableField(updateStrategy = FieldStrategy.NOT_EMPTY) + private String genPath; + /** + * 主键信息 + */ + @TableField(exist = false) + private GenTableColumn pkColumn; + /** + * 子表信息 + */ + @TableField(exist = false) + private GenTable subTable; + /** + * 表列信息 + */ + @Valid + @TableField(exist = false) + private List columns; + /** + * 其它生成选项 + */ + private String options; + /** + * 备注 + */ + private String remark; + /** + * 树编码字段 + */ + @TableField(exist = false) + private String treeCode; + /** + * 树父编码字段 + */ + @TableField(exist = false) + private String treeParentCode; + /** + * 树名称字段 + */ + @TableField(exist = false) + private String treeName; + + /* + * 菜单id列表 + */ + @TableField(exist = false) + private List menuIds; + /** + * 上级菜单ID字段 + */ + @TableField(exist = false) + private String parentMenuId; + /** + * 上级菜单名称字段 + */ + @TableField(exist = false) + private String parentMenuName; + + public boolean isSub() { + return isSub(this.tplCategory); + } + + public static boolean isSub(String tplCategory) { + return tplCategory != null && StringUtils.equals(GenConstants.TPL_SUB, tplCategory); + } + + public boolean isTree() { + return isTree(this.tplCategory); + } + + public static boolean isTree(String tplCategory) { + return tplCategory != null && StringUtils.equals(GenConstants.TPL_TREE, tplCategory); + } + + public boolean isCrud() { + return isCrud(this.tplCategory); + } + + public static boolean isCrud(String tplCategory) { + return tplCategory != null && StringUtils.equals(GenConstants.TPL_CRUD, tplCategory); + } + + public boolean isSuperColumn(String javaField) { + return isSuperColumn(this.tplCategory, javaField); + } + + public static boolean isSuperColumn(String tplCategory, String javaField) { + if (isTree(tplCategory)) { + return StringUtils.equalsAnyIgnoreCase(javaField, + ArrayUtils.addAll(GenConstants.TREE_ENTITY, GenConstants.BASE_ENTITY)); + } + return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY); + } +} diff --git a/cas-generator/src/main/java/com/inscloudtech/generator/domain/GenTableColumn.java b/cas-generator/src/main/java/com/inscloudtech/generator/domain/GenTableColumn.java new file mode 100644 index 0000000..83f6e1c --- /dev/null +++ b/cas-generator/src/main/java/com/inscloudtech/generator/domain/GenTableColumn.java @@ -0,0 +1,205 @@ +package com.inscloudtech.generator.domain; + +import com.baomidou.mybatisplus.annotation.FieldStrategy; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.inscloudtech.common.core.domain.BaseEntity; +import com.inscloudtech.common.utils.StringUtils; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.ibatis.type.JdbcType; + +import javax.validation.constraints.NotBlank; + +/** + * 代码生成业务字段表 gen_table_column + * + * @author inscloudtech + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("gen_table_column") +public class GenTableColumn extends BaseEntity { + /** + * 编号 + */ + @TableId(value = "column_id") + private Long columnId; + /** + * 归属表编号 + */ + private Long tableId; + /** + * 列名称 + */ + private String columnName; + /** + * 列描述 + */ + @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + private String columnComment; + /** + * 列类型 + */ + private String columnType; + /** + * JAVA类型 + */ + private String javaType; + /** + * JAVA字段名 + */ + @NotBlank(message = "Java属性不能为空") + private String javaField; + /** + * 是否主键(1是) + */ + @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + private String isPk; + /** + * 是否自增(1是) + */ + @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + private String isIncrement; + /** + * 是否必填(1是) + */ + @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + private String isRequired; + /** + * 是否为插入字段(1是) + */ + @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + private String isInsert; + /** + * 是否编辑字段(1是) + */ + @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + private String isEdit; + /** + * 是否列表字段(1是) + */ + @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + private String isList; + /** + * 是否查询字段(1是) + */ + @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + private String isQuery; + /** + * 查询方式(EQ等于、NE不等于、GT大于、LT小于、LIKE模糊、BETWEEN范围) + */ + private String queryType; + /** + * 显示类型(input文本框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件、image图片上传控件、upload文件上传控件、editor富文本控件) + */ + private String htmlType; + /** + * 字典类型 + */ + private String dictType; + /** + * 排序 + */ + private Integer sort; + + public String getCapJavaField() { + return StringUtils.capitalize(javaField); + } + + public boolean isPk() { + return isPk(this.isPk); + } + + public boolean isPk(String isPk) { + return isPk != null && StringUtils.equals("1", isPk); + } + + public boolean isIncrement() { + return isIncrement(this.isIncrement); + } + + public boolean isIncrement(String isIncrement) { + return isIncrement != null && StringUtils.equals("1", isIncrement); + } + + public boolean isRequired() { + return isRequired(this.isRequired); + } + + public boolean isRequired(String isRequired) { + return isRequired != null && StringUtils.equals("1", isRequired); + } + + public boolean isInsert() { + return isInsert(this.isInsert); + } + + public boolean isInsert(String isInsert) { + return isInsert != null && StringUtils.equals("1", isInsert); + } + + public boolean isEdit() { + return isInsert(this.isEdit); + } + + public boolean isEdit(String isEdit) { + return isEdit != null && StringUtils.equals("1", isEdit); + } + + public boolean isList() { + return isList(this.isList); + } + + public boolean isList(String isList) { + return isList != null && StringUtils.equals("1", isList); + } + + public boolean isQuery() { + return isQuery(this.isQuery); + } + + public boolean isQuery(String isQuery) { + return isQuery != null && StringUtils.equals("1", isQuery); + } + + public boolean isSuperColumn() { + return isSuperColumn(this.javaField); + } + + public static boolean isSuperColumn(String javaField) { + return StringUtils.equalsAnyIgnoreCase(javaField, + // BaseEntity + "createBy", "createTime", "updateBy", "updateTime", + // TreeEntity + "parentName", "parentId"); + } + + public boolean isUsableColumn() { + return isUsableColumn(javaField); + } + + public static boolean isUsableColumn(String javaField) { + // isSuperColumn()中的名单用于避免生成多余Domain属性,若某些属性在生成页面时需要用到不能忽略,则放在此处白名单 + return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum", "remark"); + } + + public String readConverterExp() { + String remarks = StringUtils.substringBetween(this.columnComment, "(", ")"); + StringBuffer sb = new StringBuffer(); + if (StringUtils.isNotEmpty(remarks)) { + for (String value : remarks.split(" ")) { + if (StringUtils.isNotEmpty(value)) { + Object startStr = value.subSequence(0, 1); + String endStr = value.substring(1); + sb.append(StringUtils.EMPTY).append(startStr).append("=").append(endStr).append(StringUtils.SEPARATOR); + } + } + return sb.deleteCharAt(sb.length() - 1).toString(); + } else { + return this.columnComment; + } + } +} diff --git a/cas-generator/src/main/java/com/inscloudtech/generator/mapper/GenTableColumnMapper.java b/cas-generator/src/main/java/com/inscloudtech/generator/mapper/GenTableColumnMapper.java new file mode 100644 index 0000000..297ff9a --- /dev/null +++ b/cas-generator/src/main/java/com/inscloudtech/generator/mapper/GenTableColumnMapper.java @@ -0,0 +1,23 @@ +package com.inscloudtech.generator.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import com.inscloudtech.generator.domain.GenTableColumn; + +import java.util.List; + +/** + * 业务字段 数据层 + * + * @author inscloudtech + */ +@InterceptorIgnore(dataPermission = "true") +public interface GenTableColumnMapper extends BaseMapperPlus { /** + * 根据表名称查询列信息 + * + * @param tableName 表名称 + * @return 列信息 + */ + List selectDbTableColumnsByName(String tableName); + +} diff --git a/cas-generator/src/main/java/com/inscloudtech/generator/mapper/GenTableMapper.java b/cas-generator/src/main/java/com/inscloudtech/generator/mapper/GenTableMapper.java new file mode 100644 index 0000000..53b43f1 --- /dev/null +++ b/cas-generator/src/main/java/com/inscloudtech/generator/mapper/GenTableMapper.java @@ -0,0 +1,53 @@ +package com.inscloudtech.generator.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import com.inscloudtech.generator.domain.GenTable; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 业务 数据层 + * + * @author inscloudtech + */ +@InterceptorIgnore(dataPermission = "true") +public interface GenTableMapper extends BaseMapperPlus { + /** + * 查询据库列表 + * + * @param genTable 查询条件 + * @return 数据库表集合 + */ + Page selectPageDbTableList(@Param("page") Page page, @Param("genTable") GenTable genTable); + /** + * 查询据库列表 + * + * @param tableNames 表名称组 + * @return 数据库表集合 + */ + List selectDbTableListByNames(String[] tableNames); + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + List selectGenTableAll(); + /** + * 查询表ID业务信息 + * + * @param id 业务ID + * @return 业务信息 + */ + GenTable selectGenTableById(Long id); + /** + * 查询表名称业务信息 + * + * @param tableName 表名称 + * @return 业务信息 + */ + GenTable selectGenTableByName(String tableName); + +} diff --git a/cas-generator/src/main/java/com/inscloudtech/generator/service/GenTableServiceImpl.java b/cas-generator/src/main/java/com/inscloudtech/generator/service/GenTableServiceImpl.java new file mode 100644 index 0000000..34e29eb --- /dev/null +++ b/cas-generator/src/main/java/com/inscloudtech/generator/service/GenTableServiceImpl.java @@ -0,0 +1,478 @@ +package com.inscloudtech.generator.service; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.constant.GenConstants; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.exception.ServiceException; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.common.utils.JsonUtils; +import com.inscloudtech.common.utils.StreamUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.file.FileUtils; +import com.inscloudtech.generator.domain.GenTable; +import com.inscloudtech.generator.domain.GenTableColumn; +import com.inscloudtech.generator.mapper.GenTableColumnMapper; +import com.inscloudtech.generator.mapper.GenTableMapper; +import com.inscloudtech.generator.util.GenUtils; +import com.inscloudtech.generator.util.VelocityInitializer; +import com.inscloudtech.generator.util.VelocityUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +/** + * 业务 服务层实现 + * + * @author inscloudtech + */ +@DS("#header.datasource") +@Slf4j +@RequiredArgsConstructor +@Service +public class GenTableServiceImpl implements IGenTableService { + + private final GenTableMapper baseMapper; + private final GenTableColumnMapper genTableColumnMapper; + private final IdentifierGenerator identifierGenerator; + /** + * 查询业务字段列表 + * + * @param tableId 业务字段编号 + * @return 业务字段集合 + */ + @Override + public List selectGenTableColumnListByTableId(Long tableId) { + return genTableColumnMapper.selectList(new LambdaQueryWrapper() + .eq(GenTableColumn::getTableId, tableId) + .orderByAsc(GenTableColumn::getSort)); + } + /** + * 查询业务信息 + * + * @param id 业务ID + * @return 业务信息 + */ + @Override + public GenTable selectGenTableById(Long id) { + GenTable genTable = baseMapper.selectGenTableById(id); + setTableFromOptions(genTable); + return genTable; + } + + @Override + public TableDataInfo selectPageGenTableList(GenTable genTable, PageQuery pageQuery) { + Page page = baseMapper.selectPage(pageQuery.build(), this.buildGenTableQueryWrapper(genTable)); + return TableDataInfo.build(page); + } + + private QueryWrapper buildGenTableQueryWrapper(GenTable genTable) { + Map params = genTable.getParams(); + QueryWrapper wrapper = Wrappers.query(); + wrapper.like(StringUtils.isNotBlank(genTable.getTableName()), "lower(table_name)", StringUtils.lowerCase(genTable.getTableName())) + .like(StringUtils.isNotBlank(genTable.getTableComment()), "lower(table_comment)", StringUtils.lowerCase(genTable.getTableComment())) + .between(params.get("beginTime") != null && params.get("endTime") != null, + "create_time", params.get("beginTime"), params.get("endTime")); + return wrapper; + } + + + @Override + public TableDataInfo selectPageDbTableList(GenTable genTable, PageQuery pageQuery) { + Page page = baseMapper.selectPageDbTableList(pageQuery.build(), genTable); + return TableDataInfo.build(page); + } + /** + * 查询据库列表 + * + * @param tableNames 表名称组 + * @return 数据库表集合 + */ + @Override + public List selectDbTableListByNames(String[] tableNames) { + return baseMapper.selectDbTableListByNames(tableNames); + } + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + @Override + public List selectGenTableAll() { + return baseMapper.selectGenTableAll(); + } + /** + * 修改业务 + * + * @param genTable 业务信息 + * @return 结果 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void updateGenTable(GenTable genTable) { + String options = JsonUtils.toJsonString(genTable.getParams()); + genTable.setOptions(options); + int row = baseMapper.updateById(genTable); + if (row > 0) { + for (GenTableColumn cenTableColumn : genTable.getColumns()) { + genTableColumnMapper.updateById(cenTableColumn); + } + } + } + /** + * 删除业务对象 + * + * @param tableIds 需要删除的数据ID + * @return 结果 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void deleteGenTableByIds(Long[] tableIds) { + List ids = Arrays.asList(tableIds); + baseMapper.deleteBatchIds(ids); + genTableColumnMapper.delete(new LambdaQueryWrapper().in(GenTableColumn::getTableId, ids)); + } + /** + * 导入表结构 + * + * @param tableList 导入表列表 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void importGenTable(List tableList) { + String operName = LoginHelper.getUsername(); + try { + for (GenTable table : tableList) { + String tableName = table.getTableName(); + GenUtils.initTable(table, operName); + table.setTableId(System.currentTimeMillis()); + int row = baseMapper.insert(table); + if (row > 0) { + // 保存列信息 + List genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName); + List saveColumns = new ArrayList<>(); + for (GenTableColumn column : genTableColumns) { + GenUtils.initColumnField(column, table); + Thread.currentThread().sleep(1); + column.setColumnId(System.currentTimeMillis()); + saveColumns.add(column); + } + if (CollUtil.isNotEmpty(saveColumns)) { + genTableColumnMapper.insertBatch(saveColumns); + } + } + } + } catch (Exception e) { + throw new ServiceException("导入失败:" + e.getMessage()); + } + } + /** + * 预览代码 + * + * @param tableId 表编号 + * @return 预览数据列表 + */ + @Override + public Map previewCode(Long tableId) { + Map dataMap = new LinkedHashMap<>(); + // 查询表信息 + GenTable table = baseMapper.selectGenTableById(tableId); + List menuIds = new ArrayList<>(); + for (int i = 0; i < 6; i++) { + menuIds.add(identifierGenerator.nextId(null).longValue()); + } + table.setMenuIds(menuIds); + // 设置主子表信息 + setSubTable(table); + // 设置主键列信息 + setPkColumn(table); + VelocityInitializer.initVelocity(); + + VelocityContext context = VelocityUtils.prepareContext(table); + + // 获取模板列表 + List templates = VelocityUtils.getTemplateList(table.getTplCategory()); + for (String template : templates) { + // 渲染模板 + StringWriter sw = new StringWriter(); + Template tpl = Velocity.getTemplate(template, Constants.UTF8); + tpl.merge(context, sw); + dataMap.put(template, sw.toString()); + } + return dataMap; + } + /** + * 生成代码(下载方式) + * + * @param tableName 表名称 + * @return 数据 + */ + @Override + public byte[] downloadCode(String tableName) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ZipOutputStream zip = new ZipOutputStream(outputStream); + generatorCode(tableName, zip); + IoUtil.close(zip); + return outputStream.toByteArray(); + } + /** + * 生成代码(自定义路径) + * + * @param tableName 表名称 + */ + @Override + public void generatorCode(String tableName) { + // 查询表信息 + GenTable table = baseMapper.selectGenTableByName(tableName); + // 设置主子表信息 + setSubTable(table); + // 设置主键列信息 + setPkColumn(table); + + VelocityInitializer.initVelocity(); + + VelocityContext context = VelocityUtils.prepareContext(table); + + // 获取模板列表 + List templates = VelocityUtils.getTemplateList(table.getTplCategory()); + for (String template : templates) { + if (!StringUtils.containsAny(template, "sql.vm", "api.js.vm", "index.vue.vm", "index-tree.vue.vm")) { + // 渲染模板 + StringWriter sw = new StringWriter(); + Template tpl = Velocity.getTemplate(template, Constants.UTF8); + tpl.merge(context, sw); + try { + String path = getGenPath(table, template); + FileUtils.writeUtf8String(sw.toString(), path); + } catch (Exception e) { + throw new ServiceException("渲染模板失败,表名:" + table.getTableName()); + } + } + } + } + /** + * 同步数据库 + * + * @param tableName 表名称 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void synchDb(String tableName) { + GenTable table = baseMapper.selectGenTableByName(tableName); + List tableColumns = table.getColumns(); + Map tableColumnMap = StreamUtils.toIdentityMap(tableColumns, GenTableColumn::getColumnName); + + List dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName); + if (CollUtil.isEmpty(dbTableColumns)) { + throw new ServiceException("同步数据失败,原表结构不存在"); + } + List dbTableColumnNames = StreamUtils.toList(dbTableColumns, GenTableColumn::getColumnName); + + List saveColumns = new ArrayList<>(); + dbTableColumns.forEach(column -> { + GenUtils.initColumnField(column, table); + if (tableColumnMap.containsKey(column.getColumnName())) { + GenTableColumn prevColumn = tableColumnMap.get(column.getColumnName()); + column.setColumnId(prevColumn.getColumnId()); + if (column.isList()) { + // 如果是列表,继续保留查询方式/字典类型选项 + column.setDictType(prevColumn.getDictType()); + column.setQueryType(prevColumn.getQueryType()); + } + if (StringUtils.isNotEmpty(prevColumn.getIsRequired()) && !column.isPk() + && (column.isInsert() || column.isEdit()) + && ((column.isUsableColumn()) || (!column.isSuperColumn()))) { + // 如果是(新增/修改&非主键/非忽略及父属性),继续保留必填/显示类型选项 + column.setIsRequired(prevColumn.getIsRequired()); + column.setHtmlType(prevColumn.getHtmlType()); + } + } + saveColumns.add(column); + }); + if (CollUtil.isNotEmpty(saveColumns)) { + genTableColumnMapper.insertOrUpdateBatch(saveColumns); + } + List delColumns = StreamUtils.filter(tableColumns, column -> !dbTableColumnNames.contains(column.getColumnName())); + if (CollUtil.isNotEmpty(delColumns)) { + List ids = StreamUtils.toList(delColumns, GenTableColumn::getColumnId); + genTableColumnMapper.deleteBatchIds(ids); + } + } + /** + * 批量生成代码(下载方式) + * + * @param tableNames 表数组 + * @return 数据 + */ + @Override + public byte[] downloadCode(String[] tableNames) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ZipOutputStream zip = new ZipOutputStream(outputStream); + for (String tableName : tableNames) { + generatorCode(tableName, zip); + } + IoUtil.close(zip); + return outputStream.toByteArray(); + } + /** + * 查询表信息并生成代码 + */ + private void generatorCode(String tableName, ZipOutputStream zip) { + // 查询表信息 + GenTable table = baseMapper.selectGenTableByName(tableName); + List menuIds = new ArrayList<>(); + for (int i = 0; i < 6; i++) { + menuIds.add(identifierGenerator.nextId(null).longValue()); + } + table.setMenuIds(menuIds); + // 设置主子表信息 + setSubTable(table); + // 设置主键列信息 + setPkColumn(table); + + VelocityInitializer.initVelocity(); + + VelocityContext context = VelocityUtils.prepareContext(table); + + // 获取模板列表 + List templates = VelocityUtils.getTemplateList(table.getTplCategory()); + for (String template : templates) { + // 渲染模板 + StringWriter sw = new StringWriter(); + Template tpl = Velocity.getTemplate(template, Constants.UTF8); + tpl.merge(context, sw); + try { + // 添加到zip + zip.putNextEntry(new ZipEntry(VelocityUtils.getFileName(template, table))); + IoUtil.write(zip, StandardCharsets.UTF_8, false, sw.toString()); + IoUtil.close(sw); + zip.flush(); + zip.closeEntry(); + } catch (IOException e) { + log.error("渲染模板失败,表名:" + table.getTableName(), e); + } + } + } + /** + * 修改保存参数校验 + * + * @param genTable 业务信息 + */ + @Override + public void validateEdit(GenTable genTable) { + if (GenConstants.TPL_TREE.equals(genTable.getTplCategory())) { + String options = JsonUtils.toJsonString(genTable.getParams()); + Dict paramsObj = JsonUtils.parseMap(options); + if (StringUtils.isEmpty(paramsObj.getStr(GenConstants.TREE_CODE))) { + throw new ServiceException("树编码字段不能为空"); + } else if (StringUtils.isEmpty(paramsObj.getStr(GenConstants.TREE_PARENT_CODE))) { + throw new ServiceException("树父编码字段不能为空"); + } else if (StringUtils.isEmpty(paramsObj.getStr(GenConstants.TREE_NAME))) { + throw new ServiceException("树名称字段不能为空"); + } else if (GenConstants.TPL_SUB.equals(genTable.getTplCategory())) { + if (StringUtils.isEmpty(genTable.getSubTableName())) { + throw new ServiceException("关联子表的表名不能为空"); + } else if (StringUtils.isEmpty(genTable.getSubTableFkName())) { + throw new ServiceException("子表关联的外键名不能为空"); + } + } + } + } + /** + * 设置主键列信息 + * + * @param table 业务表信息 + */ + public void setPkColumn(GenTable table) { + for (GenTableColumn column : table.getColumns()) { + if (column.isPk()) { + table.setPkColumn(column); + break; + } + } + if (ObjectUtil.isNull(table.getPkColumn())) { + table.setPkColumn(table.getColumns().get(0)); + } + if (GenConstants.TPL_SUB.equals(table.getTplCategory())) { + for (GenTableColumn column : table.getSubTable().getColumns()) { + if (column.isPk()) { + table.getSubTable().setPkColumn(column); + break; + } + } + if (ObjectUtil.isNull(table.getSubTable().getPkColumn())) { + table.getSubTable().setPkColumn(table.getSubTable().getColumns().get(0)); + } + } + } + /** + * 设置主子表信息 + * + * @param table 业务表信息 + */ + public void setSubTable(GenTable table) { + String subTableName = table.getSubTableName(); + if (StringUtils.isNotEmpty(subTableName)) { + table.setSubTable(baseMapper.selectGenTableByName(subTableName)); + } + } + /** + * 设置代码生成其他选项值 + * + * @param genTable 设置后的生成对象 + */ + public void setTableFromOptions(GenTable genTable) { + Dict paramsObj = JsonUtils.parseMap(genTable.getOptions()); + if (ObjectUtil.isNotNull(paramsObj)) { + String treeCode = paramsObj.getStr(GenConstants.TREE_CODE); + String treeParentCode = paramsObj.getStr(GenConstants.TREE_PARENT_CODE); + String treeName = paramsObj.getStr(GenConstants.TREE_NAME); + String parentMenuId = paramsObj.getStr(GenConstants.PARENT_MENU_ID); + String parentMenuName = paramsObj.getStr(GenConstants.PARENT_MENU_NAME); + + genTable.setTreeCode(treeCode); + genTable.setTreeParentCode(treeParentCode); + genTable.setTreeName(treeName); + genTable.setParentMenuId(parentMenuId); + genTable.setParentMenuName(parentMenuName); + } + } + /** + * 获取代码生成地址 + * + * @param table 业务表信息 + * @param template 模板文件路径 + * @return 生成地址 + */ + public static String getGenPath(GenTable table, String template) { + String genPath = table.getGenPath(); + if (StringUtils.equals(genPath, "/")) { + return System.getProperty("user.dir") + File.separator + "src" + File.separator + VelocityUtils.getFileName(template, table); + } + return genPath + File.separator + VelocityUtils.getFileName(template, table); + } +} + diff --git a/cas-generator/src/main/java/com/inscloudtech/generator/service/IGenTableService.java b/cas-generator/src/main/java/com/inscloudtech/generator/service/IGenTableService.java new file mode 100644 index 0000000..1ed9d28 --- /dev/null +++ b/cas-generator/src/main/java/com/inscloudtech/generator/service/IGenTableService.java @@ -0,0 +1,118 @@ +package com.inscloudtech.generator.service; + +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.generator.domain.GenTable; +import com.inscloudtech.generator.domain.GenTableColumn; + +import java.util.List; +import java.util.Map; + +/** + * 业务 服务层 + * + * @author inscloudtech + */ +public interface IGenTableService { + /** + * 查询业务字段列表 + * + * @param tableId 业务字段编号 + * @return 业务字段集合 + */ + List selectGenTableColumnListByTableId(Long tableId); + /** + * 查询业务列表 + * + * @param genTable 业务信息 + * @return 业务集合 + */ + TableDataInfo selectPageGenTableList(GenTable genTable, PageQuery pageQuery); + /** + * 查询据库列表 + * + * @param genTable 业务信息 + * @return 数据库表集合 + */ + TableDataInfo selectPageDbTableList(GenTable genTable, PageQuery pageQuery); + /** + * 查询据库列表 + * + * @param tableNames 表名称组 + * @return 数据库表集合 + */ + List selectDbTableListByNames(String[] tableNames); + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + List selectGenTableAll(); + /** + * 查询业务信息 + * + * @param id 业务ID + * @return 业务信息 + */ + GenTable selectGenTableById(Long id); + /** + * 修改业务 + * + * @param genTable 业务信息 + * @return 结果 + */ + void updateGenTable(GenTable genTable); + /** + * 删除业务信息 + * + * @param tableIds 需要删除的表数据ID + * @return 结果 + */ + void deleteGenTableByIds(Long[] tableIds); + /** + * 导入表结构 + * + * @param tableList 导入表列表 + */ + void importGenTable(List tableList); + /** + * 预览代码 + * + * @param tableId 表编号 + * @return 预览数据列表 + */ + Map previewCode(Long tableId); + /** + * 生成代码(下载方式) + * + * @param tableName 表名称 + * @return 数据 + */ + byte[] downloadCode(String tableName); + /** + * 生成代码(自定义路径) + * + * @param tableName 表名称 + * @return 数据 + */ + void generatorCode(String tableName); + /** + * 同步数据库 + * + * @param tableName 表名称 + */ + void synchDb(String tableName); + /** + * 批量生成代码(下载方式) + * + * @param tableNames 表数组 + * @return 数据 + */ + byte[] downloadCode(String[] tableNames); + /** + * 修改保存参数校验 + * + * @param genTable 业务信息 + */ + void validateEdit(GenTable genTable); +} diff --git a/cas-generator/src/main/java/com/inscloudtech/generator/util/GenUtils.java b/cas-generator/src/main/java/com/inscloudtech/generator/util/GenUtils.java new file mode 100644 index 0000000..9a0f369 --- /dev/null +++ b/cas-generator/src/main/java/com/inscloudtech/generator/util/GenUtils.java @@ -0,0 +1,222 @@ +package com.inscloudtech.generator.util; + +import com.inscloudtech.common.constant.GenConstants; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.generator.config.GenConfig; +import com.inscloudtech.generator.domain.GenTable; +import com.inscloudtech.generator.domain.GenTableColumn; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.RegExUtils; + +import java.util.Arrays; + +/** + * 代码生成器 工具类 + * + * @author inscloudtech + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class GenUtils { + /** + * 初始化表信息 + */ + public static void initTable(GenTable genTable, String operName) { + genTable.setClassName(convertClassName(genTable.getTableName())); + genTable.setPackageName(GenConfig.getPackageName()); + genTable.setModuleName(getModuleName(GenConfig.getPackageName())); + genTable.setBusinessName(getBusinessName(genTable.getTableName())); + genTable.setFunctionName(replaceText(genTable.getTableComment())); + genTable.setFunctionAuthor(GenConfig.getAuthor()); + genTable.setCreateBy(operName); + } + /** + * 初始化列属性字段 + */ + public static void initColumnField(GenTableColumn column, GenTable table) { + String dataType = getDbType(column.getColumnType()); + String columnName = column.getColumnName(); + column.setTableId(table.getTableId()); + column.setCreateBy(table.getCreateBy()); + // 设置java字段名 + column.setJavaField(StringUtils.toCamelCase(columnName)); + // 设置默认类型 + column.setJavaType(GenConstants.TYPE_STRING); + column.setQueryType(GenConstants.QUERY_EQ); + + if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType)) { + // 字符串长度超过500设置为文本域 + Integer columnLength = getColumnLength(column.getColumnType()); + String htmlType = columnLength >= 500 || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType) ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT; + column.setHtmlType(htmlType); + } else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType)) { + column.setJavaType(GenConstants.TYPE_DATE); + column.setHtmlType(GenConstants.HTML_DATETIME); + } else if (arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType)) { + column.setHtmlType(GenConstants.HTML_INPUT); + + // 如果是浮点型 统一用BigDecimal + String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), StringUtils.SEPARATOR); + if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0) { + column.setJavaType(GenConstants.TYPE_BIGDECIMAL); + } + // 如果是整形 + else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10) { + column.setJavaType(GenConstants.TYPE_INTEGER); + } + // 长整形 + else { + column.setJavaType(GenConstants.TYPE_LONG); + } + } + + // BO对象 默认插入勾选 + if (!arraysContains(GenConstants.COLUMNNAME_NOT_ADD, columnName) && !column.isPk()) { + column.setIsInsert(GenConstants.REQUIRE); + } + // BO对象 默认编辑勾选 + if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName)) { + column.setIsEdit(GenConstants.REQUIRE); + } + // BO对象 默认是否必填勾选 + if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName)) { + column.setIsRequired(GenConstants.REQUIRE); + } + // VO对象 默认返回勾选 + if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName)) { + column.setIsList(GenConstants.REQUIRE); + } + // BO对象 默认查询勾选 + if (!arraysContains(GenConstants.COLUMNNAME_NOT_QUERY, columnName) && !column.isPk()) { + column.setIsQuery(GenConstants.REQUIRE); + } + + // 查询字段类型 + if (StringUtils.endsWithIgnoreCase(columnName, "name")) { + column.setQueryType(GenConstants.QUERY_LIKE); + } + // 状态字段设置单选框 + if (StringUtils.endsWithIgnoreCase(columnName, "status")) { + column.setHtmlType(GenConstants.HTML_RADIO); + } + // 类型&性别字段设置下拉框 + else if (StringUtils.endsWithIgnoreCase(columnName, "type") + || StringUtils.endsWithIgnoreCase(columnName, "sex")) { + column.setHtmlType(GenConstants.HTML_SELECT); + } + // 图片字段设置图片上传控件 + else if (StringUtils.endsWithIgnoreCase(columnName, "image")) { + column.setHtmlType(GenConstants.HTML_IMAGE_UPLOAD); + } + // 文件字段设置文件上传控件 + else if (StringUtils.endsWithIgnoreCase(columnName, "file")) { + column.setHtmlType(GenConstants.HTML_FILE_UPLOAD); + } + // 内容字段设置富文本控件 + else if (StringUtils.endsWithIgnoreCase(columnName, "content")) { + column.setHtmlType(GenConstants.HTML_EDITOR); + } + } + /** + * 校验数组是否包含指定值 + * + * @param arr 数组 + * @param targetValue 值 + * @return 是否包含 + */ + public static boolean arraysContains(String[] arr, String targetValue) { + return Arrays.asList(arr).contains(targetValue); + } + /** + * 获取模块名 + * + * @param packageName 包名 + * @return 模块名 + */ + public static String getModuleName(String packageName) { + int lastIndex = packageName.lastIndexOf("."); + int nameLength = packageName.length(); + return StringUtils.substring(packageName, lastIndex + 1, nameLength); + } + /** + * 获取业务名 + * + * @param tableName 表名 + * @return 业务名 + */ + public static String getBusinessName(String tableName) { + int firstIndex = tableName.indexOf("_"); + int nameLength = tableName.length(); + String businessName = StringUtils.substring(tableName, firstIndex + 1, nameLength); + businessName = StringUtils.toCamelCase(businessName); + return businessName; + } + /** + * 表名转换成Java类名 + * + * @param tableName 表名称 + * @return 类名 + */ + public static String convertClassName(String tableName) { + boolean autoRemovePre = GenConfig.getAutoRemovePre(); + String tablePrefix = GenConfig.getTablePrefix(); + if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix)) { + String[] searchList = StringUtils.split(tablePrefix, StringUtils.SEPARATOR); + tableName = replaceFirst(tableName, searchList); + } + return StringUtils.convertToCamelCase(tableName); + } + /** + * 批量替换前缀 + * + * @param replacementm 替换值 + * @param searchList 替换列表 + * @return + */ + public static String replaceFirst(String replacementm, String[] searchList) { + String text = replacementm; + for (String searchString : searchList) { + if (replacementm.startsWith(searchString)) { + text = replacementm.replaceFirst(searchString, StringUtils.EMPTY); + break; + } + } + return text; + } + /** + * 关键字替换 + * + * @param text 需要被替换的名字 + * @return 替换后的名字 + */ + public static String replaceText(String text) { + return RegExUtils.replaceAll(text, "(?:表|若依)", ""); + } + /** + * 获取数据库类型字段 + * + * @param columnType 列类型 + * @return 截取后的列类型 + */ + public static String getDbType(String columnType) { + if (StringUtils.indexOf(columnType, '(') > 0) { + return StringUtils.substringBefore(columnType, "("); + } else { + return columnType; + } + } + /** + * 获取字段长度 + * + * @param columnType 列类型 + * @return 截取后的列类型 + */ + public static Integer getColumnLength(String columnType) { + if (StringUtils.indexOf(columnType, '(') > 0) { + String length = StringUtils.substringBetween(columnType, "(", ")"); + return Integer.valueOf(length); + } else { + return 0; + } + } +} diff --git a/cas-generator/src/main/java/com/inscloudtech/generator/util/VelocityInitializer.java b/cas-generator/src/main/java/com/inscloudtech/generator/util/VelocityInitializer.java new file mode 100644 index 0000000..6b55099 --- /dev/null +++ b/cas-generator/src/main/java/com/inscloudtech/generator/util/VelocityInitializer.java @@ -0,0 +1,34 @@ +package com.inscloudtech.generator.util; + +import com.inscloudtech.common.constant.Constants; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.velocity.app.Velocity; + +import java.util.Properties; + +/** + * VelocityEngine工厂 + * + * @author inscloudtech + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class VelocityInitializer { + /** + * 初始化vm方法 + */ + public static void initVelocity() { + Properties p = new Properties(); + try { + // 加载classpath目录下的vm文件 + p.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + // 定义字符集 + p.setProperty(Velocity.INPUT_ENCODING, Constants.UTF8); + // 初始化Velocity引擎,指定配置Properties + Velocity.init(p); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/cas-generator/src/main/java/com/inscloudtech/generator/util/VelocityUtils.java b/cas-generator/src/main/java/com/inscloudtech/generator/util/VelocityUtils.java new file mode 100644 index 0000000..061f74e --- /dev/null +++ b/cas-generator/src/main/java/com/inscloudtech/generator/util/VelocityUtils.java @@ -0,0 +1,353 @@ +package com.inscloudtech.generator.util; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.ObjectUtil; +import com.inscloudtech.common.constant.GenConstants; +import com.inscloudtech.common.helper.DataBaseHelper; +import com.inscloudtech.common.utils.DateUtils; +import com.inscloudtech.common.utils.JsonUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.generator.domain.GenTable; +import com.inscloudtech.generator.domain.GenTableColumn; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.velocity.VelocityContext; + +import java.util.*; + +/** + * 模板处理工具类 + * + * @author inscloudtech + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class VelocityUtils { + /** + * 项目空间路径 + */ + private static final String PROJECT_PATH = "main/java"; + /** + * mybatis空间路径 + */ + private static final String MYBATIS_PATH = "main/resources/mapper"; + /** + * 默认上级菜单,系统工具 + */ + private static final String DEFAULT_PARENT_MENU_ID = "3"; + /** + * 设置模板变量信息 + * + * @return 模板列表 + */ + public static VelocityContext prepareContext(GenTable genTable) { + String moduleName = genTable.getModuleName(); + String businessName = genTable.getBusinessName(); + String packageName = genTable.getPackageName(); + String tplCategory = genTable.getTplCategory(); + String functionName = genTable.getFunctionName(); + + VelocityContext velocityContext = new VelocityContext(); + velocityContext.put("tplCategory", genTable.getTplCategory()); + velocityContext.put("tableName", genTable.getTableName()); + velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "【请填写功能名称】"); + velocityContext.put("ClassName", genTable.getClassName()); + velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName())); + velocityContext.put("moduleName", genTable.getModuleName()); + velocityContext.put("BusinessName", StringUtils.capitalize(genTable.getBusinessName())); + velocityContext.put("businessName", genTable.getBusinessName()); + velocityContext.put("basePackage", getPackagePrefix(packageName)); + velocityContext.put("packageName", packageName); + velocityContext.put("author", genTable.getFunctionAuthor()); + velocityContext.put("datetime", DateUtils.getDate()); + velocityContext.put("pkColumn", genTable.getPkColumn()); + velocityContext.put("importList", getImportList(genTable)); + velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName)); + velocityContext.put("columns", genTable.getColumns()); + velocityContext.put("table", genTable); + velocityContext.put("dicts", getDicts(genTable)); + setMenuVelocityContext(velocityContext, genTable); + if (GenConstants.TPL_TREE.equals(tplCategory)) { + setTreeVelocityContext(velocityContext, genTable); + } + if (GenConstants.TPL_SUB.equals(tplCategory)) { + setSubVelocityContext(velocityContext, genTable); + } + return velocityContext; + } + + public static void setMenuVelocityContext(VelocityContext context, GenTable genTable) { + String options = genTable.getOptions(); + Dict paramsObj = JsonUtils.parseMap(options); + String parentMenuId = getParentMenuId(paramsObj); + context.put("parentMenuId", parentMenuId); + } + + public static void setTreeVelocityContext(VelocityContext context, GenTable genTable) { + String options = genTable.getOptions(); + Dict paramsObj = JsonUtils.parseMap(options); + String treeCode = getTreecode(paramsObj); + String treeParentCode = getTreeParentCode(paramsObj); + String treeName = getTreeName(paramsObj); + + context.put("treeCode", treeCode); + context.put("treeParentCode", treeParentCode); + context.put("treeName", treeName); + context.put("expandColumn", getExpandColumn(genTable)); + if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) { + context.put("tree_parent_code", paramsObj.get(GenConstants.TREE_PARENT_CODE)); + } + if (paramsObj.containsKey(GenConstants.TREE_NAME)) { + context.put("tree_name", paramsObj.get(GenConstants.TREE_NAME)); + } + } + + public static void setSubVelocityContext(VelocityContext context, GenTable genTable) { + GenTable subTable = genTable.getSubTable(); + String subTableName = genTable.getSubTableName(); + String subTableFkName = genTable.getSubTableFkName(); + String subClassName = genTable.getSubTable().getClassName(); + String subTableFkClassName = StringUtils.convertToCamelCase(subTableFkName); + + context.put("subTable", subTable); + context.put("subTableName", subTableName); + context.put("subTableFkName", subTableFkName); + context.put("subTableFkClassName", subTableFkClassName); + context.put("subTableFkclassName", StringUtils.uncapitalize(subTableFkClassName)); + context.put("subClassName", subClassName); + context.put("subclassName", StringUtils.uncapitalize(subClassName)); + context.put("subImportList", getImportList(genTable.getSubTable())); + } + /** + * 获取模板信息 + * + * @return 模板列表 + */ + public static List getTemplateList(String tplCategory) { + List templates = new ArrayList(); + templates.add("vm/java/domain.java.vm"); +// templates.add("vm/java/vo.java.vm"); +// templates.add("vm/java/bo.java.vm"); + templates.add("vm/java/mapper.java.vm"); + templates.add("vm/java/service.java.vm"); + templates.add("vm/java/serviceImpl.java.vm"); + templates.add("vm/java/controller.java.vm"); + templates.add("vm/xml/mapper.xml.vm"); + if (DataBaseHelper.isOracle()) { + templates.add("vm/sql/oracle/sql.vm"); + } else if (DataBaseHelper.isPostgerSql()) { + templates.add("vm/sql/postgres/sql.vm"); + } else if (DataBaseHelper.isSqlServer()) { + templates.add("vm/sql/sqlserver/sql.vm"); + } else { + templates.add("vm/sql/sql.vm"); + } + templates.add("vm/js/api.js.vm"); + if (GenConstants.TPL_CRUD.equals(tplCategory)) { + templates.add("vm/vue/index.vue.vm"); + } else if (GenConstants.TPL_TREE.equals(tplCategory)) { + templates.add("vm/vue/index-tree.vue.vm"); + } else if (GenConstants.TPL_SUB.equals(tplCategory)) { + templates.add("vm/vue/index.vue.vm"); + templates.add("vm/java/sub-domain.java.vm"); + } + return templates; + } + /** + * 获取文件名 + */ + public static String getFileName(String template, GenTable genTable) { + // 文件名称 + String fileName = ""; + // 包路径 + String packageName = genTable.getPackageName(); + // 模块名 + String moduleName = genTable.getModuleName(); + // 大写类名 + String className = genTable.getClassName(); + // 业务名称 + String businessName = genTable.getBusinessName(); + + String javaPath = PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/"); + String mybatisPath = MYBATIS_PATH + "/" + moduleName; + String vuePath = "vue"; + + if (template.contains("domain.java.vm")) { + fileName = StringUtils.format("{}/domain/{}.java", javaPath, className); + } +// if (template.contains("vo.java.vm")) { +// fileName = StringUtils.format("{}/domain/vo/{}Vo.java", javaPath, className); +// } +// if (template.contains("bo.java.vm")) { +// fileName = StringUtils.format("{}/domain/bo/{}Bo.java", javaPath, className); +// } + if (template.contains("sub-domain.java.vm") && StringUtils.equals(GenConstants.TPL_SUB, genTable.getTplCategory())) { + fileName = StringUtils.format("{}/domain/{}.java", javaPath, genTable.getSubTable().getClassName()); + } else if (template.contains("mapper.java.vm")) { + fileName = StringUtils.format("{}/mapper/{}Mapper.java", javaPath, className); + } else if (template.contains("service.java.vm")) { + fileName = StringUtils.format("{}/service/I{}Service.java", javaPath, className); + } else if (template.contains("serviceImpl.java.vm")) { + fileName = StringUtils.format("{}/service/impl/{}ServiceImpl.java", javaPath, className); + } else if (template.contains("controller.java.vm")) { + fileName = StringUtils.format("{}/controller/{}Controller.java", javaPath, className); + } else if (template.contains("mapper.xml.vm")) { + fileName = StringUtils.format("{}/{}Mapper.xml", mybatisPath, className); + } else if (template.contains("sql.vm")) { + fileName = businessName + "Menu.sql"; + } else if (template.contains("api.js.vm")) { + fileName = StringUtils.format("{}/api/{}/{}.js", vuePath, moduleName, businessName); + } else if (template.contains("index.vue.vm")) { + fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName); + } else if (template.contains("index-tree.vue.vm")) { + fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName); + } + return fileName; + } + /** + * 获取包前缀 + * + * @param packageName 包名称 + * @return 包前缀名称 + */ + public static String getPackagePrefix(String packageName) { + int lastIndex = packageName.lastIndexOf("."); + return StringUtils.substring(packageName, 0, lastIndex); + } + /** + * 根据列类型获取导入包 + * + * @param genTable 业务表对象 + * @return 返回需要导入的包列表 + */ + public static HashSet getImportList(GenTable genTable) { + List columns = genTable.getColumns(); + GenTable subGenTable = genTable.getSubTable(); + HashSet importList = new HashSet<>(); + if (ObjectUtil.isNotNull(subGenTable)) { + importList.add("java.util.List"); + } + for (GenTableColumn column : columns) { + if (!column.isSuperColumn() && GenConstants.TYPE_DATE.equals(column.getJavaType())) { + importList.add("java.util.Date"); + importList.add("com.fasterxml.jackson.annotation.JsonFormat"); + } else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType())) { + importList.add("java.math.BigDecimal"); + } + } + return importList; + } + /** + * 根据列类型获取字典组 + * + * @param genTable 业务表对象 + * @return 返回字典组 + */ + public static String getDicts(GenTable genTable) { + List columns = genTable.getColumns(); + Set dicts = new HashSet(); + addDicts(dicts, columns); + if (ObjectUtil.isNotNull(genTable.getSubTable())) { + List subColumns = genTable.getSubTable().getColumns(); + addDicts(dicts, subColumns); + } + return StringUtils.join(dicts, ", "); + } + /** + * 添加字典列表 + * + * @param dicts 字典列表 + * @param columns 列集合 + */ + public static void addDicts(Set dicts, List columns) { + for (GenTableColumn column : columns) { + if (!column.isSuperColumn() && StringUtils.isNotEmpty(column.getDictType()) && StringUtils.equalsAny( + column.getHtmlType(), + new String[] { GenConstants.HTML_SELECT, GenConstants.HTML_RADIO, GenConstants.HTML_CHECKBOX })) { + dicts.add("'" + column.getDictType() + "'"); + } + } + } + /** + * 获取权限前缀 + * + * @param moduleName 模块名称 + * @param businessName 业务名称 + * @return 返回权限前缀 + */ + public static String getPermissionPrefix(String moduleName, String businessName) { + return StringUtils.format("{}:{}", moduleName, businessName); + } + /** + * 获取上级菜单ID字段 + * + * @param paramsObj 生成其他选项 + * @return 上级菜单ID字段 + */ + public static String getParentMenuId(Dict paramsObj) { + if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID) + && StringUtils.isNotEmpty(paramsObj.getStr(GenConstants.PARENT_MENU_ID))) { + return paramsObj.getStr(GenConstants.PARENT_MENU_ID); + } + return DEFAULT_PARENT_MENU_ID; + } + /** + * 获取树编码 + * + * @param paramsObj 生成其他选项 + * @return 树编码 + */ + public static String getTreecode(Map paramsObj) { + if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_CODE)) { + return StringUtils.toCamelCase(Convert.toStr(paramsObj.get(GenConstants.TREE_CODE))); + } + return StringUtils.EMPTY; + } + /** + * 获取树父编码 + * + * @param paramsObj 生成其他选项 + * @return 树父编码 + */ + public static String getTreeParentCode(Dict paramsObj) { + if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) { + return StringUtils.toCamelCase(paramsObj.getStr(GenConstants.TREE_PARENT_CODE)); + } + return StringUtils.EMPTY; + } + /** + * 获取树名称 + * + * @param paramsObj 生成其他选项 + * @return 树名称 + */ + public static String getTreeName(Dict paramsObj) { + if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_NAME)) { + return StringUtils.toCamelCase(paramsObj.getStr(GenConstants.TREE_NAME)); + } + return StringUtils.EMPTY; + } + /** + * 获取需要在哪一列上面显示展开按钮 + * + * @param genTable 业务表对象 + * @return 展开按钮列序号 + */ + public static int getExpandColumn(GenTable genTable) { + String options = genTable.getOptions(); + Dict paramsObj = JsonUtils.parseMap(options); + String treeName = paramsObj.getStr(GenConstants.TREE_NAME); + int num = 0; + for (GenTableColumn column : genTable.getColumns()) { + if (column.isList()) { + num++; + String columnName = column.getColumnName(); + if (columnName.equals(treeName)) { + break; + } + } + } + return num; + } +} diff --git a/cas-generator/src/main/resources/generator.yml b/cas-generator/src/main/resources/generator.yml new file mode 100644 index 0000000..0c9883d --- /dev/null +++ b/cas-generator/src/main/resources/generator.yml @@ -0,0 +1,10 @@ +# 代码生成 +gen: + # 作者 + author: inscloudtech + # 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool + packageName: com.inscloudtech.system + # 自动去除表前缀,默认是false + autoRemovePre: false + # 表前缀(生成类名不会包含表前缀,多个用逗号分隔) + tablePrefix: sys_ diff --git a/cas-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml b/cas-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml new file mode 100644 index 0000000..d923522 --- /dev/null +++ b/cas-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cas-generator/src/main/resources/mapper/generator/GenTableMapper.xml b/cas-generator/src/main/resources/mapper/generator/GenTableMapper.xml new file mode 100644 index 0000000..c4b03fe --- /dev/null +++ b/cas-generator/src/main/resources/mapper/generator/GenTableMapper.xml @@ -0,0 +1,259 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cas-generator/src/main/resources/mapper/package-info.md b/cas-generator/src/main/resources/mapper/package-info.md new file mode 100644 index 0000000..c938b1e --- /dev/null +++ b/cas-generator/src/main/resources/mapper/package-info.md @@ -0,0 +1,3 @@ +java包使用 `.` 分割 resource 目录使用 `/` 分割 +
+此文件目的 防止文件夹粘连找不到 `xml` 文件 \ No newline at end of file diff --git a/cas-generator/src/main/resources/vm/java/bo.java.vm b/cas-generator/src/main/resources/vm/java/bo.java.vm new file mode 100644 index 0000000..3e0c7dc --- /dev/null +++ b/cas-generator/src/main/resources/vm/java/bo.java.vm @@ -0,0 +1,58 @@ +package ${packageName}.domain.bo; + +import com.inscloudtech.common.core.validate.AddGroup; +import com.inscloudtech.common.core.validate.EditGroup; +import lombok.Data; +import lombok.EqualsAndHashCode; +import javax.validation.constraints.*; + +#foreach ($import in $importList) +import ${import}; +#end +#if($table.crud || $table.sub) +import com.inscloudtech.common.core.domain.BaseEntity; +#elseif($table.tree) +import com.inscloudtech.common.core.domain.TreeEntity; +#end + +/** + * ${functionName}业务对象 ${tableName} + * + * @author ${author} + * @date ${datetime} + */ +#if($table.crud || $table.sub) +#set($Entity="BaseEntity") +#elseif($table.tree) +#set($Entity="TreeEntity<${ClassName}Bo>") +#end + +@Data +@EqualsAndHashCode(callSuper = true) +public class ${ClassName}Bo extends ${Entity} { + +#foreach ($column in $columns) +#if(!$table.isSuperColumn($column.javaField) && ($column.query || $column.insert || $column.edit)) + /** + * $column.columnComment + */ +#if($column.insert && $column.edit) +#set($Group="AddGroup.class, EditGroup.class") +#elseif($column.insert) +#set($Group="AddGroup.class") +#elseif($column.edit) +#set($Group="EditGroup.class") +#end +#if($column.required) +#if($column.javaType == 'String') + @NotBlank(message = "$column.columnComment不能为空", groups = { $Group }) +#else + @NotNull(message = "$column.columnComment不能为空", groups = { $Group }) +#end +#end + private $column.javaType $column.javaField; + +#end +#end + +} diff --git a/cas-generator/src/main/resources/vm/java/controller.java.vm b/cas-generator/src/main/resources/vm/java/controller.java.vm new file mode 100644 index 0000000..e5a4600 --- /dev/null +++ b/cas-generator/src/main/resources/vm/java/controller.java.vm @@ -0,0 +1,115 @@ +package ${packageName}.controller; + +import java.util.List; +import java.util.Arrays; + +import lombok.RequiredArgsConstructor; +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import com.inscloudtech.common.annotation.RepeatSubmit; +import com.inscloudtech.common.annotation.Log; +import com.inscloudtech.common.core.controller.BaseController; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.R; +import com.inscloudtech.common.core.validate.AddGroup; +import com.inscloudtech.common.core.validate.EditGroup; +import com.inscloudtech.common.enums.BusinessType; +import com.inscloudtech.common.utils.poi.ExcelUtil; +import ${packageName}.domain.${ClassName}; +import ${packageName}.service.I${ClassName}Service; +#if($table.crud || $table.sub) +import com.inscloudtech.common.core.page.TableDataInfo; +#elseif($table.tree) +#end + +/** + * ${functionName} + * + * @author ${author} + * @date ${datetime} + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/${moduleName}/${businessName}") +public class ${ClassName}Controller extends BaseController { + + private final I${ClassName}Service i${ClassName}Service; + + /** + * 查询${functionName}列表 + */ + @SaCheckPermission("${permissionPrefix}:list") + @GetMapping("/list") +#if($table.crud || $table.sub) + public TableDataInfo<${ClassName}> list(${ClassName} bo, PageQuery pageQuery) { + return i${ClassName}Service.queryPageList(bo, pageQuery); + } +#elseif($table.tree) + public R> list(${ClassName} bo) { + List<${ClassName}> list = i${ClassName}Service.queryList(bo); + return R.ok(list); + } +#end + + /** + * 导出${functionName}列表 + */ + @SaCheckPermission("${permissionPrefix}:export") + @Log(title = "${functionName}", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(${ClassName} bo, HttpServletResponse response) { + List<${ClassName}> list = i${ClassName}Service.queryList(bo); + ExcelUtil.exportExcel(list, "${functionName}", ${ClassName}.class, response); + } + + /** + * 获取${functionName}详细信息 + * + * @param ${pkColumn.javaField} 主键 + */ + @SaCheckPermission("${permissionPrefix}:query") + @GetMapping("/{${pkColumn.javaField}}") + public R<${ClassName}> getInfo(@NotNull(message = "主键不能为空") + @PathVariable ${pkColumn.javaType} ${pkColumn.javaField}) { + return R.ok(i${ClassName}Service.queryById(${pkColumn.javaField})); + } + + /** + * 新增${functionName} + */ + @SaCheckPermission("${permissionPrefix}:add") + @Log(title = "${functionName}", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody ${ClassName} bo) { + return toAjax(i${ClassName}Service.insertByBo(bo)); + } + + /** + * 修改${functionName} + */ + @SaCheckPermission("${permissionPrefix}:edit") + @UpdateLog(title = "${functionName}",mapperClass = ${ClassName}Mapper.class, businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody ${ClassName} bo) { + return toAjax(i${ClassName}Service.updateByBo(bo)); + } + + /** + * 删除${functionName} + * + * @param ${pkColumn.javaField}s 主键串 + */ + @SaCheckPermission("${permissionPrefix}:remove") + @Log(title = "${functionName}", businessType = BusinessType.DELETE) + @DeleteMapping("/{${pkColumn.javaField}s}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s) { + return toAjax(i${ClassName}Service.deleteWithValidByIds(Arrays.asList(${pkColumn.javaField}s), true)); + } +} diff --git a/cas-generator/src/main/resources/vm/java/domain.java.vm b/cas-generator/src/main/resources/vm/java/domain.java.vm new file mode 100644 index 0000000..064cb9d --- /dev/null +++ b/cas-generator/src/main/resources/vm/java/domain.java.vm @@ -0,0 +1,57 @@ +package ${packageName}.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.annotation.UpdateValueLog; +#foreach ($import in $importList) +import ${import}; +#end +#if($table.crud || $table.sub) +import com.inscloudtech.common.core.domain.BaseEntity; +#elseif($table.tree) +import com.inscloudtech.common.core.domain.TreeEntity; +#end + +/** + * ${functionName}对象 ${tableName} + * + * @author ${author} + * @date ${datetime} + */ +#if($table.crud || $table.sub) + #set($Entity="BaseEntity") +#elseif($table.tree) + #set($Entity="TreeEntity<${ClassName}>") +#end +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("${tableName}") +@ExcelIgnoreUnannotated +public class ${ClassName} extends ${Entity} { + + private static final long serialVersionUID=1L; + +#foreach ($column in $columns) +#if(!$table.isSuperColumn($column.javaField)) + /** + * $column.columnComment + */ +#if($column.javaField=='delFlag') + @TableLogic +#end +#if($column.javaField=='version') + @Version +#end +#if($column.pk) + @TableId(value = "$column.columnName") +#end + @ExcelProperty(value = "$column.columnComment") + @UpdateValueLog(fieldName = "$column.columnComment") + private $column.javaType $column.javaField; +#end +#end + +} diff --git a/cas-generator/src/main/resources/vm/java/mapper.java.vm b/cas-generator/src/main/resources/vm/java/mapper.java.vm new file mode 100644 index 0000000..e89a5b7 --- /dev/null +++ b/cas-generator/src/main/resources/vm/java/mapper.java.vm @@ -0,0 +1,14 @@ +package ${packageName}.mapper; + +import ${packageName}.domain.${ClassName}; +import com.inscloudtech.common.core.mapper.BaseMapperPlus; + +/** + * ${functionName}Mapper接口 + * + * @author ${author} + * @date ${datetime} + */ +public interface ${ClassName}Mapper extends BaseMapperPlus<${ClassName}Mapper, ${ClassName}, ${ClassName}> { + +} diff --git a/cas-generator/src/main/resources/vm/java/service.java.vm b/cas-generator/src/main/resources/vm/java/service.java.vm new file mode 100644 index 0000000..49ee1b7 --- /dev/null +++ b/cas-generator/src/main/resources/vm/java/service.java.vm @@ -0,0 +1,51 @@ +package ${packageName}.service; + +import ${packageName}.domain.${ClassName}; +#if($table.crud || $table.sub) +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.core.domain.PageQuery; +#end + +import java.util.Collection; +import java.util.List; + +/** + * ${functionName}Service接口 + * + * @author ${author} + * @date ${datetime} + */ +public interface I${ClassName}Service { + + /** + * 查询${functionName} + */ + ${ClassName} queryById(${pkColumn.javaType} ${pkColumn.javaField}); + +#if($table.crud || $table.sub) + /** + * 查询${functionName}列表 + */ + TableDataInfo<${ClassName}> queryPageList(${ClassName} bo, PageQuery pageQuery); +#end + + /** + * 查询${functionName}列表 + */ + List<${ClassName}> queryList(${ClassName} bo); + + /** + * 新增${functionName} + */ + Boolean insertByBo(${ClassName} bo); + + /** + * 修改${functionName} + */ + Boolean updateByBo(${ClassName} bo); + + /** + * 校验并批量删除${functionName}信息 + */ + Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid); +} diff --git a/cas-generator/src/main/resources/vm/java/serviceImpl.java.vm b/cas-generator/src/main/resources/vm/java/serviceImpl.java.vm new file mode 100644 index 0000000..36103ea --- /dev/null +++ b/cas-generator/src/main/resources/vm/java/serviceImpl.java.vm @@ -0,0 +1,132 @@ +package ${packageName}.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import com.inscloudtech.common.utils.StringUtils; +#if($table.crud || $table.sub) +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.core.domain.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +#end +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ${packageName}.domain.${ClassName}; +import ${packageName}.mapper.${ClassName}Mapper; +import ${packageName}.service.I${ClassName}Service; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * ${functionName}Service业务层处理 + * + * @author ${author} + * @date ${datetime} + */ +@RequiredArgsConstructor +@Service +public class ${ClassName}ServiceImpl implements I${ClassName}Service { + + private final ${ClassName}Mapper baseMapper; + + /** + * 查询${functionName} + */ + @Override + public ${ClassName} queryById(${pkColumn.javaType} ${pkColumn.javaField}){ + return baseMapper.selectById(${pkColumn.javaField}); + } + +#if($table.crud || $table.sub) + /** + * 查询${functionName}列表 + */ + @Override + public TableDataInfo<${ClassName}> queryPageList(${ClassName} bo, PageQuery pageQuery) { + LambdaQueryWrapper<${ClassName}> lqw = buildQueryWrapper(bo); + Page<${ClassName}> result = baseMapper.selectPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } +#end + + /** + * 查询${functionName}列表 + */ + @Override + public List<${ClassName}> queryList(${ClassName} bo) { + LambdaQueryWrapper<${ClassName}> lqw = buildQueryWrapper(bo); + return baseMapper.selectList(lqw); + } + + private LambdaQueryWrapper<${ClassName}> buildQueryWrapper(${ClassName} bo) { + Map params = bo.getParams(); + LambdaQueryWrapper<${ClassName}> lqw = Wrappers.lambdaQuery(); +#foreach($column in $columns) +#if($column.query) +#set($queryType=$column.queryType) +#set($javaField=$column.javaField) +#set($javaType=$column.javaType) +#set($columnName=$column.columnName) +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#set($mpMethod=$column.queryType.toLowerCase()) +#if($queryType != 'BETWEEN') +#if($javaType == 'String') +#set($condition='StringUtils.isNotBlank(bo.get'+$AttrName+'())') +#else +#set($condition='bo.get'+$AttrName+'() != null') +#end + lqw.$mpMethod($condition, ${ClassName}::get$AttrName, bo.get$AttrName()); +#else + lqw.between(params.get("begin$AttrName") != null && params.get("end$AttrName") != null, + ${ClassName}::get$AttrName ,params.get("begin$AttrName"), params.get("end$AttrName")); +#end +#end +#end + return lqw; + } + + /** + * 新增${functionName} + */ + @Override + public Boolean insertByBo(${ClassName} bo) { + ${ClassName} add = BeanUtil.toBean(bo, ${ClassName}.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; +#set($pk=$pkColumn.javaField.substring(0,1).toUpperCase() + ${pkColumn.javaField.substring(1)}) + if (flag) { + bo.set$pk(add.get$pk()); + } + return flag; + } + + /** + * 修改${functionName} + */ + @Override + public Boolean updateByBo(${ClassName} bo) { + ${ClassName} update = BeanUtil.toBean(bo, ${ClassName}.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(${ClassName} entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 批量删除${functionName} + */ + @Override + public Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteBatchIds(ids) > 0; + } +} diff --git a/cas-generator/src/main/resources/vm/java/sub-domain.java.vm b/cas-generator/src/main/resources/vm/java/sub-domain.java.vm new file mode 100644 index 0000000..334a6d3 --- /dev/null +++ b/cas-generator/src/main/resources/vm/java/sub-domain.java.vm @@ -0,0 +1,76 @@ +package ${packageName}.domain; + +#foreach ($import in $subImportList) +import ${import}; +#end +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.inscloudtech.common.annotation.Excel; +import com.inscloudtech.common.core.domain.BaseEntity; + +/** + * ${subTable.functionName}对象 ${subTableName} + * + * @author ${author} + * @date ${datetime} + */ +public class ${subClassName} extends BaseEntity +{ + private static final long serialVersionUID = 1L; + +#foreach ($column in $subTable.columns) +#if(!$table.isSuperColumn($column.javaField)) + /** $column.columnComment */ +#if($column.list) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if($parentheseIndex != -1) + @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()") +#elseif($column.javaType == 'Date') + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "${comment}", width = 30, dateFormat = "yyyy-MM-dd") +#else + @Excel(name = "${comment}") +#end +#end + private $column.javaType $column.javaField; + +#end +#end +#foreach ($column in $subTable.columns) +#if(!$table.isSuperColumn($column.javaField)) +#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]")) +#set($AttrName=$column.javaField) +#else +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#end + public void set${AttrName}($column.javaType $column.javaField) + { + this.$column.javaField = $column.javaField; + } + + public $column.javaType get${AttrName}() + { + return $column.javaField; + } +#end +#end + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) +#foreach ($column in $subTable.columns) +#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]")) +#set($AttrName=$column.javaField) +#else +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#end + .append("${column.javaField}", get${AttrName}()) +#end + .toString(); + } +} diff --git a/cas-generator/src/main/resources/vm/java/vo.java.vm b/cas-generator/src/main/resources/vm/java/vo.java.vm new file mode 100644 index 0000000..57c611a --- /dev/null +++ b/cas-generator/src/main/resources/vm/java/vo.java.vm @@ -0,0 +1,50 @@ +package ${packageName}.domain.vo; + +#foreach ($import in $importList) +import ${import}; +#end +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.annotation.ExcelDictFormat; +import com.inscloudtech.common.convert.ExcelDictConvert; +import lombok.Data; + + +/** + * ${functionName}视图对象 ${tableName} + * + * @author ${author} + * @date ${datetime} + */ +@Data +@ExcelIgnoreUnannotated +public class ${ClassName}Vo { + + private static final long serialVersionUID = 1L; + +#foreach ($column in $columns) +#if($column.list) + /** + * $column.columnComment + */ +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if(${column.dictType} && ${column.dictType} != '') + @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "${column.dictType}") +#elseif($parentheseIndex != -1) + @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "$column.readConverterExp()") +#else + @ExcelProperty(value = "${comment}") +#end + private $column.javaType $column.javaField; + +#end +#end + +} diff --git a/cas-generator/src/main/resources/vm/js/api.js.vm b/cas-generator/src/main/resources/vm/js/api.js.vm new file mode 100644 index 0000000..9295524 --- /dev/null +++ b/cas-generator/src/main/resources/vm/js/api.js.vm @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询${functionName}列表 +export function list${BusinessName}(query) { + return request({ + url: '/${moduleName}/${businessName}/list', + method: 'get', + params: query + }) +} + +// 查询${functionName}详细 +export function get${BusinessName}(${pkColumn.javaField}) { + return request({ + url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField}, + method: 'get' + }) +} + +// 新增${functionName} +export function add${BusinessName}(data) { + return request({ + url: '/${moduleName}/${businessName}', + method: 'post', + data: data + }) +} + +// 修改${functionName} +export function update${BusinessName}(data) { + return request({ + url: '/${moduleName}/${businessName}', + method: 'put', + data: data + }) +} + +// 删除${functionName} +export function del${BusinessName}(${pkColumn.javaField}) { + return request({ + url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField}, + method: 'delete' + }) +} diff --git a/cas-generator/src/main/resources/vm/sql/oracle/sql.vm b/cas-generator/src/main/resources/vm/sql/oracle/sql.vm new file mode 100644 index 0000000..3de2fa4 --- /dev/null +++ b/cas-generator/src/main/resources/vm/sql/oracle/sql.vm @@ -0,0 +1,19 @@ +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', sysdate, '', null, '${functionName}菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 'admin', sysdate, '', null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 'admin', sysdate, '', null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 'admin', sysdate, '', null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 'admin', sysdate, '', null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 'admin', sysdate, '', null, ''); diff --git a/cas-generator/src/main/resources/vm/sql/postgres/sql.vm b/cas-generator/src/main/resources/vm/sql/postgres/sql.vm new file mode 100644 index 0000000..e8b45c9 --- /dev/null +++ b/cas-generator/src/main/resources/vm/sql/postgres/sql.vm @@ -0,0 +1,20 @@ +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', now(), '', null, '${functionName}菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 'admin', now(), '', null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 'admin', now(), '', null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 'admin', now(), '', null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 'admin', now(), '', null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 'admin', now(), '', null, ''); + diff --git a/cas-generator/src/main/resources/vm/sql/sql.vm b/cas-generator/src/main/resources/vm/sql/sql.vm new file mode 100644 index 0000000..9bc0b02 --- /dev/null +++ b/cas-generator/src/main/resources/vm/sql/sql.vm @@ -0,0 +1,19 @@ +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', sysdate(), '', null, '${functionName}菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 'admin', sysdate(), '', null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 'admin', sysdate(), '', null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 'admin', sysdate(), '', null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 'admin', sysdate(), '', null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 'admin', sysdate(), '', null, ''); diff --git a/cas-generator/src/main/resources/vm/sql/sqlserver/sql.vm b/cas-generator/src/main/resources/vm/sql/sqlserver/sql.vm new file mode 100644 index 0000000..956534f --- /dev/null +++ b/cas-generator/src/main/resources/vm/sql/sqlserver/sql.vm @@ -0,0 +1,19 @@ +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', getdate(), '', null, '${functionName}菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 'admin', getdate(), '', null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 'admin', getdate(), '', null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 'admin', getdate(), '', null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 'admin', getdate(), '', null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 'admin', getdate(), '', null, ''); diff --git a/cas-generator/src/main/resources/vm/vue/index-tree.vue.vm b/cas-generator/src/main/resources/vm/vue/index-tree.vue.vm new file mode 100644 index 0000000..4f10953 --- /dev/null +++ b/cas-generator/src/main/resources/vm/vue/index-tree.vue.vm @@ -0,0 +1,486 @@ + + + diff --git a/cas-generator/src/main/resources/vm/vue/index.vue.vm b/cas-generator/src/main/resources/vm/vue/index.vue.vm new file mode 100644 index 0000000..7053940 --- /dev/null +++ b/cas-generator/src/main/resources/vm/vue/index.vue.vm @@ -0,0 +1,601 @@ + + + diff --git a/cas-generator/src/main/resources/vm/vue/v2/index-tree.vue.vm b/cas-generator/src/main/resources/vm/vue/v2/index-tree.vue.vm new file mode 100644 index 0000000..fd07e4d --- /dev/null +++ b/cas-generator/src/main/resources/vm/vue/v2/index-tree.vue.vm @@ -0,0 +1,518 @@ + + + diff --git a/cas-generator/src/main/resources/vm/vue/v2/index.vue.vm b/cas-generator/src/main/resources/vm/vue/v2/index.vue.vm new file mode 100644 index 0000000..7e41538 --- /dev/null +++ b/cas-generator/src/main/resources/vm/vue/v2/index.vue.vm @@ -0,0 +1,615 @@ + + + diff --git a/cas-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm b/cas-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm new file mode 100644 index 0000000..4f10953 --- /dev/null +++ b/cas-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm @@ -0,0 +1,486 @@ + + + diff --git a/cas-generator/src/main/resources/vm/vue/v3/index.vue.vm b/cas-generator/src/main/resources/vm/vue/v3/index.vue.vm new file mode 100644 index 0000000..7053940 --- /dev/null +++ b/cas-generator/src/main/resources/vm/vue/v3/index.vue.vm @@ -0,0 +1,601 @@ + + + diff --git a/cas-generator/src/main/resources/vm/vue/v3/readme.txt b/cas-generator/src/main/resources/vm/vue/v3/readme.txt new file mode 100644 index 0000000..e6dc758 --- /dev/null +++ b/cas-generator/src/main/resources/vm/vue/v3/readme.txt @@ -0,0 +1 @@ +如果使用的是Vue3前端,那么需要覆盖一下此目录的模板index.vue.vm、index-tree.vue.vm文件到上级vue目录。 diff --git a/cas-generator/src/main/resources/vm/xml/mapper.xml.vm b/cas-generator/src/main/resources/vm/xml/mapper.xml.vm new file mode 100644 index 0000000..2a128fb --- /dev/null +++ b/cas-generator/src/main/resources/vm/xml/mapper.xml.vm @@ -0,0 +1,14 @@ + + + + + +#foreach ($column in $columns) + +#end + + + + diff --git a/cas-system/lib/aspose-cells-crack-21.11.jar b/cas-system/lib/aspose-cells-crack-21.11.jar new file mode 100644 index 0000000..ae48554 Binary files /dev/null and b/cas-system/lib/aspose-cells-crack-21.11.jar differ diff --git a/cas-system/lib/aspose-pdf-crack-21.11.jar b/cas-system/lib/aspose-pdf-crack-21.11.jar new file mode 100644 index 0000000..03be864 Binary files /dev/null and b/cas-system/lib/aspose-pdf-crack-21.11.jar differ diff --git a/cas-system/lib/aspose-words-21.1-jdk17.jar b/cas-system/lib/aspose-words-21.1-jdk17.jar new file mode 100644 index 0000000..7429c78 Binary files /dev/null and b/cas-system/lib/aspose-words-21.1-jdk17.jar differ diff --git a/cas-system/lib/asyncTool-1.4.2.jar b/cas-system/lib/asyncTool-1.4.2.jar new file mode 100644 index 0000000..9603e7a Binary files /dev/null and b/cas-system/lib/asyncTool-1.4.2.jar differ diff --git a/cas-system/pom.xml b/cas-system/pom.xml new file mode 100644 index 0000000..d37f534 --- /dev/null +++ b/cas-system/pom.xml @@ -0,0 +1,66 @@ + + + + cas-server + com.inscloudtech + 4.7.0 + + 4.0.0 + + cas-system + + + system系统模块 + + + + + + + com.inscloudtech + cas-common + + + + org.dromara.easy-es + easy-es-boot-starter + + + + com.aspose + aspose-pdf + 21.11 + system + ${project.basedir}/lib/aspose-pdf-crack-21.11.jar + + + + com.aspose + aspose-cells + 21.11 + system + ${project.basedir}/lib/aspose-cells-crack-21.11.jar + + + + com.aspose + aspose-words + 21.1 + jdk17 + system + ${project.basedir}/lib/aspose-words-21.1-jdk17.jar + + + + com.gitee.jd-platform-opensource + asyncTool + V1.4.2 + system + ${project.basedir}/lib/asyncTool-1.4.2.jar + + + + + diff --git a/cas-system/src/main/java/com/inscloudtech/analysiscenter/domain/AnalysisDto.java b/cas-system/src/main/java/com/inscloudtech/analysiscenter/domain/AnalysisDto.java new file mode 100644 index 0000000..b104d0f --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/analysiscenter/domain/AnalysisDto.java @@ -0,0 +1,63 @@ +package com.inscloudtech.analysiscenter.domain; + + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.baomidou.mybatisplus.annotation.TableField; +import lombok.Data; + +import java.util.*; + +/** + * 分析中心-分析成果对象 + * + * @author inscloudtech + * @date 2023-11-09 + */ +@Data +@ExcelIgnoreUnannotated +public class AnalysisDto { + + private static final long serialVersionUID = 1L; + + + /** + * 业务模块 + * BANK_STATEMENT-银行流水 + * TRANSACTION_PARTNER-所在单位交易客户 + * PUBLIC_FAMILY-职工及家属名册 + * CAR_INFO-车辆信息 + * REAL_ESTATE-不动产 + * TRANSACTION_PARTNER-所在单位交易客户 + * OTHER_ASSETS-其他资产 + * OTHER_INFORMATION-其他信息 + * ANALYSIS_REPORT-分析报告 + * ANALYSIS_RESULT-分析结果 + */ +// @NotBlank(message = "业务模块不能为空", groups = { AddGroup.class, EditGroup.class }) + private String businessModule; + +// @NotBlank(message = "业务模块不能为空", groups = { AddGroup.class, EditGroup.class }) + /** + * 模块下标列表 + */ + private List moduleIndexList; + + /** + * 源案件id + */ + private String sourceCaseId; + + /** + * 并入案件id + */ + private String targetCaseId; + + + @ExcelIgnore + @TableField(exist = false) + private Set ids = new HashSet<>(); + + private String analysisResultId; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/analysiscenter/domain/AnalysisPerson.java b/cas-system/src/main/java/com/inscloudtech/analysiscenter/domain/AnalysisPerson.java new file mode 100644 index 0000000..4635129 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/analysiscenter/domain/AnalysisPerson.java @@ -0,0 +1,46 @@ +package com.inscloudtech.analysiscenter.domain; + + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.inscloudtech.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.easyes.annotation.IndexField; + +import java.util.Date; + +/** + * 分析中心-分析报告 + * + * @author inscloudtech + * @date 2023-11-09 + */ +@Data +@TableName("ac_analysis_person") +@ExcelIgnoreUnannotated +public class AnalysisPerson { + + private static final long serialVersionUID=1L; + + @TableId(type = IdType.ASSIGN_ID) + @ExcelProperty("id") + private String id; + + private String label; + + //人员类别 0内部 1外部 + private int type; + + private String caseId; + + private String value; + + @IndexField(exist = false) + @TableLogic + @JsonIgnore + private String delFlag; +} diff --git a/cas-system/src/main/java/com/inscloudtech/analysiscenter/domain/AnalysisReport.java b/cas-system/src/main/java/com/inscloudtech/analysiscenter/domain/AnalysisReport.java new file mode 100644 index 0000000..756ad6e --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/analysiscenter/domain/AnalysisReport.java @@ -0,0 +1,90 @@ +package com.inscloudtech.analysiscenter.domain; + + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.inscloudtech.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Date; +import java.util.Set; + +/** + * 分析中心-分析报告 + * + * @author inscloudtech + * @date 2023-11-09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("ac_analysis_report") +@ExcelIgnoreUnannotated +public class AnalysisReport extends BaseEntity { + + private static final long serialVersionUID=1L; + + @TableId(type = IdType.ASSIGN_ID) + @ExcelProperty("id") + private String id; + + @ExcelProperty("name") + private String name; + + private String ossId; + + private String caseId; + + @ExcelProperty("idCard") + private String idCard; + + + @ExcelProperty("analysisResultId") + private String analysisResultId; + + @ExcelProperty("history") + private String history; + + /** + * 可疑金额 + */ + @TableField(exist = false) + private String suspiciousAmount; + + /** + * 取现金额 + */ + @TableField(exist = false) + private String withdrawalAmount; + + /** + * 笔数 + */ + @TableField(exist = false) + private Integer transCount; + + @ExcelProperty("创建者") + private String createBy; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @ExcelProperty("创建时间") + private Date createTime; + + @ExcelProperty("更新者") + private String updateBy; + + @ExcelProperty("更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + + /** + * 人员类型 + */ + private Integer type; +} diff --git a/cas-system/src/main/java/com/inscloudtech/analysiscenter/domain/AnalysisReportVo.java b/cas-system/src/main/java/com/inscloudtech/analysiscenter/domain/AnalysisReportVo.java new file mode 100644 index 0000000..f12c790 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/analysiscenter/domain/AnalysisReportVo.java @@ -0,0 +1,161 @@ +package com.inscloudtech.analysiscenter.domain; + +import com.inscloudtech.common.annotation.DeduplicationField; +import com.inscloudtech.datacenter.domain.CarInfo; +import com.inscloudtech.datacenter.domain.RealEstate; +import com.inscloudtech.datacenter.domain.dto.OtherAssetsDto; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +/** + * 分析中心-分析报告v0 + * + * @author inscloudtech + * @date 2023-11-09 + */ +@Data +public class AnalysisReportVo implements Serializable { + + private static final long serialVersionUID = 1L; + + private String name; + + private String idCard; + + private String nativePlace; + + private String company = "未匹配"; + + private String relationPerson = "未匹配"; + + private String phone; + + private Integer houseCount; + private String houseArea; + private String houseValue; + + private Integer carCount; + + private String ossId; + + private String caseId; + + private String baseInfo; + + // 相关 + // 账户个数 + private Integer accountCount; + // 入账金额 + private BigDecimal entryAmount; + // 余额 + private BigDecimal balance; + // 账户总体情况 + private List itemList = new ArrayList<>(); + + // 车 + private List carInfos = new ArrayList<>(); + + private List houseInfos = new ArrayList<>(); + + // 其他资产 + private List otherAssetsInfo = new ArrayList<>(); + + private List otherInformationInfo = new ArrayList<>(); + + // 涉嫌关联交易 + private List transItems = new ArrayList<>(); + // 可疑交易 + private List suspiciousItems = new ArrayList<>(); + + /** + * 可疑金额 + */ + private String suspiciousAmount; + private String suspiciousAmountStr; + + private String analysisResultId;//分析成果Id + + /** + * 笔数 + */ + private Integer transCount; + + private String personTypeStr; + + //内部外部 + private int personType; + private String typeStr; + + + //存取现情况 + private String cqx; + private List dwItems = new ArrayList<>(); + //时间区间 + private String dwDateRange; + private BigDecimal withdrawalAmount; + // 取现笔数 + private long withdrawMoneyCount; + // 取现金额 + private BigDecimal withdrawMoneyAmount; + // 存现笔数 + private long depositMoneyCount; + // 存现金额 + private BigDecimal depositMoneyAmount; + + @Data + public static class DWItem { + private String date; + //银行名称 + private String dwBankName; + + private String cardNumber; + + // 取现金额 + private BigDecimal withdrawMoneyAmount; + + // 存现金额 + private BigDecimal depositMoneyAmount; + + } + + @Data + public static class ConnectedTransItem { + @DeduplicationField + private String name; + + @DeduplicationField + private String transDateRange; + + @DeduplicationField + private BigDecimal transformAmount = BigDecimal.ZERO; + //转入 + @DeduplicationField + private BigDecimal entryAmount = BigDecimal.ZERO; + + @DeduplicationField + private String transRemark; + + // 交易对象身份 + private String counterpartyIdentity; + // 欠款情况 + private BigDecimal debitAmount = BigDecimal.ZERO; + // 关联交易情况 + private BigDecimal relatedPartyTransactions = BigDecimal.ZERO; + // 其他可疑交易-其他信息 + private String suspiciousRemark; + // 备注 + private String remark; + } + + @Data + public static class BSItem { + private String bankName; + private String accountNumber; + private BigDecimal entryAmount; + private BigDecimal balance; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/analysiscenter/domain/AnalysisResult.java b/cas-system/src/main/java/com/inscloudtech/analysiscenter/domain/AnalysisResult.java new file mode 100644 index 0000000..fbca3e7 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/analysiscenter/domain/AnalysisResult.java @@ -0,0 +1,66 @@ +package com.inscloudtech.analysiscenter.domain; + + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.*; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import com.fasterxml.jackson.annotation.JsonFormat; + +import com.inscloudtech.common.annotation.UpdateValueLog; +import com.inscloudtech.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.RefreshPolicy; + +import java.util.Date; +import java.util.Set; + +/** + * 分析中心-分析成果对象 + * + * @author inscloudtech + * @date 2023-11-09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("ac_analysis_result") +@ExcelIgnoreUnannotated +public class AnalysisResult extends BaseEntity { + + private static final long serialVersionUID=1L; + + @TableId(type = IdType.ASSIGN_ID) + @ExcelProperty("id") + private String id; + + @ExcelProperty("name") + private String name; + + private String ossId; + + private String caseId; + + @ExcelProperty("创建者") + private String createBy; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @ExcelProperty("创建时间") + private Date createTime; + + @ExcelProperty("更新者") + private String updateBy; + + @ExcelProperty("更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + + + + @TableField(exist = false) + private Integer downloadTemplate; +} diff --git a/cas-system/src/main/java/com/inscloudtech/analysiscenter/mapper/AnalysisPersonMapper.java b/cas-system/src/main/java/com/inscloudtech/analysiscenter/mapper/AnalysisPersonMapper.java new file mode 100644 index 0000000..365005b --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/analysiscenter/mapper/AnalysisPersonMapper.java @@ -0,0 +1,9 @@ +package com.inscloudtech.analysiscenter.mapper; + + +import com.inscloudtech.analysiscenter.domain.AnalysisPerson; +import com.inscloudtech.common.core.mapper.BaseMapperPlus; + +public interface AnalysisPersonMapper extends BaseMapperPlus { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/analysiscenter/mapper/AnalysisReportMapper.java b/cas-system/src/main/java/com/inscloudtech/analysiscenter/mapper/AnalysisReportMapper.java new file mode 100644 index 0000000..9246f40 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/analysiscenter/mapper/AnalysisReportMapper.java @@ -0,0 +1,10 @@ +package com.inscloudtech.analysiscenter.mapper; + + +import com.inscloudtech.analysiscenter.domain.AnalysisReport; +import com.inscloudtech.analysiscenter.domain.AnalysisResult; +import com.inscloudtech.common.core.mapper.BaseMapperPlus; + +public interface AnalysisReportMapper extends BaseMapperPlus { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/analysiscenter/mapper/AnalysisResultMapper.java b/cas-system/src/main/java/com/inscloudtech/analysiscenter/mapper/AnalysisResultMapper.java new file mode 100644 index 0000000..e8e5cc0 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/analysiscenter/mapper/AnalysisResultMapper.java @@ -0,0 +1,9 @@ +package com.inscloudtech.analysiscenter.mapper; + + +import com.inscloudtech.analysiscenter.domain.AnalysisResult; +import com.inscloudtech.common.core.mapper.BaseMapperPlus; + +public interface AnalysisResultMapper extends BaseMapperPlus { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/analysiscenter/service/IAnalysisReportService.java b/cas-system/src/main/java/com/inscloudtech/analysiscenter/service/IAnalysisReportService.java new file mode 100644 index 0000000..2169ab2 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/analysiscenter/service/IAnalysisReportService.java @@ -0,0 +1,42 @@ +package com.inscloudtech.analysiscenter.service; + + +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.analysiscenter.domain.AnalysisReport; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * + * @author inscloudtech + * @date 2023-11-10 + */ +public interface IAnalysisReportService { + + AnalysisReport queryById(String id); + + TableDataInfo queryPageList(AnalysisReport bo, PageQuery pageQuery); + + List queryList(AnalysisReport bo); + + Boolean insert(AnalysisReport bo); + + Boolean update(AnalysisReport bo); + + Boolean deleteWithValidByIds(Collection ids); + + void download(String ossId, HttpServletResponse response) throws IOException; + + void save2AnalysisResult(AnalysisDto dto); + + Boolean caseMerge(String sourceCaseId,String targetCaseId); + + void analysisResultMerge(Map sourceArIdTargetArIdMap); + +} diff --git a/cas-system/src/main/java/com/inscloudtech/analysiscenter/service/IAnalysisResultService.java b/cas-system/src/main/java/com/inscloudtech/analysiscenter/service/IAnalysisResultService.java new file mode 100644 index 0000000..d1dcd28 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/analysiscenter/service/IAnalysisResultService.java @@ -0,0 +1,37 @@ +package com.inscloudtech.analysiscenter.service; + + +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.analysiscenter.domain.AnalysisResult; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.util.Collection; +import java.util.List; + +/** + * + * @author inscloudtech + * @date 2023-11-10 + */ +public interface IAnalysisResultService { + + AnalysisResult queryById(String id); + + TableDataInfo queryPageList(AnalysisResult bo, PageQuery pageQuery); + + List queryList(AnalysisResult bo); + + Boolean insert(AnalysisResult bo); + + Boolean update(AnalysisResult bo); + + Boolean deleteWithValidByIds(Collection ids); + + void importData(MultipartFile file, String caseId, String analysisResultId); + + Boolean caseMerge(String sourceCaseId,String targetCaseId); + +} diff --git a/cas-system/src/main/java/com/inscloudtech/analysiscenter/service/impl/AnalysisReportServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/analysiscenter/service/impl/AnalysisReportServiceImpl.java new file mode 100644 index 0000000..cba3615 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/analysiscenter/service/impl/AnalysisReportServiceImpl.java @@ -0,0 +1,1952 @@ +package com.inscloudtech.analysiscenter.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.IdcardUtil; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; + +import cn.hutool.json.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.inscloudtech.analysiscenter.domain.*; +import com.inscloudtech.analysiscenter.mapper.AnalysisReportMapper; +import com.inscloudtech.analysiscenter.service.IAnalysisReportService; +import com.inscloudtech.analysiscenter.word.FileToMultipartFile; +import com.inscloudtech.analysiscenter.word.WordUtil; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.common.config.ProjectConfig; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.common.utils.file.FileUtils; +import com.inscloudtech.common.utils.redis.RedisUtils; +import com.inscloudtech.datacenter.domain.*; +import com.inscloudtech.datacenter.domain.dto.OtherAssetsDto; +import com.inscloudtech.datacenter.domain.vo.GetBSFieldValueCountReq; +import com.inscloudtech.datacenter.domain.vo.GetPersonReq; +import com.inscloudtech.system.domain.SysOss; +import com.inscloudtech.system.mapper.SysOssMapper; +import com.inscloudtech.datacenter.service.BankService; +import com.inscloudtech.system.service.ISysOssService; +import com.inscloudtech.datacenter.service.QueryCenterService; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; + +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.RoundingMode; +import java.time.Duration; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * + * @author zyl + * @date 2023-11-07Impl + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class AnalysisReportServiceImpl implements IAnalysisReportService { + + private final AnalysisReportMapper baseMapper; + + private final QueryCenterService queryCenterService; + + private final ISysOssService sysOssService; + + private final BankService bankService; + + private static final List> INDEX_LIST = Arrays.asList( + PublicFamily.class, + TransactionPartner.class, + RealEstate.class, + CarInfo.class); + + // 进行高亮查询 + private static final List> OTHER_INDEX_LIST = Arrays.asList(OtherAssets.class, OtherInformation.class); + + private static final String PERSON_INFO_STR_TEMPLATE = "%s%s,性别:%s,身份证号码:%s,单位信息:%s,关联人员:%s,电话号码:%s。"; + private static final String COMPANY_INFO_STR_TEMPLATE = + "%s%s,全国统一信用代码(组织机构代码证)%s,注册地址:%s,联系电话:%s,与该公司的交易情况(来往金额:%s,当前欠款金额:%s,股东及高管:%s,关联企业%s,关联人%s。"; + + + private final SysOssMapper sysOssMapper; + + @Override + public AnalysisReport queryById(String id) { + return baseMapper.selectById(id); + } + + @Override + public TableDataInfo queryPageList(AnalysisReport bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectPage(pageQuery.build(), lqw); + TableDataInfo tableDataInfo = TableDataInfo.build(result); + return tableDataInfo; + } + + private LambdaQueryWrapper buildQueryWrapper(AnalysisReport bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StrUtil.isNotBlank(bo.getCaseId()),AnalysisReport::getCaseId, bo.getCaseId()); + lqw.like(StrUtil.isNotBlank(bo.getName()), AnalysisReport::getName, bo.getName()); + lqw.between( + params.get("beginCreateTime") != null && params.get("endCreateTime") != null, + AnalysisReport::getCreateTime, + params.get("beginCreateTime"), + params.get("endCreateTime")); + lqw.eq(bo.getAnalysisResultId() != null, AnalysisReport::getAnalysisResultId, bo.getAnalysisResultId()); + + // 分析报告历史纪录 + String idCard = bo.getIdCard(); + if (StrUtil.isNotBlank(idCard) || StrUtil.isNotBlank(bo.getName())) { + if (IdcardUtil.isValidCard(idCard)) { + lqw.eq(true, AnalysisReport::getIdCard, idCard); + } +// else { +// throw new RuntimeException("身份证号无效!"); +// } + } else { + // 不是查询历史报告,则展示最新一条数据 + lqw.isNull(AnalysisReport::getHistory); + } + + return lqw; + } + + @Override + public List queryList(AnalysisReport bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectList(lqw); + } + + @SneakyThrows + @Override + public Boolean insert(AnalysisReport add) { + String idCard = add.getIdCard(); + String name = add.getName(); + String key = name + idCard; + lock(key); + AnalysisReportVo vo = new AnalysisReportVo(); + vo.setName(name); + vo.setIdCard(idCard); + vo.setAnalysisResultId(add.getAnalysisResultId()); + vo.setCaseId(add.getCaseId()); + // 交易笔数 + Integer transCount = add.getTransCount() == null?20:add.getTransCount(); + vo.setTransCount(transCount); + String suspiciousAmount = StrUtil.isBlank(add.getSuspiciousAmount())?"50000":add.getSuspiciousAmount(); + vo.setSuspiciousAmount(suspiciousAmount); + + if(StrUtil.isNotEmpty(add.getWithdrawalAmount())){ + vo.setWithdrawalAmount(new BigDecimal(add.getWithdrawalAmount())); + } + + String type = ""; + if(add.getType() != null){ + if(add.getType() == 0){ + type = "(内部)"; + }else if(add.getType() == 1){ + type = "(外部)"; + } + } + vo.setTypeStr(type); + vo.setPersonType(add.getType()); + + JSONObject esData = queryCenterService.getData4Report(INDEX_LIST, name, idCard, add.getCaseId()); + esData.putAll(queryCenterService.getData4ReportWithHighlight(OTHER_INDEX_LIST, name, idCard, add.getCaseId())); + esData.putOpt("dc_bank_statement",this.getBankStatement(name, idCard, add.getCaseId())); + + if(StrUtil.isNotEmpty(vo.getSuspiciousAmount())){ + BigDecimal tempAmount = BigDecimal.ZERO; + if(StrUtil.isNotEmpty(vo.getSuspiciousAmount())){ + try { + tempAmount = NumberUtil.toBigDecimal(vo.getSuspiciousAmount()); + } catch (Exception e) { + throw new RuntimeException("可疑金额格式不正确"); + } + } + vo.setSuspiciousAmountStr(tempAmount.divide(new BigDecimal("10000")).toString()); + } + File file = generateWordFileByTemplate(esData, vo, add.getCaseId()); + + if(StrUtil.isNotEmpty(type)){ + add.setName(name +type+"分析报告"); + }else { + add.setName(name + "分析报告"); + } + + SysOss sysOss = sysOssService.upload2Local(1, "", new FileToMultipartFile(file), + add.getCaseId(), "ANALYSIS_REPORT"); + FileUtil.del(file); + add.setOssId(sysOss.getOssId()); + + AnalysisReport analysisReport; + if(StrUtil.isNotEmpty(idCard)){ + analysisReport = baseMapper.selectOne(new LambdaQueryWrapper() + .eq(AnalysisReport::getIdCard, idCard).eq(AnalysisReport::getType, add.getType()) + .isNull(AnalysisReport::getHistory)); + }else { + analysisReport = baseMapper.selectOne(new LambdaQueryWrapper() + .eq(AnalysisReport::getName, add.getName() + "分析报告").eq(AnalysisReport::getType, add.getType()) + .isNull(AnalysisReport::getHistory)); + } + + if (null != analysisReport) { + analysisReport.setHistory("1"); + baseMapper.updateById(analysisReport); + } + boolean b = baseMapper.insert(add) > 0; + RedisUtils.deleteObject(key); + return b; + } + + void lock(String key) { + Object generating = RedisUtils.getCacheObject(key); + if (ObjUtil.isNotNull(generating)) { + throw new RuntimeException(key + "分析报告正在生成中,请勿重复提交!"); + } + RedisUtils.setCacheObject(key, "ing", Duration.ofMinutes(10)); + } + + private File generateWordFileByTemplate(JSONObject esData, AnalysisReportVo vo, String caseId) throws Exception { + // 一、基础信息 + setValueByPublicFamily(esData, vo); + setPhoneByBankStatement(esData, vo); + + // 二、账户总体情况 + handleOverallAccountInfo(esData, vo); + + // 三、涉嫌关联交易 + handleConnectedTransaction(esData, vo, caseId); + + // 四、其他可疑交易 + handleSuspiciousTransactions(esData, vo); + + // 五、可疑资金来源及去向 + // 六、存取现情况 + handleDepositAndWithdrawal(vo); + + // 七、资产信息 + // (一)房产 + setValueByRealEstate(esData, vo); + // (二)车产 + setValueByCarInfo(esData, vo); + // (三)其他资产 + setValueByOtherAssets(esData, vo); + // 八、其他信息 + setValueByOtherInformation(esData, vo); + + // 基本信息 + String baseInfo; + if (IdcardUtil.isValidCard(vo.getIdCard()) || vo.getName().length() < 6 ) { + String gender = "未知"; + if(StrUtil.isNotEmpty(vo.getIdCard())){ + int genderByIdCard = IdcardUtil.getGenderByIdCard(vo.getIdCard()); + gender = genderByIdCard == 1?"男":"女"; + } +// String gender = "未匹配"; + baseInfo = String.format( + PERSON_INFO_STR_TEMPLATE, + vo.getName(), + vo.getTypeStr(), + gender, + vo.getIdCard(), +// vo.getNativePlace(), + vo.getCompany(), + vo.getRelationPerson(), + vo.getPhone()); + } else { + if (esData.containsKey("dc_transaction_partner")) { + List transactionPartnerList = esData.getBeanList("dc_transaction_partner", TransactionPartner.class); + TransactionPartner transactionPartner = null; + for (TransactionPartner temp : transactionPartnerList) { + if (temp.getTravellingTrader().contains(vo.getName())) { + transactionPartner = temp; + break; + } + } + + if(transactionPartner == null){ + baseInfo = String.format( + COMPANY_INFO_STR_TEMPLATE, + vo.getName(), + vo.getTypeStr(), + vo.getIdCard(), + "无数据", + "无数据", + "无数据", + "无数据", + "无数据", + "无数据", + "无数据"); + }else { + String idCard = vo.getIdCard(); + idCard = StrUtil.isBlank(idCard)?transactionPartner.getOrganizationCode():idCard; + baseInfo = String.format( + COMPANY_INFO_STR_TEMPLATE, + vo.getName(), + vo.getTypeStr(), + idCard, + transactionPartner.getRegisteredAddress(), + StrUtil.isEmpty(vo.getPhone())?"无":vo.getPhone(), + transactionPartner.getTransactionAmount() == null?"无":transactionPartner.getTransactionAmount()+"元", + transactionPartner.getDebt() == null?"无":transactionPartner.getDebt()+"元", + transactionPartner.getStockholder(), + transactionPartner.getRelateCompany(), + transactionPartner.getStockholderRelated()); + } + + } else { + baseInfo = String.format( + COMPANY_INFO_STR_TEMPLATE, + vo.getName(), + vo.getTypeStr(), + vo.getIdCard(), + "无数据", + "无数据", + "无数据", + "无数据", + "无数据", + "无数据", + "无数据"); + } + } + vo.setBaseInfo(baseInfo); + + return WordUtil.generateWordFileByTemplate(vo); + } + + /** + * 存取现情况 + */ + private void handleDepositAndWithdrawal(AnalysisReportVo vo) throws Exception { + String analysisResultId = vo.getAnalysisResultId(); + if (Objects.isNull(analysisResultId)) { +// throw new RuntimeException("分析结果id不能为空"); + String cqx = "未设置,请在报告大纲设置!"; + vo.setCqx(cqx); + return; + } + + GetBSFieldValueCountReq req = new GetBSFieldValueCountReq(); + req.setAnalysisResultId(analysisResultId); + List analysisResultList = bankService.getBSList(req); + if(CollectionUtil.isEmpty(analysisResultList)){ + return; + } + analyzeDataPerBank(vo, analysisResultList); + } + + private void analyzeDataPerBank(AnalysisReportVo vo, List analysisResultList) { + List tempBsList = new ArrayList<>(); + String name = vo.getName(); + for (BankStatement bs : analysisResultList) { + BigDecimal transactionAmount = bs.getTransactionAmount(); + if(null == transactionAmount){ + continue; + } + BigDecimal abs = transactionAmount.abs(); + if(abs.compareTo(vo.getWithdrawalAmount()) < 0){ + continue; + } + + if (StrUtil.isBlank(bs.getCardHolderName()) && StrUtil.isBlank(bs.getIdCardNo())) { + continue; + } + String counterpartyName = bs.getCounterpartyName(); + if (StringUtils.isNotEmpty(counterpartyName) && counterpartyName.equals(vo.getName())) { + continue; + } + if (!Objects.equals(bs.getCardHolderName().trim(), name)){ + continue; + } +// if(StrUtil.isEmpty(idCard)){ +// if (!Objects.equals(bs.getCardHolderName().trim(), name)){ +// continue; +// } +// }else { +// if (StrUtil.isBlank(bs.getIdCardNo())) { +// continue; +// } +// if (!(Objects.equals(bs.getCardHolderName().trim(), name) && Objects.equals(bs.getIdCardNo().trim(), idCard))) { +// continue; +// } +// } + tempBsList.add(bs); + } + if(tempBsList.isEmpty()){ + return; + } + tempBsList.sort(Comparator.comparing(BankStatement::getTransactionTime)); + // 区间 + Date beginTime = tempBsList.get(0).getTransactionTime(); + Date endTime = tempBsList.get(tempBsList.size() - 1).getTransactionTime(); + if (beginTime.compareTo(endTime) > 0) { + Date temp = beginTime; + beginTime = endTime; + endTime = temp; + } + String format = "yyyy年MM月dd日"; + String range = DateUtil.format(beginTime, format) + "至" + DateUtil.format(endTime, format); + vo.setDwDateRange(range); + + // 取现金额 + BigDecimal allWithdrawMoneyAmount = BigDecimal.ZERO; + // 取现笔数 + Integer allWithdrawMoneyCount = 0; + + // 存现笔数 + Integer allDepositMoneyCount = 0; + // 存现金额 + BigDecimal allDepositMoneyAmount = BigDecimal.ZERO;; + + BigDecimal setWithdrawalAmount = vo.getWithdrawalAmount(); + List matchList = new ArrayList<>(); + if(setWithdrawalAmount == null){ + for (BankStatement bankStatement : tempBsList) { + BigDecimal transactionAmount = bankStatement.getTransactionAmount(); + if (transactionAmount.compareTo(BigDecimal.ZERO) < 0) { //取现 + allWithdrawMoneyCount++; + allWithdrawMoneyAmount = allWithdrawMoneyAmount.add(transactionAmount); + }else if (transactionAmount.compareTo(BigDecimal.ZERO) > 0) {//存现 + allDepositMoneyCount++; + allDepositMoneyAmount = allDepositMoneyAmount.add(transactionAmount); + } + } + matchList.addAll(tempBsList); + }else { //根据前端设置取现金额取数 + for (BankStatement bankStatement : tempBsList) { + BigDecimal transactionAmount = bankStatement.getTransactionAmount(); + if (transactionAmount.compareTo(BigDecimal.ZERO) < 0) {//取现 + BigDecimal abs = transactionAmount.abs(); + if(abs.compareTo(setWithdrawalAmount) >= 0){ + allWithdrawMoneyCount++; + allWithdrawMoneyAmount = allWithdrawMoneyAmount.add(abs); + matchList.add(bankStatement); + } + }else if (transactionAmount.compareTo(BigDecimal.ZERO) > 0) {//存现 + if(transactionAmount.compareTo(setWithdrawalAmount) >= 0){ + allDepositMoneyCount++; + allDepositMoneyAmount = allDepositMoneyAmount.add(transactionAmount); + matchList.add(bankStatement); + } + } + } + } + + vo.setWithdrawMoneyCount(allWithdrawMoneyCount); + allWithdrawMoneyAmount = allWithdrawMoneyAmount.abs(); + vo.setWithdrawMoneyAmount(allWithdrawMoneyAmount.divide(new BigDecimal("10000")).setScale(2, RoundingMode.HALF_UP)); + + vo.setDepositMoneyCount(allDepositMoneyCount); + vo.setDepositMoneyAmount(allDepositMoneyAmount.divide(new BigDecimal("10000")).setScale(2, RoundingMode.HALF_UP)); + + List dwItems = new ArrayList<>(); + for (BankStatement bankStatement : matchList) { + AnalysisReportVo.DWItem item = new AnalysisReportVo.DWItem(); + item.setDwBankName(bankStatement.getBankName()); + item.setDate(DateUtil.format(bankStatement.getTransactionTime(), DatePattern.NORM_DATE_PATTERN)); + item.setCardNumber(bankStatement.getCardNumber()); + BigDecimal transactionAmount = bankStatement.getTransactionAmount(); + if(setWithdrawalAmount == null){ + if (transactionAmount.compareTo(BigDecimal.ZERO) < 0) { //取现 + item.setWithdrawMoneyAmount(transactionAmount.abs()); + }else if (transactionAmount.compareTo(BigDecimal.ZERO) > 0) {//存现 + item.setDepositMoneyAmount(transactionAmount); + } + }else { + if (transactionAmount.compareTo(BigDecimal.ZERO) < 0) {//取现 + BigDecimal abs = transactionAmount.abs(); + if(abs.compareTo(setWithdrawalAmount) >= 0){ + item.setWithdrawMoneyAmount(abs); + } + }else if (transactionAmount.compareTo(BigDecimal.ZERO) > 0) {//存现 + if(transactionAmount.compareTo(setWithdrawalAmount) >= 0){ + item.setDepositMoneyAmount(transactionAmount); + } + } + } + dwItems.add(item); + } + // 排序 + dwItems.sort(Comparator.comparing(AnalysisReportVo.DWItem::getDate)); + AnalysisReportVo.DWItem totalItem = new AnalysisReportVo.DWItem(); + + totalItem.setDate("合计"); + totalItem.setWithdrawMoneyAmount(allWithdrawMoneyAmount); + totalItem.setDepositMoneyAmount(allDepositMoneyAmount); + dwItems.add(totalItem); + vo.getDwItems().addAll(dwItems); + String cqx = vo.getName() + "," +vo.getDwDateRange()+"期间,取现"+allWithdrawMoneyCount+"笔共计"+vo.getWithdrawMoneyAmount()+"万元,存现"+allDepositMoneyCount+"笔共计"+vo.getDepositMoneyAmount()+"万元,大额存取现情况如下表:"; + vo.setCqx(cqx); + + } + + private String getTitle(long base) { + String prefix = "金额"; + if (base == 10L) { + return prefix; + } else if (base == 100L) { + return prefix + "(百元)"; + } else if (base == 1000L) { + return prefix + "(千元)"; + } else if (base == 10000L) { + return prefix + "(万元)"; + } else if (base == 100000L) { + return prefix + "(十万元)"; + } else if (base == 1000000L) { + return prefix + "(百万元)"; + } else { + return prefix + "(千万元)"; + } + } + + + /** + * 可疑交易 + */ + private void handleSuspiciousTransactions(JSONObject esData, AnalysisReportVo vo) { + if (!esData.containsKey("dc_bank_statement")) { + return; + } + + // 交易笔数 + Integer transCount = vo.getTransCount(); + BigDecimal suspiciousAmount = NumberUtil.toBigDecimal(vo.getSuspiciousAmount()); + + // 筛选某人作为交易对手的流水数据,其中有交易时间,以及交易金额,进为转入金额,出为转出金额,获取交易备注 + String name = vo.getName(); + String idCard = vo.getIdCard(); + + List transItems = vo.getTransItems(); // 涉嫌关联交易 + Set nameSet = transItems.stream() + .filter(item -> StrUtil.isNotEmpty(item.getName())) + .map(AnalysisReportVo.ConnectedTransItem::getName) + .collect(Collectors.toSet()); + + // 分析theList + Map> counterpartyBSMap = new HashMap<>(); + // 可疑交易 跟 涉嫌关联交易 不重合 + List bsList = esData.getBeanList("dc_bank_statement", BankStatement.class); + for (BankStatement bs : bsList) { + String counterpartyName = bs.getCounterpartyName(); + if (StrUtil.isNotEmpty(counterpartyName)) { + if(filterByCounterpartyName(counterpartyName,1)){ + continue; + } + } + + if (StrUtil.isBlank(bs.getCardHolderName()) && StrUtil.isBlank(bs.getIdCardNo())) { + continue; + } + + if (StringUtils.isNotEmpty(counterpartyName) && counterpartyName.equals(vo.getName())) { + continue; + } + if(StrUtil.isEmpty(idCard)){ + if (Objects.equals(bs.getCardHolderName().trim(), name) + && !nameSet.contains(bs.getCounterpartyName().trim())){ + + if (StringUtils.isEmpty(counterpartyName)) { + continue; + } + List list = counterpartyBSMap.getOrDefault(counterpartyName, null); + if (list == null) { + counterpartyBSMap.put(counterpartyName, new ArrayList<>()); + } + counterpartyBSMap.get(counterpartyName).add(bs); + } + }else { + if (StrUtil.isBlank(bs.getIdCardNo())) { + continue; + } + if (Objects.equals(bs.getCardHolderName().trim(), name) + && Objects.equals(bs.getIdCardNo().trim(), idCard) + && (StrUtil.isNotBlank(bs.getCounterpartyName()) + && !nameSet.contains(bs.getCounterpartyName().trim()))) { + if (StringUtils.isEmpty(counterpartyName)) { + continue; + } + List list = counterpartyBSMap.getOrDefault(counterpartyName, null); + if (list == null) { + counterpartyBSMap.put(counterpartyName, new ArrayList<>()); + } + counterpartyBSMap.get(counterpartyName).add(bs); + } + } + + } + + + List rst = new ArrayList<>(); + + //同时满足两个条件的数据会重复 + + Set idSet = new HashSet<>(); + + //交易笔数 + if(transCount > 0){ + for (Map.Entry> entry : counterpartyBSMap.entrySet()) { + List tempList = entry.getValue(); + if (tempList.isEmpty()) { + continue; + } + if (transCount > tempList.size()) { // 连正常笔数都达不到不继续 + continue; + } + + String counterpartyName = entry.getKey(); + + tempList.sort((o1, o2) -> { + Date t1 = o1.getTransactionTime(); + Date t2 = o2.getTransactionTime(); + return t1.compareTo(t2); + }); + + BankStatement theStartBs = tempList.get(0); + Date startDate = theStartBs.getTransactionTime(); + + BankStatement theEndBs = tempList.get(tempList.size() - 1); + Date endDate = theEndBs.getTransactionTime(); + + if (startDate.compareTo(endDate) > 0) { + Date tmp = startDate; + startDate = endDate; + endDate = tmp; + } + + String format = "yyyy.MM.dd"; + String rangeStr = DateUtil.format(startDate, format) + "-" + DateUtil.format(endDate, format); + + // 转出金额 + BigDecimal transformAmount = BigDecimal.ZERO; + + // 转入金额 + BigDecimal entryAmount = BigDecimal.ZERO; + + Set remarkSet = new HashSet<>(); + + for (BankStatement bs : tempList) { + BigDecimal transactionAmount = bs.getTransactionAmount(); + String summary = bs.getSummary(); + String transRemarkTemp = bs.getTransRemark(); + String remark = bs.getRemark(); + if (StrUtil.isNotBlank(summary)) { + remarkSet.add(summary); + } + if (StrUtil.isNotBlank(transRemarkTemp)) { + remarkSet.add(transRemarkTemp); + } + if (StrUtil.isNotBlank(remark)) { + remarkSet.add(remark); + } + + if(transactionAmount.compareTo(BigDecimal.ZERO) < 0){ + transformAmount = transformAmount.add(transactionAmount.negate()); + } + + if(transactionAmount.compareTo(BigDecimal.ZERO) > 0){ + entryAmount = entryAmount.add(transactionAmount); + } + + } + + // 交易备注 + String transRemark = String.join("、", remarkSet); + if(transRemark.length() > 20){ + transRemark = transRemark.substring(0,19) + "...等"; + } + AnalysisReportVo.ConnectedTransItem item = new AnalysisReportVo.ConnectedTransItem(); + item.setName(counterpartyName); + item.setTransDateRange(rangeStr); + item.setTransRemark(transRemark); + item.setEntryAmount(entryAmount); + item.setTransformAmount(transformAmount); + String uniqueKey = BeanUtils.getUniqueKey(item); + String md5Id = HelperUtil.generateMD5(uniqueKey); + if(idSet.contains(md5Id)){ + continue; + } + idSet.add(md5Id); + rst.add(item); + } + } + + //可疑金额 + if(suspiciousAmount.compareTo(BigDecimal.ZERO) > 0){ + for (Map.Entry> entry : counterpartyBSMap.entrySet()) { + List tempList = entry.getValue(); + if (tempList.isEmpty()) { + continue; + } + + + String counterpartyName = entry.getKey(); + + + //,比如除了5万还有一个1万,则应该做加总,显示为6万,就是满足条件后把小的金额加总进来。 + boolean flag = false; + for (BankStatement bs : tempList) { + if(bs.getTransactionAmount().abs().compareTo(suspiciousAmount) >= 0){ + flag = true; + break; + } + } + + if(!flag){ + continue; + } + + BigDecimal sumAmount = BigDecimal.ZERO; + + // 转出金额 + BigDecimal transformAmount = BigDecimal.ZERO; + + // 转入金额 + BigDecimal entryAmount = BigDecimal.ZERO; + + Set remarkSet = new HashSet<>(); + + for (BankStatement bs : tempList) { + BigDecimal transactionAmount = bs.getTransactionAmount(); + if(null != transactionAmount){ + sumAmount = sumAmount.add(transactionAmount); + } + + String summary = bs.getSummary(); + String transRemarkTemp = bs.getTransRemark(); + String remark = bs.getRemark(); + if (StrUtil.isNotBlank(summary)) { + remarkSet.add(summary); + } + if (StrUtil.isNotBlank(transRemarkTemp)) { + remarkSet.add(transRemarkTemp); + } + if (StrUtil.isNotBlank(remark)) { + remarkSet.add(remark); + } + + if(transactionAmount.compareTo(BigDecimal.ZERO) < 0){ + transformAmount = transformAmount.add(transactionAmount.negate()); + } + + if(transactionAmount.compareTo(BigDecimal.ZERO) > 0){ + entryAmount = entryAmount.add(transactionAmount); + } + + } + + // 交易备注 + String transRemark = String.join("、", remarkSet); + if(transRemark.length() > 20){ + transRemark = transRemark.substring(0,19) + "...等"; + } + + tempList.sort((o1, o2) -> { + Date t1 = o1.getTransactionTime(); + Date t2 = o2.getTransactionTime(); + return t1.compareTo(t2); + }); + + BankStatement theStartBs = tempList.get(0); + Date startDate = theStartBs.getTransactionTime(); + + BankStatement theEndBs = tempList.get(tempList.size() - 1); + Date endDate = theEndBs.getTransactionTime(); + + if (startDate.compareTo(endDate) > 0) { + Date tmp = startDate; + startDate = endDate; + endDate = tmp; + } + + String format = "yyyy.MM.dd"; + String rangeStr = DateUtil.format(startDate, format) + "-" + DateUtil.format(endDate, format); + + AnalysisReportVo.ConnectedTransItem item = new AnalysisReportVo.ConnectedTransItem(); + item.setName(counterpartyName); + item.setTransDateRange(rangeStr); + item.setTransRemark(transRemark); + item.setTransformAmount(transformAmount); + item.setEntryAmount(entryAmount); + String uniqueKey = BeanUtils.getUniqueKey(item); + String md5Id = HelperUtil.generateMD5(uniqueKey); + if(idSet.contains(md5Id)){ + continue; + } + idSet.add(md5Id); + rst.add(item); + } + } + + + // 排序 + rst.sort(Comparator.comparing(AnalysisReportVo.ConnectedTransItem::getEntryAmount).reversed()); + vo.setSuspiciousItems(rst); + } + + List getBankStatementByCardHolderNameSet(Set cardHolderNameSet, String caseId){ + GetBSFieldValueCountReq req = new GetBSFieldValueCountReq(); + req.setCaseId(caseId); + req.setCardHolderNameSet(cardHolderNameSet); + try { + return bankService.getBSList(req); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + List getBankStatement(String cardHolderName,String idCard, String caseId){ + GetBSFieldValueCountReq req = new GetBSFieldValueCountReq(); + req.setCaseId(caseId); + if(StrUtil.isNotEmpty(cardHolderName)){ + req.setCardHolderName(cardHolderName); + } + + List bsList = new ArrayList<>(); + try { + bsList = bankService.getBSList(req); + } catch (Exception e) { + e.printStackTrace(); + } + + + return bsList; + } + + + /** + * 根据分析对象的流水,以分析对象的交易对手名字为key分组的流水Map + * @param + */ + Map> getCounterpartyBSMap(List mainBsList,String name,String idCard){ + Map> counterpartyBSMap = new HashMap<>(); + for (BankStatement bs : mainBsList) { + + String cardHolderName = bs.getCardHolderName(); + if(StrUtil.isEmpty(cardHolderName)){ + continue; + } + + String counterpartyName = bs.getCounterpartyName(); + if (StrUtil.isEmpty(counterpartyName)) { + continue; + } + +// boolean flag = false; +// for (String invalidStr : INVALID_STR_ARR) { +// if (counterpartyName.contains(invalidStr)){ +// flag = true; +// break; +// } +// } +// +// if(flag){ +// continue; +// } + + if(filterByCounterpartyName(counterpartyName,0)){ + continue; + } + + if (counterpartyName.equals(name)) { + continue; + } + + String bsIdCard = bs.getIdCardNo(); + bsIdCard = bsIdCard == null?"": bsIdCard; + + if(StrUtil.isNotEmpty(name)){//分析人员有名字 + if(StrUtil.isNotEmpty(idCard)){//有身份证 + if(StrUtil.isEmpty(bsIdCard)){//流水里无身份证 + continue; + } + }else {//没有身份证 + if(!Objects.equals(cardHolderName, name)){//没有身份证并且持卡人名字不等于分析人名字 + continue; + } + } + } + + + if (counterpartyName.contains("(特约)")) { + counterpartyName = counterpartyName.replace("(特约)", ""); + } else if (counterpartyName.contains("(特约)")) { + counterpartyName = counterpartyName.replace("(特约)", ""); + } else if (counterpartyName.contains("(信贷还款)")) { + counterpartyName = counterpartyName.replace("(信贷还款)", ""); + } else if (counterpartyName.contains("(商户清结算)")) { + counterpartyName = counterpartyName.replace("(商户清结算)", ""); + } + + + List list = counterpartyBSMap.getOrDefault(counterpartyName, null); + if (list == null) { + counterpartyBSMap.put(counterpartyName, new ArrayList<>()); + } + counterpartyBSMap.get(counterpartyName).add(bs); + } + + mainBsList.clear(); + return counterpartyBSMap; + } + + boolean filterByCounterpartyName(String counterpartyName,int type){ + if(type == 0){ + if (counterpartyName.contains("支付宝") || counterpartyName.contains("微信") || counterpartyName.contains("财付通") + || counterpartyName.contains("基金") || counterpartyName.contains("开店宝") || counterpartyName.contains("证券") + || counterpartyName.contains("现金") ){ + return true; + } + } + if (counterpartyName.contains("钱袋宝") || counterpartyName.contains("拉卡拉") + || counterpartyName.contains("美团") || counterpartyName.contains("客户单利") || counterpartyName.contains("重庆小贷") + || counterpartyName.contains("税务") || counterpartyName.contains("系统") || counterpartyName.contains("存款利息") + || counterpartyName.contains("二维码") || counterpartyName.contains("短信") || counterpartyName.contains("卡通") + || counterpartyName.contains("资金") || counterpartyName.contains("医院")|| counterpartyName.contains("结算") + || counterpartyName.contains("肯德基") || counterpartyName.contains("话费") || counterpartyName.contains("中国") + || counterpartyName.contains("银行") || counterpartyName.contains("税局")|| counterpartyName.contains("信用卡") + || counterpartyName.contains("收入") || counterpartyName.contains("支付")|| counterpartyName.contains("住房公积金管理中心") + || counterpartyName.contains("住房资金")|| counterpartyName.contains("三快科技")|| counterpartyName.contains("曹操出行") + || counterpartyName.contains("生活缴费")|| counterpartyName.contains("中油")|| counterpartyName.contains("中石油") + || counterpartyName.contains("中国石油")|| counterpartyName.contains("中国石化")|| counterpartyName.contains("海油") + || counterpartyName.contains("退汇")|| counterpartyName.contains("转汇") + || counterpartyName.contains("滴滴出行")|| counterpartyName.contains("快钱支付")|| counterpartyName.contains("充值") + || counterpartyName.contains("手续费")|| counterpartyName.contains("停车")|| counterpartyName.contains("专户") + || counterpartyName.contains("国家金库")|| counterpartyName.contains("抖音")|| counterpartyName.contains("商户") + || counterpartyName.contains("工本费")|| counterpartyName.contains("0")|| counterpartyName.contains("利息") + || counterpartyName.contains("还款")|| counterpartyName.contains("收款")|| counterpartyName.contains("面对面") + || counterpartyName.contains("代收")|| counterpartyName.contains("ETC") + || counterpartyName.contains("网银在线")|| counterpartyName.contains("代扣户")|| counterpartyName.contains("拼多多") + || counterpartyName.contains("唯品会")|| counterpartyName.contains("转汇专户")|| counterpartyName.contains("特约商户") + || counterpartyName.contains("应付")|| counterpartyName.contains("代扣") + || counterpartyName.contains("丰巢")|| counterpartyName.contains("宝付")|| counterpartyName.contains("平安付") + || counterpartyName.contains("过渡户") || counterpartyName.contains("过渡") || counterpartyName.contains("专用户")|| counterpartyName.contains("保险") + || counterpartyName.contains("中国银联")|| counterpartyName.contains("百付宝")|| counterpartyName.contains("直付通") + || counterpartyName.contains("乘车码")|| counterpartyName.contains("管理费") + || counterpartyName.contains("云闪付")|| counterpartyName.contains("中间业务") + || counterpartyName.contains("度小满")|| counterpartyName.contains("暂收") + || counterpartyName.contains("消费金融")|| counterpartyName.contains("分行运营管理部") + || counterpartyName.contains("缴费")|| counterpartyName.equals("@") + || counterpartyName.contains("合众易宝")|| counterpartyName.contains("备付金") + || counterpartyName.contains("汽车金融")|| counterpartyName.contains("盛付通") + || counterpartyName.contains("食堂")|| counterpartyName.contains("清算") + ) { + return true; + } + return false; + } + + + /** + * 内部人员涉嫌关联交易 + */ + private List getInnerTransItems(List mainBsList, String name,String idCard, String caseId) { + + //用于-内部人员直接关系:A的银行流水中直接出现了B的名字 + Map> tpBsCNameAndCardMap = new HashMap<>(); + + //用于-内部人员间接关系:A流水中出现的名字C,在所有的B的流水中也出现了,则是间接关系 + Map> tpBsCNameAndCounterpartMap = new HashMap<>(); + List rst = new ArrayList<>(); + //交易对象 以所有名称字段拼接key,对象为value + Map tpMap = getTransactionPartnerMap(caseId); + if (CollectionUtil.isEmpty(tpMap)) { + return rst; + } + + Set tpCardHolderNameSet = new HashSet<>(); + for (TransactionPartner transactionPartner : tpMap.values()) { + if(StrUtil.isNotBlank(transactionPartner.getTravellingTrader())){ + tpCardHolderNameSet.add(transactionPartner.getTravellingTrader()); + } + + String stockholder = transactionPartner.getStockholder(); + if(StrUtil.isNotEmpty(stockholder)){ + if(stockholder.contains(",")){ + String[] split = stockholder.split(","); + for (String s : split) { + tpCardHolderNameSet.add(s); + } + }else if(stockholder.contains("、")){ + String[] split = stockholder.split("、"); + for (String s : split) { + tpCardHolderNameSet.add(s); + } + }else if(stockholder.contains(";")){ + String[] split = stockholder.split(";"); + for (String s : split) { + tpCardHolderNameSet.add(s); + } + }else { + tpCardHolderNameSet.add(stockholder); + } + } + String stockholderRelated = transactionPartner.getStockholderRelated(); + if(StrUtil.isNotEmpty(stockholderRelated)){ + if(stockholderRelated.contains(",")){ + String[] split = stockholderRelated.split(","); + for (String s : split) { + tpCardHolderNameSet.add(s); + } + }else if(stockholderRelated.contains("、")){ + String[] split = stockholderRelated.split("、"); + for (String s : split) { + tpCardHolderNameSet.add(s); + } + }else if(stockholderRelated.contains(";")){ + String[] split = stockholderRelated.split(";"); + for (String s : split) { + tpCardHolderNameSet.add(s); + } + }else { + tpCardHolderNameSet.add(stockholderRelated); + } + } + String relateCompany = transactionPartner.getRelateCompany(); + if(StrUtil.isNotEmpty(relateCompany)){ + if(relateCompany.contains(",")){ + String[] split = relateCompany.split(","); + for (String s : split) { + tpCardHolderNameSet.add(s); + } + }else if(relateCompany.contains("、")){ + String[] split = relateCompany.split("、"); + for (String s : split) { + tpCardHolderNameSet.add(s); + } + }else if(relateCompany.contains(";")){ + String[] split = relateCompany.split(";"); + for (String s : split) { + tpCardHolderNameSet.add(s); + } + }else { + tpCardHolderNameSet.add(relateCompany); + } + } + } + if(tpCardHolderNameSet.contains(name)){ + tpCardHolderNameSet.remove(name); + } + List tpBsList = getBankStatementByCardHolderNameSet(tpCardHolderNameSet, caseId); + if (CollectionUtil.isEmpty(tpBsList)) { + return rst; + } + GetPersonReq req = new GetPersonReq(); + req.setCaseId(caseId); + List personInfo = bankService.getPersonInfo(req); + Map groupByLabel = personInfo.stream() + .filter(item -> StrUtil.isNotEmpty(item.getLabel())) + .collect(Collectors.toMap(AnalysisPerson::getLabel, AnalysisPerson::getType)); + + + // 根据交易对象流水获取 1交易对象名字为key,交易对象的卡号为value的Map 2交易对象名字为key,交易对象的交易对手的名字为value的Map + for (BankStatement item : tpBsList) { + String cardHolderName = item.getCardHolderName(); + if (StrUtil.isEmpty(cardHolderName)) { + continue; + } + String cardNumber = item.getCardNumber(); + String counterpartyName = item.getCounterpartyName(); + + if (StrUtil.isNotEmpty(cardNumber)) { + Set cardSet; + if (tpBsCNameAndCardMap.containsKey(cardHolderName)) { + cardSet = tpBsCNameAndCardMap.get(cardHolderName); + } else { + cardSet = new HashSet<>(); + } + cardSet.add(cardNumber); + tpBsCNameAndCardMap.put(cardHolderName, cardSet); + } + + if (StrUtil.isNotEmpty(counterpartyName)) { + List tempBsList; + if (tpBsCNameAndCounterpartMap.containsKey(cardHolderName)) { + tempBsList = tpBsCNameAndCounterpartMap.get(cardHolderName); + } else { + tempBsList = new ArrayList<>(); + } + tempBsList.add(item); + tpBsCNameAndCounterpartMap.put(cardHolderName, tempBsList); + } + + } + + + // 根据分析对象的流水,以分析对象的交易对手名字为key分组的流水Map + Map> mainCounterpartyMap = getCounterpartyBSMap(mainBsList, name, idCard); + + for (Map.Entry> entry : mainCounterpartyMap.entrySet()) { + String counterpartyName = entry.getKey(); + + if(counterpartyName.equals(name)){ + continue; + } + + List counterpartyNameMainList = entry.getValue(); + if (counterpartyNameMainList.isEmpty()) { + continue; + } + //counterpartyAccountSet 主体流水中提取的交易对手卡号 + Set mainCounterpartyAccountSet = counterpartyNameMainList.stream().filter(item -> StrUtil.isNotEmpty(item.getCounterpartyAccount())).map(BankStatement::getCounterpartyAccount).collect(Collectors.toSet()); + + AnalysisReportVo.ConnectedTransItem connectedTransItem = new AnalysisReportVo.ConnectedTransItem(); + connectedTransItem.setName(counterpartyName); + + //直接关系:从A的银行流水,及交易对象表格查找 A的银行流水中直接出现了B的名字 开始 + if (tpBsCNameAndCardMap.keySet().contains(counterpartyName)) { + connectedTransItem.setRemark("直接关联,仅名称相同,需确认"); + if (CollectionUtil.isNotEmpty(mainCounterpartyAccountSet)) { + Set tempCardSet = tpBsCNameAndCardMap.get(counterpartyName); + mainCounterpartyAccountSet.retainAll(tempCardSet); + if (CollectionUtil.isNotEmpty(mainCounterpartyAccountSet)) {//取交集 + connectedTransItem.setRemark("直接关联,名称和卡号相同"); + } + } + connectedTransactionCommonMethod(tpMap,counterpartyName,connectedTransItem,counterpartyNameMainList); + + rst.add(connectedTransItem); + //直接关系:从A的银行流水,及交易对象表格查找 A的银行流水中直接出现了B的名字 结束 + }else { + //间接关系 + for(Map.Entry> tpEntry : tpBsCNameAndCounterpartMap.entrySet()){ + String tpCardHolderName = tpEntry.getKey(); + + List bsList = tpEntry.getValue(); + Set tpCounterpartyAccountSet = bsList.stream().filter(item -> StrUtil.isNotEmpty(item.getCounterpartyAccount())).map(BankStatement::getCounterpartyAccount).collect(Collectors.toSet()); + Set tpCounterpartyNameSet = bsList.stream().filter(item -> StrUtil.isNotEmpty(item.getCounterpartyName())).map(BankStatement::getCounterpartyName).collect(Collectors.toSet()); + + //括内部人,也不包括自己。比如敖云松的报告,就不包括内部人藏美芳,因为他们是同事、必然是间接关系(有共同的交易对象即公司给他们发工资), + Integer personType = groupByLabel.get(tpCardHolderName); + if(tpCounterpartyNameSet.contains(counterpartyName) && personType != 0){//间接关系 A流水中出现的名字C,在所有的B的流水中也出现了,则是AB间接关系 + AnalysisReportVo.ConnectedTransItem indirectItem = new AnalysisReportVo.ConnectedTransItem(); + indirectItem.setName(counterpartyName); + indirectItem.setRemark("间接关联,该交易对象与本单位客户"+tpCardHolderName+"有疑似经济往来,仅名称相同,需确认"); + if (CollectionUtil.isNotEmpty(mainCounterpartyAccountSet)) { + mainCounterpartyAccountSet.retainAll(tpCounterpartyAccountSet); + if (CollectionUtil.isNotEmpty(mainCounterpartyAccountSet)) {//取交集 + indirectItem.setRemark("间接关联,该交易对象与本单位客户"+tpCardHolderName+"有经济往来"); + } + } + connectedTransactionCommonMethod(tpMap,counterpartyName,indirectItem,counterpartyNameMainList); + rst.add(indirectItem); + } + } + } + } + return rst; + } + + + /** + * 外部人员涉嫌关联交易 + */ + private List getOutSideTransItems(List mainBsList, String name,String idCard, String caseId) { + + //用于-内部人员直接关系:A的银行流水中直接出现了B的名字 + Map> familyBsCNameAndCardMap = new HashMap<>(); + + //用于-内部人员间接关系:A流水中出现的名字C,在所有的B的流水中也出现了,则是间接关系 + Map> familyBsCNameAndCounterpartMap = new HashMap<>(); + List rst = new ArrayList<>(); + //交易对象 以所有名称字段拼接key,对象为value + Map familyMap = getFamilyMap(caseId); + if (CollectionUtil.isEmpty(familyMap)) { + return rst; + } + + Map tpMap = getTransactionPartnerMap(caseId); + + Set cardHolderNameSet = new HashSet<>(); + for (PublicFamily family : familyMap.values()) { + if(StrUtil.isNotEmpty(family.getName())){ + cardHolderNameSet.add(family.getName()); + } + if(StrUtil.isNotEmpty(family.getMemberName1())){ + cardHolderNameSet.add(family.getMemberName1()); + } + if(StrUtil.isNotEmpty(family.getMemberName2())){ + cardHolderNameSet.add(family.getMemberName2()); + } + if(StrUtil.isNotEmpty(family.getMemberName3())){ + cardHolderNameSet.add(family.getMemberName3()); + } + if(StrUtil.isNotEmpty(family.getMemberName4())){ + cardHolderNameSet.add(family.getMemberName4()); + } + if(StrUtil.isNotEmpty(family.getMemberName5())){ + cardHolderNameSet.add(family.getMemberName5()); + } + if(StrUtil.isNotEmpty(family.getMemberName6())){ + cardHolderNameSet.add(family.getMemberName6()); + } + if(StrUtil.isNotEmpty(family.getMemberName7())){ + cardHolderNameSet.add(family.getMemberName7()); + } + } + if(cardHolderNameSet.contains(name)){ + cardHolderNameSet.remove(name); + } + List familyBsList = getBankStatementByCardHolderNameSet(cardHolderNameSet, caseId); + if (CollectionUtil.isEmpty(familyBsList)) { + return rst; + } + + // 根据交易对象流水获取 1交易对象名字为key,交易对象的卡号为value的Map 2交易对象名字为key,交易对象的交易对手的名字为value的Map + for (BankStatement item : familyBsList) { + String cardHolderName = item.getCardHolderName(); + if (StrUtil.isEmpty(cardHolderName)) { + continue; + } + String cardNumber = item.getCardNumber(); + String counterpartyName = item.getCounterpartyName(); + + if (StrUtil.isNotEmpty(cardNumber)) { + Set cardSet; + if (familyBsCNameAndCardMap.containsKey(cardHolderName)) { + cardSet = familyBsCNameAndCardMap.get(cardHolderName); + } else { + cardSet = new HashSet<>(); + } + cardSet.add(cardNumber); + familyBsCNameAndCardMap.put(cardHolderName, cardSet); + } + + if (StrUtil.isNotEmpty(counterpartyName)) { + List tempBsList; + if (familyBsCNameAndCounterpartMap.containsKey(cardHolderName)) { + tempBsList = familyBsCNameAndCounterpartMap.get(cardHolderName); + } else { + tempBsList = new ArrayList<>(); + } + tempBsList.add(item); + familyBsCNameAndCounterpartMap.put(cardHolderName, tempBsList); + } + + } + + + // 根据分析对象的流水,以分析对象的交易对手名字为key分组的流水Map + Map> mainCounterpartyMap = getCounterpartyBSMap(mainBsList, name, idCard); + + for (Map.Entry> entry : mainCounterpartyMap.entrySet()) { + String counterpartyName = entry.getKey(); + if(counterpartyName.equals(name)){ + continue; + } + List counterpartyNameMainList = entry.getValue(); + if (counterpartyNameMainList.isEmpty()) { + continue; + } + //counterpartyAccountSet 主体流水中提取的交易对手卡号 + Set mainCounterpartyAccountSet = counterpartyNameMainList.stream().filter(item -> StrUtil.isNotEmpty(item.getCounterpartyAccount())).map(BankStatement::getCounterpartyAccount).collect(Collectors.toSet()); + + AnalysisReportVo.ConnectedTransItem connectedTransItem = new AnalysisReportVo.ConnectedTransItem(); + connectedTransItem.setName(counterpartyName); + + //直接关系:从A的银行流水,及交易对象表格查找 A的银行流水中直接出现了B的名字 开始 + if (familyBsCNameAndCardMap.keySet().contains(counterpartyName)) { + connectedTransItem.setRemark("直接关联,仅名称相同,需确认"); + if (CollectionUtil.isNotEmpty(mainCounterpartyAccountSet)) { + Set tempCardSet = familyBsCNameAndCardMap.get(counterpartyName); + mainCounterpartyAccountSet.retainAll(tempCardSet); + if (CollectionUtil.isNotEmpty(mainCounterpartyAccountSet)) {//取交集 + connectedTransItem.setRemark("直接关联,名称和卡号相同"); + } + } + connectedTransactionCommonMethod(tpMap,counterpartyName,connectedTransItem,counterpartyNameMainList); + rst.add(connectedTransItem); + //直接关系:从A的银行流水,及交易对象表格查找 A的银行流水中直接出现了B的名字 结束 + }else { + //间接关系 + for(Map.Entry> tpEntry : familyBsCNameAndCounterpartMap.entrySet()){ + String key = tpEntry.getKey(); + List bsList = tpEntry.getValue(); + Set tpCounterpartyAccountSet = bsList.stream().filter(item -> StrUtil.isNotEmpty(item.getCounterpartyAccount())).map(BankStatement::getCounterpartyAccount).collect(Collectors.toSet()); + Set tpCounterpartyNameSet = bsList.stream().filter(item -> StrUtil.isNotEmpty(item.getCounterpartyName())).map(BankStatement::getCounterpartyName).collect(Collectors.toSet()); + + if(tpCounterpartyNameSet.contains(counterpartyName)){//间接关系 A流水中出现的名字C,在所有的B的流水中也出现了,则是AB间接关系 + AnalysisReportVo.ConnectedTransItem indirectItem = new AnalysisReportVo.ConnectedTransItem(); + indirectItem.setName(counterpartyName); + indirectItem.setRemark("间接关联,该交易对象与本单位员工或其亲属"+key+"有疑似经济往来,仅名称相同,需确认"); + if (CollectionUtil.isNotEmpty(mainCounterpartyAccountSet)) { + mainCounterpartyAccountSet.retainAll(tpCounterpartyAccountSet); + if (CollectionUtil.isNotEmpty(mainCounterpartyAccountSet)) {//取交集 + indirectItem.setRemark("间接关联,该交易对象与本单位员工或其亲属"+key+"有经济往来"); + } + } + connectedTransactionCommonMethod(tpMap,counterpartyName,indirectItem,counterpartyNameMainList); + rst.add(indirectItem); + } + } + } + } + return rst; + } + + + void setCounterpartyIdentityValue(Map tpMap,String counterpartyName,AnalysisReportVo.ConnectedTransItem connectedTransItem){ + // 设置交易对象身份 开始 + Map> counterpartyIdentityMap = new HashMap<>(); + for (String nameAppend : tpMap.keySet()) { + if (!nameAppend.contains(counterpartyName)) { + continue; + } + TransactionPartner transactionPartner = tpMap.get(nameAppend); + String transactionAmount = transactionPartner.getTransactionAmount(); + if (!NumberUtil.isNumber(transactionAmount)) { + transactionAmount = "0"; + } + + // 关联交易情况 + connectedTransItem.setRelatedPartyTransactions(new BigDecimal(transactionAmount)); + // 欠款情况 + connectedTransItem.setDebitAmount(transactionPartner.getDebt() == null ? BigDecimal.ZERO : transactionPartner.getDebt()); + + String counterpartyIdentity = transactionPartner.getTravellingTrader(); + // 交易对象身份 + if (StrUtil.isNotBlank(transactionPartner.getStockholder()) + && transactionPartner.getStockholder().contains(counterpartyName)) { + Set stockholderSet = counterpartyIdentityMap.get("股东及高管"); + if (stockholderSet == null) { + stockholderSet = new HashSet<>(); + } + stockholderSet.add(counterpartyIdentity); + counterpartyIdentityMap.put("股东及高管", stockholderSet); + } else if (StrUtil.isNotBlank(transactionPartner.getStockholderRelated()) + && transactionPartner.getStockholderRelated().contains(counterpartyName)) { + Set stockholderSet = counterpartyIdentityMap.get("关联人"); + if (stockholderSet == null) { + stockholderSet = new HashSet<>(); + } + stockholderSet.add(counterpartyIdentity); + } else if (StrUtil.isNotBlank(transactionPartner.getRelateCompany()) + && transactionPartner.getRelateCompany().contains(counterpartyName)) { + Set stockholderSet = counterpartyIdentityMap.get("关联企业"); + if (stockholderSet == null) { + stockholderSet = new HashSet<>(); + } + stockholderSet.add(counterpartyIdentity); + } + } + String counterpartyIdentity = ""; + for (String s : counterpartyIdentityMap.keySet()) { + Set strings = counterpartyIdentityMap.get(s); + counterpartyIdentity = String.join(",", strings); + counterpartyIdentity += s; + } + if (StrUtil.isNotEmpty(counterpartyIdentity)) { + connectedTransItem.setCounterpartyIdentity(counterpartyName + "为" + counterpartyIdentity); + } + } + + + void connectedTransactionCommonMethod(Map tpMap,String counterpartyName, + AnalysisReportVo.ConnectedTransItem connectedTransItem, + List mainList){ + + setCounterpartyIdentityValue(tpMap,counterpartyName,connectedTransItem); + + // 设置交易对象身份 结束 + + mainList.sort((o1, o2) -> { + Date t1 = o1.getTransactionTime(); + Date t2 = o2.getTransactionTime(); + return t1.compareTo(t2); + }); + + BankStatement theStartBs = mainList.get(0); + Date startDate = theStartBs.getTransactionTime(); + + BankStatement theEndBs = mainList.get(mainList.size() - 1); + Date endDate = theEndBs.getTransactionTime(); + + if (startDate.compareTo(endDate) > 0) { + Date tmp = startDate; + startDate = endDate; + endDate = tmp; + } + + String format = "yyyy.MM"; + String rangeStr = DateUtil.format(startDate, format) + "-" + DateUtil.format(endDate, format); + + + connectedTransItem.setTransDateRange(rangeStr); + // 转出金额 + Optional opt = mainList.stream() + .filter(bs -> bs.getTransactionAmount() != null) + .filter(bs -> bs.getTransactionAmount().compareTo(BigDecimal.ZERO) < 0) + .map(bs -> bs.getTransactionAmount().negate()) + .reduce(BigDecimal::add); + BigDecimal transformAmount = opt.orElseGet(() -> BigDecimal.ZERO); + connectedTransItem.setTransformAmount(transformAmount); + // 转入金额 + opt = mainList.stream() + .filter(bs -> bs.getTransactionAmount() != null) + .map(BankStatement::getTransactionAmount) + .filter(transactionAmount -> transactionAmount.compareTo(BigDecimal.ZERO) > 0) + .reduce(BigDecimal::add); + BigDecimal entryAmount = opt.orElseGet(() -> BigDecimal.ZERO); + connectedTransItem.setEntryAmount(entryAmount); + // 交易备注 + Set transRemarkList = null; + Set> collect = mainList.stream() + .map(bs -> { + String summary = bs.getSummary(); + String transRemark = bs.getTransRemark(); + String remark = bs.getRemark(); + + Set sb = new HashSet<>(); + if (StrUtil.isNotBlank(summary)) { + sb.add(handleString(summary)); + } + + if (StrUtil.isNotBlank(transRemark)) { + sb.add(handleString(transRemark)); + } + + if (StrUtil.isNotBlank(remark)) { + sb.add(handleString(remark)); + } + + return sb; + }) + .filter(it -> !it.isEmpty()) + .collect(Collectors.toSet()); + transRemarkList = collect.stream().flatMap(Collection::stream).collect(Collectors.toSet()); + String transRemark = String.join("、", transRemarkList); + if (transRemark.length() > 20) { + transRemark = transRemark.substring(0, 19) + "...等"; + } + connectedTransItem.setTransRemark(transRemark); + } + + /** + * 涉嫌关联交易 + */ + private void handleConnectedTransaction(JSONObject esData, AnalysisReportVo vo, String caseId) { + if (!esData.containsKey("dc_bank_statement")) { + return; + } + String name = vo.getName(); + if(StrUtil.isEmpty(name)){ + return; + } + List mainBsList = esData.getBeanList("dc_bank_statement", BankStatement.class); + List rst = null; + + + String idCard = vo.getIdCard(); + + String personTypeStr = "与本单位的交易对象或其股东有直接或间接重合,"; + if(vo.getPersonType() == 0){ //内部,交易对象不能为空 + rst = getInnerTransItems(mainBsList, name, idCard, caseId); + }else if(vo.getPersonType() == 1){ //外部,家属表不能为空 + personTypeStr = "与本单位员工或其亲属有直接或间接重合,"; + rst = getOutSideTransItems(mainBsList, name, idCard, caseId); + } + + List result = new ArrayList<>(); + result.addAll(rst); + + vo.setPersonTypeStr(personTypeStr); + + if(CollectionUtil.isNotEmpty(result)){ + // 按照 balance 和 transactionAmount 倒序排序银行流水账单列表 + result.sort(Comparator.comparing(AnalysisReportVo.ConnectedTransItem::getDebitAmount).reversed() + .thenComparing(AnalysisReportVo.ConnectedTransItem::getRelatedPartyTransactions).reversed() + .thenComparing(AnalysisReportVo.ConnectedTransItem::getEntryAmount).reversed() + .thenComparing(AnalysisReportVo.ConnectedTransItem::getTransformAmount).reversed()); + } + + vo.setTransItems(result); + } + + + private Map getTransactionPartnerMap(String caseId) { + Map tpMap = new HashMap<>(); + BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); + boolQuery.must(QueryBuilders.termQuery("caseId", caseId)); + JSONObject result = new JSONObject(); + queryCenterService.scrollSearch("dc_transaction_partner", boolQuery, result); + if (result.containsKey("dc_transaction_partner")) { + List tpList = result.getBeanList("dc_transaction_partner", TransactionPartner.class); + for (TransactionPartner transactionPartner : tpList) { + StringBuilder tpSb = new StringBuilder(); + tpSb.append(transactionPartner.getTravellingTrader()).append(","); + tpSb.append(transactionPartner.getStockholder()).append(","); + tpSb.append(transactionPartner.getStockholderRelated()).append(","); + tpSb.append(transactionPartner.getRelateCompany()).append(","); + String key = tpSb.toString(); + tpMap.put(key, transactionPartner); + } + } + return tpMap; + } + + private Map getFamilyMap(String caseId) { + Map tpMap = new HashMap<>(); + BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); + boolQuery.must(QueryBuilders.termQuery("caseId", caseId)); + JSONObject result = new JSONObject(); + queryCenterService.scrollSearch("dc_public_family", boolQuery, result); + if (result.containsKey("dc_public_family")) { + List tpList = result.getBeanList("dc_public_family", PublicFamily.class); + for (PublicFamily family : tpList) { + StringBuilder tpSb = new StringBuilder(); + tpSb.append(family.getName()).append(","); + tpSb.append(family.getMemberName1()).append(","); + tpSb.append(family.getMemberName2()).append(","); + tpSb.append(family.getMemberName3()).append(","); + tpSb.append(family.getMemberName4()).append(","); + tpSb.append(family.getMemberName5()).append(","); + tpSb.append(family.getMemberName6()).append(","); + tpSb.append(family.getMemberName7()).append(","); + String key = tpSb.toString(); + tpMap.put(key, family); + } + } + return tpMap; + } + + + private static String handleString(String str) { + + str = str.replaceAll(" ", ""); + + return str.trim(); + } + + private void setValueByOtherAssets(JSONObject esData, AnalysisReportVo vo) { + if (!esData.containsKey("dc_other_assets")) { + return; + } + List otherAssets = esData.getBeanList("dc_other_assets", OtherAssetsDto.class); + int index = 0; + for (OtherAssetsDto otherAsset : otherAssets) { + index++; + otherAsset.setOriginalName(index + "."+otherAsset.getOriginalName() + "(详见数据中心-其他信息)"); + } + vo.setOtherAssetsInfo(otherAssets); + } + + private void setValueByOtherInformation(JSONObject esData, AnalysisReportVo vo) { + if (!esData.containsKey("dc_other_information")) { + return; + } + List otherInformationList = esData.getBeanList("dc_other_information", OtherAssetsDto.class); + int index = 0; + for (OtherAssetsDto otherAsset : otherInformationList) { + index++; + otherAsset.setOriginalName(index+ "."+otherAsset.getOriginalName() + "(详见数据中心-其他信息)"); + } + vo.setOtherInformationInfo(otherInformationList); + } + + /** + * 账户总体情况 + */ + private void handleOverallAccountInfo(JSONObject esData, AnalysisReportVo vo) { + if (!esData.containsKey("dc_bank_statement")) { + return; + } + + // 分析流水 + List bsList = esData.getBeanList("dc_bank_statement", BankStatement.class); + + Map> groupByCard = bsList.stream().filter(i ->StrUtil.isNotEmpty(i.getCardNumber())).collect(Collectors.groupingBy(BankStatement::getCardNumber)); + + // 账户总体情况 + List lzditemList = new ArrayList<>(); + for (String card : groupByCard.keySet()) { + List bankStatements = groupByCard.get(card); + BankStatement bankStatement = bankStatements.get(0); + String cardHolderName = bankStatement.getCardHolderName() == null?"":bankStatement.getCardHolderName(); + String idCardNo = bankStatement.getIdCardNo() == null?"":bankStatement.getIdCardNo(); + + if(StrUtil.isNotEmpty(vo.getName()) && StrUtil.isNotEmpty(vo.getIdCard())){ + if(StrUtil.isEmpty(idCardNo) && StrUtil.isNotEmpty((cardHolderName))){ + if(!cardHolderName.equals(vo.getName())){ + continue; + } + } else if(StrUtil.isEmpty(cardHolderName) && StrUtil.isNotEmpty(idCardNo)){ + if(!idCardNo.equals(vo.getIdCard())){ + continue; + } + }else if(!(cardHolderName.equals(vo.getName()) && idCardNo.equals(vo.getIdCard()))){ + continue; + } + + + }else if(StrUtil.isNotEmpty(vo.getName()) && StrUtil.isEmpty(vo.getIdCard())){ + if(!cardHolderName.equals(vo.getName())){ + continue; + } + }else if(StrUtil.isEmpty(vo.getName()) && StrUtil.isNotEmpty(vo.getIdCard())){ + if(!idCardNo.equals(vo.getIdCard())){ + continue; + } + }else if(StrUtil.isEmpty(vo.getName()) && StrUtil.isEmpty(vo.getIdCard())){ + continue; + } + + AnalysisReportVo.BSItem bsItem = new AnalysisReportVo.BSItem(); + + Optional entryAmountOpt = bankStatements.stream() + .filter(item -> (item.getTransactionAmount() == null ? BigDecimal.ZERO:item.getTransactionAmount()).compareTo(BigDecimal.ZERO) > 0) + .map(item -> item.getTransactionAmount()) + .reduce(BigDecimal::add); + BigDecimal entryAmount = entryAmountOpt.orElseGet(() -> new BigDecimal("0.00")); +// entryAmount = entryAmount.divide(new BigDecimal("10000")).setScale(2, RoundingMode.HALF_UP); + bsItem.setEntryAmount(entryAmount); + + + // 按照 transactionTime 排序,取出 transactionTime 最大的那条数据 + Optional balanceOpt = bankStatements.stream().filter(item -> item.getTransactionTime() != null) + .max(Comparator.comparing(BankStatement::getTransactionTime)); + + BankStatement tempBs = balanceOpt.get(); +// tempBs.getBalance().divide(new BigDecimal("10000")).setScale(2, RoundingMode.HALF_UP) + BigDecimal balance = tempBs.getBalance(); + if(balance == null){ + balance = BigDecimal.ZERO; + } + bsItem.setBalance(balance); + + bsItem.setAccountNumber(card); + bsItem.setBankName(bankStatement.getBankName()); + lzditemList.add(bsItem); + } +// 按照银行名称排序银行流水账单列表 + lzditemList.sort(Comparator.comparing(AnalysisReportVo.BSItem::getBankName)); + + AnalysisReportVo.BSItem total = new AnalysisReportVo.BSItem(); + total.setBankName("合计"); + BigDecimal totalBalance = lzditemList.stream() + .filter(item -> item.getBalance() != null) + .map(AnalysisReportVo.BSItem::getBalance) + .reduce(BigDecimal.ZERO, BigDecimal::add); + total.setBalance(totalBalance); + BigDecimal totalEntryAmount = lzditemList.stream() + .filter(item -> item.getEntryAmount() != null) + .map(AnalysisReportVo.BSItem::getEntryAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add); + total.setEntryAmount(totalEntryAmount); + lzditemList.add(total); + //xiexiesmjb + vo.setAccountCount(lzditemList.size()); + vo.setItemList(lzditemList); + vo.setEntryAmount(totalEntryAmount.divide(new BigDecimal("10000")).setScale(2, RoundingMode.HALF_UP)); + vo.setBalance(totalBalance.divide(new BigDecimal("10000")).setScale(2, RoundingMode.HALF_UP)); + } + + private void setValueByCarInfo(JSONObject esData, AnalysisReportVo vo) { + if (!esData.containsKey("dc_car_info")) { + return; + } + List list = esData.getBeanList("dc_car_info", CarInfo.class); + List carInfos = new ArrayList<>(); + int carCount = 0; + for (CarInfo p : list) { + if (vo.getName().equals(p.getName().trim())) { + carInfos.add(p); + carCount++; + } + } + vo.setCarCount(carCount); + vo.setCarInfos(carInfos); + } + + private void setValueByRealEstate(JSONObject esData, AnalysisReportVo vo) { + if (!esData.containsKey("dc_real_estate")) { + return; + } + List list = esData.getBeanList("dc_real_estate", RealEstate.class); + List houseInfos = new ArrayList<>(); + BigDecimal houseArea = new BigDecimal(0); + BigDecimal houseValue = new BigDecimal(0); + int carCount = 0; + for (RealEstate p : list) { + // String transferInformation = StrUtil.isEmpty(p.getTransferInformation()) ? "" : + // p.getTransferInformation(); + // String otherInformation = StrUtil.isEmpty(p.getOtherInformation()) ? "" : + // p.getOtherInformation(); + // String remark = StrUtil.isEmpty(p.getRemark()) ? "" : p.getRemark(); + // if (vo.getName().equals(p.getName()) + // && !(StrUtil.isEmpty(transferInformation) + // && StrUtil.isEmpty(otherInformation) + // && StrUtil.isEmpty(remark))) { + // + // if (transferInformation.contains(vo.getIdCard()) + // || otherInformation.contains(vo.getIdCard()) + // || remark.contains(vo.getIdCard())) { + // houseInfos.add(p); + // houseArea = houseArea.add(p.getArea()); + // houseValue = houseValue.add(p.getValuation()); + // carCount++; + // } + // } + + if (vo.getName().equals(p.getName())) { + houseInfos.add(p); + houseArea = houseArea.add(p.getArea() == null ? new BigDecimal(BigInteger.ZERO) : p.getArea()); + houseValue = + houseValue.add(p.getValuation() == null ? new BigDecimal(BigInteger.ZERO) : p.getValuation()); + carCount++; + } + } + vo.setHouseArea(houseArea.toString()); + vo.setHouseValue(houseValue.toString()); + vo.setHouseCount(carCount); + vo.setHouseInfos(houseInfos); + } + + private void setValueByPublicFamily(JSONObject esData, AnalysisReportVo vo) { + if (!esData.containsKey("dc_public_family")) { + return; + } + List list = esData.getBeanList("dc_public_family", PublicFamily.class); + for (PublicFamily p : list) { + if(ObjUtil.isNull(p) || ObjUtil.isNull(vo) ){ + continue; + } + if(StrUtil.isEmpty(vo.getName()) || StrUtil.isEmpty(p.getName())){ + continue; + } + if (vo.getName().equals(p.getName())) { + if (StrUtil.isNotEmpty(vo.getIdCard())) { + if (!vo.getIdCard().equals(p.getIdCard().trim())) { + continue; + } + } + vo.setCompany(p.getEnterpriseName()+"员工"); +// vo.setNativePlace(p.getNativePlace()); + StringBuffer relationPersonSb = new StringBuffer(); + + if(StrUtil.isNotEmpty(p.getMemberRelation1())){ + relationPersonSb.append(p.getMemberRelation1()).append("-").append(p.getMemberName1()).append("、"); + } + if(StrUtil.isNotEmpty(p.getMemberRelation2())){ + relationPersonSb.append(p.getMemberRelation2()).append("-").append(p.getMemberName2()).append("、"); + } + if(StrUtil.isNotEmpty(p.getMemberRelation3())){ + relationPersonSb.append(p.getMemberRelation3()).append("-").append(p.getMemberName3()).append("、"); + } + if(StrUtil.isNotEmpty(p.getMemberRelation4())){ + relationPersonSb.append(p.getMemberRelation4()).append("-").append(p.getMemberName4()).append("、"); + } + if(StrUtil.isNotEmpty(p.getMemberRelation5())){ + relationPersonSb.append(p.getMemberRelation5()).append("-").append(p.getMemberName5()).append("、"); + } + if(StrUtil.isNotEmpty(p.getMemberRelation6())){ + relationPersonSb.append(p.getMemberRelation6()).append("-").append(p.getMemberName6()).append("、"); + } + if(StrUtil.isNotEmpty(p.getMemberRelation7())){ + relationPersonSb.append(p.getMemberRelation7()).append("-").append(p.getMemberName7()).append("、"); + } + if(relationPersonSb.length() > 1){ + relationPersonSb.deleteCharAt(relationPersonSb.length() -1); + } + vo.setRelationPerson(relationPersonSb.toString()); + break; + } + } + + if (esData.containsKey("dc_transaction_partner")) { + Set companyNameSet = new HashSet<>(); + List transactionPartnerList = esData.getBeanList("dc_transaction_partner", TransactionPartner.class); + for (TransactionPartner tp : transactionPartnerList) { + if (StrUtil.isNotEmpty(tp.getStockholder()) && tp.getStockholder().contains(vo.getName())) { + companyNameSet.add(tp.getTravellingTrader()); + } + } + for (String companyName : companyNameSet) { + vo.setCompany(vo.getCompany() + ","+companyName+"股东及高管"); + } + } + } + + private void setPhoneByBankStatement(JSONObject esData, AnalysisReportVo vo) { + if (!esData.containsKey("dc_bank_statement")) { + return; + } + List list = esData.getBeanList("dc_bank_statement", BankStatement.class); + Set phoneSet = new HashSet<>(); + for (BankStatement p : list) { + if (!(StrUtil.isNotBlank(p.getCardHolderName()) && StrUtil.isNotBlank(p.getIdCardNo()))) { + continue; + } + if (vo.getName().equals(p.getCardHolderName().trim()) && StrUtil.isNotEmpty(p.getPhone())) { + if (StrUtil.isNotEmpty(vo.getIdCard())){ + if (!vo.getIdCard().equals(p.getIdCardNo().trim())) { + continue; + } + } + phoneSet.add(p.getPhone()); + } + } + if (StrUtil.isNotEmpty(vo.getPhone())) { + phoneSet.add(vo.getPhone()); + } + vo.setPhone(CollectionUtil.join(phoneSet, ",")); + } + + @Override + public Boolean update(AnalysisReport update) { + return baseMapper.updateById(update) > 0; + } + + @Override + public Boolean deleteWithValidByIds(Collection ids) { + return baseMapper.deleteBatchIds(ids) > 0; + } + + @Override + public void download(String ossId, HttpServletResponse response) throws IOException { + SysOss oss = sysOssMapper.selectById(ossId); + + String fileName = oss.getFileName(); + String originalName = oss.getOriginalName(); + + if (!FileUtils.checkAllowDownload(fileName)) { + throw new RuntimeException(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName)); + } + + String extName = FileUtil.extName(fileName); + String newFileName = FileUtil.mainName(fileName) + ".pdf"; + String newOriginalName = originalName.replaceAll(extName, "pdf"); + + String filePath = ProjectConfig.getUploadPath() + fileName; + + String pdfFilePath = FileUtil.getTmpDirPath() + newFileName; + + AsposeUtil.wordToPdf(filePath, pdfFilePath); + + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + FileUtils.setAttachmentResponseHeader(response, newOriginalName); + FileUtils.writeBytes(pdfFilePath, response.getOutputStream()); + FileUtil.del(pdfFilePath); + } + + @Override + public Boolean caseMerge(String sourceCaseId,String targetCaseId) { + AnalysisReport analysisReport = new AnalysisReport(); + analysisReport.setCaseId(sourceCaseId); + List analysisResults = queryList(analysisReport); + List addList = new ArrayList<>(); + for (AnalysisReport result : analysisResults) { + result.setCaseId(targetCaseId); + String md5Id = HelperUtil.generateMD5(result.toString()); + result.setId(md5Id); + if(!result.getName().contains("(并入)")){ + result.setName(result.getName() + "(并入)"); + } + addList.add(result); + } + if(CollectionUtil.isNotEmpty(addList)){ + baseMapper.insertBatch(addList); + sysOssService.caseMerge(sourceCaseId,targetCaseId,"ANALYSIS_REPORT"); + } + return true; + } + + @Override + public void analysisResultMerge(Map sourceArIdTargetArIdMap) { + List analysisReportList = baseMapper.selectList(new LambdaQueryWrapper() + .in(AnalysisReport::getAnalysisResultId,sourceArIdTargetArIdMap.keySet())); + Map> arMap = analysisReportList.stream().collect(Collectors.groupingBy(AnalysisReport::getAnalysisResultId)); + List addList = new ArrayList<>(); + for (Map.Entry > entry : arMap.entrySet()) { + String sourceArId = entry.getKey(); + List reports = entry.getValue(); + String targetArId = sourceArIdTargetArIdMap.get(sourceArId); + for (AnalysisReport result : reports) { + result.setAnalysisResultId(targetArId); + String md5Id = HelperUtil.generateMD5(result.toString()); + result.setId(md5Id); + addList.add(result); + } + } + if(CollectionUtil.isNotEmpty(addList)){ + baseMapper.insertBatch(addList); + } + } + + + + + @Override + public void save2AnalysisResult(AnalysisDto dto) { + Set ids = dto.getIds(); + if (ids.isEmpty()) { + return; + } + String analysisResultId = dto.getAnalysisResultId(); + List analysisReports = baseMapper.selectBatchIds(ids); + Set uniqueKeySet = new HashSet(); + List result = new ArrayList<>(); + for (AnalysisReport item : analysisReports) { + item.setCaseId(null); + item.setAnalysisResultId(analysisResultId); + String md5Id = HelperUtil.generateMD5(item.toString()); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + item.setId(md5Id); + result.add(item); + } + uniqueKeySet.clear(); + if (CollectionUtil.isNotEmpty(result)) { + //根据id取es查询 返回的就是重复数据 + Map groupById = result.stream().collect(Collectors.toMap(AnalysisReport::getId, Function.identity())); + Set idSet = groupById.keySet(); + List existIdList = baseMapper.selectBatchIds(idSet); + + if(CollectionUtil.isEmpty(existIdList)){ + baseMapper.insertBatch(result); + }else { + Set esIdSet = existIdList.stream().filter(item -> StrUtil.isNotEmpty(item.getId())).map(AnalysisReport::getId).collect(Collectors.toSet()); + idSet.removeAll(esIdSet); + if(CollectionUtil.isNotEmpty(idSet)){ + List saveLis = new ArrayList<>(); + for (String id : idSet) { + saveLis.add(groupById.get(id)); + } + baseMapper.insertBatch(saveLis); + } + } + + Set ossIdSet = result.stream().map(AnalysisReport::getOssId).collect(Collectors.toSet()); + AnalysisDto updateOss = new AnalysisDto(); + updateOss.setIds(ossIdSet); + updateOss.setAnalysisResultId(analysisResultId); + sysOssService.save2AnalysisResult(updateOss); + + } + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/analysiscenter/service/impl/AnalysisResultServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/analysiscenter/service/impl/AnalysisResultServiceImpl.java new file mode 100644 index 0000000..d082e9f --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/analysiscenter/service/impl/AnalysisResultServiceImpl.java @@ -0,0 +1,237 @@ +package com.inscloudtech.analysiscenter.service.impl; + + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.util.ListUtils; +import com.alibaba.excel.write.metadata.WriteSheet; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.analysiscenter.domain.AnalysisReport; +import com.inscloudtech.analysiscenter.domain.AnalysisResult; +import com.inscloudtech.analysiscenter.mapper.AnalysisResultMapper; +import com.inscloudtech.analysiscenter.service.IAnalysisReportService; +import com.inscloudtech.analysiscenter.service.IAnalysisResultService; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.utils.spring.SpringUtils; + +import com.inscloudtech.datacenter.domain.*; +import com.inscloudtech.datacenter.domain.dto.QueryCenterQuery; +import com.inscloudtech.datacenter.service.*; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import org.dromara.easyes.annotation.IndexName; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.lang.reflect.Method; +import java.net.URLEncoder; +import java.util.*; +import java.util.stream.Collectors; + + +/** + + * @author + * @date 2023-11-07Impl + */ +@RequiredArgsConstructor +@Service +public class AnalysisResultServiceImpl implements IAnalysisResultService { + + private final AnalysisResultMapper baseMapper; + + @Override + public AnalysisResult queryById(String id) { + return baseMapper.selectById(id); + } + + @Override + public TableDataInfo queryPageList(AnalysisResult bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + int start = (pageQuery.getPageNum() - 1) * pageQuery.getPageSize(); + lqw.last( "order by create_time desc limit "+start+","+ pageQuery.getPageSize()); + Page result = baseMapper.selectPage(pageQuery.build(), lqw); + TableDataInfo tableDataInfo = TableDataInfo.build(result); + tableDataInfo.setTotal(baseMapper.selectCount(lqw)); + return tableDataInfo; + } + + private LambdaQueryWrapper buildQueryWrapper(AnalysisResult bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(AnalysisResult::getCaseId, bo.getCaseId()); + lqw.like(StrUtil.isNotBlank(bo.getName()),AnalysisResult::getName, bo.getName()); + lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null, + AnalysisResult::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime")); + return lqw; + } + + @Override + public List queryList(AnalysisResult bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + List analysisResults = baseMapper.selectList(lqw); + return analysisResults; + } + + @Override + public Boolean insert(AnalysisResult add) { + Long count = baseMapper.selectCount(new LambdaQueryWrapper().eq(AnalysisResult::getName, add.getName()) + .eq(AnalysisResult::getCaseId, add.getCaseId())); + if(count > 0){ + throw new RuntimeException("成果名称-" + add.getName() + "已存在!"); + } + return baseMapper.insert(add) > 0; + } + + @Override + public Boolean update(AnalysisResult update) { + return baseMapper.updateById(update) > 0; + } + + @Override + public Boolean deleteWithValidByIds(Collection ids) { + return baseMapper.deleteBatchIds(ids) > 0; + } + + private static final List CLASS_LIST = Arrays.asList(BankStatement.class, OpeningAccountInfo.class,TransactionPartner.class, PublicFamily.class, + RealEstate.class, CarInfo.class, OtherAssets.class, OtherInformation.class); + private static final List SERVICE_LIST = Arrays.asList(BankService.class, OpeningAccountInfoService.class,ITransactionPartnerService.class, IPublicFamilyService.class, + IRealEstateService.class, ICarInfoService.class); + + + @SneakyThrows + @Override + public void importData(MultipartFile file, String caseId, String analysisResultId) { + List readSheets = new ArrayList<>(); + for(int i = 0; i < CLASS_LIST.size(); i++){ + if(i == 5){ + break; + } + Class aClass = CLASS_LIST.get(i); + Class serviceClass = SERVICE_LIST.get(i); + ReadSheet readSheet = EasyExcel.readSheet(i).head(aClass).registerReadListener(getReadListener(serviceClass, analysisResultId)).build(); + readSheets.add(readSheet); + } + + try (ExcelReader excelReader = EasyExcel.read(file.getInputStream()).build()) { + // 这里注意 一定要把sheet1 sheet2 一起传进去,不然有个问题就是03版的excel 会读取多次,浪费性能 + excelReader.read(readSheets); + } + } + + + @Override + public Boolean caseMerge(String sourceCaseId,String targetCaseId) { + AnalysisResult analysisResult = new AnalysisResult(); + analysisResult.setCaseId(sourceCaseId); + List analysisResults = queryList(analysisResult); + Map sourceArIdTargetArIdMap = new HashMap<>(); + + List addList = new ArrayList<>(); + for (AnalysisResult result : analysisResults) { + result.setCaseId(targetCaseId); + String md5Id = HelperUtil.generateMD5(result.toString()); + sourceArIdTargetArIdMap.put(result.getId(),md5Id); + result.setId(md5Id); + if(!result.getName().contains("(并入)")){ + result.setName(result.getName() + "(并入)"); + } + addList.add(result); + } + if(CollectionUtil.isNotEmpty(addList)){ + baseMapper.insertBatch(addList); + //8个模块数据 + analysisResultItemMerge(sourceArIdTargetArIdMap); + } + + return true; + } + + private static final List SERVICE_LIST_MERGE = Arrays.asList(BankService.class, OpeningAccountInfoService.class,ITransactionPartnerService.class, IPublicFamilyService.class, + IRealEstateService.class, ICarInfoService.class,IOtherAssetsService.class,IOtherInformationService.class, + IAnalysisReportService.class); + + public void analysisResultItemMerge(Map sourceArIdTargetArIdMap) { + + for (Class serviceClass : SERVICE_LIST_MERGE) { + Object serviceObj = SpringUtils.getBean(serviceClass); + String methodName = "analysisResultMerge"; + List methodList = Arrays.stream(serviceClass.getMethods()).filter(method -> method.getName().equals(methodName)).collect(Collectors.toList()); + Method method = methodList.get(0);// + Object[] args = new Object[]{sourceArIdTargetArIdMap}; + + try { + method.invoke(serviceObj, args); + }catch (Exception e){ + e.printStackTrace(); + } + + } + } + + + + + + /** + * 存ES,同时设置ID + */ + public static ReadListener getReadListener(Class serviceClass,String analysisResultId) { + return new ReadListener() { + List dataList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + @Override + public void invoke(T data, AnalysisContext context) { + try { + dataList.add(data); + } catch (Exception e) { + e.printStackTrace(); + } + if (dataList.size() >= Constants.BATCH_SIZE) { + save(); + } + } + + @SneakyThrows + private void save() { + Object serviceObj = SpringUtils.getBean(serviceClass); + String methodName = "importAnalysisResult"; + List methodList = Arrays.stream(serviceClass.getMethods()).filter(method -> method.getName().equals(methodName)).collect(Collectors.toList()); + Method method = methodList.get(0);// + Object[] argsz = new Object[]{dataList, analysisResultId, ""}; + method.invoke(serviceObj, argsz); + dataList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!dataList.isEmpty()) { + save(); + } + } + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + + ReadListener.super.onException(exception, context); + } + }; + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/analysiscenter/word/FileToMultipartFile.java b/cas-system/src/main/java/com/inscloudtech/analysiscenter/word/FileToMultipartFile.java new file mode 100644 index 0000000..95f1fb7 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/analysiscenter/word/FileToMultipartFile.java @@ -0,0 +1,68 @@ +package com.inscloudtech.analysiscenter.word; + + +import org.springframework.web.multipart.MultipartFile; +import java.io.*; + +public class FileToMultipartFile implements MultipartFile { + + private final File file; + + public FileToMultipartFile(File file) { + this.file = file; + } + + @Override + public String getName() { + return file.getName(); + } + + @Override + public String getOriginalFilename() { + return file.getName(); + } + + @Override + public String getContentType() { + return "application/octet-stream"; + } + + @Override + public boolean isEmpty() { + return file.length() == 0; + } + + @Override + public long getSize() { + return file.length(); + } + + @Override + public byte[] getBytes() throws IOException { + InputStream is = new FileInputStream(file); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int len; + while ((len = is.read(buffer)) != -1) { + baos.write(buffer, 0, len); + } + return baos.toByteArray(); + } + + @Override + public InputStream getInputStream() throws IOException { + return new FileInputStream(file); + } + + @Override + public void transferTo(File dest) throws IOException, IllegalStateException { + try (InputStream is = new FileInputStream(file); + OutputStream os = new FileOutputStream(dest)) { + byte[] buffer = new byte[1024]; + int len; + while ((len = is.read(buffer)) != -1) { + os.write(buffer, 0, len); + } + } + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/analysiscenter/word/WordUtil.java b/cas-system/src/main/java/com/inscloudtech/analysiscenter/word/WordUtil.java new file mode 100644 index 0000000..979a5fc --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/analysiscenter/word/WordUtil.java @@ -0,0 +1,72 @@ +package com.inscloudtech.analysiscenter.word; + + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import com.aspose.words.*; +import com.inscloudtech.analysiscenter.domain.AnalysisReportVo; +import lombok.SneakyThrows; +import org.springframework.core.io.ClassPathResource; +import org.springframework.web.multipart.MultipartFile; + +import java.awt.*; +import java.io.File; + +/** + * @Description: + * @Author: Tarzan Liu + * @Date: 2022/9/13 4:54 + */ +public class WordUtil { + + private static final String TEMPLATE_FILE_NAME = "analysisReport.docx"; + @SneakyThrows + public static void main(String[] args) { + String fileName = "D:\\b案件陈斌分析报告_2024-05-13.docx"; + Document doc = new Document(fileName); + ReportingEngine engine = new ReportingEngine(); + +// + NodeCollection tables = doc.getChildNodes(NodeType.TABLE, true); +// +// 遍历每个表格 + for (Table table : tables) { + // 遍历表格中的每个单元格 + for (Row row : table.getRows()) { + for (Cell cell : row.getCells()) { + // 获取单元格中的段落 + ParagraphCollection paragraphs = cell.getParagraphs(); + // 遍历段落中的每个运行 + for (Paragraph paragraph : paragraphs) { + for (Run run : paragraph.getRuns()) { + String text = run.getText(); + System.out.println("text>>>" + text); +// if (text.contains("陈斌")) { +// run.getFont().setColor(Color.GREEN); +// } + } + } + } + } + } + doc.save(fileName); + } + + @SneakyThrows + public static File generateWordFileByTemplate(AnalysisReportVo vo){ + ClassPathResource cpr = new ClassPathResource("template/" + TEMPLATE_FILE_NAME); + Document doc = new Document(cpr.getInputStream()); + ReportingEngine engine = new ReportingEngine(); + engine.buildReport(doc, vo, "vo"); + String name = vo.getName(); + if(name.contains("*")){ + name = name.replace("*","某"); + } + String fileName = FileUtil.getTmpDirPath()+"/"+ name +"分析报告"+ DateUtil.today() +".docx"; + doc.save(fileName); + + File file = FileUtil.file(fileName); + return file; + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/HeadField.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/HeadField.java new file mode 100644 index 0000000..d19e548 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/HeadField.java @@ -0,0 +1,22 @@ +package com.inscloudtech.bankStatementAnalysis.domain; + +import lombok.Data; + +/** + * 表头出现在多行 + * 金额字段/商密二级 昆明市盘龙区恒诺广告制作部 " 2502117919024533414" + * 帐号 工作日期 入帐日期 + * " 2502117919024533414" " 2016-03-08" " 2016-03-08" + */ +@Data +public class HeadField { + + private String field; + + private String value; + + public HeadField(String field, String value) { + this.field = field; + this.value = value; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/ImportOpeningAccountInfo.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/ImportOpeningAccountInfo.java new file mode 100644 index 0000000..df287ed --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/ImportOpeningAccountInfo.java @@ -0,0 +1,123 @@ +package com.inscloudtech.bankStatementAnalysis.domain; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.format.NumberFormat; +import com.baomidou.mybatisplus.annotation.TableId; +import com.inscloudtech.common.annotation.DeduplicationField; +import com.inscloudtech.common.constant.BankStatementConstants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * 导入银行流水开户信息模板 + */ +@Data +@IndexName(BankStatementConstants.IMPORT_TEMPLATE_OPENING_ACCOUNT) +public class ImportOpeningAccountInfo { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty({"客户名称", "客户名","账户户名","姓名"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String name; + + @ExcelProperty({"客户号"}) + private String customerId; + + @ExcelProperty({"客户账号","客户主账号", "主账号", "卡号", "账号","卡号或帐号"}) + private String accountNumber; + + @ExcelProperty({"账号对应卡号"}) + private String account2CardNumber; + + @ExcelProperty({"子账号"}) + private String accountNumberItem; + + @ExcelProperty({"证件号码","证件号","客户证件号"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String idNo; + + @ExcelProperty({"证件类型","证件名称"}) + private String idType; + + @ExcelProperty({"住宅地址","家庭地址"}) + private String address; + + @ExcelProperty({"联系电话","移动电话号码"}) + private String phone; + + @ExcelProperty({"开户日期","开卡日期"}) + private String openingAccountDate; + + @ExcelProperty("账户余额") + private BigDecimal balance; + + @ExcelProperty({"系统账户状态", "账户状态"}) + private String status; + + @ExcelProperty({"开户行","开户机构", "开户机构名称"}) + private String accountOpeningInstitution; + + private String caseId; + + private String bankName; + + /** + * 新账号 + */ + @ExcelProperty(value = "新账号") + @DeduplicationField + private String newAccountNumber; + + + + /** + * 销户日期 + */ + @ExcelProperty(value = "销户日期") + @DeduplicationField + private String closingDate; + + + + /** + * 账户类型 + */ + @ExcelProperty({"账户类型","账号类型"}) + @DeduplicationField + private String type; + + /** + * 冻结信息 + */ + @ExcelProperty(value = "冻结信息") + @DeduplicationField + private String freezeInfo; + + // 冻结日期 + @ExcelProperty(value = "冻结日期") + @DeduplicationField + private String freezeDate; + + @ExcelProperty("备注") + @DeduplicationField + private String remark; + + @ExcelIgnore + @IndexField(fieldType = FieldType.KEYWORD) + private String analysisResultId; + + // 网银签约信息 + @ExcelProperty("网银签约信息") + @DeduplicationField + private String onlineBankingSigningInfo; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/ReadDto.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/ReadDto.java new file mode 100644 index 0000000..150c1c0 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/ReadDto.java @@ -0,0 +1,30 @@ +package com.inscloudtech.bankStatementAnalysis.domain; + +import com.alibaba.excel.read.listener.ReadListener; +import com.inscloudtech.bankStatementAnalysis.domain.HeadField; +import lombok.Data; +import org.dromara.easyes.core.core.BaseEsMapper; + +import java.io.File; +import java.util.List; + +/** + * + */ +@Data +public class ReadDto { + + private String caseId; + private String bankName; + + private String excelFileName; + private int headRowNumber; + private int sheetNo; + private Class headClass; + private BaseEsMapper esMapper; + private String cardHolderName; + private List headFields; + private String sourceFile; + private ReadListener readListener; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/ABCCompanyInfoEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/ABCCompanyInfoEntity.java new file mode 100644 index 0000000..3822e77 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/ABCCompanyInfoEntity.java @@ -0,0 +1,64 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 农业银行开户信息-公司信息 + *
+ * 都是人民币 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_ABC_COMPANY_OPENING_ACCOUNT) +public class ABCCompanyInfoEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty({"户名","合约名称"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("联系电话") + private String phone; + + @ExcelProperty("证件号码") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + /** + * 多个账号,用'/'分割 + */ + @ExcelProperty({"账号","产品号/账号/客户号","卡号"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty({"地址/住址","住址/地址"}) + private String address; + + @ExcelProperty({"产品开户行名","组织单元名称"}) + private String accountOpeningInstitution; + + @ExcelProperty({"账户状态","合约生命周期状态代码"}) + private String status; + + @ExcelProperty({"账户启用日期","合约建立日期"}) + private String openingAccountDate; + + @ExcelProperty({"账户终止日期","销户日期"}) + private String closeDate; + + @ExcelProperty("合约号") + private String contractNo; + + @ExcelProperty("产品号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber2; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/ABCCompanyStatementEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/ABCCompanyStatementEntity.java new file mode 100644 index 0000000..3ede4f8 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/ABCCompanyStatementEntity.java @@ -0,0 +1,80 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * 农业银行流水读取-公司流水 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_ABC_COMPANY_STATEMENT) +public class ABCCompanyStatementEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelIgnore + private String cardHolderName; + + // 卡号 + @ExcelProperty({"账号","合约号","产品号"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + // 收入金额 + @ExcelProperty({"交易金额","发生额"}) + private BigDecimal transactionAmount; + + //交易时间 + @ExcelProperty({"交易日期","日期"}) + private String transactionDate; + /** + * 需要截取 + */ + @ExcelProperty({"交易时间","时间"}) + private String transactionTime; + + // 交易后余额 + @ExcelProperty({"余额","合约账户余额","交易后余额"}) + private BigDecimal balance; + + @ExcelProperty({"对方账号户名","对方客户名称","对方账户户名","对方户名"}) + private String counterpartyName; + + @ExcelProperty({"交易行名","交易组织单元代码名称","行名"}) + private String transactionInstitutions; + + @ExcelProperty({"对方账号","对方合约外部服务标识号码"}) + private String counterpartyAccount; + + @ExcelProperty({"对方账号开户行","对方组织单元代码名称","对方开户行"}) + private String counterpartyBankName; + + @ExcelProperty({"交易渠道","交易来源"}) + private String transChannel; + + @ExcelProperty({"摘要","摘要信息"}) + private String summary; + + //交易备注 + @ExcelProperty("附言") + private String transactionRemark; + + @ExcelProperty("合约号") + private String contractNo; + + @ExcelIgnore + private String sourceFile; + + @ExcelIgnore + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/ABCCustomerInfoEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/ABCCustomerInfoEntity.java new file mode 100644 index 0000000..160e0d3 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/ABCCustomerInfoEntity.java @@ -0,0 +1,70 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * 农业银行开户信息-客户信息 + *
+ * 都是人民币 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_ABC_CUSTOMER_OPENING_ACCOUNT) +public class ABCCustomerInfoEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty({"户名","客户名称"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("证件号码") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + @ExcelProperty({"手机号码", "联系电话", "联系方式"}) + private String phone; + + @ExcelProperty({"卡号","产品号"}) + private String cardNumber; + + @ExcelProperty("账号") + private String accountNo; + + @ExcelProperty({"开户行名", "卡开户行名","开卡网点名称"}) + private String accountOpeningInstitution; + + @ExcelProperty({"账户状态","状态"}) + private String status; + + @ExcelProperty({"开户日期" }) + private String openingAccountDate; + + @ExcelProperty({"销户日期"}) + private String closeDate; + + @ExcelProperty({"地址", "住址/地址"}) + private String address; + + @ExcelProperty("账户余额") + private BigDecimal balance; + + @ExcelProperty("产品号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber2; + + @ExcelProperty("客户号") + @IndexField(fieldType = FieldType.KEYWORD) + private String customerId; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/ABCCustomerStatementEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/ABCCustomerStatementEntity.java new file mode 100644 index 0000000..2064e9d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/ABCCustomerStatementEntity.java @@ -0,0 +1,92 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * 农业银行流水读取-客户流水 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_ABC_CUSTOMER_STATEMENT) +public class ABCCustomerStatementEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + /** + * 客户名称 + */ + @ExcelProperty({"客户名称"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("身份证号码") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + // 卡号 + @ExcelProperty({"产品号","客户号"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + + @ExcelProperty("账号") + @IndexField(fieldType = FieldType.KEYWORD) + private String accountNo; + + + // 交易日期 + @ExcelProperty({"交易日期", "日期"}) + private String transactionDate; + + // 收入金额 + @ExcelProperty({"发生额","交易金额"}) + private BigDecimal transactionAmount; + + @ExcelProperty({"交易时间", "时间"}) + private String transactionTime; + + // 交易后余额 + @ExcelProperty("交易后余额") + private BigDecimal balance; + + // 对方账号 + @ExcelProperty({"对方账号","交易对手账号"}) + private String counterpartyAccount; + + @ExcelProperty("对方身份证号码") + private String counterpartyIdCardNo; + + @ExcelProperty({"对方户名","交易对手户名"}) + private String counterpartyName; + + @ExcelProperty({"对方开户行名","对方银行名称"}) + private String counterpartyBankName; + + @ExcelProperty("交易渠道") + private String transChannel; + + // 交易机构名称 + @ExcelProperty({"行名","交易行名"}) + private String transactionInstitutions; + + @ExcelProperty("摘要") + private String summary; + + @ExcelProperty("附言") + private String transRemark; + + @ExcelIgnore + private String sourceFile; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/BOCOMAccountInfoEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/BOCOMAccountInfoEntity.java new file mode 100644 index 0000000..8e99892 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/BOCOMAccountInfoEntity.java @@ -0,0 +1,76 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 交通银行客户信息 + *
+ * 都是人民币 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_BOCOM_OPENING_ACCOUNT) +public class BOCOMAccountInfoEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty({"客户名称", "户名", "姓名"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("证件种类") + private String idType; + + @ExcelProperty({"证件号码", "证件号"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + @ExcelProperty({"账号", "卡号"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("手机号码") + private String phone; + + /** + * 开户日期 + */ + @ExcelProperty({"账号开户日期", "开户日期","客户号开户日期"}) + private String openingAccountDate; + + + /** + * 账户状态 + */ + @ExcelProperty("账户状态") + private String status; + + /** + * 账户类型 + */ + @ExcelProperty("记账账号类型") + private String type; + + + /** + * 开户机构 + */ + @ExcelProperty({"账号开户网点", "客户机构名称","客户号开户网点"}) + private String accountOpeningInstitution; + + @ExcelProperty("家庭地址") + private String address; + + //信用额度 + @ExcelProperty("信用额度") + private String creditLimit; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/BOCOMStatementEntry.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/BOCOMStatementEntry.java new file mode 100644 index 0000000..f57d39a --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/BOCOMStatementEntry.java @@ -0,0 +1,92 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.format.NumberFormat; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * 交通银行流水读取 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_BOCOM_STATEMENT) +public class BOCOMStatementEntry { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + /** + * 客户名称 + */ + @ExcelProperty({"户名", "客户姓名", "客户姓名"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + // 卡号 + @ExcelProperty({"账号", "卡号", "当前主卡卡号"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + // 交易日期 yyyyMMdd + @ExcelProperty("交易日期") + private String transDate; + // 交易时间 HHmmss + @ExcelProperty("交易时间") + private String transTime; + + @ExcelIgnore + private String transactionTime; + + // 借方金额 + @ExcelProperty("借方发生额") + private BigDecimal debitAmount; + // 贷方金额 + @ExcelProperty("贷方发生额") + private BigDecimal creditAmount; + + // 收入金额 + @ExcelProperty("交易金额") + @NumberFormat("#.00") + private BigDecimal transactionAmount; + + // C - 贷 + + // D - 借 - + @ExcelProperty("借贷标志") + private String loanFlag; + + // 交易后余额 + @ExcelProperty({"余额", "历史余额"}) + @NumberFormat("#.00") + private BigDecimal balance; + + @ExcelProperty({"对方户名", "交易对手姓名"}) + private String counterpartyName; + + @ExcelProperty("交易分行") + private String transactionInstitutions; + + @ExcelProperty({"对方账号", "交易对手账户编号"}) + private String counterpartyAccount; + + @ExcelProperty("对方行名") + private String counterpartyBankName; + + @ExcelProperty({"业务摘要码名称", "摘要", "交易地点"}) + private String summary; + + @ExcelProperty("业务摘要") + private String transRemark; + + @ExcelProperty({"交易名称", "渠道", "交易说明"}) + private String transChannel; + + private String sourceFile; + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/BOCPrivateBankStatementEntry.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/BOCPrivateBankStatementEntry.java new file mode 100644 index 0000000..2865739 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/BOCPrivateBankStatementEntry.java @@ -0,0 +1,78 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * 中国银行流水读取 /不区分私人,公司 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_BOC_STATEMENT_PRIVATE) +public class BOCPrivateBankStatementEntry { + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + /** + * 客户名称 + */ + @ExcelProperty({"客户名称", "客户名", "姓名", "姓名"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + // 卡号 + @ExcelProperty({"账号", "账号卡号"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + // 交易日期 + @ExcelProperty("交易日期") + private String transDate; + + @ExcelProperty("交易时间") + private String transTime; + + @ExcelProperty("交易机构") + private String transactionSituation; + + @ExcelProperty({"交易类型", "交易码"}) + private String transRemark; + + // 收入金额 + @ExcelProperty("交易金额") + private BigDecimal transactionAmount; + + // 交易后余额 + @ExcelProperty({"交易后余额","余额"}) + private BigDecimal balance; + + @ExcelProperty({"交易描述"}) + private String transSummary; + + // 对方账号 + @ExcelProperty({"对手账号", "对方账号"}) + private String counterpartyAccount; + + @ExcelProperty({"对手名称", "对方户名", "对方名称"}) + private String counterpartyName; + + @ExcelProperty({"对手行", "对方行名", "对方银行"}) + private String counterpartyBankName; + + @ExcelProperty("摘要") + private String summary; + + private String caseId; + + @ExcelIgnore + private String sourceFile; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CCBCurrentAccountInfoEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CCBCurrentAccountInfoEntity.java new file mode 100644 index 0000000..a4e08a2 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CCBCurrentAccountInfoEntity.java @@ -0,0 +1,78 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 建设银行客户信息-活期 + *
+ * 都是人民币 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CCB_OPENING_ACCOUNT) +public class CCBCurrentAccountInfoEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty({"客户名称","账户名称"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("证件号码") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + @ExcelProperty({"客户账号","账号"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + /** + * 证件类型 + */ + @ExcelProperty("证件类型") + private String idType; + + /** + * 开户日期 + */ + @ExcelProperty("开户日期") + private String openingAccountDate; + + /** + * 销户日期 + */ + @ExcelProperty("销户日期") + private String closingDate; + + /** + * 账户状态 + */ + @ExcelProperty("账户状态") + private String status; + + /** + * 开户机构 + */ + @ExcelProperty("开户机构名称") + private String accountOpeningInstitution; + + @ExcelProperty("余额") + private String balance; + + // 冻结信息 + @ExcelProperty({"冻结状态","账户状态"}) + private String freezeInfo; + + private String caseId; + + @ExcelIgnore + private String sourceFile; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CCBCurrentBankStatementEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CCBCurrentBankStatementEntity.java new file mode 100644 index 0000000..0a929d5 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CCBCurrentBankStatementEntity.java @@ -0,0 +1,90 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 建设银行流水读取-个人活期明细 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CCB_CURRENT_STATEMENT) +public class CCBCurrentBankStatementEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + /** + * 客户名称 + */ + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + // 卡号 + // 根据交易卡号从账户信息中可以获取用户名 + @ExcelProperty("交易卡号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + // 交易日期 + @ExcelProperty("交易日期") + private String transDate; + + @ExcelProperty("交易时间") + private String transTime; + + // - + @ExcelProperty("借方发生额") + private String expenditureAmount; + + @ExcelProperty("贷方发生额") + private String incomeAmount; + + @ExcelProperty("借贷方向") + private String loanFlag; + + // 收入金额 + // 通过前面两个参数来计算 + @ExcelProperty("交易金额") + private String transactionAmount; + + // 交易后余额 + @ExcelProperty("账户余额") + private String balance; + + @ExcelProperty("交易机构名称") + private String transactionInstitutions; + + // 对方账号 + @ExcelProperty("对方账号") + private String counterpartyAccount; + + @ExcelProperty("对方户名") + private String counterpartyName; + + @ExcelProperty("对方行名") + private String counterpartyBankName; + + @ExcelProperty("交易渠道") + private String transChannel; + + @ExcelProperty({"交易备注", "扩充备注"}) + private String tansRemark; + + @ExcelProperty({"摘要", "摘要描述"}) + private String summary; + + @ExcelProperty("交易流水号") + private String serialNumber; + + private String caseId; + + @ExcelIgnore + private String sourceFile; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CCBElectronicCashAccountInfoEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CCBElectronicCashAccountInfoEntity.java new file mode 100644 index 0000000..c60ebcc --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CCBElectronicCashAccountInfoEntity.java @@ -0,0 +1,46 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 建设银行客户信息-电子现金 + *
+ * 都是人民币 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CCB_ELECTRONIC_CASH_OPENING_ACCOUNT) +public class CCBElectronicCashAccountInfoEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("证件号码") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + /** + * 证件类型 + */ + @ExcelProperty("证件类型") + private String idType; + + @ExcelProperty("客户账号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + private String caseId; + + @ExcelIgnore + private String sourceFile; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CCBElectronicCashBankStatementEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CCBElectronicCashBankStatementEntity.java new file mode 100644 index 0000000..909aab1 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CCBElectronicCashBankStatementEntity.java @@ -0,0 +1,73 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 建设银行流水读取-电子现金明细 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CCB_ELECTRONIC_CASH_STATEMENT) +public class CCBElectronicCashBankStatementEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + /** + * 客户名称 + */ + @ExcelIgnore + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + // 卡号 + //根据交易卡号从账户信息中可以获取用户名 + @ExcelProperty("卡号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + // 交易日期 + @ExcelProperty("交易日期") + private String transDate; + @ExcelProperty("交易时间") + private String transTime; + + //- + @ExcelProperty("借记卡借方发生额") + private String expenditureAmount; + + @ExcelProperty("借记卡贷方发生额") + private String incomeAmount; + + // 收入金额 + @ExcelIgnore + private String transactionAmount; + + // 交易后余额 + @ExcelProperty("账户余额") + private String balance; + // 对方账号 + @ExcelProperty("对方交易账号") + private String counterpartyAccount; + + @ExcelProperty("对方交易账号名称") + private String counterpartyName; + + @ExcelProperty("对方交易支付行号") + private String counterpartyBankName; + + @ExcelProperty("交易备注") + private String tansRemark; + + private String caseId; + + @ExcelIgnore + private String sourceFile; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CCBRegularAccountInfoEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CCBRegularAccountInfoEntity.java new file mode 100644 index 0000000..4b9f384 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CCBRegularAccountInfoEntity.java @@ -0,0 +1,71 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 建设银行客户信息-定期 + *
+ * 都是人民币 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CCB_OPENING_ACCOUNT) +public class CCBRegularAccountInfoEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("证件号码") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + @ExcelProperty("客户账号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + /** + * 证件类型 + */ + @ExcelProperty("证件类型") + private String idType; + + /** + * 开户日期 + */ + @ExcelProperty("开户日期") + private String openingAccountDate; + + /** + * 销户日期 + */ + @ExcelProperty("销户日期") + private String closingDate; + + /** + * 账户状态 + */ + @ExcelProperty("账户状态") + private String status; + + /** + * 开户机构 + */ + @ExcelProperty("开户机构名称") + private String accountOpeningInstitution; + + private String caseId; + + @ExcelIgnore + private String sourceFile; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CCBRegularBankStatementEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CCBRegularBankStatementEntity.java new file mode 100644 index 0000000..fc77a3d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CCBRegularBankStatementEntity.java @@ -0,0 +1,81 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.format.NumberFormat; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * 建设银行流水读取-个人定期明细 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CCB_REGULAR_STATEMENT) +public class CCBRegularBankStatementEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + /** + * 客户名称 + */ + @ExcelIgnore + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + // 卡号 + // 根据交易卡号从账户信息中可以获取用户名 + @ExcelIgnore + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + // 交易日期 + @ExcelProperty("交易日期") + private String transDate; + + @ExcelProperty("交易时间") + private String transTime; + + // 贷-+ + // 借-- + @ExcelProperty("借贷方标志") + private String loanFlag; + + // 收入金额 + @ExcelProperty("交易金额") + @NumberFormat("#.00") + private BigDecimal transactionAmount; + + // 交易后余额 + @ExcelProperty("账户余额") + @NumberFormat("#.00") + private BigDecimal balance; + + @ExcelProperty("交易机构名称") + private String transactionInstitutions; + + // 对方账号 + @ExcelProperty("对方账号") + private String counterpartyAccount; + + @ExcelProperty("对方户名") + private String counterpartyName; + + @ExcelProperty("交易渠道") + private String transChannel; + + @ExcelProperty({"摘要", "摘要描述"}) + private String summary; + + private String caseId; + + @ExcelIgnore + private String sourceFile; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CCBSummaryEntry.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CCBSummaryEntry.java new file mode 100644 index 0000000..4ef9bbb --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CCBSummaryEntry.java @@ -0,0 +1,19 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +/** + * 建行,个人汇总 + */ +@Data +public class CCBSummaryEntry { + @ExcelProperty("条件值") + private String conditionValue; + + @ExcelProperty("参考结果笔数") + private Integer resultCount; + + @ExcelProperty("查询结果所在文件名称") + private String resultFileName; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CEBCreditCardStatementEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CEBCreditCardStatementEntity.java new file mode 100644 index 0000000..2753c08 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CEBCreditCardStatementEntity.java @@ -0,0 +1,63 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 光大银行流水读取-信用卡 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CEB_CREDIT_CARD_STATEMENT) +public class CEBCreditCardStatementEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + /** + * 客户名称 + */ + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + // 卡号 + @ExcelProperty("卡号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + // 交易日期 2019-12-03 + @ExcelProperty("交易日期") + private String transactionTime; + + @ExcelProperty("资金收付标识") + private String loanFlag; + + @ExcelProperty("原币种交易金额") + private String transactionAmount; + + @ExcelProperty("交易摘要") + private String transSummary; + + @ExcelProperty("交易对方账户名称") + private String counterpartyName; + // 对方账号 + @ExcelProperty("交易对方账号或卡号") + private String counterpartyAccount; + // 对方账户名称 + @ExcelProperty("对方账户名称") + private String counterpartyAccountName; + + @ExcelProperty("交易对手银行名称") + private String counterpartyBankName; + + @ExcelProperty("信用卡消费商户名称") + private String transRemark; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CEBSavingsCardStatementEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CEBSavingsCardStatementEntity.java new file mode 100644 index 0000000..47039aa --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CEBSavingsCardStatementEntity.java @@ -0,0 +1,65 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 光大银行流水读取-储蓄卡 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CEB_SAVINGS_CARD_STATEMENT) +public class CEBSavingsCardStatementEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + /** + * 客户名称 + */ + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + // 卡号 + @ExcelProperty("客户账号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + // 交易日期 20191203 + @ExcelProperty("交易日期") + private String transactionTime; + + @ExcelProperty("借贷方式") + private String loanFlag; + + // 收入金额 + @ExcelProperty("原币种交易金额") + private String transactionAmount; + + // 收入金额 + @ExcelProperty("存入金额") + private String revenueAmount; + // 支出金额 + @ExcelProperty("转出金额") + private String expenditureAmount; + + // 交易后余额 + @ExcelProperty("账户余额") + private String balance; + + @ExcelProperty("摘要") + private String transSummary; + + @ExcelProperty("对方名称") + private String counterpartyName; + // 对方账号 + @ExcelProperty("对方账号") + private String counterpartyAccount; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCCreditCardAccountInfoEntry.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCCreditCardAccountInfoEntry.java new file mode 100644 index 0000000..33201fa --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCCreditCardAccountInfoEntry.java @@ -0,0 +1,49 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 广发银行信用卡开户信息 + *
+ * 都是人民币 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CGBC_OPENING_ACCOUNT) +public class CGBCCreditCardAccountInfoEntry { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty("姓名") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("证件名称") + private String idType; + + @ExcelProperty("证件号") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + @ExcelProperty("卡号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("移动电话号码") + private String phone; + + @ExcelProperty("家庭地址") + private String address; + + @ExcelProperty("开卡日期") + private String openingAccountDate; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCCreditCardOtherStatementEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCCreditCardOtherStatementEntity.java new file mode 100644 index 0000000..6edfafe --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCCreditCardOtherStatementEntity.java @@ -0,0 +1,66 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 光大银行流水读取-信用卡-其他模板 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CGBC_OTHER_CREDIT_CARD_STATEMENT) +public class CGBCCreditCardOtherStatementEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + /** + * 客户名称 + */ + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + // 卡号 + @ExcelProperty("卡号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + // 交易日期 2019-12-03 + @ExcelProperty("交易日期") + private String transactionTime; + + @ExcelProperty("资金收付标识") + private String loanFlag; + + @ExcelProperty("入账金额") + private String transactionAmount; + + @ExcelProperty("交易描述") + private String transSummary; + + @ExcelProperty("交易对方账户名称") + private String counterpartyName; + // 对方账号 + @ExcelProperty("交易对方账号或卡号") + private String counterpartyAccount; + // 对方账户名称 + @ExcelProperty("对方账户名称") + private String counterpartyAccountName; + + @ExcelProperty("交易对手银行名称") + private String counterpartyBankName; + + @ExcelProperty("信用卡消费商户名称") + private String transRemark; + + private String caseId; + + @ExcelIgnore + private String sourceFile; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCCreditCardStatementEntry.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCCreditCardStatementEntry.java new file mode 100644 index 0000000..71aae73 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCCreditCardStatementEntry.java @@ -0,0 +1,69 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * 广发银行流水读取-信用卡 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CGBC_CREDIT_CARD_STATEMENT) +public class CGBCCreditCardStatementEntry { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + /** + * 客户名称 + */ + @ExcelProperty("姓名") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + // 卡号 + @ExcelProperty("卡号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("证件号") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + // 交易日期 + @ExcelProperty("交易日期") + private String transactionTime; + + // 当入账金额不等于原交易金额时,都是-,否则为+ + @ExcelProperty("入账金额") + private BigDecimal entryAmount; + + @ExcelProperty("原交易金额") + private BigDecimal transactionAmount; + + @ExcelProperty("交易金额") + private BigDecimal transactionAmountNext; + + @ExcelProperty("交易描述") + private String summary; + + @ExcelProperty("交易代码中文") + private String transRemark; + + @ExcelProperty("交易代码") + private String transCode; + + @ExcelProperty("授权号") + private String sqCode; + + private String caseId; + + private String sourceFile; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCNewCompanyInfoEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCNewCompanyInfoEntity.java new file mode 100644 index 0000000..557cae2 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCNewCompanyInfoEntity.java @@ -0,0 +1,46 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 广发银行客户信息 + *
+ * 都是人民币 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CGBC_CUSTOMER_INFO) +public class CGBCNewCompanyInfoEntity { + + //搜索关键字 + public static final String KEY = "新核心对公客户资料"; + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("证件类型") + @IndexField(fieldType = FieldType.KEYWORD) + private String idType; + + @ExcelProperty("证件号码") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + @ExcelProperty("联系方式") + private String phone; + + @ExcelProperty("地址") + private String address; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCNewCurrentAccountInfoEntry.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCNewCurrentAccountInfoEntry.java new file mode 100644 index 0000000..3cc7eec --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCNewCurrentAccountInfoEntry.java @@ -0,0 +1,54 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 广发银行活期开户信息 + *
+ * 都是人民币 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CGBC_OPENING_ACCOUNT) +public class CGBCNewCurrentAccountInfoEntry { + + public static final String KEY = "新核心活期开户资料"; + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("证件类型") + private String idType; + + @ExcelProperty("证件号码") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + @ExcelProperty("账号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("账户状态字") + private String status; + + @ExcelProperty("开户日期") + private String openingAccountDate; + + @ExcelProperty("销户日期") + private String closeDate; + + @ExcelProperty("开户行名") + private String accountOpeningInstitution; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCNewCustomerInfoEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCNewCustomerInfoEntity.java new file mode 100644 index 0000000..dc3fa97 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCNewCustomerInfoEntity.java @@ -0,0 +1,45 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 广发银行客户信息 + *
+ * 都是人民币 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CGBC_CUSTOMER_INFO) +public class CGBCNewCustomerInfoEntity { + + //搜索关键字 + public static final String KEY = "新核心个人客户资料"; + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("证件类型") + private String idType; + + @ExcelProperty("证件号码") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + @ExcelProperty("电话") + private String phone; + + @ExcelProperty("地址") + private String address; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCNewRegularAccountInfoEntry.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCNewRegularAccountInfoEntry.java new file mode 100644 index 0000000..ef8550d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCNewRegularAccountInfoEntry.java @@ -0,0 +1,54 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 广发银行定期开户信息 + *
+ * 都是人民币 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CGBC_OPENING_ACCOUNT) +public class CGBCNewRegularAccountInfoEntry { + + public static final String KEY = "新核心定期开户资料"; + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("证件类型") + private String idType; + + @ExcelProperty("证件号码") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + @ExcelProperty("实体账号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("账户状态字") + private String status; + + @ExcelProperty("开户日期") + private String openingAccountDate; + + @ExcelProperty("销户日期") + private String closeDate; + + @ExcelProperty("开户行名") + private String accountOpeningInstitution; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCNewStatementEntry.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCNewStatementEntry.java new file mode 100644 index 0000000..f94a55d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCNewStatementEntry.java @@ -0,0 +1,80 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * 广发银行流水读取-新核心交易流水 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CGBC_SAVINGS_CARD_NEW_STATEMENT) +public class CGBCNewStatementEntry { + + public static final int SHEET_NO = 2; + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + /** + * 客户名称 + */ + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + // 卡号 + @ExcelProperty("本方账号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + // 交易日期 + @ExcelProperty("交易日期") + private String transDate; + + @ExcelProperty("交易时间") + private String transTime; + + @ExcelProperty("借贷\n" + "标识") + private String loanFlag; + + // 收入金额 + @ExcelProperty("交易金额") + private BigDecimal transactionAmount; + + // 交易后余额 + @ExcelProperty("当前余额") + private BigDecimal balance; + + // 对方账号 + @ExcelProperty("对方账号") + private String counterpartyAccount; + + @ExcelProperty("对手账号名称") + private String counterpartyName; + + @ExcelProperty("摘要中文") + private String summary; + + @ExcelProperty("附言") + private String transRemark1; + @ExcelProperty("备注") + private String transRemark2; + + @ExcelProperty("交易渠道") + private String transChannel; + + private String caseId; + + @ExcelIgnore + private String sourceFile; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCOldAccountInfoEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCOldAccountInfoEntity.java new file mode 100644 index 0000000..5ff9954 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCOldAccountInfoEntity.java @@ -0,0 +1,60 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 广发银行旧核心开户信息 + *
+ * 都是人民币 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CGBC_OPENING_ACCOUNT) +public class CGBCOldAccountInfoEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + public static final String KEY = "旧核心开户资料"; + + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("证件类型") + private String idType; + + @ExcelProperty("证件号码") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + @ExcelProperty("卡号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("移动电话") + private String phone; + + @ExcelProperty("账户状态字") + private String status; + + @ExcelProperty("开户日期") + private String openingAccountDate; + + @ExcelProperty("销户日期") + private String closeDate; + + @ExcelProperty("开户行所") + private String accountOpeningInstitution; + + @ExcelProperty("通讯地址") + private String address; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCStatementEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCStatementEntity.java new file mode 100644 index 0000000..27c455d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGBCStatementEntity.java @@ -0,0 +1,78 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 广发银行流水读取-旧核心交易流水 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CGBC_SAVINGS_CARD_STATEMENT) +public class CGBCStatementEntity { + + public static final int SHEET_NO = 1; + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + /** + * 客户名称 + */ + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + // 卡号 + @ExcelProperty("账号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + // 交易日期 + @ExcelProperty("交易日期") + private String transDate; + + @ExcelProperty("交易时间") + private String transTime; + + //出账 - + @ExcelProperty({"借贷\n标识","借贷标识"}) + private String loanFlag; + // 收入金额 + @ExcelProperty("交易金额") + private String transactionAmount; + + // 交易后余额 + @ExcelProperty("余额") + private String balance; + + // 对方账号 + @ExcelProperty("对手账号") + private String counterpartyAccount; + + @ExcelProperty("对手名") + private String counterpartyName; + + @ExcelProperty("对方行名") + private String counterpartyBankName; + + @ExcelProperty("摘要中文") + private String summary; + + @ExcelProperty("备注") + private String transRemark; + + @ExcelProperty("交易渠道") + private String transChannel; + + private String caseId; + + @ExcelIgnore + private String sourceFile; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGSBankStatement.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGSBankStatement.java new file mode 100644 index 0000000..ab312ea --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGSBankStatement.java @@ -0,0 +1,76 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * 中国银行流水读取-公司 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CGS_STATEMENT) +public class CGSBankStatement { + + @IndexId(type = IdType.CUSTOMIZE) + @ExcelProperty("id") + private String id; + + @ExcelProperty("银行") + @IndexField(fieldType = FieldType.KEYWORD) + private String bankName; + + @ExcelProperty("查询卡号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("借贷标志") + private String creditMark; + + @ExcelProperty("交易金额") + private BigDecimal transactionAmount; + + @ExcelProperty("交易余额") + private BigDecimal balance; + + @ExcelProperty("交易时间") + private String transTime; + + @ExcelProperty("交易对方名称") + private String counterpartyName; + + @ExcelProperty("交易对方卡号") + private String counterpartyAccount; + + @ExcelProperty("交易对方证件号码") + private String counterpartyIdCardNo; + + @ExcelProperty("交易对方账号开户行") + private String counterpartyBankName; + + @ExcelProperty("交易摘要") + private String transSummary; + + @ExcelProperty("交易网点名称") + private String transactionSituation; + + @ExcelProperty("交易发生地") + private String transChannel; + + @ExcelProperty("备注") + private String transRemark; + + private String caseId; + + @ExcelIgnore + private String sourceFile; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGSOpenAccountInfo.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGSOpenAccountInfo.java new file mode 100644 index 0000000..8710034 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CGSOpenAccountInfo.java @@ -0,0 +1,66 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + + +/** + * 央地系统流水读取-公司 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CGS_OPEN_ACCOUNT_INFO) +public class CGSOpenAccountInfo { + + @IndexId(type = IdType.CUSTOMIZE) + @ExcelProperty("id") + private String id; + + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("证件/证照类型代码") + private String idType; + + @ExcelProperty("证件/证照号码") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + @ExcelProperty("联系手机") + private String phone; + + @ExcelProperty("住宅地址") + private String address; + + @ExcelProperty("卡号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("账号") + @IndexField(fieldType = FieldType.KEYWORD) + private String accountNo; + + @ExcelProperty("开户网点") + private String accountOpeningInstitution; + + @ExcelProperty("开户日期") + private String openingAccountDate; + + @ExcelProperty("账户状态") + private String status; + + @ExcelProperty("销户日期") + private String closeDate; + + @ExcelProperty("银行名称") + private String bankName; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CIBCreditCardBSEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CIBCreditCardBSEntity.java new file mode 100644 index 0000000..305a006 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CIBCreditCardBSEntity.java @@ -0,0 +1,57 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.util.Date; + +/** + * 兴业银行信用卡流水 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CIB_CREDIT_CARD_STATEMENT) +public class CIBCreditCardBSEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + /** + * 银行名称 + */ + @ExcelProperty(value = "银行名称") + private String bankName; + + @ExcelProperty("卡号") + private String cardNumber; + + @ExcelProperty(value = "持卡人姓名") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("交易摘要") + private String summary; + + /** + * 交易金额 + */ + @ExcelProperty("交易金额") + private String transactionAmount; + /** + * 交易时间 + */ + @com.alibaba.excel.annotation.format.DateTimeFormat("yyyyMMdd HH:mm:ss") + @ExcelProperty("交易日期") + private Date transactionTime; + + private String caseId; + + @ExcelIgnore + private String sourceFile; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CIBOpeningAccountInfoEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CIBOpeningAccountInfoEntity.java new file mode 100644 index 0000000..6facae5 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CIBOpeningAccountInfoEntity.java @@ -0,0 +1,70 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 兴业银行开户信息 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CIB_OPENING_ACCOUNT) +public class CIBOpeningAccountInfoEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + /** + * 户名 + */ + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + /** + * 银行名称 + */ + private String bankName; + + /** + * 通过账号与流水连上 + */ + @ExcelProperty("账户代号") + @IndexField(fieldType = FieldType.KEYWORD) + private String newAccountNumber; + + /** + * 账号 + */ + @ExcelProperty("卡号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + /** + * 证件类型 + */ + private String idType; + + /** + * 证件号码 + */ + @ExcelProperty("证件号码") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + /** + * 开户日期 + */ + @ExcelProperty("开户日期") + private String openingAccountDate; + + @ExcelProperty("记录状态") + private String status; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CIBStatementEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CIBStatementEntity.java new file mode 100644 index 0000000..15d2079 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CIBStatementEntity.java @@ -0,0 +1,77 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 兴业银行流水读取 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CIB_STATEMENT) +public class CIBStatementEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + /** + * 客户名称 + */ + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + // 卡号 + @ExcelProperty("账户代号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + // 交易日期 + @ExcelProperty("交易日期") + private String transDate; + + @ExcelProperty("交易时间") + private String transTime; + + /** + * 1为+,0为- + */ + @ExcelProperty("借贷标记") + private String loanFlag; + + // 收入金额 + @ExcelProperty("交易金额") + private String transactionAmount; + + // 交易后余额 + @ExcelProperty("账户余额") + private String balance; + + // 对方账号 + @ExcelProperty("对方账户代号") + private String counterpartyAccount; + + @ExcelProperty("对方客户名称") + private String counterpartyName; + + @ExcelProperty("对方行名") + private String counterpartyBankName; + + @ExcelProperty("摘要说明") + private String summary; + + @ExcelProperty("用途") + private String transRemark; + + private String caseId; + + @ExcelIgnore + private String sourceFile; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CITICBankStatementEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CITICBankStatementEntity.java new file mode 100644 index 0000000..18de72d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CITICBankStatementEntity.java @@ -0,0 +1,87 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.format.NumberFormat; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 中信银行开户信息 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CITIC_STATEMENT) +public class CITICBankStatementEntity { + + @ExcelIgnore + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty({"客户名称","账户名称","姓名"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String customerName; + + @ExcelProperty({"客户账号", "客户账户","卡号"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty({"证件号"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + + + @ExcelProperty({"交易日期","入账日期"}) + private String transDate; + + @ExcelProperty("交易时间") + private String transTime; + + @ExcelProperty("币种") + private String transCurrencyType; + + /** + * C - +,D - - + */ + @ExcelProperty({"借贷标识","借贷"}) + private String creditMark; + + @ExcelProperty({"交易金额","入账金额"}) + @NumberFormat("#.00") + private String transactionAmount; + + @ExcelProperty({"账户余额", "账号余额", "交易后余额"}) + @NumberFormat("#.00") + private String balance; + + @ExcelProperty({"通用对方客户账号", "对方账号"}) + private String counterpartyAccount; + + @ExcelProperty("对方行名称") + private String counterpartyBankName; + + @ExcelProperty({"摘要", "传票摘要","交易描述"}) + private String summary; + + @ExcelProperty("摘要长内容") + private String transRemark; + + @ExcelProperty({"对方账户名称", "对方账户名称"}) + private String counterpartyName; + + @ExcelProperty("交易渠道") + private String transChannel; + + @ExcelProperty("是否信用卡") + private Boolean creditCard = false; + + @ExcelIgnore + private String sourceFile; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CITICOpeningAccountInfoEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CITICOpeningAccountInfoEntity.java new file mode 100644 index 0000000..bad43a1 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CITICOpeningAccountInfoEntity.java @@ -0,0 +1,63 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * 中信银行开户信息 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CITIC_OPENING_ACCOUNT) +public class CITICOpeningAccountInfoEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty({"客户名称", "客户名","账户户名"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty({"客户账号", "客户主账号", "主账号", "客户号", "卡号", "账号"}) + private String accountNumber; + + @ExcelProperty({"子账号"}) + private String accountNumberItem; + + @ExcelProperty("证件号码") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + @ExcelProperty("证件类型") + private String idType; + + @ExcelProperty("住宅地址") + private String address; + + @ExcelProperty("联系电话") + private String phone; + + @ExcelProperty("客户号") + private String customerId; + + @ExcelProperty("开户日期") + private String openingAccountDate; + + @ExcelProperty("账户余额") + private BigDecimal balance; + + @ExcelProperty({"系统账户状态", "账户状态"}) + private String status; + + @ExcelProperty(value = "开户机构名称") + private String accountOpeningInstitution; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBCCreditCardAccountInfoEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBCCreditCardAccountInfoEntity.java new file mode 100644 index 0000000..bb35c8f --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBCCreditCardAccountInfoEntity.java @@ -0,0 +1,61 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 民生银行客户信息-信用卡 + *
+ * 都是人民币 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CMBC_CREDIT_CARD_OPENING_ACCOUNT) +public class CMBCCreditCardAccountInfoEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("证件号码") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + @ExcelProperty("证件种类") + private String idType; + + @ExcelProperty({"卡号", "客户账号"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty({"手机号码", "联系手机"}) + private String phone; + + /** + * 地址 + */ + @ExcelProperty({" 通讯地址", "通讯地址"}) + private String address; + + /** + * 开户日期 + */ + @ExcelProperty("开户日期") + private String openingAccountDate; + + /** + * 开户机构 + */ + @ExcelProperty("开户机构") + private String accountOpeningInstitution; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBCCreditCardBankStatementEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBCCreditCardBankStatementEntity.java new file mode 100644 index 0000000..ffa2e33 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBCCreditCardBankStatementEntity.java @@ -0,0 +1,81 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 民生银行流水读取-信用卡 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CMBC_CREDIT_CARD_STATEMENT) +public class CMBCCreditCardBankStatementEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @IndexField(fieldType = FieldType.KEYWORD) + @ExcelProperty("客户名称") + private String cardHolderName; + + // 卡号 + @ExcelProperty("查询帐号") + @IndexField(fieldType = FieldType.KEYWORD) + private String accountNumber; + + // 卡号 + @ExcelProperty("查询卡号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("借贷标志") + private String loanFlag; + + // 交易日期 2012/12/18 13:19:08 + @ExcelProperty("交易时间") + private String transactionTime; + + // 收入金额 + @ExcelProperty("交易金额") + private String transactionAmount; + + // 交易后余额 + @ExcelProperty("交易余额") + private String balance; + + // 对方账号 + @ExcelProperty("交易对方账号") + private String counterpartyAccount; + + @ExcelProperty("交易对方名称") + private String counterpartyName; + + @ExcelProperty("交易对方账号开户行") + private String counterpartyBankName; + + @ExcelProperty("交易对方证件号码") + private String counterpartyIdCardNo; + + @ExcelProperty("交易摘要") + private String summary; + + @ExcelProperty("交易网点代码") + private String transRemark; + + @ExcelProperty("交易渠道") + private String transChannel; + + @ExcelProperty("交易流水号") + private String serialNumber; + + @ExcelIgnore + private String sourceFile; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBCSavingsCardAccountInfoEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBCSavingsCardAccountInfoEntity.java new file mode 100644 index 0000000..c98e26f --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBCSavingsCardAccountInfoEntity.java @@ -0,0 +1,68 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 民生银行客户信息-储蓄卡 + *
+ * 都是人民币 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CMBC_SAVINGS_CARD_OPENING_ACCOUNT) +public class CMBCSavingsCardAccountInfoEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("证件号码") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + @ExcelProperty({"卡号", "客户账号"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + // 如果卡号和账号相同,那么是信用卡,否则为储蓄卡 + @ExcelProperty({"账号", "账户账号"}) + private String accountNumber; + + @ExcelProperty("手机号码") + private String phone; + + /** + * 证件类型 + */ + @ExcelProperty(" 证件种类") + private String idType; + + /** + * 地址 + */ + @ExcelProperty(" 通讯地址") + private String address; + + /** + * 开户日期 + */ + @ExcelProperty("开户日期") + private String openingAccountDate; + + /** + * 开户机构 + */ + @ExcelProperty("开户机构") + private String accountOpeningInstitution; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBCSavingsCardBankStatementEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBCSavingsCardBankStatementEntity.java new file mode 100644 index 0000000..9ac3802 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBCSavingsCardBankStatementEntity.java @@ -0,0 +1,91 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.format.NumberFormat; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * 招商银行流水读取-储蓄卡 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CMBC_SAVINGS_CARD_STATEMENT) +public class CMBCSavingsCardBankStatementEntity { + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + /** + * 客户名称 + */ + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + // 卡号 + @ExcelProperty("查询卡号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("查询帐号") + private String accountNumber; + + @ExcelProperty("借贷标志") + private String loanFlag; + + // 交易日期 2012/12/18 13:19:08 + @ExcelProperty("交易时间") + private String transactionTime; + + // 收入金额 + @ExcelProperty("交易金额") + @NumberFormat("#.00") + private BigDecimal transactionAmount; + + // 交易后余额 + @ExcelProperty("交易余额") + @NumberFormat("#.00") + private BigDecimal balance; + + // 对方账号 + @ExcelProperty("交易对方账号") + private String counterpartyAccount; + + @ExcelProperty("交易对方名称") + private String counterpartyName; + + @ExcelProperty("交易对方账号开户行") + private String counterpartyBankName; + + @ExcelProperty("交易对方证件号码") + private String counterpartyIdCardNo; + + @ExcelProperty("交易摘要") + private String summary; + + @ExcelProperty("交易网点名称") + private String transRemark; + + @ExcelProperty("交易渠道") + private String transChannel; + + @ExcelProperty("交易流水号") + private String serialNumber; + + //交易网点代码 + @ExcelProperty("交易网点代码") + private String transactionInstitutions; + + @ExcelIgnore + private String sourceFile; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBCSavingsCardCompanyInfoEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBCSavingsCardCompanyInfoEntity.java new file mode 100644 index 0000000..2914b42 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBCSavingsCardCompanyInfoEntity.java @@ -0,0 +1,70 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 民生银行客户信息-储蓄卡-公司 + *
+ * 都是人民币 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CMBC_SAVINGS_CARD_COMPANY_INFO) +public class CMBCSavingsCardCompanyInfoEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty({"组织机构代码", "证件号码"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + @ExcelProperty("客户账号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("联系人电话号码") + private String phone; + + /** + * 证件类型 + */ + @ExcelProperty("证件种类") + private String idType; + + /** + * 地址 + */ + @ExcelProperty("通讯地址") + private String address; + + /** + * 开户日期 + */ + @ExcelProperty("开户日期") + private String openingAccountDate; + + @ExcelProperty("销户日期") + private String closeDate; + + /** + * 开户机构 + */ + @ExcelProperty("开户机构") + private String accountOpeningInstitution; + + @ExcelProperty("存款账户状态") + private String status; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBOpeningAccountInfoEntry.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBOpeningAccountInfoEntry.java new file mode 100644 index 0000000..019a06f --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBOpeningAccountInfoEntry.java @@ -0,0 +1,64 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 招商银行开户信息 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CMB_OPENING_ACCOUNT) +public class CMBOpeningAccountInfoEntry { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty({"客户姓名","客户名称","姓名"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("证件号码") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + @ExcelProperty({"移动电话","手机号"}) + private String phone; + + @ExcelProperty({"户口号","账号","卡号"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + + @ExcelProperty("开户机构") + private String openingAccountSituation; + + @ExcelProperty("开户日期") + private String openingAccountDate; + + @ExcelProperty("关户日期") + private String closeAccountDate; + + @ExcelProperty("户口状态") + private String status; + + @ExcelProperty("证件类型") + private String idType; + + @ExcelProperty("联系地址") + private String address; + + @ExcelProperty("户口代码") + private String type; + + private String caseId; + + @ExcelProperty("账户号") + private String accountNo; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBRetailStatementEntry.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBRetailStatementEntry.java new file mode 100644 index 0000000..4bbc0ee --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBRetailStatementEntry.java @@ -0,0 +1,67 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.format.DateTimeFormat; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * 招商银行流水信息-零售 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CMB_RETAIL_STATEMENT) +public class CMBRetailStatementEntry { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("交易卡号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("交易日期") + @DateTimeFormat("yyyy-MM-DD") + private String transDate; + + @ExcelProperty("交易时间") + @DateTimeFormat("HH:mm:ss") + private String transTime; + + @ExcelProperty("交易金额") + private BigDecimal transactionAmount; + + @ExcelProperty("联机余额") + private BigDecimal balance; + + @ExcelProperty("收付方名称") + private String counterpartyName; + + @ExcelProperty("收付方账号") + private String counterpartyAccount; + + @ExcelProperty("收付方行名") + private String counterpartyBankName; + + @ExcelProperty("我方摘要") + private String summary; + + @ExcelProperty("交易描述") + private String transRemark; + + @ExcelProperty("交易机构名称") + private String transInstitutions; + + private String caseId; + private String sourceFile; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBStatementEntry.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBStatementEntry.java new file mode 100644 index 0000000..9bc0265 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/CMBStatementEntry.java @@ -0,0 +1,80 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.format.DateTimeFormat; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * 招商银行流水信息 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_CMB_STATEMENT) +public class CMBStatementEntry { + + @ExcelIgnore + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("交易卡号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("交易日期") + @DateTimeFormat("yyyy-MM-DD") + private String transDate; + + @ExcelProperty("交易时间") + @DateTimeFormat("HH:mm:ss") + private String transTime; + + @ExcelProperty("交易金额") + private BigDecimal transactionAmount; + + @ExcelProperty("联机余额") + private BigDecimal balance; + + @ExcelProperty("对方客户名称") + private String counterpartyName; + + @ExcelProperty("对方帐号") + private String counterpartyAccount; + + @ExcelProperty("对手客户证件号码") + private String counterpartyIdCardNo; + + @ExcelProperty("对方帐号开户机构名称") + private String counterpartyBankName; + + @ExcelProperty("摘要名称") + private String summary; + + @ExcelProperty("文字摘要") + private String transRemark; + + @ExcelProperty("渠道名称") + private String transChannel; + + @ExcelProperty("交易机构") + private String transInstitutions; + + @ExcelProperty("交易流水") + private String serialNumber; + + private String caseId; + + private String sourceFile; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/FDBPrivateAccountOpeningInfoEntry.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/FDBPrivateAccountOpeningInfoEntry.java new file mode 100644 index 0000000..0f957c3 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/FDBPrivateAccountOpeningInfoEntry.java @@ -0,0 +1,53 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 富滇银行开户信息读取-个人 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_FDB_OPENING_ACCOUNT_PRIVATE) +public class FDBPrivateAccountOpeningInfoEntry { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty("开户机构") + private String accountOpeningInstitution; + + @ExcelProperty("主账号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("客户姓名") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty({"身份证",""}) + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + @ExcelProperty("余额") + private String balance; + + @ExcelProperty("账户状态") + private String status; + + @ExcelProperty("开户日") + private String openingAccountDate; + + /** + * 销户日期 + */ + @ExcelProperty("销户日期") + private String closingDate; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/FDBPublicAccountOpeningInfoEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/FDBPublicAccountOpeningInfoEntity.java new file mode 100644 index 0000000..a77a684 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/FDBPublicAccountOpeningInfoEntity.java @@ -0,0 +1,57 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 富滇银行开户信息读取-对公 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_FDB_OPENING_ACCOUNT_PUBLIC) +public class FDBPublicAccountOpeningInfoEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty("开户机构") + @IndexField(fieldType = FieldType.KEYWORD) + private String accountOpeningInstitution; + + @ExcelProperty("主账号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("户名") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("证件类型") + private String idType; + + @ExcelProperty("证件号码") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + @ExcelProperty("账户余额") + private String balance; + + @ExcelProperty("账户状态") + private String status; + + @ExcelProperty("开户日期") + private String openingAccountDate; + + /** + * 销户日期 + */ + @ExcelProperty("销户日期") + private String closingDate; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/FDBStatementEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/FDBStatementEntity.java new file mode 100644 index 0000000..d67022d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/FDBStatementEntity.java @@ -0,0 +1,91 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 富滇银行流水读取 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_FDB_STATEMENT) +public class FDBStatementEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + /** + * 客户名称 + */ + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String customerName; + // 主账号 可以视为卡号 + //由于个人客户只有主账号,所以,统一用主账号作为卡号 + @ExcelProperty("主账号") + @IndexField(fieldType = FieldType.KEYWORD) + private String masterAccount; + // 账号 + @ExcelProperty("账号") + private String account; + // 卡号 + @ExcelProperty("卡号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + // 开户机构名称 + @ExcelProperty("开户机构名称") + private String openingSituation; + + @ExcelProperty("交易币种") + private String transCurrencyType; + // 交易日期 + @ExcelProperty("交易日期") + private String transactionTime; + + // 收入金额 + @ExcelProperty("收入金额") + private String revenueAmount; + // 支出金额 + @ExcelProperty("支出金额") + private String expenditureAmount; + // 交易后余额 + @ExcelProperty("交易后余额") + private String balance; + + @ExcelProperty("交易摘要") + private String transSummary; + + // 交易机构名称 + @ExcelProperty("交易机构名称") + private String transactionSituationName; + // 对方账号 + @ExcelProperty("对方账号") + private String counterpartyAccount; + // 对方账户名称 + @ExcelProperty("对方账户名称") + private String counterpartyAccountName; + // 对方机构名称 + @ExcelProperty("对方机构名称") + private String counterpartySituationName; + + @ExcelProperty("渠道类型") + private String transChannel; + + @ExcelProperty("交易流水号") + private String transNo; + + @ExcelProperty("子交易流水号") + private String transChildNo; + + @ExcelIgnore + private String sourceFile; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/HFCompanyStatement.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/HFCompanyStatement.java new file mode 100644 index 0000000..158c0e8 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/HFCompanyStatement.java @@ -0,0 +1,73 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_HF_COMPANY_STATEMENT) +public class HFCompanyStatement { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty("交易日期") + private String transDate; + + @ExcelProperty("交易时间") + private String transTime; + + @ExcelProperty("账号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("户名") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty({"借贷标识d借c贷","交易方向"}) + private String loanFlag; + + @ExcelProperty("交易金额") + private BigDecimal transactionAmount; + + @ExcelProperty("交易余额") + private BigDecimal balance; + + @ExcelProperty({"交易对手方账户","对方账号"}) + private String counterpartyAccount; + + @ExcelProperty({"交易对手方户名","对方户名"}) + private String counterpartyName; + + @ExcelProperty({"交易对手方行名","对方行名"}) + private String counterpartyBankName; + + @ExcelProperty({"摘要码","摘要码+交易码"}) + private String summary; + + @ExcelProperty("交易码") + private String transChannel; + + @ExcelProperty({"交易码描述","备注"}) + private String transRemark; + + private String caseId; + + @ExcelIgnore + private String sourceFile; + + +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/HFCompanyStatementV2.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/HFCompanyStatementV2.java new file mode 100644 index 0000000..a0384cc --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/HFCompanyStatementV2.java @@ -0,0 +1,73 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_HF_COMPANY_STATEMENT_V2) +public class HFCompanyStatementV2 { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty("交易日期") + private String transDate; + + @ExcelProperty("交易本地时间") + private String transTime; + + @ExcelProperty("客户账号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("户名") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + + //借方金额 + @ExcelProperty("存款借方发生额") + private BigDecimal debitAmount; + + //贷方金额 + @ExcelProperty("存款贷方发生额") + private BigDecimal creditAmount; + + @ExcelProperty("交易金额") + private BigDecimal transactionAmount; + + @ExcelProperty("交易余额") + private BigDecimal balance; + + @ExcelProperty("对方交易账号") + private String counterpartyAccount; + + @ExcelProperty("对方交易账号名称") + private String counterpartyName; + + @ExcelProperty("对方交易行名") + private String counterpartyBankName; + + @ExcelProperty("交易备注") + private String transRemark; + + private String caseId; + + @ExcelIgnore + private String sourceFile; + + +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/HXBankStatementEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/HXBankStatementEntity.java new file mode 100644 index 0000000..a845807 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/HXBankStatementEntity.java @@ -0,0 +1,74 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * 华夏银行账户明细 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_HUAXIA_STATEMENT) +public class HXBankStatementEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + /** + * 客户名称 + */ + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + // 卡号 + @ExcelProperty("查询卡账号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("借贷标志") + private String loanFlag; + + // 交易日期 20110921002233 + @ExcelProperty("交易时间") + private String transactionTime; + + // 收入金额 + @ExcelProperty("交易金额") + private BigDecimal transactionAmount; + + // 交易后余额 + @ExcelProperty("交易余额") + private BigDecimal balance; + + // 对方账号 + @ExcelProperty("交易对方账卡号") + private String counterpartyAccount; + + @ExcelProperty("交易对方名称") + private String counterpartyName; + + @ExcelProperty("交易对方证件号码") + private String counterpartyIdCardNo; + + @ExcelProperty("交易对方账号开户行") + private String counterpartyBankName; + + @ExcelProperty("交易网点名称") + private String transactionInstitutions; + + @ExcelProperty("交易摘要") + private String summary; + + @ExcelIgnore + private String sourceFile; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/HXPersonalBankStatementEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/HXPersonalBankStatementEntity.java new file mode 100644 index 0000000..73c204b --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/HXPersonalBankStatementEntity.java @@ -0,0 +1,76 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * 华夏银行个人账户明细 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_HUAXIA_STATEMENT_PERSONAL) +public class HXPersonalBankStatementEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + /** + * 客户名称 + */ + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + // 卡号 + @ExcelProperty("账号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + // 交易日期 + @ExcelProperty({"发生日期", "过账日期"}) + private String transDate; + + @ExcelProperty("交易机构") + private String transactionInstitutions; + + + @ExcelProperty("摘要") + private String summary; + + @ExcelProperty("借贷标志") + private String loanFlag; + + // 收入金额 + @ExcelProperty("发生额") + private BigDecimal transactionAmount; + + // 交易后余额 + @ExcelProperty("余额") + private BigDecimal balance; + + //对手名 + @ExcelProperty("对方户名(或商户名称)") + private String counterpartyName; + + @ExcelProperty("对方账号(或商户编号)") + private String counterpartyAccount; + + @ExcelProperty("对方银行") + private String counterpartyBankName; + + //交易备注 + @ExcelProperty("业务类型") + private String transRemark; + + @ExcelIgnore + private String sourceFile; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/HuaXiaAccountInfoEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/HuaXiaAccountInfoEntity.java new file mode 100644 index 0000000..76eb5ae --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/HuaXiaAccountInfoEntity.java @@ -0,0 +1,70 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 华夏银行-账户信息列表 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_HUAXIA_OPENING_ACCOUNT_INFO) +public class HuaXiaAccountInfoEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + /** 户名 */ + @ExcelProperty("客户名称") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + /** 账号 */ + @ExcelProperty("账号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + /** 证件类型 */ + @ExcelProperty(value = {"证照类型代码", "证件类型"}) + private String idType; + + /** 证件号码 */ + @ExcelProperty(value = {"证照号码", "证件号码"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + /** 电话号码 */ + @ExcelProperty("联系手机") + private String phone; + + /** 地址 */ + @ExcelProperty("住宅地址") + private String address; + + /** 开户日期 */ + @ExcelProperty("开户日期") + private String openingAccountDate; + + /** 销户日期 */ + @ExcelProperty("销户日期") + private String closingDate; + + /** 账户状态 */ + @ExcelProperty("账户状态") + private String status; + + /** 账户类型 */ + @ExcelProperty("账户类别") + private String type; + + /** 开户机构 */ + @ExcelProperty("开户网点") + private String accountOpeningInstitution; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/ICBCBankStatementEntry.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/ICBCBankStatementEntry.java new file mode 100644 index 0000000..6b4aed4 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/ICBCBankStatementEntry.java @@ -0,0 +1,86 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 工商银行流水信息-储蓄卡流水 + *
+ * 都是人民币 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_ICBC_STATEMENT) +public class ICBCBankStatementEntry { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + private String cardHolderName; + + @ExcelProperty({"账号","帐号"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String accountNumber; + + @ExcelProperty("卡号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("币种") + private String transCurrencyType; + + // 2011-01-27-16.43.28.841519 + @ExcelProperty({"交易时间戳","入帐时间"}) + private String transactionTime; + + @ExcelProperty("入帐日期") + private String transactionDate; + + @ExcelProperty("证件号码") + private String idCardNo; + + /** + * 借- - + * 贷- + + */ + @ExcelProperty("借贷标志") + private String loanFlag; + + @ExcelProperty("发生额") + private String transactionAmount; + + @ExcelProperty("余额") + private String balance; + + @ExcelProperty("注释") + private String transRemark; + + @ExcelProperty({"对方帐户","对方账号","对方帐号"}) + private String counterpartyAccount; + + @ExcelProperty({"交易网点号","交易核算机构号"}) + private String transactionInstitutions; + + @ExcelProperty("对方户名") + private String counterpartName; + + @ExcelProperty("对方开户行名") + private String counterpartyBankName; + + @ExcelProperty("交易场所简称") + private String summary; + + @ExcelProperty("服务界面") + private String transChannel; + + @ExcelIgnore + private String sourceFile; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/ICBCCreditCardBankStatementEntry.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/ICBCCreditCardBankStatementEntry.java new file mode 100644 index 0000000..e4e7610 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/ICBCCreditCardBankStatementEntry.java @@ -0,0 +1,76 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * 工商银行流水信息 - 信用卡流水 + *
+ * 都是人民币 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_ICBC_STATEMENT_CREDIT_CARD) +public class ICBCCreditCardBankStatementEntry { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + private String cardHolderName; + + @ExcelProperty({"账号","帐号"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String accountNumber; + + @ExcelProperty("卡号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("币种") + private String transCurrencyType; + + @ExcelProperty("交易时间戳") + private String transactionTime; + + @ExcelProperty("交易场所简称") + private String summary; + + /** + * 借是-,贷是+ + */ + @ExcelProperty("借贷标志") + private String loanFlag; + + /** + * 其中可能有正负之分,不对,需要重新矫正 + */ + @ExcelProperty("发生额") + private BigDecimal transactionAmount; + + @ExcelProperty("交易地区号") + private String transactionInstitutions; + + @ExcelProperty("对方卡号/账号") + private String counterpartyAccount; + + @ExcelProperty("对方帐户户名") + private String counterpartyName; + + @ExcelProperty("交易描述") + private String transRemark; + + @ExcelProperty("更新后余额") + private BigDecimal updateBalance; + + private String caseId; + + private String sourceFile; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/PSBCETStatementEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/PSBCETStatementEntity.java new file mode 100644 index 0000000..66ee25c --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/PSBCETStatementEntity.java @@ -0,0 +1,66 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 邮储银行流水 + */ +@Data +public class PSBCETStatementEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + /** + * 客户名称 + */ + @ExcelProperty("账户户名") + private String cardHolderName; + + @ExcelProperty({"客户账号"}) + private String cardNumber; + + // 交易日期 2011/07/04 + @ExcelProperty({"交易日期"}) + private String tDate; + + @ExcelProperty({"交易时间"}) + private String tTime; + + // 交易日期 2011/07/04 + + private String transactionTime; + + // 收入金额 + @ExcelProperty("交易金额") + private String transactionAmount; + + // 交易后余额 + @ExcelProperty("账户余额") + private String balance; + + // 对方账号 + @ExcelProperty("对方账号") + private String counterpartyAccount; + + @ExcelProperty("对方户名") + private String counterpartyName; + + @ExcelProperty("对方行名") + private String counterpartyBankName; + + @ExcelProperty("交易渠道") + private String transChannel; + + @ExcelProperty("交易摘要") + private String summary; + + @ExcelIgnore + private String sourceFile; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/PSBCOpeningAccountInfoEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/PSBCOpeningAccountInfoEntity.java new file mode 100644 index 0000000..eec504a --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/PSBCOpeningAccountInfoEntity.java @@ -0,0 +1,92 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 邮储银行开户信息 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_PSBC_ACCOUNT_INFO) +public class PSBCOpeningAccountInfoEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + /** + * 户名 + */ + @ExcelProperty({"户名","账户名称"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + /** + * 账号 + */ + @ExcelProperty({"账号卡号", "账号/卡号","客户账号"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + /** + * 证件类型 + */ + @ExcelProperty("证件类型") + private String idType; + + /** + * 证件号码 + */ + @ExcelProperty("证件号码") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + /** + * 电话号码 + */ + @ExcelProperty({"移动电话", "移动号码"}) + private String phone; + + /** + * 地址 + */ + @ExcelProperty("联系地址") + private String address; + + /** + * 开户日期 + */ + @ExcelProperty("开户日期") + private String openingAccountDate; + + /** + * 销户日期 + */ + @ExcelProperty("销户日期") + private String closingDate; + + /** + * 账户状态 + */ + @ExcelProperty("账户状态") + private String status; + + /** + * 冻结信息 + */ + @ExcelProperty("冻结标志") + private String freezeInfo; + + /** + * 开户机构 + */ + @ExcelProperty("开户机构名称") + private String accountOpeningInstitution; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/PSBCStatementEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/PSBCStatementEntity.java new file mode 100644 index 0000000..a246cf8 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/PSBCStatementEntity.java @@ -0,0 +1,67 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 邮储银行流水 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_PSBC_STATEMENT) +public class PSBCStatementEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + /** + * 客户名称 + */ + @IndexField(fieldType = FieldType.KEYWORD) + @ExcelIgnore + private String cardHolderName; + + // 卡号 + @IndexField(fieldType = FieldType.KEYWORD) + @ExcelIgnore + private String cardNumber; + + // 交易日期 2011/07/04 + @ExcelProperty({"交易日期", "交易时间"}) + private String transactionTime; + + // 收入金额 + @ExcelProperty("交易金额") + private String transactionAmount; + + // 交易后余额 + @ExcelProperty("账户余额") + private String balance; + + // 对方账号 + @ExcelProperty("对方账号") + private String counterpartyAccount; + + @ExcelProperty("对方户名") + private String counterpartyName; + + @ExcelProperty("对方行名") + private String counterpartyBankName; + + @ExcelProperty("交易渠道") + private String transChannel; + + @ExcelProperty("摘要") + private String summary; + + @ExcelIgnore + private String sourceFile; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/QJCCBStatementEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/QJCCBStatementEntity.java new file mode 100644 index 0000000..112f326 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/QJCCBStatementEntity.java @@ -0,0 +1,86 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 曲靖商行流水 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_QJCCB_STATEMENT) +public class QJCCBStatementEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + /** + * 客户名称 + */ + @ExcelProperty("户名") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + // 卡号 + @ExcelProperty("账号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + // 交易日期 + @ExcelProperty("交易日期") + private String transDate; + + @ExcelProperty("交易时间") + private String transTime; + + // 收入金额 + @ExcelProperty("交易金额") + private String transactionAmount; + + // 交易后余额 + @ExcelProperty("余额") + private String balance; + @ExcelProperty("账户余额") + private String balance1; + + // 对方账号 + // 6228490860006670017 陆建明 + // 需要解析 + @ExcelProperty("对方账号与户名") + private String counterpartyInfo; + + @ExcelProperty("对方账号") + private String counterpartyAccount; + @ExcelProperty("对方户名") + private String counterpartyName; + @ExcelProperty("对方行名称") + private String counterpartyBankName; + + @ExcelProperty("交易日期 现转 借贷") + private String aboutTime; + + @ExcelProperty("摘要") + private String summary; + + @ExcelProperty("摘要与凭证号") + private String summary1; + + @ExcelProperty("交易名称") + private String transRemark; + + @ExcelProperty("借贷") + private String loanFlag; + + @ExcelProperty("机构名称") + private String transactionInstitutions; + + private String caseId; + + private String sourceFile; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/RCCBankStatementEntry.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/RCCBankStatementEntry.java new file mode 100644 index 0000000..f26a7f0 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/RCCBankStatementEntry.java @@ -0,0 +1,79 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 农村信用社流水信息 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_RCC_STATEMENT) +public class RCCBankStatementEntry { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty("户名") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("账号卡号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("交易日期") + private String transDate; + + @ExcelProperty("交易时间") + private String transTime; + + @ExcelProperty("货币号") + private String transCurrencyType; + + @ExcelProperty("交易金额") + private String transactionAmount; + + @ExcelProperty({"余额", "余额(额度)"}) + private String balance; + + @ExcelProperty("对方账号卡号") + private String counterpartyAccount; + + @ExcelProperty("对方户名") + private String counterpartName; + + @ExcelProperty("对方行号名称") + private String counterpartyBankName; + +// @ExcelProperty("商户名称地址") +// private String summary; + + @ExcelProperty("备注摘要") + private String transRemark; + + // 交易机构名称 + @ExcelProperty("代理机构名称") + private String transactionInstitutions; + + @ExcelProperty("交易渠道") + private String transChannel; + + //交易名称 + @ExcelProperty("交易名称") + private String realCounterpartyName; + + @ExcelProperty("账户类型") + private String cardType; + + @ExcelIgnore + private String sourceFile; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/RCCOpeningAccountInfoEntry.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/RCCOpeningAccountInfoEntry.java new file mode 100644 index 0000000..1ac4d41 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/RCCOpeningAccountInfoEntry.java @@ -0,0 +1,71 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 农村信用社开户信息 + */ +@Data +@IndexName(Constants.MONGO_COLLECTION_NAME_RCC_OPENING_ACCOUNT) +public class RCCOpeningAccountInfoEntry { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty("账号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("新帐号") + private String newAccountNumber; + + @ExcelProperty("户名") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty + private String idType; + + @ExcelProperty("证件号码") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + @ExcelProperty("证件地址") + private String address; + + @ExcelProperty("开户日期") + private String openingAccountDate; + + @ExcelProperty("销户日期") + private String closeAccountDate; + + @ExcelProperty("电话号码") + private String phone; + + @ExcelProperty("账户状态") + private String status; + + @ExcelProperty("账户类型") + private String type; + + /** + * 冻结信息 + */ + @ExcelProperty("冻结信息") + private String freezeInfo; + + /** + * 开户机构 + */ + @ExcelProperty("开户机构名称") + private String accountOpeningInstitution; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/SPAAccountInfoEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/SPAAccountInfoEntity.java new file mode 100644 index 0000000..d48fb2a --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/SPAAccountInfoEntity.java @@ -0,0 +1,70 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 平安银行开户信息 + *
+ * 都是人民币 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_PING_AN_ACCOUNT_INFO) +public class SPAAccountInfoEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty({"客户姓名","账户名称"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty({"新卡号","卡/折号"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty(value = {"证件类型","客户证件名称"}) + private String idType; + + @ExcelProperty({"证件号码","证件号"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + @ExcelProperty({"账户状态","账户状态字名称"}) + private String status; + + @ExcelProperty({"业务类型","业务类型名称"}) + private String type; + + /** + * 开户机构 + */ + @ExcelProperty({"开户网点(支行)","开户机构"}) + private String accountOpeningInstitution; + + @ExcelProperty("客户电话") + private String phone; + + /** + * 开户日期 + */ + @ExcelProperty("开户日期") + private String openingAccountDate; + + /** + * 销户日期 + */ + @ExcelProperty("销户日期") + private String closingDate; + + @ExcelProperty("家庭地址") + private String address; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/SPACreditCardAccountInfoEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/SPACreditCardAccountInfoEntity.java new file mode 100644 index 0000000..4aa56d6 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/SPACreditCardAccountInfoEntity.java @@ -0,0 +1,41 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 平安银行开户信息-信用卡 + *
+ * 都是人民币 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_PING_AN_CREDIT_CARD_ACCOUNT_INFO) +public class SPACreditCardAccountInfoEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty("姓名") + private String cardHolderName; + + @ExcelProperty("卡号") + private String cardNumber; + + @ExcelProperty("18位身份证号码") + private String idCardNo; + + @ExcelProperty("手机号码") + private String phone; + + @ExcelProperty("录入日期") + private String openingAccountDate; + + @ExcelProperty("账单地址") + private String address; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/SPACreditCardStatementEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/SPACreditCardStatementEntity.java new file mode 100644 index 0000000..d184ff5 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/SPACreditCardStatementEntity.java @@ -0,0 +1,57 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.format.NumberFormat; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * 平安银行流水-信用卡 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_PING_AN_CREDIT_CARD_STATEMENT) +public class SPACreditCardStatementEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + /** + * 客户名称 + */ + @ExcelProperty("客户姓名") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + // 卡号 + @ExcelProperty("卡号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty("证件号") + private String idCardNo; + + // 交易日期 + @ExcelProperty("交易日期") + private String transDate; + + // 收入金额 + @ExcelProperty("交易金额") + @NumberFormat("#.00") + private BigDecimal transactionAmount; + + @ExcelProperty("商户描述") + private String transRemark; + + private String caseId; + + @ExcelIgnore + private String sourceFile; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/SPACustomerInfoEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/SPACustomerInfoEntity.java new file mode 100644 index 0000000..204875c --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/SPACustomerInfoEntity.java @@ -0,0 +1,70 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 平安银行开户信息 + *
+ * 都是人民币 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_PING_AN_CUSTOMER_INFO) +public class SPACustomerInfoEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + @ExcelProperty("客户姓名") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + @ExcelProperty("新卡号") + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + @ExcelProperty(value = {"客户证件类型"}) + private String idType; + + @ExcelProperty("证件号码") + @IndexField(fieldType = FieldType.KEYWORD) + private String idCardNo; + + @ExcelProperty("账户状态") + private String status; + + @ExcelProperty("业务类型") + private String type; + + /** + * 开户机构 + */ + @ExcelProperty("开户网点(支行)") + private String accountOpeningInstitution; + + @ExcelProperty("客户电话") + private String phone; + + /** + * 开户日期 + */ + @ExcelProperty("开户日期") + private String openingAccountDate; + + /** + * 销户日期 + */ + @ExcelProperty("销户日期") + private String closingDate; + + @ExcelProperty("家庭地址") + private String address; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/SPAOtherStatementEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/SPAOtherStatementEntity.java new file mode 100644 index 0000000..aa2fe64 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/SPAOtherStatementEntity.java @@ -0,0 +1,83 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * 平安银行流水-另一种形式 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_PING_AN_STATEMENT) +public class SPAOtherStatementEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + /** + * 客户名称 + */ + @ExcelProperty({"户名","账户名称"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + // 卡号 + @IndexField(fieldType = FieldType.KEYWORD) + @ExcelProperty({"卡号","客户账号"}) + private String cardNumber; + + // 交易日期 + @ExcelProperty("交易日期") + private String transDate; + + @ExcelProperty("交易时间") + private String transTime; + + /** + * 借贷标记+ - +, - - - + */ + @ExcelProperty("借贷标志") + private String loanFlag; + + // 收入金额 + @ExcelProperty({"金额(元)","交易金额"}) + private BigDecimal transactionAmount; + + // 交易后余额 + @ExcelProperty({"显示余额","账面余额"}) + private BigDecimal balance; + + @ExcelProperty({"交易机构","交易营业机构"}) + private String transactionInstitutions; + + @ExcelProperty("摘要") + private String summary; + + @ExcelProperty("备注") + private String transRemark; + + // 对方账号 + @ExcelProperty("对方账号") + private String counterpartyAccount; + + @ExcelProperty("对方户名") + private String counterpartyName; + + @ExcelProperty("对方行名") + private String counterpartyBankName; + + @ExcelProperty("真实交易对手账号") + private String realCounterpartyAccount; + + @ExcelProperty("真实交易对手名称") + private String realCounterpartyName; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/SPAStatementEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/SPAStatementEntity.java new file mode 100644 index 0000000..4a9a9f9 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/SPAStatementEntity.java @@ -0,0 +1,86 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * 平安银行流水 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_PING_AN_STATEMENT) +public class SPAStatementEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + + /** + * 客户名称 + */ + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + + // 卡号 + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + + // 交易日期 + @ExcelProperty("交易日期") + private String transDate; + + @ExcelProperty("交易时间") + private String transTime; + + /** + * 借贷标记+ - +, - - - + */ + @ExcelProperty("D/C") + private String loanFlag; + + //借方金额 + @ExcelProperty("借方发生额") + private BigDecimal debitAmount; + //贷方金额 + @ExcelProperty("贷方发生额") + private BigDecimal creditAmount; + + // 收入金额 + @ExcelProperty("交易金额") + private BigDecimal transactionAmount; + + // 交易后余额 + @ExcelProperty({"可用余额", "账户余额","账面余额"}) + private BigDecimal balance; + + @ExcelProperty({"交易机构", "交易网点"}) + private String transactionInstitutions; + + @ExcelProperty("摘要") + private String summary; + @ExcelProperty("备注") + private String transRemark; + + // 对方账号 + @ExcelProperty({"交易对手账号", "交易对方账号"}) + private String counterpartyAccount; + + @ExcelProperty({"交易对手名称", "交易对方户名"}) + private String counterpartyName; + + @ExcelProperty({"交易对手开户行", "交易对方行名称"}) + private String counterpartyBankName; + + @ExcelIgnore + private String sourceFile; + + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/SPDBBSEntity.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/SPDBBSEntity.java new file mode 100644 index 0000000..f2b7bc1 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/domain/entity/SPDBBSEntity.java @@ -0,0 +1,78 @@ +package com.inscloudtech.bankStatementAnalysis.domain.entity; + + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.constant.Constants; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; + +import java.math.BigDecimal; + +/** + * 浦发银行流水 + */ +@Data +@IndexName(Constants.ES_INDEX_NAME_SPDB_CREDIT_CARD_CUSTOMER_STATEMENT) +public class SPDBBSEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + /** + * 客户名称 + */ + @ExcelProperty({"账户中文名", "姓名"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardHolderName; + // 卡号 + @ExcelProperty({"账号", "交易卡号"}) + @IndexField(fieldType = FieldType.KEYWORD) + private String cardNumber; + // 交易日期 + @ExcelProperty({"交易日期", "交易发生日期"}) + private String transDate; + @ExcelProperty("交易时间") + private String transTime; + @ExcelProperty("借贷标志") + private Integer loanFlag; + // 收入金额 + @ExcelProperty("交易金额") + private BigDecimal transactionAmount; + + // 交易后余额 + @ExcelProperty("账户余额") + private BigDecimal balance; + + @ExcelProperty({"摘要代码", "交易描述1"}) + private String summary; + + @ExcelProperty({"对手备注信息", "交易描述2"}) + private String transRemark; + + // 对方账号 + @ExcelProperty({"对方账号", "转出方卡号"}) + private String counterpartyAccount; + + @ExcelProperty({"对方户名", "转出方姓名"}) + private String counterpartyName; + + @ExcelProperty("对方行名") + private String counterpartyBankName; + + //证件号码 + @ExcelProperty("证件号") + private String idCard; + + //交易渠道 + @ExcelProperty("交易类别") + private String transChannel; + + private String caseId; + + @ExcelIgnore + private String sourceFile; +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/excel/CellsWrapper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/excel/CellsWrapper.java new file mode 100644 index 0000000..3765628 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/excel/CellsWrapper.java @@ -0,0 +1,161 @@ +package com.inscloudtech.bankStatementAnalysis.excel; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.exception.ExcelAnalysisStopException; + +import com.aspose.cells.Cell; +import com.aspose.cells.Cells; +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; +import lombok.Getter; +import org.springframework.lang.Nullable; + + +import java.lang.reflect.Field; +import java.util.*; + +//todo:关键字 +@Getter +public class CellsWrapper { + private final Cells cells; + private final Class clazz; + private final boolean isBs; + private final Map fieldMap = new HashMap<>(); + private int headRowNum; + @Getter + private List entryList = new ArrayList<>(); + + public CellsWrapper(Cells cells, Class clazz, boolean isBs) throws Exception { + this.cells = cells; + this.clazz = clazz; + this.isBs = isBs; + init(); + } + + //获取任意一个读出来的实体 + @Nullable + public T getAny() { + if (entryList.isEmpty()) { + return null; + } + return entryList.get(0); + } + + + public void doRead(int limit) { + try { + + int cnt = 0; + if (limit == -1) { + //不限制 + limit = cells.getMaxRow() - headRowNum + 1; + } + + for (int row = headRowNum; row <= cells.getMaxRow(); row++) { + Map map = new HashMap<>(); + for (int col = 0; col < cells.getMaxColumn(); col++) { + Cell cell = cells.get(row, col); + if (cell == null) { + continue; + } + + String value = cell.getStringValue(); + if (StrUtil.isNotEmpty(value)) { + value = value.trim(); + } + + Field field = getFieldByCol(col); + if (field == null) { + continue; + } + field.setAccessible(true); + map.put(field.getName(), value); + } + map.put("id", IdUtil.objectId()); + addToList(map); + cnt++; + if (cnt >= limit) { + throw new ExcelAnalysisStopException(); + } + } + } catch (ExcelAnalysisStopException ex) { + //主动停止 + } + } + + private void addToList(Map map) { + String str = JSONUtil.toJsonStr(map); + entryList.add(JSONUtil.toBean(str, clazz)); + } + + private void init() { + + Map> map = new HashMap<>(); + + Field[] fields = ReflectUtil.getFields(clazz); + for (Field field : fields) { + //获取注解 + ExcelProperty annotation = field.getAnnotation(ExcelProperty.class); + if (annotation == null) { + continue; + } + + map.put(field, Arrays.asList(annotation.value())); + } + + //获取表头 + if (!isBs) { + //开户信息 + //一般情况下,会根据'开户日期'来获取表头 + Cell cell = AsposeUtil.getCell(cells, "开户日期"); + if (cell == null) { + cell = AsposeUtil.getCell(cells, "启用日期"); + if (cell == null) { + cell = AsposeUtil.getCell(cells, "账户启用日期"); + if (cell == null) { + throw new RuntimeException("获取表头关键字不明确,请确认."); + } + } + } + + headRowNum = cell.getRow() + 1; + } else { + Cell cell = AsposeUtil.getCell(cells, "交易日期"); + if (cell == null) { + cell = AsposeUtil.getCell(cells, "交易码"); + if (cell == null) { + throw new RuntimeException("获取表头关键字不明确,请确认."); + } + } + + headRowNum = cell.getRow() + 1; + } + + for (int col = 0; col <= cells.getMaxColumn(); col++) { + String cellValue = cells.get(headRowNum - 1, col).getStringValue().trim(); + for (Map.Entry> entry : map.entrySet()) { + if (entry.getValue().contains(cellValue)) { + fieldMap.put(col, entry.getKey()); + } + } + } + } + + //通过反射获取class对象的属性 + private Field getFieldByCol(int col) { + return fieldMap.getOrDefault(col, null); + } + + public void setValue(String fieldName, String value) throws IllegalAccessException { + for (T t : entryList) { + Field field = ReflectUtil.getField(clazz, fieldName); + if (field != null) { + field.setAccessible(true); + field.set(t, value); + } + } + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/ABCDataAnalysisHelper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/ABCDataAnalysisHelper.java new file mode 100644 index 0000000..867b2bd --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/ABCDataAnalysisHelper.java @@ -0,0 +1,1151 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.exception.ExcelAnalysisStopException; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.util.ListUtils; +import com.aspose.cells.Cell; +import com.aspose.cells.Cells; +import com.aspose.cells.Workbook; +import com.aspose.cells.Worksheet; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; + +import com.inscloudtech.bankStatementAnalysis.excel.CellsWrapper; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.bankStatementAnalysis.service.ImportService; +import com.inscloudtech.common.constant.BankStatementConstants; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.exception.dc.AnalyzeDataFailedException; +import com.inscloudtech.common.exception.dc.ImportDataFailedException; +import com.inscloudtech.common.exception.dc.TemplateNotFindException; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.common.utils.file.FileUtils; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.mapper.es.*; +import com.inscloudtech.datacenter.service.ImportResultService; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; + +import com.inscloudtech.bankStatementAnalysis.domain.entity.ABCCompanyInfoEntity; +import com.inscloudtech.bankStatementAnalysis.domain.entity.ABCCompanyStatementEntity; +import com.inscloudtech.bankStatementAnalysis.domain.entity.ABCCustomerInfoEntity; +import com.inscloudtech.bankStatementAnalysis.domain.entity.ABCCustomerStatementEntity; + +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.openxml4j.exceptions.OLE2NotOfficeXmlFileException; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.util.*; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * 农业银行数据分析 + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class ABCDataAnalysisHelper { + + private final ImportResultService importResultService; + private final ImportService importService; + + private final EsABCCustomerStatementMapper esABCCustomerStatementMapper; + private final EsABCCompanyStatementMapper esABCCompanyStatementMapper; + private final EsABCCustomerInfoMapper esABCCustomerInfoMapper; + private final EsABCCompanyInfoMapper esABCCompanyInfoMapper; + private final ESOpeningAccountInfoMapper esOpeningAccountInfoMapper; + private final static String BANK_NAME = "农业银行"; + private final static String IGNORE_SHEET_NAME = "金融资产列表,首页,子账户列表,冻结历史列表,共有权列表"; + + public void importData(File file, String caseId) { + List fileList = FileUtil.loopFiles(file); + + // 筛选文件 + List excelFileList = HelperUtil.getExcelFile(fileList); + + //农行数据大致分为两类: + // 1. 开户信息和流水在同一个工作簿 + // 2. 开户信息和流水分开工作簿 + //农行的数据文件分两类:1、无法读取;2、可以读取 + for (File excelFile : excelFileList) { + try { + String excelFileName = excelFile.getAbsolutePath(); + String sourceFile = HelperUtil.getSourceFileName(excelFileName, BANK_NAME); + Workbook wb = new Workbook(excelFileName); + List companyOAIList = new ArrayList<>(); + boolean bsHasNotCard = false; + + int count = wb.getWorksheets().getCount(); + for (int sheetNo = 0; sheetNo < count; sheetNo++) { + try { + boolean templateIsExist = false; + Worksheet worksheet = wb.getWorksheets().get(sheetNo); + Cells cells = worksheet.getCells(); + String sheetName = worksheet.getName(); + String nameWithSheetName = sourceFile + BankStatementConstants.NAME_WITH_SHEET_NAME + sheetName; + Cell oaiCell1 = AsposeUtil.getCell(cells, "开户日期"); + if (oaiCell1 != null) {//个人开户信息 + if (excelFileName.endsWith(".xlsx")) { + personOai(oaiCell1, excelFileName, sheetNo, cells); + } + + if (excelFileName.endsWith(".xls")) { + Cell tradeDateCell = AsposeUtil.getCell(cells, "发生额"); + if (tradeDateCell != null) {//20240428新模板 个人,开户流水在一个模板里 + readBsAndOai(excelFileName, cells, sheetNo, nameWithSheetName); + } else { + readOAI(cells); + } + } + + templateIsExist = true; + } + + if (!templateIsExist) { + Cell oaiCell2 = AsposeUtil.getCell(cells, "账户启用日期"); + Cell oaiCell3 = AsposeUtil.getCell(cells, "合约建立日期"); + + if (oaiCell2 != null || oaiCell3 != null) {//公司开户信息 + Cell tradeDateCell = AsposeUtil.getCell(cells, "交易日期"); + if (tradeDateCell != null) {//20240416新模板 对公开户,流水在一个模板里 + readBsAndOai(excelFileName, cells, sheetNo, nameWithSheetName); + templateIsExist = true; + } else { + Cell tempCell = oaiCell3; + if (oaiCell2 != null) { + tempCell = oaiCell2; + bsHasNotCard = true;//这种模板 开户+流水,但是流水里没有卡号,开户表里只能有一行 + } + if (excelFileName.endsWith(".xls")) { + companyOAIList = readCompanyOAIByXls(cells); + } else { + companyOai(tempCell, excelFileName, sheetNo, companyOAIList); + } + templateIsExist = true; + } + + } + } + + if (!templateIsExist && bsHasNotCard) { + Cell bsCell1 = AsposeUtil.getCell(cells, "交易行省市代码"); + if (bsCell1 != null) {//这种模板 开户+流水,但是流水里没有卡号 + //2023081615505557832-账号:24055401040001038 + if (excelFileName.endsWith(".xls")) { + readCompanyBSByXls(excelFileName, cells, companyOAIList.get(0)); + } else { + companyBs(bsCell1, excelFileName, sheetNo, companyOAIList.get(0));//这个表的时间长度较长 + } + templateIsExist = true; + } + } + + if (!templateIsExist) { + Cell bsCell2 = AsposeUtil.getCell(cells, "合约账户余额"); + if (bsCell2 != null) { + companyBs(bsCell2, excelFileName, sheetNo, null); + templateIsExist = true; + } + } + + if (!templateIsExist) { + Cell bsCell3 = AsposeUtil.getCell(cells, "子账号序号"); + if (bsCell3 != null) { + Cell temp = AsposeUtil.getCell(cells, "交易日期"); + if (temp != null) { + personBs(bsCell3, excelFileName, sheetNo); + templateIsExist = true; + } + } + } + + if (!templateIsExist) { + Cell bsCell4 = AsposeUtil.getCell(cells, "身份证号码"); + if (bsCell4 != null) { + if (excelFileName.endsWith(".xlsx")) { + personBs(bsCell4, excelFileName, sheetNo); + } + + if (excelFileName.endsWith(".xls")) { + readABCCustomerBS(excelFileName, cells, null); + } + + templateIsExist = true; + } + } + + if (!templateIsExist) { + Cell flagCell = AsposeUtil.getCell(cells, "中国农业银行司法查询控制系统"); + if (flagCell != null) { + Cell temp = AsposeUtil.getCell(cells, "交易日期"); + if (temp != null) { + personBs(temp, excelFileName, sheetNo); + templateIsExist = true; + } + } + } + + if (!templateIsExist && (!IGNORE_SHEET_NAME.contains(sheetName))) { + throw new TemplateNotFindException(sourceFile + BankStatementConstants.NAME_WITH_SHEET_NAME + sheetName); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } + + private void readBsAndOai(String excelFileName, Cells cells,int sheetNo,String nameWithSheetName) { + Cell cardCell = AsposeUtil.getCell(cells, "产品号/账号/客户号"); + if (cardCell == null) { + cardCell = AsposeUtil.getCell(cells, "卡号"); + if(cardCell == null){ + throw new TemplateNotFindException(nameWithSheetName); + } + } + String cardNumber = getCardNumber(cardCell,cells,nameWithSheetName); + String cardHolderName = getCardHolderName(cells,nameWithSheetName); + + List oaiList = new ArrayList<>(); + try (ExcelReader reader = EasyExcel.read(excelFileName).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(cardCell.getRow()+1) + .head(ABCCompanyInfoEntity.class) + .registerReadListener(companyOAIReadListener(oaiList)) + .build(); + reader.read(sheet); + } catch (Exception e) { + throw new ImportDataFailedException(e.getMessage(), nameWithSheetName); + } + + + Cell tradeDateCell = AsposeUtil.getCell(cells, "交易日期"); + if (tradeDateCell == null) { + tradeDateCell = AsposeUtil.getCell(cells, "发生额");//20240428 + if(tradeDateCell == null){ + throw new TemplateNotFindException(nameWithSheetName); + } + } + try (ExcelReader reader = EasyExcel.read(excelFileName).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(tradeDateCell.getRow() + 1) + .head(ABCCompanyStatementEntity.class) + .registerReadListener(companyBsListenerFor20240416(cardNumber,cardHolderName,nameWithSheetName)) + .build(); + reader.read(sheet); + } catch (Exception e) { + throw new ImportDataFailedException(e.getMessage(), nameWithSheetName); + } + + } + + + private String getCardNumber(Cell cardCell,Cells cells,String sourceFile) { + + int startRow = cardCell.getRow(); + int startCol = cardCell.getColumn(); + Cell cardNumberCell = cells.get(startRow + 1, startCol); + if(null == cardNumberCell || StrUtil.isEmpty(cardNumberCell.getStringValue())){ + throw new ImportDataFailedException("读取卡号信息异常", sourceFile); + } + String cardNumber = cardNumberCell.getStringValue().trim(); + if(cardNumber.contains("/")){ + cardNumber = cardNumber.split("/")[0]; + } + return cardNumber; + } + + private String getCardHolderName(Cells cells,String sourceFile) { + Cell cardCell = AsposeUtil.getCell(cells, "户名"); + if (cardCell == null) { + throw new ImportDataFailedException("无法读取表头信息.", sourceFile); + } + int startRow = cardCell.getRow(); + int startCol = cardCell.getColumn(); + Cell cardNumberCell = cells.get(startRow + 1, startCol); + if(null == cardNumberCell || StrUtil.isEmpty(cardNumberCell.getStringValue())){ + throw new ImportDataFailedException("读取户名信息异常", sourceFile); + } + String cardNumber = cardNumberCell.getStringValue().trim(); + if(cardNumber.contains("/")){ + cardNumber = cardNumber.split("/")[0]; + } + return cardNumber; + } + + + void personBs(Cell bsCell, String excelFileName, int sheetNo){ + int headRowNum = bsCell.getRow() + 1; + String sourceFile = HelperUtil.getSourceFileName(excelFileName,BANK_NAME); + try (ExcelReader reader = EasyExcel.read(excelFileName).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNum) + .head(ABCCustomerStatementEntity.class) + .registerReadListener(personBSReadListener(null,sourceFile)) + .build(); + reader.read(sheet); + } catch (Exception e) { + throw new ImportDataFailedException(e.getMessage(), excelFileName); + } + } + + private void companyBs(Cell tempCell, String excelFileName, int sheetNo,ABCCompanyInfoEntity oai) { + String sourceFile = HelperUtil.getSourceFileName(excelFileName,BANK_NAME); + int headRowNum = tempCell.getRow() + 1; + try (ExcelReader reader = EasyExcel.read(excelFileName).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNum) + .head(ABCCompanyStatementEntity.class) + .registerReadListener(companyBSReadListener(oai,sourceFile)) + .build(); + reader.read(sheet); + } catch (Exception e) { + throw new ImportDataFailedException(e.getMessage(), excelFileName); + } + } + + + private void companyOai(Cell tempCell, String excelFileName, int sheetNo,List oaiList) { + int headRowNum = tempCell.getRow() + 1; + try (ExcelReader reader = EasyExcel.read(excelFileName).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNum) + .head(ABCCompanyInfoEntity.class) + .registerReadListener(companyOAIReadListener(oaiList)) + .build(); + reader.read(sheet); + + + } catch (Exception e) { + throw new ImportDataFailedException(e.getMessage(), excelFileName); + } + } + + private void personOai(Cell oaiCell1, String excelFileName,int sheetNo,Cells cells) { + int headRowNum = oaiCell1.getRow() + 1; + try (ExcelReader reader = EasyExcel.read(excelFileName).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNum) + .head(ABCCustomerInfoEntity.class) + .registerReadListener(personOAIReadListener()) + .build(); + reader.read(sheet); + } catch (Exception e) { + if(e instanceof OLE2NotOfficeXmlFileException){ + String sourceFile = HelperUtil.getSourceFileName(excelFileName,BANK_NAME); + log.error("xlsx是手动改的后缀 而不是通过另存为的方式-"+sourceFile); + try { + CellsWrapper wrapper = new CellsWrapper<>(cells, ABCCustomerInfoEntity.class, false); + wrapper.doRead(-1); + List entryList = wrapper.getEntryList(); + esABCCustomerInfoMapper.insertBatch(entryList); + } catch (Exception ex) { + throw new ImportDataFailedException(ex.getMessage(), sourceFile); + } + + }else { + throw new AnalyzeDataFailedException(e.getMessage(),e); +// HelperUtil.recordErrorImportResult(e.getMessage(), sourceFile,sheetName,caseId,BANK_NAME); + } + } + } + + + + public ReadListener companyBsListenerFor20240416(String cardNumber,String cardHolderName,String sourceFile) { + return new ReadListener() { + + List cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + @Override + public void invoke(ABCCompanyStatementEntity entity, AnalysisContext context) { + // 4 交易日期 + String transDate = entity.getTransactionDate(); + try { + if (StrUtil.isNotEmpty(transDate)) { // 20211006 + String transTime = entity.getTransactionTime(); + if (StrUtil.isNotEmpty(transTime)) { // 14:15:07 + if (transTime.length() > Constants.DATE_TIME_FULL_FORMAT_LENGTH) { + // 20131001145718000 + transTime = transTime.substring(8, 14); + DateUtil.parse(transTime, "HHmmss"); + entity.setTransactionTime(transTime); + } else { // 20081222 030411 + if (transTime.contains(":")) { + DateUtil.parse(transDate + " " + transTime, "yyyyMMdd HH:mm:ss"); + } else { + DateUtil.parse(transDate + transTime, "yyyyMMddHHmmss"); + } + } + } else { + DateUtil.parse(transDate, "yyyyMMdd"); + } + } + } catch (Exception e) { + log.error(sourceFile+"解析交易日期异常", e); + Integer currentRowNum = context.getCurrentRowNum() + 1; + throw new AnalyzeDataFailedException("第"+ currentRowNum +"行解析交易日期异常", e, sourceFile); + } + entity.setId(IdUtil.objectId()); + entity.setCardNumber(cardNumber); + entity.setCardHolderName(cardHolderName); + entity.setSourceFile(sourceFile); + cacheList.add(entity); + if (cacheList.size() >= Constants.BATCH_SIZE) { + save(); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!cacheList.isEmpty()) { + save(); + } + } + + private void save() { + esABCCompanyStatementMapper.insertBatch(cacheList); + cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + }; + } + + + public ReadListener personOAIReadListener() { + return new ReadListener() { + + List cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + @Override + public void invoke(ABCCustomerInfoEntity entity, AnalysisContext context) { + entity.setId(IdUtil.objectId()); + cacheList.add(entity); + if (cacheList.size() >= Constants.BATCH_SIZE) { + save(); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!cacheList.isEmpty()) { + save(); + } + } + + private void save() { + esABCCustomerInfoMapper.insertBatch(cacheList); + cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + }; + } + + public ReadListener companyOAIReadListener(List oaiList) { + return new ReadListener() { + + List cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + @Override + public void invoke(ABCCompanyInfoEntity entity, AnalysisContext context) { + String cardNumber = entity.getCardNumber(); + if(StrUtil.isEmpty(cardNumber)){ + return; + } + if (HelperUtil.isContainsChinese(cardNumber)){ + return; + } + cardNumber = entity.getCardNumber().trim(); + if(cardNumber.contains("/")){ + cardNumber = cardNumber.split("/")[0]; + } + + if(StrUtil.isEmpty(entity.getIdCardNo())){ + entity.setIdCardNo("");//做统计值是null不会被统计,空字符串可以 + } + + entity.setCardNumber(cardNumber); + entity.setId(IdUtil.objectId()); + cacheList.add(entity); + oaiList.add(entity); + if (cacheList.size() >= Constants.BATCH_SIZE) { + save(); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!cacheList.isEmpty()) { + save(); + } + } + + private void save() { + esABCCompanyInfoMapper.insertBatch(cacheList); + cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + }; + } + + public ReadListener companyBSReadListener(ABCCompanyInfoEntity oai,String sourceFile) { + return new ReadListener() { + + List cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + @Override + public void invoke(ABCCompanyStatementEntity entity, AnalysisContext context) { + entity.setId(IdUtil.objectId()); + entity.setSourceFile(sourceFile); + if(null != oai && StrUtil.isEmpty(entity.getCardNumber())){ + entity.setCardNumber(oai.getCardNumber2()); + entity.setCardHolderName(oai.getCardHolderName()); + } + cacheList.add(entity); + if (cacheList.size() >= Constants.BATCH_SIZE) { + save(); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!cacheList.isEmpty()) { + save(); + } + } + + private void save() { + esABCCompanyStatementMapper.insertBatch(cacheList); + cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + }; + } + + public ReadListener personBSReadListener(ABCCustomerStatementEntity oai,String sourceFile) { + return new ReadListener() { + + List cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + @Override + public void invoke(ABCCustomerStatementEntity entity, AnalysisContext context) { + entity.setId(IdUtil.objectId()); + entity.setSourceFile(sourceFile); + cacheList.add(entity); + if (cacheList.size() >= Constants.BATCH_SIZE) { + save(); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!cacheList.isEmpty()) { + save(); + } + } + + private void save() { + esABCCustomerStatementMapper.insertBatch(cacheList); + cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + }; + } + + public void analyzeData(String caseId) { + + // 开户信息 + analyzeOAI(caseId); + // 流水信息 + analyzeBS(caseId); + } + + private void analyzeOAI(String caseId) { + // 先分析公司数据 + analyzeCompanyOAI(caseId); + analyzeCustomerOAI(caseId); + } + + private void analyzeCustomerOAI(String caseId) { + List oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(esABCCustomerInfoMapper, ABCCustomerInfoEntity.class); + Set uniqueKeySet = new HashSet(); + for (ABCCustomerInfoEntity entity : entityList) { + + OpeningAccountInfo oai = getOpeningAccountInfo( entity); + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + oaiList.add(oai); + if (oaiList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + uniqueKeySet.clear(); + if (!oaiList.isEmpty()) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + } + } + + private static OpeningAccountInfo getOpeningAccountInfo(ABCCustomerInfoEntity entity) { + OpeningAccountInfo oai = new OpeningAccountInfo(); + oai.setBankName(BANK_NAME); + + String cardNumber = entity.getCardNumber(); + oai.setAccountNumber(cardNumber); + oai.setIdNo(entity.getIdCardNo()); + + oai.setName(entity.getCardHolderName()); + + oai.setPhone(entity.getPhone()); + oai.setAddress(entity.getAddress()); + oai.setOpeningAccountDate(entity.getOpeningAccountDate()); + oai.setClosingDate(entity.getCloseDate()); + oai.setStatus(entity.getStatus()); + oai.setAccountOpeningInstitution(entity.getAccountOpeningInstitution()); + oai.setBalance(entity.getBalance()); + + return oai; + } + + private void analyzeCompanyOAI(String caseId) { + + List oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(esABCCompanyInfoMapper, ABCCompanyInfoEntity.class); + Set uniqueKeySet = new HashSet(); + for (ABCCompanyInfoEntity entity : entityList) { + + OpeningAccountInfo oai = getOpeningAccountInfo(entity); + + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + oaiList.add(oai); + if (oaiList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + if (!oaiList.isEmpty()) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + } + } + + private static OpeningAccountInfo getOpeningAccountInfo(ABCCompanyInfoEntity entity) { + OpeningAccountInfo oai = new OpeningAccountInfo(); + oai.setName(entity.getCardHolderName()); + oai.setBankName(BANK_NAME); + oai.setAccountNumber(entity.getCardNumber()); + oai.setPhone(entity.getPhone()); + oai.setAddress(entity.getAddress()); + oai.setOpeningAccountDate(entity.getOpeningAccountDate()); + oai.setClosingDate(entity.getCloseDate()); + oai.setStatus(entity.getStatus()); + oai.setAccountOpeningInstitution(entity.getAccountOpeningInstitution()); + return oai; + } + + private void analyzeBS(String caseId) { + // 异步进行 + analyzeBSForCompany(caseId); + analyzeBSForCustomer(caseId); + } + + private void analyzeBSForCustomer(String caseId) { + //去重 + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + + List bsList = new ArrayList<>(); + + + Map cache = new HashMap<>(); + + List oaiList = HelperUtil.getEntityListV2(esOpeningAccountInfoMapper, OpeningAccountInfo.class, caseId); + + List customerInfoList = + HelperUtil.getEntityList(esABCCustomerInfoMapper, ABCCustomerInfoEntity.class); + for (ABCCustomerInfoEntity info : customerInfoList) { + cache.put(info.getIdCardNo(), info); + } + + Map> groupByCardNumber = customerInfoList.stream().filter(item ->StrUtil.isNotEmpty(item.getCardNumber())) + .collect(Collectors.groupingBy(ABCCustomerInfoEntity::getCardNumber)); + Map> groupByAccountNo = customerInfoList.stream().filter(item ->StrUtil.isNotEmpty(item.getAccountNo())) + .collect(Collectors.groupingBy(ABCCustomerInfoEntity::getAccountNo)); + // 处理个人流水 + List entityList = + HelperUtil.getEntityList(esABCCustomerStatementMapper, ABCCustomerStatementEntity.class); + entityList.stream().filter(item ->StrUtil.isNotEmpty(item.getAccountNo())) + .collect(Collectors.groupingBy(ABCCustomerStatementEntity::getAccountNo)); + // 主要其实就是流水数据 + for (ABCCustomerStatementEntity entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + // 流水 + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + String cardNumber = entity.getCardNumber(); + String accountNo = entity.getAccountNo(); + bs.setIdCardNo(entity.getIdCardNo()); + bs.setCardHolderName(entity.getCardHolderName()); + bs.setCardNumber(cardNumber); + if (StrUtil.isEmpty(bs.getIdCardNo()) || StrUtil.isEmpty(bs.getCardHolderName())) { + if (groupByCardNumber.containsKey(cardNumber)) { + List abcCustomerInfoEntities = groupByCardNumber.get(cardNumber); + ABCCustomerInfoEntity oai = abcCustomerInfoEntities.get(0); + bs.setIdCardNo(oai.getIdCardNo()); + bs.setCardHolderName(oai.getCardHolderName()); + bs.setCardNumber(StringUtils.isEmpty(oai.getCardNumber())?oai.getCardNumber2():oai.getCardNumber()); + } + + if(StrUtil.isEmpty(bs.getCardHolderName()) && StrUtil.isEmpty(entity.getCardHolderName()) && StrUtil.isNotEmpty(accountNo) ){ + for (String oaiAccountNo : groupByAccountNo.keySet()) { + if(oaiAccountNo.contains(accountNo)){ + List abcCustomerInfoEntities = groupByAccountNo.get(oaiAccountNo); + ABCCustomerInfoEntity oai = abcCustomerInfoEntities.get(0); + bs.setIdCardNo(oai.getIdCardNo()); + bs.setCardHolderName(oai.getCardHolderName()); + bs.setCardNumber(StringUtils.isEmpty(oai.getCardNumber())?oai.getCardNumber2():oai.getCardNumber()); + break; + } + } + } + } + + + ABCCustomerInfoEntity info = cache.getOrDefault(bs.getIdCardNo(), null); + if (info != null) { + bs.setPhone(info.getPhone()); + if (StringUtils.isEmpty(bs.getCardHolderName())) { + bs.setCardHolderName(info.getCardHolderName()); + if (StringUtils.isEmpty(bs.getCardHolderName())) { + Optional first = cache.values().stream().filter(cs -> cs.getCardNumber().equalsIgnoreCase(bs.getCardNumber())).findFirst(); + first.ifPresent(abcCustomerInfoEntity -> bs.setCardHolderName(abcCustomerInfoEntity.getCardHolderName())); + first.ifPresent(abcCustomerInfoEntity -> bs.setIdCardNo(abcCustomerInfoEntity.getIdCardNo())); + } + } + + if (StringUtils.isEmpty(bs.getCardNumber())) { + bs.setCardNumber(info.getCardNumber()); + if (StringUtils.isEmpty(bs.getCardNumber())) { + Optional first = cache.values().stream().filter(cs -> cs.getIdCardNo().equalsIgnoreCase(bs.getIdCardNo())).findFirst(); + first.ifPresent(abcCustomerInfoEntity -> bs.setCardNumber(abcCustomerInfoEntity.getCardNumber())); + } + } + + + cache.put(info.getIdCardNo(), info); + } + + if (StringUtils.isEmpty(bs.getIdCardNo()) && StringUtils.isNotEmpty(bs.getCardNumber())) { + Optional first = oaiList.stream().filter(cs -> StrUtil.isNotEmpty(cs.getAccountNumber())).filter(cs -> cs.getAccountNumber().equalsIgnoreCase(bs.getCardNumber())).findFirst(); + first.ifPresent(abcCustomerInfoEntity -> bs.setIdCardNo(abcCustomerInfoEntity.getIdNo())); + } + // 1 货币类型 + // 人民币 + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + + // 2 交易金额 可能是double或者int类型 + bs.setTransactionAmount(entity.getTransactionAmount()); + + // 3 余额 + bs.setBalance(entity.getBalance()); + // 4 交易时间 + String transactionDate = entity.getTransactionDate(); + String transTime = entity.getTransactionTime(); + if (StrUtil.isNotEmpty(transactionDate)) { + + if (StringUtils.isEmpty(transTime)) { + transTime = "000000"; + } + if(!isInteger(transTime)){ + transTime = "000000"; + } + + String transactionTime = transactionDate + transTime; + String format = "yyyyMMddHHmmss"; + try { + + if (transactionTime.length() > format.length()) { + transactionTime = transactionTime.substring(0, format.length()); + } + + bs.setTransactionTime(DateUtil.parse(transactionTime, format)); + } catch (Exception e) { + + String filename = entity.getSourceFile(); + + log.error("解析交易时间异常: {}{}", e.getMessage(), e,filename); + throw new AnalyzeDataFailedException(String.format("解析交易时间错误,无法将【%s】格式化为【%s】", transactionTime, format), e, sourceFile); + } + } + + String counterpartyName = entity.getCounterpartyName(); + String counterpartyIdCardNo = entity.getCounterpartyIdCardNo(); + bs.setCounterpartIdCardNo(counterpartyIdCardNo); + if (StrUtil.isNotEmpty(counterpartyName) && StrUtil.isEmpty(counterpartyIdCardNo)) { + List rstList = cache.values().stream() + .filter(cs -> cs.getCardHolderName().equalsIgnoreCase(counterpartyName)) + .collect(Collectors.toList()); + if (!rstList.isEmpty()) { + ABCCustomerInfoEntity cs = rstList.get(0); + bs.setCounterpartIdCardNo(cs.getIdCardNo()); + } + } + + bs.setCounterpartyName(counterpartyName); + bs.setCounterpartyBankName(entity.getCounterpartyBankName()); + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + bs.setTransactionInstitutions(entity.getTransactionInstitutions()); + bs.setSummary(entity.getSummary()); + bs.setTransRemark(entity.getTransRemark()); + bs.setTransChannel(entity.getTransChannel()); + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entity.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e, sourceFile); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + + // 保存数据库 + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + private void analyzeBSForCompany(String caseId) { + List bsList = new ArrayList<>(); + + + List entityList = + HelperUtil.getEntityList(esABCCompanyStatementMapper, ABCCompanyStatementEntity.class); + + + List companyInfoList = + HelperUtil.getEntityList(esABCCompanyInfoMapper, ABCCompanyInfoEntity.class); + Map nameCompanyInfoMap = new HashMap<>(); + + for (ABCCompanyInfoEntity entity : companyInfoList) { + nameCompanyInfoMap.put(entity.getCardHolderName(), entity); + } + + Map> groupByContractNo = companyInfoList.stream() + .filter(item ->StrUtil.isNotEmpty(item.getContractNo())) + .collect(Collectors.groupingBy(ABCCompanyInfoEntity::getContractNo)); + + + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + + for (ABCCompanyStatementEntity entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + // 流水 + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + + String cardHolderName = entity.getCardHolderName(); + bs.setCardHolderName(cardHolderName); + bs.setCardNumber(entity.getCardNumber()); + if (StrUtil.isEmpty(bs.getCardHolderName())) { + if (groupByContractNo.containsKey(entity.getContractNo())) { + List abcCompanyInfoEntities = groupByContractNo.get(entity.getContractNo()); + ABCCompanyInfoEntity companyInfo = abcCompanyInfoEntities.get(0); + bs.setCardHolderName(companyInfo.getCardHolderName()); + String cardNumber = companyInfo.getCardNumber(); + cardNumber = StrUtil.isEmpty(cardNumber) ? companyInfo.getCardNumber2() : cardNumber; + bs.setCardNumber(StrUtil.isEmpty(cardNumber) ? companyInfo.getContractNo() : cardNumber); + bs.setIdCardNo(companyInfo.getIdCardNo()); + } + } + if (StrUtil.isEmpty(bs.getIdCardNo())) { + bs.setIdCardNo(""); + } + ABCCompanyInfoEntity ci = nameCompanyInfoMap.getOrDefault(cardHolderName, null); + if (ci != null) { + if (StrUtil.isEmpty(bs.getCardNumber())) { + bs.setCardNumber(ci.getCardNumber()); + } + bs.setPhone(ci.getPhone()); + } + // 1 货币类型 + // 人民币 + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + + // 2 交易金额 可能是double或者int类型 + bs.setTransactionAmount(entity.getTransactionAmount()); + + // 3 余额 + bs.setBalance(entity.getBalance()); + // 4 交易日期 20170314143047165086 + String transactionDate = entity.getTransactionDate(); + if (StrUtil.isNotEmpty(transactionDate)) { + // 如果包含-,则用yyyy-MM-dd来解析 + String format; + if (transactionDate.contains("-")) { + format = "yyyy-MM-dd"; + } else if (transactionDate.contains("/")) { + format = "yyyy/MM/dd"; + } else { + format = "yyyyMMdd"; + } + + String transactionTime = entity.getTransactionTime(); + // 如果不为空,则组合 + if (StrUtil.isNotEmpty(transactionTime)) { + if (!isInteger(transactionTime)) { + transactionTime = "00:00:00"; + } + // 还需要分情况考虑,一种是交易时间的长度超过了14位,另一种是交易时间的长度小于14位 + if (transactionTime.length() > Constants.DATE_TIME_FULL_FORMAT_LENGTH) { + transactionTime = transactionTime.substring( + Constants.DATE_FULL_FORMAT_LENGTH, Constants.DATE_TIME_FULL_FORMAT_LENGTH); + } + + transactionDate += " " + transactionTime; + // 如果包含:,则用HH:mm:ss来解析 + if (transactionTime.contains(":")) { + format = format + " HH:mm:ss"; + } else { + format += " HHmmss"; + } + + try { + bs.setTransactionTime(DateUtil.parse(transactionDate, format)); + } catch (Exception e) { + log.error("解析交易日期异常:{},{}", e.getMessage() + entity.getSourceFile(), e); + throw new AnalyzeDataFailedException( + "解析交易日期失败,无法将【" + transactionDate + transactionTime + "】以格式【" + format + "】解析", e, entity.getSourceFile()); + } + } + } else { + // 一般情况下,交易日期不为空 + // 若是为空,则交易日期和时间同时包含在交易时间内哦 + String transactionTime = entity.getTransactionTime(); + if (transactionTime != null) { + + String format = "yyyyMMddHHmmss"; + + try { + // 需要截断 20170314 143047 + int len = format.length(); + if (transactionTime.length() > len) { + transactionTime = transactionTime.substring(0, len); + } + bs.setTransactionTime(DateUtil.parse(transactionTime, format)); + } catch (Exception e) { + log.error("解析交易日期异常:{}", e.getMessage(), e); + + + throw new AnalyzeDataFailedException( + "解析交易日期失败,无法将【" + transactionTime + "】以格式【" + format + "】解析", e, sourceFile); + } + } + } + + String counterpartyName = entity.getCounterpartyName(); + bs.setCounterpartyName(counterpartyName); + + + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + bs.setCounterpartyBankName(entity.getCounterpartyBankName()); + bs.setTransChannel(entity.getTransChannel()); + bs.setSummary(entity.getSummary()); + bs.setTransactionInstitutions(entity.getTransactionInstitutions()); + + String md5Id = HelperUtil.generateMD5Id(bs, caseId); + //未导入数据内部去重 + if (HelperUtil.deduplication(md5Id, uniqueKeySet)) { + continue; + } + + bs.setSourceFile(entity.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + + bsList.clear(); + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e, sourceFile); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + // 保存数据库 + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + public static boolean isInteger(String str) { + Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$"); + return pattern.matcher(str).matches(); + } + + private List readOAI( Cells cells) throws Exception { + CellsWrapper wrapper = new CellsWrapper<>(cells, ABCCustomerInfoEntity.class, false); + wrapper.doRead(-1); + List entryList = wrapper.getEntryList(); + esABCCustomerInfoMapper.insertBatch(entryList); + return entryList; + } + + private List readCompanyOAIByXls(Cells cells) throws Exception { + CellsWrapper wrapper = new CellsWrapper<>(cells, ABCCompanyInfoEntity.class, false); + wrapper.doRead(-1); + List entryList = wrapper.getEntryList(); + esABCCompanyInfoMapper.insertBatch(entryList); + return entryList; + } + + private void readABCCustomerBS(String excelFileName, Cells cells, List oaiList) throws Exception { + String sourceFile = HelperUtil.getSourceFileName(excelFileName,BANK_NAME); + + // 读个人流水 + try { + CellsWrapper wrapper = new CellsWrapper<>(cells, ABCCustomerStatementEntity.class, true); + wrapper.doRead(-1); + List entryList = wrapper.getEntryList(); + Map> groupByAccountNo = new HashMap<>(); + if(CollectionUtil.isNotEmpty(oaiList)){ + groupByAccountNo = oaiList.stream().collect(Collectors.groupingBy(ABCCustomerInfoEntity::getAccountNo)); + } + for (ABCCustomerStatementEntity bs : entryList) { + bs.setId(IdUtil.objectId()); + bs.setSourceFile(sourceFile); + String accountNo = bs.getAccountNo(); + if(StrUtil.isNotEmpty(accountNo)){ + if (groupByAccountNo.containsKey(accountNo)) { + List tempList = groupByAccountNo.get(accountNo); + ABCCustomerInfoEntity oai = tempList.get(0); + bs.setCardHolderName(oai.getCardHolderName()); + bs.setCardNumber(oai.getCardNumber()); + } + } + } + + //save to es + esABCCustomerStatementMapper.insertBatch(entryList); + + } catch (Exception e) { + + if (e instanceof ExcelAnalysisStopException) { + return; + } + + log.error("readABCCustomerBS:读取文件异常:{}", e.getMessage(), e); + throw new ImportDataFailedException(e.getMessage(), excelFileName); + } + } + + private void readCompanyBSByXls(String excelFileName, Cells cells,ABCCompanyInfoEntity oai) throws Exception { + String sourceFile = HelperUtil.getSourceFileName(excelFileName,BANK_NAME); + + try { + + CellsWrapper wrapper = new CellsWrapper<>(cells, ABCCompanyStatementEntity.class, true); + wrapper.doRead(-1); + String cardHolderName = oai.getCardHolderName(); + String cardNumber = oai.getCardNumber(); + if(StrUtil.isEmpty(cardNumber)){ + cardNumber = oai.getCardNumber2(); + }else { + if(cardNumber.length() > 17){ + cardNumber = oai.getCardNumber2(); + } + } + List entryList = wrapper.getEntryList(); + //加ID + for (ABCCompanyStatementEntity bs : entryList) { + bs.setId(IdUtil.objectId()); + bs.setSourceFile(sourceFile); + bs.setCardNumber(cardNumber); + bs.setCardHolderName(cardHolderName); + } + + //save to es + esABCCompanyStatementMapper.insertBatch(entryList); + + } catch (Exception e) { + log.error("readABCCompanyBS:读取文件异常:{}", e.getMessage(), e); + throw new ImportDataFailedException(e.getMessage(), excelFileName); + } + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/BOCDataAnalysisHelper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/BOCDataAnalysisHelper.java new file mode 100644 index 0000000..1eccde4 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/BOCDataAnalysisHelper.java @@ -0,0 +1,297 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.util.ListUtils; +import com.aspose.cells.Cell; +import com.aspose.cells.Cells; +import com.aspose.cells.Workbook; +import com.aspose.cells.Worksheet; + +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.bankStatementAnalysis.service.ImportService; +import com.inscloudtech.common.constant.BankStatementConstants; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.exception.dc.AnalyzeDataFailedException; +import com.inscloudtech.common.exception.dc.TemplateNotFindException; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.mapper.es.EsBOCPrivateBankStatementMapper; +import com.inscloudtech.datacenter.service.ImportResultService; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; +import com.inscloudtech.bankStatementAnalysis.domain.entity.BOCPrivateBankStatementEntry; + +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.math.BigDecimal; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static com.inscloudtech.common.constant.Constants.BATCH_SIZE; + +/** + * 中国银行数据分析 + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class BOCDataAnalysisHelper { + + private final static String BANK_NAME = "中国银行"; + private final static String IGNORE_SHEET_NAME = "客户信息,基本信息,卡户对应关系,主子账户对应,新旧账号对应"; + private final ImportService importService; + private final ImportResultService importResultService; + private final EsBOCPrivateBankStatementMapper esBOCPrivateBankStatementMapper; + + public void importData(File file, String caseId) throws Exception { + List fileList = FileUtil.loopFiles(file); + if (fileList == null || fileList.isEmpty()) { + return; + } + List excelFile = HelperUtil.getExcelFile(fileList); + for (File f : excelFile) { + try { + + + String excelFileName = f.getAbsolutePath(); + String sourceFile = HelperUtil.getSourceFileName(excelFileName, BANK_NAME); + Workbook wb = new Workbook(excelFileName); + for (int sheetNum = 0; sheetNum < wb.getWorksheets().getCount(); sheetNum++) { + try { + Worksheet worksheet = wb.getWorksheets().get(sheetNum); + String worksheetName = worksheet.getName(); + String nameWithSheetName = sourceFile + BankStatementConstants.NAME_WITH_SHEET_NAME + worksheetName; + Cells cells = worksheet.getCells(); + + Cell khcell = AsposeUtil.getCell(cells, "开户日期"); + Cell khjg = AsposeUtil.getCell(cells, "开户机构"); + Cell tradeCell = AsposeUtil.getCell(cells, "交易日期"); + Cell contentCell = cells.get(0, 0); + if (tradeCell != null) { + importService.readMultiplePersonAndMultipleHeadBankStatement(excelFileName, tradeCell.getRow() + 1, sheetNum, + BOCPrivateBankStatementEntry.class, esBOCPrivateBankStatementMapper, "", nameWithSheetName, null); + } else if (khcell != null || khjg != null) { + Cell headCell = khcell == null?khjg:khcell; + importService.readOAIData(excelFileName, headCell.getRow() + 1, + sheetNum, caseId, BANK_NAME, nameWithSheetName); + } else if (contentCell.getValue() == null) { + continue; + } else if (IGNORE_SHEET_NAME.contains(worksheetName)) {//最好取excel文件字段 + //跳过 + continue; + } else { + throw new TemplateNotFindException(nameWithSheetName); + } + } catch (Exception e) { + e.printStackTrace(); + importResultService.record(caseId, BANK_NAME, e); + } + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } + + + public void analyzeData(String caseId) { + List bsList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + List oaiList = importService.getOAIData(caseId, BANK_NAME); + Map nameIdCardMap = new HashMap<>(); + Map groupByCard = new HashMap<>(); + for (OpeningAccountInfo oai : oaiList) { + if (!nameIdCardMap.containsKey(oai.getName())) { + nameIdCardMap.put(oai.getName(), oai.getIdNo()); + } + if (StrUtil.isNotEmpty(oai.getAccountNumber()) && !groupByCard.containsKey(oai.getAccountNumber())) { + groupByCard.put(oai.getAccountNumber(), oai); + } + } + + List entityList = + HelperUtil.getEntityList(esBOCPrivateBankStatementMapper, BOCPrivateBankStatementEntry.class); + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + for (BOCPrivateBankStatementEntry bocBs : entityList) { + String sourceFile = bocBs.getSourceFile(); + try { + // 不用客户名,因为可能有多条同一个客户的数据 + String cardNumber = bocBs.getCardNumber(); + + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + + bs.setCardNumber(cardNumber); + String idCardNo = ""; + String cardHolderName = bocBs.getCardHolderName(); + if (StrUtil.isEmpty(cardHolderName) && groupByCard.containsKey(cardNumber)) { + OpeningAccountInfo info = groupByCard.get(cardNumber); + cardHolderName = info.getName(); + idCardNo = info.getIdNo(); + } + + bs.setCardHolderName(cardHolderName); + if (StrUtil.isEmpty(idCardNo)) { + idCardNo = nameIdCardMap.getOrDefault(cardHolderName, null); + } + bs.setIdCardNo(idCardNo); + + String counterpartyName = bocBs.getCounterpartyName(); + bs.setCounterpartyName(counterpartyName); + + if (StrUtil.isNotEmpty(counterpartyName)) { + String v = nameIdCardMap.getOrDefault(counterpartyName, null); + if (v != null) { + bs.setCounterpartIdCardNo(v); + } + } + + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + bs.setTransactionAmount(bocBs.getTransactionAmount()); + // 交易金额栏,使用双逻辑,1.有正负标志的,赋予其正负;2.余额后减去前,变大为正。 + BigDecimal balance = bocBs.getBalance(); + if (balance == null) { + bs.setBalance(BigDecimal.ZERO); + bs.setRemark("信用卡"); + } else { + bs.setBalance(balance); + } + // 交易时间 + // 交易日期:2006-09-05 00:00:00 2006/9/5 0:00:00 + String format = null; + String transDate = bocBs.getTransDate(); + if (StrUtil.isNotEmpty(transDate)) { + String[] arr = transDate.split(" "); + if (arr.length == 2) { + transDate = arr[0]; + if (transDate.contains("-")) { + format = "yyyy-MM-dd"; + } else if (transDate.contains("/")) { + format = "yyyy/MM/dd"; + } + } else { + format = "yyyyMMdd"; + } + + // 交易时间:1、113657;2、13:45:07;3、空 + String transTime = bocBs.getTransTime(); + if (StrUtil.isNotEmpty(transTime) && !isContainsStr(transTime) && transDate != null) { + + if (transTime.contains(":")) { + format += " HH:mm:ss"; + } else { + format += " HHmmss"; + } + + transDate += " " + transTime; + } + try { + // 判断transDate中是否包含字母 + if (isContainsStr(transDate)) { + // 截取空格前部分 + if (transDate.contains(" ")) { + transDate = transDate.substring(0, transDate.indexOf(" ")); + } + } + + bs.setTransactionTime(DateUtil.parse(transDate, format)); + } catch (Exception e) { + log.error("解析交易日期出错:{}", e.getMessage(), e); + throw new AnalyzeDataFailedException( + StrUtil.format("解析交易日期出错, 无法将字符串【{}】按照模式【{}】格式化为日期。", transDate, format), e, sourceFile); + } + } + + +// +// String transDate = pbs.getTransDate(); +// if (StrUtil.isNotEmpty(transDate)) { +// String transTime = pbs.getTransTime(); +// try { +// Date transactionTime; +// if (StrUtil.isNotEmpty(transTime)) { +// if(transDate.contains("/")){ +// if(transDate.length() < 11){ +// transDate += " 00:00:00"; +// } +// transactionTime = (DateUtil.parse(transDate, "yyyy/MM/dd HH:mm:ss")); +// }else { +// transactionTime = DateUtil.parse(transDate + " " + transTime, "yyyyMMdd HH:mm:ss"); +// } +// } else { +// transactionTime = (DateUtil.parse(transDate, "yyyyMMdd")); +// } +// bs.setTransactionTime(transactionTime); +// } catch (Exception e) { +// throw new AnalyzeDataFailedException( +// StrUtil.format("解析交易时间异常: 无法将字符串转化为日期格式,{}.", e.getMessage()), e, sourceFile); +// } +// } + + + bs.setCounterpartyBankName(bocBs.getCounterpartyBankName()); + bs.setTransactionInstitutions(bocBs.getTransactionSituation()); + + String summary = bocBs.getSummary(); + if (StrUtil.isNotBlank(summary)) { + bs.setSummary(summary); + } else { + bs.setSummary(bocBs.getTransSummary()); + } + // 交易备注 + bs.setTransRemark(bocBs.getTransRemark()); + bs.setCounterpartyAccount(bocBs.getCounterpartyAccount()); + + String md5Id = HelperUtil.generateMD5Id(bs, caseId); + //未导入数据内部去重 + if (HelperUtil.deduplication(md5Id, uniqueKeySet)) { + continue; + } + + bs.setSourceFile(bocBs.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs, plateNumberInfoList); + + + if (bsList.size() >= BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + + bsList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e, sourceFile); + } + } + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + // 保存数据库 + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + private boolean isContainsStr(String str) { + String regex = ".*[a-zA-Z]+.*"; + Matcher m = Pattern.compile(regex).matcher(str); + return m.matches(); + } + + +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/BOCOMDataAnalysisHelper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/BOCOMDataAnalysisHelper.java new file mode 100644 index 0000000..35bbfb2 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/BOCOMDataAnalysisHelper.java @@ -0,0 +1,448 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.util.ListUtils; +import com.aspose.cells.Cell; +import com.aspose.cells.Workbook; +import com.aspose.cells.Worksheet; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; + +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.exception.dc.AnalyzeDataFailedException; +import com.inscloudtech.common.exception.dc.ImportDataFailedException; +import com.inscloudtech.common.exception.dc.TemplateNotFindException; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.mapper.es.ESOpeningAccountInfoMapper; +import com.inscloudtech.datacenter.mapper.es.EsBOCOMAccountInfoMapper; +import com.inscloudtech.datacenter.mapper.es.EsBOCOMStatementMapper; +import com.inscloudtech.datacenter.service.ImportResultService; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; +import com.inscloudtech.bankStatementAnalysis.domain.entity.BOCOMAccountInfoEntity; +import com.inscloudtech.bankStatementAnalysis.domain.entity.BOCOMStatementEntry; + +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 交通银行数据分析: + * 两个文件,一个含有客户信息,一个含有流水信息 + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class BOCOMDataAnalysisHelper { + private final ImportResultService importResultService; + private final EsBOCOMAccountInfoMapper esBOCOMAccountInfoMapper; + private final EsBOCOMStatementMapper esBOCOMStatementMapper; + + private final ESOpeningAccountInfoMapper esOpeningAccountInfoMapper; + private final static String BANK_NAME = "交通银行"; + + public void analyzeData(String caseId) { + // 分析开户信息s + analyzeOAI(caseId); + // 分析流水 + analyzeBS(caseId); + } + + private void analyzeOAI(String caseId) { + + List oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(esBOCOMAccountInfoMapper, BOCOMAccountInfoEntity.class); + Set uniqueKeySet = new HashSet(); + for (BOCOMAccountInfoEntity entity : entityList) { + OpeningAccountInfo oai = getOpeningAccountInfo(BANK_NAME, entity); + if (oai == null) { + continue; + } + + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + oaiList.add(oai); + if (oaiList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + if (!oaiList.isEmpty()) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + } + } + + private static OpeningAccountInfo getOpeningAccountInfo(String bankName, BOCOMAccountInfoEntity entity) { + OpeningAccountInfo oai = new OpeningAccountInfo(); + String cardHolderName = entity.getCardHolderName(); + // 如果持卡人姓名为空,那么返回null + if (StringUtils.isEmpty(cardHolderName)) { + return null; + } + + oai.setName(cardHolderName); + oai.setBankName(BANK_NAME); + + String cardNumber = entity.getCardNumber(); + if (StringUtils.isEmpty(cardNumber)) { + return null; + } + + if (StrUtil.isNotEmpty(cardNumber) && cardNumber.contains("'")) { + cardNumber = cardNumber.replace("'", ""); + } + + oai.setAccountNumber(cardNumber); + oai.setIdType(entity.getIdType()); + + String idCardNo = entity.getIdCardNo(); + if (StrUtil.isNotEmpty(idCardNo) && idCardNo.contains("'")) { + idCardNo = idCardNo.replace("'", ""); + } + oai.setIdNo(idCardNo); + + oai.setPhone(entity.getPhone()); + oai.setOpeningAccountDate(entity.getOpeningAccountDate()); + oai.setStatus(entity.getStatus()); + oai.setType(entity.getType()); + oai.setAccountOpeningInstitution(entity.getAccountOpeningInstitution()); + oai.setAddress(entity.getAddress()); + // 如果信用额度不为空,那么备注信用卡 + if (StrUtil.isNotEmpty(entity.getCreditLimit())) { + oai.setRemark("信用卡"); + } + + return oai; + } + + private void analyzeBS(String caseId) { + + List bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(esBOCOMStatementMapper, BOCOMStatementEntry.class); + entityList = entityList.stream() + .peek(entry -> { + String cardNumber = entry.getCardNumber(); + if (StrUtil.isNotEmpty(cardNumber) && cardNumber.contains("'")) { + cardNumber = cardNumber.replace("'", ""); + entry.setCardNumber(cardNumber); + } + }) + .collect(Collectors.toList()); + + List accList = + HelperUtil.getEntityListV2(esOpeningAccountInfoMapper, OpeningAccountInfo.class, caseId); + // 根据备注,提取信用卡卡号 + List creditCardNumberList = new ArrayList<>(); + accList.stream() + .filter(entity -> StrUtil.isNotEmpty(entity.getRemark())) + .filter(entity -> entity.getRemark().contains("信用卡")) + .forEach(entity -> { + creditCardNumberList.add(entity.getAccountNumber()); + }); + + Map bocNameAccMap = new HashMap<>(); + Map cardNumberAccMap = new HashMap<>(); + + for (OpeningAccountInfo entity : accList) { + bocNameAccMap.put(entity.getName(), entity); + + if (StrUtil.isNotEmpty(entity.getAccountNumber())) { + cardNumberAccMap.put(entity.getAccountNumber(), entity); + } + } + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + + for (BOCOMStatementEntry entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + String cardHolderName = entity.getCardHolderName(); + String cardNumber = entity.getCardNumber(); + if (StringUtils.isEmpty(cardHolderName) && StringUtils.isEmpty(cardNumber)) { + continue; + } + // 流水 + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + bs.setCardHolderName(cardHolderName); + + { + // 根据名称去查找基本信息 + OpeningAccountInfo acc = bocNameAccMap.getOrDefault(cardHolderName, null); + if (acc != null) { + bs.setPhone(acc.getPhone()); + bs.setIdCardNo(acc.getIdNo()); + } + } + + bs.setCardNumber(cardNumber); + // 处理持卡人姓名和卡号,没有持卡人姓名,可以从开户信息中获取 + if (StringUtils.isEmpty(cardHolderName) && StrUtil.isNotEmpty(cardNumber)) { + OpeningAccountInfo acc = cardNumberAccMap.getOrDefault(cardNumber, null); + if (acc != null) { + bs.setCardHolderName(acc.getName()); + + if (StringUtils.isEmpty(bs.getIdCardNo())) { + bs.setIdCardNo(acc.getIdNo()); + } + } + } + + // 1 货币类型 + // 人民币 + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + + // 2 交易金额 可能是double或者int类型 + // 这里和借贷标记有关 + { + BigDecimal transactionAmount; + String loanFlag = entity.getLoanFlag(); + if (StrUtil.isNotEmpty(loanFlag)) { + if (loanFlag.contains("借")) { + transactionAmount = BigDecimal.ZERO.subtract(entity.getTransactionAmount()); + } else { + transactionAmount = entity.getTransactionAmount(); + } + + bs.setTransactionAmount(transactionAmount); + } else { + // 没有借贷标记的情况 + bs.setTransactionAmount(entity.getTransactionAmount()); + } + } + { + // 借方金额 + BigDecimal debitAmount = entity.getDebitAmount(); + if (debitAmount != null) { + bs.setTransactionAmount(debitAmount.negate()); + } + // 贷方金额 + BigDecimal creditAmount = entity.getCreditAmount(); + if (creditAmount != null) { + bs.setTransactionAmount(creditAmount); + } + } + + // 3 余额 + // 如果卡号不为空,且又是信用卡,则余额为零 + if (StrUtil.isNotEmpty(cardNumber) && creditCardNumberList.contains(cardNumber)) { + bs.setBalance(BigDecimal.ZERO); + // 备注 信用卡 + bs.setRemark("信用卡"); + } else { + bs.setBalance(entity.getBalance()); + } + // 4 交易日期 + String transDate = entity.getTransDate(); + if (StrUtil.isNotEmpty(transDate)) { + String format = null; + // 如果包含/ + if (transDate.contains("/")) { + format = "yyyy/MM/dd"; + } else if (transDate.contains("-")) { + format = "yyyy-MM-dd"; + } else { + format = "yyyyMMdd"; + } + + if (transDate.contains(".")) { + // 截取 + if(transDate.contains("E7")){ + transDate = transDate.replaceAll("E7",""); + transDate = transDate.replaceAll("\\.",""); + }else { + transDate = transDate.substring(0, transDate.indexOf(".")); + } + } + + String transTime = entity.getTransTime(); + if (StrUtil.isNotEmpty(transTime)) { + if (transTime.contains(".")) { + transTime = transTime.substring(0, transTime.indexOf(".")); + } + + if (transTime.contains(":")) { + format += " HH:mm:ss"; + } else { + format += " HHmmss"; + if (transTime.length() < Constants.TIME_FULL_FORMAT_LENGTH) { + + int cnt = Constants.TIME_FULL_FORMAT_LENGTH - transTime.length(); + StringBuilder transTimeBuilder = new StringBuilder(transTime); + for (int i = 0; i < cnt; i++) { + transTimeBuilder.insert(0, "0"); + } + + transTime = String.valueOf(transTimeBuilder); + } + } + } + + transDate = transDate + " " + transTime; + + try { + bs.setTransactionTime(DateUtil.parse(transDate, format)); + } catch (Exception e) { + log.error("解析日期失败", e); + throw new AnalyzeDataFailedException(StrUtil.format("解析交易时间失败:{},格式:{}", entity.getTransDate() + entity.getTransTime(), format), e, entity.getSourceFile()); + } + } + + String counterpartyName = entity.getCounterpartyName(); + bs.setCounterpartyName(counterpartyName); + + if (StrUtil.isNotEmpty(counterpartyName)) { + // 根据对手名去查找 + OpeningAccountInfo ac = bocNameAccMap.getOrDefault(counterpartyName, null); + if (ac != null) { + bs.setCounterpartIdCardNo(ac.getIdNo()); + } + } + + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + bs.setCounterpartyBankName(entity.getCounterpartyBankName()); + bs.setSummary(entity.getSummary()); + bs.setTransRemark(entity.getTransRemark()); + bs.setTransactionInstitutions(entity.getTransactionInstitutions()); + bs.setTransChannel(entity.getTransChannel()); + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entity.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + + HelperUtil.batchInsert2Es(dest, caseId); + + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e,sourceFile); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + // 保存数据库 + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + public void importData(File file,String caseId) throws Exception { + + if (!file.exists()) { + return; + } + + List fileList = FileUtil.loopFiles(file); + List excelFile = HelperUtil.getExcelFile(fileList); + + // 有交易时间就是流水,否则就是开户信息 + for (File f : excelFile) { + String absolutePath = f.getAbsolutePath(); + Workbook wb = new Workbook(absolutePath); + String sourceFile = HelperUtil.getSourceFileName(absolutePath,BANK_NAME); + for (int sheetNo = 0; sheetNo < wb.getWorksheets().getCount(); sheetNo++) { + Worksheet worksheet = wb.getWorksheets().get(sheetNo); + String nameWithSheetName = sourceFile + "-" + worksheet.getName(); + Cell cell = AsposeUtil.getCell(f, sheetNo, "交易时间"); + Cell khCell = AsposeUtil.getCell(f, sheetNo, "开户日期"); + Cell khV2Cell = AsposeUtil.getCell(f, sheetNo, "客户号开户日期"); + if (cell != null) { + // 流水 + readBankCommStatement(f, sheetNo,cell.getRow() + 1); + } else if (khCell != null || khV2Cell != null) { + // 开户信息 + Cell headCell = khCell == null?khV2Cell:khCell; + readOpeningAccountInfo(f, sheetNo,headCell.getRow() + 1); + } else { + throw new TemplateNotFindException(nameWithSheetName); + } + } + } + } + + + + /** + * 读取流水 + */ + private void readBankCommStatement(File excelFile, int sheetNo,int headRowNumber) { + String sourceFile = HelperUtil.getSourceFileName(excelFile.getAbsolutePath(),BANK_NAME); + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNumber) + .head(BOCOMStatementEntry.class) + .registerReadListener( + HelperUtil.getReadListener(esBOCOMStatementMapper, BOCOMStatementEntry.class, false,sourceFile)) + .build(); + reader.read(sheet); + } catch (Exception e) { + log.error("读取流水失败", e); + throw new ImportDataFailedException(e.getMessage(), sourceFile); + } + } + + /** + * 读取客户信息 + */ + private void readOpeningAccountInfo(File excelFile, int sheetNo,int headRowNumber) { + String sourceFile = HelperUtil.getSourceFileName(excelFile.getAbsolutePath(),BANK_NAME); + // 表头还得读出来 + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNumber) + .head(BOCOMAccountInfoEntity.class) + .registerReadListener( + HelperUtil.getReadListener(esBOCOMAccountInfoMapper, BOCOMAccountInfoEntity.class, true, sourceFile)) + .build(); + reader.read(sheet); + } catch (Exception e) { + log.error("读取客户信息失败", e); + throw new ImportDataFailedException(e.getMessage(), sourceFile); + } + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CCBDataAnalysisHelper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CCBDataAnalysisHelper.java new file mode 100644 index 0000000..06d974d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CCBDataAnalysisHelper.java @@ -0,0 +1,1547 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.exception.ExcelAnalysisStopException; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.util.ListUtils; +import com.aspose.cells.*; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; + + +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.common.constant.BankStatementConstants; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.exception.dc.AnalyzeDataFailedException; +import com.inscloudtech.common.exception.dc.ImportDataFailedException; +import com.inscloudtech.common.exception.dc.TemplateNotFindException; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.common.utils.file.FileUtils; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.mapper.es.*; +import com.inscloudtech.datacenter.service.ImportResultService; +import com.inscloudtech.bankStatementAnalysis.listener.ReadCCBCurrentAccountInfoListener; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; + +import com.inscloudtech.bankStatementAnalysis.domain.entity.*; +import com.inscloudtech.bankStatementAnalysis.util.AnalyzeFileHelper; +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; + +import lombok.Data; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.openxml4j.util.ZipSecureFile; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.math.BigDecimal; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +/** + * 建设银行数据分析 + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class CCBDataAnalysisHelper { + private final ImportResultService importResultService; + private final EsCCBCurrentAccountInfoMapper accountInfoMapper; + private final EsCCBRegularAccountInfoMapper esCCBRegularAccountInfoMapper; + private final EsCCBElectronicCashAccountInfoMapper esCCBElectronicCashAccountInfoMapper; + private final EsCCBElectronicCashBankStatementMapper esCCBElectronicCashBankStatementMapper; + private final EsCCBRegularBankStatementMapper esCCBRegularBankStatementMapper; + private final EsCCBCurrentBankStatementMapper esCCBCurrentBankStatementMapper; + private final static String BANK_NAME = "建设银行"; + + public void analyzeData(String caseId) { + analyzeOAI(caseId); + analyzeBS(caseId); + } + + /** + * 开户信息分析 + */ + private void analyzeOAI(String caseId) { + analyzeElectronicCashOpeningAccountInfo(caseId); + analyzeOtherOpeningAccountInfo(caseId); + } + + private void analyzeElectronicCashOpeningAccountInfo(String caseId) { + + List oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = HelperUtil.getEntityList( + esCCBElectronicCashAccountInfoMapper, CCBElectronicCashAccountInfoEntity.class); + Set uniqueKeySet = new HashSet(); + for (CCBElectronicCashAccountInfoEntity entity : entityList) { + + String cardHolderName = entity.getCardHolderName(); + if (StringUtils.isEmpty(cardHolderName)) { + continue; + } + + OpeningAccountInfo oai = new OpeningAccountInfo(); + oai.setName(cardHolderName); + oai.setBankName(BANK_NAME); + oai.setAccountNumber(entity.getCardNumber()); + oai.setIdType(entity.getIdType()); + oai.setIdNo(entity.getIdCardNo()); + + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + oaiList.add(oai); + if (oaiList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + if (!oaiList.isEmpty()) { + HelperUtil.batchSaveOAI2Es(oaiList, caseId); + } + } + + private void analyzeOtherOpeningAccountInfo(String caseId) { + + List oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(accountInfoMapper, CCBCurrentAccountInfoEntity.class); + Set uniqueKeySet = new HashSet(); + for (CCBCurrentAccountInfoEntity entity : entityList) { + + String cardHolderName = entity.getCardHolderName(); + if (StringUtils.isEmpty(cardHolderName)) { + continue; + } + + OpeningAccountInfo oai = getOpeningAccountInfo(BANK_NAME, entity); + + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + oaiList.add(oai); + if (oaiList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + if (!oaiList.isEmpty()) { + HelperUtil.batchSaveOAI2Es(oaiList, caseId); + } + } + + private static OpeningAccountInfo getOpeningAccountInfo(String bankName, CCBCurrentAccountInfoEntity entity) { + OpeningAccountInfo oai = new OpeningAccountInfo(); + oai.setName(entity.getCardHolderName()); + oai.setBankName(BANK_NAME); + oai.setAccountNumber(entity.getCardNumber()); + oai.setIdType(entity.getIdType()); + oai.setIdNo(entity.getIdCardNo()); + oai.setOpeningAccountDate(entity.getOpeningAccountDate()); + oai.setClosingDate(entity.getClosingDate()); + oai.setStatus(entity.getStatus()); + oai.setAccountOpeningInstitution(entity.getAccountOpeningInstitution()); + oai.setBalance( + StrUtil.isEmpty(entity.getBalance()) ? BigDecimal.ZERO : NumberUtil.toBigDecimal(entity.getBalance())); + oai.setFreezeInfo(entity.getFreezeInfo()); + + return oai; + } + + /** + * 分析交易流水 + */ + private void analyzeBS(String caseId) { + analyzeCurrentBS(caseId); + analyzeRegularBS(caseId); + analyzeElectronicCashBS(caseId); + } + + private void analyzeElectronicCashBS(String caseId) { + + List bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = HelperUtil.getEntityList( + esCCBElectronicCashBankStatementMapper, CCBElectronicCashBankStatementEntity.class); + // 根据名称去查找基本信息 + List infoList = HelperUtil.getEntityList(esCCBElectronicCashAccountInfoMapper, + CCBElectronicCashAccountInfoEntity.class); + Map> groupByCardHolderName = infoList.stream().filter(item ->StrUtil.isNotEmpty(item.getCardHolderName())).collect(Collectors.groupingBy(CCBElectronicCashAccountInfoEntity::getCardHolderName)); + + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + + for (CCBElectronicCashBankStatementEntity entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + String cardHolderName = entity.getCardHolderName(); + if (StringUtils.isEmpty(cardHolderName)) { + continue; + } + + // 流水 + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + bs.setCardHolderName(cardHolderName); + + + + if(StrUtil.isNotEmpty(cardHolderName) && StrUtil.isEmpty(bs.getIdCardNo())) { + if (groupByCardHolderName.containsKey(cardHolderName)) { + List infoEntities = groupByCardHolderName.get(cardHolderName); + for (CCBElectronicCashAccountInfoEntity infoEntity : infoEntities) { + if (StrUtil.isNotEmpty(infoEntity.getIdCardNo())) { + bs.setIdCardNo(infoEntity.getIdCardNo()); + break; + } + } + } + } + + + + bs.setCardNumber(entity.getCardNumber()); + // 1 货币类型 + // 人民币 + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + + // 2 交易金额 可能是double或者int类型 + String expenditureAmount = entity.getExpenditureAmount(); + if (StrUtil.isNotEmpty(expenditureAmount)) { + bs.setTransactionAmount(new BigDecimal(expenditureAmount)); + } + + String incomeAmount = entity.getIncomeAmount(); + if (StrUtil.isNotEmpty(incomeAmount)) { + BigDecimal value =new BigDecimal(incomeAmount); + bs.setTransactionAmount(BigDecimal.ZERO.subtract(value)); + } + + // 3 余额 + bs.setBalance(BigDecimal.valueOf(Double.parseDouble(entity.getBalance()))); + // 4 交易日期 + String transDate = entity.getTransDate(); + if (StrUtil.isNotEmpty(transDate)) { + String transTime = entity.getTransTime(); + try { + if (StrUtil.isNotEmpty(transTime)) { + bs.setTransactionTime(DateUtil.parse(transDate + " " + transTime, "yyyy-MM-dd HH:mm:ss")); + } else { + bs.setTransactionTime(DateUtil.parse(transDate, "yyyy-MM-dd")); + } + } catch (Exception e) { + log.error("解析日期出错", e); + + + throw new AnalyzeDataFailedException( + StrUtil.format("日期格式为:yyyy-MM-dd HH:mm:ss,日期为:{}", transDate), e, sourceFile); + } + } + + String counterpartyName = entity.getCounterpartyName(); + bs.setCounterpartyName(counterpartyName); + + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + bs.setCounterpartyBankName(entity.getCounterpartyBankName()); + bs.setTransRemark(entity.getTansRemark()); + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entity.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + + HelperUtil.batchInsert2Es(dest, caseId); + + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e,sourceFile); + } + } + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + // 保存数据库 + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + private void analyzeRegularBS(String caseId) { + + List bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(esCCBRegularBankStatementMapper, CCBRegularBankStatementEntity.class); + // 根据名称去查找基本信息 + List infoList = HelperUtil.getEntityList(esCCBRegularAccountInfoMapper, CCBRegularAccountInfoEntity.class); + Map> groupByCardHolderName = infoList.stream().filter(item ->StrUtil.isNotEmpty(item.getCardHolderName())).collect(Collectors.groupingBy(CCBRegularAccountInfoEntity::getCardHolderName)); + + + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + for (CCBRegularBankStatementEntity entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + String cardHolderName = entity.getCardHolderName(); + if (StringUtils.isEmpty(cardHolderName)) { + continue; + } + + // 流水 + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + bs.setCardHolderName(cardHolderName); + + if(StrUtil.isNotEmpty(cardHolderName) && StrUtil.isEmpty(bs.getIdCardNo())) { + if (groupByCardHolderName.containsKey(cardHolderName)) { + List infoEntities = groupByCardHolderName.get(cardHolderName); + for (CCBRegularAccountInfoEntity infoEntity : infoEntities) { + if (StrUtil.isNotEmpty(infoEntity.getIdCardNo())) { + bs.setIdCardNo(infoEntity.getIdCardNo()); + break; + } + } + } + } + + bs.setCardNumber(entity.getCardNumber()); + // 1 货币类型 + // 人民币 + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + + // 2 交易金额 可能是double或者int类型 + BigDecimal transactionAmount = entity.getTransactionAmount(); + String loanFlag = entity.getLoanFlag(); + if (StrUtil.isNotEmpty(loanFlag)) { + if (Objects.equals("贷", loanFlag)) { + bs.setTransactionAmount(transactionAmount); + } else { + bs.setTransactionAmount(BigDecimal.ZERO.subtract(transactionAmount)); + } + } + + // 3 余额 + bs.setBalance(entity.getBalance()); + // 4 交易日期 + String transDate = entity.getTransDate(); + if (StrUtil.isNotEmpty(transDate)) { + String transTime = entity.getTransTime(); + try { + if (StrUtil.isNotEmpty(transTime)) { + bs.setTransactionTime(DateUtil.parse(transDate + " " + transTime, "yyyy-MM-dd HH:mm:ss")); + } else { + bs.setTransactionTime(DateUtil.parse(transDate, "yyyy-MM-dd")); + } + } catch (Exception e) { + log.error("日期转换异常", e); + + + throw new AnalyzeDataFailedException(StrUtil.format("日期转换异常,日期:{},时间:{}", transDate), e, sourceFile); + } + } + + String counterpartyName = entity.getCounterpartyName(); + bs.setCounterpartyName(counterpartyName); + + bs.setTransactionInstitutions(entity.getTransactionInstitutions()); + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + bs.setTransChannel(entity.getTransChannel()); + bs.setSummary(entity.getSummary()); + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entity.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + + HelperUtil.batchInsert2Es(dest, caseId); + + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e,sourceFile); + } + } + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + // 保存数据库 + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + private void analyzeCurrentBS(String caseId) { + + List bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(esCCBCurrentBankStatementMapper, CCBCurrentBankStatementEntity.class); + List oaiList = + HelperUtil.getEntityList(accountInfoMapper, CCBCurrentAccountInfoEntity.class); + Map> groupByCardNumber = oaiList.stream().filter(item ->StrUtil.isNotEmpty(item.getCardNumber())).collect(Collectors.groupingBy(CCBCurrentAccountInfoEntity::getCardNumber)); + Map> groupByCardHolderName = oaiList.stream().filter(item ->StrUtil.isNotEmpty(item.getCardHolderName())).collect(Collectors.groupingBy(CCBCurrentAccountInfoEntity::getCardHolderName)); + + + Map> map = new HashMap<>(); + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + for (CCBCurrentBankStatementEntity entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + boolean isSame = false; + + String cardHolderName = entity.getCardHolderName(); + String cardNumber = entity.getCardNumber(); + + if (StringUtils.isEmpty(cardHolderName)) {//这个判断直接过滤了企业数据 + if (groupByCardNumber.containsKey(cardNumber)) { + List tempList = groupByCardNumber.get(cardNumber); + for (CCBCurrentAccountInfoEntity oai : tempList) { + if(StrUtil.isNotEmpty(oai.getCardHolderName())){ + cardHolderName = oai.getCardHolderName(); + } + } + } + } + + if (HelperUtil.isContainsChinese(entity.getTransDate())) { + continue; + } + + // 去重 + String serialNumber = entity.getSerialNumber(); + if (StringUtils.isEmpty(serialNumber)) { + serialNumber = "-"; + } + + List value = map.getOrDefault(serialNumber, null); + if (value == null) { + value = new ArrayList<>(); + value.add(entity); + + map.put(serialNumber, value); + } else { + for (CCBCurrentBankStatementEntity entry : value) { + if (HelperUtil.isTheSameBankStatement(entity, entry)) { + isSame = true; + break; + } + } + + if (isSame) { + continue; + } else { + map.get(serialNumber).add(entity); + } + } + + // 流水 + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + bs.setCardHolderName(cardHolderName); + // 根据名称去查找基本信息 + + if(StrUtil.isNotEmpty(cardHolderName) && StrUtil.isEmpty(bs.getIdCardNo())) { + if (groupByCardHolderName.containsKey(cardHolderName)) { + List infoEntities = groupByCardHolderName.get(cardHolderName); + for (CCBCurrentAccountInfoEntity infoEntity : infoEntities) { + if (StrUtil.isNotEmpty(infoEntity.getIdCardNo())) { + bs.setIdCardNo(infoEntity.getIdCardNo()); + break; + } + } + } + } + bs.setCardNumber(entity.getCardNumber()); + // 1 货币类型 + // 人民币 + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + + // 2 交易金额 可能是double或者int类型 + + if(StrUtil.isEmpty(entity.getLoanFlag())){ + BigDecimal expenditureAmount = BigDecimal.valueOf(Double.parseDouble(entity.getExpenditureAmount())); + BigDecimal incomeAmount = BigDecimal.valueOf(Double.parseDouble(entity.getIncomeAmount())); + bs.setTransactionAmount(incomeAmount.subtract(expenditureAmount)); + }else { + BigDecimal transactionAmount = new BigDecimal(entity.getTransactionAmount()); + if(entity.getLoanFlag().contains("借")){ + bs.setTransactionAmount(transactionAmount.negate()); + } else { + bs.setTransactionAmount(transactionAmount); + } + } + + // 3 余额 + bs.setBalance(BigDecimal.valueOf(Double.parseDouble(entity.getBalance()))); + // 4 交易日期 + String transDate = entity.getTransDate(); + if (StrUtil.isNotEmpty(transDate)) { + String transTime = entity.getTransTime(); + try { + if (StrUtil.isNotEmpty(transTime)) { + bs.setTransactionTime(DateUtil.parse(transDate + " " + transTime, "yyyy-MM-dd HH:mm:ss")); + } else { + bs.setTransactionTime(DateUtil.parse(transDate, "yyyy-MM-dd")); + } + } catch (Exception e) { + log.error("日期转换异常", e); + throw new AnalyzeDataFailedException(StrUtil.format("日期转换异常:{}", transDate), e, sourceFile); + } + } + + String counterpartyName = entity.getCounterpartyName(); + bs.setCounterpartyName(counterpartyName); + + bs.setTransactionInstitutions(entity.getTransactionInstitutions()); + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + bs.setCounterpartyBankName(entity.getCounterpartyBankName()); + bs.setTransChannel(entity.getTransChannel()); + bs.setTransRemark(entity.getTansRemark()); + bs.setSummary(entity.getSummary()); + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entity.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + + HelperUtil.batchInsert2Es(dest, caseId); + + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e,sourceFile); + } + } + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + // 保存数据库 + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + public void importData(File file,String caseId) throws Exception { + + List fileList = FileUtil.loopFiles(file); + + if (fileList.isEmpty()) { + throw new ImportDataFailedException( + StrUtil.format("导入失败,未找到Excel文件:{}", file.getName()), file.getAbsolutePath()); + } + + // 剔除汇总表 + fileList = fileList.stream() + .filter(f -> { + if (FileUtil.mainName(f).contains("汇总")) { + AnalyzeFileHelper.putBSFile(f); + return false; + } + + return true; + }) + .collect(Collectors.toList()); + List excelFileList = HelperUtil.getExcelFile(fileList); + for (File excelFile : excelFileList) { + try { + analysisCCBExcel(excelFile,caseId); + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } + + private void analysisCCBExcel(File excelFile,String caseId) throws Exception { + ZipSecureFile.setMinInflateRatio(0.001); + String absolutePath = excelFile.getAbsolutePath(); + Workbook wb = new Workbook(absolutePath); + WorksheetCollection worksheets = wb.getWorksheets(); + String sourceFile = HelperUtil.getSourceFileName(absolutePath,BANK_NAME); + int count = worksheets.getCount(); + for (int sheetNo = 0; sheetNo < count; sheetNo++) { + try { + Worksheet ws = worksheets.get(sheetNo); + String sheetName = ws.getName(); + Cells cells = ws.getCells(); + String s = sourceFile + BankStatementConstants.NAME_WITH_SHEET_NAME + sheetName; + if (AsposeUtil.getCell(cells, "个人账户信息") != null) { + // 读取账户信息 + readAccountInfo(excelFile, cells, sheetNo); + } else if (AsposeUtil.getCell(cells, "个人活期明细信息") != null) { + // 读取活期信息 + readCurrentDetailsV2(excelFile, cells, sheetNo); + } else if (AsposeUtil.getCell(cells, "个人定期明细信息") != null) { + // 读取定期明细 + readRegularDetailsV2(excelFile, cells, sheetNo); + } else if (AsposeUtil.getCell(cells, "新一代电子现金") != null || AsposeUtil.getCell(cells, "电子现金-新一代") != null) { + // 读取电子现金明细 + readElectronicCashDetails(excelFile, cells, sheetNo); + } else if (AsposeUtil.getCell(cells, "企业账户信息") != null) { + // 读取企业账户信息 + readCompanyAccountInfo(excelFile, cells, sheetNo); + } else if (AsposeUtil.getCell(cells, "企业活期明细信息") != null) { + // 读取活期明细 +// readCompanyCurrentDetails(excelFile, cells, sheetNo); + xiangjiaoTemplate(excelFile, sheetNo); + List entityList = HelperUtil.getEntityList(esCCBCurrentBankStatementMapper, CCBCurrentBankStatementEntity.class); + entityList.size(); + } else if (AsposeUtil.getCell(cells, "企业定期明细信息") != null) { + // 读取定期明细 + readCompanyRegularDetails(excelFile, cells, sheetNo); + } else if (AsposeUtil.getCell(cells, "笔号") != null) { + if(AsposeUtil.getCell(cells, "交易日期") != null ){ + readBSTemplate20240417(absolutePath, sheetNo,caseId, s); + }else if(AsposeUtil.getCell(cells, "开户日期") != null ){ + readOAITemplate20240417(absolutePath, sheetNo,caseId, s); + } + } else if (AsposeUtil.getCell(cells, "错误原因") != null) { + continue; + }else if (AsposeUtil.getCell(cells, "有无查询结果") != null) { + continue; + }else { + throw new TemplateNotFindException(s); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } + + private void readOAITemplate20240417(String excelFile, int sheetNo, String caseId, String sourceFile) { + ExcelReader reader = EasyExcel.read(excelFile).build(); + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(1) + .head(CCBCurrentAccountInfoEntity.class) + .registerReadListener(readTemplate20240417OAIReadListener(caseId,sourceFile)) + .build(); + reader.read(sheet); + } + + private void readBSTemplate20240417(String excelFile,int sheetNo,String caseId,String sourceFile) { + ExcelReader reader = EasyExcel.read(excelFile).build(); + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(1) + .head(CCBCurrentBankStatementEntity.class) + .registerReadListener(readTemplate20240417ReadListener(caseId,sourceFile)) + .build(); + reader.read(sheet); + } + + public ReadListener readTemplate20240417OAIReadListener(String caseId,String sourceFile) { + return new ReadListener() { + + List cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + @Override + public void invoke(CCBCurrentAccountInfoEntity entity, AnalysisContext context) { + entity.setId(IdUtil.objectId()); + entity.setSourceFile(sourceFile); + entity.setCaseId(caseId); + cacheList.add(entity); + if (cacheList.size() >= Constants.BATCH_SIZE) { + save(); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!cacheList.isEmpty()) { + save(); + } + } + + private void save() { + accountInfoMapper.insertBatch(cacheList); + cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + }; + } + + public ReadListener readTemplate20240417ReadListener(String caseId,String sourceFile) { + return new ReadListener() { + + List cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + @Override + public void invoke(CCBCurrentBankStatementEntity entity, AnalysisContext context) { + entity.setId(IdUtil.objectId()); + entity.setSourceFile(sourceFile); + entity.setCaseId(caseId); + cacheList.add(entity); + if (cacheList.size() >= Constants.BATCH_SIZE) { + save(); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!cacheList.isEmpty()) { + save(); + } + } + + private void save() { + esCCBCurrentBankStatementMapper.insertBatch(cacheList); + cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + }; + } + + private void readCompanyRegularDetails(File excelFile, Cells cells, int sheetNo) { + Class headClazz = CCBRegularBankStatementEntity.class; + String sourceFile = HelperUtil.getSourceFileName(excelFile.getAbsolutePath(),BANK_NAME); + Cell startCell = null; + Cell endCell = null; + int startRow = 0; + int endRow = 0; + + for (; ; ) { + startCell = AsposeUtil.getCell(cells, "交易日期", startRow); + if (startCell == null) { + break; + } + + startRow = startCell.getRow() + 1; // headRowNum + endCell = AsposeUtil.getCell(cells, "根据查询条件", startRow); + if (endCell == null) { + // 设置最后一行 + endRow = cells.getMaxRow() + 1; + } else { + endRow = endCell.getRow() + 1; + } + + try (ExcelReader r = EasyExcel.read(excelFile).build()) { + ReadSheet rs = EasyExcel.readSheet(sheetNo) + .head(headClazz) + .headRowNumber(startRow) + .registerReadListener(HelperUtil.getReadListener( + esCCBRegularBankStatementMapper, headClazz, false, startRow, endRow,sourceFile)) + .build(); + r.read(rs); + + + } catch (Exception e) { + +// if (e instanceof ExcelAnalysisStopException) { +// continue; +// } +// +// log.error("读取企业定期流水信息失败: " + e.getMessage(), e); +// throw new ImportDataFailedException("读取企业定期流水信息失败: " + e.getMessage(), excelFile.getAbsolutePath()); + } + + startRow = endRow; + } + } + + // 读取活期明细 + private void readCompanyCurrentDetails(File excelFile, Cells cells, int sheetNo) { + String sourceFile = HelperUtil.getSourceFileName(excelFile.getAbsolutePath(),BANK_NAME); + Class headClazz = CCBCurrentBankStatementEntity.class; + + Cell startCell = null; + Cell endCell = null; + int startRow = 0; + int endRow = 0; + + for (; ; ) { + startCell = AsposeUtil.getCell(cells, "交易日期", startRow); + if (startCell == null) { + break; + } + + startRow = startCell.getRow() + 1; // headRowNum + endCell = AsposeUtil.getCell(cells, "根据查询条件", startRow); + if (endCell == null) { + // 设置最后一行 + endRow = cells.getMaxRow() + 1; + } else { + endRow = endCell.getRow() + 1; + } + + try (ExcelReader r = EasyExcel.read(excelFile).build()) { + ReadSheet rs = EasyExcel.readSheet(sheetNo) + .head(headClazz) + .headRowNumber(startRow) + .registerReadListener(HelperUtil.getReadListener( + esCCBCurrentBankStatementMapper, headClazz, false, startRow, endRow,sourceFile)) + .build(); + r.read(rs); + + + } catch (Exception e) { + + if (e instanceof ExcelAnalysisStopException) { + continue; + } + + log.error("读取企业活期流水信息失败: " + e.getMessage(), e); + throw new ImportDataFailedException("读取企业活期流水信息失败: " + e.getMessage(), sourceFile); + } + + startRow = endRow; + } + } + + private void xiangjiaoTemplate(File excelFile, int sheetNo ) throws Exception { + List itemList = getAnalyzeItemList(excelFile.getAbsolutePath(), sheetNo); + + for (AnalyzeItem item : itemList) { + + try (ExcelReader r = EasyExcel.read(excelFile).build()) { + ReadSheet readSheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(item.headRowNumber) + .head(CCBCurrentBankStatementEntity.class) + .registerReadListener(getCurrentDetailListener(item)) + .build(); + r.read(readSheet); + + } catch (Exception e) { + if (e instanceof ExcelAnalysisStopException) { + continue; + } + + // 停止继续读取需要抛出异常,这里不必处理 + log.error("读取个人活期明细信息失败: " + e.getMessage(), e); + throw new AnalyzeDataFailedException("读取个人活期明细信息失败: " + e.getMessage(), e); + } + } + } + + private void readCompanyAccountInfo(File excelFile, Cells cells, int sheetNo) { + String sourceFile = HelperUtil.getSourceFileName(excelFile.getAbsolutePath(),BANK_NAME); + + // 关键字:企业活期账户信息 + Cell startCell = null; + Cell endCell = null; + int startRow = 0; + int endRow = 0; + + Class headClazz = CCBCurrentAccountInfoEntity.class; + + String[] keys = {"企业活期账户信息", "企业定期账户信息"}; + + for (String key : keys) { + + startCell = AsposeUtil.getCell(cells, key, startRow); + if (startCell == null) { + break; + } + + startRow = startCell.getRow(); + + + + Cell cell = AsposeUtil.getCell(cells, "开户日期", startRow ); + if (cell == null) { + continue; + } + startRow = cell.getRow(); + +// if (endCell != null) { +// startRow = endCell.getRow(); +// } + endCell = AsposeUtil.getCell(cells, "根据查询条件", startRow); + if (endCell == null) { + // 设置最后一行 + endRow = cells.getMaxRow() + 1; + } else { + endRow = endCell.getRow() + 1; + } + + int headRowNumber = cell.getRow() + 1; + + try (ExcelReader r = EasyExcel.read(excelFile).build()) { + ReadSheet rs = EasyExcel.readSheet(sheetNo) + .head(headClazz) + .headRowNumber(headRowNumber) + .registerReadListener( + HelperUtil.getReadListener(accountInfoMapper, headClazz, true, startRow, endRow,sourceFile)) + .build(); + r.read(rs); + } catch (Exception e) { + + if (e instanceof ExcelAnalysisStopException) { + continue; + } + + log.error("读取企业活期账户信息失败: " + e.getMessage(), e); + throw new ImportDataFailedException("读取企业活期账户信息失败: " + e.getMessage(), sourceFile); + } + } + } + + // 读取定期数据,分为个人和企业两种数据 + private void readRegularDetailsV2(File excelFile, Cells cells, int sheetNo) throws Exception { + + Cell cell = AsposeUtil.getCell(excelFile, sheetNo, "企业"); + if (cell != null) { + readRegularDetailsForCompany(excelFile, sheetNo); + } else { + readRegularDetailsForPerson(excelFile, sheetNo); + } + } + + private void readRegularDetailsForCompany(File excelFile, int sheetNo) throws Exception { + List itemList = getAnalyzeItemListForCompany(excelFile.getAbsolutePath(), sheetNo); + + for (AnalyzeItem item : itemList) { + + try (ExcelReader r = EasyExcel.read(excelFile).build()) { + ReadSheet readSheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(item.headRowNumber) + .head(CCBRegularBankStatementEntity.class) + .registerReadListener(getRegularDetailListener(item)) + .build(); + r.read(readSheet); + + } catch (Exception e) { + // 停止继续读取需要抛出异常,这里不必处理 + if (e instanceof ExcelAnalysisStopException) { + continue; + } + + log.error("读取公司定期流水文件失败: " + e.getMessage(), e); + throw new ImportDataFailedException("读取公司定期流水文件失败: " + e.getMessage(), excelFile.getAbsolutePath()); + } + } + } + + private void readRegularDetailsForPerson(File excelFile, int sheetNo) throws Exception { + List itemList = getAnalyzeItemList(excelFile.getAbsolutePath(), sheetNo); + + for (AnalyzeItem item : itemList) { + + try (ExcelReader r = EasyExcel.read(excelFile).build()) { + ReadSheet readSheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(item.headRowNumber) + .head(CCBRegularBankStatementEntity.class) + .registerReadListener(getRegularDetailListener(item)) + .build(); + r.read(readSheet); + + + } catch (Exception e) { + // 停止继续读取需要抛出异常,这里不必处理 + log.error("读取_accounts_info文件失败", e); + throw new AnalyzeDataFailedException("读取_accounts_info文件失败", e); + } + } + } + + private ReadListener getRegularDetailListener(AnalyzeItem item) { + AtomicInteger cnt = new AtomicInteger(item.headRowNumber + 1); + return new ReadListener() { + + private List docList = + ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + @Override + public void invoke(CCBRegularBankStatementEntity entity, AnalysisContext context) { + + String id = IdUtil.objectId(); + + + entity.setId(id); + entity.setCardNumber(item.getCardNumber()); + entity.setCardHolderName(item.getCardHolderName()); + + docList.add(entity); + if (docList.size() >= Constants.BATCH_SIZE) { + saveToMongo(); + docList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + + if (cnt.incrementAndGet() > item.endRowNumber) { + saveToMongo(); + throw new ExcelAnalysisStopException("stop running."); + } + } + + private void saveToMongo() { + if (!docList.isEmpty()) { + esCCBRegularBankStatementMapper.insertBatch(docList); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!docList.isEmpty()) { + saveToMongo(); + } + } + }; + } + + // 个人活期明细信息 + private void readCurrentDetailsV2(File excelFile, Cells cells, int sheetNo) throws Exception { + List itemList = getAnalyzeItemList(excelFile.getAbsolutePath(), sheetNo); + + for (AnalyzeItem item : itemList) { + + try (ExcelReader r = EasyExcel.read(excelFile).build()) { + ReadSheet readSheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(item.headRowNumber) + .head(CCBCurrentBankStatementEntity.class) + .registerReadListener(getCurrentDetailListener(item)) + .build(); + r.read(readSheet); + + } catch (Exception e) { + if (e instanceof ExcelAnalysisStopException) { + continue; + } + + // 停止继续读取需要抛出异常,这里不必处理 + log.error("读取个人活期明细信息失败: " + e.getMessage(), e); + throw new AnalyzeDataFailedException("读取个人活期明细信息失败: " + e.getMessage(), e); + } + } + } + + private ReadListener getCurrentDetailListener(AnalyzeItem item) { + AtomicInteger cnt = new AtomicInteger(item.headRowNumber + 1); + return new ReadListener() { + + private List docList = + ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + @Override + public void invoke(CCBCurrentBankStatementEntity entity, AnalysisContext context) { + + if (HelperUtil.isContainsChinese(entity.getId())) { + return; + } + + String id = IdUtil.objectId(); + + + entity.setId(id); + if(StrUtil.isEmpty(entity.getCardNumber())){ + entity.setCardNumber(item.getCardNumber()); + } + entity.setCardHolderName(item.getCardHolderName()); + + docList.add(entity); + if (docList.size() >= Constants.BATCH_SIZE) { + saveToMongo(); + docList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + + if (cnt.incrementAndGet() > item.endRowNumber) { + saveToMongo(); + throw new ExcelAnalysisStopException("stop running."); + } + } + + private void saveToMongo() { + if (!docList.isEmpty()) { + esCCBCurrentBankStatementMapper.insertBatch(docList); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!docList.isEmpty()) { + saveToMongo(); + } + } + }; + } + + /** + * 读取电子现金明细 + */ + private void readElectronicCashDetails(File excelFile, Cells cells, int sheetNo) throws Exception { + List itemList = getAnalyzeItemList(excelFile.getAbsolutePath(), sheetNo); + + for (AnalyzeItem item : itemList) { + + try (ExcelReader r = EasyExcel.read(excelFile).build()) { + ReadSheet readSheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(item.headRowNumber) + .head(CCBElectronicCashBankStatementEntity.class) + .registerReadListener(getElectronicCashDetailListener(item)) + .build(); + r.read(readSheet); + + } catch (Exception e) { + + if (e instanceof ExcelAnalysisStopException) { + // 停止继续读取需要抛出异常,这里不必处理 + continue; + } else { + // 打印日志,抛出异常 + log.error("读取电子现金明细异常", e); + throw new ImportDataFailedException(e.getMessage(), excelFile.getAbsolutePath()); + } + } + } + } + + private ReadListener getElectronicCashDetailListener(AnalyzeItem item) { + AtomicInteger cnt = new AtomicInteger(item.headRowNumber + 1); + return new ReadListener() { + + private List docList = + ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + @Override + public void invoke(CCBElectronicCashBankStatementEntity entity, AnalysisContext context) { + String id = IdUtil.objectId(); + + entity.setId(id); + entity.setCardNumber(item.getCardNumber()); + entity.setCardHolderName(item.getCardHolderName()); + + docList.add(entity); + if (docList.size() >= Constants.BATCH_SIZE) { + saveToMongo(); + docList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + + if (cnt.incrementAndGet() > item.endRowNumber) { + saveToMongo(); + throw new ExcelAnalysisStopException("stop running."); + } + } + + private void saveToMongo() { + if (!docList.isEmpty()) { + esCCBElectronicCashBankStatementMapper.insertBatch(docList); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!docList.isEmpty()) { + saveToMongo(); + } + } + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + HelperUtil.handleException(exception); + + ReadListener.super.onException(exception, context); + } + }; + } + + /** + * 读取账户信息 + */ + private void readAccountInfo(File excelFile, Cells cells, int sheetNo) throws Exception { + // 三种账户信息 + int currentStartRow = AsposeUtil.getRowNumber(excelFile, sheetNo, "活期账户信息", 0); + if (currentStartRow != -1) { + currentStartRow += 3; + // 根据查询条件 + int currentEndRow = AsposeUtil.getRowNumber(excelFile, sheetNo, "根据查询条件", currentStartRow); + if (currentEndRow != -1) { + // 1、个人活期账户信息 个人活期账户信息 + readCurrentAccountInfo(excelFile, sheetNo, currentStartRow, currentEndRow); + } + } + int regularStartRow = AsposeUtil.getRowNumber(excelFile, sheetNo, "定期账户信息", 0); + if (regularStartRow != -1) { + regularStartRow += 3; + int regularEndRow = AsposeUtil.getRowNumber(excelFile, sheetNo, "根据查询条件", regularStartRow); + if (regularEndRow != -1) { + // 2、个人定期账户信息 + readRegularAccountInfo(excelFile, sheetNo, regularStartRow, regularEndRow); + } + } + + int electronicCashStartRow = AsposeUtil.getRowNumber(excelFile, sheetNo, "个人电子现金账户信息", 0); + if (electronicCashStartRow != -1) { + electronicCashStartRow += 3; + int electronicCashEndRow = + AsposeUtil.getRowNumber(excelFile, sheetNo, "个人电子现金账户信息", electronicCashStartRow); + if (electronicCashEndRow != -1) { + // 3、个人电子现金账户信息 + readElectronicCashAccountInfo(excelFile, sheetNo, electronicCashStartRow, electronicCashEndRow); + } + } + } + + /** + * 读取电子现金账户信息 + */ + private void readElectronicCashAccountInfo(File excelFile, int sheetNo, int startRow, int endRow) { + String sourceFile = HelperUtil.getSourceFileName(excelFile.getAbsolutePath(),BANK_NAME); + Class clazz = CCBElectronicCashAccountInfoEntity.class; + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + ReadSheet readSheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(startRow) + .head(clazz) + .registerReadListener(HelperUtil.getReadListener( + esCCBElectronicCashAccountInfoMapper, clazz, true, startRow, endRow,sourceFile)) + .build(); + reader.read(readSheet); + } catch (Exception e) { + + if (e instanceof ExcelAnalysisStopException) { + return; + } + + log.error("read current account info error", e); + throw new ImportDataFailedException(e.getMessage(), excelFile.getAbsolutePath()); + } + } + + /** + * 读取定期账户信息 + */ + private void readRegularAccountInfo(File excelFile, int sheetNo, int startRow, int endRow) { + String sourceFile = HelperUtil.getSourceFileName(excelFile.getAbsolutePath(),BANK_NAME); + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + ReadSheet readSheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(startRow) + .head(CCBRegularAccountInfoEntity.class) + .registerReadListener( + HelperUtil.getReadListener(esCCBRegularAccountInfoMapper, CCBRegularAccountInfoEntity.class, true, startRow, endRow,sourceFile)) + .build(); + reader.read(readSheet); + } catch (Exception e) { + if (e instanceof ExcelAnalysisStopException) { + return; + } + + log.error("read current account info error", e); + throw new ImportDataFailedException(e.getMessage(), excelFile.getAbsolutePath()); + } + } + + /** + * 读取活期账户信息 + */ + private void readCurrentAccountInfo(File excelFile, int sheetNo, int startRow, int endRow) { + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + ReadSheet readSheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(startRow) + .head(CCBCurrentAccountInfoEntity.class) + .registerReadListener(new ReadCCBCurrentAccountInfoListener(startRow, endRow, accountInfoMapper)) + .build(); + reader.read(readSheet); + } catch (Exception e) { + + if (e instanceof ExcelAnalysisStopException) { + return; + } + + log.error("read current account info error", e); + throw new ImportDataFailedException(e.getMessage(), excelFile.getAbsolutePath()); + } + } + + /** + * 通过读取汇总结果,得到相关文件 + */ + private Set readSummary(File f) { + + List summaryList = new ArrayList<>(); + + Set fileNameSet = new HashSet<>(); + + try (ExcelReader reader = EasyExcel.read(f).build()) { + ReadSheet sheet = EasyExcel.readSheet() + .headRowNumber(2) + .head(CCBSummaryEntry.class) + .registerReadListener(new ReadListener() { + @Override + public void invoke(CCBSummaryEntry entry, AnalysisContext context) { + summaryList.add(entry); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + // 读取文件结束 + for (CCBSummaryEntry entry : summaryList) { + String resultFileName = entry.getResultFileName(); + if (!com.inscloudtech.common.utils.StringUtils.isEmpty(resultFileName)) { + int idx = resultFileName.indexOf("_"); + if (idx != -1) { + String fileName = resultFileName.substring(idx + 1); + + Integer resultCount = entry.getResultCount(); + if (resultCount != 0) { + fileNameSet.add(fileName); + } + } + } + } + } + }) + .build(); + // 读文件 + reader.read(sheet); + } + + return fileNameSet; + } + + // ------------------------------------------------------------------------------------------------------------------ + + private List getAnalyzeItemListForCompany(String filename, int sheetNo) throws Exception { + Workbook wb = new Workbook(filename); + WorksheetCollection worksheets = wb.getWorksheets(); + + Worksheet ws = worksheets.get(sheetNo); + + String mainKey = "根据查询条件"; + final String key = "客户名称"; + + Cells cells = ws.getCells(); + + Cell roundStartCell = cells.find(mainKey, null); + + List itemList = new ArrayList<>(); + + for (; ; ) { + + if (roundStartCell == null) { + break; + } + + Cell roundEndCell = cells.find(mainKey, roundStartCell); + + Cell cell = cells.find(key, roundStartCell); + if (cell == null) { + break; + } + + int roundEndRow; + if (roundEndCell == null) { + roundEndRow = cells.getMaxRow(); + } else { + roundEndRow = roundEndCell.getRow(); + } + + int row = cell.getRow(); + + while (row < roundEndRow) { + AnalyzeItem ai = new AnalyzeItem(); + // 说明这一轮有数据 + // 客户名称:徐唯,客户编号:667190000103481964,客户账号:3860740150310007432,一本通账号或卡号:4340613860503177,存款种类:一户通,币别:人民币元,钞汇标志:钞,册号:0,笔号:1 + String complexStr = cell.getStringValue(); // 解析客户名称和客户账号 + if (StrUtil.isNotEmpty(complexStr)) { + String[] strArr = complexStr.split(","); + if (strArr.length > 3) { + String nameStr = strArr[0]; + String[] nameArr = nameStr.split(":"); + if (nameArr.length == 2) { + ai.setCardHolderName(nameArr[1]); + } else { + break; + } + + String cardNumberStr = strArr[2]; + String[] cardNumberArr = cardNumberStr.split(":"); + if (cardNumberArr.length == 2) { + ai.setCardNumber(cardNumberArr[1]); + } else { + break; + } + } + } else { + break; + } + + int headRowNumber = cell.getRow() + 2; + + ai.setHeadRowNumber(headRowNumber); + + cell = cells.find(key, cell); + if (cell == null) { + ai.setEndRowNumber(roundEndRow); + itemList.add(ai); + + break; + } + + row = cell.getRow(); + ai.setEndRowNumber(Math.min(row, roundEndRow)); + + itemList.add(ai); + } + + // 这一轮没有数据,开始下一轮 + roundStartCell = roundEndCell; + } + return itemList; + } + + private List getAnalyzeItemList(String filename, int sheetNo) throws Exception { + Workbook wb = new Workbook(filename); + WorksheetCollection worksheets = wb.getWorksheets(); + + Worksheet ws = worksheets.get(sheetNo); + + String mainKey = "根据查询条件"; + final String key = "客户名称"; + + Cells cells = ws.getCells(); + + Cell roundStartCell = cells.find(mainKey, null); + + List itemList = new ArrayList<>(); + + for (; ; ) { + + if (roundStartCell == null) { + break; + } + + Cell roundEndCell = cells.find(mainKey, roundStartCell); + + Cell cell = cells.find(key, roundStartCell); + if (cell == null) { + break; + } + + int roundEndRow; + if (roundEndCell == null) { + roundEndRow = cells.getMaxRow() + 1; + } else { + roundEndRow = roundEndCell.getRow(); + } + + int row = cell.getRow(); + + while (row <= roundEndRow) { + AnalyzeItem ai = new AnalyzeItem(); + // 说明这一轮有数据 + // 客户名称:徐唯,客户编号:667190000103481964,客户账号:3860740150310007432,一本通账号或卡号:4340613860503177,存款种类:一户通,币别:人民币元,钞汇标志:钞,册号:0,笔号:1 + String complexStr = cell.getStringValue(); // 解析客户名称和客户账号 + if (StrUtil.isNotEmpty(complexStr)) { + String[] strArr = complexStr.split(","); + if (strArr.length > 3) { + String nameStr = strArr[0]; + String[] nameArr = nameStr.split(":"); + if (nameArr.length == 2) { + ai.setCardHolderName(nameArr[1]); + } else { + break; + } + + String cardNumberStr = strArr[2]; + String[] cardNumberArr = cardNumberStr.split(":"); + if (cardNumberArr.length == 2) { + ai.setCardNumber(cardNumberArr[1]); + } else { + break; + } + } + } else { + break; + } + + int headRowNumber = cell.getRow() + 2; + + ai.setHeadRowNumber(headRowNumber); + + cell = cells.find(key, cell); + if (cell == null) { + ai.setEndRowNumber(roundEndRow); + itemList.add(ai); + + break; + } + + row = cell.getRow(); + ai.setEndRowNumber(Math.min(row, roundEndRow)); + + itemList.add(ai); + } + + // 这一轮没有数据,开始下一轮 + roundStartCell = roundEndCell; + } + return itemList; + } + + @Data + public static class AnalyzeItem { + private int headRowNumber; + private int endRowNumber; + private String cardHolderName; + private String cardNumber; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CEBDataAnalysisHelper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CEBDataAnalysisHelper.java new file mode 100644 index 0000000..72aac0c --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CEBDataAnalysisHelper.java @@ -0,0 +1,574 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.converters.bigdecimal.BigDecimalStringConverter; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.util.ListUtils; +import com.aspose.cells.Cell; +import com.aspose.cells.Workbook; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.mapper.es.EsCEBCreditCardStatementMapper; +import com.inscloudtech.datacenter.mapper.es.EsCEBSavingsCardStatementMapper; +import com.inscloudtech.datacenter.domain.BankStatement; + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CEBCreditCardStatementEntity; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CEBSavingsCardStatementEntity; +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.lang.reflect.Field; +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 光大银行 + */ +@RequiredArgsConstructor +@Slf4j +@Component +public class CEBDataAnalysisHelper { + + + + private final EsCEBCreditCardStatementMapper esCEBCreditCardStatementMapper; + private final EsCEBSavingsCardStatementMapper esCEBSavingsCardStatementMapper; + private final static String BANK_NAME = "光大银行"; + public void analyzeCEBData(String caseId) { + + analyzeSavingsCardBS(caseId); + analyzeCreditCardBS(caseId); + } + + private void analyzeCreditCardBS(String caseId) { + + List bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(esCEBCreditCardStatementMapper, CEBCreditCardStatementEntity.class); + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + for (CEBCreditCardStatementEntity entity : entityList) { + + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + bs.setCardHolderName(entity.getCardHolderName()); + + + + bs.setCardNumber(entity.getCardNumber()); + bs.setCounterpartyName(entity.getCounterpartyName()); + bs.setCounterpartIdCardNo(null); + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + bs.setCounterpartyBankName(entity.getCounterpartyBankName()); + bs.setTransRemark(entity.getTransRemark()); + bs.setSummary(entity.getTransSummary()); + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + + String transAmount = entity.getTransactionAmount(); + BigDecimal transactionAmount = BigDecimal.valueOf(Double.parseDouble(transAmount)); + String loanFlag = entity.getLoanFlag(); + if (StrUtil.isNotEmpty(loanFlag)) { + if (Objects.equals("付", loanFlag)) { + bs.setTransactionAmount(BigDecimal.ZERO.subtract(transactionAmount)); + } else { + bs.setTransactionAmount(transactionAmount); + } + } + + bs.setBalance(BigDecimal.ZERO); + + // 2015-12-19 + bs.setTransactionTime(DateUtil.parse(entity.getTransactionTime(), "yyyy-MM-dd")); + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + + + private void analyzeSavingsCardBS(String caseId) { + + List bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(esCEBSavingsCardStatementMapper, CEBSavingsCardStatementEntity.class); + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + for (CEBSavingsCardStatementEntity entity : entityList) { + + if (HelperUtil.isContainsChinese(entity.getBalance()) + || HelperUtil.isContainsChinese(entity.getRevenueAmount()) + || HelperUtil.isContainsChinese(entity.getExpenditureAmount())) { + continue; + } + + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + bs.setCardHolderName(entity.getCardHolderName()); + + + bs.setCardNumber(entity.getCardNumber()); + bs.setCounterpartyName(entity.getCounterpartyName()); + + + + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + bs.setSummary(entity.getTransSummary()); + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + // 存入金额 + BigDecimal revenueAmount = BigDecimal.ZERO; + String revenueAmountStr = entity.getRevenueAmount(); + if (StrUtil.isNotEmpty(revenueAmountStr)) { + try { + revenueAmount = BigDecimal.valueOf(Double.parseDouble(revenueAmountStr)); + } catch (Exception e) { + // + continue; + } + } + // 转出 + BigDecimal expenditureAmount = BigDecimal.ZERO; + String expenditureAmountStr = entity.getExpenditureAmount(); + if (StrUtil.isNotEmpty(expenditureAmountStr)) { + try { + expenditureAmount = BigDecimal.valueOf(Double.parseDouble(expenditureAmountStr)); + } catch (Exception e) { + // + continue; + } + } + // 交易金额 + bs.setTransactionAmount(revenueAmount.subtract(expenditureAmount)); + + bs.setBalance(NumberUtil.toBigDecimal(entity.getBalance())); + + // 20110317 + try { + bs.setTransactionTime(DateUtil.parse(entity.getTransactionTime(), "yyyyMMdd")); + } catch (Exception e) { + continue; + } + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + public void importCEBData(File file) throws Exception { + List fileList = FileUtil.loopFiles(file); + // 分开 + List excelFileList = fileList.stream() + .filter(f -> { + String extName = FileUtil.extName(f); + return StrUtil.isNotEmpty(extName) && (extName.contains("xls") || extName.contains("xlsx")); + }) + .collect(Collectors.toList()); + + List pdfFileList = fileList.stream() + .filter(f -> { + String extName = FileUtil.extName(f); + return StrUtil.isNotEmpty(extName) && extName.contains("pdf"); + }) + .collect(Collectors.toList()); + + // pdf转Excel + for (File f : pdfFileList) { + readPDFSavingsCardBS(f); + } + + for (File excelFile : excelFileList) { + // 信用卡流水 信用卡消费商户名称 + Cell cell = AsposeUtil.getCell(excelFile, 0, "信用卡消费商户名称"); + if (cell != null) { + // 信用卡流水 + readCreditCardBS(excelFile); + } else if (AsposeUtil.getCell(excelFile, 0, "对私活期账户对账单") != null) { + // 储蓄卡流水信息 + readSavingsCardBS(excelFile); + } else { + // 可能是客户信息,也可能是其他信息,看不清楚,数据不全 + log.info("其他信息:{}", excelFile.getAbsolutePath()); + } + } + } + + private void readPDFSavingsCardBS(File f) { + + String cardHolderName = null; + String cardNumber = null; + + Field[] fields = ReflectUtil.getFields(CEBSavingsCardStatementEntity.class); + + List entityList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + Map filedNameAndAnnoMap = new HashMap<>(); + + for (Field field : fields) { + field.setAccessible(true); + + ExcelProperty prop = field.getAnnotation(ExcelProperty.class); + if (prop == null) { + continue; + } + + String[] valueArr = prop.value(); + if (valueArr.length > 0) { + filedNameAndAnnoMap.put(valueArr[0], field.getName()); + } + } + +/* + try (com.aspose.pdf.Document doc = new com.aspose.pdf.Document(f.getAbsolutePath())) { + + TextFragmentAbsorber tfa = new TextFragmentAbsorber(); + + for (Page page : doc.getPages()) { + page.accept(tfa); + + boolean isBegin = false; + boolean isReadHead = false; + + List headList = new ArrayList<>(); + List dataList = new ArrayList<>(); + // 一页数据 + for (TextFragment textFragment : tfa.getTextFragments()) { + + String data = textFragment.getText().trim(); + + if (data.contains("客户姓名")) { + // 截取客户姓名 + String[] arr = data.split(":"); + if (arr.length == 2) { + cardHolderName = arr[1]; + } + } + + if (data.contains("客户账号") && data.contains(":")) { + // 截取客户姓名 + String[] arr = data.split(":"); + if (arr.length == 2) { + cardNumber = arr[1]; + } + } + + if (Objects.equals("客户账号", data)) { + isReadHead = true; + isBegin = true; + } + + if (isReadHead) { + // 读取表头 + headList.add(data); + if (Objects.equals("对方名称", data)) { + isReadHead = false; + } + + continue; + } + + if (isBegin) { + if (StringUtils.isEmpty(data)) { + dataList.add("-"); + } else { + if (data.equalsIgnoreCase("司") || data.equalsIgnoreCase("公司")) { + String newData = dataList.get(dataList.size() - 1) + data; + dataList.set(dataList.size() - 1, newData); + continue; + } + + if (data.contains("第") + || data.contains("共") + || data.contains("CEBBANK") + || data.contains("736275")) { + continue; + } + + dataList.add(data); + } + } + } + int cnt = 0; + + List part = new ArrayList<>(); + Map objMap = new HashMap<>(); + + for (String s : dataList) { + if (StrUtil.isNotEmpty(s) && s.equalsIgnoreCase("-")) { + s = ""; + } + + part.add(s); + if (++cnt % headList.size() == 0) { + cnt = 0; + + for (int i = 0; i < headList.size(); i++) { + objMap.put(filedNameAndAnnoMap.get(headList.get(i)), part.get(i)); + } + + String jsonStr = JSONUtil.toJsonStr(objMap); + + CEBSavingsCardStatementEntity entity = + JSONUtil.parseObj(jsonStr, CEBSavingsCardStatementEntity.class); + + String transactionTime = entity.getTransactionTime(); + if (StringUtils.isEmpty(transactionTime)) { + part.clear(); + continue; + } + + entity.setCardHolderName(cardHolderName); + + String cn = entity.getCardNumber(); + if (StringUtils.isEmpty(cn)) { + entity.setCardNumber(cardNumber); + } + + entityList.add(entity); + + if (entityList.size() >= Constants.BATCH_SIZE) { + entityList = saveToES(entityList); + } + + part.clear(); + } + } + + if (!entityList.isEmpty()) { + entityList = saveToES(entityList); + } + + tfa.reset(); + } + } +*/ + } + + private List saveToES(List entityList) { + List dest = HelperUtil.getDest(entityList); + + dest = dest.stream().peek(entity -> entity.setId(IdUtil.objectId())).collect(Collectors.toList()); + + esCEBSavingsCardStatementMapper.insertBatch(dest); + + entityList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + return entityList; + } + + private void readSavingsCardBS(File excelFile) throws Exception { + Workbook wb = new Workbook(excelFile.getAbsolutePath()); + int count = wb.getWorksheets().getCount(); + + for (int sheetNo = 0; sheetNo < count; sheetNo++) { + readSavingsCardSheetData(excelFile, sheetNo); + } + } + + private void readSavingsCardSheetData(File excelFile, int sheetNo) { + String cardHolderName = null; + // 查找客户姓名 + Cell cell = AsposeUtil.getCell(excelFile, sheetNo, "客户姓名"); + if (cell == null) { + String mainName = FileUtil.mainName(excelFile); + //todo +// cardHolderName = HanLPUtil.getName(mainName); + cardHolderName = mainName; + } else { + String nameStr = cell.getStringValue(); + if (nameStr.contains(":")) { + // 客户姓名:刘旺 + String[] strArr = nameStr.split(":"); + if (strArr.length == 2) { + cardHolderName = strArr[1]; + } + } + } + + cell = AsposeUtil.getCell(excelFile, sheetNo, "交易日期"); + if (cell == null) { + return; + } + + int headRowNumber = cell.getRow() + 1; + + try (ExcelReader r = EasyExcel.read(excelFile).build()) { + ReadSheet rs = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNumber) + .head(CEBSavingsCardStatementEntity.class) + .registerReadListener(getReadListenerForSavingsCard(cardHolderName)) + .build(); + r.read(rs); + } + } + + private ReadListener getReadListenerForSavingsCard(String cardHolderName) { + return new ReadListener() { + + List cacheList = + ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + @Override + public void invoke(CEBSavingsCardStatementEntity entity, AnalysisContext context) { + + entity.setId(IdUtil.objectId()); + + String balance = entity.getBalance(); + if (StrUtil.isNotEmpty(balance) || HelperUtil.isContainsChinese(balance)) { + return; + } + + entity.setCardHolderName(cardHolderName); + + cacheList.add(entity); + if (cacheList.size() >= Constants.BATCH_SIZE) { + saveDataToES(); + } + } + + private void saveDataToES() { + esCEBSavingsCardStatementMapper.insertBatch(cacheList); + cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!cacheList.isEmpty()) { + saveDataToES(); + } + } + }; + } + + private void readCreditCardBS(File excelFile) throws Exception { + Workbook wb = new Workbook(excelFile.getAbsolutePath()); + int count = wb.getWorksheets().getCount(); + + for (int sheetNo = 0; sheetNo < count; sheetNo++) { + readCreditCardSheetData(excelFile, sheetNo); + } + } + + private void readCreditCardSheetData(File excelFile, int sheetNo) { + + String mainName = FileUtil.mainName(excelFile); +// String cardHolderName = HanLPUtil.getName(mainName); + try (ExcelReader r = EasyExcel.read(excelFile).build()) { + ReadSheet rs = EasyExcel.readSheet(sheetNo) + .registerConverter(new BigDecimalStringConverter()) + .head(CEBCreditCardStatementEntity.class) + .registerReadListener(getReadListener(mainName)) + .build(); + r.read(rs); + } + } + + public ReadListener getReadListener(String cardHolderName) { + return new ReadListener() { + + List cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + @Override + public void invoke(CEBCreditCardStatementEntity entity, AnalysisContext context) { + + entity.setId(IdUtil.objectId()); + entity.setCardHolderName(cardHolderName); + + String transactionAmount = entity.getTransactionAmount(); + if (StrUtil.isNotEmpty(transactionAmount) && transactionAmount.contains(",")) { + transactionAmount = transactionAmount.replaceAll(",", ""); + entity.setTransactionAmount(transactionAmount); + } + + cacheList.add(entity); + if (cacheList.size() >= Constants.BATCH_SIZE) { + save(); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!cacheList.isEmpty()) { + save(); + } + } + + private void save() { + esCEBCreditCardStatementMapper.insertBatch(cacheList); + cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + }; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CGBCDataAnalysisHelper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CGBCDataAnalysisHelper.java new file mode 100644 index 0000000..b82b49f --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CGBCDataAnalysisHelper.java @@ -0,0 +1,1206 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.exception.ExcelAnalysisStopException; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.util.ListUtils; + +import com.aspose.cells.*; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; + +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.bankStatementAnalysis.listener.CGBCCreditCardOpeningAccountInfoReadListener; +import com.inscloudtech.bankStatementAnalysis.service.ImportService; +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; +import com.inscloudtech.common.constant.BankStatementConstants; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.exception.dc.AnalyzeDataFailedException; +import com.inscloudtech.common.exception.dc.ImportDataFailedException; +import com.inscloudtech.common.exception.dc.TemplateNotFindException; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.common.utils.file.FileUtils; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.mapper.es.*; +import com.inscloudtech.datacenter.service.ImportResultService; + + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.*; + + + + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.easyes.core.core.BaseEsMapper; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 广发银行数据分析 + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class CGBCDataAnalysisHelper { + + private final ImportService importService; + private final ImportResultService importResultService; + + // 信用卡 + private final EsCGBCCreditCardAccountInfoMapper esCGBCCreditCardAccountInfoMapper; + private final EsCGBCCreditCardStatementMapper esCGBCCreditCardStatementMapper; + private final EsCGBCCreditCardOtherStatementMapper esCGBCCreditCardOtherStatementMapper; + // 旧核心 + private final EsCGBCOldAccountInfoMapper esCGBCOldAccountInfoMapper; + private final EsCGBCStatementMapper esCGBCStatementMapper; + // 新核心 + private final EsCGBCNewCustomerInfoMapper esCGBCNewCustomerInfoMapper; + private final EsCGBCNewCurrentAccountInfoMapper esCGBCNewCurrentAccountInfoMapper; + private final EsCGBCNewRegularAccountInfoMapper esCGBCNewRegularAccountInfoMapper; + private final EsCGBCNewCompanyInfoMapper esCGBCNewCompanyInfoMapper; + private final EsCGBCNewStatementMapper esCGBCNewStatementMapper; + + private final ESOpeningAccountInfoMapper esOpeningAccountInfoMapper; + + // 支出 + private final List payTransCodeList = Arrays.asList( + "1005", "1007", "1009", "1280", "202", "3100", "3102", "3103", "3300", "4001", "4005", "4007", "4025", + "4099", "5501", "5803", "5805", "5817", "5823", "5880", "5883", "6009", "6017"); + + // 入账 + private final List entryTransCodeList = Arrays.asList( + "1006", "1301", "2003", "2006", "2007", "203", "2098", "3000", "3400", "4102", "5918", "6140", "8400", + "8600", "8800", "4318"); + private final static String BANK_NAME = "广发银行"; + + public void analyzeData(String caseId) { + // 开户信息 + analyzeOAI(caseId); + // 流水分析 + analyzeBS(caseId); + } + + private void analyzeOAI(String caseId) { + + List oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + Map customerMap = new HashMap<>(); + + List entityList = + HelperUtil.getEntityList(esCGBCOldAccountInfoMapper, CGBCOldAccountInfoEntity.class); + // 旧核心开户信息 + Set uniqueKeySet = new HashSet(); + for (CGBCOldAccountInfoEntity entity : entityList) { + + String cardHolderName = entity.getCardHolderName(); + if (StrUtil.isEmpty(cardHolderName) + || cardHolderName.equals("客户编号") + || !HelperUtil.isContainsChinese(cardHolderName)) { + continue; + } + + OpeningAccountInfo oai = new OpeningAccountInfo(); + oai.setName(cardHolderName); + oai.setBankName(BANK_NAME); + oai.setAccountNumber(entity.getCardNumber()); + oai.setIdType(entity.getIdType()); + oai.setIdNo(entity.getIdCardNo()); + oai.setPhone(entity.getPhone()); + + if (StringUtils.isEmpty(oai.getPhone())) { + if (customerMap.containsKey(oai.getName())) { + CGBCNewCustomerInfoEntity customer = customerMap.get(oai.getName()); + oai.setPhone(customer.getPhone()); + } else { + //todo 需优化 + CGBCNewCustomerInfoEntity info = HelperUtil.getEntity( + esCGBCNewCustomerInfoMapper, + CGBCNewCustomerInfoEntity.class, + "cardHolderName", + oai.getName()); + if (info != null) { + oai.setPhone(info.getPhone()); + + customerMap.put(info.getCardHolderName(), info); + } + } + } + + oai.setAddress(entity.getAddress()); + if (StringUtils.isEmpty(oai.getAddress())) { + if (customerMap.containsKey(oai.getName())) { + CGBCNewCustomerInfoEntity customer = customerMap.get(oai.getName()); + oai.setAddress(customer.getAddress()); + } else { + //todo 需优化 + CGBCNewCustomerInfoEntity info = HelperUtil.getEntity( + esCGBCNewCustomerInfoMapper, + CGBCNewCustomerInfoEntity.class, + "cardHolderName", + oai.getName()); + if (info != null) { + oai.setAddress(info.getAddress()); + + customerMap.put(info.getCardHolderName(), info); + } + } + } + + oai.setOpeningAccountDate(entity.getOpeningAccountDate()); + oai.setClosingDate(entity.getCloseDate()); + oai.setStatus(entity.getStatus()); + oai.setAccountOpeningInstitution(entity.getAccountOpeningInstitution()); + + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + oaiList.add(oai); + if (oaiList.size() >= Constants.BATCH_SIZE) { + // 保存数据库 + List dest = HelperUtil.getDest(oaiList); + + HelperUtil.batchSaveOAI2Es(dest, caseId); + + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + if (!oaiList.isEmpty()) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + } + + // 新核心开户信息 + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + List newCurrentEntityList = + HelperUtil.getEntityList(esCGBCNewCurrentAccountInfoMapper, CGBCNewCurrentAccountInfoEntry.class); + List newRegularEntityList = + HelperUtil.getEntityList(esCGBCNewRegularAccountInfoMapper, CGBCNewRegularAccountInfoEntry.class); + + List newCompanyList = + HelperUtil.getEntityList(esCGBCNewCompanyInfoMapper, CGBCNewCompanyInfoEntity.class); + List newCustomerList = + HelperUtil.getEntityList(esCGBCNewCustomerInfoMapper, CGBCNewCustomerInfoEntity.class); + + Map nameCompanyMap = new HashMap<>(); + for (CGBCNewCompanyInfoEntity entity : newCompanyList) { + nameCompanyMap.put(entity.getCardHolderName(), entity); + } + + Map nameCustomerMap = new HashMap<>(); + for (CGBCNewCustomerInfoEntity entity : newCustomerList) { + nameCustomerMap.put(entity.getCardHolderName(), entity); + } + + for (CGBCNewCurrentAccountInfoEntry entry : newCurrentEntityList) { + + String cardHolderName = entry.getCardHolderName(); + if (StrUtil.isEmpty(cardHolderName) + || cardHolderName.equals("客户编号") + || !HelperUtil.isContainsChinese(cardHolderName)) { + continue; + } + + OpeningAccountInfo oai = new OpeningAccountInfo(); + oai.setName(cardHolderName); + oai.setBankName(BANK_NAME); + oai.setNewAccountNumber(null); + oai.setAccountNumber(entry.getCardNumber()); + oai.setIdType(entry.getIdType()); + oai.setIdNo(entry.getIdCardNo()); + + CGBCNewCustomerInfoEntity customer = nameCustomerMap.getOrDefault(entry.getCardHolderName(), null); + if (customer != null) { + oai.setPhone(customer.getPhone()); + oai.setAddress(customer.getAddress()); + } else { + CGBCNewCompanyInfoEntity company = nameCompanyMap.getOrDefault(entry.getCardHolderName(), null); + if (company != null) { + oai.setPhone(company.getPhone()); + oai.setAddress(company.getAddress()); + } + } + + oai.setOpeningAccountDate(entry.getOpeningAccountDate()); + oai.setClosingDate(entry.getCloseDate()); + oai.setStatus(entry.getStatus()); + oai.setAccountOpeningInstitution(entry.getAccountOpeningInstitution()); + oai.setCaseId(caseId); + + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + oaiList.add(oai); + if (oaiList.size() >= Constants.BATCH_SIZE) { + // 保存数据库 + List dest = HelperUtil.getDest(oaiList); + + HelperUtil.batchSaveOAI2Es(dest, caseId); + + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + for (CGBCNewRegularAccountInfoEntry entry : newRegularEntityList) { + + String cardHolderName = entry.getCardHolderName(); + if (StrUtil.isEmpty(cardHolderName) + || cardHolderName.equals("客户编号") + || !HelperUtil.isContainsChinese(cardHolderName)) { + continue; + } + + OpeningAccountInfo oai = new OpeningAccountInfo(); + oai.setName(cardHolderName); + oai.setBankName(BANK_NAME); + oai.setNewAccountNumber(null); + oai.setAccountNumber(entry.getCardNumber()); + oai.setIdType(entry.getIdType()); + oai.setIdNo(entry.getIdCardNo()); + + CGBCNewCustomerInfoEntity customer = nameCustomerMap.getOrDefault(entry.getCardHolderName(), null); + if (customer != null) { + oai.setPhone(customer.getPhone()); + oai.setAddress(customer.getAddress()); + } else { + CGBCNewCompanyInfoEntity company = nameCompanyMap.getOrDefault(entry.getCardHolderName(), null); + if (company != null) { + oai.setPhone(company.getPhone()); + oai.setAddress(company.getAddress()); + } + } + + oai.setOpeningAccountDate(entry.getOpeningAccountDate()); + oai.setClosingDate(entry.getCloseDate()); + oai.setStatus(entry.getStatus()); + oai.setCaseId(caseId); + oai.setBalance(new BigDecimal("0")); + + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + oaiList.add(oai); + if (oaiList.size() >= Constants.BATCH_SIZE) { + // 保存数据库 + List dest = HelperUtil.getDest(oaiList); + + HelperUtil.batchSaveOAI2Es(dest, caseId); + + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + if (!oaiList.isEmpty()) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + } + } + + private void analyzeBS(String caseId) { + // 储蓄卡流水 + analyzeSavingsCardBS(caseId); + // 信用卡流水 + analyzeCreditCardBS(caseId); + } + + private void analyzeCreditCardBS(String caseId) { + analyzeOther(caseId); // pdf,没有开户信息 + analyzeNormal(caseId); // 有开户信息 + } + + private void analyzeNormal(String caseId) { + + List bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(esCGBCCreditCardStatementMapper, CGBCCreditCardStatementEntry.class); + + Map> oaiMap = importService.getOAIMap(caseId, BANK_NAME); + + List infoList = + HelperUtil.getEntityList(esCGBCCreditCardAccountInfoMapper, CGBCCreditCardAccountInfoEntry.class); + + Map nameInfoMap = new HashMap<>(); + + for (CGBCCreditCardAccountInfoEntry entry : infoList) { + nameInfoMap.put(entry.getCardHolderName(), entry); + } + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + for (CGBCCreditCardStatementEntry entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + String cardHolderName = entity.getCardHolderName(); + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + bs.setCardHolderName(cardHolderName); + + CGBCCreditCardAccountInfoEntry info = nameInfoMap.getOrDefault(cardHolderName, null); + if (info != null) { + bs.setIdCardNo(info.getIdCardNo()); + bs.setPhone(info.getPhone()); + }else { + if(oaiMap.containsKey(cardHolderName)){ + List openingAccountInfos = oaiMap.get(cardHolderName); + for (OpeningAccountInfo openingAccountInfo : openingAccountInfos) { + if (StrUtil.isNotEmpty(openingAccountInfo.getIdNo())) { + bs.setIdCardNo(openingAccountInfo.getIdNo()); + } + if (StrUtil.isNotEmpty(openingAccountInfo.getPhone())) { + bs.setPhone(openingAccountInfo.getPhone()); + } + } + + } + + + } + + bs.setCardNumber(entity.getCardNumber()); + bs.setSummary(entity.getSummary()); + bs.setTransRemark(entity.getTransRemark()); + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + // 根据交易代码来计算 + String transCode = entity.getTransCode(); + + //982 9999999999999999999 802410502830915151 20110110 8600 自动转账还款 人民币 131081 自动转账还款 王魁 410502198309151513 +// if(entity.getEntryAmount() == null && entity.getTransactionAmount()== null){ +// +// } + BigDecimal transactionAmount = entity.getEntryAmount() == null?entity.getTransactionAmount():entity.getEntryAmount(); + if(transactionAmount == null){ + transactionAmount = BigDecimal.ZERO; + } + if(transactionAmount.compareTo(BigDecimal.ZERO) == 0){ + transactionAmount = entity.getTransactionAmountNext(); + } + if(transactionAmount == null){ + transactionAmount = BigDecimal.ZERO; + } + if(ObjUtil.isNotEmpty(transactionAmount)){ + if (payTransCodeList.contains(transCode)) { + bs.setTransactionAmount(transactionAmount.negate()); + } else if (entryTransCodeList.contains(transCode)) { + bs.setTransactionAmount(transactionAmount); + } else { + bs.setTransactionAmount(transactionAmount); + } + } + + // 20190503 + try { + bs.setTransactionTime(DateUtil.parse(entity.getTransactionTime(), "yyyyMMdd")); + } catch (Exception e) { + log.error("解析日期异常", e); + + throw new AnalyzeDataFailedException( + StrUtil.format("解析日期异常,日期:{}", entity.getTransactionTime()), e.getCause(), sourceFile); + } + + bs.setBalance(BigDecimal.ZERO); + bs.setRemark("信用卡"); + String uniqueKey = caseId +BANK_NAME+ cardHolderName +entity.getIdCardNo()+entity.getCardNumber()+entity.getTransactionTime()+entity.getTransactionAmount()+ + entity.getTransCode()+entity.getSqCode(); + String id = HelperUtil.generateMD5(uniqueKey); + + if(HelperUtil.deduplication(id,uniqueKeySet)){ + continue; + } + bs.setCaseId(caseId); + bs.setId(id); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e,sourceFile); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + private void analyzeOther(String caseId) { + + List bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = HelperUtil.getEntityList( + esCGBCCreditCardOtherStatementMapper, CGBCCreditCardOtherStatementEntity.class); + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + for (CGBCCreditCardOtherStatementEntity entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + bs.setCardHolderName(entity.getCardHolderName()); + + + + bs.setCardNumber(entity.getCardNumber()); + String counterpartyName = entity.getCounterpartyName(); + bs.setCounterpartyName(counterpartyName); + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + + + bs.setCounterpartyBankName(entity.getCounterpartyBankName()); + bs.setSummary(entity.getTransSummary()); + bs.setTransRemark(entity.getTransRemark()); + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + + String transactionAmount = entity.getTransactionAmount(); + if (StrUtil.isNotEmpty(transactionAmount)) { + bs.setTransactionAmount(BigDecimal.valueOf(Double.parseDouble(transactionAmount))); + } else { + bs.setTransactionAmount(BigDecimal.ZERO); + } + + // 2011/03/09 + try { + bs.setTransactionTime(DateUtil.parse(entity.getTransactionTime(), "yyyy/MM/dd")); + } catch (Exception e) { + log.error("日期格式错误", e); + + throw new AnalyzeDataFailedException( + StrUtil.format("日期格式错误:{}", entity.getTransactionTime()), e, sourceFile); + } + + bs.setBalance(BigDecimal.ZERO); + bs.setRemark("信用卡"); + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entity.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest,caseId); + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e,sourceFile); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + private void analyzeSavingsCardBS(String caseId) { + // 旧核心交易流水 + analyzeSavingsCardOldBS(caseId); + // 新核心交易流水 + analyzeSavingsCardNewBS(caseId); + } + + private void analyzeSavingsCardNewBS(String caseId) { + + List bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(esCGBCNewStatementMapper, CGBCNewStatementEntry.class); + + List oaiList = + HelperUtil.getEntityListV2(esOpeningAccountInfoMapper, OpeningAccountInfo.class, caseId); + Map nameOAIMap = new HashMap<>(); + + for (OpeningAccountInfo oai : oaiList) { + nameOAIMap.put(oai.getName(), oai); + } + + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + + for (CGBCNewStatementEntry entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + String cardHolderName = entity.getCardHolderName(); + if (StringUtils.isEmpty(cardHolderName)) { + continue; + } + + // 流水 + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + bs.setCardHolderName(cardHolderName); + + // 根据名称去查找基本信息 + OpeningAccountInfo oai = nameOAIMap.getOrDefault(cardHolderName, null); + if (oai != null) { + bs.setPhone(oai.getPhone()); + bs.setIdCardNo(oai.getIdNo()); + } + + bs.setCardNumber(entity.getCardNumber()); + // 1 货币类型 + // 人民币 + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + + // 2 交易金额 可能是double或者int类型 + BigDecimal transactionAmount = entity.getTransactionAmount(); + + //sbluoji + String loanFlag = entity.getLoanFlag(); + if (StrUtil.isNotEmpty(loanFlag)) { + if (Objects.equals("出账", loanFlag)) { + bs.setTransactionAmount(transactionAmount.negate()); + } else { + bs.setTransactionAmount(transactionAmount); + } + }else { + bs.setTransactionAmount(transactionAmount); + } + // 3 余额 + bs.setBalance(entity.getBalance()); + // 4 交易日期 20100503 + String transDate = entity.getTransDate(); + if (StrUtil.isNotEmpty(transDate)) { + String transTime = entity.getTransTime(); // 09:34:06 + try { + if (StrUtil.isNotEmpty(transTime)) { + bs.setTransactionTime(DateUtil.parse(transDate + " " + transTime, "yyyyMMdd HH:mm:ss")); + } else { + bs.setTransactionTime(DateUtil.parse(transDate, "yyyyMMdd")); + } + } catch (Exception e) { + log.error("日期格式错误", e); + + throw new AnalyzeDataFailedException(StrUtil.format("日期格式错误: {}", transDate), e, sourceFile); + } + } + + String counterpartyName = entity.getCounterpartyName(); + bs.setCounterpartyName(counterpartyName); + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + + if (StrUtil.isNotEmpty(counterpartyName)) { + // 根据对手名去查找 + OpeningAccountInfo ac = nameOAIMap.getOrDefault(counterpartyName, null); + if (ac != null) { + bs.setCounterpartIdCardNo(ac.getIdNo()); + } + } + + String transRemark1 = entity.getTransRemark1(); + if (StrUtil.isNotEmpty(transRemark1)) { + String transRemark2 = entity.getTransRemark2(); + if (StrUtil.isNotEmpty(transRemark2)) { + bs.setTransRemark(transRemark1 + " " + transRemark2); + } else { + bs.setTransRemark(transRemark1); + } + } + + bs.setSummary(entity.getSummary()); + bs.setTransChannel(entity.getTransChannel()); + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entity.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + BeanUtils.beanAttributeValueTrim(bs); + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + + HelperUtil.batchInsert2Es(dest, caseId); + + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e,sourceFile); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + + // 保存数据库 + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + private void analyzeSavingsCardOldBS(String caseId) { + + List bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(esCGBCStatementMapper, CGBCStatementEntity.class); + + List accountList = + HelperUtil.getEntityList(esCGBCOldAccountInfoMapper, CGBCOldAccountInfoEntity.class); + Map nameAccountMap = new HashMap<>(); + + for (CGBCOldAccountInfoEntity entity : accountList) { + nameAccountMap.put(entity.getCardHolderName(), entity); + } + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + for (CGBCStatementEntity entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + String cardHolderName = entity.getCardHolderName().trim(); + if (StringUtils.isEmpty(cardHolderName)) { + continue; + } + + // 流水 + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + bs.setCardHolderName(cardHolderName); + + // 根据名称去查找基本信息 + CGBCOldAccountInfoEntity account = nameAccountMap.getOrDefault(cardHolderName, null); + if (account != null) { + bs.setPhone(account.getPhone()); + bs.setIdCardNo(account.getIdCardNo()); + } + + bs.setCardNumber(entity.getCardNumber()); + // 1 货币类型 + // 人民币 + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + + // 2 交易金额 可能是double或者int类型 + + BigDecimal transactionAmount = NumberUtil.toBigDecimal(entity.getTransactionAmount()); + + String loanFlag = entity.getLoanFlag(); + if (StrUtil.isNotEmpty(loanFlag)) { + if (Objects.equals("出账", loanFlag)) { + bs.setTransactionAmount(BigDecimal.ZERO.subtract(transactionAmount)); + } else { + bs.setTransactionAmount(transactionAmount); + } + }else { + bs.setTransactionAmount(transactionAmount); + } + + // 3 余额 + bs.setBalance(NumberUtil.toBigDecimal(entity.getBalance())); + // 4 交易日期 20100503 + String transDate = entity.getTransDate(); + if (StrUtil.isNotEmpty(transDate)) { + String transTime = entity.getTransTime(); // 09:34:06 + try { + if (StrUtil.isNotEmpty(transTime)) { + bs.setTransactionTime(DateUtil.parse(transDate + " " + transTime, "yyyyMMdd HH:mm:ss")); + } else { + bs.setTransactionTime(DateUtil.parse(transDate, "yyyyMMdd")); + } + } catch (Exception e) { + log.error("交易时间解析失败:{}", transTime); + + throw new AnalyzeDataFailedException(StrUtil.format("解析时间失败,日期:{}", transDate), e, sourceFile); + } + } + + String counterpartyName = entity.getCounterpartyName(); + bs.setCounterpartyName(counterpartyName); + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + + if (StrUtil.isNotEmpty(counterpartyName)) { + // 根据对手名去查找 + CGBCOldAccountInfoEntity acc = nameAccountMap.getOrDefault(cardHolderName, null); + if (acc != null) { + bs.setCounterpartIdCardNo(acc.getIdCardNo()); + } + } + + bs.setCounterpartyBankName(entity.getCounterpartyBankName()); + bs.setSummary(entity.getSummary()); + bs.setTransChannel(entity.getTransChannel()); + bs.setTransRemark(entity.getTransRemark()); + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entity.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e,sourceFile); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + // 保存数据库 + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + public void importData(File file,String caseId) throws Exception { + File[] files = file.listFiles(); + if (files == null) { + return; + } + + List fileList = FileUtil.loopFiles(file); + // 分开 + List pdfFileList = fileList.stream() + .filter(f -> { + String extName = FileUtil.extName(f); + return StrUtil.isNotEmpty(extName) && (extName.contains("pdf")); + }) + .collect(Collectors.toList()); + + List excelFileList = HelperUtil.getExcelFile(fileList); + + boolean isHasOpeningAccountInfo = !pdfFileList.isEmpty(); + + for (File f : pdfFileList) { + // 删除pdf中的图片 + AsposeUtil.removeImages(f.getAbsolutePath()); + String excelFilename = AsposeUtil.pdf2ExcelV6(f.getAbsolutePath()); + excelFileList.add(new File(excelFilename)); + } + + for (File f : excelFileList) { + try{ + String absolutePath = f.getAbsolutePath(); + Workbook wb = new Workbook(absolutePath); + String sourceFile = HelperUtil.getSourceFileName(absolutePath,BANK_NAME); + Cells cells = wb.getWorksheets().get(0).getCells(); + Cell cell = AsposeUtil.getCell(cells, "原交易金额"); + + if(cell != null){ + readCGBCCreditCardData(f, isHasOpeningAccountInfo); + }else { + boolean hasDeal = readCGBCSavingsCardData(f); + if(!hasDeal){ + int count = wb.getWorksheets().getCount(); + for (int sheetNo = 0; sheetNo < count; sheetNo++) { + try { + Worksheet worksheet = wb.getWorksheets().get(sheetNo); + Cells worksheetCells = worksheet.getCells(); + String sheetName = worksheet.getName(); + String withname = sourceFile + BankStatementConstants.NAME_WITH_SHEET_NAME + sheetName; + Cell oaiCell1 = AsposeUtil.getCell(worksheetCells, "开卡日期"); + if(oaiCell1 != null){ + importService.readOAIData(absolutePath,oaiCell1.getRow() + 1, + sheetNo,caseId,BANK_NAME, withname); + }else { + throw new TemplateNotFindException(withname); + } + }catch (Exception e){ + importResultService.record(caseId,BANK_NAME,e); + } + } + + } + } + }catch (Exception e){ + importResultService.record(caseId,BANK_NAME,e); + } + } + } + /** + * 储蓄卡数据 + */ + private boolean readCGBCSavingsCardData(File excelFile) throws Exception { + boolean hasDeal = false; + // 有四种数据,所以有四种表头 + Workbook wb = new Workbook(excelFile.getAbsolutePath()); + WorksheetCollection worksheets = wb.getWorksheets(); + Cells cells = worksheets.get(0).getCells(); + String sourceFile = HelperUtil.getSourceFileName(excelFile.getAbsolutePath(),BANK_NAME); + + // 新核心对公客户资料 CGBCCompanyInfoEntity + Cell companyCell = cells.find(CGBCNewCompanyInfoEntity.KEY, null); + if (companyCell != null) { + int headRow = companyCell.getRow() + 2; + readCGBCEachData(excelFile, headRow, CGBCNewCompanyInfoEntity.class, esCGBCNewCompanyInfoMapper, sourceFile); + hasDeal = true; + } + // 新核心个人客户资料 CGBCCustomerInfoEntry + Cell customerCell = cells.find(CGBCNewCustomerInfoEntity.KEY, companyCell); + if (customerCell != null) { + int headRow = customerCell.getRow() + 2; + readCGBCEachData(excelFile, headRow, CGBCNewCustomerInfoEntity.class, esCGBCNewCustomerInfoMapper, sourceFile); + hasDeal = true; + } + // 新核心活期开户资料 CGBCCurrentAccountInfoEntry + Cell currentAccountInfoCell = cells.find(CGBCNewCurrentAccountInfoEntry.KEY, customerCell); + if (currentAccountInfoCell != null) { + int headRow = currentAccountInfoCell.getRow() + 2; + readCGBCEachData( + excelFile, headRow, CGBCNewCurrentAccountInfoEntry.class, esCGBCNewCurrentAccountInfoMapper, sourceFile); + hasDeal = true; + } + // 新核心定期开户资料 CGBCRegularAccountInfoEntry + Cell regularAccountInfoCell = cells.find(CGBCNewRegularAccountInfoEntry.KEY, currentAccountInfoCell); + if (regularAccountInfoCell != null) { + int headRow = regularAccountInfoCell.getRow() + 2; + readCGBCEachData( + excelFile, headRow, CGBCNewRegularAccountInfoEntry.class, esCGBCNewRegularAccountInfoMapper, sourceFile); + hasDeal = true; + } + // 旧核心开户资料 CGBCAccountInfoEntry + Cell oldCoreAccountInfoCell = cells.find(CGBCOldAccountInfoEntity.KEY, regularAccountInfoCell); + if (oldCoreAccountInfoCell != null) { + int headRow = oldCoreAccountInfoCell.getRow() + 2; + readCGBCEachData(excelFile, headRow, CGBCOldAccountInfoEntity.class, esCGBCOldAccountInfoMapper, sourceFile); + hasDeal = true; + } + + //主附卡标识 + // 读取流水数据,两种流水数据 + for (int sheetNo = 0; sheetNo < worksheets.getCount(); sheetNo++) { + // + Worksheet ws = worksheets.get(sheetNo); + if (ws.getName().contains("新核心交易流水")) { + readCGBCStatement(excelFile, sheetNo, CGBCNewStatementEntry.class, esCGBCNewStatementMapper,sourceFile); + hasDeal = true; + } else if (ws.getName().contains("旧核心交易流水")) { + readCGBCStatement(excelFile, sheetNo, CGBCStatementEntity.class, esCGBCStatementMapper,sourceFile); + hasDeal = true; + } + } + return hasDeal; + } + + + private void readCGBCStatement(File excelFile, int sheetNo, Class clazz, BaseEsMapper esMapper, String sourceFile) { + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .head(clazz) + .registerReadListener(getReadListenerV2(esMapper, clazz, sourceFile)) + .build(); + reader.read(sheet); + + + + } catch (Exception e) { + log.error("读取数据失败", e); + throw new ImportDataFailedException(e.getMessage(), excelFile.getAbsolutePath()); + } + } + + private void readCGBCEachData( + File excelFile, int headRowNumber, Class clazz, BaseEsMapper baseEsMapper, String sourceFile) { + + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + ReadSheet sheet = EasyExcel.readSheet(0) + .headRowNumber(headRowNumber) + .head(clazz) + .registerReadListener(getReadListenerV2(baseEsMapper, clazz, sourceFile)) + .build(); + reader.read(sheet); + + + } catch (Exception e) { + log.error("读取数据失败", e); + throw new ImportDataFailedException(e.getMessage(), excelFile.getAbsolutePath()); + } + } + + private static ReadListener getReadListenerV2(BaseEsMapper esMapper, Class clazz, String sourceFile) { + return new ReadListener() { + final int batchSize = Constants.BATCH_SIZE; + List docList = ListUtils.newArrayListWithExpectedSize(batchSize); + + @Override + public void invoke(T data, AnalysisContext context) { + + String str = JSONUtil.toJsonStr(data); + JSONObject obj = JSONUtil.parseObj(str); + String cardHolderName = obj.getStr("cardHolderName"); + if (StringUtils.isEmpty(cardHolderName)) { + doAfterAllAnalysed(context); // 否则无法保存已经读取的数据 + throw new ExcelAnalysisStopException(); + } + String id = IdUtil.objectId(); + obj.put("id", id); + obj.put("sourceFile", sourceFile); + + + + docList.add(obj.toBean(clazz)); + + if (docList.size() >= batchSize) { + esMapper.insertBatch(docList); + docList = ListUtils.newArrayListWithExpectedSize(batchSize); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!docList.isEmpty()) { + esMapper.insertBatch(docList); + } + } + }; + } + + /** + * 广发银行信用卡数据 + */ + private void readCGBCCreditCardData(File excelFile, boolean isHasOpeningAccountInfo) throws Exception { + + if (isHasOpeningAccountInfo) { // PDF中有信用卡流水 + readCGBCCreditCardOtherBS(excelFile); + } else { + Cell cell = AsposeUtil.getCell(excelFile, 0, "交易"); + if (cell == null) { + readCGBCCreditCardOpeningInfo(excelFile); + } else { + // 这种方式只有流水 + readCGBCCreditCardStatement(excelFile); + } + } + } + + private void readCGBCCreditCardOtherBS(File excelFile) throws Exception { + Workbook wb = new Workbook(excelFile.getAbsolutePath()); + int count = wb.getWorksheets().getCount(); + + for (int sheetNo = 0; sheetNo < count; sheetNo++) { + readCreditCardBS(excelFile, sheetNo); + } + } + + private void readCreditCardBS(File excelFile, int sheetNo) { + // 从文件名获取用户名 + // 然后查找 + String cardHolderName = ""; + Integer headRowNumber = null; + + //todo + Cell cell = AsposeUtil.getCell(excelFile, sheetNo, "当期账单周期"); + if (cell != null) { + Workbook wb = null; + try { + wb = new Workbook(excelFile.getAbsolutePath()); + } catch (Exception e) { + e.printStackTrace(); + } + Worksheet ws = wb.getWorksheets().get(sheetNo); + + cardHolderName = ws.getCells() + .get(cell.getRow() -2, 0) + .getStringValue(); + if(StrUtil.isNotEmpty(cardHolderName) && cardHolderName.length() > 4){ + //取3456行 比较谁最短 + for(int rowIndex = 2; rowIndex < 7;rowIndex++){ + cardHolderName = ws.getCells() + .get(rowIndex, 0) + .getStringValue(); + if(StrUtil.isNotEmpty(cardHolderName) && cardHolderName.length() < 5){ + break; + } + } + } + } else { + return; + } + + // 交易日期 + cell = AsposeUtil.getCell(excelFile, sheetNo, "交易日期"); + if (cell != null) { + headRowNumber = cell.getRow() + 1; + } + + if (headRowNumber == null) { + return; + } + String sourceFile = HelperUtil.getSourceFileName(excelFile.getAbsolutePath(),BANK_NAME); + try (ExcelReader r = EasyExcel.read(excelFile).build()) { + ReadSheet rs = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNumber) + .head(CGBCCreditCardOtherStatementEntity.class) + .registerReadListener(getOtherReadListener(cardHolderName,sourceFile)) + .build(); + r.read(rs); + } catch (Exception e) { + log.error("read excel error", e); + throw new ImportDataFailedException(e.getMessage(), excelFile.getAbsolutePath()); + } + } + + private ReadListener getOtherReadListener(String cardHolderName,String sourceFile) { + return new ReadListener() { + + List cacheList = + ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + @Override + public void invoke(CGBCCreditCardOtherStatementEntity entity, AnalysisContext context) { + + entity.setId(IdUtil.objectId()); + + String transactionTime = entity.getTransactionTime(); + if (StrUtil.isNotEmpty(transactionTime)) { + if (HelperUtil.isContainsChinese(transactionTime) + || "2011/02/01".length() != transactionTime.length()) { + return; + } + } else { + return; + } + + String transactionAmount = entity.getTransactionAmount(); + if (StrUtil.isNotEmpty(transactionAmount) && transactionAmount.contains(",")) { + transactionAmount = transactionAmount.replaceAll(",", ""); + entity.setTransactionAmount(transactionAmount); + } + entity.setSourceFile(sourceFile); + entity.setCardHolderName(cardHolderName); + + cacheList.add(entity); + if (cacheList.size() >= Constants.BATCH_SIZE) { + save(); + } + } + + private void save() { + esCGBCCreditCardOtherStatementMapper.insertBatch(cacheList); + cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!cacheList.isEmpty()) { + save(); + } + } + }; + } + + /** + * 广发银行信用卡数据-流水 + */ + private void readCGBCCreditCardStatement(File excelFile) { + + Class clazz = CGBCCreditCardStatementEntry.class; + String sourceFile = HelperUtil.getSourceFileName(excelFile.getAbsolutePath(),BANK_NAME); + + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + ReadSheet sheet = EasyExcel.readSheet(0) + .head(clazz) + .registerReadListener(getReadListenerV2(esCGBCCreditCardStatementMapper, clazz, sourceFile)) + .build(); + reader.read(sheet); + + + } catch (Exception e) { + log.error("解析流水错误: {}", e.getMessage(), e); + throw new ImportDataFailedException(e.getMessage(), excelFile.getAbsolutePath()); + } + } + + /** + * 广发银行信用卡数据-开户 + */ + private void readCGBCCreditCardOpeningInfo(File excelFile) { + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + ReadSheet sheet = EasyExcel.readSheet(0) + .head(CGBCCreditCardAccountInfoEntry.class) + .registerReadListener( + new CGBCCreditCardOpeningAccountInfoReadListener(esCGBCCreditCardAccountInfoMapper)) + .build(); + reader.read(sheet); + } catch (Exception e) { + log.error("解析开户信息错误: {}", e.getMessage(), e); + throw new ImportDataFailedException(e.getMessage(), excelFile.getAbsolutePath()); + } + } + + +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CGSAnalysisHelper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CGSAnalysisHelper.java new file mode 100644 index 0000000..8b0acf6 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CGSAnalysisHelper.java @@ -0,0 +1,472 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.util.ListUtils; +import com.aspose.cells.Cell; +import com.aspose.cells.Cells; +import com.aspose.cells.Workbook; +import com.aspose.cells.Worksheet; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; + +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.common.constant.BankStatementConstants; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.exception.dc.AnalyzeDataFailedException; +import com.inscloudtech.common.exception.dc.ImportDataFailedException; +import com.inscloudtech.common.exception.dc.TemplateNotFindException; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.common.utils.file.FileUtils; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.mapper.es.CGSOpeningAccountInfoMapper; +import com.inscloudtech.datacenter.mapper.es.CGSStatementMapper; +import com.inscloudtech.datacenter.mapper.es.ESOpeningAccountInfoMapper; +import com.inscloudtech.datacenter.service.ImportResultService; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CGSBankStatement; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CGSOpenAccountInfo; + +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 央地系统数据分析 + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class CGSAnalysisHelper { + + + + private final CGSStatementMapper cgsStatementMapper; + private final CGSOpeningAccountInfoMapper cgsOpeningAccountInfoMapper; + private final ESOpeningAccountInfoMapper esOpeningAccountInfoMapper; + private final static String format = "yyyyMMddHHmmss"; + private final static String BANK_NAME = "央地系统"; + private final ImportResultService importResultService; + + public void importData(File file,String caseId) throws Exception { + List fileList = FileUtil.loopFiles(file); + + List excelFileList = HelperUtil.getExcelFile(fileList); + + + for (File excelFile : excelFileList) { + try { + String excelFileName = excelFile.getAbsolutePath(); + if(excelFileName.contains("金融理财")){ + continue; + } + String bankName = ""; + + if(excelFileName.contains("_")){ + int count = countString(excelFileName, "_"); + String[] arr = excelFileName.split("_"); + bankName = arr[1]; + if(count == 5){ + bankName = arr[2]; + } + } + Workbook wb = new Workbook(excelFileName); + List baseInfoList = new ArrayList<>(); + String sourceFile = HelperUtil.getSourceFileName(excelFileName,BANK_NAME); + + for (int sheetNo = 0; sheetNo < wb.getWorksheets().getCount(); sheetNo++) { + try { + Worksheet worksheet = wb.getWorksheets().get(sheetNo); + String worksheetName = worksheet.getName(); + if(worksheetName.equals("交易流水信息")){ + saveBS(wb,sheetNo,excelFileName,bankName); + } else if(worksheetName.equals("客户基本信息")){ + getBaseInfo(wb,sheetNo,excelFileName,baseInfoList); + } else if(worksheetName.equals("账户基本信息")){ + saveOpenInfo(wb,sheetNo,excelFileName,baseInfoList,bankName); + }else { + throw new TemplateNotFindException(sourceFile + BankStatementConstants.NAME_WITH_SHEET_NAME+ worksheetName); + } + }catch (Exception e){ + importResultService.record(caseId,BANK_NAME,e); + } + } + }catch (Exception e){ + importResultService.record(caseId,BANK_NAME,e); + } + } + } + + public static int countString(String str,String s) { + int count = 0,len = str.length(); + while(str.indexOf(s) != -1) { + str = str.substring(str.indexOf(s) + 1,str.length()); + count++; + } +// System.out.println("此字符串有" + count + "个" + s); + return count; + } + + void getBaseInfo(Workbook wb,int sheetNo, String excelFileName,List baseInfoList){ + Cells cells = wb.getWorksheets().get(sheetNo).getCells(); + Cell cell = AsposeUtil.getCell(cells, "客户名称"); + if (cell == null) { + return; + } + + int headRowNum = cell.getRow() + 1; + + try (ExcelReader reader = EasyExcel.read(excelFileName).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNum) + .head(CGSOpenAccountInfo.class) + .registerReadListener(getOAIReadListener(baseInfoList)) + .build(); + reader.read(sheet); + + + } catch (Exception e) { + log.error("读取央地系统数据失败", e); + throw new ImportDataFailedException(e.getMessage(), excelFileName); + } + } + + void saveOpenInfo(Workbook wb,int sheetNo, String excelFileName,List baseInfoList,String bankName){ + Cells cells = wb.getWorksheets().get(sheetNo).getCells(); + Cell cell = AsposeUtil.getCell(cells, "卡号"); + if (cell == null) { + return; + } + + int headRowNum = cell.getRow() + 1; + List accountBaseInfoList = new ArrayList<>(); + try (ExcelReader reader = EasyExcel.read(excelFileName).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNum) + .head(CGSOpenAccountInfo.class) + .registerReadListener(getOAIReadListener(accountBaseInfoList)) + .build(); + reader.read(sheet); + + + List saveList = new ArrayList<>(); + for (CGSOpenAccountInfo accountBaseInfo : accountBaseInfoList) { + CGSOpenAccountInfo accountInfo = new CGSOpenAccountInfo(); + String cardNumber = accountBaseInfo.getCardNumber(); + if(StrUtil.isEmpty(cardNumber)){ + if(StrUtil.isEmpty(accountBaseInfo.getAccountNo())){ + continue; + } + cardNumber = accountBaseInfo.getAccountNo(); + } + if(cardNumber.contains("_")){ + String[] temArr = cardNumber.split("_"); + cardNumber = temArr[0]; + } + accountInfo.setCardNumber(cardNumber); + accountInfo.setStatus(accountBaseInfo.getStatus()); + accountInfo.setAccountOpeningInstitution(accountBaseInfo.getAccountOpeningInstitution()); + accountInfo.setOpeningAccountDate(accountBaseInfo.getOpeningAccountDate()); + accountInfo.setCloseDate(accountBaseInfo.getCloseDate()); + accountInfo.setId(IdUtil.objectId()); + //todo 可能有多个人 + for (CGSOpenAccountInfo baseInfo : baseInfoList) { + accountInfo.setIdType(baseInfo.getIdType()); + accountInfo.setIdCardNo(baseInfo.getIdCardNo()); + accountInfo.setCardHolderName(baseInfo.getCardHolderName()); + accountInfo.setPhone(baseInfo.getPhone()); + accountInfo.setAddress(baseInfo.getAddress()); + accountInfo.setBankName(BANK_NAME); + } + if(accountInfo.getCardHolderName() == null){ + excelFileName.length(); + } + saveList.add(accountInfo); + } + cgsOpeningAccountInfoMapper.insertBatch(saveList); + } catch (Exception e) { + log.error("读取央地系统数据失败", e); + throw new ImportDataFailedException(e.getMessage(), excelFileName); + } + } + + void saveBS(Workbook wb,int sheetNo, String excelFileName,String bankName){ + Cells cells = wb.getWorksheets().get(sheetNo).getCells(); + Cell cell = AsposeUtil.getCell(cells, "交易时间"); + if (cell == null) { + return; + } + + int headRowNum = cell.getRow() + 1; + List bsList = new ArrayList<>(); + try (ExcelReader reader = EasyExcel.read(excelFileName).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNum) + .head(CGSBankStatement.class) + .registerReadListener(getBSReadListener(bsList,bankName)) + .build(); + reader.read(sheet); + + + } catch (Exception e) { + log.error("读取央地系统数据失败", e); + throw new ImportDataFailedException(e.getMessage(), excelFileName); + } + } + + + private ReadListener getOAIReadListener(List accountInfoList) { + return new ReadListener() { + @Override + public void invoke(CGSOpenAccountInfo data, AnalysisContext context) { + accountInfoList.add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + + } + }; + } + + private ReadListener getBSReadListener(List bsList,String bankName) { + return new ReadListener() { + @Override + public void invoke(CGSBankStatement data, AnalysisContext context) { + if(StrUtil.isEmpty(data.getCardNumber())){ + return; + } + String transTime = data.getTransTime(); + try { + if(StrUtil.isNotEmpty(transTime)){ + if (transTime.length() > format.length()) { + transTime = transTime.substring(0, format.length()); + }else if (transTime.length() < format.length()){ + transTime += "000000"; + data.setTransTime(transTime); + } + DateUtil.parse(transTime, format); + }else { + throw new AnalyzeDataFailedException( + String.format("解析交易时间错误,无法将【%s】格式化为【%s】", transTime, format), new Exception()); + } + + } catch (Exception e) { + + log.error("解析交易时间异常: {}", e.getMessage(), e); + throw new AnalyzeDataFailedException( + String.format("解析交易时间错误,无法将【%s】格式化为【%s】", transTime, format), e); + } + data.setBankName(BANK_NAME); + data.setId(IdUtil.objectId()); + bsList.add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!bsList.isEmpty()) { + cgsStatementMapper.insertBatch(bsList); + bsList.clear(); + } + } + }; + } + + + public void analyzeData(String caseId) { + // 开户信息 + analyzeOAI(caseId); + // 流水信息 + analyzeBS(caseId); + } + + private void analyzeOAI(String caseId) { + List oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + List entityList = HelperUtil.getEntityList(cgsOpeningAccountInfoMapper, CGSOpenAccountInfo.class); + Map> groupByCard = entityList.stream().filter(item ->StrUtil.isNotEmpty(item.getCardNumber())).collect(Collectors.groupingBy(CGSOpenAccountInfo::getCardNumber)); + Set uniqueKeySet = new HashSet(); + + for (String card : groupByCard.keySet()) { + CGSOpenAccountInfo entity = groupByCard.get(card).get(0); + OpeningAccountInfo oai = getOpeningAccountInfo(entity.getBankName(), entity); + + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + oaiList.add(oai); + if (oaiList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + if (!oaiList.isEmpty()) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + } + } + + private static OpeningAccountInfo getOpeningAccountInfo(String bankName, CGSOpenAccountInfo entity) { + OpeningAccountInfo oai = new OpeningAccountInfo(); + oai.setBankName(BANK_NAME); + + String cardNumber = entity.getCardNumber(); + oai.setAccountNumber(cardNumber); + oai.setIdNo(entity.getIdCardNo()); + + oai.setName(entity.getCardHolderName()); + + oai.setPhone(entity.getPhone()); + oai.setAddress(entity.getAddress()); + oai.setOpeningAccountDate(entity.getOpeningAccountDate()); + oai.setClosingDate(entity.getCloseDate()); + oai.setStatus(entity.getStatus()); + oai.setAccountOpeningInstitution(entity.getAccountOpeningInstitution()); +// oai.setBalance(entity.getBalance()); + return oai; + } + + private void analyzeBS(String caseId) { + List bsList = new ArrayList<>(); + int batchSize = 1000; + + List oaiList = HelperUtil.getEntityListV2(esOpeningAccountInfoMapper, OpeningAccountInfo.class, caseId); + + Map> groupByCardNumber = oaiList.stream().filter(oai -> StrUtil.isNotEmpty(oai.getAccountNumber())).collect(Collectors.groupingBy(OpeningAccountInfo::getAccountNumber)); + + List cgsBankStatementList = HelperUtil.getEntityList(cgsStatementMapper, CGSBankStatement.class); + + //去重 + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + + for (CGSBankStatement entity : cgsBankStatementList) { + String sourceFile = entity.getSourceFile(); + try { + // 流水 + String cardNumber = entity.getCardNumber(); + if(StrUtil.isEmpty(cardNumber)){ + continue; + } + + BankStatement bs = new BankStatement(); + bs.setBankName(entity.getBankName()); + if (groupByCardNumber.containsKey(cardNumber)) { + List abcCustomerInfoEntities = groupByCardNumber.get(cardNumber); + OpeningAccountInfo oai = abcCustomerInfoEntities.get(0); + bs.setIdCardNo(oai.getIdNo()); + bs.setCardHolderName(oai.getName()); + bs.setPhone(oai.getPhone()); + } + bs.setCardNumber(cardNumber); + // 4 交易时间 + String transTime = entity.getTransTime(); + + if (StringUtils.isNotEmpty(transTime)) { + bs.setTransactionTime(DateUtil.parse(transTime, format)); + } + + // 2交易金额 + // 借贷标记来计算 + // 进,出 + String creditMark = entity.getCreditMark(); + if (StrUtil.isNotEmpty(creditMark)) { + BigDecimal transactionAmount = NumberUtil.toBigDecimal(entity.getTransactionAmount()); + if (creditMark.equalsIgnoreCase("进")) { + bs.setTransactionAmount(transactionAmount); + } else { + bs.setTransactionAmount(BigDecimal.ZERO.subtract(transactionAmount)); + } + } else { // 没有借贷标志,说明交易金额是零 + bs.setTransactionAmount(BigDecimal.ZERO); + } + + // 3 余额 + bs.setBalance(entity.getBalance()); + + //去重 + String uniqueKey = bs.getCardHolderName()+bs.getIdCardNo()+bs.getCardNumber()+bs.getTransactionTime()+bs.getTransactionAmount()+ + bs.getBalance(); + if (uniqueKeySet.contains(uniqueKey)) { + continue; + } + uniqueKeySet.add(uniqueKey); + + + // 1 货币类型 + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + + + + bs.setCounterpartyName(entity.getCounterpartyName()); + bs.setCounterpartyBankName(entity.getCounterpartyBankName()); + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + bs.setTransactionInstitutions(entity.getTransactionSituation()); + bs.setSummary(entity.getTransSummary()); + bs.setTransRemark(entity.getTransRemark()); + bs.setTransChannel(entity.getTransChannel()); + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entity.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= batchSize) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + + bsList = ListUtils.newArrayListWithExpectedSize(batchSize); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e,sourceFile); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + + // 保存数据库 + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + + } + + +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CIBDataAnalysisHelper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CIBDataAnalysisHelper.java new file mode 100644 index 0000000..32bfc2b --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CIBDataAnalysisHelper.java @@ -0,0 +1,734 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.exception.ExcelAnalysisStopException; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.util.ListUtils; +import com.aspose.cells.*; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; + +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.bankStatementAnalysis.service.ImportService; +import com.inscloudtech.common.constant.BankStatementConstants; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.exception.dc.AnalyzeDataFailedException; +import com.inscloudtech.common.exception.dc.ImportDataFailedException; +import com.inscloudtech.common.exception.dc.TemplateNotFindException; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.mapper.es.EsCIBCreditCardBankStatementMapper; +import com.inscloudtech.datacenter.mapper.es.EsCIBOpeningAccountInfoMapper; +import com.inscloudtech.datacenter.mapper.es.EsCIBStatementMapper; +import com.inscloudtech.datacenter.service.ImportResultService; +import com.inscloudtech.bankStatementAnalysis.listener.ReadCIBOpeningAccountInfoListener; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CIBCreditCardBSEntity; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CIBOpeningAccountInfoEntity; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CIBStatementEntity; + +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.easyes.core.core.BaseEsMapper; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.math.BigDecimal; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 兴业银行数据分析 + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class CIBDataAnalysisHelper { + + private final ImportResultService importResultService; + private final ImportService importService; + + private final EsCIBOpeningAccountInfoMapper esCIBOpeningAccountInfoMapper; + private final EsCIBCreditCardBankStatementMapper esCIBCreditCardBankStatementMapper; + private final EsCIBStatementMapper esCIBStatementMapper; + private final static String BANK_NAME = "兴业银行"; + + public void importData(File zipFile,String caseId){ + + List fileList = FileUtil.loopFiles(zipFile); + + if (fileList.isEmpty()) { + return; + } + // 分为储蓄卡流水和信用卡流水 + // 有些有开户信息 + // 有开户信息,有账号为储蓄卡,没有账户为信用卡 + List excelFileList = HelperUtil.getExcelFile(fileList); + + for (File excelFile : excelFileList) { + try { + String absolutePath = excelFile.getAbsolutePath(); + String sourceFile = HelperUtil.getSourceFileName(absolutePath,BANK_NAME); + Workbook wb = new Workbook(absolutePath); + for (int sheetNo = 0; sheetNo < wb.getWorksheets().getCount(); sheetNo++) { + try { + Worksheet worksheet = wb.getWorksheets().get(sheetNo); + Cells cells = worksheet.getCells(); + Cell cardHolderNameCell = cells.get(0, 0); + if(null == cardHolderNameCell.getValue()){ + //空的sheet + continue; + } + + Cell cell = AsposeUtil.getCell(cells, "开户日期"); + String sourceFileWithSheetName = sourceFile+ BankStatementConstants.NAME_WITH_SHEET_NAME+worksheet.getName(); + Cell tradeCell = AsposeUtil.getCell(cells, "交易日期");//这种类似csv格式 + Cell flagCell = AsposeUtil.getCell(cells, "最低金额");//这种类似csv格式 + if (cell != null) { + readOpeningAccountInfo(excelFile, sheetNo,caseId); + } else if(flagCell != null && tradeCell != null){ + // readBSWithLikeCSV(cells, caseId,sourceFileWithSheetName,tradeCell.getRow() + 1); + throw new TemplateNotFindException(sourceFileWithSheetName); + }else { + Cell c = AsposeUtil.getCell(cells, "信用卡历史账单"); + if (tradeCell != null && c == null) { + ExcelReader reader = EasyExcel.read(excelFile).build(); + Class clazz = CIBStatementEntity.class; + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(1) + .head(clazz) + .registerReadListener(getReadListener(esCIBStatementMapper,caseId,sourceFile)) + .build(); + reader.read(sheet); + }else if(c != null){ + readCreditCardBS(cells,sourceFileWithSheetName,caseId,sheetNo,excelFile); + }else { + throw new TemplateNotFindException(sourceFileWithSheetName); + } + } + }catch (Exception e){ + importResultService.record(caseId,BANK_NAME,e); + } + } + }catch (Exception e){ + importResultService.record(caseId,BANK_NAME,e); + } + } + } + + private void readBSWithLikeCSV(Cells cells, String caseId,String sourceFile,int headRow) { + try { + Cell cardHolderNameCell = cells.get(0, 0); + Object cardHolderNameObj = cardHolderNameCell.getValue(); + String cardHolderName = ""; + if(cardHolderNameObj != null){ + cardHolderName = cardHolderNameObj.toString(); + } + + if (StringUtils.isEmpty(cardHolderName)) { + throw new ImportDataFailedException("客户名称为空",sourceFile); + } + + if(cardHolderName.contains("客户名称:")){ + cardHolderName = cardHolderName.split("客户名称:")[1]; + } + + Cell cardNumberCell = cells.get(0, 0); + Object cardNumberCellObj = cardNumberCell.getValue(); + String cardNumber = ""; + if(cardNumberCellObj != null){ + cardNumber = cardNumberCellObj.toString(); + } + + if (StringUtils.isEmpty(cardNumber)) { + throw new ImportDataFailedException("账户代号为空",sourceFile); + } + + if(cardNumber.contains("账户代号:")){ + cardNumber = cardNumber.split("账户代号:")[1]; + } + List cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + int dataRow = cells.getMaxRow() - 2; + for (int row = headRow; headRow < dataRow ; row++){ + Cell dataCell = cells.get(row, 0); + Object valueObj = dataCell.getValue(); + if(valueObj == null){ + continue; + } + String dataStr = valueObj.toString(); + String[] dataArr = dataStr.split(" "); + List itemList = Arrays.stream(dataArr).filter(s1 -> StrUtil.isNotEmpty(s1)).collect(Collectors.toList()); + // if(itemList.size() < 8){ +// return; +// } + CIBStatementEntity entity = new CIBStatementEntity(); + entity.setCardNumber(cardNumber); + entity.setCardHolderName(cardHolderName); + entity.setCaseId(caseId); + + cacheList.add(entity); + if (cacheList.size() >= Constants.BATCH_SIZE) { + insertBatchCIBStatementEntity(cacheList); + cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + if(CollectionUtil.isNotEmpty(cacheList)){ + insertBatchCIBStatementEntity(cacheList); + } + + }catch (Exception e){ + throw new ImportDataFailedException(e.getMessage(), sourceFile); + } + } + + private void insertBatchCIBStatementEntity(List cacheList) { + esCIBStatementMapper.insertBatch(cacheList); + } + + + public void analyzeData(String caseId) { + // 分析开户信息 + analyzeOAI(caseId); + // 分析流水 + analyzeBS(caseId); + } + + + private void analyzeOAI(String caseId) { + + List oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(esCIBOpeningAccountInfoMapper, CIBOpeningAccountInfoEntity.class); + Set uniqueKeySet = new HashSet(); + + for (CIBOpeningAccountInfoEntity entity : entityList) { + + OpeningAccountInfo oai = new OpeningAccountInfo(); + oai.setName(entity.getCardHolderName()); + oai.setBankName(BANK_NAME); + oai.setAccountNumber(entity.getCardNumber()); + oai.setIdNo(entity.getIdCardNo()); + oai.setOpeningAccountDate(entity.getOpeningAccountDate()); + + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + oaiList.add(oai); + if (oaiList.size() >= Constants.BATCH_SIZE) { + // 保存数据库 + List dest = HelperUtil.getDest(oaiList); + + HelperUtil.batchSaveOAI2Es(dest, caseId); + + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + if (!oaiList.isEmpty()) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + } + } + + private void analyzeBS(String caseId) { + // 储蓄卡流水分析 + analyzeSavingCardBS(caseId); + // 信用卡流水分析 + analyzeCreditCardBS(caseId); + } + + private void analyzeCreditCardBS(String caseId) { + + // 信用卡流水 + List bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(esCIBCreditCardBankStatementMapper, CIBCreditCardBSEntity.class); + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + Map> oaiMap = importService.getOAIMap(caseId, BANK_NAME); + + for (CIBCreditCardBSEntity entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + + String cardHolderName = entity.getCardHolderName(); + bs.setCardHolderName(cardHolderName); + importService.setIdCardAndCardNumberByCardHolderName(oaiMap,cardHolderName,bs); + + bs.setSummary(entity.getSummary()); + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + bs.setTransactionAmount(BigDecimal.valueOf(Double.parseDouble(entity.getTransactionAmount()))); + bs.setTransactionTime(entity.getTransactionTime()); + bs.setBalance(new BigDecimal("0")); + bs.setRemark("信用卡"); + BeanUtils.beanAttributeValueTrim(bs); + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entity.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + }catch (Exception e){ + importResultService.record(caseId,BANK_NAME,e,sourceFile); + } + + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + + // 保存数据库 + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + private void analyzeSavingCardBS(String caseId) { + // 储蓄卡流水分析 + List bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = HelperUtil.getEntityList(esCIBStatementMapper, CIBStatementEntity.class); + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + Map> oaiMap = importService.getOAIMap(caseId, BANK_NAME); + for (CIBStatementEntity entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + bs.setCardHolderName(entity.getCardHolderName()); + importService.setIdCardAndCardNumberByCardHolderName(oaiMap,entity.getCardHolderName(),bs); + + bs.setCardNumber(entity.getCardNumber()); + bs.setCounterpartyName(entity.getCounterpartyName()); + bs.setCounterpartIdCardNo(null); + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + bs.setCounterpartyBankName(entity.getCounterpartyBankName()); + bs.setSummary(entity.getSummary()); + bs.setTransRemark(entity.getTransRemark()); + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + try { + // 交易金额 + String loanFlag = entity.getLoanFlag(); + if (StrUtil.isNotEmpty(loanFlag)) { + BigDecimal transAmount = NumberUtil.toBigDecimal(entity.getTransactionAmount()); + if (Objects.equals("0", loanFlag)) { + bs.setTransactionAmount(transAmount.negate()); + } else { + bs.setTransactionAmount(transAmount); + } + } + } catch (Exception e) { + throw new AnalyzeDataFailedException(StrUtil.format(BankStatementConstants.ANALYZE_TRANSACTION_AMOUNT_FAIL_TIPS, entity.getTransactionAmount()), e, sourceFile); + } + + + // 交易时间 + String transDate = entity.getTransDate(); + if (StrUtil.isNotEmpty(transDate)) { + + // 如果transDate的长度大于10,则截取 + if (transDate.length() > 10) { + transDate = transDate.substring(0, 10); + } + + String format; + // 如果包含吧-,则格式为yyyy-MM-dd HH:mm:ss + if (transDate.contains("-")) { + format = "yyyy-MM-dd"; + } else if (transDate.contains("/")) { + format = "yyyy/MM/dd"; + } else { + format = "yyyyMMdd"; + } + + String transTime = entity.getTransTime(); + if (StrUtil.isNotEmpty(transTime)) { + try { + // 如果包含: + if (transTime.contains(":")) { + format += " HH:mm:ss"; + } else { + transTime = transTime.substring(0, 6); + format += " HHmmss"; + } + + + bs.setTransactionTime(DateUtil.parse(transDate + " " + transTime, DateTimeFormatter.ofPattern(format))); + } catch (Exception e) { + log.error("解析日期失败,日期为:{}", transDate + " " + transTime); + throw new AnalyzeDataFailedException( + StrUtil.format("解析交易时间失败,日期为:{}", entity.getTransDate() + " " + entity.getTransTime()), e, sourceFile); + } + } else { + try { + bs.setTransactionTime(DateUtil.parse(transDate, "yyyy-MM-dd")); + } catch (Exception e) { + log.error("解析日期失败,日期为:{}", transDate); + throw new AnalyzeDataFailedException(StrUtil.format(BankStatementConstants.ANALYZE_TRANSACTION_DATE_FAIL_TIPS, entity.getTransDate()), e, sourceFile); + } + } + } + + try { + bs.setBalance(NumberUtil.toBigDecimal(entity.getBalance())); + } catch (Exception e) { + log.error("解析余额失败,余额为:{}", entity.getBalance()); + throw new AnalyzeDataFailedException(StrUtil.format(BankStatementConstants.ANALYZE_BALANCE_FAIL_TIPS, entity.getBalance()), e, sourceFile); + } + BeanUtils.beanAttributeValueTrim(bs); + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(sourceFile); + bs.setId(md5Id); + bs.setCaseId(caseId); + + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + }catch (Exception e){ + importResultService.record(caseId,BANK_NAME,e,sourceFile); + } + + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + // 保存数据库 + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + + + + /** + * 信用卡流水 + */ + private void readCreditCardBS(Cells cells,String sourceFile,String caseId,int sheetNo,File file) throws Exception { + Cell cell = cells.find("信用卡历史账单交易流水", null); + if (cell == null) { + return; + } + // 客户名称 + String cardHolderName = null; + + + Cell firstCell = cells.get(0, 0); + + Cell nameCell = cells.find("尊敬的", firstCell); + if (nameCell == null) { + return; + } + + String value = nameCell.getStringValue(); // 尊敬的xxx先生/女士: + int startIdx = value.indexOf("的"); + if (startIdx != -1) { + int endIdx = value.lastIndexOf("先"); + if (endIdx != -1) { + cardHolderName = value.substring(startIdx + 1, endIdx); + } + } + + if (StringUtils.isEmpty(cardHolderName)) { + throw new ImportDataFailedException("无法获取客户名称.",sourceFile); + } + + + List> entryList = obtainNecessaryData(file, sheetNo); + for (Map.Entry entry : entryList) { + Integer headRowNumber = entry.getKey(); + int[] limit = {entry.getValue()}; + + try (ExcelReader r = EasyExcel.read(file).build()) { + ReadSheet readSheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNumber) + .head(SimpleEntity.class) + .registerReadListener(getReadListener(cardHolderName, limit[0],caseId,sourceFile)) + .build(); + r.read(readSheet); + } catch (Exception e) { + + if (e instanceof ExcelAnalysisStopException) { + continue; + } + + log.error(e.getMessage(), e); + throw new ImportDataFailedException(e.getMessage(), sourceFile); + } + } + } + + /** + * 开户信息 + */ + private void readOpeningAccountInfo(File f, int sheetNo,String caseId) { + if (sheetNo == -1) { + return; + } + + try (ExcelReader reader = EasyExcel.read(f).build()) { + ReadSheet readSheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(1) + .head(CIBOpeningAccountInfoEntity.class) + .registerReadListener(new ReadCIBOpeningAccountInfoListener(esCIBOpeningAccountInfoMapper,caseId)) + .build(); + reader.read(readSheet); + } catch (Exception e) { + log.error(e.getMessage(), e); + throw new ImportDataFailedException(e.getMessage(), f.getAbsolutePath()); + } + } + + + private ReadListener csvRowEntityReadListener(String cardHolderName,String cardNumber, String caseId) { + return new ReadListener() { + + List cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + @Override + public void invoke(CsvRowEntity data, AnalysisContext context) { + System.out.println("data = " + data); + String v = data.v; +// +// String[] s = v.split(" "); +// List itemList = +// Arrays.stream(s).filter(s1 -> !"".equals(s1)).collect(Collectors.toList()); +// if(itemList.size() < 8){ +// return; +// } +// CIBStatementEntity entity = array2BankStatement(itemList); +// +// entity.setCardHolderName(cardHolderName); +// entity.setCaseId(caseId); +// cacheList.add(entity); +// if (cacheList.size() >= Constants.BATCH_SIZE) { +// save(); +// } + } + + private void save() { + esCIBStatementMapper.insertBatch(cacheList); + cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + + private CIBStatementEntity array2BankStatement(List items) { + // [20181029, 22:21, 20181030, RMB, 198.00, 财付通--广州唯品会电子商务有限公司, 主卡, 8103] + CIBStatementEntity entity = new CIBStatementEntity(); + entity.setId(IdUtil.objectId()); + entity.setTransactionAmount(items.get(4)); + entity.setSummary(items.get(5)); + + return entity; + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!cacheList.isEmpty()) { + save(); + } + } + }; + } + + + private ReadListener getReadListener(String cardHolderName, int limit, String caseId,String sourceFile) { + return new ReadListener() { + int cnt = 0; + List cache = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + @Override + public void invoke(SimpleEntity data, AnalysisContext context) { + + String v = data.v; + + String[] s = v.split(" "); + List itemList = Arrays.stream(s).filter(s1 -> !"".equals(s1)).collect(Collectors.toList()); + if(itemList.size() < 8){ + return; + } + CIBCreditCardBSEntity entity = array2CIBCreditBankStatement(itemList); + + entity.setCardHolderName(cardHolderName); + entity.setCaseId(caseId); + entity.setSourceFile(sourceFile); + cache.add(entity); + if (cache.size() >= Constants.BATCH_SIZE) { + save(); + } + + cnt++; + if (cnt >= limit) { + save(); + throw new ExcelAnalysisStopException("主动停止."); // 退出读的过程 + } + } + + private void save() { + esCIBCreditCardBankStatementMapper.insertBatch(cache); + cache = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + + private CIBCreditCardBSEntity array2CIBCreditBankStatement(List items) { + // [20181029, 22:21, 20181030, RMB, 198.00, 财付通--广州唯品会电子商务有限公司, 主卡, 8103] + CIBCreditCardBSEntity entity = new CIBCreditCardBSEntity(); + entity.setId(IdUtil.objectId()); + entity.setTransactionTime(DateUtil.parse(items.get(0) + " " + items.get(1), "yyyyMMdd HH:mm")); + entity.setTransactionAmount(items.get(4)); + entity.setSummary(items.get(5)); + + return entity; + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + // + if (!cache.isEmpty()) { + save(); + } + } + }; + } + + private static ReadListener getReadListener(BaseEsMapper esMapper,String caseId,String sourceFile) { + return new ReadListener() { + final int batchSize = Constants.BATCH_SIZE; + List cacheList = ListUtils.newArrayListWithExpectedSize(batchSize); + + @Override + public void invoke(CIBStatementEntity entity, AnalysisContext context) { + if(StrUtil.isEmpty(entity.getTransDate()) && StrUtil.isNotEmpty(entity.getTransactionAmount())){ + throw new RuntimeException("交易日期为空"); + }else if(StrUtil.isEmpty(entity.getTransDate()) && StrUtil.isEmpty(entity.getTransactionAmount())) { + return; + } + entity.setId(IdUtil.objectId()); + // 交易金额 + String transactionAmountStr = entity.getTransactionAmount(); + if (StrUtil.isNotEmpty(transactionAmountStr)) { + transactionAmountStr = transactionAmountStr.replaceAll(",", ""); + entity.setTransactionAmount(transactionAmountStr); + } + // 余额 + String balanceStr = entity.getBalance(); + if (StrUtil.isNotEmpty(balanceStr)) { + balanceStr = balanceStr.replaceAll(",", ""); + entity.setBalance(balanceStr); + } + entity.setSourceFile(sourceFile); + cacheList.add(entity); + + if (cacheList.size() >= batchSize) { + esMapper.insertBatch(cacheList); + cacheList = ListUtils.newArrayListWithExpectedSize(batchSize); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!cacheList.isEmpty()) { + esMapper.insertBatch(cacheList); + } + } + }; + } + + private List> obtainNecessaryData(File excelFile, int sheetNo) { + List> rst = new ArrayList<>(); + int headRowNumber = 0; + int flagRowNumber = 0; + for (; ; ) { + int rowNumber = AsposeUtil.getRowNumber(excelFile, sheetNo, "交易明细", headRowNumber); + if (rowNumber == -1) { + break; + } + + headRowNumber = rowNumber + 2; + + Cell ce = AsposeUtil.getCell(excelFile, sheetNo, "共计", flagRowNumber); + if (ce != null) { + // ********共计29条******** + String value = ce.getStringValue(); + int idx = value.lastIndexOf("计"); + if (idx != -1) { + int endIdx = value.lastIndexOf("条"); + if (endIdx != -1) { + String v = value.substring(idx + 1, endIdx); + int number = Integer.parseInt(v); + rst.add(new AbstractMap.SimpleEntry<>(headRowNumber, number)); + } + } + + flagRowNumber = ce.getRow(); + } else { + break; + } + } + + return rst; + } + + @Data + public static class SimpleEntity { + @ExcelProperty("交易日期 记账日期 交易金额 交易摘要 尾号4位") + private String v; + } + + @Data + public static class CsvRowEntity { + @ExcelProperty("交易日期 交易时间 柜员流水 币种 借/贷 现/转 被冲标志 交易金额 账户余额 交易对手名称 交易对手账号 交易对手行名 交易对手行号 摘要代号 用途 交易备注 渠道 交易代码 经办机构 记账日期") + private String v; + + @ExcelProperty("交易日期") + private String b; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CITICDataAnalysisHelper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CITICDataAnalysisHelper.java new file mode 100644 index 0000000..f55ec00 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CITICDataAnalysisHelper.java @@ -0,0 +1,701 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.exception.ExcelAnalysisStopException; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.util.ListUtils; +import com.aspose.cells.Cell; +import com.aspose.cells.Cells; +import com.aspose.cells.Workbook; +import com.aspose.cells.Worksheet; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; + +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.exception.dc.AnalyzeDataFailedException; +import com.inscloudtech.common.exception.dc.ImportDataFailedException; +import com.inscloudtech.common.exception.dc.TemplateNotFindException; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.converter.ExcelStringToJavaBigDecimalConverter; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.mapper.es.ESOpeningAccountInfoMapper; +import com.inscloudtech.datacenter.mapper.es.EsCITICBankStatementMapper; +import com.inscloudtech.datacenter.mapper.es.EsCITICOpeningAccountInfoMapper; +import com.inscloudtech.datacenter.service.ImportResultService; +import com.inscloudtech.bankStatementAnalysis.listener.CITICBankOpeningAccountInfoReadListener; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CITICBankStatementEntity; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CITICOpeningAccountInfoEntity; + +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 中信银行数据分析 + */ +@RequiredArgsConstructor +@Component +@Slf4j +public class CITICDataAnalysisHelper { + + private final ImportResultService importResultService; + private final EsCITICOpeningAccountInfoMapper esCITICOpeningAccountInfoMapper; + private final EsCITICBankStatementMapper esCITICBankStatementMapper; + + private final ESOpeningAccountInfoMapper esOAIMapper; + + private final static String BANK_NAME = "中信银行"; + private String caseId = ""; + + + public void analyzeData(String caseId) throws Exception { + // 开户信息分析 + analyzeOAI( caseId); + analyzeBS(caseId); + } + + public void importData(File file,String caseId) throws Exception { + this.caseId = caseId; + if (!file.exists()) { + return; + } + + List fileList = FileUtil.loopFiles(file); +// // pdf +// List pdfFileList = +// fileList.stream().filter(f -> f.getName().endsWith(".pdf")).collect(Collectors.toList()); +// + +// +// // pdf转化为Excel +// for (File f : pdfFileList) { +// try { +// String excelFilename = AsposeUtil.pdf2ExcelV6(f.getAbsolutePath()); +// excelFile.add(new File(excelFilename)); +// } catch (Exception e) { +// log.error("pdf文件转excel失败:" + e.getMessage(), e); +// throw new ImportDataFailedException("pdf文件转excel失败:" + f.getAbsolutePath()); +// } +// } + List excelFile = HelperUtil.getExcelFile(fileList); + for (File f : excelFile) { + try { + readDataFromExcel(Collections.singletonList(f.getAbsolutePath())); + }catch (Exception e){ + importResultService.record(caseId,BANK_NAME,e); + } + + } + } + + private void analyzeBS(String caseId) { + + List bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(esCITICBankStatementMapper, CITICBankStatementEntity.class); + + List oaiList = HelperUtil.getEntityListV2(esOAIMapper, OpeningAccountInfo.class, caseId); + + Map> groupByName = oaiList.stream().filter(item ->StrUtil.isNotEmpty(item.getName())) + .collect(Collectors.groupingBy(OpeningAccountInfo::getName)); + + Map> groupByAccountNumber = oaiList.stream().filter(item ->StrUtil.isNotEmpty(item.getAccountNumber())) + .collect(Collectors.groupingBy(OpeningAccountInfo::getAccountNumber)); + + Map> groupByIdCard = oaiList.stream().filter(item ->StrUtil.isNotEmpty(item.getIdNo())) + .collect(Collectors.groupingBy(OpeningAccountInfo::getIdNo)); + + Map nameCardNumberMap = new HashMap<>(); + + Map cardAndIdCardMap = new HashMap<>(); + + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + + for (CITICBankStatementEntity entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + + String cardNumber = entity.getCardNumber(); + bs.setCardNumber(cardNumber); + + String customerName = entity.getCustomerName(); + if(StrUtil.isEmpty(customerName)){//流水名字为空,通过卡号关联出名字 + if(groupByAccountNumber.containsKey(cardNumber)){ + List openingAccountInfos = groupByAccountNumber.get(cardNumber); + for (OpeningAccountInfo info : openingAccountInfos) { + if(StrUtil.isNotEmpty(info.getName())){ + customerName = info.getName(); + break; + } + } + } + } + + bs.setCardHolderName(customerName); + + if (StringUtils.isNotEmpty(cardNumber)) { + nameCardNumberMap.put(customerName, cardNumber); + if(groupByAccountNumber.containsKey(cardNumber)){ + List openingAccountInfos = groupByAccountNumber.get(cardNumber); + for (OpeningAccountInfo info : openingAccountInfos) { + if(StrUtil.isNotEmpty(info.getIdNo())){ + bs.setIdCardNo(info.getIdNo()); + break; + } + } + } + + // 开户信息中没有的卡号,根据姓名来查询 + // 姓名为空,则不处理 + if (StringUtils.isNotEmpty(customerName)) { + if(groupByName.containsKey(customerName)){ + List infoList = groupByName.get(customerName); + for (OpeningAccountInfo info : infoList) { + if(StrUtil.isNotEmpty(info.getIdNo())){ + bs.setIdCardNo(info.getIdNo()); + break; + } + } + } + } + } + if(StrUtil.isEmpty(bs.getIdCardNo()) && StrUtil.isNotEmpty(entity.getIdCardNo())){ + bs.setIdCardNo(entity.getIdCardNo()); + } + + if(StrUtil.isEmpty(bs.getCardHolderName()) && StrUtil.isNotEmpty(bs.getIdCardNo())){ + if(groupByIdCard.containsKey(bs.getIdCardNo())){ + List openingAccountInfos = groupByIdCard.get(bs.getIdCardNo()); + for (OpeningAccountInfo info : openingAccountInfos) { + if(StrUtil.isNotEmpty(info.getName())){ + bs.setCardHolderName(info.getName()); + break; + } + } + } + } + + + // 交易时间 + String transDate = entity.getTransDate(); + if (StrUtil.isNotEmpty(transDate)) { + // 三种情况,/ - 以及没有符号 + String format = null; + if (transDate.contains("/")) { + format = "yyyy/MM/dd"; + } else if (transDate.contains("-")) { + format = "yyyy-MM-dd"; + } else { + format = "yyyyMMdd"; + } + + + String transTime = entity.getTransTime(); + if (StrUtil.isNotEmpty(transTime)) { + // 两种情况,一种是包含冒号,一种没有 + if (transTime.contains(":")) { + format = format + " HH:mm:ss"; + } else { + format = format + " HHmmss"; + } + + // 如果不足六位,则补足 + if (transTime.length() < Constants.TIME_FULL_FORMAT_LENGTH) { + + int cnt = Constants.TIME_FULL_FORMAT_LENGTH - transTime.length(); + StringBuilder transTimeBuilder = new StringBuilder(transTime); + + for (int i = 0; i < cnt; i++) { + transTimeBuilder.insert(0, "0"); + } + + transTime = String.valueOf(transTimeBuilder); + } + + try { + bs.setTransactionTime(DateUtil.parse(transDate + " " + transTime, format)); + } catch (Exception e) { + throw new AnalyzeDataFailedException( + StrUtil.format("解析交易时间异常[{}]", entity.getTransDate() + " " + entity.getTransTime()), e, entity.getSourceFile()); + } + } else { + try { + bs.setTransactionTime(DateUtil.parse(transDate, format)); + } catch (Exception e) { + throw new AnalyzeDataFailedException(StrUtil.format("解析交易时间异常[{}]", entity.getTransDate()+ " " + entity.getTransTime()), e,entity.getSourceFile()); + } + } + } + // 交易金额 + // 需要根据借贷标记来计算 + // c+ d- + String creditMark = entity.getCreditMark(); + if (StrUtil.isNotEmpty(creditMark)) { + BigDecimal transactionAmount = NumberUtil.toBigDecimal(entity.getTransactionAmount()); + if (creditMark.toLowerCase().contains("c")) { + bs.setTransactionAmount(transactionAmount); + } else { + bs.setTransactionAmount(BigDecimal.ZERO.subtract(transactionAmount)); + } + } else if (entity.getCreditCard()){ // 没有借贷标志,说明交易金额是零 + bs.setTransactionAmount(NumberUtil.toBigDecimal(entity.getTransactionAmount())); + }else { + bs.setTransactionAmount(BigDecimal.ZERO); + } + // 余额 + bs.setBalance(NumberUtil.toBigDecimal(entity.getBalance())); + + // 交易对手 + String counterpartName = entity.getCounterpartyName(); + bs.setCounterpartyName(counterpartName); + // 交易币种 + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + bs.setCounterpartyBankName(entity.getCounterpartyBankName()); + + bs.setSummary(entity.getSummary()); + bs.setTransRemark(entity.getTransRemark()); + bs.setTransChannel(entity.getTransChannel()); + cardAndIdCardMap.put(bs.getCardNumber(),bs.getIdCardNo()); + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entity.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= Constants.BATCH_SIZE) { + bsList = handleCardNumber(bsList, nameCardNumberMap); + // 批量保存 + // 保存数据库 + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e,sourceFile); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + + if (!bsList.isEmpty()) { + //注释原因该方法导致某些流水姓名字段为空 +// bsList = handleCardNumber(bsList, nameCardNumberMap); + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + /** + * 为什么再次 if (StrUtil.isNotEmpty(cardNumber)) { bs.setCardNumber(no); + * @param bsList + * @param nameCardNumberMap + * @return + */ + private List handleCardNumber(List bsList, Map nameCardNumberMap) { + return bsList.stream() + .peek(bs -> { + String cardNumber = bs.getCardNumber(); + if (StrUtil.isNotEmpty(cardNumber)) { + String cardHolderName = bs.getCardHolderName(); + if (StrUtil.isNotEmpty(cardHolderName)) { + String no = nameCardNumberMap.getOrDefault(cardHolderName, null); + if (StrUtil.isNotEmpty(no)) { + bs.setCardNumber(no); + } + } + } + }) + .collect(Collectors.toList()); + } + + private void analyzeOAI( String caseId) { + List oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + // ES中有开户信息 + List entityList = + HelperUtil.getEntityList(esCITICOpeningAccountInfoMapper, CITICOpeningAccountInfoEntity.class); + Set uniqueKeySet = new HashSet(); + for (CITICOpeningAccountInfoEntity entity : entityList) { + + if (StringUtils.isEmpty(entity.getCardHolderName())) { + continue; + } + + OpeningAccountInfo oai = new OpeningAccountInfo(); + oai.setName(entity.getCardHolderName()); + oai.setBankName(BANK_NAME); + oai.setIdType(entity.getIdType()); + oai.setIdNo(entity.getIdCardNo()); + oai.setPhone(entity.getPhone()); + oai.setAddress(entity.getAddress()); + String accountNumber = StrUtil.isEmpty(entity.getAccountNumberItem())?entity.getAccountNumber():entity.getAccountNumberItem(); + oai.setAccountNumber(accountNumber); + oai.setStatus(entity.getStatus()); + oai.setOpeningAccountDate(entity.getOpeningAccountDate()); + oai.setBalance(entity.getBalance()); + + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + oaiList.add(oai); + if (oaiList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + } + } + + if (!oaiList.isEmpty()) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + } + } + + private void readDataFromExcel(List excelFileList) throws Exception { + for (String filename : excelFileList) { + // 读取文件来确认是开户信息,还是流水信息 + // 这种方式是有漏洞的,一个文件,既可能包含开户信息,也可能包含流水信心 + Workbook wb = new Workbook(filename); + for (int sheetNo = 0; sheetNo < wb.getWorksheets().getCount(); sheetNo++) { + try { + Cells cells = wb.getWorksheets().get(sheetNo).getCells(); + String sourceFile = HelperUtil.getSourceFileName(filename,BANK_NAME); + File file = new File(filename); + Cell creditCardDateCell = AsposeUtil.getCell(cells, "入账日期"); + Cell tradeCell = AsposeUtil.getCell(cells, "交易日期"); + if (AsposeUtil.getCell(cells, "开户日期") != null) { + if((AsposeUtil.getCell(cells, "地址") != null + && !Objects.equals( + Objects.requireNonNull(AsposeUtil.getCell(cells, "地址")) + .getStringValue(), + "IP地址"))){ + // 解析开户信息 + readOAI(file, cells, sheetNo); + }else { + try (ExcelReader excelReader = EasyExcel.read(file).build()) { + ReadSheet readSheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(1) + .head(CITICOpeningAccountInfoEntity.class) + .registerReadListener(new CITICBankOpeningAccountInfoReadListener( + esCITICOpeningAccountInfoMapper, null)) + .build(); + excelReader.read(readSheet); + } catch (Exception e) { + log.error("解析Excel文件失败.", e); + throw new ImportDataFailedException(e.getMessage(), sourceFile); + } + } + } else if (tradeCell != null) { + if(AsposeUtil.getCell(cells, "交易时间") != null){ + readBSV4(wb, file, cells, sheetNo); + }else { + /**20240428新流水模板*/ + readCreditCard(filename,sheetNo,tradeCell); + } + }else if(creditCardDateCell != null){ + /**20240418新信用卡流水模板*/ + readCreditCard(filename,sheetNo,creditCardDateCell); + }else { +// throw new ImportDataFailedException("文件无对应模板", sourceFile); + } + }catch (Exception e){ + importResultService.record(caseId,BANK_NAME,e); + } + } + } + } + + public ReadListener creditCardReadListener(String sourceFile) { + return new ReadListener() { + + List cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + @Override + public void invoke(CITICBankStatementEntity entity, AnalysisContext context) { + entity.setId(IdUtil.objectId()); + entity.setSourceFile(sourceFile); + entity.setCreditCard(true); + entity.setBalance("0.0"); + cacheList.add(entity); + if (cacheList.size() >= Constants.BATCH_SIZE) { + saveData2Es(); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!cacheList.isEmpty()) { + saveData2Es(); + } + } + + private void saveData2Es() { + esCITICBankStatementMapper.insertBatch(cacheList); + cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + }; + } + + private void readCreditCard(String excelFileName,int sheetNum,Cell creditCardDateCell) { + String sourceFile = HelperUtil.getSourceFileName(excelFileName,BANK_NAME); + int headRowNumber = creditCardDateCell.getRow() + 1; + try (ExcelReader reader = EasyExcel.read(excelFileName).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNum) + .head(CITICBankStatementEntity.class) + .headRowNumber(headRowNumber) + .registerReadListener(creditCardReadListener(sourceFile)) + .build(); + reader.read(sheet); + } catch (Exception e) { +// log.error("读取私人银行流水出错:{}", e.getMessage(), e); + throw new ImportDataFailedException( + StrUtil.format("读取私人银行流水出错, 请检查文件【{}秒】是否正确。", excelFileName), excelFileName); + } + } + + + private void readBSV4(Workbook wb, File excelFile, Cells cells, int sheetNo) throws Exception { + // 表头 + List headerCellList = AsposeUtil.find(cells, "交易日期"); + for (Cell headerCell : headerCellList) { + int headerRowNum = headerCell.getRow() + 1; + + boolean modified = fixWorksheetAndReadExcelFile(wb, cells, excelFile, headerCell, headerRowNum, sheetNo); + if (modified) { + wb = new Workbook(excelFile.getAbsolutePath()); + Worksheet worksheet = wb.getWorksheets().get(sheetNo); + cells = worksheet.getCells(); + } + } + } + + private boolean fixWorksheetAndReadExcelFile(Workbook wb, Cells cells, File excelFile, Cell headerCell, int headRowNum, int sheetNo) + throws Exception { + int customerInfoRow = headerCell.getRow() - 1; + boolean isModified = false; + // 需要分类 + // 先根据客户名来分,一种有客户名,一种没有客户名 + Cell customerNameCell = AsposeUtil.getCell(cells, "客户名", Math.max(customerInfoRow, 0)); + String pathname = excelFile.getAbsolutePath(); + String sourceFile = HelperUtil.getSourceFileName(pathname,BANK_NAME); + if (customerNameCell != null && customerNameCell.getRow() == customerInfoRow) { + // 有客户名的又分为两种, + // 一种是账号在外,一种是表内有客户账号 + Cell cell = AsposeUtil.getCell(cells, "账号", Math.max(customerInfoRow, 0)); + if (cell != null && cell.getRow() <= headRowNum - 1) { + + String customerName = null; + // 获取客户名 + String v = customerNameCell.getStringValue(); + if (StrUtil.isNotEmpty(v)) { + if (v.contains(":") || v.contains(":")) { + v = v.replace(":", ":"); + customerName = + v.substring(v.indexOf(":") + 1).trim(); + } else { + customerName = AsposeUtil.getNextCellValue(pathname, 0, customerNameCell); + } + } + + if (cell.getRow() < headRowNum - 1) { + // 一种,客户账号在表外 + String cardNumber = null; + + // 获取账号 + String value = cell.getStringValue(); + if (StrUtil.isNotEmpty(value)) { + if (value.contains(":") || value.contains(":")) { + value = value.replace(":", ":"); + cardNumber = value.substring(value.indexOf(":") + 1).trim(); + } else { + cardNumber = AsposeUtil.getNextCellValue(pathname, 0, cell); + } + } + + Cell c = AsposeUtil.getCell(cells, "客户名", headerCell.getRow() + 1); + + int endRowNum = -1; + + if (c != null) { + endRowNum = c.getRow(); + } else { + endRowNum = cells.getMaxRow(); + } + + if (StrUtil.isNotEmpty(cardNumber)) { + fix(wb, pathname, cells, headerCell, endRowNum, "客户账号", cardNumber); + isModified = true; + excelFile = new File(pathname); + } + + if (StrUtil.isNotEmpty(customerName)) { + fix(wb, pathname, cells, headerCell, endRowNum, "客户名称", customerName); + isModified = true; + excelFile = new File(pathname); + } + + readBSV5(pathname, headRowNum, endRowNum, sheetNo); + } else { + // 一种,客户账号在表内 + try { + // 分析 + Cell c = AsposeUtil.getCell(cells, "客户名", headerCell.getRow() + 1); + int endRowNum = -1; + if (c != null) { + endRowNum = c.getRow(); + } else { + endRowNum = cells.getMaxRow(); + } + + if (StrUtil.isNotEmpty(customerName)) { + // 添加一列 + fix(wb, pathname, cells, headerCell, endRowNum, "客户名称", customerName); + isModified = true; + excelFile = new File(pathname);//?? + } + + readBSV5(pathname, headRowNum, endRowNum, sheetNo); + } catch (Exception e) { + log.error("解析Excel文件失败.", e); + throw new ImportDataFailedException(e.getMessage(), pathname); + } + } + } + } else { + if(customerNameCell == null){ + /**20240418新模板*/ + customerNameCell = AsposeUtil.getCell(cells, "客户名", Math.max(customerInfoRow - 1, 0)); + if(customerNameCell != null){ + fix(wb, pathname, cells, headerCell, cells.getMaxRow(), "客户名称", cells.get(customerInfoRow, 1).getStringValue()); + readBSV5(excelFile.getAbsolutePath(), headRowNum, cells.getMaxRow() + 1, sheetNo); + }else { + throw new TemplateNotFindException(sourceFile); + } + }else { + readBSV5(excelFile.getAbsolutePath(), headRowNum, cells.getMaxRow() + 1, sheetNo); + } + + } + + return isModified; + } + + private void readBSV5(String pathname, int headRowNumber, int endRowNum, int sheetNo) { + String sourceFile = HelperUtil.getSourceFileName(pathname,BANK_NAME); + try (ExcelReader reader = EasyExcel.read(pathname).build()) { + ReadSheet rs = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNumber) + .head(CITICBankStatementEntity.class) + .registerReadListener(HelperUtil.getReadListener( + esCITICBankStatementMapper, + CITICBankStatementEntity.class, + false, + headRowNumber, + endRowNum + 1,pathname)) + .build(); + reader.read(rs); + } catch (Exception e) { + + if (e instanceof ExcelAnalysisStopException) { + return; + } + + log.error("解析Excel文件失败.", e); + throw new ImportDataFailedException(e.getMessage(), sourceFile); + } + } + + private void fix(Workbook wb, String filename, Cells cells, Cell headerCell, int endRowNum, String cellName, String cellValue) + throws Exception { + cells.insertColumn(0, true); + cells.get(headerCell.getRow(), 0).setValue(cellName); + + for (int i = headerCell.getRow() + 1; i <= endRowNum; i++) { + cells.get(i, 0).setValue(cellValue); + } + + wb.save(filename); + } + + + /** + * 解析开户信息 + */ + private void readOAI(File file, Cells cells, int sheetNo) { + // 获取表头信息 + try { + // 身份证号 + String idCarNo = null; + Cell idCell = AsposeUtil.getCell(cells, "证件号码"); + if (idCell != null) { + int headRowNumber = idCell.getRow() + 1; + int col = idCell.getColumn(); + + idCarNo = cells.get(headRowNumber, col).getStringValue(); + } + + Cell cell = AsposeUtil.getCell(cells, "客户号"); + if (cell != null) { + int headRowNumber = cell.getRow() + 1; + + try (ExcelReader excelReader = EasyExcel.read(file).build()) { + ReadSheet readSheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNumber) + .head(CITICOpeningAccountInfoEntity.class) + .registerConverter(new ExcelStringToJavaBigDecimalConverter()) + .registerReadListener(new CITICBankOpeningAccountInfoReadListener( + esCITICOpeningAccountInfoMapper, idCarNo)) + .build(); + + excelReader.read(readSheet); + } catch (Exception e) { + log.error("解析Excel文件失败.", e); + throw new ImportDataFailedException(e.getMessage(), file.getAbsolutePath()); + } + } + } catch (Exception e) { + log.error("解析Excel文件失败.", e); + throw new ImportDataFailedException(e.getMessage(), file.getAbsolutePath()); + } + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CMBCDataAnalysisHelper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CMBCDataAnalysisHelper.java new file mode 100644 index 0000000..cfb4298 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CMBCDataAnalysisHelper.java @@ -0,0 +1,1009 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.util.ListUtils; +import com.aspose.cells.Cell; +import com.aspose.cells.Cells; +import com.aspose.cells.Workbook; +import com.aspose.cells.Worksheet; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; + +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.common.constant.BankStatementConstants; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.exception.dc.AnalyzeDataFailedException; +import com.inscloudtech.common.exception.dc.ImportDataFailedException; +import com.inscloudtech.common.exception.dc.TemplateNotFindException; +import com.inscloudtech.common.utils.DateUtils; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.common.utils.file.FileUtils; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.mapper.es.*; +import com.inscloudtech.datacenter.service.ImportResultService; +import com.inscloudtech.bankStatementAnalysis.listener.*; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; +import com.inscloudtech.bankStatementAnalysis.domain.entity.*; + +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.easyes.core.core.BaseEsMapper; +import org.dromara.easyes.core.core.EsWrappers; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.math.BigDecimal; +import java.util.*; + +/** + * 民生银行数据分析 + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class CMBCDataAnalysisHelper { + + + private final ImportResultService importResultService; + private final EsCMBCSavingsCardCompanyInfoMapper savingsCardCompanyInfoMapper; + private final EsCMBCSavingsCardAccountInfoMapper savingsCardAccountInfoMapper; + private final EsCMBCCreditCardAccountInfoMapper creditCardAccountInfoMapper; + private final EsCMBCSavingsCardBankStatementMapper savingsCardBankStatementMapper; + private final EsCMBCCreditCardBankStatementMapper creditCardBankStatementMapper; + private final static String BANK_NAME = "民生银行"; + private final ESOpeningAccountInfoMapper esOAIMapper; + + public void importData(File dir,String caseId) throws Exception { + List fileList = FileUtil.loopFiles(dir); + List excelFile = HelperUtil.getExcelFile(fileList); + // 筛选Excel文件 + for (File file : excelFile) { + try { + String absolutePath = file.getAbsolutePath(); + String sourceFile = HelperUtil.getSourceFileName(absolutePath,BANK_NAME); + Workbook wb = new Workbook(absolutePath); + for (int sheetNum = 0; sheetNum < wb.getWorksheets().getCount(); sheetNum++) { + try { + Worksheet worksheet = wb.getWorksheets().get(sheetNum); + Cells cells = worksheet.getCells(); + + Cell cell = AsposeUtil.getCell(cells, "交易时间"); + if (cell != null) { + readMinShengBankStatement(file, cells, sheetNum); + } else { + cell = AsposeUtil.getCell(cells, "交易日期"); + Cell khCell = AsposeUtil.getCell(cells, "开户日期"); + Cell wckhxx = AsposeUtil.getCell(cells, "无此客户信息"); + Cell cxjysbzs = AsposeUtil.getCell(cells, "交易明细查询失败总数"); + Cell qlxhcell = AsposeUtil.getCell(cells, "权利序号"); + if (cell != null) { + readMinShengBankStatement(file, cells, sheetNum); + } else if(khCell != null) { + int headRowNum = khCell.getRow() + 1; + readMinShengBankOpeningAccountInfo(file, cells, sheetNum,headRowNum); + }else if(wckhxx != null) { + continue; + }else if(cxjysbzs != null) { + continue; + }else if(qlxhcell != null) { + continue; + }else { + String name = worksheet.getName(); + throw new TemplateNotFindException(sourceFile+BankStatementConstants.NAME_WITH_SHEET_NAME+ name); + } + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } + + public void analyzeData(String caseId) { + // 开户信息 + analyzeOpeningAccountInfo(caseId); + // 流水 + analyzeBS(caseId); + } + + private void analyzeBS(String caseId) { + // 信用卡流水 + analyzeCreditCardBS(caseId); + // 储蓄卡流水 + analyzeSavingsCardBS(caseId); + } + + private void analyzeOpeningAccountInfo(String caseId) { + // 信用卡 + analyzeCreditCardOAI(caseId); + // 储蓄卡 + analyzeSavingsCardOAI(caseId); + } + + private void analyzeSavingsCardOAI(String caseId) { + // 个人 + analyzeSavingsCardForPersonOAI(caseId); + // 企业 + analyzeSavingsCardForCompanyOAI(caseId); + } + + private void analyzeSavingsCardForCompanyOAI(String caseId) { + List oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(savingsCardCompanyInfoMapper, CMBCSavingsCardCompanyInfoEntity.class); + Set uniqueKeySet = new HashSet(); + for (CMBCSavingsCardCompanyInfoEntity entity : entityList) { + + String cardNumber = entity.getCardNumber(); +// if (StringUtils.isEmpty(cardNumber)) { +// continue; +// } + + OpeningAccountInfo oai = new OpeningAccountInfo(); + oai.setName(entity.getCardHolderName()); + oai.setBankName(BANK_NAME); + oai.setAccountNumber(cardNumber); + oai.setIdType(entity.getIdType()); + oai.setIdNo(entity.getIdCardNo()); + oai.setPhone(entity.getPhone()); + oai.setAddress(entity.getAddress()); + oai.setOpeningAccountDate(entity.getOpeningAccountDate()); + oai.setAccountOpeningInstitution(entity.getAccountOpeningInstitution()); + oai.setClosingDate(entity.getCloseDate()); + oai.setStatus(entity.getStatus()); + + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + oaiList.add(oai); + if (oaiList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + if (!oaiList.isEmpty()) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + } + } + + private void analyzeSavingsCardForPersonOAI(String caseId) { + List oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(savingsCardAccountInfoMapper, CMBCSavingsCardAccountInfoEntity.class); + Set uniqueKeySet = new HashSet(); + for (CMBCSavingsCardAccountInfoEntity entity : entityList) { + + String cardNumber = entity.getCardNumber(); + if (StringUtils.isEmpty(cardNumber)) { + continue; + } + + OpeningAccountInfo oai = getOpeningAccountInfo(BANK_NAME, entity, cardNumber); + + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + oaiList.add(oai); + if (oaiList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + if (!oaiList.isEmpty()) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + } + } + + private static OpeningAccountInfo getOpeningAccountInfo( + String bankName, CMBCSavingsCardAccountInfoEntity entity, String cardNumber) { + OpeningAccountInfo oai = new OpeningAccountInfo(); + oai.setName(entity.getCardHolderName()); + oai.setBankName(BANK_NAME); + oai.setAccountNumber(cardNumber); + oai.setIdType(entity.getIdType()); + oai.setIdNo(entity.getIdCardNo()); + oai.setPhone(entity.getPhone()); + oai.setAddress(entity.getAddress()); + oai.setOpeningAccountDate(entity.getOpeningAccountDate()); + oai.setAccountOpeningInstitution(entity.getAccountOpeningInstitution()); + return oai; + } + + private void analyzeCreditCardOAI(String caseId) { + + List oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(creditCardAccountInfoMapper, CMBCCreditCardAccountInfoEntity.class); + Set uniqueKeySet = new HashSet(); + for (CMBCCreditCardAccountInfoEntity entity : entityList) { + + OpeningAccountInfo oai = getOpeningAccountInfo(BANK_NAME, entity); + + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + oaiList.add(oai); + if (oaiList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + if (!oaiList.isEmpty()) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + } + } + + private static OpeningAccountInfo getOpeningAccountInfo(String bankName, CMBCCreditCardAccountInfoEntity entity) { + OpeningAccountInfo oai = new OpeningAccountInfo(); + oai.setName(entity.getCardHolderName()); + oai.setBankName(BANK_NAME); + oai.setAccountNumber(entity.getCardNumber()); + oai.setIdType(entity.getIdType()); + oai.setIdNo(entity.getIdCardNo()); + oai.setPhone(entity.getPhone()); + oai.setAddress(entity.getAddress()); + oai.setOpeningAccountDate(entity.getOpeningAccountDate()); + oai.setAccountOpeningInstitution(entity.getAccountOpeningInstitution()); + return oai; + } + + private void analyzeCreditCardBS(String caseId) { + + List bsList = new ArrayList<>(); + + List entityList = + HelperUtil.getEntityList(creditCardBankStatementMapper, CMBCCreditCardBankStatementEntity.class); + + List oaiList = HelperUtil.getEntityListV2(esOAIMapper, OpeningAccountInfo.class, caseId); + + Map nameAccMap = new HashMap<>(); + Map cardNumberAccMap = new HashMap<>(); + + for (OpeningAccountInfo entity : oaiList) { + nameAccMap.put(entity.getName(), entity); + cardNumberAccMap.put(entity.getAccountNumber(), entity); + } + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + + for (CMBCCreditCardBankStatementEntity entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + bs.setCardHolderName(entity.getCardHolderName()); + String cardNumber = StrUtil.isEmpty(entity.getCardNumber())?entity.getAccountNumber():entity.getCardNumber(); + OpeningAccountInfo info = nameAccMap.getOrDefault(entity.getCardHolderName(), null); + + if (info != null) { + bs.setIdCardNo(info.getIdNo()); + bs.setPhone(info.getPhone()); + } else { + info = cardNumberAccMap.getOrDefault(cardNumber, null); + if (info != null) { + bs.setIdCardNo(info.getIdNo()); + + // if cardHolderName is empty, then set cardHolderName by info + if (StringUtils.isEmpty(entity.getCardHolderName())) { + bs.setCardHolderName(info.getName()); + } + } + } + bs.setCardNumber(cardNumber); + bs.setCounterpartyName(entity.getCounterpartyName()); + bs.setCounterpartIdCardNo(entity.getCounterpartyIdCardNo()); + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + bs.setCounterpartyBankName(entity.getCounterpartyBankName()); + bs.setSummary(entity.getSummary()); + bs.setTransRemark(entity.getTransRemark()); + bs.setTransChannel(entity.getTransChannel()); + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + // 交易金额 + // 根据借贷标志 + String loanFlag = entity.getLoanFlag(); + if (StrUtil.isNotEmpty(loanFlag)) { + BigDecimal transactionAmount = NumberUtil.toBigDecimal(entity.getTransactionAmount()); + if (loanFlag.equals("付款") || loanFlag.equals("出") || loanFlag.equals("借")) { + bs.setTransactionAmount(transactionAmount.negate()); + } else { + bs.setTransactionAmount(transactionAmount); + } + } + + + + // 2012/12/18 13:19:08 + // 交易时间 + String transactionTime = entity.getTransactionTime(); + if (StrUtil.isNotEmpty(transactionTime)) { + + String format = "yyyy/MM/dd HH:mm:ss"; // 大部分人数据的格式 + // 2018112914:52:18 + if (!transactionTime.contains(" ")) { + if (transactionTime.contains("/")) { + format = "yyyy/MM/ddHH:mm:ss"; + } else if (transactionTime.contains("-")) { + format = "yyyy-MM-ddHH:mm:ss"; + } else if (transactionTime.contains(":")) { + format = "yyyyMMddHHHH:mm:ss"; + } else { + format = "yyyyMMddHHmmss"; + } + }else if (transactionTime.contains("-")){ + format = "yyyy-MM-dd HH:mm:ss"; // 大部分人数据的格式 + } + + try { + bs.setTransactionTime(DateUtils.parseDate(transactionTime, format)); + } catch (Exception e) { + log.error("transactionTime: {}", transactionTime); + + throw new AnalyzeDataFailedException( + StrUtil.format("用模板[{}]解析交易时间错误: {}", format, transactionTime), e, sourceFile); + } + } + + bs.setBalance(BigDecimal.valueOf(0.0)); + bs.setRemark("信用卡"); + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entity.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e,sourceFile); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + if (!bsList.isEmpty()) { + HelperUtil.batchInsert2Es(bsList, caseId); + } + } + + @Getter + private static class GetCardTypeList { + private final List creditCardList = new ArrayList<>(); + private final List savingsCardList = new ArrayList<>(); + + GetCardTypeList( + BaseEsMapper savingsCardAccountInfoMapper, + BaseEsMapper creditCardAccountInfoMapper, + EsCMBCSavingsCardCompanyInfoMapper savingsCardCompanyInfoMapper) { + + List savingsCardAccountInfoList = + HelperUtil.getEntityList(savingsCardAccountInfoMapper, CMBCSavingsCardAccountInfoEntity.class); + + for (CMBCSavingsCardAccountInfoEntity entity : savingsCardAccountInfoList) { + String cardNumber = entity.getCardNumber(); + String accountNumber = entity.getAccountNumber(); + + if (Objects.equals(cardNumber, accountNumber)) { + creditCardList.add(cardNumber); + } else { + savingsCardList.add(cardNumber); + } + } + + List savingsCardCompanyInfoEntityList = + HelperUtil.getEntityList(savingsCardCompanyInfoMapper, CMBCSavingsCardCompanyInfoEntity.class); + for (CMBCSavingsCardCompanyInfoEntity entity : savingsCardCompanyInfoEntityList) { + savingsCardList.add(entity.getCardNumber()); + } + + List cmbcCreditCardAccountInfoList = + creditCardAccountInfoMapper.selectList( + EsWrappers.lambdaQuery(CMBCCreditCardAccountInfoEntity.class)); + + cmbcCreditCardAccountInfoList.forEach(entity -> creditCardList.add(entity.getCardNumber())); + } + } + + /** + * 其中包含了个人和企业储蓄卡流水 + */ + private void analyzeSavingsCardBS(String caseId) { + + GetCardTypeList cardTypeList = new GetCardTypeList( + savingsCardAccountInfoMapper, creditCardAccountInfoMapper, savingsCardCompanyInfoMapper); + + List bsList = new ArrayList<>(); + + List entityList = + HelperUtil.getEntityList(savingsCardBankStatementMapper, CMBCSavingsCardBankStatementEntity.class); + + // 个人开户信息 + List accountInfoList = + HelperUtil.getEntityList(savingsCardAccountInfoMapper, CMBCSavingsCardAccountInfoEntity.class); + Map nameAccountInfoMap = new HashMap<>(); + for (CMBCSavingsCardAccountInfoEntity entity : accountInfoList) { + JSONObject obj = new JSONObject(); + obj.putOnce("phone",entity.getPhone()); + obj.putOnce("idCardNo",entity.getIdCardNo()); + nameAccountInfoMap.put(entity.getCardHolderName(), obj); + } + + // 企业开户信息 + List companyInfoList = + HelperUtil.getEntityList(savingsCardCompanyInfoMapper, CMBCSavingsCardCompanyInfoEntity.class); + for (CMBCSavingsCardCompanyInfoEntity entity : companyInfoList) { + JSONObject obj = new JSONObject(); + obj.putOnce("phone",entity.getPhone()); + obj.putOnce("idCardNo",entity.getIdCardNo()); + nameAccountInfoMap.put(entity.getCardHolderName(), obj); + } + + Map> serialNumberCustomerMap = new HashMap<>(); + + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + + for (CMBCSavingsCardBankStatementEntity entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + if (StringUtils.isEmpty(entity.getCardHolderName())) { + continue; + } + + String serialNumber = entity.getSerialNumber(); + + boolean isSameBS = false; + + if (serialNumberCustomerMap.containsKey(serialNumber)) { + List list = serialNumberCustomerMap.get(serialNumber); + for (CMBCSavingsCardBankStatementEntity oldEntity : list) { + if (simpleCompare(oldEntity, entity)) { + isSameBS = true; + break; + } + } + + if (isSameBS) { + continue; + } else { + serialNumberCustomerMap.get(serialNumber).add(entity); + } + + } else { + List list = new ArrayList<>(); + list.add(entity); + + serialNumberCustomerMap.put(serialNumber, list); + } + + // 流水 + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + bs.setCardHolderName(entity.getCardHolderName()); + + JSONObject info = nameAccountInfoMap.getOrDefault(entity.getCardHolderName(), null); + if (info != null) { + bs.setPhone(info.getStr("phone")); + bs.setIdCardNo(info.getStr("idCardNo")); + } + + bs.setCardNumber(entity.getCardNumber()); + // 1 货币类型 + // 人民币 + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + + // 2 交易金额 可能是double或者int类型 + String loanFlag = entity.getLoanFlag(); + if (StrUtil.isNotEmpty(loanFlag)) { + if (Objects.equals("借", loanFlag) || Objects.equals("出", loanFlag)) { + bs.setTransactionAmount(entity.getTransactionAmount().negate()); + } else { + bs.setTransactionAmount(entity.getTransactionAmount()); + } + } else { + bs.setTransactionAmount(BigDecimal.ZERO); + } +// bs.setBalance(entity.getBalance()); + // 3 余额 ??? + if (cardTypeList.savingsCardList.contains(entity.getCardNumber())) { + bs.setBalance(entity.getBalance()); + } else { + bs.setBalance(new BigDecimal("0.00")); + } + + // 4 交易日期 + String transactionTime = entity.getTransactionTime(); + if (StrUtil.isNotEmpty(transactionTime)) { + String pattern; + if (transactionTime.contains("-")) { + pattern = "yyyy-MM-dd HH:mm:ss"; + } else if (transactionTime.contains("/")) { + pattern = "yyyy/MM/dd HH:mm:ss"; + } else if (transactionTime.contains(":")) { + pattern = "yyyyMMddHH:mm:ss"; + } else { + pattern = "yyyyMMddHHmmss"; + } + + if (transactionTime.length() < pattern.length()) { + pattern = pattern.substring(0, transactionTime.length()); + } else if (transactionTime.length() > pattern.length()) { + transactionTime = transactionTime.substring(0, pattern.length()); + } + + try { + //2022/06/07 06:05 + bs.setTransactionTime(DateUtils.parseDate(transactionTime, pattern)); + } catch (Exception e) { + log.error("解析交易时间失败:{}", e.getMessage(), e); + + throw new AnalyzeDataFailedException(StrUtil.format("解析交易时间失败:{}", e.getMessage()), e, sourceFile); + } + } + + bs.setCounterpartyName(entity.getCounterpartyName()); + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + + String counterpartyIdCardNo = entity.getCounterpartyIdCardNo(); + if (StrUtil.isNotEmpty(counterpartyIdCardNo)) { + bs.setCounterpartIdCardNo(counterpartyIdCardNo.replaceAll("'", "")); + } + + if (StrUtil.isNotEmpty(entity.getCounterpartyIdCardNo())) { + // 根据对手名去查找 + JSONObject accountInfoJson = nameAccountInfoMap.getOrDefault(entity.getCounterpartyName(), null); + if (accountInfoJson != null) { + bs.setCounterpartIdCardNo(accountInfoJson.getStr("idCardNo")); + } + } + + bs.setSummary(entity.getSummary()); + bs.setTransChannel(entity.getTransChannel()); + bs.setTransRemark(entity.getTransRemark()); + bs.setCounterpartyBankName(entity.getCounterpartyBankName()); + bs.setTransactionInstitutions(entity.getTransactionInstitutions()); + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entity.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= Constants.BATCH_SIZE) { + + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e,sourceFile); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + // 保存数据库 + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + private boolean simpleCompare( + CMBCSavingsCardBankStatementEntity oldEntity, CMBCSavingsCardBankStatementEntity entity) { + + if (!Objects.equals(oldEntity.getSerialNumber(), entity.getSerialNumber())) { + return false; + } + + if (!StringUtils.equals(oldEntity.getTransactionTime(), entity.getTransactionTime())) { + return false; + } + + if (!StringUtils.equals(oldEntity.getLoanFlag(), entity.getLoanFlag())) { + return false; + } + + if (!StringUtils.equals(oldEntity.getCardNumber(), entity.getCardNumber())) { + return false; + } + + return oldEntity.getBalance().compareTo(entity.getBalance()) == 0; + } + + + /** + * 读取开户信息 + */ + private void readMinShengBankOpeningAccountInfo(File excelFile, Cells cells, int sheetNum,int headRowNum) throws Exception { + // 区分谁是信用卡,谁是储蓄卡 + // 这里区分的其实还是'信用卡开户_录入批次1.csv' 这个文件,其他的区分不了 + // 信用卡和储蓄卡最主要的区分点就是 账号和卡号是否相同,相同则为信用卡,否则为储蓄卡 + + // 如果证件号码在外面,那么,需要修复表 + Cell cell = AsposeUtil.getCell(cells, "证件号码"); + if (cell == null) { + return; + } + + boolean isFixed = false; + boolean isCompany = isCompany(excelFile); + if (cell.getRow() < headRowNum) { + + if (isCompany) { + excelFile = fixTable4Company(excelFile, sheetNum, headRowNum); + }else { + excelFile = fixTable(excelFile, sheetNum, headRowNum); + } + + isFixed = true; + } + + if (isCreditCardBS(excelFile, "账号") && !isCompany(excelFile)) { + // 没有‘账号’为信用卡 + // 信用卡 + readCreditCardOAI(excelFile, sheetNum); + } else { + // 储蓄卡 + readSavingsCardOAI(excelFile, sheetNum,isCompany); + } + } + + private File fixTable(File excelFile, int sheetNum, int headRowNum) throws Exception { + // 获取客户名称 + Workbook wb = new Workbook(excelFile.getAbsolutePath()); + Cells cells = wb.getWorksheets().get(sheetNum).getCells(); + + String customerName = getStringValue(cells, "客户名称"); + // 证件类型 + String idType = getStringValue(cells, "证件类型"); + // 证件号码 + String idNumber = getStringValue(cells, "证件号码"); + // 联系手机 + String phone = getStringValue(cells, "手机号码"); + // 住宅地址 + String address = getStringValue(cells, "住宅地址"); + + // 表头 + Map map = new HashMap<>(); + map.put("客户名称", customerName); + map.put("证件种类", idType); + map.put("证件号码", idNumber); + map.put("联系手机", phone); + map.put(" 通讯地址", address); + // 最后一列 + String pathname = excelFile.getAbsolutePath(); + fixColumns(wb, pathname, cells, headRowNum, map); + excelFile = new File(pathname); + + return excelFile; + } + + private File fixTable4Company(File excelFile, int sheetNum, int headRowNum) throws Exception { + // 获取客户名称 + Workbook wb = new Workbook(excelFile.getAbsolutePath()); + Cells cells = wb.getWorksheets().get(sheetNum).getCells(); + + String customerName = getStringValue(cells, "客户名称"); + // 证件类型 +// String idType = getStringValue(cells, "证件类型"); + // 证件号码 + String idNumber = getStringValue(cells, "机构信用代码证"); + // 联系手机 + String phone = getStringValue(cells, "手机号码"); + // 住宅地址 + String address = getStringValue(cells, "住宅地址"); + + // 表头 + Map map = new HashMap<>(); + map.put("客户名称", customerName); + map.put("证件种类", "机构信用代码证"); + map.put("证件号码", idNumber); + map.put("联系手机", phone); + map.put(" 通讯地址", address); + // 最后一列 + String pathname = excelFile.getAbsolutePath(); + fixColumns(wb, pathname, cells, headRowNum, map); + excelFile = new File(pathname); + + return excelFile; + } + + private void fixColumns(Workbook wb, String filename, Cells cells, int headRowNum, Map map) + throws Exception { + cells.insertRow(cells.getMaxRow() + 1); + int startCol = cells.getMaxColumn() + 1; + for (Map.Entry entry : map.entrySet()) { + String headName = entry.getKey(); + String columnValue = entry.getValue(); + cells.get(headRowNum - 1, startCol).setValue(headName); + + for (int row = headRowNum; row <= cells.getMaxRow(); row++) { + cells.get(row, startCol).setValue(columnValue); + } + + ++startCol; + } + + wb.save(filename); + } + + private String getStringValue(Cells cells, String key) { + Cell cell = AsposeUtil.getCell(cells, key); + if (cell == null) { + // 即便无法获取客户名称,也可以通过账号找到对应信息,无关紧要 + return ""; + } + + String rstValue = cells.get(cell.getRow(), cell.getColumn() + 1).getStringValue(); + if (StringUtils.isBlank(rstValue)) { + return ""; + } + + return rstValue; + } + + private void readCreditCardOAI(File excelFile, int sheetNum) { + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNum) + .head(CMBCCreditCardAccountInfoEntity.class) + .registerReadListener(new ReadCMBCCreditCardOpeningAccountInfoListener(creditCardAccountInfoMapper)) + .build(); + reader.read(sheet); + } catch (Exception e) { + log.error("读取信用卡开户信息失败", e); + throw new ImportDataFailedException(e.getMessage(), excelFile.getAbsolutePath()); + } + } + + private void readSavingsCardOAI(File excelFile, int sheetNum, boolean isCompany) throws Exception { + + Workbook wb = new Workbook(excelFile.getAbsolutePath()); + Cells cells = wb.getWorksheets().get(sheetNum).getCells(); + Cell cell = AsposeUtil.getCell(cells, "开户日期"); + if (cell == null) { + return; + } + + int headRowNum = cell.getRow() + 1; + + if (isCompany) { + excelFile = fixTable4Company(excelFile, sheetNum, headRowNum); + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + Class clazz = CMBCSavingsCardCompanyInfoEntity.class; + ReadSheet sheet = EasyExcel.readSheet(sheetNum) + .head(clazz) + .headRowNumber(headRowNum) + .registerReadListener( + new ReadCMBCSavingsCardOpeningCompanyInfoListener(savingsCardCompanyInfoMapper)) + .build(); + reader.read(sheet); + } catch (Exception e) { + log.error("读取储蓄卡开户信息失败", e); + throw new ImportDataFailedException(e.getMessage(), excelFile.getAbsolutePath()); + } + } else { + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + Class clazz = CMBCSavingsCardAccountInfoEntity.class; + ReadSheet sheet = EasyExcel.readSheet(sheetNum) + .head(clazz) + .headRowNumber(headRowNum) + .registerReadListener( + new ReadCMBCSavingsCardOpeningAccountInfoListener(savingsCardAccountInfoMapper)) + .build(); + reader.read(sheet); + } catch (Exception e) { + log.error("读取储蓄卡开户信息失败", e); + throw new ImportDataFailedException(e.getMessage(), excelFile.getAbsolutePath()); + } + } + } + + /** + * 读取流水 + */ + protected void readMinShengBankStatement(File excelFile, Cells cells, int sheetNum) throws Exception { + // 还需要区分储蓄卡和信用卡流水 + // 储蓄卡有客户名称,信用卡没有 + // 无法真正区分,主要区分的还是这个文件'信用卡交易流水_新涉案_自由组合字段_录入批次1.csv' + // 用交易时间字段来判断开头 + Cell cell = AsposeUtil.getCell(cells, "交易时间"); + if (cell == null) { + return; + } + + int headRowNum = cell.getRow() + 1; + // 以下代表两种不同的模板 + cell = AsposeUtil.getCell(cells, "客户名称"); + // 一种模板表示客户名称不在表头 + if (cell != null && cell.getRow() < headRowNum) { + // 增加包括客户名称和客户账号两列 + fixExcel(excelFile, sheetNum, headRowNum); + // 根据客户账号和账户账号是否相同来区分为信用卡和储蓄卡 + String customerAccount = getStringValue(cells, "客户账号"); + String Account = getStringValue(cells, "账户账号"); + String name = getStringValue(cells, "客户名称"); + if (Objects.equals(customerAccount, Account) && !name.contains("公司")) { + // 信用卡 + readCreditCardBS(excelFile, sheetNum, headRowNum); + } else { + readSavingsCardBS(excelFile, sheetNum, headRowNum,customerAccount); + } + + return; + } + // 第二种模板表示客户名称在表头 + if (isCreditCardBS(excelFile)) { + readCreditCardBS(excelFile, sheetNum, headRowNum); + } else { // 储蓄卡 + readSavingsCardBS(excelFile, sheetNum, headRowNum,null); + } + } + + private void fixExcel(File excelFile, int sheetNum, int headRowNum) throws Exception { + + Workbook wb = new Workbook(excelFile.getAbsolutePath()); + Cells cells = wb.getWorksheets().get(sheetNum).getCells(); + + // 获取客户名称 + Cell cell = AsposeUtil.getCell(cells, "客户名称"); + if (cell == null) { + return; + } + + String customerName = cells.get(cell.getRow(), cell.getColumn() + 1).getStringValue(); + if (StringUtils.isEmpty(customerName)) { + return; + } + + // 获取客户账号 + cell = AsposeUtil.getCell(cells, "客户账号"); + if (cell == null) { + return; + } + String cardHolderName = cells.get(cell.getRow(), cell.getColumn() + 1).getStringValue(); + if (StringUtils.isEmpty(cardHolderName)) { + return; + } + + int startColumn = cells.getMaxColumn() + 1; + cells.get(headRowNum - 1, startColumn).setValue("客户名称"); + cells.get(headRowNum - 1, startColumn + 1).setValue("客户账号"); + + // 设置列值 + for (int i = headRowNum; i <= cells.getMaxRow(); i++) { + cells.get(i, startColumn).setValue(customerName); + cells.get(i, startColumn + 1).setValue(cardHolderName); + } + + // 保存文件 + wb.save(excelFile.getAbsolutePath()); + } + + /** + * 是否是信用卡 + */ + private boolean isCreditCardBS(File excelFile, String key) throws Exception { + Cell cell = AsposeUtil.getCell(excelFile, 0, key); + return cell == null; + } + + private boolean isCompany(File excelFile) throws Exception { + Cell cell = AsposeUtil.getCell(excelFile, 0, "法人"); + return cell != null; + } + + private boolean isCreditCardBS(File excelFile) { + Cell cell = AsposeUtil.getCell(excelFile, 0, "客户名称"); + return cell == null; + } + + /** + * 信用卡流水 + */ + private void readCreditCardBS(File excelFile, int sheetNum, int headRowNum) { + String sourceFile = HelperUtil.getSourceFileName(excelFile.getAbsolutePath(),BANK_NAME); + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNum) + .headRowNumber(headRowNum) + .head(CMBCCreditCardBankStatementEntity.class) + .registerReadListener(new ReadCMBCCreditCardBankStatementListener(creditCardBankStatementMapper,sourceFile)) + .build(); + reader.read(sheet); + + } catch (Exception e) { + log.error("读取信用卡流水失败", e); + throw new ImportDataFailedException(e.getMessage(), excelFile.getAbsolutePath()); + } + } + + /** + * 储蓄卡流水 + */ + private void readSavingsCardBS(File excelFile, int sheetNum, int headRowNum, String companyCard) { + String sourceFile = HelperUtil.getSourceFileName(excelFile.getAbsolutePath(),BANK_NAME); + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNum) + .headRowNumber(headRowNum) + .head(CMBCSavingsCardBankStatementEntity.class) + .registerReadListener(new ReadCMBCSavingsCardBankStatementListener(savingsCardBankStatementMapper,companyCard,sourceFile)) + .build(); + reader.read(sheet); + + + } catch (Exception e) { + log.error("读取储蓄卡流水失败", e); + throw new ImportDataFailedException(e.getMessage(), excelFile.getAbsolutePath()); + } + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CMBDataAnalysisHelper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CMBDataAnalysisHelper.java new file mode 100644 index 0000000..b22badf --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/CMBDataAnalysisHelper.java @@ -0,0 +1,569 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.util.ListUtils; +import com.aspose.cells.Cell; +import com.aspose.cells.Cells; +import com.aspose.cells.Workbook; +import com.aspose.cells.Worksheet; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; + +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.bankStatementAnalysis.service.ImportService; +import com.inscloudtech.common.constant.BankStatementConstants; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.exception.dc.AnalyzeDataFailedException; +import com.inscloudtech.common.exception.dc.ImportDataFailedException; +import com.inscloudtech.common.exception.dc.TemplateNotFindException; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.common.utils.file.FileUtils; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.mapper.es.EsCMBOpeningAccountInfoMapper; +import com.inscloudtech.datacenter.mapper.es.EsCMBRetailStatementMapper; +import com.inscloudtech.datacenter.mapper.es.EsCMBStatementMapper; +import com.inscloudtech.datacenter.service.ImportResultService; +import com.inscloudtech.bankStatementAnalysis.listener.CMBOpeningAccountInfoReadListener; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CMBOpeningAccountInfoEntry; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CMBRetailStatementEntry; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CMBStatementEntry; + +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.util.*; + +/** + * 招商银行数据分析 + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class CMBDataAnalysisHelper { + + private final ImportService importService; + private final ImportResultService importResultService; + private final EsCMBOpeningAccountInfoMapper openingAccountInfoMapper; + private final EsCMBStatementMapper statementMapper; + private final EsCMBRetailStatementMapper retailStatementMapper; + private final static String BANK_NAME = "招商银行"; + private final EsCMBOpeningAccountInfoMapper accountInfoMapper; + + public void importData(File file, String caseId) throws Exception { + + if (file == null || !file.exists()) { + return; + } + + List fileList = FileUtil.loopFiles(file); + // 筛选Excel文件,包括xls、xlsx、csv三中格式 + List excelFile = HelperUtil.getExcelFile(fileList); + + for (File f : excelFile) { + try { + String absolutePath = f.getAbsolutePath(); + String sourceFile = HelperUtil.getSourceFileName(absolutePath, BANK_NAME); + if (f.getName().toLowerCase().endsWith("csv")) { + BufferedReader fileReader = new BufferedReader(new InputStreamReader(new FileInputStream(absolutePath), "GBK")); + String line; + if ((line = fileReader.readLine()) != null) { // 读取第一行 + if (line.contains("开户日期")) { + // 开户信息 + readMerchantsBankCustomerInfo(f); + } else if (line.contains("交易日期")) { + if(line.contains("借贷方向 ")){ + readMerchantsBankRetailStatement(f);// 零售交易流水 + }else if(line.contains("交易方向")){ + readMerchantsBankStatement(f); + }else { + throw new ImportDataFailedException("该文件无匹配模板,无法读取", sourceFile); + } + }else { + throw new ImportDataFailedException("文件无表头信息,建议将标准表头复制-粘贴后,再行导入即可", sourceFile); + } + } + }else { + Workbook wb = new Workbook(absolutePath); + for (int sheetNum = 0; sheetNum < wb.getWorksheets().getCount(); sheetNum++) { + try { + Worksheet worksheet = wb.getWorksheets().get(sheetNum); + String sourceFileWithSheetName = sourceFile + BankStatementConstants.NAME_WITH_SHEET_NAME + worksheet.getName(); + Cells cells = worksheet.getCells(); + Cell cell = AsposeUtil.getCell(cells, "交易日期"); + Cell oaiCell = AsposeUtil.getCell(cells, "开户日期"); + Cell nameCell = AsposeUtil.getCell(cells, "姓名"); + if (cell != null) { + readMerchantsBankStatement(f); + } else if (oaiCell != null) { + try (ExcelReader reader = EasyExcel.read(absolutePath).build()) { + ReadSheet sheet = EasyExcel.readSheet() + .headRowNumber(1) + .head(CMBOpeningAccountInfoEntry.class) + .registerReadListener(new CMBOpeningAccountInfoReadListener(openingAccountInfoMapper)) + .build(); + reader.read(sheet); + } catch (Exception e) { + log.error("读取招商银行客户信息失败", e); + throw new ImportDataFailedException(e.getMessage(), sourceFileWithSheetName); + } + } else if (nameCell != null) { + getCMBOpeningAccountInfo(nameCell, cells, sourceFileWithSheetName); + } else { + throw new TemplateNotFindException(sourceFileWithSheetName); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } + + + + private void getCMBOpeningAccountInfo(Cell nameCell,Cells cells,String sourceFile) { + CMBOpeningAccountInfoEntry infoEntry = new CMBOpeningAccountInfoEntry(); + int startRow = nameCell.getRow(); + int startCol = nameCell.getColumn(); + Cell nameValueCell = cells.get(startRow + 1, startCol); + Object nameValueCellValue = nameValueCell.getValue(); + if(nameValueCellValue != null){ + infoEntry.setCardHolderName(nameValueCellValue.toString()); + } + + Cell idCardNoCell = AsposeUtil.getCell(cells, "证件号"); + if(idCardNoCell != null){ + Cell idCardNoValueCell = cells.get(idCardNoCell.getRow() + 1, idCardNoCell.getColumn()); + Object idCardNoValueCellObj = idCardNoValueCell.getValue(); + if(idCardNoValueCellObj != null){ + infoEntry.setIdCardNo(idCardNoValueCellObj.toString()); + } + } + + Cell phoneCell = AsposeUtil.getCell(cells, "手机号"); + if(phoneCell != null){ + Cell phoneValueCell = cells.get(phoneCell.getRow() + 1, phoneCell.getColumn()); + Object phoneValueCellObj = phoneValueCell.getValue(); + if(phoneValueCellObj != null){ + infoEntry.setPhone(phoneValueCellObj.toString()); + } + } + + Cell accountNoCell = AsposeUtil.getCell(cells, "账户号"); + if(accountNoCell != null){ + Cell accountNoValueCell = cells.get(accountNoCell.getRow() + 1, accountNoCell.getColumn()); + Object accountNoValueCellObj = accountNoValueCell.getValue(); + if(accountNoValueCellObj != null){ + infoEntry.setAccountNo(accountNoValueCellObj.toString()); + } + } + + Cell cardNumberCell = AsposeUtil.getCell(cells, "卡号"); + if(cardNumberCell != null){ + Cell cardNumberValueCell = cells.get(cardNumberCell.getRow() + 1, cardNumberCell.getColumn()); + Object cardNumberValueCellObj = cardNumberValueCell.getValue(); + if(cardNumberValueCellObj != null){ + infoEntry.setCardNumber(cardNumberValueCellObj.toString()); + } + } + infoEntry.setId(IdUtil.objectId()); + accountInfoMapper.insert(infoEntry); + + } + + public void analyzeData(String caseId) throws Exception { + + // 开户信息 + analyzeOpeningAccountInfo(caseId); + // 流水 + analyzeBS(caseId); + } + + private void analyzeOpeningAccountInfo(String caseId) { + List oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(openingAccountInfoMapper, CMBOpeningAccountInfoEntry.class); + Set uniqueKeySet = new HashSet(); + for (CMBOpeningAccountInfoEntry entry : entityList) { + + OpeningAccountInfo oai = getOpeningAccountInfo(entry); + + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + oaiList.add(oai); + if (oaiList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + if (!oaiList.isEmpty()) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + } + } + + private static OpeningAccountInfo getOpeningAccountInfo( CMBOpeningAccountInfoEntry entry) { + OpeningAccountInfo oai = new OpeningAccountInfo(); + oai.setName(entry.getCardHolderName()); + oai.setBankName(BANK_NAME); + oai.setAccountNumber(entry.getCardNumber()); + oai.setIdType(entry.getIdType()); + oai.setIdNo(entry.getIdCardNo()); + oai.setPhone(entry.getPhone()); + oai.setAddress(entry.getAddress()); + oai.setOpeningAccountDate(entry.getOpeningAccountDate()); + oai.setClosingDate(entry.getCloseAccountDate()); + oai.setStatus(entry.getStatus()); + oai.setType(entry.getType()); + oai.setAccountOpeningInstitution(entry.getOpeningAccountSituation()); + return oai; + } + + private void analyzeBS(String caseId) { + List bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + Map> oaiMap = importService.getOAIMapByCardNumber(caseId, BANK_NAME); + // 非零售流水 + { + List entityList = HelperUtil.getEntityList(statementMapper, CMBStatementEntry.class); + + List serialNumberList = new ArrayList<>(); + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + + for (CMBStatementEntry entry : entityList) { + String sourceFile = entry.getSourceFile(); + try { + // 筛选流水,流水号相同,是同一条流水 + if (serialNumberList.contains(entry.getSerialNumber())) { + continue; + } + + serialNumberList.add(entry.getSerialNumber()); + + BankStatement bs = getBankStatement(oaiMap, entry,sourceFile); + + String md5Id = HelperUtil.generateMD5Id(bs, caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setId(md5Id); + bs.setCaseId(caseId); + BeanUtils.beanAttributeValueTrim(bs); + + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e, sourceFile); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + // 零售流水 + Map cardNumberDocMap = new HashMap<>(); + + { + List entityList = + HelperUtil.getEntityList(retailStatementMapper, CMBRetailStatementEntry.class); + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + + for (CMBRetailStatementEntry entry : entityList) { + String sourceFile = entry.getSourceFile(); + try { + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + bs.setCardHolderName(entry.getCardHolderName()); + + String cardNumber = entry.getCardNumber(); + if (StringUtils.isEmpty(cardNumber)) { + continue; + } + + bs.setCardNumber(cardNumber); + + if (cardNumberDocMap.containsKey(cardNumber)) { + CMBOpeningAccountInfoEntry info = cardNumberDocMap.get(cardNumber); + bs.setIdCardNo(info.getIdCardNo()); + bs.setPhone(info.getPhone()); + } + + String counterpartyName = entry.getCounterpartyName(); + bs.setCounterpartyName(counterpartyName); + + bs.setCounterpartyAccount(entry.getCounterpartyAccount()); + bs.setCounterpartyBankName(entry.getCounterpartyBankName()); + bs.setSummary(entry.getSummary()); + bs.setTransRemark(entry.getTransRemark()); + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + bs.setTransactionInstitutions(entry.getTransInstitutions()); + bs.setTransactionAmount(entry.getTransactionAmount()); + // 交易时间 + String transDate = entry.getTransDate(); // 2008-05-12 + if (StrUtil.isNotEmpty(transDate)) { + + String format = null; + // 如果包含-,则为yyyy-MM-dd + // 如果包含/,则为yyyy/MM/dd + if (transDate.contains("-")) { + format = "yyyy-MM-dd"; + } else if (transDate.contains("/")) { + format = "yyyy/MM/dd"; + } + + String transTime = entry.getTransTime(); // 15:53:51 + if (StrUtil.isNotEmpty(transTime)) { + + if (transTime.contains(":")) { + format = format + " HH:mm:ss"; + } else { + format = format + " HHmmss"; + } + + transDate += " " + transTime; + } + + try { + bs.setTransactionTime(DateUtil.parse(transDate, format)); + } catch (Exception e) { + log.error("transDate:{}", transDate); + + + throw new AnalyzeDataFailedException(StrUtil.format("日期格式错误:{}", transDate), e, sourceFile); + } + } + + bs.setBalance(entry.getBalance()); + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setId(md5Id); + bs.setCaseId(caseId); + + BeanUtils.beanAttributeValueTrim(bs); + + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e, sourceFile); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + } + + private BankStatement getBankStatement(Map> oaiMap, CMBStatementEntry entry,String sourceFile) { + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + bs.setCardHolderName(entry.getCardHolderName()); + bs.setIdCardNo(null); + bs.setPhone(null); + bs.setCardNumber(entry.getCardNumber()); + String cardNumber = bs.getCardNumber(); + if (StrUtil.isNotEmpty(cardNumber) && oaiMap.containsKey(cardNumber)) { + importService.setIdCardAndPhoneByCardNumber(oaiMap, cardNumber, bs); + } + bs.setCounterpartyName(entry.getCounterpartyName()); + bs.setCounterpartIdCardNo(entry.getCounterpartyIdCardNo()); + bs.setCounterpartyAccount(entry.getCounterpartyAccount()); + bs.setCounterpartyBankName(entry.getCounterpartyBankName()); + bs.setSummary(entry.getSummary()); + bs.setTransRemark(entry.getTransRemark()); + bs.setTransChannel(entry.getTransChannel()); + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + bs.setTransactionInstitutions(entry.getTransInstitutions()); + bs.setTransactionAmount(entry.getTransactionAmount()); + // 交易时间 + String transDate = entry.getTransDate(); // 2008-05-12 + if (StrUtil.isNotEmpty(transDate)) { + + String format = null; + // 如果包含-,则为yyyy-MM-dd + // 如果包含/,则为yyyy/MM/dd + if (transDate.contains("-")) { + format = "yyyy-MM-dd"; + } else if (transDate.contains("/")) { + format = "yyyy/MM/dd"; + } + + String transTime = entry.getTransTime(); // 15:53:51 + if (StrUtil.isNotEmpty(transTime)) { + + if (transTime.contains(":")) { + format = format + " HH:mm:ss"; + } else { + format = format + " HHmmss"; + } + + transDate += " " + transTime; + } + + try { + bs.setTransactionTime(DateUtil.parse(transDate, format)); + } catch (Exception e) { + log.error("解析交易时间失败", e); + + throw new AnalyzeDataFailedException(StrUtil.format("解析交易时间字符串[{}]失败", transDate), e, sourceFile); + } + } + + bs.setBalance(entry.getBalance()); + + return bs; + } + + + /** + * 招商银行银行流水 + */ + private void readMerchantsBankStatement(File csvFile) { + Class clazz = CMBStatementEntry.class; + try { + ExcelReader reader = EasyExcel.read(csvFile).charset(Charset.forName("GBK")).build(); + ReadSheet sheet = EasyExcel.readSheet() + .headRowNumber(1) + .head(clazz) + .registerReadListener(HelperUtil.getReadListener(statementMapper, clazz, false,csvFile.getAbsolutePath().split("招商银行")[1])) + .build(); + reader.read(sheet); + + + } catch (Exception e) { + log.error("读取招商银行流水失败", e); + throw new ImportDataFailedException(e.getMessage(), csvFile.getAbsolutePath()); + } + } + + /** + * 招商银行零售流水 + */ + private void readMerchantsBankRetailStatement(File csvFile) { + try (ExcelReader reader = + EasyExcel.read(csvFile).charset(Charset.forName("GBK")).build()) { + ReadSheet sheet = EasyExcel.readSheet() + .headRowNumber(1) + .head(CMBRetailStatementEntry.class) + .registerReadListener(new ReadListener() { + + private static final int BATCH_SIZE = 200; + + private List cache = + ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + + @Override + public void invoke(CMBRetailStatementEntry entry, AnalysisContext analysisContext) { + + String id = IdUtil.objectId(); + entry.setId(id); + + + + cache.add(entry); + + if (cache.size() >= BATCH_SIZE) { + saveData(); + cache = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + log.info("读取招商银行零售流水数据结束"); + + if (!cache.isEmpty()) { + saveData(); + } + } + + private void saveData() { + + retailStatementMapper.insertBatch(cache); + + log.info("{}条数据,开始存储ES数据库!", cache.size()); + log.info("存储ES数据库成功!"); + } + }) + .build(); + reader.read(sheet); + + + } catch (Exception e) { + log.error("读取招商银行零售流水失败", e); + throw new ImportDataFailedException(e.getMessage(), csvFile.getAbsolutePath()); + } + } + + private void readMerchantsBankCustomerInfo(File csvFile) { + try (ExcelReader reader = + EasyExcel.read(csvFile).charset(Charset.forName("GBK")).build()) { + ReadSheet sheet = EasyExcel.readSheet() + .headRowNumber(1) + .head(CMBOpeningAccountInfoEntry.class) + .registerReadListener(new CMBOpeningAccountInfoReadListener(openingAccountInfoMapper)) + .build(); + reader.read(sheet); + } catch (Exception e) { + log.error("读取招商银行客户信息失败", e); + throw new ImportDataFailedException(e.getMessage(), csvFile.getAbsolutePath()); + } + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/EsIndexHelper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/EsIndexHelper.java new file mode 100644 index 0000000..c0f3481 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/EsIndexHelper.java @@ -0,0 +1,526 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.datacenter.mapper.es.*; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +/** + * ES索引管理 + */ +@Component +@RequiredArgsConstructor +public class EsIndexHelper { + // 1 CCB 建设银行 + private final EsCCBCurrentAccountInfoMapper esCCBCurrentAccountInfoMapper; + private final EsCCBCurrentBankStatementMapper esCCBCurrentBankStatementMapper; + private final EsCCBElectronicCashAccountInfoMapper esCCBElectronicCashAccountInfoMapper; + private final EsCCBElectronicCashBankStatementMapper esCCBElectronicCashBankStatementMapper; + private final EsCCBRegularBankStatementMapper esCCBRegularBankStatementMapper; + // 2 FDB 富滇银行 + private final EsFDBPrivateAccountOpeningInfoMapper fdbPrivateAccountOpeningInfoMapper; + private final EsFDBPublicAccountOpeningInfoMapper fdbPublicAccountOpeningInfoMapper; + private final EsFDBStatementMapper fdbStatementMapper; + // 3 BOC 中国银行 + private final EsBOCPrivateBankStatementMapper bocPrivateBankStatementMapper; + + // 4 CITIC 中信银行 + private final EsCITICBankStatementMapper esCITICBankStatementMapper; + private final EsCITICOpeningAccountInfoMapper esCITICOpeningAccountInfoMapper; + // 5 CMB 招商银行 + private final EsCMBOpeningAccountInfoMapper esCMBOpeningAccountInfoMapper; + private final EsCMBStatementMapper esCMBStatementMapper; + private final EsCMBRetailStatementMapper esCMBRetailStatementMapper; + // 6 ICBC 工商银行 + private final EsICBCBankStatementMapper esICBCBankStatementMapper; + private final EsICBCCreditCardBankStatementMapper esICBCCreditCardBankStatementMapper; + + // 7 RCC 农村信用社 + private final EsRCCBankStatementMapper esRCCBankStatementMapper; + private final EsRCCOpeningAccountInfoMapper esRCCOpeningAccountInfoMapper; + // 8 SPDB 浦发银行 + private final EsSPDBBSMapper esSPDBBSMapper; + // 9 HUAXIA 华夏银行 + private final EsHuaXiaAccountInfoMapper esHuaXiaAccountInfoMapper; + private final EsHXBankStatementMapper esHXBankStatementMapper; + private final EsHXPersonalBankStatementMapper esHXPersonalBankStatementMapper; + // 10 PAB 平安银行 + private final EsSPABANKOpeningAccountInfoMapper esSPAAccountInfoMapper; + private final EsSPACustomerInfoMapper esSPACustomerInfoMapper; + private final EsSPABANKStatementMapper esSPAStatementMapper; + private final EsSPACreditCardStatementMapper esSPACreditCardStatementMapper; + private final EsSPACreditCardAccountInfoMapper esSPACreditCardAccountInfoMapper; + // 11 CIB 兴业银行 + private final EsCIBOpeningAccountInfoMapper esCIBOpeningAccountInfoMapper; + private final EsCIBCreditCardBankStatementMapper esCIBCreditCardBankStatementMapper; + private final EsCIBStatementMapper esCIBStatementMapper; + // 12 CMBC 民生银行 + private final EsCMBCSavingsCardAccountInfoMapper esCMBCSavingsCardAccountInfoMapper; + private final EsCMBCCreditCardAccountInfoMapper esCMBCCreditCardAccountInfoMapper; + private final EsCMBCSavingsCardBankStatementMapper esCMBCSavingsCardBankStatementMapper; + private final EsCMBCCreditCardBankStatementMapper esCMBCCreditCardBankStatementMapper; + private final EsCMBCSavingsCardCompanyInfoMapper esCMBCSavingsCardCompanyInfoMapper; + // 13 BOCOM 交通银行 + private final EsBOCOMAccountInfoMapper esBOCOMAccountInfoMapper; + private final EsBOCOMStatementMapper esBOCOMStatementMapper; + // 14 QJCCB 曲靖商业银行 + private final EsQJCCBStatementMapper esQJCCBStatementMapper; + // 15 PSBC 邮储银行 + private final EsPSBCOpeningAccountInfoMapper esPSBCOpeningAccountInfoMapper; + private final EsPSBCStatementMapper esPSBCStatementMapper; + // 16 CGBC 广发银行 + private final EsCGBCCreditCardAccountInfoMapper esCGBCCreditCardAccountInfoMapper; + private final EsCGBCNewCustomerInfoMapper esCGBCNewCustomerInfoMapper; + private final EsCGBCCreditCardStatementMapper esCGBCCreditCardStatementMapper; + private final EsCGBCCreditCardOtherStatementMapper esCGBCCreditCardOtherStatementMapper; + private final EsCGBCNewStatementMapper esCGBCNewStatementMapper; + private final EsCGBCStatementMapper esCGBCStatementMapper; + // 17 CEB 光大银行 + private final EsCEBCreditCardStatementMapper esCEBCreditCardStatementMapper; + private final EsCEBSavingsCardStatementMapper esCEBSavingsCardStatementMapper; + // 18 ABC 农业银行 + private final EsABCCustomerStatementMapper esABCCustomerStatementMapper; + private final EsABCCompanyStatementMapper esABCCompanyStatementMapper; + private final EsABCCustomerInfoMapper esABCCustomerInfoMapper; + private final EsABCCompanyInfoMapper esABCCompanyInfoMapper; + + // 19 CGS 央地系统 + private final CGSOpeningAccountInfoMapper cgsOpeningAccountInfoMapper; + private final CGSStatementMapper cgsStatementMapper; + + // 20 恒丰银行 + private final HFCompanyStatementMapper hfCompanyStatementMapper; + private final HFCompanyStatementV2Mapper hfCompanyStatementV2Mapper; + + + public void delABCIndex(String caseId) { +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_ABC_CUSTOMER_STATEMENT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_ABC_COMPANY_STATEMENT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_ABC_CUSTOMER_OPENING_ACCOUNT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_ABC_COMPANY_OPENING_ACCOUNT,caseId); + + + esABCCustomerStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_ABC_CUSTOMER_STATEMENT); + esABCCompanyStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_ABC_COMPANY_STATEMENT); + esABCCustomerInfoMapper.deleteIndex(Constants.ES_INDEX_NAME_ABC_CUSTOMER_OPENING_ACCOUNT); + esABCCompanyInfoMapper.deleteIndex(Constants.ES_INDEX_NAME_ABC_COMPANY_OPENING_ACCOUNT); + } + + public void createABCIndex() { + if (!esABCCustomerStatementMapper.existsIndex(Constants.ES_INDEX_NAME_ABC_CUSTOMER_STATEMENT)) { + esABCCustomerStatementMapper.createIndex(); + } + if (!esABCCompanyStatementMapper.existsIndex(Constants.ES_INDEX_NAME_ABC_COMPANY_STATEMENT)) { + esABCCompanyStatementMapper.createIndex(); + } + if (!esABCCustomerInfoMapper.existsIndex(Constants.ES_INDEX_NAME_ABC_CUSTOMER_OPENING_ACCOUNT)) { + esABCCustomerInfoMapper.createIndex(); + } + if (!esABCCompanyInfoMapper.existsIndex(Constants.ES_INDEX_NAME_ABC_COMPANY_OPENING_ACCOUNT)) { + esABCCompanyInfoMapper.createIndex(); + } + } + + public void delCEBIndex() { + esCEBCreditCardStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_CEB_CREDIT_CARD_STATEMENT); + esCEBSavingsCardStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_CEB_SAVINGS_CARD_STATEMENT); + } + + public void createCEBIndex() { + esCEBCreditCardStatementMapper.createIndex(); + esCEBSavingsCardStatementMapper.createIndex(); + } + + public void delCGBCIndex(String caseId) { +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CGBC_OPENING_ACCOUNT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CGBC_CUSTOMER_INFO,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CGBC_CREDIT_CARD_STATEMENT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CGBC_OTHER_CREDIT_CARD_STATEMENT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CGBC_SAVINGS_CARD_NEW_STATEMENT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CGBC_SAVINGS_CARD_STATEMENT,caseId); + + esCGBCCreditCardAccountInfoMapper.deleteIndex(Constants.ES_INDEX_NAME_CGBC_OPENING_ACCOUNT); + esCGBCNewCustomerInfoMapper.deleteIndex(Constants.ES_INDEX_NAME_CGBC_CUSTOMER_INFO); + esCGBCCreditCardStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_CGBC_CREDIT_CARD_STATEMENT); + esCGBCCreditCardOtherStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_CGBC_OTHER_CREDIT_CARD_STATEMENT); + esCGBCNewStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_CGBC_SAVINGS_CARD_NEW_STATEMENT); + esCGBCStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_CGBC_SAVINGS_CARD_STATEMENT); + } + + public void createCGBCIndex() { + if (!esCGBCCreditCardAccountInfoMapper.existsIndex(Constants.ES_INDEX_NAME_CGBC_OPENING_ACCOUNT)) { + esCGBCCreditCardAccountInfoMapper.createIndex(); + } + if (!esCGBCNewCustomerInfoMapper.existsIndex(Constants.ES_INDEX_NAME_CGBC_CUSTOMER_INFO)) { + esCGBCNewCustomerInfoMapper.createIndex(); + } + if (!esCGBCCreditCardStatementMapper.existsIndex(Constants.ES_INDEX_NAME_CGBC_CREDIT_CARD_STATEMENT)) { + esCGBCCreditCardStatementMapper.createIndex(); + } + if (!esCGBCCreditCardOtherStatementMapper.existsIndex(Constants.ES_INDEX_NAME_CGBC_OTHER_CREDIT_CARD_STATEMENT)) { + esCGBCCreditCardOtherStatementMapper.createIndex(); + } + if (!esCGBCNewStatementMapper.existsIndex(Constants.ES_INDEX_NAME_CGBC_SAVINGS_CARD_NEW_STATEMENT)) { + esCGBCNewStatementMapper.createIndex(); + } + if (!esCGBCStatementMapper.existsIndex(Constants.ES_INDEX_NAME_CGBC_SAVINGS_CARD_STATEMENT)) { + esCGBCStatementMapper.createIndex(); + } + + } + + public void delPSBCIndex(String caseId) { +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_PSBC_ACCOUNT_INFO,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_PSBC_STATEMENT,caseId); + + esPSBCOpeningAccountInfoMapper.deleteIndex(Constants.ES_INDEX_NAME_PSBC_ACCOUNT_INFO); + esPSBCStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_PSBC_STATEMENT); + } + + public void createPSBCIndex() { + if (!esPSBCOpeningAccountInfoMapper.existsIndex(Constants.ES_INDEX_NAME_PSBC_ACCOUNT_INFO)) { + esPSBCOpeningAccountInfoMapper.createIndex(); + } + if (!esPSBCStatementMapper.existsIndex(Constants.ES_INDEX_NAME_PSBC_STATEMENT)) { + esPSBCStatementMapper.createIndex(); + } + } + + public void delQJCCBIndex(String caseId) { +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_QJCCB_STATEMENT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_QJCCB_ACCOUNT_INFO,caseId); + + esQJCCBStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_QJCCB_STATEMENT); + } + + public void createQJCCBIndex() { + if (!esQJCCBStatementMapper.existsIndex(Constants.ES_INDEX_NAME_QJCCB_STATEMENT)) { + esQJCCBStatementMapper.createIndex(); + } + } + + public void delBOCOMIndex(String caseId) { +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_BOCOM_OPENING_ACCOUNT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_BOCOM_STATEMENT,caseId); + + esBOCOMAccountInfoMapper.deleteIndex(Constants.ES_INDEX_NAME_BOCOM_OPENING_ACCOUNT); + esBOCOMStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_BOCOM_STATEMENT); + } + + public void createBOCOMIndex() { + if (!esBOCOMAccountInfoMapper.existsIndex(Constants.ES_INDEX_NAME_BOCOM_OPENING_ACCOUNT)) { + esBOCOMAccountInfoMapper.createIndex(); + } + if (!esBOCOMStatementMapper.existsIndex(Constants.ES_INDEX_NAME_BOCOM_STATEMENT)) { + esBOCOMStatementMapper.createIndex(); + } + } + + public void delCMBCIndex(String caseId) { +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CMBC_CREDIT_CARD_OPENING_ACCOUNT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CMBC_CREDIT_CARD_STATEMENT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CMBC_SAVINGS_CARD_OPENING_ACCOUNT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CMBC_SAVINGS_CARD_STATEMENT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CMBC_SAVINGS_CARD_COMPANY_INFO,caseId); + + esCMBCCreditCardAccountInfoMapper.deleteIndex(Constants.ES_INDEX_NAME_CMBC_CREDIT_CARD_OPENING_ACCOUNT); + esCMBCCreditCardBankStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_CMBC_CREDIT_CARD_STATEMENT); + esCMBCSavingsCardAccountInfoMapper.deleteIndex(Constants.ES_INDEX_NAME_CMBC_SAVINGS_CARD_OPENING_ACCOUNT); + esCMBCSavingsCardBankStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_CMBC_SAVINGS_CARD_STATEMENT); + esCMBCSavingsCardCompanyInfoMapper.deleteIndex(Constants.ES_INDEX_NAME_CMBC_SAVINGS_CARD_COMPANY_INFO); + } + + public void createCMBCIndex() { + if (!esCMBCCreditCardAccountInfoMapper.existsIndex(Constants.ES_INDEX_NAME_CMBC_CREDIT_CARD_OPENING_ACCOUNT)) { + esCMBCCreditCardAccountInfoMapper.createIndex(); + } + if (!esCMBCCreditCardBankStatementMapper.existsIndex(Constants.ES_INDEX_NAME_CMBC_CREDIT_CARD_STATEMENT)) { + esCMBCCreditCardBankStatementMapper.createIndex(); + } + if (!esCMBCSavingsCardAccountInfoMapper.existsIndex(Constants.ES_INDEX_NAME_CMBC_SAVINGS_CARD_OPENING_ACCOUNT)) { + esCMBCSavingsCardAccountInfoMapper.createIndex(); + } + if (!esCMBCSavingsCardBankStatementMapper.existsIndex(Constants.ES_INDEX_NAME_CMBC_SAVINGS_CARD_STATEMENT)) { + esCMBCSavingsCardBankStatementMapper.createIndex(); + } + if (!esCMBCSavingsCardCompanyInfoMapper.existsIndex(Constants.ES_INDEX_NAME_CMBC_SAVINGS_CARD_COMPANY_INFO)) { + esCMBCSavingsCardCompanyInfoMapper.createIndex(); + } + } + + public void delCIBIndex(String caseId) { +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CIB_OPENING_ACCOUNT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CIB_CREDIT_CARD_STATEMENT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CIB_STATEMENT,caseId); + + esCIBOpeningAccountInfoMapper.deleteIndex(Constants.ES_INDEX_NAME_CIB_OPENING_ACCOUNT); + esCIBCreditCardBankStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_CIB_CREDIT_CARD_STATEMENT); + esCIBStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_CIB_STATEMENT); + } + + public void createCIBIndex() { + if (!esCIBOpeningAccountInfoMapper.existsIndex(Constants.ES_INDEX_NAME_CIB_OPENING_ACCOUNT)) { + esCIBOpeningAccountInfoMapper.createIndex(); + } + if (!esCIBCreditCardBankStatementMapper.existsIndex(Constants.ES_INDEX_NAME_CIB_CREDIT_CARD_STATEMENT)) { + esCIBCreditCardBankStatementMapper.createIndex(); + } + if (!esCIBStatementMapper.existsIndex(Constants.ES_INDEX_NAME_CIB_STATEMENT)) { + esCIBStatementMapper.createIndex(); + } + } + + public void delSPAIndex(String caseId) { +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_PING_AN_ACCOUNT_INFO,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_PING_AN_CUSTOMER_INFO,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_PING_AN_STATEMENT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_PING_AN_CREDIT_CARD_ACCOUNT_INFO,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_PING_AN_CREDIT_CARD_STATEMENT,caseId); + + esSPAAccountInfoMapper.deleteIndex(Constants.ES_INDEX_NAME_PING_AN_ACCOUNT_INFO); + esSPACustomerInfoMapper.deleteIndex(Constants.ES_INDEX_NAME_PING_AN_CUSTOMER_INFO); + esSPAStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_PING_AN_STATEMENT); + esSPACreditCardAccountInfoMapper.deleteIndex(Constants.ES_INDEX_NAME_PING_AN_CREDIT_CARD_ACCOUNT_INFO); + esSPACreditCardStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_PING_AN_CREDIT_CARD_STATEMENT); + } + + public void createSPAIndex() { + if (!esSPAAccountInfoMapper.existsIndex(Constants.ES_INDEX_NAME_PING_AN_ACCOUNT_INFO)) { + esSPAAccountInfoMapper.createIndex(); + } + if (!esSPACustomerInfoMapper.existsIndex(Constants.ES_INDEX_NAME_PING_AN_CUSTOMER_INFO)) { + esSPACustomerInfoMapper.createIndex(); + } + if (!esSPAStatementMapper.existsIndex(Constants.ES_INDEX_NAME_PING_AN_STATEMENT)) { + esSPAStatementMapper.createIndex(); + } + if (!esSPACreditCardAccountInfoMapper.existsIndex(Constants.ES_INDEX_NAME_PING_AN_CREDIT_CARD_ACCOUNT_INFO)) { + esSPACreditCardAccountInfoMapper.createIndex(); + } + if (!esSPACreditCardStatementMapper.existsIndex(Constants.ES_INDEX_NAME_PING_AN_CREDIT_CARD_STATEMENT)) { + esSPACreditCardStatementMapper.createIndex(); + } + } + + public void delHuaXiaIndex(String caseId) { +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_HUAXIA_OPENING_ACCOUNT_INFO,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_HUAXIA_STATEMENT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_HUAXIA_STATEMENT_PERSONAL,caseId); + + esHuaXiaAccountInfoMapper.deleteIndex(Constants.ES_INDEX_NAME_HUAXIA_OPENING_ACCOUNT_INFO); + esHXBankStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_HUAXIA_STATEMENT); + esHXPersonalBankStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_HUAXIA_STATEMENT_PERSONAL); + } + + public void createHuaXiaIndex() { + if (!esHuaXiaAccountInfoMapper.existsIndex(Constants.ES_INDEX_NAME_HUAXIA_OPENING_ACCOUNT_INFO)) { + esHuaXiaAccountInfoMapper.createIndex(); + } + if (!esHXBankStatementMapper.existsIndex(Constants.ES_INDEX_NAME_HUAXIA_STATEMENT)) { + esHXBankStatementMapper.createIndex(); + } + if (!esHXPersonalBankStatementMapper.existsIndex(Constants.ES_INDEX_NAME_HUAXIA_STATEMENT_PERSONAL)) { + esHXPersonalBankStatementMapper.createIndex(); + } + } + + public void delSPDBIndex(String caseId) { +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_SPDB_CREDIT_CARD_CUSTOMER_STATEMENT,caseId); + + esSPDBBSMapper.deleteIndex(Constants.ES_INDEX_NAME_SPDB_CREDIT_CARD_CUSTOMER_STATEMENT); + } + + public void createSPDBIndex() { + if (!esSPDBBSMapper.existsIndex(Constants.ES_INDEX_NAME_SPDB_CREDIT_CARD_CUSTOMER_STATEMENT)) { + esSPDBBSMapper.createIndex(); + } + } + + public void delRCCIndex(String caseId) { +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_RCC_STATEMENT,caseId); +// queryCenterService.deleteData(Constants.MONGO_COLLECTION_NAME_RCC_OPENING_ACCOUNT,caseId); + + esRCCBankStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_RCC_STATEMENT); + esRCCOpeningAccountInfoMapper.deleteIndex(Constants.MONGO_COLLECTION_NAME_RCC_OPENING_ACCOUNT); + } + + public void createRCCIndex() { + if (!esRCCBankStatementMapper.existsIndex(Constants.ES_INDEX_NAME_RCC_STATEMENT)) { + esRCCBankStatementMapper.createIndex(); + } + if (!esRCCOpeningAccountInfoMapper.existsIndex(Constants.MONGO_COLLECTION_NAME_RCC_OPENING_ACCOUNT)) { + esRCCOpeningAccountInfoMapper.createIndex(); + } + } + + public void delICBCIndex(String caseId) { +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_ICBC_STATEMENT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_ICBC_STATEMENT_CREDIT_CARD,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_ICBC_OPENING_ACCOUNT,caseId); + + esICBCBankStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_ICBC_STATEMENT); + esICBCCreditCardBankStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_ICBC_STATEMENT_CREDIT_CARD); + } + + public void createICBCIndex() { + if (!esICBCBankStatementMapper.existsIndex(Constants.ES_INDEX_NAME_ICBC_STATEMENT)) { + esICBCBankStatementMapper.createIndex(); + } + if (!esICBCCreditCardBankStatementMapper.existsIndex(Constants.ES_INDEX_NAME_ICBC_STATEMENT_CREDIT_CARD)) { + esICBCCreditCardBankStatementMapper.createIndex(); + } + } + + public void delCMBIndex(String caseId) { +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CMB_RETAIL_STATEMENT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CMB_STATEMENT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CMB_OPENING_ACCOUNT,caseId); + + esCMBRetailStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_CMB_RETAIL_STATEMENT); + esCMBStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_CMB_STATEMENT); + esCMBOpeningAccountInfoMapper.deleteIndex(Constants.ES_INDEX_NAME_CMB_OPENING_ACCOUNT); + } + + public void createCMBIndex() { + if (!esCMBRetailStatementMapper.existsIndex(Constants.ES_INDEX_NAME_CMB_RETAIL_STATEMENT)) { + esCMBRetailStatementMapper.createIndex(); + } + if (!esCMBStatementMapper.existsIndex(Constants.ES_INDEX_NAME_CMB_STATEMENT)) { + esCMBStatementMapper.createIndex(); + } + if (!esCMBOpeningAccountInfoMapper.existsIndex(Constants.ES_INDEX_NAME_CMB_OPENING_ACCOUNT)) { + esCMBOpeningAccountInfoMapper.createIndex(); + } + } + + public void delCITICIndex(String caseId) { +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CITIC_STATEMENT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CITIC_OPENING_ACCOUNT,caseId); + + esCITICBankStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_CITIC_STATEMENT); + esCITICOpeningAccountInfoMapper.deleteIndex(Constants.ES_INDEX_NAME_CITIC_OPENING_ACCOUNT); + } + + public void createCITICIndex() { + if (!esCITICBankStatementMapper.existsIndex(Constants.ES_INDEX_NAME_CITIC_STATEMENT)) { + esCITICBankStatementMapper.createIndex(); + } + if (!esCITICOpeningAccountInfoMapper.existsIndex(Constants.ES_INDEX_NAME_CITIC_OPENING_ACCOUNT)) { + esCITICOpeningAccountInfoMapper.createIndex(); + } + } + + public void delBOCIndex(String caseId) { +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_BOC_PRIVATE_ACCOUNT_INFO,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_BOC_PRIVATE_BASIC_INFO,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_BOC_STATEMENT_PRIVATE,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_BOC_PUBLIC_OPENING_ACCOUNT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_BOC_STATEMENT_PUBLIC,caseId); + + bocPrivateBankStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_BOC_STATEMENT_PRIVATE); + + } + + public void createBOCIndex() { + if (!bocPrivateBankStatementMapper.existsIndex(Constants.ES_INDEX_NAME_BOC_STATEMENT_PRIVATE)) { + bocPrivateBankStatementMapper.createIndex(); + } + + } + + public void delFDBIndex(String caseId) { + if (fdbStatementMapper.existsIndex(Constants.ES_INDEX_NAME_FDB_STATEMENT)) { + fdbStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_FDB_STATEMENT); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_FDB_STATEMENT,caseId); + }else { + fdbStatementMapper.createIndex(); + } + + if (fdbPrivateAccountOpeningInfoMapper.existsIndex(Constants.ES_INDEX_NAME_FDB_OPENING_ACCOUNT_PRIVATE)) { + fdbPrivateAccountOpeningInfoMapper.deleteIndex(Constants.ES_INDEX_NAME_FDB_OPENING_ACCOUNT_PRIVATE); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_FDB_OPENING_ACCOUNT_PRIVATE,caseId); + }else { + fdbPrivateAccountOpeningInfoMapper.createIndex(); + } + + if (fdbPublicAccountOpeningInfoMapper.existsIndex(Constants.ES_INDEX_NAME_FDB_OPENING_ACCOUNT_PUBLIC)) { + fdbPublicAccountOpeningInfoMapper.deleteIndex(Constants.ES_INDEX_NAME_FDB_OPENING_ACCOUNT_PUBLIC); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_FDB_OPENING_ACCOUNT_PUBLIC,caseId); + }else { + fdbPublicAccountOpeningInfoMapper.createIndex(); + } + } + + + public void createCCBIndex() { + + if (!esCCBCurrentAccountInfoMapper.existsIndex(Constants.ES_INDEX_NAME_CCB_OPENING_ACCOUNT)) { + esCCBCurrentAccountInfoMapper.createIndex(); + } + if (!esCCBCurrentBankStatementMapper.existsIndex(Constants.ES_INDEX_NAME_CCB_CURRENT_STATEMENT)) { + esCCBCurrentBankStatementMapper.createIndex(); + } + if (!esCCBElectronicCashAccountInfoMapper.existsIndex(Constants.ES_INDEX_NAME_CCB_ELECTRONIC_CASH_OPENING_ACCOUNT)) { + esCCBElectronicCashAccountInfoMapper.createIndex(); + } + if (!esCCBElectronicCashBankStatementMapper.existsIndex(Constants.ES_INDEX_NAME_CCB_ELECTRONIC_CASH_STATEMENT)) { + esCCBElectronicCashBankStatementMapper.createIndex(); + } + if (!esCCBRegularBankStatementMapper.existsIndex(Constants.ES_INDEX_NAME_CCB_REGULAR_STATEMENT)) { + esCCBRegularBankStatementMapper.createIndex(); + } + } + + public void delCCBIndex(String caseId) { +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CCB_OPENING_ACCOUNT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CCB_CURRENT_STATEMENT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CCB_ELECTRONIC_CASH_OPENING_ACCOUNT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CCB_ELECTRONIC_CASH_STATEMENT,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CCB_REGULAR_STATEMENT,caseId); + + esCCBCurrentAccountInfoMapper.deleteIndex(Constants.ES_INDEX_NAME_CCB_OPENING_ACCOUNT); + esCCBCurrentBankStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_CCB_CURRENT_STATEMENT); + esCCBElectronicCashAccountInfoMapper.deleteIndex(Constants.ES_INDEX_NAME_CCB_ELECTRONIC_CASH_OPENING_ACCOUNT); + esCCBElectronicCashBankStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_CCB_ELECTRONIC_CASH_STATEMENT); + esCCBRegularBankStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_CCB_REGULAR_STATEMENT); + } + + public void delCGSIndex(String caseId) { +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CGS_OPEN_ACCOUNT_INFO,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CGS_STATEMENT,caseId); + + cgsOpeningAccountInfoMapper.deleteIndex(Constants.ES_INDEX_NAME_CGS_OPEN_ACCOUNT_INFO); + cgsStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_CGS_STATEMENT); + } + + public void createCGSIndex() { + if (!cgsOpeningAccountInfoMapper.existsIndex(Constants.ES_INDEX_NAME_CGS_OPEN_ACCOUNT_INFO)) { + cgsOpeningAccountInfoMapper.createIndex(); + } + if (!cgsStatementMapper.existsIndex(Constants.ES_INDEX_NAME_CGS_STATEMENT)) { + cgsStatementMapper.createIndex(); + } + } + + public void delHFBIndex(String caseId) { +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CGS_OPEN_ACCOUNT_INFO,caseId); +// queryCenterService.deleteData(Constants.ES_INDEX_NAME_CGS_STATEMENT,caseId); + + hfCompanyStatementMapper.deleteIndex(Constants.ES_INDEX_NAME_HF_COMPANY_STATEMENT); + hfCompanyStatementV2Mapper.deleteIndex(Constants.ES_INDEX_NAME_HF_COMPANY_STATEMENT_V2); + + } + + public void createHFBIndex() { + if (!hfCompanyStatementMapper.existsIndex(Constants.ES_INDEX_NAME_HF_COMPANY_STATEMENT)) { + hfCompanyStatementMapper.createIndex(); + } + if (!hfCompanyStatementV2Mapper.existsIndex(Constants.ES_INDEX_NAME_HF_COMPANY_STATEMENT_V2)) { + hfCompanyStatementV2Mapper.createIndex(); + } + } + + + + +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/EsMapperHolder.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/EsMapperHolder.java new file mode 100644 index 0000000..31052e0 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/EsMapperHolder.java @@ -0,0 +1,27 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import com.inscloudtech.datacenter.mapper.es.*; +import lombok.Getter; +import lombok.Setter; + +/** + * 需要在EsListener中配置 + */ +public class EsMapperHolder { + private EsMapperHolder() { + } + + + @Getter + @Setter + private static ESBankStatementMapper esBankStatementMapper; + + @Getter + @Setter + private static ESOpeningAccountInfoMapper esOpeningAccountInfoMapper; + + @Getter + @Setter + private static PlateNumberEsMapper plateNumberEsMapper; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/FDBDataAnalysisHelper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/FDBDataAnalysisHelper.java new file mode 100644 index 0000000..bf12dbd --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/FDBDataAnalysisHelper.java @@ -0,0 +1,519 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.util.ListUtils; +import com.aspose.cells.Cell; +import com.aspose.cells.Cells; +import com.aspose.cells.Workbook; +import com.aspose.cells.Worksheet; + +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.bankStatementAnalysis.service.ImportService; +import com.inscloudtech.common.constant.BankStatementConstants; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.exception.dc.AnalyzeDataFailedException; +import com.inscloudtech.common.exception.dc.ImportDataFailedException; +import com.inscloudtech.common.exception.dc.TemplateNotFindException; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.mapper.es.EsFDBPrivateAccountOpeningInfoMapper; +import com.inscloudtech.datacenter.mapper.es.EsFDBPublicAccountOpeningInfoMapper; +import com.inscloudtech.datacenter.mapper.es.EsFDBStatementMapper; +import com.inscloudtech.datacenter.service.ImportResultService; +import com.inscloudtech.bankStatementAnalysis.listener.FDBPrivateOpeningAccountInfoReadListener; +import com.inscloudtech.bankStatementAnalysis.listener.FDBPublicOpeningAccountInfoReadListener; +import com.inscloudtech.bankStatementAnalysis.listener.FDBStatementReadListener; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; +import com.inscloudtech.bankStatementAnalysis.domain.entity.FDBPrivateAccountOpeningInfoEntry; +import com.inscloudtech.bankStatementAnalysis.domain.entity.FDBPublicAccountOpeningInfoEntity; +import com.inscloudtech.bankStatementAnalysis.domain.entity.FDBStatementEntity; + +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.io.File; +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 富滇银行数据分析 + */ +@Transactional +@Slf4j +@RequiredArgsConstructor +@Component +public class FDBDataAnalysisHelper { + + private final ImportService importService; + private final ImportResultService importResultService; + private final EsFDBPublicAccountOpeningInfoMapper publicAccountOpeningInfoMapper; + private final EsFDBPrivateAccountOpeningInfoMapper privateAccountOpeningInfoMapper; + private final EsFDBStatementMapper statementMapper; + private final static String BANK_NAME = "富滇银行"; + + public void importData(File dir,String caseId) throws Exception { + List fileList = FileUtil.loopFiles(dir); + List excelFileList = HelperUtil.getExcelFile(fileList); + for (File excelFile : excelFileList) { + try { + String sourceFile = HelperUtil.getSourceFileName(excelFile.getAbsolutePath(), BANK_NAME); + Workbook wb = new Workbook(excelFile.getAbsolutePath()); + int cnt = wb.getWorksheets().getCount(); + + for (int sheetNo = 0; sheetNo < cnt; sheetNo++) { + try { + Worksheet worksheet = wb.getWorksheets().get(sheetNo); + Cells cells = worksheet.getCells(); + String sourceFileWithSheetName = sourceFile + BankStatementConstants.NAME_WITH_SHEET_NAME + worksheet.getName(); + // 应该靠内容来区分 + Cell cell = AsposeUtil.getCell(cells, "交易流水"); + Cell khmc = AsposeUtil.getCell(cells, "客户名称"); + if (cell != null) { + // 读取流水信息 + importBankStatement(excelFile, sheetNo, caseId); + } else if (khmc != null && cell == null) {//开户 + readOAI202407224(khmc,cells,sourceFileWithSheetName); + }else { + Cell khr = AsposeUtil.getCell(cells, "开户日"); + // 对公和对私怎么区分? + Cell dgck = AsposeUtil.getCell(excelFile, sheetNo, "对公存款"); + if (khr != null && dgck != null) { + // 对公 + importPublicOpeningAccountInfo(excelFile, sheetNo, caseId); + } else if (khr != null) { + // 对私 + // 个人开户 + int headRowNumber = khr.getRow() + 1; + importPrivateOpeningAccountInfo(excelFile, sheetNo, caseId, headRowNumber); + } else { + throw new TemplateNotFindException(sourceFileWithSheetName); + } + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + + } + + /** + * excel有两列 + * 客户名称 + * 李胜成 512223197408187972 + * 喻立红 530123197703253027 + * @param khmc + * @param cells + */ + private void readOAI202407224(Cell khmc, Cells cells,String sourceFileWithSheetName) { + int maxColumn = cells.getMaxColumn(); + if(maxColumn != 1){ + throw new TemplateNotFindException(sourceFileWithSheetName); + } + List cacheList = new ArrayList<>(); + for (int row = khmc.getRow() + 1; row <= cells.getMaxRow(); row++) { + FDBPrivateAccountOpeningInfoEntry entry = new FDBPrivateAccountOpeningInfoEntry(); + for (int col = 0; col < 2; col++) { + Cell cell = cells.get(row, col); + if (cell == null) { + continue; + } + String value = cell.getStringValue(); + if (StrUtil.isNotEmpty(value)) { + value = value.trim(); + } + if(col == 0){ + entry.setCardHolderName(value); + }else if(col == 1){ + entry.setIdCardNo(value); + } + } + entry.setId(IdUtil.objectId()); + cacheList.add(entry); + } + privateAccountOpeningInfoMapper.insertBatch(cacheList); + } + + public void analyzeData(String caseId) { + // 处理开户信息 + analyzeOAI(caseId); + // 处理流水信息 + analyzeBS(caseId); + } + + private void analyzeOAI(String caseId) { + + List oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + // 个人账户信息 + if(importService.existsIndex(Constants.ES_INDEX_NAME_FDB_OPENING_ACCOUNT_PRIVATE)){ + List entityList = + HelperUtil.getEntityList(privateAccountOpeningInfoMapper, FDBPrivateAccountOpeningInfoEntry.class); + Set uniqueKeySet = new HashSet(); + for (FDBPrivateAccountOpeningInfoEntry accInfo : entityList) { + + OpeningAccountInfo oai = getOpeningAccountInfo(accInfo); + + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + oaiList.add(oai); + if (oaiList.size() >= Constants.BATCH_SIZE) { + // 保存数据库 + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + if (!oaiList.isEmpty()) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + // 企业账户 + if(importService.existsIndex(Constants.ES_INDEX_NAME_FDB_OPENING_ACCOUNT_PUBLIC)){ + List entityList = + HelperUtil.getEntityList(publicAccountOpeningInfoMapper, FDBPublicAccountOpeningInfoEntity.class); + Set uniqueKeySet = new HashSet(); + for (FDBPublicAccountOpeningInfoEntity accInfo : entityList) { + + OpeningAccountInfo oai = getOpeningAccountInfo(accInfo); + + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + oaiList.add(oai); + if (oaiList.size() >= Constants.BATCH_SIZE) { + // 保存数据库 + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + } + + if (!oaiList.isEmpty()) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + } + } + + private static OpeningAccountInfo getOpeningAccountInfo( FDBPublicAccountOpeningInfoEntity accInfo) { + OpeningAccountInfo oai = new OpeningAccountInfo(); + oai.setBankName(BANK_NAME); + oai.setAccountOpeningInstitution(accInfo.getAccountOpeningInstitution()); + oai.setAccountNumber(accInfo.getCardNumber()); + oai.setName(accInfo.getCardHolderName()); + oai.setIdNo(accInfo.getIdCardNo()); + oai.setIdType(Constants.ID_TYPE_ID_CARD); + oai.setStatus(accInfo.getStatus()); + oai.setOpeningAccountDate(accInfo.getOpeningAccountDate()); + oai.setClosingDate(accInfo.getClosingDate()); + return oai; + } + + private static OpeningAccountInfo getOpeningAccountInfo( FDBPrivateAccountOpeningInfoEntry accInfo) { + OpeningAccountInfo oai = new OpeningAccountInfo(); + oai.setBankName(BANK_NAME); + oai.setAccountOpeningInstitution(accInfo.getAccountOpeningInstitution()); + oai.setAccountNumber(accInfo.getCardNumber()); + oai.setName(accInfo.getCardHolderName()); + oai.setIdNo(accInfo.getIdCardNo()); + oai.setIdType(Constants.ID_TYPE_ID_CARD); + oai.setStatus(accInfo.getStatus()); + oai.setOpeningAccountDate(accInfo.getOpeningAccountDate()); + oai.setClosingDate(accInfo.getClosingDate()); + + return oai; + } + + private void analyzeBS(String caseId) { + // 数据导入es后分析 + List entityList = HelperUtil.getEntityList(statementMapper, FDBStatementEntity.class); + + List bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List oaiData = importService.getOAIData(caseId, BANK_NAME); + Map> groupByCard = oaiData.stream().filter(item ->StrUtil.isNotEmpty(item.getAccountNumber())) + .collect(Collectors.groupingBy(OpeningAccountInfo::getAccountNumber)); + Map> groupByName = oaiData.stream().filter(item ->StrUtil.isNotEmpty(item.getName())) + .collect(Collectors.groupingBy(OpeningAccountInfo::getName)); + + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + for (FDBStatementEntity entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + + String customerName = entity.getCustomerName(); + bs.setCardHolderName(customerName);//1593 + + // 交易卡号 + String cardNumber = entity.getMasterAccount(); + bs.setCardNumber(cardNumber); + if (groupByName.containsKey(customerName)) { + List infoList = groupByName.get(customerName); + for (OpeningAccountInfo info : infoList) { + if (StrUtil.isNotEmpty(info.getIdNo())) { + bs.setIdCardNo(info.getIdNo()); + break; + } + } + } + + if(StrUtil.isEmpty(bs.getIdCardNo())){ + if(groupByCard.containsKey(cardNumber)){ + List oaiList = groupByCard.get(cardNumber); + for (OpeningAccountInfo info : oaiList) { + if (StrUtil.isNotEmpty(info.getIdNo())) { + bs.setIdCardNo(info.getIdNo()); + break; + } + } + } + } + + + // 交易机构 + bs.setTransactionInstitutions(entity.getTransactionSituationName()); + + + String filename = entity.getSourceFile(); + + // 交易金额 + // 支出金额 + BigDecimal expenditureAmount = BigDecimal.ZERO; + String expenditureAmountStr = entity.getExpenditureAmount(); + if (StrUtil.isNotEmpty(expenditureAmountStr)) { + try { + if(expenditureAmountStr.contains(",")){ + expenditureAmountStr = expenditureAmountStr.replace(",",""); + } + expenditureAmount = BigDecimal.valueOf(Double.parseDouble(expenditureAmountStr)); + } catch (Exception e) { + log.error("解析支出金额失败: {}", e.getMessage()); + if (e instanceof NumberFormatException) { + throw new AnalyzeDataFailedException( + "解析支出金额失败:" + expenditureAmountStr + "无法转化为数字.", e, sourceFile); + } + } + } + // 收入金额 + BigDecimal revenueAmount = BigDecimal.ZERO; + String revenueAmountStr = entity.getRevenueAmount(); + if (StrUtil.isNotEmpty(revenueAmountStr)) { + try { + if(revenueAmountStr.contains(",")){ + revenueAmountStr = revenueAmountStr.replace(",",""); + } + revenueAmount = BigDecimal.valueOf(Double.parseDouble(revenueAmountStr)); + } catch (Exception e) { + log.error("解析收入金额失败: {}", e.getMessage()); + if (e instanceof NumberFormatException) { + throw new AnalyzeDataFailedException( + "解析收入金额失败, 字符串【" + revenueAmountStr + "】无法转化为金额数字.", e, sourceFile); + } + } + } + // 交易金额 + BigDecimal transactionAmount = revenueAmount.subtract(expenditureAmount); + bs.setTransactionAmount(transactionAmount); + // 摘要 + bs.setSummary(entity.getTransSummary()); + // 余额 + String balance = entity.getBalance(); + try { + if(balance.contains(",")){ + balance = balance.replace(",",""); + } + bs.setBalance(BigDecimal.valueOf(Double.parseDouble(balance))); + } catch (Exception e) { + log.error("解析余额失败, 字符串【" + balance + "】无法转化为金额数字.", e.getMessage()); + if (e instanceof NumberFormatException) { + throw new AnalyzeDataFailedException( + "解析余额失败, 字符串【" + balance + "】无法转化为金额数字.", e, sourceFile); + } + } + + // 对方账号 + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + // 对方名称 + String counterpartName = entity.getCounterpartyAccountName(); + bs.setCounterpartyName(counterpartName); + // 对方身份证号 + if (StringUtils.isNotEmpty(counterpartName)) { + if(groupByName.containsKey(counterpartName)){ + List oaiList = groupByName.get(counterpartName); + for (OpeningAccountInfo info : oaiList) { + if (StrUtil.isNotEmpty(info.getIdNo())) { + bs.setCounterpartIdCardNo(info.getIdNo()); + break; + } + } + } + } + // 对方行名 + bs.setCounterpartyBankName(entity.getCounterpartySituationName()); + + // 交易渠道 + bs.setTransChannel(entity.getTransChannel()); + + // 交易时间 + String transactionTime = entity.getTransactionTime(); + + try { + String format = "yyyyMMdd"; + if(transactionTime.contains("-")){ + format = "yyyy-MM-dd"; + } + bs.setTransactionTime(DateUtil.parse(transactionTime, format)); + } catch (Exception e) { + log.error("解析交易时间失败"+transactionTime+"无法转化为日期.", e.getMessage()); + throw new AnalyzeDataFailedException( + StrUtil.format("解析交易时间失败, {}无法转化为日期.", transactionTime), e, sourceFile); + } + + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + + bs.setTransactionInstitutions(entity.getTransactionSituationName()); + + String uniqueKey = caseId+entity.getCustomerName()+entity.getCardNumber()+entity.getRevenueAmount()+entity.getTransactionTime()+entity.getExpenditureAmount()+ + entity.getBalance() +entity.getTransSummary()+ entity.getTransNo()+entity.getTransChildNo(); + String md5Id = HelperUtil.generateMD5(uniqueKey); + + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entity.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + bs.setRemark(entity.getTransNo()+entity.getTransChildNo()); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e, sourceFile); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + private void importPublicOpeningAccountInfo(File file, int sheetNo,String caseId) { + Cell cell = AsposeUtil.getCell(file, sheetNo, "账户状态"); + if (cell == null) { + throw new RuntimeException("无法读取对公开户信息"); + } + + int headRowNumber = cell.getRow() + 1; + + try (ExcelReader excelReader = EasyExcel.read(file).build()) { + // 这里为了简单 所以注册了 同样的head 和Listener 自己使用功能必须不同的Listener + ReadSheet readSheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNumber) + .head(FDBPublicAccountOpeningInfoEntity.class) + .registerReadListener(new FDBPublicOpeningAccountInfoReadListener(publicAccountOpeningInfoMapper,caseId)) + .build(); + + excelReader.read(readSheet); + } catch (Exception e) { + throw new ImportDataFailedException(e.getMessage(), file.getAbsolutePath()); + } + } + + /** + * 富滇银行-流水数据 + */ + private void importBankStatement(File file, int sheetNo,String caseId) { + String sourceFile = HelperUtil.getSourceFileName(file.getAbsolutePath(),BANK_NAME); + Cell cell = AsposeUtil.getCell(file, sheetNo, "交易流水号"); + if (cell == null) { + throw new ImportDataFailedException("无法读取流水信息", sourceFile); + } + + int headRowNumber = cell.getRow() + 1; + + try (ExcelReader reader = EasyExcel.read(file).build()) { + ReadSheet statementSheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNumber) + .head(FDBStatementEntity.class) + .registerReadListener(new FDBStatementReadListener(statementMapper,sourceFile,caseId)) + .build(); + reader.read(statementSheet); + + + } catch (Exception e) { + throw new ImportDataFailedException(e.getMessage(), file.getAbsolutePath()); + } + } + + /** + * 富滇银行-开户信息-个人开户 + */ + private void importPrivateOpeningAccountInfo(File file, int sheetNo, String caseId,int headRowNumber) { + + + + try (ExcelReader excelReader = EasyExcel.read(file).build()) { + // 这里为了简单 所以注册了 同样的head 和Listener 自己使用功能必须不同的Listener + ReadSheet readSheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNumber) + .head(FDBPrivateAccountOpeningInfoEntry.class) + .registerReadListener(new FDBPrivateOpeningAccountInfoReadListener(privateAccountOpeningInfoMapper,caseId)) + .build(); + + excelReader.read(readSheet); + } catch (Exception e) { + log.error("导入个人开户信息失败", e); + throw new ImportDataFailedException(e.getMessage(), file.getAbsolutePath()); + } + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/HBDataAnalysisHelper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/HBDataAnalysisHelper.java new file mode 100644 index 0000000..1bf965a --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/HBDataAnalysisHelper.java @@ -0,0 +1,639 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.thread.ThreadUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.exception.ExcelDataConvertException; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.util.ListUtils; +import com.aspose.cells.*; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; + +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.bankStatementAnalysis.service.ImportService; +import com.inscloudtech.common.constant.BankStatementConstants; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.exception.dc.AnalyzeDataFailedException; +import com.inscloudtech.common.exception.dc.ImportDataFailedException; +import com.inscloudtech.common.exception.dc.TemplateNotFindException; +import com.inscloudtech.common.utils.BeanCopyUtils; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.mapper.es.ESOpeningAccountInfoMapper; +import com.inscloudtech.datacenter.mapper.es.EsHXBankStatementMapper; +import com.inscloudtech.datacenter.mapper.es.EsHXPersonalBankStatementMapper; +import com.inscloudtech.datacenter.mapper.es.EsHuaXiaAccountInfoMapper; +import com.inscloudtech.datacenter.service.ImportResultService; +import com.inscloudtech.bankStatementAnalysis.listener.ReadHuaXiaOpeningAccountInfoListener; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; +import com.inscloudtech.bankStatementAnalysis.domain.entity.HXBankStatementEntity; +import com.inscloudtech.bankStatementAnalysis.domain.entity.HXPersonalBankStatementEntity; +import com.inscloudtech.bankStatementAnalysis.domain.entity.HuaXiaAccountInfoEntity; + +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.util.*; +import java.util.stream.Collectors; + + + +/** + * 华夏银行数据分析 + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class HBDataAnalysisHelper { + + private final ImportService importService; + private final ImportResultService importResultService; + private final EsHuaXiaAccountInfoMapper accountInfoMapper; + private final EsHXBankStatementMapper statementMapper; + private final EsHXPersonalBankStatementMapper personalBankStatementMapper; + + private final static String BANK_NAME = "华夏银行"; + + private final ESOpeningAccountInfoMapper oaiMapper; + + public void importData(File file, String caseId) throws Exception { + + if (!file.exists()) { + return; + } + + List fileList = FileUtil.loopFiles(file); + + fileList = fileList.stream() + .filter(f -> f.getName().endsWith("xls") + || f.getName().endsWith("xlsx") + || f.getName().endsWith("csv")) + .collect(Collectors.toList()); + + for (File f : fileList) { + try { + String absolutePath = f.getAbsolutePath(); + String sourceFile = HelperUtil.getSourceFileName(absolutePath, BANK_NAME); + + Workbook wb; + try { + wb = new Workbook(absolutePath); + } catch (Exception e) { + if (e.getMessage().contains("password")) { + throw new AnalyzeDataFailedException("文件有密码无法解析", e, sourceFile); + } else { + throw new AnalyzeDataFailedException("解析文件失败",e,sourceFile); + } + } + + for (int sheetNum = 0; sheetNum < wb.getWorksheets().getCount(); sheetNum++) { + try { + Cells cells = wb.getWorksheets().get(sheetNum).getCells(); + Cell cell = AsposeUtil.getCell(cells, "开户日期"); + if (cell != null) { + readHuaXiaBankOpeningAccountInfo(f, cells, sheetNum); + } else { + cell = AsposeUtil.getCell(cells, "交易时间"); + Cell fseCell = AsposeUtil.getCell(cells, "发生额"); + if (cell != null) { + readHuaXiaBankStatement(f); + } else if (fseCell != null) { + readHuaXiaBankStatement(f); + } else { + throw new TemplateNotFindException(sourceFile + BankStatementConstants.NAME_WITH_SHEET_NAME + wb.getWorksheets().get(sheetNum).getName()); + } + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } + + + + public void analyzeData(String caseId) { + + analyzeOAI(caseId); + analyzeBS(caseId); + } + + /** + * 分析开户信息 + */ + private void analyzeOAI(String caseId) { + + List oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getNewEntityList(accountInfoMapper, HuaXiaAccountInfoEntity.class); + + Map map = new HashMap<>(); + + Map idNoNameMap = new HashMap<>(); + + for (HuaXiaAccountInfoEntity entity : entityList) { + String idCardNo = entity.getIdCardNo(); + String cardHolderName = entity.getCardHolderName(); + + // 证件号码和持卡人姓名都不为空 + if (StringUtils.isNotEmpty(idCardNo) && StringUtils.isNotEmpty(cardHolderName)) { + idNoNameMap.put(idCardNo, cardHolderName); + } + } + + for (HuaXiaAccountInfoEntity entity : entityList) { + String cardNumber = entity.getCardNumber(); + if (StringUtils.isEmpty(cardNumber)) { + continue; + } + + // 如果持卡人姓名为空而证件号码不为空,则补全持卡人姓名 + if (StringUtils.isEmpty(entity.getCardHolderName()) && StringUtils.isNotEmpty(entity.getIdCardNo())) { + String cardHolderName = idNoNameMap.get(entity.getIdCardNo()); + if (StringUtils.isNotEmpty(cardHolderName)) { + entity.setCardHolderName(cardHolderName); + } + } + + if (map.containsKey(cardNumber)) { + HuaXiaAccountInfoEntity info = map.get(cardNumber); + info = BeanCopyUtils.copy(entity, info, HuaXiaAccountInfoEntity.class); + map.put(cardNumber, info); + } else { + map.put(cardNumber, entity); + } + } + Set uniqueKeySet = new HashSet(); + for (HuaXiaAccountInfoEntity entity : map.values()) { + // 客户姓名都没有,则不继续处理 + // 没有账号和客户姓名,不需要 + if (StringUtils.isEmpty(entity.getCardHolderName()) || StringUtils.isEmpty(entity.getCardNumber())) { + continue; + } + + OpeningAccountInfo oai = getOpeningAccountInfo(BANK_NAME, entity); + + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + oaiList.add(oai); + if (oaiList.size() >= Constants.BATCH_SIZE) { + // 保存数据库 + List dest = HelperUtil.getDest(oaiList); + + HelperUtil.batchSaveOAI2Es(dest, caseId); + + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + if (!oaiList.isEmpty()) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + } + } + + private static OpeningAccountInfo getOpeningAccountInfo(String bankName, HuaXiaAccountInfoEntity entity) { + OpeningAccountInfo oai = new OpeningAccountInfo(); + oai.setName(entity.getCardHolderName()); + oai.setBankName(BANK_NAME); + oai.setAccountNumber(entity.getCardNumber()); + oai.setIdType(entity.getIdType()); + oai.setIdNo(entity.getIdCardNo()); + oai.setPhone(entity.getPhone()); + oai.setAddress(entity.getAddress()); + oai.setOpeningAccountDate(entity.getOpeningAccountDate()); + oai.setClosingDate(entity.getClosingDate()); + oai.setStatus(entity.getStatus()); + oai.setType(entity.getType()); + oai.setAccountOpeningInstitution(entity.getAccountOpeningInstitution()); + + return oai; + } + + /** + * 流水分析 + */ + private void analyzeBS(String caseId) { + + int batchSize = Constants.BATCH_SIZE; + List bsList = ListUtils.newArrayListWithExpectedSize(batchSize); + + List docList = HelperUtil.getEntityList(statementMapper, HXBankStatementEntity.class); + + List oaiList = HelperUtil.getEntityListV2(oaiMapper, OpeningAccountInfo.class, caseId); + + // 卡号和开户信息 + Map cardNumberAccMap = new HashMap<>(); + // 持卡人姓名和开户信息 + Map nameAccMap = new HashMap<>(); + + for (OpeningAccountInfo oai : oaiList) { + cardNumberAccMap.put(oai.getAccountNumber(), oai); + nameAccMap.put(oai.getName(), oai); + } + + // 明细中的流水,非一人一个文件流水 + // 必定有账号,根据账户信息列表中的数据,可获取持卡人、身份证等信息 + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + for (HXBankStatementEntity entity : docList) { + String sourceFile = entity.getSourceFile(); + try { + String cardNumber = entity.getCardNumber(); + if (StringUtils.isEmpty(cardNumber)) { // 没有卡号,无法获取到其他信息 + continue; + } + + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + bs.setCardNumber(cardNumber); + bs.setCardHolderName(entity.getCardHolderName()); + + { // 避免变量名冲突 + OpeningAccountInfo acc = cardNumberAccMap.getOrDefault(cardNumber, null); + if (acc != null) { + bs.setIdCardNo(acc.getIdNo()); + bs.setPhone(acc.getPhone()); + + if (StringUtils.isEmpty(bs.getCardHolderName())) { + bs.setCardHolderName(acc.getName()); + } + } + } + + String counterpartyName = entity.getCounterpartyName(); + bs.setCounterpartyName(counterpartyName); + + bs.setCounterpartIdCardNo(entity.getCounterpartyIdCardNo()); + + if (StrUtil.isNotEmpty(counterpartyName) && StringUtils.isEmpty(bs.getCounterpartIdCardNo())) { + // 根据对手名去查找 + OpeningAccountInfo acc = cardNumberAccMap.getOrDefault(counterpartyName, null); + if (acc != null) { + bs.setCounterpartIdCardNo(acc.getIdNo()); + } + } + + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + bs.setCounterpartyBankName(entity.getCounterpartyBankName()); + bs.setSummary(entity.getSummary()); + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + bs.setTransactionInstitutions(entity.getTransactionInstitutions()); + + // 交易金额 + String loanFlag = entity.getLoanFlag(); + if (StrUtil.isNotEmpty(loanFlag)) { + if (Objects.equals("贷", loanFlag)) { + bs.setTransactionAmount(entity.getTransactionAmount()); + } else { + bs.setTransactionAmount(entity.getTransactionAmount().negate()); + } + } + // 交易时间 20110921002233 + try { + bs.setTransactionTime(DateUtil.parse(entity.getTransactionTime(), "yyyyMMddHHmmss")); + } catch (Exception e) { + log.error("交易时间解析失败: {}", e.getMessage(), e); + throw new AnalyzeDataFailedException( + StrUtil.format("解析交易日期失败,无法将字符串[{}]根据模型[yyyyMMddHHmmss]转化为日期格式", entity.getTransactionTime()), + e, entity.getSourceFile()); + } + bs.setBalance(entity.getBalance()); + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entity.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= batchSize) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + bsList = ListUtils.newArrayListWithExpectedSize(batchSize); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e, sourceFile); + } + } + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + bsList = ListUtils.newArrayListWithExpectedSize(batchSize); + } + + // 一人一个文件 + List entityList = + HelperUtil.getEntityList(personalBankStatementMapper, HXPersonalBankStatementEntity.class); + + // 必定有持卡人姓名、账号(此账号有可能无法在开户或者账户明细中查询到相应的数据) + // 可根据持卡人姓名获取身份证 + for (HXPersonalBankStatementEntity entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + String cardHolderName = entity.getCardHolderName(); + if (StringUtils.isEmpty(cardHolderName)) { + continue; + } + + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + bs.setCardHolderName(cardHolderName); + + OpeningAccountInfo acc = nameAccMap.getOrDefault(cardHolderName, null); + if (acc != null) { + bs.setIdCardNo(acc.getIdNo()); + bs.setPhone(acc.getPhone()); + } + + bs.setCardNumber(entity.getCardNumber()); + bs.setSummary(entity.getSummary()); + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + // 交易金额 + String loanFlag = entity.getLoanFlag(); + if (StrUtil.isNotEmpty(loanFlag)) { + if (Objects.equals("贷", loanFlag)) { + bs.setTransactionAmount(entity.getTransactionAmount()); + } else { + bs.setTransactionAmount(entity.getTransactionAmount().negate()); + } + } + + // 交易时间 + String transDate = entity.getTransDate(); + if (StrUtil.isNotEmpty(transDate)) { // 2008/1/24 + try { + try { + bs.setTransactionTime(DateUtil.parse(transDate, "yyyy/MM/dd")); + } catch (Exception e) { + if (transDate.contains("-")) { + bs.setTransactionTime(DateUtil.parse(transDate, "yyyy-MM-dd")); + } + } + } catch (Exception e) { + log.error("交易时间解析失败: {}", e.getMessage(), e); + + throw new AnalyzeDataFailedException( + StrUtil.format("解析交易日期失败,无法将字符串[{}]根据模型转化为日期格式", transDate), e, sourceFile); + } + } + + bs.setBalance(entity.getBalance()); + bs.setCounterpartyName(entity.getCounterpartyName()); + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + bs.setCounterpartyBankName(entity.getCounterpartyBankName()); + bs.setTransRemark(entity.getTransRemark()); + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entity.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= batchSize) { + List dest = HelperUtil.getDest(bsList); + ThreadUtil.execAsync(() -> HelperUtil.batchInsert2Es(dest, caseId)); + + bsList = ListUtils.newArrayListWithExpectedSize(batchSize); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e, sourceFile); + } + } + + // 保存数据库 + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + ThreadUtil.execAsync(() -> HelperUtil.batchInsert2Es(dest, caseId)); + } + } + + + private void readHuaXiaBankOpeningAccountInfo(File excelFile, Cells cells, int sheetNum) { + Cell cell = AsposeUtil.getCell(cells, "开户日期"); + if (cell == null) { + return; + } + + int headRowNumb = cell.getRow() + 1; + + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + ReadSheet readSheet = EasyExcel.readSheet() + .headRowNumber(headRowNumb) + .sheetNo(sheetNum) + .head(HuaXiaAccountInfoEntity.class) + .registerReadListener(new ReadHuaXiaOpeningAccountInfoListener(accountInfoMapper)) + .build(); + reader.read(readSheet); + } catch (Exception e) { + log.error("读取华夏银行开户信息失败", e); + throw new ImportDataFailedException(e.getMessage(), excelFile.getAbsolutePath()); + } + } + + // 直接就是读取银行流水 + private void readHuaXiaBankStatement(File excelFile) throws Exception { + String name = excelFile.getName(); + if (name.contains("明细信息列表")) { + // 得分开,格式不同 + readHuaXiaAccountDetails(excelFile); + } else { + // 一人一Excel,其中包含账户名称 + readHuaXiaPersonalAccountDetails(excelFile); + } + } + + private void readHuaXiaPersonalAccountDetails(File excelFile) throws Exception { + String sourceFile = HelperUtil.getSourceFileName(excelFile.getAbsolutePath(),BANK_NAME); + // 先读取账户名称 + Workbook wb = new Workbook(excelFile.getAbsolutePath()); + Worksheet ws = wb.getWorksheets().get(0); + // 删除图片 + PictureCollection pictures = ws.getPictures(); + if (pictures.getCount() > 0) { + pictures.clear(); + wb.save(excelFile.getAbsolutePath()); + } + + // 读取账户名称 + Cell nameCell = AsposeUtil.getCell(excelFile, "客户名称"); + if (nameCell == null) { + nameCell = AsposeUtil.getCell(excelFile, "账户名称"); + if (nameCell == null) { + log.error("无法获取账户名称{}",excelFile.getAbsolutePath()); + readHuaXiaAccountDetails(excelFile); +// throw new ImportDataFailedException("无法获取账户名称", excelFile.getAbsolutePath()); + }else { + String cardHolderName = null; + String cardNumber = null; + + // 客户名称:刘旺 账号:10760000001262877 卡号:6230210071914745 起止日期: 2010-07-01 至 2022-09-18 币种:CNY + String value = nameCell.getStringValue(); + // 两种情况,一种是一个单元格中有内容,另一种是分开 + if (value.contains(":") || value.contains(":")) { + value = value.replaceAll(":", ":"); + if (!value.endsWith(":")) { + String[] arr = value.split(" "); + for (String str : arr) { + String[] a = str.split(":"); + if (a.length != 2) { + continue; + } + + if (str.contains("客户名称") || str.contains("账户名称")) { + cardHolderName = a[1]; + } + + if (str.contains("账号")) { + cardNumber = a[1]; + } + } + } else { + // 下一个单元格 + // 获取 + Range mr = nameCell.getMergedRange(); + if (mr != null) { + int offset = mr.getColumnCount(); + + int col = nameCell.getColumn() + offset; + + cardHolderName = ws.getCells().get(nameCell.getRow(), col).getStringValue(); + } else { + cardHolderName = ws.getCells() + .get(nameCell.getRow(), nameCell.getColumn() + 1) + .getStringValue(); + } + } + } + // 账号 + if (StringUtils.isEmpty(cardNumber)) { + Cell accountCell = AsposeUtil.getCell(excelFile, "账号"); + if (accountCell == null) { + accountCell = AsposeUtil.getCell(excelFile, "卡号"); + } + + if (accountCell != null) { + String str = accountCell.getStringValue(); + + if (str.contains(" ")) { + String[] arr = str.split(" "); + for (String s : arr) { + if (s.contains("账号")) { + cardNumber = s.substring(s.indexOf(":") + 1); + } + } + } else if (str.contains(":") || str.contains(":")) { + str = str.replaceAll(":", ":"); + String[] arr = str.split(":"); + if (arr.length == 2) { + cardNumber = arr[1]; + } + } + } + } + + // 持卡人 + if (StringUtils.isEmpty(cardHolderName)) { + log.error("无法获取持卡人姓名"+sourceFile); + return; +// throw new ImportDataFailedException("无法获取持卡人姓名", sourceFile); + } + + if (StrUtil.isNotEmpty(cardNumber)) { + // 操作Excel文件,往其中增加一列 + AsposeUtil.addOneColumn(excelFile.getAbsolutePath(), "账号", cardNumber, "余额", 0); + } + + for (int sheetNo = 0; sheetNo < wb.getWorksheets().getCount(); sheetNo++) { + Cell c = AsposeUtil.getCell(excelFile, sheetNo, "余额"); + if (c != null) { + readHuaXiaPersonalBankStatement(excelFile, cardHolderName, sheetNo, c.getRow() + 1); + } + } + } + } + } + + private void readHuaXiaPersonalBankStatement(File excelFile, String cardHolderName, int sheetNo, int headRowNumber) { + Class clazz = HXPersonalBankStatementEntity.class; + String sourceFile = HelperUtil.getSourceFileName(excelFile.getAbsolutePath(),BANK_NAME); + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNumber) + .head(clazz) + .registerReadListener( + HelperUtil.getReadListener(personalBankStatementMapper, cardHolderName, clazz,sourceFile)) + .build(); + reader.read(sheet); + } catch (Exception e) { + + if (e instanceof ExcelDataConvertException) { + return; // 通过这种方式来结束读取 + } + + log.error("读取华夏银行个人账户明细表失败", e); + throw new ImportDataFailedException(e.getMessage(), sourceFile); + } + } + + // 账户明细 + private void readHuaXiaAccountDetails(File excelFile) { + Class clazz = HXBankStatementEntity.class; + String sourceFile = HelperUtil.getSourceFileName(excelFile.getAbsolutePath(),BANK_NAME); + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + ReadSheet sheet = EasyExcel.readSheet() + .headRowNumber(2) + .head(clazz) + .registerReadListener(HelperUtil.getReadListener(statementMapper, clazz, false,sourceFile)) + .build(); + reader.read(sheet); + } catch (Exception e) { + log.error("读取华夏银行账户明细表失败", e); + throw new ImportDataFailedException(e.getMessage(), excelFile.getAbsolutePath()); + } + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/HFAnalysisHelper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/HFAnalysisHelper.java new file mode 100644 index 0000000..67100fd --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/HFAnalysisHelper.java @@ -0,0 +1,410 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.util.ListUtils; +import com.aspose.cells.Cell; +import com.aspose.cells.Cells; +import com.aspose.cells.Workbook; +import com.aspose.cells.Worksheet; + +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.common.constant.BankStatementConstants; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.exception.dc.AnalyzeDataFailedException; +import com.inscloudtech.common.exception.dc.ImportDataFailedException; +import com.inscloudtech.common.exception.dc.TemplateNotFindException; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.converter.MyStringNumberConverter; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.mapper.es.HFCompanyStatementMapper; +import com.inscloudtech.datacenter.mapper.es.HFCompanyStatementV2Mapper; +import com.inscloudtech.datacenter.service.ImportResultService; +import com.inscloudtech.datacenter.domain.BankStatement; + +import com.inscloudtech.bankStatementAnalysis.domain.entity.HFCompanyStatement; +import com.inscloudtech.bankStatementAnalysis.domain.entity.HFCompanyStatementV2; + +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * 恒丰银行数据解析 + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class HFAnalysisHelper { + + private final HFCompanyStatementMapper companyStatementMapper; + private final HFCompanyStatementV2Mapper companyStatementV2Mapper; + private final ImportResultService importResultService; + + private final static String BANK_NAME = "恒丰银行"; + + public void importData(File file,String caseId) throws Exception { + List fileList = FileUtil.loopFiles(file); + + List excelFileList = HelperUtil.getExcelFile(fileList); + + for (File excelFile : excelFileList) { + try { + String excelFileName = excelFile.getAbsolutePath(); + String sourceFile = HelperUtil.getSourceFileName(excelFileName, BANK_NAME); + Workbook wb = new Workbook(excelFileName); + for (int sheetNo = 0; sheetNo < wb.getWorksheets().getCount(); sheetNo++) { + try { + Worksheet worksheet = wb.getWorksheets().get(sheetNo); + Cells cells = worksheet.getCells(); + String sheetName = worksheet.getName(); + Cell tradeFlagCell = AsposeUtil.getCell(cells, "借贷标识d借c贷"); + Cell tradeFlagV2Cell = AsposeUtil.getCell(cells, "对方交易支付行号"); + Cell tradeFlagV3Cell = AsposeUtil.getCell(cells, "摘要码+交易码"); + if (tradeFlagCell != null) { + companyBs(tradeFlagCell, excelFileName, sheetNo); + } else if (tradeFlagV2Cell != null) { + companyBsV2(tradeFlagV2Cell, excelFileName, sheetNo); + } else if (tradeFlagV3Cell != null) { + companyBs(tradeFlagV3Cell, excelFileName, sheetNo); + } else if (sheetName.contains("首页")) { + continue; + } else { + throw new TemplateNotFindException(sourceFile + BankStatementConstants.NAME_WITH_SHEET_NAME + sheetName); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } + + private void companyBs(Cell tempCell, String excelFileName, int sheetNo) { + String sourceFile = HelperUtil.getSourceFileName(excelFileName,BANK_NAME); + int headRowNum = tempCell.getRow() + 1; + try (ExcelReader reader = EasyExcel.read(excelFileName).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNum) + .head(HFCompanyStatement.class) + .registerReadListener( + HelperUtil.getReadListener(companyStatementMapper, HFCompanyStatement.class, false,sourceFile)) + .build(); + reader.read(sheet); + } catch (Exception e) { + throw new ImportDataFailedException(e.getMessage(), excelFileName); + } + } + + private void companyBsV2(Cell tempCell, String excelFileName, int sheetNo) { + String sourceFile = HelperUtil.getSourceFileName(excelFileName,BANK_NAME); + int headRowNum = tempCell.getRow() + 1; + try (ExcelReader reader = EasyExcel.read(excelFileName).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNum) + .head(HFCompanyStatementV2.class) + .registerConverter(new MyStringNumberConverter()) + .registerReadListener( + HelperUtil.getReadListener(companyStatementV2Mapper, HFCompanyStatementV2.class, false,sourceFile)) + .build(); + reader.read(sheet); + } catch (Exception e) { + throw new ImportDataFailedException(e.getMessage(), excelFileName); + } + } + + + public void analyzeData(String caseId) { + // 开户信息 +// analyzeOAI(caseId); + // 流水信息 + analyzeBS(caseId); + } + + + private void analyzeBS(String caseId) { + analyzeBS4Company(caseId); + analyzeBS4CompanyV2(caseId); + } + + + + private void analyzeBS4CompanyV2(String caseId) { + List bsList = new ArrayList<>(); + List entityList = HelperUtil.getEntityList(companyStatementV2Mapper, HFCompanyStatementV2.class); +// List companyInfoList = +// HelperUtil.getEntityList(esABCCompanyInfoMapper, ABCCompanyInfoEntity.class); +// +// Map nameCompanyInfoMap = new HashMap<>(); +// +// for (ABCCompanyInfoEntity entity : companyInfoList) { +// nameCompanyInfoMap.put(entity.getCardHolderName(), entity); +// } +// +// Map> groupByContractNo = companyInfoList.stream() +// .filter(item ->StrUtil.isNotEmpty(item.getContractNo())) +// .collect(Collectors.groupingBy(ABCCompanyInfoEntity::getContractNo)); + + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + + for (HFCompanyStatementV2 entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + + String cardHolderName = entity.getCardHolderName(); + bs.setCardHolderName(cardHolderName); + + if (StrUtil.isEmpty(bs.getCardHolderName())) {//持卡人空处理 + + } + + bs.setCardNumber(entity.getCardNumber()); + if(StrUtil.isEmpty(bs.getIdCardNo())){ + bs.setIdCardNo(""); + } + + // 人民币 + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + + // 借方金额 + BigDecimal debitAmount = entity.getDebitAmount(); + if (debitAmount != null) { + bs.setTransactionAmount(debitAmount.negate()); + } + // 贷方金额 + BigDecimal creditAmount = entity.getCreditAmount(); + if (creditAmount != null) { + bs.setTransactionAmount(creditAmount); + } + + + // 3 余额 + bs.setBalance(entity.getBalance()); + + // 4 交易日期 + String transactionDate = entity.getTransDate(); + String transactionTime = entity.getTransTime(); + + if (StrUtil.isNotEmpty(transactionDate)) { + String dateStr = transactionDate; + String format = DatePattern.NORM_DATETIME_PATTERN; + if(transactionDate.contains("/")){ + format = "yyyy/MM/dd"; + } + + if(StrUtil.isNotEmpty(transactionTime)){ + dateStr = dateStr + " " + transactionTime; + format = "yyyy/MM/dd HH:mm:ss"; + } + + try { + bs.setTransactionTime(DateUtil.parse(dateStr, format)); + } catch (Exception e) { + log.error("解析交易日期异常:{},{}", e.getMessage()+entity.getSourceFile(), e); + throw new AnalyzeDataFailedException( + "解析交易日期失败,无法将【" + dateStr + "】以格式【" + DatePattern.NORM_DATETIME_PATTERN + "】解析", e, entity.getSourceFile()); + } + } + String counterpartyName = entity.getCounterpartyName(); + bs.setCounterpartyName(counterpartyName); + + + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + bs.setCounterpartyBankName(entity.getCounterpartyBankName()); + bs.setTransRemark(entity.getTransRemark()); + + bs.setTransactionInstitutions(entity.getCounterpartyBankName()); + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entity.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + + bsList.clear(); + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e, sourceFile); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + // 保存数据库 + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + private void analyzeBS4Company(String caseId) { + List bsList = new ArrayList<>(); + List entityList = + HelperUtil.getEntityList(companyStatementMapper, HFCompanyStatement.class); +// List companyInfoList = +// HelperUtil.getEntityList(esABCCompanyInfoMapper, ABCCompanyInfoEntity.class); +// +// Map nameCompanyInfoMap = new HashMap<>(); +// +// for (ABCCompanyInfoEntity entity : companyInfoList) { +// nameCompanyInfoMap.put(entity.getCardHolderName(), entity); +// } +// +// Map> groupByContractNo = companyInfoList.stream() +// .filter(item ->StrUtil.isNotEmpty(item.getContractNo())) +// .collect(Collectors.groupingBy(ABCCompanyInfoEntity::getContractNo)); + + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + + for (HFCompanyStatement entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + + String cardHolderName = entity.getCardHolderName(); + bs.setCardHolderName(cardHolderName); + bs.setCardNumber(entity.getCardNumber()); + if (StrUtil.isEmpty(bs.getIdCardNo())) { + bs.setIdCardNo(""); + } + + // 人民币 + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + + + //借贷标 + + BigDecimal transactionAmount = entity.getTransactionAmount(); + String loanFlag = entity.getLoanFlag(); + if (StrUtil.isNotEmpty(loanFlag)) { + if (loanFlag.toLowerCase().contains("d")) { + transactionAmount = transactionAmount.negate(); + }else if(loanFlag.contains("支出")){ + transactionAmount = transactionAmount.negate(); + } + + } + bs.setTransactionAmount(transactionAmount); + +// { +// // 借方金额 +// BigDecimal debitAmount = entity.getDebitAmount(); +// if (debitAmount != null) { +// bs.setTransactionAmount(debitAmount.negate()); +// } +// // 贷方金额 +// BigDecimal creditAmount = entity.getCreditAmount(); +// if (creditAmount != null) { +// bs.setTransactionAmount(creditAmount); +// } +// } + + + // 3 余额 + bs.setBalance(entity.getBalance()); + + // 4 交易日期 +// String transactionDate = entity.getTransDate(); + String transactionTime = entity.getTransTime(); + + if (StrUtil.isNotEmpty(transactionTime)) { + try { + if(StrUtil.isNotEmpty(entity.getTransDate())) { + transactionTime = entity.getTransDate()+" "+transactionTime; + bs.setTransactionTime(DateUtil.parse(transactionTime, DatePattern.NORM_DATETIME_PATTERN)); + }else { + bs.setTransactionTime(DateUtil.parse(transactionTime, DatePattern.NORM_DATETIME_PATTERN)); + } + } catch (Exception e) { + throw new AnalyzeDataFailedException( + "解析交易日期失败,无法将【" + transactionTime + "】以格式【" + DatePattern.NORM_DATETIME_PATTERN + "】解析", e, entity.getSourceFile()); + } + } + String counterpartyName = entity.getCounterpartyName(); + bs.setCounterpartyName(counterpartyName); + + + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + bs.setCounterpartyBankName(entity.getCounterpartyBankName()); + bs.setTransChannel(entity.getTransChannel()); + bs.setSummary(entity.getSummary()); + bs.setTransactionInstitutions(entity.getCounterpartyBankName()); + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entity.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + + bsList.clear(); + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e, sourceFile); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + // 保存数据库 + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/HelperUtil.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/HelperUtil.java new file mode 100644 index 0000000..05b0182 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/HelperUtil.java @@ -0,0 +1,1150 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.thread.ThreadUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.pinyin.PinyinUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.exception.ExcelAnalysisStopException; +import com.alibaba.excel.exception.ExcelDataConvertException; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.util.ListUtils; +import com.aspose.cells.Cell; +import com.aspose.cells.Cells; +import com.aspose.cells.Workbook; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.inscloudtech.bankStatementAnalysis.helper.EsMapperHolder; +import com.inscloudtech.bankStatementAnalysis.util.AnalyzeFileHelper; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.exception.dc.GetIndexNameFailedException; +import com.inscloudtech.common.utils.JsonUtils; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; + + +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; + + +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.common.utils.LogUtils; +import org.dromara.easyes.core.biz.SAPageInfo; +import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper; +import org.dromara.easyes.core.core.BaseEsMapper; +import org.dromara.easyes.core.core.EsWrappers; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.lang.Nullable; + + +import java.io.File; +import java.lang.reflect.Field; +import java.math.BigDecimal; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class HelperUtil { + + private static final int CORE_NUM = Runtime.getRuntime().availableProcessors(); + + + private static final Logger log = LoggerFactory.getLogger(HelperUtil.class); + + private static final Map BANK_NAME_MAP = new HashMap<>(); + + /** + * 拆分流水和开户文件 + */ + public static void splitBsAndOaiFiles(File zipDir) { + if (zipDir == null || !zipDir.exists()) { + return; + } + + List fileList = FileUtil.loopFiles(zipDir); + + // 文件扩展名分类 + List excelFiles = fileList.stream() + .filter(file -> file.getName().toLowerCase().endsWith(".xlsx") + || file.getName().toLowerCase().endsWith(".xls") + || file.getName().toLowerCase().endsWith(".csv") + || file.getName().toLowerCase().endsWith(".et")) + .collect(Collectors.toList()); + +// List pdfFiles = fileList.stream() +// .filter(file -> file.getName().endsWith(".pdf")) +// .collect(Collectors.toList()); + +// // pdf文件转化为Excel文件 +// if (!pdfFiles.isEmpty()) { +// for (File file : pdfFiles) { +// String excelFilepath = AsposeUtil.pdf2ExcelV6(file.getAbsolutePath()); +// excelFiles.add(new File(excelFilepath)); +// } +// } + + // 拆分 + for (File excelFile : excelFiles) { + try { + Workbook wb = new Workbook(excelFile.getAbsolutePath()); + + for (int sheetNum = 0; sheetNum < wb.getWorksheets().getCount(); sheetNum++) { + Cells cells = wb.getWorksheets().get(sheetNum).getCells(); + + Cell cell = AsposeUtil.getCell(cells, "开户日期"); + if (cell != null) { + AnalyzeFileHelper.putOAIFile(excelFile); + } + + cell = AsposeUtil.getCell(cells, "开户日"); + if (cell != null) { + AnalyzeFileHelper.putOAIFile(excelFile); + } + + cell = AsposeUtil.getCell(cells, "交易日期"); + if (cell != null) { + AnalyzeFileHelper.putBSFile(excelFile); + } else { + cell = AsposeUtil.getCell(cells, "交易时间"); + if (cell != null) { + AnalyzeFileHelper.putBSFile(excelFile); + } + } + } + } catch (Exception e) { + log.error("拆分文件失败,文件路径:{}", FileUtil.mainName(excelFile), e); + } + } + } + + + + @Nullable + public static T getEntity(BaseEsMapper baseEsMapper, Class clazz, String column, Object value) { + LambdaEsQueryWrapper wrapper = EsWrappers.lambdaQuery(clazz); + wrapper.eq(!Objects.isNull(value), column, value); + + List ts = baseEsMapper.selectList(wrapper); + if (ts != null && !ts.isEmpty()) { + return ts.get(0); + } + + return null; + } + + /** + * 获取一万条数据内的全量数据 + */ + public static List getNewEntityList(BaseEsMapper mapper, Class clazz) { + // 刷新索引 + try { + if (mapper.existsIndex(getIndexName(mapper.getEntityClass()))) { + mapper.refresh(); + } + } catch (Exception e) { + return new ArrayList<>(); + } + + LambdaEsQueryWrapper wrapper = EsWrappers.lambdaQuery(clazz); + wrapper.orderByDesc("id"); + + return mapper.selectList(wrapper); + } + + public static long getCount(BaseEsMapper mapper, Class clazz, String column, Object value) { + LambdaEsQueryWrapper wrapper = EsWrappers.lambdaQuery(clazz); + wrapper.eq(!Objects.isNull(value), column, value); + + return getCount(mapper, wrapper); + } + + public static Long getCount(BaseEsMapper mapper, LambdaEsQueryWrapper wrapper) { + return mapper.selectCount(wrapper); + } + + + public static List getEntityListV4(BaseEsMapper mapper, Class clazz, String column, String value) + throws Exception { + // 刷新索引 + try { + if (mapper.existsIndex(getIndexName(mapper.getEntityClass()))) { + mapper.refresh(); + } + } catch (Exception e) { + return new ArrayList<>(); + } + + LambdaEsQueryWrapper wrapper = EsWrappers.lambdaQuery(clazz); + wrapper.orderByDesc("id"); + wrapper.eq(StrUtil.isNotEmpty(value), column, value); + + return executeQuery(mapper, wrapper); + } + + private static List executeQuery(BaseEsMapper mapper, LambdaEsQueryWrapper wrapper) { + List rstList = new ArrayList<>(); + + // + int pageSize = 5 * Constants.BATCH_SIZE; + + List next = null; + + do { + SAPageInfo pi = mapper.searchAfterPage(wrapper, next, pageSize); + if (pi != null) { + rstList.addAll(pi.getList()); + next = pi.getNextSearchAfter(); + } else { + break; + } + } while (next != null); + + return rstList; + } + + /** + * 获取全量数据-适用于和案件关联的数据查询 + */ + public static List getEntityListV2(BaseEsMapper mapper, Class clazz, String caseId) { + // 刷新索引 + try { + if (mapper.existsIndex(getIndexName(mapper.getEntityClass()))) { + mapper.refresh(); + } + } catch (Exception e) { + return new ArrayList<>(); + } + + LambdaEsQueryWrapper wrapper = EsWrappers.lambdaQuery(clazz); + wrapper.orderByDesc("id"); + wrapper.eq(StrUtil.isNotEmpty(caseId), "caseId", caseId); + + List rstList = new ArrayList<>(); + + // + int pageSize = 5 * Constants.BATCH_SIZE; + + List next = null; + + do { + SAPageInfo pi = mapper.searchAfterPage(wrapper, next, pageSize); + if (pi != null) { + rstList.addAll(pi.getList()); + next = pi.getNextSearchAfter(); + } else { + break; + } + } while (next != null); + + return rstList; + } + + /** + * + */ + public static List searchId(BaseEsMapper mapper,Class clazz,Set idList,String column, String value) { + // 刷新索引 + try { + if (mapper.existsIndex(getIndexName(mapper.getEntityClass()))) { + mapper.refresh(); + } + } catch (Exception e) { + return new ArrayList<>(); + } + + LambdaEsQueryWrapper wrapper = EsWrappers.lambdaQuery(clazz); + wrapper.eq( column, value); + wrapper.in( "id", idList); + wrapper.orderByDesc("id"); +// wrapper.eq( "bankName", bankName); + wrapper.select("id"); + List rstList = new ArrayList<>(); + + // + int pageSize = 5 * Constants.BATCH_SIZE; + + List next = null; + + do { + SAPageInfo pi = mapper.searchAfterPage(wrapper, next, pageSize); + if (pi != null) { + rstList.addAll(pi.getList()); + next = pi.getNextSearchAfter(); + } else { + break; + } + } while (next != null); + + return rstList; + } + + /** + * 获取索引名称 + * + * @param clazz 标注了@IndexName的类 + * @return 索引名称 + * @throws Exception 如果没有注解,则会抛出异常 + */ + public static String getIndexName(Class clazz) throws Exception { + + IndexName indexNameAnno = clazz.getAnnotation(IndexName.class); + if (indexNameAnno == null) { + throw new GetIndexNameFailedException(clazz.getName() + "没有对应的索引."); + } + + return indexNameAnno.value(); + } + + /** + * 获取全量数据-适用于没有和案件关联的数据查询 + */ + public static List getEntityList(BaseEsMapper mapper, Class clazz) { + // 刷新索引 + try { + if (mapper.existsIndex(getIndexName(mapper.getEntityClass()))) { + mapper.refresh(); + } + } catch (Exception e) { + // + } + + LambdaEsQueryWrapper wrapper = EsWrappers.lambdaQuery(clazz); + wrapper.orderByDesc("id"); + + List rstList = new ArrayList<>(); + + // + int pageSize = 10 * Constants.BATCH_SIZE; + + List next = null; + + try { + do { + SAPageInfo pi = mapper.searchAfterPage(wrapper, next, pageSize); + if (pi != null) { + rstList.addAll(pi.getList()); + next = pi.getNextSearchAfter(); + } else { + break; + } + } while (next != null); + + return rstList; + } catch (Exception e) { + LogUtils.formatError("getEntityList(%s): %s", mapper.getClass().getSimpleName(), e.getMessage(), e); + throw new RuntimeException(e.getMessage(), e); + } + } + + public static boolean isContainsChinese(String str) { + if (str == null) { + return false; + } + Pattern p = Pattern.compile("[\u4e00-\u9fa5]"); + Matcher m = p.matcher(str); + return m.find(); + } + + private static final ExecutorService EXECUTOR_SERVICE; + + static { + EXECUTOR_SERVICE = ThreadUtil.newExecutor(CORE_NUM, CORE_NUM * 2, 1024); + } + + private HelperUtil() { + } + + public static void exeAsync(Runnable r) { + EXECUTOR_SERVICE.execute(r); + } + + /** + * 存ES,同时设置ID,可以停止 + */ + public static ReadListener getReadListener( + BaseEsMapper mapper, Class clazz, boolean isNeedSuspect, int start, int end,String sourceFile) { + return new ReadListener() { + List cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + int startRow = start; + final int endRow = end; + + @Override + public void invoke(T data, AnalysisContext context) { + + JSONObject obj = getJsonObject(data, mapper); + if (Objects.isNull(obj)) { + startRow++; + if (startRow >= endRow) { + save(); + //todo 以建设银行为例,取过了endRow不应该是,跳出循环重新开始一个start? + throw new ExcelAnalysisStopException("stop read..."); + } + return; + } + obj.put("sourceFile",sourceFile); + cacheList.add(obj.toBean(clazz)); + + if (cacheList.size() >= Constants.BATCH_SIZE) { + save(); + } + + startRow++; + if (startRow >= endRow) { + save(); + return; +// throw new ExcelAnalysisStopException("stop read..."); + } + } + + private void save() { + if (CollectionUtil.isNotEmpty(cacheList)) { + + mapper.insertBatch(cacheList); + + cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (CollectionUtil.isNotEmpty(cacheList)) { + save(); + } + } + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + + handleException(exception); + + ReadListener.super.onException(exception, context); + } + }; + } + + /** + * 存ES,同时设置ID + */ + public static ReadListener getReadListener(BaseEsMapper mapper, Class clazz, String cardHolderName,String sourceFile) { + return new ReadListener() { + List cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + @Override + public void invoke(T data, AnalysisContext context) { + JSONObject obj = getJsonObject(data, mapper); + if (obj == null) { + return; + } + + + obj.put("cardHolderName", cardHolderName); + obj.put("sourceFile", sourceFile); + try { + cacheList.add(obj.toBean(clazz)); + } catch (Exception e) { + return; + } + + if (cacheList.size() >= Constants.BATCH_SIZE) { + saveToEs(); + } + } + + private void saveToEs() { + mapper.insertBatch(cacheList); + + cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!cacheList.isEmpty()) { + saveToEs(); + } + } + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + + handleException(exception); + + ReadListener.super.onException(exception, context); + } + }; + } + + /** + * 存ES,同时设置ID + */ + public static ReadListener getReadListener(BaseEsMapper mapper, Class clazz, boolean isNeedSuspect,String sourceFile) { + return new ReadListener() { + List cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + @Override + public void invoke(T data, AnalysisContext context) { + JSONObject obj1 = JSONUtil.parseObj(data); + if (!isNeedSuspect && obj1 != null && isTransDate((clazz))) { + String transDate = obj1.getStr("transDate"); + if (isContainsChinese(transDate) || StrUtil.isEmpty(transDate)) { + return; + } + + String balance = obj1.getStr("balance"); + + if (isContainsChinese(balance) || StrUtil.isEmpty(balance)) { + if(StrUtil.isEmpty(balance) && obj1.containsKey("cardType") && obj1.getStr("cardType").equals("贷记卡")){ + obj1.put("balance","0"); + }else { + obj1.put("balance","0"); + } + } + } + + String str = Objects.requireNonNull(obj1).getStr("id"); + if (isNeedSuspect && Objects.equals(str, "账户交易明细")) { // 针对开户信息和流水纪录在同一个工作表中的模型 + throw new ExcelAnalysisStopException(); + } + + JSONObject obj = getJsonObject(data, mapper); + if (obj == null) { + return; + } + + + + if (isNeedSuspect) { // 针对开户信息 + String cardHolderName = obj.getStr("cardHolderName"); + if (StringUtils.isEmpty(cardHolderName)) { + + String cardNumber = obj.getStr("cardNumber"); + String idCardNo = obj.getStr("idCardNo"); + if (StrUtil.isNotEmpty(cardNumber) && StrUtil.isNotEmpty(idCardNo)) { + Optional op = cacheList.stream() + .map(JSONUtil::parseObj) + .filter(Objects::nonNull) + .filter(o -> o.getStr("idCardNo").equals(idCardNo)) + .findFirst(); + if (op.isPresent()) { + JSONObject jsonObject = op.get(); + // 合并 + Set keys = jsonObject.keySet(); + for (String key : keys) { + if (!obj.containsKey(key)) { + obj.put(key, jsonObject.getStr(key)); + } + } + } + } else { + return; + } + } + } else { + // 针对流水 + // 针对卡号为空的情况 + String cardNumber = obj.getStr("cardNumber"); + if (StringUtils.isEmpty(cardNumber)) { + // 找到上一条不为空的数据,根据余额和交易金额的计算,来确定卡号 + // 其实就是找上一条数据 + try { + JSONObject prevObj = obj; + for (int i = cacheList.size() - 1; i >= 0; i--) { + JSONObject jsonObject = JSONUtil.parseObj(cacheList.get(i)); + if (jsonObject != null) { + String otherCardNumber = jsonObject.getStr("cardNumber"); + String balanceStr = jsonObject.getStr("balance"); + if (StrUtil.isNotEmpty(balanceStr)) { + // 用hutool工具将字符串转化为数字形式,然后进行计算 + BigDecimal otherBalance = NumberUtil.toBigDecimal(balanceStr); + otherBalance = otherBalance == null ? BigDecimal.ZERO : otherBalance; + + BigDecimal transactionAmount = prevObj.getBigDecimal("transactionAmount"); + transactionAmount = transactionAmount == null ? BigDecimal.ZERO : transactionAmount; + if( null != prevObj.getBigDecimal("balance") ){ + if (prevObj.getBigDecimal("balance").compareTo(otherBalance.add(transactionAmount)) + == 0) { + if (StrUtil.isNotEmpty(otherCardNumber)) { + obj.put("cardNumber", otherCardNumber); + break; + } else { + prevObj = jsonObject; + } + } else { + break; // 不满足条件,则直接退出 + } + }else { + break; // 不满足条件,则直接退出 + } + } + } + } + }catch (Exception e){ + e.printStackTrace(); + } + } + } + + try { + obj.put("sourceFile",sourceFile); + cacheList.add(obj.toBean(clazz)); + } catch (Exception e) { + e.printStackTrace(); + return; + } + + if (cacheList.size() >= Constants.BATCH_SIZE) { + save(); + } + } + + private void save() { + String simpleName = mapper.getEntityClass().getSimpleName(); + if (!isNeedSuspect && simpleName.contains("Statement")) { // 只处理流水相关 + handleNoCardNumber(); + } + + mapper.insertBatch(cacheList); + + cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + + private void handleNoCardNumber() { + // 向下搜索,确定卡号 + // 先定位卡号为空的数据,然后往后搜索,以确定卡号 + for (int i = cacheList.size() - 1; i >= 0; i--) { + JSONObject jsonObject = JSONUtil.parseObj(cacheList.get(i)); + if (jsonObject != null) { + String otherCardNumber = jsonObject.getStr("cardNumber"); + if (StringUtils.isEmpty(otherCardNumber)) { + JSONObject prvObj = jsonObject; + for (int j = i + 1; j <= cacheList.size() - 1; j++) { + JSONObject currObj = JSONUtil.parseObj(cacheList.get(j)); + if (currObj != null) { + String cardNumber = currObj.getStr("cardNumber"); + // 获取余额 + BigDecimal prevBalance = prvObj.getBigDecimal("balance"); + prevBalance = prevBalance == null ? BigDecimal.ZERO : prevBalance; + // 获取交易金额 + BigDecimal transactionAmount = currObj.getBigDecimal("transactionAmount"); + transactionAmount = transactionAmount == null ? BigDecimal.ZERO : transactionAmount; + + BigDecimal balance = currObj.getBigDecimal("balance"); + balance = balance == null ? BigDecimal.ZERO : balance; + if (balance.compareTo(prevBalance.add(transactionAmount)) == 0) { + if (StrUtil.isNotEmpty(cardNumber)) { + jsonObject.put("cardNumber", cardNumber); + // 需要替换掉 + cacheList.set(i, jsonObject.toBean(mapper.getEntityClass())); + + break; + } else { + prvObj = currObj; // 如果下一行也没有卡号,在满足条件的情况下继续往下走 + } + } else { + // 不满足条件,则直接退出 + break; + } + } + } + } + } + } + } + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + + handleException(exception); + + // 记录日志 + if (!cacheList.isEmpty()) { + save(); + } + + throw new ExcelAnalysisStopException(); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!cacheList.isEmpty()) { + save(); + } + } + }; + } + + private static boolean isTransDate(Class clazz) { + Field[] fields = ReflectUtil.getFields(clazz); + for (Field field : fields) { + if (field.getName().equals("transDate")) { + return true; + } + } + return false; + } + + public static ReadListener getReadListener(BaseEsMapper mapper, String cardHolderName, Class clazz, String sourceFile) { + // 将读取的数据与文件挂钩 + return new ReadListener() { + List cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + @Override + public void invoke(T data, AnalysisContext context) { + JSONObject obj = getJsonObject(data, mapper); + if (obj == null) { + return; + } + + // 获取余额或者交易金额 + String balanceStr = obj.getStr("balance"); + if (StrUtil.isNotBlank(balanceStr) && isContainsChinese(balanceStr)) { + // 如果金额字段包含汉字,肯定不对 + return; + } + + String transactionAmountStr = obj.getStr("transactionAmount"); + if (StrUtil.isNotBlank(transactionAmountStr) && isContainsChinese(transactionAmountStr)) { + return; + } + + obj.put("cardHolderName", cardHolderName); + obj.put("sourceFile", sourceFile); + cacheList.add(obj.toBean(clazz)); + + if (cacheList.size() >= Constants.BATCH_SIZE) { + mapper.insertBatch(cacheList); + cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!cacheList.isEmpty()) { + mapper.insertBatch(cacheList); + } + } + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + + handleException(exception); + + ReadListener.super.onException(exception, context); + } + }; + } + + public static JSONObject getJsonObject(T data, BaseEsMapper mapper) { + String str = JSONUtil.toJsonStr(data); + JSONObject obj = JSONUtil.parseObj(str); + + String idStr = obj.getStr("id"); + if (StrUtil.isNotEmpty(idStr) && isContainsChinese(idStr)) { + return null; + } + + boolean isStatementData = false; + String simpleName = mapper.getEntityClass().getSimpleName(); + if (StrUtil.isNotEmpty(simpleName) && simpleName.contains("Statement")) { + isStatementData = true; + } + + // 筛选无效数据 + // 如果是开户数据,那肯定没有这个 + Object o = obj.get("transactionAmount"); + // 借方金额 + Object debitAmount = obj.get("debitAmount"); + // 贷方金额 + Object creditAmount = obj.get("creditAmount"); + Object incomeAmount = obj.get("incomeAmount"); + + if ((Objects.isNull(o) && Objects.isNull(debitAmount) && Objects.isNull(creditAmount)) + && Objects.isNull(incomeAmount) + && isStatementData) { + return null; + } + + obj.put("id", IdUtil.objectId()); + + return obj; + } + + public static void batchSaveOAI2Es(List oaiList, String caseId) { + + // 去重 + Map groupById = oaiList.stream().collect(Collectors.toMap(OpeningAccountInfo::getId, Function.identity())); + Set idSet = groupById.keySet(); + //根据id取es查询 返回的就是重复数据 + List esExistIdList = searchId(EsMapperHolder.getEsOpeningAccountInfoMapper(), OpeningAccountInfo.class, idSet, "caseId", caseId); + if(CollectionUtil.isEmpty(esExistIdList)){ + EsMapperHolder.getEsOpeningAccountInfoMapper().insertBatch(oaiList); + }else { + Set esIdSet = esExistIdList.stream().map(OpeningAccountInfo::getId).collect(Collectors.toSet()); + idSet.removeAll(esIdSet); + if(CollectionUtil.isEmpty(idSet)){ + return; + }else { + List saveLis = new ArrayList<>(); + for (String id : idSet) { + saveLis.add(groupById.get(id)); + } + EsMapperHolder.getEsOpeningAccountInfoMapper().insertBatch(saveLis); + } + } + } + + + + public static void batchInsert2Es(List bsList, String caseId) { + EsMapperHolder.getEsBankStatementMapper().refresh(); + + // 去重 + Map groupById = bsList.stream().collect(Collectors.toMap(BankStatement::getId, Function.identity())); + Set idSet = groupById.keySet(); + //根据id取es查询 返回的就是重复数据 + List esExistIdList = searchId(EsMapperHolder.getEsBankStatementMapper(), BankStatement.class, idSet,"caseId", caseId); + if(CollectionUtil.isEmpty(esExistIdList)){ + EsMapperHolder.getEsBankStatementMapper().insertBatch(bsList); + }else { + Set esIdSet = esExistIdList.stream().map(BankStatement::getId).collect(Collectors.toSet()); + idSet.removeAll(esIdSet); + if(CollectionUtil.isEmpty(idSet)){ + return; + }else { + List saveLis = new ArrayList<>(); + for (String id : idSet) { + saveLis.add(groupById.get(id)); + } + EsMapperHolder.getEsBankStatementMapper().insertBatch(saveLis); + } + } + } + + /** + * batchInsert2Es 用的地方太多先不改了 + * @param bsList + * @param analysisResultId + */ + public static void batchInsert2EsDuplicateRemoveByAnalysisResultId(List bsList, String analysisResultId) { + EsMapperHolder.getEsBankStatementMapper().refresh(); + + // 去重 + Map groupById = bsList.stream().collect(Collectors.toMap(BankStatement::getId, Function.identity())); + Set idSet = groupById.keySet(); + //根据id取es查询 返回的就是重复数据 + List esExistIdList = searchId(EsMapperHolder.getEsBankStatementMapper(), BankStatement.class, idSet,"analysisResultId", analysisResultId); + if(CollectionUtil.isEmpty(esExistIdList)){ + EsMapperHolder.getEsBankStatementMapper().insertBatch(bsList); + }else { + Set esIdSet = esExistIdList.stream().map(BankStatement::getId).collect(Collectors.toSet()); + idSet.removeAll(esIdSet); + if(CollectionUtil.isEmpty(idSet)){ + return; + }else { + List saveLis = new ArrayList<>(); + for (String id : idSet) { + saveLis.add(groupById.get(id)); + } + EsMapperHolder.getEsBankStatementMapper().insertBatch(saveLis); + } + } + } + + public static void batchInsertOai2EsDuplicateRemoveByAnalysisResultId(List oaiList, String analysisResultId) { + + // 去重 + Map groupById = oaiList.stream().collect(Collectors.toMap(OpeningAccountInfo::getId, Function.identity())); + Set idSet = groupById.keySet(); + //根据id取es查询 返回的就是重复数据 + List esExistIdList = searchId(EsMapperHolder.getEsOpeningAccountInfoMapper(), OpeningAccountInfo.class, idSet, "analysisResultId", analysisResultId); + if(CollectionUtil.isEmpty(esExistIdList)){ + EsMapperHolder.getEsOpeningAccountInfoMapper().insertBatch(oaiList); + }else { + Set esIdSet = esExistIdList.stream().map(OpeningAccountInfo::getId).collect(Collectors.toSet()); + idSet.removeAll(esIdSet); + if(CollectionUtil.isEmpty(idSet)){ + return; + }else { + List saveLis = new ArrayList<>(); + for (String id : idSet) { + saveLis.add(groupById.get(id)); + } + EsMapperHolder.getEsOpeningAccountInfoMapper().insertBatch(saveLis); + } + } + } + + public static String generateMD5(String uniqueKey) { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] messageDigest = md.digest(uniqueKey.getBytes()); + + // Convert byte array to hexadecimal string + StringBuilder hexString = new StringBuilder(); + for (byte b : messageDigest) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + + return hexString.toString(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + return null; + } + } + + public static boolean deduplication(BankStatement bs,Set uniqueKeySet){ + String uniqueKey = bs.getCardHolderName()+bs.getIdCardNo()+bs.getCardNumber()+bs.getTransactionTime()+bs.getTransactionAmount()+ + bs.getBalance()+bs.getTransactionInstitutions()+bs.getCounterpartyName()+bs.getCounterpartyAccount()+bs.getSummary()+bs.getTransRemark(); + //去重 + uniqueKey = generateMD5(uniqueKey); + if (uniqueKeySet.contains(uniqueKey)) { + return true; + } + uniqueKeySet.add(uniqueKey); + return false; + } + + public static boolean deduplication(String uniqueKey,Set uniqueKeySet){ + if (uniqueKeySet.contains(uniqueKey)) { + return true; + } + uniqueKeySet.add(uniqueKey); + return false; + } + + public static String getBSCacheKey(String bankName) { + return getCacheKeyPrefix(bankName) + ".BS"; + } + + + public static String getOAICacheKey(String bankName) { + return getCacheKeyPrefix(bankName) + ".OAI"; + } + + + private static String getCacheKeyPrefix(String bankName) { + return PinyinUtil.getPinyin(bankName); + } + + public static List getDest(List src) { + @SuppressWarnings("unchecked") + List dest = (List) Arrays.asList(new Object[src.size()]); + + Collections.copy(dest, src); + + return dest; + } + + private static final String KEY_SERIAL_NUMBER = "serialNumber"; + private static final String KEY_BALANCE = "balance"; + private static final String KEY_TRANS_TIME = "transTime"; + private static final String KEY_TRANS_DATE = "transDate"; + + /** + * 是否是同一条流水记录 + *
+     *     需要同时有三个属性
+     * 
+ * + * @param obj1 流水记录 + * @param obj2 流水记录 + * @return 返回结果 + */ + public static boolean isTheSameBankStatement(Object obj1, Object obj2) { + JSONObject entry1 = JSONUtil.parseObj(obj1); + JSONObject entry2 = JSONUtil.parseObj(obj2); + + if (entry1 == null) return false; + if (entry2 == null) return false; + + return Objects.equals(entry2.get(KEY_SERIAL_NUMBER), entry1.get(KEY_SERIAL_NUMBER)) + && Objects.equals(entry2.get(KEY_BALANCE), entry1.get(KEY_BALANCE)) + && Objects.equals(entry2.get(KEY_TRANS_DATE), entry1.get(KEY_TRANS_DATE)) + && Objects.equals(entry2.get(KEY_TRANS_TIME), entry1.get(KEY_TRANS_TIME)); + } + + public static void handleException(Exception exception) { + if (exception instanceof ExcelDataConvertException) { + ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception; + String errorInfo = StrUtil.format( + "第{}行,第{}列解析异常,数据为:{}", + excelDataConvertException.getRowIndex()+1, + excelDataConvertException.getColumnIndex()+1, + excelDataConvertException.getCellData().getStringValue()); + throw new RuntimeException(errorInfo); + } + } + + + public static String generateMD5Id(BankStatement bs,String caseId){ + String cardHolderName = StrUtil.isEmpty(bs.getCardHolderName())?"":bs.getCardHolderName(); + String idCardNo = StrUtil.isEmpty(bs.getIdCardNo())?"":bs.getIdCardNo(); + String cardNumber = StrUtil.isEmpty(bs.getCardNumber())?"":bs.getCardNumber(); + Date transactionTime = bs.getTransactionTime(); + BigDecimal transactionAmount = bs.getTransactionAmount(); + BigDecimal balance = bs.getBalance(); + String transactionInstitutions = StrUtil.isEmpty(bs.getTransactionInstitutions())?"":bs.getTransactionInstitutions(); + String counterpartyName = StrUtil.isEmpty(bs.getCounterpartyName())?"":bs.getCounterpartyName(); + String counterpartyAccount = StrUtil.isEmpty(bs.getCounterpartyAccount())?"":bs.getCounterpartyAccount(); + String summary = StrUtil.isEmpty(bs.getSummary())?"":bs.getSummary(); + String transRemark = StrUtil.isEmpty(bs.getTransRemark())?"":bs.getTransRemark(); + + String uniqueKey = caseId + bs.getBankName()+ cardHolderName + idCardNo + cardNumber + transactionTime + transactionAmount + + balance + transactionInstitutions + counterpartyName + counterpartyAccount + summary + transRemark; + //去重 + return generateMD5(uniqueKey); + } + + + public static String generateMD5Id4OAI(OpeningAccountInfo oai, String caseId) { + String uniqueKey = caseId + oai.getBankName()+oai.getName()+oai.getAccountNumber()+oai.getIdNo()+oai.getPhone()+oai.getOpeningAccountDate()+ + oai.getClosingDate()+oai.getStatus()+oai.getCustomerId()+oai.getAccount2CardNumber(); + return generateMD5(uniqueKey); + } + + public static List getExcelFile(List fileList){ + // 筛选Excel文件 + return fileList.stream() + .filter(f -> f.getName().toLowerCase().endsWith(".xls") + || f.getName().toLowerCase().endsWith(".xlsx") + || f.getName().toLowerCase().endsWith(".csv") + || f.getName().toLowerCase().endsWith(".et")) + .collect(Collectors.toList()); + + } + + public static String getSourceFileName(String absolutePath,String bankName){ + String sourceFile = absolutePath; + if(sourceFile.contains(bankName+"\\")){ + sourceFile = sourceFile.split(bankName+"\\\\")[1]; + }else if(sourceFile.contains(bankName+"/")){ + sourceFile = sourceFile.split(bankName+"/")[1]; + } + return sourceFile; + } + + + //{4,} 表示必须有四个或更多的大写字母或数字。 + private final static String PLATE_NUMBER_VERIFY = "[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领]{1}[A-Za-z]{1}[A-Za-z0-9]{2,6}"; + private final static String CarNumberVerify = "^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$"; + + public static void main(String[] args) { + + String text = "车辆违章车辆号码使DBM5226获取cookie失败,车辆违章车辆号码领aAM5226学获取cookie失败,车辆违章车辆号码云aM学获取cookie失败,车辆违章车辆号码云aM444444456777学获取cookie失败"; + // 正则表达式匹配车牌号码 + Pattern pattern = Pattern.compile(CarNumberVerify); + Matcher matcher = pattern.matcher(text); + StringBuilder result = new StringBuilder(); + while (matcher.find()) { + if (result.length() > 0) { + result.append(","); + } + result.append(matcher.group()); + } + System.out.println("提取的车牌号码:" + result.toString()); + } + + static final Pattern PLATE_NUMBER_PATTERN = Pattern.compile(PLATE_NUMBER_VERIFY); + /** + * 从流水中提取车牌号 + */ + public static void extractPlateNumber(BankStatement bs,List plateNumberInfoList){ + // 正则表达式匹配车牌号码 + String transactionInstitutions = bs.getTransactionInstitutions(); + findPlateNumber(transactionInstitutions,bs,plateNumberInfoList); + String counterpartyName = bs.getCounterpartyName(); + findPlateNumber(counterpartyName,bs,plateNumberInfoList); + String counterpartyAccount = bs.getCounterpartyAccount(); + findPlateNumber(counterpartyAccount,bs,plateNumberInfoList); + String counterpartIdCardNo = bs.getCounterpartIdCardNo(); + findPlateNumber(counterpartIdCardNo,bs,plateNumberInfoList); + String counterpartyBankName = bs.getCounterpartyBankName(); + findPlateNumber(counterpartyBankName,bs,plateNumberInfoList); + String summary = bs.getSummary(); + findPlateNumber(summary,bs,plateNumberInfoList); + String transRemark = bs.getTransRemark(); + findPlateNumber(transRemark,bs,plateNumberInfoList); + String transChannel = bs.getTransChannel(); + findPlateNumber(transChannel,bs,plateNumberInfoList); + String realCounterpartyName = bs.getRealCounterpartyName(); + findPlateNumber(realCounterpartyName,bs,plateNumberInfoList); + String realCounterpartyAccount = bs.getRealCounterpartyAccount(); + findPlateNumber(realCounterpartyAccount,bs,plateNumberInfoList); + + } + + public static void extractPlateNumberWithUploadFile(String value,String caseId,String mou,List plateNumberInfoList){ + if(StrUtil.isEmpty(value)){ + return; + } + Matcher matcher = PLATE_NUMBER_PATTERN.matcher(value); + while (matcher.find()) { + String group = matcher.group(); + + String[] split = value.split(group); + String start = split[0]; + String sourceContent = start.length() > 5?start.substring(0,4):start; + sourceContent +=group; + if(split.length > 1){ + String end = split[1]; + end = end.length() > 5?end.substring(0,4):end; + sourceContent += end; + } + + PlateNumberInfo plateNumberInfo = new PlateNumberInfo(); + plateNumberInfo.setPlateNumber(group.toUpperCase()); +// plateNumberInfo.setBsHolder(bs.getCardHolderName()); + plateNumberInfo.setSourceContent(sourceContent); + plateNumberInfo.setBankName(mou); +// plateNumberInfo.setSourceFile(bs.getBankName()+"/"+bs.getSourceFile()); + plateNumberInfo.setCaseId(caseId); + plateNumberInfo.setHasDeal(0); + plateNumberInfo.setId(IdUtil.objectId()); + plateNumberInfoList.add(plateNumberInfo); + + } + } + + public static void findPlateNumber(String value,BankStatement bs,List plateNumberInfoList){ + if(StrUtil.isEmpty(value)){ + return; + } + Matcher matcher = PLATE_NUMBER_PATTERN.matcher(value); + while (matcher.find()) { + PlateNumberInfo plateNumberInfo = new PlateNumberInfo(); + plateNumberInfo.setPlateNumber(matcher.group().toUpperCase()); + plateNumberInfo.setBsHolder(bs.getCardHolderName()); + plateNumberInfo.setSourceContent(value); + plateNumberInfo.setBankName(bs.getBankName()); +// plateNumberInfo.setSourceFile(bs.getBankName()+"/"+bs.getSourceFile()); + plateNumberInfo.setCaseId(bs.getCaseId()); + plateNumberInfo.setHasDeal(0); + plateNumberInfo.setId(IdUtil.objectId()); + plateNumberInfoList.add(plateNumberInfo); + } + } + + public static void batchInsertPlateNumber(List plateNumberInfoList) { + if(CollectionUtil.isEmpty(plateNumberInfoList)){ + return; + } + EsMapperHolder.getPlateNumberEsMapper().insertBatch(plateNumberInfoList); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/ICBCDataAnalysisHelper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/ICBCDataAnalysisHelper.java new file mode 100644 index 0000000..b3f3075 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/ICBCDataAnalysisHelper.java @@ -0,0 +1,524 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.util.ListUtils; +import com.alibaba.excel.util.StringUtils; +import com.aspose.cells.Cell; +import com.aspose.cells.Cells; +import com.aspose.cells.Workbook; +import com.aspose.cells.Worksheet; + +import com.inscloudtech.bankStatementAnalysis.domain.HeadField; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.bankStatementAnalysis.service.ImportService; +import com.inscloudtech.common.constant.BankStatementConstants; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.exception.dc.AnalyzeDataFailedException; +import com.inscloudtech.common.exception.dc.ImportDataFailedException; +import com.inscloudtech.common.exception.dc.TemplateNotFindException; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.common.utils.file.FileUtils; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.mapper.es.EsICBCBankStatementMapper; +import com.inscloudtech.datacenter.mapper.es.EsICBCCreditCardBankStatementMapper; +import com.inscloudtech.datacenter.service.ImportResultService; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; + +import com.inscloudtech.bankStatementAnalysis.domain.entity.ICBCBankStatementEntry; +import com.inscloudtech.bankStatementAnalysis.domain.entity.ICBCCreditCardBankStatementEntry; + +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.math.BigDecimal; +import java.util.*; + +/** + * 工商银行数据分析 + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class ICBCDataAnalysisHelper { + + private final ImportService importService; + private final ImportResultService importResultService; + private final EsICBCBankStatementMapper bankStatementMapper; + private final EsICBCCreditCardBankStatementMapper creditCardBankStatementMapper; + private final static String BANK_NAME = "工商银行"; + + + public void importData(File dir,String caseId) throws Exception { + List fileList = FileUtil.loopFiles(dir); + if (fileList == null) { + return; + } + + + List excelFileList = HelperUtil.getExcelFile(fileList); + + +// List pdfFileList = fileList.stream() +// .filter(file -> FileUtil.extName(file).equalsIgnoreCase("pdf")) +// .collect(Collectors.toList()); +// Map> groupByPath = excelFileList.stream().collect(Collectors.groupingBy(File::getAbsolutePath)); +// for (File file : pdfFileList) { +// String excelFilename = AsposeUtil.pdf2ExcelV6(file.getAbsolutePath()); +// if(groupByPath.containsKey(excelFilename)){ +// continue; +// } +// excelFileList.add(new File(excelFilename)); +// } + + for (File f : excelFileList) { + try { + String absolutePath = f.getAbsolutePath(); + Workbook wb = new Workbook(absolutePath); + int count = wb.getWorksheets().getCount(); + String sourceFile = HelperUtil.getSourceFileName(absolutePath, BANK_NAME); + + for (int sheetNo = 0; sheetNo < count; sheetNo++) { + try { + Worksheet worksheet = wb.getWorksheets().get(sheetNo); + Cells cells = worksheet.getCells(); + Cell contentCell = cells.get(0, 0); + if (contentCell.getValue() == null) {//空白excel + continue; + } + String worksheetName = worksheet.getName(); + Cell cell420240418 = AsposeUtil.getCell(cells, "入帐日期"); + Cell khCell = AsposeUtil.getCell(cells, "开户日期"); + Cell tradeCell = AsposeUtil.getCell(cells, "交易时间戳"); + Cell khhzh = AsposeUtil.getCell(cells, "卡号或帐号"); + String withSheetName = sourceFile + BankStatementConstants.NAME_WITH_SHEET_NAME + worksheetName; + /**20240418新增模板*/ + if (cell420240418 != null) { + readBSFor20240418(cells,cell420240418,absolutePath, sheetNo,withSheetName); + }else if (khCell != null) { + // 判断是否是开户信息 + int rowNumber = khCell.getRow() + 1; + importService.readOAIData(absolutePath, rowNumber, + sheetNo, caseId, BANK_NAME, withSheetName); + } else if (tradeCell != null) { // 流水信息 + readBS(absolutePath, sheetNo,withSheetName); + } else if (khhzh != null) { // 开户 + importService.readOAIData(absolutePath, khhzh.getRow() + 1, + sheetNo, caseId, BANK_NAME, withSheetName); + } else { + throw new TemplateNotFindException(withSheetName); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } + + private void readBSFor20240418(Cells cells,Cell dateCell,String absolutePath, int sheetNo,String sourceFile) { + int startRow = dateCell.getRow(); + Cell cardHolderNameCell = cells.get(startRow - 1, 1); + if(null == cardHolderNameCell || StrUtil.isEmpty(cardHolderNameCell.getStringValue())){ + throw new ImportDataFailedException("读取持卡人信息异常", sourceFile); + } + + String cardHolderName = cardHolderNameCell.getStringValue().trim(); + List headFields = new ArrayList<>(); + headFields.add(new HeadField("transactionAmount","发生额")); + headFields.add(new HeadField("balance","余额")); + headFields.add(new HeadField("accountNumber","商密二级,帐号")); + importService.readMultiplePersonAndMultipleHeadBankStatement(absolutePath,startRow + 1,sheetNo, + ICBCBankStatementEntry.class,bankStatementMapper,cardHolderName,sourceFile,headFields); + } + + + + + + public void analyzeIData(String caseId) { + // 储蓄卡流水 + analyzeSavingsCardBS(caseId); + // 信用卡流水 + analyzeCreditCardBS(caseId); + } + + private void analyzeCreditCardBS(String caseId) { + List bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(creditCardBankStatementMapper, ICBCCreditCardBankStatementEntry.class); + List oaiData = importService.getOAIData(caseId, BANK_NAME); + Map nameAccMap = new HashMap<>(); + Map cardNumberAccMap = new HashMap<>(); + Map account2CardNumberMap = new HashMap<>(); + + for (OpeningAccountInfo entry : oaiData) { + if (StrUtil.isNotEmpty(entry.getName())) { + nameAccMap.put(entry.getName(), entry); + } + + if (StrUtil.isNotEmpty(entry.getAccountNumber())) { + cardNumberAccMap.put(entry.getAccountNumber(), entry); + } + + if (StrUtil.isNotEmpty(entry.getAccount2CardNumber())) { + account2CardNumberMap.put(entry.getAccount2CardNumber(), entry); + } + + } + + //去重 + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + + for (ICBCCreditCardBankStatementEntry entry : entityList) { + String sourceFile = entry.getSourceFile(); + try { + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + bs.setCardNumber(entry.getCardNumber()); + bs.setCardHolderName(entry.getCardHolderName()); + if (StrUtil.isEmpty(bs.getCardHolderName())) { + // 从开户信息中获取数据 + OpeningAccountInfo acc = cardNumberAccMap.getOrDefault(entry.getCardNumber(), null); + if (acc != null) { + bs.setCardHolderName(acc.getName()); + bs.setIdCardNo(acc.getIdNo()); + }else { + acc = account2CardNumberMap.getOrDefault(entry.getCardNumber(), null); + if (acc != null) { + bs.setCardHolderName(acc.getName()); + bs.setIdCardNo(acc.getIdNo()); + } + } + }else { + // 从开户信息中获取数据 + OpeningAccountInfo acc = nameAccMap.getOrDefault(entry.getCardHolderName(), null); + if (acc != null) { + bs.setIdCardNo(acc.getIdNo()); + } + } + + bs.setCounterpartyName(entry.getCounterpartyName()); + bs.setCounterpartIdCardNo(null); + bs.setCounterpartyAccount(entry.getCounterpartyAccount()); + bs.setSummary(entry.getSummary()); + bs.setTransRemark(entry.getTransRemark()); + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + bs.setTransactionInstitutions(entry.getTransactionInstitutions()); + // 交易金额 + String loanFlag = entry.getLoanFlag(); + if (StrUtil.isNotEmpty(loanFlag)) { + if (Objects.equals("借", loanFlag)) { + bs.setTransactionAmount(BigDecimal.ZERO.subtract(entry.getTransactionAmount())); + } else { + bs.setTransactionAmount(entry.getTransactionAmount()); + } + } + // 交易时间 2015-08-29-13.16.32.670138 + String transactionTime = entry.getTransactionTime(); + String pattern = "yyyy-MM-dd-HH.mm.ss"; + int len = pattern.length(); + transactionTime = transactionTime.substring(0, len); + + try { + bs.setTransactionTime(DateUtil.parse(transactionTime, pattern)); + } catch (Exception e) { + log.error("解析时间出错", e); + + throw new AnalyzeDataFailedException("解析时间出错: " + e.getMessage(), e, sourceFile); + } + // 信用卡余额为0 + bs.setBalance(entry.getUpdateBalance()); + bs.setRemark("信用卡"); + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e, sourceFile); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + private void analyzeSavingsCardBS(String caseId) { + + List bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(bankStatementMapper, ICBCBankStatementEntry.class); + +// Map> oaiMap = importService.getOAIMap(caseId, BANK_NAME); + List oaiData = importService.getOAIData(caseId, BANK_NAME); + Map nameAccMap = new HashMap<>(); + Map cardNumberAccMap = new HashMap<>(); + Map accountNumberAccMap = new HashMap<>(); + Map account2CardNumberMap = new HashMap<>(); + + for (OpeningAccountInfo entry : oaiData) { + if (StrUtil.isNotEmpty(entry.getName())) { + nameAccMap.put(entry.getName(), entry); + } + + if (StrUtil.isNotEmpty(entry.getAccountNumber())) { + cardNumberAccMap.put(entry.getAccountNumber(), entry); + } + + if (StrUtil.isNotEmpty(entry.getCustomerId())) { + accountNumberAccMap.put(entry.getCustomerId(), entry); + } + if (StrUtil.isNotEmpty(entry.getAccount2CardNumber())) { + account2CardNumberMap.put(entry.getAccount2CardNumber(), entry); + } + + } + + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + + for (ICBCBankStatementEntry entry : entityList) { + String sourceFile = entry.getSourceFile(); + try { + String cardNumber = entry.getCardNumber(); + String accountNumber = entry.getAccountNumber(); + if (StrUtil.isEmpty(entry.getCardHolderName())) { + if (cardNumberAccMap.containsKey(cardNumber)) { + OpeningAccountInfo info = cardNumberAccMap.get(cardNumber); + entry.setCardHolderName(info.getName()); + entry.setIdCardNo(info.getIdNo()); + } else if (cardNumberAccMap.containsKey(accountNumber)) { + OpeningAccountInfo info = cardNumberAccMap.get(accountNumber); + entry.setCardHolderName(info.getName()); + entry.setIdCardNo(info.getIdNo()); + } else if(accountNumberAccMap.containsKey(cardNumber)){ + OpeningAccountInfo info = accountNumberAccMap.get(cardNumber); + entry.setCardHolderName(info.getName()); + entry.setIdCardNo(info.getIdNo()); + + } else if(accountNumberAccMap.containsKey(accountNumber)){ + OpeningAccountInfo info = accountNumberAccMap.get(accountNumber); + entry.setCardHolderName(info.getName()); + entry.setIdCardNo(info.getIdNo()); + + } else if(account2CardNumberMap.containsKey(accountNumber)){ + OpeningAccountInfo info = account2CardNumberMap.get(accountNumber); + entry.setCardHolderName(info.getName()); + entry.setIdCardNo(info.getIdNo()); + }else if(account2CardNumberMap.containsKey(cardNumber)){ + OpeningAccountInfo info = account2CardNumberMap.get(cardNumber); + entry.setCardHolderName(info.getName()); + entry.setIdCardNo(info.getIdNo()); + } + + }else { + OpeningAccountInfo acc = nameAccMap.getOrDefault(entry.getCardHolderName(), null); + if (acc != null) { + entry.setIdCardNo(acc.getIdNo()); + } + } + + + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + + cardNumber = StrUtil.isEmpty(cardNumber)? accountNumber : cardNumber; + + bs.setCardNumber(cardNumber); + + bs.setCardHolderName(entry.getCardHolderName()); + bs.setIdCardNo(entry.getIdCardNo() == null?"":entry.getIdCardNo()); + + String counterpartName = entry.getCounterpartName(); + bs.setCounterpartyName(counterpartName); + + + + bs.setCounterpartyAccount(entry.getCounterpartyAccount()); + bs.setCounterpartyBankName(entry.getCounterpartyBankName()); + bs.setTransRemark(entry.getTransRemark()); + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + bs.setTransactionInstitutions(entry.getTransactionInstitutions()); + // 交易金额 + String loanFlag = entry.getLoanFlag(); + try { + if (StrUtil.isNotEmpty(loanFlag) && StrUtil.isNotEmpty(entry.getTransactionAmount())) { + BigDecimal transactionAmount = new BigDecimal(entry.getTransactionAmount()); + if (transactionAmount.compareTo(BigDecimal.ZERO) < 0) { + transactionAmount = BigDecimal.ZERO.subtract(transactionAmount); + } + + if (Objects.equals("借", loanFlag)) { + bs.setTransactionAmount(BigDecimal.ZERO.subtract( new BigDecimal(entry.getTransactionAmount()))); + } else { + bs.setTransactionAmount(transactionAmount); + } + } + }catch (Exception e){ + throw new AnalyzeDataFailedException( + StrUtil.format("金额, 无法将字符串【{}】化为金额。", entry.getTransactionAmount()), e, entry.getSourceFile()); + } + + +// 交易时间 2015-08-29-13.16.32.670138 + String transactionTime = entry.getTransactionTime(); + String transactionDate = entry.getTransactionDate(); + try { + if(StrUtil.isNotEmpty(transactionDate)){ + String format = "yyyy-MM-ddHH.mm.ss"; + if(!transactionDate.contains("-")){ + format = "yyyyMMddHH.mm.ss"; + } + bs.setTransactionTime(DateUtil.parse(transactionDate + transactionTime, format)); + }else if(transactionTime.contains(".")){ + String pattern = "yyyy-MM-dd-HH.mm.ss"; + int len = pattern.length(); + transactionTime = transactionTime.substring(0, len); + bs.setTransactionTime(DateUtil.parse(transactionTime, pattern)); + }else { + + } + + } catch (Exception e) { + throw new AnalyzeDataFailedException(StrUtil.format("解析时间失败,时间:{}", transactionTime), e,entry.getSourceFile()); + } + + bs.setBalance(new BigDecimal(entry.getBalance())); + bs.setSummary(entry.getSummary()); + bs.setTransChannel(entry.getTransChannel()); + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entry.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e, sourceFile); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + + + private void readBS(String excelFileName, int sheetNo,String sourceFile) { + + try { + // 分两种流水,一种是信用卡流水,一种是储蓄卡流水 + int type = getBSType(excelFileName, sheetNo); + if (type == Constants.ICBC_BS_TYPE_CREDIT_CARD) { // 信用卡流水 + try (ExcelReader reader = EasyExcel.read(excelFileName).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .head(ICBCCreditCardBankStatementEntry.class) + .registerReadListener(HelperUtil.getReadListener( + creditCardBankStatementMapper, + ICBCCreditCardBankStatementEntry.class, + "",sourceFile)) + .build(); + reader.read(sheet); + + + } catch (Exception e) { + log.error("读取excel文件失败", e); + throw new ImportDataFailedException(e.getMessage(), excelFileName); + } + } else if (type == Constants.ICBC_BS_TYPE_DEBIT_CARD) { // 储蓄卡流水 + try (ExcelReader reader = EasyExcel.read(excelFileName).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .head(ICBCBankStatementEntry.class) + .registerReadListener(HelperUtil.getReadListener( + bankStatementMapper, ICBCBankStatementEntry.class, "",sourceFile)) + .build(); + reader.read(sheet); + + + } catch (Exception e) { + log.error("读取excel文件失败", e); + throw new ImportDataFailedException(e.getMessage(), excelFileName); + } + } + } catch (Exception e) { + log.error("读取excel文件失败", e); + throw new ImportDataFailedException(e.getMessage(), excelFileName); + } + } + + private int getBSType(String excelFilename, int sheetNo) { + + File file = new File(excelFilename); + Cell cell = AsposeUtil.getCell(file, sheetNo, "更新后余额"); + if (cell != null) { + return Constants.ICBC_BS_TYPE_CREDIT_CARD; + } else { + Cell c = AsposeUtil.getCell(file, sheetNo, "余额"); + if (c != null) { + return Constants.ICBC_BS_TYPE_DEBIT_CARD; + } + } + + return -1; + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/MThreadUtil.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/MThreadUtil.java new file mode 100644 index 0000000..dbd97e3 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/MThreadUtil.java @@ -0,0 +1,46 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.concurrent.Callable; +import java.util.concurrent.Future; +import java.util.concurrent.ThreadPoolExecutor; + +public class MThreadUtil { + + @RequiredArgsConstructor + @Component + public static class MasterPool { + private final ThreadPoolExecutor masterDynamicExecutor; + + public void executeAsync(Runnable r) { + masterDynamicExecutor.submit(r); + } + + public Future executeAsyncByFuture(Runnable task){ + return masterDynamicExecutor.submit(task); + } + } + + @Getter + @RequiredArgsConstructor + @Component + public static class WorkerPool { + + private final ThreadPoolExecutor workerDynamicExecutor; + + public void executeAsync(Runnable r) { + workerDynamicExecutor.submit(r); + } + + public Future executeAsync(Callable c){ + return workerDynamicExecutor.submit(c); + } + + public Future executeAsyncByFuture(Runnable r) { + return workerDynamicExecutor.submit(r); + } + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/PABDataAnalysisHelper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/PABDataAnalysisHelper.java new file mode 100644 index 0000000..edee219 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/PABDataAnalysisHelper.java @@ -0,0 +1,844 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.util.ListUtils; +import com.aspose.cells.Cell; +import com.aspose.cells.Range; +import com.aspose.cells.Workbook; +import com.aspose.cells.Worksheet; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; + +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.bankStatementAnalysis.helper.MThreadUtil; +import com.inscloudtech.bankStatementAnalysis.service.ImportService; +import com.inscloudtech.common.constant.BankStatementConstants; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.exception.dc.AnalyzeDataFailedException; +import com.inscloudtech.common.exception.dc.ImportDataFailedException; +import com.inscloudtech.common.exception.dc.TemplateNotFindException; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.common.utils.file.FileUtils; +import com.inscloudtech.converter.ExcelStringToJavaBigDecimalConverter; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.mapper.es.*; +import com.inscloudtech.datacenter.service.ImportResultService; +import com.inscloudtech.bankStatementAnalysis.listener.SPAAccountInfoReadListener; +import com.inscloudtech.bankStatementAnalysis.listener.SPACustomerInfoReadListener; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; + +import com.inscloudtech.bankStatementAnalysis.domain.entity.*; + +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + + + +/** + * 平安银行数据分析 + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class PABDataAnalysisHelper { + + + private final MThreadUtil.WorkerPool workerPool; + private final ImportService importService; + private final ImportResultService importResultService; + private final EsSPABANKOpeningAccountInfoMapper accountInfoMapper; + private final EsSPACustomerInfoMapper customerInfoMapper; + private final EsSPABANKStatementMapper statementMapper; + + private final EsSPACreditCardAccountInfoMapper esSPACreditCardAccountInfoMapper; + private final EsSPACreditCardStatementMapper esSPACreditCardStatementMapper; + private final EsSPAOtherStatementMapper esSPAOtherStatementMapper; + + private final ESOpeningAccountInfoMapper esOpeningAccountInfoMapper; + + + private final static String BANK_NAME = "平安银行"; + + private String caseId = ""; + + public void analyzeData(String caseId) { + + analyzeOAI(caseId); + analyzeBS(caseId); + } + + public void importData(File file, String caseId) throws Exception { + this.caseId = caseId; + if (!file.exists()) { + throw new RuntimeException(" 文件不存在."); + } + + List fileList = FileUtil.loopFiles(file); + List excelFile = HelperUtil.getExcelFile(fileList); + // 分为信用卡和储蓄卡 + // todo 不能直接用文件名来区分 + List creditCardFileList = excelFile.stream() + .filter(f -> { + String mainName = FileUtil.mainName(f); + + return mainName.contains("信用卡"); + }) + .collect(Collectors.toList()); + + List savingsCardFileList = + excelFile.stream().filter(f -> !creditCardFileList.contains(f)).collect(Collectors.toList()); + + boolean hasRead = readSavingsCardData(savingsCardFileList); + if(!hasRead){ + readCreditCardData(creditCardFileList); + } + + } + + + /** + * 分析开户信息 + */ + private void analyzeOAI(String caseId) { + analyzeCreditCardOAI(caseId); + analyzeSavingCardOAI(caseId); + } + + private void analyzeCreditCardOAI(String caseId) { + List oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(esSPACreditCardAccountInfoMapper, SPACreditCardAccountInfoEntity.class); + Set uniqueKeySet = new HashSet(); + for (SPACreditCardAccountInfoEntity entity : entityList) { + + OpeningAccountInfo oai = new OpeningAccountInfo(); + oai.setName(entity.getCardHolderName()); + oai.setBankName(BANK_NAME); + oai.setIdNo(entity.getIdCardNo()); + oai.setPhone(entity.getPhone()); + oai.setAccountNumber(entity.getCardNumber()); + oai.setBalance(new BigDecimal("0")); + oai.setOpeningAccountDate(entity.getOpeningAccountDate()); + oai.setAddress(entity.getAddress()); + + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + oaiList.add(oai); + if (oaiList.size() >= Constants.BATCH_SIZE) { + // 保存数据库 + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + if (!oaiList.isEmpty()) { + // 保存数据库 + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + } + } + + private void analyzeSavingCardOAI(String caseId) { + List oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getNewEntityList(accountInfoMapper, SPAAccountInfoEntity.class); + Set uniqueKeySet = new HashSet(); + for (SPAAccountInfoEntity entity : entityList) { + + OpeningAccountInfo oai = new OpeningAccountInfo(); + oai.setName(entity.getCardHolderName()); + oai.setBankName(BANK_NAME); + oai.setAccountNumber(entity.getCardNumber()); + oai.setIdType(entity.getIdType()); + oai.setIdNo(entity.getIdCardNo()); + oai.setOpeningAccountDate(entity.getOpeningAccountDate()); + oai.setClosingDate(entity.getClosingDate()); + oai.setStatus(entity.getStatus()); + oai.setType(entity.getType()); + oai.setAccountOpeningInstitution(entity.getAccountOpeningInstitution()); + + String name = oai.getName(); +//todo 需优化 + SPACustomerInfoEntity customer = + HelperUtil.getEntity(customerInfoMapper, SPACustomerInfoEntity.class, "cardHolderName", name); + if (customer != null) { + oai.setPhone(customer.getPhone()); + oai.setAddress(customer.getAddress()); + } + + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + oaiList.add(oai); + if (oaiList.size() >= Constants.BATCH_SIZE) { + // 保存数据库 + List dest = HelperUtil.getDest(oaiList); + workerPool.executeAsync(() -> HelperUtil.batchSaveOAI2Es(dest, caseId)); + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + if (!oaiList.isEmpty()) { + // 保存数据库 + List dest = HelperUtil.getDest(oaiList); + workerPool.executeAsync(() -> HelperUtil.batchSaveOAI2Es(dest, caseId)); + } + } + + /** + * 分析流水信息 + */ + private void analyzeBS(String caseId) { + analyzeSavingCardBS(caseId); + analyzeCreditCardBS(caseId); + } + + private void analyzeCreditCardBS(String caseId) { + List bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(esSPACreditCardStatementMapper, SPACreditCardStatementEntity.class); + + List accountInfoList = + HelperUtil.getEntityList(esSPACreditCardAccountInfoMapper, SPACreditCardAccountInfoEntity.class); + + Map map = new HashMap<>(); + + for (SPACreditCardAccountInfoEntity entity : accountInfoList) { + map.put(entity.getCardHolderName(), entity); + } + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + + for (SPACreditCardStatementEntity entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + bs.setCardHolderName(entity.getCardHolderName()); + bs.setIdCardNo(entity.getIdCardNo()); + + SPACreditCardAccountInfoEntity info = map.getOrDefault(entity.getCardHolderName(), null); + if (info != null) { + bs.setPhone(info.getPhone()); + } + + bs.setCardNumber(entity.getCardNumber()); + bs.setTransRemark(entity.getTransRemark()); + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + bs.setTransactionAmount(entity.getTransactionAmount()); + + try { + bs.setTransactionTime(DateUtil.parse(entity.getTransDate(), "yyyyMMdd")); + } catch (Exception e) { + log.error("解析时间失败", e); + + throw new AnalyzeDataFailedException(StrUtil.format("解析时间失败, 流水日期: {}", entity.getTransDate()), e, sourceFile); + } + + bs.setBalance(new BigDecimal("0")); + bs.setRemark("信用卡"); + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entity.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= Constants.BATCH_SIZE) { + + List dest = HelperUtil.getDest(bsList); + workerPool.executeAsync(() -> HelperUtil.batchInsert2Es(dest, caseId)); + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e, sourceFile); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + // 保存数据库 + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + workerPool.executeAsync(() -> HelperUtil.batchInsert2Es(dest, caseId)); + } + } + + private void analyzeSavingCardBS(String caseId) { + + List bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = HelperUtil.getEntityList(statementMapper, SPAStatementEntity.class); + + List oaiList = HelperUtil.getEntityListV2(esOpeningAccountInfoMapper, OpeningAccountInfo.class, caseId); + + Map map = new HashMap<>(); + for (OpeningAccountInfo entity : oaiList) { + map.put(entity.getName(), entity); + } + + Map> groupByAccountNo = oaiList.stream().filter(item -> StrUtil.isNotEmpty(item.getAccountNumber())).collect(Collectors.groupingBy(OpeningAccountInfo::getAccountNumber)); + + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + + for (SPAStatementEntity entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + String cardHolderName = entity.getCardHolderName(); + String cardNumber = entity.getCardNumber(); + if (StringUtils.isEmpty(cardHolderName)) { + if (StrUtil.isEmpty(cardNumber) || "null".equals(cardNumber)) { + continue; + } + + if (!groupByAccountNo.containsKey(cardNumber)) { + continue; + } + + List infoList = groupByAccountNo.get(cardNumber); + OpeningAccountInfo info = infoList.get(0); + + cardHolderName = info.getName(); + } + + // 流水 + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + bs.setCardHolderName(cardHolderName); + + // 根据名称去查找基本信息 + OpeningAccountInfo info = map.getOrDefault(cardHolderName, null); + if (info != null) { + bs.setPhone(info.getPhone()); + bs.setIdCardNo(info.getIdNo()); + } + + bs.setCardNumber(cardNumber); + // 1 货币类型 + // 人民币 + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + // 2 交易金额 可能是double或者int类型 + String loanFlag = entity.getLoanFlag(); + if (StrUtil.isNotEmpty(loanFlag)) { + if (Objects.equals("+", loanFlag) || Objects.equals("贷", loanFlag)) { + bs.setTransactionAmount(entity.getTransactionAmount()); + } else { + bs.setTransactionAmount(BigDecimal.ZERO.subtract(entity.getTransactionAmount())); + } + } else { + // 通过借方发生额和贷方发生额来计算交易金额 + BigDecimal debitAmount = entity.getDebitAmount(); + BigDecimal creditAmount = entity.getCreditAmount(); + + if (debitAmount != null) { + bs.setTransactionAmount(debitAmount.negate()); + } + + if (creditAmount != null) { + bs.setTransactionAmount(creditAmount); + } + } + // 3 余额 + bs.setBalance(entity.getBalance()); + // 4 交易日期 + String transDate = entity.getTransDate(); + try { + if (StrUtil.isNotEmpty(transDate)) { // 20211006 + String transTime = entity.getTransTime(); + if (StrUtil.isNotEmpty(transTime)) { // 14:15:07 + if (transTime.length() > Constants.DATE_TIME_FULL_FORMAT_LENGTH) { + // 20131001145718000 + transTime = transTime.substring(0, Constants.DATE_TIME_FULL_FORMAT_LENGTH); + bs.setTransactionTime(DateUtil.parse(transTime, "yyyyMMddHHmmss")); + } else { // 20081222 030411 + if (transTime.contains(":")) { + bs.setTransactionTime(DateUtil.parse(transDate + " " + transTime, "yyyyMMdd HH:mm:ss")); + } else { + bs.setTransactionTime(DateUtil.parse(transDate + transTime, "yyyyMMddHHmmss")); + } + } + } else { + bs.setTransactionTime(DateUtil.parse(transDate, "yyyyMMdd")); + } + } + } catch (Exception e) { + log.error("解析交易日期异常", e); +// String filename = ParseErrorHelper.getFilenameByValue(entity.getId()); + throw new AnalyzeDataFailedException(entity.getSourceFile()+"解析交易日期错误: " + e.getMessage(), e, entity.getSourceFile()); + } + + String counterpartyName = entity.getCounterpartyName(); + bs.setCounterpartyName(counterpartyName); + + if (StrUtil.isNotEmpty(counterpartyName)) { + // 根据对手名去查找 + OpeningAccountInfo f = map.getOrDefault(counterpartyName, null); + if (f != null) { + bs.setCounterpartIdCardNo(f.getIdNo()); + } + } + + bs.setTransactionInstitutions(entity.getTransactionInstitutions()); + bs.setSummary(entity.getSummary()); + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + bs.setCounterpartyBankName(entity.getCounterpartyBankName()); + bs.setTransRemark(entity.getTransRemark()); + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entity.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= Constants.BATCH_SIZE) { + + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e, sourceFile); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + + // 保存数据库 + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + workerPool.executeAsync(() -> HelperUtil.batchInsert2Es(dest, caseId)); + } + } + + + private void readCreditCardData(List creditCardFileList) { + // + for (File excelFile : creditCardFileList) { + try { + String absolutePath = excelFile.getAbsolutePath(); + Workbook wb = new Workbook(absolutePath); + int count = wb.getWorksheets().getCount(); + String sourceFile = HelperUtil.getSourceFileName(absolutePath, BANK_NAME); + for (int sheetNo = 0; sheetNo < count; sheetNo++) { + Worksheet worksheet = wb.getWorksheets().get(sheetNo); + Cell cell = AsposeUtil.getCell(excelFile, sheetNo, "手机号码"); + Cell khxmCell = AsposeUtil.getCell(excelFile, sheetNo, "客户姓名"); + if (cell != null) { + // 账户信息 + readCreditCardAccountInfo(excelFile, sheetNo); + } else if (khxmCell != null) { + int headRowNumber = khxmCell.getRow() + 1; + // 流水信息 + readCreditCardBS(excelFile, sheetNo, headRowNumber); + } else { + throw new TemplateNotFindException(sourceFile + BankStatementConstants.NAME_WITH_SHEET_NAME + worksheet.getName()); + } + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } + + private void readCreditCardBS(File excelFile, int sheetNo,int headRowNumber) { + + String sourceFile = HelperUtil.getSourceFileName(excelFile.getAbsolutePath(),BANK_NAME); + + + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + ReadSheet rs = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNumber) + .head(SPACreditCardStatementEntity.class) + .registerReadListener(HelperUtil.getReadListener( + esSPACreditCardStatementMapper, SPACreditCardStatementEntity.class, false,sourceFile)) + .build(); + reader.read(rs); + } + } + + private void readCreditCardAccountInfo(File excelFile, int sheetNo) { + Cell cell = AsposeUtil.getCell(excelFile, sheetNo, "手机号码"); + if (cell == null) { + return; + } + + int headRowNumber = cell.getRow() + 1; + + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + ReadSheet rs = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNumber) + .head(SPACreditCardAccountInfoEntity.class) + .registerReadListener(HelperUtil.getReadListener( + esSPACreditCardAccountInfoMapper, SPACreditCardAccountInfoEntity.class, true,excelFile.getAbsolutePath().split("平安银行")[1])) + .build(); + reader.read(rs); + } + } + + private boolean readSavingsCardData(List savingsCardFileList) { + boolean hasRead = false; + for (File excelFile : savingsCardFileList) { + try { + Cell cell = AsposeUtil.getCell(excelFile, 0, "交易日期"); + + if (cell != null) { + readPingAnBankStatement(excelFile); + hasRead = true; + } else { + readPingAnBankOpeningAccountInfo(excelFile); + hasRead = true; + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + return hasRead; + } + + /** + * 读取流水 + */ + private void readPingAnBankStatement(File excelFile) throws Exception { + String sourceFile = HelperUtil.getSourceFileName(excelFile.getAbsolutePath(),BANK_NAME); + Cell transDateCell = AsposeUtil.getCell(excelFile, 0, "交易日期"); + if (transDateCell == null) { + throw new RuntimeException("无法确定表头位置"+sourceFile); + } + + int headRowNumber = transDateCell.getRow() + 1; + + // 两种格式的Excel,一种是用户名在表外,一种是用户名在表内 + // 具体如何区分? + // 用户名,可能是客户名,也可能是户名 + // 主要是账号 + Cell tempCell1 = AsposeUtil.getCell(excelFile, 0, "卡号"); + Cell tempCell2 = AsposeUtil.getCell(excelFile, 0, "账号"); + Cell accountCell = tempCell1 == null?tempCell2 : tempCell1; + if (accountCell != null) { + if (accountCell.getRow() == transDateCell.getRow()) { + // 账号在表内 + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + ReadSheet sheet = EasyExcel.readSheet() + .headRowNumber(headRowNumber) + .head(SPAOtherStatementEntity.class) + .registerConverter(new ExcelStringToJavaBigDecimalConverter()) + .registerReadListener(HelperUtil.getReadListener( + esSPAOtherStatementMapper, SPAOtherStatementEntity.class, false,sourceFile)) + .build(); + + reader.read(sheet); + + + } catch (Exception e) { + throw new ImportDataFailedException(e.getMessage(), sourceFile); + } + } + else { + // 账号在表外 + String cardNumber = null; + + Workbook wb = new Workbook(excelFile.getAbsolutePath()); + Worksheet ws = wb.getWorksheets().get(0); + // 如何获取账户 +// Cell cell = AsposeUtil.getCell(excelFile, 0, "卡号"); + if (accountCell == null) { + throw new RuntimeException(" 无法获取账户"+sourceFile); + } + + String value = accountCell.getStringValue(); + if (StringUtils.isNotBlank(value)) { + if (value.contains(":") || value.contains(":")) { // 英文冒号,和中文冒号 + value = value.replace(":", ":"); + + String[] arr = value.split(":"); + if (arr.length > 1 && !arr[1].isEmpty()) { + cardNumber = arr[1]; + } else { + // 说明账号在后面一个单元格内 + Range mr = accountCell.getMergedRange(); + if (mr != null) { + int offset = mr.getColumnCount(); + + int col = accountCell.getColumn() + offset; + + cardNumber = ws.getCells() + .get(accountCell.getRow(), col) + .getStringValue(); + } else { + cardNumber = ws.getCells() + .get(accountCell.getRow(), accountCell.getColumn() + 1) + .getStringValue(); + } + } + } else { + // 说明账号在后面一个单元格内 + Range mr = accountCell.getMergedRange(); + if (mr != null) { + int offset = mr.getColumnCount(); + + int col = accountCell.getColumn() + offset; + + cardNumber = + ws.getCells().get(accountCell.getRow(), col).getStringValue(); + } else { + cardNumber = ws.getCells() + .get(accountCell.getRow(), accountCell.getColumn() + 1) + .getStringValue(); + } + //20240422针对excel中卡号显示为null字符串的野鸡银行,取账号为卡号 + if("null".equals(cardNumber)){ + accountCell = AsposeUtil.getCell(excelFile, 0, "账号"); + cardNumber = ws.getCells() + .get(accountCell.getRow(), accountCell.getColumn() + 1) + .getStringValue(); + } + } + } + if (StrUtil.isEmpty(cardNumber) || "null".equals(cardNumber)) { + throw new RuntimeException("无法获取到卡号" +sourceFile); + } + Cell nameCell = AsposeUtil.getCell(excelFile, 0, "户名"); + if (nameCell == null) { + nameCell = AsposeUtil.getCell(excelFile, 0, "客户名"); + if (nameCell == null) { + throw new RuntimeException(" 无法获取户名" +sourceFile); + } + } + + String cardHolderName = null; + + String v = nameCell.getStringValue(); + if (StringUtils.isNotBlank(v)) { + if (v.contains(":") || v.contains(":")) { // 英文冒号,和中文冒号 + v = v.replace(":", ":"); + + String[] arr = v.split(":"); + if (arr.length > 1 && !arr[1].isEmpty()) { + cardHolderName = arr[1]; + } else { + // 说明账号在后面一个单元格内 + Range mr = nameCell.getMergedRange(); + if (mr != null) { + int offset = mr.getColumnCount(); + + int col = nameCell.getColumn() + offset; + + cardHolderName = ws.getCells() + .get(nameCell.getRow(), col) + .getStringValue(); + } else { + cardHolderName = ws.getCells() + .get(nameCell.getRow(), nameCell.getColumn() + 1) + .getStringValue(); + } + } + } else { + // 说明账号在后面一个单元格内 + Range mr = nameCell.getMergedRange(); + if (mr != null) { + int offset = mr.getColumnCount(); + + int col = nameCell.getColumn() + offset; + + cardHolderName = ws.getCells() + .get(nameCell.getRow(), col) + .getStringValue(); + } else { + cardHolderName = ws.getCells() + .get(nameCell.getRow(), nameCell.getColumn() + 1) + .getStringValue(); + } + } + } + + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + ReadSheet sheet = EasyExcel.readSheet() + .headRowNumber(headRowNumber) + .head(SPAStatementEntity.class) + .registerConverter(new ExcelStringToJavaBigDecimalConverter()) + .registerReadListener(getReadListener(cardHolderName, cardNumber,sourceFile)) + .build(); + + reader.read(sheet); + + + } catch (Exception e) { + throw new ImportDataFailedException(e.getMessage(), sourceFile); + } + } + } else { + // 无法获取账户信息 + throw new RuntimeException("无法获取账户信息"+ sourceFile); + } + } + + /** + * 读取客户信息 + */ + private void readPingAnBankOpeningAccountInfo(File excelFile) throws Exception { + + Cell cell = AsposeUtil.getCell(excelFile, 0, "开户日期"); + + // 根据客户基本信息,可以获取到地址等 + Cell headCell = AsposeUtil.getCell(excelFile, 0, "证件号码"); + if (headCell == null) { + headCell = AsposeUtil.getCell(excelFile, 0, "证件号"); + if (headCell == null) { + String sourceFile = HelperUtil.getSourceFileName(excelFile.getAbsolutePath(),BANK_NAME); + throw new TemplateNotFindException(sourceFile); + } + + } + + int headRowNumber = headCell.getRow() + 1; + + if (cell != null) { // 账户信息 + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + ReadSheet sheet = EasyExcel.readSheet() + .head(SPAAccountInfoEntity.class) + .headRowNumber(headRowNumber) + .registerReadListener(new SPAAccountInfoReadListener(accountInfoMapper)) + .build(); + reader.read(sheet); + } catch (Exception e) { + throw new ImportDataFailedException(e.getMessage(), excelFile.getAbsolutePath()); + } + } else { + // 客户基本信息 + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + ReadSheet sheet = EasyExcel.readSheet() + .head(SPACustomerInfoEntity.class) + .headRowNumber(headRowNumber) + .registerReadListener(new SPACustomerInfoReadListener(customerInfoMapper)) + .build(); + reader.read(sheet); + } catch (Exception e) { + throw new ImportDataFailedException(e.getMessage(), excelFile.getAbsolutePath()); + } + } + } + + private ReadListener getReadListener(String cardHolderName, String cardNumber,String sourceFile) { + return new ReadListener() { + final int BATCH_SIZE = Constants.BATCH_SIZE; + List docs = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + + @Override + public void invoke(SPAStatementEntity entity, AnalysisContext context) { + + + + // 4 交易日期 + String transDate = entity.getTransDate(); + try { + if (StrUtil.isNotEmpty(transDate)) { // 20211006 + String transTime = entity.getTransTime(); + if (StrUtil.isNotEmpty(transTime)) { // 14:15:07 + if (transTime.length() > Constants.DATE_TIME_FULL_FORMAT_LENGTH) { + // 20131001145718000 + transTime = transTime.substring(0, Constants.DATE_TIME_FULL_FORMAT_LENGTH); + } else { // 20081222 030411 + if (transTime.contains(":")) { + DateUtil.parse(transDate + " " + transTime, "yyyyMMdd HH:mm:ss"); + } else { + DateUtil.parse(transDate + transTime, "yyyyMMddHHmmss"); + } + } + } else { + DateUtil.parse(transDate, "yyyyMMdd"); + } + } + } catch (Exception e) { + log.error(sourceFile+"解析交易日期异常", e); + Integer currentRowNum = context.getCurrentRowNum() + 1; + throw new AnalyzeDataFailedException("第"+ currentRowNum +"行解析交易日期异常", e, sourceFile); + } + entity.setCardHolderName(cardHolderName); + entity.setCardNumber(cardNumber); + entity.setSourceFile(sourceFile); + String id = IdUtil.objectId(); + entity.setId(id); + + + docs.add(entity); + + if (docs.size() >= BATCH_SIZE) { + saveDataToMongoDB(); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!docs.isEmpty()) { + saveDataToMongoDB(); + } + } + + private void saveDataToMongoDB() { + if (!docs.isEmpty()) { + statementMapper.insertBatch(docs); + + log.info("一共保存" + docs.size() + "条数据到MongoDB!"); + + docs = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } + } + }; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/PSBCDataAnalysisHelper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/PSBCDataAnalysisHelper.java new file mode 100644 index 0000000..be8c51c --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/PSBCDataAnalysisHelper.java @@ -0,0 +1,763 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.converters.ConverterKeyBuild; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.read.metadata.holder.ReadHolder; +import com.alibaba.excel.util.ListUtils; + +import com.aspose.cells.Cell; +import com.aspose.cells.Cells; +import com.aspose.cells.Workbook; +import com.aspose.cells.Worksheet; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; + +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.exception.dc.AnalyzeDataFailedException; +import com.inscloudtech.common.exception.dc.ImportDataFailedException; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.common.utils.file.FileUtils; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.mapper.es.EsPSBCOpeningAccountInfoMapper; +import com.inscloudtech.datacenter.mapper.es.EsPSBCStatementMapper; +import com.inscloudtech.datacenter.service.ImportResultService; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; + +import com.inscloudtech.bankStatementAnalysis.domain.entity.PSBCETStatementEntity; +import com.inscloudtech.bankStatementAnalysis.domain.entity.PSBCOpeningAccountInfoEntity; +import com.inscloudtech.bankStatementAnalysis.domain.entity.PSBCStatementEntity; + +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.lang.reflect.Field; +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + + + +/** + * 中国邮政储蓄银行数据分析 + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class PSBCDataAnalysisHelper { + + + private final ImportResultService importResultService; + private final EsPSBCOpeningAccountInfoMapper accountInfoMapper; + private final EsPSBCStatementMapper statementMapper; + private final static String BANK_NAME = "中国邮政储蓄银行"; + + public void analyzeData(String caseId) { + analyzeOAI(caseId); + // 流水分析 + analyzeBS(caseId); + } + + private void analyzeOAI(String caseId) { + + List oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(accountInfoMapper, PSBCOpeningAccountInfoEntity.class); + Set uniqueKeySet = new HashSet(); + for (PSBCOpeningAccountInfoEntity entity : entityList) { + + OpeningAccountInfo oai = getOpeningAccountInfo(BANK_NAME, entity); + + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + oaiList.add(oai); + if (oaiList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + if (!oaiList.isEmpty()) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + } + } + + private static OpeningAccountInfo getOpeningAccountInfo(String bankName, PSBCOpeningAccountInfoEntity entity) { + OpeningAccountInfo oai = new OpeningAccountInfo(); + oai.setName(entity.getCardHolderName()); + oai.setBankName(BANK_NAME); + oai.setAccountNumber(entity.getCardNumber()); + oai.setIdType(entity.getIdType()); + oai.setIdNo(entity.getIdCardNo()); + oai.setPhone(entity.getPhone()); + oai.setAddress(entity.getAddress()); + oai.setOpeningAccountDate(entity.getOpeningAccountDate()); + oai.setClosingDate(entity.getClosingDate()); + oai.setStatus(entity.getStatus()); + oai.setFreezeInfo(entity.getFreezeInfo()); + oai.setAccountOpeningInstitution(entity.getAccountOpeningInstitution()); + return oai; + } + + private void analyzeBS(String caseId) { + + List bsList = new ArrayList<>(); + + List entityList = HelperUtil.getEntityList(statementMapper, PSBCStatementEntity.class); + + // 处理交易金额 + entityList = handleTransactionAmount(entityList); + + List accountInfoList = + HelperUtil.getEntityList(accountInfoMapper, PSBCOpeningAccountInfoEntity.class); + + Map map = new HashMap<>(); + Map groupByCard = new HashMap<>(); + for (PSBCOpeningAccountInfoEntity entity : accountInfoList) { + map.put(entity.getCardHolderName(), entity); + groupByCard.put(entity.getCardNumber(), entity); + } + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + + for (PSBCStatementEntity entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + BankStatement bs = new BankStatement(); + String cardHolderName = entity.getCardHolderName(); + String cardNumber = entity.getCardNumber(); + if (StrUtil.isEmpty(cardHolderName) && StrUtil.isNotEmpty(cardNumber)) { + if (groupByCard.containsKey(cardNumber)) { + PSBCOpeningAccountInfoEntity info = groupByCard.getOrDefault(cardNumber, null); + if (info != null) { + cardHolderName = info.getCardHolderName(); + } + } + } + if (StrUtil.isEmpty(cardHolderName)) { + entity.toString(); + } + + bs.setBankName(BANK_NAME); + bs.setCardHolderName(cardHolderName); + bs.setCardNumber(cardNumber); + + PSBCOpeningAccountInfoEntity info = map.getOrDefault(cardHolderName, null); + if (info != null) { + bs.setIdCardNo(info.getIdCardNo()); + bs.setPhone(info.getPhone()); + } + + bs.setCounterpartyName(entity.getCounterpartyName()); + + + + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + bs.setCounterpartyBankName(entity.getCounterpartyBankName()); + bs.setTransChannel(entity.getTransChannel()); + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + // 交易时间 + String transactionTime = entity.getTransactionTime(); + try { + if(transactionTime.length() < 11){ + transactionTime += " 00:00:00"; + } + String format = "yyyy/MM/dd HH:mm:ss"; + if(!transactionTime.contains("/")){ + format = "yyyyMMdd HH:mm:ss"; + if(!transactionTime.contains(":")){ + format = "yyyyMMdd HHmmss"; + } + } + bs.setTransactionTime(DateUtil.parse(transactionTime, format)); + } catch (Exception e) { + log.error("交易时间解析错误:{}", transactionTime); + throw new AnalyzeDataFailedException( + StrUtil.format("交易时间解析错误:{}", transactionTime), e, sourceFile); + } + + BigDecimal balance = BigDecimal.valueOf(Double.parseDouble(entity.getBalance())); + bs.setBalance(balance); + + bs.setSummary(entity.getSummary()); + + BigDecimal transactionAmount = BigDecimal.valueOf(Double.parseDouble(entity.getTransactionAmount())); + + if (balance.compareTo(transactionAmount) < 0) { + bs.setTransactionAmount(BigDecimal.ZERO.subtract(transactionAmount)); + } else { + bs.setTransactionAmount(transactionAmount); + } + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entity.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + if (bsList.size() >= Constants.BATCH_SIZE) { + + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e, sourceFile); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + // 保存数据库 + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + /** + * 处理交易金额 + */ + private List handleTransactionAmount(List allList) { + Map> groupByCard = allList.stream().filter(item ->StrUtil.isNotEmpty(item.getCardNumber())).collect(Collectors.groupingBy(PSBCStatementEntity::getCardNumber)); + List result = new ArrayList<>(); + for (String card : groupByCard.keySet()) { + List bsList = groupByCard.get(card); + bsList.sort((o1, o2) -> { + // 2023/06/20 + String transTimeStr1 = o1.getTransactionTime(); + String transTimeStr2 = o2.getTransactionTime(); + String format = "yyyy/MM/dd"; + if(!transTimeStr1.contains("/")){ + format = "yyyyMMdd"; + } + DateTime transTime1 = DateUtil.parse(transTimeStr1, format); + DateTime transTime2 = DateUtil.parse(transTimeStr2, format); + + return DateUtil.compare(transTime1, transTime2); + }); + + List rstList = new ArrayList<>(); + PSBCStatementEntity prev = null; + for (int idx = 0; idx < bsList.size(); idx++) { + if (prev == null) { + prev = bsList.get(idx); + } else { + PSBCStatementEntity curr = bsList.get(idx); + String currBalanceStr = curr.getBalance(); + String prevBalanceStr = prev.getBalance(); + + BigDecimal currBalance = NumberUtil.toBigDecimal(currBalanceStr); + BigDecimal prevBalance = NumberUtil.toBigDecimal(prevBalanceStr); + + if (currBalance.compareTo(prevBalance) < 0) { + String amountStr = curr.getTransactionAmount(); + BigDecimal amount = NumberUtil.toBigDecimal(amountStr); + curr.setTransactionAmount(amount.negate() + ""); + } + + rstList.add(prev); + + prev = curr; + } + } + + if (prev != null) { + rstList.add(prev); + } + result.addAll(rstList); + } + + return result; + } + + public void importData(File file,String caseId) throws Exception { + + if (!file.exists()) { + return; + } + + List fileList = FileUtil.loopFiles(file); + // 筛选Excel文件,包括xls和xlsx,csv文件 + fileList = fileList.stream() + .filter(f -> { + String extName = FileUtil.extName(f); + return extName != null + && (extName.contains("xls") || extName.contains("xlsx") || extName.contains("csv") || extName.contains("et")); + }) + .collect(Collectors.toList()); + + for (File f : fileList) { + try { + Workbook wb = new Workbook(f.getAbsolutePath()); + for (int sheetNo = 0; sheetNo < wb.getWorksheets().getCount(); sheetNo++) { + try { + Worksheet sheet = wb.getWorksheets().get(sheetNo); + Cells cells = sheet.getCells(); + + Cell cell = AsposeUtil.getCell(cells, "交易日期"); + if (cell != null && Objects.equals(cell.getStringValue(), "交易日期")) { + // 流水文件 + readPSBCStatement(f, cells, sheetNo); + } else { + cell = AsposeUtil.getCell(cells, "交易时间"); + Cell khCell = AsposeUtil.getCell(cells, "客户账号"); + if (cell != null && Objects.equals(cell.getStringValue(), "交易时间")) { + readPSBCStatement(f, cells, sheetNo); + } else if (khCell != null) { + // 这是开户文件 + readPSBCOAIV2(f); + } else { + readPSBCOAIV3(cells); + } +// throw new TemplateNotFindException(sourceFile+BankStatementConstants.NAME_WITH_SHEET_NAME+worksheet.getName()); + + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } + + private void readPSBCOAIV3(Cells cells) throws IllegalAccessException { + Class clazz = PSBCOpeningAccountInfoEntity.class; + Field[] fields = ReflectUtil.getFields(clazz); + + Map valueFieldMap = getAnnotationValueFieldMap(fields); + + PSBCOpeningAccountInfoEntity entity = new PSBCOpeningAccountInfoEntity(); + + for (Map.Entry entry : valueFieldMap.entrySet()) { + String annoValue = entry.getKey(); + Field field = entry.getValue(); + + Cell cell = AsposeUtil.getCell(cells, annoValue); + if (cell == null) { + continue; + } + + int row = cell.getRow(); + int col = cell.getColumn(); + String value = cells.get(row, col + 1).getStringValue(); + + field.set(entity, value); + } + + String cardNumber = entity.getCardNumber(); + if (StrUtil.isNotEmpty(cardNumber)) { + cardNumber = cardNumber.replaceAll(" ", ""); + entity.setCardNumber(cardNumber); + } + + entity.setId(IdUtil.objectId()); + + accountInfoMapper.insert(entity); + } + + private void readPSBCOAIV2( File file) throws Exception { + try (ExcelReader reader = EasyExcel.read(file).build()) { + ReadSheet sheet = EasyExcel.readSheet() + .head(PSBCOpeningAccountInfoEntity.class) + .registerReadListener(new ReadListener() { + private static final int BATCH_SIZE = Constants.BATCH_SIZE; + private List cacheList = + ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + + @Override + public void invoke(PSBCOpeningAccountInfoEntity entry, AnalysisContext context) { + + + String id = IdUtil.objectId(); + entry.setId(id); + + + cacheList.add(entry); + + if (cacheList.size() >= BATCH_SIZE) { + saveData(); + cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + // 保存不够一百条数据的批次 + if (!cacheList.isEmpty()) { + saveData(); + } + + log.info("读取邮政储蓄银行流水结束"); + } + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + + log.error("解析出错: {}", exception.getMessage()); + + ReadHolder readHolder = context.currentReadHolder(); + Map> map = readHolder.converterMap(); + + + } + + private void saveData() { + accountInfoMapper.insertBatch(cacheList); + cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } + }) + .build(); + reader.read(sheet); + } + } + + private void readPSBCOAI(File excelFile) throws Exception { + // 获取字段和注解 + Class clazz = PSBCOpeningAccountInfoEntity.class; + Field[] fields = ReflectUtil.getFields(clazz); + + Map map = getAnnotationValueFieldMap(fields); + + Workbook wb = new Workbook(excelFile.getAbsolutePath()); + Cells cells = wb.getWorksheets().get(0).getCells(); + + int maxRow = cells.getMaxRow(); + int maxColumn = cells.getMaxColumn(); + + PSBCOpeningAccountInfoEntity entity = new PSBCOpeningAccountInfoEntity(); + + for (int col = 0; col < maxColumn; col += 2) { + for (int row = 1; row < maxRow - 1; row++) { + Cell cell = cells.get(row, col); + String propName = cell.getStringValue().trim(); + // 避免/影响解析 + if (propName.contains("/")) { + propName = propName.replaceAll("/", ""); + } + + if (propName.contains(":")) { + propName = propName.replaceAll(":", ""); + } + + if (map.containsKey(propName)) { + Field f = map.get(propName); + f.set(entity, cells.get(row, col + 1).getStringValue()); + } + } + } + // 中间会有空格,处理一下 + String cardNumber = entity.getCardNumber(); + if (StrUtil.isNotEmpty(cardNumber)) { + cardNumber = cardNumber.replaceAll(" ", ""); + entity.setCardNumber(cardNumber); + } + + entity.setId(IdUtil.objectId()); + + accountInfoMapper.insert(entity); + } + + private static Map getAnnotationValueFieldMap(Field[] fields) { + + Map map = new HashMap<>(); + + for (Field field : fields) { + field.setAccessible(true); + + ExcelProperty prop = field.getAnnotation(ExcelProperty.class); + if (prop == null) { + continue; + } + + String[] valueArr = prop.value(); + if (valueArr == null) { + continue; + } + + for (String value : valueArr) { + map.put(value, field); + } + } + + return map; + } + /** + * 读取开户信息 + */ + private void readETData(File excelFile) { + String excelFileName = excelFile.getAbsolutePath(); + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + ReadSheet sheet = EasyExcel.readSheet() + .head(PSBCETStatementEntity.class) + .registerReadListener(new ReadListener() { + private static final int BATCH_SIZE = Constants.BATCH_SIZE; + private List cacheList = + ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + + @Override + public void invoke(PSBCETStatementEntity entry, AnalysisContext context) { + + String balance = entry.getBalance(); + if (StringUtils.isEmpty(balance)) { // 过滤没有余额的数据 + return; + } + + String id = IdUtil.objectId(); + entry.setId(id); + + if (balance.contains(",")) { + balance = balance.replaceAll(",", ""); + entry.setBalance(balance); + } + + String transactionAmount = entry.getTransactionAmount(); + if (StrUtil.isNotEmpty(transactionAmount) && transactionAmount.contains(",")) { + transactionAmount = transactionAmount.replaceAll(",", ""); + entry.setTransactionAmount(transactionAmount); + } + String transactionTime = entry.getTDate() + " " + entry.getTTime(); + entry.setTransactionTime(transactionTime); + PSBCStatementEntity bs = new PSBCStatementEntity(); + BeanUtil.copyProperties(entry,bs); + String sourceFile = excelFileName.split("中国邮政储蓄银行")[1]; + bs.setSourceFile(sourceFile); + cacheList.add(bs); + + if (cacheList.size() >= BATCH_SIZE) { + saveData(); + cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + // 保存不够一百条数据的批次 + if (!cacheList.isEmpty()) { + saveData(); + } + + log.info("读取邮政储蓄银行流水结束"); + } + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + + log.error("解析出错: {}", exception.getMessage()); + + ReadHolder readHolder = context.currentReadHolder(); + Map> map = readHolder.converterMap(); + + + } + + private void saveData() { + + statementMapper.insertBatch(cacheList); + + log.info("{}条数据,开始存储数据库!", cacheList.size()); + + + cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } + }) + .build(); + reader.read(sheet); + } + } + private void readPSBCStatement(File excelFile, Cells cells, int sheetNo) throws Exception { + + Cell cell = AsposeUtil.getCell(cells, "交易日期"); + if (cell == null || !Objects.equals(cell.getStringValue().trim(), "交易日期")) { + cell = AsposeUtil.getCell(cells, "交易时间"); + if (cell == null || !Objects.equals(cell.getStringValue().trim(), "交易时间")) { + throw new ImportDataFailedException("无法读取表头信息,格式不正确.", excelFile.getAbsolutePath()); + } + } + + Cell rstCell = AsposeUtil.getCell(excelFile, 0, "客户账号"); + if (rstCell != null) {//et模板 + readETData(excelFile); + }else { + rstCell = AsposeUtil.getCell(excelFile, 0, "账号卡号"); + if (rstCell == null) { + rstCell = AsposeUtil.getCell(excelFile, 0, "账号/卡号"); + if (rstCell == null) { + throw new ImportDataFailedException("无法读取卡号信息,格式不正确.", excelFile.getAbsolutePath()); + } + } + + int headRowNumber = cell.getRow() + 1; + + String cardNumber = null; + String cardHolderName = null; + + int rstRow = rstCell.getRow(); + int rstCol = rstCell.getColumn(); + + Cell cardNumberCell = cells.get(rstRow, rstCol + 1); + cardNumber = cardNumberCell.getStringValue().trim(); + + if (StringUtils.isEmpty(cardNumber)) { + String str = rstCell.getStringValue(); // 账号/卡号 :6221807300008391067 户 名:徐成辉 + // 截取账号和户名 + if (str != null) { + String[] strArr = str.split(":"); // 账号/卡号 6221807300008391067 户 名 徐成辉 + if (strArr.length == 3) { + cardHolderName = strArr[2]; + + // 截取卡号 + // 6221807300008391067 户 名 + if (strArr[1] != null) { + String[] strArr2 = strArr[1].split(" "); // 6221807300008391067 + if (strArr2.length == 3) { + cardNumber = strArr2[0]; + } + } + } + } + } + + Cell namePrevCell = AsposeUtil.getCell(excelFile, 0, "户名"); + if (namePrevCell != null && StringUtils.isEmpty(cardHolderName)) { + int nameRow = namePrevCell.getRow(); + int namePrevCol = namePrevCell.getColumn(); + + Cell nameCell = cells.get(nameRow, namePrevCol + 1); + cardHolderName = nameCell.getStringValue().trim(); + } + + try (ExcelReader reader = EasyExcel.read(excelFile).build()) { + String finalCardNumber = cardNumber; + String finalCardHolderName = cardHolderName; + + Class clazz = PSBCStatementEntity.class; + String excelFileName = excelFile.getAbsolutePath(); + String sourceFile = excelFileName.split("中国邮政储蓄银行")[1]; + ReadSheet sheet = EasyExcel.readSheet() + .headRowNumber(headRowNumber) + .head(clazz) + .registerReadListener(new ReadListener() { + private static final int BATCH_SIZE = Constants.BATCH_SIZE; + private List cacheList = + ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + + @Override + public void invoke(PSBCStatementEntity entry, AnalysisContext context) { + + String balance = entry.getBalance(); + if (StringUtils.isEmpty(balance)) { // 过滤没有余额的数据 + return; + } + + String id = IdUtil.objectId(); + entry.setId(id); + entry.setCardNumber(finalCardNumber); + entry.setCardHolderName(finalCardHolderName); + entry.setSourceFile(sourceFile); + + if (balance.contains(",")) { + balance = balance.replaceAll(",", ""); + entry.setBalance(balance); + } + + String transactionAmount = entry.getTransactionAmount(); + if (StrUtil.isNotEmpty(transactionAmount) && transactionAmount.contains(",")) { + transactionAmount = transactionAmount.replaceAll(",", ""); + entry.setTransactionAmount(transactionAmount); + } + + cacheList.add(entry); + + if (cacheList.size() >= BATCH_SIZE) { + saveData(); + cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + // 保存不够一百条数据的批次 + if (!cacheList.isEmpty()) { + saveData(); + } + + log.info("读取邮政储蓄银行流水结束"); + } + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + + log.error("解析出错: {}", exception.getMessage()); + + ReadHolder readHolder = context.currentReadHolder(); + Map> map = readHolder.converterMap(); + + + } + + private void saveData() { + + statementMapper.insertBatch(cacheList); + + log.info("{}条数据,开始存储数据库!", cacheList.size()); + + + cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } + }) + .build(); + reader.read(sheet); + + + } catch (Exception e) { + log.error("解析出错: {}", e.getMessage()); + throw new ImportDataFailedException(e.getMessage(), excelFile.getAbsolutePath()); + } + } + + } + + +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/QJCCBDataAnalysisHelper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/QJCCBDataAnalysisHelper.java new file mode 100644 index 0000000..c5b0571 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/QJCCBDataAnalysisHelper.java @@ -0,0 +1,408 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.converters.ConverterKeyBuild; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.read.metadata.holder.ReadHolder; +import com.alibaba.excel.util.ListUtils; + +import com.aspose.cells.Cell; +import com.aspose.cells.Cells; +import com.aspose.cells.Workbook; +import com.aspose.cells.Worksheet; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; + +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.bankStatementAnalysis.service.ImportService; +import com.inscloudtech.common.constant.BankStatementConstants; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.exception.dc.AnalyzeDataFailedException; +import com.inscloudtech.common.exception.dc.ImportDataFailedException; +import com.inscloudtech.common.exception.dc.TemplateNotFindException; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.common.utils.file.FileUtils; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.mapper.es.EsQJCCBStatementMapper; +import com.inscloudtech.datacenter.service.ImportResultService; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; + +import com.inscloudtech.bankStatementAnalysis.domain.entity.QJCCBStatementEntity; + +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; + +import lombok.Data; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 曲靖商业银行数据分析 + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class QJCCBDataAnalysisHelper { + + private final ImportService importService; + private final ImportResultService importResultService; + private final EsQJCCBStatementMapper statementMapper; + private final static String BANK_NAME = "曲靖市商业银行"; + + + public void analyzeData(String caseId) { + + List bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + int batchSize = Constants.BATCH_SIZE; + + List entityList = HelperUtil.getEntityList(statementMapper, QJCCBStatementEntity.class); + + Map> oaiMap = importService.getOAIMap(caseId, BANK_NAME); + + // 查询es 并放入uniqueKey + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + for (QJCCBStatementEntity entity : entityList) { + String sourceFile = entity.getSourceFile(); + try { + String cardHolderName = entity.getCardHolderName(); + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + bs.setCardHolderName(cardHolderName); + + String balance = entity.getBalance(); + if (StringUtils.isNotBlank(balance)) { + bs.setBalance(NumberUtil.toBigDecimal(entity.getBalance())); + } else if (StringUtils.isNotBlank(entity.getBalance1()) && !HelperUtil.isContainsChinese(entity.getBalance1())) { + bs.setBalance(NumberUtil.toBigDecimal(entity.getBalance1())); + }else { + continue; + } + + if (oaiMap.containsKey(cardHolderName)) { + List infoList = oaiMap.get(cardHolderName); + for (OpeningAccountInfo info : infoList) { + if(StrUtil.isNotEmpty(info.getIdNo())){ + bs.setIdCardNo(info.getIdNo()); + break; + } + } + } + + bs.setCardNumber(entity.getCardNumber()); + bs.setCounterpartyName(entity.getCounterpartyName()); + bs.setCounterpartyAccount(entity.getCounterpartyAccount()); + bs.setCounterpartyBankName(entity.getCounterpartyBankName()); + + String summary = entity.getSummary(); + if (StrUtil.isNotEmpty(summary)) { + bs.setSummary(summary); + } else { + bs.setSummary(entity.getSummary1()); + } + + bs.setTransRemark(entity.getTransRemark()); + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + bs.setTransactionInstitutions(entity.getTransactionInstitutions()); + // 交易金额 + BigDecimal amount = NumberUtil.toBigDecimal(entity.getTransactionAmount()); + String loanFlag = entity.getLoanFlag(); + if (StrUtil.isNotEmpty(loanFlag)) { + if (loanFlag.contains("借")) { + bs.setTransactionAmount(BigDecimal.ZERO.subtract(amount)); + } else { + bs.setTransactionAmount(amount); + } + }else { + bs.setTransactionAmount(amount); + } + // 交易时间 + String transDate = entity.getTransDate(); + if (StrUtil.isNotEmpty(transDate)) { + String transTime = entity.getTransTime(); + try { + if (StrUtil.isNotEmpty(transTime)) { + bs.setTransactionTime(DateUtil.parse(transDate + " " + transTime, "yyyyMMdd HHmmss")); + } else { + bs.setTransactionTime(DateUtil.parse(transDate, "yyyyMMdd")); + } + } catch (Exception e) { + log.error("transDate: {}, transTime: {}", transDate, transTime); + + + + throw new AnalyzeDataFailedException( + StrUtil.format("交易日期: {}, 交易时间: {}", transDate, transTime), e, sourceFile); + } + } + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + + if (bsList.size() >= batchSize) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + bsList = ListUtils.newArrayListWithExpectedSize(batchSize); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e, sourceFile); + } + } + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + // 保存数据库 + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest,caseId); + } + + } + + public void importData(File dir,String caseId) throws Exception { + + List fileList = FileUtil.loopFiles(dir); + + List excelFileList = fileList.stream() + .filter(file -> { + String extName = FileUtil.extName(file); + return extName.equalsIgnoreCase("xls") + || extName.equalsIgnoreCase("xlsx") + || extName.equalsIgnoreCase("csv"); + }) + .collect(Collectors.toList()); + +// List pdfFileList = fileList.stream() +// .filter(file -> FileUtil.extName(file).equalsIgnoreCase("pdf")) +// .collect(Collectors.toList()); +// Map> groupByPath = excelFileList.stream().collect(Collectors.groupingBy(File::getAbsolutePath)); +// for (File file : pdfFileList) { +// String excelFilename = AsposeUtil.pdf2ExcelV6(file.getAbsolutePath()); +// if(groupByPath.containsKey(excelFilename)){ +// continue; +// } +// excelFileList.add(new File(excelFilename)); +// } + + for (File excelFile : excelFileList) { + try { + String absolutePath = excelFile.getAbsolutePath(); + Workbook wb = new Workbook(absolutePath); + String sourceFile = HelperUtil.getSourceFileName(absolutePath, BANK_NAME); + for (int sheetNo = 0; sheetNo < wb.getWorksheets().getCount(); sheetNo++) { + try { + Worksheet worksheet = wb.getWorksheets().get(sheetNo); + String withName = sourceFile + BankStatementConstants.NAME_WITH_SHEET_NAME + worksheet.getName(); + Cells cells = worksheet.getCells(); + Cell cell = AsposeUtil.getCell(cells, "开户日期"); + Cell c = AsposeUtil.getCell(cells, "交易日期"); + if (cell != null) { + // 这是开户信息 + int headRowNumber = cell.getRow() + 1; + importService.readOAIData(absolutePath, headRowNumber, sheetNo, caseId, BANK_NAME, withName); + } else if (c != null) { + // 流水信息 + readQJCCBStatement(absolutePath, sheetNo, withName); + } else { + throw new TemplateNotFindException(withName); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } + + private void readQJCCBStatement(String excelFileName, int sheetNo, String sourceFile) { + // 需要手动读取一些内容 + // 如果Excel文件是由PDF转化而来,那么需要手动读取 + QJCCBAccountInfo accountInfo = getAccountInfo(excelFileName); + + int rowNumber = AsposeUtil.getRowNumber(new File(excelFileName), 0, "交易日期"); + + try (ExcelReader reader = EasyExcel.read(excelFileName).build()) { + Class clazz = QJCCBStatementEntity.class; + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(rowNumber + 1) + .head(clazz) + .registerReadListener(new ReadListener() { + private List cacheList = + ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + @Override + public void invoke(QJCCBStatementEntity entry, AnalysisContext context) { + + String balance = entry.getBalance(); + if (StrUtil.isNotEmpty(balance) && balance.contains(",")) { + balance = balance.replaceAll(",", ""); + entry.setBalance(balance); + } + + String transactionAmount = entry.getTransactionAmount(); + if (StrUtil.isNotEmpty(transactionAmount) && transactionAmount.contains(",")) { + transactionAmount = transactionAmount.replaceAll(",", ""); + entry.setTransactionAmount(transactionAmount); + } + + if (StringUtils.isEmpty(entry.getCardHolderName())) { + if (accountInfo == null) { + return; + } + + entry.setCardNumber(accountInfo.getCardNumber()); + entry.setCardHolderName(accountInfo.cardHolderName); + } + + String counterpartyInfo = entry.getCounterpartyInfo(); + if (StrUtil.isNotEmpty(counterpartyInfo)) { + String[] infoArr = counterpartyInfo.trim().split(" "); + if (infoArr.length == 2) { + entry.setCounterpartyAccount(infoArr[0]); + entry.setCounterpartyName(infoArr[1]); + } + } + + String aboutTime = entry.getAboutTime(); + if (StrUtil.isNotEmpty(aboutTime)) { + String[] arr = aboutTime.split(" "); + if (arr.length == 3) { + String transactionTime = arr[0]; + entry.setTransDate(transactionTime); + entry.setAboutTime(null); + // 借贷标志 + entry.setLoanFlag(arr[2]); + } + } + + String id = IdUtil.objectId(); + entry.setId(id); + entry.setSourceFile(sourceFile); + cacheList.add(entry); + + + if (cacheList.size() >= Constants.BATCH_SIZE) { + saveData(); + cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + // 保存不够一百条数据的批次 + if (!cacheList.isEmpty()) { + saveData(); + } + + log.info("读取曲靖商业银行流水结束"); + } + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + + log.error("解析出错: {}", exception.getMessage()); + + ReadHolder readHolder = context.currentReadHolder(); + Map> map = readHolder.converterMap(); + + + } + + private void saveData() { + statementMapper.insertBatch(cacheList); + + log.info("{}条数据,开始存储数据库!", cacheList.size()); + + } + }) + .build(); + reader.read(sheet); + + + } catch (Exception e) { + log.error("读取文件出错: {}", e.getMessage()); + throw new ImportDataFailedException(e.getMessage(), excelFileName); + } + } + + private QJCCBAccountInfo getAccountInfo(String excelFileName) { + // A3账户 + // C3名 + // 账号: 6227773301755860 + // 账户名称:高伟 + String cardHolderName = null; + String cardNumber = null; + + try { + Cell cell = AsposeUtil.getCell(new File(excelFileName), 0, "账户名称"); + if (cell == null) { + return null; + } + + // 账户名称:高伟 + String nameStr = cell.getStringValue(); + if (nameStr.contains(":")) { + String[] nameArr = nameStr.split(":"); + if (nameArr.length == 2) { + cardHolderName = nameArr[1].trim(); + } + } + + cell = AsposeUtil.getCell(new File(excelFileName), 0, "账号"); + if (cell == null) { + return null; + } + + String accountStr = cell.getStringValue(); + if (StrUtil.isNotEmpty(accountStr) && accountStr.contains(":")) { + String[] accountArr = accountStr.split(":"); + if (accountArr.length == 2) { + cardNumber = accountArr[1].trim(); + } + } + + QJCCBAccountInfo rst = new QJCCBAccountInfo(); + rst.setCardNumber(cardNumber); + rst.setCardHolderName(cardHolderName); + + return rst; + } catch (Exception e) { + log.error("getAccountInfo: {}", e.getMessage(), e); + return null; + } + } + + @Data + private static class QJCCBAccountInfo { + private String cardHolderName; + private String cardNumber; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/RCCDataAnalysisHelper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/RCCDataAnalysisHelper.java new file mode 100644 index 0000000..93502b9 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/RCCDataAnalysisHelper.java @@ -0,0 +1,341 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.exception.ExcelAnalysisStopException; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.util.ListUtils; +import com.alibaba.excel.util.StringUtils; +import com.aspose.cells.Cell; +import com.aspose.cells.Cells; +import com.aspose.cells.Workbook; +import com.aspose.cells.Worksheet; + +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.common.constant.BankStatementConstants; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.exception.dc.AnalyzeDataFailedException; +import com.inscloudtech.common.exception.dc.ImportDataFailedException; +import com.inscloudtech.common.exception.dc.TemplateNotFindException; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.mapper.es.EsRCCBankStatementMapper; +import com.inscloudtech.datacenter.mapper.es.EsRCCOpeningAccountInfoMapper; +import com.inscloudtech.datacenter.service.ImportResultService; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; +import com.inscloudtech.bankStatementAnalysis.domain.entity.RCCBankStatementEntry; +import com.inscloudtech.bankStatementAnalysis.domain.entity.RCCOpeningAccountInfoEntry; + +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.math.BigDecimal; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + + + +/** + * 农村信用社数据分析 + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class RCCDataAnalysisHelper { + + + private final ImportResultService importResultService; + private final EsRCCOpeningAccountInfoMapper accountInfoMapper; + private final EsRCCBankStatementMapper statementMapper; + private final static String BANK_NAME = "农村信用社"; + + + public void importData(File file,String caseId) { + List fileList = FileUtil.loopFiles(file); + if (fileList == null || fileList.isEmpty()) { + return; + } + List excelFile = HelperUtil.getExcelFile(fileList); + for (File f : excelFile) { + String excelName = f.getAbsolutePath(); + String sourceFile = HelperUtil.getSourceFileName(excelName,BANK_NAME); + try { + Workbook wb = new Workbook(excelName); + int count = wb.getWorksheets().getCount(); + + for (int sheetNo = 0; sheetNo < count; sheetNo++) { + try { + Worksheet worksheet = wb.getWorksheets().get(sheetNo); + Cells cells = worksheet.getCells(); + Cell cell = AsposeUtil.getCell(cells, "开户日期"); + if (cell != null) { + // 开户数据 + readRCCOAI(excelName, sheetNo); + } else { + cell = AsposeUtil.getCell(cells, "交易日期"); + Cell cell404 = AsposeUtil.getCell(cells, "未查询到清单"); + if (cell != null) { + // 流水数据 + readRCCBS(excelName, sheetNo); + } else if (cell404 != null) { + continue; + } else { + throw new TemplateNotFindException(sourceFile + BankStatementConstants.NAME_WITH_SHEET_NAME + worksheet.getName()); + } + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } + + public void analyzeData(String caseId) { + analyzeOAI(caseId); + analyzeBS(caseId); + } + + private void analyzeOAI(String caseId) { + + List oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + + List entityList = + HelperUtil.getEntityList(accountInfoMapper, RCCOpeningAccountInfoEntry.class); + Set uniqueKeySet = new HashSet(); + for (RCCOpeningAccountInfoEntry entry : entityList) { + + if (StringUtils.isEmpty(entry.getCardNumber())) { + continue; + } + + OpeningAccountInfo oai = getOpeningAccountInfo(BANK_NAME, entry); + + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + oaiList.add(oai); + if (oaiList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + oaiList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + if (!oaiList.isEmpty()) { + List dest = HelperUtil.getDest(oaiList); + HelperUtil.batchSaveOAI2Es(dest, caseId); + } + } + + private static OpeningAccountInfo getOpeningAccountInfo(String bankName, RCCOpeningAccountInfoEntry entry) { + OpeningAccountInfo oai = new OpeningAccountInfo(); + oai.setName(entry.getCardHolderName()); + oai.setBankName(BANK_NAME); + oai.setNewAccountNumber(entry.getNewAccountNumber()); + oai.setAccountNumber(entry.getCardNumber()); + oai.setIdType(entry.getIdType()); + oai.setIdNo(entry.getIdCardNo()); + oai.setPhone(entry.getPhone()); + oai.setAddress(entry.getAddress()); + oai.setOpeningAccountDate(entry.getOpeningAccountDate()); + oai.setClosingDate(entry.getCloseAccountDate()); + oai.setStatus(entry.getStatus()); + oai.setType(entry.getType()); + oai.setFreezeInfo(entry.getFreezeInfo()); + oai.setAccountOpeningInstitution(entry.getAccountOpeningInstitution()); + return oai; + } + + private void analyzeBS(String caseId) { + + List bsList = new ArrayList<>(); + + List entityList = HelperUtil.getEntityList(statementMapper, RCCBankStatementEntry.class); + List accList = + HelperUtil.getEntityList(accountInfoMapper, RCCOpeningAccountInfoEntry.class); + Map rccNameAccMap = new HashMap<>(); + + for (RCCOpeningAccountInfoEntry entry : accList) { + rccNameAccMap.put(entry.getCardHolderName(), entry); + } + Map> groupByCardNumber = accList.stream().filter(item ->StrUtil.isNotEmpty(item.getCardNumber())) + .collect(Collectors.groupingBy(RCCOpeningAccountInfoEntry::getCardNumber)); + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + + for (RCCBankStatementEntry entry : entityList) { + String sourceFile = entry.getSourceFile(); + try { + BankStatement bs = new BankStatement(); + bs.setBankName(BANK_NAME); + String name = entry.getCardHolderName(); + + bs.setCardNumber(entry.getCardNumber()); + + if (StrUtil.isNotEmpty(name)) { + RCCOpeningAccountInfoEntry acc = rccNameAccMap.getOrDefault(name, null); + if (acc != null) { + bs.setIdCardNo(acc.getIdCardNo()); + bs.setPhone(acc.getPhone()); + } + }else { + if(groupByCardNumber.containsKey(bs.getCardNumber())){ + List oaiList = groupByCardNumber.get(bs.getCardNumber()); + RCCOpeningAccountInfoEntry acc = oaiList.get(0); + name = acc.getCardHolderName(); + bs.setIdCardNo(acc.getIdCardNo()); + bs.setPhone(acc.getPhone()); + } + } + bs.setCardHolderName(name); + String counterpartName = entry.getCounterpartName(); + bs.setCounterpartyName(counterpartName); + + if (StrUtil.isNotEmpty(counterpartName)) { + RCCOpeningAccountInfoEntry acc = rccNameAccMap.getOrDefault(counterpartName, null); + if (acc != null) { + bs.setCounterpartIdCardNo(acc.getIdCardNo()); + } + } + bs.setCounterpartyAccount(entry.getCounterpartyAccount()); + bs.setCounterpartyBankName(entry.getCounterpartyBankName()); +// bs.setSummary(entry.getSummary()); + bs.setTransRemark(entry.getTransRemark()); + bs.setTransChannel(entry.getTransChannel()); + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + bs.setTransactionInstitutions(entry.getTransactionInstitutions()); + bs.setTransactionAmount(new BigDecimal(entry.getTransactionAmount())); + String balance = entry.getBalance(); + if(StrUtil.isEmpty(balance)){ + balance = "0"; + } + bs.setBalance(new BigDecimal(balance)); + bs.setRealCounterpartyName(entry.getRealCounterpartyName()); + // 交易时间 + + String transDate = entry.getTransDate(); + if (StrUtil.isNotEmpty(transDate)) { + String transTime = entry.getTransTime(); + if (StrUtil.isNotEmpty(transTime)) { + try { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss"); + try { + bs.setTransactionTime(DateUtil.parse(transDate + " " + transTime, formatter)); + } catch (Exception e) { + bs.setTransactionTime(DateUtil.parse(transDate, "yyyyMMdd")); + } + } catch (Exception e) { + throw new AnalyzeDataFailedException(StrUtil.format("解析时间失败,日期为:{}", transDate), e, sourceFile); + } + } else { + try { + bs.setTransactionTime(DateUtil.parse(transDate, "yyyyMMdd")); + } catch (Exception e) { + throw new AnalyzeDataFailedException(StrUtil.format("解析时间失败,日期为:{}", transDate), e, sourceFile); + } + } + } + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entry.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); + try { + BeanUtils.beanAttributeValueTrim(bs); + } catch (Exception e) { + e.printStackTrace(); + } + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + + HelperUtil.batchInsert2Es(dest, caseId); + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e, sourceFile); + } + } + + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } + + private void readRCCBS(String excelName, int sheetNo) { + + int headRowNumber = AsposeUtil.getHeadRowNumber(excelName, sheetNo, "流水号"); + + Class clazz = RCCBankStatementEntry.class; + + try (ExcelReader reader = EasyExcel.read(excelName).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNumber) + .head(clazz) + .registerReadListener(HelperUtil.getReadListener(statementMapper, clazz, false,excelName.split("农村信用社")[1])) + .build(); + reader.read(sheet); + + + } catch (Exception e) { + throw new ImportDataFailedException("读取文件内容失败【"+e.getMessage()+"】", excelName); + } + } + + private void readRCCOAI(String excelFileName, int sheetNo) { + + int rowNumber = AsposeUtil.getRowNumber(new File(excelFileName), sheetNo, "开户日期"); + if (rowNumber == -1) { + throw new ImportDataFailedException("无法读取文件内容", excelFileName); + } + + rowNumber = rowNumber + 1; + + try (ExcelReader reader = EasyExcel.read(excelFileName).build()) { + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(rowNumber) + .head(RCCOpeningAccountInfoEntry.class) + .registerReadListener( + HelperUtil.getReadListener(accountInfoMapper, RCCOpeningAccountInfoEntry.class, true,excelFileName.split("农村信用社")[1])) + .build(); + reader.read(sheet); + } catch (Exception e) { + + if (e instanceof ExcelAnalysisStopException) { + return; + } + + log.error("读取文件开户信息内容失败: " + e.getMessage(), e); + throw new ImportDataFailedException("读取文件开户信息内容失败: " + e.getMessage(), excelFileName); + } + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/SPDBDataAnalysisHelper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/SPDBDataAnalysisHelper.java new file mode 100644 index 0000000..9545241 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/helper/SPDBDataAnalysisHelper.java @@ -0,0 +1,233 @@ +package com.inscloudtech.bankStatementAnalysis.helper; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.util.ListUtils; +import com.aspose.cells.Cell; +import com.aspose.cells.Cells; +import com.aspose.cells.Workbook; +import com.aspose.cells.Worksheet; + +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.common.constant.BankStatementConstants; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.exception.dc.AnalyzeDataFailedException; +import com.inscloudtech.common.exception.dc.ImportDataFailedException; +import com.inscloudtech.common.exception.dc.TemplateNotFindException; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.file.FileUtils; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.mapper.es.EsSPDBBSMapper; +import com.inscloudtech.datacenter.service.ImportResultService; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.bankStatementAnalysis.domain.entity.SPDBBSEntity; + +import com.inscloudtech.bankStatementAnalysis.util.AsposeUtil; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * 浦发银行数据分析 + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class SPDBDataAnalysisHelper { + + + private final ImportResultService importResultService; + private final EsSPDBBSMapper statementMapper; + private final static String BANK_NAME = "浦发银行"; + public void importData(File file,String caseId) throws Exception { + + if (file == null || !file.exists()) { + return; + } + + List fileList = FileUtil.loopFiles(file); + List excelFile = HelperUtil.getExcelFile(fileList); + + for (File f : excelFile) { + try { + String excelFileName = f.getAbsolutePath(); + String sourceFile = excelFileName; + if (sourceFile.contains("浦发银行\\")) { + sourceFile = sourceFile.split("浦发银行\\\\")[1]; + } else if (sourceFile.contains("浦发银行/")) { + sourceFile = sourceFile.split("浦发银行/")[1]; + } + + Workbook wb; + try { + wb = new Workbook(excelFileName); + } catch (Exception e) { + if (e.getMessage().contains("password")) { + throw new AnalyzeDataFailedException("文件有密码无法解析", e, sourceFile); + } else { + throw new AnalyzeDataFailedException("解析文件失败", e, sourceFile); + } + } + int count = wb.getWorksheets().getCount(); + for (int sheetNo = 0; sheetNo < count; sheetNo++) { + try { + Worksheet worksheet = wb.getWorksheets().get(sheetNo); + Cells cells = worksheet.getCells(); + Cell cell = AsposeUtil.getCell(cells, "交易时间"); + if (cell != null) { + int headRowNumber = cell.getRow() + 1; + try (ExcelReader reader = EasyExcel.read(excelFileName).build()) { + Class clazz = SPDBBSEntity.class; + ReadSheet sheet = EasyExcel.readSheet(sheetNo) + .headRowNumber(headRowNumber) + .head(clazz) + .registerReadListener(HelperUtil.getReadListener(statementMapper, clazz, false, sourceFile)) + .build(); + reader.read(sheet); + + } catch (Exception e) { + log.error("读取excel文件失败", e); + throw new ImportDataFailedException(e.getMessage(), excelFileName); + } + } else { + throw new TemplateNotFindException(sourceFile + BankStatementConstants.NAME_WITH_SHEET_NAME + worksheet.getName()); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e, sourceFile); + } + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e); + } + } + } + + public void analyzeData(String caseId) { + + List bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + int batchSize = Constants.BATCH_SIZE; + + List entityList = HelperUtil.getEntityList(statementMapper, SPDBBSEntity.class); + Set uniqueKeySet = new HashSet(); + List plateNumberInfoList = new ArrayList<>(); + for (SPDBBSEntity entry : entityList) { + String sourceFile = entry.getSourceFile(); + try { + BankStatement bs = new BankStatement(); + // 需要从数据库中去查找基本信息,比如身份证号等 + String cardHolderName = entry.getCardHolderName(); + if (StringUtils.isEmpty(cardHolderName)) { + continue; + } + // 没有开户信息,所以只能从数据库中查找相关信息 + // 流水 + bs.setBankName(BANK_NAME); + bs.setCardHolderName(entry.getCardHolderName()); + bs.setCardNumber(entry.getCardNumber()); + // 1 货币类型 + // 人民币 + bs.setTransCurrencyType(Constants.CURRENCY_TYPE_CHINA); + // 2 交易金额 可能是double或者int类型 + Integer loanFlag = entry.getLoanFlag(); + if (loanFlag != null) { + if (loanFlag == 0) { // + + bs.setTransactionAmount(entry.getTransactionAmount().negate()); + } else { + bs.setTransactionAmount(entry.getTransactionAmount()); + } + } else { + // 没有这个借贷标记的情况 + bs.setTransactionAmount(entry.getTransactionAmount()); + } + // 3 余额 + bs.setBalance(entry.getBalance()); + // 4 交易日期 + // 交易时间 + String transDate = entry.getTransDate(); + if (StrUtil.isNotEmpty(transDate)) { + String format = null; + // 如果包含-,则用yyyy-MM-dd这种形式 + if (transDate.contains("-")) { + format = "yyyy-MM-dd"; + } else if (transDate.contains("/")) { + format = "yyyy/MM/dd"; + } else { + format = "yyyyMMdd"; + } + + String transTime = entry.getTransTime(); + if (StrUtil.isNotEmpty(transTime)) { + if (transTime.contains(":")) { + format += " HH:mm:ss"; + } else { + transTime = transTime.substring(0, Constants.TIME_FULL_FORMAT_LENGTH); + format += " HHmmss"; + } + } + + try { + bs.setTransactionTime( + DateUtil.parse(transDate + " " + transTime, DateTimeFormatter.ofPattern(format))); + } catch (Exception e) { + log.error("解析交易日期失败:{}", e.getMessage(), e); + + + throw new AnalyzeDataFailedException(e.getMessage(), e, sourceFile); + } + } + + String counterpartyName = entry.getCounterpartyName(); + bs.setCounterpartyName(counterpartyName); + + bs.setSummary(entry.getSummary()); + bs.setTransRemark(entry.getTransRemark()); + bs.setCounterpartyBankName(entry.getCounterpartyBankName()); + bs.setCounterpartyAccount(entry.getCounterpartyAccount()); + + bs.setIdCardNo(entry.getIdCard()); + bs.setTransChannel(entry.getTransChannel()); + + + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + bs.setSourceFile(entry.getSourceFile()); + bs.setId(md5Id); + bs.setCaseId(caseId); +// bs.setRemark(entity.getTransNo()+entity.getTransChildNo()); + bsList.add(bs); + HelperUtil.extractPlateNumber(bs,plateNumberInfoList); + if (bsList.size() >= batchSize) { + + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + bsList = ListUtils.newArrayListWithExpectedSize(batchSize); + } + } catch (Exception e) { + importResultService.record(caseId, BANK_NAME, e, sourceFile); + } + } + uniqueKeySet.clear(); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + // 保存数据库 + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/CGBCCreditCardOpeningAccountInfoReadListener.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/CGBCCreditCardOpeningAccountInfoReadListener.java new file mode 100644 index 0000000..63fb297 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/CGBCCreditCardOpeningAccountInfoReadListener.java @@ -0,0 +1,66 @@ +package com.inscloudtech.bankStatementAnalysis.listener; + +import cn.hutool.core.util.IdUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.util.ListUtils; +import com.inscloudtech.datacenter.mapper.es.EsCGBCCreditCardAccountInfoMapper; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CGBCCreditCardAccountInfoEntry; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +import static com.inscloudtech.common.constant.Constants.BATCH_SIZE; + +/** + * 广发银行信用卡开户信息读取监听器 + */ +@RequiredArgsConstructor +@Slf4j +public class CGBCCreditCardOpeningAccountInfoReadListener implements ReadListener { + + private List cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + private final EsCGBCCreditCardAccountInfoMapper creditCardAccountInfoMapper; + //private final ImportResult importResult; + private int localDataCount = 0; + @Override + public void invoke(CGBCCreditCardAccountInfoEntry entry, AnalysisContext analysisContext) { + + //数据需要处理一下 + entry.setId(IdUtil.objectId()); + + cacheList.add(entry); + + if (cacheList.size() >= BATCH_SIZE) { + saveData(); + cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + if (!cacheList.isEmpty()) { + saveData(); + } + + } + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + HelperUtil.handleException(exception); + + ReadListener.super.onException(exception, context); + } + + private void saveData() { + + creditCardAccountInfoMapper.insertBatch(cacheList); + + + + log.info("{}条数据,开始存储数据库!", cacheList.size()); + + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/CITICBankOpeningAccountInfoReadListener.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/CITICBankOpeningAccountInfoReadListener.java new file mode 100644 index 0000000..75ceb9f --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/CITICBankOpeningAccountInfoReadListener.java @@ -0,0 +1,132 @@ +package com.inscloudtech.bankStatementAnalysis.listener; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.exception.ExcelAnalysisStopException; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.util.ListUtils; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.datacenter.mapper.es.EsCITICOpeningAccountInfoMapper; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CITICOpeningAccountInfoEntity; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * 中信银行开户信息读取监听器 + */ +@RequiredArgsConstructor +@Slf4j +public class CITICBankOpeningAccountInfoReadListener implements ReadListener { + + private static final int BATCH_SIZE = Constants.BATCH_SIZE; + + private final EsCITICOpeningAccountInfoMapper openingAccountInfoMapper; + private final String idCardNo; + //private final ImportResult importResult; + private List cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + + private int localDataCount = 0; + @Override + public void invoke(CITICOpeningAccountInfoEntity entry, AnalysisContext analysisContext) { + + String accountNumber = entry.getAccountNumber(); + if (StrUtil.isNotEmpty(accountNumber) && HelperUtil.isContainsChinese(accountNumber)) { + if(!cacheList.isEmpty()){ + saveData(); + } + // 当账户中包含汉字,说明已经读取超过限制 + throw new ExcelAnalysisStopException("不属于开户信息,停止读取."); + } + + String accountNumberItem = entry.getAccountNumberItem(); + if (StrUtil.isNotEmpty(accountNumberItem) && HelperUtil.isContainsChinese(accountNumberItem)) { + if(!cacheList.isEmpty()){ + saveData(); + } + // 当账户中包含汉字,说明已经读取超过限制 + throw new ExcelAnalysisStopException("不属于开户信息,停止读取."); + } + + if (StringUtils.isEmpty(entry.getIdCardNo())) { + if (StrUtil.isNotEmpty(idCardNo)) { + entry.setIdCardNo(idCardNo); + } else { +// if(StringUtils.isEmpty(accountNumberItem)){ +// return; +// } + } + } + + entry.setId(IdUtil.objectId()); + + String address = entry.getAddress(); + if (StrUtil.isNotEmpty(address)) { + address = address.replaceAll("\\n", ""); + entry.setAddress(address); + } + + String customerId = entry.getCustomerId(); + if (StrUtil.isNotEmpty(customerId)) { + customerId = customerId.replaceAll("\\n", ""); + entry.setCustomerId(customerId); + } + + String idCardNo = entry.getIdCardNo(); + if (StrUtil.isNotEmpty(idCardNo)) { + idCardNo = idCardNo.replaceAll("\\n", ""); + entry.setIdCardNo(idCardNo); + } + + String idType = entry.getIdType(); + if (StrUtil.isNotEmpty(idType)) { + idType = idType.replaceAll("\\n", ""); + entry.setIdType(idType); + } + + String cardHolderName = entry.getCardHolderName(); + if (StrUtil.isNotEmpty(cardHolderName)) { + cardHolderName = cardHolderName.replaceAll("\\n", ""); + entry.setCardHolderName(cardHolderName); + } + // 保存数据库使用 + + cacheList.add(entry); + if (cacheList.size() >= BATCH_SIZE) { + saveData(); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + if (!cacheList.isEmpty()) { + saveData(); + } + + } + + private void saveData() { + + openingAccountInfoMapper.insertBatch(cacheList); + + // 保存一份数据库,备用 + // 有些银行没有提供基本信息 + + + log.info("{}条数据,开始存储数据库!", cacheList.size()); + + // 清空 + cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + HelperUtil.handleException(exception); + + ReadListener.super.onException(exception, context); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/CMBOpeningAccountInfoReadListener.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/CMBOpeningAccountInfoReadListener.java new file mode 100644 index 0000000..864bd03 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/CMBOpeningAccountInfoReadListener.java @@ -0,0 +1,69 @@ +package com.inscloudtech.bankStatementAnalysis.listener; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.util.ListUtils; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.datacenter.mapper.es.EsCMBOpeningAccountInfoMapper; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CMBOpeningAccountInfoEntry; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * 招商银行开户信息读取监听器 + */ +@RequiredArgsConstructor +@Slf4j +public class CMBOpeningAccountInfoReadListener implements ReadListener { + + private final EsCMBOpeningAccountInfoMapper accountInfoMapper; + + private static final int BATCH_SIZE = Constants.BATCH_SIZE; + + private List cache = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + + @Override + public void invoke(CMBOpeningAccountInfoEntry entry, AnalysisContext analysisContext) { + + entry.setId(IdUtil.objectId()); + String idCardNo = entry.getIdCardNo(); + if(StrUtil.isNotEmpty(idCardNo) && idCardNo.length() != 18){ +// entry.setIdCardNo("证件号【"+idCardNo+"】,不是标准18位代码"); + entry.setIdCardNo(""); + } + cache.add(entry);//保存数据库 + + if (cache.size() >= BATCH_SIZE) { + saveData(); + cache = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + if (!cache.isEmpty()) { + saveData(); + } + } + + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + + HelperUtil.handleException(exception); + + ReadListener.super.onException(exception, context); + } + + + private void saveData() { + + accountInfoMapper.insertBatch(cache); + + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/EsListener.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/EsListener.java new file mode 100644 index 0000000..c5bef3a --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/EsListener.java @@ -0,0 +1,29 @@ +package com.inscloudtech.bankStatementAnalysis.listener; + + +import cn.hutool.extra.spring.SpringUtil; +import com.inscloudtech.bankStatementAnalysis.helper.EsMapperHolder; +import com.inscloudtech.datacenter.mapper.es.*; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class EsListener implements ApplicationContextAware { + @Override + public void setApplicationContext(ApplicationContext ctx) throws BeansException { + ESBankStatementMapper bean = ctx.getBean(ESBankStatementMapper.class); + EsMapperHolder.setEsBankStatementMapper(bean); + + ESOpeningAccountInfoMapper mapper = ctx.getBean(ESOpeningAccountInfoMapper.class); + EsMapperHolder.setEsOpeningAccountInfoMapper(mapper); + + PlateNumberEsMapper plateNumberEsMapper = ctx.getBean(PlateNumberEsMapper.class); + EsMapperHolder.setPlateNumberEsMapper(plateNumberEsMapper); + + +// SpringUtil.setApplicationContext(ctx); + + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/FDBPrivateOpeningAccountInfoReadListener.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/FDBPrivateOpeningAccountInfoReadListener.java new file mode 100644 index 0000000..39890b9 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/FDBPrivateOpeningAccountInfoReadListener.java @@ -0,0 +1,74 @@ +package com.inscloudtech.bankStatementAnalysis.listener; + +import cn.hutool.core.util.IdUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.util.ListUtils; +import com.alibaba.excel.util.StringUtils; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.datacenter.mapper.es.EsFDBPrivateAccountOpeningInfoMapper; +import com.inscloudtech.bankStatementAnalysis.domain.entity.FDBPrivateAccountOpeningInfoEntry; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * 富滇银行开户信息读取监听器 + */ +@RequiredArgsConstructor +@Slf4j +public class FDBPrivateOpeningAccountInfoReadListener implements ReadListener { + + private final EsFDBPrivateAccountOpeningInfoMapper openingInfoMapper; + private static final int BATCH_SIZE = Constants.BATCH_SIZE; + private final String caseId; + + private List cache = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + + @Override + public void invoke(FDBPrivateAccountOpeningInfoEntry entry, AnalysisContext analysisContext) { + + String cardHolderName = entry.getCardHolderName(); + if (StringUtils.isEmpty(cardHolderName)) { + return; + } + + entry.setId(IdUtil.objectId()); + entry.setCaseId(caseId); + cache.add(entry); + + if (cache.size() >= BATCH_SIZE) { + saveData(); + cache = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + log.info("读取富滇银行开户信息结束"); + + if (!cache.isEmpty()) { + saveData(); + } + } + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + + HelperUtil.handleException(exception); + + ReadListener.super.onException(exception, context); + } + + private void saveData() { + + openingInfoMapper.insertBatch(cache); + + + log.info("{}条数据,开始存储数据库!", cache.size()); + + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/FDBPublicOpeningAccountInfoReadListener.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/FDBPublicOpeningAccountInfoReadListener.java new file mode 100644 index 0000000..0d85d45 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/FDBPublicOpeningAccountInfoReadListener.java @@ -0,0 +1,74 @@ +package com.inscloudtech.bankStatementAnalysis.listener; + +import cn.hutool.core.util.IdUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.util.ListUtils; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.datacenter.mapper.es.EsFDBPublicAccountOpeningInfoMapper; +import com.inscloudtech.bankStatementAnalysis.domain.entity.FDBPublicAccountOpeningInfoEntity; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * 富滇银行开户信息读取监听器 + */ +@RequiredArgsConstructor +@Slf4j +public class FDBPublicOpeningAccountInfoReadListener + implements ReadListener { + + private final EsFDBPublicAccountOpeningInfoMapper openingInfoMapper; + + private final String caseId; + + private static final int BATCH_SIZE = Constants.BATCH_SIZE; + + private List cache = + ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + + @Override + public void invoke( + FDBPublicAccountOpeningInfoEntity entry, AnalysisContext analysisContext) { + + if (StringUtils.isEmpty(entry.getCardHolderName())) { + return; + } + entry.setCaseId(caseId); + entry.setId(IdUtil.objectId()); + cache.add(entry); + + if (cache.size() >= BATCH_SIZE) { + saveData(); + cache = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + log.info("读取富滇银行开户信息结束"); + + if (!cache.isEmpty()) { + saveData(); + } + } + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + + HelperUtil.handleException(exception); + + ReadListener.super.onException(exception, context); + } + + private void saveData() { + + openingInfoMapper.insertBatch(cache); + + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/FDBStatementReadListener.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/FDBStatementReadListener.java new file mode 100644 index 0000000..d8cf6f3 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/FDBStatementReadListener.java @@ -0,0 +1,83 @@ +package com.inscloudtech.bankStatementAnalysis.listener; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.util.ListUtils; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.datacenter.mapper.es.EsFDBStatementMapper; +import com.inscloudtech.bankStatementAnalysis.domain.entity.FDBStatementEntity; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; +import java.util.Objects; + +/** + * 富滇银行流水读取监听器 + */ +@RequiredArgsConstructor +@Slf4j +public class FDBStatementReadListener implements ReadListener { + + private final EsFDBStatementMapper statementMapper; + private final String sourceFile; + private final String caseId; + + private static final int BATCH_SIZE = Constants.BATCH_SIZE; + private List cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + + @Override + public void invoke(FDBStatementEntity entry, AnalysisContext context) { + + String expenditureAmount = entry.getExpenditureAmount(); + if (StrUtil.isNotEmpty(expenditureAmount) && Objects.equals(expenditureAmount, "支出金额")) { + return; + } + + String transactionTime = entry.getTransactionTime(); + + if (StringUtils.isEmpty(transactionTime)) { + return; + } + + String id = IdUtil.objectId(); + entry.setId(id); + entry.setSourceFile(sourceFile); + entry.setCaseId(caseId); + cacheList.add(entry); + + if (cacheList.size() >= BATCH_SIZE) { + saveData(); + cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + //保存不够一百条数据的批次 + if (!cacheList.isEmpty()) { + saveData(); + } + + + } + + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + + HelperUtil.handleException(exception); + + ReadListener.super.onException(exception, context); + } + + private void saveData() { + statementMapper.insertBatch(cacheList); + + + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadCCBCurrentAccountInfoListener.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadCCBCurrentAccountInfoListener.java new file mode 100644 index 0000000..84dcc1e --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadCCBCurrentAccountInfoListener.java @@ -0,0 +1,88 @@ +package com.inscloudtech.bankStatementAnalysis.listener; + +import cn.hutool.core.util.IdUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.exception.ExcelAnalysisStopException; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.util.ListUtils; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.datacenter.mapper.es.EsCCBCurrentAccountInfoMapper; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CCBCurrentAccountInfoEntity; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * 建设银行账户信息读取监听器 + */ +@Slf4j +public class ReadCCBCurrentAccountInfoListener implements ReadListener { + + private int startRow; + private int endRow; + + + private static final int BATCH_SIZE = 100; + + private List cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + + private final EsCCBCurrentAccountInfoMapper infoMapper; + + public ReadCCBCurrentAccountInfoListener(int startRow, int endRow, EsCCBCurrentAccountInfoMapper infoMapper) { + this.startRow = startRow; + this.endRow = endRow; + this.infoMapper = infoMapper; + } + + @Override + public void invoke(CCBCurrentAccountInfoEntity entry, AnalysisContext analysisContext) { + + entry.setId(IdUtil.objectId()); + + cacheList.add(entry); + + if (cacheList.size() >= BATCH_SIZE) { + saveData(); + } + + startRow++; + if (startRow >= endRow) { + saveData(); + throw new ExcelAnalysisStopException("stop read..."); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + if (!cacheList.isEmpty()) { + saveData(); + } + } + + private void saveData() { + + infoMapper.insertBatch(cacheList); + + + log.info("{}条数据,开始存储数据库!", cacheList.size()); + + //清空 + cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + HelperUtil.handleException(exception); + + ReadListener.super.onException(exception, context); + } + + public void setStartRow(int startRow) { + this.startRow = startRow; + } + + public void setEndRow(int endRow) { + this.endRow = endRow; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadCIBOpeningAccountInfoListener.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadCIBOpeningAccountInfoListener.java new file mode 100644 index 0000000..79bcbae --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadCIBOpeningAccountInfoListener.java @@ -0,0 +1,70 @@ +package com.inscloudtech.bankStatementAnalysis.listener; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.util.ListUtils; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.datacenter.mapper.es.EsCIBOpeningAccountInfoMapper; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CIBOpeningAccountInfoEntity; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * 农业银行开始信息读取监听器 + */ +@RequiredArgsConstructor +@Slf4j +public class ReadCIBOpeningAccountInfoListener implements ReadListener { + + private static final int BATCH_SIZE = Constants.BATCH_SIZE; + + private final EsCIBOpeningAccountInfoMapper esMapper; + + private final String caseId; + + private List cache = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + + @Override + public void invoke(CIBOpeningAccountInfoEntity entry, AnalysisContext analysisContext) { + if(StrUtil.isEmpty(entry.getCardNumber()) && StrUtil.isNotEmpty(entry.getNewAccountNumber())){ + entry.setCardNumber(entry.getNewAccountNumber()); + } + entry.setId(IdUtil.objectId()); + entry.setCaseId(caseId); + cache.add(entry); + + if (cache.size() >= BATCH_SIZE) { + saveData(); + cache = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + log.info("读兴业银行开户信息结束"); + + if (!cache.isEmpty()) { + saveData(); + } + } + + private void saveData() { + + esMapper.insertBatch(cache); + + } + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + HelperUtil.handleException(exception); + + ReadListener.super.onException(exception, context); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadCMBCCreditCardBankStatementListener.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadCMBCCreditCardBankStatementListener.java new file mode 100644 index 0000000..0f5b229 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadCMBCCreditCardBankStatementListener.java @@ -0,0 +1,100 @@ +package com.inscloudtech.bankStatementAnalysis.listener; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.util.ListUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.datacenter.mapper.es.EsCMBCCreditCardBankStatementMapper; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CMBCCreditCardBankStatementEntity; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +import static com.inscloudtech.common.constant.Constants.BATCH_SIZE; + +/** + * 民生银行流水读取监听器-信用卡 + */ +@RequiredArgsConstructor +@Slf4j +public class ReadCMBCCreditCardBankStatementListener implements ReadListener { + + + private final EsCMBCCreditCardBankStatementMapper creditCardBankStatementMapper; + private final String sourceFile; + private List cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + + + @Override + public void invoke(CMBCCreditCardBankStatementEntity entry, AnalysisContext context) { + + if (entry == null || StringUtils.isEmpty(entry.getCardNumber())) { + return; + } + + String id = IdUtil.objectId(); + entry.setSourceFile(sourceFile); + entry.setId(id); + + + String cardNumber = entry.getCardNumber(); + if (StrUtil.isNotEmpty(cardNumber)) { + cardNumber = cardNumber.replaceAll("'", ""); + entry.setCardNumber(cardNumber); + } + + String transactionTime = entry.getTransactionTime(); + if (StrUtil.isNotEmpty(transactionTime)) { + transactionTime = transactionTime.replaceAll("'", ""); + + entry.setTransactionTime(transactionTime); + } + + String counterpartyIdCardNo = entry.getCounterpartyIdCardNo(); + if (StrUtil.isNotEmpty(counterpartyIdCardNo) && counterpartyIdCardNo.trim().equalsIgnoreCase("'")) { + entry.setCounterpartyIdCardNo(null); + } + + //根据交易流水号来筛选同一条数据 + String serialNumber = entry.getSerialNumber(); + if (StrUtil.isNotEmpty(serialNumber) && serialNumber.trim().contains("'")) { + serialNumber = serialNumber.trim().replaceAll("'", ""); + entry.setSerialNumber(serialNumber); + } + + cacheList.add(entry); + + if (cacheList.size() >= BATCH_SIZE) { + saveData(); + cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } + } + + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + //保存不够一百条数据的批次 + if (!cacheList.isEmpty()) { + saveData(); + } + + } + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + + HelperUtil.handleException(exception); + + ReadListener.super.onException(exception, context); + } + + private void saveData() { + creditCardBankStatementMapper.insertBatch(cacheList); + + cacheList.clear(); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadCMBCCreditCardOpeningAccountInfoListener.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadCMBCCreditCardOpeningAccountInfoListener.java new file mode 100644 index 0000000..0931996 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadCMBCCreditCardOpeningAccountInfoListener.java @@ -0,0 +1,83 @@ +package com.inscloudtech.bankStatementAnalysis.listener; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.util.ListUtils; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.datacenter.mapper.es.EsCMBCCreditCardAccountInfoMapper; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CMBCCreditCardAccountInfoEntity; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * 民生银行开户信息读取监听器-信用卡 + */ +@RequiredArgsConstructor +@Slf4j +public class ReadCMBCCreditCardOpeningAccountInfoListener implements ReadListener { + + private static final int BATCH_SIZE = Constants.BATCH_SIZE; + + private final EsCMBCCreditCardAccountInfoMapper creditCardAccountInfoMapper; + + private List cache = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + + @Override + public void invoke(CMBCCreditCardAccountInfoEntity entry, AnalysisContext analysisContext) { + + entry.setId(IdUtil.objectId()); + + String cardHolderName = entry.getCardHolderName(); + if (StringUtils.isEmpty(cardHolderName)) { + return; + } + + //数据需要处理一下 + String idCardNo = entry.getIdCardNo(); + String cardNumber = entry.getCardNumber(); + + if (StrUtil.isNotEmpty(idCardNo)) { + idCardNo = idCardNo.replaceAll("'", ""); + entry.setIdCardNo(idCardNo); + } + + if (StrUtil.isNotEmpty(cardNumber)) { + cardNumber = cardNumber.replaceAll("'", ""); + entry.setCardNumber(cardNumber); + } + + cache.add(entry); + + if (cache.size() >= BATCH_SIZE) { + saveData(); + cache = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } + } + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + HelperUtil.handleException(exception); + + ReadListener.super.onException(exception, context); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + log.info("民生银行开户信息读取监听器-信用卡结束"); + + if (!cache.isEmpty()) { + saveData(); + } + } + + private void saveData() { + creditCardAccountInfoMapper.insertBatch(cache); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadCMBCSavingsCardBankStatementListener.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadCMBCSavingsCardBankStatementListener.java new file mode 100644 index 0000000..e5c95d9 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadCMBCSavingsCardBankStatementListener.java @@ -0,0 +1,105 @@ +package com.inscloudtech.bankStatementAnalysis.listener; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.util.ListUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.datacenter.mapper.es.EsCMBCSavingsCardBankStatementMapper; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CMBCSavingsCardBankStatementEntity; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +import static com.inscloudtech.common.constant.Constants.BATCH_SIZE; + +/** + * 民生银行流水读取监听器-储蓄卡 + */ +@RequiredArgsConstructor +@Slf4j +public class ReadCMBCSavingsCardBankStatementListener implements ReadListener { + + List entityList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + + private final EsCMBCSavingsCardBankStatementMapper savingsCardBankStatementMapper; + + private final String companyCard; + + private final String sourceFile; + + @Override + public void invoke(CMBCSavingsCardBankStatementEntity entry, AnalysisContext context) { + + if (entry == null) { + return; + } + + String id = IdUtil.objectId(); + entry.setId(id); + + String cardNumber = entry.getCardNumber(); + if (StringUtils.isNotEmpty(cardNumber)) { + cardNumber = cardNumber.replaceAll("'", ""); + entry.setCardNumber(cardNumber); + }else if(StrUtil.isNotEmpty(companyCard) && StrUtil.isEmpty(cardNumber)){ + entry.setCardNumber(companyCard); + } + + String transactionTime = entry.getTransactionTime(); + if (StrUtil.isNotEmpty(transactionTime)) { + transactionTime = transactionTime.replaceAll("'", ""); + + entry.setTransactionTime(transactionTime); + } + + String counterpartyIdCardNo = entry.getCounterpartyIdCardNo(); + if (StrUtil.isNotEmpty(counterpartyIdCardNo) && counterpartyIdCardNo.trim().equalsIgnoreCase("'")) { + entry.setCounterpartyIdCardNo(null); + } + + //根据交易流水号来筛选同一条数据 + String serialNumber = entry.getSerialNumber(); + if (StrUtil.isNotEmpty(serialNumber) && serialNumber.trim().contains("'")) { + serialNumber = serialNumber.trim().replaceAll("'", ""); + entry.setSerialNumber(serialNumber); + } + entry.setSourceFile(sourceFile); + entityList.add(entry); + + if (entityList.size() >= BATCH_SIZE) { + saveData(); + entityList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } + } + + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + //保存不够一百条数据的批次 + if (!entityList.isEmpty()) { + saveData(); + } + + log.info("读取民生银行流水结束"); + } + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + + HelperUtil.handleException(exception); + + ReadListener.super.onException(exception, context); + } + + private void saveData() { + savingsCardBankStatementMapper.insertBatch(entityList); + + log.info("{}条数据,开始存储数据库!", entityList.size()); + + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadCMBCSavingsCardOpeningAccountInfoListener.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadCMBCSavingsCardOpeningAccountInfoListener.java new file mode 100644 index 0000000..0b66a91 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadCMBCSavingsCardOpeningAccountInfoListener.java @@ -0,0 +1,89 @@ +package com.inscloudtech.bankStatementAnalysis.listener; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.util.ListUtils; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.datacenter.mapper.es.EsCMBCSavingsCardAccountInfoMapper; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CMBCSavingsCardAccountInfoEntity; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * 民生银行开户信息读取监听器-储蓄卡 + */ +@RequiredArgsConstructor +@Slf4j +public class ReadCMBCSavingsCardOpeningAccountInfoListener implements ReadListener { + + private static final int BATCH_SIZE = Constants.BATCH_SIZE; + + private final EsCMBCSavingsCardAccountInfoMapper savingsCardAccountInfoMapper; + + private List cache = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + + @Override + public void invoke(CMBCSavingsCardAccountInfoEntity entry, AnalysisContext analysisContext) { + + entry.setId(IdUtil.objectId()); + + String cardHolderName = entry.getCardHolderName(); + if (StringUtils.isEmpty(cardHolderName)) { + return; + } + + // 数据需要处理一下 + String idCardNo = entry.getIdCardNo(); + String cardNumber = entry.getCardNumber(); + String accountNumber = entry.getAccountNumber(); + + if (StrUtil.isNotEmpty(idCardNo)) { + idCardNo = idCardNo.replaceAll("'", ""); + entry.setIdCardNo(idCardNo); + } + + if (StrUtil.isNotEmpty(cardNumber)) { + cardNumber = cardNumber.replaceAll("'", ""); + entry.setCardNumber(cardNumber); + } + + if (StrUtil.isNotEmpty(accountNumber)) { + accountNumber = accountNumber.replaceAll("'", ""); + entry.setAccountNumber(accountNumber); + } + + cache.add(entry); + + if (cache.size() >= BATCH_SIZE) { + saveData(); + cache = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } + } + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + HelperUtil.handleException(exception); + + ReadListener.super.onException(exception, context); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + log.info("读取民生银行开户信息结束"); + + if (!cache.isEmpty()) { + saveData(); + } + } + + private void saveData() { + savingsCardAccountInfoMapper.insertBatch(cache); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadCMBCSavingsCardOpeningCompanyInfoListener.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadCMBCSavingsCardOpeningCompanyInfoListener.java new file mode 100644 index 0000000..19fd512 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadCMBCSavingsCardOpeningCompanyInfoListener.java @@ -0,0 +1,83 @@ +package com.inscloudtech.bankStatementAnalysis.listener; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.util.ListUtils; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.datacenter.mapper.es.EsCMBCSavingsCardCompanyInfoMapper; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CMBCSavingsCardCompanyInfoEntity; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * 民生银行开户信息读取监听器-储蓄卡 + */ +@RequiredArgsConstructor +@Slf4j +public class ReadCMBCSavingsCardOpeningCompanyInfoListener implements ReadListener { + + private static final int BATCH_SIZE = Constants.BATCH_SIZE; + + private final EsCMBCSavingsCardCompanyInfoMapper companyInfoMapper; + + private List cache = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + + @Override + public void invoke(CMBCSavingsCardCompanyInfoEntity entry, AnalysisContext analysisContext) { + + entry.setId(IdUtil.objectId()); + + String cardHolderName = entry.getCardHolderName(); + if (StringUtils.isEmpty(cardHolderName)) { + return; + } + + // 数据需要处理一下 + String idCardNo = entry.getIdCardNo(); + String cardNumber = entry.getCardNumber(); + + if (StrUtil.isNotEmpty(idCardNo)) { + idCardNo = idCardNo.replaceAll("'", ""); + entry.setIdCardNo(idCardNo); + } + + if (StrUtil.isNotEmpty(cardNumber)) { + cardNumber = cardNumber.replaceAll("'", ""); + entry.setCardNumber(cardNumber); + } + + cache.add(entry); + + if (cache.size() >= BATCH_SIZE) { + saveData(); + cache = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } + } + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + HelperUtil.handleException(exception); + + ReadListener.super.onException(exception, context); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + log.info("读取民生银行开户信息结束"); + + if (!cache.isEmpty()) { + saveData(); + } + } + + private void saveData() { + companyInfoMapper.insertBatch(cache); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadHuaXiaOpeningAccountInfoListener.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadHuaXiaOpeningAccountInfoListener.java new file mode 100644 index 0000000..2f8daf4 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/ReadHuaXiaOpeningAccountInfoListener.java @@ -0,0 +1,67 @@ +package com.inscloudtech.bankStatementAnalysis.listener; + +import cn.hutool.core.util.IdUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.util.ListUtils; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.datacenter.mapper.es.EsHuaXiaAccountInfoMapper; +import com.inscloudtech.bankStatementAnalysis.domain.entity.HuaXiaAccountInfoEntity; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * 华夏银行开户信息读取监听器 + */ +@RequiredArgsConstructor +@Slf4j +public class ReadHuaXiaOpeningAccountInfoListener implements ReadListener { + + private final EsHuaXiaAccountInfoMapper accountInfoMapper; + + private static final int BATCH_SIZE = Constants.BATCH_SIZE; + + private List cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + + + @Override + public void invoke(HuaXiaAccountInfoEntity entry, AnalysisContext analysisContext) { + + entry.setId(IdUtil.objectId()); + + cacheList.add(entry); + + if (cacheList.size() >= BATCH_SIZE) { + saveData(); + cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } + } + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + HelperUtil.handleException(exception); + + ReadListener.super.onException(exception, context); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + if (!cacheList.isEmpty()) { + saveData(); + } + + + } + + + + private void saveData() { + + accountInfoMapper.insertBatch(cacheList); + + + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/SPAAccountInfoReadListener.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/SPAAccountInfoReadListener.java new file mode 100644 index 0000000..68d5f7c --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/SPAAccountInfoReadListener.java @@ -0,0 +1,68 @@ +package com.inscloudtech.bankStatementAnalysis.listener; + +import cn.hutool.core.util.IdUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.util.ListUtils; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.datacenter.mapper.es.EsSPABANKOpeningAccountInfoMapper; +import com.inscloudtech.bankStatementAnalysis.domain.entity.SPAAccountInfoEntity; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * 平安银行客户信息读取监听器 + */ +@RequiredArgsConstructor +@Slf4j +public class SPAAccountInfoReadListener implements ReadListener { + + private final EsSPABANKOpeningAccountInfoMapper accountInfoMapper; + private static final int BATCH_SIZE = Constants.BATCH_SIZE; + private List cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + + + @Override + public void invoke(SPAAccountInfoEntity entry, AnalysisContext analysisContext) { + + entry.setId(IdUtil.objectId()); + + + cacheList.add(entry); + + + if (cacheList.size() >= BATCH_SIZE) { + saveData(); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + + if (!cacheList.isEmpty()) { + saveData(); + } + + } + + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + + HelperUtil.handleException(exception); + + ReadListener.super.onException(exception, context); + } + + private void saveData() { + + accountInfoMapper.insertBatch(cacheList); + + + //清空 + cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/SPACustomerInfoReadListener.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/SPACustomerInfoReadListener.java new file mode 100644 index 0000000..58d049c --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/listener/SPACustomerInfoReadListener.java @@ -0,0 +1,69 @@ +package com.inscloudtech.bankStatementAnalysis.listener; + +import cn.hutool.core.util.IdUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.util.ListUtils; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.datacenter.mapper.es.EsSPACustomerInfoMapper; +import com.inscloudtech.bankStatementAnalysis.domain.entity.SPACustomerInfoEntity; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * 平安银行客户信息读取监听器 + */ +@RequiredArgsConstructor +@Slf4j +public class SPACustomerInfoReadListener implements ReadListener { + + private static final int BATCH_SIZE = Constants.BATCH_SIZE; + + private final EsSPACustomerInfoMapper customerInfoMapper; + + private List cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + + + @Override + public void invoke(SPACustomerInfoEntity entry, AnalysisContext analysisContext) { + + entry.setId(IdUtil.objectId()); + + cacheList.add(entry); + + if (cacheList.size() >= BATCH_SIZE) { + saveData(); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + + if (!cacheList.isEmpty()) { + saveData(); + } + + } + + + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + + HelperUtil.handleException(exception); + + ReadListener.super.onException(exception, context); + } + + private void saveData() { + + customerInfoMapper.insertBatch(cacheList); + + + + //清空 + cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/service/ImportService.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/service/ImportService.java new file mode 100644 index 0000000..ae3e1d9 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/service/ImportService.java @@ -0,0 +1,37 @@ +package com.inscloudtech.bankStatementAnalysis.service; + +import com.inscloudtech.bankStatementAnalysis.domain.HeadField; +import com.inscloudtech.bankStatementAnalysis.domain.ReadDto; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; +import org.dromara.easyes.core.core.BaseEsMapper; + +import java.io.File; +import java.util.List; +import java.util.Map; + +public interface ImportService{ + + ReadDto buildReadDto(Object... args); + + void readOAIData(String excelFileName, int headRowNumber, int sheetNo , String caseId, String bankName,String sourceFile); + + void readOAIData(ReadDto readDto); + + + List getOAIData (String caseId, String bankName); + + Map> getOAIMap(String caseId,String bankName); + + Map> getOAIMapByCardNumber(String caseId,String bankName); + + void readMultiplePersonAndMultipleHeadBankStatement(String excelFileName, int headRowNumber, int sheetNo, Class clazz, BaseEsMapper baseEsMapper, + String cardHolderName, String sourceFile, List headFields); + + + boolean existsIndex(String indexName); + + void setIdCardAndCardNumberByCardHolderName(Map> oaiMap, String cardHolderName, BankStatement bs); + + void setIdCardAndPhoneByCardNumber(Map> oaiMap, String cardNumber, BankStatement bs); +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/service/impl/ImportServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/service/impl/ImportServiceImpl.java new file mode 100644 index 0000000..f0bc40d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/service/impl/ImportServiceImpl.java @@ -0,0 +1,367 @@ +package com.inscloudtech.bankStatementAnalysis.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.util.ListUtils; + + +import com.inscloudtech.bankStatementAnalysis.domain.HeadField; +import com.inscloudtech.bankStatementAnalysis.domain.ImportOpeningAccountInfo; +import com.inscloudtech.bankStatementAnalysis.domain.ReadDto; +import com.inscloudtech.bankStatementAnalysis.helper.EsMapperHolder; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.bankStatementAnalysis.service.ImportService; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.exception.dc.ImportDataFailedException; +import com.inscloudtech.datacenter.mapper.es.ESOpeningAccountInfoMapper; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.easyes.core.biz.SAPageInfo; +import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper; +import org.dromara.easyes.core.core.BaseEsMapper; +import org.dromara.easyes.core.core.EsWrappers; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +@Slf4j +public class ImportServiceImpl implements ImportService { + + private final ESOpeningAccountInfoMapper esOpeningAccountInfoMapper; + + @Override + public ReadDto buildReadDto(Object... args) { + + return null; + } + + @Override + public void readOAIData(String excelFileName, int headRowNumber,int sheetNo , String caseId,String bankName,String sourceFile) { + ReadDto readDto = new ReadDto(); + readDto.setExcelFileName(excelFileName); + readDto.setHeadRowNumber(headRowNumber); + readDto.setSheetNo(sheetNo); + readDto.setSourceFile(sourceFile); + readDto.setBankName(bankName); + readDto.setCaseId(caseId); + this.readOAIData(readDto); + } + + /** + * 读取开户信息 + */ + @Override + public void readOAIData(ReadDto readDto) { + readDto.setHeadClass(ImportOpeningAccountInfo.class); + readDto.setReadListener(oAIReadListener(readDto.getCaseId(),readDto.getBankName())); + this.doRead(readDto); + } + + + + @Override + public List getOAIData(String caseId, String bankName) { + + LambdaEsQueryWrapper wrapper = EsWrappers.lambdaQuery(OpeningAccountInfo.class); + wrapper.orderByDesc("id"); + wrapper.eq("caseId", caseId); + wrapper.eq("bankName", bankName); + List rstList = new ArrayList<>(); + int pageSize = 5 * Constants.BATCH_SIZE; + + List next = null; + + do { + SAPageInfo pi = esOpeningAccountInfoMapper.searchAfterPage(wrapper, next, pageSize); + if (pi != null) { + rstList.addAll(pi.getList()); + next = pi.getNextSearchAfter(); + } else { + break; + } + } while (next != null); + + return rstList; + } + + /** + * 根据户名分组 + * @param caseId + * @param bankName + * @return + */ + @Override + public Map> getOAIMap(String caseId, String bankName) { + List oaiData = this.getOAIData(caseId, bankName); + return oaiData.stream().filter(item -> StrUtil.isNotEmpty(item.getName())).collect(Collectors.groupingBy(OpeningAccountInfo::getName)); + } + + @Override + public Map> getOAIMapByCardNumber(String caseId, String bankName) { + List oaiData = this.getOAIData(caseId, bankName); + return oaiData.stream().filter(item -> StrUtil.isNotEmpty(item.getAccountNumber())).collect(Collectors.groupingBy(OpeningAccountInfo::getAccountNumber)); + } + + + private ReadListener oAIReadListener(String caseId,String bankName) { + return new ReadListener() { + + List cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + Set uniqueKeySet = new HashSet(); + @Override + public void invoke(ImportOpeningAccountInfo importOai, AnalysisContext context) { + OpeningAccountInfo oai = new OpeningAccountInfo(); + BeanUtil.copyProperties(importOai,oai); + oai.setBankName(bankName); + if(StrUtil.isEmpty(oai.getAccountNumber()) && StrUtil.isNotEmpty(importOai.getCustomerId())){ + oai.setAccountNumber(importOai.getCustomerId()); + } + String md5Id = HelperUtil.generateMD5Id4OAI(oai,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + return; + } + + oai.setId(md5Id); + oai.setCaseId(caseId); + cacheList.add(oai); + if (cacheList.size() >= Constants.BATCH_SIZE) { + batchSaveOAI2Es(cacheList, caseId); + cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (CollectionUtil.isNotEmpty(cacheList)) { + batchSaveOAI2Es(cacheList, caseId); + } + cacheList.clear(); + uniqueKeySet.clear(); + } + }; + } + + public static void batchSaveOAI2Es(List oaiList, String caseId) { + + // 去重 + Map groupById = oaiList.stream().collect(Collectors.toMap(OpeningAccountInfo::getId, Function.identity())); + Set idSet = groupById.keySet(); + //根据id取es查询 返回的就是重复数据 + List esExistIdList = searchById(EsMapperHolder.getEsOpeningAccountInfoMapper(), OpeningAccountInfo.class, idSet, "caseId", caseId); + if(CollectionUtil.isEmpty(esExistIdList)){ + EsMapperHolder.getEsOpeningAccountInfoMapper().insertBatch(oaiList); + }else { + Set esIdSet = esExistIdList.stream().map(OpeningAccountInfo::getId).collect(Collectors.toSet()); + idSet.removeAll(esIdSet); + if(CollectionUtil.isEmpty(idSet)){ + return; + }else { + List saveLis = new ArrayList<>(); + for (String id : idSet) { + saveLis.add(groupById.get(id)); + } + EsMapperHolder.getEsOpeningAccountInfoMapper().insertBatch(saveLis); + } + } + } + + /** + * + */ + public static List searchById(BaseEsMapper mapper, Class clazz, Set idList, String column, String value) { + + LambdaEsQueryWrapper wrapper = EsWrappers.lambdaQuery(clazz); + wrapper.eq( column, value); + wrapper.in( "id", idList); + wrapper.orderByDesc("id"); +// wrapper.eq( "bankName", bankName); + wrapper.select("id"); + List rstList = new ArrayList<>(); + + // + int pageSize = 5 * Constants.BATCH_SIZE; + + List next = null; + + do { + SAPageInfo pi = mapper.searchAfterPage(wrapper, next, pageSize); + if (pi != null) { + rstList.addAll(pi.getList()); + next = pi.getNextSearchAfter(); + } else { + break; + } + } while (next != null); + + return rstList; + } + + /** + * 一个excel里多个人流水,重复表头 + */ + @Override + public void readMultiplePersonAndMultipleHeadBankStatement(String excelFileName, int headRowNumber, int sheetNo, Class clazz, BaseEsMapper baseEsMapper, + String cardHolderName, String sourceFile, + List headFields) { + ReadDto readDto = new ReadDto(); + readDto.setExcelFileName(excelFileName); + readDto.setHeadRowNumber(headRowNumber); + readDto.setSheetNo(sheetNo); + readDto.setHeadClass(clazz); + readDto.setEsMapper(baseEsMapper); + readDto.setCardHolderName(cardHolderName); + readDto.setSourceFile(sourceFile); + readDto.setHeadFields(headFields); + readDto.setReadListener(readMultiplePersonAndMultipleHeadBankStatementReadListener(readDto)); + this.doRead(readDto); + } + + @Override + public boolean existsIndex(String indexName) { + return esOpeningAccountInfoMapper.existsIndex(indexName); + } + + @Override + public void setIdCardAndCardNumberByCardHolderName(Map> oaiMap, String cardHolderName, BankStatement bs) { + if(StrUtil.isNotEmpty(bs.getIdCardNo()) && StrUtil.isNotEmpty(bs.getCardNumber())){ + return; + } + + if(StrUtil.isEmpty(cardHolderName)){ + return; + } + + if(oaiMap.keySet().contains(cardHolderName)){ + List infoList = oaiMap.get(cardHolderName); + for (OpeningAccountInfo info : infoList) { + if(StrUtil.isNotEmpty(info.getIdNo())){ + bs.setIdCardNo(info.getIdNo()); + } + if(StrUtil.isNotEmpty(info.getAccountNumber())){ + bs.setCardNumber(info.getAccountNumber()); + } + } + } + } + + @Override + public void setIdCardAndPhoneByCardNumber(Map> oaiMap, String cardNumber, BankStatement bs) { + if(StrUtil.isNotEmpty(bs.getIdCardNo()) && StrUtil.isNotEmpty(bs.getPhone())){ + return; + } + + if(StrUtil.isEmpty(cardNumber)){ + return; + } + + if(oaiMap.keySet().contains(cardNumber)){ + List infoList = oaiMap.get(cardNumber); + for (OpeningAccountInfo info : infoList) { + if(StrUtil.isNotEmpty(info.getIdNo())){ + bs.setIdCardNo(info.getIdNo()); + } + if(StrUtil.isNotEmpty(info.getPhone())){ + bs.setPhone(info.getPhone()); + } + } + } + } + + + public ReadListener readMultiplePersonAndMultipleHeadBankStatementReadListener(ReadDto readDto) { + return new ReadListener() { + List cacheList = ListUtils.newArrayListWithExpectedSize( Constants.BATCH_SIZE); + BaseEsMapper esMapper = readDto.getEsMapper(); + Class headClass = readDto.getHeadClass(); + @Override + public void invoke(T data, AnalysisContext context) { + + String str = JSONUtil.toJsonStr(data); + JSONObject obj = JSONUtil.parseObj(str); + + boolean skip = false; + List amountFields = readDto.getHeadFields(); + if(CollectionUtil.isNotEmpty(amountFields)){ + for (HeadField amountField : amountFields) { + String field = amountField.getField(); + if(obj.containsKey(field)){ + String cellVal = obj.getStr(field); + if (amountField.getValue().contains(cellVal)) { + skip = true; + break; + } + } + } + } + if (skip) { + return; + } + if(StrUtil.isNotEmpty(readDto.getCardHolderName())){ + obj.put("cardHolderName", readDto.getCardHolderName()); + } + + obj.put("sourceFile", readDto.getSourceFile()+"-"+ context.getCurrentRowNum() +"行"); + + obj.put("id", IdUtil.objectId()); + cacheList.add(obj.toBean(headClass)); + + if (cacheList.size() >= Constants.BATCH_SIZE) { + esMapper.insertBatch(cacheList); + cacheList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + + + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + if (!cacheList.isEmpty()) { + esMapper.insertBatch(cacheList); + } + cacheList.clear(); + } + }; + } + + void doRead(ReadDto readDto){ + try (ExcelReader reader = EasyExcel.read(readDto.getExcelFileName()).build()) { + ReadSheet sheet = EasyExcel.readSheet(readDto.getSheetNo()) + .headRowNumber(readDto.getHeadRowNumber()) + .head(readDto.getHeadClass()) + .registerReadListener(readDto.getReadListener()) + .build(); + reader.read(sheet); + } catch (Exception e) { + log.error("读取数据失败", e); + throw new ImportDataFailedException(e.getMessage(), readDto.getSourceFile()); + } + } + + + + String phoneVerify = "(1|861)(3|5|8)\\d{9}$*"; + String idCardVerify = "([1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx])|([1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3})"; + String CarNumberVerify = "^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$"; + + + + +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/util/AnalyzeFileHelper.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/util/AnalyzeFileHelper.java new file mode 100644 index 0000000..a1da5f9 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/util/AnalyzeFileHelper.java @@ -0,0 +1,153 @@ +package com.inscloudtech.bankStatementAnalysis.util; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.ZipUtil; +import org.springframework.lang.Nullable; + + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * 辅助类,用于拆分:流水文件和开户文件 + */ +public class AnalyzeFileHelper { + + private static String originalFileName; + // 私有构造 + private AnalyzeFileHelper() {} + // 保存流水文件 + private static final List BS_FILE_LIST = new ArrayList<>(); + // 保存开户文件 + private static final List OAI_FILE_LIST = new ArrayList<>(); + + public static boolean containsFile(File file) { + return BS_FILE_LIST.contains(file) || OAI_FILE_LIST.contains(file); + } + + // 设置原始文件名 + public static void setOriginalFileName(String originalFileName) { + + if (originalFileName == null) { + return; + } + + if (originalFileName.contains(".")) { + originalFileName = originalFileName.substring(0, originalFileName.lastIndexOf(".")); + } + + AnalyzeFileHelper.originalFileName = originalFileName; + } + + public static void clear() { + BS_FILE_LIST.clear(); + OAI_FILE_LIST.clear(); + } + + public static void putBSFile(File file) { + if (file == null) { + return; + } + + if (!containsBSFile(file)) { + BS_FILE_LIST.add(file); + } + } + + private static boolean containsBSFile(File file) { + return BS_FILE_LIST.contains(file); + } + + public static void putOAIFile(File file) { + if (file == null) { + return; + } + + if (!containsOAIFile(file)) { + OAI_FILE_LIST.add(file); + } + } + + private static boolean containsOAIFile(File file) { + return OAI_FILE_LIST.contains(file); + } + + /** + * 返回打包好的文件-流水文件 + */ + @Nullable + public static File getBSZipFile() { + + File tmpDir = FileUtil.getTmpDir(); + if (tmpDir.exists()) { + // 创建新目录,将文件转移到该新目录下,完成打包 + if (tmpDir.isDirectory()) { + File dir = FileUtil.mkdir(tmpDir.getAbsolutePath() + File.separator + originalFileName + "_流水文件"); + // 转移文件 + for (File file : BS_FILE_LIST) { + // 拷贝文件 + if (file.exists()) { + FileUtil.copy(file, dir, true); + } + } + try { + // 打包 + return ZipUtil.zip(dir); + } finally { + // 删除临时文件 + FileUtil.del(dir); + } + } + } + + return null; + } + + /** + * 返回打包好的文件-开户文件 + */ + @Nullable + public static File getOAIZipFile() { + if (!OAI_FILE_LIST.isEmpty()) { + File tmpDir = FileUtil.getTmpDir(); + if (tmpDir.exists()) { + // 创建新目录,将文件转移到该新目录下,完成打包 + if (tmpDir.isDirectory()) { + File dir = FileUtil.mkdir(tmpDir.getAbsolutePath() + File.separator + originalFileName + "_开户文件"); + // 转移文件 + for (File file : OAI_FILE_LIST) { + if (file.exists()) { + FileUtil.copy(file, dir, true); + } + } + // 打包 + try { + return ZipUtil.zip(dir); + } finally { + // 删除临时文件 + FileUtil.del(dir); + } + } + } + } + + return null; + } + + public static int getFileBSTotalCount() { + return BS_FILE_LIST.size(); + } + + public static int getFileOAITotalCount() { + return OAI_FILE_LIST.size(); + } + + public static List getBsFileList() { + return BS_FILE_LIST; + } + + public static List getOaiFileList() { + return OAI_FILE_LIST; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/util/AsposeUtil.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/util/AsposeUtil.java new file mode 100644 index 0000000..f2b6300 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/util/AsposeUtil.java @@ -0,0 +1,509 @@ +package com.inscloudtech.bankStatementAnalysis.util; + +import cn.hutool.core.io.FileUtil; +import com.aspose.cells.*; +import com.aspose.cells.Cell; +import com.aspose.cells.Cells; +import com.aspose.cells.TxtLoadOptions; +import com.aspose.pdf.*; +import com.aspose.pdf.Document; +import com.aspose.pdf.SaveFormat; +import com.aspose.words.*; +import com.aspose.words.PdfSaveOptions; + + +import java.io.File; +import java.nio.charset.Charset; +import java.util.*; +import java.util.List; + +public class AsposeUtil { + private AsposeUtil() {} + + public static Cell find(Cells cells, String key, Cell previousCell) { + return cells.find(key, previousCell); + } + + public static List find(Cells cells, String key) { + List rstList = new ArrayList<>(); + Cell previousCell = null; + + for (; ; ) { + Cell cell = cells.find(key, previousCell); + if (cell == null) { + break; + } + + if (Objects.equals(cell.getStringValue().trim(), key)) { + rstList.add(cell); + } + + previousCell = cell; + } + + return rstList; + } + + public static void wordToPdf(String wordPath, String pdfPath) { + // 解决转化后pdf乱码问题 + String os = System.getProperty("os.name").toLowerCase(); + // 如果不是windows系统 + // Windows系统无需设置 + if (!os.contains("windows")) { + try { + FontSettings.getDefaultInstance() + .setFontsFolders(new String[] {"/usr/share/fonts", "/usr/share/fonts/chinese"}, true); + } catch (Exception ignore) { + // + } + } + + com.aspose.words.Document doc = null; + try { + doc = new com.aspose.words.Document(wordPath); + + Map map = new HashMap<>(); + + FindReplaceOptions options = new FindReplaceOptions(); + options.setReplacingCallback(new SearchCallBack(map)); + + doc.getRange().replace("银行卡存取现情况如下图:", "", options); + + PdfSaveOptions opt = new PdfSaveOptions(); + opt.setCompliance(com.aspose.words.PdfCompliance.PDF_17); + opt.setPrettyFormat(true); + opt.setUseHighQualityRendering(true); + opt.setImageCompression(PdfImageCompression.JPEG); + opt.setInterpolateImages(true); + opt.setSaveFormat(com.aspose.words.SaveFormat.PDF); + + doc.save(pdfPath); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static class SearchCallBack implements IReplacingCallback { + + private final Map map; + + public SearchCallBack(Map map) { + this.map = map; + } + + @Override + public int replacing(ReplacingArgs args) throws Exception { + Node currentNode = args.getMatchNode(); + printNodeInfo(currentNode); + return ReplaceAction.SKIP; + } + + private void printNodeInfo(Node node) throws Exception { + String nodeType = NodeType.toString(node.getNodeType()); + if (node.getParentNode() != null) { + int idx = node.getParentNode() + .getChildNodes(node.getNodeType(), false) + .indexOf(node); + map.put(nodeType, idx); + + if (nodeType.equalsIgnoreCase(NodeType.toString(NodeType.PARAGRAPH))) { + // 在每一个段落面前插入分页符,保证每一张图片都有足够的展示空间 + Paragraph paragraph = (Paragraph) node; + Run run = paragraph.getRuns().get(0); + // 插入分页符 + paragraph.insertBefore(new Run(paragraph.getDocument(), "\f"), run); + // 清空 + map.clear(); + } else { + printNodeInfo(node.getParentNode()); + } + } + } + } + + // 删除空白列 + public static void deleteBlankColumn(String filename) throws Exception { + Workbook wb = new Workbook(filename); + + WorksheetCollection worksheets = wb.getWorksheets(); + for (int sheetNo = 0; sheetNo < worksheets.getCount(); sheetNo++) { + worksheets.get(sheetNo).getCells().deleteBlankColumns(); + } + + wb.save(filename); + } + + public static void addOneColumn(String excelFilename, String cellName, String columnValue, String key, int sheetNo) + throws Exception { + Workbook wb = new Workbook(excelFilename); + + Worksheet ws = wb.getWorksheets().get(0); + ws.getCells().insertColumn(0); + + String theName = "A2"; + int startRow = 2; + + Cell cell = getCell(new File(excelFilename), sheetNo, key); + if (cell != null) { + int row = cell.getRow() + 1; + theName = "A" + row; + startRow = row; + } + + int maxRow = ws.getCells().getMaxRow(); + + ws.getCells().get(theName).setValue(cellName); + + for (int i = startRow; i <= maxRow; i++) { + ws.getCells().get(i, 0).setValue(columnValue); + } + + wb.save(excelFilename); + } + + public static int getSheetNo(String filename, String key) { + + Workbook wb = null; + try { + wb = new Workbook(filename); + + for (int sheetNo = 0; sheetNo < wb.getWorksheets().getCount(); sheetNo++) { + Cell cell = getCell(new File(filename), sheetNo, key); + if (cell != null) { + return sheetNo; + } + } + } catch (Exception e) { + // + } + + return -1; + } + + + public static String getCellValue(String filename, int sheetNo, String cellName) { + + try { + Workbook wb = new Workbook(filename); + Cells cells = wb.getWorksheets().get(sheetNo).getCells(); + Cell cell = cells.get(cellName); + + return cell == null ? null : cell.getStringValue(); + } catch (Exception e) { + // + } + + return null; + } + + public static Cell getCell(String filename, String key) { + + try { + Workbook wb = new Workbook(filename); + + for (int sheetNo = 0; sheetNo < wb.getWorksheets().getCount(); sheetNo++) { + Cell cell = getCell(new File(filename), sheetNo, key); + if (cell != null) { + return cell; + } + } + } catch (Exception e) { + // + } + + return null; + } + + public static Cell getCell(File excelFile, String key) { + + try { + Workbook wb = new Workbook(excelFile.getAbsolutePath()); + + for (int sheetNo = 0; sheetNo < wb.getWorksheets().getCount(); sheetNo++) { + Cell cell = getCell(excelFile, sheetNo, key); + if (cell != null) { + return cell; + } + } + } catch (Exception e) { + // + } + + return null; + } + + /** + * 判断指定Excel文件中是否包含指定的关键字 + * @param excelFile 指定的Excel文件 + * @param key 关键字 + * @return 返回结果 + * @throws IllegalArgumentException 如果参数不正确,则抛出异常 + */ + public static boolean isWorkbookContainsKey(File excelFile, String key) { + + if (excelFile == null || !excelFile.exists()) { + throw new IllegalArgumentException("The excel file must not be null and must exist."); + } + + try { + Workbook wb = new Workbook(excelFile.getAbsolutePath()); + + for (int sheetNo = 0; sheetNo < wb.getWorksheets().getCount(); sheetNo++) { + Cell cell = getCell(excelFile, sheetNo, key); + if (cell != null) { + return true; + } + } + + return false; + } catch (Exception e) { + return false; + } + } + + public static Cell getCell(Cells cells, String key) { + try { + return cells.find(key, null); + } catch (Exception e) { + return null; + } + } + + public static Cell getCell(File excelFile, int sheetNo, String key) { + try { + Workbook wb = new Workbook(excelFile.getAbsolutePath()); + Cells cells = wb.getWorksheets().get(sheetNo).getCells(); + + return cells.find(key, null); + } catch (Exception e) { + return null; + } + } + + public static Cell getCell(File excelFile, int sheetNo, String key, int startRow) { + try { + Workbook wb = new Workbook(excelFile.getAbsolutePath()); + Cells cells = wb.getWorksheets().get(sheetNo).getCells(); + + return getCell(cells, key, startRow); + } catch (Exception e) { + return null; + } + } + + public static int getRowNumber(File excelFile, int sheetNo, String key, int startRow) { + try { + Workbook wb = new Workbook(excelFile.getAbsolutePath()); + Cells cells = wb.getWorksheets().get(sheetNo).getCells(); + + return getHeadRowNumber(cells, key, startRow); + } catch (Exception e) { + return -1; + } + } + + public static int getRowNumber(File excelFile, int sheetNo, String key) { + try { + Workbook wb = new Workbook(excelFile.getAbsolutePath()); + Cells cells = wb.getWorksheets().get(sheetNo).getCells(); + + return getHeadRowNumber(cells, key); + } catch (Exception e) { + return -1; + } + } + + public static Cell getCell(Cells cells, String key, int startRow) { + Cell cell = cells.get(startRow, 0); + if (cell != null) { + String cellValue = cell.getStringValue().trim(); + if (cellValue.equals(key)) { + return cell; + } else if (cellValue.contains(key)) { + return cell; + } + } + + return cells.find(key, cells.get(startRow, 0)); + } + + public static int getHeadRowNumber(Cells cells, String key, int startRow) { + Cell cell = cells.find(key, cells.get(startRow, 0)); + if (cell != null) { + return cell.getRow(); + } + + return -1; + } + + public static int getHeadRowNumber(String filename, int sheetNo, String key) { + Cell cell = getCell(new File(filename), sheetNo, key); + if (cell != null) { + return cell.getRow() + 1; + } + + return -1; + } + + public static int getHeadRowNumber(Cells cells, String key) { + Cell cell = cells.find(key, null); + if (cell != null) { + return cell.getRow(); + } + + return -1; + } + + // GBK编码 + public static String csv2ExcelV1(String csvFile) throws Exception { + Workbook wb = new Workbook(csvFile); + Worksheet ws = wb.getWorksheets().get(0); + + ws.autoFitColumns(); + ws.autoFitRows(); + + String saveToExcelFileName = + new File(csvFile).getParent() + File.separator + FileUtil.mainName(csvFile) + ".xlsx"; + wb.save(saveToExcelFileName); + + return saveToExcelFileName; + } + + /** + * CSV格式文件转化为Excel格式 + * + * @return 返回Excel文件名,包括路径 + */ + public static String csv2Excel(String csvFile) throws Exception { + com.aspose.cells.TxtLoadOptions opt = new TxtLoadOptions(); + opt.setEncoding(Encoding.getEncoding(Charset.forName("GBK"))); + + Workbook wb = new Workbook(csvFile, opt); + Worksheet ws = wb.getWorksheets().get(0); + + ws.autoFitColumns(); + ws.autoFitRows(); + + String saveToExcelFileName = + new File(csvFile).getParent() + File.separator + FileUtil.mainName(csvFile) + ".xls"; + wb.save(saveToExcelFileName, new XlsSaveOptions()); + + return saveToExcelFileName; + } + + /** + * 将流水信息提取出来-PDF转Excel,多页 + */ + public static void pdf2ExcelV2(String pdfFileName, String saveToExcelFileName) throws Exception { + try (Document doc = new Document(pdfFileName)) { + PageCollection pages = doc.getPages(); + // Excel工作簿 + com.aspose.cells.Workbook wb = new com.aspose.cells.Workbook(); + wb.getWorksheets().clear(); + // + int gRow = 0; + int gCol = 0; + + for (Page page : pages) { + // 第一页第一个表格 + TableAbsorber absorber = new TableAbsorber(); + absorber.visit(page); + AbsorbedTable table = absorber.getTableList().get(0); + + String sheetName = "流水"; + com.aspose.cells.Worksheet ws = wb.getWorksheets().get(sheetName); + + if (ws == null) { + ws = wb.getWorksheets().add(sheetName); + } + + List rowList = table.getRowList(); + + for (AbsorbedRow rowObj : rowList) { + List cellList = rowObj.getCellList(); + for (AbsorbedCell absorbedCell : cellList) { + TextFragmentCollection textFragments = absorbedCell.getTextFragments(); + + StringBuilder sb = new StringBuilder(); + // 读取文字 + for (TextFragment textFragment : textFragments) { + String text = textFragment.getText(); + sb.append(text); + } + + ws.getCells().get(gRow, gCol).setValue(sb.toString()); + + gCol++; + } + gCol = 0; + gRow++; + } + } + + wb.save(saveToExcelFileName); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static String pdf2ExcelV6(String pdfFileName) { + try (Document doc = new Document(pdfFileName)) { + ExcelSaveOptions options = new ExcelSaveOptions(); + options.setFormat(ExcelSaveOptions.ExcelFormat.XLSX); + + String saveToExcelFilename = + FileUtil.getParent(pdfFileName, 1) + File.separator + FileUtil.mainName(pdfFileName) + ".xlsx"; + + try { + doc.save(saveToExcelFilename, options); + }catch (Exception e){ + return saveToExcelFilename; + } + + + return saveToExcelFilename; + } + } + + public static void removeImages(String pdfFilename) { + try (Document doc = new Document(pdfFilename)) { + for (Page page : doc.getPages()) { + page.getResources().getImages().delete(); + } + + doc.save(); + } + } + + public static String pdf2ExcelV7(String pdfFileName) { + try (Document doc = new Document(pdfFileName)) { + + String saveToExcelFilename = + FileUtil.getParent(pdfFileName, 1) + File.separator + FileUtil.mainName(pdfFileName) + ".xlsx"; + + ExcelSaveOptions opt = new ExcelSaveOptions(); + opt.setFormat(SaveFormat.Excel); + opt.setMinimizeTheNumberOfWorksheets(true); + + doc.save(saveToExcelFilename, opt); + + return saveToExcelFilename; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static String getNextCellValue(String filename, int sheetNo, Cell cell) { + + try { + Workbook wb = new Workbook(filename); + return wb.getWorksheets() + .get(sheetNo) + .getCells() + .get(cell.getRow(), cell.getColumn() + 1) + .getStringValue(); + } catch (Exception e) { + return null; + } + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/util/DesUtil.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/util/DesUtil.java new file mode 100644 index 0000000..5f135af --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/util/DesUtil.java @@ -0,0 +1,135 @@ +package com.inscloudtech.bankStatementAnalysis.util; + +import cn.hutool.crypto.Mode; +import cn.hutool.crypto.Padding; +import cn.hutool.crypto.symmetric.AES; +import com.inscloudtech.common.constant.Constants; +import sun.misc.BASE64Decoder; +import sun.misc.BASE64Encoder; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.security.Key; +import java.security.SecureRandom; + +public class DesUtil { + + + + /*** + * 获取加密的信息 + * @param str + * @return + */ + public static String getEncryptString(String str) { + + String KEY_STR="Inspired5212"; + String CHARSETNAME="UTF-8"; + String ALGORITHM="DES"; + Key key; + try { + //生成DES算法对象 + KeyGenerator generator=KeyGenerator.getInstance(ALGORITHM); + //运用SHA1安全策略 + SecureRandom secureRandom=SecureRandom.getInstance("SHA1PRNG"); + //设置上密钥种子 + secureRandom.setSeed(KEY_STR.getBytes()); + //初始化基于SHA1的算法对象 + generator.init(secureRandom); + //生成密钥对象 + key=generator.generateKey(); + generator=null; + } catch (Exception e) { + throw new RuntimeException(e); + } + //基于BASE64编码,接收byte[]并转换成String + BASE64Encoder encoder = new BASE64Encoder(); + try { + //按utf8编码 + byte[] bytes = str.getBytes(CHARSETNAME); + //获取加密对象 + Cipher cipher = Cipher.getInstance(ALGORITHM); + //初始化密码信息 + cipher.init(Cipher.ENCRYPT_MODE, key); + //加密 + byte[] doFinal = cipher.doFinal(bytes); + //byte[]to encode好的String 并返回 + return encoder.encode(doFinal); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /*** + * + * 解密 + * @param data 要解密的数据 + */ + public static String decrypt(String data) { + AES aes = + new AES( + Mode.CFB, + Padding.NoPadding, + new SecretKeySpec(Constants.AES_SEC_KEY, "AES"), + new IvParameterSpec(Constants.AES_SEC_KEY)); + + return new String(aes.decrypt(data)); + } + + public static String encrypt(String data) { + AES aes = + new AES( + Mode.CFB, + Padding.NoPadding, + new SecretKeySpec(Constants.AES_SEC_KEY, "AES"), + new IvParameterSpec(Constants.AES_SEC_KEY)); + + return aes.encryptBase64(data); + } + + /*** + * 获取解密之后的信息 + * @param str + * @return + */ + public static String getDecryptString(String str) { + String KEY_STR="Inspired5212"; + String CHARSET_NAME="UTF-8"; + String ALGORITHM="DES"; + Key key; + try { + //生成DES算法对象 + KeyGenerator generator=KeyGenerator.getInstance(ALGORITHM); + //运用SHA1安全策略 + SecureRandom secureRandom=SecureRandom.getInstance("SHA1PRNG"); + //设置上密钥种子 + secureRandom.setSeed(KEY_STR.getBytes()); + //初始化基于SHA1的算法对象 + generator.init(secureRandom); + //生成密钥对象 + key=generator.generateKey(); + generator=null; + } catch (Exception e) { + throw new RuntimeException(e); + } + BASE64Decoder decoder = new BASE64Decoder(); + try { + //将字符串decode成byte[] + byte[] bytes = decoder.decodeBuffer(str); + //获取解密对象 + Cipher cipher = Cipher.getInstance(ALGORITHM); + //初始化解密信息 + cipher.init(Cipher.DECRYPT_MODE, key); + //解密 + byte[] doFial = cipher.doFinal(bytes); + + return new String(doFial, CHARSET_NAME); + + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/worker/ImportWorkflowWorker.java b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/worker/ImportWorkflowWorker.java new file mode 100644 index 0000000..72ac103 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/bankStatementAnalysis/worker/ImportWorkflowWorker.java @@ -0,0 +1,65 @@ +package com.inscloudtech.bankStatementAnalysis.worker; + +import com.inscloudtech.datacenter.service.BankService; +import com.jd.platform.async.callback.ICallback; +import com.jd.platform.async.callback.IWorker; +import com.jd.platform.async.worker.WorkResult; +import com.jd.platform.async.wrapper.WorkerWrapper; +import com.inscloudtech.datacenter.domain.dto.ImportResultPromptVO; +import lombok.extern.slf4j.Slf4j; + +import java.io.File; +import java.util.Map; + +@Slf4j +public class ImportWorkflowWorker implements IWorker, ICallback { + private final File file; + private final String bankNo; + private final String caseId; + private final String bankName; + private final ImportResultPromptVO importResult; + + public ImportWorkflowWorker(File file, String bankName, String bankNo, String caseId, ImportResultPromptVO importResult) { + this.file = file; + this.bankName = bankName; + this.bankNo = bankNo; + this.caseId = caseId; + this.importResult = importResult; + } + + @Override + public Exception action(BankService bService, Map map) { + + Exception exception = null; + + try { + bService.analysisFile(file, bankNo, caseId,bankName); + } catch (Exception e) { + exception = e; + } + + return exception; + } + + @Override + public Exception defaultValue() { + // 表示没有异常 + return null; + } + + @Override + public void begin() { + log.info("开始导入[{}]银行流水", bankName); + } + + @Override + public void result(boolean success, BankService param, WorkResult workResult) { + Exception result = workResult.getResult(); + if (result == null) { + log.info("导入[{}]银行流水成功", bankName); + } else { + + log.error("导入[{}]银行流水失败:{}", bankName,result.getMessage(),result); + } + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/SysLawCase.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/SysLawCase.java new file mode 100644 index 0000000..ce4abc1 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/SysLawCase.java @@ -0,0 +1,72 @@ +package com.inscloudtech.caseMange.domain; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.inscloudtech.common.annotation.UpdateValueLog; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * 用户信息表 sys_law_case + */ +@TableName(value ="sys_law_case",autoResultMap = true) +@Data +public class SysLawCase implements Serializable { + /** + * 用户ID + */ + @TableId(type = IdType.ASSIGN_ID) + @ExcelProperty("id") + private String id; + + /** + * 案件名称 + */ + @UpdateValueLog(fieldName = "案件名称") + @ExcelProperty("案件名称") + private String name; + + /** + * 创建者 + */ + @ExcelProperty("创建者") + private String createBy; + + /** + * 创建时间 + */ + @ExcelProperty("创建时间") + private Date createTime; + + /** + * 更新者 + */ + @UpdateValueLog(fieldName = "更新者") + @ExcelProperty("更新者") + private String updateBy; + + /** + * 更新时间 + */ + @ExcelProperty("更新时间") + private Date updateTime; + + /** + * 备注 + */ + @ExcelProperty("备注") + private String remark; + + @TableField(exist = false) + private static final long serialVersionUID = 1L; + +// @ExcelProperty(value = "investigators",converter = ListConverter.class) +// @TableField(typeHandler = JacksonTypeHandler.class) + @TableField(exist = true, value = "investigator_str") + private String investigatorStr; +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/SysLawCaseInvestigator.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/SysLawCaseInvestigator.java new file mode 100644 index 0000000..74f7c79 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/SysLawCaseInvestigator.java @@ -0,0 +1,28 @@ +package com.inscloudtech.caseMange.domain; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; + +/** + * 用户和角色关联表 + * @TableName sys_law_case_investigator + */ +@TableName(value ="sys_law_case_investigator") +@Data +public class SysLawCaseInvestigator implements Serializable { + /** + * 用户ID + */ + private String lawCaseId; + + /** + * 角色ID + */ + private Long investigatorId; + + @TableField(exist = false) + private static final long serialVersionUID = 1L; +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/AddInvestigatorReq.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/AddInvestigatorReq.java new file mode 100644 index 0000000..ec3cf3a --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/AddInvestigatorReq.java @@ -0,0 +1,23 @@ +package com.inscloudtech.caseMange.domain.vo; + + +import lombok.Data; + +//"添加调查人员请求") +@Data +public class AddInvestigatorReq { + //"用户姓名") + private String userName; + + //"身份证号") + private String idCardNo; + + //"角色Id") + private Long roleId; + + //"联系方式") + private String phone; + + //"状态") + private String status = "0"; +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/AddLawCaseReq.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/AddLawCaseReq.java new file mode 100644 index 0000000..5b226c9 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/AddLawCaseReq.java @@ -0,0 +1,16 @@ +package com.inscloudtech.caseMange.domain.vo; + + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +//"添加案件请求") +@Data +public class AddLawCaseReq { + //"案件名称") + private String name; + //"案件调查人员") + private List investigators = new ArrayList<>(); +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/DeleteInvestigatorReq.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/DeleteInvestigatorReq.java new file mode 100644 index 0000000..0bb4018 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/DeleteInvestigatorReq.java @@ -0,0 +1,8 @@ +package com.inscloudtech.caseMange.domain.vo; + +import lombok.Data; + +@Data +public class DeleteInvestigatorReq { + private Long id; +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/EditInvestigatorReq.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/EditInvestigatorReq.java new file mode 100644 index 0000000..bde0840 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/EditInvestigatorReq.java @@ -0,0 +1,25 @@ +package com.inscloudtech.caseMange.domain.vo; + + +import lombok.Data; + +//"编辑调查人员信息请求封装") +@Data +public class EditInvestigatorReq { + //value = "用户编号", required = true) + private Long userId; + + //value = "用户姓名", required = false) + private String userName; + + //value = "身份证号", required = false) + private String idCardNo; + + private String roleId; + + //value = "联系方式", required = false) + private String phone; + + //value = "状态", required = false) + private String status; +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/EditLawCaseReq.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/EditLawCaseReq.java new file mode 100644 index 0000000..6955b9e --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/EditLawCaseReq.java @@ -0,0 +1,20 @@ +package com.inscloudtech.caseMange.domain.vo; + + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +//"编辑案件请求") +@Data +public class EditLawCaseReq { + //"案件Id") + private String id; + + //"案件名称") + private String name; + + //"案件调查人员") + private List investigators = new ArrayList<>(); +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/GetInvestigatorDetailReq.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/GetInvestigatorDetailReq.java new file mode 100644 index 0000000..4f6b73e --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/GetInvestigatorDetailReq.java @@ -0,0 +1,11 @@ +package com.inscloudtech.caseMange.domain.vo; + +import lombok.Data; + +@Data +public class GetInvestigatorDetailReq { + private int pageNum; + private int pageSize; + /** 调查人员Id */ + private String userId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/GetInvestigatorListReq.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/GetInvestigatorListReq.java new file mode 100644 index 0000000..6116b71 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/GetInvestigatorListReq.java @@ -0,0 +1,54 @@ +package com.inscloudtech.caseMange.domain.vo; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.fasterxml.jackson.annotation.JsonIgnore; + +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; + +import java.util.ArrayList; +import java.util.List; + +//"获取调查人员列表请求") +@Data +public class GetInvestigatorListReq { + //"当前页") + private int pageNum; + + //"页数") + private int pageSize; + + /** 用户名称 */ + //"用户姓名") + private String userName; + + /** 所属角色 */ + //"角色名称") + private String roleName; + + /** 状态 */ + //"状态") + private String status; + + /** 联系方式 */ + //"联系方式") + private String phone; + + //"身份证号") + private String idCardNo; + + /** + * 排序 + * + *

sort: { idCardNo: 'desc', name: 'asc' }, + */ + //"排序") + private Object sort; + + private List userIds = new ArrayList<>(); + + @JsonIgnore + @TableField(exist = false) + @IndexField(exist = false) + private Integer downloadTemplate; +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/GetLawCaseListResult.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/GetLawCaseListResult.java new file mode 100644 index 0000000..4e81dca --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/GetLawCaseListResult.java @@ -0,0 +1,13 @@ +package com.inscloudtech.caseMange.domain.vo; + +import lombok.Data; + +@Data +public class GetLawCaseListResult { + private long current; + private long pages; + private long size; + private long total; + + private Object records; +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/GetLoginRecordFieldValueCountReq.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/GetLoginRecordFieldValueCountReq.java new file mode 100644 index 0000000..f3339a9 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/GetLoginRecordFieldValueCountReq.java @@ -0,0 +1,37 @@ +package com.inscloudtech.caseMange.domain.vo; + +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +@Data +public class GetLoginRecordFieldValueCountReq { + @NotNull(message = "[分组字段]不能为空") + private List fields; + /** + * 没用 + */ + @NotNull(message = "[业务模块]不能为空") + private String module = "LOGIN_RECORD"; + + // 查询条件 + @NotNull(message = "[案件id]不能为空") + private String caseId; + + private String userId; + private String userName; + private String idCardNo; + private String permissionType; + + private String beginLoginDate; + private String endLoginDate; + + private Params params = new Params(); + + @Data + public static class Params { + private String beginLoginDate; + private String endLoginDate; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/GetPersonReq.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/GetPersonReq.java new file mode 100644 index 0000000..c208b94 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/GetPersonReq.java @@ -0,0 +1,8 @@ +package com.inscloudtech.caseMange.domain.vo; + +import lombok.Data; + +@Data +public class GetPersonReq { + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/Investigator.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/Investigator.java new file mode 100644 index 0000000..3b491c5 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/Investigator.java @@ -0,0 +1,25 @@ +package com.inscloudtech.caseMange.domain.vo; + +import lombok.Data; + +@Deprecated +@Data +public class Investigator { + /** 用户Id */ + private Long id; + + /** 用户名称 */ + private String userName; + + /** 身份证号 */ + private String idCardNo; + + /** 所属角色 */ + private String roleName; + + /** 联系方式 */ + private String phone; + + /** 状态 */ + private String status; +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/LawCaseListReq.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/LawCaseListReq.java new file mode 100644 index 0000000..80d6cd3 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/LawCaseListReq.java @@ -0,0 +1,51 @@ +package com.inscloudtech.caseMange.domain.vo; + + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +//"获取案件列表请求") +@Data +public class LawCaseListReq { + //"当前页") + private int pageNum = 1; + + //"每页条数") + private int pageSize = 10; + + //"案件名称") + private String name; + + //"开始时间") + private String beginTime; + + //"结束时间") + private String endTime; + + // 创建时间 + @Deprecated private List createTime = new ArrayList<>(); + + //"调查人员") + private String investigatorName; + + //"调查人员Id") + private String userId; + + // 排序 + // des ase + //"排序") + private Object sort; + + private ParamItem params = new ParamItem(); + + private String beginCreateTime; + private String endCreateTime; + + @Data + public static class ParamItem { + private String beginCreateTime; + private String endCreateTime; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/LawCaseResp.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/LawCaseResp.java new file mode 100644 index 0000000..01b24f7 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/LawCaseResp.java @@ -0,0 +1,37 @@ +package com.inscloudtech.caseMange.domain.vo; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +@Data +public class LawCaseResp { + /** + * 用户ID + */ + private String id; + + /** + * 用户账号 + */ + private String name; + + /** + * 创建时间 + */ + private Date createTime; + + private String remark; + + private String investigators; + + private List ids = new ArrayList<>(); + + @Data + public static class InvestigatorSimpleVO { + private Long id; + private String name; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/LeaderTransferReq.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/LeaderTransferReq.java new file mode 100644 index 0000000..b016c31 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/LeaderTransferReq.java @@ -0,0 +1,13 @@ +package com.inscloudtech.caseMange.domain.vo; + + +import lombok.Data; + +//"领导权限转移请求") +@Data +public class LeaderTransferReq { + //"姓名") + private String name; + //"身份证号") + private String idCardNo; +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/MInvestigator.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/MInvestigator.java new file mode 100644 index 0000000..6cbbef3 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/MInvestigator.java @@ -0,0 +1,52 @@ +package com.inscloudtech.caseMange.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * 用户对象 sys_user + * + * @author ruoyi + */ +@Data +@ExcelIgnoreUnannotated +public class MInvestigator implements Serializable { + + /** + * 用户ID + */ +// @ExcelProperty("用户序号", cellType = ColumnType.NUMERIC, prompt = "用户编号") + private Long id; + + /** + * 用户账号 + */ + @ExcelProperty("用户姓名") + private String userName; + + /** + * 手机号码 + */ + @ExcelProperty("联系方式") + private String phone; + + /** + * 身份证号 + */ + @ExcelProperty("身份证号") + private String idCardNo; + + /** + * 帐号状态(0正常 1停用) + */ +// @ExcelProperty("帐号状态", readConverterExp = "0=正常,1=停用") + private String status; +// @ExcelProperty("角色名称") + private String roleName; + private String operRecords; + private Date createTime; +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/MetaVo.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/MetaVo.java new file mode 100644 index 0000000..1efac84 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/MetaVo.java @@ -0,0 +1,91 @@ +package com.inscloudtech.caseMange.domain.vo; + +import com.inscloudtech.common.utils.StringUtils; + +/** + * 路由显示信息 + * + * @author ruoyi + */ +public class MetaVo { + /** + * 设置该路由在侧边栏和面包屑中展示的名字 + */ + private String title; + + /** + * 设置该路由的图标,对应路径src/assets/icons/svg + */ + private String icon; + + /** + * 设置为true,则不会被 缓存 + */ + private boolean noCache; + + /** + * 内链地址(http(s)://开头) + */ + private String link; + + public MetaVo() { + } + + public MetaVo(String title, String icon) { + this.title = title; + this.icon = icon; + } + + public MetaVo(String title, String icon, boolean noCache) { + this.title = title; + this.icon = icon; + this.noCache = noCache; + } + + public MetaVo(String title, String icon, String link) { + this.title = title; + this.icon = icon; + this.link = link; + } + + public MetaVo(String title, String icon, boolean noCache, String link) { + this.title = title; + this.icon = icon; + this.noCache = noCache; + if (StringUtils.ishttp(link)) { + this.link = link; + } + } + + public boolean isNoCache() { + return noCache; + } + + public void setNoCache(boolean noCache) { + this.noCache = noCache; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } + + public String getLink() { + return link; + } + + public void setLink(String link) { + this.link = link; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/QueryOperateLogReq.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/QueryOperateLogReq.java new file mode 100644 index 0000000..03ba760 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/QueryOperateLogReq.java @@ -0,0 +1,24 @@ +package com.inscloudtech.caseMange.domain.vo; + +import lombok.Data; + +@Data +public class QueryOperateLogReq { + private int pageNum; + private int pageSize; + private String userName; + private String idCardNo; + private String beginTime; + private String endTime; + private Object sort; + private String permissionType; + + private Params params; + + @Data + public static class Params { + private String beginLoginDate; + private String endLoginDate; + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/QueryOperateLogResp.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/QueryOperateLogResp.java new file mode 100644 index 0000000..aabbda9 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/QueryOperateLogResp.java @@ -0,0 +1,51 @@ +package com.inscloudtech.caseMange.domain.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +@Data +public class QueryOperateLogResp { + private Long userId; + private String userName; + private String idCardNo; + /** + * 登录时间 + */ + private Date loginDate; + /** + * 权限类别 + */ + private String permissionType; + + private List operates; + + @Data + public static class OperateRecord { + /** + * 操作模块 + */ + private String title; + /** + * 操作类别 + */ + //0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据 + private Long businessType; + /** + * 操作人员 + */ + private String operName; + /** + * 操作状态 + */ + private Integer status; + + /** + * 操作日期 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private String operTime; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/RevokeItem.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/RevokeItem.java new file mode 100644 index 0000000..08a157b --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/RevokeItem.java @@ -0,0 +1,9 @@ +package com.inscloudtech.caseMange.domain.vo; + +import lombok.Data; + +@Data +public class RevokeItem { + private String id; + private String bgColor; +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/RouterVo.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/RouterVo.java new file mode 100644 index 0000000..49d5ae4 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/RouterVo.java @@ -0,0 +1,130 @@ +package com.inscloudtech.caseMange.domain.vo; + +import com.fasterxml.jackson.annotation.JsonInclude; + +import java.util.List; + +/** + * 路由配置信息 + * + * @author ruoyi + */ +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public class RouterVo { + /** + * 路由名字 + */ + private String name; + + /** + * 路由地址 + */ + private String path; + + /** + * 是否隐藏路由,当设置 true 的时候该路由不会再侧边栏出现 + */ + private boolean hidden; + + /** + * 重定向地址,当设置 noRedirect 的时候该路由在面包屑导航中不可被点击 + */ + private String redirect; + + /** + * 组件地址 + */ + private String component; + + /** + * 路由参数:如 {"id": 1, "name": "ry"} + */ + private String query; + + /** + * 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面 + */ + private Boolean alwaysShow; + + /** + * 其他元素 + */ + private MetaVo meta; + + /** + * 子路由 + */ + private List children; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public boolean getHidden() { + return hidden; + } + + public void setHidden(boolean hidden) { + this.hidden = hidden; + } + + public String getRedirect() { + return redirect; + } + + public void setRedirect(String redirect) { + this.redirect = redirect; + } + + public String getComponent() { + return component; + } + + public void setComponent(String component) { + this.component = component; + } + + public String getQuery() { + return query; + } + + public void setQuery(String query) { + this.query = query; + } + + public Boolean getAlwaysShow() { + return alwaysShow; + } + + public void setAlwaysShow(Boolean alwaysShow) { + this.alwaysShow = alwaysShow; + } + + public MetaVo getMeta() { + return meta; + } + + public void setMeta(MetaVo meta) { + this.meta = meta; + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/SysOperUpdateLogVo.java b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/SysOperUpdateLogVo.java new file mode 100644 index 0000000..f59eca3 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/domain/vo/SysOperUpdateLogVo.java @@ -0,0 +1,135 @@ +package com.inscloudtech.caseMange.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +import java.util.Date; + + +/** + * 操作日志记录视图对象 sys_oper_update_log + * + * @author inscloudtech + * @date 2023-05-18 + */ +@Data +@ExcelIgnoreUnannotated +public class SysOperUpdateLogVo { + + private static final long serialVersionUID = 1L; + + /** + * 日志主键 + */ + @ExcelProperty(value = "日志主键") + private Long operId; + + /** + * 分类名称 + */ + @ExcelProperty(value = "分类名称") + private String title; + + /** + * 分类编码 + */ + @ExcelProperty(value = "分类编码") + private Long categoryCode; + + /** + * 方法名称 + */ + @ExcelProperty(value = "方法名称") + private String method; + + /** + * 请求方式 + */ + @ExcelProperty(value = "请求方式") + private String requestMethod; + + /** + * 操作类别(0其它 1后台用户 2手机端用户) + */ + private Long operatorType; + + /** + * 操作人员 + */ + @ExcelProperty(value = "操作人员") + private String operName; + + /** + * 部门名称 + */ + @ExcelProperty(value = "部门名称") + private String deptName; + + /** + * 请求URL + */ + @ExcelProperty(value = "请求URL") + private String operUrl; + + /** + * 主机地址 + */ + @ExcelProperty(value = "主机地址") + private String operIp; + + /** + * 操作地点 + */ + @ExcelProperty(value = "操作地点") + private String operLocation; + + /** + * 请求参数 + */ + @ExcelProperty(value = "请求参数") + private String operParam; + + /** + * 返回参数 + */ + @ExcelProperty(value = "返回参数") + private String jsonResult; + + /** + * 操作状态(0正常 1异常) + */ + private Long status; + + /** + * 错误消息 + */ + @ExcelProperty(value = "错误消息") + private String errorMsg; + + /** + * 操作时间 + */ + @ExcelProperty(value = "操作时间") + private Date operTime; + + /** + * 更新前数据 + */ + @ExcelProperty(value = "更新前数据") + private String beforeValue; + + /** + * 更新后数据 + */ + @ExcelProperty(value = "更新后数据") + private String afterValue; + + /** + * 业务主键 + */ + @ExcelProperty(value = "业务主键") + private Long businessId; + + +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/mapper/SysLawCaseInvestigatorMapper.java b/cas-system/src/main/java/com/inscloudtech/caseMange/mapper/SysLawCaseInvestigatorMapper.java new file mode 100644 index 0000000..6b112c1 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/mapper/SysLawCaseInvestigatorMapper.java @@ -0,0 +1,20 @@ +package com.inscloudtech.caseMange.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.inscloudtech.caseMange.domain.SysLawCaseInvestigator; +import org.apache.ibatis.annotations.Mapper; + +/** +* @author Administrator +* @description 针对表【sys_law_case_investigator(用户和角色关联表)】的数据库操作Mapper +* @createDate 2023-10-13 09:49:02 +* @Entity com.inscloudtech.system.domain.SysLawCaseInvestigator +*/ +@Mapper +public interface SysLawCaseInvestigatorMapper extends BaseMapper { + +} + + + + diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/mapper/SysLawCaseMapper.java b/cas-system/src/main/java/com/inscloudtech/caseMange/mapper/SysLawCaseMapper.java new file mode 100644 index 0000000..379855b --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/mapper/SysLawCaseMapper.java @@ -0,0 +1,10 @@ +package com.inscloudtech.caseMange.mapper; + +import com.inscloudtech.caseMange.domain.SysLawCase; +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SysLawCaseMapper extends BaseMapperPlus { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/service/IInvestigatorTaskService.java b/cas-system/src/main/java/com/inscloudtech/caseMange/service/IInvestigatorTaskService.java new file mode 100644 index 0000000..4275755 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/service/IInvestigatorTaskService.java @@ -0,0 +1,23 @@ +package com.inscloudtech.caseMange.service; + + +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.caseMange.domain.vo.LawCaseListReq; +import com.inscloudtech.caseMange.domain.vo.LawCaseResp; + +public interface IInvestigatorTaskService { + /** + * 获取案件列表 + * + * @param req 请求参数 + */ + TableDataInfo getLawCaseList(LawCaseListReq req); + + /** + * 添加备注 + * + * @param caseId 案件Id + * @param remark 备注 + */ + void addRemark(String caseId, String remark); +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/service/ILeaderTaskService.java b/cas-system/src/main/java/com/inscloudtech/caseMange/service/ILeaderTaskService.java new file mode 100644 index 0000000..edbdfe1 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/service/ILeaderTaskService.java @@ -0,0 +1,54 @@ +package com.inscloudtech.caseMange.service; + +import com.inscloudtech.common.core.domain.entity.SysUser; +import com.inscloudtech.caseMange.domain.vo.AddInvestigatorReq; +import com.inscloudtech.caseMange.domain.vo.EditInvestigatorReq; +import com.inscloudtech.caseMange.domain.vo.EditLawCaseReq; +import com.inscloudtech.caseMange.domain.vo.MInvestigator; + +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.util.List; + +public interface ILeaderTaskService { + + /** 领导权限转移 */ + void transform(String idCardNo, String name); + + /** + * 删除调查人员 + * + * @param id 要删除的调查人员Id + */ + void deleteInvestigator(Long id); + + /** 修改调查人员信息 */ + void editInvestigator(EditInvestigatorReq req); + + /** 添加调查人员 */ + void addInvestigator(AddInvestigatorReq req); + + /** 导入调查人员信息 */ + String importInvestigator(List users, boolean updateSupport); + + /** + * 到处调查人员信息 + * + * @param userIds 需要导出的调查人员Id + * @return + */ + void exportInvestigator(List userIds, HttpServletResponse response); + + /** 不分页获取所有调查人员信息 */ + List getInvestigatorsForAddLawCase(); + + /** 案件编辑 */ + void editLawCase(EditLawCaseReq req); + + /** + * 案件删除 + * + * @param id 案件Id + */ + void deleteLawCase(String id); +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/service/ISysLawCaseInvestigatorService.java b/cas-system/src/main/java/com/inscloudtech/caseMange/service/ISysLawCaseInvestigatorService.java new file mode 100644 index 0000000..c839ab0 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/service/ISysLawCaseInvestigatorService.java @@ -0,0 +1,14 @@ +package com.inscloudtech.caseMange.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.inscloudtech.caseMange.domain.SysLawCaseInvestigator; + + +/** +* @author Administrator +* @description 针对表【sys_law_case_investigator(用户和角色关联表)】的数据库操作Service +* @createDate 2023-10-13 09:49:02 +*/ +public interface ISysLawCaseInvestigatorService extends IService { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/service/ISysLawCaseService.java b/cas-system/src/main/java/com/inscloudtech/caseMange/service/ISysLawCaseService.java new file mode 100644 index 0000000..011f454 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/service/ISysLawCaseService.java @@ -0,0 +1,22 @@ +package com.inscloudtech.caseMange.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.inscloudtech.caseMange.domain.SysLawCase; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.caseMange.domain.vo.AddLawCaseReq; +import com.inscloudtech.caseMange.domain.vo.LawCaseListReq; + + +public interface ISysLawCaseService extends IService { + /** + * 获取所有案列列表 + * + * @param req 请求 + * @return 查询结果(分页) + */ + TableDataInfo getLawCaseList(LawCaseListReq req); + + void insert(SysLawCase sysLawCase); + + void addLawCase(AddLawCaseReq req); +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/service/impl/InvestigatorTaskService.java b/cas-system/src/main/java/com/inscloudtech/caseMange/service/impl/InvestigatorTaskService.java new file mode 100644 index 0000000..976d5df --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/service/impl/InvestigatorTaskService.java @@ -0,0 +1,307 @@ +package com.inscloudtech.caseMange.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.inscloudtech.common.core.domain.entity.SysUser; + + +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.caseMange.domain.SysLawCaseInvestigator; +import com.inscloudtech.caseMange.domain.vo.LawCaseListReq; +import com.inscloudtech.caseMange.domain.vo.LawCaseResp; +import com.inscloudtech.caseMange.mapper.SysLawCaseInvestigatorMapper; +import com.inscloudtech.caseMange.mapper.SysLawCaseMapper; +import com.inscloudtech.caseMange.service.IInvestigatorTaskService; +import com.inscloudtech.system.domain.SysUserRole; +import com.inscloudtech.caseMange.domain.SysLawCase; + +import com.inscloudtech.system.mapper.SysUserMapper; +import com.inscloudtech.system.mapper.SysUserRoleMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +@Service +public class InvestigatorTaskService implements IInvestigatorTaskService { + + private final SysLawCaseMapper lawCaseMapper; + private final SysUserMapper userMapper; + private final SysUserRoleMapper userRoleMapper; + private final SysLawCaseInvestigatorMapper lawCaseInvestigatorMapper; + + @Transactional + @Override + public void addRemark(String caseId, String remark) { + + if (StringUtils.isEmpty(caseId)) { + throw new RuntimeException("案件Id为null"); + } + + Long id = Long.parseLong(caseId); + + SysLawCase sysLawCase = lawCaseMapper.selectById(id); + if (sysLawCase == null) { + throw new RuntimeException("案件 [" + id + "]不存在."); + } + + String oldRemark = sysLawCase.getRemark(); + // 覆盖备注 + sysLawCase.setRemark(remark); + + lawCaseMapper.updateById(sysLawCase); + } + + @Override + public TableDataInfo getLawCaseList(LawCaseListReq req) { + + Long currentUserId = LoginHelper.getUserId(); + if (currentUserId == null) { + throw new RuntimeException("用户没有登录."); + } + + // 查询当前用户的角色 + List userRoleList = userRoleMapper.selectList( + Wrappers.lambdaQuery(SysUserRole.class).eq(SysUserRole::getUserId, currentUserId)); + List roleList = userRoleList.stream().map(SysUserRole::getRoleId).collect(Collectors.toList()); + if (CollectionUtil.isEmpty(roleList)) { + throw new RuntimeException("当前用户没有角色."); + } + + if (roleList.contains(1L)) { + return this.getLawCaseListForAdmin(req); + } else { + req.setUserId(currentUserId.toString()); + return this.getLawCaseListForInvestigator(req); + } + } + + private TableDataInfo getLawCaseListForInvestigator(LawCaseListReq req) { + int pageNum = req.getPageNum(); + int pageSize = req.getPageSize(); + + // 查询当前用户的案件 + List lawCaseIdList = getCurrentUserLawCase(); + if (CollectionUtil.isNotEmpty(lawCaseIdList)) { + QueryWrapper lawCaseQueryWrapper = Wrappers.query(); + // 调查人员名称 + List caseIdList = new ArrayList<>(); + if (StrUtil.isNotEmpty(req.getInvestigatorName())) { + SysUser investigator = userMapper.selectUserByUserName(req.getInvestigatorName()); + caseIdList = getLawCaseIdByUserId(investigator.getUserId()); + } + + if (CollectionUtil.isNotEmpty(caseIdList)) { + lawCaseQueryWrapper.in("id", CollectionUtil.union(lawCaseIdList, caseIdList)); + }else { + lawCaseQueryWrapper.in("id", lawCaseIdList); + } + + //案件名称 + if (StrUtil.isNotEmpty(req.getName())) { + lawCaseQueryWrapper.like("name", req.getName()); + } + + //创建时间 + if (req.getParams().getBeginCreateTime()!= null && req.getParams().getEndCreateTime()!= null) { + lawCaseQueryWrapper.between("create_time", req.getParams().getBeginCreateTime(), req.getParams().getEndCreateTime()); + } + + //排序 + + int start = (pageNum - 1) * pageSize; + lawCaseQueryWrapper.last(" limit " + start + "," + start + pageSize); + // 满足日期和排序的所有案件 + List sysLawCases = lawCaseMapper.selectList(lawCaseQueryWrapper); + if (sysLawCases.isEmpty()) { + return new TableDataInfo<>(); + } + + List rstRecord = new ArrayList<>(); + for (SysLawCase lawCase : sysLawCases) { + LawCaseResp resp = new LawCaseResp(); + + String caseId = lawCase.getId(); + + resp.setId(caseId); + resp.setName(lawCase.getName()); + resp.setCreateTime(lawCase.getCreateTime()); + resp.setRemark(lawCase.getRemark()); + String investigators = lawCase.getInvestigatorStr(); + if (StrUtil.isNotEmpty(investigators)) { + List idNoList; + if (investigators.contains(",")) { + idNoList = Arrays.asList(investigators.split(",")); + } else { + idNoList = Collections.singletonList(investigators); + } + if (CollectionUtil.isNotEmpty(idNoList)) { + LambdaQueryWrapper userLqw = Wrappers.lambdaQuery(); + userLqw.in(SysUser::getIdCardNo, idNoList); + List sysUsers = userMapper.selectList(userLqw); + // 根据案件Id,查询关联的调查人员 + List investigatorNames = new ArrayList<>(); + List investigatorIds = new ArrayList<>(); + for (SysUser user : sysUsers) { + investigatorNames.add(user.getUserName()); + investigatorIds.add(user.getUserId()); + } + resp.setInvestigators(String.join("、", investigatorNames)); + resp.setIds(investigatorIds); + } + } + + // 添加 + rstRecord.add(resp); + } + TableDataInfo tableDataInfo = new TableDataInfo(); + tableDataInfo.setTotal(sysLawCases.size()); + tableDataInfo.setRows(rstRecord); + return tableDataInfo; + } + + return new TableDataInfo<>(); + } + + private List getCurrentUserLawCase() { + return getLawCaseIdByUserId(LoginHelper.getUserId()); + } + + private List getLawCaseIdByUserId(Long userId) { + List lawCaseInvestigatorList = + lawCaseInvestigatorMapper.selectList(Wrappers.lambdaQuery(SysLawCaseInvestigator.class) + .eq(SysLawCaseInvestigator::getInvestigatorId, userId)); + + return lawCaseInvestigatorList.stream() + .map(SysLawCaseInvestigator::getLawCaseId) + .collect(Collectors.toList()); + } + + private TableDataInfo getLawCaseListForAdmin(LawCaseListReq req) { + + int pageNum = req.getPageNum(); + if (pageNum <= 0) { + pageNum = 1; + } + + int pageSize = req.getPageSize(); + if (pageSize <= 0) { + pageSize = 10; + } + + QueryWrapper lawCaseQueryWrapper = Wrappers.query(); + + String beginTimeStr = req.getBeginTime(); + String endTimeStr = req.getEndTime(); + + if (StrUtil.isNotEmpty(beginTimeStr)) { + DateTime beginTime = DateUtil.parse(beginTimeStr); + + if (StrUtil.isNotEmpty(endTimeStr)) { + DateTime endTime = DateUtil.parse(endTimeStr); + endTime = DateUtil.endOfDay(endTime); + + lawCaseQueryWrapper.between("create_time", beginTime, endTime); + } else { + lawCaseQueryWrapper.gt("create_time", beginTime); + } + } else { + if (StrUtil.isNotEmpty(endTimeStr)) { + DateTime endTime = DateUtil.parse(endTimeStr); + endTime = DateUtil.endOfDay(endTime); + + lawCaseQueryWrapper.le("create_time", endTime); + } + } + + String lawCaseName = req.getName(); + if (StrUtil.isNotEmpty(lawCaseName)) { + lawCaseQueryWrapper.like("name", lawCaseName); + } + + + int start = (pageNum - 1) * pageSize; + lawCaseQueryWrapper.last(" limit " + start + "," + start + pageSize); + // 满足日期和排序的所有案件 + List sysLawCases = lawCaseMapper.selectList(lawCaseQueryWrapper); + if (sysLawCases.isEmpty()) { + return new TableDataInfo<>(); + } + // 办案人员 + // 查询办案人员,同时要满足登录用户也是同一个案件的办案人员 + String searchName = req.getInvestigatorName(); + if (StrUtil.isNotEmpty(searchName)) { + // 根据调查人员姓名去获取userId,然后再去获取案件Id + QueryWrapper userQueryWrapper = Wrappers.query(); + userQueryWrapper.like("user_name", searchName); + // 不存在同名调查员 + List users = userMapper.selectList(userQueryWrapper); + if (users == null || users.isEmpty()) { + throw new RuntimeException("调查人员姓名【" + searchName + "】错误,没有对应的用户"); + } + + SysUser user = users.get(0); + String idCardNo = user.getIdCardNo(); + + sysLawCases = sysLawCases.stream() + .filter(sysLawCase -> sysLawCase.getInvestigatorStr().contains(idCardNo)) + .collect(Collectors.toList()); + } + + List rstRecord = new ArrayList<>(); + for (SysLawCase lawCase : sysLawCases) { + LawCaseResp resp = new LawCaseResp(); + + String caseId = lawCase.getId(); + + resp.setId(caseId); + resp.setName(lawCase.getName()); + resp.setCreateTime(lawCase.getCreateTime()); + resp.setRemark(lawCase.getRemark()); + String investigators = lawCase.getInvestigatorStr(); + if (StrUtil.isNotEmpty(investigators)) { + List idNoList; + if (investigators.contains(",")) { + idNoList = Arrays.asList(investigators.split(",")); + } else { + idNoList = Arrays.asList(investigators); + } + if (CollectionUtil.isNotEmpty(idNoList)) { + LambdaQueryWrapper userLqw = Wrappers.lambdaQuery(); + userLqw.in(SysUser::getIdCardNo, idNoList); + List sysUsers = userMapper.selectList(userLqw); + // 根据案件Id,查询关联的调查人员 + List investigatorNames = new ArrayList<>(); + List investigatorIds = new ArrayList<>(); + for (SysUser user : sysUsers) { + investigatorNames.add(user.getUserName()); + investigatorIds.add(user.getUserId()); + } + resp.setInvestigators(String.join("、", investigatorNames)); + resp.setIds(investigatorIds); + } + } + + // 添加 + rstRecord.add(resp); + } + TableDataInfo tableDataInfo = new TableDataInfo(); + tableDataInfo.setTotal(sysLawCases.size()); + tableDataInfo.setRows(rstRecord); + return tableDataInfo; + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/service/impl/LeaderTaskService.java b/cas-system/src/main/java/com/inscloudtech/caseMange/service/impl/LeaderTaskService.java new file mode 100644 index 0000000..cc540b2 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/service/impl/LeaderTaskService.java @@ -0,0 +1,583 @@ +package com.inscloudtech.caseMange.service.impl; + +import cn.dev33.satoken.secure.BCrypt; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.inscloudtech.analysiscenter.domain.AnalysisReport; +import com.inscloudtech.bankStatementAnalysis.util.DesUtil; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.core.domain.entity.SysDictData; +import com.inscloudtech.common.core.domain.entity.SysUser; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.exception.ServiceException; + +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.poi.ExcelUtil; +import com.inscloudtech.datacenter.domain.dto.QueryCenterQuery; +import com.inscloudtech.datacenter.service.IndexInitService; +import com.inscloudtech.datacenter.service.QueryCenterService; +import com.inscloudtech.caseMange.domain.SysLawCase; +import com.inscloudtech.caseMange.domain.SysLawCaseInvestigator; +import com.inscloudtech.caseMange.domain.vo.*; +import com.inscloudtech.caseMange.mapper.SysLawCaseMapper; +import com.inscloudtech.caseMange.service.ILeaderTaskService; +import com.inscloudtech.caseMange.service.ISysLawCaseInvestigatorService; +import com.inscloudtech.system.domain.SysUserRole; +import com.inscloudtech.system.mapper.SysUserMapper; +import com.inscloudtech.system.mapper.SysUserRoleMapper; +import com.inscloudtech.system.service.*; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.util.*; +import java.util.stream.Collectors; + +@Slf4j +@RequiredArgsConstructor +@Service +public class LeaderTaskService implements ILeaderTaskService { + + private final ISysUserService userService; + private final SysUserRoleMapper userRoleMapper; + private final SysUserMapper userMapper; + private final ISysConfigService configService; + private final SysLawCaseMapper lawCaseMapper; + +// private final BankService bankService; + + private final ISysLawCaseInvestigatorService sysLawCaseInvestigatorService; + + private final SysLawCaseService sysLawCaseService; + + private final QueryCenterService queryCenterService; + + private final ISysOssService sysOssService; + + @Transactional + @Override + public void deleteLawCase(String id) { + if (id == null) { + throw new RuntimeException("案件Id不能为NULL"); + } + + int affectedRows = lawCaseMapper.deleteById(id); +// if (affectedRows != 1) { +// throw new RuntimeException("删除案件失败."); +// } + +// bankService.clear(id); + + QueryCenterQuery query = new QueryCenterQuery(); + query.setCaseId(id); + String indexArr[] = {IndexInitService.TRANSACTION_PARTNER_INDEX,IndexInitService.PUBLIC_FAMILY_INDEX, + IndexInitService.REAL_ESTATE_INDEX,IndexInitService.CAR_INFO_INDEX, + IndexInitService.OTHER_ASSETS_INDEX,IndexInitService.OTHER_INFORMATION_INDEX, + IndexInitService.OTHER_INFORMATION_INDEX}; + for (String index : indexArr) { + query.setIndex(index); + queryCenterService.deleteDataByCondition(query); + } + sysOssService.deleteByCaseId(query.getCaseId()); + } + + + @Transactional + @Override + public void editLawCase(EditLawCaseReq req) { + String lawCaseName = req.getName(); + List investigators = req.getInvestigators(); + + // 案件Id + String id = req.getId(); + if (id == null) { + throw new RuntimeException("案件Id为null"); + } + + SysLawCase sysLawCase = lawCaseMapper.selectById(id); + + if (StrUtil.isNotEmpty(lawCaseName)) { + sysLawCase.setName(lawCaseName); + } + + if (investigators != null && !investigators.isEmpty()) { + // 更新案件调查人员 + List sysUsers = userMapper.selectBatchIds(investigators); + List collect = sysUsers.stream().map(SysUser::getIdCardNo).collect(Collectors.toList()); + sysLawCase.setInvestigatorStr(String.join(",", collect)); + // 更新关联表 + LambdaQueryWrapper wrapper = + Wrappers.lambdaQuery(SysLawCaseInvestigator.class).eq(SysLawCaseInvestigator::getLawCaseId, id); + Set userIdList = sysLawCaseInvestigatorService.list(wrapper).stream() + .map(SysLawCaseInvestigator::getInvestigatorId) + .collect(Collectors.toSet()); + + Set set = investigators.stream() + .filter(userId -> !userIdList.contains(userId)) + .collect(Collectors.toSet()); + // 增加 + for (Long userId : set) { + SysLawCaseInvestigator sysLawCaseInvestigator = new SysLawCaseInvestigator(); + sysLawCaseInvestigator.setLawCaseId(id); + sysLawCaseInvestigator.setInvestigatorId(userId); + + sysLawCaseInvestigatorService.save(sysLawCaseInvestigator); + } + // 删除 + userIdList.stream() + .filter(userId -> !investigators.contains(userId)) + .forEach(userId -> { + Map map = new HashMap<>(); + // 调查人员Id + map.put("investigator_id", userId); + + sysLawCaseInvestigatorService.removeByMap(map); + }); + } + + lawCaseMapper.updateById(sysLawCase); + } + + @Override + public List getInvestigatorsForAddLawCase() { + // 当前登录用户的角色Id + Long userId = LoginHelper.getUserId(); + SysUserRole sysUserRole = userRoleMapper.selectOne(new LambdaQueryWrapper() + .eq(SysUserRole::getUserId, userId)); + Long roleId = sysUserRole.getRoleId(); + // 如果当前登录用户是案管领导 + TableDataInfo pageInfo; + if (roleId.equals(Constants.LEADER_ROLE_ID)) { + // 获取参与案件的所有调查人员 + pageInfo = sysLawCaseService.getLawCaseListForLeader(new LawCaseListReq()); + } else { + pageInfo = sysLawCaseService.getLawCaseListForInvestigator(new LawCaseListReq()); + } + + List investigatorList = new ArrayList<>(); + + Set caseIdList = + pageInfo.getRows().stream().map(SysLawCase::getId).collect(Collectors.toSet()); + if (caseIdList.isEmpty()) { + return investigatorList; + } + + List sysLawCaseInvestigatorList = + sysLawCaseInvestigatorService.list(Wrappers.lambdaQuery(SysLawCaseInvestigator.class) + .in(SysLawCaseInvestigator::getLawCaseId, caseIdList)); + Set userIdList = sysLawCaseInvestigatorList.stream() + .map(SysLawCaseInvestigator::getInvestigatorId) + .collect(Collectors.toSet()); + // 查询调查人员 + List users = userMapper.selectBatchIds(userIdList); + for (SysUser user : users) { + if (user.getStatus().equals("0") || user.getStatus().equals("1")) { + MInvestigator it = new MInvestigator(); + it.setId(user.getUserId()); + it.setUserName(user.getUserName()); + it.setPhone(user.getPhonenumber()); + it.setStatus(user.getStatus()); + it.setIdCardNo(user.getIdCardNo()); +// it.setIdCardNo(LoginHelper.decryptedIdCardNo(user.getIdCardNo())); + it.setOperRecords(null); + + investigatorList.add(it); + } + } + + return investigatorList; + } + + @Override + public void exportInvestigator(List userIds, HttpServletResponse response) { + QueryWrapper qw = Wrappers.query(); + if (!userIds.isEmpty()) { + qw.in("user_id", userIds); + } + + List users = userMapper.selectList(qw); + + List investigatorList = new ArrayList<>(); + + // 构造调查人员信息 + for (SysUser user : users) { + if (Objects.equals(user.getUserId(), Constants.ADMIN_USER_ID)) { + continue; + } + + if (Objects.equals(user.getUserId(), Constants.RY_USER_ID)) { + continue; + } + + MInvestigator investigator = new MInvestigator(); + investigator.setId(user.getUserId()); + investigator.setUserName(user.getUserName()); + investigator.setPhone(user.getPhonenumber()); + investigator.setIdCardNo(DesUtil.decrypt(user.getIdCardNo())); + investigator.setStatus(user.getStatus()); + + Map map = new HashMap<>(); + map.put("user_id", user.getUserId()); + + List mSysUserRoles = userRoleMapper.selectByMap(map); + if (mSysUserRoles.size() != 1) { + throw new RuntimeException("用户[ " + user.getUserId() + "]用户角色关系异常"); + } + + SysUserRole userRole = mSysUserRoles.get(0); + Long roleId = userRole.getRoleId(); + + if (Objects.equals(roleId, Constants.INVESTIGATOR_ROLE_ID)) { + investigator.setRoleName(Constants.INVESTIGATOR_NAME); + } + + if (Objects.equals(roleId, Constants.LEADER_ROLE_ID)) { + investigator.setRoleName(Constants.LEADER_NAME); + } + + investigatorList.add(investigator); + } + + + ExcelUtil.exportExcel(investigatorList, "调查人员信息", MInvestigator.class, response); + } + + @Transactional + @Override + public String importInvestigator(List users, boolean updateSupport) { + // 导入调查人员信息 + if (CollectionUtil.isEmpty(users) || users.isEmpty()) { + throw new ServiceException("导入用户数据不能为空!"); + } + + int successNum = 0; + int failureNum = 0; + + StringBuilder successMsg = new StringBuilder(); + StringBuilder failureMsg = new StringBuilder(); + + String password = configService.selectConfigByKey("sys.user.initPassword"); + + String operName = LoginHelper.getUsername(); + + // 加密身份证号 + users.forEach(SysUser -> { + // 校验身份证号是否合法 + if (SysUser != null) { + String idCardNo = SysUser.getIdCardNo(); +// if (!IdcardUtil.isValidCard(idCardNo)) { +// throw new RuntimeException("身份证号[" + idCardNo + "]格式不正确."); +// } + + SysUser.setIdCardNo(DesUtil.encrypt(idCardNo)); + } + }); + + Set userIds = new HashSet<>(); + + for (SysUser user : users) { + try { + if (user == null) { + continue; + } + // 验证是否存在这个用户 + Map map = new HashMap<>(); + map.put("user_name", user.getUserName()); + + List dbUsers = userMapper.selectByMap(map); + if (dbUsers == null || dbUsers.isEmpty()) { + user.setPassword(BCrypt.hashpw(password)); + user.setCreateBy(operName); + user.setCreateTime(new Date()); + userMapper.insert(user); + + userIds.add(user.getUserId()); + + successNum++; + } else if (updateSupport) { + + SysUser dbUser = dbUsers.get(0); + + user.setUserId(dbUser.getUserId()); + user.setUpdateBy(operName); + + userMapper.updateById(user); + + userIds.add(user.getUserId()); + + successNum++; + } else { + failureNum++; + failureMsg + .append("
") + .append(failureNum) + .append("、账号 ") + .append(user.getUserName()) + .append(" 已存在"); + } + } catch (Exception e) { + failureNum++; + String msg = "
" + failureNum + "、账号 " + user.getUserName() + " 导入失败:"; + failureMsg.append(msg).append(e.getMessage()); + + throw new RuntimeException(msg, e); + } + } + + if (failureNum > 0) { + failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); + throw new ServiceException(failureMsg.toString()); + } else { + successMsg.insert(0, "数据已全部导入成功!共 " + successNum + " 条。"); + } + + for (Long userId : userIds) { + Long roleId = userRoleMapper.selectRoleIdByUserId(userId); + if( roleId != null){ + continue; + } + SysUserRole userRole = new SysUserRole(); + userRole.setRoleId(Constants.INVESTIGATOR_ROLE_ID); + userRole.setUserId(userId); + userRoleMapper.insert(userRole); + } + + return successMsg.toString(); + } + + @Transactional + @Override + public void addInvestigator(AddInvestigatorReq req) { + + String encryptedIdCardNo = req.getIdCardNo(); +// String idCardNo = LoginHelper.decryptedIdCardNo(encryptedIdCardNo); + + Map map = new HashMap<>(); + map.put("id_card_no", encryptedIdCardNo); + // 避免身份证号重复 + List users = userMapper.selectByMap(map); + if (users != null && !users.isEmpty()) { + throw new RuntimeException("用户身份证号重复"); + } + + SysUser user = new SysUser(); + + String userName = req.getUserName(); + user.setUserName(userName); + user.setPassword(BCrypt.hashpw(Constants.DEFAULT_PASSWD)); + + user.setIdCardNo(encryptedIdCardNo); + user.setCreateBy(LoginHelper.getUsername()); + + user.setCreateTime(new Date()); + + String phone = req.getPhone(); + user.setPhonenumber(phone); + + String status = req.getStatus(); + user.setStatus(status); + // 用户表 + int affectedRows = userMapper.insert(user); + if (affectedRows != 1) { + throw new RuntimeException("添加用户失败"); + } + + Long userId = user.getUserId(); + + // 更新用户角色表 + SysUserRole userRole = new SysUserRole(); + userRole.setUserId(userId); + userRole.setRoleId(Constants.INVESTIGATOR_ROLE_ID); + + affectedRows = userRoleMapper.insert(userRole); + if (affectedRows != 1) { + throw new RuntimeException("更新用户角色关系表出错."); + } + } + + @Transactional + @Override + public void editInvestigator(EditInvestigatorReq req) { + + SysUser user = new SysUser(); + + + Long userId = req.getUserId(); + if (userId == null) { + throw new RuntimeException("用户Id不能为空"); + } + + SysUser dbUser = userMapper.selectById(userId); + + + + Long alterByUserId = LoginHelper.getUserId(); + + + user.setUserId(userId); + + if (StrUtil.isNotEmpty(req.getUserName())) { + user.setUserName(req.getUserName()); + + } + + if (StrUtil.isNotEmpty(req.getStatus())) { + user.setStatus(req.getStatus()); + } + + if (StrUtil.isNotEmpty(req.getPhone())) { + user.setPhonenumber(req.getPhone()); + + } + + String encryptedIdCardNo = req.getIdCardNo(); + if (StrUtil.isNotEmpty(encryptedIdCardNo)) { + // 保存加密的身份证号 + user.setIdCardNo(encryptedIdCardNo); + + } + + userMapper.updateById(user); + + String roleIdStr = req.getRoleId(); + if (StrUtil.isNotEmpty(roleIdStr)) { + Long roleId = Long.parseLong(roleIdStr); + + // 修改用户角色表 + Map map = new HashMap<>(); + map.put("user_id", userId); + + List mSysUserRoles = userRoleMapper.selectByMap(map); + if (mSysUserRoles.size() != 1) { + throw new RuntimeException("用户-角色异常"); + } + + SysUserRole userRole = mSysUserRoles.get(0); + + UpdateWrapper qw = Wrappers.update(); + qw.eq("user_id", userRole.getUserId()); + qw.eq("role_id", userRole.getRoleId()); + + userRoleMapper.delete(qw); + + userRole.setRoleId(roleId); + userRoleMapper.insert(userRole); + } + + } + + @Transactional + @Override + public void deleteInvestigator(Long id) { + + // 删除用户记录 + int affectedRows = userMapper.deleteById(id); + if (affectedRows != 1) { + throw new RuntimeException("删除用户 [" + id + "] 失败"); + } + // 删除调查人员信息,需要保持之前的内容 + deleteUserRole(id); + } + + /** + * 删除用户角色关系和操作记录 + * + * @param id 用户Id + */ + private void deleteUserRole(Long id) { + int affectedRows; + Map map = new HashMap<>(); + map.put("user_id", id); + + // 删除用户角色关系 + affectedRows = userRoleMapper.deleteByMap(map); + if (affectedRows != 1) { + throw new RuntimeException("删除用户角色关系 [" + id + "] 失败"); + } + } + + @Transactional + @Override + public void transform(String idCardNo, String name) { + // 查找是否在数据库中已经有 + Map queryMap = new HashMap<>(); + queryMap.put("user_name", name); + + List users = userMapper.selectByMap(queryMap); + + if (users != null && users.size() == 1) { + SysUser dbUser = users.get(0); + // 校验身份证号 + String encryptedDbIdCardNo = dbUser.getIdCardNo(); + String dbIdCardNo = DesUtil.decrypt(encryptedDbIdCardNo); + if (!Objects.equals(dbIdCardNo, idCardNo)) { + throw new RuntimeException("身份证验证失败"); + } + + String status = dbUser.getStatus(); + String delFlag = dbUser.getDelFlag(); + if (!"0".equals(status) || !"0".equals(delFlag)) { + + dbUser.setStatus("0"); + dbUser.setDelFlag("0"); + + userMapper.updateById(dbUser); + } + + // 已经有数据 + // 更新用户为leader,也就是更新用户角色表 + Map map = new HashMap<>(); + map.put("user_id", dbUser.getUserId()); + + int affectedRows = userRoleMapper.deleteByMap(map); + if (affectedRows != 1) { + throw new RuntimeException("清理用户[" + dbUser.getUserId() + "]角色关系错误"); + } + + SysUserRole sysUserRole = new SysUserRole(); + sysUserRole.setUserId(dbUser.getUserId()); + // 案管领导 + sysUserRole.setRoleId(Constants.LEADER_ROLE_ID); + + userRoleMapper.insert(sysUserRole); + } else { + Map map = new HashMap<>(); + map.put("id_card_no", DesUtil.encrypt(idCardNo)); + // 避免身份证号重复 + List dbUser = userMapper.selectByMap(map); + if (dbUser != null && !dbUser.isEmpty()) { + throw new RuntimeException("用户身份证号重复"); + } + // 新建用户 + SysUser newLeader = new SysUser(); + newLeader.setUserName(name); + newLeader.setPassword(BCrypt.hashpw(Constants.DEFAULT_PASSWD)); + newLeader.setIdCardNo(DesUtil.encrypt(idCardNo)); + // 角色:案管领导、调查人员 + // 是不是管理员,根据Id来判断,案管领导也是如此 + userService.insertUser(newLeader); // 返回主要是为了获取Id + + // 删除原来的leader角色关系 + Map deleteOldLeaderMap = new HashMap<>(); + deleteOldLeaderMap.put("role_id", Constants.LEADER_ROLE_ID); + + userRoleMapper.deleteByMap(deleteOldLeaderMap); + + // 更新用户角色表 + SysUserRole sysUserRole = new SysUserRole(); + sysUserRole.setUserId(newLeader.getUserId()); + // 案管领导 + sysUserRole.setRoleId(Constants.LEADER_ROLE_ID); + + userRoleMapper.insert(sysUserRole); + } + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/service/impl/SysLawCaseInvestigatorServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/caseMange/service/impl/SysLawCaseInvestigatorServiceImpl.java new file mode 100644 index 0000000..47c532f --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/service/impl/SysLawCaseInvestigatorServiceImpl.java @@ -0,0 +1,24 @@ +package com.inscloudtech.caseMange.service.impl; + + + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.inscloudtech.caseMange.domain.SysLawCaseInvestigator; +import com.inscloudtech.caseMange.mapper.SysLawCaseInvestigatorMapper; +import com.inscloudtech.caseMange.service.ISysLawCaseInvestigatorService; +import org.springframework.stereotype.Service; + +/** +* @author Administrator +* @description 针对表【sys_law_case_investigator(用户和角色关联表)】的数据库操作Service实现 +* @createDate 2023-10-13 09:49:02 +*/ +@Service +public class SysLawCaseInvestigatorServiceImpl extends ServiceImpl + implements ISysLawCaseInvestigatorService { + +} + + + + diff --git a/cas-system/src/main/java/com/inscloudtech/caseMange/service/impl/SysLawCaseService.java b/cas-system/src/main/java/com/inscloudtech/caseMange/service/impl/SysLawCaseService.java new file mode 100644 index 0000000..cfc09a3 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/caseMange/service/impl/SysLawCaseService.java @@ -0,0 +1,255 @@ +package com.inscloudtech.caseMange.service.impl; + +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.entity.SysUser; +import com.inscloudtech.common.core.domain.model.LoginUser; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.system.domain.SysOss; +import com.inscloudtech.caseMange.domain.SysLawCaseInvestigator; +import com.inscloudtech.caseMange.domain.vo.AddLawCaseReq; +import com.inscloudtech.caseMange.domain.vo.LawCaseListReq; +import com.inscloudtech.caseMange.mapper.SysLawCaseInvestigatorMapper; +import com.inscloudtech.caseMange.mapper.SysLawCaseMapper; +import com.inscloudtech.caseMange.service.ISysLawCaseInvestigatorService; +import com.inscloudtech.caseMange.service.ISysLawCaseService; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.caseMange.domain.SysLawCase; +import com.inscloudtech.system.mapper.SysUserMapper; +import com.inscloudtech.system.mapper.SysUserRoleMapper; +import lombok.RequiredArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +@Service +public class SysLawCaseService extends ServiceImpl implements ISysLawCaseService { + + private final SysLawCaseMapper lawCaseMapper; + private final SysUserMapper userMapper; + private final SysLawCaseInvestigatorMapper lawCaseInvestigatorMapper; + private final ISysLawCaseInvestigatorService lawCaseInvestigatorService; + + + @Override + public TableDataInfo getLawCaseList(LawCaseListReq req) { + + // 先判断是案管领导还是调查人员 + // 根据userId获取角色Id + LoginUser loginUser = LoginHelper.getLoginUser(); + if ( StpUtil.hasRole("案管领导")) { + // 案管领导 + // 案管领导可以查看所有案件 + return getLawCaseListForLeader(req); + } else { + // 调查人员 + // 调查人员只能查看自己参与的案件 + return getLawCaseListForInvestigator(req); + } + } + + TableDataInfo getLawCaseListForInvestigator(LawCaseListReq req) { + int pageNum = req.getPageNum(); + int pageSize = req.getPageSize(); + LambdaQueryWrapper lawCaseQueryWrapper = Wrappers.lambdaQuery(); + + // 案件名称 + String lawCaseName = req.getName(); + if (StrUtil.isNotEmpty(lawCaseName)) { + lawCaseQueryWrapper.like(SysLawCase::getName, lawCaseName); + } + // 办案人员 + // 查询或者是在调查人员登录页面 + String investigatorName = req.getInvestigatorName(); + if (StringUtils.isEmpty(investigatorName)) { + investigatorName = LoginHelper.getUsername(); + } else { + // 这种情况下,表示的搜索,以调查人员姓名进行查询 + req.setUserId(LoginHelper.getUserId().toString()); + } + + // 根据调查人员姓名去获取userId,然后再去获取案件Id63-+ + SysUser user = userMapper.selectUserByUserName(investigatorName); + List caseIdList = getLawCaseIdByUserId(user.getUserId()); + + if (StrUtil.isNotEmpty(req.getUserId())) { + Collection unionColl = + CollectionUtils.intersection(caseIdList, getLawCaseIdByUserId(Long.valueOf(req.getUserId()))); + caseIdList = unionColl.stream().map(String::valueOf).collect(Collectors.toList()); + } + + if (!caseIdList.isEmpty()) { + lawCaseQueryWrapper.in(SysLawCase::getId, caseIdList); + } else { + return new TableDataInfo<>(); + } + + LawCaseListReq.ParamItem params = req.getParams(); + req.setBeginCreateTime(params.getBeginCreateTime()); + req.setEndCreateTime(params.getEndCreateTime()); + + String beginTimeStr = req.getBeginCreateTime(); + String endTimeStr = req.getEndCreateTime(); + + if (StrUtil.isNotEmpty(beginTimeStr)) { + DateTime beginTime = DateUtil.parse(beginTimeStr); + + if (StrUtil.isNotEmpty(endTimeStr)) { + DateTime endTime = DateUtil.parse(endTimeStr); + endTime = DateUtil.endOfDay(endTime); + + lawCaseQueryWrapper.between(SysLawCase::getCreateTime, beginTime, endTime); + } else { + lawCaseQueryWrapper.gt(SysLawCase::getCreateTime, beginTime); + } + } else { + if (StrUtil.isNotEmpty(endTimeStr)) { + DateTime endTime = DateUtil.parse(endTimeStr); + endTime = DateUtil.endOfDay(endTime); + + lawCaseQueryWrapper.le(SysLawCase::getCreateTime, endTime); + } + } + + lawCaseQueryWrapper.orderByDesc(SysLawCase::getCreateTime); + + PageQuery pageQuery = new PageQuery(); + pageQuery.setPageNum(pageNum); + pageQuery.setPageSize(pageSize); + + Page lawCasePage = lawCaseMapper.selectPage(pageQuery.build(), lawCaseQueryWrapper); + return TableDataInfo.build(lawCasePage); + } + + TableDataInfo getLawCaseListForLeader(LawCaseListReq req) { + int pageNum = req.getPageNum(); + int pageSize = req.getPageSize(); + LambdaQueryWrapper lawCaseQueryWrapper = Wrappers.lambdaQuery(); + + // 案件名称 + String lawCaseName = req.getName(); + if (StrUtil.isNotEmpty(lawCaseName)) { + lawCaseQueryWrapper.like(SysLawCase::getName, lawCaseName); + } + // 办案人员 + // 查询或者是在调查人员登录页面 + String investigatorName = req.getInvestigatorName(); + if (StrUtil.isNotEmpty(investigatorName)) { + // 根据调查人员姓名去获取userId,然后再去获取案件Id + SysUser user = userMapper.selectUserByUserName(investigatorName); + if (!Objects.isNull(user)) { + List caseIdList = getLawCaseIdByUserId(user.getUserId()); + if (!caseIdList.isEmpty()) { + lawCaseQueryWrapper.in(SysLawCase::getId, caseIdList); + } + } + } + + LawCaseListReq.ParamItem params = req.getParams(); + req.setBeginCreateTime(params.getBeginCreateTime()); + req.setEndCreateTime(params.getEndCreateTime()); + + String beginTimeStr = req.getBeginCreateTime(); + String endTimeStr = req.getEndCreateTime(); + + if (StrUtil.isNotEmpty(beginTimeStr)) { + DateTime beginTime = DateUtil.parse(beginTimeStr); + + if (StrUtil.isNotEmpty(endTimeStr)) { + DateTime endTime = DateUtil.parse(endTimeStr); + endTime = DateUtil.endOfDay(endTime); + + lawCaseQueryWrapper.between(SysLawCase::getCreateTime, beginTime, endTime); + } else { + lawCaseQueryWrapper.gt(SysLawCase::getCreateTime, beginTime); + } + } else { + if (StrUtil.isNotEmpty(endTimeStr)) { + DateTime endTime = DateUtil.parse(endTimeStr); + endTime = DateUtil.endOfDay(endTime); + + lawCaseQueryWrapper.le(SysLawCase::getCreateTime, endTime); + } + } + + lawCaseQueryWrapper.orderByDesc(SysLawCase::getCreateTime); + + PageQuery pageQuery = new PageQuery(); + pageQuery.setPageNum(pageNum); + pageQuery.setPageSize(pageSize); + + Page lawCasePage = lawCaseMapper.selectPage(pageQuery.build(), lawCaseQueryWrapper); + return TableDataInfo.build(lawCasePage); + } + + @Override + public void insert(SysLawCase sysLawCase) { + + sysLawCase.setId(null); + baseMapper.insert(sysLawCase); + } + + @Override + public void addLawCase(AddLawCaseReq req) { + + // 操作两个表 + String name = req.getName(); // 案件名称 + List investigators = req.getInvestigators(); // 调查人员Id列表 + + //加入领导 + investigators.add(LoginHelper.getUserId()); + + SysLawCase sysLawCase = new SysLawCase(); + sysLawCase.setName(name); + sysLawCase.setCreateBy(LoginHelper.getLoginUser().getUsername()); + sysLawCase.setCreateTime(new Date()); + sysLawCase.setUpdateBy(LoginHelper.getLoginUser().getUsername()); + sysLawCase.setUpdateTime(new Date()); + List sysUsers = userMapper.selectBatchIds(investigators); + List collect = sysUsers.stream().map(SysUser::getIdCardNo).collect(Collectors.toList()); + sysLawCase.setInvestigatorStr(String.join(",", collect)); + lawCaseMapper.insert(sysLawCase); + + // 插入关联表 + String id = sysLawCase.getId(); + + List siList = new ArrayList<>(); + + Set userIdList = sysUsers.stream().map(SysUser::getUserId).collect(Collectors.toSet()); + for (Long userId : userIdList) { + SysLawCaseInvestigator si = new SysLawCaseInvestigator(); + si.setLawCaseId(id); + si.setInvestigatorId(userId); + + siList.add(si); + } + + lawCaseInvestigatorService.saveBatch(siList); + } + + private List getLawCaseIdByUserId(Long userId) { + LambdaQueryWrapper lawCaseQueryWrapper = Wrappers.lambdaQuery(); + lawCaseQueryWrapper.eq(SysLawCaseInvestigator::getInvestigatorId, userId); + List lawCaseInvestigatorList = lawCaseInvestigatorMapper.selectList(lawCaseQueryWrapper); + + + + return lawCaseInvestigatorList.stream() + .map(SysLawCaseInvestigator::getLawCaseId) + .collect(Collectors.toList()); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/converter/ExcelStringToJavaBigDecimalConverter.java b/cas-system/src/main/java/com/inscloudtech/converter/ExcelStringToJavaBigDecimalConverter.java new file mode 100644 index 0000000..2ba1565 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/converter/ExcelStringToJavaBigDecimalConverter.java @@ -0,0 +1,44 @@ +package com.inscloudtech.converter; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.converters.ReadConverterContext; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; + +import java.math.BigDecimal; + +/** + * 转化器,在Excel中,计数使用了,号,需要去除掉,才能转化为合适的类型 + */ +public class ExcelStringToJavaBigDecimalConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return BigDecimal.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public BigDecimal convertToJavaData(ReadConverterContext ctx) { + + String value = ctx.getReadCellData().getStringValue(); + if (StringUtils.isEmpty(value)) { + return null; + } + + if (HelperUtil.isContainsChinese(value)){ + return null; + } + + if (value.contains(",")) { + value = value.replaceAll(",", ""); + } + + return BigDecimal.valueOf(Double.parseDouble(value)); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/converter/MyStringNumberConverter.java b/cas-system/src/main/java/com/inscloudtech/converter/MyStringNumberConverter.java new file mode 100644 index 0000000..cecefc0 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/converter/MyStringNumberConverter.java @@ -0,0 +1,53 @@ +package com.inscloudtech.converter; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.converters.string.StringNumberConverter; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.DateUtils; +import com.alibaba.excel.util.NumberDataFormatterUtils; +import com.alibaba.excel.util.NumberUtils; +import com.alibaba.excel.util.StringUtils; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Objects; + +public class MyStringNumberConverter extends StringNumberConverter { + + private static final String timePattern = "h:mm:ss"; + + private static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss"); + + + @Override + public String convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + // If there are "DateTimeFormat", read as date + if (contentProperty != null && contentProperty.getDateTimeFormatProperty() != null) { + return DateUtils.format(cellData.getNumberValue(), + contentProperty.getDateTimeFormatProperty().getUse1904windowing(), + contentProperty.getDateTimeFormatProperty().getFormat()); + } + // If there are "NumberFormat", read as number + if (contentProperty != null && contentProperty.getNumberFormatProperty() != null) { + return NumberUtils.format(cellData.getNumberValue(), contentProperty); + } + // Excel defines formatting + boolean hasDataFormatData = cellData.getDataFormatData() != null + && cellData.getDataFormatData().getIndex() != null && StrUtil.isNotEmpty( + cellData.getDataFormatData().getFormat()); + + if (hasDataFormatData) { + if(Objects.equals(cellData.getDataFormatData().getFormat(),timePattern)){ + LocalDateTime localDateTime = DateUtils.getLocalDateTime(cellData.getNumberValue().doubleValue(), false); + return dateTimeFormatter.format(localDateTime); + } + return NumberDataFormatterUtils.format(cellData.getNumberValue(), + cellData.getDataFormatData().getIndex(), cellData.getDataFormatData().getFormat(), globalConfiguration); + } + // Default conversion number + return NumberUtils.format(cellData.getNumberValue(), contentProperty); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/BankStatement.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/BankStatement.java new file mode 100644 index 0000000..010b01b --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/BankStatement.java @@ -0,0 +1,238 @@ +package com.inscloudtech.datacenter.domain; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.format.NumberFormat; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.inscloudtech.common.annotation.IdCardField; +import com.inscloudtech.common.annotation.NameField; + +import com.inscloudtech.datacenter.domain.vo.RevokeItem; +import lombok.Data; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.dromara.easyes.annotation.HighLight; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.RefreshPolicy; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * 银行流水表 bank_statement + */ +@TableName(value = "bank_statement") +@IndexName(value = "dc_bank_statement",refreshPolicy = RefreshPolicy.IMMEDIATE) +@Data +public class BankStatement implements Serializable { + /** + * + */ + @ExcelIgnore + @TableId(type = IdType.ASSIGN_UUID) + @IndexId(type = org.dromara.easyes.annotation.rely.IdType.CUSTOMIZE) + private String id; + /** + * 银行名称 + */ + @ExcelProperty(value = "银行名称") + private String bankName; + + @ExcelProperty(value = "持卡人姓名") + private String cardHolderName = ""; + /** + * 身份证号 + */ + @IdCardField + @ExcelProperty("身份证号") + private String idCardNo = ""; + + /** + * 卡号 + */ + + @ExcelProperty("交易卡号") + @HighLight(mappingField = "cardNumberContent") + private String cardNumber = ""; + + /** + * 高亮返回值被映射的字段 + */ + @ExcelIgnore + private String cardNumberContent; + + /** + * 交易时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @com.alibaba.excel.annotation.format.DateTimeFormat("yyyy-MM-dd HH:mm:ss") + + @ExcelProperty("交易时间") + private Date transactionTime; + + /** + * 交易金额,支出金额和收入金额的和 + */ + + @ExcelProperty("交易金额") + private BigDecimal transactionAmount = BigDecimal.ZERO; + + /** + * 余额 + */ + + @ExcelProperty("账户余额") + @NumberFormat("#.00") + private BigDecimal balance; + + // 交易机构名称 + @ExcelProperty("交易机构名称") + private String transactionInstitutions = ""; + + /** + * 交易对手名称 + */ + @NameField + + @ExcelProperty("对方户名") + private String counterpartyName = ""; + + @ExcelProperty("对方账号") + private String counterpartyAccount = ""; + + /** + * 交易对手身份证号 + */ + @IdCardField + + @ExcelProperty(value = "对方身份证号") + private String counterpartIdCardNo = ""; + + @ExcelProperty("对方行名") + private String counterpartyBankName = ""; + + @ExcelProperty("摘要") + private String summary = ""; + + @ExcelProperty("交易备注") + private String transRemark = ""; + + @ExcelProperty("交易渠道") + private String transChannel = ""; + + @NameField + @ExcelProperty("真实交易对手名称") + private String realCounterpartyName = ""; + + @ExcelProperty("真实交易对手账号") + private String realCounterpartyAccount = ""; + + /** + * 电话号码 + */ + @ExcelIgnore + private String phone = ""; + + /** + * 交易币种,1-人民币,2-美元 + */ + @ExcelIgnore + private Integer transCurrencyType; + + + @ExcelIgnore + private String sourceFile; + + /** + * 创建时间 + */ + @ExcelIgnore + private Date createTime = new Date(); + /** + * 更新时间 + */ + @ExcelIgnore + private Date updateTime = new Date(); + /** + * 颜色 + */ + @ExcelIgnore + private String bgColor; + /** + * 备注 + */ + @ExcelProperty("备注") + private String remark = ""; + + @ExcelIgnore + private String analysisResultId; + + @ExcelIgnore + @TableField(exist = false) + private static final long serialVersionUID = 1L; + + @ExcelIgnore + @TableField(exist = false) + private List ids = new ArrayList<>(); + + @ExcelIgnore + @TableField(exist = false) + private List revokeList = new ArrayList<>(); + + @ExcelIgnore + @TableField(exist = false) + private String caseId; + + @ExcelIgnore + @TableField(exist = false) + private String bgc; + + + @ExcelIgnore + private String sId; + + @Override + public boolean equals(Object object) { + if (this == object) return true; + + if (object == null || getClass() != object.getClass()) return false; + + BankStatement bs = (BankStatement) object; + + return new EqualsBuilder() + .append(bankName, bs.bankName) + .append(cardHolderName, bs.cardHolderName) + .append(idCardNo, bs.idCardNo) + .append(cardNumber, bs.cardNumber) + .append(transactionTime, bs.transactionTime) + .append(transactionAmount, bs.transactionAmount) + .append(balance, bs.balance) + .append(caseId, bs.caseId) + .isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder(17, 37) + .append(bankName) + .append(cardHolderName) + .append(idCardNo) + .append(cardNumber) + .append(transactionTime) + .append(transactionAmount) + .append(balance) + .append(caseId) + .toHashCode(); + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/CarInfo.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/CarInfo.java new file mode 100644 index 0000000..0a58ce7 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/CarInfo.java @@ -0,0 +1,107 @@ +package com.inscloudtech.datacenter.domain; + + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.*; +import com.inscloudtech.common.annotation.DeduplicationField; + +import com.inscloudtech.common.annotation.UpdateValueLog; +import com.inscloudtech.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.RefreshPolicy; + +/** + * 重点人员资产-车辆信息对象 dc_car_info + * + * @author inscloudtech + * @date 2023-11-09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("dc_car_info") +@ExcelIgnoreUnannotated +@IndexName(value = "dc_car_info",refreshPolicy = RefreshPolicy.IMMEDIATE) +public class CarInfo extends BaseEntity { + + /** id */ + @TableId(type = IdType.ASSIGN_ID) + @IndexId(type = org.dromara.easyes.annotation.rely.IdType.CUSTOMIZE) + private String id; + /** + * 姓名 + */ + @UpdateValueLog(fieldName = "姓名") + @ExcelProperty("姓名") + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + private String name; + /** + * 身份证号 + */ + @ExcelProperty("身份证号") + @DeduplicationField + @UpdateValueLog(fieldName = "身份证号") + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + private String idCard; + /** + * 车牌号 + */ + @ExcelProperty("车牌号") + @DeduplicationField + @UpdateValueLog(fieldName = "车牌号") + @IndexField(fieldType = FieldType.KEYWORD) + private String carNo; + /** + * 车型 + */ + @UpdateValueLog(fieldName = "车型") + @ExcelProperty("车型") + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD) + private String carType; + /** + * 转让登记 + */ + @UpdateValueLog(fieldName = "转让登记") + @ExcelProperty("转让登记") + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD) + private String registration; + + + /** + * 备注 + */ + @UpdateValueLog(fieldName = "备注") + @ExcelProperty("备注") + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @TableField(updateStrategy = FieldStrategy.IGNORED) + private String remark; + + /** + * 车辆停放及登记地址 + */ + @UpdateValueLog(fieldName = "车辆停放及登记地址") + @ExcelProperty("车辆停放及登记地址") + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD) + private String address; + + @UpdateValueLog(fieldName = "背景色") + @IndexField(strategy = org.dromara.easyes.annotation.rely.FieldStrategy.IGNORED) + @TableField(updateStrategy = FieldStrategy.IGNORED) + private String bgc; + + private String caseId; + + @IndexField(fieldType = FieldType.KEYWORD) + private String analysisResultId; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/ImportResult.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/ImportResult.java new file mode 100644 index 0000000..6f2dbfa --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/ImportResult.java @@ -0,0 +1,95 @@ +package com.inscloudtech.datacenter.domain; + + + import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; + import com.alibaba.excel.annotation.ExcelProperty; + import com.alibaba.excel.annotation.write.style.ColumnWidth; + import com.baomidou.mybatisplus.annotation.*; + import com.fasterxml.jackson.annotation.JsonFormat; + + import lombok.Data; + import lombok.EqualsAndHashCode; + import org.dromara.easyes.annotation.IndexField; + import org.dromara.easyes.annotation.rely.FieldType; + + import java.util.Date; + + +/** + * 流水导入结果对象 dc_import_result + * + * @author zfcf + * @date 2024-07-15 + */ +@Data +@ExcelIgnoreUnannotated +@TableName("dc_import_result") +public class ImportResult { + + private static final long serialVersionUID=1L; + + /** + * 创建者 + */ + private String createBy; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @IndexField(fieldType = FieldType.DATE, dateFormat = "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis") + private Date createTime = new Date(); + + /** + * id + */ + @TableId(value = "id") + private String id; + /** + * 银行 + */ + @ExcelProperty("银行") + private String bankName; + + /** + * 文件名称 + */ + @ExcelProperty("文件名称") + private String fileName; + + /** + * sheetName + */ + @ColumnWidth(50) // 指定列宽度 + @ExcelProperty("sheet") + private String sheetName = ""; + + /** + * 错误信息 + */ + @ExcelProperty("错误信息") + private String errorInfo; + + /** + * 文件导入结果 0 失败 1成功 + */ + private Integer success = 0; + /** + * + */ + private String caseId; + + /** + * 文件数据量 + */ + private Integer dataCount; + + + + /** + * 批次号 + */ + private String batchId; + + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/OpeningAccountInfo.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/OpeningAccountInfo.java new file mode 100644 index 0000000..68f6ff0 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/OpeningAccountInfo.java @@ -0,0 +1,243 @@ +package com.inscloudtech.datacenter.domain; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.inscloudtech.common.annotation.DeduplicationField; +import com.inscloudtech.datacenter.domain.vo.RevokeItem; +import lombok.Data; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.IdType; +import org.dromara.easyes.annotation.rely.RefreshPolicy; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * @TableName opening_account_info + */ +@TableName(value = "opening_account_info") +@IndexName(value = "dc_opening_account_info",refreshPolicy = RefreshPolicy.IMMEDIATE) +@Data +public class OpeningAccountInfo implements Serializable { + /** + * + */ + @TableId + @IndexId(type = IdType.CUSTOMIZE) + @ExcelIgnore + private String id; + + /** + * 户名 + */ + @ExcelProperty(value = "户名") + @DeduplicationField + private String name; + + /** + * 银行名称 + */ + @ExcelProperty(value = "银行名称") + @DeduplicationField + private String bankName; + + /** + * 新账号 + */ + @ExcelProperty(value = "新账号") + @DeduplicationField + private String newAccountNumber; + + /** + * 账号 + */ + @ExcelProperty(value = "账号") + @DeduplicationField + private String accountNumber; + + + /** + * 账号对应卡号 + */ + @ExcelProperty(value = "账号对应卡号") + @DeduplicationField + private String account2CardNumber; + + + /** + * 客户号 + */ + @ExcelProperty(value = "客户号") + @DeduplicationField + private String customerId; + + /** + * 证件类型 + */ + @ExcelProperty(value = "证件类型") + @DeduplicationField + private String idType; + + /** + * 证件号码 + */ + @ExcelProperty(value = "证件号码") + @DeduplicationField + private String idNo; + + /** + * 电话号码 + */ + @ExcelProperty(value = "电话号码") + @DeduplicationField + private String phone; + + /** + * 地址 + */ + @ExcelProperty(value = "地址") + @DeduplicationField + private String address; + + /** + * 开户日期 + */ + @ExcelProperty(value = "开户日期") + @DeduplicationField + private String openingAccountDate; + + /** + * 销户日期 + */ + @ExcelProperty(value = "销户日期") + @DeduplicationField + private String closingDate; + + /** + * 账户状态 + */ + @ExcelProperty(value = "账户状态") + @DeduplicationField + private String status; + + /** + * 账户类型 + */ + @ExcelProperty(value = "账户类型") + @DeduplicationField + private String type; + + /** + * 冻结信息 + */ + @ExcelProperty(value = "冻结信息") + @DeduplicationField + private String freezeInfo; + + // 冻结日期 + @ExcelProperty(value = "冻结日期") + @DeduplicationField + private String freezeDate; + + @ExcelProperty("备注") + @DeduplicationField + private String remark; + + @ExcelIgnore + @IndexField(fieldType = FieldType.KEYWORD) + private String analysisResultId; + + // 网银签约信息 + @ExcelProperty("网银签约信息") + @DeduplicationField + private String onlineBankingSigningInfo; + + /** + * 开户机构 + */ + @ExcelProperty(value = "开户机构") + @DeduplicationField + private String accountOpeningInstitution; + + @TableField(exist = false) + private static final long serialVersionUID = 1L; + + @ExcelIgnore + @TableField(exist = false) + private List ids = new ArrayList<>(); + + @ExcelIgnore + @TableField(exist = false) + private List revokeList = new ArrayList<>(); + + @ExcelIgnore + @TableField(exist = false) + private String caseId; + + @ExcelIgnore + @TableField(exist = false) + private String bgc; + + + @ExcelIgnore + private String bgColor; + + @TableField(exist = false) + @ExcelIgnore + private BigDecimal balance; + + @TableField(exist = false) + @ExcelIgnore + private String sId; + + @TableField(exist = false) + @ExcelIgnore + private Date createTime = new Date(); + + @Override + public boolean equals(Object object) { + if (this == object) return true; + + if (object == null || getClass() != object.getClass()) return false; + + OpeningAccountInfo that = (OpeningAccountInfo) object; + + return new EqualsBuilder() + .append(name, that.name) + .append(bankName, that.bankName) + .append(accountNumber, that.accountNumber) + .append(idNo, that.idNo) + .append(phone, that.phone) + .append(openingAccountDate, that.openingAccountDate) + .append(closingDate, that.closingDate) + .append(status, that.status) + .append(caseId, that.caseId) + .isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder(17, 37) + .append(name) + .append(bankName) + .append(accountNumber) + .append(idNo) + .append(phone) + .append(openingAccountDate) + .append(closingDate) + .append(status) + .append(caseId) + .toHashCode(); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/OtherAssets.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/OtherAssets.java new file mode 100644 index 0000000..ce6833b --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/OtherAssets.java @@ -0,0 +1,67 @@ +package com.inscloudtech.datacenter.domain; + + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.*; +import com.inscloudtech.common.annotation.UpdateValueLog; +import com.inscloudtech.common.core.domain.BaseEntity; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.Analyzer; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.RefreshPolicy; + +/** + * 重点人员资产-其他资产信息 + * + * @author inscloudtech + * @date 2023-11-09 + */ +@Data +@IndexName(value = "dc_other_assets",refreshPolicy = RefreshPolicy.IMMEDIATE) +@TableName("dc_other_assets") +@ExcelIgnoreUnannotated +public class OtherAssets extends BaseEntity { + + @IndexField(fieldType = FieldType.TEXT) + private String content; + + @TableId(type = IdType.ASSIGN_ID) + @IndexId(type = org.dromara.easyes.annotation.rely.IdType.CUSTOMIZE) + private String id; + + private String caseId; + + /** + * 背景色 + */ + @UpdateValueLog(fieldName = "背景色") + @IndexField(fieldType = FieldType.KEYWORD,strategy = org.dromara.easyes.annotation.rely.FieldStrategy.IGNORED) + @TableField(updateStrategy = FieldStrategy.IGNORED) + private String bgc; + + /** + * 文件名称 + */ + @ExcelProperty("文件名称") + private String originalName; + + /** + * 所属业务模块 + */ + @IndexField(exist = false) + private String businessModule; + + @IndexField(fieldType = FieldType.KEYWORD) + private String analysisResultId; + + /** + * 文件导入结果 + */ + private String result; + + private String ossId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/OtherInformation.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/OtherInformation.java new file mode 100644 index 0000000..e1fab68 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/OtherInformation.java @@ -0,0 +1,58 @@ +package com.inscloudtech.datacenter.domain; + + +import cn.hutool.core.lang.UUID; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.*; +import com.inscloudtech.common.annotation.UpdateValueLog; +import com.inscloudtech.common.core.domain.BaseEntity; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.Analyzer; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.RefreshPolicy; + +/** + * 重点人员资产-其他资产信息 + * + * @author inscloudtech + * @date 2023-11-09 + */ +@Data +@IndexName(value = "dc_other_information",refreshPolicy = RefreshPolicy.IMMEDIATE) +@TableName("dc_other_information") +@ExcelIgnoreUnannotated +public class OtherInformation extends BaseEntity { + + @IndexField(fieldType = FieldType.TEXT) + private String content; + + @TableId(type = IdType.ASSIGN_ID) + @IndexId(type = org.dromara.easyes.annotation.rely.IdType.CUSTOMIZE) + private String id; + + @IndexField(fieldType = FieldType.KEYWORD,strategy = org.dromara.easyes.annotation.rely.FieldStrategy.IGNORED) + private String caseId; + + /** + * 背景色 + */ + @UpdateValueLog(fieldName = "背景色") + @IndexField(fieldType = FieldType.KEYWORD,strategy = org.dromara.easyes.annotation.rely.FieldStrategy.IGNORED) + @TableField(updateStrategy = FieldStrategy.IGNORED) + private String bgc; + + /** + * 文件名称 + */ + @ExcelProperty("文件名称") + private String originalName; + + @IndexField(fieldType = FieldType.KEYWORD) + private String analysisResultId; + + private String ossId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/PlateNumberInfo.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/PlateNumberInfo.java new file mode 100644 index 0000000..373bc56 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/PlateNumberInfo.java @@ -0,0 +1,95 @@ +package com.inscloudtech.datacenter.domain; + + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.*; +import com.inscloudtech.common.annotation.DeduplicationField; +import com.inscloudtech.common.annotation.UpdateValueLog; +import com.inscloudtech.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.RefreshPolicy; + +/** + * 车牌抓取 + * + * @author inscloudtech + * @date 2023-11-09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ExcelIgnoreUnannotated +@IndexName(value = "dc_plate_number",refreshPolicy = RefreshPolicy.IMMEDIATE) +public class PlateNumberInfo extends BaseEntity { + + /** id */ + @TableId(type = IdType.ASSIGN_ID) + @IndexId(type = org.dromara.easyes.annotation.rely.IdType.CUSTOMIZE) + private String id; + /** + * 姓名 + */ + @UpdateValueLog(fieldName = "车牌号") + @ExcelProperty("车牌号") + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD_TEXT) + private String plateNumber; + + + /** + * 银行流水所有人 + */ + @ExcelProperty("银行流水所有人") + @DeduplicationField + @UpdateValueLog(fieldName = "银行流水所有人") + private String bsHolder; + + + /** + * 来源文件 + */ + @ExcelProperty("来源文件") + @UpdateValueLog(fieldName = "来源文件") + @IndexField(fieldType = FieldType.KEYWORD) + private String sourceFile; + + + /** + * 车牌号出现字段引用 + */ + @ExcelProperty("车牌号出现字段引用") + @UpdateValueLog(fieldName = "车牌号出现字段引用") + @IndexField(fieldType = FieldType.KEYWORD_TEXT) + private String sourceContent; + /** + * 实际持有人 + */ + @UpdateValueLog(fieldName = "实际持有人") + @ExcelProperty("实际持有人") + private String holder; + + /** + * 备注 + */ + @UpdateValueLog(fieldName = "备注") + @ExcelProperty("备注") + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @TableField(updateStrategy = FieldStrategy.IGNORED) + private String remark; + + private String bankName; + + @DeduplicationField + private String caseId; + + private Integer hasDeal; + + @IndexField(fieldType = FieldType.KEYWORD) + private String analysisResultId; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/PublicFamily.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/PublicFamily.java new file mode 100644 index 0000000..2d5b1d1 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/PublicFamily.java @@ -0,0 +1,457 @@ +package com.inscloudtech.datacenter.domain; + + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.inscloudtech.common.annotation.DeduplicationField; +import com.inscloudtech.common.annotation.IdCardField; +import com.inscloudtech.common.annotation.NameField; +import com.inscloudtech.common.annotation.UpdateValueLog; +import com.inscloudtech.common.core.domain.BaseEntity; +import com.inscloudtech.datacenter.service.QueryCenterService; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.easyes.annotation.HighLight; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.Analyzer; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.RefreshPolicy; + +import javax.validation.constraints.Size; + +/** + * 数据中心-职工家属对象 dc_public_family + * + * @author inscloudtech + * @date 2023-11-09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("dc_public_family") +@IndexName(value = "dc_public_family",refreshPolicy = RefreshPolicy.IMMEDIATE) +@ExcelIgnoreUnannotated +public class PublicFamily extends BaseEntity { + + /** + * id + */ + @TableId(type = IdType.ASSIGN_ID) + @IndexId(type = org.dromara.easyes.annotation.rely.IdType.CUSTOMIZE) + private String id; + /** + * 企业名字 + */ + @DeduplicationField + @UpdateValueLog(fieldName = "企业名字") + @ExcelProperty("企业名字") + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "enterpriseNameHighlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String enterpriseName; + + @JsonIgnore + @TableField(exist = false) + private String enterpriseNameHighlight; + + @DeduplicationField + @UpdateValueLog(fieldName = "姓名") + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "nameHighlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + @ExcelProperty("姓名") + private String name; + + + @JsonIgnore + @TableField(exist = false) + private String nameHighlight; + + + @DeduplicationField + @UpdateValueLog(fieldName = "身份证号") + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "idCardHighlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + @ExcelProperty("身份证号") + private String idCard; + + @JsonIgnore + @TableField(exist = false) + private String idCardHighlight; + + @DeduplicationField + @UpdateValueLog(fieldName = "职务") + @ExcelProperty("职务") + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "deptPostHighlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String deptPost; + + @JsonIgnore + @TableField(exist = false) + private String deptPostHighlight; + + @UpdateValueLog(fieldName = "主要家庭成员1姓名") + @NameField + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "memberName1Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + @ExcelProperty("主要家庭成员1姓名") + private String memberName1; + + @JsonIgnore + @TableField(exist = false) + private String memberName1Highlight; + + @UpdateValueLog(fieldName = "主要家庭成员1关系") + @ExcelProperty("主要家庭成员1关系") + @DeduplicationField + @Size(max = 10, message = "主要家庭成员1关系长度不能超过10") + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "memberRelation1Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String memberRelation1; + + @JsonIgnore + @TableField(exist = false) + private String memberRelation1Highlight; + + @UpdateValueLog(fieldName = "主要家庭成员1身份证号") + @ExcelProperty("主要家庭成员1身份证号") + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "memberIdCard1Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + @IdCardField + @DeduplicationField + @Size(max = 18, message = "主要家庭成员1身份证号长度不能超过18") + private String memberIdCard1; + + @JsonIgnore + @TableField(exist = false) + private String memberIdCard1Highlight; + + @UpdateValueLog(fieldName = "主要家庭成员1公司及职务") + @ExcelProperty("主要家庭成员1公司及职务") + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "deptPost1Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String deptPost1; + + @JsonIgnore + @TableField(exist = false) + private String deptPost1Highlight; + + @UpdateValueLog(fieldName = "主要家庭成员2姓名") + @NameField + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "memberName2Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + @ExcelProperty("主要家庭成员2姓名") + private String memberName2; + + @JsonIgnore + @TableField(exist = false) + private String memberName2Highlight; + + + @DeduplicationField + @UpdateValueLog(fieldName = "主要家庭成员2关系") + @ExcelProperty("主要家庭成员2关系") + @Size(max = 10, message = "主要家庭成员2关系长度不能超过10") + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "memberRelation2Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String memberRelation2; + + @JsonIgnore + @TableField(exist = false) + private String memberRelation2Highlight; + + @UpdateValueLog(fieldName = "主要家庭成员2身份证号") + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "memberIdCard2Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + @IdCardField + @ExcelProperty("主要家庭成员2身份证号") + @Size(max = 18, message = "主要家庭成员2身份证号长度不能超过18") + @DeduplicationField + private String memberIdCard2; + + @JsonIgnore + @TableField(exist = false) + private String memberIdCard2Highlight; + + @DeduplicationField + @UpdateValueLog(fieldName = "主要家庭成员2公司及职务") + @ExcelProperty("主要家庭成员2公司及职务") + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "deptPost2Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String deptPost2; + + @JsonIgnore + @TableField(exist = false) + private String deptPost2Highlight; + + @DeduplicationField + @UpdateValueLog(fieldName = "主要家庭成员3姓名") + @NameField + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "memberName3Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + @ExcelProperty("主要家庭成员3姓名") + private String memberName3; + + @JsonIgnore + @TableField(exist = false) + private String memberName3Highlight; + + @DeduplicationField + @UpdateValueLog(fieldName = "主要家庭成员3关系") + @ExcelProperty("主要家庭成员3关系") + @Size(max = 10, message = "主要家庭成员3关系长度不能超过10") + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "memberRelation3Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String memberRelation3; + + @JsonIgnore + @TableField(exist = false) + private String memberRelation3Highlight; + + @DeduplicationField + @UpdateValueLog(fieldName = "主要家庭成员3身份证号") + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "memberIdCard3Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + @ExcelProperty("主要家庭成员3身份证号") + @IdCardField + @Size(max = 18, message = "主要家庭成员3身份证号长度不能超过18") + private String memberIdCard3; + + @JsonIgnore + @TableField(exist = false) + private String memberIdCard3Highlight; + + @UpdateValueLog(fieldName = "主要家庭成员3公司及职务") + @ExcelProperty("主要家庭成员3公司及职务") + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "deptPost3Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String deptPost3; + + @JsonIgnore + @TableField(exist = false) + private String deptPost3Highlight; + + @UpdateValueLog(fieldName = "主要家庭成员4姓名") + @NameField + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "memberName4Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + @ExcelProperty("主要家庭成员4姓名") + private String memberName4; + + @JsonIgnore + @TableField(exist = false) + private String memberName4Highlight; + + @UpdateValueLog(fieldName = "主要家庭成员4关系") + @ExcelProperty("主要家庭成员4关系") + @DeduplicationField + @Size(max = 10, message = "主要家庭成员4关系长度不能超过10") + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "memberRelation4Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String memberRelation4; + + @JsonIgnore + @TableField(exist = false) + private String memberRelation4Highlight; + + @UpdateValueLog(fieldName = "主要家庭成员4身份证号") + @ExcelProperty("主要家庭成员4身份证号") + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "memberIdCard4Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + @IdCardField + @Size(max = 18, message = "主要家庭成员4身份证号长度不能超过18") + private String memberIdCard4; + + @JsonIgnore + @TableField(exist = false) + private String memberIdCard4Highlight; + + @UpdateValueLog(fieldName = "主要家庭成员4公司及职务") + @ExcelProperty("主要家庭成员4公司及职务") + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "deptPost4Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String deptPost4; + + @JsonIgnore + @TableField(exist = false) + private String deptPost4Highlight; + + @UpdateValueLog(fieldName = "主要家庭成员5姓名") + @NameField + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "memberName5Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + @ExcelProperty("主要家庭成员5姓名") + private String memberName5; + + @JsonIgnore + @TableField(exist = false) + private String memberName5Highlight; + + @UpdateValueLog(fieldName = "主要家庭成员5关系") + @ExcelProperty("主要家庭成员5关系") + @DeduplicationField + @Size(max = 10, message = "主要家庭成员5关系长度不能超过10") + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "memberRelation5Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String memberRelation5; + + @JsonIgnore + @TableField(exist = false) + private String memberRelation5Highlight; + + @UpdateValueLog(fieldName = "主要家庭成员5身份证号") + @ExcelProperty("主要家庭成员5身份证号") + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "memberIdCard5Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + @IdCardField + @Size(max = 18, message = "主要家庭成员5身份证号长度不能超过18") + private String memberIdCard5; + + @JsonIgnore + @TableField(exist = false) + private String memberIdCard5Highlight; + + @UpdateValueLog(fieldName = "主要家庭成员5公司及职务") + @ExcelProperty("主要家庭成员5公司及职务") + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "deptPost5Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String deptPost5; + + @JsonIgnore + @TableField(exist = false) + private String deptPost5Highlight; + + + @UpdateValueLog(fieldName = "主要家庭成员6姓名") + @NameField + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "memberName6Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + @ExcelProperty("主要家庭成员6姓名") + private String memberName6; + + @JsonIgnore + @TableField(exist = false) + private String memberName6Highlight; + + @UpdateValueLog(fieldName = "主要家庭成员6关系") + @ExcelProperty("主要家庭成员6关系") + @DeduplicationField + @Size(max = 10, message = "主要家庭成员6关系长度不能超过10") + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "memberRelation6Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String memberRelation6; + + @JsonIgnore + @TableField(exist = false) + private String memberRelation6Highlight; + + @UpdateValueLog(fieldName = "主要家庭成员6身份证号") + @ExcelProperty("主要家庭成员6身份证号") + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "memberIdCard6Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + @IdCardField + @Size(max = 18, message = "主要家庭成员6身份证号长度不能超过18") + private String memberIdCard6; + + @JsonIgnore + @TableField(exist = false) + private String memberIdCard6Highlight; + + @UpdateValueLog(fieldName = "主要家庭成员6公司及职务") + @ExcelProperty("主要家庭成员6公司及职务") + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "deptPost6Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String deptPost6; + + @JsonIgnore + @TableField(exist = false) + private String deptPost6Highlight; + + @UpdateValueLog(fieldName = "主要家庭成员7姓名") + @NameField + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "memberName7Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + @ExcelProperty("主要家庭成员7姓名") + private String memberName7; + + @JsonIgnore + @TableField(exist = false) + private String memberName7Highlight; + + @UpdateValueLog(fieldName = "主要家庭成员7关系") + @ExcelProperty("主要家庭成员7关系") + @DeduplicationField + @Size(max = 10, message = "主要家庭成员7关系长度不能超过10") + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "memberRelation7Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String memberRelation7; + + @JsonIgnore + @TableField(exist = false) + private String memberRelation7Highlight; + + @UpdateValueLog(fieldName = "主要家庭成员7身份证号") + @ExcelProperty("主要家庭成员7身份证号") + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "memberIdCard7Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + @IdCardField + @Size(max = 18, message = "主要家庭成员7身份证号长度不能超过18") + private String memberIdCard7; + + @JsonIgnore + @TableField(exist = false) + private String memberIdCard7Highlight; + + @UpdateValueLog(fieldName = "主要家庭成员7公司及职务") + @ExcelProperty("主要家庭成员7公司及职务") + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "deptPost7Highlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String deptPost7; + + @JsonIgnore + @TableField(exist = false) + private String deptPost7Highlight; + + @ExcelProperty("备注") + @UpdateValueLog(fieldName = "备注") + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "remarkHighlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + @TableField(updateStrategy = FieldStrategy.IGNORED) + private String remark; + + @JsonIgnore + @TableField(exist = false) + private String remarkHighlight; + + private String caseId; + /** + * 背景色 + */ + @UpdateValueLog(fieldName = "背景色") + @TableField(updateStrategy = FieldStrategy.IGNORED) + @IndexField(fieldType = FieldType.KEYWORD,strategy = org.dromara.easyes.annotation.rely.FieldStrategy.IGNORED) + private String bgc; + + + /** 分析成果id */ + @IndexField(fieldType = FieldType.KEYWORD) + private String analysisResultId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/RealEstate.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/RealEstate.java new file mode 100644 index 0000000..e84083e --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/RealEstate.java @@ -0,0 +1,112 @@ +package com.inscloudtech.datacenter.domain; + + + +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.*; +import com.inscloudtech.common.annotation.*; + +import com.inscloudtech.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.RefreshPolicy; + +import java.math.BigDecimal; + + +/** + * 重点人员资产-不动产信息对象 dc_real_estate + * + * @author inscloudtech + * @date 2023-11-09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("dc_real_estate") +@IndexName(value = "dc_real_estate",refreshPolicy = RefreshPolicy.IMMEDIATE) +@ExcelIgnoreUnannotated +public class RealEstate extends BaseEntity { + + /** id */ + @TableId(type = IdType.ASSIGN_ID) + @IndexId(type = org.dromara.easyes.annotation.rely.IdType.CUSTOMIZE) + private String id; + /** + * 姓名 + */ + @ExcelProperty("姓名") + @DeduplicationField + @UpdateValueLog(fieldName = "姓名") + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + private String name; + /** + * 房产地址 + */ + @ExcelProperty("房产地址") + @DeduplicationField + @UpdateValueLog(fieldName = "房产地址") + @IndexField(fieldType = FieldType.KEYWORD) + private String address; + /** + * 面积m2 + */ + @ExcelProperty("面积m2") + @DeduplicationField + @UpdateValueLog(fieldName = "面积m2") + @IndexField(fieldType = FieldType.DOUBLE) + private BigDecimal area; + + @ExcelProperty("购买价格") + @DeduplicationField + @UpdateValueLog(fieldName = "购买价格") + @IndexField(fieldType = FieldType.DOUBLE) + private BigDecimal valuation; + /** + * 产权转让信息 + */ + @DeduplicationField + @ExcelProperty("产权转让信息") + @UpdateValueLog(fieldName = "产权转让信息") + @IdCardField + @NameField + @IndexField(fieldType = FieldType.KEYWORD) + private String transferInformation; + /** + * 其他信息 + */ + @DeduplicationField + @ExcelProperty("其他信息") + @UpdateValueLog(fieldName = "其他信息") + @IdCardField + @NameField + @IndexField(fieldType = FieldType.KEYWORD) + private String otherInformation; + + /** + * 备注 + */ + @UpdateValueLog(fieldName = "备注") + @ExcelProperty("备注") + @DeduplicationField + @IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer") + @TableField(updateStrategy = FieldStrategy.IGNORED) + @IdCardField + @NameField + private String remark; + + @UpdateValueLog(fieldName = "bgc") + @TableField(updateStrategy = FieldStrategy.IGNORED) + @IndexField(fieldType = FieldType.KEYWORD) + private String bgc; + + private String caseId; + + @IndexField(fieldType = FieldType.KEYWORD) + private String analysisResultId; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/TransactionPartner.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/TransactionPartner.java new file mode 100644 index 0000000..1484a4d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/TransactionPartner.java @@ -0,0 +1,152 @@ +package com.inscloudtech.datacenter.domain; + + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.inscloudtech.common.annotation.DeduplicationField; + +import com.inscloudtech.common.annotation.NameField; +import com.inscloudtech.common.annotation.UpdateValueLog; +import com.inscloudtech.common.core.domain.BaseEntity; +import com.inscloudtech.datacenter.service.QueryCenterService; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.easyes.annotation.HighLight; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.Analyzer; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.RefreshPolicy; + +import java.math.BigDecimal; + +/** + * 数据中心-交易对象 dc_transaction_partner + * + * @author lingyun + * @date 2023-11-07 + */ +@Data +@TableName(value = "dc_transaction_partner") +@IndexName(value = "dc_transaction_partner",refreshPolicy = RefreshPolicy.IMMEDIATE) +@EqualsAndHashCode(callSuper = true) +@ExcelIgnoreUnannotated +public class TransactionPartner extends BaseEntity { + + /** id */ + @TableId(type = IdType.ASSIGN_ID) + @IndexId(type = org.dromara.easyes.annotation.rely.IdType.CUSTOMIZE) + private String id; + + @DeduplicationField + @ExcelProperty("客商名称") + @UpdateValueLog(fieldName = "客商名称") + @IndexField(fieldType = FieldType.TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "travellingTraderHighlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String travellingTrader; + + @JsonIgnore + @TableField(exist = false) + private String travellingTraderHighlight; + + @DeduplicationField + @ExcelProperty("来往金额") + @UpdateValueLog(fieldName = "来往金额") + @IndexField(fieldType = FieldType.KEYWORD) + @HighLight(mappingField = "transactionAmountHighlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String transactionAmount; + + @JsonIgnore + @TableField(exist = false) + private String transactionAmountHighlight; + + @DeduplicationField + @ExcelProperty("欠款金额") + @UpdateValueLog(fieldName = "欠款金额") + @IndexField(fieldType = FieldType.DOUBLE) + private BigDecimal debt; + + @DeduplicationField + @ExcelProperty("企业组织机构代码") + @UpdateValueLog(fieldName = "企业组织机构代码") + @IndexField(fieldType = FieldType.TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "organizationCodeHighlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String organizationCode; + + @JsonIgnore + @TableField(exist = false) + private String organizationCodeHighlight; + + @DeduplicationField + @ExcelProperty("企业注册地址") + @UpdateValueLog(fieldName = "企业注册地址") + @IndexField(fieldType = FieldType.TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "registeredAddressHighlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String registeredAddress; + + @JsonIgnore + @TableField(exist = false) + private String registeredAddressHighlight; + + @DeduplicationField + @NameField + @ExcelProperty("股东及高管") + @UpdateValueLog(fieldName = "股东及高管") + @IndexField(fieldType = FieldType.TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "stockholderHighlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String stockholder; + + @JsonIgnore + @TableField(exist = false) + private String stockholderHighlight; + + @DeduplicationField + @NameField + @ExcelProperty("关联企业") + @UpdateValueLog(fieldName = "关联企业") + @IndexField(fieldType = FieldType.TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "relateCompanyHighlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String relateCompany; + + @JsonIgnore + @TableField(exist = false) + private String relateCompanyHighlight; + + @DeduplicationField + @UpdateValueLog(fieldName = "关联人") + @ExcelProperty("关联人") + @IndexField(fieldType = FieldType.TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "stockholderRelatedHighlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + private String stockholderRelated; + + @JsonIgnore + @TableField(exist = false) + private String stockholderRelatedHighlight; + + @DeduplicationField + @UpdateValueLog(fieldName = "背景颜色") + @IndexField(fieldType = FieldType.KEYWORD,strategy = org.dromara.easyes.annotation.rely.FieldStrategy.IGNORED) + @TableField(updateStrategy = FieldStrategy.IGNORED) + private String bgc; + + @DeduplicationField + @TableField(updateStrategy = FieldStrategy.IGNORED) + @IndexField(fieldType = FieldType.TEXT, analyzer = "ngram_analyzer") + @HighLight(mappingField = "remarkHighlight",preTag = QueryCenterService.TAG_PREFIX,postTag = QueryCenterService.TAG_SUFFIX) + @ExcelProperty("备注") + private String remark; + + @JsonIgnore + @TableField(exist = false) + private String remarkHighlight; + + /** 案件id */ + private String caseId; + + /** 分析成果id */ + @IndexField(fieldType = FieldType.KEYWORD) + private String analysisResultId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/ImportResultPromptVO.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/ImportResultPromptVO.java new file mode 100644 index 0000000..d95da7d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/ImportResultPromptVO.java @@ -0,0 +1,57 @@ +package com.inscloudtech.datacenter.domain.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * 每次导入时提示:导入成功的银行X家,导入失败的银行X家。失败的是那家银行的那张表。 + */ +@Data +public class ImportResultPromptVO { + + /** + * 成功导入的银行计数 + */ + private int total; + + private int successImportCount; + /** + * 导入文件总数 + */ + private int fileTotalCount; + // 流水文件计数 + private int fileBSTotalCount; + // 开户文件计数 + private int fileOAITotalCount; + //流水文件,zip格式 + private File bsFile; + // 开户文件,zip格式 + private File oaiFile; + /** + * 导入失败银行计数 + */ + private int failedImportCount; + + private String globalCause; + + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private List errorItem = new ArrayList<>(); + + @Data + public static class ImportResultPromptItem { + private String bankName; + // 导入失败后的原因,主要是解析失败 + private String cause; + private List fileList = new ArrayList<>(); + } + + @Data + public static class FileItem { + private String filename; + private String cause; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/OtherAssetsDto.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/OtherAssetsDto.java new file mode 100644 index 0000000..7f8bd58 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/OtherAssetsDto.java @@ -0,0 +1,22 @@ +package com.inscloudtech.datacenter.domain.dto; + + +import lombok.Data; + +/** + * 重点人员资产-其他资产信息 + * + * @author inscloudtech + * @date 2023-11-09 + */ +@Data + +public class OtherAssetsDto { + + private String index; + + private String highlight; + + private String originalName; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/QueryCenterQuery.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/QueryCenterQuery.java new file mode 100644 index 0000000..4c9b9f5 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/QueryCenterQuery.java @@ -0,0 +1,35 @@ +package com.inscloudtech.datacenter.domain.dto; + + +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +@Data +public class QueryCenterQuery { + + /** + * 分页大小 + */ + private Integer pageSize = 10; + + private String searchValue; + + private String name; + + private String idCard; + + private String phone; + + private String caseId; + + private String index; + + private Integer isOther = 0; + + private Object[] nextSearchAfter; + + private String analysisResultId; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/QueryFailedMsgReq.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/QueryFailedMsgReq.java new file mode 100644 index 0000000..5d794c8 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/QueryFailedMsgReq.java @@ -0,0 +1,10 @@ +package com.inscloudtech.datacenter.domain.dto; + +import lombok.Data; + +@Data +public class QueryFailedMsgReq { + private String caseId; + private String ossId; + private String batchId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/StatisticsOption.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/StatisticsOption.java new file mode 100644 index 0000000..77fdac5 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/StatisticsOption.java @@ -0,0 +1,18 @@ +package com.inscloudtech.datacenter.domain.dto; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Data; + +import java.util.List; + +@Data +public class StatisticsOption { + @JsonIgnore + private String field; + + private String label; + + private String value; + + private Long count; +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/StatisticsQuery.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/StatisticsQuery.java new file mode 100644 index 0000000..6c56051 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/StatisticsQuery.java @@ -0,0 +1,21 @@ +package com.inscloudtech.datacenter.domain.dto; + + +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +@Data +public class StatisticsQuery { + @NotNull(message="[分组字段]不能为空") + private List fields; + + @NotNull(message="[业务模块]不能为空") + private String module; + + @NotNull(message="[案件id]不能为空") + private String caseId; + + private String searchValue; +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/StatisticsResult.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/StatisticsResult.java new file mode 100644 index 0000000..21dc5b0 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/StatisticsResult.java @@ -0,0 +1,14 @@ +package com.inscloudtech.datacenter.domain.dto; + +import com.inscloudtech.datacenter.domain.dto.StatisticsOption; +import lombok.Data; + +import java.util.List; + +@Data +public class StatisticsResult { + private String field; + + private List options; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/StatisticsVo.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/StatisticsVo.java new file mode 100644 index 0000000..b7600b3 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/StatisticsVo.java @@ -0,0 +1,13 @@ +package com.inscloudtech.datacenter.domain.dto; + +import lombok.Data; + +@Data +public class StatisticsVo { + + private String module; + + private int fileCount; + + private int dataCount; +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/BankStatementExportAllDto.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/BankStatementExportAllDto.java new file mode 100644 index 0000000..ca471b8 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/BankStatementExportAllDto.java @@ -0,0 +1,107 @@ +package com.inscloudtech.datacenter.domain.dto.export; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.format.NumberFormat; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.math.BigDecimal; +import java.util.Date; + + +@Data +public class BankStatementExportAllDto { + private static final long serialVersionUID = 1L; + + @ExcelProperty("id") + private String id; + + @ExcelProperty("创建者") + private String createBy; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @ExcelProperty("创建时间") + private Date createTime; + + @ExcelProperty("更新者") + private String updateBy; + + @ExcelProperty("更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + + @ExcelProperty("备注") + private String remark; + + + @ExcelProperty("bgc") + private String bgc; + + @ExcelProperty("caseId") + private String caseId; + + @ExcelProperty("analysisResultId") + private String analysisResultId; + + @ExcelProperty(value = "银行名称") + private String bankName; + + @ExcelProperty(value = "持卡人姓名") + private String cardHolderName; + + @ExcelProperty("身份证号") + private String idCardNo; + + @ExcelProperty("交易卡号") + private String cardNumber; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @ExcelProperty("交易时间") + private Date transactionTime; + + @ExcelProperty("交易金额") + private BigDecimal transactionAmount; + + @ExcelProperty("账户余额") + @NumberFormat("#.00") + private BigDecimal balance; + + @ExcelProperty("交易机构名称") + private String transactionInstitutions; + + @ExcelProperty("对方户名") + private String counterpartyName; + + @ExcelProperty("对方账号") + private String counterpartyAccount; + + @ExcelProperty(value = "对方身份证号") + private String counterpartIdCardNo; + + @ExcelProperty("对方行名") + private String counterpartyBankName; + + @ExcelProperty("摘要") + private String summary; + + @ExcelProperty("交易备注") + private String transRemark; + + @ExcelProperty("交易渠道") + private String transChannel; + + @ExcelProperty("真实交易对手名称") + private String realCounterpartyName; + + @ExcelProperty("真实交易对手账号") + private String realCounterpartyAccount; + + @ExcelProperty("电话号码") + private String phone; + + @ExcelProperty("交易币种") + private Integer transCurrencyType; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/CarInfoExportAllDto.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/CarInfoExportAllDto.java new file mode 100644 index 0000000..7994d5b --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/CarInfoExportAllDto.java @@ -0,0 +1,39 @@ +package com.inscloudtech.datacenter.domain.dto.export; + + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.core.domain.ExportBaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 重点人员资产-车辆信息对象 dc_car_info + * + * @author inscloudtech + * @date 2023-11-09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ExcelIgnoreUnannotated +public class CarInfoExportAllDto extends ExportBaseEntity { + + @ExcelProperty("姓名") + private String name; + + @ExcelProperty("身份证号") + private String idCard; + + @ExcelProperty("车牌号") + private String carNo; + + @ExcelProperty("车型") + private String carType; + + @ExcelProperty("转让登记") + private String registration; + + @ExcelProperty("车辆停放及登记地址") + private String address; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/OpeningAccountInfoExportAllDto.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/OpeningAccountInfoExportAllDto.java new file mode 100644 index 0000000..f99005e --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/OpeningAccountInfoExportAllDto.java @@ -0,0 +1,94 @@ +package com.inscloudtech.datacenter.domain.dto.export; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.util.Date; + + +@ExcelIgnoreUnannotated +@Data +public class OpeningAccountInfoExportAllDto { + + private static final long serialVersionUID = 1L; + + @ExcelProperty("id") + private String id; + + @ExcelProperty(value = "户名") + private String name; + + @ExcelProperty(value = "银行名称") + private String bankName; + + @ExcelProperty(value = "新账号") + private String newAccountNumber; + + @ExcelProperty(value = "账号") + private String accountNumber; + + @ExcelProperty(value = "证件类型") + private String idType; + + @ExcelProperty(value = "证件号码") + private String idNo; + + @ExcelProperty(value = "电话号码") + private String phone; + + @ExcelProperty(value = "地址") + private String address; + + @ExcelProperty(value = "开户日期") + private String openingAccountDate; + + @ExcelProperty(value = "销户日期") + private String closingDate; + + @ExcelProperty(value = "账户状态") + private String status; + + @ExcelProperty(value = "账户类型") + private String type; + + @ExcelProperty(value = "冻结信息") + private String freezeInfo; + + @ExcelProperty(value = "冻结日期") + private String freezeDate; + + @ExcelProperty("备注") + private String remark; + + @ExcelProperty("网银签约信息") + private String onlineBankingSigningInfo; + + @ExcelProperty(value = "开户机构") + private String accountOpeningInstitution; + + @ExcelProperty("创建者") + private String createBy; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @ExcelProperty("创建时间") + private Date createTime; + + @ExcelProperty("更新者") + private String updateBy; + + @ExcelProperty("更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + + @ExcelProperty("bgc") + private String bgc; + + @ExcelProperty("caseId") + private String caseId; + + @ExcelProperty("analysisResultId") + private String analysisResultId; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/OtherAssetsExportAllDto.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/OtherAssetsExportAllDto.java new file mode 100644 index 0000000..96558ac --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/OtherAssetsExportAllDto.java @@ -0,0 +1,32 @@ +package com.inscloudtech.datacenter.domain.dto.export; + + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.*; +import com.inscloudtech.common.annotation.UpdateValueLog; +import com.inscloudtech.common.core.domain.BaseEntity; +import com.inscloudtech.common.core.domain.ExportBaseEntity; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.RefreshPolicy; + +/** + * 重点人员资产-其他资产信息 + * + * @author inscloudtech + * @date 2023-11-09 + */ +@Data +public class OtherAssetsExportAllDto extends ExportBaseEntity { + + @ExcelProperty("content") + private String content; + + @ExcelProperty("文件名称") + private String originalName; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/OtherInformationExportAllDto.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/OtherInformationExportAllDto.java new file mode 100644 index 0000000..1229207 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/OtherInformationExportAllDto.java @@ -0,0 +1,31 @@ +package com.inscloudtech.datacenter.domain.dto.export; + + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.*; +import com.inscloudtech.common.annotation.UpdateValueLog; +import com.inscloudtech.common.core.domain.BaseEntity; +import com.inscloudtech.common.core.domain.ExportBaseEntity; +import lombok.Data; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.RefreshPolicy; + +/** + * 重点人员资产-其他资产信息 + * + * @author inscloudtech + * @date 2023-11-09 + */ +@Data +public class OtherInformationExportAllDto extends ExportBaseEntity { + + @ExcelProperty("content") + private String content; + + @ExcelProperty("文件名称") + private String originalName; +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/PlateNumberInfoExportAllDto.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/PlateNumberInfoExportAllDto.java new file mode 100644 index 0000000..c1088b8 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/PlateNumberInfoExportAllDto.java @@ -0,0 +1,60 @@ +package com.inscloudtech.datacenter.domain.dto.export; + + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.FieldStrategy; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.inscloudtech.common.annotation.DeduplicationField; +import com.inscloudtech.common.annotation.UpdateValueLog; +import com.inscloudtech.common.core.domain.ExportBaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.rely.FieldType; + +/** + * 重点人员资产-车辆信息对象 dc_car_info + * + * @author inscloudtech + * @date 2023-11-09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ExcelIgnoreUnannotated +public class PlateNumberInfoExportAllDto extends ExportBaseEntity { + + @ExcelProperty("车牌号") + private String plateNumber; + + @ExcelProperty("银行流水所有人") + private String bsHolder; + + @ExcelProperty("来源文件") + private String sourceFile; + + @ExcelProperty("车牌号出现字段引用") + private String sourceContent; + + @ExcelProperty("实际持有人") + private String holder; + + @ExcelProperty("备注") + private String remark; + + @ExcelProperty("银行名称") + private String bankName; + + @ExcelProperty("caseId") + private String caseId; + + @ExcelProperty("hasDeal") + private Integer hasDeal; + + @ExcelProperty("analysisResultId") + private String analysisResultId; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/PublicFamilyExportAllDto.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/PublicFamilyExportAllDto.java new file mode 100644 index 0000000..6837530 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/PublicFamilyExportAllDto.java @@ -0,0 +1,108 @@ +package com.inscloudtech.datacenter.domain.dto.export; + + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.*; +import com.inscloudtech.common.annotation.IdCardField; +import com.inscloudtech.common.annotation.NameField; +import com.inscloudtech.common.annotation.UpdateValueLog; +import com.inscloudtech.common.core.domain.BaseEntity; +import com.inscloudtech.common.core.domain.ExportBaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.RefreshPolicy; + +/** + * 数据中心-职工家属对象 dc_public_family + * + * @author inscloudtech + * @date 2023-11-09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ExcelIgnoreUnannotated +public class PublicFamilyExportAllDto extends ExportBaseEntity { + + @ExcelProperty("企业名字") + private String enterpriseName; + + @ExcelProperty("姓名") + private String name; + + @ExcelProperty("身份证号") + private String idCard; + + @ExcelProperty("主要家庭成员1姓名") + private String memberName1; + + @ExcelProperty("主要家庭成员1关系") + private String memberRelation1; + + @ExcelProperty("主要家庭成员1身份证号") + private String memberIdCard1; + + @ExcelProperty("主要家庭成员2姓名") + private String memberName2; + + @ExcelProperty("主要家庭成员2关系") + private String memberRelation2; + + @ExcelProperty("主要家庭成员2身份证号") + private String memberIdCard2; + + @ExcelProperty("主要家庭成员3姓名") + private String memberName3; + + @ExcelProperty("主要家庭成员3关系") + private String memberRelation3; + + @ExcelProperty("主要家庭成员3身份证号") + private String memberIdCard3; + + @ExcelProperty("主要家庭成员4姓名") + private String memberName4; + + @ExcelProperty("主要家庭成员4关系") + private String memberRelation4; + + @ExcelProperty("主要家庭成员4身份证号") + private String memberIdCard4; + + @ExcelProperty("主要家庭成员5姓名") + private String memberName5; + + @ExcelProperty("主要家庭成员5关系") + private String memberRelation5; + + @ExcelProperty("主要家庭成员5身份证号") + private String memberIdCard5; + + + + + @ExcelProperty("主要家庭成员6姓名") + private String memberName6; + + @ExcelProperty("主要家庭成员6关系") + private String memberRelation6; + + @ExcelProperty("主要家庭成员6身份证号") + private String memberIdCard6; + + + + + @ExcelProperty("主要家庭成员7姓名") + private String memberName7; + + @ExcelProperty("主要家庭成员7关系") + private String memberRelation7; + + @ExcelProperty("主要家庭成员7身份证号") + private String memberIdCard7; +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/RealEstateExportAllDto.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/RealEstateExportAllDto.java new file mode 100644 index 0000000..614f7e4 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/RealEstateExportAllDto.java @@ -0,0 +1,51 @@ +package com.inscloudtech.datacenter.domain.dto.export; + + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.*; +import com.inscloudtech.common.annotation.IdCardField; +import com.inscloudtech.common.annotation.NameField; +import com.inscloudtech.common.annotation.UpdateValueLog; +import com.inscloudtech.common.core.domain.BaseEntity; +import com.inscloudtech.common.core.domain.ExportBaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.easyes.annotation.IndexField; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.FieldType; +import org.dromara.easyes.annotation.rely.RefreshPolicy; + +import java.math.BigDecimal; + + +/** + * 重点人员资产-不动产信息对象 dc_real_estate + * + * @author inscloudtech + * @date 2023-11-09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ExcelIgnoreUnannotated +public class RealEstateExportAllDto extends ExportBaseEntity { + + @ExcelProperty("姓名") + private String name; + + @ExcelProperty("房产地址") + private String address; + + @ExcelProperty("面积m2") + private BigDecimal area; + + @ExcelProperty("购买价格") + private BigDecimal valuation; + + @ExcelProperty("产权转让信息") + private String transferInformation; + + @ExcelProperty("其他信息") + private String otherInformation; +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/TransactionPartnerExportAllDto.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/TransactionPartnerExportAllDto.java new file mode 100644 index 0000000..aff3887 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/dto/export/TransactionPartnerExportAllDto.java @@ -0,0 +1,46 @@ +package com.inscloudtech.datacenter.domain.dto.export; + + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.core.domain.ExportBaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; + +/** + * 数据中心-交易对象 dc_transaction_partner + * + * @author lingyun + * @date 2023-11-07 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ExcelIgnoreUnannotated +public class TransactionPartnerExportAllDto extends ExportBaseEntity { + + @ExcelProperty("客商名称") + private String travellingTrader; + + @ExcelProperty("来往金额") + private BigDecimal transactionAmount; + + @ExcelProperty("欠款金额") + private BigDecimal debt; + + @ExcelProperty("企业组织机构代码") + private String organizationCode; + + @ExcelProperty("企业注册地址") + private String registeredAddress; + + @ExcelProperty("股东及高管") + private String stockholder; + + @ExcelProperty("关联企业") + private String relateCompany; + + @ExcelProperty("关联人") + private String stockholderRelated; +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/vo/BankListItem.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/vo/BankListItem.java new file mode 100644 index 0000000..db4aae7 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/vo/BankListItem.java @@ -0,0 +1,17 @@ +package com.inscloudtech.datacenter.domain.vo; + +import lombok.Data; + +/** + * 返回银行信息 + */ +@Data +public class BankListItem { + private String bankNo; + private String bankName; + + public BankListItem(String bankNo, String bankName) { + this.bankNo = bankNo; + this.bankName = bankName; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/vo/GetBSFieldValueCountReq.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/vo/GetBSFieldValueCountReq.java new file mode 100644 index 0000000..44eff42 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/vo/GetBSFieldValueCountReq.java @@ -0,0 +1,116 @@ +package com.inscloudtech.datacenter.domain.vo; + +import com.baomidou.mybatisplus.annotation.TableField; +// +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.util.*; + +@Data +public class GetBSFieldValueCountReq { + @NotNull(message = "[分组字段]不能为空") + private List fields; + /** + * 没用 + */ + @NotNull(message = "[业务模块]不能为空") + private String module; + + // 查询条件 + @NotNull(message = "[案件id]不能为空") + private String caseId; + + private String bankName; + private String cardHolderName; + private String idCardNo; + private String cardNumber; + + private String beginTransactionTime; + private String endTransactionTime; + + private BigDecimal beginBalance; + private BigDecimal endBalance; + + private BigDecimal beginTransactionAmount; + private BigDecimal endTransactionAmount; + + private String transactionInstitutions; + private String counterpartyName; + private String counterpartyAccount; + private String counterpartIdCardNo; + private String counterpartyBankName; + private String summary; + private String transRemark; + private String transChannel; + private String realCounterpartyName; + private String realCounterpartyAccount; + + /** + * 银行名称列表 + */ + //odelProperty("银行名称列表") + private List bankNameList; + + //odelProperty("持卡人姓名列表") + private List cardHolderNameList; + + //odelProperty("身份证号列表") + private List idCardNoList; + + //odelProperty("交易卡号列表") + private List cardNumberList; + + //odelProperty("交易机构列表") + private List transactionInstitutionsList; + + //odelProperty("对方户名列表") + private List counterpartyNameList; + + //odelProperty("对方账号列表") + private List counterpartyAccountList; + + //odelProperty("对方身份证号列表") + private List counterpartIdCardNoList; + + //odelProperty("对方行名列表") + private List counterpartyBankNameList; + + //odelProperty("摘要列表") + private List summaryList; + + //odelProperty("交易备注列表") + private List transRemarkList; + + //odelProperty("交易渠道列表") + private List transChannelList; + + //odelProperty("真实交易对手名称列表") + private List realCounterpartyNameList; + + //odelProperty("真实交易对手账号列表") + private List realCounterpartyAccountList; + + //odelProperty("备注列表") + private List remarkList; + /** + * 备注 + */ + private String remark; + + private String searchValue; // 查询条件 +// private Params params = new Params(); + + private Map params; + + private Integer downloadTemplate; + + private String analysisResultId; + + @TableField(exist = false) + private List ids = new ArrayList<>(); + + private Set cardHolderNameSet = new HashSet(); + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/vo/GetBankStatementListReq.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/vo/GetBankStatementListReq.java new file mode 100644 index 0000000..6537a31 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/vo/GetBankStatementListReq.java @@ -0,0 +1,213 @@ +package com.inscloudtech.datacenter.domain.vo; + +import lombok.Data; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +//("获取银行流水列表参数") +@Data +public class GetBankStatementListReq { + + /** + * 主键,编号 + */ + //Property("编号") + private String id; + + /** + * 银行Id + */ + private String bankId; + + /** + * 银行名称 + */ + //Property("银行名称") + private String bankName; + + /** + * 银行名称列表 + */ + //Property("银行名称列表") + private List bankNameList; + + //Property("持卡人姓名列表") + private List cardHolderNameList; + + //Property("身份证号列表") + private List idCardNoList; + + //Property("交易卡号列表") + private List cardNumberList; + + //Property("交易机构列表") + private List transactionInstitutionsList; + + //Property("对方户名列表") + private List counterpartyNameList; + + //Property("对方账号列表") + private List counterpartyAccountList; + + //Property("对方身份证号列表") + private List counterpartIdCardNoList; + + //Property("对方行名列表") + private List counterpartyBankNameList; + + //Property("摘要列表") + private List summaryList; + + //Property("交易备注列表") + private List transRemarkList; + + //Property("交易渠道列表") + private List transChannelList; + + //Property("真实交易对手名称列表") + private List realCounterpartyNameList; + + //Property("真实交易对手账号列表") + private List realCounterpartyAccountList; + + //Property("备注列表") + private List remarkList; + + + + + + //Property("持卡人姓名") + private String cardHolderName; + + /** + * 身份证号 + */ + //Property("身份证号") + private String idCardNo; + + /** + * 电话号码 + */ + //Property("电话号码") + private String phone; + + /** + * 卡号 + */ + //Property("卡号") + private String cardNumber; + + /** + * 交易对手名称 + */ + //Property("交易对手名称") + private String counterpartyName; + // 对方账号 + private String counterpartyAccount; + + /** + * 交易对手身份证号 + */ + //Property("交易对手身份证号") + private String counterpartIdCardNo; + + /** + * 交易金额 + */ + private BigDecimal transactionAmount; + + //Property("交易时间-开始") + private BigDecimal beginTransactionAmount; + + //Property("交易时间-结束") + private BigDecimal endTransactionAmount; + + /** + * 余额 + */ + private BigDecimal balance; + + //Property("余额-开始") + private BigDecimal beginBalance; + + //Property("余额-结束") + private BigDecimal endBalance; + + /** + * 交易时间筛选-开始时间 + */ + //Property("交易时间筛选-开始时间") + private String beginTransactionTime; + /** + * 交易时间筛选-结束时间 + */ + //Property("交易时间筛选-结束时间") + private String endTransactionTime; + + private String counterpartyBankName; + + private String summary; + + private String transRemark; + + private String transChannel; + + private String realCounterpartyName; + + private String realCounterpartyAccount; + + // 交易机构 + private String transactionInstitutions; + + /** + * 分页参数-当前页数 + */ + //Property("分页参数-当前页数") + private int pageNum; + /** + * 分页参数-每一页条数 + */ + //Property("分页参数-每一页条数") + private int pageSize; + + /** + * 排序 + */ + //Property("排序") + private Object sort; + + private String searchValue; // 查询条件 + + private List sortKeyDesc = new ArrayList<>(); + private List sortKeyAsc = new ArrayList<>(); + + private List sortKeys = new ArrayList<>(); + + private String orderByColumn; + + private String isAsc; + + private String analysisResultId; + + /** + * 案件Id + */ + private String caseId; + + private Params params = new Params(); + + private String remark; + + @Data + public static class Params { + private BigDecimal beginTransactionAmount; + private BigDecimal endTransactionAmount; + private String beginTransactionTime; + private String endTransactionTime; + private BigDecimal endBalance; + private BigDecimal beginBalance; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/vo/GetOpeningAccountInfoListReq.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/vo/GetOpeningAccountInfoListReq.java new file mode 100644 index 0000000..85f281e --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/vo/GetOpeningAccountInfoListReq.java @@ -0,0 +1,151 @@ +package com.inscloudtech.datacenter.domain.vo; + +import com.baomidou.mybatisplus.annotation.TableField; + +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +//"获取银行开户信息列表参数") +@Data +public class GetOpeningAccountInfoListReq { + + /** + * 主键,编号 + */ + //"编号") + private String id; + + /** + * 银行Id + */ + private String bankId; + + /** + * 银行名称 + */ + //"银行名称") + private String bankName; + + //"持卡人姓名") + private String name; + + private String idType; + /** + * 身份证号 + */ + //"身份证号") + private String idNo; + + /** + * 电话号码 + */ + //"电话号码") + private String phone; + + /** + * 卡号 + */ + //"卡号") + private String accountNumber; + + private String newAccountNumber; + + private String address; + + private String remark; + + private String accountOpeningInstitution; + + private String status; + + private String freezeInfo; + + private String freezeDate; + + + /** + * 分页参数-当前页数 + */ + //"分页参数-当前页数") + private int pageNum; + /** + * 分页参数-每一页条数 + */ + //"分页参数-每一页条数") + private int pageSize; + + /** + * 排序 + */ + //"排序") + private Object sort; + + private List sortKeyDesc = new ArrayList<>(); + private List sortKeyAsc = new ArrayList<>(); + + private List sortKeys = new ArrayList<>(); + + /** + * 案件Id + */ + private String caseId; + + private Params params = new Params(); + + private BigDecimal beginBalance; + private BigDecimal endBalance; + + private String beginOpeningAccountDate; + private String endOpeningAccountDate; + + private String beginClosingDate; + private String endClosingDate; + + private String orderByColumn; + + public String isAsc; + + private String analysisResultId; + private String beginFreezeDate; + private String endFreezeDate; + + private String onlineBankingSigningInfo; + + @TableField(exist = false) + private List ids = new ArrayList<>(); + + private Integer downloadTemplate; + + @Data + public static class Params { + private BigDecimal beginTransactionAmount; + private BigDecimal endTransactionAmount; + private String beginOpenTime; + private String endOpenTime; + private BigDecimal endBalance; + private BigDecimal beginBalance; + private String beginOpeningAccountDate; + private String endOpeningAccountDate; + private String beginClosingDate; + private String endClosingDate; + private String beginFreezeDate; + private String endFreezeDate; + } + + @NotNull(message = "[分组字段]不能为空") + private List fields; + /** + * 没用 + */ + @NotNull(message = "[业务模块]不能为空") + private String module; + + + private String type; + + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/vo/GetPersonReq.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/vo/GetPersonReq.java new file mode 100644 index 0000000..e153284 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/vo/GetPersonReq.java @@ -0,0 +1,8 @@ +package com.inscloudtech.datacenter.domain.vo; + +import lombok.Data; + +@Data +public class GetPersonReq { + private String caseId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/vo/ImportBankStatementsReq.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/vo/ImportBankStatementsReq.java new file mode 100644 index 0000000..69e62ed --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/vo/ImportBankStatementsReq.java @@ -0,0 +1,14 @@ +package com.inscloudtech.datacenter.domain.vo; + +import lombok.Data; + +/** + * 导入银行流水请求封装 + */ +@Data +public class ImportBankStatementsReq { + /** + * 字典中银行编号,表征导入哪一个银行的流水数据 + */ + private String bankNo; +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/domain/vo/RevokeItem.java b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/vo/RevokeItem.java new file mode 100644 index 0000000..0eab474 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/domain/vo/RevokeItem.java @@ -0,0 +1,9 @@ +package com.inscloudtech.datacenter.domain.vo; + +import lombok.Data; + +@Data +public class RevokeItem { + private String id; + private String bgColor; +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/fileRead/FileReader.java b/cas-system/src/main/java/com/inscloudtech/datacenter/fileRead/FileReader.java new file mode 100644 index 0000000..306d5df --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/fileRead/FileReader.java @@ -0,0 +1,157 @@ +package com.inscloudtech.datacenter.fileRead; + +import com.aspose.cells.Cells; +import com.aspose.cells.Workbook; +import com.aspose.cells.Worksheet; +import com.aspose.words.*; +import com.inscloudtech.common.utils.file.FileUploadUtils; +import lombok.Cleanup; +import lombok.SneakyThrows; +import org.springframework.web.multipart.MultipartFile; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +public class FileReader { + + + public static final String[] DEFAULT_ALLOWED_EXTENSION = { + "doc", "docx", "xls", "xlsx", "txt", "pdf"}; + + + @SneakyThrows + public static String readWord(InputStream in){ + // ocument读取word中的内容,Document 是表示 Microsoft Word 文档的对象模型的主要类。 + Document document = new Document(in); + // 获取到这一部分的所有段落 + Paragraph[] paragraphs = document.getFirstSection().getBody().getParagraphs().toArray(); + // 通过循环来获取段落中的内容 + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < paragraphs.length; i++) { + paragraphs[i].getText(); + // 获取到这一个段落中的所有行 + Run[] runs = paragraphs[i].getRuns().toArray(); + for (Run run : runs) { + // 获取到每一行的文字打印 + sb.append(run.getText()); + } + } + +//用于提取块级节点之间内容的 Java 代码示例 + // + NodeCollection

tables = document.getChildNodes(NodeType.TABLE, true); + if(tables.getCount() > 0){ + for (Table table : tables) { + // 遍历表格中的每个单元格 + for (Row row : table.getRows()) { + sb.append(row.getText()); + sb.append("\\n"); +// for (Cell cell : row.getCells()) { +// // 获取单元格中的段落 +// ParagraphCollection paragraphs = cell.getParagraphs(); +// // 遍历段落中的每个运行 +// for (Paragraph paragraph : paragraphs) { +// for (Run run : paragraph.getRuns()) { +// String text = run.getText(); +// if (text.contains("150350262353411031989123016161")) { +// run.getFont().setColor(Color.GREEN); +// } +// } +// } +// } + } + } + } + + return sb.toString(); + } + + @SneakyThrows + public static String readPdf(InputStream in) { + // 加载PDF文件 + com.aspose.pdf.Document document = new com.aspose.pdf.Document(in); + + // 创建TextAbsorber对象,用于提取文本内容 + com.aspose.pdf.TextAbsorber textAbsorber = new com.aspose.pdf.TextAbsorber(); + + // 提取PDF中的文本内容 + document.getPages().accept(textAbsorber); + + // 获取提取的文本内容 + return textAbsorber.getText(); + } + + @SneakyThrows + public static String readExcel(InputStream in){ + // 加载Excel文件 + Workbook workbook = new Workbook(in); + + // 获取第一个工作表 + Worksheet worksheet = workbook.getWorksheets().get(0); + + // 获取单元格集合 + Cells cells = worksheet.getCells(); + StringBuilder sb = new StringBuilder(); + // 读取单元格数据 + int rowCount = cells.getMaxDataRow() + 1; + int columnCount = cells.getMaxDataColumn() + 1; + for (int row = 0; row < rowCount; row++) { + for (int col = 0; col < columnCount; col++) { + com.aspose.cells.Cell cell = cells.get(row, col); + String cellValue = cell.getStringValue(); + sb.append(cellValue); + } + } + return sb.toString(); + } + + @SneakyThrows + public static String readTxt(InputStream in){ + StringBuilder sb = new StringBuilder(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(in))) { + String line; + while ((line = reader.readLine()) != null) { + sb.append(line); + } + } catch (IOException e) { + e.printStackTrace(); + } + // 通过循环来获取段落中的内容 + return sb.toString(); + } + + + public static String read(MultipartFile file) { + boolean allowed = true; + String detailMessage = ""; + try { + FileUploadUtils.assertAllowed(file, FileReader.DEFAULT_ALLOWED_EXTENSION); + }catch (Exception e){ + allowed = false; + detailMessage = e.getMessage(); + } + + if(!allowed){ + return detailMessage; + } + String content = ""; + try { + String extension = FileUploadUtils.getExtension(file); + @Cleanup + InputStream inputStream = file.getInputStream(); + if(extension.startsWith("doc")){ + content = readWord(inputStream); + }else if(extension.startsWith("xls")){ + content = readExcel(inputStream); + }else if(extension.startsWith("pdf")){ + content = readPdf(inputStream); + }else if(extension.startsWith("txt")){ + content = readTxt(inputStream); + } + }finally { + return content; + } + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/CarInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/CarInfoMapper.java new file mode 100644 index 0000000..465306b --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/CarInfoMapper.java @@ -0,0 +1,43 @@ +package com.inscloudtech.datacenter.mapper; + + +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import com.inscloudtech.datacenter.domain.CarInfo; +import com.inscloudtech.datacenter.domain.dto.StatisticsOption; +import com.inscloudtech.datacenter.domain.dto.StatisticsResult; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; + +import java.util.List; +import java.util.Map; + +/** + * 重点人员资产-车辆信息Mapper接口 + * + * @author inscloudtech + * @date 2023-11-10 + */ +public interface CarInfoMapper extends BaseMapperPlus { + + @Select("") + List getFieldsValueCount(@Param("tableName") String tableName, @Param("fields") List fields, @Param("caseId") String caseId); + + + + @Select("SHOW INDEXES FROM #{tableName}") + List getIndexInfo(@Param("tableName") String tableName); + + @Update("update ${tableName} set del_flag = '2' WHERE case_id = ${caseId}") + void updateDelFlag(@Param("tableName") String tableName, @Param("caseId") String caseId); +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/ImportResultMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/ImportResultMapper.java new file mode 100644 index 0000000..2dfb77d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/ImportResultMapper.java @@ -0,0 +1,18 @@ +package com.inscloudtech.datacenter.mapper; + + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.inscloudtech.datacenter.domain.ImportResult; +import org.apache.ibatis.annotations.Mapper; + +/** + * 流水导入结果 + * + * @author zfcf + * @date 2024-07-15 + */ +@Mapper +public interface ImportResultMapper extends BaseMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/OtherAssetsMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/OtherAssetsMapper.java new file mode 100644 index 0000000..a4f3d64 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/OtherAssetsMapper.java @@ -0,0 +1,16 @@ +package com.inscloudtech.datacenter.mapper; + + +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import com.inscloudtech.datacenter.domain.OtherAssets; + + +/** + * + * + * @author lingyun + * @date 2023-11-07 + */ +public interface OtherAssetsMapper extends BaseMapperPlus { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/OtherInformationMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/OtherInformationMapper.java new file mode 100644 index 0000000..808e28f --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/OtherInformationMapper.java @@ -0,0 +1,16 @@ +package com.inscloudtech.datacenter.mapper; + + +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import com.inscloudtech.datacenter.domain.OtherInformation; + + +/** + * + * + * @author lingyun + * @date 2023-11-07 + */ +public interface OtherInformationMapper extends BaseMapperPlus { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/PublicFamilyMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/PublicFamilyMapper.java new file mode 100644 index 0000000..95d882a --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/PublicFamilyMapper.java @@ -0,0 +1,16 @@ +package com.inscloudtech.datacenter.mapper; + + +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import com.inscloudtech.datacenter.domain.PublicFamily; + +/** + * 数据中心-职工家属Mapper接口 + * + * @author inscloudtech + * @date 2023-11-09 + */ +public interface PublicFamilyMapper extends BaseMapperPlus { + +} + diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/RealEstateMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/RealEstateMapper.java new file mode 100644 index 0000000..b902a1d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/RealEstateMapper.java @@ -0,0 +1,15 @@ +package com.inscloudtech.datacenter.mapper; + + +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import com.inscloudtech.datacenter.domain.RealEstate; + +/** + * 重点人员资产-不动产信息Mapper接口 + * + * @author inscloudtech + * @date 2023-11-09 + */ +public interface RealEstateMapper extends BaseMapperPlus { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/TransactionPartnerMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/TransactionPartnerMapper.java new file mode 100644 index 0000000..09048b5 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/TransactionPartnerMapper.java @@ -0,0 +1,17 @@ +package com.inscloudtech.datacenter.mapper; + + + +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import com.inscloudtech.datacenter.domain.TransactionPartner; + + +/** + * 数据中心-交易对象Mapper接口 + * + * @author lingyun + * @date 2023-11-07 + */ +public interface TransactionPartnerMapper extends BaseMapperPlus { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/CGSOpeningAccountInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/CGSOpeningAccountInfoMapper.java new file mode 100644 index 0000000..0ad8f01 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/CGSOpeningAccountInfoMapper.java @@ -0,0 +1,11 @@ +package com.inscloudtech.datacenter.mapper.es; + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CGSOpenAccountInfo; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 央地系统开户信息Mapper接口 + */ +public interface CGSOpeningAccountInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/CGSStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/CGSStatementMapper.java new file mode 100644 index 0000000..1748bac --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/CGSStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CGSBankStatement; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 央地系统流水信息Mapper接口 + */ +public interface CGSStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/CarInfoEsMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/CarInfoEsMapper.java new file mode 100644 index 0000000..070a69b --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/CarInfoEsMapper.java @@ -0,0 +1,15 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.datacenter.domain.CarInfo; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 重点人员资产-车辆信息Mapper接口 + * + * @author inscloudtech + * @date 2023-11-10 + */ +public interface CarInfoEsMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/ESBankStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/ESBankStatementMapper.java new file mode 100644 index 0000000..00aefac --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/ESBankStatementMapper.java @@ -0,0 +1,8 @@ +package com.inscloudtech.datacenter.mapper.es; + +import com.inscloudtech.datacenter.domain.BankStatement; +import org.dromara.easyes.core.core.BaseEsMapper; + +public interface ESBankStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/ESOpeningAccountInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/ESOpeningAccountInfoMapper.java new file mode 100644 index 0000000..c47037b --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/ESOpeningAccountInfoMapper.java @@ -0,0 +1,8 @@ +package com.inscloudtech.datacenter.mapper.es; + +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; +import org.dromara.easyes.core.core.BaseEsMapper; + +public interface ESOpeningAccountInfoMapper extends BaseEsMapper { +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsABCCompanyInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsABCCompanyInfoMapper.java new file mode 100644 index 0000000..c06130e --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsABCCompanyInfoMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.ABCCompanyInfoEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 农业银行开户信息-公司信息Mapper接口 + */ +public interface EsABCCompanyInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsABCCompanyStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsABCCompanyStatementMapper.java new file mode 100644 index 0000000..00c7e60 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsABCCompanyStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.ABCCompanyStatementEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 农业银行开户信息-公司信息Mapper接口 + */ +public interface EsABCCompanyStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsABCCustomerInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsABCCustomerInfoMapper.java new file mode 100644 index 0000000..a64c9d3 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsABCCustomerInfoMapper.java @@ -0,0 +1,13 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.ABCCompanyInfoEntity; +import com.inscloudtech.bankStatementAnalysis.domain.entity.ABCCustomerInfoEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 农业银行开户信息-公司信息Mapper接口 + */ +public interface EsABCCustomerInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsABCCustomerStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsABCCustomerStatementMapper.java new file mode 100644 index 0000000..4d2d8d9 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsABCCustomerStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.ABCCustomerStatementEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 农业银行开户信息-公司信息Mapper接口 + */ +public interface EsABCCustomerStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsBOCOMAccountInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsBOCOMAccountInfoMapper.java new file mode 100644 index 0000000..4841440 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsBOCOMAccountInfoMapper.java @@ -0,0 +1,13 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.BOCOMAccountInfoEntity; +import com.inscloudtech.bankStatementAnalysis.domain.entity.BOCOMStatementEntry; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 交通银行客户信息Mapper接口 + */ +public interface EsBOCOMAccountInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsBOCOMStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsBOCOMStatementMapper.java new file mode 100644 index 0000000..5de6465 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsBOCOMStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.BOCOMStatementEntry; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 交通银行流水读取Mapper接口 + */ +public interface EsBOCOMStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsBOCPrivateBankStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsBOCPrivateBankStatementMapper.java new file mode 100644 index 0000000..8fb03ff --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsBOCPrivateBankStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.BOCPrivateBankStatementEntry; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 中国银行流水-对私Mapper接口 + */ +public interface EsBOCPrivateBankStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCCBCurrentAccountInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCCBCurrentAccountInfoMapper.java new file mode 100644 index 0000000..5c1b620 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCCBCurrentAccountInfoMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CCBCurrentAccountInfoEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 农业银行开户信息-公司信息Mapper接口 + */ +public interface EsCCBCurrentAccountInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCCBCurrentBankStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCCBCurrentBankStatementMapper.java new file mode 100644 index 0000000..20bd2b5 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCCBCurrentBankStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CCBCurrentBankStatementEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 建设银行流水读取-个人活期明细Mapper接口 + */ +public interface EsCCBCurrentBankStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCCBElectronicCashAccountInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCCBElectronicCashAccountInfoMapper.java new file mode 100644 index 0000000..3e3d18d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCCBElectronicCashAccountInfoMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CCBElectronicCashAccountInfoEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 建设银行客户信息-电子现金Mapper接口 + */ +public interface EsCCBElectronicCashAccountInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCCBElectronicCashBankStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCCBElectronicCashBankStatementMapper.java new file mode 100644 index 0000000..ebe3850 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCCBElectronicCashBankStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CCBElectronicCashBankStatementEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 建设银行流水读取-电子现金明细Mapper接口 + */ +public interface EsCCBElectronicCashBankStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCCBRegularAccountInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCCBRegularAccountInfoMapper.java new file mode 100644 index 0000000..6ebeafa --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCCBRegularAccountInfoMapper.java @@ -0,0 +1,13 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CCBCurrentAccountInfoEntity; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CCBRegularAccountInfoEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 建设银行客户信息-定期Mapper接口 + */ +public interface EsCCBRegularAccountInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCCBRegularBankStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCCBRegularBankStatementMapper.java new file mode 100644 index 0000000..8c770c4 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCCBRegularBankStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CCBRegularBankStatementEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 建设银行流水读取-电子现金明细Mapper接口 + */ +public interface EsCCBRegularBankStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCEBCreditCardStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCEBCreditCardStatementMapper.java new file mode 100644 index 0000000..2940915 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCEBCreditCardStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CEBCreditCardStatementEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 农业银行开户信息-公司信息Mapper接口 + */ +public interface EsCEBCreditCardStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCEBSavingsCardStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCEBSavingsCardStatementMapper.java new file mode 100644 index 0000000..9743242 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCEBSavingsCardStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CEBSavingsCardStatementEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 农业银行开户信息-公司信息Mapper接口 + */ +public interface EsCEBSavingsCardStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCCreditCardAccountInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCCreditCardAccountInfoMapper.java new file mode 100644 index 0000000..1823831 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCCreditCardAccountInfoMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CGBCCreditCardAccountInfoEntry; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 广发银行信用卡开户信息Mapper接口 + */ +public interface EsCGBCCreditCardAccountInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCCreditCardOtherStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCCreditCardOtherStatementMapper.java new file mode 100644 index 0000000..c0d2974 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCCreditCardOtherStatementMapper.java @@ -0,0 +1,13 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.ABCCompanyInfoEntity; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CGBCCreditCardOtherStatementEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 光大银行流水读取-信用卡-其他模板接口 + */ +public interface EsCGBCCreditCardOtherStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCCreditCardStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCCreditCardStatementMapper.java new file mode 100644 index 0000000..867f39d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCCreditCardStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CGBCCreditCardStatementEntry; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 广发银行流水读取-信用卡Mapper接口 + */ +public interface EsCGBCCreditCardStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCNewCompanyInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCNewCompanyInfoMapper.java new file mode 100644 index 0000000..7f9293d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCNewCompanyInfoMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CGBCNewCompanyInfoEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 广发银行客户信息Mapper接口 + */ +public interface EsCGBCNewCompanyInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCNewCurrentAccountInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCNewCurrentAccountInfoMapper.java new file mode 100644 index 0000000..a3f76da --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCNewCurrentAccountInfoMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CGBCNewCurrentAccountInfoEntry; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 农业银行开户信息-公司信息Mapper接口 + */ +public interface EsCGBCNewCurrentAccountInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCNewCustomerInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCNewCustomerInfoMapper.java new file mode 100644 index 0000000..c1b7dda --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCNewCustomerInfoMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CGBCNewCustomerInfoEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 广发银行客户信息Mapper接口 + */ +public interface EsCGBCNewCustomerInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCNewRegularAccountInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCNewRegularAccountInfoMapper.java new file mode 100644 index 0000000..1d34148 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCNewRegularAccountInfoMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CGBCNewRegularAccountInfoEntry; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 广发银行定期开户信息Mapper接口 + */ +public interface EsCGBCNewRegularAccountInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCNewStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCNewStatementMapper.java new file mode 100644 index 0000000..fb473df --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCNewStatementMapper.java @@ -0,0 +1,13 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.ABCCompanyInfoEntity; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CGBCNewStatementEntry; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 广发银行流水读取-新核心交易流水Mapper接口 + */ +public interface EsCGBCNewStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCOldAccountInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCOldAccountInfoMapper.java new file mode 100644 index 0000000..48c80ee --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCOldAccountInfoMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CGBCOldAccountInfoEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 广发银行旧核心开户信息Mapper接口 + */ +public interface EsCGBCOldAccountInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCStatementMapper.java new file mode 100644 index 0000000..de78403 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCGBCStatementMapper.java @@ -0,0 +1,13 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.ABCCompanyInfoEntity; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CGBCStatementEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 广发银行流水读取-旧核心交易流水Mapper接口 + */ +public interface EsCGBCStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCIBCreditCardBankStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCIBCreditCardBankStatementMapper.java new file mode 100644 index 0000000..7456ad0 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCIBCreditCardBankStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CIBCreditCardBSEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 兴业银行信用卡流水Mapper接口 + */ +public interface EsCIBCreditCardBankStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCIBOpeningAccountInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCIBOpeningAccountInfoMapper.java new file mode 100644 index 0000000..654ef13 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCIBOpeningAccountInfoMapper.java @@ -0,0 +1,13 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.ABCCompanyInfoEntity; +import com.inscloudtech.bankStatementAnalysis.domain.entity.CIBOpeningAccountInfoEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 兴业银行开户信息Mapper接口 + */ +public interface EsCIBOpeningAccountInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCIBStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCIBStatementMapper.java new file mode 100644 index 0000000..4914ba5 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCIBStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CIBStatementEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 兴业银行流水Mapper接口 + */ +public interface EsCIBStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCITICBankStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCITICBankStatementMapper.java new file mode 100644 index 0000000..cf52e31 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCITICBankStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CITICBankStatementEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 中信银行流水信息Mapper接口 + */ +public interface EsCITICBankStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCITICOpeningAccountInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCITICOpeningAccountInfoMapper.java new file mode 100644 index 0000000..f7fc75d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCITICOpeningAccountInfoMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CITICOpeningAccountInfoEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 中信银行开户信息Mapper接口 + */ +public interface EsCITICOpeningAccountInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBCCreditCardAccountInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBCCreditCardAccountInfoMapper.java new file mode 100644 index 0000000..6919971 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBCCreditCardAccountInfoMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CMBCCreditCardAccountInfoEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 民生银行客户信息-信用卡Mapper接口 + */ +public interface EsCMBCCreditCardAccountInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBCCreditCardBankStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBCCreditCardBankStatementMapper.java new file mode 100644 index 0000000..d553622 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBCCreditCardBankStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CMBCCreditCardBankStatementEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 民生银行流水读取-信用卡Mapper接口 + */ +public interface EsCMBCCreditCardBankStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBCSavingsCardAccountInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBCSavingsCardAccountInfoMapper.java new file mode 100644 index 0000000..562e9a3 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBCSavingsCardAccountInfoMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CMBCSavingsCardAccountInfoEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 民生银行客户信息-储蓄卡Mapper接口 + */ +public interface EsCMBCSavingsCardAccountInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBCSavingsCardBankStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBCSavingsCardBankStatementMapper.java new file mode 100644 index 0000000..684502f --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBCSavingsCardBankStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CMBCSavingsCardBankStatementEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 民生银行流水读取-储蓄卡Mapper接口 + */ +public interface EsCMBCSavingsCardBankStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBCSavingsCardCompanyInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBCSavingsCardCompanyInfoMapper.java new file mode 100644 index 0000000..16e7002 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBCSavingsCardCompanyInfoMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CMBCSavingsCardCompanyInfoEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 民生银行客户信息-信用卡Mapper接口 + */ +public interface EsCMBCSavingsCardCompanyInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBOpeningAccountInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBOpeningAccountInfoMapper.java new file mode 100644 index 0000000..a7e8280 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBOpeningAccountInfoMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CMBOpeningAccountInfoEntry; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 招商银行开户信息Mapper接口 + */ +public interface EsCMBOpeningAccountInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBRetailStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBRetailStatementMapper.java new file mode 100644 index 0000000..4b526a0 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBRetailStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CMBRetailStatementEntry; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 招商银行流水信息-零售Mapper接口 + */ +public interface EsCMBRetailStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBStatementMapper.java new file mode 100644 index 0000000..8d0f6f5 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsCMBStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.CMBStatementEntry; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 招商银行流水信息Mapper接口 + */ +public interface EsCMBStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsFDBPrivateAccountOpeningInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsFDBPrivateAccountOpeningInfoMapper.java new file mode 100644 index 0000000..ea3757a --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsFDBPrivateAccountOpeningInfoMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.FDBPrivateAccountOpeningInfoEntry; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 富滇银行开户信息读取-个人Mapper接口 + */ +public interface EsFDBPrivateAccountOpeningInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsFDBPublicAccountOpeningInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsFDBPublicAccountOpeningInfoMapper.java new file mode 100644 index 0000000..8e528ac --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsFDBPublicAccountOpeningInfoMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.FDBPublicAccountOpeningInfoEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 富滇银行开户信息读取-对公Mapper接口 + */ +public interface EsFDBPublicAccountOpeningInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsFDBStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsFDBStatementMapper.java new file mode 100644 index 0000000..103f061 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsFDBStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.FDBStatementEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 富滇银行流水Mapper接口 + */ +public interface EsFDBStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsHXBankStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsHXBankStatementMapper.java new file mode 100644 index 0000000..89615a1 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsHXBankStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.HXBankStatementEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 华夏银行账户明细Mapper接口 + */ +public interface EsHXBankStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsHXPersonalBankStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsHXPersonalBankStatementMapper.java new file mode 100644 index 0000000..d477457 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsHXPersonalBankStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.HXPersonalBankStatementEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 华夏银行个人账户明细Mapper接口 + */ +public interface EsHXPersonalBankStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsHuaXiaAccountInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsHuaXiaAccountInfoMapper.java new file mode 100644 index 0000000..d113b9f --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsHuaXiaAccountInfoMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.HuaXiaAccountInfoEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 华夏银行-账户信息列表Mapper接口 + */ +public interface EsHuaXiaAccountInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsICBCBankStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsICBCBankStatementMapper.java new file mode 100644 index 0000000..4d8ba7b --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsICBCBankStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.ICBCBankStatementEntry; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 工商银行流水信息-储蓄卡流水Mapper接口 + */ +public interface EsICBCBankStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsICBCCreditCardBankStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsICBCCreditCardBankStatementMapper.java new file mode 100644 index 0000000..ae90769 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsICBCCreditCardBankStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.ICBCCreditCardBankStatementEntry; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 商银行流水信息 - 信用卡流水Mapper接口 + */ +public interface EsICBCCreditCardBankStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsPSBCOpeningAccountInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsPSBCOpeningAccountInfoMapper.java new file mode 100644 index 0000000..7ad49d5 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsPSBCOpeningAccountInfoMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.PSBCOpeningAccountInfoEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 邮储银行开户信息Mapper接口 + */ +public interface EsPSBCOpeningAccountInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsPSBCStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsPSBCStatementMapper.java new file mode 100644 index 0000000..c18f364 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsPSBCStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.PSBCStatementEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 邮储银行流水信息Mapper接口 + */ +public interface EsPSBCStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsQJCCBStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsQJCCBStatementMapper.java new file mode 100644 index 0000000..7b0a501 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsQJCCBStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.QJCCBStatementEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 曲靖商行流水Mapper接口 + */ +public interface EsQJCCBStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsRCCBankStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsRCCBankStatementMapper.java new file mode 100644 index 0000000..8485882 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsRCCBankStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.RCCBankStatementEntry; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 农村信用社流水信息Mapper接口 + */ +public interface EsRCCBankStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsRCCOpeningAccountInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsRCCOpeningAccountInfoMapper.java new file mode 100644 index 0000000..ba73055 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsRCCOpeningAccountInfoMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.RCCOpeningAccountInfoEntry; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 农村信用社开户信息Mapper接口 + */ +public interface EsRCCOpeningAccountInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsSPABANKOpeningAccountInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsSPABANKOpeningAccountInfoMapper.java new file mode 100644 index 0000000..7648ac5 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsSPABANKOpeningAccountInfoMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.SPAAccountInfoEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 平安银行开户信息Mapper接口 + */ +public interface EsSPABANKOpeningAccountInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsSPABANKStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsSPABANKStatementMapper.java new file mode 100644 index 0000000..3f08fd6 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsSPABANKStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.SPAStatementEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 平安银行流水Mapper接口 + */ +public interface EsSPABANKStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsSPACreditCardAccountInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsSPACreditCardAccountInfoMapper.java new file mode 100644 index 0000000..079bc88 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsSPACreditCardAccountInfoMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.SPACreditCardAccountInfoEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 平安银行开户信息-信用卡Mapper接口 + */ +public interface EsSPACreditCardAccountInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsSPACreditCardStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsSPACreditCardStatementMapper.java new file mode 100644 index 0000000..3913f68 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsSPACreditCardStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.SPACreditCardStatementEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 平安银行流水-信用卡Mapper接口 + */ +public interface EsSPACreditCardStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsSPACustomerInfoMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsSPACustomerInfoMapper.java new file mode 100644 index 0000000..1771f20 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsSPACustomerInfoMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.SPACustomerInfoEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 平安银行开户信息-客户信息Mapper接口 + */ +public interface EsSPACustomerInfoMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsSPAOtherStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsSPAOtherStatementMapper.java new file mode 100644 index 0000000..abbb1d9 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsSPAOtherStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.SPAOtherStatementEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 平安银行流水-另一种形式Mapper接口 + */ +public interface EsSPAOtherStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsSPDBBSMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsSPDBBSMapper.java new file mode 100644 index 0000000..a63e443 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/EsSPDBBSMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.SPDBBSEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 浦发银行流水Mapper接口 + */ +public interface EsSPDBBSMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/HFCompanyStatementMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/HFCompanyStatementMapper.java new file mode 100644 index 0000000..a47d491 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/HFCompanyStatementMapper.java @@ -0,0 +1,12 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.HFCompanyStatement; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * + */ +public interface HFCompanyStatementMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/HFCompanyStatementV2Mapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/HFCompanyStatementV2Mapper.java new file mode 100644 index 0000000..5ac1e92 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/HFCompanyStatementV2Mapper.java @@ -0,0 +1,13 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.bankStatementAnalysis.domain.entity.HFCompanyStatement; +import com.inscloudtech.bankStatementAnalysis.domain.entity.HFCompanyStatementV2; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * + */ +public interface HFCompanyStatementV2Mapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/OtherAssetsEsMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/OtherAssetsEsMapper.java new file mode 100644 index 0000000..bd28c51 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/OtherAssetsEsMapper.java @@ -0,0 +1,15 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.datacenter.domain.OtherAssets; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 重点人员资产其他资产信息 + * + * @author inscloudtech + * @date 2023-11-10 + */ +public interface OtherAssetsEsMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/OtherInformationEsMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/OtherInformationEsMapper.java new file mode 100644 index 0000000..ef608ba --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/OtherInformationEsMapper.java @@ -0,0 +1,15 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.datacenter.domain.OtherInformation; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 重点人员资产其他资产信息 + * + * @author inscloudtech + * @date 2023-11-10 + */ +public interface OtherInformationEsMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/PlateNumberEsMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/PlateNumberEsMapper.java new file mode 100644 index 0000000..f8c27c9 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/PlateNumberEsMapper.java @@ -0,0 +1,15 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * + * + * @author inscloudtech + * @date 2023-11-10 + */ +public interface PlateNumberEsMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/PublicFamilyEsMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/PublicFamilyEsMapper.java new file mode 100644 index 0000000..cfa2ed2 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/PublicFamilyEsMapper.java @@ -0,0 +1,15 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.datacenter.domain.PublicFamily; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * + * + * @author inscloudtech + * @date 2023-11-10 + */ +public interface PublicFamilyEsMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/RealEstateEsMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/RealEstateEsMapper.java new file mode 100644 index 0000000..84f71fe --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/RealEstateEsMapper.java @@ -0,0 +1,15 @@ +package com.inscloudtech.datacenter.mapper.es; + + +import com.inscloudtech.datacenter.domain.RealEstate; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 重点人员资产-不动产信息Mapper接口 + * + * @author inscloudtech + * @date 2023-11-09 + */ +public interface RealEstateEsMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/TransactionPartnerEsMapper.java b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/TransactionPartnerEsMapper.java new file mode 100644 index 0000000..e9c1e83 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/mapper/es/TransactionPartnerEsMapper.java @@ -0,0 +1,17 @@ +package com.inscloudtech.datacenter.mapper.es; + + + +import com.inscloudtech.datacenter.domain.TransactionPartner; +import org.dromara.easyes.core.core.BaseEsMapper; + + +/** + * 数据中心-交易对象Mapper接口 + * + * @author lingyun + * @date 2023-11-07 + */ +public interface TransactionPartnerEsMapper extends BaseEsMapper { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/service/BankService.java b/cas-system/src/main/java/com/inscloudtech/datacenter/service/BankService.java new file mode 100644 index 0000000..d964e11 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/service/BankService.java @@ -0,0 +1,86 @@ +package com.inscloudtech.datacenter.service; + + +import cn.hutool.json.JSONObject; +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.analysiscenter.domain.AnalysisPerson; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; +import com.inscloudtech.datacenter.domain.vo.*; +import com.inscloudtech.system.domain.vo.*; + +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +/** + * @author Administrator + * @description 针对表【bank_statement】的数据库操作Service + * @createDate 2023-10-25 15:31:49 + */ +public interface BankService { + + /** + * 获取银行列表 + */ + List getBankList(); + + int importBankStatements(MultipartFile file, String caseId); + + TableDataInfo page(GetBankStatementListReq req) throws Exception; + + void exportBankStatement(GetBSFieldValueCountReq req, HttpServletResponse response) throws IOException; + + TableDataInfo oaiPage(GetOpeningAccountInfoListReq req) throws Exception; + + int deleteBSByIdsEsVersion(String[] bsIds); + + void exportOAI(GetOpeningAccountInfoListReq oai, HttpServletResponse response) throws IOException; + + int deleteOAIByIdsEsVersion(String[] oaiIds); + + void updateBatchOAIEsVersion(OpeningAccountInfo oai); + + void updateBatchBSEsVersion(BankStatement bs); + + JSONObject getFieldsValueCount(GetBSFieldValueCountReq req) throws IOException; + + JSONObject getFieldsValueCount4OAI(GetOpeningAccountInfoListReq req) throws IOException; + + List getBSList(GetBSFieldValueCountReq req) throws Exception; + + List getOAIList(GetOpeningAccountInfoListReq req); + + /** + * 清空案件相关数据,包括流水数据和开户数据 + * @param caseId 案件Id + */ + void clear(String caseId); + + List getPersonInfo(GetPersonReq req); + + void analysisFile(File file, String bankNo, String caseId, String bankName); + + void createTemplate(String sourceFolderPath, String zipFilePath); + + boolean importAnalysisResult(List list, String analysisResultId, String username); + + boolean editPersonInfo(List update); + + boolean importData(List list, String caseId,String fileName); + + Boolean caseMerge(String sourceCaseId,String targetCaseId); + + void analysisResultMerge(Map sourceArIdTargetArIdMap); + + boolean batchInsert(List list); + + void save2AnalysisResult(AnalysisDto dto); + + void save2AnalysisResultOai(AnalysisDto dto); +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/service/ICarInfoService.java b/cas-system/src/main/java/com/inscloudtech/datacenter/service/ICarInfoService.java new file mode 100644 index 0000000..39fb835 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/service/ICarInfoService.java @@ -0,0 +1,72 @@ +package com.inscloudtech.datacenter.service; + + +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.datacenter.domain.CarInfo; +import com.inscloudtech.datacenter.domain.PublicFamily; +import com.inscloudtech.datacenter.domain.RealEstate; +import com.inscloudtech.datacenter.domain.TransactionPartner; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.search.builder.SearchSourceBuilder; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 重点人员资产-车辆信息Service接口 + * + * @author inscloudtech + * @date 2023-11-10 + */ +public interface ICarInfoService { + + /** + * 查询重点人员资产-车辆信息 + */ + CarInfo queryById(String id); + + /** + * 查询重点人员资产-车辆信息列表 + */ + TableDataInfo queryPageList(CarInfo bo, PageQuery pageQuery); + + /** + * 查询重点人员资产-车辆信息列表 + */ + List queryList(CarInfo bo); + + /** + * 新增重点人员资产-车辆信息 + */ + Boolean insertByBo(CarInfo bo); + + /** + * 修改重点人员资产-车辆信息 + */ + Boolean updateByBo(CarInfo bo); + + /** + * 校验并批量删除重点人员资产-车辆信息信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + Boolean importData(List list,String caseId,String analysisResultId); + + Boolean caseMerge(String sourceCaseId,String targetCaseId); + + void analysisResultMerge(Map sourceArIdTargetArIdMap); + + + Boolean updateBatch(List list); + + Boolean importAnalysisResult(List list, String analysisResultId, String username); + + List dataTrimAndDeduplication(List list, String caseId, String username); + + SearchSourceBuilder getSearchSourceBuilder(CarInfo carInfo); + + void save2AnalysisResult(AnalysisDto dto); +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/service/IOtherAssetsService.java b/cas-system/src/main/java/com/inscloudtech/datacenter/service/IOtherAssetsService.java new file mode 100644 index 0000000..a10c078 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/service/IOtherAssetsService.java @@ -0,0 +1,26 @@ +package com.inscloudtech.datacenter.service; + +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.datacenter.domain.OtherAssets; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; +import java.util.Map; + +public interface IOtherAssetsService { + + TableDataInfo queryPageList(OtherAssets bo, PageQuery pageQuery); + + void insertFileContent(String ossId, MultipartFile file, String caseId, String businessModule); + + boolean remove(List ossIds); + + void save2AnalysisResult(AnalysisDto dto); + + Boolean caseMerge(String sourceCaseId,String targetCaseId); + + void analysisResultMerge(Map sourceArIdTargetArIdMap); + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/service/IOtherInformationService.java b/cas-system/src/main/java/com/inscloudtech/datacenter/service/IOtherInformationService.java new file mode 100644 index 0000000..77dfd7a --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/service/IOtherInformationService.java @@ -0,0 +1,26 @@ +package com.inscloudtech.datacenter.service; + +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.datacenter.domain.OtherInformation; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; +import java.util.Map; + +public interface IOtherInformationService { + + TableDataInfo queryPageList(OtherInformation bo, PageQuery pageQuery); + + void insertFileContent(String ossId, MultipartFile file, String caseId, String businessModule); + + boolean remove(List ossIds); + + void save2AnalysisResult(AnalysisDto dto); + + Boolean caseMerge(String sourceCaseId,String targetCaseId); + + void analysisResultMerge(Map sourceArIdTargetArIdMap); + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/service/IPublicFamilyService.java b/cas-system/src/main/java/com/inscloudtech/datacenter/service/IPublicFamilyService.java new file mode 100644 index 0000000..e2c5086 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/service/IPublicFamilyService.java @@ -0,0 +1,72 @@ +package com.inscloudtech.datacenter.service; + +import java.util.Map; +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.datacenter.domain.CarInfo; +import com.inscloudtech.datacenter.domain.PublicFamily; +import com.inscloudtech.datacenter.domain.TransactionPartner; +import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.search.builder.SearchSourceBuilder; + +import java.util.Collection; +import java.util.List; + +/** + * 数据中心-职工家属Service接口 + * + * @author inscloudtech + * @date 2023-11-09 + */ +public interface IPublicFamilyService { + + /** + * 查询数据中心-职工家属 + */ + PublicFamily queryById(String id); + + /** + * 查询数据中心-职工家属列表 + */ + TableDataInfo queryPageList(PublicFamily bo, PageQuery pageQuery); + + /** + * 查询数据中心-职工家属列表 + */ + List queryList(PublicFamily bo); + + /** + * 新增数据中心-职工家属 + */ + Boolean insertByBo(PublicFamily bo); + + /** + * 修改数据中心-职工家属 + */ + Boolean updateByBo(PublicFamily bo); + + /** + * 校验并批量删除数据中心-职工家属信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + boolean updateBatch(List list); + + boolean importData(List list,String caseId,String analysisResultId); + + Boolean caseMerge(String sourceCaseId,String targetCaseId); + + void analysisResultMerge(Map sourceArIdTargetArIdMap); + + TableDataInfo highlightList(PublicFamily bo, PageQuery pageQuery); + + List dataTrimAndDeduplication(List list, String caseId,String createBy); + + Boolean importAnalysisResult(List list, String analysisResultId, String username); + + SearchSourceBuilder getSearchSourceBuilder(PublicFamily family); + + void save2AnalysisResult(AnalysisDto dto); +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/service/IRealEstateService.java b/cas-system/src/main/java/com/inscloudtech/datacenter/service/IRealEstateService.java new file mode 100644 index 0000000..8793a53 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/service/IRealEstateService.java @@ -0,0 +1,73 @@ +package com.inscloudtech.datacenter.service; + + + + +import java.util.Map; +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.datacenter.domain.PublicFamily; +import com.inscloudtech.datacenter.domain.RealEstate; +import com.inscloudtech.datacenter.domain.TransactionPartner; +import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.search.builder.SearchSourceBuilder; + +import java.util.Collection; +import java.util.List; + +/** + * 重点人员资产-不动产信息Service接口 + * + * @author inscloudtech + * @date 2023-11-09 + */ +public interface IRealEstateService { + + /** + * 查询重点人员资产-不动产信息 + */ + RealEstate queryById(String id); + + /** + * 查询重点人员资产-不动产信息列表 + */ + TableDataInfo queryPageList(RealEstate bo, PageQuery pageQuery); + + /** + * 查询重点人员资产-不动产信息列表 + */ + List queryList(RealEstate bo); + + /** + * 新增重点人员资产-不动产信息 + */ + Boolean insertByBo(RealEstate bo); + + /** + * 修改重点人员资产-不动产信息 + */ + Boolean updateByBo(RealEstate bo); + + /** + * 校验并批量删除重点人员资产-不动产信息信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + Boolean importData(List list,String caseId,String analysisResultId); + + Boolean caseMerge(String sourceCaseId,String targetCaseId); + + void analysisResultMerge(Map sourceArIdTargetArIdMap); + + Boolean updateBatch(List list); + + Boolean importAnalysisResult(List list, String analysisResultId, String username); + + SearchSourceBuilder getSearchSourceBuilder(RealEstate family); + + List dataTrimAndDeduplication(List list, String caseId, String username); + + void save2AnalysisResult(AnalysisDto dto); +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/service/ITransactionPartnerService.java b/cas-system/src/main/java/com/inscloudtech/datacenter/service/ITransactionPartnerService.java new file mode 100644 index 0000000..6fa5554 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/service/ITransactionPartnerService.java @@ -0,0 +1,65 @@ +package com.inscloudtech.datacenter.service; + +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.excel.ExcelResult; + +import com.inscloudtech.datacenter.domain.RealEstate; +import com.inscloudtech.datacenter.domain.TransactionPartner; +import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.search.builder.SearchSourceBuilder; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +/** + * 数据中心-交易对象Service接口 + * + * @author lingyun + * @date 2023-11-07 + */ +public interface ITransactionPartnerService { + + /** + * 查询品类配置 + */ + TransactionPartner queryById(String id); + /** + * 查询品类配置列表 + */ + TableDataInfo queryPageList(TransactionPartner bo, PageQuery pageQuery); + /** + * 查询品类配置列表 + */ + List queryList(TransactionPartner bo); + /** + * 新增品类配置 + */ + Boolean insert(TransactionPartner bo); + /** + * 修改品类配置 + */ + Boolean update(TransactionPartner bo); + + Boolean deleteWithValidByIds(Collection ids); + + Boolean importData(List list,String caseId,String analysisResultId); + + Boolean caseMerge(String sourceCaseId,String targetCaseId); + + void analysisResultMerge(Map sourceArIdTargetArIdMap); + + Boolean updateBatch(List list); + + TableDataInfo highlightList(TransactionPartner bo, PageQuery pageQuery); + + List dataTrimAndDeduplication(List list, String caseId, String username); + + Boolean importAnalysisResult(List list, String analysisResultId, String username); + + SearchSourceBuilder getSearchSourceBuilder(TransactionPartner family); + + void save2AnalysisResult(AnalysisDto dto); +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/service/ImportResultService.java b/cas-system/src/main/java/com/inscloudtech/datacenter/service/ImportResultService.java new file mode 100644 index 0000000..9950d97 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/service/ImportResultService.java @@ -0,0 +1,22 @@ +package com.inscloudtech.datacenter.service; + + +import com.baomidou.mybatisplus.extension.service.IService; +import com.inscloudtech.datacenter.domain.ImportResult; + +import java.util.List; + + +/** + * 流水导入结果Service接口 + * @author zfcf + * @date 2024-07-15 + */ +public interface ImportResultService extends IService { + + void record(String caseId, String bankName, Exception exception,String sourceFile); + + ImportResult record(String caseId, String bankName, Exception exception); + + List getResultListByCaseId(String caseId,String batchId); +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/service/IndexInitService.java b/cas-system/src/main/java/com/inscloudtech/datacenter/service/IndexInitService.java new file mode 100644 index 0000000..be2affe --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/service/IndexInitService.java @@ -0,0 +1,73 @@ +package com.inscloudtech.datacenter.service; + +import java.util.HashMap; +import java.util.Map; + +public class IndexInitService { + + public static final String BANK_STATEMENT_INDEX = "dc_bank_statement"; + public static final String BANK_STATEMENT_MAPPING = "{\"properties\":{\"analysisResultId\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"balance\":{\"type\":\"scaled_float\",\"scaling_factor\":100.0},\"bankName\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"bgColor\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"bgc\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"cardHolderName\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"cardNumber\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"caseId\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"counterpartIdCardNo\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"counterpartyAccount\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"counterpartyBankName\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"counterpartyName\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"createTime\":{\"type\":\"date\"},\"idCardNo\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"ids\":{\"type\":\"text\"},\"phone\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"realCounterpartyAccount\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"realCounterpartyName\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"remark\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"revokeList\":{\"type\":\"text\"},\"sId\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"sortId\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"sourceFile\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"summary\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"transChannel\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"transCurrencyType\":{\"type\":\"integer\"},\"transRemark\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"transactionAmount\":{\"type\":\"scaled_float\",\"scaling_factor\":100.0},\"transactionInstitutions\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"transactionTime\":{\"type\":\"date\"},\"updateTime\":{\"type\":\"date\"}}}"; + + public static final String OPENING_ACCOUNT_INFO_INDEX = "dc_opening_account_info"; + public static final String OPENING_ACCOUNT_INFO_MAPPING = "{\"properties\":{\"accountNumber\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}}," + + "\"customerId\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}}," + + "\"account2CardNumber\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}}," + + "\"accountOpeningInstitution\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"address\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"analysisResultId\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"balance\":{\"type\":\"scaled_float\",\"scaling_factor\":100.0},\"bankName\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"fielddata\":true},\"bgColor\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"bgc\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"caseId\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"closingDate\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"fielddata\":true},\"createTime\":{\"type\":\"long\"},\"freezeDate\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"fielddata\":true},\"freezeInfo\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"idNo\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"fielddata\":true},\"idType\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"fielddata\":true},\"ids\":{\"type\":\"text\"},\"name\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"fielddata\":true},\"newAccountNumber\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"onlineBankingSigningInfo\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"openingAccountDate\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"fielddata\":true},\"phone\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"remark\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"revokeList\":{\"type\":\"text\"},\"sId\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"status\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"fielddata\":true},\"type\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"fielddata\":true}}}"; + + public static final String TRANSACTION_PARTNER_INDEX = "dc_transaction_partner"; + public static final String TRANSACTION_PARTNER_SETTINGS = "{\"index.max_ngram_diff\":50,\"analysis\":{\"analyzer\":{\"ngram_analyzer\":{\"tokenizer\":\"ngram_tokenizer\"}},\"tokenizer\":{\"ngram_tokenizer\":{\"min_gram\":\"1\",\"type\":\"ngram\",\"max_gram\":\"50\"}}}}"; + public static final String TRANSACTION_PARTNER_MAPPING = "{\"properties\":{\"analysisResultId\":{\"type\":\"keyword\"},\"bgc\":{\"type\":\"keyword\"},\"caseId\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"createBy\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"createTime\":{\"type\":\"date\",\"format\":\"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\"},\"debt\":{\"type\":\"double\"},\"organizationCode\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"registeredAddress\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"relateCompany\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"remark\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"stockholder\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"stockholderRelated\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"stockholderRelatedHighlight\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"transactionAmount\":{\"type\":\"keyword\"},\"travellingTrader\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"updateBy\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"updateTime\":{\"type\":\"date\",\"format\":\"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\"}}}"; + + public static final String REAL_ESTATE_INDEX = "dc_real_estate"; + public static final String REAL_ESTATE_MAPPING = "{\"properties\":{\"address\":{\"type\":\"keyword\"},\"analysisResultId\":{\"type\":\"long\"},\"area\":{\"type\":\"double\"},\"bgc\":{\"type\":\"keyword\"},\"caseId\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"createBy\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"createTime\":{\"type\":\"date\",\"format\":\"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\"},\"name\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"otherInformation\":{\"type\":\"keyword\"},\"remark\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"transferInformation\":{\"type\":\"keyword\"},\"updateBy\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"updateTime\":{\"type\":\"date\",\"format\":\"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\"},\"valuation\":{\"type\":\"double\"}}}"; + + + public static final String PUBLIC_FAMILY_INDEX = "dc_public_family"; + public static final String PUBLIC_FAMILY_MAPPING = "{\"properties\":{\"analysisResultId\":{\"type\":\"long\"},\"bgc\":{\"type\":\"keyword\"},\"caseId\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"createBy\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"createTime\":{\"type\":\"date\",\"format\":\"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\"},\"deptPost\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"deptPost1\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"deptPost2\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"deptPost3\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"deptPost4\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"deptPost5\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"deptPost6\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"deptPost7\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"enterpriseName\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"idCard\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"memberIdCard1\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"memberIdCard2\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"memberIdCard3\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"memberIdCard4\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"memberIdCard5\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"memberIdCard6\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"memberIdCard7\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"memberName1\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"memberName2\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"memberName3\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"memberName4\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"memberName5\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"memberName6\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"memberName7\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"memberRelation1\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"memberRelation2\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"memberRelation3\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"memberRelation4\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"memberRelation5\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"memberRelation6\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"memberRelation7\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"name\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"remark\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}},\"analyzer\":\"ngram_analyzer\"},\"updateBy\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"updateTime\":{\"type\":\"date\",\"format\":\"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\"}}}"; + + + public static final String CAR_INFO_INDEX = "dc_car_info"; + public static final String CAR_INFO_MAPPING = "{\"properties\":{\"address\":{\"type\":\"keyword\"},\"analysisResultId\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"bgc\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"carNo\":{\"type\":\"keyword\"},\"carType\":{\"type\":\"keyword\"},\"caseId\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"createBy\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"createTime\":{\"type\":\"date\",\"format\":\"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\"},\"idCard\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"name\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"registration\":{\"type\":\"keyword\"},\"remark\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"updateBy\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"updateTime\":{\"type\":\"date\",\"format\":\"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\"}}}"; + + public static final String PLATE_NUMBER_INDEX = "dc_plate_number"; + public static final String PLATE_NUMBER_MAPPING = "{\"properties\":{\"plateNumber\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"sourceFile\":{\"type\":\"keyword\"},\"bsHolder\":{\"type\":\"keyword\"},\"hasDeal\":{\"type\":\"byte\"},\"sourceContent\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"holder\":{\"type\":\"keyword\"},\"bankName\":{\"type\":\"keyword\"},\"caseId\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"createBy\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"createTime\":{\"type\":\"date\",\"format\":\"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\"},\"remark\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"updateBy\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"updateTime\":{\"type\":\"date\",\"format\":\"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\"}}}"; + + public static final String OTHER_ASSETS_INDEX = "dc_other_assets"; + public static final String OTHER_ASSETS_MAPPING = "{\"properties\":{\"analysisResultId\":{\"type\":\"long\"},\"bgc\":{\"type\":\"keyword\"},\"caseId\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"content\":{\"type\":\"text\"},\"createBy\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"createTime\":{\"type\":\"date\",\"format\":\"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\"},\"originalName\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"ossId\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"remark\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"result\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"updateBy\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"updateTime\":{\"type\":\"date\",\"format\":\"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\"}}}"; + + public static final String OTHER_INFORMATION_INDEX = "dc_other_information"; + public static final String OTHER_INFORMATION_MAPPING = "{\"properties\":{\"analysisResultId\":{\"type\":\"long\"},\"bgc\":{\"type\":\"keyword\"},\"caseId\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"content\":{\"type\":\"text\"},\"createBy\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"createTime\":{\"type\":\"date\",\"format\":\"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\"},\"originalName\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"ossId\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"remark\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"updateBy\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"updateTime\":{\"type\":\"date\",\"format\":\"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\"}}}"; + + public static final String SUSPECT_INDEX = "dc_suspect"; + public static final String SUSPECT_MAPPING = "{\"properties\":{\"createTime\":{\"type\":\"date\"},\"idCardNo\":{\"type\":\"keyword\"},\"name\":{\"type\":\"keyword\"},\"phone\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"remark\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"sortId\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"updateTime\":{\"type\":\"date\"}}}"; + + public static final String IMPORT_FAILED_PROMPT_MSG_INDEX = "dc_import_failed_prompt_msg"; + public static final String IMPORT_FAILED_PROMPT_MSG_MAPPING = "{\"properties\":{\"bankName\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"caseId\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"cause\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"fileNameList\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"fileNames\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"ossId\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}}}}"; + + public static final String OPER_UPDATE_LOG_INDEX = "sys_oper_update_log"; + public static final String OPER_UPDATE_LOG_MAPPING = "{\"properties\":{\"afterValue\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"beforeValue\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"businessId\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"jsonResult\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"method\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"operId\":{\"type\":\"long\"},\"operIp\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"operLocation\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"operName\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"operParam\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"operTime\":{\"type\":\"long\"},\"operUrl\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"operatorType\":{\"type\":\"long\"},\"requestMethod\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"status\":{\"type\":\"long\"},\"title\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}}}}"; + + public static final String LOGIN_RECORD_INDEX = "sys_login_record"; + public static final String LOGIN_RECORD_MAPPING = "{\"properties\":{\"createdTime\":{\"type\":\"long\"},\"idCardNo\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"loginDate\":{\"type\":\"long\"},\"permissionType\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}},\"updatedTime\":{\"type\":\"long\"},\"userId\":{\"type\":\"long\"},\"userName\":{\"type\":\"text\",\"fields\":{\"keyword\":{\"type\":\"keyword\",\"ignore_above\":256}}}}}"; + + + public static Map getInitIndexMap(){ + Map result = new HashMap<>(); + result.put(BANK_STATEMENT_INDEX,BANK_STATEMENT_MAPPING); + result.put(OPENING_ACCOUNT_INFO_INDEX,OPENING_ACCOUNT_INFO_MAPPING); + result.put(TRANSACTION_PARTNER_INDEX,TRANSACTION_PARTNER_MAPPING); + result.put(REAL_ESTATE_INDEX,REAL_ESTATE_MAPPING); + result.put(PUBLIC_FAMILY_INDEX,PUBLIC_FAMILY_MAPPING); + result.put(CAR_INFO_INDEX,CAR_INFO_MAPPING); + result.put(OTHER_ASSETS_INDEX,OTHER_ASSETS_MAPPING); + result.put(OTHER_INFORMATION_INDEX,OTHER_INFORMATION_MAPPING); + result.put(SUSPECT_INDEX,SUSPECT_MAPPING); + result.put(IMPORT_FAILED_PROMPT_MSG_INDEX,IMPORT_FAILED_PROMPT_MSG_MAPPING); + result.put(OPER_UPDATE_LOG_INDEX,OPER_UPDATE_LOG_MAPPING); + result.put(LOGIN_RECORD_INDEX,LOGIN_RECORD_MAPPING); + result.put(PLATE_NUMBER_INDEX,PLATE_NUMBER_MAPPING); + + return result; + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/service/OpeningAccountInfoService.java b/cas-system/src/main/java/com/inscloudtech/datacenter/service/OpeningAccountInfoService.java new file mode 100644 index 0000000..1bb9589 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/service/OpeningAccountInfoService.java @@ -0,0 +1,21 @@ +package com.inscloudtech.datacenter.service; + + + +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; +import com.inscloudtech.datacenter.domain.vo.GetOpeningAccountInfoListReq; + +import java.util.List; + +/** +* @author Administrator +* @description 针对表【opening_account_info】的数据库操作Service +* @createDate 2023-11-13 17:05:16 +*/ +public interface OpeningAccountInfoService { + + Boolean caseMerge(String sourceCaseId,String targetCaseId); + + Boolean importAnalysisResult(List list, String analysisResultId, String username); +} + diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/service/PlateNumberService.java b/cas-system/src/main/java/com/inscloudtech/datacenter/service/PlateNumberService.java new file mode 100644 index 0000000..7990fcb --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/service/PlateNumberService.java @@ -0,0 +1,69 @@ +package com.inscloudtech.datacenter.service; + + +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import org.elasticsearch.search.builder.SearchSourceBuilder; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +/** + * 重点人员资产-车辆信息Service接口 + * + * @author inscloudtech + * @date 2023-11-10 + */ +public interface PlateNumberService { + + /** + * 查询重点人员资产-车辆信息 + */ + PlateNumberInfo queryById(String id); + + /** + * 查询重点人员资产-车辆信息列表 + */ + TableDataInfo queryPageList(PlateNumberInfo bo, PageQuery pageQuery); + + /** + * 查询重点人员资产-车辆信息列表 + */ + List queryList(PlateNumberInfo bo); + + /** + * 新增重点人员资产-车辆信息 + */ + Boolean insertByBo(PlateNumberInfo bo); + + /** + * 修改重点人员资产-车辆信息 + */ + Boolean updateByBo(PlateNumberInfo bo); + + /** + * 校验并批量删除重点人员资产-车辆信息信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + Boolean importData(List list,String caseId,String analysisResultId); + + Boolean caseMerge(String sourceCaseId,String targetCaseId); + + void analysisResultMerge(Map sourceArIdTargetArIdMap); + + + Boolean updateBatch(List list); + + Boolean importAnalysisResult(List list, String analysisResultId, String username); + + List dataTrimAndDeduplication(List list, String caseId, String username); + + SearchSourceBuilder getSearchSourceBuilder(PlateNumberInfo PlateNumberInfo); + + void save2AnalysisResult(AnalysisDto dto); + + void invoke(String caseId); +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/service/QueryCenterService.java b/cas-system/src/main/java/com/inscloudtech/datacenter/service/QueryCenterService.java new file mode 100644 index 0000000..7778359 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/service/QueryCenterService.java @@ -0,0 +1,1490 @@ +package com.inscloudtech.datacenter.service; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ClassUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.pinyin.PinyinUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.analysiscenter.domain.AnalysisReport; +import com.inscloudtech.analysiscenter.domain.AnalysisResult; +import com.inscloudtech.analysiscenter.mapper.AnalysisReportMapper; +import com.inscloudtech.analysiscenter.mapper.AnalysisResultMapper; +import com.inscloudtech.analysiscenter.service.IAnalysisReportService; +import com.inscloudtech.analysiscenter.service.IAnalysisResultService; + +import com.inscloudtech.caseMange.domain.SysLawCase; +import com.inscloudtech.caseMange.mapper.SysLawCaseMapper; +import com.inscloudtech.common.annotation.IdCardField; +import com.inscloudtech.common.annotation.NameField; +import com.inscloudtech.common.annotation.PhoneField; +import com.inscloudtech.common.config.ProjectConfig; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.excel.ExcelResult; +import com.inscloudtech.common.excel.MyLongestMatchColumnWidthStyleStrategy; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.file.FileUtils; +import com.inscloudtech.common.utils.poi.ExcelUtil; +import com.inscloudtech.common.utils.spring.SpringUtils; + +import com.inscloudtech.datacenter.domain.*; +import com.inscloudtech.datacenter.domain.dto.*; +import com.inscloudtech.datacenter.mapper.*; +import com.inscloudtech.datacenter.mapper.es.ESBankStatementMapper; +import com.inscloudtech.datacenter.mapper.es.ESOpeningAccountInfoMapper; +import com.inscloudtech.datacenter.mapper.es.OtherInformationEsMapper; + +import com.inscloudtech.datacenter.service.*; +import com.inscloudtech.datacenter.service.BankService; +import com.inscloudtech.datacenter.service.ICarInfoService; +import com.inscloudtech.datacenter.service.IRealEstateService; +import com.inscloudtech.system.domain.SysOss; +import com.inscloudtech.system.mapper.SysOssMapper; +import com.inscloudtech.system.service.ISysOssService; +import com.inscloudtech.datacenter.service.IndexInitService; +import com.inscloudtech.datacenter.service.PlateNumberService; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.dromara.easyes.annotation.HighLight; +import org.dromara.easyes.annotation.IndexName; +import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; +import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; +import org.elasticsearch.action.search.ClearScrollRequest; +import org.elasticsearch.action.search.SearchRequest; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.action.search.SearchScrollRequest; +import org.elasticsearch.client.RequestOptions; +import org.elasticsearch.client.RestHighLevelClient; + +import org.elasticsearch.client.indices.GetIndexRequest; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.core.TimeValue; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.index.reindex.BulkByScrollResponse; +import org.elasticsearch.index.reindex.DeleteByQueryRequest; +import org.elasticsearch.search.Scroll; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.aggregations.Aggregation; +import org.elasticsearch.search.aggregations.AggregationBuilder; +import org.elasticsearch.search.aggregations.AggregationBuilders; +import org.elasticsearch.search.aggregations.Aggregations; +import org.elasticsearch.search.aggregations.bucket.terms.Terms; +import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder; +import org.elasticsearch.search.aggregations.metrics.Cardinality; +import org.elasticsearch.search.aggregations.metrics.CardinalityAggregationBuilder; +import org.elasticsearch.search.aggregations.metrics.TopHits; +import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder; +import org.elasticsearch.search.fetch.subphase.highlight.HighlightField; +import org.elasticsearch.search.sort.SortOrder; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.net.URLEncoder; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; + +@RequiredArgsConstructor +@Service +@Slf4j +public class QueryCenterService { + + private static final int AGG_MAX_PAGE_SIZE = 100; + + public static final int MAX_PAGE_SIZE = 10000; + + public static final String TAG_PREFIX = ""; + public static final String TAG_SUFFIX = ""; + + // org.elasticsearch.ElasticsearchException: Elasticsearch exception [type=illegal_argument_exception, + // reason=Result window is too large, from + size must be less than or equal to: [10000] but was [2147483647]. See + // the scroll api for a more efficient way to request large data sets. This limit can be set by changing the + // [index.max_result_window] index level setting.] + + private final RestHighLevelClient restHighLevelClient; + + private final OtherInformationEsMapper commonEsMapper; + + private final CarInfoMapper commonMysqlMapper; + + private final AnalysisReportMapper analysisReportMapper; + + private final SysOssMapper ossMapper; + + private final ISysOssService sysOssService; + + private final AnalysisResultMapper analysisResultMapper; + + private final SysLawCaseMapper lawCaseMapper; + + private final ITransactionPartnerService transactionPartnerService; + + private final IRealEstateService realEstateService; + + private final IPublicFamilyService publicFamilyService; + + private final ICarInfoService carInfoService; + + private final PlateNumberService plateNumberService; + + private Map>> importMapperMap = new HashMap(); + + private Map>> dtoMap = new HashMap(); + + + private static final List> INDEX = Arrays.asList( + PublicFamily.class, + TransactionPartner.class, + RealEstate.class, + CarInfo.class, + BankStatement.class,PlateNumberInfo.class); + + private static final List> OTHER_INDEX = Arrays.asList(OtherAssets.class, OtherInformation.class); + + public List> initQueryIndex(Integer isOther) { + List> willSearch = new ArrayList<>(INDEX); + if (isOther.equals(1)) { + willSearch.addAll(OTHER_INDEX); + } + return willSearch; + } + + public static JSONObject getQueryInfo(List> willSearch) { + Set indexList = new HashSet<>(); + Set nameFieldList = new HashSet<>(Collections.singletonList("name")); + Set idCardFieldList = new HashSet<>(Arrays.asList("idCard", "idCardNo")); + Set phoneFieldList = new HashSet<>(Collections.singletonList("phone")); + for (Class classItem : willSearch) { + String indexName = classItem.getAnnotation(IndexName.class).value(); + indexList.add(indexName); + Field[] fields = classItem.getDeclaredFields(); + for (Field field : fields) { + field.setAccessible(true); + if (field.isAnnotationPresent(NameField.class)) { + nameFieldList.add(field.getName()); + } + if (field.isAnnotationPresent(IdCardField.class)) { + idCardFieldList.add(field.getName() + ".keyword"); + } + if (field.isAnnotationPresent(PhoneField.class)) { + phoneFieldList.add(field.getName()); + } + } + } + + JSONObject result = new JSONObject(); + result.put("indexArr", ArrayUtil.toArray(indexList, String.class)); + result.put("nameFieldList", nameFieldList); + result.put("idCardFieldList", idCardFieldList); + result.put("phoneFieldList", phoneFieldList); + return result; + } + + public SearchResponse bankStatementQuery(QueryCenterQuery query){ + SearchRequest searchRequest = new SearchRequest("dc_bank_statement"); // 设置要查询的索引 + SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); + BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); + if (null != query.getCaseId()) { + boolQuery.must(QueryBuilders.termQuery("caseId", query.getCaseId())); + } + + //除了 cardHolderName + + String searchValue = query.getSearchValue().trim().replaceAll("([ ]|\\s|\\u00A0)+","") ; + + BoolQueryBuilder keywordQ = QueryBuilders.boolQuery(); + searchValue = "*" +searchValue + "*"; + keywordQ.should(QueryBuilders.wildcardQuery("idCardNo.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("cardNumber.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("transactionInstitutions.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("counterpartyName.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("counterpartyAccount.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("counterpartIdCardNo.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("counterpartyBankName.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("summary.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("transRemark.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("transChannel.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("realCounterpartyName.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("realCounterpartyAccount.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("phone.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("remark.keyword", searchValue)); + + boolQuery.must(keywordQ); + + + searchSourceBuilder.query(boolQuery); + searchRequest.source(searchSourceBuilder); + SearchResponse searchResponse = null; + try { + searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); + } catch (IOException e) { + e.printStackTrace(); + } + return searchResponse; + } + + + @SneakyThrows + public JSONObject count(QueryCenterQuery query) { + SearchResponse bsRes = this.bankStatementQuery(query); + JSONObject indexAndCount = new JSONObject(); + indexAndCount.put("dc_bank_statement",bsRes.getHits().getTotalHits().value); + + JSONObject queryInfo = getQueryInfo(initQueryIndex(0)); + String[] indexArrs = queryInfo.getBean("indexArr", String[].class); + + SearchRequest searchRequest = new SearchRequest(indexArrs); // 设置要查询的索引 + SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); + BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); + if (null != query.getCaseId()) { + boolQuery.must(QueryBuilders.termQuery("caseId", query.getCaseId())); + } + + BoolQueryBuilder shouldQueryBuilder = QueryBuilders.boolQuery(); + if (StrUtil.isNotEmpty(query.getIdCard())) { + List idCardFieldList = queryInfo.getBeanList("idCardFieldList", String.class); + for (String idField : idCardFieldList) { + shouldQueryBuilder.should(QueryBuilders.termQuery(idField, query.getIdCard())); + } + } + + if (StrUtil.isNotEmpty(query.getPhone())) { + List phoneFieldList = queryInfo.getBeanList("phoneFieldList", String.class); + for (String phoneField : phoneFieldList) { + shouldQueryBuilder.should(QueryBuilders.termQuery(phoneField, query.getPhone())); + } + } + + if (StrUtil.isNotEmpty(query.getName())) { + List nameFieldList = queryInfo.getBeanList("nameFieldList", String.class); + for (String nameField : nameFieldList) { + shouldQueryBuilder.should(QueryBuilders.termQuery(nameField, query.getName())); + } + } + searchSourceBuilder.size(1); + boolQuery.must(shouldQueryBuilder); + if (StrUtil.isNotBlank(query.getSearchValue())) { + boolQuery.must(QueryBuilders.queryStringQuery("*" + query.getSearchValue().trim().replaceAll("([ ]|\\s|\\u00A0)+","") + "*")); + } + searchSourceBuilder.query(boolQuery); + TermsAggregationBuilder aggregation = + AggregationBuilders.terms("by_index").field("_index"); + CardinalityAggregationBuilder cardinalityAggregation = + AggregationBuilders.cardinality("total_hits").field("_id"); + searchSourceBuilder.aggregation(aggregation.subAggregation(cardinalityAggregation)); + searchRequest.source(searchSourceBuilder); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); + Aggregations aggregations = searchResponse.getAggregations(); + Terms byIndexAggregation = aggregations.get("by_index"); + for (Terms.Bucket bucket : byIndexAggregation.getBuckets()) { + Cardinality totalHitsCardinality = bucket.getAggregations().get("total_hits"); + if("dc_bank_statement".equals(bucket.getKeyAsString())){ + continue; + } + indexAndCount.put(bucket.getKeyAsString(), totalHitsCardinality.getValue()); + } + + searchOtherIndex(indexAndCount,query.getCaseId(),query.getSearchValue()); + return indexAndCount; + } + + @SneakyThrows + private void searchOtherIndex(JSONObject indexAndCount, String caseId, String searchValue) { + String[] indexArrs = {"dc_other_information","dc_other_assets"}; + SearchRequest searchRequest = new SearchRequest(indexArrs); // 设置要查询的索引 + SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); + BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); + boolQuery.must(QueryBuilders.termQuery("caseId", caseId)); + + BoolQueryBuilder shouldQueryBuilder = QueryBuilders.boolQuery(); + searchSourceBuilder.size(1); + boolQuery.must(shouldQueryBuilder); + if (StrUtil.isNotBlank(searchValue)) { + boolQuery.must(QueryBuilders.matchPhraseQuery("content",searchValue.trim().replaceAll("([ ]|\\s|\\u00A0)+",""))); + } + searchSourceBuilder.query(boolQuery); + TermsAggregationBuilder aggregation = + AggregationBuilders.terms("by_index").field("_index"); + CardinalityAggregationBuilder cardinalityAggregation = + AggregationBuilders.cardinality("total_hits").field("_id"); + searchSourceBuilder.aggregation(aggregation.subAggregation(cardinalityAggregation)); + searchRequest.source(searchSourceBuilder); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); + Aggregations aggregations = searchResponse.getAggregations(); + Terms byIndexAggregation = aggregations.get("by_index"); + for (Terms.Bucket bucket : byIndexAggregation.getBuckets()) { + Cardinality totalHitsCardinality = bucket.getAggregations().get("total_hits"); + + indexAndCount.put(bucket.getKeyAsString(), totalHitsCardinality.getValue()); + } + } + + @SneakyThrows + public JSONObject indexDataCount(QueryCenterQuery query) { + JSONObject queryInfo = getQueryInfo(initQueryIndex(query.getIsOther())); + String[] indexArrs = queryInfo.getBean("indexArr", String[].class); + + List indexList = new ArrayList<>(Arrays.asList(indexArrs)); + indexList.add("dc_opening_account_info"); + String[] indexArr = indexList.toArray(new String[indexList.size()]); + SearchRequest searchRequest = new SearchRequest(); // 设置要查询的索引 + SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); + BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); + if (null != query.getCaseId()) { + boolQuery.must(QueryBuilders.termQuery("caseId", query.getCaseId())); + } + + if (StrUtil.isNotBlank(query.getSearchValue())) { + boolQuery.must(QueryBuilders.queryStringQuery("*" + query.getSearchValue().trim().replaceAll("([ ]|\\s|\\u00A0)+","") + "*")); + } + searchSourceBuilder.query(boolQuery); + TermsAggregationBuilder aggregation = + AggregationBuilders.terms("by_index").field("_index"); + + searchSourceBuilder.aggregation(aggregation); + + searchRequest.source(searchSourceBuilder); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); + Aggregations aggregations = searchResponse.getAggregations(); + Terms byIndexAggregation = aggregations.get("by_index"); + JSONObject indexAndCount = new JSONObject(); + for (Terms.Bucket bucket : byIndexAggregation.getBuckets()) { + if(indexAndCount.containsKey(bucket.getKeyAsString())){ + continue; + } + indexAndCount.put(bucket.getKeyAsString(), bucket.getDocCount()); + } + return indexAndCount; + } + + /** + * @Description search_after 深分页 + */ + @SneakyThrows + public TableDataInfo page(QueryCenterQuery query) { + SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); + BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); + boolQuery.must(QueryBuilders.termQuery("caseId", query.getCaseId())); + if (StrUtil.isNotBlank(query.getSearchValue())) { + boolQuery.must(QueryBuilders.queryStringQuery("*" + query.getSearchValue().trim().replaceAll("([ ]|\\s|\\u00A0)+","") + "*")); + } + searchSourceBuilder.query(boolQuery).sort("_id", SortOrder.DESC).from(0).size(query.getPageSize()); + SearchRequest searchRequest = new SearchRequest(query.getIndex()).source(searchSourceBuilder); + + if (ArrayUtil.isNotEmpty(query.getNextSearchAfter())) { + // 存储上一次分页的sort信息 + searchSourceBuilder.searchAfter(query.getNextSearchAfter()); + } + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); + SearchHits responseHits = searchResponse.getHits(); + SearchHit[] hits = responseHits.getHits(); + List rows = new ArrayList(); + for (SearchHit hit : hits) { + rows.add(hit.getSourceAsMap()); + } + TableDataInfo tableDataInfo = new TableDataInfo(); + tableDataInfo.setTotal(responseHits.getTotalHits().value); + tableDataInfo.setRows(rows); + return tableDataInfo; + } + + /** + * @Description search_after 深分页 + */ + @SneakyThrows + public void deleteData(String index,String caseId) { + DeleteByQueryRequest deleteByQueryRequest= new DeleteByQueryRequest(index); + deleteByQueryRequest.setQuery(QueryBuilders.termQuery("caseId", caseId)); + BulkByScrollResponse bulkByScrollResponse = restHighLevelClient.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT); + } + + + /** + * 成果中心导出数据源 + * @param query + * @return + */ + @SneakyThrows + public JSONObject getData4ExcelExport(QueryCenterQuery query) { + JSONObject queryInfo = getQueryInfo(initQueryIndex(query.getIsOther())); + SearchRequest searchRequest = new SearchRequest(queryInfo.getBean("indexArr", String[].class)); // 设置要查询的索引 + SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); + BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); +// if (null != query.getCaseId()) { +// boolQuery.must(QueryBuilders.termQuery("caseId", query.getCaseId())); +// } + if (null != query.getAnalysisResultId()) { + boolQuery.must(QueryBuilders.termQuery("analysisResultId", query.getAnalysisResultId())); + } + searchSourceBuilder.query(boolQuery); + TermsAggregationBuilder aggregation = AggregationBuilders.terms("by_index") + .field("_index") + .subAggregation(AggregationBuilders.topHits("top_hits").size(AGG_MAX_PAGE_SIZE)); + searchSourceBuilder.aggregation(aggregation); + searchRequest.source(searchSourceBuilder); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); + Aggregations aggregations = searchResponse.getAggregations(); + // 获取按_index字段聚合的结果 + Terms byIndexAggregation = aggregations.get("by_index"); + List buckets = byIndexAggregation.getBuckets(); + + JSONObject result = new JSONObject(); + Set needSearchIndexes = new HashSet<>(); + // 遍历bucket列表 + for (Terms.Bucket bucket : buckets) { + String index = bucket.getKeyAsString(); + long count = bucket.getDocCount(); + List dataList = new ArrayList<>(); + if (count > AGG_MAX_PAGE_SIZE) { + needSearchIndexes.add(index); + } else { + // 获取每个分组的顶部文档 + TopHits topHits = bucket.getAggregations().get("top_hits"); + SearchHits hits = topHits.getHits(); + // 遍历顶部文档 + for (SearchHit hit : hits.getHits()) { + JSONObject json = JSONUtil.parseObj(hit.getSourceAsString()); + + json.put("id", hit.getId()); + dataList.add(json); + } + } + result.put(index, dataList); + } + + if (CollectionUtil.isNotEmpty(needSearchIndexes)) { + getAllData(needSearchIndexes, boolQuery, result); + } + return result; + } + + @SneakyThrows + void getAllData(Set indexSet, BoolQueryBuilder boolQuery, JSONObject result) { + for (String indexName : indexSet) { + scrollSearch(indexName,boolQuery,result); + } + } + + @SneakyThrows + public void scrollSearch(String indexName, BoolQueryBuilder boolQuery, JSONObject result){ + SearchSourceBuilder ssb = new SearchSourceBuilder(); + SearchRequest searchRequest = new SearchRequest(indexName); + Scroll scroll = new Scroll(TimeValue.timeValueMinutes(3)); // 设置一次读取的最大连接时长 + ssb.query(boolQuery); + ssb.size(MAX_PAGE_SIZE); + searchRequest.source(ssb); + searchRequest.scroll(scroll); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); + SearchHits responseHits = searchResponse.getHits(); + String scrollId = searchResponse.getScrollId(); + List dataList = new ArrayList<>(); + long total = responseHits.getTotalHits().value; + if (total > MAX_PAGE_SIZE) { + while (true) { + SearchHits hits = searchResponse.getHits(); + for (SearchHit hit : hits.getHits()) { + JSONObject json = JSONUtil.parseObj(hit.getSourceAsString()); + json.put("id", hit.getId()); + dataList.add(json); + } + // 继续滚动获取下一页数据 + SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId); + scrollRequest.scroll(TimeValue.timeValueMinutes(1L)); + searchResponse = restHighLevelClient.scroll(scrollRequest, RequestOptions.DEFAULT); + scrollId = searchResponse.getScrollId(); + + // 判断是否还有数据 + if (searchResponse.getHits().getHits().length == 0) { + break; + } + } + ClearScrollRequest clearScrollRequest = new ClearScrollRequest(); + clearScrollRequest.addScrollId(scrollId); + restHighLevelClient.clearScroll(clearScrollRequest, RequestOptions.DEFAULT); + result.put(indexName, dataList); + } else { + SearchHit[] hits = responseHits.getHits(); + for (SearchHit hit : hits) { + JSONObject json = JSONUtil.parseObj(hit.getSourceAsString()); + json.put("id", hit.getId()); + dataList.add(json); + } + result.put(indexName, dataList); + } + } + + @SneakyThrows + public JSONObject getFieldsValueCount(JSONObject json) { + StatisticsQuery query = JSONUtil.toBean(json,StatisticsQuery.class); + List fields = query.getFields(); + String indexName = query.getModule(); + JSONObject resJson = new JSONObject(); +// SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); + SearchSourceBuilder searchSourceBuilder = buildSearchSourceBuilder(indexName,json); + for (String field : fields) { + AggregationBuilder agg = + AggregationBuilders.terms("groupBy_" + field).field(field+".keyword").size(10000); + searchSourceBuilder.aggregation(agg); + } + SearchRequest searchRequest = new SearchRequest(indexName); + searchRequest.source(searchSourceBuilder); + SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); + Aggregations aggregations = search.getAggregations(); + // 获取name字段的聚合结果 + Map map = aggregations.asMap(); + for (String field : fields) { + String groupByField = "groupBy_" + field; + if (map.containsKey(groupByField)) { + Terms terms = (Terms) map.get(groupByField); + List buckets = terms.getBuckets(); + List tempList = new ArrayList<>(); + for (Terms.Bucket bucket : buckets) { + StatisticsOption statisticsOption = new StatisticsOption(); + String value = bucket.getKey().toString(); + value = StrUtil.isEmpty(value)?"其它":value; + statisticsOption.setValue(value); + statisticsOption.setLabel(value); + statisticsOption.setField(PinyinUtil.getPinyin(statisticsOption.getValue())); + statisticsOption.setCount(bucket.getDocCount()); + tempList.add(statisticsOption); + } + List sortList = tempList.stream().sorted(Comparator.comparing(StatisticsOption::getField, String.CASE_INSENSITIVE_ORDER)).collect(Collectors.toList()); + resJson.put(field,sortList); + } + } + return resJson; + } + + //todo 用反射 + private SearchSourceBuilder buildSearchSourceBuilder(String indexName, JSONObject json) { + SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); + switch (indexName){ + case "dc_public_family": + PublicFamily family = JSONUtil.toBean(json.toString(), PublicFamily.class); + searchSourceBuilder = publicFamilyService.getSearchSourceBuilder(family); + break; + case "dc_real_estate": + RealEstate realEstate = JSONUtil.toBean(json.toString(), RealEstate.class); + searchSourceBuilder = realEstateService.getSearchSourceBuilder(realEstate); + break; + case "dc_transaction_partner": + TransactionPartner transactionPartner = JSONUtil.toBean(json.toString(), TransactionPartner.class); + searchSourceBuilder = transactionPartnerService.getSearchSourceBuilder(transactionPartner); + break; + case "dc_car_info": + CarInfo carInfo = JSONUtil.toBean(json.toString(), CarInfo.class); + searchSourceBuilder = carInfoService.getSearchSourceBuilder(carInfo); + break; + case "dc_plate_number": + PlateNumberInfo plateNumberInfo = JSONUtil.toBean(json.toString(), PlateNumberInfo.class); + searchSourceBuilder = plateNumberService.getSearchSourceBuilder(plateNumberInfo); + break; + default: + break; + } + return searchSourceBuilder; + } + + @SneakyThrows + public Long deleteDataByCondition(QueryCenterQuery query) { + if(null == query.getCaseId()){ + throw new RuntimeException("案件id不能为空!"); + } + String indexName = query.getIndex(); + if(StrUtil.isEmpty(indexName)){ + throw new RuntimeException("[业务模块]不能为空!"); + } + JSONObject queryInfo = getQueryInfo(initQueryIndex(1)); + String[] indexArr = queryInfo.getBean("indexArr", String[].class); + List indexList = Arrays.asList(indexArr); + if(!indexList.contains(indexName)){ + throw new RuntimeException("非法操作!"); + } + + QueryBuilder queryBuilder = QueryBuilders.termQuery("caseId", query.getCaseId()); + DeleteByQueryRequest deleteRequest = new DeleteByQueryRequest(indexName); + deleteRequest.setQuery(queryBuilder); + // 启用刷新操作 + deleteRequest.setRefresh(true); + BulkByScrollResponse response = restHighLevelClient.deleteByQuery(deleteRequest, RequestOptions.DEFAULT); + long deletedCount = response.getDeleted(); + if(!indexName.equals("dc_plate_number")){ + this.deleteMysqlData(indexName,query.getCaseId()); + } + + if(indexName.equals("dc_other_information")){ + sysOssService.deleteByCaseIdAndBusinessModule(query.getCaseId(),"OTHER_INFORMATION"); + }else if(indexName.equals("dc_other_assets")){ + sysOssService.deleteByCaseIdAndBusinessModule(query.getCaseId(),"OTHER_ASSETS"); + } + + return deletedCount; + } + + void deleteMysqlData(String indexName,String caseId){ + commonMysqlMapper.updateDelFlag(indexName,caseId); + } + + + /** + * 测试用 + */ + @SneakyThrows + public Boolean mysqlToEs(String indexName,boolean create) { + String mapperPath = "com.inscloudtech.datacenter.mapper"; + Set> classes = ClassUtil.scanPackage(mapperPath); + Map, Class> mapperMap = new HashMap(); + for (Class clazz : classes) { + if (!clazz.getName().contains("es")) { + for (Class aClass : classes) { + String esMapperName = clazz.getSimpleName().replace("Mapper", "EsMapper"); + if (esMapperName.equals(aClass.getSimpleName())) { + mapperMap.put(clazz, aClass); + break; + } + } + } + } + + for (Class mysqlMapper : mapperMap.keySet()) { + Class esMapper = mapperMap.get(mysqlMapper); + String tempIndex = + "dc_" + StrUtil.toUnderlineCase(esMapper.getSimpleName().replace("EsMapper", "")); + if (StrUtil.isNotEmpty(indexName) && !tempIndex.equals(indexName)) { + continue; + } + Object esMapperObj = SpringUtils.getBean(esMapper); + Method insertBatch = esMapper.getMethod("insertBatch", Collection.class); + if(create){ + + // Method deleteIndex = esMapper.getMethod("deleteIndex", String[].class); + // deleteIndex.invoke(esMapperObj,indexNames); + commonEsMapper.deleteIndex(tempIndex); + Method createIndex = esMapper.getMethod("createIndex"); + createIndex.invoke(esMapperObj); + + } + + + Method targetMethod = mysqlMapper.getMethod("selectList"); + Object mysqlMapperObj = SpringUtils.getBean(mysqlMapper); + Object dataList = targetMethod.invoke(mysqlMapperObj); + insertBatch.invoke(esMapperObj, dataList); + } + + return true; + } + + public JSONObject getFieldsValueCount2Mysql(StatisticsQuery query) { + List fields = query.getFields(); + List groupByFields = new ArrayList<>(); + for (String field : fields) { + groupByFields.add(StrUtil.toUnderlineCase(field)); + } + String module = query.getModule(); + List list = commonMysqlMapper.getFieldsValueCount(module, groupByFields, query.getCaseId()); + Map> listMap = + list.stream().collect(Collectors.groupingBy(StatisticsOption::getField)); + JSONObject resJson = new JSONObject(); + for (String field : listMap.keySet()) { + resJson.put(StrUtil.toCamelCase(field), listMap.get(field)); + } + return resJson; + } + + @SneakyThrows + public JSONObject getData4Report(List> willSearch, String name, String idCard, String caseId) { + JSONObject queryInfo = getQueryInfo(willSearch); + SearchRequest searchRequest = new SearchRequest(queryInfo.getBean("indexArr", String[].class)); // 设置要查询的索引 + SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); + BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); + if (null != caseId) { + boolQuery.must(QueryBuilders.termQuery("caseId", caseId)); + } + + BoolQueryBuilder shouldQueryBuilder = QueryBuilders.boolQuery(); + if (StrUtil.isNotEmpty(idCard)) { + List idCardFieldList = queryInfo.getBeanList("idCardFieldList", String.class); + for (String idCardField : idCardFieldList) { + shouldQueryBuilder.should(QueryBuilders.termQuery(idCardField, idCard)); + } + } + + if (StrUtil.isNotEmpty(name)) { + List nameFieldList = queryInfo.getBeanList("nameFieldList", String.class); + for (String nameField : nameFieldList) { + shouldQueryBuilder.should(QueryBuilders.matchQuery(nameField, name.trim())); + } + } + + boolQuery.must(shouldQueryBuilder); + searchSourceBuilder.query(boolQuery); + TermsAggregationBuilder aggregation = AggregationBuilders.terms("by_index") + .field("_index") + .subAggregation(AggregationBuilders.topHits("top_hits").size(AGG_MAX_PAGE_SIZE)); + searchSourceBuilder.aggregation(aggregation); + searchRequest.source(searchSourceBuilder); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); + Aggregations aggregations = searchResponse.getAggregations(); + // 获取按_index字段聚合的结果 + Terms byIndexAggregation = aggregations.get("by_index"); + List buckets = byIndexAggregation.getBuckets(); + + JSONObject result = new JSONObject(); + Set needSearchIndexes = new HashSet<>(); + // 遍历bucket列表 + for (Terms.Bucket bucket : buckets) { + String index = bucket.getKeyAsString(); + long count = bucket.getDocCount(); + List dataList = new ArrayList<>(); + if (count > AGG_MAX_PAGE_SIZE) { + needSearchIndexes.add(index); + } else { + // 获取每个分组的顶部文档 + TopHits topHits = bucket.getAggregations().get("top_hits"); + SearchHits hits = topHits.getHits(); + // 遍历顶部文档 + for (SearchHit hit : hits.getHits()) { + JSONObject json = JSONUtil.parseObj(hit.getSourceAsString()); + json.put("id", hit.getId()); + dataList.add(json); + } + } + result.put(index, dataList); + } + + if (CollectionUtil.isNotEmpty(needSearchIndexes)) { + getAllData(needSearchIndexes, boolQuery, result); + } + return result; + } + + + @SneakyThrows + @PostConstruct + public void initIndexes() { + Map initIndexMap = IndexInitService.getInitIndexMap(); + for (String index : initIndexMap.keySet()) { + GetIndexRequest getIndexRequest = new GetIndexRequest(index); + boolean exists = restHighLevelClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT); + if(!exists){ + CreateIndexRequest request = new CreateIndexRequest(index); + request.mapping("_doc", initIndexMap.get(index), XContentType.JSON); + if(index.equals(IndexInitService.TRANSACTION_PARTNER_INDEX) || index.equals(IndexInitService.PUBLIC_FAMILY_INDEX)){ + request.settings(IndexInitService.TRANSACTION_PARTNER_SETTINGS, XContentType.JSON); + } + CreateIndexResponse indexResponse = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT); + System.out.println("es索引" + index +"创建完毕!"); + } + } + +// String mapperPath = "com.inscloudtech.datacenter.mapper"; +// Set> classes = ClassUtil.scanPackage(mapperPath); +// Map, Class> mapperMap = new HashMap(); +// for (Class clazz : classes) { +// if (!clazz.getName().contains("es")) { +// for (Class aClass : classes) { +// String esMapperName = clazz.getSimpleName().replace("Mapper", "EsMapper"); +// if (esMapperName.equals(aClass.getSimpleName())) { +// mapperMap.put(clazz, aClass); +// break; +// } +// } +// } +// } +// +// for (Class mysqlMapper : mapperMap.keySet()) { +// Class esMapper = mapperMap.get(mysqlMapper); +// String tempIndex = +// "dc_" + StrUtil.toUnderlineCase(esMapper.getSimpleName().replace("EsMapper", "")); +// +// Object esMapperObj = SpringUtils.getBean(esMapper); +// +// Boolean existsIndex = commonEsMapper.existsIndex(tempIndex); +// if (!existsIndex) { +// Method createIndex = esMapper.getMethod("createIndex"); +// createIndex.invoke(esMapperObj); +// } +// } +// +// if (!commonEsMapper.existsIndex("dc_other_information")) { +// commonEsMapper.createIndex(); +// } + } + + @SneakyThrows + public Map getData4ReportWithHighlight(List> willSearch, String name,String idCard, String caseId) { + JSONObject queryInfo = getQueryInfo(willSearch); + SearchRequest searchRequest = new SearchRequest(queryInfo.getBean("indexArr", String[].class)); // 设置要查询的索引 + SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); + BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); + if (null != caseId) { + boolQuery.must(QueryBuilders.termQuery("caseId", caseId)); + } + BoolQueryBuilder shouldQueryBuilder = QueryBuilders.boolQuery(); + shouldQueryBuilder.should(QueryBuilders.queryStringQuery("*"+name+"*")); + shouldQueryBuilder.should(QueryBuilders.queryStringQuery("*"+idCard+"*")); + boolQuery.must(shouldQueryBuilder); + searchSourceBuilder + .query(boolQuery) + .highlighter(new HighlightBuilder() + .field("content") + .requireFieldMatch(false) + .preTags("\r\n") + .postTags("\r\n")); + searchRequest.source(searchSourceBuilder); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); + SearchHits hits1 = searchResponse.getHits(); + searchResponse.getHits().getHits(); + + List tempList = new ArrayList<>(); + for (SearchHit documentFields : hits1) { + OtherAssetsDto dto = new OtherAssetsDto(); + dto.setIndex(documentFields.getIndex()); + Map sourceAsMap = documentFields.getSourceAsMap(); + if (sourceAsMap.containsKey("originalName") && sourceAsMap.get("originalName") != null) { + dto.setOriginalName(sourceAsMap.get("originalName").toString()); + } + Map highlightFields = documentFields.getHighlightFields(); + if (CollectionUtil.isNotEmpty(highlightFields) && highlightFields.containsKey("content")) { + HighlightField content = highlightFields.get("content"); + if (content != null && CollectionUtil.isNotEmpty(Arrays.asList(content.getFragments()))) { + dto.setHighlight(content.getFragments()[0] == null ? "" : content.getFragments()[0].toString()); + } + } + tempList.add(dto); + } + Map> collect = + tempList.stream().collect(Collectors.groupingBy(OtherAssetsDto::getIndex)); + return collect; + } + + @SneakyThrows + public JSONObject getStatisticsData(String caseId) { + JSONObject result = new JSONObject(); + + //案件嫌疑人,涉及银行,涉嫌银行卡, + //cardHolderName//bankName//cardNumber//, // counterpartyBankName,counterpartyAccount + //涉嫌交易对象 counterpartyName + List fields = new ArrayList<>(Arrays.asList("cardHolderName","bankName","cardNumber")); + BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); + boolQuery.must(QueryBuilders.termQuery("caseId", caseId)); + JSONObject resJson = new JSONObject(); + SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); + + for (String field : fields) { + AggregationBuilder agg = AggregationBuilders.terms("groupBy_" + field).field(field + ".keyword").size(10000); + searchSourceBuilder.aggregation(agg); + } + fields.add("travellingTrader"); + AggregationBuilder agg = AggregationBuilders.terms("groupBy_" + "travellingTrader").field("travellingTrader").size(10000); + searchSourceBuilder.aggregation(agg); + + searchSourceBuilder.query(boolQuery); + SearchRequest searchRequest = new SearchRequest("dc_transaction_partner,dc_bank_statement"); + searchRequest.source(searchSourceBuilder); + SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); + Aggregations aggregations = search.getAggregations(); + // 获取name字段的聚合结果 + + Map asMap = aggregations.getAsMap(); + for (String field : fields) { + String groupByField = "groupBy_" + field; + if (asMap.containsKey(groupByField)) { + Terms terms = (Terms) asMap.get(groupByField); + List buckets = terms.getBuckets(); + if (CollectionUtil.isEmpty(buckets)) { + continue; + } + Set valueSet = new HashSet<>(); + for (Terms.Bucket bucket : buckets) { + String value = bucket.getKey().toString(); + value = StrUtil.isEmpty(value)?"其它":value; + valueSet.add(value); + } + resJson.put(field,valueSet.size()); + } + } + + result.put("cardHolderNameCount",resJson.getInt("cardHolderName")); + result.put("bankNameCount",resJson.getInt("bankName")); + result.put("cardNumberCount",resJson.getInt("cardNumber")); + result.put("travellingTraderCount",resJson.getInt("travellingTrader")); + + //报告数量 + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + result.put("reportCount",analysisReportMapper.selectCount(lqw.eq(AnalysisReport::getCaseId,caseId))); + + //导入数据统计 + JSONObject importDataJson = new JSONObject(); + + List moduleCNName = Arrays.asList("银行流水及开户信息","交易对象","职工家属", "不动产信息","车辆信息"); + importDataJson.put("x",moduleCNName); + List modules = Arrays.asList("BANK_STATEMENT","TRANSACTION_PARTNER","PUBLIC_FAMILY", "REAL_ESTATE","CAR_INFO"); + List y = new ArrayList<>(); + List statisticsVoList = ossMapper.statisticsData(caseId); + Map statisticsVoMap = statisticsVoList.stream().collect(Collectors.toMap(StatisticsVo::getModule, Function.identity())); + + QueryCenterQuery query = new QueryCenterQuery(); + query.setCaseId(caseId); + JSONObject countJson = this.indexDataCount(query); + + for (String module : modules) { + String indexName = "dc_" + module.toLowerCase(); + if (countJson.containsKey(indexName)) { + y.add(countJson.getLong(indexName)); + }else { + y.add(0L); + } + } + + importDataJson.put("y",y); + result.put("importData",importDataJson); + + //导入文件数量统计 + List fileJsonList = new ArrayList<>(); + for (int i = 0;i < moduleCNName.size(); i++){ + String name = moduleCNName.get(i); + String module = modules.get(i); + JSONObject json = new JSONObject(); + json.put("name",name); + int value = 0; + if (statisticsVoMap.containsKey(module)) { + StatisticsVo vo = statisticsVoMap.get(module); + value = vo.getFileCount(); + } + json.put("value",value); + fileJsonList.add(json); + } + result.put("importFile",fileJsonList); + return result; + } + + @SneakyThrows + public void exportCaseAllData(String caseId, HttpServletResponse response) { + if(null == caseId){ + throw new RuntimeException("案件id不能为空!"); + } + response.reset(); + SysLawCase sysLawCase = lawCaseMapper.selectById(caseId); + String zipName = "案件["+sysLawCase.getName()+"]相关数据.zip"; + ServletOutputStream sos = response.getOutputStream(); +// OutputStream sos = new FileOutputStream("d://" + zipName); + ZipOutputStream zipOutputStream = new ZipOutputStream(sos); + + //案件信息 + putCaseInfo(sysLawCase,zipOutputStream); + + //主数据 + putMainData(zipOutputStream,caseId); + + //其它资产,其它信息,原始数据 + putOssData(zipOutputStream,caseId); + + //分析成果 分析报告 + putAnalysisData(zipOutputStream,caseId); + + response.setContentType("application/x-download"); + response.setHeader("Content-Disposition", "attachment;filename="+ new String((zipName).getBytes(), "iso-8859-1")); + zipOutputStream.flush(); + zipOutputStream.close(); + sos.close(); + } + + @SneakyThrows + private void putCaseInfo(SysLawCase sysLawCase, ZipOutputStream zipOutputStream) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ExcelUtil.exportExcel(Arrays.asList(sysLawCase), SysLawCase.class,outputStream); + ExcelUtil.compressFileToZipStream(zipOutputStream, outputStream, "SysLawCase" + ".xlsx"); + outputStream.close(); + } + + @SneakyThrows + void putAnalysisData(ZipOutputStream zipOutputStream, String caseId){ + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(AnalysisResult::getCaseId,caseId); + List analysisResults = analysisResultMapper.selectList(lqw); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ExcelUtil.exportExcel(analysisResults, AnalysisResult.class,outputStream); + ExcelUtil.compressFileToZipStream(zipOutputStream, outputStream, "AnalysisResult" + ".xlsx"); + outputStream.close(); + + LambdaQueryWrapper reportLqw = Wrappers.lambdaQuery(); + reportLqw.eq(AnalysisReport::getCaseId,caseId); + List reportList = analysisReportMapper.selectList(reportLqw); + ByteArrayOutputStream reportOut = new ByteArrayOutputStream(); + ExcelUtil.exportExcel(reportList, AnalysisReport.class,reportOut); + ExcelUtil.compressFileToZipStream(zipOutputStream, reportOut, "AnalysisReport" + ".xlsx"); + reportOut.close(); + } + + private final static String EXPORT_ALL_DTO_PATH = "com.inscloudtech.datacenter.domain.dto.export"; + + + void putMainData(ZipOutputStream zipOutputStream, String caseId){ + Set> classes = ClassUtil.scanPackage(EXPORT_ALL_DTO_PATH); + Map> dtoMap = new HashMap(); + for (Class clazz : classes) { + String name = clazz.getSimpleName(); + if (!name.contains("ExportAllDto")) { + continue; + } + name = "dc_" + StrUtil.toUnderlineCase(name.replace("ExportAllDto","")); + dtoMap.put(name, clazz); + } + BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); + boolQuery.must(QueryBuilders.termQuery("caseId", caseId)); + for (String indexName : dtoMap.keySet()) { + Class clazz = dtoMap.get(indexName); + JSONObject result = new JSONObject(); + scrollSearch(indexName,boolQuery,result); + List tpList = new ArrayList<>(); + try { + tpList = result.getBeanList(indexName, clazz); + } catch (Exception e) { + e.printStackTrace(); + } + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ExcelUtil.exportExcel(tpList, clazz,outputStream); + ExcelUtil.compressFileToZipStream(zipOutputStream, outputStream, clazz.getSimpleName().replace("ExportAllDto","") + ".xlsx"); + try { + outputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + result.clear(); + } + } + + @SneakyThrows + void putOssData(ZipOutputStream zipOutputStream, String caseId){ + //文件记录 + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(SysOss::getCaseId, caseId); + List ossList = ossMapper.selectList(lqw); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ExcelUtil.exportExcel(ossList, SysOss.class,outputStream); + ExcelUtil.compressFileToZipStream(zipOutputStream, outputStream, "SysOss" + ".xlsx"); + outputStream.close(); + + // 创建文件夹 + String dirName = "upload"; + + //具体文件 + for (SysOss sysOss : ossList) { + String fileName = sysOss.getFileName(); + if (!FileUtils.checkAllowDownload(fileName)) { + log.error(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName)); +// throw new RuntimeException(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName)); + continue; + } + String filePath = ProjectConfig.getUploadPath() + fileName; + File file = new File(filePath); + if (!file.exists()) { + log.error("throw new FileNotFoundException{}", filePath); + continue; + } + ByteArrayOutputStream output = FileUtils.readByteArrayOutputStream(file);; + ExcelUtil.compressFileToZipStream(zipOutputStream, output, dirName +sysOss.getFileName()); + outputStream.close(); + } + } + + public void importCaseAllData(MultipartFile file) { + initImportMapper(); + initImportDto(); + String localUploadPath = ProjectConfig.getProfile()+"/"; // 替换为要保存文件的目标目录 + File tempFile = null ; + FileInputStream fis = null; + ZipInputStream zis = null; + try { + // 创建临时文件 + tempFile = File.createTempFile("caseAllData", ".zip"); +// File tempFile = new File("D:\\案件[1212]相关数据.zip"); + file.transferTo(tempFile); + // 创建zip文件输入流 + fis = new FileInputStream(tempFile); + + zis = new ZipInputStream(fis); + byte[] buffer = new byte[1024]; + // 读取zip文件中的每个条目 + ZipEntry zipEntry = zis.getNextEntry(); + while (zipEntry != null) { + // 打印文件信息 + String filePath = zipEntry.getName(); + if(filePath.contains("upload")){//原始数据上传到本地文件夹 + filePath = localUploadPath + filePath; + this.saveFilesFromZipToLocal(filePath,zipEntry,zis,buffer); + }else {//解析excel数据存入 mysql或es + this.uploadDataToMysqlOrEs(filePath,zipEntry,zis,buffer); + } + // 关闭当前条目 + zis.closeEntry(); + zipEntry = zis.getNextEntry(); + } + } catch (Exception e) { + e.printStackTrace(); + }finally { + try { + // 关闭zip文件输入流 + fis.close(); + zis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + // 删除临时文件 + tempFile.delete(); + } + + } + + + private void uploadDataToMysqlOrEs(String zipEntryName,ZipEntry zipEntry,ZipInputStream zis,byte[] buffer) throws NoSuchMethodException { + String objName = zipEntryName.replace(".xlsx",""); + List> objList = dtoMap.get(objName); + Class targetType = objList.get(0); + List dataList = zipInputStream2List(zipEntry, zis, buffer, targetType); + if(objList.size() > 1){ + dataList = BeanUtil.copyToList(dataList, objList.get(1)); + } + if(objName.equals("BankStatement")){//流水数据太大需要份 batchSize导入 + this.batchInsertBs((List)dataList); + }else{ + List> mapperClassList = importMapperMap.get(objName); + for (Class mapperClass : mapperClassList) { + Object mapperObj = SpringUtils.getBean(mapperClass); + Method insertBatch = mapperClass.getMethod("insertBatch", Collection.class); + try { + insertBatch.invoke(mapperObj, dataList); + }catch (Exception e){ + e.printStackTrace(); + } + } + } + } + + @SneakyThrows + List zipInputStream2List(ZipEntry zipEntry,ZipInputStream zis,byte[] buffer,Class clazz){ + // 读取文件内容到临时字节数组输出流 + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + int bytesRead; + while ((bytesRead = zis.read(buffer)) != -1) { + baos.write(buffer, 0, bytesRead); + } + + // 将文件内容写入临时文件 + String tempFileName = "temp_" + zipEntry.getName(); + File tempEntryFile = new File(tempFileName); + + try (FileOutputStream fos = new FileOutputStream(tempEntryFile)) { + baos.writeTo(fos); + } + ExcelResult excelResult = ExcelUtil.importExcel(new FileInputStream(tempEntryFile), clazz, true); + // 关闭字节数组输出流 + baos.close(); + tempEntryFile.delete(); + return excelResult.getList(); + } + + /** + * 保存导入的文件到本地路径 + */ + @SneakyThrows + void saveFilesFromZipToLocal(String filePath,ZipEntry zipEntry,ZipInputStream zis,byte[] buffer){ + // 确保目标文件的父文件夹存在 + File destFile = new File(filePath); + File parentDir = destFile.getParentFile(); + if (!parentDir.exists()) { + parentDir.mkdirs(); + } + if (!zipEntry.isDirectory()) { + extractFile(zis, filePath, buffer); + } + } + + void initImportMapper(){ + String mapperPath = "com.inscloudtech.datacenter.mapper"; + Set> classes = ClassUtil.scanPackage(mapperPath); + Map> collect = classes.stream().collect(Collectors.toMap(Class::getSimpleName, Function.identity())); + for (String simpleName : collect.keySet()) { + if(!simpleName.endsWith("EsMapper")){ + continue; + } + Class esMapperClass = collect.get(simpleName); + simpleName = simpleName.replace("EsMapper",""); + if(collect.containsKey(simpleName + "Mapper")){ + Class mysqlMapperClass = collect.get(simpleName + "Mapper"); + importMapperMap.put(simpleName, Arrays.asList(esMapperClass,mysqlMapperClass)); + } + } + + importMapperMap.put("OpeningAccountInfo",Arrays.asList(ESOpeningAccountInfoMapper.class)); + + importMapperMap.put("SysLawCase",Arrays.asList(SysLawCaseMapper.class)); + + importMapperMap.put("AnalysisReport",Arrays.asList(AnalysisReportMapper.class)); + + importMapperMap.put("AnalysisResult",Arrays.asList(AnalysisReportMapper.class)); + + importMapperMap.put("SysOss",Arrays.asList(SysOssMapper.class)); + + } + + void initImportDto(){ + Set> dtoClass = ClassUtil.scanPackage(EXPORT_ALL_DTO_PATH); + Set> domain = ClassUtil.scanPackage("com.inscloudtech.datacenter.domain"); + Map> collect = domain.stream().collect(Collectors.toMap(Class::getSimpleName, Function.identity())); + for (Class clazz : dtoClass) { + String name = clazz.getSimpleName(); + if (!name.contains("ExportAllDto")) { + continue; + } + name = name.replace("ExportAllDto",""); + List objList = new ArrayList(); + objList.add(clazz); + if(collect.containsKey(name)){ + objList.add(collect.get(name)); + } + dtoMap.put(name,objList); + } + dtoMap.get("BankStatement").add(BankStatement.class); + dtoMap.get("OpeningAccountInfo").add(OpeningAccountInfo.class); + + dtoMap.put("SysLawCase", Arrays.asList(SysLawCase.class)); + dtoMap.put("AnalysisReport", Arrays.asList(AnalysisReport.class)); + dtoMap.put("AnalysisResult", Arrays.asList(AnalysisResult.class)); + dtoMap.put("SysOss", Arrays.asList(SysOss.class)); + } + + private static void extractFile(ZipInputStream zipInputStream, String filePath, byte[] buffer) throws IOException { + try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath))) { + int length; + while ((length = zipInputStream.read(buffer)) > 0) { + bos.write(buffer, 0, length); + } + } + } + // public static void mysql(){ + // // + // String keyWord ="3434"; + // String caseId = 105L; + // for (Class classItem : MYSQL_DATASET) { + // String tableName = ((TableName) classItem.getAnnotation(TableName.class)).value(); + // Field[] fields = classItem.getDeclaredFields(); + // StringBuilder fieldSb = new StringBuilder(); + // //select count(*) from dc_car_info where match(name,car_no,car_type) against('小'); + // StringBuilder countSql = new StringBuilder("select count(*) from "); + // // alter table dc_car_info add fulltext index ft_index_name_car_no(name,car_no) with parser + // ngram; + // StringBuilder alterFullTextIndexSql = new StringBuilder("alter table ").append(tableName).append(" add + // fulltext index ft_index( "); + // countSql.append(tableName).append(" where caseId = ").append(caseId).append(" match("); + // for (Field field : fields) { + // field.setAccessible(true); + //// if (!field.isAnnotationPresent(FullText.class)) { + //// continue; + //// } + // fieldSb.append(field.getName()).append(","); + // } + // fieldSb.deleteCharAt(fieldSb.length() -1); + // countSql.append(fieldSb); + // countSql.append(" ) against('"); + // countSql.append(keyWord).append("')"); + // System.out.println(countSql); + // alterFullTextIndexSql.append(fieldSb); + // alterFullTextIndexSql.append(" ) with parser ngram"); + // System.out.println(alterFullTextIndexSql); + // + //// + //// + //// + //// select count(*) from dc_car_info where match(name,car_no,car_type) against('小'); + //// SHOW INDEXES FROM dc_car_info + // + // } + // } + + public static void setHighlightValue(Class clazz, Object obj, String searchValue){ + searchValue = searchValue.trim().replaceAll("([ ]|\\s|\\u00A0)+",""); + + Field[] fields = clazz.getDeclaredFields(); + for (Field field : fields) { + field.setAccessible(true); + if (!field.isAnnotationPresent(HighLight.class)) { + continue; + } + String mappingField = field.getAnnotation(HighLight.class).mappingField(); + try { + Method mappingFieldGetMethod = clazz.getMethod("get" + capitalize(mappingField)); + // 调用 get 方法获取字段的值 + String fieldValue = (String) mappingFieldGetMethod.invoke(obj); + if(StrUtil.isEmpty(fieldValue)){ + //全词匹配 高亮为null + mappingField = mappingField.split("Highlight")[0]; + mappingFieldGetMethod = clazz.getMethod("get" + capitalize(mappingField)); + // 调用 get 方法获取字段的值 + fieldValue = (String) mappingFieldGetMethod.invoke(obj); + if(StrUtil.isEmpty(fieldValue) || !fieldValue.contains(searchValue)){ + continue; + } + + } + fieldValue = fieldValue.replace(QueryCenterService.TAG_PREFIX,""); + fieldValue = fieldValue.replace(QueryCenterService.TAG_SUFFIX,""); + String[] split = fieldValue.split(searchValue); + String newValue = ""; + if(split.length == 0){ + newValue = QueryCenterService.TAG_PREFIX + searchValue + QueryCenterService.TAG_SUFFIX; + } else if(split.length == 1){ + newValue = split[0] + QueryCenterService.TAG_PREFIX + searchValue + QueryCenterService.TAG_SUFFIX; + }else if(split.length > 1){ + newValue = split[0] + QueryCenterService.TAG_PREFIX + searchValue + QueryCenterService.TAG_SUFFIX; + newValue += split[1]; + } + Method setMethod = clazz.getMethod("set" + capitalize(field.getName()), field.getType()); + setMethod.invoke(obj, newValue ); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + // 将字段名首字母大写,以符合JavaBean规范中的get和set方法命名 + private static String capitalize(String name) { + if (name == null || name.isEmpty()) { + return name; + } + return name.substring(0, 1).toUpperCase() + name.substring(1); + } + + private final ESBankStatementMapper esBsMapper; + + public boolean batchInsertBs(List list) { + int batchSize = Constants.BATCH_SIZE; + int totalRecords = list.size(); + for (int i = 0; i < totalRecords; i += batchSize) { + List batch = list.subList(i, Math.min(i + batchSize, totalRecords)); + esBsMapper.insertBatch(batch); + } + return true; + } + + private static final List CLASS_LIST = Arrays.asList(BankStatement.class, OpeningAccountInfo.class,TransactionPartner.class, PublicFamily.class, + RealEstate.class, CarInfo.class, OtherAssets.class, OtherInformation.class); + private static final List SERVICE_LIST = Arrays.asList(BankService.class, OpeningAccountInfoService.class,ITransactionPartnerService.class, IPublicFamilyService.class, + IRealEstateService.class, ICarInfoService.class); + + private static final List CLASS_NAME = Arrays.asList("银行流水","开户信息","所在单位交易客户","职工及家属名册","不动产信息","车辆信息"); + + @SneakyThrows + + public void excelExport(HttpServletResponse response,AnalysisResult bo) { + Map classMap = new HashMap<>(); + for (Class classItem : CLASS_LIST) { + if(null == classItem){ + continue; + } + String indexName = ((IndexName) classItem.getAnnotation(IndexName.class)).value(); + classMap.put(indexName,classItem); + } + Map dataMap = new HashMap<>(); + List writeSheets = new ArrayList<>(); + + for(int i = 0; i < CLASS_NAME.size(); i++){ + String className = CLASS_NAME.get(i); + WriteSheet writeSheet = EasyExcel.writerSheet(i, className) + .head(CLASS_LIST.get(i)).registerWriteHandler(new MyLongestMatchColumnWidthStyleStrategy()) + .build(); + writeSheets.add(writeSheet); + dataMap.put(className,Collections.EMPTY_LIST); + } + ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build(); + String fileName = "分析成果"; + + if(bo.getDownloadTemplate() == null){ + QueryCenterQuery query = new QueryCenterQuery(); + query.setCaseId(bo.getCaseId()); + query.setAnalysisResultId(bo.getId()); + JSONObject data4ExcelExport = this.getData4ExcelExport(query); + for (String indexName : data4ExcelExport.keySet()) { + if (classMap.containsKey(indexName)) { + Class aClass = classMap.get(indexName); + List list = data4ExcelExport.getBeanList(indexName, aClass); + dataMap.put(CLASS_NAME.get(CLASS_LIST.indexOf(aClass)),list); + } + } + } + + for (WriteSheet writeSheet : writeSheets) { + if(dataMap.containsKey(writeSheet.getSheetName())){ + excelWriter.write(dataMap.get(writeSheet.getSheetName()),writeSheet); + } + } + response.setContentType("application/vnd.ms-excel;charset=utf-8"); + response.setCharacterEncoding("UTF-8"); + response.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName+".xlsx","UTF-8")); + excelWriter.finish(); + + } + + private final IAnalysisResultService iAnalysisResultService; + + private static final List SERVICE_LIST_MERGE = Arrays.asList(BankService.class, OpeningAccountInfoService.class,ITransactionPartnerService.class, IPublicFamilyService.class, + IRealEstateService.class, ICarInfoService.class,IOtherAssetsService.class,IOtherInformationService.class, IAnalysisResultService.class, + IAnalysisReportService.class); + + public void caseMerge(AnalysisDto bo) { + + List moduleIndexList = bo.getModuleIndexList(); + if(CollectionUtil.isEmpty(moduleIndexList)){ + return; + } + + String sourceCaseId = bo.getSourceCaseId(); + String targetCaseId = bo.getTargetCaseId(); + + for (Integer moduleIndex : moduleIndexList) { + + Class serviceClass = SERVICE_LIST_MERGE.get(moduleIndex); + Object serviceObj = SpringUtils.getBean(serviceClass); + String methodName = "caseMerge"; + List methodList = Arrays.stream(serviceClass.getMethods()).filter(method -> method.getName().equals(methodName)).collect(Collectors.toList()); + Method method = methodList.get(0);// + Object[] args = new Object[]{sourceCaseId,targetCaseId}; + + try { + method.invoke(serviceObj, args); + }catch (Exception e){ + e.printStackTrace(); + } + + + } + + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/BankServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/BankServiceImpl.java new file mode 100644 index 0000000..e6b7a64 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/BankServiceImpl.java @@ -0,0 +1,2331 @@ +package com.inscloudtech.datacenter.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.alibaba.excel.util.ListUtils; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.inscloudtech.bankStatementAnalysis.helper.*; +import com.inscloudtech.bankStatementAnalysis.util.AnalyzeFileHelper; +import com.inscloudtech.bankStatementAnalysis.worker.ImportWorkflowWorker; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.utils.poi.ExcelUtil; +import com.inscloudtech.datacenter.domain.vo.*; + +import com.inscloudtech.datacenter.service.BankService; +import com.inscloudtech.system.mapper.SysOssMapper; +import com.jd.platform.async.executor.Async; +import com.jd.platform.async.wrapper.WorkerWrapper; +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.analysiscenter.domain.AnalysisPerson; +import com.inscloudtech.analysiscenter.mapper.AnalysisPersonMapper; +import com.inscloudtech.common.config.ProjectConfig; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.excel.ExcelResult; +import com.inscloudtech.common.exception.dc.RegularFailureException; +import com.inscloudtech.common.utils.BeanCopyUtils; +import com.inscloudtech.common.utils.DateUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.common.utils.file.FileUtils; +import com.inscloudtech.common.utils.redis.RedisUtils; + +import com.inscloudtech.datacenter.domain.dto.ImportResultPromptVO; +import com.inscloudtech.datacenter.domain.dto.StatisticsOption; +import com.inscloudtech.datacenter.mapper.es.ESBankStatementMapper; +import com.inscloudtech.datacenter.mapper.es.ESOpeningAccountInfoMapper; +import com.inscloudtech.datacenter.service.ImportResultService; +import com.inscloudtech.datacenter.service.QueryCenterService; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; +import com.inscloudtech.system.domain.vo.*; + + +import lombok.Data; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.dromara.easyes.core.biz.SAPageInfo; +import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper; +import org.dromara.easyes.core.core.EsWrappers; +import org.elasticsearch.action.search.ClearScrollRequest; +import org.elasticsearch.action.search.SearchRequest; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.action.search.SearchScrollRequest; +import org.elasticsearch.client.RequestOptions; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.core.TimeValue; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.search.Scroll; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.aggregations.Aggregation; +import org.elasticsearch.search.aggregations.AggregationBuilder; +import org.elasticsearch.search.aggregations.AggregationBuilders; +import org.elasticsearch.search.aggregations.Aggregations; +import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms; +import org.elasticsearch.search.aggregations.bucket.terms.Terms; +import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder; +import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StopWatch; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.math.BigDecimal; +import java.time.Duration; +import java.util.*; +import java.util.concurrent.ExecutionException; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import static com.inscloudtech.common.constant.Constants.BATCH_SIZE; + +@Slf4j +@Service +@RequiredArgsConstructor +@Transactional(propagation = Propagation.NOT_SUPPORTED) // 关闭事务 +public class BankServiceImpl implements BankService { + + private final ImportResultService importResultService; + + private final BOCDataAnalysisHelper bocDataAnalysisHelper; + private final CITICDataAnalysisHelper citicDataAnalysisHelper; + private final CMBDataAnalysisHelper cmbDataAnalysisHelper; + private final ICBCDataAnalysisHelper icbcDataAnalysisHelper; + private final RCCDataAnalysisHelper rccDataAnalysisHelper; + private final SPDBDataAnalysisHelper spdbDataAnalysisHelper; + private final HBDataAnalysisHelper hbDataAnalysisHelper; + private final PABDataAnalysisHelper pabDataAnalysisHelper; + private final CIBDataAnalysisHelper cibDataAnalysisHelper; + private final CCBDataAnalysisHelper ccbDataAnalysisHelper; + private final CMBCDataAnalysisHelper cmbcDataAnalysisHelper; + private final BOCOMDataAnalysisHelper bocomDataAnalysisHelper; + private final QJCCBDataAnalysisHelper qjccbDataAnalysisHelper; + private final PSBCDataAnalysisHelper psbcDataAnalysisHelper; + private final CGBCDataAnalysisHelper cgbcDataAnalysisHelper; + private final FDBDataAnalysisHelper fdbDataAnalysisHelper; + private final ABCDataAnalysisHelper abcDataAnalysisHelper; + private final CGSAnalysisHelper cgsAnalysisHelper; + private final HFAnalysisHelper hfAnalysisHelper; + + + + + private final ESBankStatementMapper esBsMapper; + + private final ESOpeningAccountInfoMapper esOaiMapper; + + private final EsIndexHelper esIndexHelper; + + private final RestHighLevelClient restHighLevelClient; + + private final MThreadUtil.WorkerPool workers; + + private final SysOssMapper ossMapper; + + private final AnalysisPersonMapper analysisPersonMapper; + + + @SneakyThrows + @Override + public List getPersonInfo(GetPersonReq req){ + String caseId = req.getCaseId(); + if (StrUtil.isEmpty(caseId)) { + throw new RuntimeException("案件Id不能为空"); + } + + List rst = new ArrayList<>(); + + BoolQueryBuilder query = QueryBuilders.boolQuery(); + query.must(QueryBuilders.termsQuery("caseId", caseId)); + + SearchSourceBuilder sb = new SearchSourceBuilder(); + sb.query(query); + sb.size(0); + + TermsAggregationBuilder aggBuilder = AggregationBuilders.terms("group_by_name") + .field("cardHolderName.keyword") + .size(10000); + aggBuilder.subAggregation(AggregationBuilders.terms("group_by_idCard").field("idCardNo.keyword")); + sb.aggregation(aggBuilder); + + SearchRequest sr = new SearchRequest("dc_bank_statement"); + sr.source(sb); + + SearchResponse resp = restHighLevelClient.search(sr, RequestOptions.DEFAULT); + ParsedStringTerms agg = resp.getAggregations().get("group_by_name"); + for (Terms.Bucket bucket : agg.getBuckets()) { + JSONObject obj = new JSONObject(); + String key = bucket.getKeyAsString(); + obj.put("label", key); + + ParsedStringTerms aggregation = bucket.getAggregations().get("group_by_idCard"); + Set idCards = new HashSet<>(); + for (Terms.Bucket b : aggregation.getBuckets()) { + String value = b.getKeyAsString(); + if(StrUtil.isNotEmpty(value)){ + idCards.add(value); + } + } + + if(CollectionUtil.isNotEmpty(idCards)){ + for (String idCard : idCards) { + if(key.length() <= 4){// + if(idCard.length() == 18){ + obj.put("value", idCard); + break; + } + } + obj.put("value", idCard); + } + }else { + obj.put("value", ""); + } + rst.add(obj); + } + + return addAnalysisPerson(rst,caseId); + } + + List addAnalysisPerson(List rst,String caseId){ + Set uniqueKeySet = new HashSet(); + + List analysisPersonList = new ArrayList<>(); + for (JSONObject jsonObject : rst) { + String name = jsonObject.getStr("label"); + String idCard = jsonObject.getStr("value"); + String md5Id = HelperUtil.generateMD5(caseId+name+idCard); + + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + AnalysisPerson person = new AnalysisPerson(); + person.setId(md5Id); + person.setCaseId(caseId); + person.setLabel(name); + person.setValue(idCard); + analysisPersonList.add(person); + } + + Map groupById = analysisPersonList.stream().collect(Collectors.toMap(AnalysisPerson::getId, Function.identity())); + Set idSet = groupById.keySet(); + List esExistIdList = new ArrayList<>(); + if(CollectionUtil.isNotEmpty(idSet)){ + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.in(AnalysisPerson::getId, idSet); + wrapper.select(AnalysisPerson::getId); + esExistIdList = analysisPersonMapper.selectList(wrapper); + } + + if(CollectionUtil.isEmpty(esExistIdList)){ + analysisPersonMapper.insertBatch(analysisPersonList); + }else { + Set esIdSet = esExistIdList.stream().map(AnalysisPerson::getId).collect(Collectors.toSet()); + idSet.removeAll(esIdSet); + if(CollectionUtil.isNotEmpty(idSet)){ + List saveLis = new ArrayList<>(); + for (String id : idSet) { + saveLis.add(groupById.get(id)); + } + analysisPersonMapper.insertBatch(saveLis); + } + } + + LambdaQueryWrapper webWrap = Wrappers.lambdaQuery(); + webWrap.eq(AnalysisPerson::getCaseId,caseId); + + return analysisPersonMapper.selectList(webWrap); + } + + /** + * 清空案件相关数据,包括流水数据和开户数据 + * + * @param caseId 案件Id + */ + @Override + public void clear(String caseId) { + + if (StrUtil.isNotBlank(caseId)) { + esBsMapper.delete(EsWrappers.lambdaQuery(BankStatement.class).eq(BankStatement::getCaseId, caseId)); + esOaiMapper.delete( + EsWrappers.lambdaQuery(OpeningAccountInfo.class).eq(OpeningAccountInfo::getCaseId, caseId)); +// ossMapper.delete(Wrappers.lambdaQuery(SysOss.class).eq(SysOss::getCaseId, caseId).eq(SysOss::getBusinessModule,"BANK_STATEMENT")); + + } else { + throw new RuntimeException("案件Id不能为空"); + } + } + + @SneakyThrows + @Override + public List getBSList(GetBSFieldValueCountReq req) { + SearchSourceBuilder searchSourceBuilder = buildSearchSourceBuilder(req); + + SearchRequest searchRequest = new SearchRequest("dc_bank_statement"); + Scroll scroll = new Scroll(TimeValue.timeValueMinutes(3)); // 设置一次读取的最大连接时长 + + searchSourceBuilder.size(QueryCenterService.MAX_PAGE_SIZE); + searchRequest.source(searchSourceBuilder); + searchRequest.scroll(scroll); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); + SearchHits responseHits = searchResponse.getHits(); + String scrollId = searchResponse.getScrollId(); + List dataList = new ArrayList<>(); + long total = responseHits.getTotalHits().value; + if (total > QueryCenterService.MAX_PAGE_SIZE) { + while (true) { + SearchHits hits = searchResponse.getHits(); + for (SearchHit hit : hits) { + JSONObject json = JSONUtil.parseObj(hit.getSourceAsString()); + json.put("id", hit.getId()); + dataList.add(JSONUtil.toBean(json,BankStatement.class)); + } + // 继续滚动获取下一页数据 + SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId); + scrollRequest.scroll(TimeValue.timeValueMinutes(1L)); + searchResponse = restHighLevelClient.scroll(scrollRequest, RequestOptions.DEFAULT); + scrollId = searchResponse.getScrollId(); + + // 判断是否还有数据 + if (searchResponse.getHits().getHits().length == 0) { + break; + } + } + ClearScrollRequest clearScrollRequest = new ClearScrollRequest(); + clearScrollRequest.addScrollId(scrollId); + restHighLevelClient.clearScroll(clearScrollRequest, RequestOptions.DEFAULT); + } else { + SearchHit[] hits = responseHits.getHits(); + for (SearchHit hit : hits) { + JSONObject json = JSONUtil.parseObj(hit.getSourceAsString()); + json.put("id", hit.getId()); + dataList.add(JSONUtil.toBean(json,BankStatement.class)); + } + } + return dataList; + } + + @SneakyThrows + @Override + public List getOAIList(GetOpeningAccountInfoListReq req) { + + SearchSourceBuilder searchSourceBuilder = (SearchSourceBuilder)buildOAISearchSourceBuilder(req).get("searchSourceBuilder"); + + SearchRequest searchRequest = new SearchRequest("dc_opening_account_info"); + Scroll scroll = new Scroll(TimeValue.timeValueMinutes(3)); // 设置一次读取的最大连接时长 + + searchSourceBuilder.size(QueryCenterService.MAX_PAGE_SIZE); + searchRequest.source(searchSourceBuilder); + searchRequest.scroll(scroll); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); + SearchHits responseHits = searchResponse.getHits(); + String scrollId = searchResponse.getScrollId(); + List dataList = new ArrayList<>(); + long total = responseHits.getTotalHits().value; + if (total > QueryCenterService.MAX_PAGE_SIZE) { + while (true) { + SearchHits hits = searchResponse.getHits(); + for (SearchHit hit : hits) { + JSONObject json = JSONUtil.parseObj(hit.getSourceAsString()); + json.put("id", hit.getId()); + dataList.add(JSONUtil.toBean(json,OpeningAccountInfo.class)); + } + // 继续滚动获取下一页数据 + SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId); + scrollRequest.scroll(TimeValue.timeValueMinutes(1L)); + searchResponse = restHighLevelClient.scroll(scrollRequest, RequestOptions.DEFAULT); + scrollId = searchResponse.getScrollId(); + + // 判断是否还有数据 + if (searchResponse.getHits().getHits().length == 0) { + break; + } + } + ClearScrollRequest clearScrollRequest = new ClearScrollRequest(); + clearScrollRequest.addScrollId(scrollId); + restHighLevelClient.clearScroll(clearScrollRequest, RequestOptions.DEFAULT); + } else { + SearchHit[] hits = responseHits.getHits(); + for (SearchHit hit : hits) { + JSONObject json = JSONUtil.parseObj(hit.getSourceAsString()); + json.put("id", hit.getId()); + dataList.add(JSONUtil.toBean(json,OpeningAccountInfo.class)); + } + } + return dataList; + } + + + @Data + public static class QueryInfo { + private List nameFiledList = new ArrayList<>(); + private List idCardFiledList = new ArrayList<>(); + } + + + + @Override + public JSONObject getFieldsValueCount4OAI(GetOpeningAccountInfoListReq req) throws IOException { + List fields = req.getFields(); + + JSONObject resJson = new JSONObject(); + SearchSourceBuilder searchSourceBuilder = (SearchSourceBuilder)buildOAISearchSourceBuilder(req).get("searchSourceBuilder"); + + String indexName = "dc_opening_account_info"; + for (String field : fields) { + AggregationBuilder agg = AggregationBuilders.terms("groupBy_" + field) + .field(field + ".keyword") + .size(10000); // 解决只显示10条统计结果的问题 + searchSourceBuilder.aggregation(agg); + } + + SearchRequest searchRequest = new SearchRequest(indexName); + searchRequest.source(searchSourceBuilder); + + SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); + Aggregations aggregations = search.getAggregations(); + // 获取name字段的聚合结果 + Map map = aggregations.asMap(); + for (String field : fields) { + String groupByField = "groupBy_" + field; + if (map.containsKey(groupByField)) { + Terms terms = (Terms) map.get(groupByField); + List buckets = terms.getBuckets(); + List tempList = new ArrayList<>(); + for (Terms.Bucket bucket : buckets) { + StatisticsOption statisticsOption = new StatisticsOption(); + String value = bucket.getKey().toString(); + statisticsOption.setLabel(StringUtils.isEmpty(value) ? "其他" : value); + statisticsOption.setField(value); + statisticsOption.setValue(value); + statisticsOption.setCount(bucket.getDocCount()); + tempList.add(statisticsOption); + } + // 排序 + tempList.sort(Comparator.comparing(StatisticsOption::getValue)); + + resJson.put(field, tempList); + } + } + + return resJson; + } + + SearchSourceBuilder buildSearchSourceBuilder(GetBSFieldValueCountReq req){ + + Map params = req.getParams(); + if (params != null) { + Object btObj = params.get("beginTransactionTime"); + Object etObj = params.get("endTransactionTime"); + req.setBeginTransactionTime(btObj == null?null:btObj.toString()); + req.setEndTransactionTime(etObj == null?null:etObj.toString()); + + Object btaObj = params.get("beginTransactionAmount"); + Object etaObj = params.get("endTransactionAmount"); + req.setBeginTransactionAmount(btaObj == null?null:new BigDecimal(btaObj.toString())); + req.setEndTransactionAmount(etaObj == null?null:new BigDecimal(etaObj.toString())); + + Object bbObj = params.get("beginBalance"); + Object ebObj = params.get("endBalance"); + req.setBeginBalance(bbObj == null?null:new BigDecimal(bbObj.toString())); + req.setEndBalance(ebObj == null?null:new BigDecimal(ebObj.toString())); + + } + + LambdaEsQueryWrapper wrapper = EsWrappers.lambdaQuery(BankStatement.class); + + + wrapper.in(CollectionUtil.isNotEmpty(req.getCardHolderNameSet()),BankStatement::getCardHolderName, req.getCardHolderNameSet()); + + + // 查询条件 + // 案件Id + if(StrUtil.isNotEmpty(req.getAnalysisResultId())){ + wrapper.eq(BankStatement::getAnalysisResultId, req.getAnalysisResultId()); + }else { + // 案件Id + wrapper.eq(StrUtil.isNotEmpty(req.getCaseId()), BankStatement::getCaseId, req.getCaseId()); + } + // 银行 + wrapper.like(StrUtil.isNotEmpty(req.getBankName()), BankStatement::getBankName, req.getBankName()); + // 持卡人姓名 + if(null != req.getCardHolderName()){ + wrapper.eq(BankStatement::getCardHolderName, req.getCardHolderName()); + } + + // 身份证号 + if(null != req.getIdCardNo()){ + wrapper.eq(BankStatement::getIdCardNo, req.getIdCardNo()); + } +// +// // 手机号 +// wrapper.like(StrUtil.isNotEmpty(req.getPhone()), BankStatement::getPhone, req.getPhone()); + + // 卡号 + if(null != req.getCardNumber()){ + if(req.getCardNumber().equals("")){ + wrapper.eq(BankStatement::getCardNumber,""); + } + if(StrUtil.isNotEmpty(req.getCardNumber())){ + wrapper.like(BankStatement::getCardNumber, req.getCardNumber()); + } + } + // 交易时间 + String beginTransTimeStr = req.getBeginTransactionTime(); + String endTransTimeStr = req.getEndTransactionTime(); + if (StrUtil.isNotEmpty(beginTransTimeStr) && StrUtil.isNotBlank(endTransTimeStr)) { + String pattern = "yyyy-MM-dd HH:mm:ss"; + Date beginTransTime = DateUtil.parse(beginTransTimeStr, pattern); + Date endTransTime = DateUtil.parse(endTransTimeStr, pattern); + + wrapper.between(true, BankStatement::getTransactionTime, beginTransTime.getTime(), endTransTime.getTime()); + } + + // 交易金额 + if (req.getBeginTransactionAmount() != null) { + if (req.getEndTransactionAmount() != null + && req.getBeginTransactionAmount().compareTo(req.getEndTransactionAmount()) <= 0) { + wrapper.between( + BankStatement::getTransactionAmount, + req.getBeginTransactionAmount(), + req.getEndTransactionAmount()); + } else { + // 支持单边搜索,若开始区间填写1000,则搜索1000+,包括小于-1000的数据,结束区间填写1000,搜索小于1000的数据,包括大于-1000的数诫 + BigDecimal begin = req.getBeginTransactionAmount(); + BigDecimal end = req.getBeginTransactionAmount().negate(); + if (begin.compareTo(end) > 0) { + BigDecimal tmp = begin; + begin = end; + end = tmp; + } + + BigDecimal finalBegin = begin; + BigDecimal finalEnd = end; + wrapper.not(w -> w.between(BankStatement::getTransactionAmount, finalBegin, finalEnd)); + } + } else { + // 结束区间填写1000,搜索小于1000的数据,包括大于-1000的数诫 + if (req.getEndTransactionAmount() != null) { + BigDecimal begin = req.getEndTransactionAmount(); + BigDecimal end = req.getEndTransactionAmount().negate(); + if (begin.compareTo(end) > 0) { + BigDecimal tmp = begin; + begin = end; + end = tmp; + } + + wrapper.between(BankStatement::getTransactionAmount, begin, end); + } + } + + // 余额 + if (req.getBeginBalance() != null) { + if (req.getEndBalance() != null && req.getBeginBalance().compareTo(req.getEndBalance()) <= 0) { + wrapper.between(BankStatement::getBalance, req.getBeginBalance(), req.getEndBalance()); + } else { + // 支持单达搜索,若开始区间填写1000,则搜索1000+,包括小于-1000的数据,结束区间填写1000,搜索小于1000的数据,包括大于-1000的数诫 + BigDecimal begin = req.getBeginBalance(); + BigDecimal end = begin.negate(); + if (begin.compareTo(end) > 0) { + BigDecimal tmp = begin; + begin = end; + end = tmp; + } + // 开始区间填写1000,则搜索1000+,包括小于-1000的数据 + BigDecimal finalBegin = begin; + BigDecimal finalEnd = end; + wrapper.not(w -> w.between(BankStatement::getBalance, finalBegin, finalEnd)); + } + } else { + if (req.getEndBalance() != null) { + BigDecimal begin = req.getEndBalance(); + BigDecimal end = begin.negate(); + + if (begin.compareTo(end) > 0) { + BigDecimal tmp = begin; + begin = end; + end = tmp; + } + + wrapper.between(BankStatement::getBalance, begin, end); + } + } + + // 交易机构 + wrapper.like( + StrUtil.isNotEmpty(req.getTransactionInstitutions()), + BankStatement::getTransactionInstitutions, + req.getTransactionInstitutions()); + // 对方户名 + wrapper.like( + StrUtil.isNotEmpty(req.getCounterpartyName()), + BankStatement::getCounterpartyName, + req.getCounterpartyName()); + // 对方账号 + wrapper.like( + StrUtil.isNotEmpty(req.getCounterpartyAccount()), + BankStatement::getCounterpartyAccount, + req.getCounterpartyAccount()); + // 对方行号 + wrapper.like( + StrUtil.isNotEmpty(req.getCounterpartyBankName()), + BankStatement::getCounterpartyBankName, + req.getCounterpartyBankName()); + // 对方身份证号 + wrapper.like( + StrUtil.isNotEmpty(req.getCounterpartIdCardNo()), + BankStatement::getCounterpartIdCardNo, + req.getCounterpartIdCardNo()); + // 摘要 + wrapper.like(StrUtil.isNotEmpty(req.getSummary()), BankStatement::getSummary, escape(req.getSummary())); + // 交易备注 + wrapper.like( + StrUtil.isNotEmpty(req.getTransRemark()), + BankStatement::getTransRemark, + escape(req.getTransRemark())); + // 交易渠道 + wrapper.like( + StrUtil.isNotEmpty(req.getTransChannel()), BankStatement::getTransChannel, req.getTransChannel()); + // 真实交易对手姓名 + wrapper.like( + StrUtil.isNotEmpty(req.getRealCounterpartyName()), + BankStatement::getRealCounterpartyName, + req.getRealCounterpartyName()); + // 真实交易对手账号 + wrapper.like( + StrUtil.isNotEmpty(req.getRealCounterpartyAccount()), + BankStatement::getRealCounterpartyAccount, + req.getRealCounterpartyAccount()); + // 备注 + wrapper.like(StrUtil.isNotEmpty(req.getRemark()), BankStatement::getRemark, req.getRemark()); + + + wrapper.in(CollectionUtil.isNotEmpty(req.getBankNameList()), BankStatement::getBankName, req.getBankNameList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getCardHolderNameList()), BankStatement::getCardHolderName, req.getCardHolderNameList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getIdCardNoList()), BankStatement::getIdCardNo, req.getIdCardNoList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getCardNumberList()), BankStatement::getCardNumber, req.getCardNumberList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getTransactionInstitutionsList()), BankStatement::getTransactionInstitutions, req.getTransactionInstitutionsList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getCounterpartyNameList()), BankStatement::getCounterpartyName, req.getCounterpartyNameList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getCounterpartyAccountList()), BankStatement::getCounterpartyAccount, req.getCounterpartyAccountList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getCounterpartIdCardNoList()), BankStatement::getCounterpartIdCardNo, req.getCounterpartIdCardNoList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getCounterpartyBankNameList()), BankStatement::getCounterpartyBankName, req.getCounterpartyBankNameList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getSummaryList()), BankStatement::getSummary, req.getSummaryList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getTransRemarkList()), BankStatement::getTransRemark, req.getTransRemarkList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getTransChannelList()), BankStatement::getTransChannel, req.getTransChannelList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getRealCounterpartyNameList()), BankStatement::getRealCounterpartyName, req.getRealCounterpartyNameList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getRealCounterpartyAccountList()), BankStatement::getRealCounterpartyAccount, req.getRealCounterpartyAccountList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getRemarkList()), BankStatement::getRemark, req.getRemarkList()); + if(StrUtil.isNotBlank(req.getSearchValue())){ + String searchValue = "*" + req.getSearchValue().trim().replaceAll("([ ]|\\s|\\u00A0)+","") + "*"; + BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); + BoolQueryBuilder keywordQ = QueryBuilders.boolQuery(); + keywordQ.should(QueryBuilders.wildcardQuery("idCardNo.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("bankName.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("cardNumber.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("transactionInstitutions.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("counterpartyName.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("counterpartyAccount.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("counterpartIdCardNo.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("counterpartyBankName.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("summary.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("transRemark.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("transChannel.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("realCounterpartyName.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("realCounterpartyAccount.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("phone.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("remark.keyword", searchValue)); + boolQuery.must(keywordQ); + wrapper.mix(boolQuery); + } + + + + + + wrapper.orderByDesc("id"); + + SearchSourceBuilder searchSourceBuilder = esBsMapper.getSearchSourceBuilder(wrapper); + return searchSourceBuilder; + } + + Map buildOAISearchSourceBuilder(GetOpeningAccountInfoListReq req){ + + GetOpeningAccountInfoListReq.Params params = req.getParams(); + + BigDecimal beginBalance = params.getBeginBalance(); + if (beginBalance != null) { + req.setBeginBalance(beginBalance); + } + + BigDecimal endBalance = params.getEndBalance(); + if (endBalance != null) { + req.setEndBalance(endBalance); + } + + String beginOpeningAccountDate = params.getBeginOpeningAccountDate(); + if (StrUtil.isNotEmpty(beginOpeningAccountDate)) { + req.setBeginOpeningAccountDate(beginOpeningAccountDate); + } + + String endOpeningAccountDate = params.getEndOpeningAccountDate(); + if (StrUtil.isNotEmpty(endOpeningAccountDate)) { + req.setEndOpeningAccountDate(endOpeningAccountDate); + } + + String beginClosingDate = params.getBeginClosingDate(); + if (StrUtil.isNotEmpty(beginClosingDate)) { + req.setBeginClosingDate(beginClosingDate); + } + + String endClosingDate = params.getEndClosingDate(); + if (StrUtil.isNotEmpty(endClosingDate)) { + req.setEndClosingDate(endClosingDate); + } + + String beginFreezeDate = params.getBeginFreezeDate(); + if (StrUtil.isNotEmpty(beginFreezeDate)) { + req.setBeginFreezeDate(beginFreezeDate); + } + + String endFreezeDate = params.getEndFreezeDate(); + if (StrUtil.isNotEmpty(endFreezeDate)) { + req.setEndFreezeDate(endFreezeDate); + } + + LambdaEsQueryWrapper wrapper = EsWrappers.lambdaQuery(OpeningAccountInfo.class); + // 案件Id + if(StrUtil.isNotEmpty(req.getAnalysisResultId())){ + wrapper.eq(OpeningAccountInfo::getAnalysisResultId, req.getAnalysisResultId()); + }else { + // 案件Id + wrapper.eq(StrUtil.isNotEmpty(req.getCaseId()), OpeningAccountInfo::getCaseId, req.getCaseId()); + } + + // Id + wrapper.eq(StrUtil.isNotEmpty(req.getId()), OpeningAccountInfo::getId, req.getId()); + // 银行名称 + wrapper.like(StrUtil.isNotEmpty(req.getBankName()), OpeningAccountInfo::getBankName, req.getBankName()); + // 户名 + wrapper.like(StrUtil.isNotEmpty(req.getName()), OpeningAccountInfo::getName, req.getName()); + // 证件类型 + wrapper.like(StrUtil.isNotEmpty(req.getIdType()), OpeningAccountInfo::getIdType, req.getIdType()); + // 身份证号 + wrapper.like(StrUtil.isNotEmpty(req.getIdNo()), OpeningAccountInfo::getIdNo, req.getIdNo()); + // 账号 + wrapper.like( + OpeningAccountInfo::getAccountNumber, + req.getAccountNumber()); + // 新账号 + wrapper.like( + StrUtil.isNotEmpty(req.getNewAccountNumber()), + OpeningAccountInfo::getNewAccountNumber, + req.getNewAccountNumber()); + // 电话号码 + wrapper.like(StrUtil.isNotEmpty(req.getPhone()), OpeningAccountInfo::getPhone, req.getPhone()); + // 账户状态 + wrapper.eq(StrUtil.isNotEmpty(req.getStatus()), OpeningAccountInfo::getStatus, req.getStatus()); + // 冻结信息 + wrapper.like(StrUtil.isNotEmpty(req.getFreezeInfo()), OpeningAccountInfo::getFreezeInfo, req.getFreezeInfo()); + // 冻结日期 + wrapper.between( + StrUtil.isNotEmpty(req.getBeginFreezeDate()) && StrUtil.isNotEmpty(req.getEndFreezeDate()), + OpeningAccountInfo::getFreezeDate, + req.getBeginFreezeDate(), + req.getEndFreezeDate()); + // 网银签约信息 + wrapper.like( + StrUtil.isNotEmpty(req.getOnlineBankingSigningInfo()), + OpeningAccountInfo::getOnlineBankingSigningInfo, + req.getOnlineBankingSigningInfo()); + // 开户日期 + wrapper.between( + StrUtil.isNotEmpty(req.getBeginOpeningAccountDate()) + && StrUtil.isNotEmpty(req.getEndOpeningAccountDate()), + OpeningAccountInfo::getOpeningAccountDate, + req.getBeginOpeningAccountDate(), + req.getEndOpeningAccountDate()); + // 销户日期 + wrapper.between( + StrUtil.isNotEmpty(req.getBeginClosingDate()) && StrUtil.isNotEmpty(req.getEndClosingDate()), + OpeningAccountInfo::getClosingDate, + req.getBeginClosingDate(), + req.getEndClosingDate()); + // 地址 + wrapper.like(StrUtil.isNotEmpty(req.getAddress()), OpeningAccountInfo::getAddress, req.getAddress()); + // 备注 + wrapper.like(StrUtil.isNotEmpty(req.getRemark()), OpeningAccountInfo::getRemark, req.getRemark()); + // 开户机构 + wrapper.like( + StrUtil.isNotEmpty(req.getAccountOpeningInstitution()), + OpeningAccountInfo::getAccountOpeningInstitution, + req.getAccountOpeningInstitution()); + + // 余额 + if (req.getBeginBalance() != null) { + if (req.getEndBalance() != null && req.getBeginBalance().compareTo(req.getEndBalance()) <= 0) { + wrapper.between(OpeningAccountInfo::getBalance, req.getBeginBalance(), req.getEndBalance()); + } else { + // 支持单达搜索,若开始区间填写1000,则搜索1000+,包括小于-1000的数据,结束区间填写1000,搜索小于1000的数据,包括大于-1000的数诫 + BigDecimal begin = req.getBeginBalance(); + BigDecimal end = begin.negate(); + if (begin.compareTo(end) > 0) { + BigDecimal tmp = begin; + begin = end; + end = tmp; + } + + wrapper.lt(true, OpeningAccountInfo::getBalance, begin); + wrapper.gt(true, OpeningAccountInfo::getBalance, end); + } + } else { + if (req.getEndBalance() != null) { + BigDecimal begin = req.getEndBalance(); + BigDecimal end = begin.negate(); + + if (begin.compareTo(end) > 0) { + BigDecimal tmp = begin; + begin = end; + end = tmp; + } + + wrapper.between(OpeningAccountInfo::getBalance, begin, end); + } + } + // 分析Id + wrapper.eq( + StrUtil.isNotEmpty(req.getAnalysisResultId()), + OpeningAccountInfo::getAnalysisResultId, + req.getAnalysisResultId()); + + // 排序 + String orderByColumn = req.getOrderByColumn(); + if (StrUtil.isNotEmpty(orderByColumn)) { + wrapper.orderBy(true, "asc".equalsIgnoreCase(req.getIsAsc()), req.getOrderByColumn()); + } else { + wrapper.orderByDesc("id"); + } + + wrapper.size(req.getPageSize()); + SearchSourceBuilder searchSourceBuilder = esOaiMapper.getSearchSourceBuilder(wrapper); + Map result = new HashMap<>(); + result.put("wrapper",wrapper); + result.put("searchSourceBuilder",searchSourceBuilder); + return result; + } + + @Override + public JSONObject getFieldsValueCount(GetBSFieldValueCountReq req) throws IOException { + JSONObject resJson = new JSONObject(); + SearchSourceBuilder searchSourceBuilder = buildSearchSourceBuilder(req); + String indexName = "dc_bank_statement"; + List fields = req.getFields(); + for (String field : fields) { + AggregationBuilder agg = AggregationBuilders.terms("groupBy_" + field) + .field(field + ".keyword") + .size(1000); + searchSourceBuilder.aggregation(agg); + } + + SearchRequest searchRequest = new SearchRequest(indexName); + searchRequest.source(searchSourceBuilder); + + SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); + Aggregations aggregations = search.getAggregations(); + // 获取name字段的聚合结果 + Map map = aggregations.asMap(); + for (String field : fields) { + String groupByField = "groupBy_" + field; + if (map.containsKey(groupByField)) { + Terms terms = (Terms) map.get(groupByField); + List buckets = terms.getBuckets(); + List tempList = new ArrayList<>(); + for (Terms.Bucket bucket : buckets) { + StatisticsOption statisticsOption = new StatisticsOption(); + String value = bucket.getKey().toString(); + statisticsOption.setLabel(StringUtils.isEmpty(value) ? "(空值)" : value); + statisticsOption.setField(value); + statisticsOption.setValue(value); + statisticsOption.setCount(bucket.getDocCount()); + tempList.add(statisticsOption); + } + + tempList.sort(Comparator.comparing(StatisticsOption::getValue)); + + resJson.put(field, tempList); + } + } + + return resJson; + } + + @Override + public void updateBatchBSEsVersion(BankStatement bs) { + + // 批量标记、重置 + // 单个更新 + List revokeList = bs.getRevokeList(); + + if (revokeList.isEmpty()) { + // 更新 + // 包括两个,一个是更新流水信息,一个是重置标记 + // 这两个通过什么区分 + List ids = bs.getIds(); + if (ids.isEmpty()) { // 更新流水信息 + BankStatement dbBs = esBsMapper.selectById(bs.getId()); + dbBs = BeanCopyUtils.copy(bs, dbBs, BankStatement.class); + + esBsMapper.insertBatch(Collections.singletonList(dbBs)); + } else { + // 标记重置 + List bsList = new ArrayList<>(); + + for (String id : ids) { + BankStatement dbBS = esBsMapper.selectById(id); + if (StrUtil.isNotEmpty(bs.getBgc())) { + dbBS.setBgColor(bs.getBgc()); + } + + if (StrUtil.isNotEmpty(bs.getAnalysisResultId())) { + dbBS.setAnalysisResultId(bs.getAnalysisResultId()); + } + + if (StrUtil.isNotEmpty(bs.getRemark())) { + dbBS.setRemark(bs.getRemark()); + } + + bsList.add(dbBS); + } + + esBsMapper.insertBatch(bsList); + } + } else { + // 标记 + // 先查询,然后修改,后更新 + List bsList = new ArrayList<>(); + for (RevokeItem ri : revokeList) { + BankStatement dbBs = esBsMapper.selectById(ri.getId()); + dbBs.setBgColor(ri.getBgColor()); + + if (StrUtil.isNotEmpty(bs.getAnalysisResultId())) { + dbBs.setAnalysisResultId(bs.getAnalysisResultId()); + } + + if (StrUtil.isNotEmpty(bs.getRemark())) { + dbBs.setRemark(bs.getRemark()); + } + + bsList.add(dbBs); + } + + esBsMapper.insertBatch(bsList); + } + } + + @Override + public void updateBatchOAIEsVersion(OpeningAccountInfo oai) { + // 批量标记、重置 + // 单个更新 + List revokeList = oai.getRevokeList(); + + if (revokeList.isEmpty()) { + // 更新 + // 包括两个,一个是更新流水信息,一个是重置标记 + // 这两个通过什么区分 + List ids = oai.getIds(); + if (ids.isEmpty()) { // 更新流水信息 + OpeningAccountInfo dbOai = esOaiMapper.selectById(oai.getId()); + if (dbOai == null) { + throw new RuntimeException("【" + oai.getId() + "】开户信息不存在."); + } + + dbOai = BeanCopyUtils.copy(oai, dbOai, OpeningAccountInfo.class); + + esOaiMapper.insertBatch(Collections.singletonList(dbOai)); + } else { + // 标记重置 + String bgc = oai.getBgc(); + + List oaiList = new ArrayList<>(); + + for (String id : ids) { + OpeningAccountInfo dbOai = esOaiMapper.selectById(id); + dbOai.setBgColor(bgc); + + if (StrUtil.isNotEmpty(oai.getAnalysisResultId())) { + dbOai.setAnalysisResultId(oai.getAnalysisResultId()); + } + + if (StrUtil.isNotEmpty(oai.getRemark())) { + dbOai.setRemark(oai.getRemark()); + } + + oaiList.add(dbOai); + } + + esOaiMapper.insertBatch(oaiList); + } + } else { + // 标记 + // 先查询,然后修改,后更新 + List oaiList = new ArrayList<>(); + for (RevokeItem ri : revokeList) { + OpeningAccountInfo dbOai = esOaiMapper.selectById(ri.getId()); + dbOai.setBgColor(ri.getBgColor()); + + if (StrUtil.isNotEmpty(oai.getAnalysisResultId())) { + dbOai.setAnalysisResultId(oai.getAnalysisResultId()); + } + + if (StrUtil.isNotEmpty(oai.getRemark())) { + dbOai.setRemark(oai.getRemark()); + } + + oaiList.add(dbOai); + } + + esOaiMapper.insertBatch(oaiList); + } + } + + @Override + public int deleteOAIByIdsEsVersion(String[] oaiIds) { + + if (oaiIds == null) { + throw new RuntimeException("ids 不能为null."); + } + + List coll = Arrays.asList(oaiIds); + + return esOaiMapper.deleteBatchIds(coll); + } + + @Override + public void exportOAI(GetOpeningAccountInfoListReq req, HttpServletResponse resp) { + resp.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + resp.setCharacterEncoding("utf-8"); + List list = Collections.EMPTY_LIST; + if(req.getDownloadTemplate() == null){ + if (!req.getIds().isEmpty() && StrUtil.isEmpty(req.getAnalysisResultId())) { + list = esOaiMapper.selectBatchIds(req.getIds()); + }else{ + list = this.getOAIList(req); + } + } + ExcelUtil.exportExcel(list, "开户信息", OpeningAccountInfo.class, resp); + } + + @Override + public int deleteBSByIdsEsVersion(String[] bsIds) { + + if (bsIds == null) { + throw new RuntimeException("ids不能为null."); + } + return esBsMapper.deleteBatchIds(Arrays.asList(bsIds)); + } + + @Override + public TableDataInfo oaiPage(GetOpeningAccountInfoListReq req) throws Exception { + LambdaEsQueryWrapper wrapper = (LambdaEsQueryWrapper)buildOAISearchSourceBuilder(req).get("wrapper"); + String indexName = HelperUtil.getIndexName(esOaiMapper.getEntityClass()); + if (esOaiMapper.existsIndex(indexName)) { + esOaiMapper.refresh(indexName); + } + + SAPageInfo pageInfo; + if (req.getPageNum() == 1) { + pageInfo = esOaiMapper.searchAfterPage(wrapper, null, req.getPageSize()); + } else { + pageInfo = esOaiMapper.searchAfterPage(wrapper, null, (req.getPageNum() - 1) * req.getPageSize()); + pageInfo = esOaiMapper.searchAfterPage(wrapper, pageInfo.getNextSearchAfter(), req.getPageSize()); + } + + TableDataInfo rst = new TableDataInfo<>(); + + List oaiList = pageInfo.getList(); + + if (StringUtils.isEmpty(req.getOrderByColumn())) { + oaiList.sort((o1, o2) -> { + String openingAccountDate1 = o1.getOpeningAccountDate(); + String openingAccountDate2 = o2.getOpeningAccountDate(); + + if (StrUtil.isNotEmpty(openingAccountDate1) && StrUtil.isNotEmpty(openingAccountDate2)) { + // 如果包含-,则用yyyy-MM-dd解析 + String format; + if (openingAccountDate1.contains("-")) { + format = "yyyy-MM-dd"; + } else if (openingAccountDate1.contains("/")) { + format = "yyyy/MM/dd"; + } else { + format = "yyyyMMdd"; + } + + Date d1; + try { + d1 = DateUtil.parse(openingAccountDate1, format); + } catch (Exception e) { + // 打印日志 + log.error("解析日期出错:" + openingAccountDate1); + d1 = null; + } + + // 如果包含 + if (openingAccountDate2.contains("-")) { + format = "yyyy-MM-dd"; + } else if (openingAccountDate2.contains("/")) { + format = "yyyy/MM/dd"; + } else { + format = "yyyyMMdd"; + } + + DateTime d2; + try { + d2 = DateUtil.parse(openingAccountDate2, format); + } catch (Exception e) { + // 打印日志 + log.error("解析日期出错:" + openingAccountDate2); + d2 = null; + } + + if (d1 != null && d2 != null) { + return d2.compareTo(d1); + } else if (d1 != null) { + return -1; + } else if (d2 != null) { + return 1; + } else { + return 0; + } + } else if (StrUtil.isNotEmpty(openingAccountDate1)) { + return -1; + } else if (StrUtil.isNotEmpty(openingAccountDate2)) { + return 1; + } + + return 0; + }); + } + + rst.setRows(oaiList); + rst.setTotal(HelperUtil.getCount(esOaiMapper, wrapper)); + + return rst; + } + + @Override + public void exportBankStatement(GetBSFieldValueCountReq req, HttpServletResponse resp) throws IOException { + resp.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + resp.setCharacterEncoding("utf-8"); + List bsList = Collections.EMPTY_LIST; + if(req.getDownloadTemplate() == null){ + bsList = getNeedExportBSDataEsVersion(req); + } + ExcelUtil.exportExcel(bsList, "银行流水", BankStatement.class, resp); + } + + @Override + public TableDataInfo page(GetBankStatementListReq req) throws Exception { + + GetBankStatementListReq.Params params = req.getParams(); + BigDecimal beginTransactionAmount = params.getBeginTransactionAmount(); + if (beginTransactionAmount != null) { + req.setBeginTransactionAmount(beginTransactionAmount); + } + + BigDecimal endTransactionAmount = params.getEndTransactionAmount(); + if (endTransactionAmount != null) { + req.setEndTransactionAmount(endTransactionAmount); + } + + String beginTransactionTimeStr = params.getBeginTransactionTime(); + if (StrUtil.isNotEmpty(beginTransactionTimeStr)) { + req.setBeginTransactionTime(beginTransactionTimeStr); + } + + String endTransactionTime = params.getEndTransactionTime(); + if (StrUtil.isNotEmpty(endTransactionTime)) { + req.setEndTransactionTime(endTransactionTime); + } + + BigDecimal beginBalance = params.getBeginBalance(); + if (beginBalance != null) { + req.setBeginBalance(beginBalance); + } + + BigDecimal endBalance = params.getEndBalance(); + if (endBalance != null) { + req.setEndBalance(endBalance); + } + + LambdaEsQueryWrapper wrapper = EsWrappers.lambdaQuery(BankStatement.class); + wrapper.size(req.getPageSize()); + + String caseId = req.getCaseId(); + + if(StrUtil.isNotEmpty(req.getAnalysisResultId())){ + wrapper.eq(BankStatement::getAnalysisResultId, req.getAnalysisResultId()); + }else { + // 案件Id + wrapper.eq(StrUtil.isNotEmpty(caseId), BankStatement::getCaseId, caseId); + } + + // 银行名称 + wrapper.eq(StrUtil.isNotEmpty(req.getBankName()), BankStatement::getBankName, req.getBankName()); + + wrapper.in(CollectionUtil.isNotEmpty(req.getBankNameList()), BankStatement::getBankName, req.getBankNameList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getCardHolderNameList()), BankStatement::getCardHolderName, req.getCardHolderNameList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getIdCardNoList()), BankStatement::getIdCardNo, req.getIdCardNoList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getCardNumberList()), BankStatement::getCardNumber, req.getCardNumberList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getTransactionInstitutionsList()), BankStatement::getTransactionInstitutions, req.getTransactionInstitutionsList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getCounterpartyNameList()), BankStatement::getCounterpartyName, req.getCounterpartyNameList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getCounterpartyAccountList()), BankStatement::getCounterpartyAccount, req.getCounterpartyAccountList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getCounterpartIdCardNoList()), BankStatement::getCounterpartIdCardNo, req.getCounterpartIdCardNoList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getCounterpartyBankNameList()), BankStatement::getCounterpartyBankName, req.getCounterpartyBankNameList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getSummaryList()), BankStatement::getSummary, req.getSummaryList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getTransRemarkList()), BankStatement::getTransRemark, req.getTransRemarkList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getTransChannelList()), BankStatement::getTransChannel, req.getTransChannelList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getRealCounterpartyNameList()), BankStatement::getRealCounterpartyName, req.getRealCounterpartyNameList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getRealCounterpartyAccountList()), BankStatement::getRealCounterpartyAccount, req.getRealCounterpartyAccountList()); + wrapper.in(CollectionUtil.isNotEmpty(req.getRemarkList()), BankStatement::getRemark, req.getRemarkList()); + + + + // 持卡人姓名 + if(null != req.getCardHolderName()){ + wrapper.eq(BankStatement::getCardHolderName, req.getCardHolderName()); + } + + // 身份证号 + if(null != req.getIdCardNo()){ + wrapper.eq(BankStatement::getIdCardNo, req.getIdCardNo()); + } + + // 手机号 + wrapper.like(StrUtil.isNotEmpty(req.getPhone()), BankStatement::getPhone, req.getPhone()); + + // 卡号 + if(null != req.getCardNumber()){ + if(req.getCardNumber().equals("")){ + wrapper.eq(BankStatement::getCardNumber,""); + } + if(StrUtil.isNotEmpty(req.getCardNumber())){ + wrapper.like(BankStatement::getCardNumber, req.getCardNumber()); + } + } + + // 对方名称 + wrapper.like( + StrUtil.isNotEmpty(req.getCounterpartyName()), + BankStatement::getCounterpartyName, + req.getCounterpartyName()); + // 对方身份证号 + wrapper.like( + StrUtil.isNotEmpty(req.getCounterpartIdCardNo()), + BankStatement::getCounterpartIdCardNo, + req.getCounterpartIdCardNo()); + + // 交易机构 + wrapper.like( + !StrUtil.isEmpty(req.getTransactionInstitutions()), + BankStatement::getTransactionInstitutions, + req.getTransactionInstitutions()); + // 交易对手账号 + wrapper.like( + !StrUtil.isEmpty(req.getCounterpartyAccount()), + BankStatement::getCounterpartyAccount, + req.getCounterpartyAccount()); + + // 交易金额 + if (req.getBeginTransactionAmount() != null) { + if (req.getEndTransactionAmount() != null + && req.getBeginTransactionAmount().compareTo(req.getEndTransactionAmount()) <= 0) { + wrapper.between( + BankStatement::getTransactionAmount, + req.getBeginTransactionAmount(), + req.getEndTransactionAmount()); + } else { + // 支持单边搜索,若开始区间填写1000,则搜索1000+,包括小于-1000的数据,结束区间填写1000,搜索小于1000的数据,包括大于-1000的数诫 + BigDecimal begin = req.getBeginTransactionAmount(); + BigDecimal end = req.getBeginTransactionAmount().negate(); + if (begin.compareTo(end) > 0) { + BigDecimal tmp = begin; + begin = end; + end = tmp; + } + + BigDecimal finalBegin = begin; + BigDecimal finalEnd = end; + wrapper.not(w -> w.between(BankStatement::getTransactionAmount, finalBegin, finalEnd)); + } + } else { + // 结束区间填写1000,搜索小于1000的数据,包括大于-1000的数诫 + if (req.getEndTransactionAmount() != null) { + BigDecimal begin = req.getEndTransactionAmount(); + BigDecimal end = req.getEndTransactionAmount().negate(); + if (begin.compareTo(end) > 0) { + BigDecimal tmp = begin; + begin = end; + end = tmp; + } + + wrapper.between(BankStatement::getTransactionAmount, begin, end); + } + } + + // 余额 + if (req.getBeginBalance() != null) { + if (req.getEndBalance() != null && req.getBeginBalance().compareTo(req.getEndBalance()) <= 0) { + wrapper.between(BankStatement::getBalance, req.getBeginBalance(), req.getEndBalance()); + } else { + // 支持单达搜索,若开始区间填写1000,则搜索1000+,包括小于-1000的数据,结束区间填写1000,搜索小于1000的数据,包括大于-1000的数诫 + BigDecimal begin = req.getBeginBalance(); + BigDecimal end = begin.negate(); + if (begin.compareTo(end) > 0) { + BigDecimal tmp = begin; + begin = end; + end = tmp; + } + // 开始区间填写1000,则搜索1000+,包括小于-1000的数据 + BigDecimal finalBegin = begin; + BigDecimal finalEnd = end; + wrapper.not(w -> w.between(BankStatement::getBalance, finalBegin, finalEnd)); + } + } else { + if (req.getEndBalance() != null) { + BigDecimal begin = req.getEndBalance(); + BigDecimal end = begin.negate(); + + if (begin.compareTo(end) > 0) { + BigDecimal tmp = begin; + begin = end; + end = tmp; + } + + wrapper.between(BankStatement::getBalance, begin, end); + } + } + + // 交易时间 + if (StrUtil.isNotEmpty(req.getBeginTransactionTime())) { + if (StrUtil.isNotEmpty(req.getEndTransactionTime())) { + // 2015-12-01 00:00:00 + String pattern = "yyyy-MM-dd hh:mm:ss"; + Date beginDate = DateUtils.parseDate(req.getBeginTransactionTime(), pattern); + Date endDate = DateUtils.parseDate(req.getEndTransactionTime(), pattern); + wrapper.between(BankStatement::getTransactionTime, beginDate.getTime(), endDate.getTime()); + } + } + + + // 对方行名 + wrapper.like( + StrUtil.isNotEmpty(req.getCounterpartyBankName()), + BankStatement::getCounterpartyBankName, + req.getCounterpartyBankName()); + // 摘要 + wrapper.like(StrUtil.isNotEmpty(req.getSummary()), BankStatement::getSummary, escape(req.getSummary())); + // 交易渠道 + wrapper.like( + StrUtil.isNotEmpty(req.getTransChannel()), + BankStatement::getTransChannel, + escape(req.getTransChannel())); + // 真实交易对手姓名 + wrapper.like( + StrUtil.isNotEmpty(req.getRealCounterpartyName()), + BankStatement::getRealCounterpartyName, + req.getRealCounterpartyName()); + // 真实交易对手账号 + wrapper.like( + StrUtil.isNotEmpty(req.getRealCounterpartyAccount()), + BankStatement::getRealCounterpartyAccount, + req.getRealCounterpartyAccount()); + // 备注 + wrapper.like(StrUtil.isNotEmpty(req.getRemark()), BankStatement::getRemark, req.getRemark()); + // 交易备注 + wrapper.like( + StrUtil.isNotEmpty(req.getTransRemark()), + BankStatement::getTransRemark, + escape(req.getTransRemark())); + + if(StrUtil.isNotBlank(req.getSearchValue())){ + String searchValue = "*" + req.getSearchValue().trim().replaceAll("([ ]|\\s|\\u00A0)+","") + "*"; + BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); + BoolQueryBuilder keywordQ = QueryBuilders.boolQuery(); + keywordQ.should(QueryBuilders.wildcardQuery("idCardNo.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("bankName.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("cardNumber.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("transactionInstitutions.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("counterpartyName.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("counterpartyAccount.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("counterpartIdCardNo.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("counterpartyBankName.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("summary.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("transRemark.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("transChannel.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("realCounterpartyName.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("realCounterpartyAccount.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("phone.keyword", searchValue)); + keywordQ.should(QueryBuilders.wildcardQuery("remark.keyword", searchValue)); + boolQuery.must(keywordQ); + wrapper.mix(boolQuery); + } + // 排序 + String orderByColumn = req.getOrderByColumn(); + if (StrUtil.isNotEmpty(orderByColumn) && StrUtil.isNotEmpty(req.getIsAsc())) { + if(req.getOrderByColumn().contains("amount") || req.getOrderByColumn().contains("balance") + || req.getOrderByColumn().contains("time") || req.getOrderByColumn().contains("Time") || req.getOrderByColumn().contains("Amount")){ + wrapper.orderBy(true, "asc".equalsIgnoreCase(req.getIsAsc()), req.getOrderByColumn()); + }else { + wrapper.orderBy(true, "asc".equalsIgnoreCase(req.getIsAsc()), req.getOrderByColumn()+".keyword"); + } + + } else { + wrapper.orderByDesc("id"); + } + + + + + int pageNum = req.getPageNum(); + int pageSize = req.getPageSize(); + + SAPageInfo pageInfo; + if (pageNum == 1) { + pageInfo = esBsMapper.searchAfterPage(wrapper, null, pageSize); + } else { + pageInfo = esBsMapper.searchAfterPage(wrapper, null, (pageNum - 1) * pageSize); + pageInfo = esBsMapper.searchAfterPage(wrapper, pageInfo.getNextSearchAfter(), pageSize); + } + + TableDataInfo rst = new TableDataInfo<>(); + List bsList = pageInfo.getList(); + + if (StringUtils.isEmpty(req.getOrderByColumn())) { + // 如果没有排序要求,那么就按照时间倒序排序 + bsList.sort((o1, o2) -> { + Date tt1 = o1.getTransactionTime(); + Date tt2 = o2.getTransactionTime(); + // 如果其中一个或者同时为null + if (tt1 == null && tt2 == null) { + return 0; + } else if (tt1 == null) { + return 1; + } else if (tt2 == null) { + return -1; + } + + return tt2.compareTo(tt1); + }); + } + + rst.setRows(bsList); + rst.setTotal(pageInfo.getTotal()); + return rst; + } + + private String escape(String s) { + if (s == null) { + return null; + } + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + // These characters are part of the query syntax and must be escaped + if (c == '\\' || c == '+' || c == '-' || c == '!' || c == '(' || c == ')' || c == ':' || c == '^' + || c == '[' || c == ']' || c == '\"' || c == '{' || c == '}' || c == '~' || c == '*' || c == '?' + || c == '|' || c == '&' || c == '/') { + sb.append('\\'); + } + sb.append(c); + } + return sb.toString(); + } + + + private List getNeedExportBSDataEsVersion(GetBSFieldValueCountReq req) { + if (!req.getIds().isEmpty() && StrUtil.isEmpty(req.getAnalysisResultId())) { + return esBsMapper.selectBatchIds(req.getIds()); + }else{ + return this.getBSList(req); + } + } + + private void refreshBSIndex() { + try { + String indexName = HelperUtil.getIndexName(esBsMapper.getEntityClass()); + if (esBsMapper.existsIndex(indexName)) { + esBsMapper.refresh(indexName); + } + } catch (Exception e) { + // + } + } + + private void refreshOAIIndex() { + try { + String indexName = HelperUtil.getIndexName(esOaiMapper.getEntityClass()); + if (esOaiMapper.existsIndex(indexName)) { + esOaiMapper.refresh(indexName); + } + } catch (Exception e) { + // + } + } + + @SneakyThrows + void importBsByExcel(MultipartFile file, String caseId){ + ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), BankStatement.class, true); + List list = excelResult.getList(); + if(CollectionUtil.isNotEmpty(list)){ + this.importData(list,caseId,file.getOriginalFilename()); + } + } + + @Override + public int importBankStatements(MultipartFile mf, String caseId) { + + String originalFilename = mf.getOriginalFilename(); + if (originalFilename == null || !(originalFilename.endsWith("zip") || originalFilename.endsWith("rar"))) { + throw new RuntimeException("暂不支持该文件格式【"+originalFilename+"】"); + } + // 设置文件名,同时清空原文件 + String mainName = FileUtil.mainName(originalFilename); + + AnalyzeFileHelper.setOriginalFileName(mainName); + AnalyzeFileHelper.clear(); + + + File zipDir; + try { + zipDir = FileUtils.unzip(mf.getInputStream()); +// zipDir = FileUtils.unrar(mf.getInputStream()); + } catch (Exception e) { + log.error("解压文件失败", e); + throw new RegularFailureException("解压文件失败: " + e.getMessage()); + } + + + try { + StopWatch sw = new StopWatch("导入银行流水计时监控"); + sw.start(); + File[] files = zipDir.listFiles(); + if (files == null) { + throw new RegularFailureException("zip文件为空,没有数据"); + } + + if (files.length != 1) { + throw new RegularFailureException("银行流水导入模板有误,请重新下载后载入数据."); + } + + File file = files[0]; + if (!file.isDirectory()) { + throw new RegularFailureException(FileUtil.getName(file) + "是文件夹."); + } + + // 异步去拆分文件 + File fDir = zipDir; +// masterPool.executeAsync(() -> HelperUtil.splitBsAndOaiFiles(fDir)); + + // 导入数据 + ImportResultPromptVO execVo = analysisBankData(file, caseId); + + // 等待任务完成 + sw.stop(); + + int total = execVo.getTotal(); + + rollbackProcess(execVo.getErrorItem(),caseId); + + //设置导入完成标识 + String ckey = Constants.COMPLETE_BANK_COUNT + caseId; + long atomicValue = RedisUtils.getAtomicValue(ckey); + if(total == atomicValue){ + RedisUtils.deleteObject(ckey); + RedisUtils.setCacheObject("importFile-"+caseId,1, Duration.ofMinutes(35)); + RedisUtils.deleteObject(Constants.IMPORT_BANK_COUNT + caseId); + } + + return total; + } finally { + // 分析完成,删除zip文件 + try { + // 启动定时器,过两分钟再删除文件 + Timer timer = new Timer("删除临时文件"); + File finalZipDir = zipDir; + timer.schedule( + new TimerTask() { + @Override + public void run() { + FileUtil.del(finalZipDir); + } + }, + 1000 * 30); + } catch (Exception e) { + log.error("删除zip文件失败", e); + } + } + } + + /** + * 回滚 + */ + private void rollbackProcess(List itemList,String caseId) { + + if (itemList.isEmpty()) { + return; + } + + for (ImportResultPromptVO.ImportResultPromptItem item : itemList) { + + if (StringUtils.isEmpty(item.getCause()) && item.getFileList().isEmpty()) { + continue; + } + + String bankName = item.getBankName(); + +// RedisCache redisCache = EsDataCacheHelper.getRedisCache(); + + // 清理流水缓存 + // 错一条数据,全部数据清除 + String bsCacheKey = HelperUtil.getBSCacheKey(bankName) +"-"+caseId; + if (RedisUtils.hasKey(bsCacheKey)) { + Set bsIdList = RedisUtils.getCacheSet(bsCacheKey); + List idList = bsIdList.stream().map(String::valueOf).collect(Collectors.toList()); + esBsMapper.deleteBatchIds(idList); + } + + // 清理开户信息 + String oaiCacheKey = HelperUtil.getOAICacheKey(bankName) + "-"+caseId;; + if (RedisUtils.hasKey(oaiCacheKey)) { + List cacheList = RedisUtils.getCacheList(oaiCacheKey); + List idList = cacheList.stream().map(String::valueOf).collect(Collectors.toList()); + esOaiMapper.deleteBatchIds(idList); + } + + } + } + + private ImportResultPromptVO analysisBankData(File dir, String caseId) { + + ImportResultPromptVO rstVO = new ImportResultPromptVO(); + + File[] files = dir.listFiles(); + if (files == null) { + throw new RuntimeException("空文件夹!"); + } + + + int bankCount = 0; + Map map = getBankNameAndBankNoMap(); + + List fileList = Arrays.stream(files).filter(File::isDirectory).collect(Collectors.toList()); + + List workerList = new ArrayList<>(); + //设置导入完成标识 + String ckey = Constants.COMPLETE_BANK_COUNT + caseId; + RedisUtils.deleteObject(ckey); + + for (File file : fileList) { + // + String bankName = FileUtil.mainName(file); + String bankNo; + if(bankName.equals(Constants.CENTRAL_GROUND_SYSTEM)){ + bankNo = Constants.BANK_IMPORT_MODEL_BANK_CGS; + }else { + bankNo = map.getOrDefault(bankName, null); + } + if (bankNo == null) { + String cause = "文件夹【"+bankName + "】 无法找到文件对应的模板,请检查银行名称或文件夹结构是否与模板一致。"; + importResultService.record(caseId, bankName, new RuntimeException(cause)); + continue; + } + // 空文件夹不必再分析 + if (file.isDirectory() && FileUtil.isDirEmpty(file)) { + continue; + } + // 光大银行 + if(bankNo.equals(Constants.BANK_IMPORT_MODEL_BANK_CEB_BANK)){ + continue; + } + + bankCount++; + + // 异步去处理每一个银行的文件 + ImportWorkflowWorker worker = new ImportWorkflowWorker(file, bankName, bankNo, caseId, rstVO); + workerList.add(worker); + } + // 一共导入的银行数 + rstVO.setTotal(bankCount); + String key = Constants.IMPORT_BANK_COUNT + caseId; + RedisUtils.setAtomicValue(key,bankCount); + + @SuppressWarnings("rawtypes") + List workerWrapperList = new ArrayList<>(); + // 包装 + for (ImportWorkflowWorker worker : workerList) { + WorkerWrapper wrapper = new WorkerWrapper.Builder() + .worker(worker) + .callback(worker) + .param(this) + .build(); + workerWrapperList.add(wrapper); + } + + // 开始处理 + try { + // MILLISECONDS + // 30分钟 + Async.beginWork(1000 * 60 * 30, workers.getWorkerDynamicExecutor(), workerWrapperList); + } catch (ExecutionException | InterruptedException e) { + // 异常 + log.error("异步处理失败", e); + } + + return rstVO; + } + + public void analysisFile(File file, String bankNo, String caseId, String bankName) { + try { + String completeKey = Constants.COMPLETE_BANK_COUNT +caseId; + long start = System.currentTimeMillis(); + // 导入数据 + switch (bankNo) { + case Constants.BANK_IMPORT_MODEL_BANK_FDB: // 富滇银行 + try { + esIndexHelper.delFDBIndex(caseId); + fdbDataAnalysisHelper.importData(file,caseId); + fdbDataAnalysisHelper.analyzeData(caseId); + } finally { + // 清除ES中的数据 + esIndexHelper.delFDBIndex(caseId); + RedisUtils.incrAtomicValue(completeKey); + long finish = System.currentTimeMillis(); + log.error("富滇银行---结束耗时【{}秒】",(finish - start)/1000.0); + } + break; + case Constants.BANK_IMPORT_MODEL_BOC_BANK: // 中国银行 + try { + esIndexHelper.delBOCIndex(caseId); + esIndexHelper.createBOCIndex(); + + bocDataAnalysisHelper.importData(file,caseId); + bocDataAnalysisHelper.analyzeData(caseId); + } finally { + esIndexHelper.delBOCIndex(caseId); + RedisUtils.incrAtomicValue(completeKey); + long finish = System.currentTimeMillis(); + log.error("中国银行---结束耗时【{}秒】",(finish - start)/1000.0); + } + break; + case Constants.BANK_IMPORT_MODEL_CITIC_BANK: // 中信银行 + try { + esIndexHelper.delCITICIndex(caseId); + esIndexHelper.createCITICIndex(); + + citicDataAnalysisHelper.importData(file,caseId); + citicDataAnalysisHelper.analyzeData(caseId); + + } finally { + esIndexHelper.delCITICIndex(caseId); + RedisUtils.incrAtomicValue(completeKey); + long finish = System.currentTimeMillis(); + log.error("中信银行---结束耗时【{}秒】",(finish - start)/1000.0); + } + break; + case Constants.BANK_IMPORT_MODEL_MERCHANTS_BANK: // 招商银行 + try { + esIndexHelper.delCMBIndex(caseId); + esIndexHelper.createCMBIndex(); + + cmbDataAnalysisHelper.importData(file,caseId); + cmbDataAnalysisHelper.analyzeData(caseId); + } finally { + esIndexHelper.delCMBIndex(caseId); + RedisUtils.incrAtomicValue(completeKey); + } + break; + case Constants.BANK_IMPORT_MODEL_ICBC_BANK: // 工商银行 + try { + esIndexHelper.delICBCIndex(caseId); + esIndexHelper.createICBCIndex(); + + icbcDataAnalysisHelper.importData(file,caseId); + icbcDataAnalysisHelper.analyzeIData(caseId); + } finally { + + esIndexHelper.delICBCIndex(caseId); + RedisUtils.incrAtomicValue(completeKey); + } + break; + case Constants.BANK_IMPORT_MODEL_RCC_BANK: // 农村信用社 + try { + esIndexHelper.delRCCIndex(caseId); + esIndexHelper.createRCCIndex(); + + rccDataAnalysisHelper.importData(file,caseId); + rccDataAnalysisHelper.analyzeData(caseId); + } finally { + // 启动任务,清除rcc中的数据 + esIndexHelper.delRCCIndex(caseId); + RedisUtils.incrAtomicValue(completeKey); + } + break; + case Constants.BANK_IMPORT_MODEL_SPDB_BANK: // 浦发银行 + try { + esIndexHelper.delSPDBIndex(caseId); + esIndexHelper.createSPDBIndex(); + + spdbDataAnalysisHelper.importData(file,caseId); + spdbDataAnalysisHelper.analyzeData(caseId); + } finally { + + esIndexHelper.delSPDBIndex(caseId); + RedisUtils.incrAtomicValue(completeKey); + } + break; + case Constants.BANK_IMPORT_MODEL_HUAXIA_BANK: // 华夏银行 + try { + esIndexHelper.delHuaXiaIndex(caseId); + esIndexHelper.createHuaXiaIndex(); + hbDataAnalysisHelper.importData(file,caseId); + hbDataAnalysisHelper.analyzeData(caseId); + } finally { + esIndexHelper.delHuaXiaIndex(caseId); + RedisUtils.incrAtomicValue(completeKey); + } + break; + case Constants.BANK_IMPORT_MODEL_PING_AN_BANK: // 平安银行 + try { + esIndexHelper.delSPAIndex(caseId); + esIndexHelper.createSPAIndex(); + + pabDataAnalysisHelper.importData(file,caseId); + pabDataAnalysisHelper.analyzeData(caseId); + } finally { + + esIndexHelper.delSPAIndex(caseId); + RedisUtils.incrAtomicValue(completeKey); + } + break; + case Constants.BANK_IMPORT_MODEL_INDUSTRIAL_BANK: // 兴业银行 + try { + esIndexHelper.delCIBIndex(caseId); + esIndexHelper.createCIBIndex(); + + cibDataAnalysisHelper.importData(file,caseId); + cibDataAnalysisHelper.analyzeData(caseId); + } finally { + + esIndexHelper.delCIBIndex(caseId); + RedisUtils.incrAtomicValue(completeKey); + } + break; + case Constants.BANK_IMPORT_MODEL_CCB_BANK: // 建设银行 + try { + esIndexHelper.delCCBIndex(caseId); + esIndexHelper.createCCBIndex(); + + ccbDataAnalysisHelper.importData(file,caseId); + ccbDataAnalysisHelper.analyzeData(caseId); + } finally { + + esIndexHelper.delCCBIndex(caseId); + RedisUtils.incrAtomicValue(completeKey); + } + break; + case Constants.BANK_IMPORT_MODEL_CMBC_BANK: // 民生银行 + try { + esIndexHelper.delCMBCIndex(caseId); + esIndexHelper.createCMBCIndex(); + cmbcDataAnalysisHelper.importData(file,caseId); + cmbcDataAnalysisHelper.analyzeData(caseId); + } finally { + esIndexHelper.delCMBCIndex(caseId); + RedisUtils.incrAtomicValue(completeKey); + } + break; + case Constants.BANK_IMPORT_MODEL_BANK_COMM_BANK: // 交通银行 + try { + esIndexHelper.delBOCOMIndex(caseId); + esIndexHelper.createBOCOMIndex(); + + bocomDataAnalysisHelper.importData(file,caseId); + bocomDataAnalysisHelper.analyzeData(caseId); + } finally { + esIndexHelper.delBOCOMIndex(caseId); + RedisUtils.incrAtomicValue(completeKey); + } + break; + case Constants.BANK_IMPORT_MODEL_QJCCB_BANK: // 曲靖商业银行 + try { + esIndexHelper.delQJCCBIndex(caseId); + esIndexHelper.createQJCCBIndex(); + + qjccbDataAnalysisHelper.importData(file,caseId); + qjccbDataAnalysisHelper.analyzeData(caseId); + } finally { + esIndexHelper.delQJCCBIndex(caseId); + RedisUtils.incrAtomicValue(completeKey); + } + break; + case Constants.BANK_IMPORT_MODEL_PSBC_BANK: // 邮储银行 + try { + esIndexHelper.delPSBCIndex(caseId); + esIndexHelper.createPSBCIndex(); + + psbcDataAnalysisHelper.importData(file,caseId); + psbcDataAnalysisHelper.analyzeData(caseId); + } finally { + + esIndexHelper.delPSBCIndex(caseId); + RedisUtils.incrAtomicValue(completeKey); + } + break; + case Constants.BANK_IMPORT_MODEL_CGBC_BANK: // 广发银行 + try { + esIndexHelper.delCGBCIndex(caseId); + esIndexHelper.createCGBCIndex(); + + cgbcDataAnalysisHelper.importData(file,caseId); + cgbcDataAnalysisHelper.analyzeData(caseId); + } finally { + esIndexHelper.delCGBCIndex(caseId); + RedisUtils.incrAtomicValue(completeKey); + } + break; + case Constants.BANK_IMPORT_MODEL_BANK_CEB_BANK: // 光大银行 + // try { + // esIndexHelper.delCEBIndex(); + // esIndexHelper.createCEBIndex(); + // cebDataAnalysisHelper.importCEBData(file); + // cebDataAnalysisHelper.analyzeCEBData(caseId); + // } finally { + // esIndexHelper.delCEBIndex(); + // } + // 构造返回对象,提示没有合适模板解析数据 +// throw new RegularFailureException("暂不支持导入光大银行流水."); + throw new RuntimeException("暂不支持解析光大银行流水数据"); + case Constants.BANK_IMPORT_MODEL_BANK_ABC_BANK: // 农业银行 + try { + esIndexHelper.delABCIndex(caseId); + esIndexHelper.createABCIndex(); + + abcDataAnalysisHelper.importData(file,caseId); + abcDataAnalysisHelper.analyzeData(caseId); + } finally { + esIndexHelper.delABCIndex(caseId); + RedisUtils.incrAtomicValue(completeKey); + } + break; + case Constants.BANK_IMPORT_MODEL_BANK_CGS: // 央地系统 + try { + esIndexHelper.delCGSIndex(caseId); + esIndexHelper.createCGSIndex(); + + cgsAnalysisHelper.importData(file,caseId); + cgsAnalysisHelper.analyzeData(caseId); + } finally { + esIndexHelper.delCGSIndex(caseId); + RedisUtils.incrAtomicValue(completeKey); + } + break; + case Constants.BANK_IMPORT_MODEL_BANK_HFB_BANK: // 恒丰银行 + try { + esIndexHelper.delHFBIndex(caseId); + esIndexHelper.createHFBIndex(); + + hfAnalysisHelper.importData(file,caseId); + hfAnalysisHelper.analyzeData(caseId); + } finally { + esIndexHelper.delHFBIndex(caseId); + RedisUtils.incrAtomicValue(completeKey); + } + break; + + default: + log.error("银行编号:[{}]未知.", bankNo); + break; + } + }catch (Exception e){ + e.printStackTrace(); + importResultService.record(caseId,bankName,e); + } + + } + + @Override + public void createTemplate(String sourceFolderPath, String zipFilePath) { + String[] bankArr = {"富滇银行","工商银行","央地系统","广发银行","华夏银行","建设银行","交通银行","民生银行","农村信用社","农业银行","平安银行","浦发银行", + "曲靖市商业银行","兴业银行","招商银行","中国银行","中国邮政储蓄银行","中信银行"}; + + sourceFolderPath = ProjectConfig.getUploadPath() + sourceFolderPath; + zipFilePath = ProjectConfig.getUploadPath() + "/template/"+zipFilePath; + for (String bank : bankArr) { + // 创建多层文件夹 + File folder = new File(sourceFolderPath+bank); + folder.mkdirs(); + } + + try { + zipFolder(new File(sourceFolderPath), zipFilePath); + } catch (IOException e) { + System.out.println("压缩过程中出现异常:" + e.getMessage()); + e.printStackTrace(); + } + } + + @Override + public boolean importAnalysisResult(List list, String analysisResultId, String username) { + Set uniqueKeySet = new HashSet(); + List result = new ArrayList<>(); + for (BankStatement bs : list) { + BeanUtils.beanAttributeValueTrim(bs); + String uniqueKey = getUniqueKey(bs); + String md5Id = HelperUtil.generateMD5(analysisResultId+uniqueKey); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + bs.setAnalysisResultId(analysisResultId); + bs.setId(md5Id); +// bs.setCreateBy(username); + bs.setCreateTime(new Date()); + result.add(bs); + } + + if (CollectionUtil.isNotEmpty(result)) { + //根据id取es查询 返回的就是重复数据 + GetBSFieldValueCountReq req = new GetBSFieldValueCountReq(); + req.setAnalysisResultId(analysisResultId); + //分析成果数据应该不会太多,太多就需要重写逻辑,不然这一步可能会内存溢出 + List esExistIdList = getBSList(req); + if(CollectionUtil.isEmpty(esExistIdList)){ + esBsMapper.insertBatch(result); + }else { + //重新计算md5 + Map groupByUniqueKeyMap = new HashMap<>(); + for (BankStatement bs : esExistIdList) { + BeanUtils.beanAttributeValueTrim(bs); + String uniqueKey = getUniqueKey(bs); + String md5Id = HelperUtil.generateMD5(analysisResultId+uniqueKey); + groupByUniqueKeyMap.put(md5Id,bs); + } + + List saveList = new ArrayList<>(); + for (BankStatement bankStatement : result) { + if(groupByUniqueKeyMap.containsKey(bankStatement.getId())){ + continue; + } + saveList.add(bankStatement); + } + esBsMapper.insertBatch(saveList); + } + } + + return true; + } + + @Override + public boolean editPersonInfo(List update) { + return analysisPersonMapper.updateBatchById(update); + } + + @Override + public Boolean caseMerge(String sourceCaseId,String targetCaseId) { + GetBSFieldValueCountReq req = new GetBSFieldValueCountReq(); + req.setCaseId(sourceCaseId); + List bsList = getBSList(req); + this.importData(bsList,targetCaseId,"案件合并"); + return true; + } + + + @Override + public void analysisResultMerge(Map sourceArIdTargetArIdMap) { + LambdaEsQueryWrapper wrapper = EsWrappers.lambdaQuery(BankStatement.class); + wrapper.in(BankStatement::getAnalysisResultId, sourceArIdTargetArIdMap.keySet()); + List bankStatements = esBsMapper.selectList(wrapper); + Map> arMap = bankStatements.stream().collect(Collectors.groupingBy(BankStatement::getAnalysisResultId)); + for (Map.Entry > entry : arMap.entrySet()) { + String sourceArId = entry.getKey(); + List bsList = entry.getValue(); + String targetArId = sourceArIdTargetArIdMap.get(sourceArId); + List addList = new ArrayList<>(); + for (BankStatement item : bsList) { + String md5Id = HelperUtil.generateMD5Id(item,targetArId); + item.setId(md5Id); + item.setCaseId(null); + item.setAnalysisResultId(targetArId); + addList.add(item); + } + HelperUtil.batchInsert2EsDuplicateRemoveByAnalysisResultId(addList, targetArId); + } + + //开户 + LambdaEsQueryWrapper wrapperOai = EsWrappers.lambdaQuery(OpeningAccountInfo.class); + wrapperOai.in(OpeningAccountInfo::getAnalysisResultId, sourceArIdTargetArIdMap.keySet()); + List openingAccountInfoList = esOaiMapper.selectList(wrapperOai); + Map> oaiMap = openingAccountInfoList.stream().collect(Collectors.groupingBy(OpeningAccountInfo::getAnalysisResultId)); + for (Map.Entry > entry : oaiMap.entrySet()) { + String sourceArId = entry.getKey(); + List bsList = entry.getValue(); + String targetArId = sourceArIdTargetArIdMap.get(sourceArId); + List addList = new ArrayList<>(); + for (OpeningAccountInfo item : bsList) { + String md5Id = HelperUtil.generateMD5Id4OAI(item,targetArId); + item.setId(md5Id); + item.setCaseId(null); + item.setAnalysisResultId(targetArId); + addList.add(item); + } + HelperUtil.batchInsertOai2EsDuplicateRemoveByAnalysisResultId(addList, targetArId); + } + + } + + @Override + public boolean importData(List list, String caseId,String fileName) { + Set uniqueKeySet = new HashSet(); + List bsList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + for (BankStatement bs : list) { + String md5Id = HelperUtil.generateMD5Id(bs,caseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + bs.setSourceFile(fileName); + bs.setId(md5Id); + bs.setCaseId(caseId); + BeanUtils.beanAttributeValueTrim(bs); + bsList.add(bs); + + if (bsList.size() >= Constants.BATCH_SIZE) { + + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + + uniqueKeySet.clear(); + // 保存数据库 + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2Es(dest, caseId); + } + return true; + } + + + @Override + public boolean batchInsert(List list) { + int batchSize = Constants.BATCH_SIZE; + int totalRecords = list.size(); + for (int i = 0; i < totalRecords; i += batchSize) { + List batch = list.subList(i, Math.min(i + batchSize, totalRecords)); + esBsMapper.insertBatch(batch); + } + return true; + } + + /** + * 复制出新的caseId为null的数,重新计算MD5 + * @param dto + */ + @Override + public void save2AnalysisResultOai(AnalysisDto dto) { + + Set ids = dto.getIds(); + if (ids.isEmpty()) { + return; + } + String analysisResultId = dto.getAnalysisResultId(); + List oaiList = esOaiMapper.selectBatchIds(ids); + Set uniqueKeySet = new HashSet(); + List bsList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + for (OpeningAccountInfo item : oaiList) { + String md5Id = HelperUtil.generateMD5Id4OAI(item,analysisResultId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + item.setId(md5Id); + item.setCaseId(null); + item.setAnalysisResultId(analysisResultId); + bsList.add(item); + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsertOai2EsDuplicateRemoveByAnalysisResultId(dest, analysisResultId); + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + uniqueKeySet.clear(); + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsertOai2EsDuplicateRemoveByAnalysisResultId(dest, analysisResultId); + } + } + + /** + * 复制出新的caseId为null的数,重新计算MD5 + * @param dto + */ + @Override + public void save2AnalysisResult(AnalysisDto dto) { + + Set ids = dto.getIds(); + if (ids.isEmpty()) { + return; + } + String analysisResultId = dto.getAnalysisResultId(); + List bankStatements = esBsMapper.selectBatchIds(ids); + Set uniqueKeySet = new HashSet(); + List bsList = ListUtils.newArrayListWithExpectedSize(BATCH_SIZE); + for (BankStatement item : bankStatements) { + String md5Id = HelperUtil.generateMD5Id(item,analysisResultId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + item.setId(md5Id); + item.setCaseId(null); + item.setAnalysisResultId(analysisResultId); + bsList.add(item); + + if (bsList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2EsDuplicateRemoveByAnalysisResultId(dest, analysisResultId); + bsList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + uniqueKeySet.clear(); + if (!bsList.isEmpty()) { + List dest = HelperUtil.getDest(bsList); + HelperUtil.batchInsert2EsDuplicateRemoveByAnalysisResultId(dest, analysisResultId); + } + } + + String getUniqueKey(BankStatement bs){ + // 银行名称 持卡人姓名 身份证号 交易卡号 交易时间 交易金额 账户余额 交易机构名称 对方户名 对方账号 对方身份证号 对方行名 摘要 交易备注 交易渠道 真实交易对手名称 真实交易对手账号 备注 + String counterpartyName = StrUtil.isEmpty(bs.getCounterpartyName())?"":bs.getCounterpartyName(); + String counterpartyAccount = StrUtil.isEmpty(bs.getCounterpartyAccount())?"":bs.getCounterpartyAccount(); + String counterpartIdCardNo = StrUtil.isEmpty(bs.getCounterpartIdCardNo())?"":bs.getCounterpartIdCardNo(); + String counterpartyBankName = StrUtil.isEmpty(bs.getCounterpartyBankName())?"":bs.getCounterpartyBankName(); + String bankName = StrUtil.isEmpty(bs.getBankName())?"":bs.getBankName(); + String cardHolderName = StrUtil.isEmpty(bs.getCardHolderName())?"":bs.getCardHolderName(); + String idCardNo = StrUtil.isEmpty(bs.getIdCardNo())?"":bs.getIdCardNo(); + String cardNumber = StrUtil.isEmpty(bs.getCardNumber())?"":bs.getCardNumber(); + Date transactionTime = bs.getTransactionTime(); + BigDecimal transactionAmount = bs.getTransactionAmount(); + BigDecimal balance = bs.getBalance(); + String transactionInstitutions = StrUtil.isEmpty(bs.getTransactionInstitutions())?"":bs.getTransactionInstitutions(); + String summary = StrUtil.isEmpty(bs.getSummary())?"":bs.getSummary(); + String transRemark = StrUtil.isEmpty(bs.getTransRemark())?"":bs.getTransRemark(); + String transChannel = StrUtil.isEmpty(bs.getTransChannel())?"":bs.getTransChannel(); + String realCounterpartyName = StrUtil.isEmpty(bs.getRealCounterpartyName())?"":bs.getRealCounterpartyName(); + String realCounterpartyAccount = StrUtil.isEmpty(bs.getRealCounterpartyAccount())?"":bs.getRealCounterpartyAccount(); + String uniqueKey = bankName + cardHolderName + idCardNo + cardNumber + transactionTime + transactionAmount + + balance + transactionInstitutions + + counterpartyName + + counterpartyAccount+ + counterpartIdCardNo+ + counterpartyBankName+ + summary + transRemark + transChannel + realCounterpartyName + realCounterpartyAccount; + return uniqueKey; + } + + private static void zipFolder(File sourceFolder, String zipFilePath) throws IOException { + try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFilePath))) { + zip(sourceFolder, sourceFolder.getName(), zos); + } + } + + private static void zip(File fileToZip, String fileName, ZipOutputStream zos) throws IOException { + if (fileToZip.isHidden()) { + return; + } + if (fileToZip.isDirectory()) { + if (fileName.endsWith("/")) { + zos.putNextEntry(new ZipEntry(fileName)); + } else { + zos.putNextEntry(new ZipEntry(fileName + "/")); + } + zos.closeEntry(); + for (File childFile : fileToZip.listFiles()) { + zip(childFile, fileName + "/" + childFile.getName(), zos); + } + return; + } + try (FileInputStream fis = new FileInputStream(fileToZip)) { + ZipEntry zipEntry = new ZipEntry(fileName); + zos.putNextEntry(zipEntry); + byte[] bytes = new byte[1024]; + int length; + while ((length = fis.read(bytes)) >= 0) { + zos.write(bytes, 0, length); + } + } + } + + private Map getBankNameAndBankNoMap() { + HashMap rst = new HashMap<>(); + + List bankListItemList = getBankList(); + for (BankListItem item : bankListItemList) { + rst.put(item.getBankName(), item.getBankNo()); + } + + return rst; + } + + private static List BANK_LIST = new ArrayList<>(); + + static { + BANK_LIST.add(new BankListItem(Constants.BANK_IMPORT_MODEL_BOC_BANK,"中国银行")); + BANK_LIST.add(new BankListItem(Constants.BANK_IMPORT_MODEL_CITIC_BANK,"中信银行")); + BANK_LIST.add(new BankListItem(Constants.BANK_IMPORT_MODEL_PING_AN_BANK,"平安银行")); + BANK_LIST.add(new BankListItem(Constants.BANK_IMPORT_MODEL_INDUSTRIAL_BANK,"兴业银行")); + BANK_LIST.add(new BankListItem(Constants.BANK_IMPORT_MODEL_MERCHANTS_BANK,"招商银行")); + BANK_LIST.add(new BankListItem(Constants.BANK_IMPORT_MODEL_CCB_BANK,"建设银行")); + BANK_LIST.add(new BankListItem(Constants.BANK_IMPORT_MODEL_CMBC_BANK,"民生银行")); + BANK_LIST.add(new BankListItem(Constants.BANK_IMPORT_MODEL_BANK_ABC_BANK,"农业银行")); + BANK_LIST.add(new BankListItem(Constants.BANK_IMPORT_MODEL_BANK_COMM_BANK,"交通银行")); + BANK_LIST.add(new BankListItem(Constants.BANK_IMPORT_MODEL_PSBC_BANK,"中国邮政储蓄银行")); + BANK_LIST.add(new BankListItem(Constants.BANK_IMPORT_MODEL_ICBC_BANK,"工商银行")); + BANK_LIST.add(new BankListItem(Constants.BANK_IMPORT_MODEL_HUAXIA_BANK,"华夏银行")); + BANK_LIST.add(new BankListItem(Constants.BANK_IMPORT_MODEL_CGBC_BANK,"广发银行")); + + BANK_LIST.add(new BankListItem(Constants.BANK_IMPORT_MODEL_QJCCB_BANK,"曲靖市商业银行")); + BANK_LIST.add(new BankListItem(Constants.BANK_IMPORT_MODEL_SPDB_BANK,"浦发银行")); + BANK_LIST.add(new BankListItem(Constants.BANK_IMPORT_MODEL_RCC_BANK,"农村信用社")); + BANK_LIST.add(new BankListItem(Constants.BANK_IMPORT_MODEL_BANK_FDB,"富滇银行")); + + BANK_LIST.add(new BankListItem(Constants.BANK_IMPORT_MODEL_BANK_CEB_BANK,"光大银行")); + BANK_LIST.add(new BankListItem(Constants.BANK_IMPORT_MODEL_BANK_HFB_BANK,"恒丰银行")); + BANK_LIST.add(new BankListItem(Constants.BANK_IMPORT_MODEL_BANK_CGS,"央地系统")); + + } + + + @Override + public List getBankList() { + return BANK_LIST; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/CarInfoServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/CarInfoServiceImpl.java new file mode 100644 index 0000000..9f19f22 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/CarInfoServiceImpl.java @@ -0,0 +1,384 @@ +package com.inscloudtech.datacenter.service.impl; + + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.analysiscenter.domain.AnalysisReport; +import com.inscloudtech.common.annotation.UpdateLog; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.datacenter.domain.*; +import com.inscloudtech.datacenter.domain.CarInfo; +import com.inscloudtech.datacenter.domain.CarInfo; +import com.inscloudtech.datacenter.mapper.CarInfoMapper; +import com.inscloudtech.datacenter.mapper.es.CarInfoEsMapper; +import com.inscloudtech.datacenter.service.ICarInfoService; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.easyes.core.biz.SAPageInfo; +import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper; +import org.dromara.easyes.core.core.EsWrappers; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.springframework.aop.framework.AopContext; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 重点人员资产-车辆信息Service业务层处理 + * + * @author inscloudtech + * @date 2023-11-10 + */ +@RequiredArgsConstructor +@Service +public class CarInfoServiceImpl implements ICarInfoService { + + private final CarInfoMapper baseMapper; + + private final CarInfoEsMapper esMapper; + + @Override + public void analysisResultMerge(Map sourceArIdTargetArIdMap) { + List analysisReportList = baseMapper.selectList(new LambdaQueryWrapper() + .in(CarInfo::getAnalysisResultId,sourceArIdTargetArIdMap.keySet())); + Map> arMap = analysisReportList.stream().collect(Collectors.groupingBy(CarInfo::getAnalysisResultId)); + List addList = new ArrayList<>(); + for (Map.Entry > entry : arMap.entrySet()) { + String sourceArId = entry.getKey(); + List reports = entry.getValue(); + String targetArId = sourceArIdTargetArIdMap.get(sourceArId); + for (CarInfo result : reports) { + result.setAnalysisResultId(targetArId); + String md5Id = HelperUtil.generateMD5(result.toString()); + result.setId(md5Id); + addList.add(result); + } + } + if(CollectionUtil.isNotEmpty(addList)){ + baseMapper.insertBatch(addList); + } + } + + /** + * 复制出新的caseId为null的数,重新计算MD5 + * @param dto + */ + @Override + public void save2AnalysisResult(AnalysisDto dto) { + Set ids = dto.getIds(); + if (ids.isEmpty()) { + return; + } + String analysisResultId = dto.getAnalysisResultId(); + List carInfos = esMapper.selectBatchIds(ids); + Set uniqueKeySet = new HashSet(); + List result = new ArrayList<>(); + for (CarInfo item : carInfos) { + item.setCaseId(null); + item.setAnalysisResultId(analysisResultId); + String md5Id = HelperUtil.generateMD5(item.toString()); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + item.setId(md5Id); + result.add(item); + } + uniqueKeySet.clear(); + this.importData(result,null,analysisResultId); + } + + + /** + * 查询重点人员资产-车辆信息 + */ + @Override + public CarInfo queryById(String id){ + return esMapper.selectById(id); + } + + /** + * 查询重点人员资产-车辆信息列表 + */ + @Override + public TableDataInfo queryPageList(CarInfo bo, PageQuery pageQuery) { + return esPage(bo,pageQuery); + } + public TableDataInfo esPage(CarInfo bo, PageQuery query){ + LambdaEsQueryWrapper wrapper = buildQueryWrapper(bo,query); + wrapper.size(query.getPageSize()); + + SAPageInfo pageInfo; + if(query.getPageNum() == 1){ + pageInfo = esMapper.searchAfterPage(wrapper, null, query.getPageSize()); + }else{ + pageInfo = esMapper.searchAfterPage(wrapper, null, (query.getPageNum() - 1) * query.getPageSize()); + pageInfo = esMapper.searchAfterPage(wrapper, pageInfo.getNextSearchAfter(), query.getPageSize()); + } + + TableDataInfo tableDataInfo = new TableDataInfo(); + tableDataInfo.setTotal(pageInfo.getTotal()); + tableDataInfo.setRows(pageInfo.getList()); + return tableDataInfo; + } + /** + * 查询重点人员资产-车辆信息列表 + */ + @Override + public List queryList(CarInfo bo) { + LambdaEsQueryWrapper lqw = buildQueryWrapper(bo,new PageQuery()); + return esMapper.selectList(lqw); + } + + private LambdaEsQueryWrapper buildQueryWrapper(CarInfo bo,PageQuery query) { + Map params = bo.getParams(); + LambdaEsQueryWrapper lqw = EsWrappers.lambdaQuery(CarInfo.class); + + if(StrUtil.isNotBlank(query.getOrderByColumn())){ + lqw.orderBy(StrUtil.isNotBlank(query.getOrderByColumn()),"asc".equals(query.getIsAsc()),query.getOrderByColumn()); + }else { + lqw.orderByDesc("id"); + } + lqw.eq(StringUtils.isNotBlank(bo.getName()), CarInfo::getName, bo.getName()); + lqw.eq(StringUtils.isNotBlank(bo.getIdCard()), CarInfo::getIdCard, bo.getIdCard()); + lqw.like(StringUtils.isNotBlank(bo.getCarNo()), CarInfo::getCarNo, bo.getCarNo()); + lqw.like(StringUtils.isNotBlank(bo.getCarType()), CarInfo::getCarType, bo.getCarType()); + lqw.like(StringUtils.isNotBlank(bo.getRegistration()), CarInfo::getRegistration, bo.getRegistration()); + lqw.like(StringUtils.isNotBlank(bo.getAddress()), CarInfo::getAddress, bo.getAddress()); + lqw.eq(StringUtils.isNotBlank(bo.getBgc()), CarInfo::getBgc, bo.getBgc()); + lqw.eq(StringUtils.isNotBlank(bo.getRemark()), CarInfo::getRemark, bo.getRemark()); + if(StrUtil.isNotEmpty(bo.getAnalysisResultId())){ + lqw.eq(CarInfo::getAnalysisResultId, bo.getAnalysisResultId()); + }else { + // 案件Id + lqw.eq(StrUtil.isNotEmpty(bo.getCaseId()), CarInfo::getCaseId, bo.getCaseId()); + } + if(StrUtil.isNotBlank(bo.getSearchValue())){ + lqw.queryStringQuery("*"+bo.getSearchValue().trim().replaceAll("([ ]|\\s|\\u00A0)+","")+"*"); + } + return lqw; + } + + /** + * 新增重点人员资产-车辆信息 + */ + @Override + @Transactional + public Boolean insertByBo(CarInfo bo) { + boolean flag = baseMapper.insert(bo) > 0; + if (flag) { + esMapper.insert(bo); + } + return flag; + } + + /** + * 修改重点人员资产-车辆信息 + */ + @Override + @Transactional + public Boolean updateByBo(CarInfo bo) { + CarInfo update = BeanUtil.toBean(bo, CarInfo.class); + boolean b = baseMapper.updateById(update) > 0; + if(b){ + esMapper.updateById(update); + } + return b; + } + /** + * 批量删除重点人员资产-车辆信息 + */ + @Override + @Transactional + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + baseMapper.deleteBatchIds(ids); + esMapper.deleteBatchIds(ids); + return true; + } + + @Override + @Transactional + public Boolean importData(List importList,String caseId, String analysisResultId) { + Set idCards = importList.stream().filter(item -> StrUtil.isNotEmpty(item.getIdCard())).map(CarInfo::getIdCard).collect(Collectors.toSet()); + LambdaEsQueryWrapper wrapper = EsWrappers.lambdaQuery(CarInfo.class); + wrapper.eq(StrUtil.isNotEmpty(caseId),CarInfo::getCaseId, caseId); + wrapper.in(CarInfo::getIdCard, idCards); + + //准备更新数据 + List dbList = esMapper.selectList(wrapper); + List addList = new ArrayList<>(); + List updateList = new ArrayList<>(); + + if(CollectionUtil.isNotEmpty(dbList)){ + Map map = new HashMap<>(); + for (CarInfo publicFamily : dbList) { + String _uniqueKey = publicFamily.getName() + publicFamily.getIdCard() + publicFamily.getCarNo(); + map.put(_uniqueKey,publicFamily); + } + + for (CarInfo importObj : importList) { + String uniqueKey = importObj.getName() + importObj.getIdCard() + importObj.getCarNo(); + if(map.containsKey(uniqueKey)){ + importObj.setId(null); + CarInfo update = BeanUtils.mergeObjects(map.get(uniqueKey), importObj); + updateList.add(update); + }else { + addList.add(importObj); + } + } + }else { + addList.addAll(importList); + } + if (CollectionUtil.isNotEmpty(addList)) { + //根据id取es查询 返回的就是重复数据 + Map groupById = addList.stream().collect(Collectors.toMap(CarInfo::getId, Function.identity())); + Set idSet = groupById.keySet(); + List esExistIdList; + if(StrUtil.isNotEmpty(caseId)){ + esExistIdList = HelperUtil.searchId(esMapper, CarInfo.class, idSet,"caseId", caseId); + }else { + esExistIdList = HelperUtil.searchId(esMapper, CarInfo.class, idSet,"analysisResultId", analysisResultId); + } + if(CollectionUtil.isEmpty(esExistIdList)){ + esMapper.insertBatch(addList); + }else { + Set esIdSet = esExistIdList.stream().map(CarInfo::getId).collect(Collectors.toSet()); + idSet.removeAll(esIdSet); + if(CollectionUtil.isNotEmpty(idSet)){ + List saveLis = new ArrayList<>(); + for (String id : idSet) { + saveLis.add(groupById.get(id)); + } + esMapper.insertBatch(saveLis); + } + } + } + if (CollectionUtil.isNotEmpty(updateList)) { + this.updateBatch(updateList); + } + return true; + } + + @Override + public Boolean caseMerge(String sourceCaseId,String targetCaseId) { + CarInfo bo = new CarInfo(); + bo.setCaseId(sourceCaseId); + List transactionPartners = this.queryList(bo); + transactionPartners = dataTrimAndDeduplication(transactionPartners, targetCaseId, ""); + return this.importData(transactionPartners,targetCaseId,null); + } + + @Override + @Transactional + public Boolean updateBatch(List list) { + CarInfoServiceImpl partnerService = getServiceImpl(); + list.stream().forEach(update->{ + partnerService.updateR(update); + }); + esMapper.updateBatchByIds(list); + return true; + } + + @UpdateLog(title = "车辆信息",mapperClass = CarInfoMapper.class) + public boolean updateR(CarInfo update) { + return baseMapper.updateById(update) > 0; + } + + private CarInfoServiceImpl getServiceImpl() { + return AopContext.currentProxy() != null ? (CarInfoServiceImpl) AopContext.currentProxy() : this; + } + + @Override + public Boolean importAnalysisResult(List list, String analysisResultId, String username) { + Set uniqueKeySet = new HashSet(); + List result = new ArrayList<>(); + for (CarInfo tp : list) { + BeanUtils.beanAttributeValueTrim(tp); + String uniqueKey = BeanUtils.getUniqueKey(tp); + String md5Id = HelperUtil.generateMD5(analysisResultId+uniqueKey); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + tp.setAnalysisResultId(analysisResultId); + tp.setId(md5Id); +// bs.setCreateBy(username); + tp.setCreateTime(new Date()); + result.add(tp); + } + + if (CollectionUtil.isNotEmpty(result)) { + //根据id取es查询 返回的就是重复数据 + CarInfo req = new CarInfo(); + req.setAnalysisResultId(analysisResultId); + //分析成果数据应该不会太多,太多就需要重写逻辑,不然这一步可能会内存溢出 + List esExistIdList = queryList(req); + if(CollectionUtil.isEmpty(esExistIdList)){ + esMapper.insertBatch(result); + }else { + //重新计算md5 + Map groupByUniqueKeyMap = new HashMap<>(); + for (CarInfo bs : esExistIdList) { + BeanUtils.beanAttributeValueTrim(bs); + String uniqueKey = BeanUtils.getUniqueKey(bs); + String md5Id = HelperUtil.generateMD5(analysisResultId+uniqueKey); + groupByUniqueKeyMap.put(md5Id,bs); + } + + List saveList = new ArrayList<>(); + for (CarInfo tp : result) { + if(groupByUniqueKeyMap.containsKey(tp.getId())){ + continue; + } + saveList.add(tp); + } + esMapper.insertBatch(saveList); + } + } + + return true; + } + + + @Override + public List dataTrimAndDeduplication(List list, String caseId, String createBy) { + Set uniqueKeySet = new HashSet(); + List result = new ArrayList<>(); + for (CarInfo family : list) { + try { + BeanUtils.beanAttributeValueTrim(family); + } catch (Exception e) { + e.printStackTrace(); + } + family.setCaseId(caseId); + String md5Id = HelperUtil.generateMD5(family.toString()); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + family.setId(md5Id); + family.setCreateBy(createBy); + family.setCreateTime(new Date()); + result.add(family); + } + + return result; + } + + @Override + public SearchSourceBuilder getSearchSourceBuilder(CarInfo family) { + LambdaEsQueryWrapper wrapper = buildQueryWrapper(family,new PageQuery()); + return esMapper.getSearchSourceBuilder(wrapper); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/DcImportResultServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/DcImportResultServiceImpl.java new file mode 100644 index 0000000..f50d676 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/DcImportResultServiceImpl.java @@ -0,0 +1,106 @@ +package com.inscloudtech.datacenter.service.impl; + + +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.exception.ExcelDataConvertException; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.inscloudtech.common.constant.BankStatementConstants; +import com.inscloudtech.common.exception.dc.AnalyzeDataFailedException; +import com.inscloudtech.common.exception.dc.ImportDataFailedException; +import com.inscloudtech.common.exception.dc.TemplateNotFindException; +import com.inscloudtech.common.utils.redis.RedisUtils; +import com.inscloudtech.datacenter.domain.ImportResult; +import com.inscloudtech.datacenter.mapper.ImportResultMapper; +import com.inscloudtech.datacenter.service.ImportResultService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 流水导入结果 + * + * @author zfcf + * @date 2024-07-15 + */ +@RequiredArgsConstructor +@Service +public class DcImportResultServiceImpl extends ServiceImpl implements ImportResultService { + + @Override + public void record(String caseId, String bankName, Exception exception,String sourceFile) { + ImportResult importResult = this.record(caseId, bankName, exception); + if(StrUtil.isEmpty(importResult.getFileName()) && StrUtil.isNotEmpty(sourceFile)){ + setFileNameAndSheetName(sourceFile,importResult); + } + this.updateById(importResult); + } + + @Override + public ImportResult record(String caseId, String bankName, Exception exception) { + String errorInfo = StrUtil.isEmpty(exception.getMessage())?"":exception.getMessage(); + ImportResult importResult = new ImportResult(); + if(exception instanceof TemplateNotFindException){ + TemplateNotFindException templateNotFindException = (TemplateNotFindException) exception; + String filename = templateNotFindException.getFilename(); + setFileNameAndSheetName(filename,importResult); + errorInfo = TemplateNotFindException.TIPS; + }else if(exception instanceof ImportDataFailedException){ + ImportDataFailedException importDataFailedException = (ImportDataFailedException) exception; + String filename = importDataFailedException.getFilename(); + setFileNameAndSheetName(filename,importResult); + }else if(exception instanceof AnalyzeDataFailedException){ + AnalyzeDataFailedException dataFailedException = (AnalyzeDataFailedException) exception; + String filename = dataFailedException.getRelationFilename(); + setFileNameAndSheetName(filename,importResult); + }else if (exception instanceof ExcelDataConvertException) { + ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception; + errorInfo = StrUtil.format( + "第{}行,第{}列解析异常,数据为:{}", + excelDataConvertException.getRowIndex()+1, + excelDataConvertException.getColumnIndex()+1, + excelDataConvertException.getCellData().getStringValue()); + + }else { + if (errorInfo.contains("password")) { + errorInfo = "文件有密码无法解析"; + } + } + + + importResult.setBatchId(RedisUtils.getCacheObject(BankStatementConstants.BATCH_ID_4_IMPORT+caseId)); + importResult.setErrorInfo(errorInfo); + importResult.setCaseId(caseId); + importResult.setBankName(bankName); + importResult.setCreateBy(RedisUtils.getCacheObject(BankStatementConstants.USERID_4_IMPORT+caseId)); + this.save(importResult); + return importResult; + } + + void setFileNameAndSheetName(String filename,ImportResult importResult){ + if (StrUtil.isEmpty(filename)) { + return; + } + if(filename.contains(BankStatementConstants.NAME_WITH_SHEET_NAME)){ + String[] split = filename.split(BankStatementConstants.NAME_WITH_SHEET_NAME); + importResult.setFileName(split[0]); + if(split.length > 1){ + importResult.setSheetName(StrUtil.isEmpty(split[1])?"":split[1]); + } + }else { + importResult.setFileName(filename); + } + } + + @Override + public List getResultListByCaseId(String caseId,String batchId) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(ImportResult::getCaseId,caseId); + lqw.eq(ImportResult::getBatchId,batchId); + lqw.eq(ImportResult::getSuccess,0); + return this.list(lqw); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/OpeningAccountInfoServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/OpeningAccountInfoServiceImpl.java new file mode 100644 index 0000000..b22d7b4 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/OpeningAccountInfoServiceImpl.java @@ -0,0 +1,128 @@ +package com.inscloudtech.datacenter.service.impl; + + +import cn.hutool.core.collection.CollectionUtil; +import com.alibaba.excel.util.ListUtils; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.datacenter.domain.OpeningAccountInfo; +import com.inscloudtech.datacenter.domain.vo.GetOpeningAccountInfoListReq; +import com.inscloudtech.datacenter.mapper.es.ESOpeningAccountInfoMapper; + + +import com.inscloudtech.datacenter.service.BankService; +import com.inscloudtech.datacenter.service.OpeningAccountInfoService; +import lombok.RequiredArgsConstructor; +import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper; +import org.dromara.easyes.core.core.EsWrappers; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +/** +* @author Administrator +* @description 针对表【opening_account_info】的数据库操作Service实现 +* @createDate 2023-11-13 17:05:16 +*/ +@RequiredArgsConstructor +@Transactional(rollbackFor = Exception.class) +@Service +public class OpeningAccountInfoServiceImpl implements OpeningAccountInfoService { + + + private final BankService bankService; + + private final ESOpeningAccountInfoMapper esOaiMapper; + + + @Override + public Boolean caseMerge(String sourceCaseId,String targetCaseId) { + + //开户 + Set uniqueKeySet = new HashSet(); + LambdaEsQueryWrapper lqw = EsWrappers.lambdaQuery(OpeningAccountInfo.class); + lqw.eq(OpeningAccountInfo::getCaseId, sourceCaseId); + List oaiList = esOaiMapper.selectList(lqw); + List addList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + for (OpeningAccountInfo oai : oaiList) { + String md5Id = HelperUtil.generateMD5Id4OAI(oai,targetCaseId); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + + oai.setId(md5Id); + oai.setCaseId(targetCaseId); + addList.add(oai); + if (addList.size() >= Constants.BATCH_SIZE) { + List dest = HelperUtil.getDest(addList); + HelperUtil.batchSaveOAI2Es(dest, targetCaseId); + addList = ListUtils.newArrayListWithExpectedSize(Constants.BATCH_SIZE); + } + } + uniqueKeySet.clear(); + if (!addList.isEmpty()) { + List dest = HelperUtil.getDest(addList); + HelperUtil.batchSaveOAI2Es(dest, targetCaseId); + } + + return true; + } + + @Override + public Boolean importAnalysisResult(List list, String analysisResultId, String username) { + Set uniqueKeySet = new HashSet(); + List result = new ArrayList<>(); + for (OpeningAccountInfo tp : list) { + BeanUtils.beanAttributeValueTrim(tp); + String uniqueKey = BeanUtils.getUniqueKey(tp); + String md5Id = HelperUtil.generateMD5(analysisResultId+uniqueKey); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + tp.setAnalysisResultId(analysisResultId); + tp.setId(md5Id); +// bs.setCreateBy(username); + tp.setCreateTime(new Date()); + result.add(tp); + } + + if (CollectionUtil.isNotEmpty(result)) { + //根据id取es查询 返回的就是重复数据 + GetOpeningAccountInfoListReq req = new GetOpeningAccountInfoListReq(); + req.setAnalysisResultId(analysisResultId); + //分析成果数据应该不会太多,太多就需要重写逻辑,不然这一步可能会内存溢出 + List esExistIdList = bankService.getOAIList(req); + if(CollectionUtil.isEmpty(esExistIdList)){ + esOaiMapper.insertBatch(result); + }else { + //重新计算md5 + Map groupByUniqueKeyMap = new HashMap<>(); + for (OpeningAccountInfo bs : esExistIdList) { + BeanUtils.beanAttributeValueTrim(bs); + String uniqueKey = BeanUtils.getUniqueKey(bs); + String md5Id = HelperUtil.generateMD5(analysisResultId+uniqueKey); + groupByUniqueKeyMap.put(md5Id,bs); + } + + List saveList = new ArrayList<>(); + for (OpeningAccountInfo tp : result) { + if(groupByUniqueKeyMap.containsKey(tp.getId())){ + continue; + } + saveList.add(tp); + } + esOaiMapper.insertBatch(saveList); + } + } + + return true; + } +} + + + + diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/OtherAssetsServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/OtherAssetsServiceImpl.java new file mode 100644 index 0000000..ef6294b --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/OtherAssetsServiceImpl.java @@ -0,0 +1,156 @@ +package com.inscloudtech.datacenter.service.impl; + + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; + +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.datacenter.domain.*; +import com.inscloudtech.datacenter.fileRead.FileReader; +import com.inscloudtech.datacenter.mapper.OtherAssetsMapper; +import com.inscloudtech.system.mapper.SysOssMapper; +import com.inscloudtech.datacenter.mapper.es.OtherAssetsEsMapper; +import com.inscloudtech.datacenter.service.IOtherAssetsService; +import com.inscloudtech.datacenter.service.PlateNumberService; +import com.inscloudtech.system.domain.SysOss; +import com.inscloudtech.system.service.ISysOssService; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.easyes.core.biz.SAPageInfo; +import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper; +import org.dromara.easyes.core.core.EsWrappers; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 重点人员资产-车辆信息Service业务层处理 + * + * @author inscloudtech + * @date 2023-11-10 + */ +@RequiredArgsConstructor +@Service +public class OtherAssetsServiceImpl implements IOtherAssetsService { + + private final OtherAssetsMapper baseMapper; + private final OtherAssetsEsMapper esMapper; + + private final SysOssMapper ossMapper; + + private final ISysOssService sysOssService; + + private static final String BUSINESS_MODULE = "OTHER_ASSETS"; + + private final PlateNumberService plateNumberService; + + @Override + public void analysisResultMerge(Map sourceArIdTargetArIdMap) { + sysOssService.analysisResultMerge(sourceArIdTargetArIdMap,BUSINESS_MODULE); + } + + /** + * 复制出新的caseId为null的数,重新计算MD5 + * @param dto + */ + @Override + public void save2AnalysisResult(AnalysisDto dto) { + sysOssService.save2AnalysisResult(dto); + } + + @Override + public Boolean caseMerge(String sourceCaseId,String targetCaseId) { + sysOssService.caseMerge(sourceCaseId,targetCaseId,BUSINESS_MODULE); + return true; + } + + @Override + public TableDataInfo queryPageList(OtherAssets bo, PageQuery query) { + LambdaEsQueryWrapper wrapper = buildEsQueryWrapper(bo); + wrapper.size(query.getPageSize()); + if(StrUtil.isNotBlank(query.getOrderByColumn())){ + wrapper.orderBy(StrUtil.isNotBlank(query.getOrderByColumn()),"asc".equals(query.getIsAsc()),query.getOrderByColumn()); + }else { + wrapper.orderByDesc("id"); + } + SAPageInfo pageInfo; + if(query.getPageNum() == 1){ + pageInfo = esMapper.searchAfterPage(wrapper, null, query.getPageSize()); + }else{ + pageInfo = esMapper.searchAfterPage(wrapper, null, (query.getPageNum() - 1) * query.getPageSize()); + pageInfo = esMapper.searchAfterPage(wrapper, pageInfo.getNextSearchAfter(), query.getPageSize()); + } + + TableDataInfo tableDataInfo = new TableDataInfo(); + tableDataInfo.setTotal(pageInfo.getTotal()); + tableDataInfo.setRows(pageInfo.getList()); + return tableDataInfo; + } + + private LambdaEsQueryWrapper buildEsQueryWrapper(OtherAssets bo) { + Map params = bo.getParams(); + LambdaEsQueryWrapper wrapper = EsWrappers.lambdaQuery(OtherAssets.class); + wrapper.eq(bo.getCaseId() != null, OtherAssets::getCaseId, bo.getCaseId()); + wrapper.eq(bo.getAnalysisResultId() != null, OtherAssets::getAnalysisResultId, bo.getAnalysisResultId()); + wrapper.like(StrUtil.isNotBlank(bo.getOriginalName()),OtherAssets::getOriginalName, bo.getOriginalName()); + wrapper.like(StrUtil.isNotBlank(bo.getContent()),OtherAssets::getContent, bo.getContent()); + if(StrUtil.isNotBlank(bo.getSearchValue())){ + wrapper.matchPhrase(OtherAssets::getContent,bo.getSearchValue().trim().replaceAll("([ ]|\\s|\\u00A0)+","")); + } + return wrapper; + } + + @Override + public void insertFileContent(String ossId,MultipartFile file, String caseId, String businessModule) { + OtherAssets otherAssets = new OtherAssets(); + otherAssets.setCaseId(caseId); + otherAssets.setCreateTime(new Date()); + otherAssets.setCreateBy(LoginHelper.getLoginUser().getUsername()); + otherAssets.setBusinessModule(businessModule); + String originalName = file.getOriginalFilename(); + otherAssets.setOriginalName(originalName); + this.insert(otherAssets,file,ossId,caseId); + } + + private void insert(OtherAssets otherAssets,MultipartFile file,String ossId,String caseId) { + SysOss oss = new SysOss(); + oss.setUploadResult(0); + try { + String content = FileReader.read(file); + List plateNumberInfoList = new ArrayList<>(); + HelperUtil.extractPlateNumberWithUploadFile(content,caseId,"其他资产",plateNumberInfoList); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + //处理车牌信息 + plateNumberService.invoke(caseId); + otherAssets.setContent(content); + otherAssets.setOssId(ossId); + boolean flag = baseMapper.insert(otherAssets) > 0; + if (flag) { + esMapper.insert(otherAssets); + } + }catch (Exception e){ + oss.setUploadResult(1); + oss.setErrorInfo(e.getMessage()); + }finally { + oss.setOssId(ossId); + oss.setOtherAssetsId(otherAssets.getId()); + ossMapper.updateById(oss); + } + } + + @Override + public boolean remove(List ossIds) { + List sysOsses = ossMapper.selectBatchIds(ossIds); + for (SysOss sysOss : sysOsses) { + baseMapper.deleteById(sysOss.getOtherAssetsId()); + esMapper.deleteById(sysOss.getOtherAssetsId()); + } + return sysOssService.deleteWithValidByIds(ossIds); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/OtherInformationServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/OtherInformationServiceImpl.java new file mode 100644 index 0000000..f750771 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/OtherInformationServiceImpl.java @@ -0,0 +1,143 @@ +package com.inscloudtech.datacenter.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; + +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.datacenter.domain.OtherInformation; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.domain.PublicFamily; +import com.inscloudtech.datacenter.domain.TransactionPartner; +import com.inscloudtech.datacenter.fileRead.FileReader; +import com.inscloudtech.datacenter.mapper.OtherInformationMapper; +import com.inscloudtech.datacenter.mapper.es.OtherInformationEsMapper; +import com.inscloudtech.datacenter.service.IOtherInformationService; +import com.inscloudtech.datacenter.service.PlateNumberService; +import com.inscloudtech.datacenter.domain.BankStatement; +import com.inscloudtech.system.domain.SysOss; +import com.inscloudtech.system.mapper.SysOssMapper; +import com.inscloudtech.system.service.ISysOssService; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.easyes.core.biz.SAPageInfo; +import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper; +import org.dromara.easyes.core.core.EsWrappers; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.util.*; + +@RequiredArgsConstructor +@Service +public class OtherInformationServiceImpl implements IOtherInformationService { + + private final OtherInformationMapper baseMapper; + private final OtherInformationEsMapper esMapper; + + private final SysOssMapper ossMapper; + private final ISysOssService sysOssService; + private final PlateNumberService plateNumberService; + + @Override + public void analysisResultMerge(Map sourceArIdTargetArIdMap) { + sysOssService.analysisResultMerge(sourceArIdTargetArIdMap,BUSINESS_MODULE); + } + + public void insert(OtherInformation otherInformation,MultipartFile file,String ossId,String caseId) { + String content = FileReader.read(file); + + List plateNumberInfoList = new ArrayList<>(); + HelperUtil.extractPlateNumberWithUploadFile(content,caseId,"其他信息",plateNumberInfoList); + HelperUtil.batchInsertPlateNumber(plateNumberInfoList); + //处理车牌信息 + plateNumberService.invoke(caseId); + + otherInformation.setContent(content); + otherInformation.setOssId(ossId); + boolean flag = baseMapper.insert(otherInformation) > 0; + if (flag) { + SysOss oss = new SysOss(); + oss.setOssId(ossId); + oss.setOtherAssetsId(otherInformation.getId()); + ossMapper.updateById(oss); + esMapper.insert(otherInformation); + } + } + + /** + * 复制出新的caseId为null的数,重新计算MD5 + * @param dto + */ + @Override + public void save2AnalysisResult(AnalysisDto dto) { + sysOssService.save2AnalysisResult(dto); + } + + private static final String BUSINESS_MODULE = "OTHER_INFORMATION"; + + @Override + public Boolean caseMerge(String sourceCaseId,String targetCaseId) { + sysOssService.caseMerge(sourceCaseId,targetCaseId,BUSINESS_MODULE); + return true; + } + + @Override + public boolean remove(List ossIds) { + List sysOsses = ossMapper.selectBatchIds(ossIds); + for (SysOss sysOss : sysOsses) { + baseMapper.deleteById(sysOss.getOtherAssetsId()); + esMapper.deleteById(sysOss.getOtherAssetsId()); + } + return sysOssService.deleteWithValidByIds(ossIds); + } + + @Override + public TableDataInfo queryPageList(OtherInformation bo, PageQuery query) { + LambdaEsQueryWrapper wrapper = buildEsQueryWrapper(bo); + wrapper.size(query.getPageSize()); + if(StrUtil.isNotBlank(query.getOrderByColumn())){ + wrapper.orderBy(StrUtil.isNotBlank(query.getOrderByColumn()),"asc".equals(query.getIsAsc()),query.getOrderByColumn()); + }else { + wrapper.orderByDesc("id"); + } + SAPageInfo pageInfo; + if(query.getPageNum() == 1){ + pageInfo = esMapper.searchAfterPage(wrapper, null, query.getPageSize()); + }else{ + pageInfo = esMapper.searchAfterPage(wrapper, null, (query.getPageNum() - 1) * query.getPageSize()); + pageInfo = esMapper.searchAfterPage(wrapper, pageInfo.getNextSearchAfter(), query.getPageSize()); + } + + TableDataInfo tableDataInfo = new TableDataInfo(); + tableDataInfo.setTotal(pageInfo.getTotal()); + tableDataInfo.setRows(pageInfo.getList()); + return tableDataInfo; + } + + private LambdaEsQueryWrapper buildEsQueryWrapper(OtherInformation bo) { + Map params = bo.getParams(); + LambdaEsQueryWrapper wrapper = EsWrappers.lambdaQuery(OtherInformation.class); + wrapper.eq(bo.getCaseId() != null, OtherInformation::getCaseId, bo.getCaseId()); + wrapper.eq(bo.getAnalysisResultId() != null, OtherInformation::getAnalysisResultId, bo.getAnalysisResultId()); + wrapper.like(StrUtil.isNotBlank(bo.getOriginalName()),OtherInformation::getOriginalName, bo.getOriginalName()); + wrapper.like(StrUtil.isNotBlank(bo.getContent()),OtherInformation::getContent, bo.getContent()); + if(StrUtil.isNotBlank(bo.getSearchValue())){ + wrapper.matchPhrase(OtherInformation::getContent,bo.getSearchValue().trim().replaceAll("([ ]|\\s|\\u00A0)+","")); + } + return wrapper; + } + + + @Override + public void insertFileContent(String ossId, MultipartFile file, String caseId, String businessModule) { + OtherInformation otherAssets = new OtherInformation(); + otherAssets.setCaseId(caseId); + otherAssets.setCreateTime(new Date()); + otherAssets.setCreateBy(LoginHelper.getUsername()); + String originalName = file.getOriginalFilename(); + otherAssets.setOriginalName(originalName); + this.insert(otherAssets,file,ossId,caseId); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/PlateNumberServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/PlateNumberServiceImpl.java new file mode 100644 index 0000000..02f6403 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/PlateNumberServiceImpl.java @@ -0,0 +1,489 @@ +package com.inscloudtech.datacenter.service.impl; + + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.common.annotation.UpdateLog; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.utils.BeanCopyUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.datacenter.domain.CarInfo; +import com.inscloudtech.datacenter.domain.PlateNumberInfo; +import com.inscloudtech.datacenter.mapper.CarInfoMapper; +import com.inscloudtech.datacenter.mapper.es.CarInfoEsMapper; +import com.inscloudtech.datacenter.mapper.es.PlateNumberEsMapper; +import com.inscloudtech.datacenter.service.ICarInfoService; +import com.inscloudtech.datacenter.service.PlateNumberService; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.easyes.core.biz.SAPageInfo; +import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper; +import org.dromara.easyes.core.core.EsWrappers; +import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.springframework.aop.framework.AopContext; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 重点人员资产-车辆抓取Service业务层处理 + * + * @author inscloudtech + * @date 2023-11-10 + */ +@RequiredArgsConstructor +@Service +public class PlateNumberServiceImpl implements PlateNumberService { + + private final PlateNumberEsMapper esMapper; + + private final CarInfoEsMapper carInfoEsMapper; + + /** + * 复制出新的caseId为null的数,重新计算MD5 + * @param dto + */ + @Override + public void save2AnalysisResult(AnalysisDto dto) { + Set ids = dto.getIds(); + if (ids.isEmpty()) { + return; + } + String analysisResultId = dto.getAnalysisResultId(); + List plateNumberInfos = esMapper.selectBatchIds(ids); + Set uniqueKeySet = new HashSet(); + List result = new ArrayList<>(); + for (PlateNumberInfo item : plateNumberInfos) { + item.setCaseId(null); + item.setAnalysisResultId(analysisResultId); + String md5Id = HelperUtil.generateMD5(item.toString()); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + item.setId(md5Id); + result.add(item); + } + uniqueKeySet.clear(); + this.importData(result,null,analysisResultId); + } + + @Override + public void invoke(String caseId) { + PlateNumberInfo bo = new PlateNumberInfo(); + bo.setCaseId(caseId); + bo.setHasDeal(0); + //未去重 + List numberInfoList = queryList(bo); + if(CollectionUtil.isEmpty(numberInfoList)){ + return; + } + + List idList = numberInfoList.stream() + .map(PlateNumberInfo::getId) + .collect(Collectors.toList()); + LambdaEsQueryWrapper lqw = EsWrappers.lambdaQuery(CarInfo.class); + lqw.eq(CarInfo::getCaseId,caseId); + List carInfos = carInfoEsMapper.selectList(lqw); + Map> carInfoMap = carInfos.stream().filter(item -> StrUtil.isNotEmpty(item.getCarNo())) + .collect(Collectors.groupingBy(CarInfo::getCarNo)); + + Map> plateNumberInfoMap = numberInfoList.stream().filter(item -> StrUtil.isNotEmpty(item.getPlateNumber())) + .collect(Collectors.groupingBy(PlateNumberInfo::getPlateNumber)); + + List addList = new ArrayList<>(); + for (String plateNumber : plateNumberInfoMap.keySet()) { + List plateNumberInfoList = plateNumberInfoMap.get(plateNumber); + Map> tempMap = plateNumberInfoList.stream().filter(item -> StrUtil.isNotEmpty(item.getBsHolder())) + .collect(Collectors.groupingBy(PlateNumberInfo::getBsHolder)); + String holder = ""; + if(carInfoMap.containsKey(plateNumber)){ + List tempCarInfos = carInfoMap.get(plateNumber); + for (CarInfo tempCarInfo : tempCarInfos) { + if(StrUtil.isNotEmpty(tempCarInfo.getName())){ + holder = tempCarInfo.getName(); + break; + } + } + } + if(CollectionUtil.isEmpty(tempMap)){ + List tempAddList = BeanCopyUtils.copyList(plateNumberInfoList, PlateNumberInfo.class); + for (PlateNumberInfo plateNumberInfo : tempAddList) { + plateNumberInfo.setHasDeal(1); + plateNumberInfo.setCreateTime(new Date()); + String uniqueKey = BeanUtils.getUniqueKey(plateNumberInfo); + String md5Id = HelperUtil.generateMD5(caseId+uniqueKey); + plateNumberInfo.setId(md5Id); + plateNumberInfo.setCaseId(caseId); + } + addList.addAll(tempAddList); + }else { + for (String bsHolder : tempMap.keySet()) { + PlateNumberInfo add = new PlateNumberInfo(); + add.setPlateNumber(plateNumber); + add.setBsHolder(bsHolder); + List infos = tempMap.get(bsHolder); + List uniqueSourceContent = infos.stream().filter(item->StrUtil.isNotEmpty(item.getSourceContent())) + .map(PlateNumberInfo::getSourceContent) + .distinct() + .collect(Collectors.toList()); + List bankName = infos.stream().filter(item->StrUtil.isNotEmpty(item.getBankName())) + .map(PlateNumberInfo::getBankName) + .distinct() + .collect(Collectors.toList()); +// List uniqueSourceFile = infos.stream().filter(item->StrUtil.isNotEmpty(item.getSourceFile())) +// .map(PlateNumberInfo::getSourceFile) +// .distinct() +// .collect(Collectors.toList()); +// add.setSourceFile(uniqueSourceFile.stream() +// .collect(Collectors.joining(", "))); + add.setSourceContent(uniqueSourceContent.stream() + .collect(Collectors.joining(", "))); + add.setBankName(bankName.stream() + .collect(Collectors.joining(", "))); + add.setHasDeal(1); + add.setHolder(holder); + add.setCreateTime(new Date()); + String uniqueKey = BeanUtils.getUniqueKey(add); + String md5Id = HelperUtil.generateMD5(caseId+uniqueKey); + add.setCaseId(caseId); + add.setId(md5Id); + addList.add(add); + } + } + + } + + if(CollectionUtil.isNotEmpty(addList)){ + esMapper.deleteBatchIds(idList); + esMapper.insertBatch(addList); + } + + +// String uniqueKey = BeanUtils.getUniqueKey(plateNumberInfo); +// String md5Id = HelperUtil.generateMD5(caseId+uniqueKey); +// numberInfoList.stream().forEach(item->{ +// if (carInfoMap.containsKey(item.getPlateNumber())) { +// List tempCarList = carInfoMap.get(item.getPlateNumber()); +// for (CarInfo carInfo : tempCarList) { +// if(StrUtil.isEmpty(carInfo.getName())){ +// item.setHolder(carInfo.getName()); +// break; +// } +// } +// } +//// item.get +// +// }); + + + } + + + /** + * 查询重点人员资产-车辆抓取 + */ + @Override + public PlateNumberInfo queryById(String id){ + return esMapper.selectById(id); + } + + /** + * 查询重点人员资产-车辆抓取列表 + */ + @Override + public TableDataInfo queryPageList(PlateNumberInfo bo, PageQuery pageQuery) { + return esPage(bo,pageQuery); + } + public TableDataInfo esPage(PlateNumberInfo bo, PageQuery query){ + LambdaEsQueryWrapper wrapper = buildQueryWrapper(bo,query); + wrapper.size(query.getPageSize()); + + SAPageInfo pageInfo; + if(query.getPageNum() == 1){ + pageInfo = esMapper.searchAfterPage(wrapper, null, query.getPageSize()); + }else{ + pageInfo = esMapper.searchAfterPage(wrapper, null, (query.getPageNum() - 1) * query.getPageSize()); + pageInfo = esMapper.searchAfterPage(wrapper, pageInfo.getNextSearchAfter(), query.getPageSize()); + } + + TableDataInfo tableDataInfo = new TableDataInfo(); + tableDataInfo.setTotal(pageInfo.getTotal()); + tableDataInfo.setRows(pageInfo.getList()); + return tableDataInfo; + } + /** + * 查询重点人员资产-车辆抓取列表 + */ + @Override + public List queryList(PlateNumberInfo bo) { + LambdaEsQueryWrapper lqw = buildQueryWrapper(bo,new PageQuery()); + return esMapper.selectList(lqw); + } + + private LambdaEsQueryWrapper buildQueryWrapper(PlateNumberInfo bo,PageQuery query) { + Map params = bo.getParams(); + LambdaEsQueryWrapper lqw = EsWrappers.lambdaQuery(PlateNumberInfo.class); + + if(StrUtil.isNotBlank(query.getOrderByColumn())){ + lqw.orderBy(StrUtil.isNotBlank(query.getOrderByColumn()),"asc".equals(query.getIsAsc()),query.getOrderByColumn()); + }else { + lqw.orderByDesc("createTime"); + } + lqw.eq(StringUtils.isNotBlank(bo.getPlateNumber()), PlateNumberInfo::getPlateNumber, bo.getPlateNumber()); + lqw.eq(StringUtils.isNotBlank(bo.getSourceFile()), PlateNumberInfo::getSourceFile, bo.getSourceFile()); + lqw.eq(bo.getHasDeal() != null, PlateNumberInfo::getHasDeal, bo.getHasDeal()); + lqw.like(StringUtils.isNotBlank(bo.getSourceContent()), PlateNumberInfo::getSourceContent, bo.getSourceContent()); + lqw.like(StringUtils.isNotBlank(bo.getHolder()), PlateNumberInfo::getHolder, bo.getHolder()); + lqw.like(StringUtils.isNotBlank(bo.getBankName()), PlateNumberInfo::getBankName, bo.getBankName()); + lqw.like(StringUtils.isNotBlank(bo.getRemark()), PlateNumberInfo::getRemark, bo.getRemark()); + lqw.like(StringUtils.isNotBlank(bo.getBsHolder()), PlateNumberInfo::getBsHolder, bo.getBsHolder()); + if(StrUtil.isNotEmpty(bo.getAnalysisResultId())){ + lqw.eq(PlateNumberInfo::getAnalysisResultId, bo.getAnalysisResultId()); + }else { + // 案件Id + lqw.eq(StrUtil.isNotEmpty(bo.getCaseId()), PlateNumberInfo::getCaseId, bo.getCaseId()); + } + if(StrUtil.isNotBlank(bo.getSearchValue())){ + lqw.queryStringQuery("*"+bo.getSearchValue().trim().replaceAll("([ ]|\\s|\\u00A0)+","")+"*"); + } + return lqw; + } + + /** + * 新增重点人员资产-车辆抓取 + */ + @Override + @Transactional + public Boolean insertByBo(PlateNumberInfo family) { + BeanUtils.beanAttributeValueTrim(family); + String md5Id = HelperUtil.generateMD5(family.toString()); + family.setId(md5Id); + family.setCreateTime(new Date()); + return esMapper.insert(family) > 0; + } + + /** + * 修改重点人员资产-车辆抓取 + */ + @Override + @Transactional + public Boolean updateByBo(PlateNumberInfo bo) { + return esMapper.updateById(bo) > 0; + } + /** + * 批量删除重点人员资产-车辆抓取 + */ + @Override + @Transactional + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + esMapper.deleteBatchIds(ids); + return true; + } + + @Override + @Transactional + public Boolean importData(List importList,String caseId, String analysisResultId) { + Set plateNumberSet = importList.stream().filter(item -> StrUtil.isNotEmpty(item.getPlateNumber())).map(PlateNumberInfo::getPlateNumber).collect(Collectors.toSet()); + LambdaEsQueryWrapper wrapper = EsWrappers.lambdaQuery(PlateNumberInfo.class); + wrapper.eq(StrUtil.isNotEmpty(caseId),PlateNumberInfo::getCaseId, caseId); + wrapper.in(PlateNumberInfo::getPlateNumber, plateNumberSet); + + //准备更新数据 + List dbList = esMapper.selectList(wrapper); + List addList = new ArrayList<>(); + List updateList = new ArrayList<>(); + + if(CollectionUtil.isNotEmpty(dbList)){ + Map map = new HashMap<>(); + for (PlateNumberInfo publicFamily : dbList) { + String _uniqueKey = publicFamily.getPlateNumber() + publicFamily.getBsHolder(); + map.put(_uniqueKey,publicFamily); + } + + for (PlateNumberInfo importObj : importList) { + String uniqueKey = importObj.getPlateNumber() + importObj.getBsHolder(); + if(map.containsKey(uniqueKey)){ + importObj.setId(null); + PlateNumberInfo update = BeanUtils.mergeObjects(map.get(uniqueKey), importObj); + updateList.add(update); + }else { + addList.add(importObj); + } + } + }else { + addList.addAll(importList); + } + if (CollectionUtil.isNotEmpty(addList)) { + //根据id取es查询 返回的就是重复数据 + Map groupById = addList.stream().collect(Collectors.toMap(PlateNumberInfo::getId, Function.identity())); + Set idSet = groupById.keySet(); + List esExistIdList; + if(StrUtil.isNotEmpty(caseId)){ + esExistIdList = HelperUtil.searchId(esMapper, PlateNumberInfo.class, idSet,"caseId", caseId); + }else { + esExistIdList = HelperUtil.searchId(esMapper, PlateNumberInfo.class, idSet,"analysisResultId", analysisResultId); + } + if(CollectionUtil.isEmpty(esExistIdList)){ + esMapper.insertBatch(addList); + }else { + Set esIdSet = esExistIdList.stream().map(PlateNumberInfo::getId).collect(Collectors.toSet()); + idSet.removeAll(esIdSet); + if(CollectionUtil.isNotEmpty(idSet)){ + List saveLis = new ArrayList<>(); + for (String id : idSet) { + saveLis.add(groupById.get(id)); + } + esMapper.insertBatch(saveLis); + } + } + } + if (CollectionUtil.isNotEmpty(updateList)) { + this.updateBatch(updateList); + } + return true; + } + + @Override + public Boolean caseMerge(String sourceCaseId,String targetCaseId) { + PlateNumberInfo bo = new PlateNumberInfo(); + bo.setCaseId(sourceCaseId); + List transactionPartners = this.queryList(bo); + transactionPartners = dataTrimAndDeduplication(transactionPartners, targetCaseId, ""); + return this.importData(transactionPartners,targetCaseId,null); + } + + @Override + public void analysisResultMerge(Map sourceArIdTargetArIdMap) { + LambdaEsQueryWrapper wrapper = EsWrappers.lambdaQuery(PlateNumberInfo.class); + wrapper.in(PlateNumberInfo::getAnalysisResultId, sourceArIdTargetArIdMap.keySet()); + List analysisReportList = esMapper.selectList(wrapper); + Map> arMap = analysisReportList.stream().collect(Collectors.groupingBy(PlateNumberInfo::getAnalysisResultId)); + List addList = new ArrayList<>(); + for (Map.Entry > entry : arMap.entrySet()) { + String sourceArId = entry.getKey(); + List reports = entry.getValue(); + String targetArId = sourceArIdTargetArIdMap.get(sourceArId); + for (PlateNumberInfo result : reports) { + result.setAnalysisResultId(targetArId); + String md5Id = HelperUtil.generateMD5(result.toString()); + result.setId(md5Id); + addList.add(result); + } + } + if(CollectionUtil.isNotEmpty(addList)){ + esMapper.insertBatch(addList); + } + } + + @Override + @Transactional + public Boolean updateBatch(List list) { + PlateNumberServiceImpl partnerService = getServiceImpl(); + list.stream().forEach(update->{ + partnerService.updateR(update); + }); + esMapper.updateBatchByIds(list); + return true; + } + + @UpdateLog(title = "车辆抓取",mapperClass = CarInfoMapper.class) + public boolean updateR(PlateNumberInfo update) { + return esMapper.updateById(update) > 0; + } + + private PlateNumberServiceImpl getServiceImpl() { + return AopContext.currentProxy() != null ? (PlateNumberServiceImpl) AopContext.currentProxy() : this; + } + + @Override + public Boolean importAnalysisResult(List list, String analysisResultId, String username) { + Set uniqueKeySet = new HashSet(); + List result = new ArrayList<>(); + for (PlateNumberInfo tp : list) { + BeanUtils.beanAttributeValueTrim(tp); + String uniqueKey = BeanUtils.getUniqueKey(tp); + String md5Id = HelperUtil.generateMD5(analysisResultId+uniqueKey); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + tp.setAnalysisResultId(analysisResultId); + tp.setId(md5Id); +// bs.setCreateBy(username); + tp.setCreateTime(new Date()); + result.add(tp); + } + + if (CollectionUtil.isNotEmpty(result)) { + //根据id取es查询 返回的就是重复数据 + PlateNumberInfo req = new PlateNumberInfo(); + req.setAnalysisResultId(analysisResultId); + //分析成果数据应该不会太多,太多就需要重写逻辑,不然这一步可能会内存溢出 + List esExistIdList = queryList(req); + if(CollectionUtil.isEmpty(esExistIdList)){ + esMapper.insertBatch(result); + }else { + //重新计算md5 + Map groupByUniqueKeyMap = new HashMap<>(); + for (PlateNumberInfo bs : esExistIdList) { + BeanUtils.beanAttributeValueTrim(bs); + String uniqueKey = BeanUtils.getUniqueKey(bs); + String md5Id = HelperUtil.generateMD5(analysisResultId+uniqueKey); + groupByUniqueKeyMap.put(md5Id,bs); + } + + List saveList = new ArrayList<>(); + for (PlateNumberInfo tp : result) { + if(groupByUniqueKeyMap.containsKey(tp.getId())){ + continue; + } + saveList.add(tp); + } + esMapper.insertBatch(saveList); + } + } + + return true; + } + + + @Override + public List dataTrimAndDeduplication(List list, String caseId, String createBy) { + Set uniqueKeySet = new HashSet(); + List result = new ArrayList<>(); + for (PlateNumberInfo family : list) { + try { + BeanUtils.beanAttributeValueTrim(family); + } catch (Exception e) { + e.printStackTrace(); + } + family.setCaseId(caseId); + String md5Id = HelperUtil.generateMD5(family.toString()); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + family.setId(md5Id); + family.setCreateBy(createBy); + family.setCreateTime(new Date()); + result.add(family); + } + + return result; + } + + @Override + public SearchSourceBuilder getSearchSourceBuilder(PlateNumberInfo family) { + LambdaEsQueryWrapper wrapper = buildQueryWrapper(family,new PageQuery()); + return esMapper.getSearchSourceBuilder(wrapper); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/PublicFamilyServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/PublicFamilyServiceImpl.java new file mode 100644 index 0000000..dd8cb79 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/PublicFamilyServiceImpl.java @@ -0,0 +1,428 @@ +package com.inscloudtech.datacenter.service.impl; + + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.common.annotation.DeduplicationField; + +import com.inscloudtech.common.annotation.NameField; +import com.inscloudtech.common.annotation.UpdateLog; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.datacenter.domain.*; +import com.inscloudtech.datacenter.domain.PublicFamily; +import com.inscloudtech.datacenter.mapper.PublicFamilyMapper; +import com.inscloudtech.datacenter.mapper.es.PublicFamilyEsMapper; +import com.inscloudtech.datacenter.service.IPublicFamilyService; +import com.inscloudtech.datacenter.service.QueryCenterService; +import com.inscloudtech.datacenter.domain.BankStatement; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import org.dromara.easyes.annotation.HighLight; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.core.biz.SAPageInfo; +import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper; +import org.dromara.easyes.core.core.EsWrappers; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.springframework.aop.framework.AopContext; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.math.BigDecimal; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 数据中心-职工家属Service业务层处理 + * + * @author inscloudtech + * @date 2023-11-09 + */ +@RequiredArgsConstructor +@Service +public class PublicFamilyServiceImpl implements IPublicFamilyService { + + private final PublicFamilyMapper baseMapper; + + private final PublicFamilyEsMapper esMapper; + + @Override + public void analysisResultMerge(Map sourceArIdTargetArIdMap) { + List analysisReportList = baseMapper.selectList(new LambdaQueryWrapper() + .in(PublicFamily::getAnalysisResultId,sourceArIdTargetArIdMap.keySet())); + Map> arMap = analysisReportList.stream().collect(Collectors.groupingBy(PublicFamily::getAnalysisResultId)); + List addList = new ArrayList<>(); + for (Map.Entry > entry : arMap.entrySet()) { + String sourceArId = entry.getKey(); + List reports = entry.getValue(); + String targetArId = sourceArIdTargetArIdMap.get(sourceArId); + for (PublicFamily result : reports) { + result.setAnalysisResultId(targetArId); + String md5Id = HelperUtil.generateMD5(result.toString()); + result.setId(md5Id); + addList.add(result); + } + } + if(CollectionUtil.isNotEmpty(addList)){ + baseMapper.insertBatch(addList); + } + } + + @Override + public Boolean caseMerge(String sourceCaseId,String targetCaseId) { + PublicFamily bo = new PublicFamily(); + bo.setCaseId(sourceCaseId); + List transactionPartners = this.queryList(bo); + transactionPartners = dataTrimAndDeduplication(transactionPartners, targetCaseId, ""); + return this.importData(transactionPartners,targetCaseId,null); + } + + /** + * 复制出新的caseId为null的数,重新计算MD5 + * @param dto + */ + @Override + public void save2AnalysisResult(AnalysisDto dto) { + Set ids = dto.getIds(); + if (ids.isEmpty()) { + return; + } + String analysisResultId = dto.getAnalysisResultId(); + List publicFamilies = esMapper.selectBatchIds(ids); + Set uniqueKeySet = new HashSet(); + List result = new ArrayList<>(); + for (PublicFamily item : publicFamilies) { + item.setCaseId(null); + item.setAnalysisResultId(analysisResultId); + String md5Id = HelperUtil.generateMD5(item.toString()); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + item.setId(md5Id); + result.add(item); + } + uniqueKeySet.clear(); + this.importData(result,null,analysisResultId); + } + + + /** + * 查询数据中心-职工家属 + */ + @Override + public PublicFamily queryById(String id){ + return esMapper.selectById(id); + } + + /** + * 查询数据中心-职工家属列表 + */ + @Override + public TableDataInfo queryPageList(PublicFamily bo, PageQuery query) { + LambdaEsQueryWrapper wrapper = buildQueryWrapper(bo,query); + wrapper.size(query.getPageSize()); + SAPageInfo pageInfo; + if(query.getPageNum() == 1){ + pageInfo = esMapper.searchAfterPage(wrapper, null, query.getPageSize()); + }else{ + pageInfo = esMapper.searchAfterPage(wrapper, null, (query.getPageNum() - 1) * query.getPageSize()); + pageInfo = esMapper.searchAfterPage(wrapper, pageInfo.getNextSearchAfter(), query.getPageSize()); + } + + TableDataInfo tableDataInfo = new TableDataInfo(); + tableDataInfo.setTotal(pageInfo.getTotal()); + tableDataInfo.setRows(pageInfo.getList()); + return tableDataInfo; + } + + /** + * 查询数据中心-职工家属列表 + */ + @Override + public List queryList(PublicFamily bo) { + LambdaEsQueryWrapper lqw = buildQueryWrapper(bo,new PageQuery()); + return esMapper.selectList(lqw); + } + + private LambdaEsQueryWrapper buildQueryWrapper(PublicFamily bo,PageQuery query) { + LambdaEsQueryWrapper lqw = EsWrappers.lambdaQuery(PublicFamily.class); + + if(StrUtil.isNotBlank(query.getOrderByColumn())){ + if(query.getOrderByColumn().contains("amount") || query.getOrderByColumn().contains("balance") + || query.getOrderByColumn().contains("time") || query.getOrderByColumn().contains("Time") || query.getOrderByColumn().contains("Amount")){ + lqw.orderBy(true, "asc".equalsIgnoreCase(query.getIsAsc()), query.getOrderByColumn()); + }else { + lqw.orderBy(true, "asc".equalsIgnoreCase(query.getIsAsc()), query.getOrderByColumn()+".keyword"); + } + }else { + lqw.orderByDesc("id"); + } + Map params = bo.getParams(); + + lqw.like(StringUtils.isNotBlank(bo.getEnterpriseName()), PublicFamily::getEnterpriseName, bo.getEnterpriseName()); + lqw.like(StringUtils.isNotBlank(bo.getName()), PublicFamily::getName, bo.getName()); + lqw.eq(StringUtils.isNotBlank(bo.getIdCard()), PublicFamily::getIdCard, bo.getIdCard()); + lqw.eq(StringUtils.isNotBlank(bo.getDeptPost()), PublicFamily::getDeptPost, bo.getDeptPost()); + lqw.like(StringUtils.isNotBlank(bo.getMemberName1()), PublicFamily::getMemberName1, bo.getMemberName1()); + lqw.like(StringUtils.isNotBlank(bo.getMemberRelation1()), PublicFamily::getMemberRelation1, bo.getMemberRelation1()); + lqw.eq(StringUtils.isNotBlank(bo.getMemberIdCard1()), PublicFamily::getMemberIdCard1, bo.getMemberIdCard1()); + lqw.like(StringUtils.isNotBlank(bo.getMemberName2()), PublicFamily::getMemberName2, bo.getMemberName2()); + lqw.like(StringUtils.isNotBlank(bo.getMemberRelation2()), PublicFamily::getMemberRelation2, bo.getMemberRelation2()); + lqw.eq(StringUtils.isNotBlank(bo.getMemberIdCard2()), PublicFamily::getMemberIdCard2, bo.getMemberIdCard2()); + lqw.like(StringUtils.isNotBlank(bo.getMemberName3()), PublicFamily::getMemberName3, bo.getMemberName3()); + lqw.like(StringUtils.isNotBlank(bo.getMemberRelation3()), PublicFamily::getMemberRelation3, bo.getMemberRelation3()); + lqw.eq(StringUtils.isNotBlank(bo.getMemberIdCard3()), PublicFamily::getMemberIdCard3, bo.getMemberIdCard3()); + lqw.like(StringUtils.isNotBlank(bo.getMemberName4()), PublicFamily::getMemberName4, bo.getMemberName4()); + lqw.like(StringUtils.isNotBlank(bo.getMemberRelation4()), PublicFamily::getMemberRelation4, bo.getMemberRelation4()); + lqw.eq(StringUtils.isNotBlank(bo.getMemberIdCard4()), PublicFamily::getMemberIdCard4, bo.getMemberIdCard4()); + if(StrUtil.isNotEmpty(bo.getAnalysisResultId())){ + lqw.eq(PublicFamily::getAnalysisResultId, bo.getAnalysisResultId()); + }else { + // 案件Id + lqw.eq(StrUtil.isNotEmpty(bo.getCaseId()), PublicFamily::getCaseId, bo.getCaseId()); + } + lqw.like(StringUtils.isNotBlank(bo.getBgc()), PublicFamily::getBgc, bo.getBgc()); + lqw.in(CollectionUtil.isNotEmpty(bo.getIds()), PublicFamily::getId, bo.getIds()); + + lqw.like(StringUtils.isNotBlank(bo.getRemark()), PublicFamily::getRemark, bo.getRemark()); + + if(StrUtil.isNotBlank(bo.getSearchValue())){ + lqw.queryStringQuery("*"+bo.getSearchValue().trim().replaceAll("([ ]|\\s|\\u00A0)+","")+"*"); + } + return lqw; + } + + /** + * 新增数据中心-职工家属 + */ + @Override + public Boolean insertByBo(PublicFamily bo) { + PublicFamily add = BeanUtil.toBean(bo, PublicFamily.class); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + esMapper.insert(add); + } + return flag; + } + + /** + * 修改数据中心-职工家属 + */ + @Override + @Transactional + public Boolean updateByBo(PublicFamily bo) { + PublicFamily update = BeanUtil.toBean(bo, PublicFamily.class); + boolean b = baseMapper.updateById(update) > 0; + if(b){ + esMapper.updateById(update); + } + return b; + } + + /** + * 批量删除数据中心-职工家属 + */ + @Override + @Transactional + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + baseMapper.deleteBatchIds(ids); + esMapper.deleteBatchIds(ids); + return true; + } + + @Override + @Transactional + public boolean importData(List importList, String caseId, String analysisResultId) { + + Set idCards = importList.stream().filter(item -> StrUtil.isNotEmpty(item.getIdCard())).map(PublicFamily::getIdCard).collect(Collectors.toSet()); + LambdaEsQueryWrapper wrapper = EsWrappers.lambdaQuery(PublicFamily.class); + wrapper.eq(StrUtil.isNotEmpty(caseId),PublicFamily::getCaseId, caseId); + wrapper.in(PublicFamily::getIdCard, idCards); + + List dbList = esMapper.selectList(wrapper); + List addList = new ArrayList<>(); + List updateList = new ArrayList<>(); + + if(CollectionUtil.isNotEmpty(dbList)){ + Map map = new HashMap<>(); + for (PublicFamily publicFamily : dbList) { + String _uniqueKey = publicFamily.getEnterpriseName() + publicFamily.getName() + publicFamily.getIdCard(); + map.put(_uniqueKey,publicFamily); + } + + for (PublicFamily importObj : importList) { + String uniqueKey = importObj.getEnterpriseName() + importObj.getName() + importObj.getIdCard(); + if(map.containsKey(uniqueKey)){ + importObj.setId(null); + PublicFamily update = BeanUtils.mergeObjects(map.get(uniqueKey), importObj); + updateList.add(update); + }else { + addList.add(importObj); + } + } + }else { + addList.addAll(importList); + } + if (CollectionUtil.isNotEmpty(addList)) { + //根据id取es查询 返回的就是重复数据 + Map groupById = addList.stream().collect(Collectors.toMap(PublicFamily::getId, Function.identity())); + Set idSet = groupById.keySet(); + List esExistIdList; + if(StrUtil.isNotEmpty(caseId)){ + esExistIdList = HelperUtil.searchId(esMapper, PublicFamily.class, idSet,"caseId", caseId); + }else { + esExistIdList = HelperUtil.searchId(esMapper, PublicFamily.class, idSet,"analysisResultId", analysisResultId); + } + if(CollectionUtil.isEmpty(esExistIdList)){ + esMapper.insertBatch(addList); + }else { + Set esIdSet = esExistIdList.stream().filter(item -> StrUtil.isNotEmpty(item.getId())).map(PublicFamily::getId).collect(Collectors.toSet()); + idSet.removeAll(esIdSet); + if(CollectionUtil.isNotEmpty(idSet)){ + List saveLis = new ArrayList<>(); + for (String id : idSet) { + saveLis.add(groupById.get(id)); + } + esMapper.insertBatch(saveLis); + } + } + } + if (CollectionUtil.isNotEmpty(updateList)) { + this.updateBatch(updateList); + } + return true; + } + + @Override + @Transactional + public boolean updateBatch(List list) { + esMapper.updateBatchByIds(list); +// PublicFamilyServiceImpl serviceImpl = getStockServiceImpl(); +// list.stream().forEach(update->{ +// serviceImpl.updateR(update); +// }); + return true; + } + + @UpdateLog(title = "职工家属",mapperClass = PublicFamilyMapper.class) + public boolean updateR(PublicFamily update) { +// boolean b = baseMapper.updateById(update) > 0; +// if(b){ + boolean b = esMapper.updateById(update) >0; +// } + return b; + } + + private PublicFamilyServiceImpl getStockServiceImpl() { + return AopContext.currentProxy() != null ? (PublicFamilyServiceImpl) AopContext.currentProxy() : this; + } + + @Override + public TableDataInfo highlightList(PublicFamily bo, PageQuery pageQuery) { + TableDataInfo dataInfo = this.queryPageList(bo, pageQuery); + List rows = dataInfo.getRows(); + for (PublicFamily row : rows) { + QueryCenterService.setHighlightValue(PublicFamily.class,row,bo.getSearchValue()); + } + return dataInfo; + } + + @Override + public List dataTrimAndDeduplication(List list, String caseId, String createBy) { + Set uniqueKeySet = new HashSet(); + List result = new ArrayList<>(); + for (PublicFamily family : list) { + try { + BeanUtils.beanAttributeValueTrim(family); + } catch (Exception e) { + e.printStackTrace(); + } + family.setCaseId(caseId); + String md5Id = HelperUtil.generateMD5(family.toString()); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + family.setId(md5Id); + family.setCreateBy(createBy); + family.setCreateTime(new Date()); + result.add(family); + } + + return result; + } + + + @Override + public Boolean importAnalysisResult(List list, String analysisResultId, String username) { + Set uniqueKeySet = new HashSet(); + List result = new ArrayList<>(); + for (PublicFamily tp : list) { + BeanUtils.beanAttributeValueTrim(tp); + String uniqueKey = BeanUtils.getUniqueKey(tp); + String md5Id = HelperUtil.generateMD5(analysisResultId+uniqueKey); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + tp.setAnalysisResultId(analysisResultId); + tp.setId(md5Id); +// bs.setCreateBy(username); + tp.setCreateTime(new Date()); + result.add(tp); + } + + if (CollectionUtil.isNotEmpty(result)) { + //根据id取es查询 返回的就是重复数据 + PublicFamily req = new PublicFamily(); + req.setAnalysisResultId(analysisResultId); + //分析成果数据应该不会太多,太多就需要重写逻辑,不然这一步可能会内存溢出 + List esExistIdList = queryList(req); + if(CollectionUtil.isEmpty(esExistIdList)){ + esMapper.insertBatch(result); + }else { + //重新计算md5 + Map groupByUniqueKeyMap = new HashMap<>(); + for (PublicFamily bs : esExistIdList) { + BeanUtils.beanAttributeValueTrim(bs); + String uniqueKey = BeanUtils.getUniqueKey(bs); + String md5Id = HelperUtil.generateMD5(analysisResultId+uniqueKey); + groupByUniqueKeyMap.put(md5Id,bs); + } + + List saveList = new ArrayList<>(); + for (PublicFamily tp : result) { + if(groupByUniqueKeyMap.containsKey(tp.getId())){ + continue; + } + saveList.add(tp); + } + esMapper.insertBatch(saveList); + } + } + + return true; + } + + @Override + public SearchSourceBuilder getSearchSourceBuilder(PublicFamily family) { + LambdaEsQueryWrapper wrapper = buildQueryWrapper(family,new PageQuery()); + return esMapper.getSearchSourceBuilder(wrapper); + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/RealEstateServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/RealEstateServiceImpl.java new file mode 100644 index 0000000..aa469c8 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/RealEstateServiceImpl.java @@ -0,0 +1,405 @@ +package com.inscloudtech.datacenter.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.common.annotation.UpdateLog; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.datacenter.domain.*; +import com.inscloudtech.datacenter.domain.RealEstate; +import com.inscloudtech.datacenter.domain.RealEstate; +import com.inscloudtech.datacenter.mapper.RealEstateMapper; +import com.inscloudtech.datacenter.mapper.es.RealEstateEsMapper; +import com.inscloudtech.datacenter.service.IRealEstateService; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.easyes.core.biz.SAPageInfo; +import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper; +import org.dromara.easyes.core.core.EsWrappers; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.springframework.aop.framework.AopContext; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 重点人员资产-不动产信息Service业务层处理 + * + * @author inscloudtech + * @date 2023-11-09 + */ +@RequiredArgsConstructor +@Service +public class RealEstateServiceImpl implements IRealEstateService { + + private final RealEstateMapper baseMapper; + + private final RealEstateEsMapper esMapper; + + @Override + public void analysisResultMerge(Map sourceArIdTargetArIdMap) { + List analysisReportList = baseMapper.selectList(new LambdaQueryWrapper() + .in(RealEstate::getAnalysisResultId,sourceArIdTargetArIdMap.keySet())); + Map> arMap = analysisReportList.stream().collect(Collectors.groupingBy(RealEstate::getAnalysisResultId)); + List addList = new ArrayList<>(); + for (Map.Entry > entry : arMap.entrySet()) { + String sourceArId = entry.getKey(); + List reports = entry.getValue(); + String targetArId = sourceArIdTargetArIdMap.get(sourceArId); + for (RealEstate result : reports) { + result.setAnalysisResultId(targetArId); + String md5Id = HelperUtil.generateMD5(result.toString()); + result.setId(md5Id); + addList.add(result); + } + } + if(CollectionUtil.isNotEmpty(addList)){ + baseMapper.insertBatch(addList); + } + } + + @Override + public Boolean caseMerge(String sourceCaseId,String targetCaseId) { + RealEstate bo = new RealEstate(); + bo.setCaseId(sourceCaseId); + List transactionPartners = this.queryList(bo); + transactionPartners = dataTrimAndDeduplication(transactionPartners, targetCaseId, ""); + return this.importData(transactionPartners,targetCaseId,null); + } + + /** + * 复制出新的caseId为null的数,重新计算MD5 + * @param dto + */ + @Override + public void save2AnalysisResult(AnalysisDto dto) { + Set ids = dto.getIds(); + if (ids.isEmpty()) { + return; + } + String analysisResultId = dto.getAnalysisResultId(); + List realEstates = esMapper.selectBatchIds(ids); + Set uniqueKeySet = new HashSet(); + List result = new ArrayList<>(); + for (RealEstate item : realEstates) { + item.setCaseId(null); + item.setAnalysisResultId(analysisResultId); + String md5Id = HelperUtil.generateMD5(item.toString()); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + item.setId(md5Id); + result.add(item); + } + uniqueKeySet.clear(); + this.importData(result,null,analysisResultId); + } + + + /** + * 查询重点人员资产-不动产信息 + */ + @Override + public RealEstate queryById(String id){ + return esMapper.selectById(id); + } + + /** + * 查询重点人员资产-不动产信息列表 + */ + @Override + public TableDataInfo queryPageList(RealEstate bo, PageQuery pageQuery) { + return esPage(bo,pageQuery); + } + + public TableDataInfo esPage(RealEstate bo, PageQuery query){ + LambdaEsQueryWrapper wrapper = buildQueryWrapper(bo,query); + wrapper.size(query.getPageSize()); + SAPageInfo pageInfo; + if(query.getPageNum() == 1){ + pageInfo = esMapper.searchAfterPage(wrapper, null, query.getPageSize()); + }else{ + pageInfo = esMapper.searchAfterPage(wrapper, null, (query.getPageNum() - 1) * query.getPageSize()); + pageInfo = esMapper.searchAfterPage(wrapper, pageInfo.getNextSearchAfter(), query.getPageSize()); + } + TableDataInfo tableDataInfo = new TableDataInfo(); + tableDataInfo.setTotal(pageInfo.getTotal()); + tableDataInfo.setRows(pageInfo.getList()); + return tableDataInfo; + } + + /** + * 查询重点人员资产-不动产信息列表 + */ + @Override + public List queryList(RealEstate bo) { + LambdaEsQueryWrapper lqw = buildQueryWrapper(bo,new PageQuery()); + return esMapper.selectList(lqw); + } + + private LambdaEsQueryWrapper buildQueryWrapper(RealEstate bo,PageQuery query) { + + Map params = bo.getParams(); + LambdaEsQueryWrapper lqw = EsWrappers.lambdaQuery(RealEstate.class); + + if(StrUtil.isNotBlank(query.getOrderByColumn())){ + lqw.orderBy(StrUtil.isNotBlank(query.getOrderByColumn()),"asc".equals(query.getIsAsc()),query.getOrderByColumn()); + }else { + lqw.orderByDesc("id"); + } + if(StrUtil.isNotEmpty(bo.getAnalysisResultId())){ + lqw.eq(RealEstate::getAnalysisResultId, bo.getAnalysisResultId()); + }else { + // 案件Id + lqw.eq(StrUtil.isNotEmpty(bo.getCaseId()), RealEstate::getCaseId, bo.getCaseId()); + } + + lqw.like(StringUtils.isNotBlank(bo.getName()), RealEstate::getName, bo.getName()); + lqw.like(StringUtils.isNotBlank(bo.getAddress()), RealEstate::getAddress, bo.getAddress()); + + + Object bdObj = params.get("beginArea"); + Object edObj = params.get("endArea"); + if(bdObj != null && edObj ==null){ + BigDecimal startBta = new BigDecimal(bdObj.toString()); + lqw.and(w ->w.ge(RealEstate::getArea,startBta).or().le(RealEstate::getArea,startBta.negate())); + }else if(bdObj == null && edObj != null){ + BigDecimal endBta = new BigDecimal(edObj.toString()); + lqw.between(RealEstate::getArea ,endBta.negate(), endBta); + }else if(bdObj != null && edObj != null){ + lqw.between(RealEstate::getArea ,bdObj, edObj); + } + + Object bvObj = params.get("beginValuation"); + Object evObj = params.get("endValuation"); + if(bvObj != null && evObj ==null){ + BigDecimal startBta = new BigDecimal(bvObj.toString()); + lqw.and(w ->w.ge(RealEstate::getValuation,startBta).or().le(RealEstate::getValuation,startBta.negate())); + }else if(bvObj == null && evObj != null){ + BigDecimal endBta = new BigDecimal(evObj.toString()); + lqw.between(RealEstate::getValuation ,endBta.negate(), endBta); + }else if(bvObj != null && evObj != null){ + lqw.between(RealEstate::getValuation ,bvObj, evObj); + } + + lqw.like(StringUtils.isNotBlank(bo.getTransferInformation()), RealEstate::getTransferInformation, bo.getTransferInformation()); + lqw.like(StringUtils.isNotBlank(bo.getOtherInformation()), RealEstate::getOtherInformation, bo.getOtherInformation()); + lqw.like(StringUtils.isNotBlank(bo.getRemark()), RealEstate::getRemark, bo.getRemark()); + lqw.eq(StringUtils.isNotBlank(bo.getBgc()), RealEstate::getBgc, bo.getBgc()); + + + if(StrUtil.isNotBlank(bo.getSearchValue())){ + lqw.queryStringQuery("*"+bo.getSearchValue().trim().replaceAll("([ ]|\\s|\\u00A0)+","")+"*"); + } + return lqw; + } + /** + * 新增重点人员资产-不动产信息 + */ + @Override + public Boolean insertByBo(RealEstate bo) { + boolean flag = baseMapper.insert(bo) > 0; + if (flag) { + esMapper.insert(bo); + } + return flag; + } + + /** + * 修改重点人员资产-不动产信息 + */ + @Override + public Boolean updateByBo(RealEstate bo) { + boolean b = baseMapper.updateById(bo) > 0; + if(b){ + esMapper.updateById(bo); + } + return b; + } + + + /** + * 批量删除重点人员资产-不动产信息 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + baseMapper.deleteBatchIds(ids); + esMapper.deleteBatchIds(ids); + return true; + } + + @Override + public Boolean importData(List importList,String caseId,String analysisResultId) { + Set names = importList.stream().filter(item -> StrUtil.isNotEmpty(item.getName())).map(RealEstate::getName).collect(Collectors.toSet()); + LambdaEsQueryWrapper wrapper = EsWrappers.lambdaQuery(RealEstate.class); + wrapper.eq(StrUtil.isNotEmpty(caseId),RealEstate::getCaseId, caseId); + wrapper.eq(StrUtil.isNotEmpty(analysisResultId),RealEstate::getAnalysisResultId, analysisResultId); + wrapper.in(RealEstate::getName, names); + + //准备更新数据 + List dbList = esMapper.selectList(wrapper); + List addList = new ArrayList<>(); + List updateList = new ArrayList<>(); + + if(CollectionUtil.isNotEmpty(dbList)){ + Map map = new HashMap<>(); + for (RealEstate publicFamily : dbList) { + String _uniqueKey = publicFamily.getName() + publicFamily.getAddress() ; + map.put(_uniqueKey,publicFamily); + } + + for (RealEstate importObj : importList) { + String uniqueKey = importObj.getName() + importObj.getAddress(); + if(map.containsKey(uniqueKey)){ + importObj.setId(null); + RealEstate update = BeanUtils.mergeObjects(map.get(uniqueKey), importObj); + updateList.add(update); + }else { + addList.add(importObj); + } + } + }else { + addList.addAll(importList); + } + if (CollectionUtil.isNotEmpty(addList)) { + //根据id取es查询 返回的就是重复数据 + Map groupById = addList.stream().collect(Collectors.toMap(RealEstate::getId, Function.identity())); + Set idSet = groupById.keySet(); + List esExistIdList = new ArrayList<>(); + if(StrUtil.isNotEmpty(caseId)){ + esExistIdList = HelperUtil.searchId(esMapper, RealEstate.class, idSet,"caseId", caseId); + }else { + esExistIdList = HelperUtil.searchId(esMapper, RealEstate.class, idSet,"analysisResultId", analysisResultId); + } + if(CollectionUtil.isEmpty(esExistIdList)){ + esMapper.insertBatch(addList); + }else { + Set esIdSet = esExistIdList.stream().map(RealEstate::getId).collect(Collectors.toSet()); + idSet.removeAll(esIdSet); + if(CollectionUtil.isNotEmpty(idSet)){ + List saveLis = new ArrayList<>(); + for (String id : idSet) { + saveLis.add(groupById.get(id)); + } + esMapper.insertBatch(saveLis); + } + } + } + if (CollectionUtil.isNotEmpty(updateList)) { + this.updateBatch(updateList); + } + return true; + } + + @Override + public Boolean updateBatch(List list) { + RealEstateServiceImpl partnerService = getServiceImpl(); + list.stream().forEach(update->{ + partnerService.updateR(update); + }); + esMapper.updateBatchByIds(list); + return true; + } + + @UpdateLog(title = "不动产信息",mapperClass = RealEstateMapper.class) + public boolean updateR(RealEstate update) { + return baseMapper.updateById(update) > 0; + } + + private RealEstateServiceImpl getServiceImpl() { + return AopContext.currentProxy() != null ? (RealEstateServiceImpl) AopContext.currentProxy() : this; + } + + @Override + public Boolean importAnalysisResult(List list, String analysisResultId, String username) { + Set uniqueKeySet = new HashSet(); + List result = new ArrayList<>(); + for (RealEstate tp : list) { + BeanUtils.beanAttributeValueTrim(tp); + String uniqueKey = BeanUtils.getUniqueKey(tp); + String md5Id = HelperUtil.generateMD5(analysisResultId+uniqueKey); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + tp.setAnalysisResultId(analysisResultId); + tp.setId(md5Id); +// bs.setCreateBy(username); + tp.setCreateTime(new Date()); + result.add(tp); + } + + if (CollectionUtil.isNotEmpty(result)) { + //根据id取es查询 返回的就是重复数据 + RealEstate req = new RealEstate(); + req.setAnalysisResultId(analysisResultId); + //分析成果数据应该不会太多,太多就需要重写逻辑,不然这一步可能会内存溢出 + List esExistIdList = queryList(req); + if(CollectionUtil.isEmpty(esExistIdList)){ + esMapper.insertBatch(result); + }else { + //重新计算md5 + Map groupByUniqueKeyMap = new HashMap<>(); + for (RealEstate bs : esExistIdList) { + BeanUtils.beanAttributeValueTrim(bs); + String uniqueKey = BeanUtils.getUniqueKey(bs); + String md5Id = HelperUtil.generateMD5(analysisResultId+uniqueKey); + groupByUniqueKeyMap.put(md5Id,bs); + } + + List saveList = new ArrayList<>(); + for (RealEstate tp : result) { + if(groupByUniqueKeyMap.containsKey(tp.getId())){ + continue; + } + saveList.add(tp); + } + esMapper.insertBatch(saveList); + } + } + + return true; + } + + @Override + public SearchSourceBuilder getSearchSourceBuilder(RealEstate realEstate) { + LambdaEsQueryWrapper wrapper = buildQueryWrapper(realEstate,new PageQuery()); + return esMapper.getSearchSourceBuilder(wrapper); + } + + + @Override + public List dataTrimAndDeduplication(List list, String caseId, String createBy) { + Set uniqueKeySet = new HashSet(); + List result = new ArrayList<>(); + for (RealEstate family : list) { + try { + BeanUtils.beanAttributeValueTrim(family); + } catch (Exception e) { + e.printStackTrace(); + } + family.setCaseId(caseId); + String md5Id = HelperUtil.generateMD5(family.toString()); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + family.setId(md5Id); + family.setCreateBy(createBy); + family.setCreateTime(new Date()); + result.add(family); + } + + return result; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/TransactionPartnerServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/TransactionPartnerServiceImpl.java new file mode 100644 index 0000000..bc27c7a --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/datacenter/service/impl/TransactionPartnerServiceImpl.java @@ -0,0 +1,423 @@ +package com.inscloudtech.datacenter.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.common.annotation.UpdateLog; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.utils.bean.BeanUtils; +import com.inscloudtech.datacenter.domain.TransactionPartner; +import com.inscloudtech.datacenter.mapper.TransactionPartnerMapper; +import com.inscloudtech.datacenter.mapper.es.TransactionPartnerEsMapper; +import com.inscloudtech.datacenter.service.ITransactionPartnerService; +import com.inscloudtech.datacenter.service.QueryCenterService; +import lombok.RequiredArgsConstructor; +import org.dromara.easyes.core.biz.SAPageInfo; +import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper; +import org.dromara.easyes.core.core.EsWrappers; +import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.springframework.aop.framework.AopContext; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + + +/** + * 数据中心-交易对象Service业务层处理 + * + * @author lingyun + * @date 2023-11-07 + */ +@RequiredArgsConstructor +@Service +public class TransactionPartnerServiceImpl implements ITransactionPartnerService { + + private final TransactionPartnerMapper baseMapper; + + private final TransactionPartnerEsMapper esMapper; + + @Override + public void analysisResultMerge(Map sourceArIdTargetArIdMap) { + List analysisReportList = baseMapper.selectList(new LambdaQueryWrapper() + .in(TransactionPartner::getAnalysisResultId,sourceArIdTargetArIdMap.keySet())); + Map> arMap = analysisReportList.stream().collect(Collectors.groupingBy(TransactionPartner::getAnalysisResultId)); + List addList = new ArrayList<>(); + for (Map.Entry > entry : arMap.entrySet()) { + String sourceArId = entry.getKey(); + List reports = entry.getValue(); + String targetArId = sourceArIdTargetArIdMap.get(sourceArId); + for (TransactionPartner result : reports) { + result.setAnalysisResultId(targetArId); + String md5Id = HelperUtil.generateMD5(result.toString()); + result.setId(md5Id); + addList.add(result); + } + } + if(CollectionUtil.isNotEmpty(addList)){ + baseMapper.insertBatch(addList); + } + } + + //按每3个一组分割 + private static final Integer MAX_SEND = 100; + + @Override + public Boolean caseMerge(String sourceCaseId,String targetCaseId) { + TransactionPartner bo = new TransactionPartner(); + bo.setCaseId(sourceCaseId); + List transactionPartners = this.queryList(bo); + transactionPartners = dataTrimAndDeduplication(transactionPartners, targetCaseId, ""); + return this.importData(transactionPartners,targetCaseId,null); + } + + /** + * 复制出新的caseId为null的数,重新计算MD5 + * @param dto + */ + @Override + public void save2AnalysisResult(AnalysisDto dto) { + Set ids = dto.getIds(); + if (ids.isEmpty()) { + return; + } + String analysisResultId = dto.getAnalysisResultId(); + List transactionPartners = esMapper.selectBatchIds(ids); + Set uniqueKeySet = new HashSet(); + List result = new ArrayList<>(); + for (TransactionPartner item : transactionPartners) { + item.setCaseId(null); + item.setAnalysisResultId(analysisResultId); + String md5Id = HelperUtil.generateMD5(item.toString()); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + item.setId(md5Id); + result.add(item); + } + uniqueKeySet.clear(); + this.importData(result,null,analysisResultId); + } + + @Override + public TransactionPartner queryById(String id) { + return esMapper.selectById(id); + } + + @Override + public TableDataInfo queryPageList(TransactionPartner bo, PageQuery pageQuery) { + return this.esPage(bo, pageQuery); + } + + public TableDataInfo esPage(TransactionPartner bo, PageQuery query) { + LambdaEsQueryWrapper wrapper = buildEsQueryWrapper(bo,query); + wrapper.size(query.getPageSize()); + SAPageInfo pageInfo; + if (query.getPageNum() == 1) { + pageInfo = esMapper.searchAfterPage(wrapper, null, query.getPageSize()); + } else { + pageInfo = esMapper.searchAfterPage(wrapper, null, (query.getPageNum() - 1) * query.getPageSize()); + pageInfo = esMapper.searchAfterPage(wrapper, pageInfo.getNextSearchAfter(), query.getPageSize()); + } + + TableDataInfo tableDataInfo = new TableDataInfo<>(); + tableDataInfo.setTotal(pageInfo.getTotal()); + tableDataInfo.setRows(pageInfo.getList()); + return tableDataInfo; + } + + + private LambdaEsQueryWrapper buildEsQueryWrapper(TransactionPartner bo,PageQuery query) { + LambdaEsQueryWrapper wrapper = EsWrappers.lambdaQuery(TransactionPartner.class); + + if (StrUtil.isNotBlank(query.getOrderByColumn())) { + wrapper.orderBy( + StrUtil.isNotBlank(query.getOrderByColumn()), + "asc".equals(query.getIsAsc()), + query.getOrderByColumn()); + } else { + wrapper.orderByDesc("id"); + } + + Map params = bo.getParams(); + + if(StrUtil.isNotEmpty(bo.getAnalysisResultId())){ + wrapper.eq(TransactionPartner::getAnalysisResultId, bo.getAnalysisResultId()); + }else { + // 案件Id + wrapper.eq(StrUtil.isNotEmpty(bo.getCaseId()), TransactionPartner::getCaseId, bo.getCaseId()); + } + + wrapper.like(StrUtil.isNotBlank(bo.getStockholderRelated()), TransactionPartner::getStockholderRelated, bo.getStockholderRelated()); + wrapper.like(StrUtil.isNotBlank(bo.getStockholder()), TransactionPartner::getStockholder, bo.getStockholder()); + wrapper.eq( + StrUtil.isNotBlank(bo.getTravellingTrader()), + TransactionPartner::getTravellingTrader, + bo.getTravellingTrader()); + wrapper.like( + StrUtil.isNotBlank(bo.getOrganizationCode()), + TransactionPartner::getOrganizationCode, + bo.getOrganizationCode()); + wrapper.like( + StrUtil.isNotBlank(bo.getRegisteredAddress()), + TransactionPartner::getRegisteredAddress, + bo.getRegisteredAddress()); + wrapper.like( + StrUtil.isNotBlank(bo.getRelateCompany()), TransactionPartner::getRelateCompany, bo.getRelateCompany()); + wrapper.like(StrUtil.isNotBlank(bo.getRemark()), TransactionPartner::getRemark, bo.getRemark()); + wrapper.in(CollectionUtil.isNotEmpty(bo.getIds()), TransactionPartner::getId, bo.getIds()); + + Object btaObj = params.get("beginTransactionAmount"); + Object etaObj = params.get("endTransactionAmount"); + if(btaObj != null && etaObj ==null){ + BigDecimal startBta = new BigDecimal(btaObj.toString()); + wrapper.and(w ->w.ge(TransactionPartner::getTransactionAmount,startBta).or().le(TransactionPartner::getTransactionAmount,startBta.negate())); + }else if(btaObj == null && etaObj != null){ + BigDecimal endBta = new BigDecimal(etaObj.toString()); + wrapper.between(TransactionPartner::getTransactionAmount ,endBta.negate(), endBta); + }else if(btaObj != null && etaObj != null){ + wrapper.between(TransactionPartner::getTransactionAmount ,btaObj, etaObj); + } + + Object bdObj = params.get("beginDebt"); + Object edObj = params.get("endDebt"); + if(bdObj != null && edObj ==null){ + BigDecimal startBta = new BigDecimal(edObj.toString()); + wrapper.and(w ->w.ge(TransactionPartner::getDebt,startBta).or().le(TransactionPartner::getDebt,startBta.negate())); + }else if(bdObj == null && edObj != null){ + BigDecimal endBta = new BigDecimal(edObj.toString()); + wrapper.between(TransactionPartner::getTransactionAmount ,endBta.negate(), endBta); + }else if(bdObj != null && edObj != null){ + wrapper.between(TransactionPartner::getTransactionAmount ,bdObj, edObj); + } + if(StrUtil.isNotBlank(bo.getSearchValue())){ + wrapper.queryStringQuery("*"+bo.getSearchValue().trim().replaceAll("([ ]|\\s|\\u00A0)+","")+"*"); + } + + return wrapper; + } + + @Override + public List queryList(TransactionPartner bo) { + // LambdaQueryWrapper lqw = buildQueryWrapper(bo); + LambdaEsQueryWrapper wrapper = buildEsQueryWrapper(bo,new PageQuery()); + return esMapper.selectList(wrapper); + } + + @Override + public Boolean insert(TransactionPartner add) { + boolean b = baseMapper.insert(add) > 0; + if (b) { + esMapper.insert(add); + } + return b; + } + + @Override + public Boolean update(TransactionPartner update) { + boolean b = baseMapper.updateById(update) > 0; + if (b) { + esMapper.updateById(update); + } + return b; + } + + @Override + public Boolean deleteWithValidByIds(Collection ids) { + baseMapper.deleteBatchIds(ids); + esMapper.deleteBatchIds(ids); + return true; + } + + @Override + public Boolean importData(List importList, String caseId, String analysisResultId) { + Set companyNameSet = importList.stream().filter(item ->StrUtil.isNotEmpty(item.getTravellingTrader())).map(TransactionPartner::getTravellingTrader).collect(Collectors.toSet()); +//计算切分次数 + int limit = (companyNameSet.size() + MAX_SEND - 1) / MAX_SEND; + List> companyNameList = new ArrayList<>(); + Stream.iterate(0, n -> n + 1).limit(limit).forEach(i -> { + companyNameList.add(companyNameSet.stream().skip(i * MAX_SEND).limit(MAX_SEND).collect(Collectors.toList())); + }); + + List dbList = new ArrayList<>(); + for (List companyNames : companyNameList) { + LambdaEsQueryWrapper wrapper = EsWrappers.lambdaQuery(TransactionPartner.class); + wrapper.eq(StrUtil.isNotEmpty(caseId),TransactionPartner::getCaseId, caseId); + wrapper.eq(StrUtil.isNotEmpty(analysisResultId),TransactionPartner::getAnalysisResultId, analysisResultId); + wrapper.in(TransactionPartner::getTravellingTrader, companyNames); + dbList.addAll(esMapper.selectList(wrapper)); + } + + List addList = new ArrayList<>(); + List updateList = new ArrayList<>(); + + if(CollectionUtil.isNotEmpty(dbList)){ + Map map = new HashMap<>(); + for (TransactionPartner tp : dbList) { + String _uniqueKey = tp.getTravellingTrader(); + map.put(_uniqueKey,tp); + } + + for (TransactionPartner importObj : importList) { + String uniqueKey = importObj.getTravellingTrader(); + if(map.containsKey(uniqueKey)){ + importObj.setId(null); + TransactionPartner update = BeanUtils.mergeObjects(map.get(uniqueKey), importObj); + updateList.add(update); + }else { + addList.add(importObj); + } + } + }else { + addList.addAll(importList); + } + if (CollectionUtil.isNotEmpty(addList)) { + //根据id取es查询 返回的就是重复数据 + Map groupById = addList.stream().collect(Collectors.toMap(TransactionPartner::getId, Function.identity())); + Set idSet = groupById.keySet(); + List esExistIdList = new ArrayList<>(); + if(StrUtil.isNotEmpty(caseId)){ + esExistIdList = HelperUtil.searchId(esMapper, TransactionPartner.class, idSet,"caseId", caseId); + }else { + esExistIdList = HelperUtil.searchId(esMapper, TransactionPartner.class, idSet,"analysisResultId", analysisResultId); + } + if(CollectionUtil.isEmpty(esExistIdList)){ + esMapper.insertBatch(addList); + }else { + Set esIdSet = esExistIdList.stream().map(TransactionPartner::getId).collect(Collectors.toSet()); + idSet.removeAll(esIdSet); + if(CollectionUtil.isNotEmpty(idSet)){ + List saveLis = new ArrayList<>(); + for (String id : idSet) { + saveLis.add(groupById.get(id)); + } + esMapper.insertBatch(saveLis); + } + } + } + if (CollectionUtil.isNotEmpty(updateList)) { + this.updateBatch(updateList); + } + return true; + } + + @Override + public Boolean updateBatch(List list) { +// TransactionPartnerServiceImpl partnerService = getStockServiceImpl(); +// list.stream().forEach(update -> { +// partnerService.updateR(update); +// }); + esMapper.updateBatchByIds(list); + return true; + } + + @Override + public TableDataInfo highlightList(TransactionPartner bo, PageQuery pageQuery) { + TableDataInfo dataInfo = this.queryPageList(bo, pageQuery); + List rows = dataInfo.getRows(); + for (TransactionPartner row : rows) { + QueryCenterService.setHighlightValue(TransactionPartner.class,row,bo.getSearchValue()); + } + return dataInfo; + } + + @Override + public List dataTrimAndDeduplication(List list, String caseId, String createBy) { + Set uniqueKeySet = new HashSet(); + List result = new ArrayList<>(); + for (TransactionPartner family : list) { + try { + BeanUtils.beanAttributeValueTrim(family); + } catch (Exception e) { + e.printStackTrace(); + } + family.setCaseId(caseId); + String md5Id = HelperUtil.generateMD5(family.toString()); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + family.setId(md5Id); + family.setCreateBy(createBy); + family.setCreateTime(new Date()); + result.add(family); + } + + return result; + } + + @UpdateLog(title = "交易对象",mapperClass = TransactionPartnerMapper.class) + public boolean updateR(TransactionPartner update) { + boolean b = baseMapper.updateById(update) > 0; + return b; + } + + private TransactionPartnerServiceImpl getStockServiceImpl() { + return AopContext.currentProxy() != null ? (TransactionPartnerServiceImpl) AopContext.currentProxy() : this; + } + + @Override + public Boolean importAnalysisResult(List list, String analysisResultId, String username) { + Set uniqueKeySet = new HashSet(); + List result = new ArrayList<>(); + for (TransactionPartner tp : list) { + BeanUtils.beanAttributeValueTrim(tp); + String uniqueKey = BeanUtils.getUniqueKey(tp); + String md5Id = HelperUtil.generateMD5(analysisResultId+uniqueKey); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + tp.setAnalysisResultId(analysisResultId); + tp.setId(md5Id); +// bs.setCreateBy(username); + tp.setCreateTime(new Date()); + result.add(tp); + } + + if (CollectionUtil.isNotEmpty(result)) { + //根据id取es查询 返回的就是重复数据 + TransactionPartner req = new TransactionPartner(); + req.setAnalysisResultId(analysisResultId); + //分析成果数据应该不会太多,太多就需要重写逻辑,不然这一步可能会内存溢出 + List esExistIdList = queryList(req); + if(CollectionUtil.isEmpty(esExistIdList)){ + esMapper.insertBatch(result); + }else { + //重新计算md5 + Map groupByUniqueKeyMap = new HashMap<>(); + for (TransactionPartner bs : esExistIdList) { + BeanUtils.beanAttributeValueTrim(bs); + String uniqueKey = BeanUtils.getUniqueKey(bs); + String md5Id = HelperUtil.generateMD5(analysisResultId+uniqueKey); + groupByUniqueKeyMap.put(md5Id,bs); + } + + List saveList = new ArrayList<>(); + for (TransactionPartner tp : result) { + if(groupByUniqueKeyMap.containsKey(tp.getId())){ + continue; + } + saveList.add(tp); + } + esMapper.insertBatch(saveList); + } + } + + return true; + } + + @Override + public SearchSourceBuilder getSearchSourceBuilder(TransactionPartner family) { + LambdaEsQueryWrapper wrapper = buildEsQueryWrapper(family,new PageQuery()); + return esMapper.getSearchSourceBuilder(wrapper); + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/SysCache.java b/cas-system/src/main/java/com/inscloudtech/system/domain/SysCache.java new file mode 100644 index 0000000..5f2d4ae --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/SysCache.java @@ -0,0 +1,43 @@ +package com.inscloudtech.system.domain; + +import com.inscloudtech.common.utils.StringUtils; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 缓存信息 + * + * @author inscloudtech + */ +@Data +@NoArgsConstructor +public class SysCache { + /** + * 缓存名称 + */ + private String cacheName = ""; + /** + * 缓存键名 + */ + private String cacheKey = ""; + /** + * 缓存内容 + */ + private String cacheValue = ""; + /** + * 备注 + */ + private String remark = ""; + + public SysCache(String cacheName, String remark) { + this.cacheName = cacheName; + this.remark = remark; + } + + public SysCache(String cacheName, String cacheKey, String cacheValue) { + this.cacheName = StringUtils.replace(cacheName, ":", ""); + this.cacheKey = StringUtils.replace(cacheKey, cacheName, ""); + this.cacheValue = cacheValue; + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/SysConfig.java b/cas-system/src/main/java/com/inscloudtech/system/domain/SysConfig.java new file mode 100644 index 0000000..5ae8836 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/SysConfig.java @@ -0,0 +1,65 @@ +package com.inscloudtech.system.domain; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.inscloudtech.common.annotation.ExcelDictFormat; +import com.inscloudtech.common.convert.ExcelDictConvert; +import com.inscloudtech.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; + +/** + * 参数配置表 sys_config + * + * @author inscloudtech + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_config") +@ExcelIgnoreUnannotated +public class SysConfig extends BaseEntity { + /** + * 参数主键 + */ + @ExcelProperty(value = "参数主键") + @TableId(value = "config_id") + private Long configId; + /** + * 参数名称 + */ + @ExcelProperty(value = "参数名称") + @NotBlank(message = "参数名称不能为空") + @Size(min = 0, max = 100, message = "参数名称不能超过{max}个字符") + private String configName; + /** + * 参数键名 + */ + @ExcelProperty(value = "参数键名") + @NotBlank(message = "参数键名长度不能为空") + @Size(min = 0, max = 100, message = "参数键名长度不能超过{max}个字符") + private String configKey; + /** + * 参数键值 + */ + @ExcelProperty(value = "参数键值") + @NotBlank(message = "参数键值不能为空") + @Size(min = 0, max = 500, message = "参数键值长度不能超过{max}个字符") + private String configValue; + /** + * 系统内置(Y是 N否) + */ + @ExcelProperty(value = "系统内置", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_yes_no") + private String configType; + /** + * 备注 + */ + private String remark; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/SysLogininfor.java b/cas-system/src/main/java/com/inscloudtech/system/domain/SysLogininfor.java new file mode 100644 index 0000000..5954d41 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/SysLogininfor.java @@ -0,0 +1,81 @@ +package com.inscloudtech.system.domain; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.inscloudtech.common.annotation.ExcelDictFormat; +import com.inscloudtech.common.convert.ExcelDictConvert; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * 系统访问记录表 sys_logininfor + * + * @author inscloudtech + */ + +@Data +@TableName("sys_logininfor") +@ExcelIgnoreUnannotated +public class SysLogininfor implements Serializable { + private static final long serialVersionUID = 1L; + /** + * ID + */ + @ExcelProperty(value = "序号") + @TableId(value = "info_id") + private Long infoId; + /** + * 用户账号 + */ + @ExcelProperty(value = "用户账号") + private String userName; + /** + * 登录状态 0成功 1失败 + */ + @ExcelProperty(value = "登录状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_common_status") + private String status; + /** + * 登录IP地址 + */ + @ExcelProperty(value = "登录地址") + private String ipaddr; + /** + * 登录地点 + */ + @ExcelProperty(value = "登录地点") + private String loginLocation; + /** + * 浏览器类型 + */ + @ExcelProperty(value = "浏览器") + private String browser; + /** + * 操作系统 + */ + @ExcelProperty(value = "操作系统") + private String os; + /** + * 提示消息 + */ + @ExcelProperty(value = "提示消息") + private String msg; + /** + * 访问时间 + */ + @ExcelProperty(value = "访问时间") + private Date loginTime; + /** + * 请求参数 + */ + @TableField(exist = false) + private Map params = new HashMap<>(); + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/SysNotice.java b/cas-system/src/main/java/com/inscloudtech/system/domain/SysNotice.java new file mode 100644 index 0000000..4c35967 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/SysNotice.java @@ -0,0 +1,52 @@ +package com.inscloudtech.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.inscloudtech.common.core.domain.BaseEntity; +import com.inscloudtech.common.xss.Xss; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; + + +/** + * 通知公告表 sys_notice + * + * @author inscloudtech + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_notice") +public class SysNotice extends BaseEntity { + /** + * 公告ID + */ + @TableId(value = "notice_id") + private Long noticeId; + /** + * 公告标题 + */ + @Xss(message = "公告标题不能包含脚本字符") + @NotBlank(message = "公告标题不能为空") + @Size(min = 0, max = 50, message = "公告标题不能超过{max}个字符") + private String noticeTitle; + /** + * 公告类型(1通知 2公告) + */ + private String noticeType; + /** + * 公告内容 + */ + private String noticeContent; + /** + * 公告状态(0正常 1关闭) + */ + private String status; + /** + * 备注 + */ + private String remark; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/SysNotifyMessage.java b/cas-system/src/main/java/com/inscloudtech/system/domain/SysNotifyMessage.java new file mode 100644 index 0000000..bcff6b8 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/SysNotifyMessage.java @@ -0,0 +1,71 @@ +package com.inscloudtech.system.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Date; +import java.util.Set; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.inscloudtech.common.core.domain.BaseEntity; + +/** + * 站内信消息对象 sys_notify_message + * + * @author inscloudtech + * @date 2023-06-02 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_notify_message") +public class SysNotifyMessage extends BaseEntity { + + private static final long serialVersionUID=1L; + /** + * 用户ID + */ + @TableId(value = "id") + private Long id; /** + * 用户id + */ + private Long userId; /** + * 用户类型 + */ + private Long userType; /** + * 模版编号 + */ + private Long templateId; /** + * 模板编码 + */ + private String templateCode; /** + * 模版发送人名称 + */ + private String templateNickname; + /** + * 接收人 + */ + private String userNickname; /** + * 模版内容 + */ + private String templateContent; /** + * 模版类型 + */ + private Long templateType; /** + * 模版参数 + */ + private String templateParams; /** + * 是否已读0未读,1已读 + */ + private Integer readStatus; /** + * 阅读时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date readTime; + /** + * 删除标志(0代表存在 2代表删除) + */ + @TableLogic + private String delFlag; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/SysNotifyTemplate.java b/cas-system/src/main/java/com/inscloudtech/system/domain/SysNotifyTemplate.java new file mode 100644 index 0000000..5460c93 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/SysNotifyTemplate.java @@ -0,0 +1,64 @@ +package com.inscloudtech.system.domain; + +import com.baomidou.mybatisplus.annotation.*; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import com.inscloudtech.common.core.validate.AddGroup; +import com.inscloudtech.common.core.validate.EditGroup; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import com.inscloudtech.common.core.domain.BaseEntity; + +import javax.validation.constraints.NotBlank; +import java.util.List; + +/** + * 站内信模板对象 sys_notify_template + * + * @author inscloudtech + * @date 2023-06-07 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName(autoResultMap = true) +public class SysNotifyTemplate extends BaseEntity { + + private static final long serialVersionUID=1L; + /** + * 主键 + */ + @TableId(value = "id") + private Long id; /** + * 模板名称 + */ + @NotBlank(message = "模板名称不能为空") + private String name; /** + * 模版编码 + */ + private String code; /** + * 发送人名称 + */ + private String nickname; /** + * 模版内容 + */ + @NotBlank(message = "模版内容不能为空") + private String content; /** + * 类型 + */ + private Long type; /** + * 参数数组 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List templateParams; /** + * 状态 + */ + private Long status; /** + * 备注 + */ + private String remark; /** + * 是否删除 + */ + @TableLogic + private String delFlag; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/SysOperLog.java b/cas-system/src/main/java/com/inscloudtech/system/domain/SysOperLog.java new file mode 100644 index 0000000..5e0d0d7 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/SysOperLog.java @@ -0,0 +1,124 @@ +package com.inscloudtech.system.domain; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.inscloudtech.common.annotation.ExcelDictFormat; +import com.inscloudtech.common.convert.ExcelDictConvert; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * 操作日志记录表 oper_log + * + * @author inscloudtech + */ + +@Data +@TableName("sys_oper_log") +@ExcelIgnoreUnannotated +public class SysOperLog implements Serializable { + + private static final long serialVersionUID = 1L; + /** + * 日志主键 + */ + @ExcelProperty(value = "日志主键") + @TableId(value = "oper_id") + private Long operId; + /** + * 操作模块 + */ + @ExcelProperty(value = "操作模块") + private String title; + /** + * 业务类型(0其它 1新增 2修改 3删除) + */ + @ExcelProperty(value = "业务类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_oper_type") + private Integer businessType; + /** + * 业务类型数组 + */ + @TableField(exist = false) + private Integer[] businessTypes; + /** + * 请求方法 + */ + @ExcelProperty(value = "请求方法") + private String method; + /** + * 请求方式 + */ + @ExcelProperty(value = "请求方式") + private String requestMethod; + /** + * 操作类别(0其它 1后台用户 2手机端用户) + */ + @ExcelProperty(value = "操作类别", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=其它,1=后台用户,2=手机端用户") + private Integer operatorType; + /** + * 操作人员 + */ + @ExcelProperty(value = "操作人员") + private String operName; + /** + * 部门名称 + */ + @ExcelProperty(value = "部门名称") + private String deptName; + /** + * 请求url + */ + @ExcelProperty(value = "请求地址") + private String operUrl; + /** + * 操作地址 + */ + @ExcelProperty(value = "操作地址") + private String operIp; + /** + * 操作地点 + */ + @ExcelProperty(value = "操作地点") + private String operLocation; + /** + * 请求参数 + */ + @ExcelProperty(value = "请求参数") + private String operParam; + /** + * 返回参数 + */ + @ExcelProperty(value = "返回参数") + private String jsonResult; + /** + * 操作状态(0正常 1异常) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_common_status") + private Integer status; + /** + * 错误消息 + */ + @ExcelProperty(value = "错误消息") + private String errorMsg; + /** + * 操作时间 + */ + @ExcelProperty(value = "操作时间") + private Date operTime; + /** + * 请求参数 + */ + @TableField(exist = false) + private Map params = new HashMap<>(); + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/SysOperUpdateLog.java b/cas-system/src/main/java/com/inscloudtech/system/domain/SysOperUpdateLog.java new file mode 100644 index 0000000..99b126a --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/SysOperUpdateLog.java @@ -0,0 +1,83 @@ +package com.inscloudtech.system.domain; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.inscloudtech.common.core.domain.BaseEntity; + +/** + * 操作日志记录对象 sys_oper_update_log + * + * @author inscloudtech + * @date 2023-05-18 + */ +@Data +@ExcelIgnoreUnannotated +@TableName("sys_oper_update_log") +public class SysOperUpdateLog implements Serializable { + + private static final long serialVersionUID=1L; + /** + * 日志主键 + */ + @TableId(value = "oper_id") + private Long operId; /** + * 分类名称 + */ + private String title; + /** + * 方法名称 + */ + private String method; /** + * 请求方式 + */ + private String requestMethod; /** + * 操作类别(0其它 1后台用户 2手机端用户) + */ + private Long operatorType; /** + * 操作人员 + */ + private String operName; /** + * 部门名称 + */ + private String deptName; /** + * 请求URL + */ + private String operUrl; /** + * 主机地址 + */ + private String operIp; /** + * 操作地点 + */ + private String operLocation; /** + * 请求参数 + */ + private String operParam; /** + * 返回参数 + */ + private String jsonResult; /** + * 操作状态(0正常 1异常) + */ + private Long status; /** + * 错误消息 + */ + private String errorMsg; /** + * 操作时间 + */ + private Date operTime; /** + * 更新前数据 + */ + private String beforeValue; /** + * 更新后数据 + */ + private String afterValue; /** + * 业务主键 + */ + private Long businessId; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/SysOss.java b/cas-system/src/main/java/com/inscloudtech/system/domain/SysOss.java new file mode 100644 index 0000000..cfb72a4 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/SysOss.java @@ -0,0 +1,82 @@ +package com.inscloudtech.system.domain; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.inscloudtech.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * OSS对象存储对象 + * + * @author inscloudtech + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_oss") +@ExcelIgnoreUnannotated +public class SysOss extends BaseEntity { + @TableId(value = "oss_id", type = IdType.ASSIGN_ID) + @ExcelProperty("id") + private String ossId; + + @ExcelProperty("文件名") + private String fileName; + + @ExcelProperty("原名") + private String originalName; + + @ExcelProperty("文件后缀名") + private String fileSuffix; + + @ExcelProperty("URL地址") + private String url; + + @ExcelProperty("所属业务模块") + private String businessModule; + + @ExcelProperty("caseId") + private String caseId; + + //删除文件,再删除文件内容 + @ExcelProperty("otherAssetsId") + private String otherAssetsId; + + @TableField(exist = false) + private String remark; + + //导入结果 0 成功 1失败 + @ExcelProperty("uploadResult") + private Integer uploadResult; + + //失败信息 + @ExcelProperty("errorInfo") + private String errorInfo; + + @ExcelProperty("analysisResultId") + private String analysisResultId; + + //导入数量 + @ExcelProperty("importCount") + private int importCount; + + + /** + * 案件合并导致多个案件使用该文件 0 否 1是 + */ + private Integer duplicateCase = 0; + + /** + * 被多个分析成果使用 0 否 1是 + */ + private Integer duplicateAr = 0; + + /** + * 批次号 + */ + private String batchId; +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/SysOssConfig.java b/cas-system/src/main/java/com/inscloudtech/system/domain/SysOssConfig.java new file mode 100644 index 0000000..8e92f61 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/SysOssConfig.java @@ -0,0 +1,75 @@ +package com.inscloudtech.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.inscloudtech.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 对象存储配置对象 sys_oss_config + * + * @author inscloudtech + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_oss_config") +public class SysOssConfig extends BaseEntity { + /** + * 主建 + */ + @TableId(value = "oss_config_id") + private Long ossConfigId; + /** + * 配置key + */ + private String configKey; + /** + * accessKey + */ + private String accessKey; + /** + * 秘钥 + */ + private String secretKey; + /** + * 桶名称 + */ + private String bucketName; + /** + * 前缀 + */ + private String prefix; + /** + * 访问站点 + */ + private String endpoint; + /** + * 自定义域名 + */ + private String domain; + /** + * 是否https(0否 1是) + */ + private String isHttps; + /** + * 域 + */ + private String region; + /** + * 是否默认(0=是,1=否) + */ + private String status; + /** + * 扩展字段 + */ + private String ext1; + /** + * 备注 + */ + private String remark; + /** + * 桶权限类型(0private 1public 2custom) + */ + private String accessPolicy; +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/SysPost.java b/cas-system/src/main/java/com/inscloudtech/system/domain/SysPost.java new file mode 100644 index 0000000..602d561 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/SysPost.java @@ -0,0 +1,71 @@ +package com.inscloudtech.system.domain; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.inscloudtech.common.annotation.ExcelDictFormat; +import com.inscloudtech.common.convert.ExcelDictConvert; +import com.inscloudtech.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +/** + * 岗位表 sys_post + * + * @author inscloudtech + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_post") +@ExcelIgnoreUnannotated +public class SysPost extends BaseEntity { + /** + * 岗位序号 + */ + @ExcelProperty(value = "岗位序号") + @TableId(value = "post_id") + private Long postId; + /** + * 岗位编码 + */ + @ExcelProperty(value = "岗位编码") + @NotBlank(message = "岗位编码不能为空") + @Size(min = 0, max = 64, message = "岗位编码长度不能超过{max}个字符") + private String postCode; + /** + * 岗位名称 + */ + @ExcelProperty(value = "岗位名称") + @NotBlank(message = "岗位名称不能为空") + @Size(min = 0, max = 50, message = "岗位名称长度不能超过{max}个字符") + private String postName; + /** + * 岗位排序 + */ + @ExcelProperty(value = "岗位排序") + @NotNull(message = "显示顺序不能为空") + private Integer postSort; + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + /** + * 备注 + */ + private String remark; + /** + * 用户是否存在此岗位标识 默认不存在 + */ + @TableField(exist = false) + private boolean flag = false; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/SysRoleDept.java b/cas-system/src/main/java/com/inscloudtech/system/domain/SysRoleDept.java new file mode 100644 index 0000000..09e6c23 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/SysRoleDept.java @@ -0,0 +1,27 @@ +package com.inscloudtech.system.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 角色和部门关联 sys_role_dept + * + * @author inscloudtech + */ + +@Data +@TableName("sys_role_dept") +public class SysRoleDept { + /** + * 角色ID + */ + @TableId(type = IdType.INPUT) + private Long roleId; + /** + * 部门ID + */ + private Long deptId; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/SysRoleMenu.java b/cas-system/src/main/java/com/inscloudtech/system/domain/SysRoleMenu.java new file mode 100644 index 0000000..7499377 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/SysRoleMenu.java @@ -0,0 +1,27 @@ +package com.inscloudtech.system.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 角色和菜单关联 sys_role_menu + * + * @author inscloudtech + */ + +@Data +@TableName("sys_role_menu") +public class SysRoleMenu { + /** + * 角色ID + */ + @TableId(type = IdType.INPUT) + private Long roleId; + /** + * 菜单ID + */ + private Long menuId; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/SysUserOnline.java b/cas-system/src/main/java/com/inscloudtech/system/domain/SysUserOnline.java new file mode 100644 index 0000000..cd35ed3 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/SysUserOnline.java @@ -0,0 +1,46 @@ +package com.inscloudtech.system.domain; + +import lombok.Data; + +/** + * 当前在线会话 + * + * @author inscloudtech + */ + +@Data +public class SysUserOnline { + /** + * 会话编号 + */ + private String tokenId; + /** + * 部门名称 + */ + private String deptName; + /** + * 用户名称 + */ + private String userName; + /** + * 登录IP地址 + */ + private String ipaddr; + /** + * 登录地址 + */ + private String loginLocation; + /** + * 浏览器类型 + */ + private String browser; + /** + * 操作系统 + */ + private String os; + /** + * 登录时间 + */ + private Long loginTime; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/SysUserPost.java b/cas-system/src/main/java/com/inscloudtech/system/domain/SysUserPost.java new file mode 100644 index 0000000..8a5d910 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/SysUserPost.java @@ -0,0 +1,27 @@ +package com.inscloudtech.system.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 用户和岗位关联 sys_user_post + * + * @author inscloudtech + */ + +@Data +@TableName("sys_user_post") +public class SysUserPost { + /** + * 用户ID + */ + @TableId(type = IdType.INPUT) + private Long userId; + /** + * 岗位ID + */ + private Long postId; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/SysUserRole.java b/cas-system/src/main/java/com/inscloudtech/system/domain/SysUserRole.java new file mode 100644 index 0000000..bdd871d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/SysUserRole.java @@ -0,0 +1,27 @@ +package com.inscloudtech.system.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 用户和角色关联 sys_user_role + * + * @author inscloudtech + */ + +@Data +@TableName("sys_user_role") +public class SysUserRole { + /** + * 用户ID + */ + @TableId(type = IdType.INPUT) + private Long userId; + /** + * 角色ID + */ + private Long roleId; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/bo/SysOperUpdateLogBo.java b/cas-system/src/main/java/com/inscloudtech/system/domain/bo/SysOperUpdateLogBo.java new file mode 100644 index 0000000..d3e7e4b --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/bo/SysOperUpdateLogBo.java @@ -0,0 +1,120 @@ +package com.inscloudtech.system.domain.bo; + +import com.inscloudtech.common.core.validate.AddGroup; +import com.inscloudtech.common.core.validate.EditGroup; +import lombok.Data; +import lombok.EqualsAndHashCode; +import javax.validation.constraints.*; + +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.inscloudtech.common.core.domain.BaseEntity; + +/** + * 操作日志记录业务对象 sys_oper_update_log + * + * @author inscloudtech + * @date 2023-05-18 + */ + +@Data +@EqualsAndHashCode(callSuper = true) +public class SysOperUpdateLogBo extends BaseEntity { + /** + * 日志主键 + */ + @NotNull(message = "日志主键不能为空", groups = { EditGroup.class }) + private Long operId; + /** + * 分类名称 + */ + @NotBlank(message = "分类名称不能为空", groups = { AddGroup.class, EditGroup.class }) + private String title; + /** + * 分类编码 + */ + @NotNull(message = "分类编码不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long categoryCode; + /** + * 方法名称 + */ + @NotBlank(message = "方法名称不能为空", groups = { AddGroup.class, EditGroup.class }) + private String method; + /** + * 请求方式 + */ + @NotBlank(message = "请求方式不能为空", groups = { AddGroup.class, EditGroup.class }) + private String requestMethod; + /** + * 操作类别(0其它 1后台用户 2手机端用户) + */ + @NotNull(message = "操作类别(0其它 1后台用户 2手机端用户)不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long operatorType; + /** + * 操作人员 + */ + @NotBlank(message = "操作人员不能为空", groups = { AddGroup.class, EditGroup.class }) + private String operName; + /** + * 部门名称 + */ + @NotBlank(message = "部门名称不能为空", groups = { AddGroup.class, EditGroup.class }) + private String deptName; + /** + * 请求URL + */ + @NotBlank(message = "请求URL不能为空", groups = { AddGroup.class, EditGroup.class }) + private String operUrl; + /** + * 主机地址 + */ + @NotBlank(message = "主机地址不能为空", groups = { AddGroup.class, EditGroup.class }) + private String operIp; + /** + * 操作地点 + */ + @NotBlank(message = "操作地点不能为空", groups = { AddGroup.class, EditGroup.class }) + private String operLocation; + /** + * 请求参数 + */ + @NotBlank(message = "请求参数不能为空", groups = { AddGroup.class, EditGroup.class }) + private String operParam; + /** + * 返回参数 + */ + @NotBlank(message = "返回参数不能为空", groups = { AddGroup.class, EditGroup.class }) + private String jsonResult; + /** + * 操作状态(0正常 1异常) + */ + @NotNull(message = "操作状态(0正常 1异常)不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long status; + /** + * 错误消息 + */ + @NotBlank(message = "错误消息不能为空", groups = { AddGroup.class, EditGroup.class }) + private String errorMsg; + /** + * 操作时间 + */ + @NotNull(message = "操作时间不能为空", groups = { AddGroup.class, EditGroup.class }) + private Date operTime; + /** + * 更新前数据 + */ + @NotBlank(message = "更新前数据不能为空", groups = { AddGroup.class, EditGroup.class }) + private String beforeValue; + /** + * 更新后数据 + */ + @NotBlank(message = "更新后数据不能为空", groups = { AddGroup.class, EditGroup.class }) + private String afterValue; + /** + * 业务主键 + */ + @NotNull(message = "业务主键不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long businessId; + + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/bo/SysOssBo.java b/cas-system/src/main/java/com/inscloudtech/system/domain/bo/SysOssBo.java new file mode 100644 index 0000000..6389f94 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/bo/SysOssBo.java @@ -0,0 +1,40 @@ +package com.inscloudtech.system.domain.bo; + +import com.inscloudtech.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * OSS对象存储分页查询对象 sys_oss + * + * @author inscloudtech + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class SysOssBo extends BaseEntity { + /** + * ossId + */ + private Long ossId; + /** + * 文件名 + */ + private String fileName; + /** + * 原名 + */ + private String originalName; + /** + * 文件后缀名 + */ + private String fileSuffix; + /** + * URL地址 + */ + private String url; + /** + * 服务商 + */ + private String service; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/bo/SysOssConfigBo.java b/cas-system/src/main/java/com/inscloudtech/system/domain/bo/SysOssConfigBo.java new file mode 100644 index 0000000..566f317 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/bo/SysOssConfigBo.java @@ -0,0 +1,93 @@ +package com.inscloudtech.system.domain.bo; + +import com.inscloudtech.common.core.domain.BaseEntity; +import com.inscloudtech.common.core.validate.AddGroup; +import com.inscloudtech.common.core.validate.EditGroup; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +/** + * 对象存储配置业务对象 sys_oss_config + * + * @author inscloudtech + * @author 孤舟烟雨 + * @date 2021-08-13 + */ + +@Data +@EqualsAndHashCode(callSuper = true) +public class SysOssConfigBo extends BaseEntity { + /** + * 主建 + */ + @NotNull(message = "主建不能为空", groups = {EditGroup.class}) + private Long ossConfigId; + /** + * 配置key + */ + @NotBlank(message = "配置key不能为空", groups = {AddGroup.class, EditGroup.class}) + @Size(min = 2, max = 100, message = "configKey长度必须介于{min}和{max} 之间") + private String configKey; + /** + * accessKey + */ + @NotBlank(message = "accessKey不能为空", groups = {AddGroup.class, EditGroup.class}) + @Size(min = 2, max = 100, message = "accessKey长度必须介于{min}和{max} 之间") + private String accessKey; + /** + * 秘钥 + */ + @NotBlank(message = "secretKey不能为空", groups = {AddGroup.class, EditGroup.class}) + @Size(min = 2, max = 100, message = "secretKey长度必须介于{min}和{max} 之间") + private String secretKey; + /** + * 桶名称 + */ + @NotBlank(message = "桶名称不能为空", groups = {AddGroup.class, EditGroup.class}) + @Size(min = 2, max = 100, message = "bucketName长度必须介于{min}和{max}之间") + private String bucketName; + /** + * 前缀 + */ + private String prefix; + /** + * 访问站点 + */ + @NotBlank(message = "访问站点不能为空", groups = {AddGroup.class, EditGroup.class}) + @Size(min = 2, max = 100, message = "endpoint长度必须介于{min}和{max}之间") + private String endpoint; + /** + * 自定义域名 + */ + private String domain; + /** + * 是否https(Y=是,N=否) + */ + private String isHttps; + /** + * 是否默认(0=是,1=否) + */ + private String status; + /** + * 域 + */ + private String region; + /** + * 扩展字段 + */ + private String ext1; + /** + * 备注 + */ + private String remark; + /** + * 桶权限类型(0private 1public 2custom) + */ + @NotBlank(message = "桶权限类型不能为空", groups = {AddGroup.class, EditGroup.class}) + private String accessPolicy; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/vo/LoginRecordEntity.java b/cas-system/src/main/java/com/inscloudtech/system/domain/vo/LoginRecordEntity.java new file mode 100644 index 0000000..431d6d3 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/vo/LoginRecordEntity.java @@ -0,0 +1,34 @@ +package com.inscloudtech.system.domain.vo; + +import lombok.Data; +import org.dromara.easyes.annotation.IndexId; +import org.dromara.easyes.annotation.IndexName; +import org.dromara.easyes.annotation.rely.IdType; + +/** + * 登录记录表 + */ +@Data +@IndexName("sys_login_record") +public class LoginRecordEntity { + + @IndexId(type = IdType.CUSTOMIZE) + private String id; + /** + * 用户id + */ + private Long userId; + private String userName; + private String idCardNo; + /** + * 登录时间 + */ + private Long loginDate; + /** + * 权限类别 + */ + private String permissionType; + + private Long createdTime; + private Long updatedTime; +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/vo/MetaVo.java b/cas-system/src/main/java/com/inscloudtech/system/domain/vo/MetaVo.java new file mode 100644 index 0000000..99fc320 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/vo/MetaVo.java @@ -0,0 +1,57 @@ +package com.inscloudtech.system.domain.vo; + +import com.inscloudtech.common.utils.StringUtils; +import lombok.Data; + +/** + * 路由显示信息 + * + * @author inscloudtech + */ + +@Data +public class MetaVo { + /** + * 设置该路由在侧边栏和面包屑中展示的名字 + */ + private String title; + /** + * 设置该路由的图标,对应路径src/assets/icons/svg + */ + private String icon; + /** + * 设置为true,则不会被 缓存 + */ + private boolean noCache; + /** + * 内链地址(http(s)://开头) + */ + private String link; + + public MetaVo(String title, String icon) { + this.title = title; + this.icon = icon; + } + + public MetaVo(String title, String icon, boolean noCache) { + this.title = title; + this.icon = icon; + this.noCache = noCache; + } + + public MetaVo(String title, String icon, String link) { + this.title = title; + this.icon = icon; + this.link = link; + } + + public MetaVo(String title, String icon, boolean noCache, String link) { + this.title = title; + this.icon = icon; + this.noCache = noCache; + if (StringUtils.ishttp(link)) { + this.link = link; + } + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/vo/RouterVo.java b/cas-system/src/main/java/com/inscloudtech/system/domain/vo/RouterVo.java new file mode 100644 index 0000000..9e10d4d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/vo/RouterVo.java @@ -0,0 +1,53 @@ +package com.inscloudtech.system.domain.vo; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; + +import java.util.List; + +/** + * 路由配置信息 + * + * @author inscloudtech + */ +@Data +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public class RouterVo { + /** + * 路由名字 + */ + private String name; + /** + * 路由地址 + */ + private String path; + /** + * 是否隐藏路由,当设置 true 的时候该路由不会再侧边栏出现 + */ + private boolean hidden; + /** + * 重定向地址,当设置 noRedirect 的时候该路由在面包屑导航中不可被点击 + */ + private String redirect; + /** + * 组件地址 + */ + private String component; + /** + * 路由参数:如 {"id": 1, "name": "ry"} + */ + private String query; + /** + * 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面 + */ + private Boolean alwaysShow; + /** + * 其他元素 + */ + private MetaVo meta; + /** + * 子路由 + */ + private List children; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/vo/SysNotifyTemplateVo.java b/cas-system/src/main/java/com/inscloudtech/system/domain/vo/SysNotifyTemplateVo.java new file mode 100644 index 0000000..c9ea514 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/vo/SysNotifyTemplateVo.java @@ -0,0 +1,66 @@ +package com.inscloudtech.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + + +/** + * 站内信模板视图对象 sys_notify_template + * + * @author inscloudtech + * @date 2023-06-07 + */ +@Data +@ExcelIgnoreUnannotated +public class SysNotifyTemplateVo { + + private static final long serialVersionUID = 1L; + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + /** + * 模板名称 + */ + @ExcelProperty(value = "模板名称") + private String name; + /** + * 模版编码 + */ + @ExcelProperty(value = "模版编码") + private String code; + /** + * 发送人名称 + */ + @ExcelProperty(value = "发送人名称") + private String nickname; + /** + * 模版内容 + */ + @ExcelProperty(value = "模版内容") + private String content; + /** + * 类型 + */ + @ExcelProperty(value = "类型") + private Long type; + /** + * 参数数组 + */ + @ExcelProperty(value = "参数数组") + private String params; + /** + * 状态 + */ + @ExcelProperty(value = "状态") + private Long status; + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/vo/SysOperUpdateLogVo.java b/cas-system/src/main/java/com/inscloudtech/system/domain/vo/SysOperUpdateLogVo.java new file mode 100644 index 0000000..28bd169 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/vo/SysOperUpdateLogVo.java @@ -0,0 +1,122 @@ +package com.inscloudtech.system.domain.vo; + +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.annotation.ExcelDictFormat; +import com.inscloudtech.common.convert.ExcelDictConvert; +import lombok.Data; + + +/** + * 操作日志记录视图对象 sys_oper_update_log + * + * @author inscloudtech + * @date 2023-05-18 + */ +@Data +@ExcelIgnoreUnannotated +public class SysOperUpdateLogVo { + + private static final long serialVersionUID = 1L; + /** + * 日志主键 + */ + @ExcelProperty(value = "日志主键") + private Long operId; + /** + * 分类名称 + */ + @ExcelProperty(value = "分类名称") + private String title; + /** + * 分类编码 + */ + @ExcelProperty(value = "分类编码") + private Long categoryCode; + /** + * 方法名称 + */ + @ExcelProperty(value = "方法名称") + private String method; + /** + * 请求方式 + */ + @ExcelProperty(value = "请求方式") + private String requestMethod; + /** + * 操作类别(0其它 1后台用户 2手机端用户) + */ + @ExcelProperty(value = "操作类别", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=其它,1=后台用户,2=手机端用户") + private Long operatorType; + /** + * 操作人员 + */ + @ExcelProperty(value = "操作人员") + private String operName; + /** + * 部门名称 + */ + @ExcelProperty(value = "部门名称") + private String deptName; + /** + * 请求URL + */ + @ExcelProperty(value = "请求URL") + private String operUrl; + /** + * 主机地址 + */ + @ExcelProperty(value = "主机地址") + private String operIp; + /** + * 操作地点 + */ + @ExcelProperty(value = "操作地点") + private String operLocation; + /** + * 请求参数 + */ + @ExcelProperty(value = "请求参数") + private String operParam; + /** + * 返回参数 + */ + @ExcelProperty(value = "返回参数") + private String jsonResult; + /** + * 操作状态(0正常 1异常) + */ + @ExcelProperty(value = "操作状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=异常") + private Long status; + /** + * 错误消息 + */ + @ExcelProperty(value = "错误消息") + private String errorMsg; + /** + * 操作时间 + */ + @ExcelProperty(value = "操作时间") + private Date operTime; + /** + * 更新前数据 + */ + @ExcelProperty(value = "更新前数据") + private String beforeValue; + /** + * 更新后数据 + */ + @ExcelProperty(value = "更新后数据") + private String afterValue; + /** + * 业务主键 + */ + @ExcelProperty(value = "业务主键") + private Long businessId; + + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/vo/SysOssConfigVo.java b/cas-system/src/main/java/com/inscloudtech/system/domain/vo/SysOssConfigVo.java new file mode 100644 index 0000000..fcc3e4e --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/vo/SysOssConfigVo.java @@ -0,0 +1,76 @@ +package com.inscloudtech.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import lombok.Data; + + +/** + * 对象存储配置视图对象 sys_oss_config + * + * @author inscloudtech + * @author 孤舟烟雨 + * @date 2021-08-13 + */ +@Data +@ExcelIgnoreUnannotated +public class SysOssConfigVo { + + private static final long serialVersionUID = 1L; + /** + * 主建 + */ + private Long ossConfigId; + /** + * 配置key + */ + private String configKey; + /** + * accessKey + */ + private String accessKey; + /** + * 秘钥 + */ + private String secretKey; + /** + * 桶名称 + */ + private String bucketName; + /** + * 前缀 + */ + private String prefix; + /** + * 访问站点 + */ + private String endpoint; + /** + * 自定义域名 + */ + private String domain; + /** + * 是否https(Y=是,N=否) + */ + private String isHttps; + /** + * 域 + */ + private String region; + /** + * 是否默认(0=是,1=否) + */ + private String status; + /** + * 扩展字段 + */ + private String ext1; + /** + * 备注 + */ + private String remark; + /** + * 桶权限类型(0private 1public 2custom) + */ + private String accessPolicy; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/vo/SysOssVo.java b/cas-system/src/main/java/com/inscloudtech/system/domain/vo/SysOssVo.java new file mode 100644 index 0000000..f59369d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/vo/SysOssVo.java @@ -0,0 +1,50 @@ +package com.inscloudtech.system.domain.vo; + +import lombok.Data; + +import java.util.Date; + +/** + * OSS对象存储视图对象 sys_oss + * + * @author inscloudtech + */ +@Data +public class SysOssVo { + + private static final long serialVersionUID = 1L; + /** + * 对象存储主键 + */ + private Long ossId; + /** + * 文件名 + */ + private String fileName; + /** + * 原名 + */ + private String originalName; + /** + * 文件后缀名 + */ + private String fileSuffix; + /** + * URL地址 + */ + private String url; + /** + * 创建时间 + */ + private Date createTime; + /** + * 上传人 + */ + private String createBy; + /** + * 服务商 + */ + private String service; + + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/vo/SysUserExportVo.java b/cas-system/src/main/java/com/inscloudtech/system/domain/vo/SysUserExportVo.java new file mode 100644 index 0000000..0ab737a --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/vo/SysUserExportVo.java @@ -0,0 +1,80 @@ +package com.inscloudtech.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.annotation.ExcelDictFormat; +import com.inscloudtech.common.convert.ExcelDictConvert; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Date; + +/** + * 用户对象导出VO + * + * @author inscloudtech + */ + +@Data +@NoArgsConstructor +public class SysUserExportVo implements Serializable { + private static final long serialVersionUID = 1L; + /** + * 用户ID + */ + @ExcelProperty(value = "用户序号") + private Long userId; + /** + * 用户账号 + */ + @ExcelProperty(value = "登录名称") + private String userName; + /** + * 用户昵称 + */ + @ExcelProperty(value = "用户名称") + private String nickName; + /** + * 用户邮箱 + */ + @ExcelProperty(value = "用户邮箱") + private String email; + /** + * 手机号码 + */ + @ExcelProperty(value = "手机号码") + private String phonenumber; + /** + * 用户性别 + */ + @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_user_sex") + private String sex; + /** + * 帐号状态(0正常 1停用) + */ + @ExcelProperty(value = "帐号状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + /** + * 最后登录IP + */ + @ExcelProperty(value = "最后登录IP") + private String loginIp; + /** + * 最后登录时间 + */ + @ExcelProperty(value = "最后登录时间") + private Date loginDate; + /** + * 部门名称 + */ + @ExcelProperty(value = "部门名称") + private String deptName; + /** + * 负责人 + */ + @ExcelProperty(value = "部门负责人") + private String leader; + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/domain/vo/SysUserImportVo.java b/cas-system/src/main/java/com/inscloudtech/system/domain/vo/SysUserImportVo.java new file mode 100644 index 0000000..b40d74f --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/domain/vo/SysUserImportVo.java @@ -0,0 +1,60 @@ +package com.inscloudtech.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.inscloudtech.common.annotation.ExcelDictFormat; +import com.inscloudtech.common.convert.ExcelDictConvert; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 用户对象导入VO + * + * @author inscloudtech + */ + +@Data +@NoArgsConstructor +// @Accessors(chain = true) // 导入不允许使用 会找不到set方法 +public class SysUserImportVo implements Serializable { + private static final long serialVersionUID = 1L; + /** + * 用户ID + */ + @ExcelProperty(value = "用户账号") + private Long userId; + /** + * 部门ID + */ +// @ExcelProperty(value = "部门编号") +// private Long deptId; + /** + * 用户账号 + */ + @ExcelProperty(value = "登录名称") + private String userName; + /** + * 用户昵称 + */ + @ExcelProperty(value = "用户名称") + private String nickName; + /** + * 用户邮箱 + */ + @ExcelProperty(value = "用户邮箱") + private String email; + /** + * 手机号码 + */ + @ExcelProperty(value = "手机号码") + private String phonenumber; + /** + * 用户性别 + */ + @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_user_sex") + private String sex; + + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/listener/SysUserImportListener.java b/cas-system/src/main/java/com/inscloudtech/system/listener/SysUserImportListener.java new file mode 100644 index 0000000..0dcd38d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/listener/SysUserImportListener.java @@ -0,0 +1,122 @@ +package com.inscloudtech.system.listener; + +import cn.dev33.satoken.secure.BCrypt; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.inscloudtech.common.core.domain.entity.SysUser; +import com.inscloudtech.common.excel.ExcelListener; +import com.inscloudtech.common.excel.ExcelResult; +import com.inscloudtech.common.exception.ServiceException; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.common.utils.ValidatorUtils; +import com.inscloudtech.common.utils.spring.SpringUtils; +import com.inscloudtech.system.domain.vo.SysUserImportVo; +import com.inscloudtech.system.service.ISysConfigService; +import com.inscloudtech.system.service.ISysUserService; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * 系统用户自定义导入 + * + * @author inscloudtech + */ +@Slf4j +public class SysUserImportListener extends AnalysisEventListener implements ExcelListener { + + private final ISysUserService userService; + + private final String password; + + private final Boolean isUpdateSupport; + private final String operName; + private final Long deptId; + private int successNum = 0; + private int failureNum = 0; + private final StringBuilder successMsg = new StringBuilder(); + private final StringBuilder failureMsg = new StringBuilder(); + + public SysUserImportListener(Boolean isUpdateSupport,Long deptId) { + String initPassword = SpringUtils.getBean(ISysConfigService.class).selectConfigByKey("sys.user.initPassword"); + this.userService = SpringUtils.getBean(ISysUserService.class); + this.password = BCrypt.hashpw(initPassword); + this.isUpdateSupport = isUpdateSupport; + this.operName = LoginHelper.getUsername(); + this.deptId = deptId; + } + + @Override + public void invoke(SysUserImportVo userVo, AnalysisContext context) { + SysUser user = this.userService.selectUserByUserName(userVo.getUserName()); + try { + // 验证是否存在这个用户 + if (ObjectUtil.isNull(user)) { + user = BeanUtil.toBean(userVo, SysUser.class); + ValidatorUtils.validate(user); + user.setDeptId(deptId); + user.setStatus("0"); + user.setPassword(password); + user.setCreateBy(operName); + userService.insertUser(user); + successNum++; + successMsg.append("
").append(successNum).append("、账号 ").append(user.getUserName()).append(" 导入成功"); + } else if (isUpdateSupport) { + Long userId = user.getUserId(); + user = BeanUtil.toBean(userVo, SysUser.class); + user.setUserId(userId); + user.setStatus("0"); + ValidatorUtils.validate(user); + userService.checkUserAllowed(user); + userService.checkUserDataScope(user.getUserId()); + user.setDeptId(deptId); + user.setUpdateBy(operName); + userService.updateUser(user); + successNum++; + successMsg.append("
").append(successNum).append("、账号 ").append(user.getUserName()).append(" 更新成功"); + } else { + failureNum++; + failureMsg.append("
").append(failureNum).append("、账号 ").append(user.getUserName()).append(" 已存在"); + } + } catch (Exception e) { + failureNum++; + String msg = "
" + failureNum + "、账号 " + user.getUserName() + " 导入失败:"; + failureMsg.append(msg).append(e.getMessage()); + log.error(msg, e); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + + } + + @Override + public ExcelResult getExcelResult() { + return new ExcelResult() { + + @Override + public String getAnalysis() { + if (failureNum > 0) { + failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); + throw new ServiceException(failureMsg.toString()); + } else { + successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:"); + } + return successMsg.toString(); + } + + @Override + public List getList() { + return null; + } + + @Override + public List getErrorList() { + return null; + } + }; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/mapper/SysConfigMapper.java b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysConfigMapper.java new file mode 100644 index 0000000..4216b24 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysConfigMapper.java @@ -0,0 +1,13 @@ +package com.inscloudtech.system.mapper; + +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import com.inscloudtech.system.domain.SysConfig; + +/** + * 参数配置 数据层 + * + * @author inscloudtech + */ +public interface SysConfigMapper extends BaseMapperPlus { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/mapper/SysDeptMapper.java b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysDeptMapper.java new file mode 100644 index 0000000..fcd5b97 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysDeptMapper.java @@ -0,0 +1,38 @@ +package com.inscloudtech.system.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.inscloudtech.common.annotation.DataColumn; +import com.inscloudtech.common.annotation.DataPermission; +import com.inscloudtech.common.core.domain.entity.SysDept; +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 部门管理 数据层 + * + * @author inscloudtech + */ +public interface SysDeptMapper extends BaseMapperPlus { + /** + * 查询部门管理数据 + * + * @param queryWrapper 查询条件 + * @return 部门信息集合 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id") + }) + List selectDeptList(@Param(Constants.WRAPPER) Wrapper queryWrapper); + /** + * 根据角色ID查询部门树信息 + * + * @param roleId 角色ID + * @param deptCheckStrictly 部门树选择项是否关联显示 + * @return 选中部门列表 + */ + List selectDeptListByRoleId(@Param("roleId") Long roleId, @Param("deptCheckStrictly") boolean deptCheckStrictly); + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/mapper/SysDictDataMapper.java b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysDictDataMapper.java new file mode 100644 index 0000000..b86722c --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysDictDataMapper.java @@ -0,0 +1,24 @@ +package com.inscloudtech.system.mapper; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.inscloudtech.common.constant.UserConstants; +import com.inscloudtech.common.core.domain.entity.SysDictData; +import com.inscloudtech.common.core.mapper.BaseMapperPlus; + +import java.util.List; + +/** + * 字典表 数据层 + * + * @author inscloudtech + */ +public interface SysDictDataMapper extends BaseMapperPlus { + + default List selectDictDataByType(String dictType) { + return selectList( + new LambdaQueryWrapper() + .eq(SysDictData::getStatus, UserConstants.DICT_NORMAL) + .eq(SysDictData::getDictType, dictType) + .orderByAsc(SysDictData::getDictSort)); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/mapper/SysDictTypeMapper.java b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysDictTypeMapper.java new file mode 100644 index 0000000..a1ba23d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysDictTypeMapper.java @@ -0,0 +1,13 @@ +package com.inscloudtech.system.mapper; + +import com.inscloudtech.common.core.domain.entity.SysDictType; +import com.inscloudtech.common.core.mapper.BaseMapperPlus; + +/** + * 字典表 数据层 + * + * @author inscloudtech + */ +public interface SysDictTypeMapper extends BaseMapperPlus { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/mapper/SysLogininforMapper.java b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysLogininforMapper.java new file mode 100644 index 0000000..33c26c1 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysLogininforMapper.java @@ -0,0 +1,13 @@ +package com.inscloudtech.system.mapper; + +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import com.inscloudtech.system.domain.SysLogininfor; + +/** + * 系统访问日志情况信息 数据层 + * + * @author inscloudtech + */ +public interface SysLogininforMapper extends BaseMapperPlus { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/mapper/SysMenuMapper.java b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysMenuMapper.java new file mode 100644 index 0000000..949e854 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysMenuMapper.java @@ -0,0 +1,77 @@ +package com.inscloudtech.system.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.inscloudtech.common.constant.UserConstants; +import com.inscloudtech.common.core.domain.entity.SysMenu; +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 菜单表 数据层 + * + * @author inscloudtech + */ +public interface SysMenuMapper extends BaseMapperPlus { + /** + * 根据用户所有权限 + * + * @return 权限列表 + */ + List selectMenuPerms(); + /** + * 根据用户查询系统菜单列表 + * + * @param queryWrapper 查询条件 + * @return 菜单列表 + */ + List selectMenuListByUserId(@Param(Constants.WRAPPER) Wrapper queryWrapper); + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + List selectMenuPermsByUserId(Long userId); + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + List selectMenuPermsByRoleId(Long roleId); + /** + * 根据用户ID查询菜单 + * + * @return 菜单列表 + */ + default List selectMenuTreeAll() { + LambdaQueryWrapper lqw = new LambdaQueryWrapper() + .in(SysMenu::getMenuType, UserConstants.TYPE_DIR, UserConstants.TYPE_MENU) + .eq(SysMenu::getStatus, UserConstants.MENU_NORMAL) + .orderByAsc(SysMenu::getParentId) + .orderByAsc(SysMenu::getOrderNum); + return this.selectList(lqw); + } + /** + * 根据用户ID查询菜单 + * + * @param userId 用户ID + * @return 菜单列表 + */ + List selectMenuTreeByUserId(Long userId); + /** + * 根据角色ID查询菜单树信息 + * + * @param roleId 角色ID + * @param menuCheckStrictly 菜单树选择项是否关联显示 + * @return 选中菜单列表 + */ + List selectMenuListByRoleId(@Param("roleId") Long roleId, @Param("menuCheckStrictly") boolean menuCheckStrictly); + + + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/mapper/SysNoticeMapper.java b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysNoticeMapper.java new file mode 100644 index 0000000..91b8f7a --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysNoticeMapper.java @@ -0,0 +1,13 @@ +package com.inscloudtech.system.mapper; + +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import com.inscloudtech.system.domain.SysNotice; + +/** + * 通知公告表 数据层 + * + * @author inscloudtech + */ +public interface SysNoticeMapper extends BaseMapperPlus { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/mapper/SysNotifyMessageMapper.java b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysNotifyMessageMapper.java new file mode 100644 index 0000000..2d7e97f --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysNotifyMessageMapper.java @@ -0,0 +1,14 @@ +package com.inscloudtech.system.mapper; + +import com.inscloudtech.system.domain.SysNotifyMessage; +import com.inscloudtech.common.core.mapper.BaseMapperPlus; + +/** + * 站内信消息Mapper接口 + * + * @author inscloudtech + * @date 2023-06-02 + */ +public interface SysNotifyMessageMapper extends BaseMapperPlus { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/mapper/SysNotifyTemplateMapper.java b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysNotifyTemplateMapper.java new file mode 100644 index 0000000..0727085 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysNotifyTemplateMapper.java @@ -0,0 +1,15 @@ +package com.inscloudtech.system.mapper; + +import com.inscloudtech.system.domain.SysNotifyTemplate; +import com.inscloudtech.system.domain.vo.SysNotifyTemplateVo; +import com.inscloudtech.common.core.mapper.BaseMapperPlus; + +/** + * 站内信模板Mapper接口 + * + * @author inscloudtech + * @date 2023-06-07 + */ +public interface SysNotifyTemplateMapper extends BaseMapperPlus { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/mapper/SysOperLogMapper.java b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysOperLogMapper.java new file mode 100644 index 0000000..0fe3d10 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysOperLogMapper.java @@ -0,0 +1,13 @@ +package com.inscloudtech.system.mapper; + +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import com.inscloudtech.system.domain.SysOperLog; + +/** + * 操作日志 数据层 + * + * @author inscloudtech + */ +public interface SysOperLogMapper extends BaseMapperPlus { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/mapper/SysOperUpdateLogMapper.java b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysOperUpdateLogMapper.java new file mode 100644 index 0000000..cfbf5f8 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysOperUpdateLogMapper.java @@ -0,0 +1,22 @@ +package com.inscloudtech.system.mapper; + +import com.inscloudtech.system.domain.SysOperUpdateLog; +import com.inscloudtech.system.domain.vo.SysOperUpdateLogVo; +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.Date; +import java.util.List; + +/** + * 操作日志记录Mapper接口 + * + * @author inscloudtech + * @date 2023-05-18 + */ +public interface SysOperUpdateLogMapper extends BaseMapperPlus { + + @Select("select business_id from sys_oper_update_log where title = #{title} and after_value LIKE CONCAT('%', #{afterValue}, '%') and oper_time BETWEEN #{start} and #{end} group by business_id") + List getBusinessIdList(@Param("title") String title, @Param("afterValue") String afterValue, @Param("start") Date start , @Param("end") Date end); +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/mapper/SysOssConfigMapper.java b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysOssConfigMapper.java new file mode 100644 index 0000000..7592b6a --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysOssConfigMapper.java @@ -0,0 +1,16 @@ +package com.inscloudtech.system.mapper; + +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import com.inscloudtech.system.domain.SysOssConfig; +import com.inscloudtech.system.domain.vo.SysOssConfigVo; + +/** + * 对象存储配置Mapper接口 + * + * @author inscloudtech + * @author 孤舟烟雨 + * @date 2021-08-13 + */ +public interface SysOssConfigMapper extends BaseMapperPlus { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/mapper/SysOssMapper.java b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysOssMapper.java new file mode 100644 index 0000000..202eed9 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysOssMapper.java @@ -0,0 +1,21 @@ +package com.inscloudtech.system.mapper; + +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import com.inscloudtech.datacenter.domain.dto.StatisticsVo; +import com.inscloudtech.system.domain.SysOss; +import com.inscloudtech.system.domain.vo.SysOssVo; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + * 文件上传 数据层 + * + * @author inscloudtech + */ +public interface SysOssMapper extends BaseMapperPlus { + + @Select("select business_module module ,IFNULL(count(*),0) fileCount ,IFNULL(SUM(import_count),0) dataCount FROM sys_oss where case_id = ${caseId} and business_module in ('BANK_STATEMENT','TRANSACTION_PARTNER','PUBLIC_FAMILY', 'REAL_ESTATE','CAR_INFO') and del_flag = 0 GROUP BY business_module") + List statisticsData(@Param("caseId") String caseId); +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/mapper/SysPostMapper.java b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysPostMapper.java new file mode 100644 index 0000000..945d4bf --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysPostMapper.java @@ -0,0 +1,29 @@ +package com.inscloudtech.system.mapper; + +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import com.inscloudtech.system.domain.SysPost; + +import java.util.List; + +/** + * 岗位信息 数据层 + * + * @author inscloudtech + */ +public interface SysPostMapper extends BaseMapperPlus { + /** + * 根据用户ID获取岗位选择框列表 + * + * @param userId 用户ID + * @return 选中岗位ID列表 + */ + List selectPostListByUserId(Long userId); + /** + * 查询用户所属岗位组 + * + * @param userName 用户名 + * @return 结果 + */ + List selectPostsByUserName(String userName); + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/mapper/SysRoleDeptMapper.java b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysRoleDeptMapper.java new file mode 100644 index 0000000..64a48f6 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysRoleDeptMapper.java @@ -0,0 +1,13 @@ +package com.inscloudtech.system.mapper; + +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import com.inscloudtech.system.domain.SysRoleDept; + +/** + * 角色与部门关联表 数据层 + * + * @author inscloudtech + */ +public interface SysRoleDeptMapper extends BaseMapperPlus { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/mapper/SysRoleMapper.java b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysRoleMapper.java new file mode 100644 index 0000000..311cc05 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysRoleMapper.java @@ -0,0 +1,58 @@ +package com.inscloudtech.system.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.inscloudtech.common.annotation.DataColumn; +import com.inscloudtech.common.annotation.DataPermission; +import com.inscloudtech.common.core.domain.entity.SysRole; +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 角色表 数据层 + * + * @author inscloudtech + */ +public interface SysRoleMapper extends BaseMapperPlus { + + @DataPermission({ + @DataColumn(key = "deptName", value = "d.dept_id") + }) + Page selectPageRoleList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + /** + * 根据条件分页查询角色数据 + * + * @param queryWrapper 查询条件 + * @return 角色数据集合信息 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "d.dept_id") + }) + List selectRoleList(@Param(Constants.WRAPPER) Wrapper queryWrapper); + /** + * 根据用户ID查询角色 + * + * @param userId 用户ID + * @return 角色列表 + */ + List selectRolePermissionByUserId(Long userId); + + /** + * 根据用户ID获取角色选择框列表 + * + * @param userId 用户ID + * @return 选中角色ID列表 + */ + List selectRoleListByUserId(Long userId); + /** + * 根据用户ID查询角色 + * + * @param userName 用户名 + * @return 角色列表 + */ + List selectRolesByUserName(String userName); + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/mapper/SysRoleMenuMapper.java b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysRoleMenuMapper.java new file mode 100644 index 0000000..03ff859 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysRoleMenuMapper.java @@ -0,0 +1,13 @@ +package com.inscloudtech.system.mapper; + +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import com.inscloudtech.system.domain.SysRoleMenu; + +/** + * 角色与菜单关联表 数据层 + * + * @author inscloudtech + */ +public interface SysRoleMenuMapper extends BaseMapperPlus { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/mapper/SysUserMapper.java b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysUserMapper.java new file mode 100644 index 0000000..8e3f49c --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysUserMapper.java @@ -0,0 +1,91 @@ +package com.inscloudtech.system.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.inscloudtech.common.annotation.DataColumn; +import com.inscloudtech.common.annotation.DataPermission; +import com.inscloudtech.common.core.domain.entity.SysUser; +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户表 数据层 + * + * @author inscloudtech + */ +public interface SysUserMapper extends BaseMapperPlus { + + @DataPermission({ + @DataColumn(key = "deptName", value = "d.dept_id"), + @DataColumn(key = "userName", value = "u.user_id") + }) + Page selectPageUserList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + /** + * 根据条件分页查询用户列表 + * + * @param queryWrapper 查询条件 + * @return 用户信息集合信息 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "d.dept_id"), + @DataColumn(key = "userName", value = "u.user_id") + }) + List selectUserList(@Param(Constants.WRAPPER) Wrapper queryWrapper); + /** + * 根据条件分页查询已配用户角色列表 + * + * @param queryWrapper 查询条件 + * @return 用户信息集合信息 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "d.dept_id"), + @DataColumn(key = "userName", value = "u.user_id") + }) + Page selectAllocatedList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param queryWrapper 查询条件 + * @return 用户信息集合信息 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "d.dept_id"), + @DataColumn(key = "userName", value = "u.user_id") + }) + Page selectUnallocatedList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + SysUser selectUserByUserName(String userName); + /** + * 通过手机号查询用户 + * + * @param phonenumber 手机号 + * @return 用户对象信息 + */ + SysUser selectUserByPhonenumber(String phonenumber); + /** + * 通过邮箱查询用户 + * + * @param email 邮箱 + * @return 用户对象信息 + */ + SysUser selectUserByEmail(String email); + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + SysUser selectUserById(Long userId); + + List selectUserList4Job(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/mapper/SysUserPostMapper.java b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysUserPostMapper.java new file mode 100644 index 0000000..82af30e --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysUserPostMapper.java @@ -0,0 +1,13 @@ +package com.inscloudtech.system.mapper; + +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import com.inscloudtech.system.domain.SysUserPost; + +/** + * 用户与岗位关联表 数据层 + * + * @author inscloudtech + */ +public interface SysUserPostMapper extends BaseMapperPlus { + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/mapper/SysUserRoleMapper.java b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysUserRoleMapper.java new file mode 100644 index 0000000..3932c9b --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/mapper/SysUserRoleMapper.java @@ -0,0 +1,21 @@ +package com.inscloudtech.system.mapper; + +import com.inscloudtech.common.core.mapper.BaseMapperPlus; +import com.inscloudtech.system.domain.SysUserRole; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + * 用户与角色关联表 数据层 + * + * @author inscloudtech + */ +public interface SysUserRoleMapper extends BaseMapperPlus { + + List selectUserIdsByRoleId(Long roleId); + + @Select("select role_id from sys_user_role where user_id = #{userId}") + Long selectRoleIdByUserId(@Param("userId") Long userId); +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/mapper/es/EsLoginRecordMapper.java b/cas-system/src/main/java/com/inscloudtech/system/mapper/es/EsLoginRecordMapper.java new file mode 100644 index 0000000..8ba7c90 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/mapper/es/EsLoginRecordMapper.java @@ -0,0 +1,9 @@ +package com.inscloudtech.system.mapper.es; + +import com.inscloudtech.system.domain.vo.LoginRecordEntity; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 登录记录信息Mapper接口 + */ +public interface EsLoginRecordMapper extends BaseEsMapper {} diff --git a/cas-system/src/main/java/com/inscloudtech/system/mapper/es/EsSysOperUpdateLogMapper.java b/cas-system/src/main/java/com/inscloudtech/system/mapper/es/EsSysOperUpdateLogMapper.java new file mode 100644 index 0000000..90a603d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/mapper/es/EsSysOperUpdateLogMapper.java @@ -0,0 +1,9 @@ +package com.inscloudtech.system.mapper.es; + +import com.inscloudtech.system.domain.SysOperUpdateLog; +import org.dromara.easyes.core.core.BaseEsMapper; + +/** + * 操作记录信息Mapper接口 + */ +public interface EsSysOperUpdateLogMapper extends BaseEsMapper {} diff --git a/cas-system/src/main/java/com/inscloudtech/system/runner/SystemApplicationRunner.java b/cas-system/src/main/java/com/inscloudtech/system/runner/SystemApplicationRunner.java new file mode 100644 index 0000000..8350832 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/runner/SystemApplicationRunner.java @@ -0,0 +1,39 @@ +package com.inscloudtech.system.runner; + +import com.inscloudtech.common.config.ProjectConfig; +import com.inscloudtech.system.service.ISysConfigService; +import com.inscloudtech.system.service.ISysDictTypeService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; + +/** + * 初始化 system 模块对应业务数据 + * + * @author inscloudtech + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class SystemApplicationRunner implements ApplicationRunner { + + private final ProjectConfig ruoyiConfig; + private final ISysConfigService configService; + private final ISysDictTypeService dictTypeService; + + @Override + public void run(ApplicationArguments args) throws Exception { +// ossConfigService.init(); + log.info("初始化OSS配置成功"); +// if (ruoyiConfig.isCacheLazy()) { +// return; +// } + configService.loadingConfigCache(); + log.info("加载参数缓存数据成功"); + dictTypeService.loadingDictCache(); + log.info("加载字典缓存数据成功"); + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/ISysConfigService.java b/cas-system/src/main/java/com/inscloudtech/system/service/ISysConfigService.java new file mode 100644 index 0000000..5762bc1 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/ISysConfigService.java @@ -0,0 +1,85 @@ +package com.inscloudtech.system.service; + +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.system.domain.SysConfig; + +import java.util.List; + +/** + * 参数配置 服务层 + * + * @author inscloudtech + */ +public interface ISysConfigService { + + + TableDataInfo selectPageConfigList(SysConfig config, PageQuery pageQuery); + /** + * 查询参数配置信息 + * + * @param configId 参数配置ID + * @return 参数配置信息 + */ + SysConfig selectConfigById(Long configId); + /** + * 根据键名查询参数配置信息 + * + * @param configKey 参数键名 + * @return 参数键值 + */ + String selectConfigByKey(String configKey); + /** + * 获取验证码开关 + * + * @return true开启,false关闭 + */ + boolean selectCaptchaEnabled(); + /** + * 查询参数配置列表 + * + * @param config 参数配置信息 + * @return 参数配置集合 + */ + List selectConfigList(SysConfig config); + /** + * 新增参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + String insertConfig(SysConfig config); + /** + * 修改参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + String updateConfig(SysConfig config); + /** + * 批量删除参数信息 + * + * @param configIds 需要删除的参数ID + */ + void deleteConfigByIds(Long[] configIds); + /** + * 加载参数缓存数据 + */ + void loadingConfigCache(); + /** + * 清空参数缓存数据 + */ + void clearConfigCache(); + /** + * 重置参数缓存数据 + */ + void resetConfigCache(); + /** + * 校验参数键名是否唯一 + * + * @param config 参数信息 + * @return 结果 + */ + boolean checkConfigKeyUnique(SysConfig config); + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/ISysDataScopeService.java b/cas-system/src/main/java/com/inscloudtech/system/service/ISysDataScopeService.java new file mode 100644 index 0000000..a2e292d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/ISysDataScopeService.java @@ -0,0 +1,24 @@ +package com.inscloudtech.system.service; + +/** + * 通用 数据权限 服务 + * + * @author inscloudtech + */ +public interface ISysDataScopeService { + /** + * 获取角色自定义权限 + * + * @param roleId 角色id + * @return 部门id组 + */ + String getRoleCustom(Long roleId); + /** + * 获取部门及以下权限 + * + * @param deptId 部门id + * @return 部门id组 + */ + String getDeptAndChild(Long deptId); + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/ISysDeptService.java b/cas-system/src/main/java/com/inscloudtech/system/service/ISysDeptService.java new file mode 100644 index 0000000..43a3405 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/ISysDeptService.java @@ -0,0 +1,110 @@ +package com.inscloudtech.system.service; + +import cn.hutool.core.lang.tree.Tree; +import com.inscloudtech.common.core.domain.entity.SysDept; + +import java.util.List; + +/** + * 部门管理 服务层 + * + * @author inscloudtech + */ +public interface ISysDeptService { /** + * 查询部门管理数据 + * + * @param dept 部门信息 + * @return 部门信息集合 + */ + List selectDeptList(SysDept dept); + /** + * 查询部门树结构信息 + * + * @param dept 部门信息 + * @return 部门树信息集合 + */ + List> selectDeptTreeList(SysDept dept); + /** + * 构建前端所需要下拉树结构 + * + * @param depts 部门列表 + * @return 下拉树结构列表 + */ + List> buildDeptTreeSelect(List depts); + /** + * 根据角色ID查询部门树信息 + * + * @param roleId 角色ID + * @return 选中部门列表 + */ + List selectDeptListByRoleId(Long roleId); + /** + * 根据部门ID查询信息 + * + * @param deptId 部门ID + * @return 部门信息 + */ + SysDept selectDeptById(Long deptId); + /** + * 根据ID查询所有子部门数(正常状态) + * + * @param deptId 部门ID + * @return 子部门数 + */ + long selectNormalChildrenDeptById(Long deptId); + /** + * 是否存在部门子节点 + * + * @param deptId 部门ID + * @return 结果 + */ + boolean hasChildByDeptId(Long deptId); + /** + * 查询部门是否存在用户 + * + * @param deptId 部门ID + * @return 结果 true 存在 false 不存在 + */ + boolean checkDeptExistUser(Long deptId); + /** + * 校验部门名称是否唯一 + * + * @param dept 部门信息 + * @return 结果 + */ + boolean checkDeptNameUnique(SysDept dept); + /** + * 校验部门是否有数据权限 + * + * @param deptId 部门id + */ + void checkDeptDataScope(Long deptId); + /** + * 新增保存部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + int insertDept(SysDept dept); + /** + * 修改保存部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + int updateDept(SysDept dept); + /** + * 删除部门管理信息 + * + * @param deptId 部门ID + * @return 结果 + */ + int deleteDeptById(Long deptId); + + SysDept getDeptInfo(Long deptId); + + long getParentId(Long deptId); + + List getPlanDept(); + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/ISysDictDataService.java b/cas-system/src/main/java/com/inscloudtech/system/service/ISysDictDataService.java new file mode 100644 index 0000000..38f53d0 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/ISysDictDataService.java @@ -0,0 +1,60 @@ +package com.inscloudtech.system.service; + +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.entity.SysDictData; +import com.inscloudtech.common.core.page.TableDataInfo; + +import java.util.List; + +/** + * 字典 业务层 + * + * @author inscloudtech + */ +public interface ISysDictDataService { + + + TableDataInfo selectPageDictDataList(SysDictData dictData, PageQuery pageQuery); + /** + * 根据条件分页查询字典数据 + * + * @param dictData 字典数据信息 + * @return 字典数据集合信息 + */ + List selectDictDataList(SysDictData dictData); + /** + * 根据字典类型和字典键值查询字典数据信息 + * + * @param dictType 字典类型 + * @param dictValue 字典键值 + * @return 字典标签 + */ + String selectDictLabel(String dictType, String dictValue); + /** + * 根据字典数据ID查询信息 + * + * @param dictCode 字典数据ID + * @return 字典数据 + */ + SysDictData selectDictDataById(Long dictCode); + /** + * 批量删除字典数据信息 + * + * @param dictCodes 需要删除的字典数据ID + */ + void deleteDictDataByIds(Long[] dictCodes); + /** + * 新增保存字典数据信息 + * + * @param dictData 字典数据信息 + * @return 结果 + */ + List insertDictData(SysDictData dictData); + /** + * 修改保存字典数据信息 + * + * @param dictData 字典数据信息 + * @return 结果 + */ + List updateDictData(SysDictData dictData); +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/ISysDictTypeService.java b/cas-system/src/main/java/com/inscloudtech/system/service/ISysDictTypeService.java new file mode 100644 index 0000000..1458e57 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/ISysDictTypeService.java @@ -0,0 +1,85 @@ +package com.inscloudtech.system.service; + +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.entity.SysDictData; +import com.inscloudtech.common.core.domain.entity.SysDictType; +import com.inscloudtech.common.core.page.TableDataInfo; + +import java.util.List; + +/** + * 字典 业务层 + * + * @author inscloudtech + */ +public interface ISysDictTypeService { + + + TableDataInfo selectPageDictTypeList(SysDictType dictType, PageQuery pageQuery); + /** + * 根据条件分页查询字典类型 + * + * @param dictType 字典类型信息 + * @return 字典类型集合信息 + */ + List selectDictTypeList(SysDictType dictType); + /** + * 根据所有字典类型 + * + * @return 字典类型集合信息 + */ + List selectDictTypeAll(); + /** + * 根据字典类型查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据集合信息 + */ + List selectDictDataByType(String dictType); + /** + * 根据字典类型ID查询信息 + * + * @param dictId 字典类型ID + * @return 字典类型 + */ + SysDictType selectDictTypeById(Long dictId); + /** + * 批量删除字典信息 + * + * @param dictIds 需要删除的字典ID + */ + void deleteDictTypeByIds(Long[] dictIds); + /** + * 加载字典缓存数据 + */ + void loadingDictCache(); + /** + * 清空字典缓存数据 + */ + void clearDictCache(); + /** + * 重置字典缓存数据 + */ + void resetDictCache(); + /** + * 新增保存字典类型信息 + * + * @param dictType 字典类型信息 + * @return 结果 + */ + List insertDictType(SysDictType dictType); + /** + * 修改保存字典类型信息 + * + * @param dictType 字典类型信息 + * @return 结果 + */ + List updateDictType(SysDictType dictType); + /** + * 校验字典类型称是否唯一 + * + * @param dictType 字典类型 + * @return 结果 + */ + boolean checkDictTypeUnique(SysDictType dictType); +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/ISysLogininforService.java b/cas-system/src/main/java/com/inscloudtech/system/service/ISysLogininforService.java new file mode 100644 index 0000000..cee693c --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/ISysLogininforService.java @@ -0,0 +1,42 @@ +package com.inscloudtech.system.service; + +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.system.domain.SysLogininfor; + +import java.util.List; + +/** + * 系统访问日志情况信息 服务层 + * + * @author inscloudtech + */ +public interface ISysLogininforService { + + + TableDataInfo selectPageLogininforList(SysLogininfor logininfor, PageQuery pageQuery); + /** + * 新增系统登录日志 + * + * @param logininfor 访问日志对象 + */ + void insertLogininfor(SysLogininfor logininfor); + /** + * 查询系统登录日志集合 + * + * @param logininfor 访问日志对象 + * @return 登录记录集合 + */ + List selectLogininforList(SysLogininfor logininfor); + /** + * 批量删除系统登录日志 + * + * @param infoIds 需要删除的登录日志ID + * @return 结果 + */ + int deleteLogininforByIds(Long[] infoIds); + /** + * 清空系统登录日志 + */ + void cleanLogininfor(); +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/ISysMenuService.java b/cas-system/src/main/java/com/inscloudtech/system/service/ISysMenuService.java new file mode 100644 index 0000000..149059b --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/ISysMenuService.java @@ -0,0 +1,130 @@ +package com.inscloudtech.system.service; + +import cn.hutool.core.lang.tree.Tree; +import com.inscloudtech.common.core.domain.entity.SysMenu; +import com.inscloudtech.system.domain.vo.RouterVo; + +import java.util.List; +import java.util.Set; + +/** + * 菜单 业务层 + * + * @author inscloudtech + */ +public interface ISysMenuService { + /** + * 根据用户查询系统菜单列表 + * + * @param userId 用户ID + * @return 菜单列表 + */ + List selectMenuList(Long userId); + /** + * 根据用户查询系统菜单列表 + * + * @param menu 菜单信息 + * @param userId 用户ID + * @return 菜单列表 + */ + List selectMenuList(SysMenu menu, Long userId); + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + Set selectMenuPermsByUserId(Long userId); + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + Set selectMenuPermsByRoleId(Long roleId); + /** + * 根据用户ID查询菜单树信息 + * + * @param userId 用户ID + * @return 菜单列表 + */ + List selectMenuTreeByUserId(Long userId); + /** + * 根据角色ID查询菜单树信息 + * + * @param roleId 角色ID + * @return 选中菜单列表 + */ + List selectMenuListByRoleId(Long roleId); + + /** + * 根据角色ID查询菜单树name信息 + * + * @param roleId 角色ID + * @return 选中菜单列表 + */ + List selectMenuNameListByRoleId(Long roleId); + /** + * 构建前端路由所需要的菜单 + * + * @param menus 菜单列表 + * @return 路由列表 + */ + List buildMenus(List menus); + /** + * 构建前端所需要下拉树结构 + * + * @param menus 菜单列表 + * @return 下拉树结构列表 + */ + List> buildMenuTreeSelect(List menus); + /** + * 根据菜单ID查询信息 + * + * @param menuId 菜单ID + * @return 菜单信息 + */ + SysMenu selectMenuById(Long menuId); + /** + * 是否存在菜单子节点 + * + * @param menuId 菜单ID + * @return 结果 true 存在 false 不存在 + */ + boolean hasChildByMenuId(Long menuId); + /** + * 查询菜单是否存在角色 + * + * @param menuId 菜单ID + * @return 结果 true 存在 false 不存在 + */ + boolean checkMenuExistRole(Long menuId); + /** + * 新增保存菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + int insertMenu(SysMenu menu); + /** + * 修改保存菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + int updateMenu(SysMenu menu); + /** + * 删除菜单管理信息 + * + * @param menuId 菜单ID + * @return 结果 + */ + int deleteMenuById(Long menuId); + /** + * 校验菜单名称是否唯一 + * + * @param menu 菜单信息 + * @return 结果 + */ + boolean checkMenuNameUnique(SysMenu menu); +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/ISysNoticeService.java b/cas-system/src/main/java/com/inscloudtech/system/service/ISysNoticeService.java new file mode 100644 index 0000000..d56dfa8 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/ISysNoticeService.java @@ -0,0 +1,60 @@ +package com.inscloudtech.system.service; + +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.system.domain.SysNotice; + +import java.util.List; + +/** + * 公告 服务层 + * + * @author inscloudtech + */ +public interface ISysNoticeService { + + + TableDataInfo selectPageNoticeList(SysNotice notice, PageQuery pageQuery); + /** + * 查询公告信息 + * + * @param noticeId 公告ID + * @return 公告信息 + */ + SysNotice selectNoticeById(Long noticeId); + /** + * 查询公告列表 + * + * @param notice 公告信息 + * @return 公告集合 + */ + List selectNoticeList(SysNotice notice); + /** + * 新增公告 + * + * @param notice 公告信息 + * @return 结果 + */ + int insertNotice(SysNotice notice); + /** + * 修改公告 + * + * @param notice 公告信息 + * @return 结果 + */ + int updateNotice(SysNotice notice); + /** + * 删除公告信息 + * + * @param noticeId 公告ID + * @return 结果 + */ + int deleteNoticeById(Long noticeId); + /** + * 批量删除公告信息 + * + * @param noticeIds 需要删除的公告ID + * @return 结果 + */ + int deleteNoticeByIds(Long[] noticeIds); +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/ISysNotifyMessageService.java b/cas-system/src/main/java/com/inscloudtech/system/service/ISysNotifyMessageService.java new file mode 100644 index 0000000..f2c1135 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/ISysNotifyMessageService.java @@ -0,0 +1,47 @@ +package com.inscloudtech.system.service; + +import com.inscloudtech.system.domain.SysNotifyMessage; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.core.domain.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 站内信消息Service接口 + * + * @author inscloudtech + * @date 2023-06-02 + */ +public interface ISysNotifyMessageService { + /** + * 查询站内信消息 + */ + SysNotifyMessage queryById(Long id); + /** + * 查询站内信消息列表 + */ + TableDataInfo queryPageList(SysNotifyMessage bo, PageQuery pageQuery); + /** + * 查询站内信消息列表 + */ + List queryList(SysNotifyMessage bo); + /** + * 新增站内信消息 + */ + Boolean insert(SysNotifyMessage bo); + /** + * 修改站内信消息 + */ + Boolean update(SysNotifyMessage bo); + /** + * 校验并批量删除站内信消息信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + Boolean updateNotifyMessageRead(Long[] ids, Long userId); + + Boolean updateAllNotifyMessageRead(Long userId); + + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/ISysNotifyTemplateService.java b/cas-system/src/main/java/com/inscloudtech/system/service/ISysNotifyTemplateService.java new file mode 100644 index 0000000..53fc68b --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/ISysNotifyTemplateService.java @@ -0,0 +1,44 @@ +package com.inscloudtech.system.service; + +import com.inscloudtech.system.domain.SysNotifyTemplate; +import com.inscloudtech.system.domain.vo.SysNotifyTemplateVo; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.core.domain.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 站内信模板Service接口 + * + * @author inscloudtech + * @date 2023-06-07 + */ +public interface ISysNotifyTemplateService { + /** + * 查询站内信模板 + */ + SysNotifyTemplateVo queryById(Long id); + /** + * 查询站内信模板列表 + */ + TableDataInfo queryPageList(SysNotifyTemplate bo, PageQuery pageQuery); + /** + * 查询站内信模板列表 + */ + List queryList(SysNotifyTemplate bo); + /** + * 新增站内信模板 + */ + Boolean insertByBo(SysNotifyTemplate bo); + /** + * 修改站内信模板 + */ + Boolean updateByBo(SysNotifyTemplate bo); + /** + * 校验并批量删除站内信模板信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + int sendSingleNotify(Long userId, String code, String params); +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/ISysOperLogService.java b/cas-system/src/main/java/com/inscloudtech/system/service/ISysOperLogService.java new file mode 100644 index 0000000..dfb2eb7 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/ISysOperLogService.java @@ -0,0 +1,53 @@ +package com.inscloudtech.system.service; + + +import com.inscloudtech.caseMange.domain.vo.QueryOperateLogReq; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.system.domain.SysOperLog; +import com.inscloudtech.system.domain.vo.LoginRecordEntity; + +import java.util.List; + +/** + * 操作日志 服务层 + * + * @author inscloudtech + */ +public interface ISysOperLogService { + + TableDataInfo selectPageOperLogList(SysOperLog operLog, PageQuery pageQuery); + /** + * 新增操作日志 + * + * @param operLog 操作日志对象 + */ + void insertOperlog(SysOperLog operLog); + /** + * 查询系统操作日志集合 + * + * @param operLog 操作日志对象 + * @return 操作日志集合 + */ + List selectOperLogList(SysOperLog operLog); + /** + * 批量删除系统操作日志 + * + * @param operIds 需要删除的操作日志ID + * @return 结果 + */ + int deleteOperLogByIds(Long[] operIds); + /** + * 查询操作日志详细 + * + * @param operId 操作ID + * @return 操作日志对象 + */ + SysOperLog selectOperLogById(Long operId); + /** + * 清空操作日志 + */ + void cleanOperLog(); + + TableDataInfo queryOperateLogV2(QueryOperateLogReq req); +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/ISysOperUpdateLogService.java b/cas-system/src/main/java/com/inscloudtech/system/service/ISysOperUpdateLogService.java new file mode 100644 index 0000000..176f3be --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/ISysOperUpdateLogService.java @@ -0,0 +1,43 @@ +package com.inscloudtech.system.service; + +import com.inscloudtech.system.domain.SysOperUpdateLog; +import com.inscloudtech.system.domain.vo.SysOperUpdateLogVo; +import com.inscloudtech.system.domain.bo.SysOperUpdateLogBo; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.core.domain.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 操作日志记录Service接口 + * + * @author inscloudtech + * @date 2023-05-18 + */ +public interface ISysOperUpdateLogService { + /** + * 查询操作日志记录 + */ + SysOperUpdateLogVo queryById(Long operId); + /** + * 查询操作日志记录列表 + */ + TableDataInfo queryPageList(SysOperUpdateLogBo bo, PageQuery pageQuery); + /** + * 查询操作日志记录列表 + */ + List queryList(SysOperUpdateLogBo bo); + /** + * 新增操作日志记录 + */ + Boolean insertByBo(SysOperUpdateLogBo bo); + /** + * 修改操作日志记录 + */ + Boolean updateByBo(SysOperUpdateLogBo bo); + /** + * 校验并批量删除操作日志记录信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/ISysOssService.java b/cas-system/src/main/java/com/inscloudtech/system/service/ISysOssService.java new file mode 100644 index 0000000..5dee02f --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/ISysOssService.java @@ -0,0 +1,56 @@ +package com.inscloudtech.system.service; + + +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.system.domain.SysOss; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 文件上传 服务层 + * + * @author inscloudtech + */ +public interface ISysOssService { + + TableDataInfo queryPageList(SysOss sysOss, PageQuery pageQuery); + + List listByIds(Collection ossIds); + + SysOss getById(String ossId); + + SysOss upload(MultipartFile file); + + void download(String ossId, HttpServletResponse response) throws IOException; + + Boolean deleteWithValidByIds(Collection ids); + + SysOss upload(MultipartFile file, String caseId, String businessModule); + + SysOss upload2Local(int importCount,String importResult, MultipartFile file, String caseId, String businessModule); + + List queryList(SysOss bo); + + Boolean updateBatch(List list); + + void downloadLocal(String fileName,String originalName,HttpServletResponse response); + + void deleteByCaseIdAndBusinessModule(String caseId,String businessModule); + + void deleteByCaseId(String caseId); + + void upload2LocalWithBatchId(MultipartFile file, String caseId, String bank_statement, String batchId,int uploadResult); + + void save2AnalysisResult(AnalysisDto dto); + + void caseMerge(String sourceCaseId, String targetCaseId, String businessModule); + + void analysisResultMerge(Map sourceArIdTargetArIdMap, String businessModule); +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/ISysPostService.java b/cas-system/src/main/java/com/inscloudtech/system/service/ISysPostService.java new file mode 100644 index 0000000..6bb1230 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/ISysPostService.java @@ -0,0 +1,94 @@ +package com.inscloudtech.system.service; + +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.system.domain.SysPost; + +import java.util.List; + +/** + * 岗位信息 服务层 + * + * @author inscloudtech + */ +public interface ISysPostService { + + + TableDataInfo selectPagePostList(SysPost post, PageQuery pageQuery); + /** + * 查询岗位信息集合 + * + * @param post 岗位信息 + * @return 岗位列表 + */ + List selectPostList(SysPost post); + /** + * 查询所有岗位 + * + * @return 岗位列表 + */ + List selectPostAll(); + /** + * 通过岗位ID查询岗位信息 + * + * @param postId 岗位ID + * @return 角色对象信息 + */ + SysPost selectPostById(Long postId); + /** + * 根据用户ID获取岗位选择框列表 + * + * @param userId 用户ID + * @return 选中岗位ID列表 + */ + List selectPostListByUserId(Long userId); + /** + * 校验岗位名称 + * + * @param post 岗位信息 + * @return 结果 + */ + boolean checkPostNameUnique(SysPost post); + /** + * 校验岗位编码 + * + * @param post 岗位信息 + * @return 结果 + */ + boolean checkPostCodeUnique(SysPost post); + /** + * 通过岗位ID查询岗位使用数量 + * + * @param postId 岗位ID + * @return 结果 + */ + long countUserPostById(Long postId); + /** + * 删除岗位信息 + * + * @param postId 岗位ID + * @return 结果 + */ + int deletePostById(Long postId); + /** + * 批量删除岗位信息 + * + * @param postIds 需要删除的岗位ID + * @return 结果 + */ + int deletePostByIds(Long[] postIds); + /** + * 新增保存岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + int insertPost(SysPost post); + /** + * 修改保存岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + int updatePost(SysPost post); +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/ISysRoleService.java b/cas-system/src/main/java/com/inscloudtech/system/service/ISysRoleService.java new file mode 100644 index 0000000..cab4e30 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/ISysRoleService.java @@ -0,0 +1,168 @@ +package com.inscloudtech.system.service; + +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.entity.SysRole; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.system.domain.SysUserRole; + +import java.util.List; +import java.util.Set; + +/** + * 角色业务层 + * + * @author inscloudtech + */ +public interface ISysRoleService { + + + TableDataInfo selectPageRoleList(SysRole role, PageQuery pageQuery); + /** + * 根据条件分页查询角色数据 + * + * @param role 角色信息 + * @return 角色数据集合信息 + */ + List selectRoleList(SysRole role); + /** + * 根据用户ID查询角色列表 + * + * @param userId 用户ID + * @return 角色列表 + */ + List selectRolesByUserId(Long userId); + /** + * 根据用户ID查询角色权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + Set selectRolePermissionByUserId(Long userId); + /** + * 查询所有角色 + * + * @return 角色列表 + */ + List selectRoleAll(); + /** + * 根据用户ID获取角色选择框列表 + * + * @param userId 用户ID + * @return 选中角色ID列表 + */ + List selectRoleListByUserId(Long userId); + /** + * 通过角色ID查询角色 + * + * @param roleId 角色ID + * @return 角色对象信息 + */ + SysRole selectRoleById(Long roleId); + /** + * 带了menuInfo + * @param roleId + * @return + */ + SysRole selectRoleInfoById(Long roleId); + + /** + * 校验角色名称是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + boolean checkRoleNameUnique(SysRole role); + /** + * 校验角色权限是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + boolean checkRoleKeyUnique(SysRole role); + /** + * 校验角色是否允许操作 + * + * @param role 角色信息 + */ + void checkRoleAllowed(SysRole role); + /** + * 校验角色是否有数据权限 + * + * @param roleId 角色id + */ + void checkRoleDataScope(Long roleId); + /** + * 通过角色ID查询角色使用数量 + * + * @param roleId 角色ID + * @return 结果 + */ + long countUserRoleByRoleId(Long roleId); + /** + * 新增保存角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + int insertRole(SysRole role); + /** + * 修改保存角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + int updateRole(SysRole role); + /** + * 修改角色状态 + * + * @param role 角色信息 + * @return 结果 + */ + int updateRoleStatus(SysRole role); + /** + * 修改数据权限信息 + * + * @param role 角色信息 + * @return 结果 + */ + int authDataScope(SysRole role); + /** + * 通过角色ID删除角色 + * + * @param roleId 角色ID + * @return 结果 + */ + int deleteRoleById(Long roleId); + /** + * 批量删除角色信息 + * + * @param roleIds 需要删除的角色ID + * @return 结果 + */ + int deleteRoleByIds(Long[] roleIds); + /** + * 取消授权用户角色 + * + * @param userRole 用户和角色关联信息 + * @return 结果 + */ + int deleteAuthUser(SysUserRole userRole); + /** + * 批量取消授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要取消授权的用户数据ID + * @return 结果 + */ + int deleteAuthUsers(Long roleId, Long[] userIds); + /** + * 批量选择授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要删除的用户数据ID + * @return 结果 + */ + int insertAuthUsers(Long roleId, Long[] userIds); + + void cleanOnlineUserByRole(Long roleId); +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/ISysUserService.java b/cas-system/src/main/java/com/inscloudtech/system/service/ISysUserService.java new file mode 100644 index 0000000..6d1b2ae --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/ISysUserService.java @@ -0,0 +1,193 @@ +package com.inscloudtech.system.service; + +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.entity.SysDept; +import com.inscloudtech.common.core.domain.entity.SysUser; +import com.inscloudtech.common.core.page.TableDataInfo; + +import java.util.List; + +/** + * 用户 业务层 + * + * @author inscloudtech + */ +public interface ISysUserService { + + + TableDataInfo selectPageUserList(SysUser user, PageQuery pageQuery); + /** + * 根据条件分页查询用户列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + List selectUserList(SysUser user); + /** + * 根据条件分页查询已分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + TableDataInfo selectAllocatedList(SysUser user, PageQuery pageQuery); + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + TableDataInfo selectUnallocatedList(SysUser user, PageQuery pageQuery); + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + SysUser selectUserByUserName(String userName); + /** + * 通过手机号查询用户 + * + * @param phonenumber 手机号 + * @return 用户对象信息 + */ + SysUser selectUserByPhonenumber(String phonenumber); + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + SysUser selectUserById(Long userId); + /** + * 根据用户ID查询用户所属角色组 + * + * @param userName 用户名 + * @return 结果 + */ + String selectUserRoleGroup(String userName); + /** + * 根据用户ID查询用户所属岗位组 + * + * @param userName 用户名 + * @return 结果 + */ + String selectUserPostGroup(String userName); + /** + * 校验用户名称是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + boolean checkUserNameUnique(SysUser user); + /** + * 校验手机号码是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + boolean checkPhoneUnique(SysUser user); + /** + * 校验email是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + boolean checkEmailUnique(SysUser user); + /** + * 校验用户是否允许操作 + * + * @param user 用户信息 + */ + void checkUserAllowed(SysUser user); + /** + * 校验用户是否有数据权限 + * + * @param userId 用户id + */ + void checkUserDataScope(Long userId); + /** + * 新增用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + int insertUser(SysUser user); + /** + * 注册用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + boolean registerUser(SysUser user); + /** + * 修改用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + int updateUser(SysUser user); + /** + * 用户授权角色 + * + * @param userId 用户ID + * @param roleIds 角色组 + */ + void insertUserAuth(Long userId, Long[] roleIds); + /** + * 修改用户状态 + * + * @param user 用户信息 + * @return 结果 + */ + int updateUserStatus(SysUser user); + /** + * 修改用户基本信息 + * + * @param user 用户信息 + * @return 结果 + */ + int updateUserProfile(SysUser user); + /** + * 修改用户头像 + * + * @param userName 用户名 + * @param avatar 头像地址 + * @return 结果 + */ + boolean updateUserAvatar(String userName, String avatar); + /** + * 重置用户密码 + * + * @param user 用户信息 + * @return 结果 + */ + int resetPwd(SysUser user); + /** + * 重置用户密码 + * + * @param userName 用户名 + * @param password 密码 + * @return 结果 + */ + int resetUserPwd(String userName, String password); + /** + * 通过用户ID删除用户 + * + * @param userId 用户ID + * @return 结果 + */ + int deleteUserById(Long userId); + /** + * 批量删除用户信息 + * + * @param userIds 需要删除的用户ID + * @return 结果 + */ + int deleteUserByIds(Long[] userIds); + + void updateByUsername(SysUser dbUser); + + SysDept getDzDept(); + + void freezeUser(Long userId); +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/LoginRecordHelper.java b/cas-system/src/main/java/com/inscloudtech/system/service/LoginRecordHelper.java new file mode 100644 index 0000000..626fb30 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/LoginRecordHelper.java @@ -0,0 +1,147 @@ +package com.inscloudtech.system.service; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; + +import cn.hutool.json.JSONObject; +import com.inscloudtech.caseMange.domain.vo.GetLoginRecordFieldValueCountReq; +import com.inscloudtech.datacenter.domain.dto.StatisticsOption; +import com.inscloudtech.system.mapper.es.EsLoginRecordMapper; + +import com.inscloudtech.system.domain.vo.LoginRecordEntity; + +import lombok.RequiredArgsConstructor; +import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper; +import org.dromara.easyes.core.core.EsWrappers; +import org.elasticsearch.action.search.SearchRequest; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.client.RequestOptions; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.search.aggregations.Aggregation; +import org.elasticsearch.search.aggregations.AggregationBuilder; +import org.elasticsearch.search.aggregations.AggregationBuilders; +import org.elasticsearch.search.aggregations.Aggregations; +import org.elasticsearch.search.aggregations.bucket.terms.Terms; +import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.springframework.stereotype.Component; + + +import java.io.IOException; +import java.util.*; + +@RequiredArgsConstructor +@Component +public class LoginRecordHelper { + + private final EsLoginRecordMapper loginRecordMapper; + private final RestHighLevelClient restHighLevelClient; + + // 保存登录记录信息 + public void saveLoginRecord(Long userId, String userName, String idCardNo, String permissionType) { + + // 一人一条登录记录,登录时间 + LoginRecordEntity loginRecord = getLoginRecordEntity(idCardNo); + if (loginRecord != null) { + + loginRecord.setLoginDate(new Date().getTime()); + + loginRecordMapper.updateById(loginRecord); + + return; + } + + LoginRecordEntity entity = new LoginRecordEntity(); + entity.setId(IdUtil.objectId()); + entity.setUserId(userId); + entity.setUserName(userName); + entity.setIdCardNo(idCardNo); + entity.setLoginDate(new Date().getTime()); + entity.setPermissionType(permissionType); + entity.setCreatedTime(new Date().getTime()); + entity.setUpdatedTime(new Date().getTime()); + + loginRecordMapper.insert(entity); + } + + + private LoginRecordEntity getLoginRecordEntity(String idCardNo) { + try { + + LambdaEsQueryWrapper lambdaQuery = EsWrappers.lambdaQuery(LoginRecordEntity.class); + lambdaQuery.like(StrUtil.isNotEmpty(idCardNo), LoginRecordEntity::getIdCardNo, idCardNo); + + return loginRecordMapper.selectOne(lambdaQuery); + } catch (Exception e) { + return null; + } + } + + public JSONObject getFieldsValueCount(GetLoginRecordFieldValueCountReq req) throws IOException { + + List fields = req.getFields(); + + GetLoginRecordFieldValueCountReq.Params params = req.getParams(); + if (params != null) { + req.setBeginLoginDate(params.getBeginLoginDate()); + req.setEndLoginDate(params.getEndLoginDate()); + } + + LambdaEsQueryWrapper lambdaQuery = EsWrappers.lambdaQuery(LoginRecordEntity.class); + lambdaQuery.size(0); + // userId + lambdaQuery.eq(StrUtil.isNotEmpty(req.getUserId()), LoginRecordEntity::getUserId, req.getUserId()); + // username + lambdaQuery.like(StrUtil.isNotEmpty(req.getUserName()), LoginRecordEntity::getUserName, req.getUserName()); + // idCardNo + lambdaQuery.like(StrUtil.isNotEmpty(req.getIdCardNo()), LoginRecordEntity::getIdCardNo, req.getIdCardNo()); + // permissionType + lambdaQuery.eq(StrUtil.isNotEmpty(req.getPermissionType()), LoginRecordEntity::getPermissionType, req.getPermissionType()); + // 时间 + if (StrUtil.isNotEmpty(req.getBeginLoginDate()) && StrUtil.isNotEmpty(req.getEndLoginDate())) { + lambdaQuery.between(LoginRecordEntity::getLoginDate, DateUtil.parse(req.getBeginLoginDate()).getTime(), DateUtil.parse(req.getEndLoginDate()).getTime()); + } + + JSONObject resJson = new JSONObject(); + + SearchSourceBuilder searchSourceBuilder = loginRecordMapper.getSearchSourceBuilder(lambdaQuery); + + for (String field : fields) { + AggregationBuilder agg = AggregationBuilders.terms("groupBy_" + field) + .field(field + ".keyword") + .size(1000); + searchSourceBuilder.aggregation(agg); + } + + SearchRequest searchRequest = new SearchRequest("sys_login_record"); + searchRequest.source(searchSourceBuilder); + + SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); + Aggregations aggregations = search.getAggregations(); + // 获取name字段的聚合结果 + Map map = aggregations.asMap(); + for (String field : fields) { + String groupByField = "groupBy_" + field; + if (map.containsKey(groupByField)) { + Terms terms = (Terms) map.get(groupByField); + List buckets = terms.getBuckets(); + List tempList = new ArrayList<>(); + for (Terms.Bucket bucket : buckets) { + StatisticsOption statisticsOption = new StatisticsOption(); + String value = bucket.getKey().toString(); + statisticsOption.setLabel(StrUtil.isEmpty(value) ? "其他" : value); + statisticsOption.setField(value); + statisticsOption.setValue(value); + statisticsOption.setCount(bucket.getDocCount()); + tempList.add(statisticsOption); + } + + tempList.sort(Comparator.comparing(StatisticsOption::getValue)); + + resJson.put(field, tempList); + } + } + + return resJson; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/SysLoginService.java b/cas-system/src/main/java/com/inscloudtech/system/service/SysLoginService.java new file mode 100644 index 0000000..65562cf --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/SysLoginService.java @@ -0,0 +1,339 @@ +package com.inscloudtech.system.service; + +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.secure.BCrypt; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.inscloudtech.common.constant.CacheConstants; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.core.domain.event.LogininforEvent; +import com.inscloudtech.common.core.domain.dto.RoleDTO; +import com.inscloudtech.common.core.domain.entity.SysUser; +import com.inscloudtech.common.core.domain.model.LoginUser; +import com.inscloudtech.common.core.domain.model.XcxLoginUser; +import com.inscloudtech.common.enums.DeviceType; +import com.inscloudtech.common.enums.LoginType; +import com.inscloudtech.common.enums.UserStatus; +import com.inscloudtech.common.exception.user.CaptchaException; +import com.inscloudtech.common.exception.user.CaptchaExpireException; +import com.inscloudtech.common.exception.user.UserException; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.common.utils.DateUtils; +import com.inscloudtech.common.utils.MessageUtils; +import com.inscloudtech.common.utils.ServletUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.redis.RedisUtils; +import com.inscloudtech.common.utils.spring.SpringUtils; +import com.inscloudtech.system.mapper.SysUserMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.time.Duration; +import java.util.List; +import java.util.function.Supplier; + +/** + * 登录校验方法 + * + * @author inscloudtech + */ +@RequiredArgsConstructor +@Slf4j +@Service +public class SysLoginService { + + private final SysUserMapper userMapper; + private final ISysConfigService configService; + private final SysPermissionService permissionService; + + @Value("${user.password.maxRetryCount}") + private Integer maxRetryCount; + + @Value("${user.password.lockTime}") + private Integer lockTime; + /** + * 登录验证 + * + * @param username 用户名 + * @param password 密码 + * @param code 验证码 + * @param uuid 唯一标识 + * @return 结果 + */ + public String login(String username, String password, String code, String uuid) { + boolean captchaEnabled = configService.selectCaptchaEnabled(); + // 验证码开关 + if (captchaEnabled) { + validateCaptcha(username, code, uuid); + } + SysUser user = loadUserByUsername(username); + checkLogin(LoginType.PASSWORD, username, () -> !BCrypt.checkpw(password, user.getPassword())); + // 此处可根据登录用户的数据不同 自行创建 loginUser + LoginUser loginUser = buildLoginUser(user); + // 生成token + LoginHelper.loginByDevice(loginUser, DeviceType.PC); + + recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); + recordLoginInfo(user.getUserId(), username); + return StpUtil.getTokenValue(); + } + + public String smsLogin(String phonenumber, String smsCode) { + // 通过手机号查找用户 + SysUser user = loadUserByPhonenumber(phonenumber); + + checkLogin(LoginType.SMS, user.getUserName(), () -> !validateSmsCode(phonenumber, smsCode)); + // 此处可根据登录用户的数据不同 自行创建 loginUser + LoginUser loginUser = buildLoginUser(user); + // 生成token + LoginHelper.loginByDevice(loginUser, DeviceType.APP); + + recordLogininfor(user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); + recordLoginInfo(user.getUserId(), user.getUserName()); + return StpUtil.getTokenValue(); + } + + public String emailLogin(String email, String emailCode) { + // 通过手机号查找用户 + SysUser user = loadUserByEmail(email); + + checkLogin(LoginType.EMAIL, user.getUserName(), () -> !validateEmailCode(email, emailCode)); + // 此处可根据登录用户的数据不同 自行创建 loginUser + LoginUser loginUser = buildLoginUser(user); + // 生成token + LoginHelper.loginByDevice(loginUser, DeviceType.APP); + + recordLogininfor(user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); + recordLoginInfo(user.getUserId(), user.getUserName()); + return StpUtil.getTokenValue(); + } + + public String xcxLogin(String xcxCode) { + // xcxCode 为 小程序调用 wx.login 授权后获取 + // todo 以下自行实现 + // 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key 与 openid + String openid = ""; + SysUser user = loadUserByOpenid(openid); + + // 此处可根据登录用户的数据不同 自行创建 loginUser + XcxLoginUser loginUser = new XcxLoginUser(); + loginUser.setUserId(user.getUserId()); + loginUser.setUsername(user.getUserName()); + loginUser.setUserType(user.getUserType()); + loginUser.setOpenid(openid); + // 生成token + LoginHelper.loginByDevice(loginUser, DeviceType.XCX); + + recordLogininfor(user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); + recordLoginInfo(user.getUserId(), user.getUserName()); + return StpUtil.getTokenValue(); + } + /** + * 退出登录 + */ + public void logout() { + try { + LoginUser loginUser = LoginHelper.getLoginUser(); + StpUtil.logout(); + recordLogininfor(loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success")); + } catch (NotLoginException ignored) { + } + } + /** + * 记录登录信息 + * + * @param username 用户名 + * @param status 状态 + * @param message 消息内容 + */ + private void recordLogininfor(String username, String status, String message) { + LogininforEvent logininforEvent = new LogininforEvent(); + logininforEvent.setUsername(username); + logininforEvent.setStatus(status); + logininforEvent.setMessage(message); + logininforEvent.setRequest(ServletUtils.getRequest()); + SpringUtils.context().publishEvent(logininforEvent); + } + /** + * 校验短信验证码 + */ + private boolean validateSmsCode(String phonenumber, String smsCode) { + String code = RedisUtils.getCacheObject(CacheConstants.CAPTCHA_CODE_KEY + phonenumber); + if (StringUtils.isBlank(code)) { + recordLogininfor(phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); + throw new CaptchaExpireException(); + } + return code.equals(smsCode); + } + /** + * 校验邮箱验证码 + */ + private boolean validateEmailCode(String email, String emailCode) { + String code = RedisUtils.getCacheObject(CacheConstants.CAPTCHA_CODE_KEY + email); + if (StringUtils.isBlank(code)) { + recordLogininfor(email, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); + throw new CaptchaExpireException(); + } + return code.equals(emailCode); + } + /** + * 校验验证码 + * + * @param username 用户名 + * @param code 验证码 + * @param uuid 唯一标识 + */ + public void validateCaptcha(String username, String code, String uuid) { + String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, ""); + String captcha = RedisUtils.getCacheObject(verifyKey); + RedisUtils.deleteObject(verifyKey); + if (captcha == null) { + recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); + throw new CaptchaExpireException(); + } + if (!code.equalsIgnoreCase(captcha)) { + recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")); + throw new CaptchaException(); + } + } + + private SysUser loadUserByUsername(String username) { + SysUser user = userMapper.selectOne(new LambdaQueryWrapper() + .select(SysUser::getUserName, SysUser::getStatus, SysUser::getNickName) + .eq(SysUser::getUserName, username)); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", username); + throw new UserException("user.not.exists", username); + } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", username); + throw new UserException("user.blocked", username); + } + return userMapper.selectUserByUserName(username); + } + + private SysUser loadUserByPhonenumber(String phonenumber) { + SysUser user = userMapper.selectOne(new LambdaQueryWrapper() + .select(SysUser::getPhonenumber, SysUser::getStatus) + .eq(SysUser::getPhonenumber, phonenumber)); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", phonenumber); + throw new UserException("user.not.exists", phonenumber); + } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", phonenumber); + throw new UserException("user.blocked", phonenumber); + } + return userMapper.selectUserByPhonenumber(phonenumber); + } + + private SysUser loadUserByEmail(String email) { + SysUser user = userMapper.selectOne(new LambdaQueryWrapper() + .select(SysUser::getPhonenumber, SysUser::getStatus) + .eq(SysUser::getEmail, email)); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", email); + throw new UserException("user.not.exists", email); + } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", email); + throw new UserException("user.blocked", email); + } + return userMapper.selectUserByEmail(email); + } + + private SysUser loadUserByOpenid(String openid) { + // 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户 + // todo 自行实现 userService.selectUserByOpenid(openid); + SysUser user = new SysUser(); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", openid); + // todo 用户不存在 业务逻辑自行实现 + } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", openid); + // todo 用户已被停用 业务逻辑自行实现 + } + return user; + } + /** + * 构建登录用户 + */ + private LoginUser buildLoginUser(SysUser user) { + LoginUser loginUser = new LoginUser(); + loginUser.setUserId(user.getUserId()); + loginUser.setDeptId(user.getDeptId()); + loginUser.setUsername(user.getUserName()); + loginUser.setNickname(user.getNickName()); + loginUser.setUserType(user.getUserType()); + loginUser.setMenuPermission(permissionService.getMenuPermission(user)); + loginUser.setRolePermission(permissionService.getRolePermission(user)); + loginUser.setDeptName(ObjectUtil.isNull(user.getDept()) ? "" : user.getDept().getDeptName()); + loginUser.setDeptCode(ObjectUtil.isNull(user.getDept()) ? "" : user.getDept().getDeptCode()); + List roles = BeanUtil.copyToList(user.getRoles(), RoleDTO.class); + loginUser.setRoles(roles); + return loginUser; + } + /** + * 记录登录信息 + * + * @param userId 用户ID + */ + public void recordLoginInfo(Long userId, String username) { + SysUser sysUser = new SysUser(); + sysUser.setUserId(userId); + sysUser.setLoginIp(ServletUtils.getClientIP()); + sysUser.setLoginDate(DateUtils.getNowDate()); + sysUser.setUpdateBy(username); + userMapper.updateById(sysUser); + } + /** + * 登录校验 + */ + private void checkLogin(LoginType loginType, String username, Supplier supplier) { + String errorKey = CacheConstants.PWD_ERR_CNT_KEY + username; + String loginFail = Constants.LOGIN_FAIL; + + // 获取用户登录错误次数(可自定义限制策略 例如: key + username + ip) + Integer errorNumber = RedisUtils.getCacheObject(errorKey); + // 锁定时间内登录 则踢出 + if (ObjectUtil.isNotNull(errorNumber) && errorNumber.equals(maxRetryCount)) { + recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); + throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); + } + + if (supplier.get()) { + // 是否第一次 + errorNumber = ObjectUtil.isNull(errorNumber) ? 1 : errorNumber + 1; + // 达到规定错误次数 则锁定登录 + if (errorNumber.equals(maxRetryCount)) { + RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime)); + recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); + throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); + } else { + // 未达到规定错误次数 则递增 + RedisUtils.setCacheObject(errorKey, errorNumber); + recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber)); + throw new UserException(loginType.getRetryLimitCount(), errorNumber); + } + } + + // 登录成功 清空错误次数 + RedisUtils.deleteObject(errorKey); + } + + public String usernameLogin(String username,String role) { + SysUser user = loadUserByUsername(username); + user.setFrRole(role); + userMapper.updateById(user); +// checkLogin(LoginType.PASSWORD, username, () -> !BCrypt.checkpw(password, user.getPassword())); + // 此处可根据登录用户的数据不同 自行创建 loginUser + LoginUser loginUser = buildLoginUser(user); + // 生成token + LoginHelper.loginByDevice(loginUser, DeviceType.PC); + + recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); + recordLoginInfo(user.getUserId(), username); + return StpUtil.getTokenValue(); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/SysPermissionService.java b/cas-system/src/main/java/com/inscloudtech/system/service/SysPermissionService.java new file mode 100644 index 0000000..ff6f185 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/SysPermissionService.java @@ -0,0 +1,53 @@ +package com.inscloudtech.system.service; + +import com.inscloudtech.common.core.domain.entity.SysUser; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.HashSet; +import java.util.Set; + +/** + * 用户权限处理 + * + * @author inscloudtech + */ +@RequiredArgsConstructor +@Service +public class SysPermissionService { + + private final ISysRoleService roleService; + private final ISysMenuService menuService; + /** + * 获取角色数据权限 + * + * @param user 用户信息 + * @return 角色权限信息 + */ + public Set getRolePermission(SysUser user) { + Set roles = new HashSet<>(); + // 管理员拥有所有权限 + if (user.isAdmin()) { + roles.add("admin"); + } else { + roles.addAll(roleService.selectRolePermissionByUserId(user.getUserId())); + } + return roles; + } + /** + * 获取菜单数据权限 + * + * @param user 用户信息 + * @return 菜单权限信息 + */ + public Set getMenuPermission(SysUser user) { + Set perms = new HashSet<>(); + // 管理员拥有所有权限 + if (user.isAdmin()) { + perms.add("*:*:*"); + } else { + perms.addAll(menuService.selectMenuPermsByUserId(user.getUserId())); + } + return perms; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/SysRegisterService.java b/cas-system/src/main/java/com/inscloudtech/system/service/SysRegisterService.java new file mode 100644 index 0000000..31676e6 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/SysRegisterService.java @@ -0,0 +1,98 @@ +package com.inscloudtech.system.service; + +import cn.dev33.satoken.secure.BCrypt; +import com.inscloudtech.common.constant.CacheConstants; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.core.domain.event.LogininforEvent; +import com.inscloudtech.common.core.domain.entity.SysUser; +import com.inscloudtech.common.core.domain.model.RegisterBody; +import com.inscloudtech.common.enums.UserType; +import com.inscloudtech.common.exception.user.CaptchaException; +import com.inscloudtech.common.exception.user.CaptchaExpireException; +import com.inscloudtech.common.exception.user.UserException; +import com.inscloudtech.common.utils.MessageUtils; +import com.inscloudtech.common.utils.ServletUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.redis.RedisUtils; +import com.inscloudtech.common.utils.spring.SpringUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +/** + * 注册校验方法 + * + * @author inscloudtech + */ +@RequiredArgsConstructor +@Service +public class SysRegisterService { + + private final ISysUserService userService; + private final ISysConfigService configService; + /** + * 注册 + */ + public void register(RegisterBody registerBody) { + String username = registerBody.getUsername(); + String password = registerBody.getPassword(); + // 校验用户类型是否存在 + String userType = UserType.getUserType(registerBody.getUserType()).getUserType(); + + boolean captchaEnabled = configService.selectCaptchaEnabled(); + // 验证码开关 + if (captchaEnabled) { + validateCaptcha(username, registerBody.getCode(), registerBody.getUuid()); + } + SysUser sysUser = new SysUser(); + sysUser.setUserName(username); + sysUser.setNickName(username); + sysUser.setPassword(BCrypt.hashpw(password)); + sysUser.setUserType(userType); + + if (!userService.checkUserNameUnique(sysUser)) { + throw new UserException("user.register.save.error", username); + } + boolean regFlag = userService.registerUser(sysUser); + if (!regFlag) { + throw new UserException("user.register.error"); + } + recordLogininfor(username, Constants.REGISTER, MessageUtils.message("user.register.success")); + } + /** + * 校验验证码 + * + * @param username 用户名 + * @param code 验证码 + * @param uuid 唯一标识 + */ + public void validateCaptcha(String username, String code, String uuid) { + String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, ""); + String captcha = RedisUtils.getCacheObject(verifyKey); + RedisUtils.deleteObject(verifyKey); + if (captcha == null) { + recordLogininfor(username, Constants.REGISTER, MessageUtils.message("user.jcaptcha.expire")); + throw new CaptchaExpireException(); + } + if (!code.equalsIgnoreCase(captcha)) { + recordLogininfor(username, Constants.REGISTER, MessageUtils.message("user.jcaptcha.error")); + throw new CaptchaException(); + } + } + /** + * 记录登录信息 + * + * @param username 用户名 + * @param status 状态 + * @param message 消息内容 + * @return + */ + private void recordLogininfor(String username, String status, String message) { + LogininforEvent logininforEvent = new LogininforEvent(); + logininforEvent.setUsername(username); + logininforEvent.setStatus(status); + logininforEvent.setMessage(message); + logininforEvent.setRequest(ServletUtils.getRequest()); + SpringUtils.context().publishEvent(logininforEvent); + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysConfigServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysConfigServiceImpl.java new file mode 100644 index 0000000..a7dda87 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysConfigServiceImpl.java @@ -0,0 +1,215 @@ +package com.inscloudtech.system.service.impl; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.inscloudtech.common.constant.CacheNames; +import com.inscloudtech.common.constant.UserConstants; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.core.service.ConfigService; +import com.inscloudtech.common.exception.ServiceException; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.redis.CacheUtils; +import com.inscloudtech.common.utils.spring.SpringUtils; +import com.inscloudtech.system.domain.SysConfig; +import com.inscloudtech.system.mapper.SysConfigMapper; +import com.inscloudtech.system.service.ISysConfigService; +import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * 参数配置 服务层实现 + * + * @author inscloudtech + */ +@RequiredArgsConstructor +@Service +public class SysConfigServiceImpl implements ISysConfigService, ConfigService { + + private final SysConfigMapper baseMapper; + + @Override + public TableDataInfo selectPageConfigList(SysConfig config, PageQuery pageQuery) { + Map params = config.getParams(); + LambdaQueryWrapper lqw = new LambdaQueryWrapper() + .like(StringUtils.isNotBlank(config.getConfigName()), SysConfig::getConfigName, config.getConfigName()) + .eq(StringUtils.isNotBlank(config.getConfigType()), SysConfig::getConfigType, config.getConfigType()) + .like(StringUtils.isNotBlank(config.getConfigKey()), SysConfig::getConfigKey, config.getConfigKey()) + .between(params.get("beginTime") != null && params.get("endTime") != null, + SysConfig::getCreateTime, params.get("beginTime"), params.get("endTime")); + Page page = baseMapper.selectPage(pageQuery.build(), lqw); + return TableDataInfo.build(page); + } + /** + * 查询参数配置信息 + * + * @param configId 参数配置ID + * @return 参数配置信息 + */ + @Override + @DS("master") + public SysConfig selectConfigById(Long configId) { + return baseMapper.selectById(configId); + } + /** + * 根据键名查询参数配置信息 + * + * @param configKey 参数key + * @return 参数键值 + */ + @Cacheable(cacheNames = CacheNames.SYS_CONFIG, key = "#configKey") + @Override + public String selectConfigByKey(String configKey) { + SysConfig retConfig = baseMapper.selectOne(new LambdaQueryWrapper() + .eq(SysConfig::getConfigKey, configKey)); + if (ObjectUtil.isNotNull(retConfig)) { + return retConfig.getConfigValue(); + } + return StringUtils.EMPTY; + } + /** + * 获取验证码开关 + * + * @return true开启,false关闭 + */ + @Override + public boolean selectCaptchaEnabled() { + String captchaEnabled = SpringUtils.getAopProxy(this).selectConfigByKey("sys.account.captchaEnabled"); + if (StringUtils.isEmpty(captchaEnabled)) { + return true; + } + return Convert.toBool(captchaEnabled); + } + /** + * 查询参数配置列表 + * + * @param config 参数配置信息 + * @return 参数配置集合 + */ + @Override + public List selectConfigList(SysConfig config) { + Map params = config.getParams(); + LambdaQueryWrapper lqw = new LambdaQueryWrapper() + .like(StringUtils.isNotBlank(config.getConfigName()), SysConfig::getConfigName, config.getConfigName()) + .eq(StringUtils.isNotBlank(config.getConfigType()), SysConfig::getConfigType, config.getConfigType()) + .like(StringUtils.isNotBlank(config.getConfigKey()), SysConfig::getConfigKey, config.getConfigKey()) + .between(params.get("beginTime") != null && params.get("endTime") != null, + SysConfig::getCreateTime, params.get("beginTime"), params.get("endTime")); + return baseMapper.selectList(lqw); + } + /** + * 新增参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_CONFIG, key = "#config.configKey") + @Override + public String insertConfig(SysConfig config) { + int row = baseMapper.insert(config); + if (row > 0) { + return config.getConfigValue(); + } + throw new ServiceException("操作失败"); + } + /** + * 修改参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_CONFIG, key = "#config.configKey") + @Override + public String updateConfig(SysConfig config) { + int row = 0; + if (config.getConfigId() != null) { + SysConfig temp = baseMapper.selectById(config.getConfigId()); + if (!StringUtils.equals(temp.getConfigKey(), config.getConfigKey())) { + CacheUtils.evict(CacheNames.SYS_CONFIG, temp.getConfigKey()); + } + row = baseMapper.updateById(config); + } else { + row = baseMapper.update(config, new LambdaQueryWrapper() + .eq(SysConfig::getConfigKey, config.getConfigKey())); + } + if (row > 0) { + return config.getConfigValue(); + } + throw new ServiceException("操作失败"); + } + /** + * 批量删除参数信息 + * + * @param configIds 需要删除的参数ID + */ + @Override + public void deleteConfigByIds(Long[] configIds) { + for (Long configId : configIds) { + SysConfig config = selectConfigById(configId); + if (StringUtils.equals(UserConstants.YES, config.getConfigType())) { + throw new ServiceException(String.format("内置参数【%1$s】不能删除 ", config.getConfigKey())); + } + CacheUtils.evict(CacheNames.SYS_CONFIG, config.getConfigKey()); + } + baseMapper.deleteBatchIds(Arrays.asList(configIds)); + } + /** + * 加载参数缓存数据 + */ + @Override + public void loadingConfigCache() { + List configsList = selectConfigList(new SysConfig()); + configsList.forEach(config -> + CacheUtils.put(CacheNames.SYS_CONFIG, config.getConfigKey(), config.getConfigValue())); + } + /** + * 清空参数缓存数据 + */ + @Override + public void clearConfigCache() { + CacheUtils.clear(CacheNames.SYS_CONFIG); + } + /** + * 重置参数缓存数据 + */ + @Override + public void resetConfigCache() { + clearConfigCache(); + loadingConfigCache(); + } + /** + * 校验参数键名是否唯一 + * + * @param config 参数配置信息 + * @return 结果 + */ + @Override + public boolean checkConfigKeyUnique(SysConfig config) { + long configId = ObjectUtil.isNull(config.getConfigId()) ? -1L : config.getConfigId(); + SysConfig info = baseMapper.selectOne(new LambdaQueryWrapper().eq(SysConfig::getConfigKey, config.getConfigKey())); + if (ObjectUtil.isNotNull(info) && info.getConfigId() != configId) { + return false; + } + return true; + } + /** + * 根据参数 key 获取参数值 + * + * @param configKey 参数 key + * @return 参数值 + */ + @Override + public String getConfigValue(String configKey) { + return SpringUtils.getAopProxy(this).selectConfigByKey(configKey); + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysDataScopeServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysDataScopeServiceImpl.java new file mode 100644 index 0000000..5917da0 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysDataScopeServiceImpl.java @@ -0,0 +1,61 @@ +package com.inscloudtech.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.inscloudtech.common.core.domain.entity.SysDept; +import com.inscloudtech.common.helper.DataBaseHelper; +import com.inscloudtech.common.utils.StreamUtils; +import com.inscloudtech.system.domain.SysRoleDept; +import com.inscloudtech.system.mapper.SysDeptMapper; +import com.inscloudtech.system.mapper.SysRoleDeptMapper; +import com.inscloudtech.system.service.ISysDataScopeService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 数据权限 实现 + *

+ * 注意: 此Service内不允许调用标注`数据权限`注解的方法 + * 例如: deptMapper.selectList 此 selectList 方法标注了`数据权限`注解 会出现循环解析的问题 + * + * @author inscloudtech + */ +@RequiredArgsConstructor +@Service("sdss") +public class SysDataScopeServiceImpl implements ISysDataScopeService { + + private final SysRoleDeptMapper roleDeptMapper; + private final SysDeptMapper deptMapper; + + @Override + public String getRoleCustom(Long roleId) { + List list = roleDeptMapper.selectList( + new LambdaQueryWrapper() + .select(SysRoleDept::getDeptId) + .eq(SysRoleDept::getRoleId, roleId)); + if (CollUtil.isNotEmpty(list)) { + return StreamUtils.join(list, rd -> Convert.toStr(rd.getDeptId())); + } + return null; + } + + @Override + public String getDeptAndChild(Long deptId) { + List deptList = deptMapper.selectList(new LambdaQueryWrapper() + .select(SysDept::getDeptId) + .apply(DataBaseHelper.findInSet(deptId, "ancestors"))); + List ids = StreamUtils.toList(deptList, SysDept::getDeptId); + ids.add(deptId); + List list = deptMapper.selectList(new LambdaQueryWrapper() + .select(SysDept::getDeptId) + .in(SysDept::getDeptId, ids)); + if (CollUtil.isNotEmpty(list)) { + return StreamUtils.join(list, d -> Convert.toStr(d.getDeptId())); + } + return null; + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysDeptServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysDeptServiceImpl.java new file mode 100644 index 0000000..e9e93ae --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysDeptServiceImpl.java @@ -0,0 +1,342 @@ +package com.inscloudtech.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.inscloudtech.common.constant.CacheNames; +import com.inscloudtech.common.constant.CompanyConfig; +import com.inscloudtech.common.constant.UserConstants; +import com.inscloudtech.common.core.domain.entity.SysDept; +import com.inscloudtech.common.core.domain.entity.SysRole; +import com.inscloudtech.common.core.domain.entity.SysUser; +import com.inscloudtech.common.core.domain.model.LoginUser; +import com.inscloudtech.common.core.service.DeptService; +import com.inscloudtech.common.exception.ServiceException; +import com.inscloudtech.common.helper.DataBaseHelper; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.TreeBuildUtils; +import com.inscloudtech.common.utils.redis.CacheUtils; +import com.inscloudtech.common.utils.spring.SpringUtils; +import com.inscloudtech.system.mapper.SysDeptMapper; +import com.inscloudtech.system.mapper.SysRoleMapper; +import com.inscloudtech.system.mapper.SysUserMapper; +import com.inscloudtech.system.service.ISysDeptService; +import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 部门管理 服务实现 + * + * @author inscloudtech + */ +@RequiredArgsConstructor +@Service +public class SysDeptServiceImpl implements ISysDeptService, DeptService { + + private final SysDeptMapper baseMapper; + private final SysRoleMapper roleMapper; + private final SysUserMapper userMapper; + /** + * 查询部门管理数据 + * + * @param dept 部门信息 + * @return 部门信息集合 + */ + @Override + public List selectDeptList(SysDept dept) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(SysDept::getDelFlag, "0") + .eq(ObjectUtil.isNotNull(dept.getDeptId()), SysDept::getDeptId, dept.getDeptId()) + .eq(ObjectUtil.isNotNull(dept.getParentId()), SysDept::getParentId, dept.getParentId()) + .like(StringUtils.isNotBlank(dept.getDeptName()), SysDept::getDeptName, dept.getDeptName()) + .eq(StringUtils.isNotBlank(dept.getDeptType()), SysDept::getDeptType, dept.getDeptType()) + .in(CollectionUtil.isNotEmpty(dept.getDeptTypeList()), SysDept::getDeptType, dept.getDeptTypeList()) + .in(CollectionUtil.isNotEmpty(dept.getDeptCodeList()), SysDept::getDeptCode, dept.getDeptCodeList()) + .eq(StringUtils.isNotBlank(dept.getStatus()), SysDept::getStatus, dept.getStatus()) + .orderByAsc(SysDept::getParentId) + .orderByAsc(SysDept::getOrderNum); + return baseMapper.selectDeptList(lqw); + } + /** + * 查询部门树结构信息 + * + * @param dept 部门信息 + * @return 部门树信息集合 + */ + @Override + public List> selectDeptTreeList(SysDept dept) { + List depts = this.selectDeptList(dept); + return buildDeptTreeSelect(depts); + } + /** + * 构建前端所需要下拉树结构 + * + * @param depts 部门列表 + * @return 下拉树结构列表 + */ + @Override + public List> buildDeptTreeSelect(List depts) { + if (CollUtil.isEmpty(depts)) { + return CollUtil.newArrayList(); + } + return TreeBuildUtils.build(depts, (dept, tree) -> + tree.setId(dept.getDeptId()) + .setParentId(dept.getParentId()) + .setName(dept.getDeptName()) + .setWeight(dept.getOrderNum())); + } + /** + * 根据角色ID查询部门树信息 + * + * @param roleId 角色ID + * @return 选中部门列表 + */ + @Override + public List selectDeptListByRoleId(Long roleId) { + SysRole role = roleMapper.selectById(roleId); + return baseMapper.selectDeptListByRoleId(roleId, role.getDeptCheckStrictly()); + } + /** + * 根据部门ID查询信息 + * + * @param deptId 部门ID + * @return 部门信息 + */ + @Cacheable(cacheNames = CacheNames.SYS_DEPT, key = "#deptId") + @Override + public SysDept selectDeptById(Long deptId) { + SysDept dept = baseMapper.selectById(deptId); + if (ObjectUtil.isNull(dept)) { + return null; + } + SysDept parentDept = baseMapper.selectOne(new LambdaQueryWrapper() + .select(SysDept::getDeptName).eq(SysDept::getDeptId, dept.getParentId())); + dept.setParentName(ObjectUtil.isNotNull(parentDept) ? parentDept.getDeptName() : null); + return dept; + } + /** + * 通过部门ID查询部门名称 + * + * @param deptIds 部门ID串逗号分隔 + * @return 部门名称串逗号分隔 + */ + @Override + public String selectDeptNameByIds(String deptIds) { + List list = new ArrayList<>(); + for (Long id : StringUtils.splitTo(deptIds, Convert::toLong)) { + SysDept dept = SpringUtils.getAopProxy(this).selectDeptById(id); + if (ObjectUtil.isNotNull(dept)) { + list.add(dept.getDeptName()); + } + } + return String.join(StringUtils.SEPARATOR, list); + } + /** + * 根据ID查询所有子部门数(正常状态) + * + * @param deptId 部门ID + * @return 子部门数 + */ + @Override + public long selectNormalChildrenDeptById(Long deptId) { + return baseMapper.selectCount(new LambdaQueryWrapper() + .eq(SysDept::getStatus, UserConstants.DEPT_NORMAL) + .apply(DataBaseHelper.findInSet(deptId, "ancestors"))); + } + /** + * 是否存在子节点 + * + * @param deptId 部门ID + * @return 结果 + */ + @Override + public boolean hasChildByDeptId(Long deptId) { + return baseMapper.exists(new LambdaQueryWrapper() + .eq(SysDept::getParentId, deptId)); + } + /** + * 查询部门是否存在用户 + * + * @param deptId 部门ID + * @return 结果 true 存在 false 不存在 + */ + @Override + public boolean checkDeptExistUser(Long deptId) { + return userMapper.exists(new LambdaQueryWrapper() + .eq(SysUser::getDeptId, deptId)); + } + /** + * 校验部门名称是否唯一 + * + * @param dept 部门信息 + * @return 结果 + */ + @Override + public boolean checkDeptNameUnique(SysDept dept) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysDept::getDeptName, dept.getDeptName()) + .eq(SysDept::getParentId, dept.getParentId()) + .ne(ObjectUtil.isNotNull(dept.getDeptId()), SysDept::getDeptId, dept.getDeptId())); + return !exist; + } + /** + * 校验部门是否有数据权限 + * + * @param deptId 部门id + */ + @Override + public void checkDeptDataScope(Long deptId) { + if (!LoginHelper.isAdmin()) { + SysDept dept = new SysDept(); + dept.setDeptId(deptId); + List depts = this.selectDeptList(dept); + if (CollUtil.isEmpty(depts)) { + throw new ServiceException("没有权限访问部门数据!"); + } + } + } + /** + * 新增保存部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + @Override + public int insertDept(SysDept dept) { + SysDept info = baseMapper.selectById(dept.getParentId()); + // 如果父节点不为正常状态,则不允许新增子节点 + if (!UserConstants.DEPT_NORMAL.equals(info.getStatus())) { + throw new ServiceException("部门停用,不允许新增"); + } + dept.setAncestors(info.getAncestors() + StringUtils.SEPARATOR + dept.getParentId()); + return baseMapper.insert(dept); + } + /** + * 修改保存部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + @CacheEvict(cacheNames = CacheNames.SYS_DEPT, key = "#dept.deptId") + @Override + public int updateDept(SysDept dept) { + SysDept newParentDept = baseMapper.selectById(dept.getParentId()); + SysDept oldDept = baseMapper.selectById(dept.getDeptId()); + if (ObjectUtil.isNotNull(newParentDept) && ObjectUtil.isNotNull(oldDept)) { + String newAncestors = newParentDept.getAncestors() + StringUtils.SEPARATOR + newParentDept.getDeptId(); + String oldAncestors = oldDept.getAncestors(); + dept.setAncestors(newAncestors); + updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors); + } + int result = baseMapper.updateById(dept); + if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors()) + && !StringUtils.equals(UserConstants.DEPT_NORMAL, dept.getAncestors())) { + // 如果该部门是启用状态,则启用该部门的所有上级部门 + updateParentDeptStatusNormal(dept); + } + return result; + } + /** + * 修改该部门的父级部门状态 + * + * @param dept 当前部门 + */ + private void updateParentDeptStatusNormal(SysDept dept) { + String ancestors = dept.getAncestors(); + Long[] deptIds = Convert.toLongArray(ancestors); + baseMapper.update(null, new LambdaUpdateWrapper() + .set(SysDept::getStatus, UserConstants.DEPT_NORMAL) + .in(SysDept::getDeptId, Arrays.asList(deptIds))); + } + /** + * 修改子元素关系 + * + * @param deptId 被修改的部门ID + * @param newAncestors 新的父ID集合 + * @param oldAncestors 旧的父ID集合 + */ + public void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors) { + List children = baseMapper.selectList(new LambdaQueryWrapper() + .apply(DataBaseHelper.findInSet(deptId, "ancestors"))); + List list = new ArrayList<>(); + for (SysDept child : children) { + SysDept dept = new SysDept(); + dept.setDeptId(child.getDeptId()); + dept.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors)); + list.add(dept); + } + if (CollUtil.isNotEmpty(list)) { + if (baseMapper.updateBatchById(list)) { + list.forEach(dept -> CacheUtils.evict(CacheNames.SYS_DEPT, dept.getDeptId())); + } + } + } + /** + * 删除部门管理信息 + * + * @param deptId 部门ID + * @return 结果 + */ + @CacheEvict(cacheNames = CacheNames.SYS_DEPT, key = "#deptId") + @Override + public int deleteDeptById(Long deptId) { + return baseMapper.deleteById(deptId); + } + + @Override + public SysDept getDeptInfo(Long deptId){ + if(null == deptId){ + LoginUser loginUser = LoginHelper.getLoginUser(); + SysDept dept = new SysDept(); + dept.setDeptName(loginUser.getDeptName()); + dept.setDeptCode(loginUser.getDeptCode()); + dept.setDeptId(loginUser.getDeptId()); + return dept; + }else { + return baseMapper.selectById(deptId); + } + } + + @Override + public List getPlanDept(){ + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(SysDept::getDelFlag, "0") + .in(SysDept::getDeptCode, CompanyConfig.PLAN_DEPT_CODE_LIST); + return baseMapper.selectList(lqw); + } + + @Override + public long getParentId(Long deptId){ + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(SysDept::getDelFlag, "0") + .in(SysDept::getDeptCode, CompanyConfig.PLAN_DEPT_CODE_LIST) + .orderByAsc(SysDept::getParentId) + .orderByAsc(SysDept::getOrderNum); + List targetList = baseMapper.selectList(lqw); + Map> groupByDeptName = targetList.stream().collect(Collectors.groupingBy(SysDept::getDeptName)); + return getDZDeptId(groupByDeptName.keySet(),deptId); + } + + long getDZDeptId(Set deptNameSet, Long id){ + SysDept pDept = baseMapper.selectById(id); + if(pDept == null){ + return id; + } + if(deptNameSet.contains(pDept.getDeptName())){ + return pDept.getDeptId(); + }else { + return getDZDeptId(deptNameSet,pDept.getParentId()); + } + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysDictDataServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysDictDataServiceImpl.java new file mode 100644 index 0000000..787cd9b --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysDictDataServiceImpl.java @@ -0,0 +1,124 @@ +package com.inscloudtech.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.inscloudtech.common.constant.CacheNames; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.entity.SysDictData; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.exception.ServiceException; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.redis.CacheUtils; +import com.inscloudtech.system.mapper.SysDictDataMapper; +import com.inscloudtech.system.service.ISysDictDataService; +import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.CachePut; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 字典 业务层处理 + * + * @author inscloudtech + */ +@RequiredArgsConstructor +@Service +public class SysDictDataServiceImpl implements ISysDictDataService { + + private final SysDictDataMapper baseMapper; + + @Override + public TableDataInfo selectPageDictDataList(SysDictData dictData, PageQuery pageQuery) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper() + .eq(StringUtils.isNotBlank(dictData.getDictType()), SysDictData::getDictType, dictData.getDictType()) + .like(StringUtils.isNotBlank(dictData.getDictLabel()), SysDictData::getDictLabel, dictData.getDictLabel()) + .eq(StringUtils.isNotBlank(dictData.getStatus()), SysDictData::getStatus, dictData.getStatus()) + .orderByAsc(SysDictData::getDictSort); + Page page = baseMapper.selectPage(pageQuery.build(), lqw); + return TableDataInfo.build(page); + } + /** + * 根据条件分页查询字典数据 + * + * @param dictData 字典数据信息 + * @return 字典数据集合信息 + */ + @Override + public List selectDictDataList(SysDictData dictData) { + return baseMapper.selectList(new LambdaQueryWrapper() + .eq(StringUtils.isNotBlank(dictData.getDictType()), SysDictData::getDictType, dictData.getDictType()) + .like(StringUtils.isNotBlank(dictData.getDictLabel()), SysDictData::getDictLabel, dictData.getDictLabel()) + .eq(StringUtils.isNotBlank(dictData.getStatus()), SysDictData::getStatus, dictData.getStatus()) + .orderByAsc(SysDictData::getDictSort)); + } + /** + * 根据字典类型和字典键值查询字典数据信息 + * + * @param dictType 字典类型 + * @param dictValue 字典键值 + * @return 字典标签 + */ + @Override + public String selectDictLabel(String dictType, String dictValue) { + return baseMapper.selectOne(new LambdaQueryWrapper() + .select(SysDictData::getDictLabel) + .eq(SysDictData::getDictType, dictType) + .eq(SysDictData::getDictValue, dictValue)) + .getDictLabel(); + } + /** + * 根据字典数据ID查询信息 + * + * @param dictCode 字典数据ID + * @return 字典数据 + */ + @Override + public SysDictData selectDictDataById(Long dictCode) { + return baseMapper.selectById(dictCode); + } + /** + * 批量删除字典数据信息 + * + * @param dictCodes 需要删除的字典数据ID + */ + @Override + public void deleteDictDataByIds(Long[] dictCodes) { + for (Long dictCode : dictCodes) { + SysDictData data = selectDictDataById(dictCode); + baseMapper.deleteById(dictCode); + CacheUtils.evict(CacheNames.SYS_DICT, data.getDictType()); + } + } + /** + * 新增保存字典数据信息 + * + * @param data 字典数据信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#data.dictType") + @Override + public List insertDictData(SysDictData data) { + int row = baseMapper.insert(data); + if (row > 0) { + return baseMapper.selectDictDataByType(data.getDictType()); + } + throw new ServiceException("操作失败"); + } + /** + * 修改保存字典数据信息 + * + * @param data 字典数据信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#data.dictType") + @Override + public List updateDictData(SysDictData data) { + int row = baseMapper.updateById(data); + if (row > 0) { + return baseMapper.selectDictDataByType(data.getDictType()); + } + throw new ServiceException("操作失败"); + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysDictTypeServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysDictTypeServiceImpl.java new file mode 100644 index 0000000..50257cf --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysDictTypeServiceImpl.java @@ -0,0 +1,259 @@ +package com.inscloudtech.system.service.impl; + +import cn.dev33.satoken.context.SaHolder; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.inscloudtech.common.constant.CacheConstants; +import com.inscloudtech.common.constant.CacheNames; +import com.inscloudtech.common.constant.UserConstants; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.entity.SysDictData; +import com.inscloudtech.common.core.domain.entity.SysDictType; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.core.service.DictService; +import com.inscloudtech.common.exception.ServiceException; +import com.inscloudtech.common.utils.StreamUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.redis.CacheUtils; +import com.inscloudtech.common.utils.spring.SpringUtils; +import com.inscloudtech.system.mapper.SysDictDataMapper; +import com.inscloudtech.system.mapper.SysDictTypeMapper; +import com.inscloudtech.system.service.ISysDictTypeService; +import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 字典 业务层处理 + * + * @author inscloudtech + */ +@RequiredArgsConstructor +@Service +public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService { + + private final SysDictTypeMapper baseMapper; + private final SysDictDataMapper dictDataMapper; + + @Override + public TableDataInfo selectPageDictTypeList(SysDictType dictType, PageQuery pageQuery) { + Map params = dictType.getParams(); + LambdaQueryWrapper lqw = new LambdaQueryWrapper() + .like(StringUtils.isNotBlank(dictType.getDictName()), SysDictType::getDictName, dictType.getDictName()) + .eq(StringUtils.isNotBlank(dictType.getStatus()), SysDictType::getStatus, dictType.getStatus()) + .eq(StringUtils.isNotBlank(dictType.getDictGroupValue()), SysDictType::getDictGroupValue, dictType.getDictGroupValue()) + .like(StringUtils.isNotBlank(dictType.getDictType()), SysDictType::getDictType, dictType.getDictType()) + .between(params.get("beginTime") != null && params.get("endTime") != null, + SysDictType::getCreateTime, params.get("beginTime"), params.get("endTime")); + Page page = baseMapper.selectPage(pageQuery.build(), lqw); + return TableDataInfo.build(page); + } + /** + * 根据条件分页查询字典类型 + * + * @param dictType 字典类型信息 + * @return 字典类型集合信息 + */ + @Override + public List selectDictTypeList(SysDictType dictType) { + Map params = dictType.getParams(); + return baseMapper.selectList(new LambdaQueryWrapper() + .like(StringUtils.isNotBlank(dictType.getDictName()), SysDictType::getDictName, dictType.getDictName()) + .eq(StringUtils.isNotBlank(dictType.getStatus()), SysDictType::getStatus, dictType.getStatus()) + .like(StringUtils.isNotBlank(dictType.getDictType()), SysDictType::getDictType, dictType.getDictType()) + .between(params.get("beginTime") != null && params.get("endTime") != null, + SysDictType::getCreateTime, params.get("beginTime"), params.get("endTime"))); + } + /** + * 根据所有字典类型 + * + * @return 字典类型集合信息 + */ + @Override + public List selectDictTypeAll() { + return baseMapper.selectList(); + } + /** + * 根据字典类型查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据集合信息 + */ + @Cacheable(cacheNames = CacheNames.SYS_DICT, key = "#dictType") + @Override + public List selectDictDataByType(String dictType) { + List dictDatas = dictDataMapper.selectDictDataByType(dictType); + if (CollUtil.isNotEmpty(dictDatas)) { + return dictDatas; + } + return null; + } + /** + * 根据字典类型ID查询信息 + * + * @param dictId 字典类型ID + * @return 字典类型 + */ + @Override + public SysDictType selectDictTypeById(Long dictId) { + return baseMapper.selectById(dictId); + } + + /** + * 批量删除字典类型信息 + * + * @param dictIds 需要删除的字典ID + */ + @Override + public void deleteDictTypeByIds(Long[] dictIds) { + for (Long dictId : dictIds) { + SysDictType dictType = selectDictTypeById(dictId); + if (dictDataMapper.exists(new LambdaQueryWrapper() + .eq(SysDictData::getDictType, dictType.getDictType()))) { + throw new ServiceException(String.format("%1$s已分配,不能删除", dictType.getDictName())); + } + CacheUtils.evict(CacheNames.SYS_DICT, dictType.getDictType()); + } + baseMapper.deleteBatchIds(Arrays.asList(dictIds)); + } + /** + * 加载字典缓存数据 + */ + @Override + public void loadingDictCache() { + List dictDataList = dictDataMapper.selectList( + new LambdaQueryWrapper().eq(SysDictData::getStatus, UserConstants.DICT_NORMAL)); + Map> dictDataMap = StreamUtils.groupByKey(dictDataList, SysDictData::getDictType); + dictDataMap.forEach((k,v) -> { + List dictList = StreamUtils.sorted(v, Comparator.comparing(SysDictData::getDictSort)); + CacheUtils.put(CacheNames.SYS_DICT, k, dictList); + }); + } + /** + * 清空字典缓存数据 + */ + @Override + public void clearDictCache() { + CacheUtils.clear(CacheNames.SYS_DICT); + } + /** + * 重置字典缓存数据 + */ + @Override + public void resetDictCache() { + clearDictCache(); + loadingDictCache(); + } + /** + * 新增保存字典类型信息 + * + * @param dict 字典类型信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#dict.dictType") + @Override + public List insertDictType(SysDictType dict) { + int row = baseMapper.insert(dict); + if (row > 0) { + return new ArrayList<>(); + } + throw new ServiceException("操作失败"); + } + /** + * 修改保存字典类型信息 + * + * @param dict 字典类型信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#dict.dictType") + @Override + @Transactional(rollbackFor = Exception.class) + public List updateDictType(SysDictType dict) { + SysDictType oldDict = baseMapper.selectById(dict.getDictId()); + dictDataMapper.update(null, new LambdaUpdateWrapper() + .set(SysDictData::getDictType, dict.getDictType()) + .eq(SysDictData::getDictType, oldDict.getDictType())); + int row = baseMapper.updateById(dict); + if (row > 0) { + CacheUtils.evict(CacheNames.SYS_DICT, oldDict.getDictType()); + return dictDataMapper.selectDictDataByType(dict.getDictType()); + } + throw new ServiceException("操作失败"); + } + /** + * 校验字典类型称是否唯一 + * + * @param dict 字典类型 + * @return 结果 + */ + @Override + public boolean checkDictTypeUnique(SysDictType dict) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysDictType::getDictType, dict.getDictType()) + .ne(ObjectUtil.isNotNull(dict.getDictId()), SysDictType::getDictId, dict.getDictId())); + return !exist; + } + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @param separator 分隔符 + * @return 字典标签 + */ + @SuppressWarnings("unchecked cast") + @Override + public String getDictLabel(String dictType, String dictValue, String separator) { + // 优先从本地缓存获取 + List datas = (List) SaHolder.getStorage().get(CacheConstants.SYS_DICT_KEY + dictType); + if (ObjectUtil.isNull(datas)) { + datas = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); + SaHolder.getStorage().set(CacheConstants.SYS_DICT_KEY + dictType, datas); + } + + Map map = StreamUtils.toMap(datas, SysDictData::getDictValue, SysDictData::getDictLabel); + if (StringUtils.containsAny(dictValue, separator)) { + return Arrays.stream(dictValue.split(separator)) + .map(v -> map.getOrDefault(v, StringUtils.EMPTY)) + .collect(Collectors.joining(separator)); + } else { + return map.getOrDefault(dictValue, StringUtils.EMPTY); + } + } + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @param separator 分隔符 + * @return 字典值 + */ + @SuppressWarnings("unchecked cast") + @Override + public String getDictValue(String dictType, String dictLabel, String separator) { + // 优先从本地缓存获取 + List datas = (List) SaHolder.getStorage().get(CacheConstants.SYS_DICT_KEY + dictType); + if (ObjectUtil.isNull(datas)) { + datas = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); + SaHolder.getStorage().set(CacheConstants.SYS_DICT_KEY + dictType, datas); + } + + Map map = StreamUtils.toMap(datas, SysDictData::getDictLabel, SysDictData::getDictValue); + if (StringUtils.containsAny(dictLabel, separator)) { + return Arrays.stream(dictLabel.split(separator)) + .map(l -> map.getOrDefault(l, StringUtils.EMPTY)) + .collect(Collectors.joining(separator)); + } else { + return map.getOrDefault(dictLabel, StringUtils.EMPTY); + } + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysLogininforServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysLogininforServiceImpl.java new file mode 100644 index 0000000..09ffd75 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysLogininforServiceImpl.java @@ -0,0 +1,150 @@ +package com.inscloudtech.system.service.impl; + +import cn.hutool.http.useragent.UserAgent; +import cn.hutool.http.useragent.UserAgentUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.event.LogininforEvent; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.utils.ServletUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.ip.AddressUtils; +import com.inscloudtech.system.domain.SysLogininfor; +import com.inscloudtech.system.mapper.SysLogininforMapper; +import com.inscloudtech.system.service.ISysLogininforService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * 系统访问日志情况信息 服务层处理 + * + * @author inscloudtech + */ +@RequiredArgsConstructor +@Slf4j +@Service +public class SysLogininforServiceImpl implements ISysLogininforService { + + private final SysLogininforMapper baseMapper; + /** + * 记录登录信息 + * + * @param logininforEvent 登录事件 + */ + @Async + @EventListener + public void recordLogininfor(LogininforEvent logininforEvent) { + HttpServletRequest request = logininforEvent.getRequest(); + final UserAgent userAgent = UserAgentUtil.parse(request.getHeader("User-Agent")); + final String ip = ServletUtils.getClientIP(request); + + String address = AddressUtils.getRealAddressByIP(ip); + StringBuilder s = new StringBuilder(); + s.append(getBlock(ip)); + s.append(address); + s.append(getBlock(logininforEvent.getUsername())); + s.append(getBlock(logininforEvent.getStatus())); + s.append(getBlock(logininforEvent.getMessage())); + // 打印信息到日志 + log.info(s.toString(), logininforEvent.getArgs()); + // 获取客户端操作系统 + String os = userAgent.getOs().getName(); + // 获取客户端浏览器 + String browser = userAgent.getBrowser().getName(); + // 封装对象 + SysLogininfor logininfor = new SysLogininfor(); + logininfor.setUserName(logininforEvent.getUsername()); + logininfor.setIpaddr(ip); + logininfor.setLoginLocation(address); + logininfor.setBrowser(browser); + logininfor.setOs(os); + logininfor.setMsg(logininforEvent.getMessage()); + // 日志状态 + if (StringUtils.equalsAny(logininforEvent.getStatus(), Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) { + logininfor.setStatus(Constants.SUCCESS); + } else if (Constants.LOGIN_FAIL.equals(logininforEvent.getStatus())) { + logininfor.setStatus(Constants.FAIL); + } + // 插入数据 + insertLogininfor(logininfor); + } + + private String getBlock(Object msg) { + if (msg == null) { + msg = ""; + } + return "[" + msg.toString() + "]"; + } + + @Override + public TableDataInfo selectPageLogininforList(SysLogininfor logininfor, PageQuery pageQuery) { + Map params = logininfor.getParams(); + LambdaQueryWrapper lqw = new LambdaQueryWrapper() + .like(StringUtils.isNotBlank(logininfor.getIpaddr()), SysLogininfor::getIpaddr, logininfor.getIpaddr()) + .eq(StringUtils.isNotBlank(logininfor.getStatus()), SysLogininfor::getStatus, logininfor.getStatus()) + .like(StringUtils.isNotBlank(logininfor.getUserName()), SysLogininfor::getUserName, logininfor.getUserName()) + .between(params.get("beginTime") != null && params.get("endTime") != null, + SysLogininfor::getLoginTime, params.get("beginTime"), params.get("endTime")); + if (StringUtils.isBlank(pageQuery.getOrderByColumn())) { + pageQuery.setOrderByColumn("info_id"); + pageQuery.setIsAsc("desc"); + } + Page page = baseMapper.selectPage(pageQuery.build(), lqw); + return TableDataInfo.build(page); + } + /** + * 新增系统登录日志 + * + * @param logininfor 访问日志对象 + */ + @Override + public void insertLogininfor(SysLogininfor logininfor) { + logininfor.setLoginTime(new Date()); + baseMapper.insert(logininfor); + } + /** + * 查询系统登录日志集合 + * + * @param logininfor 访问日志对象 + * @return 登录记录集合 + */ + @Override + public List selectLogininforList(SysLogininfor logininfor) { + Map params = logininfor.getParams(); + return baseMapper.selectList(new LambdaQueryWrapper() + .like(StringUtils.isNotBlank(logininfor.getIpaddr()), SysLogininfor::getIpaddr, logininfor.getIpaddr()) + .eq(StringUtils.isNotBlank(logininfor.getStatus()), SysLogininfor::getStatus, logininfor.getStatus()) + .like(StringUtils.isNotBlank(logininfor.getUserName()), SysLogininfor::getUserName, logininfor.getUserName()) + .between(params.get("beginTime") != null && params.get("endTime") != null, + SysLogininfor::getLoginTime, params.get("beginTime"), params.get("endTime")) + .orderByDesc(SysLogininfor::getInfoId)); + } + /** + * 批量删除系统登录日志 + * + * @param infoIds 需要删除的登录日志ID + * @return 结果 + */ + @Override + public int deleteLogininforByIds(Long[] infoIds) { + return baseMapper.deleteBatchIds(Arrays.asList(infoIds)); + } + /** + * 清空系统登录日志 + */ + @Override + public void cleanLogininfor() { + baseMapper.delete(new LambdaQueryWrapper<>()); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysMenuServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysMenuServiceImpl.java new file mode 100644 index 0000000..568562e --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysMenuServiceImpl.java @@ -0,0 +1,428 @@ +package com.inscloudtech.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.constant.UserConstants; +import com.inscloudtech.common.core.domain.entity.SysMenu; +import com.inscloudtech.common.core.domain.entity.SysRole; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.common.utils.StreamUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.TreeBuildUtils; +import com.inscloudtech.system.domain.SysRoleMenu; +import com.inscloudtech.system.domain.vo.MetaVo; +import com.inscloudtech.system.domain.vo.RouterVo; +import com.inscloudtech.system.mapper.SysMenuMapper; +import com.inscloudtech.system.mapper.SysRoleMapper; +import com.inscloudtech.system.mapper.SysRoleMenuMapper; +import com.inscloudtech.system.service.ISysMenuService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 菜单 业务层处理 + * + * @author inscloudtech + */ +@RequiredArgsConstructor +@Service +public class SysMenuServiceImpl implements ISysMenuService { + + private final SysMenuMapper baseMapper; + private final SysRoleMapper roleMapper; + private final SysRoleMenuMapper roleMenuMapper; + /** + * 根据用户查询系统菜单列表 + * + * @param userId 用户ID + * @return 菜单列表 + */ + @Override + public List selectMenuList(Long userId) { + return selectMenuList(new SysMenu(), userId); + } + /** + * 查询系统菜单列表 + * + * @param menu 菜单信息 + * @return 菜单列表 + */ + @Override + public List selectMenuList(SysMenu menu, Long userId) { + List menuList = null; + // 管理员显示所有菜单信息 + if (LoginHelper.isAdmin(userId)) { + menuList = baseMapper.selectList(new LambdaQueryWrapper() + .like(StringUtils.isNotBlank(menu.getMenuName()), SysMenu::getMenuName, menu.getMenuName()) + .eq(StringUtils.isNotBlank(menu.getVisible()), SysMenu::getVisible, menu.getVisible()) + .eq(StringUtils.isNotBlank(menu.getStatus()), SysMenu::getStatus, menu.getStatus()) + .orderByAsc(SysMenu::getParentId) + .orderByAsc(SysMenu::getOrderNum)); + } else { + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("sur.user_id", userId) + .like(StringUtils.isNotBlank(menu.getMenuName()), "m.menu_name", menu.getMenuName()) + .eq(StringUtils.isNotBlank(menu.getVisible()), "m.visible", menu.getVisible()) + .eq(StringUtils.isNotBlank(menu.getStatus()), "m.status", menu.getStatus()) + .orderByAsc("m.parent_id") + .orderByAsc("m.order_num"); + menuList = baseMapper.selectMenuListByUserId(wrapper); + } + return menuList; + } + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + @Override + public Set selectMenuPermsByUserId(Long userId) { + List perms = baseMapper.selectMenuPermsByUserId(userId); + Set permsSet = new HashSet<>(); + for (String perm : perms) { + if (StringUtils.isNotEmpty(perm)) { + permsSet.addAll(StringUtils.splitList(perm.trim())); + } + } + return permsSet; + } + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + @Override + public Set selectMenuPermsByRoleId(Long roleId) { + List perms = baseMapper.selectMenuPermsByRoleId(roleId); + Set permsSet = new HashSet<>(); + for (String perm : perms) { + if (StringUtils.isNotEmpty(perm)) { + permsSet.addAll(StringUtils.splitList(perm.trim())); + } + } + return permsSet; + } + /** + * 根据用户ID查询菜单 + * + * @param userId 用户名称 + * @return 菜单列表 + */ + @Override + public List selectMenuTreeByUserId(Long userId) { + List menus = null; + if (LoginHelper.isAdmin(userId)) { + menus = baseMapper.selectMenuTreeAll(); + } else { + menus = baseMapper.selectMenuTreeByUserId(userId); + } + return getChildPerms(menus, 0); + } + /** + * 根据角色ID查询菜单树信息 + * + * @param roleId 角色ID + * @return 选中菜单列表 + */ + @Override + public List selectMenuListByRoleId(Long roleId) { + SysRole role = roleMapper.selectById(roleId); + List menuList = baseMapper.selectMenuListByRoleId(roleId, role.getMenuCheckStrictly()); + List idList = menuList.stream().map(obj -> obj.getMenuId()).collect(Collectors.toList()); + return idList; + } + + @Override + public List selectMenuNameListByRoleId(Long roleId) { + SysRole role = roleMapper.selectById(roleId); + List menuList = baseMapper.selectMenuListByRoleId(roleId, role.getMenuCheckStrictly()); + List menuNameList = menuList.stream().map(obj -> obj.getMenuName()).collect(Collectors.toList()); + return menuNameList; + } + /** + * 构建前端路由所需要的菜单 + * + * @param menus 菜单列表 + * @return 路由列表 + */ + @Override + public List buildMenus(List menus) { + List routers = new LinkedList<>(); + for (SysMenu menu : menus) { + RouterVo router = new RouterVo(); + router.setHidden("1".equals(menu.getVisible())); + router.setName(getRouteName(menu)); + router.setPath(getRouterPath(menu)); + router.setComponent(getComponent(menu)); + router.setQuery(menu.getQueryParam()); + router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath())); + List cMenus = menu.getChildren(); + if (CollUtil.isNotEmpty(cMenus) && UserConstants.TYPE_DIR.equals(menu.getMenuType())) { + router.setAlwaysShow(true); + router.setRedirect("noRedirect"); + router.setChildren(buildMenus(cMenus)); + } else if (isMenuFrame(menu)) { + router.setMeta(null); + List childrenList = new ArrayList<>(); + RouterVo children = new RouterVo(); + children.setPath(menu.getPath()); + children.setComponent(menu.getComponent()); + children.setName(StringUtils.capitalize(menu.getPath())); + children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath())); + children.setQuery(menu.getQueryParam()); + childrenList.add(children); + router.setChildren(childrenList); + } else if (menu.getParentId().intValue() == 0 && isInnerLink(menu)) { + router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon())); + router.setPath("/"); + List childrenList = new ArrayList<>(); + RouterVo children = new RouterVo(); + String routerPath = innerLinkReplaceEach(menu.getPath()); + children.setPath(routerPath); + children.setComponent(UserConstants.INNER_LINK); + children.setName(StringUtils.capitalize(routerPath)); + children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath())); + childrenList.add(children); + router.setChildren(childrenList); + } + routers.add(router); + } + return routers; + } + /** + * 构建前端所需要下拉树结构 + * + * @param menus 菜单列表 + * @return 下拉树结构列表 + */ + @Override + public List> buildMenuTreeSelect(List menus) { + if (CollUtil.isEmpty(menus)) { + return CollUtil.newArrayList(); + } + return TreeBuildUtils.build(menus, (menu, tree) -> + tree.setId(menu.getMenuId()) + .setParentId(menu.getParentId()) + .setName(menu.getMenuName()) + .setWeight(menu.getOrderNum())); + } + /** + * 根据菜单ID查询信息 + * + * @param menuId 菜单ID + * @return 菜单信息 + */ + @Override + public SysMenu selectMenuById(Long menuId) { + return baseMapper.selectById(menuId); + } + /** + * 是否存在菜单子节点 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public boolean hasChildByMenuId(Long menuId) { + return baseMapper.exists(new LambdaQueryWrapper().eq(SysMenu::getParentId, menuId)); + } + /** + * 查询菜单使用数量 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public boolean checkMenuExistRole(Long menuId) { + return roleMenuMapper.exists(new LambdaQueryWrapper().eq(SysRoleMenu::getMenuId, menuId)); + } + /** + * 新增保存菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + @Override + public int insertMenu(SysMenu menu) { + return baseMapper.insert(menu); + } + /** + * 修改保存菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + @Override + public int updateMenu(SysMenu menu) { + return baseMapper.updateById(menu); + } + /** + * 删除菜单管理信息 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public int deleteMenuById(Long menuId) { + return baseMapper.deleteById(menuId); + } + /** + * 校验菜单名称是否唯一 + * + * @param menu 菜单信息 + * @return 结果 + */ + @Override + public boolean checkMenuNameUnique(SysMenu menu) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysMenu::getMenuName, menu.getMenuName()) + .eq(SysMenu::getParentId, menu.getParentId()) + .ne(ObjectUtil.isNotNull(menu.getMenuId()), SysMenu::getMenuId, menu.getMenuId())); + return !exist; + } + /** + * 获取路由名称 + * + * @param menu 菜单信息 + * @return 路由名称 + */ + public String getRouteName(SysMenu menu) { + String routerName = StringUtils.capitalize(menu.getPath()); + // 非外链并且是一级目录(类型为目录) + if (isMenuFrame(menu)) { + routerName = StringUtils.EMPTY; + } + return routerName; + } + /** + * 获取路由地址 + * + * @param menu 菜单信息 + * @return 路由地址 + */ + public String getRouterPath(SysMenu menu) { + String routerPath = menu.getPath(); + // 内链打开外网方式 + if (menu.getParentId().intValue() != 0 && isInnerLink(menu)) { + routerPath = innerLinkReplaceEach(routerPath); + } + // 非外链并且是一级目录(类型为目录) + if (0 == menu.getParentId().intValue() && UserConstants.TYPE_DIR.equals(menu.getMenuType()) + && UserConstants.NO_FRAME.equals(menu.getIsFrame())) { + routerPath = "/" + menu.getPath(); + } + // 非外链并且是一级目录(类型为菜单) + else if (isMenuFrame(menu)) { + routerPath = "/"; + } + return routerPath; + } + /** + * 获取组件信息 + * + * @param menu 菜单信息 + * @return 组件信息 + */ + public String getComponent(SysMenu menu) { + String component = UserConstants.LAYOUT; + if (StringUtils.isNotEmpty(menu.getComponent()) && !isMenuFrame(menu)) { + component = menu.getComponent(); + } else if (StringUtils.isEmpty(menu.getComponent()) && menu.getParentId().intValue() != 0 && isInnerLink(menu)) { + component = UserConstants.INNER_LINK; + } else if (StringUtils.isEmpty(menu.getComponent()) && isParentView(menu)) { + component = UserConstants.PARENT_VIEW; + } + return component; + } + /** + * 是否为菜单内部跳转 + * + * @param menu 菜单信息 + * @return 结果 + */ + public boolean isMenuFrame(SysMenu menu) { + return menu.getParentId().intValue() == 0 && UserConstants.TYPE_MENU.equals(menu.getMenuType()) + && menu.getIsFrame().equals(UserConstants.NO_FRAME); + } + /** + * 是否为内链组件 + * + * @param menu 菜单信息 + * @return 结果 + */ + public boolean isInnerLink(SysMenu menu) { + return menu.getIsFrame().equals(UserConstants.NO_FRAME) && StringUtils.ishttp(menu.getPath()); + } + /** + * 是否为parent_view组件 + * + * @param menu 菜单信息 + * @return 结果 + */ + public boolean isParentView(SysMenu menu) { + return menu.getParentId().intValue() != 0 && UserConstants.TYPE_DIR.equals(menu.getMenuType()); + } + /** + * 根据父节点的ID获取所有子节点 + * + * @param list 分类表 + * @param parentId 传入的父节点ID + * @return String + */ + public List getChildPerms(List list, int parentId) { + List returnList = new ArrayList<>(); + for (SysMenu t : list) { + // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点 + if (t.getParentId() == parentId) { + recursionFn(list, t); + returnList.add(t); + } + } + return returnList; + } + /** + * 递归列表 + * + * @param list + * @param t + */ + private void recursionFn(List list, SysMenu t) { + // 得到子节点列表 + List childList = getChildList(list, t); + t.setChildren(childList); + for (SysMenu tChild : childList) { + if (hasChild(list, tChild)) { + recursionFn(list, tChild); + } + } + } + /** + * 得到子节点列表 + */ + private List getChildList(List list, SysMenu t) { + return StreamUtils.filter(list, n -> n.getParentId().equals(t.getMenuId())); + } + /** + * 判断是否有子节点 + */ + private boolean hasChild(List list, SysMenu t) { + return CollUtil.isNotEmpty(getChildList(list, t)); + } + /** + * 内链域名特殊字符替换 + */ + public String innerLinkReplaceEach(String path) { + return StringUtils.replaceEach(path, new String[]{Constants.HTTP, Constants.HTTPS, Constants.WWW, "."}, + new String[]{"", "", "", "/"}); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysNoticeServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysNoticeServiceImpl.java new file mode 100644 index 0000000..32d234f --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysNoticeServiceImpl.java @@ -0,0 +1,100 @@ +package com.inscloudtech.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.system.domain.SysNotice; +import com.inscloudtech.system.mapper.SysNoticeMapper; +import com.inscloudtech.system.service.ISysNoticeService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; + +/** + * 公告 服务层实现 + * + * @author inscloudtech + */ +@RequiredArgsConstructor +@Service +public class SysNoticeServiceImpl implements ISysNoticeService { + + private final SysNoticeMapper baseMapper; + + @Override + public TableDataInfo selectPageNoticeList(SysNotice notice, PageQuery pageQuery) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper() + .like(StringUtils.isNotBlank(notice.getNoticeTitle()), SysNotice::getNoticeTitle, notice.getNoticeTitle()) + .eq(StringUtils.isNotBlank(notice.getNoticeType()), SysNotice::getNoticeType, notice.getNoticeType()) + .like(StringUtils.isNotBlank(notice.getCreateBy()), SysNotice::getCreateBy, notice.getCreateBy()); + Page page = baseMapper.selectPage(pageQuery.build(), lqw); + return TableDataInfo.build(page); + } + /** + * 查询公告信息 + * + * @param noticeId 公告ID + * @return 公告信息 + */ + @Override + public SysNotice selectNoticeById(Long noticeId) { + return baseMapper.selectById(noticeId); + } + /** + * 查询公告列表 + * + * @param notice 公告信息 + * @return 公告集合 + */ + @Override + public List selectNoticeList(SysNotice notice) { + return baseMapper.selectList(new LambdaQueryWrapper() + .like(StringUtils.isNotBlank(notice.getNoticeTitle()), SysNotice::getNoticeTitle, notice.getNoticeTitle()) + .eq(StringUtils.isNotBlank(notice.getNoticeType()), SysNotice::getNoticeType, notice.getNoticeType()) + .like(StringUtils.isNotBlank(notice.getCreateBy()), SysNotice::getCreateBy, notice.getCreateBy())); + } + /** + * 新增公告 + * + * @param notice 公告信息 + * @return 结果 + */ + @Override + public int insertNotice(SysNotice notice) { + return baseMapper.insert(notice); + } + /** + * 修改公告 + * + * @param notice 公告信息 + * @return 结果 + */ + @Override + public int updateNotice(SysNotice notice) { + return baseMapper.updateById(notice); + } + /** + * 删除公告对象 + * + * @param noticeId 公告ID + * @return 结果 + */ + @Override + public int deleteNoticeById(Long noticeId) { + return baseMapper.deleteById(noticeId); + } + /** + * 批量删除公告信息 + * + * @param noticeIds 需要删除的公告ID + * @return 结果 + */ + @Override + public int deleteNoticeByIds(Long[] noticeIds) { + return baseMapper.deleteBatchIds(Arrays.asList(noticeIds)); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysNotifyMessageServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysNotifyMessageServiceImpl.java new file mode 100644 index 0000000..a7cf97d --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysNotifyMessageServiceImpl.java @@ -0,0 +1,132 @@ +package com.inscloudtech.system.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.model.LoginUser; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.system.domain.SysNotifyMessage; +import com.inscloudtech.system.mapper.SysNotifyMessageMapper; +import com.inscloudtech.system.service.ISysNotifyMessageService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * 站内信消息Service业务层处理 + * + * @author inscloudtech + * @date 2023-06-02 + */ +@RequiredArgsConstructor +@Service +public class SysNotifyMessageServiceImpl implements ISysNotifyMessageService { + + private final SysNotifyMessageMapper baseMapper; + /** + * 查询站内信消息 + */ + @Override + public SysNotifyMessage queryById(Long id){ + return baseMapper.selectById(id); + } + /** + * 查询站内信消息列表 + */ + @Override + public TableDataInfo queryPageList(SysNotifyMessage message, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(message); + Page result = baseMapper.selectPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + /** + * 查询站内信消息列表 + */ + @Override + public List queryList(SysNotifyMessage message) { + LambdaQueryWrapper lqw = buildQueryWrapper(message); + return baseMapper.selectList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(SysNotifyMessage message) { + Map params = message.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); +// lqw.eq(message.getUserId() != null, SysNotifyMessage::getUserId, message.getUserId()); + lqw.eq(message.getUserType() != null, SysNotifyMessage::getUserType, message.getUserType()); + lqw.eq(message.getTemplateId() != null, SysNotifyMessage::getTemplateId, message.getTemplateId()); + lqw.eq(StringUtils.isNotBlank(message.getTemplateCode()), SysNotifyMessage::getTemplateCode, message.getTemplateCode()); + lqw.like(StringUtils.isNotBlank(message.getTemplateNickname()), SysNotifyMessage::getTemplateNickname, message.getTemplateNickname()); + lqw.like(StringUtils.isNotBlank(message.getUserNickname()), SysNotifyMessage::getUserNickname, message.getUserNickname()); + lqw.eq(StringUtils.isNotBlank(message.getTemplateContent()), SysNotifyMessage::getTemplateContent, message.getTemplateContent()); + lqw.eq(message.getTemplateType() != null, SysNotifyMessage::getTemplateType, message.getTemplateType()); + lqw.eq(StringUtils.isNotBlank(message.getTemplateParams()), SysNotifyMessage::getTemplateParams, message.getTemplateParams()); + lqw.eq(message.getReadStatus() != null, SysNotifyMessage::getReadStatus, message.getReadStatus()); + lqw.eq(message.getReadTime() != null, SysNotifyMessage::getReadTime, message.getReadTime()); + LoginUser loginUser = LoginHelper.getLoginUser(); + if (!LoginHelper.isAdmin()) {//非管理员,只加载自己的数据 + lqw.eq(SysNotifyMessage::getUserId, loginUser.getUserId()); + } + return lqw; + } + /** + * 新增站内信消息 + */ + @Override + public Boolean insert(SysNotifyMessage message) { + SysNotifyMessage add = BeanUtil.toBean(message, SysNotifyMessage.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + message.setId(add.getId()); + } + return flag; + } + /** + * 修改站内信消息 + */ + @Override + public Boolean update(SysNotifyMessage message) { + SysNotifyMessage update = BeanUtil.toBean(message, SysNotifyMessage.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(SysNotifyMessage entity){ + //TODO 做一些数据校验,如唯一约束 + } + /** + * 批量删除站内信消息 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteBatchIds(ids) > 0; + } + + @Override + public Boolean updateNotifyMessageRead(Long[] ids, Long userId) { + return baseMapper.update(null,new LambdaUpdateWrapper().in(SysNotifyMessage::getId,ids) + .set(SysNotifyMessage::getReadStatus,1).set(SysNotifyMessage::getReadTime,new Date()) + .eq(SysNotifyMessage::getUserId,userId).eq(SysNotifyMessage::getReadStatus,0)) > -1; + } + + @Override + public Boolean updateAllNotifyMessageRead(Long userId) { + return baseMapper.update(null,new LambdaUpdateWrapper() + .set(SysNotifyMessage::getReadStatus,1).set(SysNotifyMessage::getReadTime,new Date()) + .eq(SysNotifyMessage::getUserId,userId).eq(SysNotifyMessage::getReadStatus,0)) > -1; + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysNotifyTemplateServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysNotifyTemplateServiceImpl.java new file mode 100644 index 0000000..b4e60ce --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysNotifyTemplateServiceImpl.java @@ -0,0 +1,147 @@ +package com.inscloudtech.system.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.StrUtil; +import com.inscloudtech.common.core.domain.entity.SysUser; +import com.inscloudtech.common.core.domain.model.LoginUser; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.core.domain.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.inscloudtech.system.mapper.SysUserMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import com.inscloudtech.system.domain.vo.SysNotifyTemplateVo; +import com.inscloudtech.system.domain.SysNotifyTemplate; +import com.inscloudtech.system.mapper.SysNotifyTemplateMapper; +import com.inscloudtech.system.service.ISysNotifyTemplateService; + +import java.util.*; + +/** + * 站内信模板Service业务层处理 + * + * @author inscloudtech + * @date 2023-06-07 + */ +@RequiredArgsConstructor +@Service +public class SysNotifyTemplateServiceImpl implements ISysNotifyTemplateService { + + private final SysNotifyTemplateMapper baseMapper; + + private final SysUserMapper userMapper; + /** + * 查询站内信模板 + */ + @Override + public SysNotifyTemplateVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + /** + * 查询站内信模板列表 + */ + @Override + public TableDataInfo queryPageList(SysNotifyTemplate bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + /** + * 查询站内信模板列表 + */ + @Override + public List queryList(SysNotifyTemplate bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(SysNotifyTemplate bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getName()), SysNotifyTemplate::getName, bo.getName()); + lqw.eq(StringUtils.isNotBlank(bo.getCode()), SysNotifyTemplate::getCode, bo.getCode()); + lqw.like(StringUtils.isNotBlank(bo.getNickname()), SysNotifyTemplate::getNickname, bo.getNickname()); + lqw.eq(StringUtils.isNotBlank(bo.getContent()), SysNotifyTemplate::getContent, bo.getContent()); + lqw.eq(bo.getType() != null, SysNotifyTemplate::getType, bo.getType()); + lqw.eq(bo.getStatus() != null, SysNotifyTemplate::getStatus, bo.getStatus()); + return lqw; + } + /** + * 新增站内信模板 + */ + @Override + public Boolean insertByBo(SysNotifyTemplate add) { + validEntityBeforeSave(add); + SysUser user = userMapper.selectById(LoginHelper.getUserId()); + add.setNickname(user.getNickName()); + boolean flag = baseMapper.insert(add) > 0; + + return flag; + } + /** + * 修改站内信模板 + */ + @Override + public Boolean updateByBo(SysNotifyTemplate bo) { + SysNotifyTemplate update = BeanUtil.toBean(bo, SysNotifyTemplate.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(SysNotifyTemplate entity){ + //TODO 做一些数据校验,如唯一约束 + } + /** + * 批量删除站内信模板 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteBatchIds(ids) > 0; + } + + @Override + public int sendSingleNotify(Long userId, String code, String params) { + return 0; + } + +// @VisibleForTesting + public int sendSingleNotify(Long userId, Integer userType, String templateCode, Map templateParams) { + // 校验模版 +// NotifyTemplateDO template = validateNotifyTemplate(templateCode); + SysNotifyTemplate template = baseMapper.selectOne(new LambdaQueryWrapper<>()); + //.getNotifyTemplateByCodeFromCache(templateCode); + // 站内信模板不存在 +// if (Objects.equals(template.getStatus(), CommonStatusEnum.DISABLE.getStatus())) { +// log.info("[sendSingleNotify][模版({})已经关闭,无法给用户({}/{})发送]", templateCode, userId, userType); +// return null; +// } + // 校验参数 +// validateTemplateParams(template, templateParams); + + // 发送站内信 + String templateContent = formatNotifyTemplateContent(template.getContent(), templateParams); + SysNotifyTemplate message = new SysNotifyTemplate(); +// message.setUserId(userId); +// .setUserType(userType) +// .setTemplateId(template.getId()).setTemplateCode(template.getCode()) +// .setTemplateType(template.getType()).setTemplateNickname(template.getNickname()) +// .setTemplateContent(templateContent).setTemplateParams(templateParams).setReadStatus(false); + + return baseMapper.insert(message); + } + + + public String formatNotifyTemplateContent(String content, Map params) { + return StrUtil.format(content, params); + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysOperLogServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysOperLogServiceImpl.java new file mode 100644 index 0000000..77b2651 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysOperLogServiceImpl.java @@ -0,0 +1,241 @@ +package com.inscloudtech.system.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.inscloudtech.bankStatementAnalysis.util.DesUtil; +import com.inscloudtech.caseMange.domain.vo.QueryOperateLogReq; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.entity.SysUser; +import com.inscloudtech.common.core.domain.event.OperLogEvent; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.ip.AddressUtils; +import com.inscloudtech.system.domain.SysOperLog; +import com.inscloudtech.system.domain.vo.LoginRecordEntity; +import com.inscloudtech.system.mapper.SysOperLogMapper; +import com.inscloudtech.system.mapper.SysUserMapper; +import com.inscloudtech.system.mapper.SysUserRoleMapper; +import com.inscloudtech.system.mapper.es.EsLoginRecordMapper; +import com.inscloudtech.system.service.ISysOperLogService; +import lombok.RequiredArgsConstructor; +import org.dromara.easyes.core.biz.SAPageInfo; +import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper; +import org.dromara.easyes.core.core.EsWrappers; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 操作日志 服务层处理 + * + * @author inscloudtech + */ +@RequiredArgsConstructor +@Service +public class SysOperLogServiceImpl implements ISysOperLogService { + + private final SysOperLogMapper baseMapper; + + private final SysOperLogMapper operLogMapper; + private final SysUserMapper userMapper; + private final SysUserRoleMapper userRoleMapper; + private final EsLoginRecordMapper esLoginRecordMapper; + /** + * 操作日志记录 + * + * @param operLogEvent 操作日志事件 + */ + @Async + @EventListener + public void recordOper(OperLogEvent operLogEvent) { + SysOperLog operLog = BeanUtil.toBean(operLogEvent, SysOperLog.class); + // 远程查询操作地点 + operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp())); + insertOperlog(operLog); + } + + @Override + public TableDataInfo selectPageOperLogList(SysOperLog operLog, PageQuery pageQuery) { + Map params = operLog.getParams(); + LambdaQueryWrapper lqw = new LambdaQueryWrapper() + .like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle()) + .eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0, + SysOperLog::getBusinessType, operLog.getBusinessType()) + .func(f -> { + if (ArrayUtil.isNotEmpty(operLog.getBusinessTypes())) { + f.in(SysOperLog::getBusinessType, Arrays.asList(operLog.getBusinessTypes())); + } + }) + .eq(operLog.getStatus() != null, + SysOperLog::getStatus, operLog.getStatus()) + .like(StringUtils.isNotBlank(operLog.getOperName()), SysOperLog::getOperName, operLog.getOperName()) + .between(params.get("beginTime") != null && params.get("endTime") != null, + SysOperLog::getOperTime, params.get("beginTime"), params.get("endTime")); + if (StringUtils.isBlank(pageQuery.getOrderByColumn())) { + pageQuery.setOrderByColumn("oper_id"); + pageQuery.setIsAsc("desc"); + } + Page page = baseMapper.selectPage(pageQuery.build(), lqw); + return TableDataInfo.build(page); + } + /** + * 新增操作日志 + * + * @param operLog 操作日志对象 + */ + @Override + public void insertOperlog(SysOperLog operLog) { + operLog.setOperTime(new Date()); + baseMapper.insert(operLog); + } + /** + * 查询系统操作日志集合 + * + * @param operLog 操作日志对象 + * @return 操作日志集合 + */ + @Override + public List selectOperLogList(SysOperLog operLog) { + Map params = operLog.getParams(); + return baseMapper.selectList(new LambdaQueryWrapper() + .like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle()) + .eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0, + SysOperLog::getBusinessType, operLog.getBusinessType()) + .func(f -> { + if (ArrayUtil.isNotEmpty(operLog.getBusinessTypes())) { + f.in(SysOperLog::getBusinessType, Arrays.asList(operLog.getBusinessTypes())); + } + }) + .eq(operLog.getStatus() != null && operLog.getStatus() > 0, + SysOperLog::getStatus, operLog.getStatus()) + .like(StringUtils.isNotBlank(operLog.getOperName()), SysOperLog::getOperName, operLog.getOperName()) + .between(params.get("beginTime") != null && params.get("endTime") != null, + SysOperLog::getOperTime, params.get("beginTime"), params.get("endTime")) + .orderByDesc(SysOperLog::getOperId)); + } + /** + * 批量删除系统操作日志 + * + * @param operIds 需要删除的操作日志ID + * @return 结果 + */ + @Override + public int deleteOperLogByIds(Long[] operIds) { + return baseMapper.deleteBatchIds(Arrays.asList(operIds)); + } + /** + * 查询操作日志详细 + * + * @param operId 操作ID + * @return 操作日志对象 + */ + @Override + public SysOperLog selectOperLogById(Long operId) { + return baseMapper.selectById(operId); + } + /** + * 清空操作日志 + */ + @Override + public void cleanOperLog() { + baseMapper.delete(new LambdaQueryWrapper<>()); + } + + + @Override + public TableDataInfo queryOperateLogV2(QueryOperateLogReq req) { + + String userName = req.getUserName(); + String idCardNo = req.getIdCardNo(); + + LambdaEsQueryWrapper lambdaQuery = EsWrappers.lambdaQuery(LoginRecordEntity.class); + + if (StrUtil.isNotEmpty(userName)) { + lambdaQuery.like(LoginRecordEntity::getUserName, userName); + } + + // 身份证 + if (StrUtil.isNotEmpty(idCardNo)) { + lambdaQuery.like(LoginRecordEntity::getIdCardNo, idCardNo); + } + + // 时间 + QueryOperateLogReq.Params params = req.getParams(); + if (params!= null) { + req.setBeginTime(params.getBeginLoginDate()); + req.setEndTime(params.getEndLoginDate()); + } + + String beginTimeStr = req.getBeginTime(); + String endTimeStr = req.getEndTime(); + + if (StrUtil.isNotEmpty(beginTimeStr)) { + DateTime beginTime = DateUtil.parse(beginTimeStr); + if (StrUtil.isNotEmpty(endTimeStr)) { + DateTime endTime = DateUtil.parse(endTimeStr); + lambdaQuery.between(LoginRecordEntity::getLoginDate, beginTime.getTime(), endTime.getTime()); + } else { + lambdaQuery.gt(LoginRecordEntity::getLoginDate, beginTime.getTime()); + } + } + // 权限类别 + String permissionType = req.getPermissionType(); + if (StrUtil.isNotEmpty(permissionType)) { + lambdaQuery.eq(LoginRecordEntity::getPermissionType, permissionType); + } + + // 排序 + lambdaQuery.orderByDesc(LoginRecordEntity::getLoginDate); + + // 分页 + int pageNum = req.getPageNum(); + int pageSize = req.getPageSize(); + + SAPageInfo pageInfo; + if (pageNum == 1) { + pageInfo = esLoginRecordMapper.searchAfterPage(lambdaQuery, null, pageSize); + } else { + pageInfo = esLoginRecordMapper.searchAfterPage(lambdaQuery, null, (pageNum - 1) * pageSize); + pageInfo = esLoginRecordMapper.searchAfterPage(lambdaQuery, pageInfo.getNextSearchAfter(), pageSize); + } + + TableDataInfo rst = new TableDataInfo<>(); + List bsList = pageInfo.getList(); + + List idList = new ArrayList<>(); + List newList = new ArrayList<>(); + for (LoginRecordEntity loginRecord : bsList) { + Long userId = loginRecord.getUserId(); + SysUser user = userMapper.selectById(userId); + if (user == null) { + idList.add(loginRecord.getId()); + }else { + newList.add(loginRecord); + } + + } + + if(idList.size() > 0){ + esLoginRecordMapper.deleteBatchIds(idList); + } + + // 加密身份证 + newList = newList.stream() + .peek(item -> item.setIdCardNo(DesUtil.encrypt(item.getIdCardNo()))) + .collect(Collectors.toList()); + + rst.setRows(newList); + rst.setTotal(pageInfo.getTotal()); + + return rst; + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysOperUpdateLogServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysOperUpdateLogServiceImpl.java new file mode 100644 index 0000000..5da25a8 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysOperUpdateLogServiceImpl.java @@ -0,0 +1,149 @@ +package com.inscloudtech.system.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import com.inscloudtech.common.core.domain.event.OperLogEvent; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.core.domain.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.inscloudtech.common.utils.ip.AddressUtils; +import com.inscloudtech.system.domain.SysOperLog; +import lombok.RequiredArgsConstructor; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import com.inscloudtech.system.domain.bo.SysOperUpdateLogBo; +import com.inscloudtech.system.domain.vo.SysOperUpdateLogVo; +import com.inscloudtech.system.domain.SysOperUpdateLog; +import com.inscloudtech.system.mapper.SysOperUpdateLogMapper; +import com.inscloudtech.system.service.ISysOperUpdateLogService; + +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 操作日志记录Service业务层处理 + * + * @author inscloudtech + * @date 2023-05-18 + */ +@RequiredArgsConstructor +@Service +public class SysOperUpdateLogServiceImpl implements ISysOperUpdateLogService { + + private final SysOperUpdateLogMapper baseMapper; + /** + * 查询操作日志记录 + */ + @Override + public SysOperUpdateLogVo queryById(Long operId){ + return baseMapper.selectVoById(operId); + } + /** + * 查询操作日志记录列表 + */ + @Override + public TableDataInfo queryPageList(SysOperUpdateLogBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + /** + * 查询操作日志记录列表 + */ + @Override + public List queryList(SysOperUpdateLogBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(SysOperUpdateLogBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StringUtils.isNotBlank(bo.getTitle()), SysOperUpdateLog::getTitle, bo.getTitle()); + lqw.eq(StringUtils.isNotBlank(bo.getMethod()), SysOperUpdateLog::getMethod, bo.getMethod()); + lqw.eq(StringUtils.isNotBlank(bo.getRequestMethod()), SysOperUpdateLog::getRequestMethod, bo.getRequestMethod()); + lqw.eq(bo.getOperatorType() != null, SysOperUpdateLog::getOperatorType, bo.getOperatorType()); + lqw.like(StringUtils.isNotBlank(bo.getOperName()), SysOperUpdateLog::getOperName, bo.getOperName()); + lqw.like(StringUtils.isNotBlank(bo.getDeptName()), SysOperUpdateLog::getDeptName, bo.getDeptName()); + lqw.eq(StringUtils.isNotBlank(bo.getOperUrl()), SysOperUpdateLog::getOperUrl, bo.getOperUrl()); + lqw.eq(StringUtils.isNotBlank(bo.getOperIp()), SysOperUpdateLog::getOperIp, bo.getOperIp()); + lqw.eq(StringUtils.isNotBlank(bo.getOperLocation()), SysOperUpdateLog::getOperLocation, bo.getOperLocation()); + lqw.eq(StringUtils.isNotBlank(bo.getOperParam()), SysOperUpdateLog::getOperParam, bo.getOperParam()); + lqw.eq(StringUtils.isNotBlank(bo.getJsonResult()), SysOperUpdateLog::getJsonResult, bo.getJsonResult()); + lqw.eq(bo.getStatus() != null, SysOperUpdateLog::getStatus, bo.getStatus()); + lqw.eq(StringUtils.isNotBlank(bo.getErrorMsg()), SysOperUpdateLog::getErrorMsg, bo.getErrorMsg()); + lqw.eq(bo.getOperTime() != null, SysOperUpdateLog::getOperTime, bo.getOperTime()); + lqw.eq(StringUtils.isNotBlank(bo.getBeforeValue()), SysOperUpdateLog::getBeforeValue, bo.getBeforeValue()); + lqw.eq(StringUtils.isNotBlank(bo.getAfterValue()), SysOperUpdateLog::getAfterValue, bo.getAfterValue()); + lqw.eq(bo.getBusinessId() != null, SysOperUpdateLog::getBusinessId, bo.getBusinessId()); + return lqw; + } + /** + * 新增操作日志记录 + */ + @Override + public Boolean insertByBo(SysOperUpdateLogBo bo) { + SysOperUpdateLog add = BeanUtil.toBean(bo, SysOperUpdateLog.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setOperId(add.getOperId()); + } + return flag; + } + /** + * 修改操作日志记录 + */ + @Override + public Boolean updateByBo(SysOperUpdateLogBo bo) { + SysOperUpdateLog update = BeanUtil.toBean(bo, SysOperUpdateLog.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(SysOperUpdateLog entity){ + //TODO 做一些数据校验,如唯一约束 + } + /** + * 批量删除操作日志记录 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteBatchIds(ids) > 0; + } + /** + * 操作日志记录 + * + * @param operLogEvent 操作日志事件 + */ + @Async + @EventListener + public void recordOper(OperLogEvent operLogEvent) { + if(ObjectUtil.isEmpty(operLogEvent.getBusinessId()) || StringUtils.isEmpty(operLogEvent.getBeforeValue()) || StringUtils.isEmpty(operLogEvent.getAfterValue())){ + return; + } + SysOperUpdateLog operUpdateLog = BeanUtil.toBean(operLogEvent, SysOperUpdateLog.class); + // 远程查询操作地点 + operUpdateLog.setOperLocation(AddressUtils.getRealAddressByIP(operUpdateLog.getOperIp())); + insertOperlog(operUpdateLog); + } + /** + * 新增操作日志 + * + * @param operUpdateLog 操作日志对象 + */ + public void insertOperlog(SysOperUpdateLog operUpdateLog) { + operUpdateLog.setOperTime(new Date()); + baseMapper.insert(operUpdateLog); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysOssServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysOssServiceImpl.java new file mode 100644 index 0000000..1654c6a --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysOssServiceImpl.java @@ -0,0 +1,454 @@ +package com.inscloudtech.system.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.inscloudtech.analysiscenter.domain.AnalysisDto; +import com.inscloudtech.bankStatementAnalysis.helper.HelperUtil; +import com.inscloudtech.common.annotation.UpdateLog; +import com.inscloudtech.common.config.ProjectConfig; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.common.utils.ServletUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.common.utils.file.FileUploadUtils; +import com.inscloudtech.common.utils.file.FileUtils; +import com.inscloudtech.system.domain.SysOss; +import com.inscloudtech.system.mapper.SysOssMapper; +import com.inscloudtech.system.service.ISysOssService; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import org.springframework.aop.framework.AopContext; +import org.springframework.http.MediaType; +import org.springframework.scheduling.annotation.Async; +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.IOException; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 文件上传 服务层实现 + * + * @author inscloudtech + */ +@RequiredArgsConstructor +@Service +public class SysOssServiceImpl implements ISysOssService { + + private final SysOssMapper baseMapper; + +// private final MinioConfig minioConfig; + + + + @Override + public TableDataInfo queryPageList(SysOss bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectPage(pageQuery.build(), lqw); + TableDataInfo tableDataInfo = TableDataInfo.build(result); + return tableDataInfo; + } + + @Override + public List listByIds(Collection ossIds) { + List sysOssVos = baseMapper.selectList(new LambdaQueryWrapper().in(SysOss::getOssId, ossIds)); + return sysOssVos; + } + + private LambdaQueryWrapper buildQueryWrapper(SysOss bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(null != bo.getCaseId(), SysOss::getCaseId, bo.getCaseId()); + lqw.like(StrUtil.isNotBlank(bo.getFileName()), SysOss::getFileName, bo.getFileName()); + lqw.like(StrUtil.isNotBlank(bo.getOriginalName()), SysOss::getOriginalName, bo.getOriginalName()); + lqw.eq(StrUtil.isNotBlank(bo.getFileSuffix()), SysOss::getFileSuffix, bo.getFileSuffix()); + lqw.eq(StrUtil.isNotBlank(bo.getUrl()), SysOss::getUrl, bo.getUrl()); + lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null, + SysOss::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime")); + lqw.eq(StrUtil.isNotBlank(bo.getCreateBy()), SysOss::getCreateBy, bo.getCreateBy()); + lqw.eq(null != bo.getAnalysisResultId(), SysOss::getAnalysisResultId, bo.getAnalysisResultId()); + lqw.eq(StrUtil.isNotBlank(bo.getBusinessModule()), SysOss::getBusinessModule, bo.getBusinessModule()); + lqw.eq(null != bo.getUploadResult(), SysOss::getUploadResult, bo.getUploadResult()); + lqw.like(StrUtil.isNotBlank(bo.getErrorInfo()), SysOss::getErrorInfo, bo.getErrorInfo()); + lqw.ne(SysOss::getBusinessModule, "ANALYSIS_REPORT"); + return lqw; + } + + @Override + public SysOss getById(String ossId) { + return baseMapper.selectById(ossId); + } + + + @Override + public void download(String ossId, HttpServletResponse response) { + SysOss sysOss = baseMapper.selectById(ossId); +// MinioUtil.downloadFile(minioConfig.getBucketName(), sysOss.getFileName(),sysOss.getOriginalName(),response); + this.downloadLocal(sysOss.getFileName(),sysOss.getOriginalName(),response); + } + + /** + * 下载本地文件 + * @param fileName + * @param response + */ + @SneakyThrows + @Override + public void downloadLocal(String fileName,String originalName,HttpServletResponse response){ + if (!FileUtils.checkAllowDownload(fileName)) { + throw new RuntimeException(StrUtil.format("文件名称({})非法,不允许下载。 ", fileName)); + } + String filePath = ProjectConfig.getUploadPath() + fileName; + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + FileUtils.setAttachmentResponseHeader(response, originalName); + FileUtils.writeBytes(filePath, response.getOutputStream()); + } + + @Override + public SysOss upload(MultipartFile file) { + SysOss sysOss = new SysOss(); + sysOss.setCreateBy(LoginHelper.getUsername()); + sysOss.setCreateTime(new Date()); + uploadOss(sysOss,file); + return sysOss; + } + + @SneakyThrows + SysOss uploadOss(SysOss oss,MultipartFile file){ + String originalName = file.getOriginalFilename(); + String suffix = StringUtils.substring(originalName, originalName.lastIndexOf("."), originalName.length()); +// +// // 保存文件信息 +// String fileName = FileUploadUtils.extractFilename(file); +// Map stringObjectMap = MinioUtil.uploadFileReturnResult(minioConfig.getBucketName(), fileName, file); +// Integer uploadResult = 0; +// String detail = stringObjectMap.get("detail").toString(); +// if (stringObjectMap.get("success").equals(HttpStatus.ERROR)) { +// uploadResult = 1; +//// oss.setErrorInfo(oss.getErrorInfo() + detail); +// }else { +// oss.setUrl(detail); +// oss.setFileName(detail.split(minioConfig.getBucketName())[1]); +// } +// if(null != oss.getUploadResult() && oss.getUploadResult().equals(1)){ +// uploadResult = 1; +// } +// oss.setUploadResult(uploadResult); +// oss.setFileSuffix(suffix); +// oss.setOriginalName(originalName); +// baseMapper.insert(oss); + return oss; + } + + @SneakyThrows + @Override + public Boolean deleteWithValidByIds(Collection ids) { + /* List list = baseMapper.selectBatchIds(ids); + + for (SysOss sysOss : list) { + //有案件,分析成果共用文件就不删除 + if(sysOss.getDuplicateAr() == 1 || sysOss.getDuplicateCase() == 1){ + continue; + } + this.deleteLocal(sysOss.getFileName()); +// MinioUtil.deleteFile(minioConfig.getBucketName(), sysOss.getFileName()); + }*/ + return baseMapper.deleteBatchIds(ids) > 0; + } + + @Override + public void deleteByCaseIdAndBusinessModule(String caseId,String businessModule) { + baseMapper.delete(Wrappers.lambdaQuery(SysOss.class).eq(SysOss::getCaseId, caseId) + .eq(SysOss::getBusinessModule,businessModule)); + } + + @Override + public void deleteByCaseId(String caseId) { + baseMapper.delete(Wrappers.lambdaQuery(SysOss.class).eq(SysOss::getCaseId, caseId)); + } + + @Override + public void upload2LocalWithBatchId(MultipartFile file, String caseId, String businessModule, String batchId,int uploadResult) { + SysOss sysOss = new SysOss(); + sysOss.setUploadResult(uploadResult); + sysOss.setBusinessModule(businessModule); + sysOss.setCaseId(caseId); + sysOss.setBatchId(batchId); + sysOss.setCreateBy(LoginHelper.getUsername()); + sysOss.setCreateTime(new Date()); + this.uploadLocal(sysOss,file); + baseMapper.insert(sysOss); + } + + @Override + public void save2AnalysisResult(AnalysisDto dto) { + Set ids = dto.getIds(); + if (ids.isEmpty()) { + return; + } + String analysisResultId = dto.getAnalysisResultId(); + List sysOssList = baseMapper.selectBatchIds(ids); + Set uniqueKeySet = new HashSet(); + Set updateDuplicateArIdSet = new HashSet(); + + List result = new ArrayList<>(); + for (SysOss item : sysOssList) { + item.setAnalysisResultId(analysisResultId); + String md5Id = HelperUtil.generateMD5(item.toString()); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + updateDuplicateArIdSet.add(item.getOssId()); + item.setCaseId(null); + item.setDuplicateAr(1); + item.setOssId(md5Id); + result.add(item); + } + uniqueKeySet.clear(); + if (CollectionUtil.isNotEmpty(result)) { + //根据id取es查询 返回的就是重复数据 + Map groupById = result.stream().collect(Collectors.toMap(SysOss::getOssId, Function.identity())); + Set idSet = groupById.keySet(); + List existIdList = baseMapper.selectBatchIds(idSet); + + if(CollectionUtil.isEmpty(existIdList)){ + baseMapper.insertBatch(result); + }else { + Set esIdSet = existIdList.stream().filter(item -> StrUtil.isNotEmpty(item.getOssId())).map(SysOss::getOssId).collect(Collectors.toSet()); + idSet.removeAll(esIdSet); + if(CollectionUtil.isNotEmpty(idSet)){ + List saveLis = new ArrayList<>(); + for (String id : idSet) { + saveLis.add(groupById.get(id)); + } + baseMapper.insertBatch(saveLis); + } + } + } + if (CollectionUtil.isNotEmpty(updateDuplicateArIdSet)) { + SysOss sysOss = new SysOss(); + sysOss.setDuplicateAr(1); + UpdateWrapper qw = Wrappers.update(); + qw.in("oss_id",updateDuplicateArIdSet); + baseMapper.update(sysOss,qw); + } + } + + private static final String OTHER_BUSINESS_MODULE = "OTHER_ASSETS,OTHER_INFORMATION"; + + @Override + public void analysisResultMerge(Map sourceArIdTargetArIdMap, String businessModule) { + List analysisReportList = baseMapper.selectList(new LambdaQueryWrapper() + .in(SysOss::getAnalysisResultId,sourceArIdTargetArIdMap.keySet())); + Map> arMap = analysisReportList.stream().collect(Collectors.groupingBy(SysOss::getAnalysisResultId)); + List addList = new ArrayList<>(); + for (Map.Entry > entry : arMap.entrySet()) { + String sourceArId = entry.getKey(); + List reports = entry.getValue(); + String targetArId = sourceArIdTargetArIdMap.get(sourceArId); + for (SysOss result : reports) { + result.setAnalysisResultId(targetArId); + String md5Id = HelperUtil.generateMD5(result.toString()); + result.setOssId(md5Id); + addList.add(result); + } + } + if(CollectionUtil.isNotEmpty(addList)){ + baseMapper.insertBatch(addList); + } +// if (CollectionUtil.isNotEmpty(updateDuplicateArIdSet)) { +// SysOss sysOss = new SysOss(); +// sysOss.setDuplicateAr(1); +// UpdateWrapper qw = Wrappers.update(); +// qw.in("oss_id",updateDuplicateArIdSet); +// baseMapper.update(sysOss,qw); +// } + } + + @Override + public void caseMerge(String sourceCaseId, String targetCaseId, String businessModule) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(SysOss::getCaseId,sourceCaseId); + lqw.eq(SysOss::getBusinessModule,businessModule); + List sysOssList = baseMapper.selectList(lqw); + Set uniqueKeySet = new HashSet(); + Set updateDuplicateArIdSet = new HashSet(); + + List result = new ArrayList<>(); + for (SysOss item : sysOssList) { + item.setCaseId(targetCaseId); + String md5Id = HelperUtil.generateMD5(item.toString()); + //未导入数据内部去重 + if(HelperUtil.deduplication(md5Id,uniqueKeySet)){ + continue; + } + updateDuplicateArIdSet.add(item.getOssId()); + item.setDuplicateCase(1); + item.setOssId(md5Id); + if(OTHER_BUSINESS_MODULE.contains(businessModule)){ + if(!item.getFileName().contains("(并入)")){ + item.setFileName(item.getFileName() + "(并入)"); + } + } + result.add(item); + } + + uniqueKeySet.clear(); + + if (CollectionUtil.isNotEmpty(result)) { + //根据id取es查询 返回的就是重复数据 + Map groupById = result.stream().collect(Collectors.toMap(SysOss::getOssId, Function.identity())); + Set idSet = groupById.keySet(); + List existIdList = baseMapper.selectBatchIds(idSet); + if(CollectionUtil.isEmpty(existIdList)){ + baseMapper.insertBatch(result); + }else { + Set esIdSet = existIdList.stream().filter(item -> StrUtil.isNotEmpty(item.getOssId())).map(SysOss::getOssId).collect(Collectors.toSet()); + idSet.removeAll(esIdSet); + if(CollectionUtil.isNotEmpty(idSet)){ + List saveLis = new ArrayList<>(); + for (String id : idSet) { + saveLis.add(groupById.get(id)); + } + baseMapper.insertBatch(saveLis); + } + } + } + + if (CollectionUtil.isNotEmpty(updateDuplicateArIdSet)) { + SysOss sysOss = new SysOss(); + sysOss.setDuplicateCase(1); + UpdateWrapper qw = Wrappers.update(); + qw.in("oss_id",updateDuplicateArIdSet); + baseMapper.update(sysOss,qw); + } + + } + + @Override + public SysOss upload(MultipartFile file, String caseId, String businessModule) { + SysOss sysOss = new SysOss(); + sysOss.setCreateBy(LoginHelper.getUsername()); + sysOss.setCreateTime(new Date()); + sysOss.setBusinessModule(businessModule); + sysOss.setCaseId(caseId); + sysOss.setCaseId(caseId); + uploadOss(sysOss,file); + return sysOss; + } + + @Override + @Async + public SysOss upload2Local(int importCount,String importResult, MultipartFile file, String caseId, String businessModule) { + SysOss sysOss = new SysOss(); + sysOss.setErrorInfo(importResult); + if(StrUtil.isNotEmpty(importResult)){ + sysOss.setUploadResult(1); + }else { + sysOss.setUploadResult(0); + } + sysOss.setBusinessModule(businessModule); + sysOss.setCaseId(caseId); + sysOss.setCreateBy(LoginHelper.getUsername()); + sysOss.setCreateTime(new Date()); + sysOss.setImportCount(importCount); + this.uploadLocal(sysOss,file); + baseMapper.insert(sysOss); + + return sysOss; + } + + + /** + * 删除本地文件 + * @param fileName + */ + void deleteLocal(String fileName){ + String filePath = ProjectConfig.getUploadPath() + fileName; + FileUtils.deleteFile(filePath); + } + + /** + * 上传文件到本地 + * @param sysOss + * @param file + */ + void uploadLocal(SysOss sysOss,MultipartFile file){ + // 上传文件路径 + String filePath = ProjectConfig.getUploadPath(); + Integer uploadResult = sysOss.getUploadResult(); + // 上传并返回新文件名称 + String fileName = null; + try { + fileName = FileUploadUtils.upload(filePath, file); + } catch (IOException e) { + uploadResult = 1; + sysOss.setErrorInfo(sysOss.getErrorInfo() + e.getMessage()); + } + if(StrUtil.isEmpty(fileName)){ + return; + } + String url = this.getUrl() + fileName; + sysOss.setUrl(url); + sysOss.setUploadResult(uploadResult); + + if(fileName.contains("/profile/upload")){ + fileName = fileName.replace("/profile/upload",""); + } + sysOss.setFileName(fileName); + sysOss.setUploadResult(uploadResult); + String originalName = file.getOriginalFilename(); + sysOss.setOriginalName(originalName); + String suffix = StringUtils.substring(originalName, originalName.lastIndexOf("."), originalName.length()); + sysOss.setFileSuffix(suffix); + + } + + @Override + public List queryList(SysOss bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectList(lqw); + } + + @Override + @Transactional + public Boolean updateBatch(List list) { + SysOssServiceImpl partnerService = getServiceImpl(); + list.stream().forEach(update->{ + partnerService.updateR(update); + }); + return true; + } + + @UpdateLog(title = "其他信息",mapperClass = SysOssMapper.class) + public boolean updateR(SysOss sysOss) { + return baseMapper.updateById(sysOss) > 0; + } + + private SysOssServiceImpl getServiceImpl() { + return AopContext.currentProxy() != null ? (SysOssServiceImpl) AopContext.currentProxy() : this; + } + + /** + * 获取完整的请求路径,包括:域名,端口,上下文访问路径 + * + * @return 服务地址 + */ + public String getUrl() { + HttpServletRequest request = ServletUtils.getRequest(); + StringBuffer url = request.getRequestURL(); + String contextPath = request.getServletContext().getContextPath(); + return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString(); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysPostServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysPostServiceImpl.java new file mode 100644 index 0000000..812e867 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysPostServiceImpl.java @@ -0,0 +1,166 @@ +package com.inscloudtech.system.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.exception.ServiceException; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.system.domain.SysPost; +import com.inscloudtech.system.domain.SysUserPost; +import com.inscloudtech.system.mapper.SysPostMapper; +import com.inscloudtech.system.mapper.SysUserPostMapper; +import com.inscloudtech.system.service.ISysPostService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; + +/** + * 岗位信息 服务层处理 + * + * @author inscloudtech + */ +@RequiredArgsConstructor +@Service +public class SysPostServiceImpl implements ISysPostService { + + private final SysPostMapper baseMapper; + private final SysUserPostMapper userPostMapper; + + @Override + public TableDataInfo selectPagePostList(SysPost post, PageQuery pageQuery) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper() + .like(StringUtils.isNotBlank(post.getPostCode()), SysPost::getPostCode, post.getPostCode()) + .eq(StringUtils.isNotBlank(post.getStatus()), SysPost::getStatus, post.getStatus()) + .like(StringUtils.isNotBlank(post.getPostName()), SysPost::getPostName, post.getPostName()); + Page page = baseMapper.selectPage(pageQuery.build(), lqw); + return TableDataInfo.build(page); + } + /** + * 查询岗位信息集合 + * + * @param post 岗位信息 + * @return 岗位信息集合 + */ + @Override + public List selectPostList(SysPost post) { + return baseMapper.selectList(new LambdaQueryWrapper() + .like(StringUtils.isNotBlank(post.getPostCode()), SysPost::getPostCode, post.getPostCode()) + .eq(StringUtils.isNotBlank(post.getStatus()), SysPost::getStatus, post.getStatus()) + .like(StringUtils.isNotBlank(post.getPostName()), SysPost::getPostName, post.getPostName())); + } + /** + * 查询所有岗位 + * + * @return 岗位列表 + */ + @Override + public List selectPostAll() { + return baseMapper.selectList(); + } + /** + * 通过岗位ID查询岗位信息 + * + * @param postId 岗位ID + * @return 角色对象信息 + */ + @Override + public SysPost selectPostById(Long postId) { + return baseMapper.selectById(postId); + } + /** + * 根据用户ID获取岗位选择框列表 + * + * @param userId 用户ID + * @return 选中岗位ID列表 + */ + @Override + public List selectPostListByUserId(Long userId) { + return baseMapper.selectPostListByUserId(userId); + } + /** + * 校验岗位名称是否唯一 + * + * @param post 岗位信息 + * @return 结果 + */ + @Override + public boolean checkPostNameUnique(SysPost post) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysPost::getPostName, post.getPostName()) + .ne(ObjectUtil.isNotNull(post.getPostId()), SysPost::getPostId, post.getPostId())); + return !exist; + } + /** + * 校验岗位编码是否唯一 + * + * @param post 岗位信息 + * @return 结果 + */ + @Override + public boolean checkPostCodeUnique(SysPost post) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysPost::getPostCode, post.getPostCode()) + .ne(ObjectUtil.isNotNull(post.getPostId()), SysPost::getPostId, post.getPostId())); + return !exist; + } + /** + * 通过岗位ID查询岗位使用数量 + * + * @param postId 岗位ID + * @return 结果 + */ + @Override + public long countUserPostById(Long postId) { + return userPostMapper.selectCount(new LambdaQueryWrapper().eq(SysUserPost::getPostId, postId)); + } + /** + * 删除岗位信息 + * + * @param postId 岗位ID + * @return 结果 + */ + @Override + public int deletePostById(Long postId) { + return baseMapper.deleteById(postId); + } + /** + * 批量删除岗位信息 + * + * @param postIds 需要删除的岗位ID + * @return 结果 + */ + @Override + public int deletePostByIds(Long[] postIds) { + for (Long postId : postIds) { + SysPost post = selectPostById(postId); + if (countUserPostById(postId) > 0) { + throw new ServiceException(String.format("%1$s已分配,不能删除", post.getPostName())); + } + } + return baseMapper.deleteBatchIds(Arrays.asList(postIds)); + } + /** + * 新增保存岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + @Override + public int insertPost(SysPost post) { + return baseMapper.insert(post); + } + /** + * 修改保存岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + @Override + public int updatePost(SysPost post) { + return baseMapper.updateById(post); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysRoleServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysRoleServiceImpl.java new file mode 100644 index 0000000..5c09cfb --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysRoleServiceImpl.java @@ -0,0 +1,431 @@ +package com.inscloudtech.system.service.impl; + +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.inscloudtech.common.constant.UserConstants; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.entity.SysRole; +import com.inscloudtech.common.core.domain.model.LoginUser; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.exception.ServiceException; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.common.utils.StreamUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.system.domain.SysRoleDept; +import com.inscloudtech.system.domain.SysRoleMenu; +import com.inscloudtech.system.domain.SysUserRole; +import com.inscloudtech.system.mapper.SysRoleDeptMapper; +import com.inscloudtech.system.mapper.SysRoleMapper; +import com.inscloudtech.system.mapper.SysRoleMenuMapper; +import com.inscloudtech.system.mapper.SysUserRoleMapper; +import com.inscloudtech.system.service.ISysMenuService; +import com.inscloudtech.system.service.ISysRoleService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +/** + * 角色 业务层处理 + * + * @author inscloudtech + */ +@RequiredArgsConstructor +@Service +public class SysRoleServiceImpl implements ISysRoleService { + + private final SysRoleMapper baseMapper; + private final SysRoleMenuMapper roleMenuMapper; + private final SysUserRoleMapper userRoleMapper; + private final SysRoleDeptMapper roleDeptMapper; + private final ISysMenuService menuService; + + @Override + public TableDataInfo selectPageRoleList(SysRole role, PageQuery pageQuery) { + Page page = baseMapper.selectPageRoleList(pageQuery.build(), this.buildQueryWrapper(role)); + return TableDataInfo.build(page); + } + /** + * 根据条件分页查询角色数据 + * + * @param role 角色信息 + * @return 角色数据集合信息 + */ + @Override + public List selectRoleList(SysRole role) { + return baseMapper.selectRoleList(this.buildQueryWrapper(role)); + } + + private Wrapper buildQueryWrapper(SysRole role) { + Map params = role.getParams(); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("r.del_flag", UserConstants.ROLE_NORMAL) + .eq(ObjectUtil.isNotNull(role.getRoleId()), "r.role_id", role.getRoleId()) + .like(StringUtils.isNotBlank(role.getRoleName()), "r.role_name", role.getRoleName()) + .eq(StringUtils.isNotBlank(role.getStatus()), "r.status", role.getStatus()) + .like(StringUtils.isNotBlank(role.getRoleKey()), "r.role_key", role.getRoleKey()) + .between(params.get("beginTime") != null && params.get("endTime") != null, + "r.create_time", params.get("beginTime"), params.get("endTime")) + .orderByAsc("r.role_sort").orderByAsc("r.create_time"); + return wrapper; + } + /** + * 根据用户ID查询角色 + * + * @param userId 用户ID + * @return 角色列表 + */ + @Override + public List selectRolesByUserId(Long userId) { + List userRoles = baseMapper.selectRolePermissionByUserId(userId); + List roles = selectRoleAll(); + for (SysRole role : roles) { + for (SysRole userRole : userRoles) { + if (role.getRoleId().longValue() == userRole.getRoleId().longValue()) { + role.setFlag(true); + break; + } + } + } + return roles; + } + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + @Override + public Set selectRolePermissionByUserId(Long userId) { + List perms = baseMapper.selectRolePermissionByUserId(userId); + Set permsSet = new HashSet<>(); + for (SysRole perm : perms) { + if (ObjectUtil.isNotNull(perm)) { + permsSet.addAll(StringUtils.splitList(perm.getRoleKey().trim())); + } + } + return permsSet; + } + /** + * 查询所有角色 + * + * @return 角色列表 + */ + @Override + public List selectRoleAll() { + return this.selectRoleList(new SysRole()); + } + /** + * 根据用户ID获取角色选择框列表 + * + * @param userId 用户ID + * @return 选中角色ID列表 + */ + @Override + public List selectRoleListByUserId(Long userId) { + return baseMapper.selectRoleListByUserId(userId); + } + /** + * 通过角色ID查询角色 + * + * @param roleId 角色ID + * @return 角色对象信息 + */ + @Override + public SysRole selectRoleById(Long roleId) { + return baseMapper.selectById(roleId); + } + + @Override + public SysRole selectRoleInfoById(Long roleId) { + SysRole role = baseMapper.selectById(roleId); + role.setMenuNames(menuService.selectMenuNameListByRoleId(roleId)); + return role; + } + + /** + * 校验角色名称是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + public boolean checkRoleNameUnique(SysRole role) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysRole::getRoleName, role.getRoleName()) + .ne(ObjectUtil.isNotNull(role.getRoleId()), SysRole::getRoleId, role.getRoleId())); + return !exist; + } + /** + * 校验角色权限是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + public boolean checkRoleKeyUnique(SysRole role) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysRole::getRoleKey, role.getRoleKey()) + .ne(ObjectUtil.isNotNull(role.getRoleId()), SysRole::getRoleId, role.getRoleId())); + return !exist; + } + /** + * 校验角色是否允许操作 + * + * @param role 角色信息 + */ + @Override + public void checkRoleAllowed(SysRole role) { + if (ObjectUtil.isNotNull(role.getRoleId()) && role.isAdmin()) { + throw new ServiceException("不允许操作超级管理员角色"); + } + } + /** + * 校验角色是否有数据权限 + * + * @param roleId 角色id + */ + @Override + public void checkRoleDataScope(Long roleId) { + if (!LoginHelper.isAdmin()) { + SysRole role = new SysRole(); + role.setRoleId(roleId); + List roles = this.selectRoleList(role); + if (CollUtil.isEmpty(roles)) { + throw new ServiceException("没有权限访问角色数据!"); + } + } + } + /** + * 通过角色ID查询角色使用数量 + * + * @param roleId 角色ID + * @return 结果 + */ + @Override + public long countUserRoleByRoleId(Long roleId) { + return userRoleMapper.selectCount(new LambdaQueryWrapper().eq(SysUserRole::getRoleId, roleId)); + } + /** + * 新增保存角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int insertRole(SysRole role) { + // 新增角色信息 + baseMapper.insert(role); + return insertRoleMenu(role); + } + /** + * 修改保存角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int updateRole(SysRole role) { + // 修改角色信息 + baseMapper.updateById(role); + // 删除角色与菜单关联 + roleMenuMapper.delete(new LambdaQueryWrapper().eq(SysRoleMenu::getRoleId, role.getRoleId())); + return insertRoleMenu(role); + } + /** + * 修改角色状态 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + public int updateRoleStatus(SysRole role) { + return baseMapper.updateById(role); + } + /** + * 修改数据权限信息 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int authDataScope(SysRole role) { + // 修改角色信息 + baseMapper.updateById(role); + // 删除角色与部门关联 + roleDeptMapper.delete(new LambdaQueryWrapper().eq(SysRoleDept::getRoleId, role.getRoleId())); + // 新增角色和部门信息(数据权限) + return insertRoleDept(role); + } + /** + * 新增角色菜单信息 + * + * @param role 角色对象 + */ + public int insertRoleMenu(SysRole role) { + int rows = 1; + // 新增用户与角色管理 + List list = new ArrayList(); + for (Long menuId : role.getMenuIds()) { + SysRoleMenu rm = new SysRoleMenu(); + rm.setRoleId(role.getRoleId()); + rm.setMenuId(menuId); + list.add(rm); + } + if (list.size() > 0) { + rows = roleMenuMapper.insertBatch(list) ? list.size() : 0; + } + return rows; + } + /** + * 新增角色部门信息(数据权限) + * + * @param role 角色对象 + */ + public int insertRoleDept(SysRole role) { + int rows = 1; + // 新增角色与部门(数据权限)管理 + List list = new ArrayList(); + for (Long deptId : role.getDeptIds()) { + SysRoleDept rd = new SysRoleDept(); + rd.setRoleId(role.getRoleId()); + rd.setDeptId(deptId); + list.add(rd); + } + if (list.size() > 0) { + rows = roleDeptMapper.insertBatch(list) ? list.size() : 0; + } + return rows; + } + /** + * 通过角色ID删除角色 + * + * @param roleId 角色ID + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteRoleById(Long roleId) { + // 删除角色与菜单关联 + roleMenuMapper.delete(new LambdaQueryWrapper().eq(SysRoleMenu::getRoleId, roleId)); + // 删除角色与部门关联 + roleDeptMapper.delete(new LambdaQueryWrapper().eq(SysRoleDept::getRoleId, roleId)); + return baseMapper.deleteById(roleId); + } + /** + * 批量删除角色信息 + * + * @param roleIds 需要删除的角色ID + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteRoleByIds(Long[] roleIds) { + for (Long roleId : roleIds) { + checkRoleAllowed(new SysRole(roleId)); + checkRoleDataScope(roleId); + SysRole role = selectRoleById(roleId); + if (countUserRoleByRoleId(roleId) > 0) { + throw new ServiceException(String.format("%1$s已分配,不能删除", role.getRoleName())); + } + } + List ids = Arrays.asList(roleIds); + // 删除角色与菜单关联 + roleMenuMapper.delete(new LambdaQueryWrapper().in(SysRoleMenu::getRoleId, ids)); + // 删除角色与部门关联 + roleDeptMapper.delete(new LambdaQueryWrapper().in(SysRoleDept::getRoleId, ids)); + return baseMapper.deleteBatchIds(ids); + } + /** + * 取消授权用户角色 + * + * @param userRole 用户和角色关联信息 + * @return 结果 + */ + @Override + public int deleteAuthUser(SysUserRole userRole) { + int rows = userRoleMapper.delete(new LambdaQueryWrapper() + .eq(SysUserRole::getRoleId, userRole.getRoleId()) + .eq(SysUserRole::getUserId, userRole.getUserId())); + if (rows > 0) { + cleanOnlineUserByRole(userRole.getRoleId()); + } + return rows; + } + /** + * 批量取消授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要取消授权的用户数据ID + * @return 结果 + */ + @Override + public int deleteAuthUsers(Long roleId, Long[] userIds) { + int rows = userRoleMapper.delete(new LambdaQueryWrapper() + .eq(SysUserRole::getRoleId, roleId) + .in(SysUserRole::getUserId, Arrays.asList(userIds))); + if (rows > 0) { + cleanOnlineUserByRole(roleId); + } + return rows; + } + /** + * 批量选择授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要授权的用户数据ID + * @return 结果 + */ + @Override + public int insertAuthUsers(Long roleId, Long[] userIds) { + // 新增用户与角色管理 + int rows = 1; + List list = StreamUtils.toList(Arrays.asList(userIds), userId -> { + SysUserRole ur = new SysUserRole(); + ur.setUserId(userId); + ur.setRoleId(roleId); + return ur; + }); + if (CollUtil.isNotEmpty(list)) { + rows = userRoleMapper.insertBatch(list) ? list.size() : 0; + } + if (rows > 0) { + cleanOnlineUserByRole(roleId); + } + return rows; + } + + @Override + public void cleanOnlineUserByRole(Long roleId) { + List keys = StpUtil.searchTokenValue("", 0, -1, false); + if (CollUtil.isEmpty(keys)) { + return; + } + // 角色关联的在线用户量过大会导致redis阻塞卡顿 谨慎操作 + keys.parallelStream().forEach(key -> { + String token = StringUtils.substringAfterLast(key, ":"); + // 如果已经过期则跳过 + if (StpUtil.stpLogic.getTokenActivityTimeoutByToken(token) < -1) { + return; + } + LoginUser loginUser = LoginHelper.getLoginUser(token); + if (loginUser.getRoles().stream().anyMatch(r -> r.getRoleId().equals(roleId))) { + try { + StpUtil.logoutByTokenValue(token); + } catch (NotLoginException ignored) { + } + } + }); + } +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysSensitiveServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysSensitiveServiceImpl.java new file mode 100644 index 0000000..0d50f65 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysSensitiveServiceImpl.java @@ -0,0 +1,25 @@ +package com.inscloudtech.system.service.impl; + +import com.inscloudtech.common.core.service.SensitiveService; +import com.inscloudtech.common.helper.LoginHelper; +import org.springframework.stereotype.Service; + +/** + * 脱敏服务 + * 默认管理员不过滤 + * 需自行根据业务重写实现 + * + * @author inscloudtech + * @version 3.6.0 + */ +@Service +public class SysSensitiveServiceImpl implements SensitiveService { + /** + * 是否脱敏 + */ + @Override + public boolean isSensitive() { + return !LoginHelper.isAdmin(); + } + +} diff --git a/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysUserServiceImpl.java b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysUserServiceImpl.java new file mode 100644 index 0000000..0f273f7 --- /dev/null +++ b/cas-system/src/main/java/com/inscloudtech/system/service/impl/SysUserServiceImpl.java @@ -0,0 +1,536 @@ +package com.inscloudtech.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.inscloudtech.common.constant.CacheNames; +import com.inscloudtech.common.constant.Constants; +import com.inscloudtech.common.constant.UserConstants; +import com.inscloudtech.common.core.domain.PageQuery; +import com.inscloudtech.common.core.domain.entity.SysDept; +import com.inscloudtech.common.core.domain.entity.SysRole; +import com.inscloudtech.common.core.domain.entity.SysUser; +import com.inscloudtech.common.core.domain.model.LoginUser; +import com.inscloudtech.common.core.page.TableDataInfo; +import com.inscloudtech.common.core.service.UserService; +import com.inscloudtech.common.exception.ServiceException; +import com.inscloudtech.common.helper.DataBaseHelper; +import com.inscloudtech.common.helper.LoginHelper; +import com.inscloudtech.common.utils.StreamUtils; +import com.inscloudtech.common.utils.StringUtils; +import com.inscloudtech.system.domain.SysPost; +import com.inscloudtech.system.domain.SysUserPost; +import com.inscloudtech.system.domain.SysUserRole; +import com.inscloudtech.system.mapper.*; +import com.inscloudtech.system.service.ISysUserService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 用户 业务层处理 + * + * @author Lion Li + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class SysUserServiceImpl implements ISysUserService, UserService { + + private final SysUserMapper baseMapper; + private final SysDeptMapper deptMapper; + private final SysRoleMapper roleMapper; + private final SysPostMapper postMapper; + private final SysUserRoleMapper userRoleMapper; + private final SysUserPostMapper userPostMapper; + + @Override + public TableDataInfo selectPageUserList(SysUser user, PageQuery pageQuery) { + Page page = baseMapper.selectPageUserList(pageQuery.build(), this.buildQueryWrapper(user)); + return TableDataInfo.build(page); + } + /** + * 根据条件分页查询用户列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + public List selectUserList(SysUser user) { + return baseMapper.selectUserList(this.buildQueryWrapper(user)); + } + + private Wrapper buildQueryWrapper(SysUser user) { + Map params = user.getParams(); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("u.del_flag", UserConstants.USER_NORMAL) + .eq(ObjectUtil.isNotNull(user.getUserId()), "u.user_id", user.getUserId()) + .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName()) + .like(StringUtils.isNotBlank(user.getNickName()), "u.nick_name", user.getNickName()) + .eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus()) + .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber()) + .between(params.get("beginTime") != null && params.get("endTime") != null, + "u.create_time", params.get("beginTime"), params.get("endTime")) + .and(ObjectUtil.isNotNull(user.getDeptId()), w -> { + List deptList = deptMapper.selectList(new LambdaQueryWrapper() + .select(SysDept::getDeptId) + .apply(DataBaseHelper.findInSet(user.getDeptId(), "ancestors"))); + List ids = StreamUtils.toList(deptList, SysDept::getDeptId); + ids.add(user.getDeptId()); + w.in("u.dept_id", ids); + }) + .and(ObjectUtil.isNotNull(user.getRoleId()), w -> { + List roleList = roleMapper.selectList(new LambdaQueryWrapper() + .select(SysRole::getRoleId).eq(SysRole::getRoleId,user.getRoleId())); + List ids = StreamUtils.toList(roleList, SysRole::getRoleId); + w.in("r.role_id", ids); + }); + if(CollectionUtil.isNotEmpty(user.getIds())){ + wrapper.in("user_id",user.getIds()); + } + return wrapper; + } + /** + * 根据条件分页查询已分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + public TableDataInfo selectAllocatedList(SysUser user, PageQuery pageQuery) { + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("u.del_flag", UserConstants.USER_NORMAL) + .eq(ObjectUtil.isNotNull(user.getRoleId()), "r.role_id", user.getRoleId()) + .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName()) + .eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus()) + .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber()); + Page page = baseMapper.selectAllocatedList(pageQuery.build(), wrapper); + return TableDataInfo.build(page); + } + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + public TableDataInfo selectUnallocatedList(SysUser user, PageQuery pageQuery) { + List userIds = userRoleMapper.selectUserIdsByRoleId(user.getRoleId()); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("u.del_flag", UserConstants.USER_NORMAL) + .and(w -> w.ne("r.role_id", user.getRoleId()).or().isNull("r.role_id")) + .notIn(CollUtil.isNotEmpty(userIds), "u.user_id", userIds) + .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName()) + .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber()); + Page page = baseMapper.selectUnallocatedList(pageQuery.build(), wrapper); + return TableDataInfo.build(page); + } + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + @Override + public SysUser selectUserByUserName(String userName) { + return baseMapper.selectUserByUserName(userName); + } + /** + * 通过手机号查询用户 + * + * @param phonenumber 手机号 + * @return 用户对象信息 + */ + @Override + public SysUser selectUserByPhonenumber(String phonenumber) { + return baseMapper.selectUserByPhonenumber(phonenumber); + } + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + @Override + public SysUser selectUserById(Long userId) { + return baseMapper.selectUserById(userId); + } + /** + * 查询用户所属角色组 + * + * @param userName 用户名 + * @return 结果 + */ + @Override + public String selectUserRoleGroup(String userName) { + List list = roleMapper.selectRolesByUserName(userName); + if (CollUtil.isEmpty(list)) { + return StringUtils.EMPTY; + } + return StreamUtils.join(list, SysRole::getRoleName); + } + /** + * 查询用户所属岗位组 + * + * @param userName 用户名 + * @return 结果 + */ + @Override + public String selectUserPostGroup(String userName) { + List list = postMapper.selectPostsByUserName(userName); + if (CollUtil.isEmpty(list)) { + return StringUtils.EMPTY; + } + return StreamUtils.join(list, SysPost::getPostName); + } + /** + * 校验用户名称是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public boolean checkUserNameUnique(SysUser user) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysUser::getUserName, user.getUserName()) + .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId())); + return !exist; + } + /** + * 校验手机号码是否唯一 + * + * @param user 用户信息 + */ + @Override + public boolean checkPhoneUnique(SysUser user) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysUser::getPhonenumber, user.getPhonenumber()) + .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId())); + return !exist; + } + /** + * 校验email是否唯一 + * + * @param user 用户信息 + */ + @Override + public boolean checkEmailUnique(SysUser user) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysUser::getEmail, user.getEmail()) + .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId())); + return !exist; + } + /** + * 校验用户是否允许操作 + * + * @param user 用户信息 + */ + @Override + public void checkUserAllowed(SysUser user) { + if (ObjectUtil.isNotNull(user.getUserId()) && user.isAdmin()) { + throw new ServiceException("不允许操作超级管理员用户"); + } + } + /** + * 校验用户是否有数据权限 + * + * @param userId 用户id + */ + @Override + public void checkUserDataScope(Long userId) { + if (!LoginHelper.isAdmin()) { + SysUser user = new SysUser(); + user.setUserId(userId); + List users = this.selectUserList(user); + if (CollUtil.isEmpty(users)) { + throw new ServiceException("没有权限访问用户数据!"); + } + } + } + /** + * 新增保存用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int insertUser(SysUser user) { + // 新增用户信息 + int rows = baseMapper.insert(user); + // 新增用户岗位关联 + insertUserPost(user); + // 新增用户与角色管理 + insertUserRole(user); + return rows; + } + /** + * 注册用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public boolean registerUser(SysUser user) { + user.setCreateBy(user.getUserName()); + user.setUpdateBy(user.getUserName()); + return baseMapper.insert(user) > 0; + } + /** + * 修改保存用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int updateUser(SysUser user) { + Long userId = user.getUserId(); + // 删除用户与角色关联 + userRoleMapper.delete(new LambdaQueryWrapper().eq(SysUserRole::getUserId, userId)); + // 新增用户与角色管理 + insertUserRole(user); + // 删除用户与岗位关联 + userPostMapper.delete(new LambdaQueryWrapper().eq(SysUserPost::getUserId, userId)); + // 新增用户与岗位管理 + insertUserPost(user); + return baseMapper.updateById(user); + } + /** + * 用户授权角色 + * + * @param userId 用户ID + * @param roleIds 角色组 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void insertUserAuth(Long userId, Long[] roleIds) { + userRoleMapper.delete(new LambdaQueryWrapper() + .eq(SysUserRole::getUserId, userId)); + insertUserRole(userId, roleIds); + } + /** + * 修改用户状态 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public int updateUserStatus(SysUser user) { + return baseMapper.updateById(user); + } + /** + * 修改用户基本信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public int updateUserProfile(SysUser user) { + return baseMapper.updateById(user); + } + /** + * 修改用户头像 + * + * @param userName 用户名 + * @param avatar 头像地址 + * @return 结果 + */ + @Override + public boolean updateUserAvatar(String userName, String avatar) { + return baseMapper.update(null, + new LambdaUpdateWrapper() + .set(SysUser::getAvatar, avatar) + .eq(SysUser::getUserName, userName)) > 0; + } + /** + * 重置用户密码 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public int resetPwd(SysUser user) { + return baseMapper.updateById(user); + } + /** + * 重置用户密码 + * + * @param userName 用户名 + * @param password 密码 + * @return 结果 + */ + @Override + public int resetUserPwd(String userName, String password) { + return baseMapper.update(null, + new LambdaUpdateWrapper() + .set(SysUser::getPassword, password) + .eq(SysUser::getUserName, userName)); + } + /** + * 新增用户角色信息 + * + * @param user 用户对象 + */ + public void insertUserRole(SysUser user) { + this.insertUserRole(user.getUserId(), user.getRoleIds()); + } + /** + * 新增用户岗位信息 + * + * @param user 用户对象 + */ + public void insertUserPost(SysUser user) { + Long[] posts = user.getPostIds(); + if (ArrayUtil.isNotEmpty(posts)) { + // 新增用户与岗位管理 + List list = StreamUtils.toList(Arrays.asList(posts), postId -> { + SysUserPost up = new SysUserPost(); + up.setUserId(user.getUserId()); + up.setPostId(postId); + return up; + }); + userPostMapper.insertBatch(list); + } + } + /** + * 新增用户角色信息 + * + * @param userId 用户ID + * @param roleIds 角色组 + */ + public void insertUserRole(Long userId, Long[] roleIds) { + if (ArrayUtil.isNotEmpty(roleIds)) { + // 新增用户与角色管理 + List list = StreamUtils.toList(Arrays.asList(roleIds), roleId -> { + SysUserRole ur = new SysUserRole(); + ur.setUserId(userId); + ur.setRoleId(roleId); + return ur; + }); + userRoleMapper.insertBatch(list); + } + } + /** + * 通过用户ID删除用户 + * + * @param userId 用户ID + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteUserById(Long userId) { + // 删除用户与角色关联 + userRoleMapper.delete(new LambdaQueryWrapper().eq(SysUserRole::getUserId, userId)); + // 删除用户与岗位表 + userPostMapper.delete(new LambdaQueryWrapper().eq(SysUserPost::getUserId, userId)); + return baseMapper.deleteById(userId); + } + /** + * 批量删除用户信息 + * + * @param userIds 需要删除的用户ID + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteUserByIds(Long[] userIds) { + for (Long userId : userIds) { + checkUserAllowed(new SysUser(userId)); + checkUserDataScope(userId); + } + List ids = Arrays.asList(userIds); + // 删除用户与角色关联 + userRoleMapper.delete(new LambdaQueryWrapper().in(SysUserRole::getUserId, ids)); + // 删除用户与岗位表 + userPostMapper.delete(new LambdaQueryWrapper().in(SysUserPost::getUserId, ids)); + return baseMapper.deleteBatchIds(ids); + } + + @Override + public void updateByUsername(SysUser dbUser) { + baseMapper.update(dbUser,new LambdaQueryWrapper().eq(SysUser::getUserName,dbUser.getUserName())); + } + + @Override + public SysDept getDzDept() { + LoginUser loginUser = LoginHelper.getLoginUser(); + + String[] deptTypeArr = {"分公司", "全资子公司", "控股子公司","代管单位","电厂"}; + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(SysDept::getDelFlag, "0") + .in(SysDept::getDeptType, Arrays.asList(deptTypeArr)) + .orderByAsc(SysDept::getParentId) + .orderByAsc(SysDept::getOrderNum); + List targetList = deptMapper.selectList(lqw); + Map> groupByDeptName = targetList.stream().collect(Collectors.groupingBy(SysDept::getDeptName)); + return getDZDept(groupByDeptName.keySet(),loginUser.getDeptId()); + } + + + + SysDept getDZDept(Set deptNameSet, Long id){ + SysDept pDept = deptMapper.selectById(id); + if(pDept.getParentId().equals(0L)){ + return pDept; + } + if(deptNameSet.contains(pDept.getDeptName())){ + return pDept; + }else { + return getDZDept(deptNameSet,pDept.getParentId()); + } + } + + + @Cacheable(cacheNames = CacheNames.SYS_USER_ID, key = "#userId") + @Override + public String selectUserNameById(Long userId) { + SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper() + .select(SysUser::getUserName).eq(SysUser::getUserId, userId)); + return ObjectUtil.isNull(sysUser) ? null : sysUser.getUserName(); + } + + @Cacheable(cacheNames = CacheNames.SYS_USER_NAME, key = "#userName") + @Override + public String selectNicknameByUserName(String userName) { + SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper() + .select(SysUser::getNickName).eq(SysUser::getUserName, userName)); + return ObjectUtil.isNull(sysUser) ? null : sysUser.getNickName(); + } + + @Transactional + @Override + public void freezeUser(Long userId) { + // 帐号状态(0正常 1停用) + SysUser user = baseMapper.selectById(userId); + if (user == null){ + return; + } + + user.setStatus("1"); + // 逻辑删除 + user.setDelFlag("0"); + + baseMapper.updateById(user); + + //更新用户角色表 + userRoleMapper.delete(new LambdaQueryWrapper().eq(SysUserRole::getUserId, userId)); + insertUserRole(userId, new Long[]{Constants.INVESTIGATOR_ROLE_ID}); + } + +} diff --git a/cas-system/src/main/resources/mapper/package-info.md b/cas-system/src/main/resources/mapper/package-info.md new file mode 100644 index 0000000..c938b1e --- /dev/null +++ b/cas-system/src/main/resources/mapper/package-info.md @@ -0,0 +1,3 @@ +java包使用 `.` 分割 resource 目录使用 `/` 分割 +
+此文件目的 防止文件夹粘连找不到 `xml` 文件 \ No newline at end of file diff --git a/cas-system/src/main/resources/mapper/system/SysConfigMapper.xml b/cas-system/src/main/resources/mapper/system/SysConfigMapper.xml new file mode 100644 index 0000000..2a53c2f --- /dev/null +++ b/cas-system/src/main/resources/mapper/system/SysConfigMapper.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + diff --git a/cas-system/src/main/resources/mapper/system/SysDeptMapper.xml b/cas-system/src/main/resources/mapper/system/SysDeptMapper.xml new file mode 100644 index 0000000..8468182 --- /dev/null +++ b/cas-system/src/main/resources/mapper/system/SysDeptMapper.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cas-system/src/main/resources/mapper/system/SysDictDataMapper.xml b/cas-system/src/main/resources/mapper/system/SysDictDataMapper.xml new file mode 100644 index 0000000..af86490 --- /dev/null +++ b/cas-system/src/main/resources/mapper/system/SysDictDataMapper.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/cas-system/src/main/resources/mapper/system/SysDictTypeMapper.xml b/cas-system/src/main/resources/mapper/system/SysDictTypeMapper.xml new file mode 100644 index 0000000..b0b03b7 --- /dev/null +++ b/cas-system/src/main/resources/mapper/system/SysDictTypeMapper.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff --git a/cas-system/src/main/resources/mapper/system/SysLogininforMapper.xml b/cas-system/src/main/resources/mapper/system/SysLogininforMapper.xml new file mode 100644 index 0000000..a88e96b --- /dev/null +++ b/cas-system/src/main/resources/mapper/system/SysLogininforMapper.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + diff --git a/cas-system/src/main/resources/mapper/system/SysMenuMapper.xml b/cas-system/src/main/resources/mapper/system/SysMenuMapper.xml new file mode 100644 index 0000000..8b506ce --- /dev/null +++ b/cas-system/src/main/resources/mapper/system/SysMenuMapper.xml @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cas-system/src/main/resources/mapper/system/SysNoticeMapper.xml b/cas-system/src/main/resources/mapper/system/SysNoticeMapper.xml new file mode 100644 index 0000000..aace059 --- /dev/null +++ b/cas-system/src/main/resources/mapper/system/SysNoticeMapper.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + diff --git a/cas-system/src/main/resources/mapper/system/SysOperLogMapper.xml b/cas-system/src/main/resources/mapper/system/SysOperLogMapper.xml new file mode 100644 index 0000000..04a7c02 --- /dev/null +++ b/cas-system/src/main/resources/mapper/system/SysOperLogMapper.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cas-system/src/main/resources/mapper/system/SysOssConfigMapper.xml b/cas-system/src/main/resources/mapper/system/SysOssConfigMapper.xml new file mode 100644 index 0000000..a89491a --- /dev/null +++ b/cas-system/src/main/resources/mapper/system/SysOssConfigMapper.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cas-system/src/main/resources/mapper/system/SysOssMapper.xml b/cas-system/src/main/resources/mapper/system/SysOssMapper.xml new file mode 100644 index 0000000..c98990d --- /dev/null +++ b/cas-system/src/main/resources/mapper/system/SysOssMapper.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/cas-system/src/main/resources/mapper/system/SysPostMapper.xml b/cas-system/src/main/resources/mapper/system/SysPostMapper.xml new file mode 100644 index 0000000..c7250a7 --- /dev/null +++ b/cas-system/src/main/resources/mapper/system/SysPostMapper.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/cas-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml b/cas-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml new file mode 100644 index 0000000..bab9838 --- /dev/null +++ b/cas-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/cas-system/src/main/resources/mapper/system/SysRoleMapper.xml b/cas-system/src/main/resources/mapper/system/SysRoleMapper.xml new file mode 100644 index 0000000..12c9c46 --- /dev/null +++ b/cas-system/src/main/resources/mapper/system/SysRoleMapper.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + select distinct r.role_id, + r.role_name, + r.role_key, + r.role_sort, + r.data_scope, + r.menu_check_strictly, + r.dept_check_strictly, + r.status, + r.del_flag, + r.create_time, + r.remark + from sys_role r + left join sys_user_role sur on sur.role_id = r.role_id + left join sys_user u on u.user_id = sur.user_id + left join sys_dept d on u.dept_id = d.dept_id + + + + + + + + + + + + + diff --git a/cas-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml b/cas-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml new file mode 100644 index 0000000..61a0939 --- /dev/null +++ b/cas-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/cas-system/src/main/resources/mapper/system/SysUserMapper.xml b/cas-system/src/main/resources/mapper/system/SysUserMapper.xml new file mode 100644 index 0000000..22a53d9 --- /dev/null +++ b/cas-system/src/main/resources/mapper/system/SysUserMapper.xml @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select u.user_id, + u.dept_id, + u.user_name, + u.nick_name, + u.user_type, + u.email, + u.avatar, + u.phonenumber, + u.password, + u.sex, + u.status, + u.del_flag, + u.login_ip, + u.login_date, + u.create_by, + u.create_time, + u.remark, + d.dept_id, + d.parent_id, + d.ancestors, + d.dept_name, + d.order_num, + d.leader, + d.status as dept_status, + r.role_id, + r.role_name, + r.role_key, + r.role_sort, + r.data_scope, + r.status as role_status + from sys_user u + left join sys_dept d on u.dept_id = d.dept_id + left join sys_user_role sur on u.user_id = sur.user_id + left join sys_role r on r.role_id = sur.role_id + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cas-system/src/main/resources/mapper/system/SysUserPostMapper.xml b/cas-system/src/main/resources/mapper/system/SysUserPostMapper.xml new file mode 100644 index 0000000..eee2dd1 --- /dev/null +++ b/cas-system/src/main/resources/mapper/system/SysUserPostMapper.xml @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/cas-system/src/main/resources/mapper/system/SysUserRoleMapper.xml b/cas-system/src/main/resources/mapper/system/SysUserRoleMapper.xml new file mode 100644 index 0000000..eb3389d --- /dev/null +++ b/cas-system/src/main/resources/mapper/system/SysUserRoleMapper.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/classfinal-code.txt b/classfinal-code.txt new file mode 100644 index 0000000..b684b2d --- /dev/null +++ b/classfinal-code.txt @@ -0,0 +1 @@ +78828431441AC7E1D92FC694D6886239D41D8CD98F00B204E9800998ECF8427ED41D8CD98F00B204E9800998ECF8427E \ No newline at end of file diff --git a/classfinal-fatjar-1.2.1.jar b/classfinal-fatjar-1.2.1.jar new file mode 100644 index 0000000..56b97a7 Binary files /dev/null and b/classfinal-fatjar-1.2.1.jar differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..5adf0c3 --- /dev/null +++ b/pom.xml @@ -0,0 +1,418 @@ + + + 4.0.0 + + com.inscloudtech + cas-server + 4.7.0 + + + 4.7.0 + 2.7.11 + UTF-8 + UTF-8 + 1.8 + 3.2.2 + 2.2.2 + 1.6.15 + 4.1.2 + 3.2.1 + 2.3 + 1.34.0 + 3.5.3.1 + 3.9.1 + 5.8.18 + 4.10.0 + 2.7.10 + 3.20.1 + 2.2.3 + 3.5.2 + 2.14.2 + 1.18.26 + 1.72 + + 2.7.0 + 2.13.0 + + 1.33 + + + + + + dev + + + dev + debug + + + + true + + + + prod + + prod + warn + + + + + + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + cn.hutool + hutool-bom + ${hutool.version} + pom + import + + + + org.springdoc + springdoc-openapi-webmvc-core + ${springdoc.version} + + + + org.springdoc + springdoc-openapi-javadoc + ${springdoc.version} + + + + org.projectlombok + lombok + ${lombok.version} + + + + org.apache.poi + poi + ${poi.version} + + + org.apache.poi + poi-ooxml + ${poi.version} + + + com.alibaba + easyexcel + ${easyexcel.version} + + + org.apache.poi + poi-ooxml-schemas + + + + + + + org.apache.velocity + velocity-engine-core + ${velocity.version} + + + + + cn.dev33 + sa-token-spring-boot-starter + ${satoken.version} + + + + cn.dev33 + sa-token-jwt + ${satoken.version} + + + cn.hutool + hutool-all + + + + + + + com.baomidou + dynamic-datasource-spring-boot-starter + ${dynamic-ds.version} + + + + com.baomidou + mybatis-plus-boot-starter + ${mybatis-plus.version} + + + + + p6spy + p6spy + ${p6spy.version} + + + + com.squareup.okhttp3 + okhttp + ${okhttp.version} + + + + + de.codecentric + spring-boot-admin-starter-server + ${spring-boot-admin.version} + + + de.codecentric + spring-boot-admin-starter-client + ${spring-boot-admin.version} + + + + + org.redisson + redisson-spring-boot-starter + ${redisson.version} + + + org.redisson + redisson-spring-data-30 + + + + + org.redisson + redisson-spring-data-27 + ${redisson.version} + + + + com.baomidou + lock4j-redisson-spring-boot-starter + ${lock4j.version} + + + + com.alibaba + transmittable-thread-local + ${alibaba-ttl.version} + + + + + org.lionsoul + ip2region + ${ip2region.version} + + + + + org.yaml + snakeyaml + ${snakeyaml.version} + + + + + org.bouncycastle + bcprov-jdk15to18 + ${bouncycastle.version} + + + + + com.inscloudtech + cas-generator + ${cas-server.version} + + + + + com.inscloudtech + cas-framework + ${cas-server.version} + + + + + com.inscloudtech + cas-system + ${cas-server.version} + + + + + com.inscloudtech + cas-common + ${cas-server.version} + + + + + com.belerweb + pinyin4j + 2.5.0 + + + + commons-httpclient + commons-httpclient + 3.1 + + + + com.belerweb + pinyin4j + 2.5.0 + + + + org.elasticsearch.client + elasticsearch-rest-high-level-client + 7.14.0 + + + org.elasticsearch.client + elasticsearch-rest-client + 7.14.0 + + + org.elasticsearch + elasticsearch + 7.14.0 + + + + org.dromara.easy-es + easy-es-boot-starter + 2.0.0-beta4 + + + + org.dromara.easy-es + easy-es-annotation + 2.0.0-beta4 + + + + + + cas-admin + cas-framework + cas-system + cas-generator + cas-common + + pom + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.9.0 + + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + + + com.github.therapi + therapi-runtime-javadoc-scribe + 0.15.0 + + + org.projectlombok + lombok + ${lombok.version} + + + org.springframework.boot + spring-boot-configuration-processor + ${spring-boot.version} + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + -Dfile.encoding=UTF-8 + + ${profiles.active} + + exclude + + + + + + src/main/resources + + false + + + src/main/resources + + + application* + bootstrap* + banner* + + + true + + + + + + + public + aliyun nexus + https://maven.aliyun.com/repository/public/ + + true + + + + + + + public + aliyun nexus + https://maven.aliyun.com/repository/public/ + + true + + + false + + + + + + + diff --git a/script/bin/ry.bat b/script/bin/ry.bat new file mode 100644 index 0000000..35b111f --- /dev/null +++ b/script/bin/ry.bat @@ -0,0 +1,68 @@ +rem 使用者应根据自身平台编码自行转换 防止乱码 例如 win使用gbk编码 +@echo off + +rem jar平级目录 +set AppName=cas-admin.jar + +rem JVM参数 +set JVM_OPTS="-Dname=%AppName% -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC" + + +ECHO. + ECHO. [1] 启动%AppName% + ECHO. [2] 关闭%AppName% + ECHO. [3] 重启%AppName% + ECHO. [4] 启动状态 %AppName% + ECHO. [5] 退 出 +ECHO. + +ECHO.请输入选择项目的序号: +set /p ID= + IF "%id%"=="1" GOTO start + IF "%id%"=="2" GOTO stop + IF "%id%"=="3" GOTO restart + IF "%id%"=="4" GOTO status + IF "%id%"=="5" EXIT +PAUSE +:start + for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do ( + set pid=%%a + set image_name=%%b + ) + if defined pid ( + echo %%is running + PAUSE + ) + +start javaw %JVM_OPTS% -jar %AppName% + +echo starting…… +echo Start %AppName% success... +goto:eof + +rem 函数stop通过jps命令查找pid并结束进程 +:stop + for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do ( + set pid=%%a + set image_name=%%b + ) + if not defined pid (echo process %AppName% does not exists) else ( + echo prepare to kill %image_name% + echo start kill %pid% ... + rem 根据进程ID,kill进程 + taskkill /f /pid %pid% + ) +goto:eof +:restart + call :stop + call :start +goto:eof +:status + for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do ( + set pid=%%a + set image_name=%%b + ) + if not defined pid (echo process %AppName% is dead ) else ( + echo %image_name% is running + ) +goto:eof diff --git a/script/bin/ry.sh b/script/bin/ry.sh new file mode 100644 index 0000000..0c57824 --- /dev/null +++ b/script/bin/ry.sh @@ -0,0 +1,85 @@ +#!/bin/sh +# ./ry.sh start 启动 stop 停止 restart 重启 status 状态 +AppName=cas-admin.jar + +# JVM参数 +JVM_OPTS="-Dname=$AppName -Duser.timezone=Asia/Shanghai -Xms1024m -Xmx2048m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC" +APP_HOME=`pwd` +LOG_PATH=$APP_HOME/logs/$AppName.log + +if [ "$1" = "" ]; +then + echo -e "\033[0;31m 未输入操作名 \033[0m \033[0;34m {start|stop|restart|status} \033[0m" + exit 1 +fi + +if [ "$AppName" = "" ]; +then + echo -e "\033[0;31m 未输入应用名 \033[0m" + exit 1 +fi + +function start(){ + PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'` + + if [ x"$PID" != x"" ]; then + echo "$AppName is running..." + else + nohup java $JVM_OPTS -jar $AppName > /dev/null 2>&1 & + echo "Start $AppName success..." + fi +} + +function stop() +{ + echo "Stop $AppName" + + PID="" + query(){ + PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'` + } + + query + if [ x"$PID" != x"" ]; then + kill -TERM $PID + echo "$AppName (pid:$PID) exiting..." + while [ x"$PID" != x"" ] + do + sleep 1 + query + done + echo "$AppName exited." + else + echo "$AppName already stopped." + fi +} + +function restart() +{ + stop + sleep 2 + start +} + +function status() +{ + PID=`ps -ef |grep java|grep $AppName|grep -v grep|wc -l` + if [ $PID != 0 ];then + echo "$AppName is running..." + else + echo "$AppName is not running..." + fi +} + +case $1 in + start) + start;; + stop) + stop;; + restart) + restart;; + status) + status;; + *) + +esac diff --git a/script/sql/chng_wuzi.sql b/script/sql/chng_wuzi.sql new file mode 100644 index 0000000..76d4ada --- /dev/null +++ b/script/sql/chng_wuzi.sql @@ -0,0 +1,698 @@ +create database `chng_wuzi` default character set utf8mb4 collate utf8mb4_general_ci; +use chng_wuzi; +-- ---------------------------- +-- 1、部门表 +-- ---------------------------- +drop table if exists sys_dept; +create table sys_dept ( + dept_id bigint(20) not null comment '部门id', + parent_id bigint(20) default 0 comment '父部门id', + ancestors varchar(500) default '' comment '祖级列表', + dept_name varchar(30) default '' comment '部门名称', + order_num int(4) default 0 comment '显示顺序', + leader varchar(20) default null comment '负责人', + phone varchar(11) default null comment '联系电话', + email varchar(50) default null comment '邮箱', + status char(1) default '0' comment '部门状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + primary key (dept_id) +) engine=innodb comment = '部门表'; + +-- ---------------------------- +-- 初始化-部门表数据 +-- ---------------------------- +insert into sys_dept values(100, 0, '0', '若依科技', 0, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(101, 100, '0,100', '深圳总公司', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(102, 100, '0,100', '长沙分公司', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(103, 101, '0,100,101', '研发部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(104, 101, '0,100,101', '市场部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(105, 101, '0,100,101', '测试部门', 3, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(106, 101, '0,100,101', '财务部门', 4, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(107, 101, '0,100,101', '运维部门', 5, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(108, 102, '0,100,102', '市场部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(109, 102, '0,100,102', '财务部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); + + +-- ---------------------------- +-- 2、用户信息表 +-- ---------------------------- +drop table if exists sys_user; +create table sys_user ( + user_id bigint(20) not null comment '用户ID', + dept_id bigint(20) default null comment '部门ID', + user_name varchar(30) not null comment '用户账号', + nick_name varchar(30) not null comment '用户昵称', + user_type varchar(10) default 'sys_user' comment '用户类型(sys_user系统用户)', + email varchar(50) default '' comment '用户邮箱', + phonenumber varchar(11) default '' comment '手机号码', + sex char(1) default '0' comment '用户性别(0男 1女 2未知)', + avatar varchar(100) default '' comment '头像地址', + password varchar(100) default '' comment '密码', + status char(1) default '0' comment '帐号状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', + login_ip varchar(128) default '' comment '最后登录IP', + login_date datetime comment '最后登录时间', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (user_id) +) engine=innodb comment = '用户信息表'; + +-- ---------------------------- +-- 初始化-用户信息表数据 +-- ---------------------------- +insert into sys_user values(1, 103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 'admin', sysdate(), '', null, '管理员'); +insert into sys_user values(2, 105, 'lionli', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 'admin', sysdate(), '', null, '测试员'); + + +-- ---------------------------- +-- 3、岗位信息表 +-- ---------------------------- +drop table if exists sys_post; +create table sys_post +( + post_id bigint(20) not null comment '岗位ID', + post_code varchar(64) not null comment '岗位编码', + post_name varchar(50) not null comment '岗位名称', + post_sort int(4) not null comment '显示顺序', + status char(1) not null comment '状态(0正常 1停用)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (post_id) +) engine=innodb comment = '岗位信息表'; + +-- ---------------------------- +-- 初始化-岗位信息表数据 +-- ---------------------------- +insert into sys_post values(1, 'ceo', '董事长', 1, '0', 'admin', sysdate(), '', null, ''); +insert into sys_post values(2, 'se', '项目经理', 2, '0', 'admin', sysdate(), '', null, ''); +insert into sys_post values(3, 'hr', '人力资源', 3, '0', 'admin', sysdate(), '', null, ''); +insert into sys_post values(4, 'user', '普通员工', 4, '0', 'admin', sysdate(), '', null, ''); + + +-- ---------------------------- +-- 4、角色信息表 +-- ---------------------------- +drop table if exists sys_role; +create table sys_role ( + role_id bigint(20) not null comment '角色ID', + role_name varchar(30) not null comment '角色名称', + role_key varchar(100) not null comment '角色权限字符串', + role_sort int(4) not null comment '显示顺序', + data_scope char(1) default '1' comment '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)', + menu_check_strictly tinyint(1) default 1 comment '菜单树选择项是否关联显示', + dept_check_strictly tinyint(1) default 1 comment '部门树选择项是否关联显示', + status char(1) not null comment '角色状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (role_id) +) engine=innodb comment = '角色信息表'; + +-- ---------------------------- +-- 初始化-角色信息表数据 +-- ---------------------------- +insert into sys_role values('1', '超级管理员', 'admin', 1, 1, 1, 1, '0', '0', 'admin', sysdate(), '', null, '超级管理员'); +insert into sys_role values('2', '普通角色', 'common', 2, 2, 1, 1, '0', '0', 'admin', sysdate(), '', null, '普通角色'); + + +-- ---------------------------- +-- 5、菜单权限表 +-- ---------------------------- +drop table if exists sys_menu; +create table sys_menu ( + menu_id bigint(20) not null comment '菜单ID', + menu_name varchar(50) not null comment '菜单名称', + parent_id bigint(20) default 0 comment '父菜单ID', + order_num int(4) default 0 comment '显示顺序', + path varchar(200) default '' comment '路由地址', + component varchar(255) default null comment '组件路径', + query_param varchar(255) default null comment '路由参数', + is_frame int(1) default 1 comment '是否为外链(0是 1否)', + is_cache int(1) default 0 comment '是否缓存(0缓存 1不缓存)', + menu_type char(1) default '' comment '菜单类型(M目录 C菜单 F按钮)', + visible char(1) default 0 comment '显示状态(0显示 1隐藏)', + status char(1) default 0 comment '菜单状态(0正常 1停用)', + perms varchar(100) default null comment '权限标识', + icon varchar(100) default '#' comment '菜单图标', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default '' comment '备注', + primary key (menu_id) +) engine=innodb comment = '菜单权限表'; + +-- ---------------------------- +-- 初始化-菜单信息表数据 +-- ---------------------------- +-- 一级菜单 +insert into sys_menu values('1', '系统管理', '0', '1', 'system', null, '', 1, 0, 'M', '0', '0', '', 'system', 'admin', sysdate(), '', null, '系统管理目录'); +insert into sys_menu values('2', '系统监控', '0', '2', 'monitor', null, '', 1, 0, 'M', '0', '0', '', 'monitor', 'admin', sysdate(), '', null, '系统监控目录'); +insert into sys_menu values('3', '系统工具', '0', '3', 'tool', null, '', 1, 0, 'M', '0', '0', '', 'tool', 'admin', sysdate(), '', null, '系统工具目录'); +insert into sys_menu values('4', 'PLUS官网', '0', '4', 'https://gitee.com/dromara/RuoYi-Vue-Plus', null, '', 0, 0, 'M', '0', '0', '', 'guide', 'admin', sysdate(), '', null, 'RuoYi-Vue-Plus官网地址'); +-- 二级菜单 +insert into sys_menu values('100', '用户管理', '1', '1', 'user', 'system/user/index', '', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 'admin', sysdate(), '', null, '用户管理菜单'); +insert into sys_menu values('101', '角色管理', '1', '2', 'role', 'system/role/index', '', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 'admin', sysdate(), '', null, '角色管理菜单'); +insert into sys_menu values('102', '菜单管理', '1', '3', 'menu', 'system/menu/index', '', 1, 0, 'C', '0', '0', 'system:menu:list', 'tree-table', 'admin', sysdate(), '', null, '菜单管理菜单'); +insert into sys_menu values('103', '部门管理', '1', '4', 'dept', 'system/dept/index', '', 1, 0, 'C', '0', '0', 'system:dept:list', 'tree', 'admin', sysdate(), '', null, '部门管理菜单'); +insert into sys_menu values('104', '岗位管理', '1', '5', 'post', 'system/post/index', '', 1, 0, 'C', '0', '0', 'system:post:list', 'post', 'admin', sysdate(), '', null, '岗位管理菜单'); +insert into sys_menu values('105', '字典管理', '1', '6', 'dict', 'system/dict/index', '', 1, 0, 'C', '0', '0', 'system:dict:list', 'dict', 'admin', sysdate(), '', null, '字典管理菜单'); +insert into sys_menu values('106', '参数设置', '1', '7', 'config', 'system/config/index', '', 1, 0, 'C', '0', '0', 'system:config:list', 'edit', 'admin', sysdate(), '', null, '参数设置菜单'); +insert into sys_menu values('107', '通知公告', '1', '8', 'notice', 'system/notice/index', '', 1, 0, 'C', '0', '0', 'system:notice:list', 'message', 'admin', sysdate(), '', null, '通知公告菜单'); +insert into sys_menu values('108', '日志管理', '1', '9', 'log', '', '', 1, 0, 'M', '0', '0', '', 'log', 'admin', sysdate(), '', null, '日志管理菜单'); +insert into sys_menu values('109', '在线用户', '2', '1', 'online', 'monitor/online/index', '', 1, 0, 'C', '0', '0', 'monitor:online:list', 'online', 'admin', sysdate(), '', null, '在线用户菜单'); +insert into sys_menu values('112', '缓存列表', '2', '6', 'cacheList', 'monitor/cache/list', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis-list', 'admin', sysdate(), '', null, '缓存列表菜单'); +insert into sys_menu values('113', '缓存监控', '2', '5', 'cache', 'monitor/cache/index', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis', 'admin', sysdate(), '', null, '缓存监控菜单'); +insert into sys_menu values('114', '表单构建', '3', '1', 'build', 'tool/build/index', '', 1, 0, 'C', '0', '0', 'tool:build:list', 'build', 'admin', sysdate(), '', null, '表单构建菜单'); +insert into sys_menu values('115', '代码生成', '3', '2', 'gen', 'tool/gen/index', '', 1, 0, 'C', '0', '0', 'tool:gen:list', 'code', 'admin', sysdate(), '', null, '代码生成菜单'); +-- springboot-admin监控 +insert into sys_menu values('117', 'Admin监控', '2', '5', 'Admin', 'monitor/admin/index', '', 1, 0, 'C', '0', '0', 'monitor:admin:list', 'dashboard', 'admin', sysdate(), '', null, 'Admin监控菜单'); +-- oss菜单 +insert into sys_menu values('118', '文件管理', '1', '10', 'oss', 'system/oss/index', '', 1, 0, 'C', '0', '0', 'system:oss:list', 'upload', 'admin', sysdate(), '', null, '文件管理菜单'); +-- xxl-job-admin控制台 +insert into sys_menu values('120', '任务调度中心', '2', '5', 'XxlJob', 'monitor/xxljob/index', '', 1, 0, 'C', '0', '0', 'monitor:xxljob:list', 'job', 'admin', sysdate(), '', null, 'Xxl-Job控制台菜单'); + +-- 三级菜单 +insert into sys_menu values('500', '操作日志', '108', '1', 'operlog', 'monitor/operlog/index', '', 1, 0, 'C', '0', '0', 'monitor:operlog:list', 'form', 'admin', sysdate(), '', null, '操作日志菜单'); +insert into sys_menu values('501', '登录日志', '108', '2', 'logininfor', 'monitor/logininfor/index', '', 1, 0, 'C', '0', '0', 'monitor:logininfor:list', 'logininfor', 'admin', sysdate(), '', null, '登录日志菜单'); +-- 用户管理按钮 +insert into sys_menu values('1001', '用户查询', '100', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:user:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1002', '用户新增', '100', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:user:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1003', '用户修改', '100', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:user:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1004', '用户删除', '100', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:user:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1005', '用户导出', '100', '5', '', '', '', 1, 0, 'F', '0', '0', 'system:user:export', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1006', '用户导入', '100', '6', '', '', '', 1, 0, 'F', '0', '0', 'system:user:import', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1007', '重置密码', '100', '7', '', '', '', 1, 0, 'F', '0', '0', 'system:user:resetPwd', '#', 'admin', sysdate(), '', null, ''); +-- 角色管理按钮 +insert into sys_menu values('1008', '角色查询', '101', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:role:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1009', '角色新增', '101', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:role:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1010', '角色修改', '101', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:role:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1011', '角色删除', '101', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:role:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1012', '角色导出', '101', '5', '', '', '', 1, 0, 'F', '0', '0', 'system:role:export', '#', 'admin', sysdate(), '', null, ''); +-- 菜单管理按钮 +insert into sys_menu values('1013', '菜单查询', '102', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1014', '菜单新增', '102', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1015', '菜单修改', '102', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1016', '菜单删除', '102', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:remove', '#', 'admin', sysdate(), '', null, ''); +-- 部门管理按钮 +insert into sys_menu values('1017', '部门查询', '103', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1018', '部门新增', '103', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1019', '部门修改', '103', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1020', '部门删除', '103', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:remove', '#', 'admin', sysdate(), '', null, ''); +-- 岗位管理按钮 +insert into sys_menu values('1021', '岗位查询', '104', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:post:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1022', '岗位新增', '104', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:post:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1023', '岗位修改', '104', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:post:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1024', '岗位删除', '104', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:post:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1025', '岗位导出', '104', '5', '', '', '', 1, 0, 'F', '0', '0', 'system:post:export', '#', 'admin', sysdate(), '', null, ''); +-- 字典管理按钮 +insert into sys_menu values('1026', '字典查询', '105', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1027', '字典新增', '105', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1028', '字典修改', '105', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1029', '字典删除', '105', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1030', '字典导出', '105', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:export', '#', 'admin', sysdate(), '', null, ''); +-- 参数设置按钮 +insert into sys_menu values('1031', '参数查询', '106', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1032', '参数新增', '106', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1033', '参数修改', '106', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1034', '参数删除', '106', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1035', '参数导出', '106', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:export', '#', 'admin', sysdate(), '', null, ''); +-- 通知公告按钮 +insert into sys_menu values('1036', '公告查询', '107', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1037', '公告新增', '107', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1038', '公告修改', '107', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1039', '公告删除', '107', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:remove', '#', 'admin', sysdate(), '', null, ''); +-- 操作日志按钮 +insert into sys_menu values('1040', '操作查询', '500', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1041', '操作删除', '500', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1042', '日志导出', '500', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:export', '#', 'admin', sysdate(), '', null, ''); +-- 登录日志按钮 +insert into sys_menu values('1043', '登录查询', '501', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1044', '登录删除', '501', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1045', '日志导出', '501', '3', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:export', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1050', '账户解锁', '501', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock', '#', 'admin', sysdate(), '', null, ''); +-- 在线用户按钮 +insert into sys_menu values('1046', '在线查询', '109', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1047', '批量强退', '109', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:batchLogout', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1048', '单条强退', '109', '3', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:forceLogout', '#', 'admin', sysdate(), '', null, ''); +-- 代码生成按钮 +insert into sys_menu values('1055', '生成查询', '115', '1', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1056', '生成修改', '115', '2', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1057', '生成删除', '115', '3', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1058', '导入代码', '115', '2', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:import', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1059', '预览代码', '115', '4', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:preview', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1060', '生成代码', '115', '5', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:code', '#', 'admin', sysdate(), '', null, ''); +-- oss相关按钮 +insert into sys_menu values('1600', '文件查询', '118', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1601', '文件上传', '118', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:upload', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1602', '文件下载', '118', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:download', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1603', '文件删除', '118', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1604', '配置添加', '118', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1605', '配置编辑', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:edit', '#', 'admin', sysdate(), '', null, ''); + + +-- ---------------------------- +-- 6、用户和角色关联表 用户N-1角色 +-- ---------------------------- +drop table if exists sys_user_role; +create table sys_user_role ( + user_id bigint(20) not null comment '用户ID', + role_id bigint(20) not null comment '角色ID', + primary key(user_id, role_id) +) engine=innodb comment = '用户和角色关联表'; + +-- ---------------------------- +-- 初始化-用户和角色关联表数据 +-- ---------------------------- +insert into sys_user_role values ('1', '1'); +insert into sys_user_role values ('2', '2'); + + +-- ---------------------------- +-- 7、角色和菜单关联表 角色1-N菜单 +-- ---------------------------- +drop table if exists sys_role_menu; +create table sys_role_menu ( + role_id bigint(20) not null comment '角色ID', + menu_id bigint(20) not null comment '菜单ID', + primary key(role_id, menu_id) +) engine=innodb comment = '角色和菜单关联表'; + +-- ---------------------------- +-- 初始化-角色和菜单关联表数据 +-- ---------------------------- +insert into sys_role_menu values ('2', '1'); +insert into sys_role_menu values ('2', '2'); +insert into sys_role_menu values ('2', '3'); +insert into sys_role_menu values ('2', '4'); +insert into sys_role_menu values ('2', '100'); +insert into sys_role_menu values ('2', '101'); +insert into sys_role_menu values ('2', '102'); +insert into sys_role_menu values ('2', '103'); +insert into sys_role_menu values ('2', '104'); +insert into sys_role_menu values ('2', '105'); +insert into sys_role_menu values ('2', '106'); +insert into sys_role_menu values ('2', '107'); +insert into sys_role_menu values ('2', '108'); +insert into sys_role_menu values ('2', '109'); +insert into sys_role_menu values ('2', '110'); +insert into sys_role_menu values ('2', '111'); +insert into sys_role_menu values ('2', '112'); +insert into sys_role_menu values ('2', '113'); +insert into sys_role_menu values ('2', '114'); +insert into sys_role_menu values ('2', '115'); +insert into sys_role_menu values ('2', '116'); +insert into sys_role_menu values ('2', '500'); +insert into sys_role_menu values ('2', '501'); +insert into sys_role_menu values ('2', '1000'); +insert into sys_role_menu values ('2', '1001'); +insert into sys_role_menu values ('2', '1002'); +insert into sys_role_menu values ('2', '1003'); +insert into sys_role_menu values ('2', '1004'); +insert into sys_role_menu values ('2', '1005'); +insert into sys_role_menu values ('2', '1006'); +insert into sys_role_menu values ('2', '1007'); +insert into sys_role_menu values ('2', '1008'); +insert into sys_role_menu values ('2', '1009'); +insert into sys_role_menu values ('2', '1010'); +insert into sys_role_menu values ('2', '1011'); +insert into sys_role_menu values ('2', '1012'); +insert into sys_role_menu values ('2', '1013'); +insert into sys_role_menu values ('2', '1014'); +insert into sys_role_menu values ('2', '1015'); +insert into sys_role_menu values ('2', '1016'); +insert into sys_role_menu values ('2', '1017'); +insert into sys_role_menu values ('2', '1018'); +insert into sys_role_menu values ('2', '1019'); +insert into sys_role_menu values ('2', '1020'); +insert into sys_role_menu values ('2', '1021'); +insert into sys_role_menu values ('2', '1022'); +insert into sys_role_menu values ('2', '1023'); +insert into sys_role_menu values ('2', '1024'); +insert into sys_role_menu values ('2', '1025'); +insert into sys_role_menu values ('2', '1026'); +insert into sys_role_menu values ('2', '1027'); +insert into sys_role_menu values ('2', '1028'); +insert into sys_role_menu values ('2', '1029'); +insert into sys_role_menu values ('2', '1030'); +insert into sys_role_menu values ('2', '1031'); +insert into sys_role_menu values ('2', '1032'); +insert into sys_role_menu values ('2', '1033'); +insert into sys_role_menu values ('2', '1034'); +insert into sys_role_menu values ('2', '1035'); +insert into sys_role_menu values ('2', '1036'); +insert into sys_role_menu values ('2', '1037'); +insert into sys_role_menu values ('2', '1038'); +insert into sys_role_menu values ('2', '1039'); +insert into sys_role_menu values ('2', '1040'); +insert into sys_role_menu values ('2', '1041'); +insert into sys_role_menu values ('2', '1042'); +insert into sys_role_menu values ('2', '1043'); +insert into sys_role_menu values ('2', '1044'); +insert into sys_role_menu values ('2', '1045'); +insert into sys_role_menu values ('2', '1050'); +insert into sys_role_menu values ('2', '1046'); +insert into sys_role_menu values ('2', '1047'); +insert into sys_role_menu values ('2', '1048'); +insert into sys_role_menu values ('2', '1055'); +insert into sys_role_menu values ('2', '1056'); +insert into sys_role_menu values ('2', '1057'); +insert into sys_role_menu values ('2', '1058'); +insert into sys_role_menu values ('2', '1059'); +insert into sys_role_menu values ('2', '1060'); + +-- ---------------------------- +-- 8、角色和部门关联表 角色1-N部门 +-- ---------------------------- +drop table if exists sys_role_dept; +create table sys_role_dept ( + role_id bigint(20) not null comment '角色ID', + dept_id bigint(20) not null comment '部门ID', + primary key(role_id, dept_id) +) engine=innodb comment = '角色和部门关联表'; + +-- ---------------------------- +-- 初始化-角色和部门关联表数据 +-- ---------------------------- +insert into sys_role_dept values ('2', '100'); +insert into sys_role_dept values ('2', '101'); +insert into sys_role_dept values ('2', '105'); + + +-- ---------------------------- +-- 9、用户与岗位关联表 用户1-N岗位 +-- ---------------------------- +drop table if exists sys_user_post; +create table sys_user_post +( + user_id bigint(20) not null comment '用户ID', + post_id bigint(20) not null comment '岗位ID', + primary key (user_id, post_id) +) engine=innodb comment = '用户与岗位关联表'; + +-- ---------------------------- +-- 初始化-用户与岗位关联表数据 +-- ---------------------------- +insert into sys_user_post values ('1', '1'); +insert into sys_user_post values ('2', '2'); + + +-- ---------------------------- +-- 10、操作日志记录 +-- ---------------------------- +drop table if exists sys_oper_log; +create table sys_oper_log ( + oper_id bigint(20) not null comment '日志主键', + title varchar(50) default '' comment '模块标题', + business_type int(2) default 0 comment '业务类型(0其它 1新增 2修改 3删除)', + method varchar(100) default '' comment '方法名称', + request_method varchar(10) default '' comment '请求方式', + operator_type int(1) default 0 comment '操作类别(0其它 1后台用户 2手机端用户)', + oper_name varchar(50) default '' comment '操作人员', + dept_name varchar(50) default '' comment '部门名称', + oper_url varchar(255) default '' comment '请求URL', + oper_ip varchar(128) default '' comment '主机地址', + oper_location varchar(255) default '' comment '操作地点', + oper_param varchar(2000) default '' comment '请求参数', + json_result varchar(2000) default '' comment '返回参数', + status int(1) default 0 comment '操作状态(0正常 1异常)', + error_msg varchar(2000) default '' comment '错误消息', + oper_time datetime comment '操作时间', + primary key (oper_id), + key idx_sys_oper_log_bt (business_type), + key idx_sys_oper_log_s (status), + key idx_sys_oper_log_ot (oper_time) +) engine=innodb comment = '操作日志记录'; + + +-- ---------------------------- +-- 11、字典类型表 +-- ---------------------------- +drop table if exists sys_dict_type; +create table sys_dict_type +( + dict_id bigint(20) not null comment '字典主键', + dict_name varchar(100) default '' comment '字典名称', + dict_type varchar(100) default '' comment '字典类型', + status char(1) default '0' comment '状态(0正常 1停用)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (dict_id), + unique (dict_type) +) engine=innodb comment = '字典类型表'; + +insert into sys_dict_type values(1, '用户性别', 'sys_user_sex', '0', 'admin', sysdate(), '', null, '用户性别列表'); +insert into sys_dict_type values(2, '菜单状态', 'sys_show_hide', '0', 'admin', sysdate(), '', null, '菜单状态列表'); +insert into sys_dict_type values(3, '系统开关', 'sys_normal_disable', '0', 'admin', sysdate(), '', null, '系统开关列表'); +insert into sys_dict_type values(6, '系统是否', 'sys_yes_no', '0', 'admin', sysdate(), '', null, '系统是否列表'); +insert into sys_dict_type values(7, '通知类型', 'sys_notice_type', '0', 'admin', sysdate(), '', null, '通知类型列表'); +insert into sys_dict_type values(8, '通知状态', 'sys_notice_status', '0', 'admin', sysdate(), '', null, '通知状态列表'); +insert into sys_dict_type values(9, '操作类型', 'sys_oper_type', '0', 'admin', sysdate(), '', null, '操作类型列表'); +insert into sys_dict_type values(10, '系统状态', 'sys_common_status', '0', 'admin', sysdate(), '', null, '登录状态列表'); + + +-- ---------------------------- +-- 12、字典数据表 +-- ---------------------------- +drop table if exists sys_dict_data; +create table sys_dict_data +( + dict_code bigint(20) not null comment '字典编码', + dict_sort int(4) default 0 comment '字典排序', + dict_label varchar(100) default '' comment '字典标签', + dict_value varchar(100) default '' comment '字典键值', + dict_type varchar(100) default '' comment '字典类型', + css_class varchar(100) default null comment '样式属性(其他样式扩展)', + list_class varchar(100) default null comment '表格回显样式', + is_default char(1) default 'N' comment '是否默认(Y是 N否)', + status char(1) default '0' comment '状态(0正常 1停用)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (dict_code) +) engine=innodb comment = '字典数据表'; + +insert into sys_dict_data values(1, 1, '男', '0', 'sys_user_sex', '', '', 'Y', '0', 'admin', sysdate(), '', null, '性别男'); +insert into sys_dict_data values(2, 2, '女', '1', 'sys_user_sex', '', '', 'N', '0', 'admin', sysdate(), '', null, '性别女'); +insert into sys_dict_data values(3, 3, '未知', '2', 'sys_user_sex', '', '', 'N', '0', 'admin', sysdate(), '', null, '性别未知'); +insert into sys_dict_data values(4, 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '显示菜单'); +insert into sys_dict_data values(5, 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '隐藏菜单'); +insert into sys_dict_data values(6, 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '正常状态'); +insert into sys_dict_data values(7, 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '停用状态'); +insert into sys_dict_data values(12, 1, '是', 'Y', 'sys_yes_no', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '系统默认是'); +insert into sys_dict_data values(13, 2, '否', 'N', 'sys_yes_no', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '系统默认否'); +insert into sys_dict_data values(14, 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', '0', 'admin', sysdate(), '', null, '通知'); +insert into sys_dict_data values(15, 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', '0', 'admin', sysdate(), '', null, '公告'); +insert into sys_dict_data values(16, 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '正常状态'); +insert into sys_dict_data values(17, 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '关闭状态'); +insert into sys_dict_data values(29, 99, '其他', '0', 'sys_oper_type', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '其他操作'); +insert into sys_dict_data values(18, 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '新增操作'); +insert into sys_dict_data values(19, 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '修改操作'); +insert into sys_dict_data values(20, 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '删除操作'); +insert into sys_dict_data values(21, 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', '0', 'admin', sysdate(), '', null, '授权操作'); +insert into sys_dict_data values(22, 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '导出操作'); +insert into sys_dict_data values(23, 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '导入操作'); +insert into sys_dict_data values(24, 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '强退操作'); +insert into sys_dict_data values(25, 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '生成操作'); +insert into sys_dict_data values(26, 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '清空操作'); +insert into sys_dict_data values(27, 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', '0', 'admin', sysdate(), '', null, '正常状态'); +insert into sys_dict_data values(28, 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '停用状态'); + + +-- ---------------------------- +-- 13、参数配置表 +-- ---------------------------- +drop table if exists sys_config; +create table sys_config ( + config_id bigint(20) not null comment '参数主键', + config_name varchar(100) default '' comment '参数名称', + config_key varchar(100) default '' comment '参数键名', + config_value varchar(500) default '' comment '参数键值', + config_type char(1) default 'N' comment '系统内置(Y是 N否)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (config_id) +) engine=innodb comment = '参数配置表'; + +insert into sys_config values(1, '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 'admin', sysdate(), '', null, '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow' ); +insert into sys_config values(2, '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 'admin', sysdate(), '', null, '初始化密码 123456' ); +insert into sys_config values(3, '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-dark', 'Y', 'admin', sysdate(), '', null, '深色主题theme-dark,浅色主题theme-light' ); +insert into sys_config values(4, '账号自助-验证码开关', 'sys.account.captchaEnabled', 'true', 'Y', 'admin', sysdate(), '', null, '是否开启验证码功能(true开启,false关闭)'); +insert into sys_config values(5, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 'admin', sysdate(), '', null, '是否开启注册用户功能(true开启,false关闭)'); +insert into sys_config values(11, 'OSS预览列表资源开关', 'sys.oss.previewListResource', 'true', 'Y', 'admin', sysdate(), '', null, 'true:开启, false:关闭'); + + +-- ---------------------------- +-- 14、系统访问记录 +-- ---------------------------- +drop table if exists sys_logininfor; +create table sys_logininfor ( + info_id bigint(20) not null comment '访问ID', + user_name varchar(50) default '' comment '用户账号', + ipaddr varchar(128) default '' comment '登录IP地址', + login_location varchar(255) default '' comment '登录地点', + browser varchar(50) default '' comment '浏览器类型', + os varchar(50) default '' comment '操作系统', + status char(1) default '0' comment '登录状态(0成功 1失败)', + msg varchar(255) default '' comment '提示消息', + login_time datetime comment '访问时间', + primary key (info_id), + key idx_sys_logininfor_s (status), + key idx_sys_logininfor_lt (login_time) +) engine=innodb comment = '系统访问记录'; + + +-- ---------------------------- +-- 17、通知公告表 +-- ---------------------------- +drop table if exists sys_notice; +create table sys_notice ( + notice_id bigint(20) not null comment '公告ID', + notice_title varchar(50) not null comment '公告标题', + notice_type char(1) not null comment '公告类型(1通知 2公告)', + notice_content longblob default null comment '公告内容', + status char(1) default '0' comment '公告状态(0正常 1关闭)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(255) default null comment '备注', + primary key (notice_id) +) engine=innodb comment = '通知公告表'; + +-- ---------------------------- +-- 初始化-公告信息表数据 +-- ---------------------------- +insert into sys_notice values('1', '温馨提醒:2018-07-01 新版本发布啦', '2', '新版本内容', '0', 'admin', sysdate(), '', null, '管理员'); +insert into sys_notice values('2', '维护通知:2018-07-01 系统凌晨维护', '1', '维护内容', '0', 'admin', sysdate(), '', null, '管理员'); + + +-- ---------------------------- +-- 18、代码生成业务表 +-- ---------------------------- +drop table if exists gen_table; +create table gen_table ( + table_id bigint(20) not null comment '编号', + table_name varchar(200) default '' comment '表名称', + table_comment varchar(500) default '' comment '表描述', + sub_table_name varchar(64) default null comment '关联子表的表名', + sub_table_fk_name varchar(64) default null comment '子表关联的外键名', + class_name varchar(100) default '' comment '实体类名称', + tpl_category varchar(200) default 'crud' comment '使用的模板(crud单表操作 tree树表操作)', + package_name varchar(100) comment '生成包路径', + module_name varchar(30) comment '生成模块名', + business_name varchar(30) comment '生成业务名', + function_name varchar(50) comment '生成功能名', + function_author varchar(50) comment '生成功能作者', + gen_type char(1) default '0' comment '生成代码方式(0zip压缩包 1自定义路径)', + gen_path varchar(200) default '/' comment '生成路径(不填默认项目路径)', + options varchar(1000) comment '其它生成选项', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (table_id) +) engine=innodb comment = '代码生成业务表'; + + +-- ---------------------------- +-- 19、代码生成业务表字段 +-- ---------------------------- +drop table if exists gen_table_column; +create table gen_table_column ( + column_id bigint(20) not null comment '编号', + table_id bigint(20) comment '归属表编号', + column_name varchar(200) comment '列名称', + column_comment varchar(500) comment '列描述', + column_type varchar(100) comment '列类型', + java_type varchar(500) comment 'JAVA类型', + java_field varchar(200) comment 'JAVA字段名', + is_pk char(1) comment '是否主键(1是)', + is_increment char(1) comment '是否自增(1是)', + is_required char(1) comment '是否必填(1是)', + is_insert char(1) comment '是否为插入字段(1是)', + is_edit char(1) comment '是否编辑字段(1是)', + is_list char(1) comment '是否列表字段(1是)', + is_query char(1) comment '是否查询字段(1是)', + query_type varchar(200) default 'EQ' comment '查询方式(等于、不等于、大于、小于、范围)', + html_type varchar(200) comment '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)', + dict_type varchar(200) default '' comment '字典类型', + sort int comment '排序', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + primary key (column_id) +) engine=innodb comment = '代码生成业务表字段'; + +-- ---------------------------- +-- OSS对象存储表 +-- ---------------------------- +drop table if exists sys_oss; +create table sys_oss ( + oss_id bigint(20) not null comment '对象存储主键', + file_name varchar(255) not null default '' comment '文件名', + original_name varchar(255) not null default '' comment '原名', + file_suffix varchar(10) not null default '' comment '文件后缀名', + url varchar(500) not null comment 'URL地址', + create_time datetime default null comment '创建时间', + create_by varchar(64) default '' comment '上传人', + update_time datetime default null comment '更新时间', + update_by varchar(64) default '' comment '更新人', + service varchar(20) not null default 'minio' comment '服务商', + primary key (oss_id) +) engine=innodb comment ='OSS对象存储表'; + +-- ---------------------------- +-- OSS对象存储动态配置表 +-- ---------------------------- +drop table if exists sys_oss_config; +create table sys_oss_config ( + oss_config_id bigint(20) not null comment '主建', + config_key varchar(20) not null default '' comment '配置key', + access_key varchar(255) default '' comment 'accessKey', + secret_key varchar(255) default '' comment '秘钥', + bucket_name varchar(255) default '' comment '桶名称', + prefix varchar(255) default '' comment '前缀', + endpoint varchar(255) default '' comment '访问站点', + domain varchar(255) default '' comment '自定义域名', + is_https char(1) default 'N' comment '是否https(Y=是,N=否)', + region varchar(255) default '' comment '域', + access_policy char(1) not null default '1' comment '桶权限类型(0=private 1=public 2=custom)', + status char(1) default '1' comment '是否默认(0=是,1=否)', + ext1 varchar(255) default '' comment '扩展字段', + create_by varchar(64) default '' comment '创建者', + create_time datetime default null comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime default null comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (oss_config_id) +) engine=innodb comment='对象存储配置表'; + +insert into sys_oss_config values (1, 'minio', 'cas', 'ruoyi123', 'cas', '', '127.0.0.1:9000', '','N', '', '1' ,'0', '', 'admin', sysdate(), 'admin', sysdate(), NULL); +insert into sys_oss_config values (2, 'qiniu', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'cas', '', 's3-cn-north-1.qiniucs.com', '','N', '', '1' ,'1', '', 'admin', sysdate(), 'admin', sysdate(), NULL); +insert into sys_oss_config values (3, 'aliyun', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'cas', '', 'oss-cn-beijing.aliyuncs.com', '','N', '', '1' ,'1', '', 'admin', sysdate(), 'admin', sysdate(), NULL); +insert into sys_oss_config values (4, 'qcloud', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'cas-1250000000', '', 'cos.ap-beijing.myqcloud.com', '','N', 'ap-beijing', '1' ,'1', '', 'admin', sysdate(), 'admin', sysdate(), NULL); +insert into sys_oss_config values (5, 'image', 'cas', 'ruoyi123', 'cas', 'image', '127.0.0.1:9000', '','N', '', '1' ,'1', '', 'admin', sysdate(), 'admin', sysdate(), NULL); diff --git a/script/sql/tables_xxl_job.sql b/script/sql/tables_xxl_job.sql new file mode 100644 index 0000000..236c557 --- /dev/null +++ b/script/sql/tables_xxl_job.sql @@ -0,0 +1,119 @@ +# +# XXL-JOB v2.3.0 +# Copyright (c) 2015-present, xuxueli. + +SET NAMES utf8mb4; + +CREATE TABLE `xxl_job_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_group` int(11) NOT NULL COMMENT '执行器主键ID', + `job_desc` varchar(255) NOT NULL, + `add_time` datetime DEFAULT NULL, + `update_time` datetime DEFAULT NULL, + `author` varchar(64) DEFAULT NULL COMMENT '作者', + `alarm_email` varchar(255) DEFAULT NULL COMMENT '报警邮件', + `schedule_type` varchar(50) NOT NULL DEFAULT 'NONE' COMMENT '调度类型', + `schedule_conf` varchar(128) DEFAULT NULL COMMENT '调度配置,值含义取决于调度类型', + `misfire_strategy` varchar(50) NOT NULL DEFAULT 'DO_NOTHING' COMMENT '调度过期策略', + `executor_route_strategy` varchar(50) DEFAULT NULL COMMENT '执行器路由策略', + `executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler', + `executor_param` varchar(512) DEFAULT NULL COMMENT '执行器任务参数', + `executor_block_strategy` varchar(50) DEFAULT NULL COMMENT '阻塞处理策略', + `executor_timeout` int(11) NOT NULL DEFAULT '0' COMMENT '任务执行超时时间,单位秒', + `executor_fail_retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '失败重试次数', + `glue_type` varchar(50) NOT NULL COMMENT 'GLUE类型', + `glue_source` mediumtext COMMENT 'GLUE源代码', + `glue_remark` varchar(128) DEFAULT NULL COMMENT 'GLUE备注', + `glue_updatetime` datetime DEFAULT NULL COMMENT 'GLUE更新时间', + `child_jobid` varchar(255) DEFAULT NULL COMMENT '子任务ID,多个逗号分隔', + `trigger_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '调度状态:0-停止,1-运行', + `trigger_last_time` bigint(13) NOT NULL DEFAULT '0' COMMENT '上次调度时间', + `trigger_next_time` bigint(13) NOT NULL DEFAULT '0' COMMENT '下次调度时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE `xxl_job_log` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `job_group` int(11) NOT NULL COMMENT '执行器主键ID', + `job_id` int(11) NOT NULL COMMENT '任务,主键ID', + `executor_address` varchar(255) DEFAULT NULL COMMENT '执行器地址,本次执行的地址', + `executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler', + `executor_param` varchar(512) DEFAULT NULL COMMENT '执行器任务参数', + `executor_sharding_param` varchar(20) DEFAULT NULL COMMENT '执行器任务分片参数,格式如 1/2', + `executor_fail_retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '失败重试次数', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_code` int(11) NOT NULL COMMENT '调度-结果', + `trigger_msg` text COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_code` int(11) NOT NULL COMMENT '执行-状态', + `handle_msg` text COMMENT '执行-日志', + `alarm_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '告警状态:0-默认、1-无需告警、2-告警成功、3-告警失败', + PRIMARY KEY (`id`), + KEY `I_trigger_time` (`trigger_time`), + KEY `I_handle_code` (`handle_code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE `xxl_job_log_report` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `trigger_day` datetime DEFAULT NULL COMMENT '调度-时间', + `running_count` int(11) NOT NULL DEFAULT '0' COMMENT '运行中-日志数量', + `suc_count` int(11) NOT NULL DEFAULT '0' COMMENT '执行成功-日志数量', + `fail_count` int(11) NOT NULL DEFAULT '0' COMMENT '执行失败-日志数量', + `update_time` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `i_trigger_day` (`trigger_day`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE `xxl_job_logglue` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_id` int(11) NOT NULL COMMENT '任务,主键ID', + `glue_type` varchar(50) DEFAULT NULL COMMENT 'GLUE类型', + `glue_source` mediumtext COMMENT 'GLUE源代码', + `glue_remark` varchar(128) NOT NULL COMMENT 'GLUE备注', + `add_time` datetime DEFAULT NULL, + `update_time` datetime DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE `xxl_job_registry` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `registry_group` varchar(50) NOT NULL, + `registry_key` varchar(255) NOT NULL, + `registry_value` varchar(255) NOT NULL, + `update_time` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `i_g_k_v` (`registry_group`,`registry_key`,`registry_value`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE `xxl_job_group` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `app_name` varchar(64) NOT NULL COMMENT '执行器AppName', + `title` varchar(12) NOT NULL COMMENT '执行器名称', + `address_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '执行器地址类型:0=自动注册、1=手动录入', + `address_list` text COMMENT '执行器地址列表,多地址逗号分隔', + `update_time` datetime DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE `xxl_job_user` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `username` varchar(50) NOT NULL COMMENT '账号', + `password` varchar(50) NOT NULL COMMENT '密码', + `role` tinyint(4) NOT NULL COMMENT '角色:0-普通用户、1-管理员', + `permission` varchar(255) DEFAULT NULL COMMENT '权限:执行器ID列表,多个逗号分割', + PRIMARY KEY (`id`), + UNIQUE KEY `i_username` (`username`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE `xxl_job_lock` ( + `lock_name` varchar(50) NOT NULL COMMENT '锁名称', + PRIMARY KEY (`lock_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +INSERT INTO `xxl_job_group`(`id`, `app_name`, `title`, `address_type`, `address_list`, `update_time`) VALUES (1, 'xxl-job-executor', '示例执行器', 0, NULL, '2018-11-03 22:21:31' ); +INSERT INTO `xxl_job_info`(`id`, `job_group`, `job_desc`, `add_time`, `update_time`, `author`, `alarm_email`, `schedule_type`, `schedule_conf`, `misfire_strategy`, `executor_route_strategy`, `executor_handler`, `executor_param`, `executor_block_strategy`, `executor_timeout`, `executor_fail_retry_count`, `glue_type`, `glue_source`, `glue_remark`, `glue_updatetime`, `child_jobid`) VALUES (1, 1, '测试任务1', '2018-11-03 22:21:31', '2018-11-03 22:21:31', 'XXL', '', 'CRON', '0 0 0 * * ? *', 'DO_NOTHING', 'FIRST', 'demoJobHandler', '', 'SERIAL_EXECUTION', 0, 0, 'BEAN', '', 'GLUE代码初始化', '2018-11-03 22:21:31', ''); +INSERT INTO `xxl_job_user`(`id`, `username`, `password`, `role`, `permission`) VALUES (1, 'admin', 'e10adc3949ba59abbe56e057f20f883e', 1, NULL); +INSERT INTO `xxl_job_lock` ( `lock_name`) VALUES ( 'schedule_lock'); + +commit; +