diff --git a/.gitignore b/.gitignore index a81c8ee121952cf06bfaf9ff9988edd8cded763c..f37062d0975df9ed24b2dc70151231353e4f511f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,54 @@ + +###################################################################### + +# 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/ +dist/ +nbdist/ +.nb-gradle/ + +###################################################################### + +# Others +*.log +*.xml.versionsBackup +*.swp +!*/build/*.java +!*/build/*.html +!*/build/*.xml +sonar-project.properties +.scannerwork/ + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] @@ -8,9 +59,7 @@ __pycache__/ # Distribution / packaging .Python -build/ develop-eggs/ -dist/ downloads/ eggs/ .eggs/ @@ -27,6 +76,7 @@ share/python-wheels/ MANIFEST # PyInstaller + # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest @@ -56,7 +106,6 @@ cover/ *.pot # Django stuff: -*.log local_settings.py db.sqlite3 db.sqlite3-journal @@ -73,7 +122,6 @@ docs/_build/ # PyBuilder .pybuilder/ -target/ # Jupyter Notebook .ipynb_checkpoints @@ -85,6 +133,7 @@ ipython_config.py # pyenv # For a library or package, you might want to ignore these files since the code is # intended to run in multiple environments; otherwise, check them in: + # .python-version # pipenv @@ -92,6 +141,7 @@ ipython_config.py # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. + #Pipfile.lock # PEP 582; used by e.g. github.com/David-OConnor/pyflow @@ -136,3 +186,24 @@ dmypy.json # Cython debug symbols cython_debug/ + +# Frontend +.DS_Store +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +**/*.log +tests/**/coverage/ +tests/e2e/reports +selenium-debug.log + +# Editor directories and files +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.local +package-lock.json +yarn.lock diff --git a/CSP-admin/pom.xml b/CSP-admin/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..2b799f43bbaa4a5d705bfef0b07936c618eb3406 --- /dev/null +++ b/CSP-admin/pom.xml @@ -0,0 +1,94 @@ + + + + CodeScanningPlatform-Backend + com.RVSmartPorting + 1.0.0 + + 4.0.0 + + CSP-admin + + + + web服务入口 + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + org.springframework.boot + spring-boot-devtools + true + + + + + io.springfox + springfox-boot-starter + + + + + io.swagger + swagger-models + 1.6.2 + + + + + mysql + mysql-connector-java + + + + com.RVSmartPorting + CSP-core + + + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + 2.1.1.RELEASE + + true + + + + + + repackage + + + + + + org.apache.maven.plugins + maven-war-plugin + 3.1.0 + + false + ${project.artifactId} + + + + ${project.artifactId} + + + \ No newline at end of file diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/CSPApplication.java b/CSP-admin/src/main/java/com/RVSmartPorting/CSPApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..0e611a93ba4244f85a1228488f3f26b95e8ea314 --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/CSPApplication.java @@ -0,0 +1,16 @@ +package com.RVSmartPorting; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) +public class CSPApplication +{ + public static void main(String[] args) + { + SpringApplication.run(CSPApplication.class, args); + + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/common/CaptchaController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/common/CaptchaController.java new file mode 100644 index 0000000000000000000000000000000000000000..47d99f547a6df623603f14378b72bb35cd79cf56 --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/common/CaptchaController.java @@ -0,0 +1,95 @@ +package com.RVSmartPorting.web.controller.common; + +import com.RVSmartPorting.common.config.CSPConfig; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.utils.redis.RedisCache; +import com.RVSmartPorting.core.system.service.ISysConfigService; +import com.google.code.kaptcha.Producer; +import com.RVSmartPorting.common.constant.CacheConstants; +import com.RVSmartPorting.common.constant.Constants; +import com.RVSmartPorting.common.utils.sign.Base64; +import com.RVSmartPorting.common.utils.uuid.IdUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.FastByteArrayOutputStream; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.imageio.ImageIO; +import javax.servlet.http.HttpServletResponse; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +/** + * 验证码操作处理 + * + * @author ruoyi + */ +@RestController +public class CaptchaController +{ + @Resource(name = "captchaProducer") + private Producer captchaProducer; + + @Resource(name = "captchaProducerMath") + private Producer captchaProducerMath; + + @Autowired + private RedisCache redisCache; + + @Autowired + private ISysConfigService configService; + /** + * 生成验证码 + */ + @GetMapping("/captchaImage") + public AjaxResult getCode(HttpServletResponse response) throws IOException + { + AjaxResult ajax = AjaxResult.success(); + boolean captchaEnabled = configService.selectCaptchaEnabled(); + ajax.put("captchaEnabled", captchaEnabled); + if (!captchaEnabled) + { + return ajax; + } + + // 保存验证码信息 + String uuid = IdUtils.simpleUUID(); + String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid; + + String capStr = null, code = null; + BufferedImage image = null; + + // 生成验证码 + String captchaType = CSPConfig.getCaptchaType(); + if ("math".equals(captchaType)) + { + String capText = captchaProducerMath.createText(); + capStr = capText.substring(0, capText.lastIndexOf("@")); + code = capText.substring(capText.lastIndexOf("@") + 1); + image = captchaProducerMath.createImage(capStr); + } + else if ("char".equals(captchaType)) + { + capStr = code = captchaProducer.createText(); + image = captchaProducer.createImage(capStr); + } + + redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES); + // 转换流信息写出 + FastByteArrayOutputStream os = new FastByteArrayOutputStream(); + try + { + ImageIO.write(image, "jpg", os); + } + catch (IOException e) + { + return AjaxResult.error(e.getMessage()); + } + + ajax.put("uuid", uuid); + ajax.put("img", Base64.encode(os.toByteArray())); + return ajax; + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/common/CommonController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/common/CommonController.java new file mode 100644 index 0000000000000000000000000000000000000000..3e48cb21a9b56b46ebf40271bacfe2e477a3f5ae --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/common/CommonController.java @@ -0,0 +1,164 @@ +package com.RVSmartPorting.web.controller.common; + +import com.RVSmartPorting.common.config.CSPConfig; +import com.RVSmartPorting.common.constant.Constants; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.file.FileUploadUtils; +import com.RVSmartPorting.common.utils.file.FileUtils; +import com.RVSmartPorting.core.config.ServerConfig; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.List; + +/** + * 通用请求处理 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/common") +public class CommonController +{ + private static final Logger log = LoggerFactory.getLogger(CommonController.class); + + @Autowired + private ServerConfig serverConfig; + + private static final String FILE_DELIMETER = ","; + + /** + * 通用下载请求 + * + * @param fileName 文件名称 + * @param delete 是否删除 + */ + @GetMapping("/download") + public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request) + { + try + { + if (!FileUtils.checkAllowDownload(fileName)) + { + throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName)); + } + String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1); + String filePath = CSPConfig.getDownloadPath() + fileName; + + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + FileUtils.setAttachmentResponseHeader(response, realFileName); + FileUtils.writeBytes(filePath, response.getOutputStream()); + if (delete) + { + FileUtils.deleteFile(filePath); + } + } + catch (Exception e) + { + log.error("下载文件失败", e); + } + } + + /** + * 通用上传请求(单个) + */ + @PostMapping("/upload") + public AjaxResult uploadFile(MultipartFile file) throws Exception + { + try + { + // 上传文件路径 + String filePath = CSPConfig.getUploadPath(); + // 上传并返回新文件名称 + String fileName = FileUploadUtils.upload(filePath, file); + String url = serverConfig.getUrl() + fileName; + AjaxResult ajax = AjaxResult.success(); + ajax.put("url", url); + ajax.put("fileName", fileName); + ajax.put("newFileName", FileUtils.getName(fileName)); + ajax.put("originalFilename", file.getOriginalFilename()); + return ajax; + } + catch (Exception e) + { + return AjaxResult.error(e.getMessage()); + } + } + + /** + * 通用上传请求(多个) + */ + @PostMapping("/uploads") + public AjaxResult uploadFiles(List files) throws Exception + { + try + { + // 上传文件路径 + String filePath = CSPConfig.getUploadPath(); + List urls = new ArrayList(); + List fileNames = new ArrayList(); + List newFileNames = new ArrayList(); + List originalFilenames = new ArrayList(); + for (MultipartFile file : files) + { + // 上传并返回新文件名称 + String fileName = FileUploadUtils.upload(filePath, file); + String url = serverConfig.getUrl() + fileName; + urls.add(url); + fileNames.add(fileName); + newFileNames.add(FileUtils.getName(fileName)); + originalFilenames.add(file.getOriginalFilename()); + } + AjaxResult ajax = AjaxResult.success(); + ajax.put("urls", StringUtils.join(urls, FILE_DELIMETER)); + ajax.put("fileNames", StringUtils.join(fileNames, FILE_DELIMETER)); + ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMETER)); + ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMETER)); + return ajax; + } + catch (Exception e) + { + return AjaxResult.error(e.getMessage()); + } + } + + /** + * 本地资源通用下载 + */ + @GetMapping("/download/resource") + public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response) + throws Exception + { + try + { + if (!FileUtils.checkAllowDownload(resource)) + { + throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource)); + } + // 本地资源路径 + String localPath = CSPConfig.getProfile(); + // 数据库资源地址 + String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX); + // 下载名称 + String downloadName = StringUtils.substringAfterLast(downloadPath, "/"); + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + FileUtils.setAttachmentResponseHeader(response, downloadName); + FileUtils.writeBytes(downloadPath, response.getOutputStream()); + } + catch (Exception e) + { + log.error("下载文件失败", e); + } + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/monitor/CacheController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/monitor/CacheController.java new file mode 100644 index 0000000000000000000000000000000000000000..73db005a35d9576ab688ab571569ffd04bee7441 --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/monitor/CacheController.java @@ -0,0 +1,111 @@ +package com.RVSmartPorting.web.controller.monitor; + +import com.RVSmartPorting.common.constant.CacheConstants; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.core.system.domain.SysCache; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisCallback; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.*; + +/** + * 缓存监控 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/monitor/cache") +public class CacheController +{ + @Autowired + private RedisTemplate redisTemplate; + + private final static List caches = new ArrayList(); + { + caches.add(new SysCache(CacheConstants.LOGIN_TOKEN_KEY, "用户信息")); + caches.add(new SysCache(CacheConstants.SYS_CONFIG_KEY, "配置信息")); + caches.add(new SysCache(CacheConstants.SYS_DICT_KEY, "数据字典")); + 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(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数")); + } + + @PreAuthorize("@ss.hasPermi('monitor:cache:list')") + @GetMapping() + public AjaxResult getInfo() throws Exception + { + Properties info = (Properties) redisTemplate.execute((RedisCallback) connection -> connection.info()); + Properties commandStats = (Properties) redisTemplate.execute((RedisCallback) connection -> connection.info("commandstats")); + Object dbSize = redisTemplate.execute((RedisCallback) connection -> connection.dbSize()); + + Map result = new HashMap<>(3); + result.put("info", info); + result.put("dbSize", dbSize); + + List> pieList = new ArrayList<>(); + 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 AjaxResult.success(result); + } + + @PreAuthorize("@ss.hasPermi('monitor:cache:list')") + @GetMapping("/getNames") + public AjaxResult cache() + { + return AjaxResult.success(caches); + } + + @PreAuthorize("@ss.hasPermi('monitor:cache:list')") + @GetMapping("/getKeys/{cacheName}") + public AjaxResult getCacheKeys(@PathVariable String cacheName) + { + Set cacheKeys = redisTemplate.keys(cacheName + "*"); + return AjaxResult.success(cacheKeys); + } + + @PreAuthorize("@ss.hasPermi('monitor:cache:list')") + @GetMapping("/getValue/{cacheName}/{cacheKey}") + public AjaxResult getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey) + { + String cacheValue = redisTemplate.opsForValue().get(cacheKey); + SysCache sysCache = new SysCache(cacheName, cacheKey, cacheValue); + return AjaxResult.success(sysCache); + } + + @PreAuthorize("@ss.hasPermi('monitor:cache:list')") + @DeleteMapping("/clearCacheName/{cacheName}") + public AjaxResult clearCacheName(@PathVariable String cacheName) + { + Collection cacheKeys = redisTemplate.keys(cacheName + "*"); + redisTemplate.delete(cacheKeys); + return AjaxResult.success(); + } + + @PreAuthorize("@ss.hasPermi('monitor:cache:list')") + @DeleteMapping("/clearCacheKey/{cacheKey}") + public AjaxResult clearCacheKey(@PathVariable String cacheKey) + { + redisTemplate.delete(cacheKey); + return AjaxResult.success(); + } + + @PreAuthorize("@ss.hasPermi('monitor:cache:list')") + @DeleteMapping("/clearCacheAll") + public AjaxResult clearCacheAll() + { + Collection cacheKeys = redisTemplate.keys("*"); + redisTemplate.delete(cacheKeys); + return AjaxResult.success(); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/monitor/ServerController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/monitor/ServerController.java new file mode 100644 index 0000000000000000000000000000000000000000..1ab386075b35f39ccc80eab29d3c6ba982fc5412 --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/monitor/ServerController.java @@ -0,0 +1,27 @@ +package com.RVSmartPorting.web.controller.monitor; + +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.core.web.domain.Server; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 服务器监控 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/monitor/server") +public class ServerController +{ + @PreAuthorize("@ss.hasPermi('monitor:server:list')") + @GetMapping() + public AjaxResult getInfo() throws Exception + { + Server server = new Server(); + server.copyTo(); + return AjaxResult.success(server); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/monitor/SysLogininforController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/monitor/SysLogininforController.java new file mode 100644 index 0000000000000000000000000000000000000000..dc6be53f3f3408167fd226f5cd9b845daca78fe0 --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/monitor/SysLogininforController.java @@ -0,0 +1,78 @@ +package com.RVSmartPorting.web.controller.monitor; + +import com.RVSmartPorting.common.annotation.Log; +import com.RVSmartPorting.common.core.controller.BaseController; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.page.TableDataInfo; +import com.RVSmartPorting.common.enums.BusinessType; +import com.RVSmartPorting.common.utils.poi.ExcelUtil; +import com.RVSmartPorting.core.system.domain.SysLogininfor; +import com.RVSmartPorting.core.system.service.ISysLogininforService; +import com.RVSmartPorting.core.web.service.SysPasswordService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 系统访问记录 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/monitor/logininfor") +public class SysLogininforController extends BaseController +{ + @Autowired + private ISysLogininforService logininforService; + + @Autowired + private SysPasswordService passwordService; + + @PreAuthorize("@ss.hasPermi('monitor:logininfor:list')") + @GetMapping("/list") + public TableDataInfo list(SysLogininfor logininfor) + { + startPage(); + List list = logininforService.selectLogininforList(logininfor); + return getDataTable(list); + } + + @Log(title = "登录日志", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('monitor:logininfor:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysLogininfor logininfor) + { + List list = logininforService.selectLogininforList(logininfor); + ExcelUtil util = new ExcelUtil(SysLogininfor.class); + util.exportExcel(response, list, "登录日志"); + } + + @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')") + @Log(title = "登录日志", businessType = BusinessType.DELETE) + @DeleteMapping("/{infoIds}") + public AjaxResult remove(@PathVariable Long[] infoIds) + { + return toAjax(logininforService.deleteLogininforByIds(infoIds)); + } + + @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')") + @Log(title = "登录日志", businessType = BusinessType.CLEAN) + @DeleteMapping("/clean") + public AjaxResult clean() + { + logininforService.cleanLogininfor(); + return success(); + } + + @PreAuthorize("@ss.hasPermi('monitor:logininfor:unlock')") + @Log(title = "账户解锁", businessType = BusinessType.OTHER) + @GetMapping("/unlock/{userName}") + public AjaxResult unlock(@PathVariable("userName") String userName) + { + passwordService.clearLoginRecordCache(userName); + return success(); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/monitor/SysOperlogController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/monitor/SysOperlogController.java new file mode 100644 index 0000000000000000000000000000000000000000..541843913ccacd0dd11b32d0749e2461fd2458c9 --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/monitor/SysOperlogController.java @@ -0,0 +1,65 @@ +package com.RVSmartPorting.web.controller.monitor; + +import com.RVSmartPorting.common.annotation.Log; +import com.RVSmartPorting.common.core.controller.BaseController; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.page.TableDataInfo; +import com.RVSmartPorting.common.enums.BusinessType; +import com.RVSmartPorting.common.utils.poi.ExcelUtil; +import com.RVSmartPorting.core.system.domain.SysOperLog; +import com.RVSmartPorting.core.system.service.ISysOperLogService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 操作日志记录 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/monitor/operlog") +public class SysOperlogController extends BaseController +{ + @Autowired + private ISysOperLogService operLogService; + + @PreAuthorize("@ss.hasPermi('monitor:operlog:list')") + @GetMapping("/list") + public TableDataInfo list(SysOperLog operLog) + { + startPage(); + List list = operLogService.selectOperLogList(operLog); + return getDataTable(list); + } + + @Log(title = "操作日志", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('monitor:operlog:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysOperLog operLog) + { + List list = operLogService.selectOperLogList(operLog); + ExcelUtil util = new ExcelUtil(SysOperLog.class); + util.exportExcel(response, list, "操作日志"); + } + + @Log(title = "操作日志", businessType = BusinessType.DELETE) + @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')") + @DeleteMapping("/{operIds}") + public AjaxResult remove(@PathVariable Long[] operIds) + { + return toAjax(operLogService.deleteOperLogByIds(operIds)); + } + + @Log(title = "操作日志", businessType = BusinessType.CLEAN) + @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')") + @DeleteMapping("/clean") + public AjaxResult clean() + { + operLogService.cleanOperLog(); + return success(); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/monitor/SysUserOnlineController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/monitor/SysUserOnlineController.java new file mode 100644 index 0000000000000000000000000000000000000000..09b43f67854dd06dc6ce2f1d0b54256b0a26e45f --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/monitor/SysUserOnlineController.java @@ -0,0 +1,80 @@ +package com.RVSmartPorting.web.controller.monitor; + +import com.RVSmartPorting.common.annotation.Log; +import com.RVSmartPorting.common.constant.CacheConstants; +import com.RVSmartPorting.common.core.controller.BaseController; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.domain.model.LoginUser; +import com.RVSmartPorting.common.core.page.TableDataInfo; +import com.RVSmartPorting.common.enums.BusinessType; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.redis.RedisCache; +import com.RVSmartPorting.core.system.domain.SysUserOnline; +import com.RVSmartPorting.core.system.service.ISysUserOnlineService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * 在线用户监控 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/monitor/online") +public class SysUserOnlineController extends BaseController +{ + @Autowired + private ISysUserOnlineService userOnlineService; + + @Autowired + private RedisCache redisCache; + + @PreAuthorize("@ss.hasPermi('monitor:online:list')") + @GetMapping("/list") + public TableDataInfo list(String ipaddr, String userName) + { + Collection keys = redisCache.keys(CacheConstants.LOGIN_TOKEN_KEY + "*"); + List userOnlineList = new ArrayList(); + for (String key : keys) + { + LoginUser user = redisCache.getCacheObject(key); + if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) + { + userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user)); + } + else if (StringUtils.isNotEmpty(ipaddr)) + { + userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user)); + } + else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser())) + { + userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user)); + } + else + { + userOnlineList.add(userOnlineService.loginUserToUserOnline(user)); + } + } + Collections.reverse(userOnlineList); + userOnlineList.removeAll(Collections.singleton(null)); + return getDataTable(userOnlineList); + } + + /** + * 强退用户 + */ + @PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')") + @Log(title = "在线用户", businessType = BusinessType.FORCE) + @DeleteMapping("/{tokenId}") + public AjaxResult forceLogout(@PathVariable String tokenId) + { + redisCache.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId); + return success(); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/CodeProjectController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/CodeProjectController.java new file mode 100644 index 0000000000000000000000000000000000000000..e76866813bb8f467c54c169781b8ab1d778a24b9 --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/CodeProjectController.java @@ -0,0 +1,197 @@ +package com.RVSmartPorting.web.controller.system; + +import com.RVSmartPorting.common.annotation.Log; +import com.RVSmartPorting.common.core.controller.BaseController; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.domain.entity.SysUser; +import com.RVSmartPorting.common.core.page.TableDataInfo; +import com.RVSmartPorting.common.enums.BusinessType; +import com.RVSmartPorting.common.utils.SecurityUtils; +import com.RVSmartPorting.common.utils.file.FileUploadUtils; +import com.RVSmartPorting.common.utils.file.FileUtils; +import com.RVSmartPorting.common.utils.file.PathConverterUtil; +import com.RVSmartPorting.common.utils.poi.ExcelUtil; +import com.RVSmartPorting.core.system.domain.CodeProject; +import com.RVSmartPorting.core.system.fileStorage.AbstractFileStorage; +import com.RVSmartPorting.core.system.fileStorage.FileStorageFactory; +import com.RVSmartPorting.core.system.fileStorage.HDFSService; +import com.RVSmartPorting.core.system.fileStorage.LocalFileStorage; +import com.RVSmartPorting.core.system.fileStorage.git.GitService; +import com.RVSmartPorting.core.system.fileStorage.http.OkHttpService; +import com.RVSmartPorting.core.system.service.ICodeProjectService; +import lombok.extern.slf4j.Slf4j; +import okhttp3.Call; +import org.apache.hadoop.fs.FSDataInputStream; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.InputStreamResource; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.util.FileCopyUtils; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.List; + + +/** + * 代码项目信息Controller + * + * @author ruoyi + * @date 2023-08-24 + */ +@Slf4j +@RestController +@RequestMapping("/system/codeProject") +public class CodeProjectController extends BaseController { + @Autowired + private ICodeProjectService codeProjectService; + + /** + * 上传 + */ + @PreAuthorize("@ss.hasPermi('system:codeProject:edit')") + @PostMapping("/upload") + public AjaxResult upload(@RequestParam(value = "file", required = false) MultipartFile file, + String uploadType, + @RequestParam(required = false) Long codeProjectId, + @RequestParam(required = false) String repositoryType, + @RequestParam(required = false) String projectRepositoryURL, + @RequestParam(required = false) String branchName, + @RequestParam(required = false) String downloadLink, + @RequestParam(required = false) String authenticationMethod, + @RequestParam(required = false) String username, + @RequestParam(required = false) String password, + @RequestParam(required = false) String personalAccessToken + ) throws Exception { + SysUser user = SecurityUtils.getLoginUser().getUser(); + String data = codeProjectService.upload(user, file, uploadType, codeProjectId, repositoryType, + projectRepositoryURL, branchName, downloadLink, authenticationMethod, username, password, personalAccessToken); + AjaxResult ajax = AjaxResult.success(); + ajax.put("data", data); + return ajax; + } + + @PostMapping("/cancelDownloadFromLink/{requestId}") + public void cancelDownloadFromLink(@PathVariable("requestId") String requestId) { + Call call = OkHttpService.getActiveDownloads().remove(requestId); + if (call != null) { + call.cancel(); + } + } + + @PostMapping("/cancelGitDownloadFromLink/{requestId}") + public void cancelGitDownloadFromLink(@PathVariable("requestId") String requestId) { + GitService.removeActiveDownload(requestId); + } + + /** + * 查询代码项目信息列表 + */ + @PreAuthorize("@ss.hasPermi('system:codeProject:list')") + @GetMapping("/list") + public TableDataInfo list(CodeProject codeProject) { + SysUser user = SecurityUtils.getLoginUser().getUser(); + codeProject.setUserId(user.getUserId()); + startPage(); + List list = codeProjectService.selectCodeProjectList(codeProject); + return getDataTable(list); + } + + /** + * 导出代码项目信息列表 + */ + @PreAuthorize("@ss.hasPermi('system:codeProject:export')") + @Log(title = "代码项目信息", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, CodeProject codeProject) { + List list = codeProjectService.selectCodeProjectList(codeProject); + ExcelUtil util = new ExcelUtil(CodeProject.class); + util.exportExcel(response, list, "代码项目信息数据"); + } + + /** + * 获取代码项目信息详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:codeProject:query')") + @GetMapping(value = "/{codeProjectId}") + public AjaxResult getInfo(@PathVariable("codeProjectId") Long codeProjectId) { + return success(codeProjectService.selectCodeProjectByCodeProjectId(codeProjectId)); + } + + /** + * 新增代码项目信息 + */ + @PreAuthorize("@ss.hasPermi('system:codeProject:add')") + @Log(title = "代码项目信息", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody CodeProject codeProject) { + SysUser user = SecurityUtils.getLoginUser().getUser(); + codeProject.setUserId(user.getUserId()); + return toAjax(codeProjectService.insertCodeProject(codeProject)); + } + + /** + * 修改代码项目信息 + */ + @PreAuthorize("@ss.hasPermi('system:codeProject:edit')") + @Log(title = "代码项目信息", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody CodeProject codeProject) { + return toAjax(codeProjectService.updateCodeProject(codeProject)); + } + + /** + * 删除代码项目信息 + */ + @PreAuthorize("@ss.hasPermi('system:codeProject:remove')") + @Log(title = "代码项目信息", businessType = BusinessType.DELETE) + @DeleteMapping("/{codeProjectIds}") + public AjaxResult remove(@PathVariable Long[] codeProjectIds) { + return toAjax(codeProjectService.deleteCodeProjectByCodeProjectIds(codeProjectIds)); + } + + + @Autowired + FileStorageFactory fileStorageFactory; + + @PostMapping("/download/hdfsFile") + public ResponseEntity downloadFile(@RequestParam String hdfsCodePackPath) { + + try { + hdfsCodePackPath = URLDecoder.decode(hdfsCodePackPath, "UTF-8"); + final AbstractFileStorage fileStorage = fileStorageFactory.getFileStorage(); + if (fileStorage instanceof LocalFileStorage) { + hdfsCodePackPath = PathConverterUtil.convertPath(hdfsCodePackPath); + } + InputStream inputStream = fileStorage.downloadFile(hdfsCodePackPath); + // 获取文件的MIME类型 + String contentType = "application/octet-stream"; // 默认为二进制流 + + // 构建响应头 + HttpHeaders headers = new HttpHeaders(); + String encodedFileName = URLEncoder.encode(new File(hdfsCodePackPath).getName(), "UTF-8"); + headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + encodedFileName); + + ResponseEntity responseEntity = ResponseEntity.ok() + .headers(headers) + .contentType(MediaType.parseMediaType(contentType)) + .body(new InputStreamResource(inputStream)); + log.info("responseEntity:{}", responseEntity); + return responseEntity; + } catch (IOException e) { + log.error("Error while downloading file from HDFS: {}", e.getMessage(), e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/GitNetworkSettingController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/GitNetworkSettingController.java new file mode 100644 index 0000000000000000000000000000000000000000..fa88971cb11cee4e474a1821595b9f9325527499 --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/GitNetworkSettingController.java @@ -0,0 +1,105 @@ +package com.RVSmartPorting.web.controller.system; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; + +import com.RVSmartPorting.common.annotation.Log; +import com.RVSmartPorting.common.core.controller.BaseController; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.page.TableDataInfo; +import com.RVSmartPorting.common.enums.BusinessType; +import com.RVSmartPorting.common.utils.poi.ExcelUtil; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.RVSmartPorting.core.system.domain.GitNetworkSetting; +import com.RVSmartPorting.core.system.service.IGitNetworkSettingService; + +/** + * git网络镜像代理配置Controller + * + * @author ruoyi + * @date 2023-09-09 + */ +@RestController +@RequestMapping("/system/gitNetworkSetting") +public class GitNetworkSettingController extends BaseController +{ + @Autowired + private IGitNetworkSettingService gitNetworkSettingService; + + /** + * 查询git网络镜像代理配置列表 + */ + @PreAuthorize("@ss.hasPermi('system:gitNetworkSetting:list')") + @GetMapping("/list") + public TableDataInfo list(GitNetworkSetting gitNetworkSetting) + { + startPage(); + List list = gitNetworkSettingService.selectGitNetworkSettingList(gitNetworkSetting); + return getDataTable(list); + } + + /** + * 导出git网络镜像代理配置列表 + */ + @PreAuthorize("@ss.hasPermi('system:gitNetworkSetting:export')") + @Log(title = "git网络镜像代理配置", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, GitNetworkSetting gitNetworkSetting) + { + List list = gitNetworkSettingService.selectGitNetworkSettingList(gitNetworkSetting); + ExcelUtil util = new ExcelUtil(GitNetworkSetting.class); + util.exportExcel(response, list, "git网络镜像代理配置数据"); + } + + /** + * 获取git网络镜像代理配置详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:gitNetworkSetting:query')") + @GetMapping(value = "/{gitNetworkSettingId}") + public AjaxResult getInfo(@PathVariable("gitNetworkSettingId") Long gitNetworkSettingId) + { + return success(gitNetworkSettingService.selectGitNetworkSettingByGitNetworkSettingId(gitNetworkSettingId)); + } + + /** + * 新增git网络镜像代理配置 + */ + @PreAuthorize("@ss.hasPermi('system:gitNetworkSetting:add')") + @Log(title = "git网络镜像代理配置", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody GitNetworkSetting gitNetworkSetting) + { + return toAjax(gitNetworkSettingService.insertGitNetworkSetting(gitNetworkSetting)); + } + + /** + * 修改git网络镜像代理配置 + */ + @PreAuthorize("@ss.hasPermi('system:gitNetworkSetting:edit')") + @Log(title = "git网络镜像代理配置", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody GitNetworkSetting gitNetworkSetting) + { + return toAjax(gitNetworkSettingService.updateGitNetworkSetting(gitNetworkSetting)); + } + + /** + * 删除git网络镜像代理配置 + */ + @PreAuthorize("@ss.hasPermi('system:gitNetworkSetting:remove')") + @Log(title = "git网络镜像代理配置", businessType = BusinessType.DELETE) + @DeleteMapping("/{gitNetworkSettingIds}") + public AjaxResult remove(@PathVariable Long[] gitNetworkSettingIds) + { + return toAjax(gitNetworkSettingService.deleteGitNetworkSettingByGitNetworkSettingIds(gitNetworkSettingIds)); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/RuleController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/RuleController.java new file mode 100644 index 0000000000000000000000000000000000000000..0a718af89740820db174f4d2aebd32a53426676e --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/RuleController.java @@ -0,0 +1,106 @@ +package com.RVSmartPorting.web.controller.system; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; + +import com.RVSmartPorting.common.annotation.Log; +import com.RVSmartPorting.common.core.controller.BaseController; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.page.TableDataInfo; +import com.RVSmartPorting.common.enums.BusinessType; +import com.RVSmartPorting.common.utils.poi.ExcelUtil; +import com.RVSmartPorting.core.system.domain.Rule; +import com.RVSmartPorting.core.system.service.IRuleService; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + + +/** + * 规则信息Controller + * + * @author ruoyi + * @date 2023-08-15 + */ +@RestController +@RequestMapping("/system/rule") +public class RuleController extends BaseController +{ + @Autowired + private IRuleService ruleService; + + /** + * 查询规则信息列表 + */ + @PreAuthorize("@ss.hasPermi('system:rule:list')") + @GetMapping("/list") + public TableDataInfo list(Rule rule) + { + startPage(); + List list = ruleService.selectRuleList(rule); + return getDataTable(list); + } + + /** + * 导出规则信息列表 + */ + @PreAuthorize("@ss.hasPermi('system:rule:export')") + @Log(title = "规则信息", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, Rule rule) + { + List list = ruleService.selectRuleList(rule); + ExcelUtil util = new ExcelUtil(Rule.class); + util.exportExcel(response, list, "规则信息数据"); + } + + /** + * 获取规则信息详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:rule:query')") + @GetMapping(value = "/{ruleId}") + public AjaxResult getInfo(@PathVariable("ruleId") Long ruleId) + { + return success(ruleService.selectRuleByRuleId(ruleId)); + } + + /** + * 新增规则信息 + */ + @PreAuthorize("@ss.hasPermi('system:rule:add')") + @Log(title = "规则信息", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody Rule rule) + { + return toAjax(ruleService.insertRule(rule)); + } + + /** + * 修改规则信息 + */ + @PreAuthorize("@ss.hasPermi('system:rule:edit')") + @Log(title = "规则信息", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody Rule rule) + { + return toAjax(ruleService.updateRule(rule)); + } + + /** + * 删除规则信息 + */ + @PreAuthorize("@ss.hasPermi('system:rule:remove')") + @Log(title = "规则信息", businessType = BusinessType.DELETE) + @DeleteMapping("/{ruleIds}") + public AjaxResult remove(@PathVariable Long[] ruleIds) + { + return toAjax(ruleService.deleteRuleByRuleIds(ruleIds)); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/RuleSetController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/RuleSetController.java new file mode 100644 index 0000000000000000000000000000000000000000..6797e4b94bd8762af520ff189ee2f2e2f3977713 --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/RuleSetController.java @@ -0,0 +1,105 @@ +package com.RVSmartPorting.web.controller.system; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; + +import com.RVSmartPorting.common.annotation.Log; +import com.RVSmartPorting.common.core.controller.BaseController; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.page.TableDataInfo; +import com.RVSmartPorting.common.enums.BusinessType; +import com.RVSmartPorting.common.utils.poi.ExcelUtil; +import com.RVSmartPorting.core.system.domain.RuleSet; +import com.RVSmartPorting.core.system.service.IRuleSetService; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 规则集信息Controller + * + * @author ruoyi + * @date 2023-08-16 + */ +@RestController +@RequestMapping("/system/ruleSet") +public class RuleSetController extends BaseController +{ + @Autowired + private IRuleSetService ruleSetService; + + /** + * 查询规则集信息列表 + */ + @PreAuthorize("@ss.hasPermi('system:ruleSet:list')") + @GetMapping("/list") + public TableDataInfo list(RuleSet ruleSet) + { + startPage(); + List list = ruleSetService.selectRuleSetList(ruleSet); + return getDataTable(list); + } + + /** + * 导出规则集信息列表 + */ + @PreAuthorize("@ss.hasPermi('system:ruleSet:export')") + @Log(title = "规则集信息", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, RuleSet ruleSet) + { + List list = ruleSetService.selectRuleSetList(ruleSet); + ExcelUtil util = new ExcelUtil(RuleSet.class); + util.exportExcel(response, list, "规则集信息数据"); + } + + /** + * 获取规则集信息详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:ruleSet:query')") + @GetMapping(value = "/{ruleSetId}") + public AjaxResult getInfo(@PathVariable("ruleSetId") Long ruleSetId) + { + return success(ruleSetService.selectRuleSetByRuleSetId(ruleSetId)); + } + + /** + * 新增规则集信息 + */ + @PreAuthorize("@ss.hasPermi('system:ruleSet:add')") + @Log(title = "规则集信息", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody RuleSet ruleSet) + { + return toAjax(ruleSetService.insertRuleSet(ruleSet)); + } + + /** + * 修改规则集信息 + */ + @PreAuthorize("@ss.hasPermi('system:ruleSet:edit')") + @Log(title = "规则集信息", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody RuleSet ruleSet) + { + return toAjax(ruleSetService.updateRuleSet(ruleSet)); + } + + /** + * 删除规则集信息 + */ + @PreAuthorize("@ss.hasPermi('system:ruleSet:remove')") + @Log(title = "规则集信息", businessType = BusinessType.DELETE) + @DeleteMapping("/{ruleSetIds}") + public AjaxResult remove(@PathVariable Long[] ruleSetIds) + { + return toAjax(ruleSetService.deleteRuleSetByRuleSetIds(ruleSetIds)); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/ScanTaskController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/ScanTaskController.java new file mode 100644 index 0000000000000000000000000000000000000000..c676235dfc78b33c0aa6b4644e83b21558f56758 --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/ScanTaskController.java @@ -0,0 +1,104 @@ +package com.RVSmartPorting.web.controller.system; + +import com.RVSmartPorting.common.annotation.Log; +import com.RVSmartPorting.common.core.controller.BaseController; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.domain.model.LoginUser; +import com.RVSmartPorting.common.core.page.TableDataInfo; +import com.RVSmartPorting.common.enums.BusinessType; +import com.RVSmartPorting.common.utils.SecurityUtils; +import com.RVSmartPorting.common.utils.poi.ExcelUtil; +import com.RVSmartPorting.core.system.domain.ScanTask; +import com.RVSmartPorting.core.system.service.IScanTaskService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 代码扫描任务信息Controller + * + * @author ruoyi + * @date 2023-09-17 + */ +@RestController +@RequestMapping("/system/scanTask") +public class ScanTaskController extends BaseController +{ + @Autowired + private IScanTaskService scanTaskService; + + /** + * 查询代码扫描任务信息列表 + */ + @PreAuthorize("@ss.hasPermi('system:scanTask:list')") + @GetMapping("/list") + public TableDataInfo list(ScanTask scanTask) + { + final LoginUser loginUser = SecurityUtils.getLoginUser(); + scanTask.setUserId(loginUser.getUserId()); + startPage(); + List list = scanTaskService.selectScanTaskList(scanTask); + return getDataTable(list); + } + + /** + * 导出代码扫描任务信息列表 + */ + @PreAuthorize("@ss.hasPermi('system:scanTask:export')") + @Log(title = "代码扫描任务信息", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, ScanTask scanTask) + { + List list = scanTaskService.selectScanTaskList(scanTask); + ExcelUtil util = new ExcelUtil(ScanTask.class); + util.exportExcel(response, list, "代码扫描任务信息数据"); + } + + /** + * 获取代码扫描任务信息详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:scanTask:query')") + @GetMapping(value = "/{taskId}") + public AjaxResult getInfo(@PathVariable("taskId") Long taskId) + { + return success(scanTaskService.selectScanTaskByTaskId(taskId)); + } + + /** + * 新增代码扫描任务信息 + */ + @PreAuthorize("@ss.hasPermi('system:scanTask:add')") + @Log(title = "代码扫描任务信息", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody ScanTask scanTask) + { + final LoginUser loginUser = SecurityUtils.getLoginUser(); + scanTask.setUserId(loginUser.getUserId()); + return toAjax(scanTaskService.insertScanTask(scanTask)); + } + + /** + * 修改代码扫描任务信息 + */ + @PreAuthorize("@ss.hasPermi('system:scanTask:edit')") + @Log(title = "代码扫描任务信息", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody ScanTask scanTask) + { + return toAjax(scanTaskService.updateScanTask(scanTask)); + } + + /** + * 删除代码扫描任务信息 + */ + @PreAuthorize("@ss.hasPermi('system:scanTask:remove')") + @Log(title = "代码扫描任务信息", businessType = BusinessType.DELETE) + @DeleteMapping("/{taskIds}") + public AjaxResult remove(@PathVariable Long[] taskIds) + { + return toAjax(scanTaskService.deleteScanTaskByTaskIds(taskIds)); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/ScanToolConfigController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/ScanToolConfigController.java new file mode 100644 index 0000000000000000000000000000000000000000..aaa8d2f666fdd40136e6282b693e82650db437c0 --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/ScanToolConfigController.java @@ -0,0 +1,98 @@ +package com.RVSmartPorting.web.controller.system; + +import com.RVSmartPorting.common.annotation.Log; +import com.RVSmartPorting.common.core.controller.BaseController; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.page.TableDataInfo; +import com.RVSmartPorting.common.enums.BusinessType; +import com.RVSmartPorting.common.utils.poi.ExcelUtil; +import com.RVSmartPorting.core.system.domain.ScanToolConfig; +import com.RVSmartPorting.core.system.service.IScanToolConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 扫描工具配置Controller + * + * @author xuqiangli + * @date 2023-09-22 + */ +@RestController +@RequestMapping("/system/scanToolConfig") +public class ScanToolConfigController extends BaseController +{ + @Autowired + private IScanToolConfigService scanToolConfigService; + + /** + * 查询扫描工具配置列表 + */ + @PreAuthorize("@ss.hasPermi('system:scanToolConfig:list')") + @GetMapping("/list") + public TableDataInfo list(ScanToolConfig scanToolConfig) + { + startPage(); + List list = scanToolConfigService.selectScanToolConfigList(scanToolConfig); + return getDataTable(list); + } + + /** + * 导出扫描工具配置列表 + */ + @PreAuthorize("@ss.hasPermi('system:scanToolConfig:export')") + @Log(title = "扫描工具配置", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, ScanToolConfig scanToolConfig) + { + List list = scanToolConfigService.selectScanToolConfigList(scanToolConfig); + ExcelUtil util = new ExcelUtil(ScanToolConfig.class); + util.exportExcel(response, list, "扫描工具配置数据"); + } + + /** + * 获取扫描工具配置详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:scanToolConfig:query')") + @GetMapping(value = "/{scanToolConfigId}") + public AjaxResult getInfo(@PathVariable("scanToolConfigId") Long scanToolConfigId) + { + return success(scanToolConfigService.selectScanToolConfigByScanToolConfigId(scanToolConfigId)); + } + + /** + * 新增扫描工具配置 + */ + @PreAuthorize("@ss.hasPermi('system:scanToolConfig:add')") + @Log(title = "扫描工具配置", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody ScanToolConfig scanToolConfig) + { + return toAjax(scanToolConfigService.insertScanToolConfig(scanToolConfig)); + } + + /** + * 修改扫描工具配置 + */ + @PreAuthorize("@ss.hasPermi('system:scanToolConfig:edit')") + @Log(title = "扫描工具配置", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody ScanToolConfig scanToolConfig) + { + return toAjax(scanToolConfigService.updateScanToolConfig(scanToolConfig)); + } + + /** + * 删除扫描工具配置 + */ + @PreAuthorize("@ss.hasPermi('system:scanToolConfig:remove')") + @Log(title = "扫描工具配置", businessType = BusinessType.DELETE) + @DeleteMapping("/{scanToolConfigIds}") + public AjaxResult remove(@PathVariable Long[] scanToolConfigIds) + { + return toAjax(scanToolConfigService.deleteScanToolConfigByScanToolConfigIds(scanToolConfigIds)); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/ScanToolController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/ScanToolController.java new file mode 100644 index 0000000000000000000000000000000000000000..392167db091ba1e6956383bacfafbee0c9352061 --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/ScanToolController.java @@ -0,0 +1,98 @@ +package com.RVSmartPorting.web.controller.system; + +import com.RVSmartPorting.common.annotation.Log; +import com.RVSmartPorting.common.core.controller.BaseController; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.page.TableDataInfo; +import com.RVSmartPorting.common.enums.BusinessType; +import com.RVSmartPorting.common.utils.poi.ExcelUtil; +import com.RVSmartPorting.core.system.domain.ScanTool; +import com.RVSmartPorting.core.system.service.IScanToolService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 扫描工具Controller + * + * @author ruoyi + * @date 2023-09-17 + */ +@RestController +@RequestMapping("/system/scanTool") +public class ScanToolController extends BaseController +{ + @Autowired + private IScanToolService scanToolService; + + /** + * 查询扫描工具列表 + */ + @PreAuthorize("@ss.hasPermi('system:scanTool:list')") + @GetMapping("/list") + public TableDataInfo list(ScanTool scanTool) + { + startPage(); + List list = scanToolService.selectScanToolList(scanTool); + return getDataTable(list); + } + + /** + * 导出扫描工具列表 + */ + @PreAuthorize("@ss.hasPermi('system:scanTool:export')") + @Log(title = "扫描工具", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, ScanTool scanTool) + { + List list = scanToolService.selectScanToolList(scanTool); + ExcelUtil util = new ExcelUtil(ScanTool.class); + util.exportExcel(response, list, "扫描工具数据"); + } + + /** + * 获取扫描工具详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:scanTool:query')") + @GetMapping(value = "/{scanToolId}") + public AjaxResult getInfo(@PathVariable("scanToolId") Long scanToolId) + { + return success(scanToolService.selectScanToolByScanToolId(scanToolId)); + } + + /** + * 新增扫描工具 + */ + @PreAuthorize("@ss.hasPermi('system:scanTool:add')") + @Log(title = "扫描工具", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody ScanTool scanTool) + { + return toAjax(scanToolService.insertScanTool(scanTool)); + } + + /** + * 修改扫描工具 + */ + @PreAuthorize("@ss.hasPermi('system:scanTool:edit')") + @Log(title = "扫描工具", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody ScanTool scanTool) + { + return toAjax(scanToolService.updateScanTool(scanTool)); + } + + /** + * 删除扫描工具 + */ + @PreAuthorize("@ss.hasPermi('system:scanTool:remove')") + @Log(title = "扫描工具", businessType = BusinessType.DELETE) + @DeleteMapping("/{scanToolIds}") + public AjaxResult remove(@PathVariable Long[] scanToolIds) + { + return toAjax(scanToolService.deleteScanToolByScanToolIds(scanToolIds)); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SseController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SseController.java new file mode 100644 index 0000000000000000000000000000000000000000..367c5ae1a81d0fc0cc11a8b84ac87085be6cd35c --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SseController.java @@ -0,0 +1,34 @@ +package com.RVSmartPorting.web.controller.system; + +import com.RVSmartPorting.common.constant.Constants; +import com.RVSmartPorting.common.core.domain.entity.SysUser; +import com.RVSmartPorting.common.utils.SecurityUtils; +import com.RVSmartPorting.core.system.sse.SseServer; +import org.apache.commons.lang3.RandomUtils; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; + + +import javax.servlet.http.HttpServletResponse; + +@RestController +@RequestMapping("/sse") +public class SseController { + + /** + * 用户SSE连接 + * 它返回一个SseEmitter实例,这时候连接就已经创建了. + * + * @return + */ + @GetMapping(value = "/userConnect/http/{userUUID}", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public SseEmitter httpSseConnect(@PathVariable("userUUID") String userUUID) { + return SseServer.createConnect(Constants.HTTP_MESSAGE_ID_PREFIX + userUUID); + } + + @GetMapping(value = "/userConnect/git/{userUUID}", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public SseEmitter gitSseConnect(@PathVariable("userUUID") String userUUID) { + return SseServer.createConnect(Constants.GIT_MESSAGE_ID_PREFIX + userUUID); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysConfigController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysConfigController.java new file mode 100644 index 0000000000000000000000000000000000000000..32ad64a24b6fd6766958134234354cf16ccfde76 --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysConfigController.java @@ -0,0 +1,127 @@ +package com.RVSmartPorting.web.controller.system; + +import com.RVSmartPorting.common.annotation.Log; +import com.RVSmartPorting.common.core.controller.BaseController; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.page.TableDataInfo; +import com.RVSmartPorting.common.enums.BusinessType; +import com.RVSmartPorting.common.utils.poi.ExcelUtil; +import com.RVSmartPorting.core.system.domain.SysConfig; +import com.RVSmartPorting.core.system.service.ISysConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 参数配置 信息操作处理 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/system/config") +public class SysConfigController extends BaseController +{ + @Autowired + private ISysConfigService configService; + + /** + * 获取参数配置列表 + */ + @PreAuthorize("@ss.hasPermi('system:config:list')") + @GetMapping("/list") + public TableDataInfo list(SysConfig config) + { + startPage(); + List list = configService.selectConfigList(config); + return getDataTable(list); + } + + @Log(title = "参数管理", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('system:config:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysConfig config) + { + List list = configService.selectConfigList(config); + ExcelUtil util = new ExcelUtil(SysConfig.class); + util.exportExcel(response, list, "参数数据"); + } + + /** + * 根据参数编号获取详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:config:query')") + @GetMapping(value = "/{configId}") + public AjaxResult getInfo(@PathVariable Long configId) + { + return success(configService.selectConfigById(configId)); + } + + /** + * 根据参数键名查询参数值 + */ + @GetMapping(value = "/configKey/{configKey}") + public AjaxResult getConfigKey(@PathVariable String configKey) + { + return success(configService.selectConfigByKey(configKey)); + } + + /** + * 新增参数配置 + */ + @PreAuthorize("@ss.hasPermi('system:config:add')") + @Log(title = "参数管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysConfig config) + { + if (!configService.checkConfigKeyUnique(config)) + { + return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在"); + } + config.setCreateBy(getUsername()); + return toAjax(configService.insertConfig(config)); + } + + /** + * 修改参数配置 + */ + @PreAuthorize("@ss.hasPermi('system:config:edit')") + @Log(title = "参数管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysConfig config) + { + if (!configService.checkConfigKeyUnique(config)) + { + return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在"); + } + config.setUpdateBy(getUsername()); + return toAjax(configService.updateConfig(config)); + } + + /** + * 删除参数配置 + */ + @PreAuthorize("@ss.hasPermi('system:config:remove')") + @Log(title = "参数管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{configIds}") + public AjaxResult remove(@PathVariable Long[] configIds) + { + configService.deleteConfigByIds(configIds); + return success(); + } + + /** + * 刷新参数缓存 + */ + @PreAuthorize("@ss.hasPermi('system:config:remove')") + @Log(title = "参数管理", businessType = BusinessType.CLEAN) + @DeleteMapping("/refreshCache") + public AjaxResult refreshCache() + { + configService.resetConfigCache(); + return success(); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysDeptController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysDeptController.java new file mode 100644 index 0000000000000000000000000000000000000000..70c0ee9d7dcd30db88a84f6e0ffc9ba3b6c8c28b --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysDeptController.java @@ -0,0 +1,126 @@ +package com.RVSmartPorting.web.controller.system; + +import com.RVSmartPorting.common.annotation.Log; +import com.RVSmartPorting.common.constant.UserConstants; +import com.RVSmartPorting.common.core.controller.BaseController; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.domain.entity.SysDept; +import com.RVSmartPorting.common.enums.BusinessType; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.core.system.service.ISysDeptService; +import org.apache.commons.lang3.ArrayUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 部门信息 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/system/dept") +public class SysDeptController extends BaseController +{ + @Autowired + private ISysDeptService deptService; + + /** + * 获取部门列表 + */ + @PreAuthorize("@ss.hasPermi('system:dept:list')") + @GetMapping("/list") + public AjaxResult list(SysDept dept) + { + List depts = deptService.selectDeptList(dept); + return success(depts); + } + + /** + * 查询部门列表(排除节点) + */ + @PreAuthorize("@ss.hasPermi('system:dept:list')") + @GetMapping("/list/exclude/{deptId}") + public AjaxResult excludeChild(@PathVariable(value = "deptId", required = false) Long deptId) + { + List depts = deptService.selectDeptList(new SysDept()); + depts.removeIf(d -> d.getDeptId().intValue() == deptId || ArrayUtils.contains(StringUtils.split(d.getAncestors(), ","), deptId + "")); + return success(depts); + } + + /** + * 根据部门编号获取详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:dept:query')") + @GetMapping(value = "/{deptId}") + public AjaxResult getInfo(@PathVariable Long deptId) + { + deptService.checkDeptDataScope(deptId); + return success(deptService.selectDeptById(deptId)); + } + + /** + * 新增部门 + */ + @PreAuthorize("@ss.hasPermi('system:dept:add')") + @Log(title = "部门管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysDept dept) + { + if (!deptService.checkDeptNameUnique(dept)) + { + return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在"); + } + dept.setCreateBy(getUsername()); + return toAjax(deptService.insertDept(dept)); + } + + /** + * 修改部门 + */ + @PreAuthorize("@ss.hasPermi('system:dept:edit')") + @Log(title = "部门管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysDept dept) + { + Long deptId = dept.getDeptId(); + deptService.checkDeptDataScope(deptId); + if (!deptService.checkDeptNameUnique(dept)) + { + return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在"); + } + else if (dept.getParentId().equals(deptId)) + { + return error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己"); + } + else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0) + { + return error("该部门包含未停用的子部门!"); + } + dept.setUpdateBy(getUsername()); + return toAjax(deptService.updateDept(dept)); + } + + /** + * 删除部门 + */ + @PreAuthorize("@ss.hasPermi('system:dept:remove')") + @Log(title = "部门管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{deptId}") + public AjaxResult remove(@PathVariable Long deptId) + { + if (deptService.hasChildByDeptId(deptId)) + { + return warn("存在下级部门,不允许删除"); + } + if (deptService.checkDeptExistUser(deptId)) + { + return warn("部门存在用户,不允许删除"); + } + deptService.checkDeptDataScope(deptId); + return toAjax(deptService.deleteDeptById(deptId)); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysDictDataController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysDictDataController.java new file mode 100644 index 0000000000000000000000000000000000000000..703f4475e65c32395d6c94c56d8c1ea89ec2e618 --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysDictDataController.java @@ -0,0 +1,115 @@ +package com.RVSmartPorting.web.controller.system; + +import com.RVSmartPorting.common.annotation.Log; +import com.RVSmartPorting.common.core.controller.BaseController; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.domain.entity.SysDictData; +import com.RVSmartPorting.common.core.page.TableDataInfo; +import com.RVSmartPorting.common.enums.BusinessType; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.poi.ExcelUtil; +import com.RVSmartPorting.core.system.service.ISysDictDataService; +import com.RVSmartPorting.core.system.service.ISysDictTypeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.List; + +/** + * 数据字典信息 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/system/dict/data") +public class SysDictDataController extends BaseController +{ + @Autowired + private ISysDictDataService dictDataService; + + @Autowired + private ISysDictTypeService dictTypeService; + + @PreAuthorize("@ss.hasPermi('system:dict:list')") + @GetMapping("/list") + public TableDataInfo list(SysDictData dictData) + { + startPage(); + List list = dictDataService.selectDictDataList(dictData); + return getDataTable(list); + } + + @Log(title = "字典数据", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('system:dict:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysDictData dictData) + { + List list = dictDataService.selectDictDataList(dictData); + ExcelUtil util = new ExcelUtil(SysDictData.class); + util.exportExcel(response, list, "字典数据"); + } + + /** + * 查询字典数据详细 + */ + @PreAuthorize("@ss.hasPermi('system:dict:query')") + @GetMapping(value = "/{dictCode}") + public AjaxResult getInfo(@PathVariable Long dictCode) + { + return success(dictDataService.selectDictDataById(dictCode)); + } + + /** + * 根据字典类型查询字典数据信息 + */ + @GetMapping(value = "/type/{dictType}") + public AjaxResult dictType(@PathVariable String dictType) + { + List data = dictTypeService.selectDictDataByType(dictType); + if (StringUtils.isNull(data)) + { + data = new ArrayList(); + } + return success(data); + } + + /** + * 新增字典类型 + */ + @PreAuthorize("@ss.hasPermi('system:dict:add')") + @Log(title = "字典数据", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysDictData dict) + { + dict.setCreateBy(getUsername()); + return toAjax(dictDataService.insertDictData(dict)); + } + + /** + * 修改保存字典类型 + */ + @PreAuthorize("@ss.hasPermi('system:dict:edit')") + @Log(title = "字典数据", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysDictData dict) + { + dict.setUpdateBy(getUsername()); + return toAjax(dictDataService.updateDictData(dict)); + } + + /** + * 删除字典类型 + */ + @PreAuthorize("@ss.hasPermi('system:dict:remove')") + @Log(title = "字典类型", businessType = BusinessType.DELETE) + @DeleteMapping("/{dictCodes}") + public AjaxResult remove(@PathVariable Long[] dictCodes) + { + dictDataService.deleteDictDataByIds(dictCodes); + return success(); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysDictTypeController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysDictTypeController.java new file mode 100644 index 0000000000000000000000000000000000000000..c5acd7b5c65bf1a536d063fe926d4507be658932 --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysDictTypeController.java @@ -0,0 +1,125 @@ +package com.RVSmartPorting.web.controller.system; + +import com.RVSmartPorting.common.annotation.Log; +import com.RVSmartPorting.common.core.controller.BaseController; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.domain.entity.SysDictType; +import com.RVSmartPorting.common.core.page.TableDataInfo; +import com.RVSmartPorting.common.enums.BusinessType; +import com.RVSmartPorting.common.utils.poi.ExcelUtil; +import com.RVSmartPorting.core.system.service.ISysDictTypeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 数据字典信息 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/system/dict/type") +public class SysDictTypeController extends BaseController +{ + @Autowired + private ISysDictTypeService dictTypeService; + + @PreAuthorize("@ss.hasPermi('system:dict:list')") + @GetMapping("/list") + public TableDataInfo list(SysDictType dictType) + { + startPage(); + List list = dictTypeService.selectDictTypeList(dictType); + return getDataTable(list); + } + + @Log(title = "字典类型", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('system:dict:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysDictType dictType) + { + List list = dictTypeService.selectDictTypeList(dictType); + ExcelUtil util = new ExcelUtil(SysDictType.class); + util.exportExcel(response, list, "字典类型"); + } + + /** + * 查询字典类型详细 + */ + @PreAuthorize("@ss.hasPermi('system:dict:query')") + @GetMapping(value = "/{dictId}") + public AjaxResult getInfo(@PathVariable Long dictId) + { + return success(dictTypeService.selectDictTypeById(dictId)); + } + + /** + * 新增字典类型 + */ + @PreAuthorize("@ss.hasPermi('system:dict:add')") + @Log(title = "字典类型", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysDictType dict) + { + if (!dictTypeService.checkDictTypeUnique(dict)) + { + return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在"); + } + dict.setCreateBy(getUsername()); + return toAjax(dictTypeService.insertDictType(dict)); + } + + /** + * 修改字典类型 + */ + @PreAuthorize("@ss.hasPermi('system:dict:edit')") + @Log(title = "字典类型", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysDictType dict) + { + if (!dictTypeService.checkDictTypeUnique(dict)) + { + return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在"); + } + dict.setUpdateBy(getUsername()); + return toAjax(dictTypeService.updateDictType(dict)); + } + + /** + * 删除字典类型 + */ + @PreAuthorize("@ss.hasPermi('system:dict:remove')") + @Log(title = "字典类型", businessType = BusinessType.DELETE) + @DeleteMapping("/{dictIds}") + public AjaxResult remove(@PathVariable Long[] dictIds) + { + dictTypeService.deleteDictTypeByIds(dictIds); + return success(); + } + + /** + * 刷新字典缓存 + */ + @PreAuthorize("@ss.hasPermi('system:dict:remove')") + @Log(title = "字典类型", businessType = BusinessType.CLEAN) + @DeleteMapping("/refreshCache") + public AjaxResult refreshCache() + { + dictTypeService.resetDictCache(); + return success(); + } + + /** + * 获取字典选择框列表 + */ + @GetMapping("/optionselect") + public AjaxResult optionselect() + { + List dictTypes = dictTypeService.selectDictTypeAll(); + return success(dictTypes); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysIndexController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysIndexController.java new file mode 100644 index 0000000000000000000000000000000000000000..0d68b1d125d1d5f58f74a06c830f03a63fd3352e --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysIndexController.java @@ -0,0 +1,29 @@ +package com.RVSmartPorting.web.controller.system; + +import com.RVSmartPorting.common.config.CSPConfig; +import com.RVSmartPorting.common.utils.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 首页 + * + * @author ruoyi + */ +@RestController +public class SysIndexController +{ + /** 系统基础配置 */ + @Autowired + private CSPConfig CSPConfig; + + /** + * 访问首页,提示语 + */ + @RequestMapping("/") + public String index() + { + return StringUtils.format("欢迎使用{}后台管理框架,当前版本:v{},请通过前端地址访问。", CSPConfig.getName(), CSPConfig.getVersion()); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysLoginController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysLoginController.java new file mode 100644 index 0000000000000000000000000000000000000000..189f34ad6920e2257e4bbd68d8b91e7eef90e522 --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysLoginController.java @@ -0,0 +1,87 @@ +package com.RVSmartPorting.web.controller.system; + +import com.RVSmartPorting.common.constant.Constants; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.domain.entity.SysMenu; +import com.RVSmartPorting.common.core.domain.entity.SysUser; +import com.RVSmartPorting.common.core.domain.model.LoginBody; +import com.RVSmartPorting.common.utils.SecurityUtils; +import com.RVSmartPorting.core.system.service.ISysMenuService; +import com.RVSmartPorting.core.web.service.SysLoginService; +import com.RVSmartPorting.core.web.service.SysPermissionService; +import org.springframework.beans.factory.annotation.Autowired; +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; +import java.util.Set; + +/** + * 登录验证 + * + * @author ruoyi + */ +@RestController +public class SysLoginController +{ + @Autowired + private SysLoginService loginService; + + @Autowired + private ISysMenuService menuService; + + @Autowired + private SysPermissionService permissionService; + + /** + * 登录方法 + * + * @param loginBody 登录信息 + * @return 结果 + */ + @PostMapping("/login") + public AjaxResult login(@RequestBody LoginBody loginBody) + { + AjaxResult ajax = AjaxResult.success(); + // 生成令牌 + String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(), + loginBody.getUuid()); + ajax.put(Constants.TOKEN, token); + return ajax; + } + + /** + * 获取用户信息 + * + * @return 用户信息 + */ + @GetMapping("getInfo") + public AjaxResult getInfo() + { + SysUser user = SecurityUtils.getLoginUser().getUser(); + // 角色集合 + Set roles = permissionService.getRolePermission(user); + // 权限集合 + Set permissions = permissionService.getMenuPermission(user); + AjaxResult ajax = AjaxResult.success(); + ajax.put("user", user); + ajax.put("roles", roles); + ajax.put("permissions", permissions); + return ajax; + } + + /** + * 获取路由信息 + * + * @return 路由信息 + */ + @GetMapping("getRouters") + public AjaxResult getRouters() + { + Long userId = SecurityUtils.getUserId(); + List menus = menuService.selectMenuTreeByUserId(userId); + return AjaxResult.success(menuService.buildMenus(menus)); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysMenuController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysMenuController.java new file mode 100644 index 0000000000000000000000000000000000000000..8a147653de28eecf1446e3db00b72a387cc6e60a --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysMenuController.java @@ -0,0 +1,136 @@ +package com.RVSmartPorting.web.controller.system; + +import com.RVSmartPorting.common.annotation.Log; +import com.RVSmartPorting.common.constant.UserConstants; +import com.RVSmartPorting.common.core.controller.BaseController; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.domain.entity.SysMenu; +import com.RVSmartPorting.common.enums.BusinessType; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.core.system.service.ISysMenuService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 菜单信息 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/system/menu") +public class SysMenuController extends BaseController +{ + @Autowired + private ISysMenuService menuService; + + /** + * 获取菜单列表 + */ + @PreAuthorize("@ss.hasPermi('system:menu:list')") + @GetMapping("/list") + public AjaxResult list(SysMenu menu) + { + List menus = menuService.selectMenuList(menu, getUserId()); + return success(menus); + } + + /** + * 根据菜单编号获取详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:menu:query')") + @GetMapping(value = "/{menuId}") + public AjaxResult getInfo(@PathVariable Long menuId) + { + return success(menuService.selectMenuById(menuId)); + } + + /** + * 获取菜单下拉树列表 + */ + @GetMapping("/treeselect") + public AjaxResult treeselect(SysMenu menu) + { + List menus = menuService.selectMenuList(menu, getUserId()); + return success(menuService.buildMenuTreeSelect(menus)); + } + + /** + * 加载对应角色菜单列表树 + */ + @GetMapping(value = "/roleMenuTreeselect/{roleId}") + public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId) + { + List menus = menuService.selectMenuList(getUserId()); + AjaxResult ajax = AjaxResult.success(); + ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId)); + ajax.put("menus", menuService.buildMenuTreeSelect(menus)); + return ajax; + } + + /** + * 新增菜单 + */ + @PreAuthorize("@ss.hasPermi('system:menu:add')") + @Log(title = "菜单管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysMenu menu) + { + if (!menuService.checkMenuNameUnique(menu)) + { + return error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); + } + else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) + { + return error("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); + } + menu.setCreateBy(getUsername()); + return toAjax(menuService.insertMenu(menu)); + } + + /** + * 修改菜单 + */ + @PreAuthorize("@ss.hasPermi('system:menu:edit')") + @Log(title = "菜单管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysMenu menu) + { + if (!menuService.checkMenuNameUnique(menu)) + { + return error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); + } + else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) + { + return error("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); + } + else if (menu.getMenuId().equals(menu.getParentId())) + { + return error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己"); + } + menu.setUpdateBy(getUsername()); + return toAjax(menuService.updateMenu(menu)); + } + + /** + * 删除菜单 + */ + @PreAuthorize("@ss.hasPermi('system:menu:remove')") + @Log(title = "菜单管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{menuId}") + public AjaxResult remove(@PathVariable("menuId") Long menuId) + { + if (menuService.hasChildByMenuId(menuId)) + { + return warn("存在子菜单,不允许删除"); + } + if (menuService.checkMenuExistRole(menuId)) + { + return warn("菜单已分配,不允许删除"); + } + return toAjax(menuService.deleteMenuById(menuId)); + } +} \ No newline at end of file diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysNoticeController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysNoticeController.java new file mode 100644 index 0000000000000000000000000000000000000000..bcde8e215fbb45d52fb1883e442bbc59c2e3823e --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysNoticeController.java @@ -0,0 +1,85 @@ +package com.RVSmartPorting.web.controller.system; + +import com.RVSmartPorting.common.annotation.Log; +import com.RVSmartPorting.common.core.controller.BaseController; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.page.TableDataInfo; +import com.RVSmartPorting.common.enums.BusinessType; +import com.RVSmartPorting.core.system.domain.SysNotice; +import com.RVSmartPorting.core.system.service.ISysNoticeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 公告 信息操作处理 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/system/notice") +public class SysNoticeController extends BaseController +{ + @Autowired + private ISysNoticeService noticeService; + + /** + * 获取通知公告列表 + */ + @PreAuthorize("@ss.hasPermi('system:notice:list')") + @GetMapping("/list") + public TableDataInfo list(SysNotice notice) + { + startPage(); + List list = noticeService.selectNoticeList(notice); + return getDataTable(list); + } + + /** + * 根据通知公告编号获取详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:notice:query')") + @GetMapping(value = "/{noticeId}") + public AjaxResult getInfo(@PathVariable Long noticeId) + { + return success(noticeService.selectNoticeById(noticeId)); + } + + /** + * 新增通知公告 + */ + @PreAuthorize("@ss.hasPermi('system:notice:add')") + @Log(title = "通知公告", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysNotice notice) + { + notice.setCreateBy(getUsername()); + return toAjax(noticeService.insertNotice(notice)); + } + + /** + * 修改通知公告 + */ + @PreAuthorize("@ss.hasPermi('system:notice:edit')") + @Log(title = "通知公告", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysNotice notice) + { + notice.setUpdateBy(getUsername()); + return toAjax(noticeService.updateNotice(notice)); + } + + /** + * 删除通知公告 + */ + @PreAuthorize("@ss.hasPermi('system:notice:remove')") + @Log(title = "通知公告", businessType = BusinessType.DELETE) + @DeleteMapping("/{noticeIds}") + public AjaxResult remove(@PathVariable Long[] noticeIds) + { + return toAjax(noticeService.deleteNoticeByIds(noticeIds)); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysPostController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysPostController.java new file mode 100644 index 0000000000000000000000000000000000000000..3934b5b202f214837d338b990387ca39c8bee5b1 --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysPostController.java @@ -0,0 +1,123 @@ +package com.RVSmartPorting.web.controller.system; + +import com.RVSmartPorting.common.annotation.Log; +import com.RVSmartPorting.common.core.controller.BaseController; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.page.TableDataInfo; +import com.RVSmartPorting.common.enums.BusinessType; +import com.RVSmartPorting.common.utils.poi.ExcelUtil; +import com.RVSmartPorting.core.system.domain.SysPost; +import com.RVSmartPorting.core.system.service.ISysPostService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 岗位信息操作处理 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/system/post") +public class SysPostController extends BaseController +{ + @Autowired + private ISysPostService postService; + + /** + * 获取岗位列表 + */ + @PreAuthorize("@ss.hasPermi('system:post:list')") + @GetMapping("/list") + public TableDataInfo list(SysPost post) + { + startPage(); + List list = postService.selectPostList(post); + return getDataTable(list); + } + + @Log(title = "岗位管理", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('system:post:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysPost post) + { + List list = postService.selectPostList(post); + ExcelUtil util = new ExcelUtil(SysPost.class); + util.exportExcel(response, list, "岗位数据"); + } + + /** + * 根据岗位编号获取详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:post:query')") + @GetMapping(value = "/{postId}") + public AjaxResult getInfo(@PathVariable Long postId) + { + return success(postService.selectPostById(postId)); + } + + /** + * 新增岗位 + */ + @PreAuthorize("@ss.hasPermi('system:post:add')") + @Log(title = "岗位管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysPost post) + { + if (!postService.checkPostNameUnique(post)) + { + return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在"); + } + else if (!postService.checkPostCodeUnique(post)) + { + return error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在"); + } + post.setCreateBy(getUsername()); + return toAjax(postService.insertPost(post)); + } + + /** + * 修改岗位 + */ + @PreAuthorize("@ss.hasPermi('system:post:edit')") + @Log(title = "岗位管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysPost post) + { + if (!postService.checkPostNameUnique(post)) + { + return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在"); + } + else if (!postService.checkPostCodeUnique(post)) + { + return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在"); + } + post.setUpdateBy(getUsername()); + return toAjax(postService.updatePost(post)); + } + + /** + * 删除岗位 + */ + @PreAuthorize("@ss.hasPermi('system:post:remove')") + @Log(title = "岗位管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{postIds}") + public AjaxResult remove(@PathVariable Long[] postIds) + { + return toAjax(postService.deletePostByIds(postIds)); + } + + /** + * 获取岗位选择框列表 + */ + @GetMapping("/optionselect") + public AjaxResult optionselect() + { + List posts = postService.selectPostAll(); + return success(posts); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysProfileController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysProfileController.java new file mode 100644 index 0000000000000000000000000000000000000000..966ce84a0778638cbdc2d48118d86c5d25bba1b6 --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysProfileController.java @@ -0,0 +1,135 @@ +package com.RVSmartPorting.web.controller.system; + +import com.RVSmartPorting.common.annotation.Log; +import com.RVSmartPorting.common.config.CSPConfig; +import com.RVSmartPorting.common.core.controller.BaseController; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.domain.entity.SysUser; +import com.RVSmartPorting.common.core.domain.model.LoginUser; +import com.RVSmartPorting.common.enums.BusinessType; +import com.RVSmartPorting.common.utils.SecurityUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.file.FileUploadUtils; +import com.RVSmartPorting.common.utils.file.MimeTypeUtils; +import com.RVSmartPorting.core.system.service.ISysUserService; +import com.RVSmartPorting.core.web.service.TokenService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +/** + * 个人信息 业务处理 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/system/user/profile") +public class SysProfileController extends BaseController +{ + @Autowired + private ISysUserService userService; + + @Autowired + private TokenService tokenService; + + /** + * 个人信息 + */ + @GetMapping + public AjaxResult profile() + { + LoginUser loginUser = getLoginUser(); + SysUser user = loginUser.getUser(); + AjaxResult ajax = AjaxResult.success(user); + ajax.put("roleGroup", userService.selectUserRoleGroup(loginUser.getUsername())); + ajax.put("postGroup", userService.selectUserPostGroup(loginUser.getUsername())); + return ajax; + } + + /** + * 修改用户 + */ + @Log(title = "个人信息", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult updateProfile(@RequestBody SysUser user) + { + LoginUser loginUser = getLoginUser(); + SysUser sysUser = loginUser.getUser(); + user.setUserName(sysUser.getUserName()); + if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) + { + return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); + } + if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) + { + return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); + } + user.setUserId(sysUser.getUserId()); + user.setPassword(null); + user.setAvatar(null); + user.setDeptId(null); + if (userService.updateUserProfile(user) > 0) + { + // 更新缓存用户信息 + sysUser.setNickName(user.getNickName()); + sysUser.setPhonenumber(user.getPhonenumber()); + sysUser.setEmail(user.getEmail()); + sysUser.setSex(user.getSex()); + tokenService.setLoginUser(loginUser); + return success(); + } + return error("修改个人信息异常,请联系管理员"); + } + + /** + * 重置密码 + */ + @Log(title = "个人信息", businessType = BusinessType.UPDATE) + @PutMapping("/updatePwd") + public AjaxResult updatePwd(String oldPassword, String newPassword) + { + LoginUser loginUser = getLoginUser(); + String userName = loginUser.getUsername(); + String password = loginUser.getPassword(); + if (!SecurityUtils.matchesPassword(oldPassword, password)) + { + return error("修改密码失败,旧密码错误"); + } + if (SecurityUtils.matchesPassword(newPassword, password)) + { + return error("新密码不能与旧密码相同"); + } + if (userService.resetUserPwd(userName, SecurityUtils.encryptPassword(newPassword)) > 0) + { + // 更新缓存用户密码 + loginUser.getUser().setPassword(SecurityUtils.encryptPassword(newPassword)); + tokenService.setLoginUser(loginUser); + return success(); + } + return error("修改密码异常,请联系管理员"); + } + + /** + * 头像上传 + */ + @Log(title = "用户头像", businessType = BusinessType.UPDATE) + @PostMapping("/avatar") + public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws Exception + { + if (!file.isEmpty()) + { + LoginUser loginUser = getLoginUser(); + String avatar = FileUploadUtils.upload(CSPConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION); + if (userService.updateUserAvatar(loginUser.getUsername(), avatar)) + { + AjaxResult ajax = AjaxResult.success(); + ajax.put("imgUrl", avatar); + // 更新缓存用户头像 + loginUser.getUser().setAvatar(avatar); + tokenService.setLoginUser(loginUser); + return ajax; + } + } + return error("上传图片异常,请联系管理员"); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysRegisterController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysRegisterController.java new file mode 100644 index 0000000000000000000000000000000000000000..969c85c8dce5e29263808384913badebf250b501 --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysRegisterController.java @@ -0,0 +1,38 @@ +package com.RVSmartPorting.web.controller.system; + +import com.RVSmartPorting.common.core.controller.BaseController; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.domain.model.RegisterBody; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.core.system.service.ISysConfigService; +import com.RVSmartPorting.core.web.service.SysRegisterService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +/** + * 注册验证 + * + * @author ruoyi + */ +@RestController +public class SysRegisterController extends BaseController +{ + @Autowired + private SysRegisterService registerService; + + @Autowired + private ISysConfigService configService; + + @PostMapping("/register") + public AjaxResult register(@RequestBody RegisterBody user) + { + if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) + { + return error("当前系统没有开启注册功能!"); + } + String msg = registerService.register(user); + return StringUtils.isEmpty(msg) ? success() : error(msg); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysRoleController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysRoleController.java new file mode 100644 index 0000000000000000000000000000000000000000..d635ac837c01864a33192f1773057ae1c60d7f61 --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysRoleController.java @@ -0,0 +1,257 @@ +package com.RVSmartPorting.web.controller.system; + +import com.RVSmartPorting.common.annotation.Log; +import com.RVSmartPorting.common.core.controller.BaseController; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.domain.entity.SysDept; +import com.RVSmartPorting.common.core.domain.entity.SysRole; +import com.RVSmartPorting.common.core.domain.entity.SysUser; +import com.RVSmartPorting.common.core.domain.model.LoginUser; +import com.RVSmartPorting.common.core.page.TableDataInfo; +import com.RVSmartPorting.common.enums.BusinessType; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.poi.ExcelUtil; +import com.RVSmartPorting.core.system.domain.SysUserRole; +import com.RVSmartPorting.core.system.service.ISysDeptService; +import com.RVSmartPorting.core.system.service.ISysRoleService; + +import com.RVSmartPorting.core.system.service.ISysUserService; +import com.RVSmartPorting.core.web.service.SysPermissionService; +import com.RVSmartPorting.core.web.service.TokenService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 角色信息 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/system/role") +public class SysRoleController extends BaseController +{ + @Autowired + private ISysRoleService roleService; + + @Autowired + private TokenService tokenService; + + @Autowired + private SysPermissionService permissionService; + + @Autowired + private ISysUserService userService; + + @Autowired + private ISysDeptService deptService; + + @PreAuthorize("@ss.hasPermi('system:role:list')") + @GetMapping("/list") + public TableDataInfo list(SysRole role) + { + startPage(); + List list = roleService.selectRoleList(role); + return getDataTable(list); + } + + @Log(title = "角色管理", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('system:role:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysRole role) + { + List list = roleService.selectRoleList(role); + ExcelUtil util = new ExcelUtil(SysRole.class); + util.exportExcel(response, list, "角色数据"); + } + + /** + * 根据角色编号获取详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:role:query')") + @GetMapping(value = "/{roleId}") + public AjaxResult getInfo(@PathVariable Long roleId) + { + roleService.checkRoleDataScope(roleId); + return success(roleService.selectRoleById(roleId)); + } + + /** + * 新增角色 + */ + @PreAuthorize("@ss.hasPermi('system:role:add')") + @Log(title = "角色管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysRole role) + { + if (!roleService.checkRoleNameUnique(role)) + { + return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在"); + } + else if (!roleService.checkRoleKeyUnique(role)) + { + return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在"); + } + role.setCreateBy(getUsername()); + return toAjax(roleService.insertRole(role)); + + } + + /** + * 修改保存角色 + */ + @PreAuthorize("@ss.hasPermi('system:role:edit')") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysRole role) + { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + if (!roleService.checkRoleNameUnique(role)) + { + return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在"); + } + else if (!roleService.checkRoleKeyUnique(role)) + { + return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在"); + } + role.setUpdateBy(getUsername()); + + if (roleService.updateRole(role) > 0) + { + // 更新缓存用户权限 + LoginUser loginUser = getLoginUser(); + if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin()) + { + loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser())); + loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName())); + tokenService.setLoginUser(loginUser); + } + return success(); + } + return error("修改角色'" + role.getRoleName() + "'失败,请联系管理员"); + } + + /** + * 修改保存数据权限 + */ + @PreAuthorize("@ss.hasPermi('system:role:edit')") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @PutMapping("/dataScope") + public AjaxResult dataScope(@RequestBody SysRole role) + { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + return toAjax(roleService.authDataScope(role)); + } + + /** + * 状态修改 + */ + @PreAuthorize("@ss.hasPermi('system:role:edit')") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody SysRole role) + { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + role.setUpdateBy(getUsername()); + return toAjax(roleService.updateRoleStatus(role)); + } + + /** + * 删除角色 + */ + @PreAuthorize("@ss.hasPermi('system:role:remove')") + @Log(title = "角色管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{roleIds}") + public AjaxResult remove(@PathVariable Long[] roleIds) + { + return toAjax(roleService.deleteRoleByIds(roleIds)); + } + + /** + * 获取角色选择框列表 + */ + @PreAuthorize("@ss.hasPermi('system:role:query')") + @GetMapping("/optionselect") + public AjaxResult optionselect() + { + return success(roleService.selectRoleAll()); + } + + /** + * 查询已分配用户角色列表 + */ + @PreAuthorize("@ss.hasPermi('system:role:list')") + @GetMapping("/authUser/allocatedList") + public TableDataInfo allocatedList(SysUser user) + { + startPage(); + List list = userService.selectAllocatedList(user); + return getDataTable(list); + } + + /** + * 查询未分配用户角色列表 + */ + @PreAuthorize("@ss.hasPermi('system:role:list')") + @GetMapping("/authUser/unallocatedList") + public TableDataInfo unallocatedList(SysUser user) + { + startPage(); + List list = userService.selectUnallocatedList(user); + return getDataTable(list); + } + + /** + * 取消授权用户 + */ + @PreAuthorize("@ss.hasPermi('system:role:edit')") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @PutMapping("/authUser/cancel") + public AjaxResult cancelAuthUser(@RequestBody SysUserRole userRole) + { + return toAjax(roleService.deleteAuthUser(userRole)); + } + + /** + * 批量取消授权用户 + */ + @PreAuthorize("@ss.hasPermi('system:role:edit')") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @PutMapping("/authUser/cancelAll") + public AjaxResult cancelAuthUserAll(Long roleId, Long[] userIds) + { + return toAjax(roleService.deleteAuthUsers(roleId, userIds)); + } + + /** + * 批量选择用户授权 + */ + @PreAuthorize("@ss.hasPermi('system:role:edit')") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @PutMapping("/authUser/selectAll") + public AjaxResult selectAuthUserAll(Long roleId, Long[] userIds) + { + roleService.checkRoleDataScope(roleId); + return toAjax(roleService.insertAuthUsers(roleId, userIds)); + } + + /** + * 获取对应角色部门树列表 + */ + @PreAuthorize("@ss.hasPermi('system:role:query')") + @GetMapping(value = "/deptTree/{roleId}") + public AjaxResult deptTree(@PathVariable("roleId") Long roleId) + { + AjaxResult ajax = AjaxResult.success(); + ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId)); + ajax.put("depts", deptService.selectDeptTreeList(new SysDept())); + return ajax; + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysUserController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysUserController.java new file mode 100644 index 0000000000000000000000000000000000000000..38ee166e859aee1fa363adc56188ad875ac09561 --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/system/SysUserController.java @@ -0,0 +1,247 @@ +package com.RVSmartPorting.web.controller.system; + +import com.RVSmartPorting.common.annotation.Log; +import com.RVSmartPorting.common.core.controller.BaseController; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.domain.entity.SysDept; +import com.RVSmartPorting.common.core.domain.entity.SysRole; +import com.RVSmartPorting.common.core.domain.entity.SysUser; +import com.RVSmartPorting.common.core.page.TableDataInfo; +import com.RVSmartPorting.common.enums.BusinessType; +import com.RVSmartPorting.common.utils.SecurityUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.poi.ExcelUtil; +import com.RVSmartPorting.common.utils.uuid.IdUtils; +import com.RVSmartPorting.core.system.service.ISysDeptService; +import com.RVSmartPorting.core.system.service.ISysPostService; +import com.RVSmartPorting.core.system.service.ISysRoleService; +import com.RVSmartPorting.core.system.service.ISysUserService; +import org.apache.commons.lang3.ArrayUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +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.List; +import java.util.stream.Collectors; + +/** + * 用户信息 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/system/user") +public class SysUserController extends BaseController +{ + @Autowired + private ISysUserService userService; + + @Autowired + private ISysRoleService roleService; + + @Autowired + private ISysDeptService deptService; + + @Autowired + private ISysPostService postService; + + /** + * 获取用户列表 + */ + @PreAuthorize("@ss.hasPermi('system:user:list')") + @GetMapping("/list") + public TableDataInfo list(SysUser user) + { + startPage(); + List list = userService.selectUserList(user); + return getDataTable(list); + } + + @Log(title = "用户管理", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('system:user:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysUser user) + { + List list = userService.selectUserList(user); + ExcelUtil util = new ExcelUtil(SysUser.class); + util.exportExcel(response, list, "用户数据"); + } + + @Log(title = "用户管理", businessType = BusinessType.IMPORT) + @PreAuthorize("@ss.hasPermi('system:user:import')") + @PostMapping("/importData") + public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception + { + ExcelUtil util = new ExcelUtil(SysUser.class); + List userList = util.importExcel(file.getInputStream()); + String operName = getUsername(); + String message = userService.importUser(userList, updateSupport, operName); + return success(message); + } + + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) + { + ExcelUtil util = new ExcelUtil(SysUser.class); + util.importTemplateExcel(response, "用户数据"); + } + + /** + * 根据用户编号获取详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:user:query')") + @GetMapping(value = { "/", "/{userId}" }) + public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId) + { + userService.checkUserDataScope(userId); + AjaxResult ajax = AjaxResult.success(); + List roles = roleService.selectRoleAll(); + ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); + ajax.put("posts", postService.selectPostAll()); + if (StringUtils.isNotNull(userId)) + { + SysUser sysUser = userService.selectUserById(userId); + ajax.put(AjaxResult.DATA_TAG, sysUser); + ajax.put("postIds", postService.selectPostListByUserId(userId)); + ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList())); + } + return ajax; + } + + /** + * 新增用户 + */ + @PreAuthorize("@ss.hasPermi('system:user:add')") + @Log(title = "用户管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysUser user) + { + if (!userService.checkUserNameUnique(user)) + { + return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在"); + } + else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) + { + return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在"); + } + else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) + { + return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在"); + } + user.setCreateBy(getUsername()); + user.setPassword(SecurityUtils.encryptPassword(user.getPassword())); + user.setUserUUID(IdUtils.randomUUID()); + return toAjax(userService.insertUser(user)); + } + + /** + * 修改用户 + */ + @PreAuthorize("@ss.hasPermi('system:user:edit')") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysUser user) + { + userService.checkUserAllowed(user); + userService.checkUserDataScope(user.getUserId()); + if (!userService.checkUserNameUnique(user)) + { + return error("修改用户'" + user.getUserName() + "'失败,登录账号已存在"); + } + else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) + { + return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); + } + else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) + { + return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); + } + user.setUpdateBy(getUsername()); + return toAjax(userService.updateUser(user)); + } + + /** + * 删除用户 + */ + @PreAuthorize("@ss.hasPermi('system:user:remove')") + @Log(title = "用户管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{userIds}") + public AjaxResult remove(@PathVariable Long[] userIds) + { + if (ArrayUtils.contains(userIds, getUserId())) + { + return error("当前用户不能删除"); + } + return toAjax(userService.deleteUserByIds(userIds)); + } + + /** + * 重置密码 + */ + @PreAuthorize("@ss.hasPermi('system:user:resetPwd')") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PutMapping("/resetPwd") + public AjaxResult resetPwd(@RequestBody SysUser user) + { + userService.checkUserAllowed(user); + userService.checkUserDataScope(user.getUserId()); + user.setPassword(SecurityUtils.encryptPassword(user.getPassword())); + user.setUpdateBy(getUsername()); + return toAjax(userService.resetPwd(user)); + } + + /** + * 状态修改 + */ + @PreAuthorize("@ss.hasPermi('system:user:edit')") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody SysUser user) + { + userService.checkUserAllowed(user); + userService.checkUserDataScope(user.getUserId()); + user.setUpdateBy(getUsername()); + return toAjax(userService.updateUserStatus(user)); + } + + /** + * 根据用户编号获取授权角色 + */ + @PreAuthorize("@ss.hasPermi('system:user:query')") + @GetMapping("/authRole/{userId}") + public AjaxResult authRole(@PathVariable("userId") Long userId) + { + AjaxResult ajax = AjaxResult.success(); + SysUser user = userService.selectUserById(userId); + List roles = roleService.selectRolesByUserId(userId); + ajax.put("user", user); + ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); + return ajax; + } + + /** + * 用户授权角色 + */ + @PreAuthorize("@ss.hasPermi('system:user:edit')") + @Log(title = "用户管理", businessType = BusinessType.GRANT) + @PutMapping("/authRole") + public AjaxResult insertAuthRole(Long userId, Long[] roleIds) + { + userService.checkUserDataScope(userId); + userService.insertUserAuth(userId, roleIds); + return success(); + } + + /** + * 获取部门树列表 + */ + @PreAuthorize("@ss.hasPermi('system:user:list')") + @GetMapping("/deptTree") + public AjaxResult deptTree(SysDept dept) + { + return success(deptService.selectDeptTreeList(dept)); + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/tool/TestController.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/tool/TestController.java new file mode 100644 index 0000000000000000000000000000000000000000..16371c252ebc691b326c0f979cedb65ef024c4ae --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/controller/tool/TestController.java @@ -0,0 +1,172 @@ +package com.RVSmartPorting.web.controller.tool; + +import com.RVSmartPorting.common.core.controller.BaseController; +import com.RVSmartPorting.common.core.domain.R; +import com.RVSmartPorting.common.utils.StringUtils; +import io.swagger.annotations.*; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * swagger 用户测试方法 + * + * @author ruoyi + */ +@Api("用户信息管理") +@RestController +@RequestMapping("/test/user") +public class TestController extends BaseController +{ + private final static Map users = new LinkedHashMap(); + { + users.put(1, new UserEntity(1, "admin", "admin123", "15888888888")); + users.put(2, new UserEntity(2, "ry", "admin123", "15666666666")); + } + + @ApiOperation("获取用户列表") + @GetMapping("/list") + public R> userList() + { + List userList = new ArrayList(users.values()); + return R.ok(userList); + } + + @ApiOperation("获取用户详细") + @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class) + @GetMapping("/{userId}") + public R getUser(@PathVariable Integer userId) + { + if (!users.isEmpty() && users.containsKey(userId)) + { + return R.ok(users.get(userId)); + } + else + { + return R.fail("用户不存在"); + } + } + + @ApiOperation("新增用户") + @ApiImplicitParams({ + @ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", dataTypeClass = Integer.class), + @ApiImplicitParam(name = "username", value = "用户名称", dataType = "String", dataTypeClass = String.class), + @ApiImplicitParam(name = "password", value = "用户密码", dataType = "String", dataTypeClass = String.class), + @ApiImplicitParam(name = "mobile", value = "用户手机", dataType = "String", dataTypeClass = String.class) + }) + @PostMapping("/save") + public R save(UserEntity user) + { + if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId())) + { + return R.fail("用户ID不能为空"); + } + users.put(user.getUserId(), user); + return R.ok(); + } + + @ApiOperation("更新用户") + @PutMapping("/update") + public R update(@RequestBody UserEntity user) + { + if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId())) + { + return R.fail("用户ID不能为空"); + } + if (users.isEmpty() || !users.containsKey(user.getUserId())) + { + return R.fail("用户不存在"); + } + users.remove(user.getUserId()); + users.put(user.getUserId(), user); + return R.ok(); + } + + @ApiOperation("删除用户信息") + @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class) + @DeleteMapping("/{userId}") + public R delete(@PathVariable Integer userId) + { + if (!users.isEmpty() && users.containsKey(userId)) + { + users.remove(userId); + return R.ok(); + } + else + { + return R.fail("用户不存在"); + } + } +} + +@ApiModel(value = "UserEntity", description = "用户实体") +class UserEntity +{ + @ApiModelProperty("用户ID") + private Integer userId; + + @ApiModelProperty("用户名称") + private String username; + + @ApiModelProperty("用户密码") + private String password; + + @ApiModelProperty("用户手机") + private String mobile; + + public UserEntity() + { + + } + + public UserEntity(Integer userId, String username, String password, String mobile) + { + this.userId = userId; + this.username = username; + this.password = password; + this.mobile = mobile; + } + + public Integer getUserId() + { + return userId; + } + + public void setUserId(Integer userId) + { + this.userId = userId; + } + + public String getUsername() + { + return username; + } + + public void setUsername(String username) + { + this.username = username; + } + + public String getPassword() + { + return password; + } + + public void setPassword(String password) + { + this.password = password; + } + + public String getMobile() + { + return mobile; + } + + public void setMobile(String mobile) + { + this.mobile = mobile; + } +} diff --git a/CSP-admin/src/main/java/com/RVSmartPorting/web/core/config/SwaggerConfig.java b/CSP-admin/src/main/java/com/RVSmartPorting/web/core/config/SwaggerConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..6d8d29e557c3549a080799ec91c3512c6cecd1a9 --- /dev/null +++ b/CSP-admin/src/main/java/com/RVSmartPorting/web/core/config/SwaggerConfig.java @@ -0,0 +1,121 @@ +package com.RVSmartPorting.web.core.config; + +import com.RVSmartPorting.common.config.CSPConfig; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.*; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spi.service.contexts.SecurityContext; +import springfox.documentation.spring.web.plugins.Docket; +import io.swagger.models.auth.In; + +import java.util.ArrayList; +import java.util.List; + +/** + * Swagger2的接口配置 + * + * @author ruoyi + */ +@Configuration +public class SwaggerConfig +{ + /** 系统基础配置 */ + @Autowired + private CSPConfig CSPConfig; + + /** 是否开启swagger */ + @Value("${swagger.enabled}") + private boolean enabled; + + /** 设置请求的统一前缀 */ + @Value("${swagger.pathMapping}") + private String pathMapping; + + /** + * 创建API + */ + @Bean + public Docket createRestApi() + { + return new Docket(DocumentationType.OAS_30) + // 是否启用Swagger + .enable(enabled) + // 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息) + .apiInfo(apiInfo()) + // 设置哪些接口暴露给Swagger展示 + .select() + // 扫描所有有注解的api,用这种方式更灵活 + .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) + // 扫描指定包中的swagger注解 + // .apis(RequestHandlerSelectors.basePackage("com.RVSmartPorting.project.tool.swagger")) + // 扫描所有 .apis(RequestHandlerSelectors.any()) + .paths(PathSelectors.any()) + .build() + /* 设置安全模式,swagger可以设置访问token */ + .securitySchemes(securitySchemes()) + .securityContexts(securityContexts()) + .pathMapping(pathMapping); + } + + /** + * 安全模式,这里指定token通过Authorization头请求头传递 + */ + private List securitySchemes() + { + List apiKeyList = new ArrayList(); + apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue())); + return apiKeyList; + } + + /** + * 安全上下文 + */ + private List securityContexts() + { + List securityContexts = new ArrayList<>(); + securityContexts.add( + SecurityContext.builder() + .securityReferences(defaultAuth()) + .operationSelector(o -> o.requestMappingPattern().matches("/.*")) + .build()); + return securityContexts; + } + + /** + * 默认的安全上引用 + */ + private List defaultAuth() + { + AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); + AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; + authorizationScopes[0] = authorizationScope; + List securityReferences = new ArrayList<>(); + securityReferences.add(new SecurityReference("Authorization", authorizationScopes)); + return securityReferences; + } + + /** + * 添加摘要信息 + */ + private ApiInfo apiInfo() + { + // 用ApiInfoBuilder进行定制 + return new ApiInfoBuilder() + // 设置标题 + .title("在线代码扫描服务平台接口文档") + // 描述 + .description("描述:具体包括用户模块、规则模块、规则集模块、代码上传下载模块、后台管理模块、扫描报告管理模块、扫描任务管理模块") + // 作者信息 + .contact(new Contact(CSPConfig.getName(), null, null)) + // 版本 + .version("版本号:" + CSPConfig.getVersion()) + .build(); + } +} diff --git a/CSP-admin/src/main/resources/application.yml b/CSP-admin/src/main/resources/application.yml new file mode 100644 index 0000000000000000000000000000000000000000..43d2d25b797466c6da5afe3215c562886e78635a --- /dev/null +++ b/CSP-admin/src/main/resources/application.yml @@ -0,0 +1,178 @@ +csp: + # 验证码类型 math 数组计算 char 字符验证 + captchaType: math + profile: C:/Temp/test_upload_repo + hdfsEnabled: false + +hdfs: + hostname: 127.0.0.1 + port: 9000 + username: Lenovo + HADOOP_HOME: C:\Users\Lenovo\Desktop\ospp\hadoop\hadoop + +# 开发环境配置 +server: + # 服务器的HTTP端口,默认为8080 + port: 8080 + servlet: + # 应用的访问路径 + context-path: / + tomcat: + # tomcat的URI编码 + uri-encoding: UTF-8 + # 连接数满后的排队数,默认为100 + accept-count: 1000 + threads: + # tomcat最大线程数,默认为200 + max: 800 + # Tomcat启动初始化的线程数,默认值10 + min-spare: 100 + +spring: + # 资源信息 + messages: + # 国际化资源文件路径 + basename: i18n/messages + # 数据源配置 + datasource: + type: com.alibaba.druid.pool.DruidDataSource + driverClassName: com.mysql.cj.jdbc.Driver + druid: + # 主库数据源 + master: + url: jdbc:mysql://101.132.172.189:3306/CodeScanningPlatform?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + username: root + password: lxq6655063 + # 从库数据源 + slave: + # 从数据源开关/默认关闭 + enabled: false + url: + username: + password: + # 初始连接数 + initialSize: 5 + # 最小连接池数量 + minIdle: 10 + # 最大连接池数量 + maxActive: 20 + # 配置获取连接等待超时的时间 + maxWait: 60000 + # 配置连接超时时间 + connectTimeout: 30000 + # 配置网络超时时间 + socketTimeout: 60000 + # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + timeBetweenEvictionRunsMillis: 60000 + # 配置一个连接在池中最小生存的时间,单位是毫秒 + minEvictableIdleTimeMillis: 300000 + # 配置一个连接在池中最大生存的时间,单位是毫秒 + maxEvictableIdleTimeMillis: 900000 + # 配置检测连接是否有效 + validationQuery: SELECT 1 FROM DUAL + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + webStatFilter: + enabled: true + statViewServlet: + enabled: true + # 设置白名单,不填则允许所有访问 + allow: + url-pattern: /druid/* + # 控制台管理用户名和密码 + login-username: admin + login-password: admin + filter: + stat: + enabled: true + # 慢SQL记录 + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: true + wall: + config: + multi-statement-allow: true + + devtools: + # 热部署生效 + add-properties: true + # 设置重启的目录 + restart: + additional-paths: src/main/java + application: + name: CSP-admin + #Redis配置 + redis: + # 地址 + host: 101.132.172.189 + #Redis服务器连接密码(默认为空) + password: Lxq6655063 + # Redis数据库索引(默认为0) + database: 0 + # 端口,默认为6379 + port: 6379 + # 连接超时时间 + timeout: 10s + lettuce: + pool: + # 连接池中的最小空闲连接 + min-idle: 0 + # 连接池中的最大空闲连接 + max-idle: 8 + # 连接池的最大数据库连接数 + max-active: 8 + # #连接池最大阻塞等待时间(使用负值表示没有限制) + max-wait: -1ms + + +mybatis: + # 声明 XxxMapper.xml文件路径 + mapperLocations: classpath*:mapper/**/*Mapper.xml + # 扫描实体类路径 + typeAliasesPackage: com.RVSmartPorting.**.domain + # 加载全局的配置文件 + configLocation: classpath:mybatis/mybatis-config.xml + + +# 用户配置 +user: + password: + # 密码最大错误次数 + maxRetryCount: 10 + # 密码锁定时间(默认10分钟) + lockTime: 10 + +# PageHelper分页插件 +pagehelper: + # 指定分页插件使用哪种数据库方言 + helperDialect: mysql + # 当该参数设置为 true 时,pageNum<=0 时会查询第一页, pageNum>pages(超过总数时),会查询最后一页。 + reasonable: true + # 支持通过 Mapper 接口参数来传递分页参数,默认值false,分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页。 + supportMethodsArguments: true + +# token配置 +token: + # 令牌自定义标识 + header: Authorization + # 令牌密钥 + secret: abcdefghijklmnopqrstuvwxyz + # 令牌有效期(默认30分钟) + expireTime: 300 + +# Swagger配置 +swagger: + # 是否开启swagger + enabled: true + # 请求前缀 + pathMapping: /dev-api + +# 防止XSS攻击 +xss: + # 过滤开关 + enabled: true + # 排除链接(多个用逗号分隔) + excludes: /system/notice + # 匹配链接 + urlPatterns: /system/*,/monitor/*,/tool/* diff --git a/CSP-admin/src/main/resources/i18n/messages.properties b/CSP-admin/src/main/resources/i18n/messages.properties new file mode 100644 index 0000000000000000000000000000000000000000..c3956b27d60d30a7feca662e95ba47ef546aff6d --- /dev/null +++ b/CSP-admin/src/main/resources/i18n/messages.properties @@ -0,0 +1,38 @@ +#错误消息 +not.null=* 必须填写 +user.jcaptcha.error=验证码错误 +user.jcaptcha.expire=验证码已失效 +user.not.exists=用户不存在/密码错误 +user.password.not.match=用户不存在/密码错误 +user.password.retry.limit.count=密码输入错误{0}次 +user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟 +user.password.delete=对不起,您的账号已被删除 +user.blocked=用户已封禁,请联系管理员 +role.blocked=角色已封禁,请联系管理员 +login.blocked=很遗憾,访问IP已被列入系统黑名单 +user.logout.success=退出成功 + +length.not.valid=长度必须在{min}到{max}个字符之间 + +user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 +user.password.not.valid=* 5-50个字符 + +user.email.not.valid=邮箱格式错误 +user.mobile.phone.number.not.valid=手机号格式错误 +user.login.success=登录成功 +user.register.success=注册成功 +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}] diff --git a/CSP-admin/src/main/resources/log4j2.xml b/CSP-admin/src/main/resources/log4j2.xml new file mode 100644 index 0000000000000000000000000000000000000000..eade0c2a0c5ba0f38bc9818f247ad0b6aee8fbe9 --- /dev/null +++ b/CSP-admin/src/main/resources/log4j2.xml @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CSP-admin/src/main/resources/mybatis/mybatis-config.xml b/CSP-admin/src/main/resources/mybatis/mybatis-config.xml new file mode 100644 index 0000000000000000000000000000000000000000..4b8c49628deacd7867f7e7684f127d14ddf3396e --- /dev/null +++ b/CSP-admin/src/main/resources/mybatis/mybatis-config.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + diff --git a/CSP-admin/src/test/java/com/RVSmartPorting/core/system/mapper/RuleSetMapperTest.java b/CSP-admin/src/test/java/com/RVSmartPorting/core/system/mapper/RuleSetMapperTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c12861ee83a96e79337d0d1e670152ec0132dfa5 --- /dev/null +++ b/CSP-admin/src/test/java/com/RVSmartPorting/core/system/mapper/RuleSetMapperTest.java @@ -0,0 +1,36 @@ +package com.RVSmartPorting.core.system.mapper; + + +import com.RVSmartPorting.CSPApplication; +import com.RVSmartPorting.core.system.domain.RuleSet; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.List; + +/** + * @author xuqiangli + * @create 2023-08-21 10:58 + */ + +@SpringBootTest(classes = CSPApplication.class) +class RuleSetMapperTest { + + @Autowired + RuleSetMapper ruleSetMapper; + + @Test + void selectRuleSetByRuleSetId() { + final RuleSet ruleSet = ruleSetMapper.selectRuleSetByRuleSetId(1L); + System.out.println("ruleSet = " + ruleSet); + } + + @Test + void selectRuleSetList() { + final RuleSet ruleSet = new RuleSet(); +// ruleSet.setRuleSetId(); + final List ruleSets = ruleSetMapper.selectRuleSetList(ruleSet); + System.out.println("ruleSets = " + ruleSets); + } +} \ No newline at end of file diff --git a/CSP-admin/src/test/java/com/RVSmartPorting/core/system/service/impl/CodeProjectServiceImplTest.java b/CSP-admin/src/test/java/com/RVSmartPorting/core/system/service/impl/CodeProjectServiceImplTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c78b7a31a1a5c395814ce593a1e1d00ad283b036 --- /dev/null +++ b/CSP-admin/src/test/java/com/RVSmartPorting/core/system/service/impl/CodeProjectServiceImplTest.java @@ -0,0 +1,9 @@ +package com.RVSmartPorting.core.system.service.impl; + +/** + * @author xuqiangli + * @create 2023-09-09 12:13 + */ +public class CodeProjectServiceImplTest { + +} diff --git a/CSP-admin/src/test/java/com/RVSmartPorting/core/system/service/impl/RuleSetServiceImplTest.java b/CSP-admin/src/test/java/com/RVSmartPorting/core/system/service/impl/RuleSetServiceImplTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ffbddbbca069cee33a554b9557bc2e59280910a6 --- /dev/null +++ b/CSP-admin/src/test/java/com/RVSmartPorting/core/system/service/impl/RuleSetServiceImplTest.java @@ -0,0 +1,28 @@ +package com.RVSmartPorting.core.system.service.impl; + +import com.RVSmartPorting.CSPApplication; +import com.RVSmartPorting.core.system.domain.RuleSet; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.List; + +/** + * @author xuqiangli + * @create 2023-08-21 12:10 + */ +@SpringBootTest(classes = CSPApplication.class) +class RuleSetServiceImplTest { + @Autowired + RuleSetServiceImpl ruleSetService; + @Test + void selectRuleSetByRuleSetId() { + } + + @Test + void selectRuleSetList() { + final List ruleSets = ruleSetService.selectRuleSetList(new RuleSet()); + System.out.println("ruleSets = " + ruleSets); + } +} \ No newline at end of file diff --git a/CSP-admin/src/test/java/com/RVSmartPorting/web/controller/system/CodeProjectControllerTest.java b/CSP-admin/src/test/java/com/RVSmartPorting/web/controller/system/CodeProjectControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b57ce8ec4c9a43318b34b7a1983216f9a0a538f0 --- /dev/null +++ b/CSP-admin/src/test/java/com/RVSmartPorting/web/controller/system/CodeProjectControllerTest.java @@ -0,0 +1,196 @@ +package com.RVSmartPorting.web.controller.system; + +import com.RVSmartPorting.common.utils.file.FileUtils; +import lombok.extern.slf4j.Slf4j; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FSDataInputStream; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.io.InputStreamResource; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.util.FileCopyUtils; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URLDecoder; + +/** + * @author xuqiangli + * @create 2023-09-13 10:20 + */ +@Slf4j +@SpringBootTest +@AutoConfigureMockMvc +class CodeProjectControllerTest { + @Autowired + private MockMvc mockMvc; + + // Replace with the actual path to an existing HDFS file + private static final String HDFS_FILE_PATH = "/codePackStorageRoot/90/9a/909a6fa778c7605b8df76f90c14fc1a1a0f4157a" + + "/test.zip"; + private static final String localFileBasePath = "E:\\.java\\temp\\"; + + public static void testDownloadFile() throws Exception { + final ResponseEntity response = testDownloadFileFromHDFS(); + if (response.getStatusCode().is2xxSuccessful()) { + Resource resource = response.getBody(); + try { + final String localFilePath = localFileBasePath + FileUtils.extractFileName(response); + FileOutputStream outputStream = new FileOutputStream(localFilePath); + FileCopyUtils.copy(resource.getInputStream(), outputStream); + outputStream.close(); + log.info("File downloaded and saved to: {}", localFilePath); + } catch (IOException e) { + log.error("Error while saving file: " + e.getMessage()); + } + } else { + log.error("Failed to download file. HTTP status code: " + response.getStatusCode()); + } + } + + + public static void testExtractFileName() { + String contentDisposition = "attachment; filename=test.zip"; + int startIndex = contentDisposition.indexOf("filename=") + 9; // 10 is the length of "filename=" + System.out.println(contentDisposition.substring(startIndex)); + } + + public static ResponseEntity testDownloadFileFromHDFS() { + try { + // 获取HDFS文件系统 + FileSystem hdfs; + try { + System.setProperty("hadoop.home.dir", "C:\\Users\\Lenovo\\Desktop\\ospp\\hadoop\\hadoop"); + System.setProperty("HADOOP_HOME", "C:\\Users\\Lenovo\\Desktop\\ospp\\hadoop\\hadoop"); + hdfs = FileSystem.get(new URI("127.0.0.1"), new Configuration(), "Lenovo"); + } catch (Exception e) { + throw new RuntimeException("Error initializing HDFSUtil", e); + } + // 构建HDFS文件路径 + Path hdfsFilePath = new Path(HDFS_FILE_PATH); + + // 检查文件是否存在 + if (!hdfs.exists(hdfsFilePath)) { +// return ResponseEntity.notFound().build(); + log.info("ResponseEntity.notFound().build():{}", ResponseEntity.notFound().build()); + } + + // 创建HDFS文件系统的输入流 + FSDataInputStream inputStream = hdfs.open(hdfsFilePath); + + // 获取文件的MIME类型 + String contentType = "application/octet-stream"; // 默认为二进制流 + + // 构建响应头 + HttpHeaders headers = new HttpHeaders(); + headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + hdfsFilePath.getName()); + return ResponseEntity.ok() + .headers(headers) + .contentType(org.springframework.http.MediaType.parseMediaType(contentType)) + .body(new InputStreamResource(inputStream)); + + } catch (IOException e) { + log.error("Error while downloading file from HDFS: {}", e.getMessage(), e); + log.error("ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build():{}", + ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + + } + } + + public static void test2(String[] args) { + try { + // 获取HDFS文件系统 + FileSystem hdfs; + try { + System.setProperty("hadoop.home.dir", "C:\\Users\\Lenovo\\Desktop\\ospp\\hadoop\\hadoop"); + System.setProperty("HADOOP_HOME", "C:\\Users\\Lenovo\\Desktop\\ospp\\hadoop\\hadoop"); + hdfs = FileSystem.get(new URI("127.0.0.1"), new Configuration(), "Lenovo"); + } catch (Exception e) { + throw new RuntimeException("Error initializing HDFSUtil", e); + } + // 构建HDFS文件路径 + Path hdfsFilePath = new Path(HDFS_FILE_PATH); + + // 检查文件是否存在 + if (!hdfs.exists(hdfsFilePath)) { +// return ResponseEntity.notFound().build(); + log.info("ResponseEntity.notFound().build():{}", ResponseEntity.notFound().build()); + } + + // 创建HDFS文件系统的输入流 + FSDataInputStream inputStream = hdfs.open(hdfsFilePath); + + // 获取文件的MIME类型 + String contentType = "application/octet-stream"; // 默认为二进制流 + + // 构建响应头 + HttpHeaders headers = new HttpHeaders(); + headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + hdfsFilePath.getName()); + +// return ResponseEntity.ok() +// .headers(headers) +// .contentType(org.springframework.http.MediaType.parseMediaType(contentType)) +// .body(new InputStreamResource(inputStream)); + final ResponseEntity responseEntity = ResponseEntity.ok() + .headers(headers) + .contentType(MediaType.parseMediaType(contentType)) + .body(new InputStreamResource(inputStream)); + log.info("responseEntity: {}", responseEntity); + } catch (IOException e) { + log.error("Error while downloading file from HDFS: {}", e.getMessage(), e); +// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + log.error("ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build():{}", + ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build()); + } + } + + @Autowired + CodeProjectController codeProjectController; + + @Test + public void test3(String[] args) { + String path = "C:/Temp/test_upload_repo/upload/codePackStorageRoot/67/40/6740dd62cc8b506ce1a62bacac55476bb57fe596/test.zip"; + ResponseEntity responseEntity = codeProjectController.downloadFile(path); + Resource body = responseEntity.getBody(); + saveResourceToFile(body,"C:\\Temp\\test_upload_repo\\upload\\scanServerCodePackStorageRoot\\1695088624118\\2\\t.zip"); + } + + private void saveResourceToFile(Resource resource, String localCodePackFilePath) { + try { + // 创建文件对象 + File localCodePackFile = new File(localCodePackFilePath); + // 检查文件所在的目录是否存在,如果不存在则创建 + File parentDirectory = localCodePackFile.getParentFile(); + if (!parentDirectory.exists()) { + parentDirectory.mkdirs(); + } + FileOutputStream outputStream = new FileOutputStream(localCodePackFile); + FileCopyUtils.copy(resource.getInputStream(), outputStream); + outputStream.close(); + log.info("File downloaded and saved to: {}", localCodePackFilePath); + } catch (IOException e) { + log.error("Error while saving file: " + e.getMessage()); + } + } + public static void test4() throws UnsupportedEncodingException { + String encodedFileName = "test+-+%E5%89%AF%E6%9C%AC.zip"; + String decodedFileName = URLDecoder.decode(encodedFileName, "UTF-8"); + System.out.println("decodedFileName = " + decodedFileName); + } + public static void main(String[] args) throws Exception { + testDownloadFile(); + } +} \ No newline at end of file diff --git a/CSP-common/pom.xml b/CSP-common/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..98d94fd13339ec02a62936d73e8880703cf5e3dd --- /dev/null +++ b/CSP-common/pom.xml @@ -0,0 +1,227 @@ + + + + CodeScanningPlatform-Backend + com.RVSmartPorting + 1.0.0 + + 4.0.0 + + CSP-common + + + + common通用工具模块 + + + + + org.apache.hadoop + hadoop-common + + + javax.servlet + servlet-api + + + + + org.apache.hadoop + hadoop-client + + + javax.servlet + servlet-api + + + + + org.apache.hadoop + hadoop-hdfs + + + javax.servlet + servlet-api + + + + + + + + com.github.junrar + junrar + + + + org.tukaani + xz + + + + org.apache.commons + commons-compress + + + org.apache.ant + ant + + + + + org.eclipse.jgit + org.eclipse.jgit + + + org.eclipse.jgit + org.eclipse.jgit.ssh.jsch + + + org.projectlombok + lombok + + + + org.springframework.boot + spring-boot-starter-validation + + + + org.apache.poi + poi-ooxml + + + commons-io + commons-io + + + + io.jsonwebtoken + jjwt + + + + + + eu.bitwalker + UserAgentUtils + + + + + + org.springframework.boot + spring-boot-starter-security + + + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + + + org.apache.commons + commons-pool2 + + + + + + org.springframework + spring-context-support + + + + + + org.springframework + spring-web + + + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + + + com.alibaba + fastjson + + + + + + org.apache.commons + commons-lang3 + + + + + + javax.servlet + javax.servlet-api + + + + + + com.github.pagehelper + pagehelper-spring-boot-starter + + + + + + javax.validation + validation-api + + + + + + javax.xml.bind + jaxb-api + 2.3.0 + + + com.sun.xml.bind + jaxb-impl + 2.3.0 + + + com.sun.xml.bind + jaxb-core + 2.3.0 + + + javax.activation + activation + 1.1.1 + + + + org.bouncycastle + bcprov-jdk15on + + + + com.squareup.okhttp3 + okhttp + + + + + + \ No newline at end of file diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/Anonymous.java b/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/Anonymous.java new file mode 100644 index 0000000000000000000000000000000000000000..a957a01031bf7e3fee8e30604dfde06c4a1d1b4e --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/Anonymous.java @@ -0,0 +1,15 @@ +package com.RVSmartPorting.common.annotation; + +import java.lang.annotation.*; + +/** + * 匿名访问不鉴权注解 + * + * @author ruoyi + */ +@Target({ ElementType.METHOD, ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Anonymous +{ +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/DataScope.java b/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/DataScope.java new file mode 100644 index 0000000000000000000000000000000000000000..fa80d9cbf966511c8ac5674db67be4e4761d2ed4 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/DataScope.java @@ -0,0 +1,29 @@ +package com.RVSmartPorting.common.annotation; + +import java.lang.annotation.*; + +/** + * 数据权限过滤注解 + * + * @author ruoyi + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DataScope +{ + /** + * 部门表的别名 + */ + public String deptAlias() default ""; + + /** + * 用户表的别名 + */ + public String userAlias() default ""; + + /** + * 权限字符(用于多个角色匹配符合要求的权限)默认根据权限注解@ss获取,多个权限用逗号分隔开来 + */ + public String permission() default ""; +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/DataSource.java b/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/DataSource.java new file mode 100644 index 0000000000000000000000000000000000000000..a3da253cefbd047cfcc1e0b1eebf09ad512aa0eb --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/DataSource.java @@ -0,0 +1,24 @@ +package com.RVSmartPorting.common.annotation; + +import com.RVSmartPorting.common.enums.DataSourceType; + +import java.lang.annotation.*; + +/** + * 自定义多数据源切换注解 + * + * 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准 + * + * @author ruoyi + */ +@Target({ ElementType.METHOD, ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +public @interface DataSource +{ + /** + * 切换数据源名称 + */ + public DataSourceType value() default DataSourceType.MASTER; +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/Excel.java b/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/Excel.java new file mode 100644 index 0000000000000000000000000000000000000000..7b76f4a978bd8189a1ddeedd94077c2c585d9ba3 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/Excel.java @@ -0,0 +1,188 @@ +package com.RVSmartPorting.common.annotation; + +import com.RVSmartPorting.common.utils.poi.ExcelHandlerAdapter; +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.ss.usermodel.IndexedColors; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.math.BigDecimal; + +/** + * 自定义导出Excel数据注解 + * + * @author ruoyi + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Excel +{ + /** + * 导出时在excel中排序 + */ + public int sort() default Integer.MAX_VALUE; + + /** + * 导出到Excel中的名字. + */ + public String name() default ""; + + /** + * 日期格式, 如: yyyy-MM-dd + */ + public String dateFormat() default ""; + + /** + * 如果是字典类型,请设置字典的type值 (如: sys_user_sex) + */ + public String dictType() default ""; + + /** + * 读取内容转表达式 (如: 0=男,1=女,2=未知) + */ + public String readConverterExp() default ""; + + /** + * 分隔符,读取字符串组内容 + */ + public String separator() default ","; + + /** + * BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化) + */ + public int scale() default -1; + + /** + * BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN + */ + public int roundingMode() default BigDecimal.ROUND_HALF_EVEN; + + /** + * 导出时在excel中每个列的高度 + */ + public double height() default 14; + + /** + * 导出时在excel中每个列的宽度 + */ + public double width() default 16; + + /** + * 文字后缀,如% 90 变成90% + */ + public String suffix() default ""; + + /** + * 当值为空时,字段的默认值 + */ + public String defaultValue() default ""; + + /** + * 提示信息 + */ + public String prompt() default ""; + + /** + * 设置只能选择不能输入的列内容. + */ + public String[] combo() default {}; + + /** + * 是否需要纵向合并单元格,应对需求:含有list集合单元格) + */ + public boolean needMerge() default false; + + /** + * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写. + */ + public boolean isExport() default true; + + /** + * 另一个类中的属性名称,支持多级获取,以小数点隔开 + */ + public String targetAttr() default ""; + + /** + * 是否自动统计数据,在最后追加一行统计数据总和 + */ + public boolean isStatistics() default false; + + /** + * 导出类型(0数字 1字符串 2图片) + */ + public ColumnType cellType() default ColumnType.STRING; + + /** + * 导出列头背景颜色 + */ + public IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT; + + /** + * 导出列头字体颜色 + */ + public IndexedColors headerColor() default IndexedColors.WHITE; + + /** + * 导出单元格背景颜色 + */ + public IndexedColors backgroundColor() default IndexedColors.WHITE; + + /** + * 导出单元格字体颜色 + */ + public IndexedColors color() default IndexedColors.BLACK; + + /** + * 导出字段对齐方式 + */ + public HorizontalAlignment align() default HorizontalAlignment.CENTER; + + /** + * 自定义数据处理器 + */ + public Class handler() default ExcelHandlerAdapter.class; + + /** + * 自定义数据处理器参数 + */ + public String[] args() default {}; + + /** + * 字段类型(0:导出导入;1:仅导出;2:仅导入) + */ + Type type() default Type.ALL; + + public enum Type + { + ALL(0), EXPORT(1), IMPORT(2); + private final int value; + + Type(int value) + { + this.value = value; + } + + public int value() + { + return this.value; + } + } + + public enum ColumnType + { + NUMERIC(0), STRING(1), IMAGE(2); + private final int value; + + ColumnType(int value) + { + this.value = value; + } + + public int value() + { + return this.value; + } + } +} \ No newline at end of file diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/Excels.java b/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/Excels.java new file mode 100644 index 0000000000000000000000000000000000000000..54d34a77560bd8feb4e411b9c7db986144238653 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/Excels.java @@ -0,0 +1,18 @@ +package com.RVSmartPorting.common.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Excel注解集 + * + * @author ruoyi + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Excels +{ + public Excel[] value(); +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/Log.java b/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/Log.java new file mode 100644 index 0000000000000000000000000000000000000000..bf9618152a1ce70c966a7a11b8d4e9dcbfc6993b --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/Log.java @@ -0,0 +1,47 @@ +package com.RVSmartPorting.common.annotation; + +import com.RVSmartPorting.common.enums.BusinessType; +import com.RVSmartPorting.common.enums.OperatorType; +import java.lang.annotation.*; + +/** + * 自定义操作日志记录注解 + * + * @author ruoyi + * + */ +@Target({ ElementType.PARAMETER, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Log +{ + /** + * 模块 + */ + public String title() default ""; + + /** + * 功能 + */ + public BusinessType businessType() default BusinessType.OTHER; + + /** + * 操作人类别 + */ + public OperatorType operatorType() default OperatorType.MANAGE; + + /** + * 是否保存请求的参数 + */ + public boolean isSaveRequestData() default true; + + /** + * 是否保存响应的参数 + */ + public boolean isSaveResponseData() default true; + + /** + * 排除指定的请求参数 + */ + public String[] excludeParamNames() default {}; +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/RateLimiter.java b/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/RateLimiter.java new file mode 100644 index 0000000000000000000000000000000000000000..3695c8cb66e7009fc4e6901ee387ae5073201b88 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/RateLimiter.java @@ -0,0 +1,37 @@ +package com.RVSmartPorting.common.annotation; + +import com.RVSmartPorting.common.constant.CacheConstants; +import com.RVSmartPorting.common.enums.LimitType; + +import java.lang.annotation.*; + +/** + * 限流注解 + * + * @author ruoyi + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RateLimiter +{ + /** + * 限流key + */ + public String key() default CacheConstants.RATE_LIMIT_KEY; + + /** + * 限流时间,单位秒 + */ + public int time() default 60; + + /** + * 限流次数 + */ + public int count() default 100; + + /** + * 限流类型 + */ + public LimitType limitType() default LimitType.DEFAULT; +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/RepeatSubmit.java b/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/RepeatSubmit.java new file mode 100644 index 0000000000000000000000000000000000000000..7eb84cbde6aadf61081aa45c4cad6d2f5da866c6 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/annotation/RepeatSubmit.java @@ -0,0 +1,26 @@ +package com.RVSmartPorting.common.annotation; + +import java.lang.annotation.*; + +/** + * 自定义注解防止表单重复提交 + * + * @author ruoyi + * + */ +@Inherited +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RepeatSubmit +{ + /** + * 间隔时间(ms),小于此时间视为重复提交 + */ + public int interval() default 5000; + + /** + * 提示消息 + */ + public String message() default "不允许重复提交,请稍候再试"; +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/config/CSPConfig.java b/CSP-common/src/main/java/com/RVSmartPorting/common/config/CSPConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..a2839091bfc5d4720373f00e724dbfa56729eeec --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/config/CSPConfig.java @@ -0,0 +1,181 @@ +package com.RVSmartPorting.common.config; + +/** + * 读取项目相关配置 + * + * @author ruoyi + */ + +import com.RVSmartPorting.common.utils.file.PathConverterUtil; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "csp") +public class CSPConfig { + /** + * 项目名称 + */ + private String name; + + /** + * 版本 + */ + private String version; + + /** + * 版权年份 + */ + private String copyrightYear; + + /** + * 实例演示开关 + */ + private boolean demoEnabled; + + /** + * 上传路径 + */ + private static String profile; + + + /** + * 获取地址开关 + */ + private static boolean addressEnabled; + + /** + * 验证码类型 + */ + private static String captchaType; + + /** + * 是否启用hdfs,true代表启动hdfs,false则会采用本地文件存储 + */ + private static boolean hdfsEnabled; + + 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; + } + + public static String getProfile() { + return profile; + } + + public void setProfile(String profile) { + CSPConfig.profile = profile; + } + + public static boolean isAddressEnabled() { + return addressEnabled; + } + + public void setAddressEnabled(boolean addressEnabled) { + CSPConfig.addressEnabled = addressEnabled; + } + + public static String getCaptchaType() { + return captchaType; + } + + public void setCaptchaType(String captchaType) { + CSPConfig.captchaType = captchaType; + } + + /** + * 获取导入上传路径 + */ + public static String getImportPath() { + return getProfile() + "/import"; + } + + /** + * 获取头像上传路径 + */ + public static String getAvatarPath() { + return getProfile() + "/avatar"; + } + + /** + * 获取代码文件上传路径 + */ + public static String getUploadTmpFolderPath() { + return getUploadPath() + "/uploadTmpFolder"; + } + + public static boolean isHdfsEnabled() { + return hdfsEnabled; + } + + public void setHdfsEnabled(boolean hdfsEnabled) { + CSPConfig.hdfsEnabled = hdfsEnabled; + } + + /** + * 获取代码文件上传hdfs路径 + */ + public static String getCodePackStorageRoot() { + String baseRoot = "/codePackStorageRoot"; + if (hdfsEnabled) { + return baseRoot; + } else { + return PathConverterUtil.convertPath(getUploadPath() + baseRoot); + } + } + + public static String getScanServerCodePackStorageRoot() { + String baseRoot = "/scanServerCodePackStorageRoot"; + if (hdfsEnabled) { + return baseRoot; + } else { + return PathConverterUtil.convertPath(getUploadPath() + baseRoot); + } + } + + /** + * 获取下载路径 + */ + public static String getDownloadPath() { + String path = getProfile() + "/download/"; + path = PathConverterUtil.convertPath(path); + return path; + } + + /** + * 获取上传路径 + */ + public static String getUploadPath() { + String path = getProfile() + "/upload"; + path = PathConverterUtil.convertPath(path); + return path; + } +} + diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/config/HDFSConfig.java b/CSP-common/src/main/java/com/RVSmartPorting/common/config/HDFSConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..862caf8e3301b007f982d5b36302cbc29712be1d --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/config/HDFSConfig.java @@ -0,0 +1,43 @@ +package com.RVSmartPorting.common.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "hdfs") +@Data +public class HDFSConfig { + + + /** + * hdfs 服务器地址 + **/ + private String hostname; + /** + * hdfs 服务器端口 + **/ + private String port; + /** + * hdfs 服务器账户 + **/ + private String username; + + private String HADOOP_HOME; + + public String getUsername() { + return username; + } + + public String getHadoopHome() { + return HADOOP_HOME; + } + + + /** + * 拼接连接 + **/ + public String getHdfsUrl() { + return "hdfs://" + hostname + ":" + port; + } +} \ No newline at end of file diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/constant/CacheConstants.java b/CSP-common/src/main/java/com/RVSmartPorting/common/constant/CacheConstants.java new file mode 100644 index 0000000000000000000000000000000000000000..1ebbce7218e0f35f6b26e0801bd7bcd96fb04db0 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/constant/CacheConstants.java @@ -0,0 +1,44 @@ +package com.RVSmartPorting.common.constant; + +/** + * 缓存的key 常量 + * + * @author ruoyi + */ +public class CacheConstants +{ + /** + * 登录用户 redis key + */ + public static final String LOGIN_TOKEN_KEY = "login_tokens:"; + + /** + * 验证码 redis key + */ + public static final String CAPTCHA_CODE_KEY = "captcha_codes:"; + + /** + * 参数管理 cache key + */ + public static final String SYS_CONFIG_KEY = "sys_config:"; + + /** + * 字典管理 cache key + */ + public static final String SYS_DICT_KEY = "sys_dict:"; + + /** + * 防重提交 redis key + */ + public static final String REPEAT_SUBMIT_KEY = "repeat_submit:"; + + /** + * 限流 redis key + */ + public static final String RATE_LIMIT_KEY = "rate_limit:"; + + /** + * 登录账户密码错误次数 redis key + */ + public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:"; +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/constant/Constants.java b/CSP-common/src/main/java/com/RVSmartPorting/common/constant/Constants.java new file mode 100644 index 0000000000000000000000000000000000000000..6afa0a0b0fc8b9300f109ee1a27329aa65a440e9 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/constant/Constants.java @@ -0,0 +1,148 @@ +package com.RVSmartPorting.common.constant; + +import io.jsonwebtoken.Claims; + +/** + * 通用常量信息 + * + * @author ruoyi + */ +public class Constants +{ + + /** + * 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:"; + + /** + * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加) + */ + public static final String[] JOB_WHITELIST_STR = { "com.RVSmartPorting" }; + + /** + * 定时任务违规的字符 + */ + public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml", + "org.springframework", "org.apache", "com.RVSmartPorting.common.utils.file", "com.RVSmartPorting.common.config" }; + + public static final String GIT_MESSAGE_ID_PREFIX = "git:"; + public static final String HTTP_MESSAGE_ID_PREFIX = "http:"; + +} + diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/constant/HttpStatus.java b/CSP-common/src/main/java/com/RVSmartPorting/common/constant/HttpStatus.java new file mode 100644 index 0000000000000000000000000000000000000000..06a3eb3dc71f6a0c798b71033f7c3913766cf917 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/constant/HttpStatus.java @@ -0,0 +1,98 @@ +package com.RVSmartPorting.common.constant; + +import java.time.Year; + +/** + * 返回状态码 + * + * @author ruoyi + */ + +public class HttpStatus +{ + /** + * 操作成功 + */ + public static final int SUCCESS = 200; + + /** + * 对象创建成功 + */ + public static final int CREATED = 201; + + /** + * 请求已经被接受 + */ + public static final int ACCEPTED = 202; + + /** + * 操作已经执行成功,但是没有返回数据 + */ + public static final int NO_CONTENT = 204; + + /** + * 资源已被移除 + */ + public static final int MOVED_PERM = 301; + + /** + * 重定向 + */ + public static final int SEE_OTHER = 303; + + /** + * 资源没有被修改 + */ + public static final int NOT_MODIFIED = 304; + + /** + * 参数列表错误(缺少,格式不匹配) + */ + public static final int BAD_REQUEST = 400; + + /** + * 未授权 + */ + public static final int UNAUTHORIZED = 401; + + /** + * 访问受限,授权过期 + */ + public static final int FORBIDDEN = 403; + + /** + * 资源,服务未找到 + */ + public static final int NOT_FOUND = 404; + + /** + * 不允许的http方法 + */ + public static final int BAD_METHOD = 405; + + /** + * 资源冲突,或者资源被锁 + */ + public static final int CONFLICT = 409; + + /** + * 不支持的数据,媒体类型 + */ + public static final int UNSUPPORTED_TYPE = 415; + + /** + * 系统内部错误 + */ + public static final int ERROR = 500; + + /** + * 接口未实现 + */ + public static final int NOT_IMPLEMENTED = 501; + + /** + * 系统警告消息 + */ + public static final int WARN = 601; +} + diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/constant/TableSupport.java b/CSP-common/src/main/java/com/RVSmartPorting/common/constant/TableSupport.java new file mode 100644 index 0000000000000000000000000000000000000000..2163300d88f1d4711052c0e96de4fa3dcca2ad46 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/constant/TableSupport.java @@ -0,0 +1,32 @@ +package com.RVSmartPorting.common.constant; + + +/** + * 表格数据处理 + * + * @author ruoyi + */ + +public class TableSupport +{ + /** + * 当前记录起始索引 + */ + public static final String PAGE_NUM = "pageNum"; + + /** + * 每页显示记录数 + */ + public static final String PAGE_SIZE = "pageSize"; + + /** + * 排序列 + */ + public static final String ORDER_BY_COLUMN = "orderByColumn"; + + /** + * 排序的方向 "desc" 或者 "asc". + */ + public static final String IS_ASC = "isAsc"; + +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/constant/UserConstants.java b/CSP-common/src/main/java/com/RVSmartPorting/common/constant/UserConstants.java new file mode 100644 index 0000000000000000000000000000000000000000..8d7349736c4161439016b93d772fbe5f334bbbee --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/constant/UserConstants.java @@ -0,0 +1,75 @@ +package com.RVSmartPorting.common.constant; + +/** + * 用户常量信息 + **/ +public class UserConstants { + /** + * 平台内系统用户的唯一标志 + */ + public static final String SYS_USER = "SYS_USER"; + + /** 正常状态 */ + public static final String NORMAL = "0"; + + /** 异常状态 */ + public static final String EXCEPTION = "1"; + + /** 用户封禁状态 */ + public static final String USER_DISABLE = "1"; + + /** 角色封禁状态 */ + public static final String ROLE_DISABLE = "1"; + + /** 部门正常状态 */ + public static final String DEPT_NORMAL = "0"; + + /** 部门停用状态 */ + public static final String DEPT_DISABLE = "1"; + + /** 字典正常状态 */ + public static final String DICT_NORMAL = "0"; + + /** 是否为系统默认(是) */ + public static final String YES = "Y"; + + /** 是否菜单外链(是) */ + public static final String YES_FRAME = "0"; + + /** 是否菜单外链(否) */ + public static final String NO_FRAME = "1"; + + /** 菜单类型(目录) */ + public static final String TYPE_DIR = "M"; + + /** 菜单类型(菜单) */ + public static final String TYPE_MENU = "C"; + + /** 菜单类型(按钮) */ + public static final String TYPE_BUTTON = "F"; + + /** Layout组件标识 */ + public final static String LAYOUT = "Layout"; + + /** ParentView组件标识 */ + public final static String PARENT_VIEW = "ParentView"; + + /** InnerLink组件标识 */ + public final static String INNER_LINK = "InnerLink"; + + /** 校验是否唯一的返回标识 */ + public final static boolean UNIQUE = true; + public final static boolean NOT_UNIQUE = false; + + /** + * 用户名长度限制 + */ + public static final int USERNAME_MIN_LENGTH = 2; + public static final int USERNAME_MAX_LENGTH = 20; + + /** + * 密码长度限制 + */ + public static final int PASSWORD_MIN_LENGTH = 5; + public static final int PASSWORD_MAX_LENGTH = 20; +} \ No newline at end of file diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/core/controller/BaseController.java b/CSP-common/src/main/java/com/RVSmartPorting/common/core/controller/BaseController.java new file mode 100644 index 0000000000000000000000000000000000000000..ec9afb20c11893fa2f4fda5522eccd5ef23fad62 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/core/controller/BaseController.java @@ -0,0 +1,203 @@ +package com.RVSmartPorting.common.core.controller; + +import com.RVSmartPorting.common.constant.HttpStatus; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.domain.model.LoginUser; +import com.RVSmartPorting.common.core.page.PageDomain; +import com.RVSmartPorting.common.core.page.TableDataInfo; +import com.RVSmartPorting.common.core.page.TableSupport; +import com.RVSmartPorting.common.utils.DateUtils; +import com.RVSmartPorting.common.utils.PageUtils; +import com.RVSmartPorting.common.utils.SecurityUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.sql.SqlUtil; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.InitBinder; + +import java.beans.PropertyEditorSupport; +import java.util.Date; +import java.util.List; + +/** + * web层通用数据处理 + * + * @author ruoyi + */ +public class BaseController +{ + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + + /** + * 将前台传递过来的日期格式的字符串,自动转化为Date类型 + */ + @InitBinder + public void initBinder(WebDataBinder binder) + { + // Date 类型转换 + binder.registerCustomEditor(Date.class, new PropertyEditorSupport() + { + @Override + public void setAsText(String text) + { + setValue(DateUtils.parseDate(text)); + } + }); + } + + /** + * 设置请求分页数据 + */ + protected void startPage() + { + PageUtils.startPage(); + } + + /** + * 设置请求排序数据 + */ + protected void startOrderBy() + { + PageDomain pageDomain = TableSupport.buildPageRequest(); + if (StringUtils.isNotEmpty(pageDomain.getOrderBy())) + { + String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy()); + PageHelper.orderBy(orderBy); + } + } + + /** + * 清理分页的线程变量 + */ + protected void clearPage() + { + PageUtils.clearPage(); + } + + /** + * 响应请求分页数据 + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected TableDataInfo getDataTable(List list) + { + TableDataInfo rspData = new TableDataInfo(); + rspData.setCode(HttpStatus.SUCCESS); + rspData.setMsg("查询成功"); + rspData.setRows(list); + rspData.setTotal(new PageInfo(list).getTotal()); + return rspData; + } + + /** + * 返回成功 + */ + public AjaxResult success() + { + return AjaxResult.success(); + } + + /** + * 返回失败消息 + */ + public AjaxResult error() + { + return AjaxResult.error(); + } + + /** + * 返回成功消息 + */ + public AjaxResult success(String message) + { + return AjaxResult.success(message); + } + + /** + * 返回成功消息 + */ + public AjaxResult success(Object data) + { + return AjaxResult.success(data); + } + + /** + * 返回失败消息 + */ + public AjaxResult error(String message) + { + return AjaxResult.error(message); + } + + /** + * 返回警告消息 + */ + public AjaxResult warn(String message) + { + return AjaxResult.warn(message); + } + + /** + * 响应返回结果 + * + * @param rows 影响行数 + * @return 操作结果 + */ + protected AjaxResult toAjax(int rows) + { + return rows > 0 ? AjaxResult.success() : AjaxResult.error(); + } + + /** + * 响应返回结果 + * + * @param result 结果 + * @return 操作结果 + */ + protected AjaxResult toAjax(boolean result) + { + return result ? success() : error(); + } + + /** + * 页面跳转 + */ + public String redirect(String url) + { + return StringUtils.format("redirect:{}", url); + } + + /** + * 获取用户缓存信息 + */ + public LoginUser getLoginUser() + { + return SecurityUtils.getLoginUser(); + } + + /** + * 获取登录用户id + */ + public Long getUserId() + { + return getLoginUser().getUserId(); + } + + /** + * 获取登录部门id + */ + public Long getDeptId() + { + return getLoginUser().getDeptId(); + } + + /** + * 获取登录用户名 + */ + public String getUsername() + { + return getLoginUser().getUsername(); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/AjaxResult.java b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/AjaxResult.java new file mode 100644 index 0000000000000000000000000000000000000000..22d5c3a9bc5bb2251fd61e1d48c018e32ce0b12a --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/AjaxResult.java @@ -0,0 +1,217 @@ +package com.RVSmartPorting.common.core.domain; + +import com.RVSmartPorting.common.constant.HttpStatus; +import com.RVSmartPorting.common.utils.StringUtils; + +import java.util.HashMap; +import java.util.Objects; + +/** + * 操作消息提醒 + * + * @author ruoyi + */ +public class AjaxResult extends HashMap +{ + private static final long serialVersionUID = 1L; + + /** 状态码 */ + public static final String CODE_TAG = "code"; + + /** 返回内容 */ + public static final String MSG_TAG = "msg"; + + /** 数据对象 */ + public static final String DATA_TAG = "data"; + + /** + * 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。 + */ + public AjaxResult() + { + } + + /** + * 初始化一个新创建的 AjaxResult 对象 + * + * @param code 状态码 + * @param msg 返回内容 + */ + public AjaxResult(int code, String msg) + { + super.put(CODE_TAG, code); + super.put(MSG_TAG, msg); + } + + /** + * 初始化一个新创建的 AjaxResult 对象 + * + * @param code 状态码 + * @param msg 返回内容 + * @param data 数据对象 + */ + public AjaxResult(int code, String msg, Object data) + { + super.put(CODE_TAG, code); + super.put(MSG_TAG, msg); + if (StringUtils.isNotNull(data)) + { + super.put(DATA_TAG, data); + } + } + + /** + * 返回成功消息 + * + * @return 成功消息 + */ + public static AjaxResult success() + { + return AjaxResult.success("操作成功"); + } + + /** + * 返回成功数据 + * + * @return 成功消息 + */ + public static AjaxResult success(Object data) + { + return AjaxResult.success("操作成功", data); + } + + /** + * 返回成功消息 + * + * @param msg 返回内容 + * @return 成功消息 + */ + public static AjaxResult success(String msg) + { + return AjaxResult.success(msg, null); + } + + /** + * 返回成功消息 + * + * @param msg 返回内容 + * @param data 数据对象 + * @return 成功消息 + */ + public static AjaxResult success(String msg, Object data) + { + return new AjaxResult(HttpStatus.SUCCESS, msg, data); + } + + /** + * 返回警告消息 + * + * @param msg 返回内容 + * @return 警告消息 + */ + public static AjaxResult warn(String msg) + { + return AjaxResult.warn(msg, null); + } + + /** + * 返回警告消息 + * + * @param msg 返回内容 + * @param data 数据对象 + * @return 警告消息 + */ + public static AjaxResult warn(String msg, Object data) + { + return new AjaxResult(HttpStatus.WARN, msg, data); + } + + /** + * 返回错误消息 + * + * @return 错误消息 + */ + public static AjaxResult error() + { + return AjaxResult.error("操作失败"); + } + + /** + * 返回错误消息 + * + * @param msg 返回内容 + * @return 错误消息 + */ + public static AjaxResult error(String msg) + { + return AjaxResult.error(msg, null); + } + + /** + * 返回错误消息 + * + * @param msg 返回内容 + * @param data 数据对象 + * @return 错误消息 + */ + public static AjaxResult error(String msg, Object data) + { + return new AjaxResult(HttpStatus.ERROR, msg, data); + } + + /** + * 返回错误消息 + * + * @param code 状态码 + * @param msg 返回内容 + * @return 错误消息 + */ + public static AjaxResult error(int code, String msg) + { + return new AjaxResult(code, msg, null); + } + + /** + * 是否为成功消息 + * + * @return 结果 + */ + public boolean isSuccess() + { + return Objects.equals(HttpStatus.SUCCESS, this.get(CODE_TAG)); + } + + /** + * 是否为警告消息 + * + * @return 结果 + */ + public boolean isWarn() + { + return Objects.equals(HttpStatus.WARN, this.get(CODE_TAG)); + } + + /** + * 是否为错误消息 + * + * @return 结果 + */ + public boolean isError() + { + return Objects.equals(HttpStatus.ERROR, this.get(CODE_TAG)); + } + + /** + * 方便链式调用 + * + * @param key 键 + * @param value 值 + * @return 数据对象 + */ + @Override + public AjaxResult put(String key, Object value) + { + super.put(key, value); + return this; + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/BaseEntity.java b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/BaseEntity.java new file mode 100644 index 0000000000000000000000000000000000000000..8abaa8167e4977daf667218006f527018e620481 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/BaseEntity.java @@ -0,0 +1,119 @@ +package com.RVSmartPorting.common.core.domain; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; + +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * Entity基类 + * + * @author ruoyi + */ +public class BaseEntity implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** 搜索值 */ + @JsonIgnore + private String searchValue; + + /** 创建者 */ + private String createBy; + + /** 创建时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + /** 更新者 */ + private String updateBy; + + /** 更新时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + + /** 备注 */ + private String remark; + + /** 请求参数 */ + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private Map params; + + public String getSearchValue() + { + return searchValue; + } + + public void setSearchValue(String searchValue) + { + this.searchValue = searchValue; + } + + public String getCreateBy() + { + return createBy; + } + + public void setCreateBy(String createBy) + { + this.createBy = createBy; + } + + public Date getCreateTime() + { + return createTime; + } + + public void setCreateTime(Date createTime) + { + this.createTime = createTime; + } + + public String getUpdateBy() + { + return updateBy; + } + + public void setUpdateBy(String updateBy) + { + this.updateBy = updateBy; + } + + public Date getUpdateTime() + { + return updateTime; + } + + public void setUpdateTime(Date updateTime) + { + this.updateTime = updateTime; + } + + public String getRemark() + { + return remark; + } + + public void setRemark(String remark) + { + this.remark = remark; + } + + public Map getParams() + { + if (params == null) + { + params = new HashMap<>(); + } + return params; + } + + public void setParams(Map params) + { + this.params = params; + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/R.java b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/R.java new file mode 100644 index 0000000000000000000000000000000000000000..37070a047337edfdcbe54a811c08c75dac84a636 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/R.java @@ -0,0 +1,116 @@ +package com.RVSmartPorting.common.core.domain; + +import com.RVSmartPorting.common.constant.HttpStatus; + +import java.io.Serializable; + +/** + * 响应信息主体 + * + * @author ruoyi + */ +public class R implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** 成功 */ + public static final int SUCCESS = HttpStatus.SUCCESS; + + /** 失败 */ + public static final int FAIL = HttpStatus.ERROR; + + 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(T data, String msg) + { + 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(T data, String msg) + { + return restResult(data, FAIL, msg); + } + + public static R fail(int code, String msg) + { + return restResult(null, code, msg); + } + + private static R restResult(T data, int code, String msg) + { + R apiResult = new R<>(); + apiResult.setCode(code); + apiResult.setData(data); + apiResult.setMsg(msg); + return apiResult; + } + + public int getCode() + { + return code; + } + + public void setCode(int code) + { + this.code = code; + } + + public String getMsg() + { + return msg; + } + + public void setMsg(String msg) + { + this.msg = msg; + } + + public T getData() + { + return data; + } + + public void setData(T data) + { + this.data = data; + } + + public static Boolean isError(R ret) + { + return !isSuccess(ret); + } + + public static Boolean isSuccess(R ret) + { + return R.SUCCESS == ret.getCode(); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/TreeEntity.java b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/TreeEntity.java new file mode 100644 index 0000000000000000000000000000000000000000..6b319cec7832f6bfbeb085e8d0469161f1452ab4 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/TreeEntity.java @@ -0,0 +1,79 @@ +package com.RVSmartPorting.common.core.domain; + +import java.util.ArrayList; +import java.util.List; + +/** + * Tree基类 + * + * @author ruoyi + */ +public class TreeEntity extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 父菜单名称 */ + private String parentName; + + /** 父菜单ID */ + private Long parentId; + + /** 显示顺序 */ + private Integer orderNum; + + /** 祖级列表 */ + private String ancestors; + + /** 子部门 */ + private List children = new ArrayList<>(); + + public String getParentName() + { + return parentName; + } + + public void setParentName(String parentName) + { + this.parentName = parentName; + } + + public Long getParentId() + { + return parentId; + } + + public void setParentId(Long parentId) + { + this.parentId = parentId; + } + + public Integer getOrderNum() + { + return orderNum; + } + + public void setOrderNum(Integer orderNum) + { + this.orderNum = orderNum; + } + + public String getAncestors() + { + return ancestors; + } + + public void setAncestors(String ancestors) + { + this.ancestors = ancestors; + } + + public List getChildren() + { + return children; + } + + public void setChildren(List children) + { + this.children = children; + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/TreeSelect.java b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/TreeSelect.java new file mode 100644 index 0000000000000000000000000000000000000000..3c7f3e42942ca93c2df3ddaa886b61266d3a4956 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/TreeSelect.java @@ -0,0 +1,78 @@ +package com.RVSmartPorting.common.core.domain; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.RVSmartPorting.common.core.domain.entity.SysDept; +import com.RVSmartPorting.common.core.domain.entity.SysMenu; + +import java.io.Serializable; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Treeselect树结构实体类 + * + * @author ruoyi + */ +public class TreeSelect implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** 节点ID */ + private Long id; + + /** 节点名称 */ + private String label; + + /** 子节点 */ + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private List children; + + public TreeSelect() + { + + } + + public TreeSelect(SysDept dept) + { + this.id = dept.getDeptId(); + this.label = dept.getDeptName(); + this.children = dept.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList()); + } + + public TreeSelect(SysMenu menu) + { + this.id = menu.getMenuId(); + this.label = menu.getMenuName(); + this.children = menu.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList()); + } + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public String getLabel() + { + return label; + } + + public void setLabel(String label) + { + this.label = label; + } + + public List getChildren() + { + return children; + } + + public void setChildren(List children) + { + this.children = children; + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/entity/SysDept.java b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/entity/SysDept.java new file mode 100644 index 0000000000000000000000000000000000000000..6b8bb2184dcbeb4e0a30c8a7bd4c0568011f6602 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/entity/SysDept.java @@ -0,0 +1,206 @@ +package com.RVSmartPorting.common.core.domain.entity; + +import com.RVSmartPorting.common.core.domain.BaseEntity; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.ibatis.type.Alias; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.ArrayList; +import java.util.List; + +/** + * 部门表 sys_dept + * + * @author ruoyi + */ +@Alias("SysDept") +public class SysDept extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 部门ID */ + private Long deptId; + + /** 父部门ID */ + private Long parentId; + + /** 祖级列表 */ + private String ancestors; + + /** 部门名称 */ + private String deptName; + + /** 显示顺序 */ + private Integer orderNum; + + /** 负责人 */ + private String leader; + + /** 联系电话 */ + private String phone; + + /** 邮箱 */ + private String email; + + /** 部门状态:0正常,1停用 */ + private String status; + + /** 删除标志(0代表存在 2代表删除) */ + private String delFlag; + + /** 父部门名称 */ + private String parentName; + + /** 子部门 */ + private List children = new ArrayList(); + + public Long getDeptId() + { + return deptId; + } + + public void setDeptId(Long deptId) + { + this.deptId = deptId; + } + + public Long getParentId() + { + return parentId; + } + + public void setParentId(Long parentId) + { + this.parentId = parentId; + } + + public String getAncestors() + { + return ancestors; + } + + public void setAncestors(String ancestors) + { + this.ancestors = ancestors; + } + + @NotBlank(message = "部门名称不能为空") + @Size(min = 0, max = 30, message = "部门名称长度不能超过30个字符") + public String getDeptName() + { + return deptName; + } + + public void setDeptName(String deptName) + { + this.deptName = deptName; + } + + @NotNull(message = "显示顺序不能为空") + public Integer getOrderNum() + { + return orderNum; + } + + public void setOrderNum(Integer orderNum) + { + this.orderNum = orderNum; + } + + public String getLeader() + { + return leader; + } + + public void setLeader(String leader) + { + this.leader = leader; + } + + @Size(min = 0, max = 11, message = "联系电话长度不能超过11个字符") + public String getPhone() + { + return phone; + } + + public void setPhone(String phone) + { + this.phone = phone; + } + + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符") + public String getEmail() + { + return email; + } + + public void setEmail(String email) + { + this.email = email; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + public String getDelFlag() + { + return delFlag; + } + + public void setDelFlag(String delFlag) + { + this.delFlag = delFlag; + } + + public String getParentName() + { + return parentName; + } + + public void setParentName(String parentName) + { + this.parentName = parentName; + } + + public List getChildren() + { + return children; + } + + public void setChildren(List children) + { + this.children = children; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("deptId", getDeptId()) + .append("parentId", getParentId()) + .append("ancestors", getAncestors()) + .append("deptName", getDeptName()) + .append("orderNum", getOrderNum()) + .append("leader", getLeader()) + .append("phone", getPhone()) + .append("email", getEmail()) + .append("status", getStatus()) + .append("delFlag", getDelFlag()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .toString(); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/entity/SysDictData.java b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/entity/SysDictData.java new file mode 100644 index 0000000000000000000000000000000000000000..1e45297d323783000c0ea2ec2019aa5660f6cb6f --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/entity/SysDictData.java @@ -0,0 +1,179 @@ +package com.RVSmartPorting.common.core.domain.entity; + +import com.RVSmartPorting.common.annotation.Excel; +import com.RVSmartPorting.common.annotation.Excel.ColumnType; +import com.RVSmartPorting.common.constant.UserConstants; +import com.RVSmartPorting.common.core.domain.BaseEntity; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.ibatis.type.Alias; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; + +/** + * 字典数据表 sys_dict_data + * + * @author ruoyi + */ +@Alias("SysDictData") +public class SysDictData extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 字典编码 */ + @Excel(name = "字典编码", cellType = ColumnType.NUMERIC) + private Long dictCode; + + /** 字典排序 */ + @Excel(name = "字典排序", cellType = ColumnType.NUMERIC) + private Long dictSort; + + /** 字典标签 */ + @Excel(name = "字典标签") + private String dictLabel; + + /** 字典键值 */ + @Excel(name = "字典键值") + private String dictValue; + + /** 字典类型 */ + @Excel(name = "字典类型") + private String dictType; + + /** 样式属性(其他样式扩展) */ + private String cssClass; + + /** 表格字典样式 */ + private String listClass; + + /** 是否默认(Y是 N否) */ + @Excel(name = "是否默认", readConverterExp = "Y=是,N=否") + private String isDefault; + + /** 状态(0正常 1停用) */ + @Excel(name = "状态", readConverterExp = "0=正常,1=停用") + private String status; + + public Long getDictCode() + { + return dictCode; + } + + public void setDictCode(Long dictCode) + { + this.dictCode = dictCode; + } + + public Long getDictSort() + { + return dictSort; + } + + public void setDictSort(Long dictSort) + { + this.dictSort = dictSort; + } + + @NotBlank(message = "字典标签不能为空") + @Size(min = 0, max = 100, message = "字典标签长度不能超过100个字符") + public String getDictLabel() + { + return dictLabel; + } + + public void setDictLabel(String dictLabel) + { + this.dictLabel = dictLabel; + } + + @NotBlank(message = "字典键值不能为空") + @Size(min = 0, max = 100, message = "字典键值长度不能超过100个字符") + public String getDictValue() + { + return dictValue; + } + + public void setDictValue(String dictValue) + { + this.dictValue = dictValue; + } + + @NotBlank(message = "字典类型不能为空") + @Size(min = 0, max = 100, message = "字典类型长度不能超过100个字符") + public String getDictType() + { + return dictType; + } + + public void setDictType(String dictType) + { + this.dictType = dictType; + } + + @Size(min = 0, max = 100, message = "样式属性长度不能超过100个字符") + public String getCssClass() + { + return cssClass; + } + + public void setCssClass(String cssClass) + { + this.cssClass = cssClass; + } + + public String getListClass() + { + return listClass; + } + + public void setListClass(String listClass) + { + this.listClass = listClass; + } + + public boolean getDefault() + { + return UserConstants.YES.equals(this.isDefault); + } + + public String getIsDefault() + { + return isDefault; + } + + public void setIsDefault(String isDefault) + { + this.isDefault = isDefault; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("dictCode", getDictCode()) + .append("dictSort", getDictSort()) + .append("dictLabel", getDictLabel()) + .append("dictValue", getDictValue()) + .append("dictType", getDictType()) + .append("cssClass", getCssClass()) + .append("listClass", getListClass()) + .append("isDefault", getIsDefault()) + .append("status", getStatus()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/entity/SysDictType.java b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/entity/SysDictType.java new file mode 100644 index 0000000000000000000000000000000000000000..4433c4b801a06fb06f6082741be3fc951acfb9f7 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/entity/SysDictType.java @@ -0,0 +1,99 @@ +package com.RVSmartPorting.common.core.domain.entity; + +import com.RVSmartPorting.common.annotation.Excel; +import com.RVSmartPorting.common.annotation.Excel.ColumnType; +import com.RVSmartPorting.common.core.domain.BaseEntity; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.ibatis.type.Alias; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; + +/** + * 字典类型表 sys_dict_type + * + * @author ruoyi + */ +@Alias("SysDictType") +public class SysDictType extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 字典主键 */ + @Excel(name = "字典主键", cellType = ColumnType.NUMERIC) + private Long dictId; + + /** 字典名称 */ + @Excel(name = "字典名称") + private String dictName; + + /** 字典类型 */ + @Excel(name = "字典类型") + private String dictType; + + /** 状态(0正常 1停用) */ + @Excel(name = "状态", readConverterExp = "0=正常,1=停用") + private String status; + + public Long getDictId() + { + return dictId; + } + + public void setDictId(Long dictId) + { + this.dictId = dictId; + } + + @NotBlank(message = "字典名称不能为空") + @Size(min = 0, max = 100, message = "字典类型名称长度不能超过100个字符") + public String getDictName() + { + return dictName; + } + + public void setDictName(String dictName) + { + this.dictName = dictName; + } + + @NotBlank(message = "字典类型不能为空") + @Size(min = 0, max = 100, message = "字典类型类型长度不能超过100个字符") + @Pattern(regexp = "^[a-z][a-z0-9_]*$", message = "字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)") + public String getDictType() + { + return dictType; + } + + public void setDictType(String dictType) + { + this.dictType = dictType; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("dictId", getDictId()) + .append("dictName", getDictName()) + .append("dictType", getDictType()) + .append("status", getStatus()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/entity/SysMenu.java b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/entity/SysMenu.java new file mode 100644 index 0000000000000000000000000000000000000000..1c5fa758a3d8d08e14bbd487114b72cd55d448b9 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/entity/SysMenu.java @@ -0,0 +1,262 @@ +package com.RVSmartPorting.common.core.domain.entity; + +import com.RVSmartPorting.common.core.domain.BaseEntity; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.ibatis.type.Alias; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.ArrayList; +import java.util.List; + +/** + * 菜单权限表 sys_menu + * + * @author ruoyi + */ +@Alias("SysMenu") +public class SysMenu extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 菜单ID */ + private Long menuId; + + /** 菜单名称 */ + private String menuName; + + /** 父菜单名称 */ + private String parentName; + + /** 父菜单ID */ + private Long parentId; + + /** 显示顺序 */ + private Integer orderNum; + + /** 路由地址 */ + private String path; + + /** 组件路径 */ + private String component; + + /** 路由参数 */ + private String query; + + /** 是否为外链(0是 1否) */ + private String isFrame; + + /** 是否缓存(0缓存 1不缓存) */ + private String isCache; + + /** 类型(M目录 C菜单 F按钮) */ + private String menuType; + + /** 显示状态(0显示 1隐藏) */ + private String visible; + + /** 菜单状态(0正常 1停用) */ + private String status; + + /** 权限字符串 */ + private String perms; + + /** 菜单图标 */ + private String icon; + + /** 子菜单 */ + private List children = new ArrayList(); + + public Long getMenuId() + { + return menuId; + } + + public void setMenuId(Long menuId) + { + this.menuId = menuId; + } + + @NotBlank(message = "菜单名称不能为空") + @Size(min = 0, max = 50, message = "菜单名称长度不能超过50个字符") + public String getMenuName() + { + return menuName; + } + + public void setMenuName(String menuName) + { + this.menuName = menuName; + } + + public String getParentName() + { + return parentName; + } + + public void setParentName(String parentName) + { + this.parentName = parentName; + } + + public Long getParentId() + { + return parentId; + } + + public void setParentId(Long parentId) + { + this.parentId = parentId; + } + + @NotNull(message = "显示顺序不能为空") + public Integer getOrderNum() + { + return orderNum; + } + + public void setOrderNum(Integer orderNum) + { + this.orderNum = orderNum; + } + + @Size(min = 0, max = 200, message = "路由地址不能超过200个字符") + public String getPath() + { + return path; + } + + public void setPath(String path) + { + this.path = path; + } + + @Size(min = 0, max = 200, message = "组件路径不能超过255个字符") + 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 String getIsFrame() + { + return isFrame; + } + + public void setIsFrame(String isFrame) + { + this.isFrame = isFrame; + } + + public String getIsCache() + { + return isCache; + } + + public void setIsCache(String isCache) + { + this.isCache = isCache; + } + + @NotBlank(message = "菜单类型不能为空") + public String getMenuType() + { + return menuType; + } + + public void setMenuType(String menuType) + { + this.menuType = menuType; + } + + public String getVisible() + { + return visible; + } + + public void setVisible(String visible) + { + this.visible = visible; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + @Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符") + public String getPerms() + { + return perms; + } + + public void setPerms(String perms) + { + this.perms = perms; + } + + public String getIcon() + { + return icon; + } + + public void setIcon(String icon) + { + this.icon = icon; + } + + public List getChildren() + { + return children; + } + + public void setChildren(List children) + { + this.children = children; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("menuId", getMenuId()) + .append("menuName", getMenuName()) + .append("parentId", getParentId()) + .append("orderNum", getOrderNum()) + .append("path", getPath()) + .append("component", getComponent()) + .append("isFrame", getIsFrame()) + .append("IsCache", getIsCache()) + .append("menuType", getMenuType()) + .append("visible", getVisible()) + .append("status ", getStatus()) + .append("perms", getPerms()) + .append("icon", getIcon()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/entity/SysRole.java b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/entity/SysRole.java new file mode 100644 index 0000000000000000000000000000000000000000..53b161a4632802734d6449daf7d474c7a78d02d7 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/entity/SysRole.java @@ -0,0 +1,244 @@ +package com.RVSmartPorting.common.core.domain.entity; + +import com.RVSmartPorting.common.annotation.Excel; +import com.RVSmartPorting.common.annotation.Excel.ColumnType; +import com.RVSmartPorting.common.core.domain.BaseEntity; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.ibatis.type.Alias; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Set; + +/** + * 角色表 sys_role + * + * @author ruoyi + */ +@Alias("SysRole") +public class SysRole extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 角色ID */ + @Excel(name = "角色序号", cellType = ColumnType.NUMERIC) + private Long roleId; + + /** 角色名称 */ + @Excel(name = "角色名称") + private String roleName; + + /** 角色权限 */ + @Excel(name = "角色权限") + private String roleKey; + + /** 角色排序 */ + @Excel(name = "角色排序") + private Integer roleSort; + + /** 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限) */ + @Excel(name = "数据范围", readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限") + private String dataScope; + + /** 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示) */ + private boolean menuCheckStrictly; + + /** 部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示 ) */ + private boolean deptCheckStrictly; + + /** 角色状态(0正常 1停用) */ + @Excel(name = "角色状态", readConverterExp = "0=正常,1=停用") + private String status; + + /** 删除标志(0代表存在 2代表删除) */ + private String delFlag; + + /** 用户是否存在此角色标识 默认不存在 */ + private boolean flag = false; + + /** 菜单组 */ + private Long[] menuIds; + + /** 部门组(数据权限) */ + private Long[] deptIds; + + /** 角色菜单权限 */ + private Set permissions; + + public SysRole() + { + + } + + public SysRole(Long roleId) + { + this.roleId = roleId; + } + + public Long getRoleId() + { + return roleId; + } + + public void setRoleId(Long roleId) + { + this.roleId = roleId; + } + + public boolean isAdmin() + { + return isAdmin(this.roleId); + } + + public static boolean isAdmin(Long roleId) + { + return roleId != null && 1L == roleId; + } + + @NotBlank(message = "角色名称不能为空") + @Size(min = 0, max = 30, message = "角色名称长度不能超过30个字符") + public String getRoleName() + { + return roleName; + } + + public void setRoleName(String roleName) + { + this.roleName = roleName; + } + + @NotBlank(message = "权限字符不能为空") + @Size(min = 0, max = 100, message = "权限字符长度不能超过100个字符") + public String getRoleKey() + { + return roleKey; + } + + public void setRoleKey(String roleKey) + { + this.roleKey = roleKey; + } + + @NotNull(message = "显示顺序不能为空") + public Integer getRoleSort() + { + return roleSort; + } + + public void setRoleSort(Integer roleSort) + { + this.roleSort = roleSort; + } + + public String getDataScope() + { + return dataScope; + } + + public void setDataScope(String dataScope) + { + this.dataScope = dataScope; + } + + public boolean isMenuCheckStrictly() + { + return menuCheckStrictly; + } + + public void setMenuCheckStrictly(boolean menuCheckStrictly) + { + this.menuCheckStrictly = menuCheckStrictly; + } + + public boolean isDeptCheckStrictly() + { + return deptCheckStrictly; + } + + public void setDeptCheckStrictly(boolean deptCheckStrictly) + { + this.deptCheckStrictly = deptCheckStrictly; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + public String getDelFlag() + { + return delFlag; + } + + public void setDelFlag(String delFlag) + { + this.delFlag = delFlag; + } + + public boolean isFlag() + { + return flag; + } + + public void setFlag(boolean flag) + { + this.flag = flag; + } + + public Long[] getMenuIds() + { + return menuIds; + } + + public void setMenuIds(Long[] menuIds) + { + this.menuIds = menuIds; + } + + public Long[] getDeptIds() + { + return deptIds; + } + + public void setDeptIds(Long[] deptIds) + { + this.deptIds = deptIds; + } + + public Set getPermissions() + { + return permissions; + } + + public void setPermissions(Set permissions) + { + this.permissions = permissions; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("roleId", getRoleId()) + .append("roleName", getRoleName()) + .append("roleKey", getRoleKey()) + .append("roleSort", getRoleSort()) + .append("dataScope", getDataScope()) + .append("menuCheckStrictly", isMenuCheckStrictly()) + .append("deptCheckStrictly", isDeptCheckStrictly()) + .append("status", getStatus()) + .append("delFlag", getDelFlag()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/entity/SysUser.java b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/entity/SysUser.java new file mode 100644 index 0000000000000000000000000000000000000000..6d4ffff61cf0b05b16c6dfb227e13577e3d21f8c --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/entity/SysUser.java @@ -0,0 +1,340 @@ +package com.RVSmartPorting.common.core.domain.entity; + +import com.RVSmartPorting.common.annotation.Excel; +import com.RVSmartPorting.common.annotation.Excel.ColumnType; +import com.RVSmartPorting.common.annotation.Excel.Type; +import com.RVSmartPorting.common.annotation.Excels; +import com.RVSmartPorting.common.core.domain.BaseEntity; +import com.RVSmartPorting.common.xss.Xss; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.ibatis.type.Alias; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; +import java.util.Date; +import java.util.List; + +/** + * 用户对象 sys_user + * + * @author ruoyi + */ +@Alias("SysUser") +public class SysUser extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 用户ID */ + @Excel(name = "用户序号", cellType = ColumnType.NUMERIC, prompt = "用户编号") + private Long userId; + + /** 部门ID */ + @Excel(name = "部门编号", type = Type.IMPORT) + private Long deptId; + + /** 用户账号 */ + @Excel(name = "登录名称") + private String userName; + + /** 用户昵称 */ + @Excel(name = "用户名称") + private String nickName; + + /** 用户邮箱 */ + @Excel(name = "用户邮箱") + private String email; + + /** 手机号码 */ + @Excel(name = "手机号码") + private String phonenumber; + + /** 用户性别 */ + @Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知") + private String sex; + + /** 用户头像 */ + private String avatar; + + /** 密码 */ + private String password; + + /** 帐号状态(0正常 1停用) */ + @Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用") + private String status; + + /** 删除标志(0代表存在 2代表删除) */ + private String delFlag; + + /** 最后登录IP */ + @Excel(name = "最后登录IP", type = Type.EXPORT) + private String loginIp; + + /** 最后登录时间 */ + @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT) + private Date loginDate; + + /** 部门对象 */ + @Excels({ + @Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT), + @Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT) + }) + private SysDept dept; + + /** 角色对象 */ + private List roles; + + /** 角色组 */ + private Long[] roleIds; + + /** 岗位组 */ + private Long[] postIds; + + /** 角色ID */ + private Long roleId; + + /** 用户UUID */ + private String userUUID; + + public SysUser() + { + + } + + public SysUser(Long userId) + { + this.userId = userId; + } + + public Long getUserId() + { + return userId; + } + + public void setUserId(Long userId) + { + this.userId = userId; + } + + public boolean isAdmin() + { + return isAdmin(this.userId); + } + + public static boolean isAdmin(Long userId) + { + return userId != null && 1L == userId; + } + + public Long getDeptId() + { + return deptId; + } + + public void setDeptId(Long deptId) + { + this.deptId = deptId; + } + + @Xss(message = "用户昵称不能包含脚本字符") + @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符") + public String getNickName() + { + return nickName; + } + + public void setNickName(String nickName) + { + this.nickName = nickName; + } + + @Xss(message = "用户账号不能包含脚本字符") + @NotBlank(message = "用户账号不能为空") + @Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符") + public String getUserName() + { + return userName; + } + + public void setUserName(String userName) + { + this.userName = userName; + } + + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符") + public String getEmail() + { + return email; + } + + public void setEmail(String email) + { + this.email = email; + } + + @Size(min = 0, max = 11, message = "手机号码长度不能超过11个字符") + public String getPhonenumber() + { + return phonenumber; + } + + public void setPhonenumber(String phonenumber) + { + this.phonenumber = phonenumber; + } + + public String getSex() + { + return sex; + } + + public void setSex(String sex) + { + this.sex = sex; + } + + public String getAvatar() + { + return avatar; + } + + public void setAvatar(String avatar) + { + this.avatar = avatar; + } + + public String getPassword() + { + return password; + } + + public void setPassword(String password) + { + this.password = password; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + public String getDelFlag() + { + return delFlag; + } + + public void setDelFlag(String delFlag) + { + this.delFlag = delFlag; + } + + public String getLoginIp() + { + return loginIp; + } + + public void setLoginIp(String loginIp) + { + this.loginIp = loginIp; + } + + public Date getLoginDate() + { + return loginDate; + } + + public void setLoginDate(Date loginDate) + { + this.loginDate = loginDate; + } + + public SysDept getDept() + { + return dept; + } + + public void setDept(SysDept dept) + { + this.dept = dept; + } + + public List getRoles() + { + return roles; + } + + public void setRoles(List roles) + { + this.roles = roles; + } + + public Long[] getRoleIds() + { + return roleIds; + } + + public void setRoleIds(Long[] roleIds) + { + this.roleIds = roleIds; + } + + public Long[] getPostIds() + { + return postIds; + } + + public void setPostIds(Long[] postIds) + { + this.postIds = postIds; + } + + public Long getRoleId() + { + return roleId; + } + + public void setRoleId(Long roleId) + { + this.roleId = roleId; + } + + public String getUserUUID() { + return userUUID; + } + + public void setUserUUID(String userUUID) { + this.userUUID = userUUID; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("userId", getUserId()) + .append("deptId", getDeptId()) + .append("userName", getUserName()) + .append("nickName", getNickName()) + .append("email", getEmail()) + .append("phonenumber", getPhonenumber()) + .append("sex", getSex()) + .append("avatar", getAvatar()) + .append("password", getPassword()) + .append("status", getStatus()) + .append("delFlag", getDelFlag()) + .append("loginIp", getLoginIp()) + .append("loginDate", getLoginDate()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .append("dept", getDept()) + .toString(); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/model/LoginBody.java b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/model/LoginBody.java new file mode 100644 index 0000000000000000000000000000000000000000..06e08f1dbbff79c15e8528d7c2a9efbe870c13ef --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/model/LoginBody.java @@ -0,0 +1,69 @@ +package com.RVSmartPorting.common.core.domain.model; + +/** + * 用户登录对象 + * + * @author ruoyi + */ +public class LoginBody +{ + /** + * 用户名 + */ + private String username; + + /** + * 用户密码 + */ + private String password; + + /** + * 验证码 + */ + private String code; + + /** + * 唯一标识 + */ + private String uuid; + + public String getUsername() + { + return username; + } + + public void setUsername(String username) + { + this.username = username; + } + + public String getPassword() + { + return password; + } + + public void setPassword(String password) + { + this.password = password; + } + + public String getCode() + { + return code; + } + + public void setCode(String code) + { + this.code = code; + } + + public String getUuid() + { + return uuid; + } + + public void setUuid(String uuid) + { + this.uuid = uuid; + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/model/LoginUser.java b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/model/LoginUser.java new file mode 100644 index 0000000000000000000000000000000000000000..fca32e8bf03c83b1116b9a6d068495e0a3ecd22f --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/model/LoginUser.java @@ -0,0 +1,269 @@ +package com.RVSmartPorting.common.core.domain.model; + +import com.RVSmartPorting.common.core.domain.entity.SysUser; +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Data; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.Collection; +import java.util.Set; + +/** + * 登录用户身份权限 + * + * @author ruoyi + */ +@Data +public class LoginUser implements UserDetails +{ + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + private Long userId; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 用户唯一标识 + */ + private String token; + + /** + * 登录时间 + */ + private Long loginTime; + + /** + * 过期时间 + */ + private Long expireTime; + + /** + * 登录IP地址 + */ + private String ipaddr; + + /** + * 登录地点 + */ + private String loginLocation; + + /** + * 浏览器类型 + */ + private String browser; + + /** + * 操作系统 + */ + private String os; + + /** + * 权限列表 + */ + private Set permissions; + + /** + * 用户信息 + */ + private SysUser user; + + public LoginUser() + { + } + + public LoginUser(SysUser user, Set permissions) + { + this.user = user; + this.permissions = permissions; + } + + public LoginUser(Long userId, Long deptId, SysUser user, Set permissions) + { + this.userId = userId; + this.deptId = deptId; + this.user = user; + this.permissions = permissions; + } + + public Long getUserId() + { + return userId; + } + + public void setUserId(Long userId) + { + this.userId = userId; + } + + public Long getDeptId() + { + return deptId; + } + + public void setDeptId(Long deptId) + { + this.deptId = deptId; + } + + public String getToken() + { + return token; + } + + public void setToken(String token) + { + this.token = token; + } + + @JSONField(serialize = false) + @Override + public String getPassword() + { + return user.getPassword(); + } + + @Override + public String getUsername() + { + return user.getUserName(); + } + + /** + * 账户是否未过期,过期无法验证 + */ + @JSONField(serialize = false) + @Override + public boolean isAccountNonExpired() + { + return true; + } + + /** + * 指定用户是否解锁,锁定的用户无法进行身份验证 + * + * @return + */ + @JSONField(serialize = false) + @Override + public boolean isAccountNonLocked() + { + return true; + } + + /** + * 指示是否已过期的用户的凭据(密码),过期的凭据防止认证 + * + * @return + */ + @JSONField(serialize = false) + @Override + public boolean isCredentialsNonExpired() + { + return true; + } + + /** + * 是否可用 ,禁用的用户不能身份验证 + * + * @return + */ + @JSONField(serialize = false) + @Override + public boolean isEnabled() + { + return true; + } + + public Long getLoginTime() + { + return loginTime; + } + + public void setLoginTime(Long loginTime) + { + this.loginTime = loginTime; + } + + public String getIpaddr() + { + return ipaddr; + } + + public void setIpaddr(String ipaddr) + { + this.ipaddr = ipaddr; + } + + public String getLoginLocation() + { + return loginLocation; + } + + public void setLoginLocation(String loginLocation) + { + this.loginLocation = loginLocation; + } + + public String getBrowser() + { + return browser; + } + + public void setBrowser(String browser) + { + this.browser = browser; + } + + public String getOs() + { + return os; + } + + public void setOs(String os) + { + this.os = os; + } + + public Long getExpireTime() + { + return expireTime; + } + + public void setExpireTime(Long expireTime) + { + this.expireTime = expireTime; + } + + public Set getPermissions() + { + return permissions; + } + + public void setPermissions(Set permissions) + { + this.permissions = permissions; + } + + public SysUser getUser() + { + return user; + } + + public void setUser(SysUser user) + { + this.user = user; + } + + @Override + public Collection getAuthorities() + { + return null; + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/model/RegisterBody.java b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/model/RegisterBody.java new file mode 100644 index 0000000000000000000000000000000000000000..ea1c81a5199c7d98e7e635537ba9729d363ae2e0 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/core/domain/model/RegisterBody.java @@ -0,0 +1,11 @@ +package com.RVSmartPorting.common.core.domain.model; + +/** + * 用户注册对象 + * + * @author ruoyi + */ +public class RegisterBody extends LoginBody +{ + +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/core/page/PageDomain.java b/CSP-common/src/main/java/com/RVSmartPorting/common/core/page/PageDomain.java new file mode 100644 index 0000000000000000000000000000000000000000..561ab600ab8ac70aca1cc95138a711c62dac5e8f --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/core/page/PageDomain.java @@ -0,0 +1,101 @@ +package com.RVSmartPorting.common.core.page; + +import com.RVSmartPorting.common.utils.StringUtils; + +/** + * 分页数据 + * + * @author ruoyi + */ +public class PageDomain +{ + /** 当前记录起始索引 */ + private Integer pageNum; + + /** 每页显示记录数 */ + private Integer pageSize; + + /** 排序列 */ + private String orderByColumn; + + /** 排序的方向desc或者asc */ + private String isAsc = "asc"; + + /** 分页参数合理化 */ + private Boolean reasonable = true; + + public String getOrderBy() + { + if (StringUtils.isEmpty(orderByColumn)) + { + return ""; + } + return StringUtils.toUnderScoreCase(orderByColumn) + " " + isAsc; + } + + public Integer getPageNum() + { + return pageNum; + } + + public void setPageNum(Integer pageNum) + { + this.pageNum = pageNum; + } + + public Integer getPageSize() + { + return pageSize; + } + + public void setPageSize(Integer pageSize) + { + this.pageSize = pageSize; + } + + public String getOrderByColumn() + { + return orderByColumn; + } + + public void setOrderByColumn(String orderByColumn) + { + this.orderByColumn = orderByColumn; + } + + public String getIsAsc() + { + return isAsc; + } + + public void setIsAsc(String isAsc) + { + if (StringUtils.isNotEmpty(isAsc)) + { + // 兼容前端排序类型 + if ("ascending".equals(isAsc)) + { + isAsc = "asc"; + } + else if ("descending".equals(isAsc)) + { + isAsc = "desc"; + } + this.isAsc = isAsc; + } + } + + public Boolean getReasonable() + { + if (StringUtils.isNull(reasonable)) + { + return Boolean.TRUE; + } + return reasonable; + } + + public void setReasonable(Boolean reasonable) + { + this.reasonable = reasonable; + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/core/page/TableDataInfo.java b/CSP-common/src/main/java/com/RVSmartPorting/common/core/page/TableDataInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..81a3712631d56a243fb72078a20a2c8f09ba7b6f --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/core/page/TableDataInfo.java @@ -0,0 +1,85 @@ +package com.RVSmartPorting.common.core.page; + +import java.io.Serializable; +import java.util.List; + +/** + * 表格分页数据对象 + * + * @author ruoyi + */ +public class TableDataInfo implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** 总记录数 */ + private long total; + + /** 列表数据 */ + private List rows; + + /** 消息状态码 */ + private int code; + + /** 消息内容 */ + private String msg; + + /** + * 表格数据对象 + */ + public TableDataInfo() + { + } + + /** + * 分页 + * + * @param list 列表数据 + * @param total 总记录数 + */ + public TableDataInfo(List list, int total) + { + this.rows = list; + this.total = total; + } + + public long getTotal() + { + return total; + } + + public void setTotal(long total) + { + this.total = total; + } + + public List getRows() + { + return rows; + } + + public void setRows(List rows) + { + this.rows = rows; + } + + public int getCode() + { + return code; + } + + public void setCode(int code) + { + this.code = code; + } + + public String getMsg() + { + return msg; + } + + public void setMsg(String msg) + { + this.msg = msg; + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/core/page/TableSupport.java b/CSP-common/src/main/java/com/RVSmartPorting/common/core/page/TableSupport.java new file mode 100644 index 0000000000000000000000000000000000000000..2c5d985858b96b1bf4a30f19f99586c00fcc233e --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/core/page/TableSupport.java @@ -0,0 +1,56 @@ +package com.RVSmartPorting.common.core.page; + +import com.RVSmartPorting.common.utils.ServletUtils; +import com.RVSmartPorting.common.core.text.Convert; + +/** + * 表格数据处理 + * + * @author ruoyi + */ +public class TableSupport +{ + /** + * 当前记录起始索引 + */ + public static final String PAGE_NUM = "pageNum"; + + /** + * 每页显示记录数 + */ + public static final String PAGE_SIZE = "pageSize"; + + /** + * 排序列 + */ + public static final String ORDER_BY_COLUMN = "orderByColumn"; + + /** + * 排序的方向 "desc" 或者 "asc". + */ + public static final String IS_ASC = "isAsc"; + + /** + * 分页参数合理化 + */ + public static final String REASONABLE = "reasonable"; + + /** + * 封装分页对象 + */ + public static PageDomain getPageDomain() + { + PageDomain pageDomain = new PageDomain(); + pageDomain.setPageNum(Convert.toInt(ServletUtils.getParameter(PAGE_NUM), 1)); + pageDomain.setPageSize(Convert.toInt(ServletUtils.getParameter(PAGE_SIZE), 10)); + pageDomain.setOrderByColumn(ServletUtils.getParameter(ORDER_BY_COLUMN)); + pageDomain.setIsAsc(ServletUtils.getParameter(IS_ASC)); + pageDomain.setReasonable(ServletUtils.getParameterToBool(REASONABLE)); + return pageDomain; + } + + public static PageDomain buildPageRequest() + { + return getPageDomain(); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/core/text/CharsetKit.java b/CSP-common/src/main/java/com/RVSmartPorting/common/core/text/CharsetKit.java new file mode 100644 index 0000000000000000000000000000000000000000..3573851058bb04d11b58c81d94223410c1ec3f2b --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/core/text/CharsetKit.java @@ -0,0 +1,94 @@ +package com.RVSmartPorting.common.core.text; + +/** + * 字符集工具类 + * + * @author ruoyi + */ + +import com.RVSmartPorting.common.utils.StringUtils; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +/** + * 字符集工具类 + * + * @author ruoyi + */ +public class CharsetKit +{ + /** ISO-8859-1 */ + public static final String ISO_8859_1 = "ISO-8859-1"; + /** UTF-8 */ + public static final String UTF_8 = "UTF-8"; + /** GBK */ + public static final String GBK = "GBK"; + + /** ISO-8859-1 */ + public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1); + /** UTF-8 */ + public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8); + /** GBK */ + public static final Charset CHARSET_GBK = Charset.forName(GBK); + + /** + * 转换为Charset对象 + * + * @param charset 字符集,为空则返回默认字符集 + * @return Charset + */ + public static Charset charset(String charset) + { + return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset); + } + + /** + * 转换字符串的字符集编码 + * + * @param source 字符串 + * @param srcCharset 源字符集,默认ISO-8859-1 + * @param destCharset 目标字符集,默认UTF-8 + * @return 转换后的字符集 + */ + public static String convert(String source, String srcCharset, String destCharset) + { + return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset)); + } + + /** + * 转换字符串的字符集编码 + * + * @param source 字符串 + * @param srcCharset 源字符集,默认ISO-8859-1 + * @param destCharset 目标字符集,默认UTF-8 + * @return 转换后的字符集 + */ + public static String convert(String source, Charset srcCharset, Charset destCharset) + { + if (null == srcCharset) + { + srcCharset = StandardCharsets.ISO_8859_1; + } + + if (null == destCharset) + { + destCharset = StandardCharsets.UTF_8; + } + + if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset)) + { + return source; + } + return new String(source.getBytes(srcCharset), destCharset); + } + + /** + * @return 系统字符集编码 + */ + public static String systemCharset() + { + return Charset.defaultCharset().name(); + } +} + diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/core/text/Convert.java b/CSP-common/src/main/java/com/RVSmartPorting/common/core/text/Convert.java new file mode 100644 index 0000000000000000000000000000000000000000..c0a0c019abeb13b71861f48dcfbe6daaffe325b4 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/core/text/Convert.java @@ -0,0 +1,1002 @@ +package com.RVSmartPorting.common.core.text; + +/** + * 类型转换器 + * + * @author ruoyi + */ + +import com.RVSmartPorting.common.utils.StringUtils; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.text.NumberFormat; +import java.util.Set; + +public class Convert +{ + /** + * 转换为字符串
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static String toStr(Object value, String defaultValue) + { + if (null == value) + { + return defaultValue; + } + if (value instanceof String) + { + return (String) value; + } + return value.toString(); + } + + /** + * 转换为字符串
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static String toStr(Object value) + { + return toStr(value, null); + } + + /** + * 转换为字符
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Character toChar(Object value, Character defaultValue) + { + if (null == value) + { + return defaultValue; + } + if (value instanceof Character) + { + return (Character) value; + } + + final String valueStr = toStr(value, null); + return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0); + } + + /** + * 转换为字符
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Character toChar(Object value) + { + return toChar(value, null); + } + + /** + * 转换为byte
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Byte toByte(Object value, Byte defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Byte) + { + return (Byte) value; + } + if (value instanceof Number) + { + return ((Number) value).byteValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Byte.parseByte(valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为byte
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Byte toByte(Object value) + { + return toByte(value, null); + } + + /** + * 转换为Short
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Short toShort(Object value, Short defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Short) + { + return (Short) value; + } + if (value instanceof Number) + { + return ((Number) value).shortValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Short.parseShort(valueStr.trim()); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为Short
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Short toShort(Object value) + { + return toShort(value, null); + } + + /** + * 转换为Number
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Number toNumber(Object value, Number defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Number) + { + return (Number) value; + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return NumberFormat.getInstance().parse(valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为Number
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Number toNumber(Object value) + { + return toNumber(value, null); + } + + /** + * 转换为int
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Integer toInt(Object value, Integer defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Integer) + { + return (Integer) value; + } + if (value instanceof Number) + { + return ((Number) value).intValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Integer.parseInt(valueStr.trim()); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为int
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Integer toInt(Object value) + { + return toInt(value, null); + } + + /** + * 转换为Integer数组
+ * + * @param str 被转换的值 + * @return 结果 + */ + public static Integer[] toIntArray(String str) + { + return toIntArray(",", str); + } + + /** + * 转换为Long数组
+ * + * @param str 被转换的值 + * @return 结果 + */ + public static Long[] toLongArray(String str) + { + return toLongArray(",", str); + } + + /** + * 转换为Integer数组
+ * + * @param split 分隔符 + * @param split 被转换的值 + * @return 结果 + */ + public static Integer[] toIntArray(String split, String str) + { + if (StringUtils.isEmpty(str)) + { + return new Integer[] {}; + } + String[] arr = str.split(split); + final Integer[] ints = new Integer[arr.length]; + for (int i = 0; i < arr.length; i++) + { + final Integer v = toInt(arr[i], 0); + ints[i] = v; + } + return ints; + } + + /** + * 转换为Long数组
+ * + * @param split 分隔符 + * @param str 被转换的值 + * @return 结果 + */ + public static Long[] toLongArray(String split, String str) + { + if (StringUtils.isEmpty(str)) + { + return new Long[] {}; + } + String[] arr = str.split(split); + final Long[] longs = new Long[arr.length]; + for (int i = 0; i < arr.length; i++) + { + final Long v = toLong(arr[i], null); + longs[i] = v; + } + return longs; + } + + /** + * 转换为String数组
+ * + * @param str 被转换的值 + * @return 结果 + */ + public static String[] toStrArray(String str) + { + return toStrArray(",", str); + } + + /** + * 转换为String数组
+ * + * @param split 分隔符 + * @param split 被转换的值 + * @return 结果 + */ + public static String[] toStrArray(String split, String str) + { + return str.split(split); + } + + /** + * 转换为long
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Long toLong(Object value, Long defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Long) + { + return (Long) value; + } + if (value instanceof Number) + { + return ((Number) value).longValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + // 支持科学计数法 + return new BigDecimal(valueStr.trim()).longValue(); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为long
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Long toLong(Object value) + { + return toLong(value, null); + } + + /** + * 转换为double
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Double toDouble(Object value, Double defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Double) + { + return (Double) value; + } + if (value instanceof Number) + { + return ((Number) value).doubleValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + // 支持科学计数法 + return new BigDecimal(valueStr.trim()).doubleValue(); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为double
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Double toDouble(Object value) + { + return toDouble(value, null); + } + + /** + * 转换为Float
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Float toFloat(Object value, Float defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Float) + { + return (Float) value; + } + if (value instanceof Number) + { + return ((Number) value).floatValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Float.parseFloat(valueStr.trim()); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为Float
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Float toFloat(Object value) + { + return toFloat(value, null); + } + + /** + * 转换为boolean
+ * String支持的值为:true、false、yes、ok、no,1,0 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Boolean toBool(Object value, Boolean defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Boolean) + { + return (Boolean) value; + } + String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + valueStr = valueStr.trim().toLowerCase(); + switch (valueStr) + { + case "true": + return true; + case "false": + return false; + case "yes": + return true; + case "ok": + return true; + case "no": + return false; + case "1": + return true; + case "0": + return false; + default: + return defaultValue; + } + } + + /** + * 转换为boolean
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Boolean toBool(Object value) + { + return toBool(value, null); + } + + /** + * 转换为Enum对象
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * + * @param clazz Enum的Class + * @param value 值 + * @param defaultValue 默认值 + * @return Enum + */ + public static > E toEnum(Class clazz, Object value, E defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (clazz.isAssignableFrom(value.getClass())) + { + @SuppressWarnings("unchecked") + E myE = (E) value; + return myE; + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Enum.valueOf(clazz, valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为Enum对象
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * + * @param clazz Enum的Class + * @param value 值 + * @return Enum + */ + public static > E toEnum(Class clazz, Object value) + { + return toEnum(clazz, value, null); + } + + /** + * 转换为BigInteger
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static BigInteger toBigInteger(Object value, BigInteger defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof BigInteger) + { + return (BigInteger) value; + } + if (value instanceof Long) + { + return BigInteger.valueOf((Long) value); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return new BigInteger(valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为BigInteger
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static BigInteger toBigInteger(Object value) + { + return toBigInteger(value, null); + } + + /** + * 转换为BigDecimal
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof BigDecimal) + { + return (BigDecimal) value; + } + if (value instanceof Long) + { + return new BigDecimal((Long) value); + } + if (value instanceof Double) + { + return new BigDecimal((Double) value); + } + if (value instanceof Integer) + { + return new BigDecimal((Integer) value); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return new BigDecimal(valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为BigDecimal
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static BigDecimal toBigDecimal(Object value) + { + return toBigDecimal(value, null); + } + + /** + * 将对象转为字符串
+ * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @return 字符串 + */ + public static String utf8Str(Object obj) + { + return str(obj, CharsetKit.CHARSET_UTF_8); + } + + /** + * 将对象转为字符串
+ * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @param charsetName 字符集 + * @return 字符串 + */ + public static String str(Object obj, String charsetName) + { + return str(obj, Charset.forName(charsetName)); + } + + /** + * 将对象转为字符串
+ * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @param charset 字符集 + * @return 字符串 + */ + public static String str(Object obj, Charset charset) + { + if (null == obj) + { + return null; + } + + if (obj instanceof String) + { + return (String) obj; + } + else if (obj instanceof byte[] || obj instanceof Byte[]) + { + return str((Byte[]) obj, charset); + } + else if (obj instanceof ByteBuffer) + { + return str((ByteBuffer) obj, charset); + } + return obj.toString(); + } + + /** + * 将byte数组转为字符串 + * + * @param bytes byte数组 + * @param charset 字符集 + * @return 字符串 + */ + public static String str(byte[] bytes, String charset) + { + return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset)); + } + + /** + * 解码字节码 + * + * @param data 字符串 + * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 + * @return 解码后的字符串 + */ + public static String str(byte[] data, Charset charset) + { + if (data == null) + { + return null; + } + + if (null == charset) + { + return new String(data); + } + return new String(data, charset); + } + + /** + * 将编码的byteBuffer数据转换为字符串 + * + * @param data 数据 + * @param charset 字符集,如果为空使用当前系统字符集 + * @return 字符串 + */ + public static String str(ByteBuffer data, String charset) + { + if (data == null) + { + return null; + } + + return str(data, Charset.forName(charset)); + } + + /** + * 将编码的byteBuffer数据转换为字符串 + * + * @param data 数据 + * @param charset 字符集,如果为空使用当前系统字符集 + * @return 字符串 + */ + public static String str(ByteBuffer data, Charset charset) + { + if (null == charset) + { + charset = Charset.defaultCharset(); + } + return charset.decode(data).toString(); + } + + // ----------------------------------------------------------------------- 全角半角转换 + /** + * 半角转全角 + * + * @param input String. + * @return 全角字符串. + */ + public static String toSBC(String input) + { + return toSBC(input, null); + } + + /** + * 半角转全角 + * + * @param input String + * @param notConvertSet 不替换的字符集合 + * @return 全角字符串. + */ + public static String toSBC(String input, Set notConvertSet) + { + char c[] = input.toCharArray(); + for (int i = 0; i < c.length; i++) + { + if (null != notConvertSet && notConvertSet.contains(c[i])) + { + // 跳过不替换的字符 + continue; + } + + if (c[i] == ' ') + { + c[i] = '\u3000'; + } + else if (c[i] < '\177') + { + c[i] = (char) (c[i] + 65248); + + } + } + return new String(c); + } + + /** + * 全角转半角 + * + * @param input String. + * @return 半角字符串 + */ + public static String toDBC(String input) + { + return toDBC(input, null); + } + + /** + * 替换全角为半角 + * + * @param text 文本 + * @param notConvertSet 不替换的字符集合 + * @return 替换后的字符 + */ + public static String toDBC(String text, Set notConvertSet) + { + char c[] = text.toCharArray(); + for (int i = 0; i < c.length; i++) + { + if (null != notConvertSet && notConvertSet.contains(c[i])) + { + // 跳过不替换的字符 + continue; + } + + if (c[i] == '\u3000') + { + c[i] = ' '; + } + else if (c[i] > '\uFF00' && c[i] < '\uFF5F') + { + c[i] = (char) (c[i] - 65248); + } + } + String returnString = new String(c); + + return returnString; + } + + /** + * 数字金额大写转换 先写个完整的然后将如零拾替换成零 + * + * @param n 数字 + * @return 中文大写数字 + */ + public static String digitUppercase(double n) + { + String[] fraction = { "角", "分" }; + String[] digit = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" }; + String[][] unit = { { "元", "万", "亿" }, { "", "拾", "佰", "仟" } }; + + String head = n < 0 ? "负" : ""; + n = Math.abs(n); + + String s = ""; + for (int i = 0; i < fraction.length; i++) + { + s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", ""); + } + if (s.length() < 1) + { + s = "整"; + } + int integerPart = (int) Math.floor(n); + + for (int i = 0; i < unit[0].length && integerPart > 0; i++) + { + String p = ""; + for (int j = 0; j < unit[1].length && n > 0; j++) + { + p = digit[integerPart % 10] + unit[1][j] + p; + integerPart = integerPart / 10; + } + s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s; + } + return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整"); + } +} + diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/core/text/StrFormatter.java b/CSP-common/src/main/java/com/RVSmartPorting/common/core/text/StrFormatter.java new file mode 100644 index 0000000000000000000000000000000000000000..96f26967b06aff877b2c36c666aa8c5249765398 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/core/text/StrFormatter.java @@ -0,0 +1,93 @@ +package com.RVSmartPorting.common.core.text; + +import com.RVSmartPorting.common.utils.StringUtils; + +/** + * 字符串格式化 + * + * @author ruoyi + */ +public class StrFormatter +{ + public static final String EMPTY_JSON = "{}"; + public static final char C_BACKSLASH = '\\'; + public static final char C_DELIM_START = '{'; + public static final char C_DELIM_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 strPattern 字符串模板 + * @param argArray 参数列表 + * @return 结果 + */ + public static String format(final String strPattern, final Object... argArray) + { + if (StringUtils.isEmpty(strPattern) || StringUtils.isEmpty(argArray)) + { + return strPattern; + } + final int strPatternLength = strPattern.length(); + + // 初始化定义好的长度以获得更好的性能 + StringBuilder sbuf = new StringBuilder(strPatternLength + 50); + + int handledPosition = 0; + int delimIndex;// 占位符所在位置 + for (int argIndex = 0; argIndex < argArray.length; argIndex++) + { + delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition); + if (delimIndex == -1) + { + if (handledPosition == 0) + { + return strPattern; + } + else + { // 字符串模板剩余部分不再包含占位符,加入剩余部分后返回结果 + sbuf.append(strPattern, handledPosition, strPatternLength); + return sbuf.toString(); + } + } + else + { + if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH) + { + if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH) + { + // 转义符之前还有一个转义符,占位符依旧有效 + sbuf.append(strPattern, handledPosition, delimIndex - 1); + sbuf.append(Convert.utf8Str(argArray[argIndex])); + handledPosition = delimIndex + 2; + } + else + { + // 占位符被转义 + argIndex--; + sbuf.append(strPattern, handledPosition, delimIndex - 1); + sbuf.append(C_DELIM_START); + handledPosition = delimIndex + 1; + } + } + else + { + // 正常占位符 + sbuf.append(strPattern, handledPosition, delimIndex); + sbuf.append(Convert.utf8Str(argArray[argIndex])); + handledPosition = delimIndex + 2; + } + } + } + // 加入最后一个占位符后所有的字符 + sbuf.append(strPattern, handledPosition, strPattern.length()); + + return sbuf.toString(); + } +} + diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/enums/AuthenticationMethodType.java b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/AuthenticationMethodType.java new file mode 100644 index 0000000000000000000000000000000000000000..8fbcf48d8234bc945630ba05c2688cce1ad6a959 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/AuthenticationMethodType.java @@ -0,0 +1,11 @@ +package com.RVSmartPorting.common.enums; + +/** + * @author xuqiangli + * @create 2023-09-09 10:16 + */ +public enum AuthenticationMethodType { + usernamePassword, + sshKey, + personalAccessToken +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/enums/BusinessStatus.java b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/BusinessStatus.java new file mode 100644 index 0000000000000000000000000000000000000000..9d61eac8e2bdab57428488e56fbb29f836fada3a --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/BusinessStatus.java @@ -0,0 +1,20 @@ +package com.RVSmartPorting.common.enums; + +/** + * 操作状态 + * + * @author ruoyi + * + */ +public enum BusinessStatus +{ + /** + * 成功 + */ + SUCCESS, + + /** + * 失败 + */ + FAIL, +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/enums/BusinessType.java b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/BusinessType.java new file mode 100644 index 0000000000000000000000000000000000000000..7c2a15d53b9d328aaab3d71c0b98023e33b69a50 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/BusinessType.java @@ -0,0 +1,59 @@ +package com.RVSmartPorting.common.enums; + +/** + * 业务操作类型 + * + * @author ruoyi + */ +public enum BusinessType +{ + /** + * 其它 + */ + OTHER, + + /** + * 新增 + */ + INSERT, + + /** + * 修改 + */ + UPDATE, + + /** + * 删除 + */ + DELETE, + + /** + * 授权 + */ + GRANT, + + /** + * 导出 + */ + EXPORT, + + /** + * 导入 + */ + IMPORT, + + /** + * 强退 + */ + FORCE, + + /** + * 生成代码 + */ + GENCODE, + + /** + * 清空数据 + */ + CLEAN, +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/enums/DataSourceType.java b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/DataSourceType.java new file mode 100644 index 0000000000000000000000000000000000000000..71ada7489a424a18ddef532afc733c53e43a51f1 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/DataSourceType.java @@ -0,0 +1,19 @@ +package com.RVSmartPorting.common.enums; + +/** + * 数据源 + * + * @author ruoyi + */ +public enum DataSourceType +{ + /** + * 主库 + */ + MASTER, + + /** + * 从库 + */ + SLAVE +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/enums/FileType.java b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/FileType.java new file mode 100644 index 0000000000000000000000000000000000000000..ea9a0c53c471fac2ad2557c52a511ef516266b25 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/FileType.java @@ -0,0 +1,14 @@ +package com.RVSmartPorting.common.enums; + +public enum FileType { + // 未知 + UNKNOWN, + // 压缩文件 + ZIP, RAR, RAR4, _7Z, TAR, GZ, TAR_GZ, BZ2, TAR_BZ2, + // 位图文件 + BMP, PNG, JPG, JPEG, + // 矢量图文件 + SVG, + // 影音文件 + AVI, MP4, MP3, AAR, OGG, WAV, WAVE +} \ No newline at end of file diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/enums/GitCloneAccelerateType.java b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/GitCloneAccelerateType.java new file mode 100644 index 0000000000000000000000000000000000000000..ec5e8343dc644cbdae7819f8e49db76b0e634967 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/GitCloneAccelerateType.java @@ -0,0 +1,12 @@ +package com.RVSmartPorting.common.enums; + +/** + * @author xuqiangli + * @create 2023-09-09 18:20 + */ +public enum GitCloneAccelerateType { + mirror, + http, + https, + socks5 +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/enums/GitMirrorAddressRule.java b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/GitMirrorAddressRule.java new file mode 100644 index 0000000000000000000000000000000000000000..6338fdd5e1491e6e0b618c00172f7f45a0d6b7a2 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/GitMirrorAddressRule.java @@ -0,0 +1,10 @@ +package com.RVSmartPorting.common.enums; + +/** + * @author xuqiangli + * @create 2023-09-09 18:26 + */ +public enum GitMirrorAddressRule { + direct, + replace_domain +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/enums/HttpMethod.java b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/HttpMethod.java new file mode 100644 index 0000000000000000000000000000000000000000..0ccb63655dfa8504bd59b039ab75d443f3154475 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/HttpMethod.java @@ -0,0 +1,37 @@ +package com.RVSmartPorting.common.enums; + +import org.springframework.lang.Nullable; + +import java.util.HashMap; +import java.util.Map; + +/** + * 请求方式 + * + * @author ruoyi + */ +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/CSP-common/src/main/java/com/RVSmartPorting/common/enums/LimitType.java b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/LimitType.java new file mode 100644 index 0000000000000000000000000000000000000000..8afce5b741e7c8aabcf58fc82989315c187be4f8 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/LimitType.java @@ -0,0 +1,20 @@ +package com.RVSmartPorting.common.enums; + +/** + * 限流类型 + * + * @author ruoyi + */ + +public enum LimitType +{ + /** + * 默认策略全局限流 + */ + DEFAULT, + + /** + * 根据请求者IP进行限流 + */ + IP +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/enums/OperatorType.java b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/OperatorType.java new file mode 100644 index 0000000000000000000000000000000000000000..76c4815a2f7fa372385bcb0fc46fef07eb5311a3 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/OperatorType.java @@ -0,0 +1,24 @@ +package com.RVSmartPorting.common.enums; + +/** + * 操作人类别 + * + * @author ruoyi + */ +public enum OperatorType +{ + /** + * 其它 + */ + OTHER, + + /** + * 后台用户 + */ + MANAGE, + + /** + * 手机端用户 + */ + MOBILE +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/enums/UploadType.java b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/UploadType.java new file mode 100644 index 0000000000000000000000000000000000000000..06f5223e1403496c5c809f17b01dd172d0626ac4 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/UploadType.java @@ -0,0 +1,37 @@ +package com.RVSmartPorting.common.enums; + +import org.springframework.lang.Nullable; + +import java.util.HashMap; +import java.util.Map; + +/** + * 请求方式 + * + * @author ruoyi + */ +public enum UploadType { + Git, Local, Link; + private static final Map mappings = new HashMap<>(16); + + static { + for (UploadType uploadType : values()) { + mappings.put(uploadType.name(), uploadType); + } + } + + @Nullable + public static UploadType resolve(@Nullable String uploadType) { + return (uploadType != null ? mappings.get(uploadType) : null); + } + + public boolean matches(String uploadType) { + return (this == resolve(uploadType)); + } + + + public static void main(String[] args) { + System.out.println(UploadType.Git.ordinal()); + System.out.println(UploadType.Local.ordinal()); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/enums/UserStatus.java b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/UserStatus.java new file mode 100644 index 0000000000000000000000000000000000000000..b7427705eb120379c1758baa46bb6595c7687a9b --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/enums/UserStatus.java @@ -0,0 +1,30 @@ +package com.RVSmartPorting.common.enums; + +/** + * 用户状态 + * + * @author ruoyi + */ +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/CSP-common/src/main/java/com/RVSmartPorting/common/exception/DemoModeException.java b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/DemoModeException.java new file mode 100644 index 0000000000000000000000000000000000000000..d9156465a38454d7c1a0780d35a21684498b9ce9 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/DemoModeException.java @@ -0,0 +1,15 @@ +package com.RVSmartPorting.common.exception; + +/** + * 演示模式异常 + * + * @author ruoyi + */ +public class DemoModeException extends RuntimeException +{ + private static final long serialVersionUID = 1L; + + public DemoModeException() + { + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/exception/GlobalException.java b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/GlobalException.java new file mode 100644 index 0000000000000000000000000000000000000000..8abf415ecc9f7715712f1a45bc5f50fa4041eb4e --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/GlobalException.java @@ -0,0 +1,58 @@ +package com.RVSmartPorting.common.exception; + +/** + * 全局异常 + * + * @author ruoyi + */ +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; + } +} \ No newline at end of file diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/exception/ServiceException.java b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/ServiceException.java new file mode 100644 index 0000000000000000000000000000000000000000..a271aa510de8dffca3abe915bf66b9bd1473cd6a --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/ServiceException.java @@ -0,0 +1,74 @@ +package com.RVSmartPorting.common.exception; + +/** + * 业务异常 + * + * @author ruoyi + */ +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; + } +} \ No newline at end of file diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/exception/UtilException.java b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/UtilException.java new file mode 100644 index 0000000000000000000000000000000000000000..47a385208e9a178192f4f4d05911771e0621bee0 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/UtilException.java @@ -0,0 +1,26 @@ +package com.RVSmartPorting.common.exception; + +/** + * 工具类异常 + * + * @author ruoyi + */ +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/CSP-common/src/main/java/com/RVSmartPorting/common/exception/base/BaseException.java b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/base/BaseException.java new file mode 100644 index 0000000000000000000000000000000000000000..97affaa28b225a2b1882cd0a4df5b6e6b1c50482 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/base/BaseException.java @@ -0,0 +1,97 @@ +package com.RVSmartPorting.common.exception.base; + +import com.RVSmartPorting.common.utils.MessageUtils; +import com.RVSmartPorting.common.utils.StringUtils; + +/** + * 基础异常 + * + * @author ruoyi + */ +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; + } + + public String getModule() + { + return module; + } + + public String getCode() + { + return code; + } + + public Object[] getArgs() + { + return args; + } + + public String getDefaultMessage() + { + return defaultMessage; + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/exception/file/FileException.java b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/file/FileException.java new file mode 100644 index 0000000000000000000000000000000000000000..4a2dd094a690ae0c56f8746063909c2e86d82484 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/file/FileException.java @@ -0,0 +1,19 @@ +package com.RVSmartPorting.common.exception.file; + +import com.RVSmartPorting.common.exception.base.BaseException; + +/** + * 文件信息异常类 + * + * @author ruoyi + */ +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/CSP-common/src/main/java/com/RVSmartPorting/common/exception/file/FileNameLengthLimitExceededException.java b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/file/FileNameLengthLimitExceededException.java new file mode 100644 index 0000000000000000000000000000000000000000..86222f20506192a90a5f2bf6c3553466650f4a04 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/file/FileNameLengthLimitExceededException.java @@ -0,0 +1,16 @@ +package com.RVSmartPorting.common.exception.file; + +/** + * 文件名称超长限制异常类 + * + * @author ruoyi + */ +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/CSP-common/src/main/java/com/RVSmartPorting/common/exception/file/FileSizeLimitExceededException.java b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/file/FileSizeLimitExceededException.java new file mode 100644 index 0000000000000000000000000000000000000000..342fc91d9208b7f38d1a8edb8fc4ecdbfeda1c39 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/file/FileSizeLimitExceededException.java @@ -0,0 +1,16 @@ +package com.RVSmartPorting.common.exception.file; + +/** + * 文件名大小限制异常类 + * + * @author ruoyi + */ +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/CSP-common/src/main/java/com/RVSmartPorting/common/exception/file/FileUploadException.java b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/file/FileUploadException.java new file mode 100644 index 0000000000000000000000000000000000000000..5fba9f3160224d2d373e360ff33e457fd584e0c9 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/file/FileUploadException.java @@ -0,0 +1,61 @@ +package com.RVSmartPorting.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/CSP-common/src/main/java/com/RVSmartPorting/common/exception/file/InvalidExtensionException.java b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/file/InvalidExtensionException.java new file mode 100644 index 0000000000000000000000000000000000000000..443bc7730f5c0508302cb7bc560c590caebda8cd --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/file/InvalidExtensionException.java @@ -0,0 +1,90 @@ +package com.RVSmartPorting.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); + } + } + + public static class InvalidCompressExtensionException extends InvalidExtensionException + { + private static final long serialVersionUID = 1L; + + public InvalidCompressExtensionException(String[] allowedExtension, String extension, String filename) + { + super(allowedExtension, extension, filename); + } + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/exception/job/TaskException.java b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/job/TaskException.java new file mode 100644 index 0000000000000000000000000000000000000000..6730532de51dcbde46289975392ac2aaa24e956f --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/job/TaskException.java @@ -0,0 +1,34 @@ +package com.RVSmartPorting.common.exception.job; + +/** + * 计划策略异常 + * + * @author ruoyi + */ +public class TaskException extends Exception +{ + private static final long serialVersionUID = 1L; + + private Code code; + + public TaskException(String msg, Code code) + { + this(msg, code, null); + } + + public TaskException(String msg, Code code, Exception nestedEx) + { + super(msg, nestedEx); + this.code = code; + } + + public Code getCode() + { + return code; + } + + public enum Code + { + TASK_EXISTS, NO_TASK_EXISTS, TASK_ALREADY_STARTED, UNKNOWN, CONFIG_ERROR, TASK_NODE_NOT_AVAILABLE + } +} \ No newline at end of file diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/exception/user/BlackListException.java b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/user/BlackListException.java new file mode 100644 index 0000000000000000000000000000000000000000..a1af46162a1313e70b660c069f22245e1933144b --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/user/BlackListException.java @@ -0,0 +1,16 @@ +package com.RVSmartPorting.common.exception.user; + +/** + * 黑名单IP异常类 + * + * @author ruoyi + */ +public class BlackListException extends UserException +{ + private static final long serialVersionUID = 1L; + + public BlackListException() + { + super("login.blocked", null); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/exception/user/CaptchaException.java b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/user/CaptchaException.java new file mode 100644 index 0000000000000000000000000000000000000000..ba7479ed62aabd924b9baf6ddddad6727f3c4bec --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/user/CaptchaException.java @@ -0,0 +1,16 @@ +package com.RVSmartPorting.common.exception.user; + +/** + * 验证码错误异常类 + * + * @author ruoyi + */ +public class CaptchaException extends UserException +{ + private static final long serialVersionUID = 1L; + + public CaptchaException() + { + super("user.jcaptcha.error", null); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/exception/user/CaptchaExpireException.java b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/user/CaptchaExpireException.java new file mode 100644 index 0000000000000000000000000000000000000000..5d9f92eb0ee238fa40a83d82a6702f5e0a3b8300 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/user/CaptchaExpireException.java @@ -0,0 +1,16 @@ +package com.RVSmartPorting.common.exception.user; + +/** + * 验证码失效异常类 + * + * @author ruoyi + */ +public class CaptchaExpireException extends UserException +{ + private static final long serialVersionUID = 1L; + + public CaptchaExpireException() + { + super("user.jcaptcha.expire", null); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/exception/user/UserException.java b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/user/UserException.java new file mode 100644 index 0000000000000000000000000000000000000000..30f84852a89d08aad756d9c7720e2001fc955776 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/user/UserException.java @@ -0,0 +1,18 @@ +package com.RVSmartPorting.common.exception.user; + +import com.RVSmartPorting.common.exception.base.BaseException; + +/** + * 用户信息异常类 + * + * @author ruoyi + */ +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/CSP-common/src/main/java/com/RVSmartPorting/common/exception/user/UserNotExistsException.java b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/user/UserNotExistsException.java new file mode 100644 index 0000000000000000000000000000000000000000..4be0536f1f364101bbb8cd9dbe8cadb7aee87651 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/user/UserNotExistsException.java @@ -0,0 +1,16 @@ +package com.RVSmartPorting.common.exception.user; + +/** + * 用户不存在异常类 + * + * @author ruoyi + */ +public class UserNotExistsException extends UserException +{ + private static final long serialVersionUID = 1L; + + public UserNotExistsException() + { + super("user.not.exists", null); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/exception/user/UserPasswordNotMatchException.java b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/user/UserPasswordNotMatchException.java new file mode 100644 index 0000000000000000000000000000000000000000..b21fa39c43738c1ff4b1bfb28b30e4542f374d14 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/user/UserPasswordNotMatchException.java @@ -0,0 +1,16 @@ +package com.RVSmartPorting.common.exception.user; + +/** + * 用户密码不正确或不符合规范异常类 + * + * @author ruoyi + */ +public class UserPasswordNotMatchException extends UserException +{ + private static final long serialVersionUID = 1L; + + public UserPasswordNotMatchException() + { + super("user.password.not.match", null); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/exception/user/UserPasswordRetryLimitExceedException.java b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/user/UserPasswordRetryLimitExceedException.java new file mode 100644 index 0000000000000000000000000000000000000000..0eba1ec905e304bdce972de47e65189b0f6085cc --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/exception/user/UserPasswordRetryLimitExceedException.java @@ -0,0 +1,16 @@ +package com.RVSmartPorting.common.exception.user; + +/** + * 用户错误最大次数异常类 + * + * @author ruoyi + */ +public class UserPasswordRetryLimitExceedException extends UserException +{ + private static final long serialVersionUID = 1L; + + public UserPasswordRetryLimitExceedException(int retryLimitCount, int lockTime) + { + super("user.password.retry.limit.exceed", new Object[] { retryLimitCount, lockTime }); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/filter/PropertyPreExcludeFilter.java b/CSP-common/src/main/java/com/RVSmartPorting/common/filter/PropertyPreExcludeFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..011f6a426b6d6c903fddf1234b2a85650266985c --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/filter/PropertyPreExcludeFilter.java @@ -0,0 +1,24 @@ +package com.RVSmartPorting.common.filter; + +import com.alibaba.fastjson2.filter.SimplePropertyPreFilter; + +/** + * 排除JSON敏感属性 + * + * @author ruoyi + */ +public class PropertyPreExcludeFilter extends SimplePropertyPreFilter +{ + public PropertyPreExcludeFilter() + { + } + + public PropertyPreExcludeFilter addExcludes(String... filters) + { + for (int i = 0; i < filters.length; i++) + { + this.getExcludes().add(filters[i]); + } + return this; + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/filter/RepeatableFilter.java b/CSP-common/src/main/java/com/RVSmartPorting/common/filter/RepeatableFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..e0ba1df16e08329cf9a1048d2aefa4fac7369b7b --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/filter/RepeatableFilter.java @@ -0,0 +1,48 @@ +package com.RVSmartPorting.common.filter; + +import com.RVSmartPorting.common.utils.StringUtils; +import org.springframework.http.MediaType; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +/** + * Repeatable 过滤器 + * + * @author ruoyi + */ +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/CSP-common/src/main/java/com/RVSmartPorting/common/filter/RepeatedlyRequestWrapper.java b/CSP-common/src/main/java/com/RVSmartPorting/common/filter/RepeatedlyRequestWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..383dcfcef328e941772aaec04f632ebda5fb2c12 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/filter/RepeatedlyRequestWrapper.java @@ -0,0 +1,77 @@ +package com.RVSmartPorting.common.filter; + +import com.RVSmartPorting.common.constant.Constants; +import com.RVSmartPorting.common.utils.http.HttpHelper; + +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 ruoyi + */ +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 = HttpHelper.getBodyString(request).getBytes(Constants.UTF8); + } + + @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/CSP-common/src/main/java/com/RVSmartPorting/common/filter/XssFilter.java b/CSP-common/src/main/java/com/RVSmartPorting/common/filter/XssFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..cc17671a7d7f7990ba4d38fe96636f780680d978 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/filter/XssFilter.java @@ -0,0 +1,72 @@ +package com.RVSmartPorting.common.filter; + + +import com.RVSmartPorting.common.utils.StringUtils; +import org.springframework.http.HttpMethod; + +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 ruoyi + */ +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(","); + 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() + { + + } +} \ No newline at end of file diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/filter/XssHttpServletRequestWrapper.java b/CSP-common/src/main/java/com/RVSmartPorting/common/filter/XssHttpServletRequestWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..24e8bd3ecc738cec8dadfab9303819600e4a5b8e --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/filter/XssHttpServletRequestWrapper.java @@ -0,0 +1,110 @@ +package com.RVSmartPorting.common.filter; + +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.html.EscapeUtil; +import org.apache.commons.io.IOUtils; +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; + +/** + * XSS过滤处理 + * + * @author ruoyi + */ +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] = EscapeUtil.clean(values[i]).trim(); + } + return escapesValues; + } + return super.getParameterValues(name); + } + + @Override + public ServletInputStream getInputStream() throws IOException + { + // 非json类型,直接返回 + if (!isJsonRequest()) + { + return super.getInputStream(); + } + + // 为空,直接返回 + String json = IOUtils.toString(super.getInputStream(), "utf-8"); + if (StringUtils.isEmpty(json)) + { + return super.getInputStream(); + } + + // xss过滤 + json = EscapeUtil.clean(json).trim(); + byte[] jsonBytes = json.getBytes("utf-8"); + final ByteArrayInputStream bis = new ByteArrayInputStream(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); + } +} \ No newline at end of file diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/Arith.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/Arith.java new file mode 100644 index 0000000000000000000000000000000000000000..ec09c8b2d51cf0f9aa939c21333913aad4926a13 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/Arith.java @@ -0,0 +1,114 @@ +package com.RVSmartPorting.common.utils; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +/** + * 精确的浮点数运算 + * + * @author ruoyi + */ +public class Arith +{ + + /** 默认除法运算精度 */ + private static final int DEF_DIV_SCALE = 10; + + /** 这个类不能实例化 */ + private Arith() + { + } + + /** + * 提供精确的加法运算。 + * @param v1 被加数 + * @param v2 加数 + * @return 两个参数的和 + */ + public static double add(double v1, double v2) + { + BigDecimal b1 = new BigDecimal(Double.toString(v1)); + BigDecimal b2 = new BigDecimal(Double.toString(v2)); + return b1.add(b2).doubleValue(); + } + + /** + * 提供精确的减法运算。 + * @param v1 被减数 + * @param v2 减数 + * @return 两个参数的差 + */ + public static double sub(double v1, double v2) + { + BigDecimal b1 = new BigDecimal(Double.toString(v1)); + BigDecimal b2 = new BigDecimal(Double.toString(v2)); + return b1.subtract(b2).doubleValue(); + } + + /** + * 提供精确的乘法运算。 + * @param v1 被乘数 + * @param v2 乘数 + * @return 两个参数的积 + */ + public static double mul(double v1, double v2) + { + BigDecimal b1 = new BigDecimal(Double.toString(v1)); + BigDecimal b2 = new BigDecimal(Double.toString(v2)); + return b1.multiply(b2).doubleValue(); + } + + /** + * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 + * 小数点以后10位,以后的数字四舍五入。 + * @param v1 被除数 + * @param v2 除数 + * @return 两个参数的商 + */ + public static double div(double v1, double v2) + { + return div(v1, v2, DEF_DIV_SCALE); + } + + /** + * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 + * 定精度,以后的数字四舍五入。 + * @param v1 被除数 + * @param v2 除数 + * @param scale 表示表示需要精确到小数点以后几位。 + * @return 两个参数的商 + */ + public static double div(double v1, double v2, int scale) + { + if (scale < 0) + { + throw new IllegalArgumentException( + "The scale must be a positive integer or zero"); + } + BigDecimal b1 = new BigDecimal(Double.toString(v1)); + BigDecimal b2 = new BigDecimal(Double.toString(v2)); + if (b1.compareTo(BigDecimal.ZERO) == 0) + { + return BigDecimal.ZERO.doubleValue(); + } + return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue(); + } + + /** + * 提供精确的小数位四舍五入处理。 + * @param v 需要四舍五入的数字 + * @param scale 小数点后保留几位 + * @return 四舍五入后的结果 + */ + public static double round(double v, int scale) + { + if (scale < 0) + { + throw new IllegalArgumentException( + "The scale must be a positive integer or zero"); + } + BigDecimal b = new BigDecimal(Double.toString(v)); + BigDecimal one = BigDecimal.ONE; + return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue(); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/DateUtils.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/DateUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..6ec46e4592749c11b133ef0b06f6ee5d51313032 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/DateUtils.java @@ -0,0 +1,190 @@ +package com.RVSmartPorting.common.utils; + + +import org.apache.commons.lang3.time.DateFormatUtils; + +import java.lang.management.ManagementFactory; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.*; +import java.util.Date; + +/** + * 时间工具类 + * + * @author ruoyi + */ + +public class DateUtils extends org.apache.commons.lang3.time.DateUtils +{ + public static String YYYY = "yyyy"; + + public static String YYYY_MM = "yyyy-MM"; + + public static String YYYY_MM_DD = "yyyy-MM-dd"; + + public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss"; + + public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; + + private static String[] parsePatterns = { + "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 final String getTime() + { + return dateTimeNow(YYYY_MM_DD_HH_MM_SS); + } + + public static final String dateTimeNow() + { + return dateTimeNow(YYYYMMDDHHMMSS); + } + + public static final String dateTimeNow(final String format) + { + return parseDateToStr(format, new Date()); + } + + public static final String dateTime(final Date date) + { + return parseDateToStr(YYYY_MM_DD, date); + } + + public static final String parseDateToStr(final String format, final Date date) + { + return new SimpleDateFormat(format).format(date); + } + + public static final 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 final String datePath() + { + Date now = new Date(); + return DateFormatUtils.format(now, "yyyy/MM/dd"); + } + + /** + * 日期路径 即年/月/日 如20180808 + */ + public static final 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(), parsePatterns); + } + 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))); + } + + /** + * 计算时间差 + * + * @param endDate 最后时间 + * @param startTime 开始时间 + * @return 时间差(天/小时/分钟) + */ + public static String timeDistance(Date endDate, Date startTime) + { + long nd = 1000 * 24 * 60 * 60; + long nh = 1000 * 60 * 60; + long nm = 1000 * 60; + // long ns = 1000; + // 获得两个时间的毫秒时间差异 + long diff = endDate.getTime() - startTime.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()); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/DictUtils.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/DictUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..12604f8dc6f5bf7ef856f67aac7f90e9a4e5a897 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/DictUtils.java @@ -0,0 +1,188 @@ +package com.RVSmartPorting.common.utils; + +import com.RVSmartPorting.common.constant.CacheConstants; +import com.RVSmartPorting.common.core.domain.entity.SysDictData; +import com.RVSmartPorting.common.utils.redis.RedisCache; +import com.RVSmartPorting.common.utils.spring.SpringUtils; +import com.alibaba.fastjson2.JSONArray; + + +import java.util.Collection; +import java.util.List; + +/** + * 字典工具类 + * + * @author ruoyi + */ +public class DictUtils +{ + /** + * 分隔符 + */ + public static final String SEPARATOR = ","; + + /** + * 设置字典缓存 + * + * @param key 参数键 + * @param dictDatas 字典数据列表 + */ + public static void setDictCache(String key, List dictDatas) + { + SpringUtils.getBean(RedisCache.class).setCacheObject(getCacheKey(key), dictDatas); + } + + /** + * 获取字典缓存 + * + * @param key 参数键 + * @return dictDatas 字典数据列表 + */ + public static List getDictCache(String key) + { + JSONArray arrayCache = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key)); + if (StringUtils.isNotNull(arrayCache)) + { + return arrayCache.toList(SysDictData.class); + } + return null; + } + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @return 字典标签 + */ + public static String getDictLabel(String dictType, String dictValue) + { + return getDictLabel(dictType, dictValue, SEPARATOR); + } + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @return 字典值 + */ + public static String getDictValue(String dictType, String dictLabel) + { + return getDictValue(dictType, dictLabel, SEPARATOR); + } + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @param separator 分隔符 + * @return 字典标签 + */ + public static String getDictLabel(String dictType, String dictValue, String separator) + { + StringBuilder propertyString = new StringBuilder(); + List datas = getDictCache(dictType); + + if (StringUtils.isNotNull(datas)) + { + if (StringUtils.containsAny(separator, dictValue)) + { + for (SysDictData dict : datas) + { + for (String value : dictValue.split(separator)) + { + if (value.equals(dict.getDictValue())) + { + propertyString.append(dict.getDictLabel()).append(separator); + break; + } + } + } + } + else + { + for (SysDictData dict : datas) + { + if (dictValue.equals(dict.getDictValue())) + { + return dict.getDictLabel(); + } + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @param separator 分隔符 + * @return 字典值 + */ + public static String getDictValue(String dictType, String dictLabel, String separator) + { + StringBuilder propertyString = new StringBuilder(); + List datas = getDictCache(dictType); + + if (StringUtils.containsAny(separator, dictLabel) && StringUtils.isNotEmpty(datas)) + { + for (SysDictData dict : datas) + { + for (String label : dictLabel.split(separator)) + { + if (label.equals(dict.getDictLabel())) + { + propertyString.append(dict.getDictValue()).append(separator); + break; + } + } + } + } + else + { + for (SysDictData dict : datas) + { + if (dictLabel.equals(dict.getDictLabel())) + { + return dict.getDictValue(); + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 删除指定字典缓存 + * + * @param key 字典键 + */ + public static void removeDictCache(String key) + { + SpringUtils.getBean(RedisCache.class).deleteObject(getCacheKey(key)); + } + + /** + * 清空字典缓存 + */ + public static void clearDictCache() + { + Collection keys = SpringUtils.getBean(RedisCache.class).keys(CacheConstants.SYS_DICT_KEY + "*"); + SpringUtils.getBean(RedisCache.class).deleteObject(keys); + } + + /** + * 设置cache key + * + * @param configKey 参数键 + * @return 缓存键key + */ + public static String getCacheKey(String configKey) + { + return CacheConstants.SYS_DICT_KEY + configKey; + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/JGitUtil.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/JGitUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..44b4dc84f22f180095cfc042154acf87db676d2f --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/JGitUtil.java @@ -0,0 +1,209 @@ +package com.RVSmartPorting.common.utils; + +import com.RVSmartPorting.common.exception.file.FileNameLengthLimitExceededException; +import com.RVSmartPorting.common.utils.file.FileUploadUtils; +import com.RVSmartPorting.common.utils.file.FileUtils; +import com.jcraft.jsch.JSch; +import com.jcraft.jsch.JSchException; +import com.jcraft.jsch.Session; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.eclipse.jgit.api.CloneCommand; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.TransportConfigCallback; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.transport.*; +import org.eclipse.jgit.util.FS; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.nio.file.Files; + +/** + * @ClassName JGitUtil + * @Description git命令操作工具 + **/ +@Slf4j +@Component +public class JGitUtil { + /** + * @Description git clone操作 https形式 + **/ + public static void cloneRepository(String gitUrl, String localPath, String branchName, String username, + String password) throws Exception { + + try { + File file = new File(localPath); + if (!file.exists()) { + file.mkdirs(); + } else { + FileUtils.cleanDirectory(file); + } + long begin = System.currentTimeMillis(); + log.info("开始git下载"); + CloneCommand cc = null; + if (StringUtils.isNotEmpty(username) && StringUtils.isNotEmpty(password)) { + UsernamePasswordCredentialsProvider pro = new UsernamePasswordCredentialsProvider(username, password); + cc = Git.cloneRepository().setURI(gitUrl).setCredentialsProvider(pro).setBranch(branchName); + } else { + cc = Git.cloneRepository().setURI(gitUrl).setBranch(branchName); + } + + Git result = cc.setDirectory(new File(localPath)).call(); + result.close(); + log.info("git下载完成"); + long end = System.currentTimeMillis(); + log.info("耗时:" + (end - begin) / 1000); + } catch (Exception e) { + log.error("git clone 执行失败,请检查", e); + throw new Exception("git clone 执行失败,请检查"); + } + } + + //ssh + public static String cloneRepositoryBySSH(String sshGitURI, String localPath, String branchName, String username, + String password) { + try { + File file = new File(localPath); + if (!file.exists()) { + + file.mkdirs(); + } + long begin = System.currentTimeMillis(); + log.info("开始git下载"); + File workingDir = Files.createTempDirectory("workspace").toFile(); + TransportConfigCallback transportConfigCallback = new SshTransportConfigCallback(); + Git git = Git.cloneRepository().setDirectory(workingDir).setTransportConfigCallback(transportConfigCallback) + .setURI(sshGitURI).call(); + git.close(); + log.info("git下载完成"); + long end = System.currentTimeMillis(); + log.info("耗时:" + (end - begin) / 1000); + return "success"; + } catch (Exception e) { + e.printStackTrace(); + return "error"; + } + } + + private static final String sshPrivateFilePath = "C:\\Users\\Lenovo\\.ssh\\known_hosts"; // replace with your ssh private + private static final String sshPassword = "lxq6655063"; // replace with your ssh key password + + private static class SshTransportConfigCallback implements TransportConfigCallback { + + private final SshSessionFactory sshSessionFactory = new JschConfigSessionFactory() { + @Override + protected void configure(OpenSshConfig.Host hc, Session session) { + session.setConfig("StrictHostKeyChecking", "no"); + } + + @Override + protected JSch createDefaultJSch(FS fs) throws JSchException { + JSch jSch = super.createDefaultJSch(fs); + jSch.addIdentity(sshPrivateFilePath, sshPassword.getBytes()); + return jSch; + } + }; + + @Override + public void configure(Transport transport) { + SshTransport sshTransport = (SshTransport) transport; + sshTransport.setSshSessionFactory(sshSessionFactory); + } + } + + /** + * @Args:公有仓库,http协议,github,no Credential + * @Res: https://gitee.com/magnificent0121/git_test_idea.git: Authentication is required but no + * CredentialsProvider has been registered + */ + public static void test2() throws Exception { + String url = "https://github.com/magnificent0121/heimaSpringCloud.git"; + String localPath = "C:\\Users\\Lenovo\\Desktop\\实习\\java\\.project\\HCSS\\temp\\demo2"; + JGitUtil.cloneRepository(url, localPath, "main", null, null); + } + + public static void test3() throws Exception { + String url = "https://github.com/magnificent0121/heimaSpringCloud.git"; + String localPath = "C:\\Users\\Lenovo\\Desktop\\实习\\java\\.project\\HCSS\\temp\\demo2"; + JGitUtil.cloneRepository(url, localPath, "master", "magnificent0121", "lxq6655063"); + } + + public static void test4() throws Exception { + String url = "https://gitee.com/magnificent0121/Godot3.2ARPGDemo.git"; + String localPath = "C:\\Users\\Lenovo\\Desktop\\实习\\java\\.project\\HCSS\\temp\\demo2"; + JGitUtil.cloneRepository(url, localPath, "master", "magnificent0121", "lxq6655063"); + } + + public static void test5() throws Exception { + String url = "https://gitee.com/magnificent0121/Godot3.2ARPGDemo.git"; + String localPath = "C:\\Users\\Lenovo\\Desktop\\实习\\java\\.project\\HCSS\\temp\\demo3"; + JGitUtil.cloneRepository(url, localPath, "master", "magnificent0121", "lxq665506"); + } + + public static void test6() throws Exception { + String url = "https://gitee.com/qwop/qttabbar.git"; + String localPath = "C:\\Users\\Lenovo\\Desktop\\实习\\java\\.project\\HCSS\\temp\\demo4"; + JGitUtil.cloneRepository(url, localPath, "master", null, null); + } + + /** + * @Args:私有仓库,http协议,gitee,no Credential + * @Res: https://gitee.com/magnificent0121/git_test_idea.git: Authentication is required but no + * CredentialsProvider has been registered + */ + public static void test7() throws Exception { + String url = "https://gitee.com/magnificent0121/git_test_idea.git"; + String localPath = "C:\\Users\\Lenovo\\Desktop\\实习\\java\\.project\\HCSS\\temp\\demo7"; + JGitUtil.cloneRepository(url, localPath, "master", null, null); + } + + /** + * @Args: 私有仓库,http协议,gitee,with Credential + * @Res: clone success + */ + public static void test8() throws Exception { + String url = "https://gitee.com/magnificent0121/git_test_idea.git"; + String localPath = "C:\\Users\\Lenovo\\Desktop\\实习\\java\\.project\\HCSS\\temp\\demo8"; + JGitUtil.cloneRepository(url, localPath, "master", "magnificent0121", "lxq6655063"); + } + + public static void test9() throws Exception { + String url = "git@gitee.com:magnificent0121/git_test_idea.git"; + String localPath = "C:\\Users\\Lenovo\\Desktop\\实习\\java\\.project\\HCSS\\temp\\demo9"; + JGitUtil.cloneRepository(url, localPath, "master", "magnificent0121", "lxq6655063"); + } + + public static void test10() throws Exception { + String url = "git@github.com:magnificent0121/heimaSpringCloud.git"; + String localPath = "C:\\Users\\Lenovo\\Desktop\\实习\\java\\.project\\HCSS\\temp\\demo10"; + JGitUtil.cloneRepository(url, localPath, "master", "magnificent0121", "lxq6655063"); + } + + public static void test11() throws Exception { + String url = "https://github.com/magnificent0121/heimaSpringCloud.git"; + String localPath = "C:\\Users\\Lenovo\\Desktop\\实习\\java\\.project\\HCSS\\temp\\demo11"; + JGitUtil.cloneRepository(url, localPath, "master", "magnificent0121", "lxq6655063"); + } + + public static void test12() throws Exception { + String url = "https://github.com/magnificent0121/heimaSpringCloud.git"; + String localPath = "C:\\Users\\Lenovo\\Desktop\\实习\\java\\.project\\HCSS\\temp\\demo13"; + JGitUtil.cloneRepository(url, localPath, "master", "magnificent0121", "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"); + } + + public static void main(String[] args) throws Exception { +// test1(); +// test2(); +// test3(); +// test4(); +// test5(); +// test6(); +// test7(); +// test8(); +// test9(); +// test10(); +// test11(); + test12(); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/LogUtils.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/LogUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..36f8c8824b4526e39ae893213ece1d70a6bdcd8f --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/LogUtils.java @@ -0,0 +1,17 @@ +package com.RVSmartPorting.common.utils; + + +/** + * 处理并记录日志文件 + **/ +public class LogUtils +{ + public static String getBlock(Object msg) + { + if (msg == null) + { + msg = ""; + } + return "[" + msg.toString() + "]"; + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/MessageUtils.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/MessageUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..2779b2ce1b66219764c8567b2cf843c4640f2986 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/MessageUtils.java @@ -0,0 +1,32 @@ +package com.RVSmartPorting.common.utils; + + +import com.RVSmartPorting.common.utils.spring.SpringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.MessageSource; +import org.springframework.context.NoSuchMessageException; +import org.springframework.context.i18n.LocaleContextHolder; + +/** + * 获取i18n资源文件 + * + * @author ruoyi + */ + +public class MessageUtils +{ + /** + * 根据消息键和参数 获取消息 委托给spring messageSource + * + * @param code 消息键 + * @param args 参数 + * @return 获取国际化翻译值 + */ + public static String message(String code, Object... args) + { + MessageSource messageSource = SpringUtils.getBean(MessageSource.class); + return messageSource.getMessage(code, args, LocaleContextHolder.getLocale()); + } +} + diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/PageUtils.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/PageUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..2bdbf52d2e9b4c2ce86ee1d27fc26945393e2ae4 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/PageUtils.java @@ -0,0 +1,35 @@ +package com.RVSmartPorting.common.utils; + +import com.github.pagehelper.PageHelper; +import com.RVSmartPorting.common.core.page.PageDomain; +import com.RVSmartPorting.common.core.page.TableSupport; +import com.RVSmartPorting.common.utils.sql.SqlUtil; + +/** + * 分页工具类 + * + * @author ruoyi + */ +public class PageUtils extends PageHelper +{ + /** + * 设置请求分页数据 + */ + public static void startPage() + { + PageDomain pageDomain = TableSupport.buildPageRequest(); + Integer pageNum = pageDomain.getPageNum(); + Integer pageSize = pageDomain.getPageSize(); + String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy()); + Boolean reasonable = pageDomain.getReasonable(); + PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable); + } + + /** + * 清理分页的线程变量 + */ + public static void clearPage() + { + PageHelper.clearPage(); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/SecurityUtils.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/SecurityUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..272969d1188b2ffad8e3ac73ee5e05942e7d3512 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/SecurityUtils.java @@ -0,0 +1,123 @@ +package com.RVSmartPorting.common.utils; + +import com.RVSmartPorting.common.constant.HttpStatus; +import com.RVSmartPorting.common.core.domain.model.LoginUser; +import com.RVSmartPorting.common.exception.ServiceException; +import com.RVSmartPorting.common.constant.HttpStatus; +import com.RVSmartPorting.common.core.domain.model.LoginUser; +import com.RVSmartPorting.common.exception.ServiceException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +/** + * 安全服务工具类 + * + * @author ruoyi + */ +public class SecurityUtils +{ + /** + * 用户ID + **/ + public static Long getUserId() + { + try + { + return getLoginUser().getUserId(); + } + catch (Exception e) + { + throw new ServiceException("获取用户ID异常", HttpStatus.UNAUTHORIZED); + } + } + + /** + * 获取部门ID + **/ + public static Long getDeptId() + { + try + { + return getLoginUser().getDeptId(); + } + catch (Exception e) + { + throw new ServiceException("获取部门ID异常", HttpStatus.UNAUTHORIZED); + } + } + + /** + * 获取用户账户 + **/ + public static String getUsername() + { + try + { + return getLoginUser().getUsername(); + } + catch (Exception e) + { + throw new ServiceException("获取用户账户异常", HttpStatus.UNAUTHORIZED); + } + } + + /** + * 获取用户 + **/ + public static LoginUser getLoginUser() + { + try + { + return (LoginUser) getAuthentication().getPrincipal(); + } + catch (Exception e) + { + throw new ServiceException("获取用户信息异常", HttpStatus.UNAUTHORIZED); + } + } + + /** + * 获取Authentication + */ + public static Authentication getAuthentication() + { + return SecurityContextHolder.getContext().getAuthentication(); + } + + /** + * 生成BCryptPasswordEncoder密码 + * + * @param password 密码 + * @return 加密字符串 + */ + public static String encryptPassword(String password) + { + BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + return passwordEncoder.encode(password); + } + + /** + * 判断密码是否相同 + * + * @param rawPassword 真实密码 + * @param encodedPassword 加密后字符 + * @return 结果 + */ + public static boolean matchesPassword(String rawPassword, String encodedPassword) + { + BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + return passwordEncoder.matches(rawPassword, encodedPassword); + } + + /** + * 是否为管理员 + * + * @param userId 用户ID + * @return 结果 + */ + public static boolean isAdmin(Long userId) + { + return userId != null && 1L == userId; + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/ServletUtils.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/ServletUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..177778c88ab9d0c54b461c6e2df98fdf43b8f1f5 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/ServletUtils.java @@ -0,0 +1,222 @@ +package com.RVSmartPorting.common.utils; + +/** + * 客户端工具类 + * + * @author ruoyi + */ + +import com.RVSmartPorting.common.constant.Constants; +import com.RVSmartPorting.common.core.text.Convert; +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.util.Collections; +import java.util.HashMap; +import java.util.Map; + + +public class ServletUtils +{ + /** + * 获取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(), ",")); + } + 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(200); + response.setContentType("application/json"); + response.setCharacterEncoding("utf-8"); + 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("application/json")) + { + return true; + } + + String xRequestedWith = request.getHeader("X-Requested-With"); + if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest")) + { + return true; + } + + String uri = request.getRequestURI(); + if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml")) + { + return true; + } + + String ajax = request.getParameter("__ajax"); + return StringUtils.inStringIgnoreCase(ajax, "json", "xml"); + } + + /** + * 内容编码 + * + * @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/CSP-common/src/main/java/com/RVSmartPorting/common/utils/StringUtils.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/StringUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..cd7e0b1e15939fc4ced5e3abeb7b8839d24f2230 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/StringUtils.java @@ -0,0 +1,615 @@ +package com.RVSmartPorting.common.utils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.RVSmartPorting.common.constant.Constants; +import com.RVSmartPorting.common.core.text.StrFormatter; +import org.springframework.util.AntPathMatcher; + +/** + * 字符串工具类 + * + * @author ruoyi + */ +public class StringUtils extends org.apache.commons.lang3.StringUtils +{ + /** 空字符串 */ + private static final String NULLSTR = ""; + + /** 下划线 */ + private static final char SEPARATOR = '_'; + + /** + * 获取参数不为空值 + * + * @param value defaultValue 要判断的value + * @return value 返回值 + */ + public static T nvl(T value, T defaultValue) + { + return value != null ? value : defaultValue; + } + + /** + * * 判断一个Collection是否为空, 包含List,Set,Queue + * + * @param coll 要判断的Collection + * @return true:为空 false:非空 + */ + public static boolean isEmpty(Collection coll) + { + return isNull(coll) || coll.isEmpty(); + } + + /** + * * 判断一个Collection是否非空,包含List,Set,Queue + * + * @param coll 要判断的Collection + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Collection coll) + { + return !isEmpty(coll); + } + + /** + * * 判断一个对象数组是否为空 + * + * @param objects 要判断的对象数组 + ** @return true:为空 false:非空 + */ + public static boolean isEmpty(Object[] objects) + { + return isNull(objects) || (objects.length == 0); + } + + /** + * * 判断一个对象数组是否非空 + * + * @param objects 要判断的对象数组 + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Object[] objects) + { + return !isEmpty(objects); + } + + /** + * * 判断一个Map是否为空 + * + * @param map 要判断的Map + * @return true:为空 false:非空 + */ + public static boolean isEmpty(Map map) + { + return isNull(map) || map.isEmpty(); + } + + /** + * * 判断一个Map是否为空 + * + * @param map 要判断的Map + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Map map) + { + return !isEmpty(map); + } + + /** + * * 判断一个字符串是否为空串 + * + * @param str String + * @return true:为空 false:非空 + */ + public static boolean isEmpty(String str) + { + return isNull(str) || NULLSTR.equals(str.trim()); + } + + /** + * * 判断一个字符串是否为非空串 + * + * @param str String + * @return true:非空串 false:空串 + */ + public static boolean isNotEmpty(String str) + { + return !isEmpty(str); + } + + /** + * * 判断一个对象是否为空 + * + * @param object Object + * @return true:为空 false:非空 + */ + public static boolean isNull(Object object) + { + return object == null; + } + + /** + * * 判断一个对象是否非空 + * + * @param object Object + * @return true:非空 false:空 + */ + public static boolean isNotNull(Object object) + { + return !isNull(object); + } + + /** + * * 判断一个对象是否是数组类型(Java基本型别的数组) + * + * @param object 对象 + * @return true:是数组 false:不是数组 + */ + public static boolean isArray(Object object) + { + return isNotNull(object) && object.getClass().isArray(); + } + + /** + * 去空格 + */ + public static String trim(String str) + { + return (str == null ? "" : str.trim()); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @return 结果 + */ + public static String substring(final String str, int start) + { + if (str == null) + { + return NULLSTR; + } + + if (start < 0) + { + start = str.length() + start; + } + + if (start < 0) + { + start = 0; + } + if (start > str.length()) + { + return NULLSTR; + } + + return str.substring(start); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @param end 结束 + * @return 结果 + */ + public static String substring(final String str, int start, int end) + { + if (str == null) + { + return NULLSTR; + } + + if (end < 0) + { + end = str.length() + end; + } + if (start < 0) + { + start = str.length() + start; + } + + if (end > str.length()) + { + end = str.length(); + } + + if (start > end) + { + return NULLSTR; + } + + if (start < 0) + { + start = 0; + } + if (end < 0) + { + end = 0; + } + + return str.substring(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) + { + if (isEmpty(params) || isEmpty(template)) + { + return template; + } + return StrFormatter.format(template, params); + } + + /** + * 是否为http(s)://开头 + * + * @param link 链接 + * @return 结果 + */ + public static boolean ishttp(String link) + { + return StringUtils.startsWithAny(link, Constants.HTTP, Constants.HTTPS); + } + + /** + * 字符串转set + * + * @param str 字符串 + * @param sep 分隔符 + * @return set集合 + */ + public static final 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 final List str2List(String str, String sep, boolean filterBlank, boolean trim) + { + List list = new ArrayList(); + if (StringUtils.isEmpty(str)) + { + return list; + } + + // 过滤空白字符串 + if (filterBlank && StringUtils.isBlank(str)) + { + return list; + } + String[] split = str.split(sep); + for (String string : split) + { + if (filterBlank && StringUtils.isBlank(string)) + { + continue; + } + if (trim) + { + string = string.trim(); + } + list.add(string); + } + + return list; + } + + /** + * 判断给定的collection列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value + * + * @param collection 给定的集合 + * @param array 给定的数组 + * @return boolean 结果 + */ + public static boolean containsAny(Collection collection, String... array) + { + if (isEmpty(collection) || isEmpty(array)) + { + return false; + } + else + { + for (String str : array) + { + if (collection.contains(str)) + { + return true; + } + } + return false; + } + } + + /** + * 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写 + * + * @param cs 指定字符串 + * @param searchCharSequences 需要检查的字符串数组 + * @return 是否包含任意一个字符串 + */ + public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) + { + if (isEmpty(cs) || isEmpty(searchCharSequences)) + { + return false; + } + for (CharSequence testStr : searchCharSequences) + { + if (containsIgnoreCase(cs, testStr)) + { + return true; + } + } + return false; + } + + /** + * 驼峰转下划线命名 + */ + public static String toUnderScoreCase(String str) + { + if (str == null) + { + return null; + } + StringBuilder sb = new StringBuilder(); + // 前置字符是否大写 + boolean preCharIsUpperCase = true; + // 当前字符是否大写 + boolean curreCharIsUpperCase = true; + // 下一字符是否大写 + boolean nexteCharIsUpperCase = true; + for (int i = 0; i < str.length(); i++) + { + char c = str.charAt(i); + if (i > 0) + { + preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1)); + } + else + { + preCharIsUpperCase = false; + } + + curreCharIsUpperCase = Character.isUpperCase(c); + + if (i < (str.length() - 1)) + { + nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1)); + } + + if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) + { + sb.append(SEPARATOR); + } + else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) + { + sb.append(SEPARATOR); + } + sb.append(Character.toLowerCase(c)); + } + + return sb.toString(); + } + + /** + * 是否包含字符串 + * + * @param str 验证字符串 + * @param strs 字符串组 + * @return 包含返回true + */ + public static boolean inStringIgnoreCase(String str, String... strs) + { + if (str != null && strs != null) + { + for (String s : strs) + { + if (str.equalsIgnoreCase(trim(s))) + { + return true; + } + } + } + return false; + } + + /** + * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld + * + * @param name 转换前的下划线大写方式命名的字符串 + * @return 转换后的驼峰式命名的字符串 + */ + public static String convertToCamelCase(String name) + { + StringBuilder result = new StringBuilder(); + // 快速检查 + if (name == null || name.isEmpty()) + { + // 没必要转换 + return ""; + } + else if (!name.contains("_")) + { + // 不含下划线,仅将首字母大写 + return name.substring(0, 1).toUpperCase() + name.substring(1); + } + // 用下划线将原始字符串分割 + String[] camels = name.split("_"); + for (String camel : camels) + { + // 跳过原始字符串中开头、结尾的下换线或双重下划线 + if (camel.isEmpty()) + { + continue; + } + // 首字母大写 + result.append(camel.substring(0, 1).toUpperCase()); + result.append(camel.substring(1).toLowerCase()); + } + return result.toString(); + } + + /** + * 驼峰式命名法 + * 例如:user_name->userName + */ + public static String toCamelCase(String s) + { + if (s == null) + { + return null; + } + if (s.indexOf(SEPARATOR) == -1) + { + return s; + } + s = s.toLowerCase(); + StringBuilder sb = new StringBuilder(s.length()); + boolean upperCase = false; + for (int i = 0; i < s.length(); i++) + { + char c = s.charAt(i); + + if (c == SEPARATOR) + { + upperCase = true; + } + else if (upperCase) + { + sb.append(Character.toUpperCase(c)); + upperCase = false; + } + else + { + sb.append(c); + } + } + return sb.toString(); + } + + /** + * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串 + * + * @param str 指定字符串 + * @param strs 需要检查的字符串数组 + * @return 是否匹配 + */ + public static boolean matches(String str, List strs) + { + if (isEmpty(str) || isEmpty(strs)) + { + return false; + } + for (String pattern : strs) + { + if (isMatch(pattern, str)) + { + return true; + } + } + return false; + } + + /** + * 判断url是否与规则配置: + * ? 表示单个字符; + * * 表示一层路径内的任意字符串,不可跨层级; + * ** 表示任意层路径; + * + * @param pattern 匹配规则 + * @param url 需要匹配的url + * @return + */ + public static boolean isMatch(String pattern, String url) + { + AntPathMatcher matcher = new AntPathMatcher(); + return matcher.match(pattern, url); + } + + @SuppressWarnings("unchecked") + public static T cast(Object obj) + { + return (T) obj; + } + + /** + * 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。 + * + * @param num 数字对象 + * @param size 字符串指定长度 + * @return 返回数字的字符串格式,该字符串为指定长度。 + */ + public static final 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 final 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(); + } +} \ No newline at end of file diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/Threads.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/Threads.java new file mode 100644 index 0000000000000000000000000000000000000000..21231f0220539e154767ef293c4f7d36e431d018 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/Threads.java @@ -0,0 +1,97 @@ +package com.RVSmartPorting.common.utils; + +/** + * 线程相关工具类. + * + * @author ruoyi + */ + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.*; + +public class Threads +{ + private static final Logger logger = LoggerFactory.getLogger(Threads.class); + + /** + * 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)) + { + logger.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) + { + logger.error(t.getMessage(), t); + } + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/bean/BeanUtils.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/bean/BeanUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..2fa0487c64f74c04a7d18a6e781faf0a21326120 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/bean/BeanUtils.java @@ -0,0 +1,110 @@ +package com.RVSmartPorting.common.utils.bean; + +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)); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/bean/BeanValidators.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/bean/BeanValidators.java new file mode 100644 index 0000000000000000000000000000000000000000..22dacbf2072e521076d11eebc73a402b7e3e7fb1 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/bean/BeanValidators.java @@ -0,0 +1,24 @@ +package com.RVSmartPorting.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/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/FileCompressUtil.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/FileCompressUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..450f6743e14ff62870498934f57edfedb9c99e8a --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/FileCompressUtil.java @@ -0,0 +1,55 @@ +package com.RVSmartPorting.common.utils.file; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +public class FileCompressUtil { + + public static String compressDirectory(String localRepositoryPath) { + File directoryToCompress = new File(localRepositoryPath); + String zipFileName = directoryToCompress.getName() + ".zip"; + File zipFile = new File(directoryToCompress.getParent(), zipFileName); + + try (FileOutputStream fos = new FileOutputStream(zipFile); + ZipOutputStream zos = new ZipOutputStream(fos)) { + + compress(directoryToCompress, zos, ""); + + } catch (IOException e) { + e.printStackTrace(); + } + + return zipFile.getAbsolutePath(); + } + + private static void compress(File fileToCompress, ZipOutputStream zos, String parentDirectoryName) throws IOException { + if (fileToCompress.isDirectory()) { + String[] children = fileToCompress.list(); + if (children != null) { + for (String child : children) { + compress(new File(fileToCompress, child), zos, parentDirectoryName + fileToCompress.getName() + "/"); + } + } + } else { + byte[] buffer = new byte[1024]; + try (FileInputStream fis = new FileInputStream(fileToCompress)) { + zos.putNextEntry(new ZipEntry(parentDirectoryName + fileToCompress.getName())); + int length; + while ((length = fis.read(buffer)) > 0) { + zos.write(buffer, 0, length); + } + zos.closeEntry(); + } + } + } + + public static void main(String[] args) { + String localRepositoryPath = "C:\\Users\\Lenovo\\Desktop\\ospp\\测试\\test6\\11"; + String compressedFilePath = compressDirectory(localRepositoryPath); + System.out.println("Compressed file saved at: " + compressedFilePath); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/FileDecompressUtil.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/FileDecompressUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..d33b12f734121823678e29658411a32622a5c3a8 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/FileDecompressUtil.java @@ -0,0 +1,599 @@ +package com.RVSmartPorting.common.utils.file; + +import com.RVSmartPorting.common.enums.FileType; +import com.github.junrar.Archive; +import com.github.junrar.exception.RarException; +import com.github.junrar.rarfile.FileHeader; +import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry; +import org.apache.commons.compress.archivers.sevenz.SevenZFile; +import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream; +import org.apache.tools.tar.TarEntry; +import org.apache.tools.tar.TarInputStream; + +import java.io.*; +import java.util.Enumeration; +import java.util.zip.GZIPInputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +/** + * @refer https://www.cnblogs.com/peashooter/p/9455498.html + * @create 2023-08-26 16:26 + */ +public class FileDecompressUtil { + /** + * 获取文件真实类型 + * + * @param file 要获取类型的文件。 + * @return 文件类型枚举。 + */ + private static FileType getFileType(File file) { + FileInputStream inputStream = null; + try { + inputStream = new FileInputStream(file); + byte[] head = new byte[4]; + if (-1 == inputStream.read(head)) { + return FileType.UNKNOWN; + } + int headHex = 0; + for (byte b : head) { + headHex <<= 8; + headHex |= b; + } + switch (headHex) { + case 0x504B0304: + return FileType.ZIP; + case 0x776f7264: + return FileType.TAR; + case -0x51: + return FileType._7Z; + case 0x425a6839: + return FileType.BZ2; + case -0x74f7f8: + return FileType.GZ; + case 0x52617221: + return FileType.RAR; + default: + return FileType.UNKNOWN; + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (inputStream != null) { + inputStream.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + return FileType.UNKNOWN; + } + + public static void decompressFile(File file, String targetPath, boolean delete) { + final FileType fileType = getFileType(file); + switch (fileType) { + case ZIP: + decompressZip(file, targetPath, delete); + break; + case TAR: + decompressTar(file, targetPath, delete); + break; + case BZ2: + decompressBZ2(file, targetPath, delete); + break; + case TAR_BZ2: + decompressTarBz2(file, targetPath, delete); + break; + case TAR_GZ: + decompressTarGz(file, targetPath, delete); + break; + case _7Z: + decompress7Z(file, targetPath, delete); + break; + case RAR4: + decompressRAR4(file, targetPath, delete); + break; + default: + break; + } + } + + /** + * 构建目录 + * + * @param outputDir 输出目录 + * @param subDir 子目录 + */ + private static void createDirectory(String outputDir, String subDir) { + File file = new File(outputDir); + if (!(subDir == null || subDir.trim().equals(""))) {//子目录不为空 + file = new File(outputDir + '/' + subDir); + } + if (!file.exists()) { + if (!file.getParentFile().exists()) { + file.getParentFile().mkdirs(); + } + file.mkdirs(); + } + } + + /** + * zip解压 + * + * @param srcFile zip源文件 + * @param destDirPath 解压后的目标文件夹 + * @throws RuntimeException 解压失败会抛出运行时异常 + */ + public static void decompressZip(File srcFile, String destDirPath, boolean delete) throws RuntimeException { + long start = System.currentTimeMillis(); + // 判断源文件是否存在 + if (!srcFile.exists()) { + throw new RuntimeException(srcFile.getPath() + "所指文件不存在"); + } + // 开始解压 + ZipFile zipFile = null; + try { + zipFile = new ZipFile(srcFile); + Enumeration entries = zipFile.entries(); + while (entries.hasMoreElements()) { + ZipEntry entry = (ZipEntry) entries.nextElement(); + // 如果是文件夹,就创建个文件夹 + if (entry.isDirectory()) { + String dirPath = destDirPath + "/" + entry.getName(); + File dir = new File(dirPath); + dir.mkdirs(); + } else { + // 如果是文件,就先创建一个文件,然后用io流把内容copy过去 + File targetFile = new File(destDirPath + "/" + entry.getName()); + // 保证这个文件的父文件夹必须要存在 + if (!targetFile.getParentFile().exists()) { + targetFile.getParentFile().mkdirs(); + } + targetFile.createNewFile(); + // 将压缩文件内容写入到这个文件中 + InputStream is = zipFile.getInputStream(entry); + FileOutputStream fos = new FileOutputStream(targetFile); + int len; + byte[] buf = new byte[2 * 1024]; + while ((len = is.read(buf)) != -1) { + fos.write(buf, 0, len); + } + // 关流顺序,先打开的后关闭 + fos.close(); + is.close(); + } + } + long end = System.currentTimeMillis(); + } catch (Exception e) { + throw new RuntimeException("unzip error from ZipUtils", e); + } finally { + if (zipFile != null) { + try { + zipFile.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + // 根据条件决定是否删除原压缩包文件 + if (delete) { + srcFile.delete(); + } + } + } + + /** + * 解压缩tar文件 + * + * @param file 压缩包文件 + * @param targetPath 目标文件夹 + * @param delete 解压后是否删除原压缩包文件 + */ + private static void decompressTar(File file, String targetPath, boolean delete) { + FileInputStream fis = null; + OutputStream fos = null; + TarInputStream tarInputStream = null; + try { + fis = new FileInputStream(file); + tarInputStream = new TarInputStream(fis, 1024 * 2); + // 创建输出目录 + createDirectory(targetPath, null); + + TarEntry entry = null; + while (true) { + entry = tarInputStream.getNextEntry(); + if (entry == null) { + break; + } + if (entry.isDirectory()) { + createDirectory(targetPath, entry.getName()); // 创建子目录 + } else { + fos = new FileOutputStream(new File(targetPath + File.separator + entry.getName())); + int count; + byte data[] = new byte[2048]; + while ((count = tarInputStream.read(data)) != -1) { + fos.write(data, 0, count); + } + fos.flush(); + } + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (fis != null) { + fis.close(); + } + if (fos != null) { + fos.close(); + } + if (tarInputStream != null) { + tarInputStream.close(); + } + // 根据条件决定是否删除原压缩包文件 + if (delete) { + file.delete(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * 解压缩bz2文件 + * + * @param file 压缩包文件 + * @param targetPath 目标文件夹 + * @param delete 解压后是否删除原压缩包文件 + */ + public static void decompressBZ2(File file, String targetPath, boolean delete) { + FileInputStream fis = null; + OutputStream fos = null; + BZip2CompressorInputStream bis = null; + String suffix = ".bz2"; + try { + fis = new FileInputStream(file); + bis = new BZip2CompressorInputStream(fis); + // 创建输出目录 + createDirectory(targetPath, null); + File tempFile = new File(targetPath + File.separator + file.getName().replace(suffix, "")); + fos = new FileOutputStream(tempFile); + + int count; + byte data[] = new byte[2048]; + while ((count = bis.read(data)) != -1) { + fos.write(data, 0, count); + } + fos.flush(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (fis != null) { + fis.close(); + } + if (fos != null) { + fos.close(); + } + if (bis != null) { + bis.close(); + } + // 根据条件决定是否删除原压缩包文件 + if (delete) { + file.delete(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * 解压缩tar.bz2文件 + * + * @param file 压缩包文件 + * @param targetPath 目标文件夹 + * @param delete 解压后是否删除原压缩包文件 + */ + public static void decompressTarBz2(File file, String targetPath, boolean delete) { + FileInputStream fis = null; + OutputStream fos = null; + BZip2CompressorInputStream bis = null; + TarInputStream tis = null; + try { + fis = new FileInputStream(file); + bis = new BZip2CompressorInputStream(fis); + tis = new TarInputStream(bis, 1024 * 2); + // 创建输出目录 + createDirectory(targetPath, null); + TarEntry entry; + while ((entry = tis.getNextEntry()) != null) { + if (entry.isDirectory()) { + createDirectory(targetPath, entry.getName()); // 创建子目录 + } else { + fos = new FileOutputStream(new File(targetPath + File.separator + entry.getName())); + int count; + byte data[] = new byte[2048]; + while ((count = tis.read(data)) != -1) { + fos.write(data, 0, count); + } + fos.flush(); + } + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (fis != null) { + fis.close(); + } + if (fos != null) { + fos.close(); + } + if (bis != null) { + bis.close(); + } + if (tis != null) { + tis.close(); + } + // 根据条件决定是否删除原压缩包文件 + if (delete) { + file.delete(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * 解压缩tar.gz文件 + * + * @param file 压缩包文件 + * @param targetPath 目标文件夹 + * @param delete 解压后是否删除原压缩包文件 + */ + private static void decompressTarGz(File file, String targetPath, boolean delete) { + FileInputStream fileInputStream = null; + BufferedInputStream bufferedInputStream = null; + GZIPInputStream gzipIn = null; + TarInputStream tarIn = null; + OutputStream out = null; + try { + fileInputStream = new FileInputStream(file); + bufferedInputStream = new BufferedInputStream(fileInputStream); + gzipIn = new GZIPInputStream(bufferedInputStream); + tarIn = new TarInputStream(gzipIn, 1024 * 2); + + // 创建输出目录 + createDirectory(targetPath, null); + + TarEntry entry = null; + while ((entry = tarIn.getNextEntry()) != null) { + if (entry.isDirectory()) { // 是目录 + createDirectory(targetPath, entry.getName()); // 创建子目录 + } else { // 是文件 + File tempFIle = new File(targetPath + File.separator + entry.getName()); + createDirectory(tempFIle.getParent() + File.separator, null); + out = new FileOutputStream(tempFIle); + int len = 0; + byte[] b = new byte[2048]; + + while ((len = tarIn.read(b)) != -1) { + out.write(b, 0, len); + } + out.flush(); + } + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (out != null) { + out.close(); + } + if (tarIn != null) { + tarIn.close(); + } + if (gzipIn != null) { + gzipIn.close(); + } + if (bufferedInputStream != null) { + bufferedInputStream.close(); + } + if (fileInputStream != null) { + fileInputStream.close(); + } + // 根据条件决定是否删除原压缩包文件 + if (delete) { + file.delete(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * 解压缩gz文件 + * + * @param file 压缩包文件 + * @param targetPath 目标文件夹 + * @param delete 解压后是否删除原压缩包文件 + */ + private static void decompressGz(File file, String targetPath, boolean delete) { + FileInputStream fileInputStream = null; + GZIPInputStream gzipIn = null; + OutputStream out = null; + String suffix = ".gz"; + try { + fileInputStream = new FileInputStream(file); + gzipIn = new GZIPInputStream(fileInputStream); + // 创建输出目录 + createDirectory(targetPath, null); + + File tempFile = new File(targetPath + File.separator + file.getName().replace(suffix, "")); + out = new FileOutputStream(tempFile); + int count; + byte data[] = new byte[2048]; + while ((count = gzipIn.read(data)) != -1) { + out.write(data, 0, count); + } + out.flush(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (out != null) { + out.close(); + } + if (gzipIn != null) { + gzipIn.close(); + } + if (fileInputStream != null) { + fileInputStream.close(); + } + // 根据条件决定是否删除原压缩包文件 + if (delete) { + file.delete(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * 解压缩7z文件 + * + * @param file 压缩包文件 + * @param targetPath 目标文件夹 + * @param delete 解压后是否删除原压缩包文件 + */ + private static void decompress7Z(File file, String targetPath, boolean delete) { + SevenZFile sevenZFile = null; + OutputStream outputStream = null; + try { + sevenZFile = new SevenZFile(file); + // 创建输出目录 + createDirectory(targetPath, null); + SevenZArchiveEntry entry; + + while ((entry = sevenZFile.getNextEntry()) != null) { + if (entry.isDirectory()) { + createDirectory(targetPath, entry.getName()); // 创建子目录 + } else { + outputStream = new FileOutputStream(new File(targetPath + File.separator + entry.getName())); + int len = 0; + byte[] b = new byte[2048]; + while ((len = sevenZFile.read(b)) != -1) { + outputStream.write(b, 0, len); + } + outputStream.flush(); + } + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (sevenZFile != null) { + sevenZFile.close(); + } + if (outputStream != null) { + outputStream.close(); + } + // 根据条件决定是否删除原压缩包文件 + if (delete) { + file.delete(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * 解压缩RAR4文件 + * 注:目前不支持直接解压缩RAR5文件,原因见:https://blog.csdn.net/weixin_39821604/article/details/111484465 + * + * @param file 压缩包文件 + * @param targetPath 目标文件夹 + * @param delete 压缩后是否删除原压缩包文件 + */ + private static void decompressRAR4(File file, String targetPath, boolean delete) { + Archive archive = null; + OutputStream outputStream = null; + try { + archive = new Archive(file); + FileHeader fileHeader; + + // 创建输出目录 + createDirectory(targetPath, null); + + while ((fileHeader = archive.nextFileHeader()) != null) { + if (fileHeader.isDirectory()) { + createDirectory(targetPath, fileHeader.getFileNameString().trim()); // 创建子目录 + } else { + final File file1 = new File(targetPath + File.separator + fileHeader.getFileNameString().trim()); + File parentDirectory = file1.getParentFile(); + if (!parentDirectory.exists()) { + parentDirectory.mkdirs(); + } + outputStream = new FileOutputStream(file1); + archive.extractFile(fileHeader, outputStream); + } + } + + } catch (IOException | RarException e) { + e.printStackTrace(); + } finally { + try { + if (archive != null) { + archive.close(); + } + if (outputStream != null) { + outputStream.close(); + } + // 根据条件决定是否删除原压缩包文件 + if (delete) { + file.delete(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public static void test_getFileType() { + File rarfile = new File("C:\\Users\\Lenovo\\Desktop\\ospp\\测试\\test.rar"); + final FileType rarfileType = FileDecompressUtil.getFileType(rarfile); + System.out.println("rarfileType.name() = " + rarfileType.name()); + File zipfile = new File("C:\\Users\\Lenovo\\Desktop\\ospp\\测试\\test.zip"); + final FileType zipfileType = FileDecompressUtil.getFileType(zipfile); + System.out.println("zipfileType.name() = " + zipfileType.name()); + } + + public static void test_decompressRAR4() { + String testFilePath = "C:\\Users\\Lenovo\\Desktop\\ospp\\测试\\testrar4\\1.rar"; + String targetPath = "C:\\Users\\Lenovo\\Desktop\\ospp\\测试\\testrar4"; + boolean deleteOriginal = true; // Set this according to your test case + File testFile = new File(testFilePath); + FileDecompressUtil.decompressRAR4(testFile, targetPath, deleteOriginal); + } + + public static void test_decompressZip() { + String testFilePath = "C:\\Users\\Lenovo\\Desktop\\ospp\\测试\\testzip\\a.zip"; + String targetPath = "C:\\Users\\Lenovo\\Desktop\\ospp\\测试\\testzip"; + boolean deleteOriginal = true; // Set this according to your test case + File testFile = new File(testFilePath); + FileDecompressUtil.decompressZip(testFile, targetPath, deleteOriginal); + } + + public static void main(String[] args) { +// test_getFileType(); +// test_decompressRAR4(); +// test_decompressZip(); + + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/FileHashUtil.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/FileHashUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..0fe0348fe6dcaae98cf2a951108416a0d57a4773 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/FileHashUtil.java @@ -0,0 +1,60 @@ +package com.RVSmartPorting.common.utils.file; +import java.security.MessageDigest; +import org.bouncycastle.crypto.digests.SM3Digest; + +import java.io.*; + + +public class FileHashUtil { + public enum HashAlgorithm { + SHA1, + SM3 + } + public static String calculateHash(File file, HashAlgorithm algorithm) throws Exception { + FileInputStream fis = new FileInputStream(file); + byte[] buffer = new byte[8192]; + int bytesRead; + + if (algorithm == HashAlgorithm.SHA1) { + MessageDigest md = MessageDigest.getInstance("SHA-1"); + while ((bytesRead = fis.read(buffer)) != -1) { + md.update(buffer, 0, bytesRead); + } + fis.close(); + byte[] hash = md.digest(); + StringBuilder hashHex = new StringBuilder(); + for (byte b : hash) { + hashHex.append(String.format("%02x", b)); + } + return hashHex.toString(); + } else if (algorithm == HashAlgorithm.SM3) { + SM3Digest sm3 = new SM3Digest(); + while ((bytesRead = fis.read(buffer)) != -1) { + sm3.update(buffer, 0, bytesRead); + } + fis.close(); + byte[] hash = new byte[sm3.getDigestSize()]; + sm3.doFinal(hash, 0); + StringBuilder hashHex = new StringBuilder(); + for (byte b : hash) { + hashHex.append(String.format("%02x", b)); + } + return hashHex.toString(); + } else { + throw new IllegalArgumentException("Unsupported hash algorithm"); + } + } + + public static void main(String[] args) { + File file = new File("C:\\Users\\Lenovo\\Desktop\\ospp\\测试\\a.zip"); + try { + String sha1Hash = FileHashUtil.calculateHash(file, HashAlgorithm.SHA1); + String sm3Hash = FileHashUtil.calculateHash(file, HashAlgorithm.SM3); + + System.out.println("SHA-1 Hash: " + sha1Hash); + System.out.println("SM3 Hash: " + sm3Hash); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/FileTypeUtils.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/FileTypeUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..64d27ce46a945e1218109e4425c9adb4c5fe1384 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/FileTypeUtils.java @@ -0,0 +1,77 @@ +package com.RVSmartPorting.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; + } +} \ No newline at end of file diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/FileUploadUtils.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/FileUploadUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..7edcc4368f1f1440ca1d22ddee62c55bab356340 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/FileUploadUtils.java @@ -0,0 +1,273 @@ +package com.RVSmartPorting.common.utils.file; + +import com.RVSmartPorting.common.config.CSPConfig; +import com.RVSmartPorting.common.constant.Constants; +import com.RVSmartPorting.common.core.domain.entity.SysUser; +import com.RVSmartPorting.common.exception.file.FileNameLengthLimitExceededException; +import com.RVSmartPorting.common.exception.file.FileSizeLimitExceededException; +import com.RVSmartPorting.common.exception.file.InvalidExtensionException; +import com.RVSmartPorting.common.utils.DateUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.uuid.Seq; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FilenameUtils; +import org.springframework.core.io.Resource; +import org.springframework.util.FileCopyUtils; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.Objects; + +/** + * 文件上传工具类 + * + * @author ruoyi + */ +@Slf4j +public class FileUploadUtils { + /** + * 默认大小 100M + */ + public static final long DEFAULT_MAX_SIZE = 100 * 1024 * 1024; + + /** + * 默认的文件名最大长度 100 + */ + public static final int DEFAULT_FILE_NAME_LENGTH = 100; + + /** + * 默认上传的地址 + */ + private static String defaultBaseDir = CSPConfig.getProfile(); + + public static void setDefaultBaseDir(String defaultBaseDir) { + FileUploadUtils.defaultBaseDir = defaultBaseDir; + } + + public static String getDefaultBaseDir() { + return defaultBaseDir; + } + + /** + * 以默认配置进行文件上传 + * + * @param file 上传的文件 + * @return 文件名称 + * @throws Exception + */ + public static final String upload(MultipartFile file) throws IOException { + try { + return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); + } catch (Exception e) { + throw new IOException(e.getMessage(), e); + } + } + public static void saveResourceToFile(Resource resource, String localFileStoragePath) { + try { + // 创建文件对象 + File localCodePackFile = new File(localFileStoragePath); + // 检查文件所在的目录是否存在,如果不存在则创建 + File parentDirectory = localCodePackFile.getParentFile(); + if (!parentDirectory.exists()) { + parentDirectory.mkdirs(); + } + FileOutputStream outputStream = new FileOutputStream(localCodePackFile); + FileCopyUtils.copy(resource.getInputStream(), outputStream); + outputStream.close(); + log.info("File downloaded and saved to: {}", localFileStoragePath); + } catch (IOException e) { + log.error("Error while saving file: " + e.getMessage()); + } + } + /** + * 根据文件路径上传 + * + * @param baseDir 相对应用的基目录 + * @param file 上传的文件 + * @return 文件名称 + * @throws IOException + */ + public static final 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 final 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)); + return getPathFileName(baseDir, fileName); + } + + /** + * 代码项目文件上传 + * + * @param baseDir 相对应用的基目录 + * @param file 上传的文件 + * @return 返回上传成功的文件名 + * @throws FileSizeLimitExceededException 如果超出最大大小 + * @throws FileNameLengthLimitExceededException 文件名太长 + * @throws IOException 比如读写文件出错时 + * @throws InvalidExtensionException 文件校验异常 + */ + public static final String uploadCodePack2TmpFolder(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 fileAbsDiskPath = + getAbsoluteFile(baseDir, file.getOriginalFilename()).getAbsolutePath(); + FileUtils.cleanDirectory(new File(baseDir)); + file.transferTo(Paths.get(fileAbsDiskPath)); + return fileAbsDiskPath; + } + /** + * 代码项目文件上传 + * + * @param baseDir 相对应用的基目录 + * @param file 上传的文件 + * @return 返回上传成功的文件名 + * @throws FileSizeLimitExceededException 如果超出最大大小 + * @throws FileNameLengthLimitExceededException 文件名太长 + * @throws IOException 比如读写文件出错时 + * @throws InvalidExtensionException 文件校验异常 + */ + public static final String uploadCodePack2TmpFolder(String baseDir, File file) + throws FileSizeLimitExceededException, IOException{ + int fileNameLength = Objects.requireNonNull(file.getName()).length(); + if (fileNameLength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) { + throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); + } + String fileAbsDiskPath = + getAbsoluteFile(baseDir, file.getName()).getAbsolutePath(); + FileUtils.cleanDirectory(new File(baseDir)); + FileUtils.copyFile(file, new File(fileAbsDiskPath)); + return fileAbsDiskPath; + } + /** + * 编码文件名 + */ + public static final String extractFilename(MultipartFile file) { + return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(), + FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file)); + } + + public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException { + File desc = new File(uploadDir + '/' + fileName); + + if (!desc.exists()) { + if (!desc.getParentFile().exists()) { + desc.getParentFile().mkdirs(); + } + } + return desc; + } + + public static final String getPathFileName(String uploadDir, String fileName) throws IOException { + int dirLastIndex = CSPConfig.getProfile().length() + 1; + String currentDir = StringUtils.substring(uploadDir, dirLastIndex); + return Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName; + } + + /** + * 文件大小校验 + * + * @param file 上传的文件 + * @return + * @throws FileSizeLimitExceededException 如果超出最大大小 + * @throws InvalidExtensionException + */ + public static final 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 if (allowedExtension == MimeTypeUtils.COMPRESS_EXTENSION) { + throw new InvalidExtensionException.InvalidCompressExtensionException(allowedExtension, extension, + fileName); + } else { + throw new InvalidExtensionException(allowedExtension, extension, fileName); + } + } + } + + /** + * 判断MIME类型是否是允许的MIME类型 + * + * @param extension + * @param allowedExtension + * @return + */ + public static final boolean isAllowedExtension(String extension, String[] allowedExtension) { + for (String str : allowedExtension) { + if (str.equalsIgnoreCase(extension)) { + return true; + } + } + return false; + } + + /** + * 获取文件名的后缀 + * + * @param file 表单文件 + * @return 后缀名 + */ + public static final 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/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/FileUtils.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/FileUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..bf39aaed414ecc366aa356cc5c12f664c0a95bab --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/FileUtils.java @@ -0,0 +1,337 @@ +package com.RVSmartPorting.common.utils.file; + + +import com.RVSmartPorting.common.config.CSPConfig; +import com.RVSmartPorting.common.utils.DateUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.uuid.IdUtils; +import com.alibaba.fastjson.util.IOUtils; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.ArrayUtils; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +/** + * 文件处理工具类 + * + * @author ruoyi + */ +@Slf4j +public class FileUtils { + public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+"; + + public static void copyFile(File srcFile, File destFile) throws IOException { + org.apache.commons.io.FileUtils.copyFile(srcFile, destFile); + } + + public static String extractFileNameFromUrl(String urlString) { + try { + URL url = new URL(urlString); + return new File(url.getPath()).getName(); + } catch (Exception e) { + e.printStackTrace(); + return null; // 或者返回一个默认的文件名 + } + } + + public static String extractFileName(ResponseEntity response) { + if (response.getStatusCode().is2xxSuccessful()) { + HttpHeaders headers = response.getHeaders(); + String contentDisposition = headers.getFirst(HttpHeaders.CONTENT_DISPOSITION); + + if (contentDisposition != null && contentDisposition.contains("filename=")) { + int startIndex = contentDisposition.indexOf("filename=") + 9; // 10 is the length of "filename=\"" + return contentDisposition.substring(startIndex); + } else { + log.error("Content-Disposition header not found or does not contain a filename."); + return null; + } + } else { + log.error("Failed to download file. HTTP status code: " + response.getStatusCode()); + return null; + } + } + public static void createFileIfNotExists(String filePath) { + File file = new File(filePath); + // 获取文件所在的父文件夹路径 + String parentFolderPath = file.getParent(); + File parentFolder = new File(parentFolderPath); + + // 检查父文件夹是否存在,如果不存在则创建 + if (!parentFolder.exists()) { + if (parentFolder.mkdirs()) { + log.info("父文件夹已成功创建:{}", parentFolderPath); + } else { + log.error("父文件夹创建失败:{}", parentFolderPath); + return; // 停止创建文件,因为父文件夹未创建成功 + } + } + // 检查文件是否存在 + if (file.exists()) { + log.info("文件已存在。"); + } else { + try { + // 创建文件 + if (file.createNewFile()) { + log.info("文件已成功创建。"); + } else { + log.error("文件创建失败。"); + } + } catch (IOException e) { + log.error("创建文件时出现异常:" + e.getMessage(), e); + } + } + } + public static void deleteDirectory(File directory) { + if (directory.exists()) { + File[] files = directory.listFiles(); + if (files != null) { + for (File file : files) { + if (file.isDirectory()) { + // 递归删除子文件夹 + deleteDirectory(file); + } else { + // 删除文件 + file.delete(); + } + } + } + // 删除空文件夹 + directory.delete(); + } + } + + /** + * 输出指定文件的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 { + IOUtils.close(os); + IOUtils.close(fis); + } + } + + /** + * 写数据到文件中 + * + * @param data 数据 + * @return 目标文件 + * @throws IOException IO异常 + */ + public static String writeImportBytes(byte[] data) throws IOException { + return writeBytes(data, CSPConfig.getImportPath()); + } + + /** + * 写数据到文件中 + * + * @param data 数据 + * @param uploadDir 目标文件 + * @return 目标文件 + * @throws IOException IO异常 + */ + public static String writeBytes(byte[] data, String uploadDir) throws IOException { + FileOutputStream fos = null; + String pathName = ""; + try { + String extension = getFileExtendName(data); + pathName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension; + File file = FileUploadUtils.getAbsoluteFile(uploadDir, pathName); + fos = new FileOutputStream(file); + fos.write(data); + } finally { + IOUtils.close(fos); + } + return FileUploadUtils.getPathFileName(uploadDir, pathName); + } + + + public static void cleanDirectory(File file) throws IOException { + org.apache.commons.io.FileUtils.cleanDirectory(file); + } + + /** + * 删除文件 + * + * @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; + } + + /** + * 文件名称验证 + * + * @param filename 文件名称 + * @return true 正常 false 非法 + */ + public static boolean isValidFilename(String filename) { + return filename.matches(FILENAME_PATTERN); + } + + /** + * 检查文件是否可下载 + * + * @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 request 请求对象 + * @param fileName 文件名 + * @return 编码后的文件名 + */ + public static String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException { + final String agent = request.getHeader("USER-AGENT"); + String filename = fileName; + if (agent.contains("MSIE")) { + // IE浏览器 + filename = URLEncoder.encode(filename, "utf-8"); + filename = filename.replace("+", " "); + } else if (agent.contains("Firefox")) { + // 火狐浏览器 + filename = new String(fileName.getBytes(), "ISO8859-1"); + } else if (agent.contains("Chrome")) { + // google浏览器 + filename = URLEncoder.encode(filename, "utf-8"); + } else { + // 其它浏览器 + filename = URLEncoder.encode(filename, "utf-8"); + } + return filename; + } + + /** + * 下载文件名重新编码 + * + * @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"); + } + + /** + * 获取图像后缀 + * + * @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; + } + + /** + * 获取文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi.png + * + * @param fileName 路径名称 + * @return 没有文件路径的名称 + */ + public static String getName(String fileName) { + if (fileName == null) { + return null; + } + int lastUnixPos = fileName.lastIndexOf('/'); + int lastWindowsPos = fileName.lastIndexOf('\\'); + int index = Math.max(lastUnixPos, lastWindowsPos); + return fileName.substring(index + 1); + } + + /** + * 获取不带后缀文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi + * + * @param fileName 路径名称 + * @return 没有文件路径和后缀的名称 + */ + public static String getNameNotSuffix(String fileName) { + if (fileName == null) { + return null; + } + String baseName = FilenameUtils.getBaseName(fileName); + return baseName; + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/ImageUtils.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/ImageUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..4a41c9b42606af4b90cd706f25565de987677811 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/ImageUtils.java @@ -0,0 +1,99 @@ +package com.RVSmartPorting.common.utils.file; + +import com.RVSmartPorting.common.config.CSPConfig; +import com.RVSmartPorting.common.constant.Constants; +import com.RVSmartPorting.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 = CSPConfig.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/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/MimeTypeUtils.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/MimeTypeUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..beedca3a1f1362547b5e48435ed92a709da28037 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/MimeTypeUtils.java @@ -0,0 +1,60 @@ +package com.RVSmartPorting.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[] COMPRESS_EXTENSION = {"rar", "zip", "gz", "bz2", "7z", "xz", "bz2", "tar", "tar.gz", + "tar", "xz", "tar.bz2"}; + + + 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/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/PathConverterUtil.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/PathConverterUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..01229ab0435a1e77c0342e920d83167bb91f65c6 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/file/PathConverterUtil.java @@ -0,0 +1,36 @@ +package com.RVSmartPorting.common.utils.file; + +public class PathConverterUtil { + public static String convertPath(String absolutePath) { + // 获取当前操作系统的名称 + String os = System.getProperty("os.name").toLowerCase(); + + // 如果是Windows系统,将路径分隔符替换为Windows风格 + if (os.contains("win")) { + return absolutePath.replace("/", "\\"); + } + + // 如果是Linux系统,将路径分隔符替换为Linux风格 + if (os.contains("nix") || os.contains("nux") || os.contains("mac")) { + return absolutePath.replace("\\", "/"); + } + + // 如果不是Windows或Linux,则保持原样 + return absolutePath; + } + public static void test() { + // 示例用法 + String absolutePath = "C:/Temp/test_upload_repo/upload/codePackStorageRoot/b7/a0/b7a0f48c7642d0264d0b5617d7773a0fa5ae9c90/1695285270657.zip"; + String convertedPath = convertPath(absolutePath); + System.out.println("Converted Path: " + convertedPath); + } + public static void test2() { + String absolutePath = "C:/Users/User/Documents/file.txt"; + String convertedPath = convertPath(absolutePath); + System.out.println("Converted Path: " + convertedPath); + } + public static void main(String[] args) { + // 示例用法 + test(); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/html/EscapeUtil.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/html/EscapeUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..dc4f35052d44791d4705ea1d8ea2bbbedb953113 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/html/EscapeUtil.java @@ -0,0 +1,157 @@ +package com.RVSmartPorting.common.utils.html; + + +import com.RVSmartPorting.common.utils.StringUtils; + +/** + * 转义和反转义工具类 + * + * @author ruoyi + */ +public class EscapeUtil +{ + public static final String RE_HTML_MARK = "(<[^<]*?>)|(<[\\s]*?/[^<]*?>)|(<[^<]*?/[\\s]*?>)"; + + private static final char[][] TEXT = new char[64][]; + + static + { + for (int i = 0; i < 64; i++) + { + TEXT[i] = new char[] { (char) i }; + } + + // special HTML characters + TEXT['\''] = "'".toCharArray(); // 单引号 + TEXT['"'] = """.toCharArray(); // 单引号 + TEXT['&'] = "&".toCharArray(); // &符 + TEXT['<'] = "<".toCharArray(); // 小于号 + TEXT['>'] = ">".toCharArray(); // 大于号 + } + + /** + * 转义文本中的HTML字符为安全的字符 + * + * @param text 被转义的文本 + * @return 转义后的文本 + */ + public static String escape(String text) + { + return encode(text); + } + + /** + * 还原被转义的HTML特殊字符 + * + * @param content 包含转义符的HTML内容 + * @return 转换后的字符串 + */ + public static String unescape(String content) + { + return decode(content); + } + + /** + * 清除所有HTML标签,但是不删除标签内的内容 + * + * @param content 文本 + * @return 清除标签后的文本 + */ + public static String clean(String content) + { + return new HTMLFilter().filter(content); + } + + /** + * Escape编码 + * + * @param text 被编码的文本 + * @return 编码后的字符 + */ + private static String encode(String text) + { + int len; + if ((text == null) || ((len = text.length()) == 0)) + { + return StringUtils.EMPTY; + } + StringBuilder buffer = new StringBuilder(len + (len >> 2)); + char c; + for (int i = 0; i < len; i++) + { + c = text.charAt(i); + if (c < 64) + { + buffer.append(TEXT[c]); + } + else + { + buffer.append(c); + } + } + return buffer.toString(); + } + + /** + * Escape解码 + * + * @param content 被转义的内容 + * @return 解码后的字符串 + */ + public static String decode(String content) + { + if (StringUtils.isEmpty(content)) + { + return content; + } + + StringBuilder tmp = new StringBuilder(content.length()); + int lastPos = 0, pos = 0; + char ch; + while (lastPos < content.length()) + { + pos = content.indexOf("%", lastPos); + if (pos == lastPos) + { + if (content.charAt(pos + 1) == 'u') + { + ch = (char) Integer.parseInt(content.substring(pos + 2, pos + 6), 16); + tmp.append(ch); + lastPos = pos + 6; + } + else + { + ch = (char) Integer.parseInt(content.substring(pos + 1, pos + 3), 16); + tmp.append(ch); + lastPos = pos + 3; + } + } + else + { + if (pos == -1) + { + tmp.append(content.substring(lastPos)); + lastPos = content.length(); + } + else + { + tmp.append(content.substring(lastPos, pos)); + lastPos = pos; + } + } + } + return tmp.toString(); + } + + public static void main(String[] args) + { + String html = ""; + // String html = "ipt>alert(\"XSS\")ipt>"; + // String html = "<123"; + // String html = "123>"; + System.out.println(EscapeUtil.clean(html)); + System.out.println(EscapeUtil.escape(html)); + System.out.println(EscapeUtil.unescape(html)); + } +} + diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/html/HTMLFilter.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/html/HTMLFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..477de4d6c172cd3bb57f9a3cf244ea759ab94695 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/html/HTMLFilter.java @@ -0,0 +1,567 @@ +package com.RVSmartPorting.common.utils.html; + +/** + * HTML过滤器,用于去除XSS漏洞隐患。 + * + * @author ruoyi + */ + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public final class HTMLFilter +{ + /** + * regex flag union representing /si modifiers in php + **/ + private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL; + private static final Pattern P_COMMENTS = Pattern.compile("", Pattern.DOTALL); + private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI); + private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL); + private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI); + private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI); + private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI); + private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI); + private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI); + private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?"); + private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?"); + private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?"); + private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))"); + private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL); + private static final Pattern P_END_ARROW = Pattern.compile("^>"); + private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)"); + private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)"); + private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)"); + private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)"); + private static final Pattern P_AMP = Pattern.compile("&"); + private static final Pattern P_QUOTE = Pattern.compile("\""); + private static final Pattern P_LEFT_ARROW = Pattern.compile("<"); + private static final Pattern P_RIGHT_ARROW = Pattern.compile(">"); + private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>"); + + // @xxx could grow large... maybe use sesat's ReferenceMap + private static final ConcurrentMap P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<>(); + private static final ConcurrentMap P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<>(); + + /** + * set of allowed html elements, along with allowed attributes for each element + **/ + private final Map> vAllowed; + /** + * counts of open tags for each (allowable) html element + **/ + private final Map vTagCounts = new HashMap<>(); + + /** + * html elements which must always be self-closing (e.g. "") + **/ + private final String[] vSelfClosingTags; + /** + * html elements which must always have separate opening and closing tags (e.g. "") + **/ + private final String[] vNeedClosingTags; + /** + * set of disallowed html elements + **/ + private final String[] vDisallowed; + /** + * attributes which should be checked for valid protocols + **/ + private final String[] vProtocolAtts; + /** + * allowed protocols + **/ + private final String[] vAllowedProtocols; + /** + * tags which should be removed if they contain no content (e.g. "" or "") + **/ + private final String[] vRemoveBlanks; + /** + * entities allowed within html markup + **/ + private final String[] vAllowedEntities; + /** + * flag determining whether comments are allowed in input String. + */ + private final boolean stripComment; + private final boolean encodeQuotes; + /** + * flag determining whether to try to make tags when presented with "unbalanced" angle brackets (e.g. "" + * becomes " text "). If set to false, unbalanced angle brackets will be html escaped. + */ + private final boolean alwaysMakeTags; + + /** + * Default constructor. + */ + public HTMLFilter() + { + vAllowed = new HashMap<>(); + + final ArrayList a_atts = new ArrayList<>(); + a_atts.add("href"); + a_atts.add("target"); + vAllowed.put("a", a_atts); + + final ArrayList img_atts = new ArrayList<>(); + img_atts.add("src"); + img_atts.add("width"); + img_atts.add("height"); + img_atts.add("alt"); + vAllowed.put("img", img_atts); + + final ArrayList no_atts = new ArrayList<>(); + vAllowed.put("b", no_atts); + vAllowed.put("strong", no_atts); + vAllowed.put("i", no_atts); + vAllowed.put("em", no_atts); + + vSelfClosingTags = new String[] { "img" }; + vNeedClosingTags = new String[] { "a", "b", "strong", "i", "em" }; + vDisallowed = new String[] {}; + vAllowedProtocols = new String[] { "http", "mailto", "https" }; // no ftp. + vProtocolAtts = new String[] { "src", "href" }; + vRemoveBlanks = new String[] { "a", "b", "strong", "i", "em" }; + vAllowedEntities = new String[] { "amp", "gt", "lt", "quot" }; + stripComment = true; + encodeQuotes = true; + alwaysMakeTags = false; + } + + /** + * Map-parameter configurable constructor. + * + * @param conf map containing configuration. keys match field names. + */ + @SuppressWarnings("unchecked") + public HTMLFilter(final Map conf) + { + + assert conf.containsKey("vAllowed") : "configuration requires vAllowed"; + assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags"; + assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags"; + assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed"; + assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols"; + assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts"; + assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks"; + assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities"; + + vAllowed = Collections.unmodifiableMap((HashMap>) conf.get("vAllowed")); + vSelfClosingTags = (String[]) conf.get("vSelfClosingTags"); + vNeedClosingTags = (String[]) conf.get("vNeedClosingTags"); + vDisallowed = (String[]) conf.get("vDisallowed"); + vAllowedProtocols = (String[]) conf.get("vAllowedProtocols"); + vProtocolAtts = (String[]) conf.get("vProtocolAtts"); + vRemoveBlanks = (String[]) conf.get("vRemoveBlanks"); + vAllowedEntities = (String[]) conf.get("vAllowedEntities"); + stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true; + encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true; + alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true; + } + + private void reset() + { + vTagCounts.clear(); + } + + // --------------------------------------------------------------- + // my versions of some PHP library functions + public static String chr(final int decimal) + { + return String.valueOf((char) decimal); + } + + public static String htmlSpecialChars(final String s) + { + String result = s; + result = regexReplace(P_AMP, "&", result); + result = regexReplace(P_QUOTE, """, result); + result = regexReplace(P_LEFT_ARROW, "<", result); + result = regexReplace(P_RIGHT_ARROW, ">", result); + return result; + } + + // --------------------------------------------------------------- + + /** + * given a user submitted input String, filter out any invalid or restricted html. + * + * @param input text (i.e. submitted by a user) than may contain html + * @return "clean" version of input, with only valid, whitelisted html elements allowed + */ + public String filter(final String input) + { + reset(); + String s = input; + + s = escapeComments(s); + + s = balanceHTML(s); + + s = checkTags(s); + + s = processRemoveBlanks(s); + + // s = validateEntities(s); + + return s; + } + + public boolean isAlwaysMakeTags() + { + return alwaysMakeTags; + } + + public boolean isStripComments() + { + return stripComment; + } + + private String escapeComments(final String s) + { + final Matcher m = P_COMMENTS.matcher(s); + final StringBuffer buf = new StringBuffer(); + if (m.find()) + { + final String match = m.group(1); // (.*?) + m.appendReplacement(buf, Matcher.quoteReplacement("")); + } + m.appendTail(buf); + + return buf.toString(); + } + + private String balanceHTML(String s) + { + if (alwaysMakeTags) + { + // + // try and form html + // + s = regexReplace(P_END_ARROW, "", s); + // 不追加结束标签 + s = regexReplace(P_BODY_TO_END, "<$1>", s); + s = regexReplace(P_XML_CONTENT, "$1<$2", s); + + } + else + { + // + // escape stray brackets + // + s = regexReplace(P_STRAY_LEFT_ARROW, "<$1", s); + s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2><", s); + + // + // the last regexp causes '<>' entities to appear + // (we need to do a lookahead assertion so that the last bracket can + // be used in the next pass of the regexp) + // + s = regexReplace(P_BOTH_ARROWS, "", s); + } + + return s; + } + + private String checkTags(String s) + { + Matcher m = P_TAGS.matcher(s); + + final StringBuffer buf = new StringBuffer(); + while (m.find()) + { + String replaceStr = m.group(1); + replaceStr = processTag(replaceStr); + m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr)); + } + m.appendTail(buf); + + // these get tallied in processTag + // (remember to reset before subsequent calls to filter method) + final StringBuilder sBuilder = new StringBuilder(buf.toString()); + for (String key : vTagCounts.keySet()) + { + for (int ii = 0; ii < vTagCounts.get(key); ii++) + { + sBuilder.append(""); + } + } + s = sBuilder.toString(); + + return s; + } + + private String processRemoveBlanks(final String s) + { + String result = s; + for (String tag : vRemoveBlanks) + { + if (!P_REMOVE_PAIR_BLANKS.containsKey(tag)) + { + P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?>")); + } + result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result); + if (!P_REMOVE_SELF_BLANKS.containsKey(tag)) + { + P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>")); + } + result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result); + } + + return result; + } + + private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s) + { + Matcher m = regex_pattern.matcher(s); + return m.replaceAll(replacement); + } + + private String processTag(final String s) + { + // ending tags + Matcher m = P_END_TAG.matcher(s); + if (m.find()) + { + final String name = m.group(1).toLowerCase(); + if (allowed(name)) + { + if (false == inArray(name, vSelfClosingTags)) + { + if (vTagCounts.containsKey(name)) + { + vTagCounts.put(name, vTagCounts.get(name) - 1); + return ""; + } + } + } + } + + // starting tags + m = P_START_TAG.matcher(s); + if (m.find()) + { + final String name = m.group(1).toLowerCase(); + final String body = m.group(2); + String ending = m.group(3); + + // debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" ); + if (allowed(name)) + { + final StringBuilder params = new StringBuilder(); + + final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body); + final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body); + final List paramNames = new ArrayList<>(); + final List paramValues = new ArrayList<>(); + while (m2.find()) + { + paramNames.add(m2.group(1)); // ([a-z0-9]+) + paramValues.add(m2.group(3)); // (.*?) + } + while (m3.find()) + { + paramNames.add(m3.group(1)); // ([a-z0-9]+) + paramValues.add(m3.group(3)); // ([^\"\\s']+) + } + + String paramName, paramValue; + for (int ii = 0; ii < paramNames.size(); ii++) + { + paramName = paramNames.get(ii).toLowerCase(); + paramValue = paramValues.get(ii); + + // debug( "paramName='" + paramName + "'" ); + // debug( "paramValue='" + paramValue + "'" ); + // debug( "allowed? " + vAllowed.get( name ).contains( paramName ) ); + + if (allowedAttribute(name, paramName)) + { + if (inArray(paramName, vProtocolAtts)) + { + paramValue = processParamProtocol(paramValue); + } + params.append(' ').append(paramName).append("=\"").append(paramValue).append("\""); + } + } + + if (inArray(name, vSelfClosingTags)) + { + ending = " /"; + } + + if (inArray(name, vNeedClosingTags)) + { + ending = ""; + } + + if (ending == null || ending.length() < 1) + { + if (vTagCounts.containsKey(name)) + { + vTagCounts.put(name, vTagCounts.get(name) + 1); + } + else + { + vTagCounts.put(name, 1); + } + } + else + { + ending = " /"; + } + return "<" + name + params + ending + ">"; + } + else + { + return ""; + } + } + + // comments + m = P_COMMENT.matcher(s); + if (!stripComment && m.find()) + { + return "<" + m.group() + ">"; + } + + return ""; + } + + private String processParamProtocol(String s) + { + s = decodeEntities(s); + final Matcher m = P_PROTOCOL.matcher(s); + if (m.find()) + { + final String protocol = m.group(1); + if (!inArray(protocol, vAllowedProtocols)) + { + // bad protocol, turn into local anchor link instead + s = "#" + s.substring(protocol.length() + 1); + if (s.startsWith("#//")) + { + s = "#" + s.substring(3); + } + } + } + + return s; + } + + private String decodeEntities(String s) + { + StringBuffer buf = new StringBuffer(); + + Matcher m = P_ENTITY.matcher(s); + while (m.find()) + { + final String match = m.group(1); + final int decimal = Integer.decode(match).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + buf = new StringBuffer(); + m = P_ENTITY_UNICODE.matcher(s); + while (m.find()) + { + final String match = m.group(1); + final int decimal = Integer.valueOf(match, 16).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + buf = new StringBuffer(); + m = P_ENCODE.matcher(s); + while (m.find()) + { + final String match = m.group(1); + final int decimal = Integer.valueOf(match, 16).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + s = validateEntities(s); + return s; + } + + private String validateEntities(final String s) + { + StringBuffer buf = new StringBuffer(); + + // validate entities throughout the string + Matcher m = P_VALID_ENTITIES.matcher(s); + while (m.find()) + { + final String one = m.group(1); // ([^&;]*) + final String two = m.group(2); // (?=(;|&|$)) + m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two))); + } + m.appendTail(buf); + + return encodeQuotes(buf.toString()); + } + + private String encodeQuotes(final String s) + { + if (encodeQuotes) + { + StringBuffer buf = new StringBuffer(); + Matcher m = P_VALID_QUOTES.matcher(s); + while (m.find()) + { + final String one = m.group(1); // (>|^) + final String two = m.group(2); // ([^<]+?) + final String three = m.group(3); // (<|$) + // 不替换双引号为",防止json格式无效 regexReplace(P_QUOTE, """, two) + m.appendReplacement(buf, Matcher.quoteReplacement(one + two + three)); + } + m.appendTail(buf); + return buf.toString(); + } + else + { + return s; + } + } + + private String checkEntity(final String preamble, final String term) + { + + return ";".equals(term) && isValidEntity(preamble) ? '&' + preamble : "&" + preamble; + } + + private boolean isValidEntity(final String entity) + { + return inArray(entity, vAllowedEntities); + } + + private static boolean inArray(final String s, final String[] array) + { + for (String item : array) + { + if (item != null && item.equals(s)) + { + return true; + } + } + return false; + } + + private boolean allowed(final String name) + { + return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed); + } + + private boolean allowedAttribute(final String name, final String paramName) + { + return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName)); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/http/FileDownloadListener.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/http/FileDownloadListener.java new file mode 100644 index 0000000000000000000000000000000000000000..5198637307146a66b1f0f2f62d257b227c855cd0 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/http/FileDownloadListener.java @@ -0,0 +1,41 @@ +package com.RVSmartPorting.common.utils.http; + +import java.io.File; + +public interface FileDownloadListener { + + /** + * 开始回调 + * + */ + void onDownloadStart(); + + /** + * 完成回调 + * + * @param file 下载的文件 + */ + void onDownloadSuccess(File file); + + /** + * 下载进度 + * + * @param progress 下载进度 + */ + void onDownloading(int progress); + + /** + * 出错回调 + * + * @param e 异常 + */ + void onDownloadFailed(Exception e); + + /** + * 超时回调 + * + * @param e 异常 + */ + void onDownloadTimeout(Exception e); + +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/http/HttpHelper.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/http/HttpHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..a20a5638d9341e5d11160f6a3b8832bae22acff4 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/http/HttpHelper.java @@ -0,0 +1,56 @@ +package com.RVSmartPorting.common.utils.http; + +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.ServletRequest; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; + +/** + * 通用http工具封装 + * + * @author ruoyi + */ +public class HttpHelper +{ + private static final Logger LOGGER = LoggerFactory.getLogger(HttpHelper.class); + + public static String getBodyString(ServletRequest request) + { + StringBuilder sb = new StringBuilder(); + BufferedReader reader = null; + try (InputStream inputStream = request.getInputStream()) + { + reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); + String line = ""; + while ((line = reader.readLine()) != null) + { + sb.append(line); + } + } + catch (IOException e) + { + LOGGER.warn("getBodyString出现问题!"); + } + finally + { + if (reader != null) + { + try + { + reader.close(); + } + catch (IOException e) + { + LOGGER.error(ExceptionUtils.getMessage(e)); + } + } + } + return sb.toString(); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/http/HttpUtils.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/http/HttpUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..5fb590405e4fc43014ce8abb0de39657dd6506c4 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/http/HttpUtils.java @@ -0,0 +1,260 @@ +package com.RVSmartPorting.common.utils.http; + +/** + * 通用http发送方法 + * + * @author ruoyi + */ + +import com.RVSmartPorting.common.constant.Constants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.*; +import java.io.*; +import java.net.ConnectException; +import java.net.SocketTimeoutException; +import java.net.URL; +import java.net.URLConnection; +import java.security.cert.X509Certificate; + +/** + * 通用http发送方法 + * + * @author ruoyi + */ +public class HttpUtils +{ + private static final Logger log = LoggerFactory.getLogger(HttpUtils.class); + + /** + * 向指定 URL 发送GET方法的请求 + * + * @param url 发送请求的 URL + * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 + * @return 所代表远程资源的响应结果 + */ + public static String sendGet(String url, String param) + { + return sendGet(url, param, Constants.UTF8); + } + + /** + * 向指定 URL 发送GET方法的请求 + * + * @param url 发送请求的 URL + * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 + * @param contentType 编码类型 + * @return 所代表远程资源的响应结果 + */ + public static String sendGet(String url, String param, String contentType) + { + StringBuilder result = new StringBuilder(); + BufferedReader in = null; + try + { + String urlNameString = url + "?" + param; + log.info("sendGet - {}", urlNameString); + URL realUrl = new URL(urlNameString); + URLConnection connection = realUrl.openConnection(); + connection.setRequestProperty("accept", "*/*"); + connection.setRequestProperty("connection", "Keep-Alive"); + connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); + connection.connect(); + in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType)); + String line; + while ((line = in.readLine()) != null) + { + result.append(line); + } + log.info("recv - {}", result); + } + catch (ConnectException e) + { + log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e); + } + catch (SocketTimeoutException e) + { + log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e); + } + catch (IOException e) + { + log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e); + } + catch (Exception e) + { + log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e); + } + finally + { + try + { + if (in != null) + { + in.close(); + } + } + catch (Exception ex) + { + log.error("调用in.close Exception, url=" + url + ",param=" + param, ex); + } + } + return result.toString(); + } + + /** + * 向指定 URL 发送POST方法的请求 + * + * @param url 发送请求的 URL + * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 + * @return 所代表远程资源的响应结果 + */ + public static String sendPost(String url, String param) + { + PrintWriter out = null; + BufferedReader in = null; + StringBuilder result = new StringBuilder(); + try + { + String urlNameString = url; + log.info("sendPost - {}", urlNameString); + URL realUrl = new URL(urlNameString); + URLConnection conn = realUrl.openConnection(); + conn.setRequestProperty("accept", "*/*"); + conn.setRequestProperty("connection", "Keep-Alive"); + conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); + conn.setRequestProperty("Accept-Charset", "utf-8"); + conn.setRequestProperty("contentType", "utf-8"); + conn.setDoOutput(true); + conn.setDoInput(true); + out = new PrintWriter(conn.getOutputStream()); + out.print(param); + out.flush(); + in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8")); + String line; + while ((line = in.readLine()) != null) + { + result.append(line); + } + log.info("recv - {}", result); + } + catch (ConnectException e) + { + log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e); + } + catch (SocketTimeoutException e) + { + log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e); + } + catch (IOException e) + { + log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e); + } + catch (Exception e) + { + log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e); + } + finally + { + try + { + if (out != null) + { + out.close(); + } + if (in != null) + { + in.close(); + } + } + catch (IOException ex) + { + log.error("调用in.close Exception, url=" + url + ",param=" + param, ex); + } + } + return result.toString(); + } + + public static String sendSSLPost(String url, String param) + { + StringBuilder result = new StringBuilder(); + String urlNameString = url + "?" + param; + try + { + log.info("sendSSLPost - {}", urlNameString); + SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom()); + URL console = new URL(urlNameString); + HttpsURLConnection conn = (HttpsURLConnection) console.openConnection(); + conn.setRequestProperty("accept", "*/*"); + conn.setRequestProperty("connection", "Keep-Alive"); + conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); + conn.setRequestProperty("Accept-Charset", "utf-8"); + conn.setRequestProperty("contentType", "utf-8"); + conn.setDoOutput(true); + conn.setDoInput(true); + + conn.setSSLSocketFactory(sc.getSocketFactory()); + conn.setHostnameVerifier(new TrustAnyHostnameVerifier()); + conn.connect(); + InputStream is = conn.getInputStream(); + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + String ret = ""; + while ((ret = br.readLine()) != null) + { + if (ret != null && !"".equals(ret.trim())) + { + result.append(new String(ret.getBytes("ISO-8859-1"), "utf-8")); + } + } + log.info("recv - {}", result); + conn.disconnect(); + br.close(); + } + catch (ConnectException e) + { + log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e); + } + catch (SocketTimeoutException e) + { + log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e); + } + catch (IOException e) + { + log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e); + } + catch (Exception e) + { + log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e); + } + return result.toString(); + } + + private static class TrustAnyTrustManager implements X509TrustManager + { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) + { + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) + { + } + + @Override + public X509Certificate[] getAcceptedIssuers() + { + return new X509Certificate[] {}; + } + } + + private static class TrustAnyHostnameVerifier implements HostnameVerifier + { + @Override + public boolean verify(String hostname, SSLSession session) + { + return true; + } + } +} \ No newline at end of file diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/ip/AddressUtils.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/ip/AddressUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..2b418ad05bd0b3a6150b8f89de4dfaf2a06ec57e --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/ip/AddressUtils.java @@ -0,0 +1,58 @@ +package com.RVSmartPorting.common.utils.ip; + +/** + * 获取地址类 + * + * @author ruoyi + */ + +import com.RVSmartPorting.common.constant.Constants; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.http.HttpUtils; +import com.RVSmartPorting.common.config.CSPConfig; +import com.alibaba.fastjson.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AddressUtils +{ + private static final Logger log = LoggerFactory.getLogger(AddressUtils.class); + + // IP地址查询 + public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp"; + + // 未知地址 + public static final String UNKNOWN = "XX XX"; + + public static String getRealAddressByIP(String ip) + { + String address = UNKNOWN; + // 内网不查询 + if (IpUtils.internalIp(ip)) + { + return "内网IP"; + } + if (CSPConfig.isAddressEnabled()) + { + try + { + String rspStr = HttpUtils.sendGet(IP_URL, "ip=" + ip + "&json=true", Constants.GBK); + if (StringUtils.isEmpty(rspStr)) + { + log.error("获取地理位置异常 {}", ip); + return UNKNOWN; + } + JSONObject obj = JSONObject.parseObject(rspStr); + String region = obj.getString("pro"); + String city = obj.getString("city"); + return String.format("%s %s", region, city); + } + catch (Exception e) + { + log.error("获取地理位置异常 {}", ip); + } + } + return address; + } +} + diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/ip/IpUtils.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/ip/IpUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..3540ff1828607026e2a60f5f70a23ff87790c39c --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/ip/IpUtils.java @@ -0,0 +1,457 @@ +package com.RVSmartPorting.common.utils.ip; + +import com.RVSmartPorting.common.utils.ServletUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import lombok.extern.slf4j.Slf4j; + +import java.net.InetAddress; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.servlet.http.HttpServletRequest; + +/** + * 获取IP方法 + * + * @author ruoyi + */ +@Slf4j +public class IpUtils { + public final static String REGX_0_255 = "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)"; + // 匹配 ip + public final static String REGX_IP = "((" + REGX_0_255 + "\\.){3}" + REGX_0_255 + ")"; + public final static String REGX_IP_WILDCARD = "(((\\*\\.){3}\\*)|(" + REGX_0_255 + "(\\.\\*){3})|(" + REGX_0_255 + "\\." + REGX_0_255 + ")(\\.\\*){2}" + "|((" + REGX_0_255 + "\\.){3}\\*))"; + // 匹配网段 + public final static String REGX_IP_SEG = "(" + REGX_IP + "\\-" + REGX_IP + ")"; + + /** + * 获取客户端IP + * + * @return IP地址 + */ + public static String getIpAddr() { + return getIpAddr(ServletUtils.getRequest()); + } + + /** + * 获取客户端IP + * + * @param request 请求对象 + * @return IP地址 + */ + public static String getIpAddr(HttpServletRequest request) { + if (request == null) { + return "unknown"; + } + String ip = request.getHeader("x-forwarded-for"); + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("X-Forwarded-For"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("X-Real-IP"); + } + + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + + return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip); + } + + /** + * 检查是否为内部IP地址 + * + * @param ip IP地址 + * @return 结果 + */ + public static boolean internalIp(String ip) { + byte[] addr = textToNumericFormatV4(ip); + return internalIp(addr) || "127.0.0.1".equals(ip); + } + + /** + * 检查是否为内部IP地址 + * + * @param addr byte地址 + * @return 结果 + */ + private static boolean internalIp(byte[] addr) { + if (StringUtils.isNull(addr) || addr.length < 2) { + return true; + } + final byte b0 = addr[0]; + final byte b1 = addr[1]; + // 10.x.x.x/8 + final byte SECTION_1 = 0x0A; + // 172.16.x.x/12 + final byte SECTION_2 = (byte) 0xAC; + final byte SECTION_3 = (byte) 0x10; + final byte SECTION_4 = (byte) 0x1F; + // 192.168.x.x/16 + final byte SECTION_5 = (byte) 0xC0; + final byte SECTION_6 = (byte) 0xA8; + switch (b0) { + case SECTION_1: + return true; + case SECTION_2: + if (b1 >= SECTION_3 && b1 <= SECTION_4) { + return true; + } + case SECTION_5: + switch (b1) { + case SECTION_6: + return true; + } + default: + return false; + } + } + + /** + * 将IPv4地址转换成字节 + * + * @param text IPv4地址 + * @return byte 字节 + */ + public static byte[] textToNumericFormatV4(String text) { + if (text.length() == 0) { + return null; + } + + byte[] bytes = new byte[4]; + String[] elements = text.split("\\.", -1); + try { + long l; + int i; + switch (elements.length) { + case 1: + l = Long.parseLong(elements[0]); + if ((l < 0L) || (l > 4294967295L)) { + return null; + } + bytes[0] = (byte) (int) (l >> 24 & 0xFF); + bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF); + bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); + bytes[3] = (byte) (int) (l & 0xFF); + break; + case 2: + l = Integer.parseInt(elements[0]); + if ((l < 0L) || (l > 255L)) { + return null; + } + bytes[0] = (byte) (int) (l & 0xFF); + l = Integer.parseInt(elements[1]); + if ((l < 0L) || (l > 16777215L)) { + return null; + } + bytes[1] = (byte) (int) (l >> 16 & 0xFF); + bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); + bytes[3] = (byte) (int) (l & 0xFF); + break; + case 3: + for (i = 0; i < 2; ++i) { + l = Integer.parseInt(elements[i]); + if ((l < 0L) || (l > 255L)) { + return null; + } + bytes[i] = (byte) (int) (l & 0xFF); + } + l = Integer.parseInt(elements[2]); + if ((l < 0L) || (l > 65535L)) { + return null; + } + bytes[2] = (byte) (int) (l >> 8 & 0xFF); + bytes[3] = (byte) (int) (l & 0xFF); + break; + case 4: + for (i = 0; i < 4; ++i) { + l = Integer.parseInt(elements[i]); + if ((l < 0L) || (l > 255L)) { + return null; + } + bytes[i] = (byte) (int) (l & 0xFF); + } + break; + default: + return null; + } + } catch (NumberFormatException e) { + return null; + } + return bytes; + } + + /** + * 获取IP地址 + * + * @return 本地IP地址 + */ + public static String getHostIp() { + try { + return InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + } + return "127.0.0.1"; + } + + /** + * 获取主机名 + * + * @return 本地主机名 + */ + public static String getHostName() { + try { + return InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException e) { + } + return "未知"; + } + + /** + * 从多级反向代理中获得第一个非unknown IP地址 + * + * @param ip 获得的IP地址 + * @return 第一个非unknown IP地址 + */ + public static String getMultistageReverseProxyIp(String ip) { + // 多级反向代理检测 + if (ip != null && ip.indexOf(",") > 0) { + final String[] ips = ip.trim().split(","); + for (String subIp : ips) { + if (false == isUnknown(subIp)) { + ip = subIp; + break; + } + } + } + return StringUtils.substring(ip, 0, 255); + } + + /** + * 检测给定字符串是否为未知,多用于检测HTTP请求相关 + * + * @param checkString 被检测的字符串 + * @return 是否未知 + */ + public static boolean isUnknown(String checkString) { + return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString); + } + + /** + * 是否为IP + */ + public static boolean isIP(String ip) { + return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP); + } + + /** + * 是否为IP,或 *为间隔的通配符地址 + */ + public static boolean isIpWildCard(String ip) { + return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP_WILDCARD); + } + + /** + * 检测参数是否在ip通配符里 + */ + public static boolean ipIsInWildCardNoCheck(String ipWildCard, String ip) { + String[] s1 = ipWildCard.split("\\."); + String[] s2 = ip.split("\\."); + boolean isMatchedSeg = true; + for (int i = 0; i < s1.length && !s1[i].equals("*"); i++) { + if (!s1[i].equals(s2[i])) { + isMatchedSeg = false; + break; + } + } + return isMatchedSeg; + } + + /** + * 是否为特定格式如:“10.10.10.1-10.10.10.99”的ip段字符串 + */ + public static boolean isIPSegment(String ipSeg) { + return StringUtils.isNotBlank(ipSeg) && ipSeg.matches(REGX_IP_SEG); + } + + /** + * 判断ip是否在指定网段中 + */ + public static boolean ipIsInNetNoCheck(String iparea, String ip) { + int idx = iparea.indexOf('-'); + String[] sips = iparea.substring(0, idx).split("\\."); + String[] sipe = iparea.substring(idx + 1).split("\\."); + String[] sipt = ip.split("\\."); + long ips = 0L, ipe = 0L, ipt = 0L; + for (int i = 0; i < 4; ++i) { + ips = ips << 8 | Integer.parseInt(sips[i]); + ipe = ipe << 8 | Integer.parseInt(sipe[i]); + ipt = ipt << 8 | Integer.parseInt(sipt[i]); + } + if (ips > ipe) { + long t = ips; + ips = ipe; + ipe = t; + } + return ips <= ipt && ipt <= ipe; + } + + /** + * 校验ip是否符合过滤串规则 + * + * @param filter 过滤IP列表,支持后缀'*'通配,支持网段如:`10.10.10.1-10.10.10.99` + * @param ip 校验IP地址 + * @return boolean 结果 + */ + public static boolean isMatchedIp(String filter, String ip) { + if (StringUtils.isEmpty(filter) || StringUtils.isEmpty(ip)) { + return false; + } + String[] ips = filter.split(";"); + for (String iStr : ips) { + if (isIP(iStr) && iStr.equals(ip)) { + return true; + } else if (isIpWildCard(iStr) && ipIsInWildCardNoCheck(iStr, ip)) { + return true; + } else if (isIPSegment(iStr) && ipIsInNetNoCheck(iStr, ip)) { + return true; + } + } + return false; + } + + public static boolean isDomainMatch(String domainFilter, String domain) { + if (StringUtils.isBlank(domain)) { + return false; + } + // 去掉协议部分 + String domainFilterWithoutProtocol = domainFilter.replaceFirst("^(https?://)?", "").replaceAll("/$", "");; + String domainWithoutProtocol = domain.replaceFirst("^(https?://)?", ""); + + // 使用正则表达式匹配域名 + Pattern pattern = Pattern.compile(domainFilterWithoutProtocol, Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(domainWithoutProtocol); + return matcher.matches(); + } + + /** + * 校验ip或者域名是否符合过滤串规则 + * + * @param filter 过滤列表,同时支持IP及域名,支持后缀'*'通配,支持网段如:`10.10.10.1-10.10.10.99`,支持域名通配符如:`.*google\.com;.*example\.org` + * @param URL 校验URL(Uniform Resource Locator) + * @return boolean 结果 + */ + public static boolean isMatchedIpAndDomain(String filter, String URL) { + if (StringUtils.isEmpty(filter) || StringUtils.isEmpty(URL)) { + return false; + } + String domainOrIP = extractDomainOrIP(URL); + if (StringUtils.isEmpty(domainOrIP)) { + return false; + } + String[] ipsAndDomains = filter.split(";"); + for (String iStrOrDomainStr : ipsAndDomains) { + if (isIP(iStrOrDomainStr) && iStrOrDomainStr.equals(domainOrIP)) { + return true; + } else if (isIpWildCard(iStrOrDomainStr) && ipIsInWildCardNoCheck(iStrOrDomainStr, domainOrIP)) { + return true; + } else if (isIPSegment(iStrOrDomainStr) && ipIsInNetNoCheck(iStrOrDomainStr, domainOrIP)) { + return true; + } else if (isDomainWildCard(iStrOrDomainStr) && isDomainMatch(iStrOrDomainStr, domainOrIP)) { + return true; + } + } + return false; + } + + public static String extractDomainOrIP(String path) { + try { + URI uri = new URI(path); + String host = uri.getHost(); + if (host != null) { + // Removing "www." prefix if present + if (host.startsWith("www.")) { + host = host.substring(4); + } + return host; + } + } catch (URISyntaxException e) { + log.info("path extractDomain failed: " + path); + return ""; + } + return ""; + } + + private static boolean isDomainWildCard(String iStrOrDomainStr) { + return StringUtils.isNotBlank(iStrOrDomainStr); + } + + public static void test1() { + String filter = ".*google\\.com;.*example\\.org"; + String domain = "www.google.com"; + + if (IpUtils.isMatchedIpAndDomain(filter, domain)) { + System.out.println("Domain matches filter."); + } else { + System.out.println("Domain does not match filter."); + } + } + + public static void test2() { + String path1 = "http://www.google.com"; + String path2 = "https://example.org/a/b.zip"; + String path3 = "https://101.132.168.156/a/b.zip"; + + String domain1 = extractDomainOrIP(path1); + String domain2 = extractDomainOrIP(path2); + String domain3 = extractDomainOrIP(path3); + if (domain1 != null) { + System.out.println("Domain from path 1: " + domain1); + } else { + System.out.println("Failed to extract domain from path 1."); + } + if (domain2 != null) { + System.out.println("Domain from path 2: " + domain2); + } else { + System.out.println("Failed to extract domain from path 2."); + } + if (domain3 != null) { + System.out.println("Domain from path 3: " + domain3); + } else { + System.out.println("Failed to extract domain from path 3."); + } + } + + public static void test3() { + String filter = ".*google\\.com;.*example\\.org;101.132.153.123"; + String domain1 = "http://www.google.com"; + System.out.println(IpUtils.isMatchedIpAndDomain(filter, domain1)); + String domain2 = "http://www.google.com/a/b/zip"; + System.out.println(IpUtils.isMatchedIpAndDomain(filter, domain2)); + String domain3 = "http://101.132.153.123/a/b/zip"; + System.out.println(IpUtils.isMatchedIpAndDomain(filter, domain3)); + } + + public static void test4() throws URISyntaxException { + String path="www.google.com"; + URI uri = new URI(path); + String host = uri.getHost(); + System.out.println(host); + } + + public static void test5() { + System.out.println(isDomainMatch("https://gitee.com/","gitee.com")); + } + + public static void main(String[] args) throws URISyntaxException { + test5(); + } +} \ No newline at end of file diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/poi/ExcelHandlerAdapter.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/poi/ExcelHandlerAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..6649919c3855f10b3c71a81b9077d6b68b91b2c0 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/poi/ExcelHandlerAdapter.java @@ -0,0 +1,19 @@ +package com.RVSmartPorting.common.utils.poi; + +/** + * Excel数据格式处理适配器 + * + * @author ruoyi + */ +public interface ExcelHandlerAdapter +{ + /** + * 格式化 + * + * @param value 单元格数据值 + * @param args excel注解args参数组 + * + * @return 处理后的值 + */ + Object format(Object value, String[] args); +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/poi/ExcelUtil.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/poi/ExcelUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..f56f9b82f0aed6f72b5ff19963558b8e75501d0a --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/poi/ExcelUtil.java @@ -0,0 +1,1702 @@ +package com.RVSmartPorting.common.utils.poi; + +import com.RVSmartPorting.common.annotation.Excel; +import com.RVSmartPorting.common.annotation.Excel.ColumnType; +import com.RVSmartPorting.common.annotation.Excel.Type; +import com.RVSmartPorting.common.annotation.Excels; +import com.RVSmartPorting.common.config.CSPConfig; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.exception.UtilException; +import com.RVSmartPorting.common.utils.DateUtils; +import com.RVSmartPorting.common.utils.DictUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.file.FileTypeUtils; +import com.RVSmartPorting.common.utils.file.FileUtils; +import com.RVSmartPorting.common.utils.file.ImageUtils; +import com.RVSmartPorting.common.utils.reflect.ReflectUtils; +import com.RVSmartPorting.common.core.text.Convert; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.RegExUtils; +import org.apache.commons.lang3.reflect.FieldUtils; +import org.apache.poi.hssf.usermodel.*; +import org.apache.poi.ooxml.POIXMLDocumentPart; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.ss.util.CellRangeAddressList; +import org.apache.poi.util.IOUtils; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.*; +import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.math.BigDecimal; +import java.text.DecimalFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +/** + * Excel相关处理 + * + * @author ruoyi + */ +public class ExcelUtil +{ + private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class); + + public static final String FORMULA_REGEX_STR = "=|-|\\+|@"; + + public static final String[] FORMULA_STR = { "=", "-", "+", "@" }; + + /** + * 用于dictType属性数据存储,避免重复查缓存 + */ + public Map sysDictMap = new HashMap(); + + /** + * Excel sheet最大行数,默认65536 + */ + public static final int sheetSize = 65536; + + /** + * 工作表名称 + */ + private String sheetName; + + /** + * 导出类型(EXPORT:导出数据;IMPORT:导入模板) + */ + private Type type; + + /** + * 工作薄对象 + */ + private Workbook wb; + + /** + * 工作表对象 + */ + private Sheet sheet; + + /** + * 样式列表 + */ + private Map styles; + + /** + * 导入导出数据列表 + */ + private List list; + + /** + * 注解列表 + */ + private List fields; + + /** + * 当前行号 + */ + private int rownum; + + /** + * 标题 + */ + private String title; + + /** + * 最大高度 + */ + private short maxHeight; + + /** + * 合并后最后行数 + */ + private int subMergedLastRowNum = 0; + + /** + * 合并后开始行数 + */ + private int subMergedFirstRowNum = 1; + + /** + * 对象的子列表方法 + */ + private Method subMethod; + + /** + * 对象的子列表属性 + */ + private List subFields; + + /** + * 统计列表 + */ + private Map statistics = new HashMap(); + + /** + * 数字格式 + */ + private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00"); + + /** + * 实体对象 + */ + public Class clazz; + + /** + * 需要排除列属性 + */ + public String[] excludeFields; + + public ExcelUtil(Class clazz) + { + this.clazz = clazz; + } + + /** + * 隐藏Excel中列属性 + * + * @param fields 列属性名 示例[单个"name"/多个"id","name"] + * @throws Exception + */ + public void hideColumn(String... fields) + { + this.excludeFields = fields; + } + + public void init(List list, String sheetName, String title, Type type) + { + if (list == null) + { + list = new ArrayList(); + } + this.list = list; + this.sheetName = sheetName; + this.type = type; + this.title = title; + createExcelField(); + createWorkbook(); + createTitle(); + createSubHead(); + } + + /** + * 创建excel第一行标题 + */ + public void createTitle() + { + if (StringUtils.isNotEmpty(title)) + { + subMergedFirstRowNum++; + subMergedLastRowNum++; + int titleLastCol = this.fields.size() - 1; + if (isSubList()) + { + titleLastCol = titleLastCol + subFields.size() - 1; + } + Row titleRow = sheet.createRow(rownum == 0 ? rownum++ : 0); + titleRow.setHeightInPoints(30); + Cell titleCell = titleRow.createCell(0); + titleCell.setCellStyle(styles.get("title")); + titleCell.setCellValue(title); + sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(), titleLastCol)); + } + } + + /** + * 创建对象的子列表名称 + */ + public void createSubHead() + { + if (isSubList()) + { + subMergedFirstRowNum++; + subMergedLastRowNum++; + Row subRow = sheet.createRow(rownum); + int excelNum = 0; + for (Object[] objects : fields) + { + Excel attr = (Excel) objects[1]; + Cell headCell1 = subRow.createCell(excelNum); + headCell1.setCellValue(attr.name()); + headCell1.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor()))); + excelNum++; + } + int headFirstRow = excelNum - 1; + int headLastRow = headFirstRow + subFields.size() - 1; + if (headLastRow > headFirstRow) + { + sheet.addMergedRegion(new CellRangeAddress(rownum, rownum, headFirstRow, headLastRow)); + } + rownum++; + } + } + + /** + * 对excel表单默认第一个索引名转换成list + * + * @param is 输入流 + * @return 转换后集合 + */ + public List importExcel(InputStream is) throws Exception + { + return importExcel(is, 0); + } + + /** + * 对excel表单默认第一个索引名转换成list + * + * @param is 输入流 + * @param titleNum 标题占用行数 + * @return 转换后集合 + */ + public List importExcel(InputStream is, int titleNum) throws Exception + { + return importExcel(StringUtils.EMPTY, is, titleNum); + } + + /** + * 对excel表单指定表格索引名转换成list + * + * @param sheetName 表格索引名 + * @param titleNum 标题占用行数 + * @param is 输入流 + * @return 转换后集合 + */ + public List importExcel(String sheetName, InputStream is, int titleNum) throws Exception + { + this.type = Type.IMPORT; + this.wb = WorkbookFactory.create(is); + List list = new ArrayList(); + // 如果指定sheet名,则取指定sheet中的内容 否则默认指向第1个sheet + Sheet sheet = StringUtils.isNotEmpty(sheetName) ? wb.getSheet(sheetName) : wb.getSheetAt(0); + if (sheet == null) + { + throw new IOException("文件sheet不存在"); + } + boolean isXSSFWorkbook = !(wb instanceof HSSFWorkbook); + Map pictures; + if (isXSSFWorkbook) + { + pictures = getSheetPictures07((XSSFSheet) sheet, (XSSFWorkbook) wb); + } + else + { + pictures = getSheetPictures03((HSSFSheet) sheet, (HSSFWorkbook) wb); + } + // 获取最后一个非空行的行下标,比如总行数为n,则返回的为n-1 + int rows = sheet.getLastRowNum(); + + if (rows > 0) + { + // 定义一个map用于存放excel列的序号和field. + Map cellMap = new HashMap(); + // 获取表头 + Row heard = sheet.getRow(titleNum); + for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++) + { + Cell cell = heard.getCell(i); + if (StringUtils.isNotNull(cell)) + { + String value = this.getCellValue(heard, i).toString(); + cellMap.put(value, i); + } + else + { + cellMap.put(null, i); + } + } + // 有数据时才处理 得到类的所有field. + List fields = this.getFields(); + Map fieldsMap = new HashMap(); + for (Object[] objects : fields) + { + Excel attr = (Excel) objects[1]; + Integer column = cellMap.get(attr.name()); + if (column != null) + { + fieldsMap.put(column, objects); + } + } + for (int i = titleNum + 1; i <= rows; i++) + { + // 从第2行开始取数据,默认第一行是表头. + Row row = sheet.getRow(i); + // 判断当前行是否是空行 + if (isRowEmpty(row)) + { + continue; + } + T entity = null; + for (Map.Entry entry : fieldsMap.entrySet()) + { + Object val = this.getCellValue(row, entry.getKey()); + + // 如果不存在实例则新建. + entity = (entity == null ? clazz.newInstance() : entity); + // 从map中得到对应列的field. + Field field = (Field) entry.getValue()[0]; + Excel attr = (Excel) entry.getValue()[1]; + // 取得类型,并根据对象类型设置值. + Class fieldType = field.getType(); + if (String.class == fieldType) + { + String s = Convert.toStr(val); + if (StringUtils.endsWith(s, ".0")) + { + val = StringUtils.substringBefore(s, ".0"); + } + else + { + String dateFormat = field.getAnnotation(Excel.class).dateFormat(); + if (StringUtils.isNotEmpty(dateFormat)) + { + val = parseDateToStr(dateFormat, val); + } + else + { + val = Convert.toStr(val); + } + } + } + else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val))) + { + val = Convert.toInt(val); + } + else if ((Long.TYPE == fieldType || Long.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val))) + { + val = Convert.toLong(val); + } + else if (Double.TYPE == fieldType || Double.class == fieldType) + { + val = Convert.toDouble(val); + } + else if (Float.TYPE == fieldType || Float.class == fieldType) + { + val = Convert.toFloat(val); + } + else if (BigDecimal.class == fieldType) + { + val = Convert.toBigDecimal(val); + } + else if (Date.class == fieldType) + { + if (val instanceof String) + { + val = DateUtils.parseDate(val); + } + else if (val instanceof Double) + { + val = DateUtil.getJavaDate((Double) val); + } + } + else if (Boolean.TYPE == fieldType || Boolean.class == fieldType) + { + val = Convert.toBool(val, false); + } + if (StringUtils.isNotNull(fieldType)) + { + String propertyName = field.getName(); + if (StringUtils.isNotEmpty(attr.targetAttr())) + { + propertyName = field.getName() + "." + attr.targetAttr(); + } + else if (StringUtils.isNotEmpty(attr.readConverterExp())) + { + val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator()); + } + else if (StringUtils.isNotEmpty(attr.dictType())) + { + val = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator()); + } + else if (!attr.handler().equals(ExcelHandlerAdapter.class)) + { + val = dataFormatHandlerAdapter(val, attr); + } + else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures)) + { + PictureData image = pictures.get(row.getRowNum() + "_" + entry.getKey()); + if (image == null) + { + val = ""; + } + else + { + byte[] data = image.getData(); + val = FileUtils.writeImportBytes(data); + } + } + ReflectUtils.invokeSetter(entity, propertyName, val); + } + } + list.add(entity); + } + } + return list; + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @return 结果 + */ + public AjaxResult exportExcel(List list, String sheetName) + { + return exportExcel(list, sheetName, StringUtils.EMPTY); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param title 标题 + * @return 结果 + */ + public AjaxResult exportExcel(List list, String sheetName, String title) + { + this.init(list, sheetName, title, Type.EXPORT); + return exportExcel(); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param response 返回数据 + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @return 结果 + */ + public void exportExcel(HttpServletResponse response, List list, String sheetName) + { + exportExcel(response, list, sheetName, StringUtils.EMPTY); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param response 返回数据 + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param title 标题 + * @return 结果 + */ + public void exportExcel(HttpServletResponse response, List list, String sheetName, String title) + { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + this.init(list, sheetName, title, Type.EXPORT); + exportExcel(response); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param sheetName 工作表的名称 + * @return 结果 + */ + public AjaxResult importTemplateExcel(String sheetName) + { + return importTemplateExcel(sheetName, StringUtils.EMPTY); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param sheetName 工作表的名称 + * @param title 标题 + * @return 结果 + */ + public AjaxResult importTemplateExcel(String sheetName, String title) + { + this.init(null, sheetName, title, Type.IMPORT); + return exportExcel(); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param sheetName 工作表的名称 + * @return 结果 + */ + public void importTemplateExcel(HttpServletResponse response, String sheetName) + { + importTemplateExcel(response, sheetName, StringUtils.EMPTY); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param sheetName 工作表的名称 + * @param title 标题 + * @return 结果 + */ + public void importTemplateExcel(HttpServletResponse response, String sheetName, String title) + { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + this.init(null, sheetName, title, Type.IMPORT); + exportExcel(response); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @return 结果 + */ + public void exportExcel(HttpServletResponse response) + { + try + { + writeSheet(); + wb.write(response.getOutputStream()); + } + catch (Exception e) + { + log.error("导出Excel异常{}", e.getMessage()); + } + finally + { + IOUtils.closeQuietly(wb); + } + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @return 结果 + */ + public AjaxResult exportExcel() + { + OutputStream out = null; + try + { + writeSheet(); + String filename = encodingFilename(sheetName); + out = new FileOutputStream(getAbsoluteFile(filename)); + wb.write(out); + return AjaxResult.success(filename); + } + catch (Exception e) + { + log.error("导出Excel异常{}", e.getMessage()); + throw new UtilException("导出Excel失败,请联系网站管理员!"); + } + finally + { + IOUtils.closeQuietly(wb); + IOUtils.closeQuietly(out); + } + } + + /** + * 创建写入数据到Sheet + */ + public void writeSheet() + { + // 取出一共有多少个sheet. + int sheetNo = Math.max(1, (int) Math.ceil(list.size() * 1.0 / sheetSize)); + for (int index = 0; index < sheetNo; index++) + { + createSheet(sheetNo, index); + + // 产生一行 + Row row = sheet.createRow(rownum); + int column = 0; + // 写入各个字段的列头名称 + for (Object[] os : fields) + { + Field field = (Field) os[0]; + Excel excel = (Excel) os[1]; + if (Collection.class.isAssignableFrom(field.getType())) + { + for (Field subField : subFields) + { + Excel subExcel = subField.getAnnotation(Excel.class); + this.createHeadCell(subExcel, row, column++); + } + } + else + { + this.createHeadCell(excel, row, column++); + } + } + if (Type.EXPORT.equals(type)) + { + fillExcelData(index, row); + addStatisticsRow(); + } + } + } + + /** + * 填充excel数据 + * + * @param index 序号 + * @param row 单元格行 + */ + @SuppressWarnings("unchecked") + public void fillExcelData(int index, Row row) + { + int startNo = index * sheetSize; + int endNo = Math.min(startNo + sheetSize, list.size()); + int rowNo = (1 + rownum) - startNo; + for (int i = startNo; i < endNo; i++) + { + rowNo = isSubList() ? (i > 1 ? rowNo + 1 : rowNo + i) : i + 1 + rownum - startNo; + row = sheet.createRow(rowNo); + // 得到导出对象. + T vo = (T) list.get(i); + Collection subList = null; + if (isSubList()) + { + if (isSubListValue(vo)) + { + subList = getListCellValue(vo); + subMergedLastRowNum = subMergedLastRowNum + subList.size(); + } + else + { + subMergedFirstRowNum++; + subMergedLastRowNum++; + } + } + int column = 0; + for (Object[] os : fields) + { + Field field = (Field) os[0]; + Excel excel = (Excel) os[1]; + if (Collection.class.isAssignableFrom(field.getType()) && StringUtils.isNotNull(subList)) + { + boolean subFirst = false; + for (Object obj : subList) + { + if (subFirst) + { + rowNo++; + row = sheet.createRow(rowNo); + } + List subFields = FieldUtils.getFieldsListWithAnnotation(obj.getClass(), Excel.class); + int subIndex = 0; + for (Field subField : subFields) + { + if (subField.isAnnotationPresent(Excel.class)) + { + subField.setAccessible(true); + Excel attr = subField.getAnnotation(Excel.class); + this.addCell(attr, row, (T) obj, subField, column + subIndex); + } + subIndex++; + } + subFirst = true; + } + this.subMergedFirstRowNum = this.subMergedFirstRowNum + subList.size(); + } + else + { + this.addCell(excel, row, vo, field, column++); + } + } + } + } + + /** + * 创建表格样式 + * + * @param wb 工作薄对象 + * @return 样式列表 + */ + private Map createStyles(Workbook wb) + { + // 写入各条记录,每条记录对应excel表中的一行 + Map styles = new HashMap(); + CellStyle style = wb.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + Font titleFont = wb.createFont(); + titleFont.setFontName("Arial"); + titleFont.setFontHeightInPoints((short) 16); + titleFont.setBold(true); + style.setFont(titleFont); + styles.put("title", style); + + style = wb.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setBorderRight(BorderStyle.THIN); + style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderLeft(BorderStyle.THIN); + style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderTop(BorderStyle.THIN); + style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderBottom(BorderStyle.THIN); + style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + Font dataFont = wb.createFont(); + dataFont.setFontName("Arial"); + dataFont.setFontHeightInPoints((short) 10); + style.setFont(dataFont); + styles.put("data", style); + + style = wb.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + Font totalFont = wb.createFont(); + totalFont.setFontName("Arial"); + totalFont.setFontHeightInPoints((short) 10); + style.setFont(totalFont); + styles.put("total", style); + + styles.putAll(annotationHeaderStyles(wb, styles)); + + styles.putAll(annotationDataStyles(wb)); + + return styles; + } + + /** + * 根据Excel注解创建表格头样式 + * + * @param wb 工作薄对象 + * @return 自定义样式列表 + */ + private Map annotationHeaderStyles(Workbook wb, Map styles) + { + Map headerStyles = new HashMap(); + for (Object[] os : fields) + { + Excel excel = (Excel) os[1]; + String key = StringUtils.format("header_{}_{}", excel.headerColor(), excel.headerBackgroundColor()); + if (!headerStyles.containsKey(key)) + { + CellStyle style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setFillForegroundColor(excel.headerBackgroundColor().index); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + Font headerFont = wb.createFont(); + headerFont.setFontName("Arial"); + headerFont.setFontHeightInPoints((short) 10); + headerFont.setBold(true); + headerFont.setColor(excel.headerColor().index); + style.setFont(headerFont); + headerStyles.put(key, style); + } + } + return headerStyles; + } + + /** + * 根据Excel注解创建表格列样式 + * + * @param wb 工作薄对象 + * @return 自定义样式列表 + */ + private Map annotationDataStyles(Workbook wb) + { + Map styles = new HashMap(); + for (Object[] os : fields) + { + Excel excel = (Excel) os[1]; + String key = StringUtils.format("data_{}_{}_{}", excel.align(), excel.color(), excel.backgroundColor()); + if (!styles.containsKey(key)) + { + CellStyle style = wb.createCellStyle(); + style.setAlignment(excel.align()); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setBorderRight(BorderStyle.THIN); + style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderLeft(BorderStyle.THIN); + style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderTop(BorderStyle.THIN); + style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderBottom(BorderStyle.THIN); + style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + style.setFillForegroundColor(excel.backgroundColor().getIndex()); + Font dataFont = wb.createFont(); + dataFont.setFontName("Arial"); + dataFont.setFontHeightInPoints((short) 10); + dataFont.setColor(excel.color().index); + style.setFont(dataFont); + styles.put(key, style); + } + } + return styles; + } + + /** + * 创建单元格 + */ + public Cell createHeadCell(Excel attr, Row row, int column) + { + // 创建列 + Cell cell = row.createCell(column); + // 写入列信息 + cell.setCellValue(attr.name()); + setDataValidation(attr, row, column); + cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor()))); + if (isSubList()) + { + // 填充默认样式,防止合并单元格样式失效 + sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor()))); + if (attr.needMerge()) + { + sheet.addMergedRegion(new CellRangeAddress(rownum - 1, rownum, column, column)); + } + } + return cell; + } + + /** + * 设置单元格信息 + * + * @param value 单元格值 + * @param attr 注解相关 + * @param cell 单元格信息 + */ + public void setCellVo(Object value, Excel attr, Cell cell) + { + if (ColumnType.STRING == attr.cellType()) + { + String cellValue = Convert.toStr(value); + // 对于任何以表达式触发字符 =-+@开头的单元格,直接使用tab字符作为前缀,防止CSV注入。 + if (StringUtils.startsWithAny(cellValue, FORMULA_STR)) + { + cellValue = RegExUtils.replaceFirst(cellValue, FORMULA_REGEX_STR, "\t$0"); + } + if (value instanceof Collection && StringUtils.equals("[]", cellValue)) + { + cellValue = StringUtils.EMPTY; + } + cell.setCellValue(StringUtils.isNull(cellValue) ? attr.defaultValue() : cellValue + attr.suffix()); + } + else if (ColumnType.NUMERIC == attr.cellType()) + { + if (StringUtils.isNotNull(value)) + { + cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value)); + } + } + else if (ColumnType.IMAGE == attr.cellType()) + { + ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), cell.getRow().getRowNum() + 1); + String imagePath = Convert.toStr(value); + if (StringUtils.isNotEmpty(imagePath)) + { + byte[] data = ImageUtils.getImage(imagePath); + getDrawingPatriarch(cell.getSheet()).createPicture(anchor, + cell.getSheet().getWorkbook().addPicture(data, getImageType(data))); + } + } + } + + /** + * 获取画布 + */ + public static Drawing getDrawingPatriarch(Sheet sheet) + { + if (sheet.getDrawingPatriarch() == null) + { + sheet.createDrawingPatriarch(); + } + return sheet.getDrawingPatriarch(); + } + + /** + * 获取图片类型,设置图片插入类型 + */ + public int getImageType(byte[] value) + { + String type = FileTypeUtils.getFileExtendName(value); + if ("JPG".equalsIgnoreCase(type)) + { + return Workbook.PICTURE_TYPE_JPEG; + } + else if ("PNG".equalsIgnoreCase(type)) + { + return Workbook.PICTURE_TYPE_PNG; + } + return Workbook.PICTURE_TYPE_JPEG; + } + + /** + * 创建表格样式 + */ + public void setDataValidation(Excel attr, Row row, int column) + { + if (attr.name().indexOf("注:") >= 0) + { + sheet.setColumnWidth(column, 6000); + } + else + { + // 设置列宽 + sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256)); + } + if (StringUtils.isNotEmpty(attr.prompt()) || attr.combo().length > 0) + { + if (attr.combo().length > 15 || StringUtils.join(attr.combo()).length() > 255) + { + // 如果下拉数大于15或字符串长度大于255,则使用一个新sheet存储,避免生成的模板下拉值获取不到 + setXSSFValidationWithHidden(sheet, attr.combo(), attr.prompt(), 1, 100, column, column); + } + else + { + // 提示信息或只能选择不能输入的列内容. + setPromptOrValidation(sheet, attr.combo(), attr.prompt(), 1, 100, column, column); + } + } + } + + /** + * 添加单元格 + */ + public Cell addCell(Excel attr, Row row, T vo, Field field, int column) + { + Cell cell = null; + try + { + // 设置行高 + row.setHeight(maxHeight); + // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列. + if (attr.isExport()) + { + // 创建cell + cell = row.createCell(column); + if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge()) + { + CellRangeAddress cellAddress = new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column); + sheet.addMergedRegion(cellAddress); + } + cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor()))); + + // 用于读取对象中的属性 + Object value = getTargetValue(vo, field, attr); + String dateFormat = attr.dateFormat(); + String readConverterExp = attr.readConverterExp(); + String separator = attr.separator(); + String dictType = attr.dictType(); + if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) + { + cell.setCellValue(parseDateToStr(dateFormat, value)); + } + else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) + { + cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator)); + } + else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value)) + { + if (!sysDictMap.containsKey(dictType + value)) + { + String lable = convertDictByExp(Convert.toStr(value), dictType, separator); + sysDictMap.put(dictType + value, lable); + } + cell.setCellValue(sysDictMap.get(dictType + value)); + } + else if (value instanceof BigDecimal && -1 != attr.scale()) + { + cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).doubleValue()); + } + else if (!attr.handler().equals(ExcelHandlerAdapter.class)) + { + cell.setCellValue(dataFormatHandlerAdapter(value, attr)); + } + else + { + // 设置列类型 + setCellVo(value, attr, cell); + } + addStatisticsData(column, Convert.toStr(value), attr); + } + } + catch (Exception e) + { + log.error("导出Excel失败{}", e); + } + return cell; + } + + /** + * 设置 POI XSSFSheet 单元格提示或选择框 + * + * @param sheet 表单 + * @param textlist 下拉框显示的内容 + * @param promptContent 提示内容 + * @param firstRow 开始行 + * @param endRow 结束行 + * @param firstCol 开始列 + * @param endCol 结束列 + */ + public void setPromptOrValidation(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow, + int firstCol, int endCol) + { + DataValidationHelper helper = sheet.getDataValidationHelper(); + DataValidationConstraint constraint = textlist.length > 0 ? helper.createExplicitListConstraint(textlist) : helper.createCustomConstraint("DD1"); + CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); + DataValidation dataValidation = helper.createValidation(constraint, regions); + if (StringUtils.isNotEmpty(promptContent)) + { + // 如果设置了提示信息则鼠标放上去提示 + dataValidation.createPromptBox("", promptContent); + dataValidation.setShowPromptBox(true); + } + // 处理Excel兼容性问题 + if (dataValidation instanceof XSSFDataValidation) + { + dataValidation.setSuppressDropDownArrow(true); + dataValidation.setShowErrorBox(true); + } + else + { + dataValidation.setSuppressDropDownArrow(false); + } + sheet.addValidationData(dataValidation); + } + + /** + * 设置某些列的值只能输入预制的数据,显示下拉框(兼容超出一定数量的下拉框). + * + * @param sheet 要设置的sheet. + * @param textlist 下拉框显示的内容 + * @param promptContent 提示内容 + * @param firstRow 开始行 + * @param endRow 结束行 + * @param firstCol 开始列 + * @param endCol 结束列 + */ + public void setXSSFValidationWithHidden(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow, int firstCol, int endCol) + { + String hideSheetName = "combo_" + firstCol + "_" + endCol; + Sheet hideSheet = wb.createSheet(hideSheetName); // 用于存储 下拉菜单数据 + for (int i = 0; i < textlist.length; i++) + { + hideSheet.createRow(i).createCell(0).setCellValue(textlist[i]); + } + // 创建名称,可被其他单元格引用 + Name name = wb.createName(); + name.setNameName(hideSheetName + "_data"); + name.setRefersToFormula(hideSheetName + "!$A$1:$A$" + textlist.length); + DataValidationHelper helper = sheet.getDataValidationHelper(); + // 加载下拉列表内容 + DataValidationConstraint constraint = helper.createFormulaListConstraint(hideSheetName + "_data"); + // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 + CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); + // 数据有效性对象 + DataValidation dataValidation = helper.createValidation(constraint, regions); + if (StringUtils.isNotEmpty(promptContent)) + { + // 如果设置了提示信息则鼠标放上去提示 + dataValidation.createPromptBox("", promptContent); + dataValidation.setShowPromptBox(true); + } + // 处理Excel兼容性问题 + if (dataValidation instanceof XSSFDataValidation) + { + dataValidation.setSuppressDropDownArrow(true); + dataValidation.setShowErrorBox(true); + } + else + { + dataValidation.setSuppressDropDownArrow(false); + } + + sheet.addValidationData(dataValidation); + // 设置hiddenSheet隐藏 + wb.setSheetHidden(wb.getSheetIndex(hideSheet), true); + } + + /** + * 解析导出值 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(","); + 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(","); + 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); + } + + /** + * 解析字典值 + * + * @param dictValue 字典值 + * @param dictType 字典类型 + * @param separator 分隔符 + * @return 字典标签 + */ + public static String convertDictByExp(String dictValue, String dictType, String separator) + { + return DictUtils.getDictLabel(dictType, dictValue, separator); + } + + /** + * 反向解析值字典值 + * + * @param dictLabel 字典标签 + * @param dictType 字典类型 + * @param separator 分隔符 + * @return 字典值 + */ + public static String reverseDictByExp(String dictLabel, String dictType, String separator) + { + return DictUtils.getDictValue(dictType, dictLabel, separator); + } + + /** + * 数据处理器 + * + * @param value 数据值 + * @param excel 数据注解 + * @return + */ + public String dataFormatHandlerAdapter(Object value, Excel excel) + { + try + { + Object instance = excel.handler().newInstance(); + Method formatMethod = excel.handler().getMethod("format", new Class[] { Object.class, String[].class }); + value = formatMethod.invoke(instance, value, excel.args()); + } + catch (Exception e) + { + log.error("不能格式化数据 " + excel.handler(), e.getMessage()); + } + return Convert.toStr(value); + } + + /** + * 合计统计信息 + */ + private void addStatisticsData(Integer index, String text, Excel entity) + { + if (entity != null && entity.isStatistics()) + { + Double temp = 0D; + if (!statistics.containsKey(index)) + { + statistics.put(index, temp); + } + try + { + temp = Double.valueOf(text); + } + catch (NumberFormatException e) + { + } + statistics.put(index, statistics.get(index) + temp); + } + } + + /** + * 创建统计行 + */ + public void addStatisticsRow() + { + if (statistics.size() > 0) + { + Row row = sheet.createRow(sheet.getLastRowNum() + 1); + Set keys = statistics.keySet(); + Cell cell = row.createCell(0); + cell.setCellStyle(styles.get("total")); + cell.setCellValue("合计"); + + for (Integer key : keys) + { + cell = row.createCell(key); + cell.setCellStyle(styles.get("total")); + cell.setCellValue(DOUBLE_FORMAT.format(statistics.get(key))); + } + statistics.clear(); + } + } + + /** + * 编码文件名 + */ + public String encodingFilename(String filename) + { + filename = UUID.randomUUID() + "_" + filename + ".xlsx"; + return filename; + } + + /** + * 获取下载路径 + * + * @param filename 文件名称 + */ + public String getAbsoluteFile(String filename) + { + String downloadPath = CSPConfig.getDownloadPath() + filename; + File desc = new File(downloadPath); + if (!desc.getParentFile().exists()) + { + desc.getParentFile().mkdirs(); + } + return downloadPath; + } + + /** + * 获取bean中的属性值 + * + * @param vo 实体对象 + * @param field 字段 + * @param excel 注解 + * @return 最终的属性值 + * @throws Exception + */ + private Object getTargetValue(T vo, Field field, Excel excel) throws Exception + { + Object o = field.get(vo); + if (StringUtils.isNotEmpty(excel.targetAttr())) + { + String target = excel.targetAttr(); + if (target.contains(".")) + { + String[] targets = target.split("[.]"); + for (String name : targets) + { + o = getValue(o, name); + } + } + else + { + o = getValue(o, target); + } + } + return o; + } + + /** + * 以类的属性的get方法方法形式获取值 + * + * @param o + * @param name + * @return value + * @throws Exception + */ + private Object getValue(Object o, String name) throws Exception + { + if (StringUtils.isNotNull(o) && StringUtils.isNotEmpty(name)) + { + Class clazz = o.getClass(); + Field field = clazz.getDeclaredField(name); + field.setAccessible(true); + o = field.get(o); + } + return o; + } + + /** + * 得到所有定义字段 + */ + private void createExcelField() + { + this.fields = getFields(); + this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList()); + this.maxHeight = getRowHeight(); + } + + /** + * 获取字段注解信息 + */ + public List getFields() + { + List fields = new ArrayList(); + List tempFields = new ArrayList<>(); + tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); + tempFields.addAll(Arrays.asList(clazz.getDeclaredFields())); + for (Field field : tempFields) + { + if (!ArrayUtils.contains(this.excludeFields, field.getName())) + { + // 单注解 + if (field.isAnnotationPresent(Excel.class)) + { + Excel attr = field.getAnnotation(Excel.class); + if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) + { + field.setAccessible(true); + fields.add(new Object[] { field, attr }); + } + if (Collection.class.isAssignableFrom(field.getType())) + { + subMethod = getSubMethod(field.getName(), clazz); + ParameterizedType pt = (ParameterizedType) field.getGenericType(); + Class subClass = (Class) pt.getActualTypeArguments()[0]; + this.subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class); + } + } + + // 多注解 + if (field.isAnnotationPresent(Excels.class)) + { + Excels attrs = field.getAnnotation(Excels.class); + Excel[] excels = attrs.value(); + for (Excel attr : excels) + { + if (!ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr()) + && (attr != null && (attr.type() == Type.ALL || attr.type() == type))) + { + field.setAccessible(true); + fields.add(new Object[] { field, attr }); + } + } + } + } + } + return fields; + } + + /** + * 根据注解获取最大行高 + */ + public short getRowHeight() + { + double maxHeight = 0; + for (Object[] os : this.fields) + { + Excel excel = (Excel) os[1]; + maxHeight = Math.max(maxHeight, excel.height()); + } + return (short) (maxHeight * 20); + } + + /** + * 创建一个工作簿 + */ + public void createWorkbook() + { + this.wb = new SXSSFWorkbook(500); + this.sheet = wb.createSheet(); + wb.setSheetName(0, sheetName); + this.styles = createStyles(wb); + } + + /** + * 创建工作表 + * + * @param sheetNo sheet数量 + * @param index 序号 + */ + public void createSheet(int sheetNo, int index) + { + // 设置工作表的名称. + if (sheetNo > 1 && index > 0) + { + this.sheet = wb.createSheet(); + this.createTitle(); + wb.setSheetName(index, sheetName + index); + } + } + + /** + * 获取单元格值 + * + * @param row 获取的行 + * @param column 获取单元格列号 + * @return 单元格值 + */ + public Object getCellValue(Row row, int column) + { + if (row == null) + { + return row; + } + Object val = ""; + try + { + Cell cell = row.getCell(column); + if (StringUtils.isNotNull(cell)) + { + if (cell.getCellType() == CellType.NUMERIC || cell.getCellType() == CellType.FORMULA) + { + val = cell.getNumericCellValue(); + if (DateUtil.isCellDateFormatted(cell)) + { + val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换 + } + else + { + if ((Double) val % 1 != 0) + { + val = new BigDecimal(val.toString()); + } + else + { + val = new DecimalFormat("0").format(val); + } + } + } + else if (cell.getCellType() == CellType.STRING) + { + val = cell.getStringCellValue(); + } + else if (cell.getCellType() == CellType.BOOLEAN) + { + val = cell.getBooleanCellValue(); + } + else if (cell.getCellType() == CellType.ERROR) + { + val = cell.getErrorCellValue(); + } + + } + } + catch (Exception e) + { + return val; + } + return val; + } + + /** + * 判断是否是空行 + * + * @param row 判断的行 + * @return + */ + private boolean isRowEmpty(Row row) + { + if (row == null) + { + return true; + } + for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++) + { + Cell cell = row.getCell(i); + if (cell != null && cell.getCellType() != CellType.BLANK) + { + return false; + } + } + return true; + } + + /** + * 获取Excel2003图片 + * + * @param sheet 当前sheet对象 + * @param workbook 工作簿对象 + * @return Map key:图片单元格索引(1_1)String,value:图片流PictureData + */ + public static Map getSheetPictures03(HSSFSheet sheet, HSSFWorkbook workbook) + { + Map sheetIndexPicMap = new HashMap(); + List pictures = workbook.getAllPictures(); + if (!pictures.isEmpty()) + { + for (HSSFShape shape : sheet.getDrawingPatriarch().getChildren()) + { + HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor(); + if (shape instanceof HSSFPicture) + { + HSSFPicture pic = (HSSFPicture) shape; + int pictureIndex = pic.getPictureIndex() - 1; + HSSFPictureData picData = pictures.get(pictureIndex); + String picIndex = anchor.getRow1() + "_" + anchor.getCol1(); + sheetIndexPicMap.put(picIndex, picData); + } + } + return sheetIndexPicMap; + } + else + { + return sheetIndexPicMap; + } + } + + /** + * 获取Excel2007图片 + * + * @param sheet 当前sheet对象 + * @param workbook 工作簿对象 + * @return Map key:图片单元格索引(1_1)String,value:图片流PictureData + */ + public static Map getSheetPictures07(XSSFSheet sheet, XSSFWorkbook workbook) + { + Map sheetIndexPicMap = new HashMap(); + for (POIXMLDocumentPart dr : sheet.getRelations()) + { + if (dr instanceof XSSFDrawing) + { + XSSFDrawing drawing = (XSSFDrawing) dr; + List shapes = drawing.getShapes(); + for (XSSFShape shape : shapes) + { + if (shape instanceof XSSFPicture) + { + XSSFPicture pic = (XSSFPicture) shape; + XSSFClientAnchor anchor = pic.getPreferredSize(); + CTMarker ctMarker = anchor.getFrom(); + String picIndex = ctMarker.getRow() + "_" + ctMarker.getCol(); + sheetIndexPicMap.put(picIndex, pic.getPictureData()); + } + } + } + } + return sheetIndexPicMap; + } + + /** + * 格式化不同类型的日期对象 + * + * @param dateFormat 日期格式 + * @param val 被格式化的日期对象 + * @return 格式化后的日期字符 + */ + public String parseDateToStr(String dateFormat, Object val) + { + if (val == null) + { + return ""; + } + String str; + if (val instanceof Date) + { + str = DateUtils.parseDateToStr(dateFormat, (Date) val); + } + else if (val instanceof LocalDateTime) + { + str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDateTime) val)); + } + else if (val instanceof LocalDate) + { + str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDate) val)); + } + else + { + str = val.toString(); + } + return str; + } + + /** + * 是否有对象的子列表 + */ + public boolean isSubList() + { + return StringUtils.isNotNull(subFields) && subFields.size() > 0; + } + + /** + * 是否有对象的子列表,集合不为空 + */ + public boolean isSubListValue(T vo) + { + return StringUtils.isNotNull(subFields) && subFields.size() > 0 && StringUtils.isNotNull(getListCellValue(vo)) && getListCellValue(vo).size() > 0; + } + + /** + * 获取集合的值 + */ + public Collection getListCellValue(Object obj) + { + Object value; + try + { + value = subMethod.invoke(obj, new Object[] {}); + } + catch (Exception e) + { + return new ArrayList(); + } + return (Collection) value; + } + + /** + * 获取对象的子列表方法 + * + * @param name 名称 + * @param pojoClass 类对象 + * @return 子列表方法 + */ + public Method getSubMethod(String name, Class pojoClass) + { + StringBuffer getMethodName = new StringBuffer("get"); + getMethodName.append(name.substring(0, 1).toUpperCase()); + getMethodName.append(name.substring(1)); + Method method = null; + try + { + method = pojoClass.getMethod(getMethodName.toString(), new Class[] {}); + } + catch (Exception e) + { + log.error("获取对象异常{}", e.getMessage()); + } + return method; + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/redis/RedisCache.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/redis/RedisCache.java new file mode 100644 index 0000000000000000000000000000000000000000..c3bcc52a03b0692533bdd013f0e1adc0e28fe3c2 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/redis/RedisCache.java @@ -0,0 +1,269 @@ +package com.RVSmartPorting.common.utils.redis; + +import com.RVSmartPorting.common.utils.spring.SpringUtils; +import org.apache.ibatis.cache.Cache; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.data.redis.core.*; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * spring redis 工具类 + * + * @author ruoyi + **/ +@Component +public class RedisCache{ + @Autowired + public RedisTemplate redisTemplate; + + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + */ + public void setCacheObject(final String key, final T value) + { + redisTemplate.opsForValue().set(key, value); + } + + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + * @param timeout 时间 + * @param timeUnit 时间颗粒度 + */ + public void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) + { + redisTemplate.opsForValue().set(key, value, timeout, timeUnit); + } + + /** + * 设置有效时间 + * + * @param key Redis键 + * @param timeout 超时时间 + * @return true=设置成功;false=设置失败 + */ + public boolean expire(final String key, final long timeout) + { + return expire(key, timeout, TimeUnit.SECONDS); + } + + /** + * 设置有效时间 + * + * @param key Redis键 + * @param timeout 超时时间 + * @param unit 时间单位 + * @return true=设置成功;false=设置失败 + */ + public boolean expire(final String key, final long timeout, final TimeUnit unit) + { + return redisTemplate.expire(key, timeout, unit); + } + + /** + * 获取有效时间 + * + * @param key Redis键 + * @return 有效时间 + */ + public long getExpire(final String key) + { + return redisTemplate.getExpire(key); + } + + /** + * 判断 key是否存在 + * + * @param key 键 + * @return true 存在 false不存在 + */ + public Boolean hasKey(String key) + { + return redisTemplate.hasKey(key); + } + + /** + * 获得缓存的基本对象。 + * + * @param key 缓存键值 + * @return 缓存键值对应的数据 + */ + public T getCacheObject(final String key) + { + ValueOperations operation = redisTemplate.opsForValue(); + return operation.get(key); + } + + /** + * 删除单个对象 + * + * @param key + */ + public boolean deleteObject(final String key) + { + return redisTemplate.delete(key); + } + + /** + * 删除集合对象 + * + * @param collection 多个对象 + * @return + */ + public boolean deleteObject(final Collection collection) + { + return redisTemplate.delete(collection) > 0; + } + + /** + * 缓存List数据 + * + * @param key 缓存的键值 + * @param dataList 待缓存的List数据 + * @return 缓存的对象 + */ + public long setCacheList(final String key, final List dataList) + { + Long count = redisTemplate.opsForList().rightPushAll(key, dataList); + return count == null ? 0 : count; + } + + /** + * 获得缓存的list对象 + * + * @param key 缓存的键值 + * @return 缓存键值对应的数据 + */ + public List getCacheList(final String key) + { + return redisTemplate.opsForList().range(key, 0, -1); + } + + /** + * 缓存Set + * + * @param key 缓存键值 + * @param dataSet 缓存的数据 + * @return 缓存数据的对象 + */ + public BoundSetOperations setCacheSet(final String key, final Set dataSet) + { + BoundSetOperations setOperation = redisTemplate.boundSetOps(key); + Iterator it = dataSet.iterator(); + while (it.hasNext()) + { + setOperation.add(it.next()); + } + return setOperation; + } + + /** + * 获得缓存的set + * + * @param key + * @return + */ + public Set getCacheSet(final String key) + { + return redisTemplate.opsForSet().members(key); + } + + /** + * 缓存Map + * + * @param key + * @param dataMap + */ + public void setCacheMap(final String key, final Map dataMap) + { + if (dataMap != null) { + redisTemplate.opsForHash().putAll(key, dataMap); + } + } + + /** + * 获得缓存的Map + * + * @param key + * @return + */ + public Map getCacheMap(final String key) + { + return redisTemplate.opsForHash().entries(key); + } + + /** + * 往Hash中存入数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @param value 值 + */ + public void setCacheMapValue(final String key, final String hKey, final T value) + { + redisTemplate.opsForHash().put(key, hKey, value); + } + + /** + * 获取Hash中的数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @return Hash中的对象 + */ + public T getCacheMapValue(final String key, final String hKey) + { + HashOperations opsForHash = redisTemplate.opsForHash(); + return opsForHash.get(key, hKey); + } + + /** + * 获取多个Hash中的数据 + * + * @param key Redis键 + * @param hKeys Hash键集合 + * @return Hash对象集合 + */ + public List getMultiCacheMapValue(final String key, final Collection hKeys) + { + return redisTemplate.opsForHash().multiGet(key, hKeys); + } + + /** + * 删除Hash中的某条数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @return 是否成功 + */ + public boolean deleteCacheMapValue(final String key, final String hKey) + { + return redisTemplate.opsForHash().delete(key, hKey) > 0; + } + + /** + * 获得缓存的基本对象列表 + * + * @param pattern 字符串前缀 + * @return 对象列表 + */ + public Collection keys(final String pattern) + { + return redisTemplate.keys(pattern); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/reflect/ReflectUtils.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/reflect/ReflectUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..2e6e55f98639b2557c979a89f20a82987b9a7373 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/reflect/ReflectUtils.java @@ -0,0 +1,406 @@ +package com.RVSmartPorting.common.utils.reflect; + +import com.RVSmartPorting.common.utils.DateUtils; +import com.RVSmartPorting.common.core.text.Convert; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; +import org.apache.poi.ss.usermodel.DateUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.*; +import java.util.Date; + +/** + * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数. + * + * @author ruoyi + */ +@SuppressWarnings("rawtypes") +public class ReflectUtils +{ + private static final String SETTER_PREFIX = "set"; + + private static final String GETTER_PREFIX = "get"; + + private static final String CGLIB_CLASS_SEPARATOR = "$$"; + + private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class); + + /** + * 调用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 = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {}); + } + 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 = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {}); + } + else + { + String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]); + invokeMethodByName(object, setterMethodName, new Object[] { value }); + } + } + } + + /** + * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数. + */ + @SuppressWarnings("unchecked") + public static E getFieldValue(final Object obj, final String fieldName) + { + Field field = getAccessibleField(obj, fieldName); + if (field == null) + { + logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); + return null; + } + E result = null; + try + { + result = (E) field.get(obj); + } + catch (IllegalAccessException e) + { + logger.error("不可能抛出的异常{}", e.getMessage()); + } + return result; + } + + /** + * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数. + */ + public static void setFieldValue(final Object obj, final String fieldName, final E value) + { + Field field = getAccessibleField(obj, fieldName); + if (field == null) + { + // throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); + logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); + return; + } + try + { + field.set(obj, value); + } + catch (IllegalAccessException e) + { + logger.error("不可能抛出的异常: {}", e.getMessage()); + } + } + + /** + * 直接调用对象方法, 无视private/protected修饰符. + * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用. + * 同时匹配方法名+参数类型, + */ + @SuppressWarnings("unchecked") + public static E invokeMethod(final Object obj, final String methodName, final Class[] parameterTypes, + final Object[] args) + { + if (obj == null || methodName == null) + { + return null; + } + Method method = getAccessibleMethod(obj, methodName, parameterTypes); + if (method == null) + { + logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 "); + return null; + } + try + { + return (E) method.invoke(obj, args); + } + catch (Exception e) + { + String msg = "method: " + method + ", obj: " + obj + ", args: " + args + ""; + throw convertReflectionExceptionToUnchecked(msg, e); + } + } + + /** + * 直接调用对象方法, 无视private/protected修饰符, + * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用. + * 只匹配函数名,如果有多个同名函数调用第一个。 + */ + @SuppressWarnings("unchecked") + public static E invokeMethodByName(final Object obj, final String methodName, final Object[] args) + { + Method method = getAccessibleMethodByName(obj, methodName, args.length); + if (method == null) + { + // 如果为空不报错,直接返回空。 + logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 "); + return null; + } + try + { + // 类型转换(将参数数据类型转换为目标方法参数类型) + Class[] cs = method.getParameterTypes(); + for (int i = 0; i < cs.length; i++) + { + if (args[i] != null && !args[i].getClass().equals(cs[i])) + { + if (cs[i] == String.class) + { + args[i] = Convert.toStr(args[i]); + if (StringUtils.endsWith((String) args[i], ".0")) + { + args[i] = StringUtils.substringBefore((String) args[i], ".0"); + } + } + else if (cs[i] == Integer.class) + { + args[i] = Convert.toInt(args[i]); + } + else if (cs[i] == Long.class) + { + args[i] = Convert.toLong(args[i]); + } + else if (cs[i] == Double.class) + { + args[i] = Convert.toDouble(args[i]); + } + else if (cs[i] == Float.class) + { + args[i] = Convert.toFloat(args[i]); + } + else if (cs[i] == Date.class) + { + if (args[i] instanceof String) + { + args[i] = DateUtils.parseDate(args[i]); + } + else + { + args[i] = DateUtil.getJavaDate((Double) args[i]); + } + } + else if (cs[i] == boolean.class || cs[i] == Boolean.class) + { + args[i] = Convert.toBool(args[i]); + } + } + } + return (E) method.invoke(obj, args); + } + catch (Exception e) + { + String msg = "method: " + method + ", obj: " + obj + ", args: " + args + ""; + throw convertReflectionExceptionToUnchecked(msg, e); + } + } + + /** + * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问. + * 如向上转型到Object仍无法找到, 返回null. + */ + public static Field getAccessibleField(final Object obj, final String fieldName) + { + // 为空不报错。直接返回 null + if (obj == null) + { + return null; + } + Validate.notBlank(fieldName, "fieldName can't be blank"); + for (Class superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) + { + try + { + Field field = superClass.getDeclaredField(fieldName); + makeAccessible(field); + return field; + } + catch (NoSuchFieldException e) + { + continue; + } + } + return null; + } + + /** + * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. + * 如向上转型到Object仍无法找到, 返回null. + * 匹配函数名+参数类型。 + * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) + */ + public static Method getAccessibleMethod(final Object obj, final String methodName, + final Class... parameterTypes) + { + // 为空不报错。直接返回 null + if (obj == null) + { + return null; + } + Validate.notBlank(methodName, "methodName can't be blank"); + for (Class searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) + { + try + { + Method method = searchType.getDeclaredMethod(methodName, parameterTypes); + makeAccessible(method); + return method; + } + catch (NoSuchMethodException e) + { + continue; + } + } + return null; + } + + /** + * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. + * 如向上转型到Object仍无法找到, 返回null. + * 只匹配函数名。 + * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) + */ + public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum) + { + // 为空不报错。直接返回 null + if (obj == null) + { + return null; + } + Validate.notBlank(methodName, "methodName can't be blank"); + for (Class searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) + { + Method[] methods = searchType.getDeclaredMethods(); + for (Method method : methods) + { + if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum) + { + makeAccessible(method); + return method; + } + } + } + return null; + } + + /** + * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 + */ + public static void makeAccessible(Method method) + { + if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) + && !method.isAccessible()) + { + method.setAccessible(true); + } + } + + /** + * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 + */ + public static void makeAccessible(Field field) + { + if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) + || Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) + { + field.setAccessible(true); + } + } + + /** + * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处 + * 如无法找到, 返回Object.class. + */ + @SuppressWarnings("unchecked") + public static Class getClassGenricType(final Class clazz) + { + return getClassGenricType(clazz, 0); + } + + /** + * 通过反射, 获得Class定义中声明的父类的泛型参数的类型. + * 如无法找到, 返回Object.class. + */ + public static Class getClassGenricType(final Class clazz, final int index) + { + Type genType = clazz.getGenericSuperclass(); + + if (!(genType instanceof ParameterizedType)) + { + logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType"); + return Object.class; + } + + Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); + + if (index >= params.length || index < 0) + { + logger.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " + + params.length); + return Object.class; + } + if (!(params[index] instanceof Class)) + { + logger.debug(clazz.getSimpleName() + " not set the actual class on superclass generic parameter"); + return Object.class; + } + + return (Class) params[index]; + } + + public static Class getUserClass(Object instance) + { + if (instance == null) + { + throw new RuntimeException("Instance must not be null"); + } + Class clazz = instance.getClass(); + if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) + { + Class superClass = clazz.getSuperclass(); + if (superClass != null && !Object.class.equals(superClass)) + { + return superClass; + } + } + return clazz; + + } + + /** + * 将反射时的checked exception转换为unchecked exception. + */ + public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e) + { + if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException + || e instanceof NoSuchMethodException) + { + return new IllegalArgumentException(msg, e); + } + else if (e instanceof InvocationTargetException) + { + return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException()); + } + return new RuntimeException(msg, e); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/sign/Base64.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/sign/Base64.java new file mode 100644 index 0000000000000000000000000000000000000000..5c20897856030101eb0c180727a992fd1d175e89 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/sign/Base64.java @@ -0,0 +1,289 @@ +package com.RVSmartPorting.common.utils.sign; + +/** + * Base64工具类 + **/ +public final class Base64 +{ + static private final int BASELENGTH = 128; + static private final int LOOKUPLENGTH = 64; + static private final int TWENTYFOURBITGROUP = 24; + static private final int EIGHTBIT = 8; + static private final int SIXTEENBIT = 16; + static private final int FOURBYTE = 4; + static private final int SIGN = -128; + static private final char PAD = '='; + static final private byte[] base64Alphabet = new byte[BASELENGTH]; + static final private char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH]; + + static + { + for (int i = 0; i < BASELENGTH; ++i) + { + base64Alphabet[i] = -1; + } + for (int i = 'Z'; i >= 'A'; i--) + { + base64Alphabet[i] = (byte) (i - 'A'); + } + for (int i = 'z'; i >= 'a'; i--) + { + base64Alphabet[i] = (byte) (i - 'a' + 26); + } + + for (int i = '9'; i >= '0'; i--) + { + base64Alphabet[i] = (byte) (i - '0' + 52); + } + + base64Alphabet['+'] = 62; + base64Alphabet['/'] = 63; + + for (int i = 0; i <= 25; i++) + { + lookUpBase64Alphabet[i] = (char) ('A' + i); + } + + for (int i = 26, j = 0; i <= 51; i++, j++) + { + lookUpBase64Alphabet[i] = (char) ('a' + j); + } + + for (int i = 52, j = 0; i <= 61; i++, j++) + { + lookUpBase64Alphabet[i] = (char) ('0' + j); + } + lookUpBase64Alphabet[62] = (char) '+'; + lookUpBase64Alphabet[63] = (char) '/'; + } + + private static boolean isWhiteSpace(char octect) + { + return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9); + } + + private static boolean isPad(char octect) + { + return (octect == PAD); + } + + private static boolean isData(char octect) + { + return (octect < BASELENGTH && base64Alphabet[octect] != -1); + } + + /** + * Encodes hex octects into Base64 + * + * @param binaryData Array containing binaryData + * @return Encoded Base64 array + */ + public static String encode(byte[] binaryData) + { + if (binaryData == null) + { + return null; + } + + int lengthDataBits = binaryData.length * EIGHTBIT; + if (lengthDataBits == 0) + { + return ""; + } + + int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP; + int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP; + int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets; + char encodedData[] = null; + + encodedData = new char[numberQuartet * 4]; + + byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; + + int encodedIndex = 0; + int dataIndex = 0; + + for (int i = 0; i < numberTriplets; i++) + { + b1 = binaryData[dataIndex++]; + b2 = binaryData[dataIndex++]; + b3 = binaryData[dataIndex++]; + + l = (byte) (b2 & 0x0f); + k = (byte) (b1 & 0x03); + + byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); + byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); + byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc); + + encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f]; + } + + // form integral number of 6-bit groups + if (fewerThan24bits == EIGHTBIT) + { + b1 = binaryData[dataIndex]; + k = (byte) (b1 & 0x03); + byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); + encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4]; + encodedData[encodedIndex++] = PAD; + encodedData[encodedIndex++] = PAD; + } + else if (fewerThan24bits == SIXTEENBIT) + { + b1 = binaryData[dataIndex]; + b2 = binaryData[dataIndex + 1]; + l = (byte) (b2 & 0x0f); + k = (byte) (b1 & 0x03); + + byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); + byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); + + encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2]; + encodedData[encodedIndex++] = PAD; + } + return new String(encodedData); + } + + /** + * Decodes Base64 data into octects + * + * @param encoded string containing Base64 data + * @return Array containind decoded data. + */ + public static byte[] decode(String encoded) + { + if (encoded == null) + { + return null; + } + + char[] base64Data = encoded.toCharArray(); + // remove white spaces + int len = removeWhiteSpace(base64Data); + + if (len % FOURBYTE != 0) + { + return null;// should be divisible by four + } + + int numberQuadruple = (len / FOURBYTE); + + if (numberQuadruple == 0) + { + return new byte[0]; + } + + byte decodedData[] = null; + byte b1 = 0, b2 = 0, b3 = 0, b4 = 0; + char d1 = 0, d2 = 0, d3 = 0, d4 = 0; + + int i = 0; + int encodedIndex = 0; + int dataIndex = 0; + decodedData = new byte[(numberQuadruple) * 3]; + + for (; i < numberQuadruple - 1; i++) + { + + if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++])) + || !isData((d3 = base64Data[dataIndex++])) || !isData((d4 = base64Data[dataIndex++]))) + { + return null; + } // if found "no data" just return null + + b1 = base64Alphabet[d1]; + b2 = base64Alphabet[d2]; + b3 = base64Alphabet[d3]; + b4 = base64Alphabet[d4]; + + decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); + decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); + decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); + } + + if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) + { + return null;// if found "no data" just return null + } + + b1 = base64Alphabet[d1]; + b2 = base64Alphabet[d2]; + + d3 = base64Data[dataIndex++]; + d4 = base64Data[dataIndex++]; + if (!isData((d3)) || !isData((d4))) + {// Check if they are PAD characters + if (isPad(d3) && isPad(d4)) + { + if ((b2 & 0xf) != 0)// last 4 bits should be zero + { + return null; + } + byte[] tmp = new byte[i * 3 + 1]; + System.arraycopy(decodedData, 0, tmp, 0, i * 3); + tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); + return tmp; + } + else if (!isPad(d3) && isPad(d4)) + { + b3 = base64Alphabet[d3]; + if ((b3 & 0x3) != 0)// last 2 bits should be zero + { + return null; + } + byte[] tmp = new byte[i * 3 + 2]; + System.arraycopy(decodedData, 0, tmp, 0, i * 3); + tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); + tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); + return tmp; + } + else + { + return null; + } + } + else + { // No PAD e.g 3cQl + b3 = base64Alphabet[d3]; + b4 = base64Alphabet[d4]; + decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); + decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); + decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); + + } + return decodedData; + } + + /** + * remove WhiteSpace from MIME containing encoded Base64 data. + * + * @param data the byte array of base64 data (with WS) + * @return the new length + */ + private static int removeWhiteSpace(char[] data) + { + if (data == null) + { + return 0; + } + + // count characters that's not whitespace + int newSize = 0; + int len = data.length; + for (int i = 0; i < len; i++) + { + if (!isWhiteSpace(data[i])) + { + data[newSize++] = data[i]; + } + } + return newSize; + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/spring/SpringUtils.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/spring/SpringUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..c62c2e9e438fc038ca55b426e90130799464472d --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/spring/SpringUtils.java @@ -0,0 +1,147 @@ +package com.RVSmartPorting.common.utils.spring; + +/** + * spring工具类 方便在非spring管理环境中获取bean + * + * @author ruoyi + */ +import com.RVSmartPorting.common.utils.StringUtils; +import org.springframework.aop.framework.AopContext; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +@Component +public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware +{ + /** Spring应用上下文环境 */ + private static ConfigurableListableBeanFactory beanFactory; + + private static ApplicationContext applicationContext; + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException + { + SpringUtils.beanFactory = beanFactory; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException + { + SpringUtils.applicationContext = applicationContext; + } + + /** + * 获取对象 + * + * @param name + * @return Object 一个以所给名字注册的bean的实例 + * @throws BeansException + * + */ + @SuppressWarnings("unchecked") + public static T getBean(String name) throws BeansException + { + return (T) beanFactory.getBean(name); + } + + /** + * 获取类型为requiredType的对象 + * + * @param clz + * @return + * @throws BeansException + * + */ + public static T getBean(Class clz) throws BeansException + { + T result = (T) beanFactory.getBean(clz); + return result; + } + + /** + * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true + * + * @param name + * @return boolean + */ + public static boolean containsBean(String name) + { + return beanFactory.containsBean(name); + } + + /** + * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException) + * + * @param name + * @return boolean + * @throws NoSuchBeanDefinitionException + * + */ + public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException + { + return beanFactory.isSingleton(name); + } + + /** + * @param name + * @return Class 注册对象的类型 + * @throws NoSuchBeanDefinitionException + * + */ + public static Class getType(String name) throws NoSuchBeanDefinitionException + { + return beanFactory.getType(name); + } + + /** + * 如果给定的bean名字在bean定义中有别名,则返回这些别名 + * + * @param name + * @return + * @throws NoSuchBeanDefinitionException + * + */ + public static String[] getAliases(String name) throws NoSuchBeanDefinitionException + { + return beanFactory.getAliases(name); + } + + /** + * 获取aop代理对象 + * + * @param invoker + * @return + */ + @SuppressWarnings("unchecked") + public static T getAopProxy(T invoker) + { + return (T) AopContext.currentProxy(); + } + + /** + * 获取当前的环境配置,无配置返回null + * + * @return 当前的环境配置 + */ + public static String[] getActiveProfiles() + { + return applicationContext.getEnvironment().getActiveProfiles(); + } + + /** + * 获取当前的环境配置,当有多个环境配置时,只获取第一个 + * + * @return 当前的环境配置 + */ + public static String getActiveProfile() + { + final String[] activeProfiles = getActiveProfiles(); + return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null; + } +} + diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/utils/sql/SqlUtil.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/sql/SqlUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..47f4c5c2b49cc404c3b8e3fe76a007881a4b1f90 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/sql/SqlUtil.java @@ -0,0 +1,71 @@ +package com.RVSmartPorting.common.utils.sql; + +import com.RVSmartPorting.common.exception.UtilException; +import com.RVSmartPorting.common.utils.StringUtils; + +/** + * sql操作工具类 + * + * @author ruoyi + */ + +public class SqlUtil +{ + /** + * 定义常用的 sql关键字 + */ + public static String SQL_REGEX = "and |extractvalue|updatexml|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |+|user()"; + + /** + * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序) + */ + public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+"; + + /** + * 限制orderBy最大长度 + */ + private static final int ORDER_BY_MAX_LENGTH = 500; + + /** + * 检查字符,防止注入绕过 + */ + public static String escapeOrderBySql(String value) + { + if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) + { + throw new UtilException("参数不符合规范,不能进行查询"); + } + if (StringUtils.length(value) > ORDER_BY_MAX_LENGTH) + { + 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/CSP-common/src/main/java/com/RVSmartPorting/common/utils/uuid/IdUtils.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/uuid/IdUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..854b517e1f01148a05958aae2398b7f988c78746 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/uuid/IdUtils.java @@ -0,0 +1,51 @@ +package com.RVSmartPorting.common.utils.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/CSP-common/src/main/java/com/RVSmartPorting/common/utils/uuid/Seq.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/uuid/Seq.java new file mode 100644 index 0000000000000000000000000000000000000000..0cda05de31cda9fb3fa558b9e2d30f8e01ce92d2 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/uuid/Seq.java @@ -0,0 +1,88 @@ +package com.RVSmartPorting.common.utils.uuid; + + +import com.RVSmartPorting.common.utils.DateUtils; +import com.RVSmartPorting.common.utils.StringUtils; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author ruoyi 序列生成类 + */ +public class Seq +{ + // 通用序列类型 + public static final String commSeqType = "COMMON"; + + // 上传序列类型 + public static final String uploadSeqType = "UPLOAD"; + + // 通用接口序列数 + private static AtomicInteger commSeq = new AtomicInteger(1); + + // 上传接口序列数 + private static AtomicInteger uploadSeq = new AtomicInteger(1); + + // 机器标识 + private static final String machineCode = "A"; + + /** + * 获取通用序列号 + * + * @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/CSP-common/src/main/java/com/RVSmartPorting/common/utils/uuid/UUID.java b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/uuid/UUID.java new file mode 100644 index 0000000000000000000000000000000000000000..566b9685379f420ae5ad66cd80ec7dcfa58ed0d2 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/utils/uuid/UUID.java @@ -0,0 +1,485 @@ +package com.RVSmartPorting.common.utils.uuid; + +import com.RVSmartPorting.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 ruoyi + */ +public final class UUID implements java.io.Serializable, Comparable +{ + private static final long serialVersionUID = -1185015143654744140L; + + /** + * SecureRandom 的单例 + * + */ + private static class Holder + { + static final SecureRandom numberGenerator = getSecureRandom(); + } + + /** 此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); + } + + /** + * 返回此 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(); + } + + /** + * 返回此 UUID 的哈希码。 + * + * @return UUID 的哈希码值。 + */ + @Override + public int hashCode() + { + long hilo = mostSigBits ^ leastSigBits; + return ((int) (hilo >> 32)) ^ (int) hilo; + } + + /** + * 将此对象与指定对象比较。 + *

+ * 当且仅当参数不为 {@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); + } + + // Comparison Operations + + /** + * 将此 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)))); + } + + // ------------------------------------------------------------------------------------------------------------------- + // Private method start + /** + * 返回指定数字对应的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); + } + + /** + * 检查是否为time-based版本UUID + */ + private void checkTimeBase() + { + if (version() != 1) + { + throw new UnsupportedOperationException("Not a time-based UUID"); + } + } + + /** + * 获取{@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(); + } +} diff --git a/CSP-common/src/main/java/com/RVSmartPorting/common/xss/Xss.java b/CSP-common/src/main/java/com/RVSmartPorting/common/xss/Xss.java new file mode 100644 index 0000000000000000000000000000000000000000..922d3990cb508c63c5510138548d9cab1806129d --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/xss/Xss.java @@ -0,0 +1,27 @@ +package com.RVSmartPorting.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 ruoyi + */ +@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/CSP-common/src/main/java/com/RVSmartPorting/common/xss/XssValidator.java b/CSP-common/src/main/java/com/RVSmartPorting/common/xss/XssValidator.java new file mode 100644 index 0000000000000000000000000000000000000000..48404f3af3890396b304384d6e819074b4310582 --- /dev/null +++ b/CSP-common/src/main/java/com/RVSmartPorting/common/xss/XssValidator.java @@ -0,0 +1,36 @@ +package com.RVSmartPorting.common.xss; + + +import com.RVSmartPorting.common.utils.StringUtils; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 自定义xss校验注解实现 + * + * @author ruoyi + */ +public class XssValidator implements ConstraintValidator +{ + private static final String HTML_PATTERN = "<(\\S*?)[^>]*>.*?|<.*? />"; + + @Override + public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) + { + if (StringUtils.isBlank(value)) + { + return true; + } + return !containsHtml(value); + } + + public static boolean containsHtml(String value) + { + Pattern pattern = Pattern.compile(HTML_PATTERN); + Matcher matcher = pattern.matcher(value); + return matcher.matches(); + } +} \ No newline at end of file diff --git a/CSP-core/pom.xml b/CSP-core/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..e73661bec1818809dee37cc4eeb583331a8605cd --- /dev/null +++ b/CSP-core/pom.xml @@ -0,0 +1,103 @@ + + + + CodeScanningPlatform-Backend + com.RVSmartPorting + 1.0.0 + + 4.0.0 + + CSP-core + + + core框架核心模块 + + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + com.github.oshi + oshi-core + + + org.projectlombok + lombok + + + + + com.github.penggle + kaptcha + + + javax.servlet-api + javax.servlet + + + + + + + + com.baomidou + mybatis-plus-extension + + + + + + com.alibaba + druid-spring-boot-starter + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-logging + + + + + + + + org.springframework.boot + spring-boot-starter-aop + + + + + + org.springframework.boot + spring-boot-starter-log4j2 + + + + + + com.RVSmartPorting + CSP-common + + + + + + + \ No newline at end of file diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/aspectj/DataScopeAspect.java b/CSP-core/src/main/java/com/RVSmartPorting/core/aspectj/DataScopeAspect.java new file mode 100644 index 0000000000000000000000000000000000000000..0cb5b5b4c843c0e7e7d1230108e8bf6089df6f54 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/aspectj/DataScopeAspect.java @@ -0,0 +1,176 @@ +package com.RVSmartPorting.core.aspectj; + +import com.RVSmartPorting.common.annotation.DataScope; +import com.RVSmartPorting.common.annotation.DataScope; +import com.RVSmartPorting.common.core.domain.BaseEntity; +import com.RVSmartPorting.common.core.domain.entity.SysRole; +import com.RVSmartPorting.common.core.domain.entity.SysUser; +import com.RVSmartPorting.common.core.domain.model.LoginUser; +import com.RVSmartPorting.common.core.text.Convert; +import com.RVSmartPorting.common.utils.SecurityUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.core.security.context.PermissionContextHolder; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +/** + * 数据过滤处理 + * + * @author RVSmartPorting + */ +@Aspect +@Component +public class DataScopeAspect +{ + /** + * 全部数据权限 + */ + public static final String DATA_SCOPE_ALL = "1"; + + /** + * 自定数据权限 + */ + public static final String DATA_SCOPE_CUSTOM = "2"; + + /** + * 部门数据权限 + */ + public static final String DATA_SCOPE_DEPT = "3"; + + /** + * 部门及以下数据权限 + */ + public static final String DATA_SCOPE_DEPT_AND_CHILD = "4"; + + /** + * 仅本人数据权限 + */ + public static final String DATA_SCOPE_SELF = "5"; + + /** + * 数据权限过滤关键字 + */ + public static final String DATA_SCOPE = "dataScope"; + + @Before("@annotation(controllerDataScope)") + public void doBefore(JoinPoint point, DataScope controllerDataScope) throws Throwable + { + clearDataScope(point); + handleDataScope(point, controllerDataScope); + } + + protected void handleDataScope(final JoinPoint joinPoint, DataScope controllerDataScope) + { + // 获取当前的用户 + LoginUser loginUser = SecurityUtils.getLoginUser(); + if (StringUtils.isNotNull(loginUser)) + { + SysUser currentUser = loginUser.getUser(); + // 如果是超级管理员,则不过滤数据 + if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) + { + String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), PermissionContextHolder.getContext()); + dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), + controllerDataScope.userAlias(), permission); + } + } + } + + /** + * 数据范围过滤 + * + * @param joinPoint 切点 + * @param user 用户 + * @param deptAlias 部门别名 + * @param userAlias 用户别名 + * @param permission 权限字符 + */ + public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias, String permission) + { + StringBuilder sqlString = new StringBuilder(); + List conditions = new ArrayList(); + + for (SysRole role : user.getRoles()) + { + String dataScope = role.getDataScope(); + if (!DATA_SCOPE_CUSTOM.equals(dataScope) && conditions.contains(dataScope)) + { + continue; + } + if (StringUtils.isNotEmpty(permission) && StringUtils.isNotEmpty(role.getPermissions()) + && !StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission))) + { + continue; + } + if (DATA_SCOPE_ALL.equals(dataScope)) + { + sqlString = new StringBuilder(); + conditions.add(dataScope); + break; + } + else if (DATA_SCOPE_CUSTOM.equals(dataScope)) + { + sqlString.append(StringUtils.format( + " OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias, + role.getRoleId())); + } + else if (DATA_SCOPE_DEPT.equals(dataScope)) + { + sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId())); + } + else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) + { + sqlString.append(StringUtils.format( + " OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )", + deptAlias, user.getDeptId(), user.getDeptId())); + } + else if (DATA_SCOPE_SELF.equals(dataScope)) + { + if (StringUtils.isNotBlank(userAlias)) + { + sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId())); + } + else + { + // 数据权限为仅本人且没有userAlias别名不查询任何数据 + sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias)); + } + } + conditions.add(dataScope); + } + + // 多角色情况下,所有角色都不包含传递过来的权限字符,这个时候sqlString也会为空,所以要限制一下,不查询任何数据 + if (StringUtils.isEmpty(conditions)) + { + sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias)); + } + + if (StringUtils.isNotBlank(sqlString.toString())) + { + Object params = joinPoint.getArgs()[0]; + if (StringUtils.isNotNull(params) && params instanceof BaseEntity) + { + BaseEntity baseEntity = (BaseEntity) params; + baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")"); + } + } + } + + /** + * 拼接权限sql前先清空params.dataScope参数防止注入 + */ + private void clearDataScope(final JoinPoint joinPoint) + { + Object params = joinPoint.getArgs()[0]; + if (StringUtils.isNotNull(params) && params instanceof BaseEntity) + { + BaseEntity baseEntity = (BaseEntity) params; + baseEntity.getParams().put(DATA_SCOPE, ""); + } + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/aspectj/DataSourceAspect.java b/CSP-core/src/main/java/com/RVSmartPorting/core/aspectj/DataSourceAspect.java new file mode 100644 index 0000000000000000000000000000000000000000..079a9a8cd07ae19e9f9d26eaa0ebd65ec5a78463 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/aspectj/DataSourceAspect.java @@ -0,0 +1,73 @@ +package com.RVSmartPorting.core.aspectj; + +import com.RVSmartPorting.common.annotation.DataSource; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.core.datasource.DynamicDataSourceContextHolder; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.Objects; + +/** + * 多数据源处理 + * + * @author ruoyi + */ +@Aspect +@Order(1) +@Component +public class DataSourceAspect +{ + protected Logger logger = LoggerFactory.getLogger(getClass()); + + @Pointcut("@annotation(com.RVSmartPorting.common.annotation.DataSource)" + + "|| @within(com.RVSmartPorting.common.annotation.DataSource)") + public void dsPointCut() + { + + } + + @Around("dsPointCut()") + public Object around(ProceedingJoinPoint point) throws Throwable + { + DataSource dataSource = getDataSource(point); + + if (StringUtils.isNotNull(dataSource)) + { + DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name()); + } + + try + { + return point.proceed(); + } + finally + { + // 销毁数据源 在执行方法之后 + DynamicDataSourceContextHolder.clearDataSourceType(); + } + } + + /** + * 获取需要切换的数据源 + */ + public DataSource getDataSource(ProceedingJoinPoint point) + { + MethodSignature signature = (MethodSignature) point.getSignature(); + DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class); + if (Objects.nonNull(dataSource)) + { + return dataSource; + } + + return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/aspectj/LogAspect.java b/CSP-core/src/main/java/com/RVSmartPorting/core/aspectj/LogAspect.java new file mode 100644 index 0000000000000000000000000000000000000000..27533ba8f550972c78a733db23b15f43444c42cb --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/aspectj/LogAspect.java @@ -0,0 +1,250 @@ +package com.RVSmartPorting.core.aspectj; + +import com.RVSmartPorting.core.manager.AsyncManager; +import com.RVSmartPorting.core.manager.factory.AsyncFactory; +import com.RVSmartPorting.core.system.domain.SysOperLog; +import com.alibaba.fastjson2.JSON; +import com.RVSmartPorting.common.annotation.Log; +import com.RVSmartPorting.common.core.domain.model.LoginUser; +import com.RVSmartPorting.common.enums.BusinessStatus; +import com.RVSmartPorting.common.enums.HttpMethod; +import com.RVSmartPorting.common.filter.PropertyPreExcludeFilter; +import com.RVSmartPorting.common.utils.SecurityUtils; +import com.RVSmartPorting.common.utils.ServletUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.ip.IpUtils; +import org.apache.commons.lang3.ArrayUtils; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.NamedThreadLocal; +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 ruoyi + */ +@Aspect +@Component +public class LogAspect +{ + private static final Logger log = LoggerFactory.getLogger(LogAspect.class); + + /** 排除敏感属性字段 */ + public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" }; + + /** 计算操作消耗时间 */ + private static final ThreadLocal TIME_THREADLOCAL = new NamedThreadLocal("Cost Time"); + + /** + * 处理请求前执行 + */ + @Before(value = "@annotation(controllerLog)") + public void boBefore(JoinPoint joinPoint, Log controllerLog) + { + TIME_THREADLOCAL.set(System.currentTimeMillis()); + } + + /** + * 处理完请求后执行 + * + * @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 + { + // 获取当前的用户 + LoginUser loginUser = SecurityUtils.getLoginUser(); + + // *========数据库日志=========*// + SysOperLog operLog = new SysOperLog(); + operLog.setStatus(BusinessStatus.SUCCESS.ordinal()); + // 请求的地址 + String ip = IpUtils.getIpAddr(); + operLog.setOperIp(ip); + operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255)); + if (loginUser != null) + { + operLog.setOperName(loginUser.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); + // 设置消耗时间 + operLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get()); + // 保存数据库 + AsyncManager.me().execute(AsyncFactory.recordOper(operLog)); + } + catch (Exception exp) + { + // 记录本地异常日志 + log.error("异常信息:{}", exp.getMessage()); + exp.printStackTrace(); + } + finally + { + TIME_THREADLOCAL.remove(); + } + } + + /** + * 获取注解中对方法的描述信息 用于Controller层注解 + * + * @param log 日志 + * @param operLog 操作日志 + * @throws Exception + */ + public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog 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() && StringUtils.isNotNull(jsonResult)) + { + operLog.setJsonResult(StringUtils.substring(JSON.toJSONString(jsonResult), 0, 2000)); + } + } + + /** + * 获取请求的参数,放到log中 + * + * @param operLog 操作日志 + * @throws Exception 异常 + */ + private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog, String[] excludeParamNames) throws Exception + { + Map paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest()); + String requestMethod = operLog.getRequestMethod(); + if (StringUtils.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 + { + operLog.setOperParam(StringUtils.substring(JSON.toJSONString(paramsMap, excludePropertyPreFilter(excludeParamNames)), 0, 2000)); + } + } + + /** + * 参数拼装 + */ + private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames) + { + String params = ""; + if (paramsArray != null && paramsArray.length > 0) + { + for (Object o : paramsArray) + { + if (StringUtils.isNotNull(o) && !isFilterObject(o)) + { + try + { + String jsonObj = JSON.toJSONString(o, excludePropertyPreFilter(excludeParamNames)); + params += jsonObj.toString() + " "; + } + catch (Exception e) + { + } + } + } + } + return params.trim(); + } + + /** + * 忽略敏感属性 + */ + public PropertyPreExcludeFilter excludePropertyPreFilter(String[] excludeParamNames) + { + return new PropertyPreExcludeFilter().addExcludes(ArrayUtils.addAll(EXCLUDE_PROPERTIES, excludeParamNames)); + } + + /** + * 判断是否需要过滤的对象。 + * + * @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/CSP-core/src/main/java/com/RVSmartPorting/core/aspectj/RateLimiterAspect.java b/CSP-core/src/main/java/com/RVSmartPorting/core/aspectj/RateLimiterAspect.java new file mode 100644 index 0000000000000000000000000000000000000000..2adac080777f1f2bc04c2c142f0e663f6e024fb6 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/aspectj/RateLimiterAspect.java @@ -0,0 +1,90 @@ +package com.RVSmartPorting.core.aspectj; + +import com.RVSmartPorting.common.annotation.RateLimiter; +import com.RVSmartPorting.common.enums.LimitType; +import com.RVSmartPorting.common.exception.ServiceException; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.ip.IpUtils; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.script.RedisScript; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.List; + +/** + * 限流处理 + * + * @author ruoyi + */ +@Aspect +@Component +public class RateLimiterAspect +{ + private static final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class); + + private RedisTemplate redisTemplate; + + private RedisScript limitScript; + + @Autowired + public void setRedisTemplate1(RedisTemplate redisTemplate) + { + this.redisTemplate = redisTemplate; + } + + @Autowired + public void setLimitScript(RedisScript limitScript) + { + this.limitScript = limitScript; + } + + @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); + List keys = Collections.singletonList(combineKey); + try + { + Long number = redisTemplate.execute(limitScript, keys, count, time); + if (StringUtils.isNull(number) || number.intValue() > count) + { + throw new ServiceException("访问过于频繁,请稍候再试"); + } + log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), combineKey); + } + catch (ServiceException e) + { + throw e; + } + catch (Exception e) + { + throw new RuntimeException("服务器限流异常,请稍候再试"); + } + } + + public String getCombineKey(RateLimiter rateLimiter, JoinPoint point) + { + StringBuffer stringBuffer = new StringBuffer(rateLimiter.key()); + if (rateLimiter.limitType() == LimitType.IP) + { + stringBuffer.append(IpUtils.getIpAddr()).append("-"); + } + MethodSignature signature = (MethodSignature) point.getSignature(); + Method method = signature.getMethod(); + Class targetClass = method.getDeclaringClass(); + stringBuffer.append(targetClass.getName()).append("-").append(method.getName()); + return stringBuffer.toString(); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/config/ApplicationConfig.java b/CSP-core/src/main/java/com/RVSmartPorting/core/config/ApplicationConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..2c3f89e742d9de25e0082769c4da740351451ead --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/config/ApplicationConfig.java @@ -0,0 +1,31 @@ +package com.RVSmartPorting.core.config; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.EnableAspectJAutoProxy; + +import java.util.TimeZone; + +/** + * 程序注解配置 + * + * @author ruoyi + */ +@Configuration +// 表示通过aop框架暴露该代理对象,AopContext能够访问 +@EnableAspectJAutoProxy(exposeProxy = true) +// 指定要扫描的Mapper类的包的路径 +@MapperScan("com.RVSmartPorting.**.mapper") +public class ApplicationConfig +{ + /** + * 时区配置 + */ + @Bean + public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() + { + return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault()); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/config/CaptchaConfig.java b/CSP-core/src/main/java/com/RVSmartPorting/core/config/CaptchaConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..3d79ce90c7816b88b401624eb250a1026a60ff05 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/config/CaptchaConfig.java @@ -0,0 +1,85 @@ +package com.RVSmartPorting.core.config; + +import com.google.code.kaptcha.impl.DefaultKaptcha; +import com.google.code.kaptcha.util.Config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Properties; + +import static com.google.code.kaptcha.Constants.*; + +/** + * 验证码配置 + * + * @author ruoyi + */ +@Configuration +public class CaptchaConfig +{ + @Bean(name = "captchaProducer") + public DefaultKaptcha getKaptchaBean() + { + DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); + Properties properties = new Properties(); + // 是否有边框 默认为true 我们可以自己设置yes,no + properties.setProperty(KAPTCHA_BORDER, "yes"); + // 验证码文本字符颜色 默认为Color.BLACK + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black"); + // 验证码图片宽度 默认为200 + properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160"); + // 验证码图片高度 默认为50 + properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60"); + // 验证码文本字符大小 默认为40 + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38"); + // KAPTCHA_SESSION_KEY + properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode"); + // 验证码文本字符长度 默认为5 + properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4"); + // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize) + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier"); + // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy + properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy"); + Config config = new Config(properties); + defaultKaptcha.setConfig(config); + return defaultKaptcha; + } + + @Bean(name = "captchaProducerMath") + public DefaultKaptcha getKaptchaBeanMath() + { + DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); + Properties properties = new Properties(); + // 是否有边框 默认为true 我们可以自己设置yes,no + properties.setProperty(KAPTCHA_BORDER, "yes"); + // 边框颜色 默认为Color.BLACK + properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90"); + // 验证码文本字符颜色 默认为Color.BLACK + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue"); + // 验证码图片宽度 默认为200 + properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160"); + // 验证码图片高度 默认为50 + properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60"); + // 验证码文本字符大小 默认为40 + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35"); + // KAPTCHA_SESSION_KEY + properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath"); + // 验证码文本生成器 + properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.RVSmartPorting.core.config.KaptchaTextCreator"); + // 验证码文本字符间距 默认为2 + properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3"); + // 验证码文本字符长度 默认为5 + properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6"); + // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize) + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier"); + // 验证码噪点颜色 默认为Color.BLACK + properties.setProperty(KAPTCHA_NOISE_COLOR, "white"); + // 干扰实现类 + properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise"); + // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy + properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy"); + Config config = new Config(properties); + defaultKaptcha.setConfig(config); + return defaultKaptcha; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/config/DruidConfig.java b/CSP-core/src/main/java/com/RVSmartPorting/core/config/DruidConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..94984c3e11b7b981c66c2e9d1134bd7d69dee3f8 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/config/DruidConfig.java @@ -0,0 +1,123 @@ +package com.RVSmartPorting.core.config; + +import com.RVSmartPorting.core.config.properties.DruidProperties; +import com.RVSmartPorting.core.datasource.DynamicDataSource; +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; +import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties; +import com.alibaba.druid.util.Utils; +import com.RVSmartPorting.common.enums.DataSourceType; +import com.RVSmartPorting.common.utils.spring.SpringUtils; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; + +import javax.servlet.*; +import javax.sql.DataSource; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * druid 配置多数据源 + * + * @author ruoyi + */ +@Configuration +public class DruidConfig +{ + @Bean + @ConfigurationProperties("spring.datasource.druid.master") + public DataSource masterDataSource(DruidProperties druidProperties) + { + DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); + return druidProperties.dataSource(dataSource); + } + + @Bean + @ConfigurationProperties("spring.datasource.druid.slave") + @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true") + public DataSource slaveDataSource(DruidProperties druidProperties) + { + DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); + return druidProperties.dataSource(dataSource); + } + + @Bean(name = "dynamicDataSource") + @Primary + public DynamicDataSource dataSource(DataSource masterDataSource) + { + Map targetDataSources = new HashMap<>(); + targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource); + setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource"); + return new DynamicDataSource(masterDataSource, targetDataSources); + } + + /** + * 设置数据源 + * + * @param targetDataSources 备选数据源集合 + * @param sourceName 数据源名称 + * @param beanName bean名称 + */ + public void setDataSource(Map targetDataSources, String sourceName, String beanName) + { + try + { + DataSource dataSource = SpringUtils.getBean(beanName); + targetDataSources.put(sourceName, dataSource); + } + catch (Exception e) + { + } + } + + /** + * 去除监控页面底部的广告 + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Bean + @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true") + public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties) + { + // 获取web监控页面的参数 + DruidStatProperties.StatViewServlet config = properties.getStatViewServlet(); + // 提取common.js的配置路径 + String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*"; + String commonJsPattern = pattern.replaceAll("\\*", "js/common.js"); + final String filePath = "support/http/resources/js/common.js"; + // 创建filter进行过滤 + Filter filter = new Filter() + { + @Override + public void init(javax.servlet.FilterConfig filterConfig) throws ServletException + { + } + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException + { + chain.doFilter(request, response); + // 重置缓冲区,响应头不会被重置 + response.resetBuffer(); + // 获取common.js + String text = Utils.readFromResource(filePath); + // 正则替换banner, 除去底部的广告信息 + text = text.replaceAll("
", ""); + text = text.replaceAll("powered.*?shrek.wang", ""); + response.getWriter().write(text); + } + @Override + public void destroy() + { + } + }; + FilterRegistrationBean registrationBean = new FilterRegistrationBean(); + registrationBean.setFilter(filter); + registrationBean.addUrlPatterns(commonJsPattern); + return registrationBean; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/config/FastJson2JsonRedisSerializer.java b/CSP-core/src/main/java/com/RVSmartPorting/core/config/FastJson2JsonRedisSerializer.java new file mode 100644 index 0000000000000000000000000000000000000000..f36d46db3955435f35de279b3d72c45b27ef3090 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/config/FastJson2JsonRedisSerializer.java @@ -0,0 +1,49 @@ +package com.RVSmartPorting.core.config; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONReader; +import com.alibaba.fastjson2.JSONWriter; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.serializer.SerializationException; + +import java.nio.charset.Charset; + +/** + * Redis使用FastJson序列化 + * + * @author ruoyi + */ +public class FastJson2JsonRedisSerializer implements RedisSerializer +{ + public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); + + private Class clazz; + + public FastJson2JsonRedisSerializer(Class clazz) + { + super(); + this.clazz = clazz; + } + + @Override + public byte[] serialize(T t) throws SerializationException + { + if (t == null) + { + return new byte[0]; + } + return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName).getBytes(DEFAULT_CHARSET); + } + + @Override + public T deserialize(byte[] bytes) throws SerializationException + { + if (bytes == null || bytes.length <= 0) + { + return null; + } + String str = new String(bytes, DEFAULT_CHARSET); + + return JSON.parseObject(str, clazz, JSONReader.Feature.SupportAutoType); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/config/FilterConfig.java b/CSP-core/src/main/java/com/RVSmartPorting/core/config/FilterConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..1f9b0fbcc8dd64bfc2d7585c9320c1bce91d9c7a --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/config/FilterConfig.java @@ -0,0 +1,59 @@ +package com.RVSmartPorting.core.config; + +import com.RVSmartPorting.common.filter.RepeatableFilter; +import com.RVSmartPorting.common.filter.XssFilter; +import com.RVSmartPorting.common.utils.StringUtils; +import org.springframework.beans.factory.annotation.Value; +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 ruoyi + */ +@Configuration +public class FilterConfig +{ + @Value("${xss.excludes}") + private String excludes; + + @Value("${xss.urlPatterns}") + private String urlPatterns; + + @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(urlPatterns, ",")); + registration.setName("xssFilter"); + registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE); + Map initParameters = new HashMap(); + initParameters.put("excludes", excludes); + 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/CSP-core/src/main/java/com/RVSmartPorting/core/config/KaptchaTextCreator.java b/CSP-core/src/main/java/com/RVSmartPorting/core/config/KaptchaTextCreator.java new file mode 100644 index 0000000000000000000000000000000000000000..ac231e75905219231975a30d082dec5aa6006fea --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/config/KaptchaTextCreator.java @@ -0,0 +1,69 @@ +package com.RVSmartPorting.core.config; + +import com.google.code.kaptcha.text.impl.DefaultTextCreator; + +import java.util.Random; + +/** + * 验证码文本生成器 + * + * @author ruoyi + */ +public class KaptchaTextCreator extends DefaultTextCreator +{ + private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(","); + + @Override + public String getText() + { + Integer result = 0; + Random random = new Random(); + int x = random.nextInt(10); + int y = random.nextInt(10); + StringBuilder suChinese = new StringBuilder(); + int randomoperands = random.nextInt(3); + if (randomoperands == 0) + { + result = x * y; + suChinese.append(CNUMBERS[x]); + suChinese.append("*"); + suChinese.append(CNUMBERS[y]); + } + else if (randomoperands == 1) + { + if ((x != 0) && y % x == 0) + { + result = y / x; + suChinese.append(CNUMBERS[y]); + suChinese.append("/"); + suChinese.append(CNUMBERS[x]); + } + else + { + result = x + y; + suChinese.append(CNUMBERS[x]); + suChinese.append("+"); + suChinese.append(CNUMBERS[y]); + } + } + else + { + if (x >= y) + { + result = x - y; + suChinese.append(CNUMBERS[x]); + suChinese.append("-"); + suChinese.append(CNUMBERS[y]); + } + else + { + result = y - x; + suChinese.append(CNUMBERS[y]); + suChinese.append("-"); + suChinese.append(CNUMBERS[x]); + } + } + suChinese.append("=?@" + result); + return suChinese.toString(); + } +} \ No newline at end of file diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/config/MyBatisConfig.java b/CSP-core/src/main/java/com/RVSmartPorting/core/config/MyBatisConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..393d11f291c6d63f88220a347b980e09ee426b9f --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/config/MyBatisConfig.java @@ -0,0 +1,133 @@ +package com.RVSmartPorting.core.config; + +import com.RVSmartPorting.common.utils.StringUtils; +import org.apache.ibatis.io.VFS; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.mybatis.spring.boot.autoconfigure.SpringBootVFS; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.core.type.classreading.CachingMetadataReaderFactory; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.util.ClassUtils; + +import javax.sql.DataSource; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + +/** + * Mybatis支持*匹配扫描包 + * + * @author ruoyi + */ +@Configuration +public class MyBatisConfig +{ + @Autowired + private Environment env; + + static final String DEFAULT_RESOURCE_PATTERN = "**/*.class"; + + public static String setTypeAliasesPackage(String typeAliasesPackage) + { + ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver(); + MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver); + List allResult = new ArrayList(); + try + { + for (String aliasesPackage : typeAliasesPackage.split(",")) + { + List result = new ArrayList(); + aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + + ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN; + Resource[] resources = resolver.getResources(aliasesPackage); + if (resources != null && resources.length > 0) + { + MetadataReader metadataReader = null; + for (Resource resource : resources) + { + if (resource.isReadable()) + { + metadataReader = metadataReaderFactory.getMetadataReader(resource); + try + { + result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName()); + } + catch (ClassNotFoundException e) + { + e.printStackTrace(); + } + } + } + } + if (result.size() > 0) + { + HashSet hashResult = new HashSet(result); + allResult.addAll(hashResult); + } + } + if (allResult.size() > 0) + { + typeAliasesPackage = String.join(",", (String[]) allResult.toArray(new String[0])); + } + else + { + throw new RuntimeException("mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:" + typeAliasesPackage + "未找到任何包"); + } + } + catch (IOException e) + { + e.printStackTrace(); + } + return typeAliasesPackage; + } + + public Resource[] resolveMapperLocations(String[] mapperLocations) + { + ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(); + List resources = new ArrayList(); + if (mapperLocations != null) + { + for (String mapperLocation : mapperLocations) + { + try + { + Resource[] mappers = resourceResolver.getResources(mapperLocation); + resources.addAll(Arrays.asList(mappers)); + } + catch (IOException e) + { + // ignore + } + } + } + return resources.toArray(new Resource[resources.size()]); + } + + @Bean + public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception + { + String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage"); + String mapperLocations = env.getProperty("mybatis.mapperLocations"); + String configLocation = env.getProperty("mybatis.configLocation"); + typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage); + VFS.addImplClass(SpringBootVFS.class); + + final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); + sessionFactory.setDataSource(dataSource); + sessionFactory.setTypeAliasesPackage(typeAliasesPackage); + sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ","))); + sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation)); + return sessionFactory.getObject(); + } +} \ No newline at end of file diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/config/RedisConfig.java b/CSP-core/src/main/java/com/RVSmartPorting/core/config/RedisConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..c7454d5573ee57591e84d22aa4545722ff982a7c --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/config/RedisConfig.java @@ -0,0 +1,69 @@ +package com.RVSmartPorting.core.config; + +import org.springframework.cache.annotation.CachingConfigurerSupport; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.script.DefaultRedisScript; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +/** + * redis配置 + * + * @author ruoyi + */ +@Configuration +@EnableCaching +public class RedisConfig extends CachingConfigurerSupport +{ + @Bean + @SuppressWarnings(value = { "unchecked", "rawtypes" }) + public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) + { + RedisTemplate template = new RedisTemplate<>(); + template.setConnectionFactory(connectionFactory); + + FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class); + + // 使用StringRedisSerializer来序列化和反序列化redis的key值 + template.setKeySerializer(new StringRedisSerializer()); + template.setValueSerializer(serializer); + + // Hash的key也采用StringRedisSerializer的序列化方式 + template.setHashKeySerializer(new StringRedisSerializer()); + template.setHashValueSerializer(serializer); + + template.afterPropertiesSet(); + return template; + } + + @Bean + public DefaultRedisScript limitScript() + { + DefaultRedisScript redisScript = new DefaultRedisScript<>(); + redisScript.setScriptText(limitScriptText()); + redisScript.setResultType(Long.class); + return redisScript; + } + + /** + * 限流脚本 + */ + private String limitScriptText() + { + return "local key = KEYS[1]\n" + + "local count = tonumber(ARGV[1])\n" + + "local time = tonumber(ARGV[2])\n" + + "local current = redis.call('get', key);\n" + + "if current and tonumber(current) > count then\n" + + " return tonumber(current);\n" + + "end\n" + + "current = redis.call('incr', key)\n" + + "if tonumber(current) == 1 then\n" + + " redis.call('expire', key, time)\n" + + "end\n" + + "return tonumber(current);"; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/config/ResourcesConfig.java b/CSP-core/src/main/java/com/RVSmartPorting/core/config/ResourcesConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..c12585c50ef97672f853adf5810f179384ed603c --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/config/ResourcesConfig.java @@ -0,0 +1,74 @@ +package com.RVSmartPorting.core.config; + +import com.RVSmartPorting.common.config.CSPConfig; +import com.RVSmartPorting.common.constant.Constants; +import com.RVSmartPorting.core.interceptor.RepeatSubmitInterceptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.CacheControl; +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; + +import java.util.concurrent.TimeUnit; + +/** + * 通用配置 + * + * @author ruoyi + */ +@Configuration +public class ResourcesConfig implements WebMvcConfigurer +{ + @Autowired + private RepeatSubmitInterceptor repeatSubmitInterceptor; + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) + { + /** 本地文件上传路径 */ + registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**") + .addResourceLocations("file:" + CSPConfig.getProfile() + "/"); + + /** swagger配置 */ + registry.addResourceHandler("/swagger-ui/**") + .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/") + .setCacheControl(CacheControl.maxAge(5, TimeUnit.HOURS).cachePublic());; + } + + /** + * 自定义拦截规则 + */ + @Override + public void addInterceptors(InterceptorRegistry registry) + { + registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**"); + } + + /** + * 跨域配置 + */ + @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); + } +} \ No newline at end of file diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/config/SecurityConfig.java b/CSP-core/src/main/java/com/RVSmartPorting/core/config/SecurityConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..1e0a13a705ef3ff343ae001c0323eed812123c53 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/config/SecurityConfig.java @@ -0,0 +1,149 @@ +package com.RVSmartPorting.core.config; + +import com.RVSmartPorting.core.config.properties.PermitAllUrlProperties; +import com.RVSmartPorting.core.security.filter.JwtAuthenticationTokenFilter; +import com.RVSmartPorting.core.security.handle.AuthenticationEntryPointImpl; +import com.RVSmartPorting.core.security.handle.LogoutSuccessHandlerImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpMethod; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.authentication.logout.LogoutFilter; +import org.springframework.web.filter.CorsFilter; + +/** + * spring security配置 + * + * @author ruoyi + */ +@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) +public class SecurityConfig extends WebSecurityConfigurerAdapter +{ + /** + * 自定义用户认证逻辑 + */ + @Autowired + private UserDetailsService userDetailsService; + + /** + * 认证失败处理类 + */ + @Autowired + private AuthenticationEntryPointImpl unauthorizedHandler; + + /** + * 退出处理类 + */ + @Autowired + private LogoutSuccessHandlerImpl logoutSuccessHandler; + + /** + * token认证过滤器 + */ + @Autowired + private JwtAuthenticationTokenFilter authenticationTokenFilter; + + /** + * 跨域过滤器 + */ + @Autowired + private CorsFilter corsFilter; + + /** + * 允许匿名访问的地址 + */ + @Autowired + private PermitAllUrlProperties permitAllUrl; + + /** + * 解决 无法直接注入 AuthenticationManager + * + * @return + * @throws Exception + */ + @Bean + @Override + public AuthenticationManager authenticationManagerBean() throws Exception + { + return super.authenticationManagerBean(); + } + + /** + * anyRequest | 匹配所有请求路径 + * access | SpringEl表达式结果为true时可以访问 + * anonymous | 匿名可以访问 + * denyAll | 用户不能访问 + * fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录) + * hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问 + * hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问 + * hasAuthority | 如果有参数,参数表示权限,则其权限可以访问 + * hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问 + * hasRole | 如果有参数,参数表示角色,则其角色可以访问 + * permitAll | 用户可以任意访问 + * rememberMe | 允许通过remember-me登录的用户访问 + * authenticated | 用户登录后可访问 + */ + @Override + protected void configure(HttpSecurity httpSecurity) throws Exception + { + // 注解标记允许匿名访问的url + ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry registry = httpSecurity.authorizeRequests(); + permitAllUrl.getUrls().forEach(url -> registry.antMatchers(url).permitAll()); + + httpSecurity + // CSRF禁用,因为不使用session + .csrf().disable() + // 禁用HTTP响应标头 + .headers().cacheControl().disable().and() + // 认证失败处理类 + .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() + // 基于token,所以不需要session + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() + // 过滤请求 + .authorizeRequests() + .antMatchers("/system/powerjob/**").permitAll() + // 对于登录login 注册register 验证码captchaImage 允许匿名访问 + .antMatchers("/login", "/register", "/captchaImage","/sse/userConnect/**").permitAll() + // 静态资源,可匿名访问 + .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll() + .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll() + // 除上面外的所有请求全部需要鉴权认证 + .anyRequest().authenticated() + .and() + .headers().frameOptions().disable(); + // 添加Logout filter + httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler); + // 添加JWT filter + httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); + // 添加CORS filter + httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class); + httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class); + } + + /** + * 强散列哈希加密实现 + */ + @Bean + public BCryptPasswordEncoder bCryptPasswordEncoder() + { + return new BCryptPasswordEncoder(); + } + + /** + * 身份认证接口 + */ + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception + { + auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder()); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/config/ServerConfig.java b/CSP-core/src/main/java/com/RVSmartPorting/core/config/ServerConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..d4fb8fbdcd4b4b732b1277dfcc84b31c879a47de --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/config/ServerConfig.java @@ -0,0 +1,33 @@ +package com.RVSmartPorting.core.config; + +import com.RVSmartPorting.common.utils.ServletUtils; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; + +/** + * 服务相关配置 + * + * @author ruoyi + */ +@Component +public class ServerConfig +{ + /** + * 获取完整的请求路径,包括:域名,端口,上下文访问路径 + * + * @return 服务地址 + */ + public String getUrl() + { + HttpServletRequest request = ServletUtils.getRequest(); + return getDomain(request); + } + + public static String getDomain(HttpServletRequest request) + { + 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/CSP-core/src/main/java/com/RVSmartPorting/core/config/ThreadPoolConfig.java b/CSP-core/src/main/java/com/RVSmartPorting/core/config/ThreadPoolConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..280368326e73072e0c5590e00c6f41fd05c32655 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/config/ThreadPoolConfig.java @@ -0,0 +1,64 @@ +package com.RVSmartPorting.core.config; + +import com.RVSmartPorting.common.utils.Threads; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; +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 ruoyi + **/ +@Configuration +public class ThreadPoolConfig +{ + // 核心线程池大小 + private int corePoolSize = 50; + + // 最大可创建的线程数 + private int maxPoolSize = 200; + + // 队列最大长度 + private int queueCapacity = 1000; + + // 线程池维护线程所允许的空闲时间 + private int keepAliveSeconds = 300; + + @Bean(name = "threadPoolTaskExecutor") + public ThreadPoolTaskExecutor threadPoolTaskExecutor() + { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setMaxPoolSize(maxPoolSize); + executor.setCorePoolSize(corePoolSize); + executor.setQueueCapacity(queueCapacity); + executor.setKeepAliveSeconds(keepAliveSeconds); + // 线程池对拒绝任务(无线程可用)的处理策略 + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + return executor; + } + + /** + * 执行周期性或定时任务 + */ + @Bean(name = "scheduledExecutorService") + protected ScheduledExecutorService scheduledExecutorService() + { + return new ScheduledThreadPoolExecutor(corePoolSize, + 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/CSP-core/src/main/java/com/RVSmartPorting/core/config/properties/DruidProperties.java b/CSP-core/src/main/java/com/RVSmartPorting/core/config/properties/DruidProperties.java new file mode 100644 index 0000000000000000000000000000000000000000..b3da936bd16f78bf58d7879890ef4c55e8470655 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/config/properties/DruidProperties.java @@ -0,0 +1,84 @@ +package com.RVSmartPorting.core.config.properties; + +/** + * druid 配置属性 + * + * @author ruoyi + */ + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import com.alibaba.druid.pool.DruidDataSource; + +/** + * druid 配置属性 + * + * @author ruoyi + */ +@Configuration +public class DruidProperties +{ + @Value("${spring.datasource.druid.initialSize}") + private int initialSize; + + @Value("${spring.datasource.druid.minIdle}") + private int minIdle; + + @Value("${spring.datasource.druid.maxActive}") + private int maxActive; + + @Value("${spring.datasource.druid.maxWait}") + private int maxWait; + + @Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}") + private int timeBetweenEvictionRunsMillis; + + @Value("${spring.datasource.druid.minEvictableIdleTimeMillis}") + private int minEvictableIdleTimeMillis; + + @Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}") + private int maxEvictableIdleTimeMillis; + + @Value("${spring.datasource.druid.validationQuery}") + private String validationQuery; + + @Value("${spring.datasource.druid.testWhileIdle}") + private boolean testWhileIdle; + + @Value("${spring.datasource.druid.testOnBorrow}") + private boolean testOnBorrow; + + @Value("${spring.datasource.druid.testOnReturn}") + private boolean testOnReturn; + + public DruidDataSource dataSource(DruidDataSource datasource) + { + /** 配置初始化大小、最小、最大 */ + datasource.setInitialSize(initialSize); + datasource.setMaxActive(maxActive); + datasource.setMinIdle(minIdle); + + /** 配置获取连接等待超时的时间 */ + datasource.setMaxWait(maxWait); + + /** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */ + datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); + + /** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */ + datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); + datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis); + + /** + * 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。 + */ + datasource.setValidationQuery(validationQuery); + /** 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 */ + datasource.setTestWhileIdle(testWhileIdle); + /** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */ + datasource.setTestOnBorrow(testOnBorrow); + /** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */ + datasource.setTestOnReturn(testOnReturn); + return datasource; + } +} + diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/config/properties/PermitAllUrlProperties.java b/CSP-core/src/main/java/com/RVSmartPorting/core/config/properties/PermitAllUrlProperties.java new file mode 100644 index 0000000000000000000000000000000000000000..0ebb4135deb9a7429fa3c732df72a1ad123bc5b0 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/config/properties/PermitAllUrlProperties.java @@ -0,0 +1,70 @@ +package com.RVSmartPorting.core.config.properties; + +import com.RVSmartPorting.common.annotation.Anonymous; +import org.apache.commons.lang3.RegExUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.AnnotationUtils; +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; + +/** + * 设置Anonymous注解允许匿名访问的url + * + * @author ruoyi + */ +@Configuration +public class PermitAllUrlProperties implements InitializingBean, ApplicationContextAware +{ + private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}"); + + private ApplicationContext applicationContext; + + private List urls = new ArrayList<>(); + + public String ASTERISK = "*"; + + @Override + public void afterPropertiesSet() + { + RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class); + Map map = mapping.getHandlerMethods(); + + map.keySet().forEach(info -> { + HandlerMethod handlerMethod = map.get(info); + + // 获取方法上边的注解 替代path variable 为 * + Anonymous method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Anonymous.class); + Optional.ofNullable(method).ifPresent(anonymous -> Objects.requireNonNull(info.getPatternsCondition().getPatterns()) + .forEach(url -> urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK)))); + + // 获取类上边的注解, 替代path variable 为 * + Anonymous controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Anonymous.class); + Optional.ofNullable(controller).ifPresent(anonymous -> Objects.requireNonNull(info.getPatternsCondition().getPatterns()) + .forEach(url -> urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK)))); + }); + } + + @Override + public void setApplicationContext(ApplicationContext context) throws BeansException + { + this.applicationContext = context; + } + + public List getUrls() + { + return urls; + } + + public void setUrls(List urls) + { + this.urls = urls; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/datasource/DynamicDataSource.java b/CSP-core/src/main/java/com/RVSmartPorting/core/datasource/DynamicDataSource.java new file mode 100644 index 0000000000000000000000000000000000000000..76b92291a97185e6676becc7ce400f0362c75c6c --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/datasource/DynamicDataSource.java @@ -0,0 +1,28 @@ +package com.RVSmartPorting.core.datasource; + +/** + * 动态数据源 + * + * @author ruoyi + */ + +import java.util.Map; +import javax.sql.DataSource; +import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; + + +public class DynamicDataSource extends AbstractRoutingDataSource +{ + public DynamicDataSource(DataSource defaultTargetDataSource, Map targetDataSources) + { + super.setDefaultTargetDataSource(defaultTargetDataSource); + super.setTargetDataSources(targetDataSources); + super.afterPropertiesSet(); + } + + @Override + protected Object determineCurrentLookupKey() + { + return DynamicDataSourceContextHolder.getDataSourceType(); + } +} \ No newline at end of file diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/datasource/DynamicDataSourceContextHolder.java b/CSP-core/src/main/java/com/RVSmartPorting/core/datasource/DynamicDataSourceContextHolder.java new file mode 100644 index 0000000000000000000000000000000000000000..d0a0948a7d7d2acea0ee5adb3c2dbf470265beeb --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/datasource/DynamicDataSourceContextHolder.java @@ -0,0 +1,48 @@ +package com.RVSmartPorting.core.datasource; + +/** + * 动态数据源 + * + * @author ruoyi + */ + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class DynamicDataSourceContextHolder +{ + public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class); + + /** + * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本, + * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。 + */ + private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>(); + + /** + * 设置数据源的变量 + */ + public static void setDataSourceType(String dsType) + { + log.info("切换到{}数据源", dsType); + CONTEXT_HOLDER.set(dsType); + } + + /** + * 获得数据源的变量 + */ + public static String getDataSourceType() + { + return CONTEXT_HOLDER.get(); + } + + /** + * 清空数据源变量 + */ + public static void clearDataSourceType() + { + CONTEXT_HOLDER.remove(); + } +} + diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/interceptor/RepeatSubmitInterceptor.java b/CSP-core/src/main/java/com/RVSmartPorting/core/interceptor/RepeatSubmitInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..bfb60cf23560927bb84a54365b0482ffe442d4b7 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/interceptor/RepeatSubmitInterceptor.java @@ -0,0 +1,56 @@ +package com.RVSmartPorting.core.interceptor; + +import com.RVSmartPorting.common.annotation.RepeatSubmit; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.utils.ServletUtils; +import com.alibaba.fastjson2.JSON; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.lang.reflect.Method; + +/** + * 防止重复提交拦截器 + * + * @author ruoyi + */ +@Component +public abstract class RepeatSubmitInterceptor implements HandlerInterceptor +{ + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception + { + if (handler instanceof HandlerMethod) + { + HandlerMethod handlerMethod = (HandlerMethod) handler; + Method method = handlerMethod.getMethod(); + RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class); + if (annotation != null) + { + if (this.isRepeatSubmit(request, annotation)) + { + AjaxResult ajaxResult = AjaxResult.error(annotation.message()); + ServletUtils.renderString(response, JSON.toJSONString(ajaxResult)); + return false; + } + } + return true; + } + else + { + return true; + } + } + + /** + * 验证是否重复提交由子类实现具体的防重复提交的规则 + * + * @param request + * @return + * @throws Exception + */ + public abstract boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/interceptor/impl/SameUrlDataInterceptor.java b/CSP-core/src/main/java/com/RVSmartPorting/core/interceptor/impl/SameUrlDataInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..2e1a2f779be4d0f6328bfa068dc14ba37bd5b8ec --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/interceptor/impl/SameUrlDataInterceptor.java @@ -0,0 +1,112 @@ +package com.RVSmartPorting.core.interceptor.impl; + +import com.RVSmartPorting.common.annotation.RepeatSubmit; +import com.RVSmartPorting.common.constant.CacheConstants; +import com.RVSmartPorting.common.filter.RepeatedlyRequestWrapper; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.http.HttpHelper; +import com.RVSmartPorting.common.utils.redis.RedisCache; +import com.RVSmartPorting.core.interceptor.RepeatSubmitInterceptor; +import com.alibaba.fastjson2.JSON; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * 判断请求url和数据是否和上一次相同, + * 如果和上次相同,则是重复提交表单。 有效时间为10秒内。 + * + * @author ruoyi + */ +@Component +public class SameUrlDataInterceptor extends RepeatSubmitInterceptor +{ + public final String REPEAT_PARAMS = "repeatParams"; + + public final String REPEAT_TIME = "repeatTime"; + + // 令牌自定义标识 + @Value("${token.header}") + private String header; + + @Autowired + private RedisCache redisCache; + + @SuppressWarnings("unchecked") + @Override + public boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation) + { + String nowParams = ""; + if (request instanceof RepeatedlyRequestWrapper) + { + RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request; + nowParams = HttpHelper.getBodyString(repeatedlyRequest); + } + + // body参数为空,获取Parameter的数据 + if (StringUtils.isEmpty(nowParams)) + { + nowParams = JSON.toJSONString(request.getParameterMap()); + } + Map nowDataMap = new HashMap(); + nowDataMap.put(REPEAT_PARAMS, nowParams); + nowDataMap.put(REPEAT_TIME, System.currentTimeMillis()); + + // 请求地址(作为存放cache的key值) + String url = request.getRequestURI(); + + // 唯一值(没有消息头则使用请求地址) + String submitKey = StringUtils.trimToEmpty(request.getHeader(header)); + + // 唯一标识(指定key + url + 消息头) + String cacheRepeatKey = CacheConstants.REPEAT_SUBMIT_KEY + url + submitKey; + + Object sessionObj = redisCache.getCacheObject(cacheRepeatKey); + if (sessionObj != null) + { + Map sessionMap = (Map) sessionObj; + if (sessionMap.containsKey(url)) + { + Map preDataMap = (Map) sessionMap.get(url); + if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, annotation.interval())) + { + return true; + } + } + } + Map cacheMap = new HashMap(); + cacheMap.put(url, nowDataMap); + redisCache.setCacheObject(cacheRepeatKey, cacheMap, annotation.interval(), TimeUnit.MILLISECONDS); + return false; + } + + /** + * 判断参数是否相同 + */ + private boolean compareParams(Map nowMap, Map preMap) + { + String nowParams = (String) nowMap.get(REPEAT_PARAMS); + String preParams = (String) preMap.get(REPEAT_PARAMS); + return nowParams.equals(preParams); + } + + /** + * 判断两次间隔时间 + */ + private boolean compareTime(Map nowMap, Map preMap, int interval) + { + long time1 = (Long) nowMap.get(REPEAT_TIME); + long time2 = (Long) preMap.get(REPEAT_TIME); + if ((time1 - time2) < interval) + { + return true; + } + return false; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/manager/AsyncManager.java b/CSP-core/src/main/java/com/RVSmartPorting/core/manager/AsyncManager.java new file mode 100644 index 0000000000000000000000000000000000000000..9fb2d86e038a574d01615fe70e771f0866362993 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/manager/AsyncManager.java @@ -0,0 +1,64 @@ +package com.RVSmartPorting.core.manager; + +/** + * 异步任务管理器 + * + * @author ruoyi + */ + +import com.RVSmartPorting.common.utils.Threads; +import com.RVSmartPorting.common.utils.spring.SpringUtils; + +import java.util.TimerTask; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + + +/** + * 异步任务管理器 + * + * @author ruoyi + */ +public class AsyncManager +{ + /** + * 操作延迟10毫秒 + */ + private final int OPERATE_DELAY_TIME = 10; + + /** + * 异步操作任务调度线程池 + */ + private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService"); + + /** + * 单例模式 + */ + private AsyncManager(){} + + private static AsyncManager me = new AsyncManager(); + + public static AsyncManager me() + { + return me; + } + + /** + * 执行任务 + * + * @param task 任务 + */ + public void execute(TimerTask task) + { + executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS); + } + + /** + * 停止任务线程池 + */ + public void shutdown() + { + Threads.shutdownAndAwaitTermination(executor); + } +} + diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/manager/factory/AsyncFactory.java b/CSP-core/src/main/java/com/RVSmartPorting/core/manager/factory/AsyncFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..e9c5d1707ab1234c3fc9893cb1fa7d6759747a4c --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/manager/factory/AsyncFactory.java @@ -0,0 +1,105 @@ +package com.RVSmartPorting.core.manager.factory; + +/** + * 异步工厂(产生任务用) + * + * @author ruoyi + */ + +import java.util.TimerTask; + +import com.RVSmartPorting.common.constant.Constants; +import com.RVSmartPorting.common.utils.LogUtils; +import com.RVSmartPorting.common.utils.ServletUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.ip.AddressUtils; +import com.RVSmartPorting.common.utils.ip.IpUtils; +import com.RVSmartPorting.common.utils.spring.SpringUtils; +import com.RVSmartPorting.core.system.domain.SysLogininfor; +import com.RVSmartPorting.core.system.domain.SysOperLog; +import com.RVSmartPorting.core.system.service.ISysLogininforService; +import com.RVSmartPorting.core.system.service.ISysOperLogService; +import eu.bitwalker.useragentutils.UserAgent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class AsyncFactory +{ + private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user"); + + /** + * 记录登录信息 + * + * @param username 用户名 + * @param status 状态 + * @param message 消息 + * @param args 列表 + * @return 任务task + */ + public static TimerTask recordLogininfor(final String username, final String status, final String message, + final Object... args) + { + final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent")); + final String ip = IpUtils.getIpAddr(); + return new TimerTask() + { + @Override + public void run() + { + String address = AddressUtils.getRealAddressByIP(ip); + StringBuilder s = new StringBuilder(); + s.append(LogUtils.getBlock(ip)); + s.append(address); + s.append(LogUtils.getBlock(username)); + s.append(LogUtils.getBlock(status)); + s.append(LogUtils.getBlock(message)); + // 打印信息到日志 + sys_user_logger.info(s.toString(), args); + // 获取客户端操作系统 + String os = userAgent.getOperatingSystem().getName(); + // 获取客户端浏览器 + String browser = userAgent.getBrowser().getName(); + // 封装对象 + SysLogininfor logininfor = new SysLogininfor(); + logininfor.setUserName(username); + logininfor.setIpaddr(ip); + logininfor.setLoginLocation(address); + logininfor.setBrowser(browser); + logininfor.setOs(os); + logininfor.setMsg(message); + // 日志状态 + if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) + { + logininfor.setStatus(Constants.SUCCESS); + } + else if (Constants.LOGIN_FAIL.equals(status)) + { + logininfor.setStatus(Constants.FAIL); + } + // 插入数据 + SpringUtils.getBean(ISysLogininforService.class).insertLogininfor(logininfor); + } + }; + } + + /** + * 操作日志记录 + * + * @param operLog 操作日志信息 + * @return 任务task + */ + public static TimerTask recordOper(final SysOperLog operLog) + { + return new TimerTask() + { + @Override + public void run() + { + // 远程查询操作地点 + operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp())); + SpringUtils.getBean(ISysOperLogService.class).insertOperlog(operLog); + } + }; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/security/context/AuthenticationContextHolder.java b/CSP-core/src/main/java/com/RVSmartPorting/core/security/context/AuthenticationContextHolder.java new file mode 100644 index 0000000000000000000000000000000000000000..697d3d5b8510049ad23e204a004ab2f71d102ea0 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/security/context/AuthenticationContextHolder.java @@ -0,0 +1,28 @@ +package com.RVSmartPorting.core.security.context; + +import org.springframework.security.core.Authentication; + +/** + * 身份验证信息 + * + * @author ruoyi + */ +public class AuthenticationContextHolder +{ + private static final ThreadLocal contextHolder = new ThreadLocal<>(); + + public static Authentication getContext() + { + return contextHolder.get(); + } + + public static void setContext(Authentication context) + { + contextHolder.set(context); + } + + public static void clearContext() + { + contextHolder.remove(); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/security/context/PermissionContextHolder.java b/CSP-core/src/main/java/com/RVSmartPorting/core/security/context/PermissionContextHolder.java new file mode 100644 index 0000000000000000000000000000000000000000..c04bfe4fb7616c2a197cf9a70921c24e91dfe38f --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/security/context/PermissionContextHolder.java @@ -0,0 +1,27 @@ +package com.RVSmartPorting.core.security.context; + +import com.RVSmartPorting.common.core.text.Convert; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; + +/** + * 权限信息 + * + * @author ruoyi + */ +public class PermissionContextHolder +{ + private static final String PERMISSION_CONTEXT_ATTRIBUTES = "PERMISSION_CONTEXT"; + + public static void setContext(String permission) + { + RequestContextHolder.currentRequestAttributes().setAttribute(PERMISSION_CONTEXT_ATTRIBUTES, permission, + RequestAttributes.SCOPE_REQUEST); + } + + public static String getContext() + { + return Convert.toStr(RequestContextHolder.currentRequestAttributes().getAttribute(PERMISSION_CONTEXT_ATTRIBUTES, + RequestAttributes.SCOPE_REQUEST)); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/security/filter/JwtAuthenticationTokenFilter.java b/CSP-core/src/main/java/com/RVSmartPorting/core/security/filter/JwtAuthenticationTokenFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..8f67279eff8700cbb1b112e60dcf9b4a5fdede59 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/security/filter/JwtAuthenticationTokenFilter.java @@ -0,0 +1,46 @@ +package com.RVSmartPorting.core.security.filter; + +import com.RVSmartPorting.common.core.domain.model.LoginUser; +import com.RVSmartPorting.common.core.domain.model.LoginUser; +import com.RVSmartPorting.common.utils.SecurityUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.core.web.service.TokenService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * token过滤器 验证token有效性 + * + * @author ruoyi + */ +@Component +public class JwtAuthenticationTokenFilter extends OncePerRequestFilter +{ + @Autowired + private TokenService tokenService; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) + throws ServletException, IOException + { + LoginUser loginUser = tokenService.getLoginUser(request); + if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication())) + { + tokenService.verifyToken(loginUser); + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities()); + authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(authenticationToken); + } + chain.doFilter(request, response); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/security/handle/AuthenticationEntryPointImpl.java b/CSP-core/src/main/java/com/RVSmartPorting/core/security/handle/AuthenticationEntryPointImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..6cb8ad3aae3a0b575bb592cce10eb7828027df1b --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/security/handle/AuthenticationEntryPointImpl.java @@ -0,0 +1,35 @@ +package com.RVSmartPorting.core.security.handle; + +import com.alibaba.fastjson2.JSON; +import com.RVSmartPorting.common.constant.HttpStatus; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.utils.ServletUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.Serializable; + +/** + * 认证失败处理类 返回未授权 + * + * @author ruoyi + */ +@Component +public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, Serializable +{ + private static final long serialVersionUID = -8970718410437077606L; + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) + throws IOException + { + int code = HttpStatus.UNAUTHORIZED; + String msg = StringUtils.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI()); + ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(code, msg))); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/security/handle/LogoutSuccessHandlerImpl.java b/CSP-core/src/main/java/com/RVSmartPorting/core/security/handle/LogoutSuccessHandlerImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..970f8db544a70701084152dc6459ec2d18b64f9d --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/security/handle/LogoutSuccessHandlerImpl.java @@ -0,0 +1,53 @@ +package com.RVSmartPorting.core.security.handle; + +import com.RVSmartPorting.core.manager.AsyncManager; +import com.RVSmartPorting.core.manager.factory.AsyncFactory; +import com.RVSmartPorting.core.web.service.TokenService; +import com.alibaba.fastjson2.JSON; +import com.RVSmartPorting.common.constant.Constants; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.core.domain.model.LoginUser; +import com.RVSmartPorting.common.utils.ServletUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * 自定义退出处理类 返回成功 + * + * @author ruoyi + */ +@Configuration +public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler +{ + @Autowired + private TokenService tokenService; + + /** + * 退出处理 + * + * @return + */ + @Override + public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) + throws IOException, ServletException + { + LoginUser loginUser = tokenService.getLoginUser(request); + if (StringUtils.isNotNull(loginUser)) + { + String userName = loginUser.getUsername(); + // 删除用户缓存记录 + tokenService.delLoginUser(loginUser.getToken()); + // 记录用户退出日志 + AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, "退出成功")); + } + ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.success("退出成功"))); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/CodeProject.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/CodeProject.java new file mode 100644 index 0000000000000000000000000000000000000000..7bd3b30375f3d987697b27f4f074f451c08f7e87 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/CodeProject.java @@ -0,0 +1,96 @@ +package com.RVSmartPorting.core.system.domain; + +import com.RVSmartPorting.common.annotation.Excel; +import com.RVSmartPorting.common.core.domain.BaseEntity; +import lombok.Data; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.ibatis.type.Alias; + +import java.sql.Timestamp; + +/** + * 代码项目信息对象 code_project + * + * @author xuqiangli + * @date 2023-08-24 + */ +@Alias("CodeProject") +@Data +public class CodeProject extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 代码项目唯一标识 */ + private Long codeProjectId; + + /** 项目名称 */ + @Excel(name = "项目名称") + private String projectName; + + /** 项目描述 */ + @Excel(name = "项目描述") + private String projectDescription; + + /** 项目类型 */ + @Excel(name = "项目类型") + private String projectType; + + /** 项目成员 */ + @Excel(name = "项目成员") + private String projectMembers; + + /** 项目标签 */ + @Excel(name = "项目标签") + private String projectLabels; + + /** 项目图标 */ + @Excel(name = "项目图标") + private String projectIcon; + + /** 关联用户id */ + @Excel(name = "关联用户id") + private Long userId; + + /** 代码存储服务器缓存路径 */ + @Excel(name = "代码存储服务器缓存路径") + private String codeCachePath; + + /** 代码存储hdfs路径 */ + @Excel(name = "代码存储hdfs路径") + private String hdfsPath; + + /** 代码上传类型(0: 代码仓库clone, 1: 本地上传压缩包, 2: FTP上传) */ + @Excel(name = "代码上传类型", readConverterExp = "0: 代码仓库clone,1: 本地上传压缩包,2:FTP上传") + private Long codeUploadType; + + /** 代码仓库类型(gitee、github等) */ + @Excel(name = "代码仓库类型", readConverterExp = "gitee、github等") + private String codeRepoType; + + /** 代码仓库地址 */ + @Excel(name = "代码仓库地址", readConverterExp = "https://gitee.com/rvsmart-porting/code-scanning-platform.git") + private String codeRepoUrl; + + /** 代码分支名 */ + @Excel(name = "代码分支名") + private String codeBranch; + + /** 代码仓库账户名 */ + @Excel(name = "代码仓库账户名") + private String codeRepoUsername; + + /** 代码仓库密码 */ + @Excel(name = "代码仓库密码") + private String codeRepoPassword; + + /** 删除标志(0: 存在, 2: 删除) */ + private String delFlag; + + /** projectUUID */ + private String projectUUID; + + /** 代码上传时间戳 */ + private Timestamp uploadTimeStamp; + +} \ No newline at end of file diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/GitNetworkSetting.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/GitNetworkSetting.java new file mode 100644 index 0000000000000000000000000000000000000000..085c8045b820e5d46ec167b8a194f96a16c2f54b --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/GitNetworkSetting.java @@ -0,0 +1,126 @@ +package com.RVSmartPorting.core.system.domain; + +import com.RVSmartPorting.common.annotation.Excel; +import com.RVSmartPorting.common.core.domain.BaseEntity; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.ibatis.type.Alias; + +/** + * git网络镜像代理配置对象 git_network_setting + * + * @author ruoyi + * @date 2023-09-09 + */ +@Alias("GitNetworkSetting") +public class GitNetworkSetting extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** Git网络设置ID */ + private Long gitNetworkSettingId; + + /** 域名 */ + @Excel(name = "域名") + private String domain; + + /** 镜像类型或代理类型 */ + @Excel(name = "镜像类型或代理类型") + private String type; + + /** 镜像地址或代理地址 */ + @Excel(name = "镜像地址或代理地址") + private String url; + + /** 地址规则,用于构建实际的镜像地址 */ + @Excel(name = "地址规则,用于构建实际的镜像地址") + private String addressRule; + + /** 是否启用(0正常 1停用) */ + @Excel(name = "是否启用", readConverterExp = "0=正常,1=停用") + private String status; + + /** 删除标志(0代表存在 2代表删除) */ + private String delFlag; + + public void setGitNetworkSettingId(Long gitNetworkSettingId) + { + this.gitNetworkSettingId = gitNetworkSettingId; + } + + public Long getGitNetworkSettingId() + { + return gitNetworkSettingId; + } + public void setDomain(String domain) + { + this.domain = domain; + } + + public String getDomain() + { + return domain; + } + public void setType(String type) + { + this.type = type; + } + + public String getType() + { + return type; + } + public void setUrl(String url) + { + this.url = url; + } + + public String getUrl() + { + return url; + } + public void setAddressRule(String addressRule) + { + this.addressRule = addressRule; + } + + public String getAddressRule() + { + return addressRule; + } + public void setStatus(String status) + { + this.status = status; + } + + public String getStatus() + { + return status; + } + public void setDelFlag(String delFlag) + { + this.delFlag = delFlag; + } + + public String getDelFlag() + { + return delFlag; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("gitNetworkSettingId", getGitNetworkSettingId()) + .append("domain", getDomain()) + .append("type", getType()) + .append("url", getUrl()) + .append("addressRule", getAddressRule()) + .append("status", getStatus()) + .append("delFlag", getDelFlag()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .toString(); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/Rule.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/Rule.java new file mode 100644 index 0000000000000000000000000000000000000000..2b56b194320287ac38098cba4f4d89df5c0d4476 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/Rule.java @@ -0,0 +1,156 @@ +package com.RVSmartPorting.core.system.domain; + +import com.RVSmartPorting.common.annotation.Excel; +import com.RVSmartPorting.common.core.domain.BaseEntity; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.ibatis.type.Alias; + +/** + * 规则信息对象 rule + * + * @author ruoyi + * @date 2023-08-15 + */ +@Alias("Rule") +public class Rule extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 规则唯一标识 */ + private Long ruleId; + + /** 规则名 */ + @Excel(name = "规则名") + private String name; + + /** 规则所涉及的语言 */ + @Excel(name = "规则所涉及的语言") + private String language; + + /** 规则用户标签 */ + @Excel(name = "规则用户标签") + private String userTag; + + /** 规则描述 */ + @Excel(name = "规则描述") + private String comments; + + /** 正确示例 */ + @Excel(name = "正确示例") + private String goodExample; + + /** 错误示例 */ + @Excel(name = "错误示例") + private String badExample; + + /** 修复建议 */ + @Excel(name = "修复建议") + private String recommend; + + /** 规则严重等级 */ + @Excel(name = "规则严重等级") + private Long severity; + + public void setRuleId(Long ruleId) + { + this.ruleId = ruleId; + } + + public Long getRuleId() + { + return ruleId; + } + public void setName(String name) + { + this.name = name; + } + + public String getName() + { + return name; + } + public void setLanguage(String language) + { + this.language = language; + } + + public String getLanguage() + { + return language; + } + public void setUserTag(String userTag) + { + this.userTag = userTag; + } + + public String getUserTag() + { + return userTag; + } + public void setComments(String comments) + { + this.comments = comments; + } + + public String getComments() + { + return comments; + } + public void setGoodExample(String goodExample) + { + this.goodExample = goodExample; + } + + public String getGoodExample() + { + return goodExample; + } + public void setBadExample(String badExample) + { + this.badExample = badExample; + } + + public String getBadExample() + { + return badExample; + } + public void setRecommend(String recommend) + { + this.recommend = recommend; + } + + public String getRecommend() + { + return recommend; + } + public void setSeverity(Long severity) + { + this.severity = severity; + } + + public Long getSeverity() + { + return severity; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("ruleId", getRuleId()) + .append("name", getName()) + .append("language", getLanguage()) + .append("userTag", getUserTag()) + .append("comments", getComments()) + .append("goodExample", getGoodExample()) + .append("badExample", getBadExample()) + .append("recommend", getRecommend()) + .append("severity", getSeverity()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/RuleSet.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/RuleSet.java new file mode 100644 index 0000000000000000000000000000000000000000..c0c7b7cc47986c303dde43ddc3232ad7261511fd --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/RuleSet.java @@ -0,0 +1,47 @@ +package com.RVSmartPorting.core.system.domain; + +import com.RVSmartPorting.common.annotation.Excel; +import com.RVSmartPorting.common.core.domain.BaseEntity; +import lombok.Data; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.ibatis.type.Alias; + +import java.util.List; + +/** + * 规则集信息对象 rule_set + * + * @author ruoyi + * @date 2023-08-16 + */ +@Alias("RuleSet") +@Data +public class RuleSet extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 规则集的唯一标识 */ + private Long ruleSetId; + + /** 规则集名称 */ + @Excel(name = "规则集名称") + private String name; + + /** 语言 */ + @Excel(name = "语言") + private String language; + + /** 描述 */ + @Excel(name = "描述") + private String comments; + + /** 规则集类型 */ + @Excel(name = "规则集类型") + private String type; + + private Long rulesCount; + + private List ruleList; + +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/RuleSet2Rule.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/RuleSet2Rule.java new file mode 100644 index 0000000000000000000000000000000000000000..2ebdc34f1e439155b7e44a0b8a59a3a32bd68b00 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/RuleSet2Rule.java @@ -0,0 +1,20 @@ +package com.RVSmartPorting.core.system.domain; + +import lombok.Data; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.ibatis.type.Alias; + +/** + * @author xuqiangli + * @create 2023-08-18 11:11 + */ +@Alias("RuleSet2Rule") +@Data +public class RuleSet2Rule { + /** 规则集ID */ + private Long ruleSetId; + + /** 规则ID */ + private Long ruleId; +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/ScanTask.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/ScanTask.java new file mode 100644 index 0000000000000000000000000000000000000000..872862db5b512b979ee0f58972c980ac30adb3a5 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/ScanTask.java @@ -0,0 +1,401 @@ +package com.RVSmartPorting.core.system.domain; + +import com.RVSmartPorting.common.annotation.Excel; +import com.RVSmartPorting.common.core.domain.BaseEntity; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.ibatis.type.Alias; + +import java.util.Date; + +/** + * 代码扫描任务信息对象 scan_task + * + * @author ruoyi + * @date 2023-09-17 + */ +@Alias("ScanTask") +@Data +public class ScanTask extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** 任务唯一标识符 */ + private Long taskId; + + /** 任务名称 */ + @Excel(name = "任务名称") + private String taskName; + + /** 扫描工具选择 */ + @Excel(name = "扫描工具选择") + private String toolSelection; + + /** 规则集选择 */ + @Excel(name = "规则集选择") + private String ruleSet; + + /** 规则配置文件类型 */ + @Excel(name = "规则配置文件类型") + private String ruleSetType; + + /** 关联扫描工具 ID */ + @Excel(name = "关联扫描工具 ID") + private Long scanToolId; + + ScanTool scanTool; + + /** 扫描参数 */ + @Excel(name = "扫描参数") + private String scanParameters; + + /** 扫描开始时间 */ + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "扫描开始时间", width = 30, dateFormat = "yyyy-MM-dd") + private Date scanStartTime; + + /** 扫描结束时间 */ + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "扫描结束时间", width = 30, dateFormat = "yyyy-MM-dd") + private Date scanEndTime; + + /** 任务状态 */ + @Excel(name = "任务状态") + private String taskStatus; + + /** 扫描结果 */ + @Excel(name = "扫描结果") + private String scanResults; + + /** 上报凭证 */ + @Excel(name = "上报凭证") + private String reportingCredentials; + + /** 任务负责人 */ + @Excel(name = "任务负责人") + private String taskOwner; + + /** 任务描述 */ + @Excel(name = "任务描述") + private String taskDescription; + + /** 任务优先级 */ + @Excel(name = "任务优先级") + private String taskPriority; + + /** 任务进度 */ + @Excel(name = "任务进度") + private Long taskProgress; + + /** 扫描报告路径 */ + @Excel(name = "扫描报告路径") + private String scanReportPath; + + /** scan-server的扫描报告路径 */ + @Excel(name = "scan-server的扫描报告路径") + private String scanServerScanReportPath; + + /** 任务日志 */ + @Excel(name = "任务日志") + private String taskLogs; + + /** 扫描任务日志文件存储路径 */ + @Excel(name = "扫描任务日志文件存储路径") + private String taskLogPath; + + /** scan-server的日志文件存储路径 */ + @Excel(name = "scan-server的日志文件存储路径") + private String scanServerTaskLogPath; + + /** 附件 */ + @Excel(name = "附件") + private String attachments; + + /** 关联用户 ID */ + @Excel(name = "关联用户 ID") + private Long userId; + + /** 调度任务id */ + @Excel(name = "调度任务id") + private Long jobId; + + /** 扫描任务语言 */ + @Excel(name = "扫描任务语言") + private String languages; + + /** 任务实例id */ + @Excel(name = "任务实例id") + private Long instanceId; + + /** 关联项目代码 ID */ + @Excel(name = "关联项目代码 ID") + private Long codeProjectId; + + CodeProject codeProject; + + /** 任务创建时间 */ + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "任务创建时间", width = 30, dateFormat = "yyyy-MM-dd") + private Date taskCreatedAt; + + /** 任务更新时间 */ + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "任务更新时间", width = 30, dateFormat = "yyyy-MM-dd") + private Date taskUpdatedAt; + + /** 删除标志(0: 存在, 2: 删除) */ + private String delFlag; + + public void setTaskId(Long taskId) + { + this.taskId = taskId; + } + + public Long getTaskId() + { + return taskId; + } + public void setTaskName(String taskName) + { + this.taskName = taskName; + } + + public String getTaskName() + { + return taskName; + } + public void setToolSelection(String toolSelection) + { + this.toolSelection = toolSelection; + } + + public String getToolSelection() + { + return toolSelection; + } + public void setRuleSet(String ruleSet) + { + this.ruleSet = ruleSet; + } + + public String getRuleSet() + { + return ruleSet; + } + public void setRuleSetType(String ruleSetType) + { + this.ruleSetType = ruleSetType; + } + + public String getRuleSetType() + { + return ruleSetType; + } + public void setScanToolId(Long scanToolId) + { + this.scanToolId = scanToolId; + } + + public Long getScanToolId() + { + return scanToolId; + } + public void setScanParameters(String scanParameters) + { + this.scanParameters = scanParameters; + } + + public String getScanParameters() + { + return scanParameters; + } + public void setScanStartTime(Date scanStartTime) + { + this.scanStartTime = scanStartTime; + } + + public Date getScanStartTime() + { + return scanStartTime; + } + public void setScanEndTime(Date scanEndTime) + { + this.scanEndTime = scanEndTime; + } + + public Date getScanEndTime() + { + return scanEndTime; + } + public void setTaskStatus(String taskStatus) + { + this.taskStatus = taskStatus; + } + + public String getTaskStatus() + { + return taskStatus; + } + public void setScanResults(String scanResults) + { + this.scanResults = scanResults; + } + + public String getScanResults() + { + return scanResults; + } + public void setReportingCredentials(String reportingCredentials) + { + this.reportingCredentials = reportingCredentials; + } + + public String getReportingCredentials() + { + return reportingCredentials; + } + public void setTaskOwner(String taskOwner) + { + this.taskOwner = taskOwner; + } + + public String getTaskOwner() + { + return taskOwner; + } + public void setTaskDescription(String taskDescription) + { + this.taskDescription = taskDescription; + } + + public String getTaskDescription() + { + return taskDescription; + } + public void setTaskPriority(String taskPriority) + { + this.taskPriority = taskPriority; + } + + public String getTaskPriority() + { + return taskPriority; + } + public void setTaskProgress(Long taskProgress) + { + this.taskProgress = taskProgress; + } + + public Long getTaskProgress() + { + return taskProgress; + } + public void setScanReportPath(String scanReportPath) + { + this.scanReportPath = scanReportPath; + } + + public String getScanReportPath() + { + return scanReportPath; + } + public void setTaskLogs(String taskLogs) + { + this.taskLogs = taskLogs; + } + + public String getTaskLogs() + { + return taskLogs; + } + public void setAttachments(String attachments) + { + this.attachments = attachments; + } + + public String getAttachments() + { + return attachments; + } + public void setUserId(Long userId) + { + this.userId = userId; + } + + public Long getUserId() + { + return userId; + } + public void setCodeProjectId(Long codeProjectId) + { + this.codeProjectId = codeProjectId; + } + + public Long getCodeProjectId() + { + return codeProjectId; + } + public void setTaskCreatedAt(Date taskCreatedAt) + { + this.taskCreatedAt = taskCreatedAt; + } + + public Date getTaskCreatedAt() + { + return taskCreatedAt; + } + public void setTaskUpdatedAt(Date taskUpdatedAt) + { + this.taskUpdatedAt = taskUpdatedAt; + } + + public Date getTaskUpdatedAt() + { + return taskUpdatedAt; + } + public void setDelFlag(String delFlag) + { + this.delFlag = delFlag; + } + + public String getDelFlag() + { + return delFlag; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("taskId", getTaskId()) + .append("taskName", getTaskName()) + .append("toolSelection", getToolSelection()) + .append("ruleSet", getRuleSet()) + .append("ruleSetType", getRuleSetType()) + .append("scanToolId", getScanToolId()) + .append("scanParameters", getScanParameters()) + .append("scanStartTime", getScanStartTime()) + .append("scanEndTime", getScanEndTime()) + .append("taskStatus", getTaskStatus()) + .append("scanResults", getScanResults()) + .append("reportingCredentials", getReportingCredentials()) + .append("taskOwner", getTaskOwner()) + .append("taskDescription", getTaskDescription()) + .append("taskPriority", getTaskPriority()) + .append("taskProgress", getTaskProgress()) + .append("scanReportPath", getScanReportPath()) + .append("taskLogs", getTaskLogs()) + .append("attachments", getAttachments()) + .append("userId", getUserId()) + .append("codeProjectId", getCodeProjectId()) + .append("taskCreatedAt", getTaskCreatedAt()) + .append("taskUpdatedAt", getTaskUpdatedAt()) + .append("delFlag", getDelFlag()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/ScanTool.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/ScanTool.java new file mode 100644 index 0000000000000000000000000000000000000000..1cf74d9173b82a8b4a51d859e6e158df900c927c --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/ScanTool.java @@ -0,0 +1,252 @@ +package com.RVSmartPorting.core.system.domain; + +import com.RVSmartPorting.common.annotation.Excel; +import com.RVSmartPorting.common.core.domain.BaseEntity; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.ibatis.type.Alias; + +/** + * 扫描工具对象 scan_tool + * + * @author ruoyi + * @date 2023-09-23 + */ +@Alias("ScanTool") +public class ScanTool extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 扫描工具ID */ + private Long scanToolId; + + /** 扫描工具的名称 */ + @Excel(name = "扫描工具的名称") + private String toolName; + + /** 扫描工具的版本号 */ + @Excel(name = "扫描工具的版本号") + private String toolVersion; + + /** 扫描工具的描述 */ + @Excel(name = "扫描工具的描述") + private String toolDescription; + + /** 配置文件的存储路径 */ + @Excel(name = "配置文件的存储路径") + private String configurationFilePath; + + /** 使用的规则集 */ + @Excel(name = "使用的规则集") + private String ruleSet; + + /** 规则配置文件类型 */ + @Excel(name = "规则配置文件类型") + private String ruleSetType; + + /** 扫描的目标,可以是文件路径或项目标识 */ + @Excel(name = "扫描的目标,可以是文件路径或项目标识") + private String scanTarget; + + /** 扫描参数,用于指定详细选项和设置 */ + @Excel(name = "扫描参数,用于指定详细选项和设置") + private String scanParameters; + + /** 扫描结果输出路径 */ + @Excel(name = "扫描结果输出路径") + private String scanOutputPath; + + /** 通知设置,例如邮件地址或 Webhook URL */ + @Excel(name = "通知设置,例如邮件地址或 Webhook URL") + private String notificationSettings; + + /** 扫描工具支持的编程语言(一种或多种) */ + @Excel(name = "扫描工具支持的编程语言", readConverterExp = "一=种或多种") + private String supportedLanguages; + + /** 容器启动额外参数 */ + @Excel(name = "容器启动额外参数") + private String containerStartupParams; + + /** 镜像源地址及版本 */ + @Excel(name = "镜像源地址及版本") + private String imageSource; + + /** docker-compose 配置文件模板 */ + @Excel(name = "docker-compose 配置文件模板") + private String dockerComposeTemplate; + + /** 删除标志(0代表存在 2代表删除) */ + private String delFlag; + + public void setScanToolId(Long scanToolId) + { + this.scanToolId = scanToolId; + } + + public Long getScanToolId() + { + return scanToolId; + } + public void setToolName(String toolName) + { + this.toolName = toolName; + } + + public String getToolName() + { + return toolName; + } + public void setToolVersion(String toolVersion) + { + this.toolVersion = toolVersion; + } + + public String getToolVersion() + { + return toolVersion; + } + public void setToolDescription(String toolDescription) + { + this.toolDescription = toolDescription; + } + + public String getToolDescription() + { + return toolDescription; + } + public void setConfigurationFilePath(String configurationFilePath) + { + this.configurationFilePath = configurationFilePath; + } + + public String getConfigurationFilePath() + { + return configurationFilePath; + } + public void setRuleSet(String ruleSet) + { + this.ruleSet = ruleSet; + } + + public String getRuleSet() + { + return ruleSet; + } + public void setRuleSetType(String ruleSetType) + { + this.ruleSetType = ruleSetType; + } + + public String getRuleSetType() + { + return ruleSetType; + } + public void setScanTarget(String scanTarget) + { + this.scanTarget = scanTarget; + } + + public String getScanTarget() + { + return scanTarget; + } + public void setScanParameters(String scanParameters) + { + this.scanParameters = scanParameters; + } + + public String getScanParameters() + { + return scanParameters; + } + public void setScanOutputPath(String scanOutputPath) + { + this.scanOutputPath = scanOutputPath; + } + + public String getScanOutputPath() + { + return scanOutputPath; + } + public void setNotificationSettings(String notificationSettings) + { + this.notificationSettings = notificationSettings; + } + + public String getNotificationSettings() + { + return notificationSettings; + } + public void setSupportedLanguages(String supportedLanguages) + { + this.supportedLanguages = supportedLanguages; + } + + public String getSupportedLanguages() + { + return supportedLanguages; + } + public void setContainerStartupParams(String containerStartupParams) + { + this.containerStartupParams = containerStartupParams; + } + + public String getContainerStartupParams() + { + return containerStartupParams; + } + public void setImageSource(String imageSource) + { + this.imageSource = imageSource; + } + + public String getImageSource() + { + return imageSource; + } + public void setDockerComposeTemplate(String dockerComposeTemplate) + { + this.dockerComposeTemplate = dockerComposeTemplate; + } + + public String getDockerComposeTemplate() + { + return dockerComposeTemplate; + } + public void setDelFlag(String delFlag) + { + this.delFlag = delFlag; + } + + public String getDelFlag() + { + return delFlag; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("scanToolId", getScanToolId()) + .append("toolName", getToolName()) + .append("toolVersion", getToolVersion()) + .append("toolDescription", getToolDescription()) + .append("configurationFilePath", getConfigurationFilePath()) + .append("ruleSet", getRuleSet()) + .append("ruleSetType", getRuleSetType()) + .append("scanTarget", getScanTarget()) + .append("scanParameters", getScanParameters()) + .append("scanOutputPath", getScanOutputPath()) + .append("notificationSettings", getNotificationSettings()) + .append("supportedLanguages", getSupportedLanguages()) + .append("containerStartupParams", getContainerStartupParams()) + .append("imageSource", getImageSource()) + .append("dockerComposeTemplate", getDockerComposeTemplate()) + .append("delFlag", getDelFlag()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .toString(); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/ScanToolConfig.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/ScanToolConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..10c104a1812a71327589cf076ff57bef63c87f56 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/ScanToolConfig.java @@ -0,0 +1,200 @@ +package com.RVSmartPorting.core.system.domain; + +import com.RVSmartPorting.common.annotation.Excel; +import com.RVSmartPorting.common.core.domain.BaseEntity; +import lombok.Data; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import java.util.List; + +/** + * 扫描工具配置对象 scan_tool_config + * + * @author xuqiangli + * @date 2023-09-22 + */ +@Data +public class ScanToolConfig extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 扫描工具配置项ID */ + private Long scanToolConfigId; + + /** 是否开放给用户自定义,1表示是,0表示否 */ + @Excel(name = "是否开放给用户自定义,1表示是,0表示否") + private String customizableEnabled; + + /** 配置显示名称 */ + @Excel(name = "配置显示名称") + private String displayName; + + /** 配置原始名称(对应扫描工具中配置的原始名称) */ + @Excel(name = "配置原始名称", readConverterExp = "对=应扫描工具中配置的原始名称") + private String configName; + + /** 配置变量名称(作为环境变量传入扫描工具容器时的名称) */ + @Excel(name = "配置变量名称", readConverterExp = "作=为环境变量传入扫描工具容器时的名称") + private String variableName; + + /** 配置类型,可选值:布尔值 / 整数 / 枚举单选 / 枚举多选 / 字符串 */ + @Excel(name = "配置类型,可选值:布尔值 / 整数 / 枚举单选 / 枚举多选 / 字符串") + private String configType; + + /** 配置类型额外参数(仅当配置类型为枚举单选 / 枚举多选时生效),存储为JSON格式 */ + @Excel(name = "配置类型额外参数", readConverterExp = "仅=当配置类型为枚举单选,/=,枚=举多选时生效") + private String enumOptions; + + List enumOptionList; + + /** 配置值检查表达式(仅当配置类型为整数 / 字符串时生效) */ + @Excel(name = "配置值检查表达式", readConverterExp = "仅=当配置类型为整数,/=,字=符串时生效") + private String configValueCheckExpression; + + /** 配置默认值 */ + @Excel(name = "配置默认值") + private String defaultValue; + + /** 配置默认是否启用,1表示是,0表示否 */ + @Excel(name = "配置默认是否启用,1表示是,0表示否") + private String defaultEnabled; + + /** 关联配置项ID,当且仅当对应的配置启用时,该配置才可被启用 */ + @Excel(name = "关联配置项ID,当且仅当对应的配置启用时,该配置才可被启用") + private Long associatedConfigId; + + /** 删除标志(0代表存在 2代表删除) */ + private String delFlag; + + public void setScanToolConfigId(Long scanToolConfigId) + { + this.scanToolConfigId = scanToolConfigId; + } + + public Long getScanToolConfigId() + { + return scanToolConfigId; + } + public void setCustomizableEnabled(String customizableEnabled) + { + this.customizableEnabled = customizableEnabled; + } + + public String getCustomizableEnabled() + { + return customizableEnabled; + } + public void setDisplayName(String displayName) + { + this.displayName = displayName; + } + + public String getDisplayName() + { + return displayName; + } + public void setConfigName(String configName) + { + this.configName = configName; + } + + public String getConfigName() + { + return configName; + } + public void setVariableName(String variableName) + { + this.variableName = variableName; + } + + public String getVariableName() + { + return variableName; + } + public void setConfigType(String configType) + { + this.configType = configType; + } + + public String getConfigType() + { + return configType; + } + public void setEnumOptions(String enumOptions) + { + this.enumOptions = enumOptions; + } + + public String getEnumOptions() + { + return enumOptions; + } + public void setConfigValueCheckExpression(String configValueCheckExpression) + { + this.configValueCheckExpression = configValueCheckExpression; + } + + public String getConfigValueCheckExpression() + { + return configValueCheckExpression; + } + public void setDefaultValue(String defaultValue) + { + this.defaultValue = defaultValue; + } + + public String getDefaultValue() + { + return defaultValue; + } + public void setDefaultEnabled(String defaultEnabled) + { + this.defaultEnabled = defaultEnabled; + } + + public String getDefaultEnabled() + { + return defaultEnabled; + } + public void setAssociatedConfigId(Long associatedConfigId) + { + this.associatedConfigId = associatedConfigId; + } + + public Long getAssociatedConfigId() + { + return associatedConfigId; + } + public void setDelFlag(String delFlag) + { + this.delFlag = delFlag; + } + + public String getDelFlag() + { + return delFlag; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("scanToolConfigId", getScanToolConfigId()) + .append("customizableEnabled", getCustomizableEnabled()) + .append("displayName", getDisplayName()) + .append("configName", getConfigName()) + .append("variableName", getVariableName()) + .append("configType", getConfigType()) + .append("enumOptions", getEnumOptions()) + .append("configValueCheckExpression", getConfigValueCheckExpression()) + .append("defaultValue", getDefaultValue()) + .append("defaultEnabled", getDefaultEnabled()) + .append("associatedConfigId", getAssociatedConfigId()) + .append("delFlag", getDelFlag()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .toString(); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysCache.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysCache.java new file mode 100644 index 0000000000000000000000000000000000000000..f34351f39214f6d11b58036fe5cb479e9e119c78 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysCache.java @@ -0,0 +1,83 @@ +package com.RVSmartPorting.core.system.domain; + +import com.RVSmartPorting.common.utils.StringUtils; +import org.apache.ibatis.type.Alias; + +/** + * 缓存信息 + * + * @author ruoyi + */ +//@Alias("SysCache") +public class SysCache +{ + /** 缓存名称 */ + private String cacheName = ""; + + /** 缓存键名 */ + private String cacheKey = ""; + + /** 缓存内容 */ + private String cacheValue = ""; + + /** 备注 */ + private String remark = ""; + + public SysCache() + { + + } + + 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; + } + + public String getCacheName() + { + return cacheName; + } + + public void setCacheName(String cacheName) + { + this.cacheName = cacheName; + } + + public String getCacheKey() + { + return cacheKey; + } + + public void setCacheKey(String cacheKey) + { + this.cacheKey = cacheKey; + } + + public String getCacheValue() + { + return cacheValue; + } + + public void setCacheValue(String cacheValue) + { + this.cacheValue = cacheValue; + } + + public String getRemark() + { + return remark; + } + + public void setRemark(String remark) + { + this.remark = remark; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysConfig.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..e70fb7d7a17c0fc7952e5d33ea98840804775028 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysConfig.java @@ -0,0 +1,114 @@ +package com.RVSmartPorting.core.system.domain; + +import com.RVSmartPorting.common.annotation.Excel; +import com.RVSmartPorting.common.annotation.Excel.ColumnType; +import com.RVSmartPorting.common.core.domain.BaseEntity; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.ibatis.type.Alias; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; + +/** + * 参数配置表 sys_config + * + * @author ruoyi + */ +@Alias("SysConfig") +public class SysConfig extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 参数主键 */ + @Excel(name = "参数主键", cellType = ColumnType.NUMERIC) + private Long configId; + + /** 参数名称 */ + @Excel(name = "参数名称") + private String configName; + + /** 参数键名 */ + @Excel(name = "参数键名") + private String configKey; + + /** 参数键值 */ + @Excel(name = "参数键值") + private String configValue; + + /** 系统内置(Y是 N否) */ + @Excel(name = "系统内置", readConverterExp = "Y=是,N=否") + private String configType; + + public Long getConfigId() + { + return configId; + } + + public void setConfigId(Long configId) + { + this.configId = configId; + } + + @NotBlank(message = "参数名称不能为空") + @Size(min = 0, max = 100, message = "参数名称不能超过100个字符") + public String getConfigName() + { + return configName; + } + + public void setConfigName(String configName) + { + this.configName = configName; + } + + @NotBlank(message = "参数键名长度不能为空") + @Size(min = 0, max = 100, message = "参数键名长度不能超过100个字符") + public String getConfigKey() + { + return configKey; + } + + public void setConfigKey(String configKey) + { + this.configKey = configKey; + } + +// @NotBlank(message = "参数键值不能为空") + @Size(min = 0, max = 500, message = "参数键值长度不能超过500个字符") + public String getConfigValue() + { + return configValue; + } + + public void setConfigValue(String configValue) + { + this.configValue = configValue; + } + + public String getConfigType() + { + return configType; + } + + public void setConfigType(String configType) + { + this.configType = configType; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("configId", getConfigId()) + .append("configName", getConfigName()) + .append("configKey", getConfigKey()) + .append("configValue", getConfigValue()) + .append("configType", getConfigType()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysLogininfor.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysLogininfor.java new file mode 100644 index 0000000000000000000000000000000000000000..695e8777db9fc9fb2aaf5621b86242972b751960 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysLogininfor.java @@ -0,0 +1,147 @@ +package com.RVSmartPorting.core.system.domain; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.RVSmartPorting.common.annotation.Excel; +import com.RVSmartPorting.common.annotation.Excel.ColumnType; +import com.RVSmartPorting.common.core.domain.BaseEntity; +import org.apache.ibatis.type.Alias; + +import java.util.Date; + +/** + * 系统访问记录表 sys_logininfor + * + * @author ruoyi + */ +@Alias("SysLogininfor") +public class SysLogininfor extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** ID */ + @Excel(name = "序号", cellType = ColumnType.NUMERIC) + private Long infoId; + + /** 用户账号 */ + @Excel(name = "用户账号") + private String userName; + + /** 登录状态 0成功 1失败 */ + @Excel(name = "登录状态", readConverterExp = "0=成功,1=失败") + private String status; + + /** 登录IP地址 */ + @Excel(name = "登录地址") + private String ipaddr; + + /** 登录地点 */ + @Excel(name = "登录地点") + private String loginLocation; + + /** 浏览器类型 */ + @Excel(name = "浏览器") + private String browser; + + /** 操作系统 */ + @Excel(name = "操作系统") + private String os; + + /** 提示消息 */ + @Excel(name = "提示消息") + private String msg; + + /** 访问时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "访问时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date loginTime; + + public Long getInfoId() + { + return infoId; + } + + public void setInfoId(Long infoId) + { + this.infoId = infoId; + } + + public String getUserName() + { + return userName; + } + + public void setUserName(String userName) + { + this.userName = userName; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + public String getIpaddr() + { + return ipaddr; + } + + public void setIpaddr(String ipaddr) + { + this.ipaddr = ipaddr; + } + + public String getLoginLocation() + { + return loginLocation; + } + + public void setLoginLocation(String loginLocation) + { + this.loginLocation = loginLocation; + } + + public String getBrowser() + { + return browser; + } + + public void setBrowser(String browser) + { + this.browser = browser; + } + + public String getOs() + { + return os; + } + + public void setOs(String os) + { + this.os = os; + } + + public String getMsg() + { + return msg; + } + + public void setMsg(String msg) + { + this.msg = msg; + } + + public Date getLoginTime() + { + return loginTime; + } + + public void setLoginTime(Date loginTime) + { + this.loginTime = loginTime; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysNotice.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysNotice.java new file mode 100644 index 0000000000000000000000000000000000000000..1b9b78ccebf5cdafd85afa63277b51b3990ae2e6 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysNotice.java @@ -0,0 +1,105 @@ +package com.RVSmartPorting.core.system.domain; + +import com.RVSmartPorting.common.core.domain.BaseEntity; +import com.RVSmartPorting.common.xss.Xss; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.ibatis.type.Alias; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; + +/** + * 通知公告表 sys_notice + * + * @author ruoyi + */ +@Alias("SysNotice") +public class SysNotice extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 公告ID */ + private Long noticeId; + + /** 公告标题 */ + private String noticeTitle; + + /** 公告类型(1通知 2公告) */ + private String noticeType; + + /** 公告内容 */ + private String noticeContent; + + /** 公告状态(0正常 1关闭) */ + private String status; + + public Long getNoticeId() + { + return noticeId; + } + + public void setNoticeId(Long noticeId) + { + this.noticeId = noticeId; + } + + public void setNoticeTitle(String noticeTitle) + { + this.noticeTitle = noticeTitle; + } + + @Xss(message = "公告标题不能包含脚本字符") + @NotBlank(message = "公告标题不能为空") + @Size(min = 0, max = 50, message = "公告标题不能超过50个字符") + public String getNoticeTitle() + { + return noticeTitle; + } + + public void setNoticeType(String noticeType) + { + this.noticeType = noticeType; + } + + public String getNoticeType() + { + return noticeType; + } + + public void setNoticeContent(String noticeContent) + { + this.noticeContent = noticeContent; + } + + public String getNoticeContent() + { + return noticeContent; + } + + public void setStatus(String status) + { + this.status = status; + } + + public String getStatus() + { + return status; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("noticeId", getNoticeId()) + .append("noticeTitle", getNoticeTitle()) + .append("noticeType", getNoticeType()) + .append("noticeContent", getNoticeContent()) + .append("status", getStatus()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysOperLog.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysOperLog.java new file mode 100644 index 0000000000000000000000000000000000000000..2c9357625cbd69b2e0504aa8658217024eecabb5 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysOperLog.java @@ -0,0 +1,272 @@ +package com.RVSmartPorting.core.system.domain; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.RVSmartPorting.common.annotation.Excel; +import com.RVSmartPorting.common.annotation.Excel.ColumnType; +import com.RVSmartPorting.common.core.domain.BaseEntity; +import org.apache.ibatis.type.Alias; + +import java.util.Date; + +/** + * 操作日志记录表 oper_log + * + * @author ruoyi + */ +@Alias("SysOperLog") +public class SysOperLog extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 日志主键 */ + @Excel(name = "操作序号", cellType = ColumnType.NUMERIC) + private Long operId; + + /** 操作模块 */ + @Excel(name = "操作模块") + private String title; + + /** 业务类型(0其它 1新增 2修改 3删除) */ + @Excel(name = "业务类型", readConverterExp = "0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据") + private Integer businessType; + + /** 业务类型数组 */ + private Integer[] businessTypes; + + /** 请求方法 */ + @Excel(name = "请求方法") + private String method; + + /** 请求方式 */ + @Excel(name = "请求方式") + private String requestMethod; + + /** 操作类别(0其它 1后台用户 2手机端用户) */ + @Excel(name = "操作类别", readConverterExp = "0=其它,1=后台用户,2=手机端用户") + private Integer operatorType; + + /** 操作人员 */ + @Excel(name = "操作人员") + private String operName; + + /** 部门名称 */ + @Excel(name = "部门名称") + private String deptName; + + /** 请求url */ + @Excel(name = "请求地址") + private String operUrl; + + /** 操作地址 */ + @Excel(name = "操作地址") + private String operIp; + + /** 操作地点 */ + @Excel(name = "操作地点") + private String operLocation; + + /** 请求参数 */ + @Excel(name = "请求参数") + private String operParam; + + /** 返回参数 */ + @Excel(name = "返回参数") + private String jsonResult; + + /** 操作状态(0正常 1异常) */ + @Excel(name = "状态", readConverterExp = "0=正常,1=异常") + private Integer status; + + /** 错误消息 */ + @Excel(name = "错误消息") + private String errorMsg; + + /** 操作时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "操作时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date operTime; + + /** 消耗时间 */ + @Excel(name = "消耗时间", suffix = "毫秒") + private Long costTime; + + public Long getOperId() + { + return operId; + } + + public void setOperId(Long operId) + { + this.operId = operId; + } + + public String getTitle() + { + return title; + } + + public void setTitle(String title) + { + this.title = title; + } + + public Integer getBusinessType() + { + return businessType; + } + + public void setBusinessType(Integer businessType) + { + this.businessType = businessType; + } + + public Integer[] getBusinessTypes() + { + return businessTypes; + } + + public void setBusinessTypes(Integer[] businessTypes) + { + this.businessTypes = businessTypes; + } + + public String getMethod() + { + return method; + } + + public void setMethod(String method) + { + this.method = method; + } + + public String getRequestMethod() + { + return requestMethod; + } + + public void setRequestMethod(String requestMethod) + { + this.requestMethod = requestMethod; + } + + public Integer getOperatorType() + { + return operatorType; + } + + public void setOperatorType(Integer operatorType) + { + this.operatorType = operatorType; + } + + public String getOperName() + { + return operName; + } + + public void setOperName(String operName) + { + this.operName = operName; + } + + public String getDeptName() + { + return deptName; + } + + public void setDeptName(String deptName) + { + this.deptName = deptName; + } + + public String getOperUrl() + { + return operUrl; + } + + public void setOperUrl(String operUrl) + { + this.operUrl = operUrl; + } + + public String getOperIp() + { + return operIp; + } + + public void setOperIp(String operIp) + { + this.operIp = operIp; + } + + public String getOperLocation() + { + return operLocation; + } + + public void setOperLocation(String operLocation) + { + this.operLocation = operLocation; + } + + public String getOperParam() + { + return operParam; + } + + public void setOperParam(String operParam) + { + this.operParam = operParam; + } + + public String getJsonResult() + { + return jsonResult; + } + + public void setJsonResult(String jsonResult) + { + this.jsonResult = jsonResult; + } + + public Integer getStatus() + { + return status; + } + + public void setStatus(Integer status) + { + this.status = status; + } + + public String getErrorMsg() + { + return errorMsg; + } + + public void setErrorMsg(String errorMsg) + { + this.errorMsg = errorMsg; + } + + public Date getOperTime() + { + return operTime; + } + + public void setOperTime(Date operTime) + { + this.operTime = operTime; + } + + public Long getCostTime() + { + return costTime; + } + + public void setCostTime(Long costTime) + { + this.costTime = costTime; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysPost.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysPost.java new file mode 100644 index 0000000000000000000000000000000000000000..a28a1b3eac1d0ea63fc481701fddfbacd011b5a4 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysPost.java @@ -0,0 +1,127 @@ +package com.RVSmartPorting.core.system.domain; + +import com.RVSmartPorting.common.annotation.Excel; +import com.RVSmartPorting.common.annotation.Excel.ColumnType; +import com.RVSmartPorting.common.core.domain.BaseEntity; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.ibatis.type.Alias; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +/** + * 岗位表 sys_post + * + * @author ruoyi + */ +@Alias("SysPost") +public class SysPost extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 岗位序号 */ + @Excel(name = "岗位序号", cellType = ColumnType.NUMERIC) + private Long postId; + + /** 岗位编码 */ + @Excel(name = "岗位编码") + private String postCode; + + /** 岗位名称 */ + @Excel(name = "岗位名称") + private String postName; + + /** 岗位排序 */ + @Excel(name = "岗位排序") + private Integer postSort; + + /** 状态(0正常 1停用) */ + @Excel(name = "状态", readConverterExp = "0=正常,1=停用") + private String status; + + /** 用户是否存在此岗位标识 默认不存在 */ + private boolean flag = false; + + public Long getPostId() + { + return postId; + } + + public void setPostId(Long postId) + { + this.postId = postId; + } + + @NotBlank(message = "岗位编码不能为空") + @Size(min = 0, max = 64, message = "岗位编码长度不能超过64个字符") + public String getPostCode() + { + return postCode; + } + + public void setPostCode(String postCode) + { + this.postCode = postCode; + } + + @NotBlank(message = "岗位名称不能为空") + @Size(min = 0, max = 50, message = "岗位名称长度不能超过50个字符") + public String getPostName() + { + return postName; + } + + public void setPostName(String postName) + { + this.postName = postName; + } + + @NotNull(message = "显示顺序不能为空") + public Integer getPostSort() + { + return postSort; + } + + public void setPostSort(Integer postSort) + { + this.postSort = postSort; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + public boolean isFlag() + { + return flag; + } + + public void setFlag(boolean flag) + { + this.flag = flag; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("postId", getPostId()) + .append("postCode", getPostCode()) + .append("postName", getPostName()) + .append("postSort", getPostSort()) + .append("status", getStatus()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysRoleDept.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysRoleDept.java new file mode 100644 index 0000000000000000000000000000000000000000..9ba7d778a60ac979b8da920575b34d787054fd30 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysRoleDept.java @@ -0,0 +1,48 @@ +package com.RVSmartPorting.core.system.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.ibatis.type.Alias; + +/** + * 角色和部门关联 sys_role_dept + * + * @author ruoyi + */ +@Alias("SysRoleDept") +public class SysRoleDept +{ + /** 角色ID */ + private Long roleId; + + /** 部门ID */ + private Long deptId; + + public Long getRoleId() + { + return roleId; + } + + public void setRoleId(Long roleId) + { + this.roleId = roleId; + } + + public Long getDeptId() + { + return deptId; + } + + public void setDeptId(Long deptId) + { + this.deptId = deptId; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("roleId", getRoleId()) + .append("deptId", getDeptId()) + .toString(); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysRoleMenu.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysRoleMenu.java new file mode 100644 index 0000000000000000000000000000000000000000..b8985716304eaff07177023b647229c1dadb20d8 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysRoleMenu.java @@ -0,0 +1,48 @@ +package com.RVSmartPorting.core.system.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.ibatis.type.Alias; + +/** + * 角色和菜单关联 sys_role_menu + * + * @author ruoyi + */ +@Alias("SysRoleMenu") +public class SysRoleMenu +{ + /** 角色ID */ + private Long roleId; + + /** 菜单ID */ + private Long menuId; + + public Long getRoleId() + { + return roleId; + } + + public void setRoleId(Long roleId) + { + this.roleId = roleId; + } + + public Long getMenuId() + { + return menuId; + } + + public void setMenuId(Long menuId) + { + this.menuId = menuId; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("roleId", getRoleId()) + .append("menuId", getMenuId()) + .toString(); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysUserOnline.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysUserOnline.java new file mode 100644 index 0000000000000000000000000000000000000000..61f48d2d708fcc476a43c419f6f709ac58e126f0 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysUserOnline.java @@ -0,0 +1,116 @@ +package com.RVSmartPorting.core.system.domain; + +import org.apache.ibatis.type.Alias; + +/** + * 当前在线会话 + * + * @author ruoyi + */ +@Alias("SysUserOnline") +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; + + public String getTokenId() + { + return tokenId; + } + + public void setTokenId(String tokenId) + { + this.tokenId = tokenId; + } + + public String getDeptName() + { + return deptName; + } + + public void setDeptName(String deptName) + { + this.deptName = deptName; + } + + public String getUserName() + { + return userName; + } + + public void setUserName(String userName) + { + this.userName = userName; + } + + public String getIpaddr() + { + return ipaddr; + } + + public void setIpaddr(String ipaddr) + { + this.ipaddr = ipaddr; + } + + public String getLoginLocation() + { + return loginLocation; + } + + public void setLoginLocation(String loginLocation) + { + this.loginLocation = loginLocation; + } + + public String getBrowser() + { + return browser; + } + + public void setBrowser(String browser) + { + this.browser = browser; + } + + public String getOs() + { + return os; + } + + public void setOs(String os) + { + this.os = os; + } + + public Long getLoginTime() + { + return loginTime; + } + + public void setLoginTime(Long loginTime) + { + this.loginTime = loginTime; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysUserPost.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysUserPost.java new file mode 100644 index 0000000000000000000000000000000000000000..25cea79054984fadc9e5f423d082b4ab577fb8db --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysUserPost.java @@ -0,0 +1,48 @@ +package com.RVSmartPorting.core.system.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.ibatis.type.Alias; + +/** + * 用户和岗位关联 sys_user_post + * + * @author ruoyi + */ +@Alias("SysUserPost") +public class SysUserPost +{ + /** 用户ID */ + private Long userId; + + /** 岗位ID */ + private Long postId; + + public Long getUserId() + { + return userId; + } + + public void setUserId(Long userId) + { + this.userId = userId; + } + + public Long getPostId() + { + return postId; + } + + public void setPostId(Long postId) + { + this.postId = postId; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("userId", getUserId()) + .append("postId", getPostId()) + .toString(); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysUserRole.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysUserRole.java new file mode 100644 index 0000000000000000000000000000000000000000..849f6d3cb773d50974547c8f163b2ed1a4bdeba4 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/SysUserRole.java @@ -0,0 +1,48 @@ +package com.RVSmartPorting.core.system.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.ibatis.type.Alias; + +/** + * 用户和角色关联 sys_user_role + * + * @author ruoyi + */ +@Alias("SysUserRole") +public class SysUserRole +{ + /** 用户ID */ + private Long userId; + + /** 角色ID */ + private Long roleId; + + public Long getUserId() + { + return userId; + } + + public void setUserId(Long userId) + { + this.userId = userId; + } + + public Long getRoleId() + { + return roleId; + } + + public void setRoleId(Long roleId) + { + this.roleId = roleId; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("userId", getUserId()) + .append("roleId", getRoleId()) + .toString(); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/vo/MetaVo.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/vo/MetaVo.java new file mode 100644 index 0000000000000000000000000000000000000000..e02e0634e8bfa709131c8b58facddaed6413c3af --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/vo/MetaVo.java @@ -0,0 +1,106 @@ +package com.RVSmartPorting.core.system.domain.vo; + +import com.RVSmartPorting.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/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/vo/RouterVo.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/vo/RouterVo.java new file mode 100644 index 0000000000000000000000000000000000000000..f78df8be55815f2a245a156f549be6019da2f895 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/domain/vo/RouterVo.java @@ -0,0 +1,149 @@ +package com.RVSmartPorting.core.system.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/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/AbstractFileStorage.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/AbstractFileStorage.java new file mode 100644 index 0000000000000000000000000000000000000000..05f413662e1e20f599b076724f02c35caed5d377 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/AbstractFileStorage.java @@ -0,0 +1,17 @@ +package com.RVSmartPorting.core.system.fileStorage; + +import org.springframework.core.io.Resource; + +import java.io.IOException; +import java.io.InputStream; + +/** + * @author xuqiangli + * @create 2023-08-30 14:02 + */ +public interface AbstractFileStorage { + void uploadFile(String srcPath, String aimPath) throws IOException; + InputStream downloadFile(String filePath) throws IOException; + void deleteFile(String path) throws IOException; + // ... 其他方法 +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/FileStorageFactory.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/FileStorageFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..8854a88e6083ba010944c243696aeffd311b7134 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/FileStorageFactory.java @@ -0,0 +1,24 @@ +package com.RVSmartPorting.core.system.fileStorage; + +import com.RVSmartPorting.common.config.CSPConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class FileStorageFactory { + + private final AbstractFileStorage fileStorage; + + @Autowired + public FileStorageFactory(CSPConfig cspConfig) { + if (CSPConfig.isHdfsEnabled()) { + fileStorage = new HDFSFileStorage(); + } else { + fileStorage = new LocalFileStorage(); + } + } + + public AbstractFileStorage getFileStorage() { + return fileStorage; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/HDFSFileStorage.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/HDFSFileStorage.java new file mode 100644 index 0000000000000000000000000000000000000000..c947092d50d2b1e8be66115855955ce06ba71cca --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/HDFSFileStorage.java @@ -0,0 +1,55 @@ +package com.RVSmartPorting.core.system.fileStorage; + +import lombok.extern.slf4j.Slf4j; +import org.apache.hadoop.fs.FSDataInputStream; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.springframework.core.io.InputStreamResource; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.io.InputStream; + +/** + * @author xuqiangli + * @create 2023-08-30 14:22 + */ +@Component +@Slf4j +public class HDFSFileStorage implements AbstractFileStorage { + @Override + public void uploadFile(String srcPath, String aimPath) throws IOException { + HDFSService.disk2hdfs(srcPath, aimPath); + } + + @Override + public FSDataInputStream downloadFile(String filePath) throws IOException { + try { + // 获取HDFS文件系统 + FileSystem hdfs = HDFSService.getFileSystem(); + + // 构建HDFS文件路径 + Path hdfsFilePath = new Path(filePath); + + // 检查文件是否存在 + if (!hdfs.exists(hdfsFilePath)) { + return null; + } + + // 创建HDFS文件系统的输入流 + FSDataInputStream inputStream = hdfs.open(hdfsFilePath); + + return inputStream; + } catch (IOException e) { + log.error("Error while downloading file from HDFS: {}", e.getMessage(), e); + return null; + } + } + + @Override + public void deleteFile(String path) throws IOException { + + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/HDFSService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/HDFSService.java new file mode 100644 index 0000000000000000000000000000000000000000..8589e05f3ce82716273b42c110eda0fa1059b18f --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/HDFSService.java @@ -0,0 +1,132 @@ +package com.RVSmartPorting.core.system.fileStorage; + +import com.RVSmartPorting.common.config.HDFSConfig; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.IOUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; + +/** + * @author xuqiangli + * @create 2023-08-26 14:06 + */ +@Component +public class HDFSService { + public static FileSystem fileSystem; + + public static FileSystem getFileSystem() { + return fileSystem; + } + + @Autowired + public HDFSService(HDFSConfig hdfsConfig) { + System.setProperty("hadoop.home.dir", hdfsConfig.getHadoopHome()); + System.setProperty("HADOOP_HOME", hdfsConfig.getHadoopHome()); + try { + // 获得FileSystem对象,使用指定用户上传 + fileSystem = FileSystem.get(new URI(hdfsConfig.getHdfsUrl()), new Configuration(), hdfsConfig.getUsername()); + } catch (Exception e) { + throw new RuntimeException("Error initializing HDFSUtil", e); + } + } + + /** + * disk复制文件到hdfs + * + * @param diskSourcePath + * @param hdfsDestinationPath + * @return void + **/ + public static void disk2hdfs(String diskSourcePath, String hdfsDestinationPath) { + try { + // 先清空,再复制,以达到覆盖的目的 + fileSystem.delete(new Path(hdfsDestinationPath), true); + fileSystem.copyFromLocalFile(new Path(diskSourcePath), new Path(hdfsDestinationPath)); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * hdfs复制文件到disk + * + * @param hdfsSourcePath + * @param diskDestinationPath + * @return void + **/ + public static void hdfs2disk(String hdfsSourcePath, String diskDestinationPath) { + try { + // 调用open方法进行下载,参数HDFS路径 + InputStream in = fileSystem.open(new Path(hdfsSourcePath)); + // 创建输出流,参数指定文件输出地址 + OutputStream out = new FileOutputStream(diskDestinationPath); + IOUtils.copyBytes(in, out, 4096, true); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 删除文件 + * + * @param target + * @param recursive + * @return boolean + **/ + public static boolean delete(String target, boolean recursive) { + boolean flag = false; + try { + // 调用delete方法,删除指定的文件。参数:false:表示是否递归删除 + flag = fileSystem.delete(new Path(target), recursive); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + return flag; + } + + /** + * 创建文件夹 + * + * @param directory + * @return boolean + * @author big uncle + * @date 2021/5/10 19:59 + **/ + public static boolean mkdir(String directory) { + boolean flag = false; + try { + // 调用mkdirs方法,在HDFS文件服务器上创建文件夹。 + flag = fileSystem.mkdirs(new Path(directory)); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + ; + return flag; + } + + public static void test2() throws Exception { + String diskSourcePath = "C:\\Users\\Lenovo\\Desktop\\ospp\\测试\\test.zip"; + String hdfsDestinationPath = "/test/demo4"; + HDFSService.disk2hdfs(diskSourcePath, hdfsDestinationPath); + } + + public static void test3() throws Exception { + String diskSourcePath = "C:\\Users\\Lenovo\\Desktop\\ospp\\测试\\a"; + String hdfsDestinationPath = "/test/demo3"; + HDFSService.disk2hdfs(diskSourcePath, hdfsDestinationPath); + } + + public static void main(String[] args) throws Exception { + test2(); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/LocalFileStorage.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/LocalFileStorage.java new file mode 100644 index 0000000000000000000000000000000000000000..810a3785149647d3058ab95f6e63687edbabc561 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/LocalFileStorage.java @@ -0,0 +1,61 @@ +package com.RVSmartPorting.core.system.fileStorage; + +import org.springframework.core.io.Resource; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * @author xuqiangli + * @create 2023-08-30 14:22 + */ +@Component +public class LocalFileStorage implements AbstractFileStorage { + + @Override + public void uploadFile(String srcPath, String aimPath) throws IOException { + Path sourceFilePath = Paths.get(srcPath); + Path targetFilePath = Paths.get(aimPath); + // 获取目标文件夹路径 + Path targetFolderPath = targetFilePath.getParent(); + + // 检查目标文件夹是否存在,如果不存在就创建 + if (!Files.exists(targetFolderPath)) { + Files.createDirectories(targetFolderPath); + } + // 检查目标文件是否已经存在 + if (Files.exists(targetFilePath)) { + // 文件已存在,你可以选择覆盖它或者采取其他操作 + // 这里示例选择删除已存在文件并进行覆盖 + Files.delete(targetFilePath); + } + Files.copy(sourceFilePath, targetFilePath); + } + + @Override + public InputStream downloadFile(String filePath) throws IOException { + File file = new File(filePath); + if (file.exists()) { + return Files.newInputStream(file.toPath()); + } else { + throw new IOException("File not found: " + filePath); + } + } + + @Override + public void deleteFile(String path) throws IOException { + + } + + public static void main(String[] args) throws IOException { + String srcPath = "C:\\Users\\Lenovo\\Desktop\\ospp\\测试\\test.zip"; + String aimPath = "C:\\Users\\Lenovo\\Desktop\\ospp\\测试\\a - 副本\\test.zip"; + Files.copy(Paths.get(srcPath), Paths.get(aimPath)); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/git/CancellableProgressMonitor.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/git/CancellableProgressMonitor.java new file mode 100644 index 0000000000000000000000000000000000000000..e7b35498337f78179abbd83d8cec2be2d594751e --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/git/CancellableProgressMonitor.java @@ -0,0 +1,34 @@ +package com.RVSmartPorting.core.system.fileStorage.git; + +import org.eclipse.jgit.lib.TextProgressMonitor; + +public class CancellableProgressMonitor extends TextProgressMonitor { + private final GitDownloadProcessListener listener; + private volatile boolean cancelled = false; + public CancellableProgressMonitor(GitDownloadProcessListener listener) { + this.listener = listener; + } + public void setCancelled() { + cancelled = true; + } + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void start(int totalTasks) { + listener.onDownloadStart(); + } + + @Override + public void onUpdate(String taskName, int cmp, int totalWork, int pcnt) { + // 在每次更新时处理任务名、已完成工作、总工作量和百分比 + listener.onDownloading(pcnt, taskName); +// try { +// Thread.sleep(1000); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/git/GitDownloadProcessListener.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/git/GitDownloadProcessListener.java new file mode 100644 index 0000000000000000000000000000000000000000..c3b68feb246b3ec0652c5737a536493db27c89a7 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/git/GitDownloadProcessListener.java @@ -0,0 +1,38 @@ +package com.RVSmartPorting.core.system.fileStorage.git; + +public interface GitDownloadProcessListener { + + /** + * 开始回调 + */ + void onDownloadStart(); + + /** + * 完成回调 + * + * @param + */ + void onDownloadSuccess(); + + /** + * 下载进度 + * + * @param progress 下载进度 + */ + void onDownloading(int progress, String currentTaskName); + + /** + * 出错回调 + * + * @param e 异常 + */ + void onDownloadFailed(Exception e); + + /** + * 超时回调 + * + * @param e 异常 + */ + void onDownloadTimeout(Exception e); + +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/git/GitService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/git/GitService.java new file mode 100644 index 0000000000000000000000000000000000000000..f11731669c779cb9cffe8e4908bdd39e54def1d0 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/git/GitService.java @@ -0,0 +1,332 @@ +package com.RVSmartPorting.core.system.fileStorage.git; + +import com.RVSmartPorting.common.enums.AuthenticationMethodType; +import com.RVSmartPorting.common.enums.GitCloneAccelerateType; +import com.RVSmartPorting.common.enums.GitMirrorAddressRule; +import com.RVSmartPorting.core.system.domain.GitNetworkSetting; +import com.RVSmartPorting.core.system.mapper.GitNetworkSettingMapper; +import com.RVSmartPorting.core.system.service.IGitNetworkSettingService; +import com.RVSmartPorting.core.system.service.ISysConfigService; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.jgit.api.*; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.transport.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.*; +import java.net.*; +import java.util.*; +import java.util.concurrent.*; + +/** + * @author xuqiangli + * @create 2023-09-06 18:52 + */ +@Slf4j +@Service +public class GitService { + @Autowired + ISysConfigService sysConfigService; + + @Autowired + IGitNetworkSettingService gitNetworkSettingService; + + @Autowired + GitNetworkSettingMapper gitNetworkSettingMapper; + + private static Map activeDownloads = new ConcurrentHashMap<>(); + + public static Map getActiveDownloads() { + return activeDownloads; + } + + public static Map removeActiveDownload(String requestId) { + CancellableProgressMonitor cancellableProgressMonitor = activeDownloads.get(requestId); + if (cancellableProgressMonitor != null) { + cancellableProgressMonitor.setCancelled(); + } + activeDownloads.remove(requestId); + return activeDownloads; + } + + public String gitDownloadFilesAsynchronous(String remoteRepositoryURI, String localRepositoryPath, + String branchName, + String authenticationMethod, + String username, + String password, + String personalAccessToken, + GitDownloadProcessListener listener) throws Exception { + CompletableFuture future = new CompletableFuture<>(); + final CancellableProgressMonitor cancellableProgressMonitor = new CancellableProgressMonitor(listener); + // 返回用于此下载请求的唯一标识符 + String requestId = generateUniqueRequestId(); // 需要实现此方法 + log.info("Generating unique gitDownloadFilesAsynchronous request, id: " + requestId); + // 应用代理和镜像的加速 + final String actualUrl = accelerateGitClone(remoteRepositoryURI); + Executors.newSingleThreadExecutor().submit(() -> { + CloneCommand cloneCommand = null; + Git git = null; + try { + CredentialsProvider credentialsProvider = null; + if (AuthenticationMethodType.usernamePassword.name().equalsIgnoreCase(authenticationMethod)) { + credentialsProvider = new UsernamePasswordCredentialsProvider(username, password); + } else if (AuthenticationMethodType.personalAccessToken.name().equalsIgnoreCase(authenticationMethod)) { + credentialsProvider = new UsernamePasswordCredentialsProvider(username, personalAccessToken); + } + + + cloneCommand = Git.cloneRepository() + .setURI(actualUrl) + .setDirectory(new File(localRepositoryPath)) + .setProgressMonitor(cancellableProgressMonitor) + .setBranch(branchName) + .setCredentialsProvider(credentialsProvider); + // 如果存在代理,则直接递归克隆子模块,否则后续先进行子模块git地址替换镜像地址,再递归克隆子模块 + if (isProxyEnabled(remoteRepositoryURI)) { + // true to initialize and update submodules. + cloneCommand = cloneCommand.setCloneSubmodules(true); + } + activeDownloads.put(requestId, cancellableProgressMonitor); + git = cloneCommand.call(); + + // 拉取子模块 + updateSubmoduleUrlsIfMirrorEnabled(git, remoteRepositoryURI, localRepositoryPath); + // 拉取成功回调 + listener.onDownloadSuccess(); + // 完成 CompletableFuture + future.complete(null); + } catch (Exception e) { + log.error("git clone occurs error:", e); + listener.onDownloadFailed(e); + future.completeExceptionally(e); // 将异常传递回主线程 + } finally { + if (git != null) { + git.close(); // 关闭 Git 对象 + } + } + }); + final Long maxTimeoutDuration = Long.valueOf( + sysConfigService.selectConfigByKey("sys.codeProject.git.maxTimeoutDuration")); + // 添加超时逻辑 + Executors.newSingleThreadScheduledExecutor().schedule(() -> { + if (!future.isDone()) { + // 如果任务未完成,表示超时,触发超时回调 + future.completeExceptionally(new TimeoutException("Download timed out.")); + listener.onDownloadTimeout(new TimeoutException("Download timed out.")); + cancellableProgressMonitor.setCancelled(); + } + }, maxTimeoutDuration, TimeUnit.SECONDS); + return requestId; + } + + private static String generateUniqueRequestId() { + return UUID.randomUUID().toString(); + } + + public boolean isProxyEnabled(String gitRepositoryUrl) { + String domain = getDomain(gitRepositoryUrl); // 获取域名(gitee.com、github.com等) + List settings = gitNetworkSettingMapper.selectGitNetworkSettingListByDomain(domain); + Optional mirrorConfig = settings.stream() + .filter(config -> !GitCloneAccelerateType.mirror.name().equalsIgnoreCase(config.getType())) + .findFirst(); + return mirrorConfig.isPresent(); + } + + /** + * 更新子模块git地址为镜像加速地址 + * + * @param gitRepositoryUrl + * @param localRepositoryPath + * @throws IOException + * @throws GitAPIException + */ + private void updateSubmoduleUrlsIfMirrorEnabled(Git git, String gitRepositoryUrl, String localRepositoryPath) throws IOException, + GitAPIException { + try { + // 如果有代理配置,则之前已经递归拉取过子模块,直接返回 + if (isProxyEnabled(gitRepositoryUrl)) { + return; + } + // 镜像加速只针对http、https + if (!gitRepositoryUrl.startsWith("https://") && !gitRepositoryUrl.startsWith("http://")) { + return; + } + // 1. 手动加载并解析 .gitmodules 文件 + File gitModulesFile = new File(localRepositoryPath, ".gitmodules"); + + // 如果 .gitmodules 文件不存在,说明没有子模块,直接返回 + if (!gitModulesFile.exists()) { + return; + } + + Properties gitModulesProps = new Properties(); + try (BufferedReader reader = new BufferedReader(new FileReader(gitModulesFile))) { + gitModulesProps.load(reader); + } + + // 2. 修改子模块的 URL + String domain = getDomain(gitRepositoryUrl); // 获取域名(gitee.com、github.com等) + List settings = gitNetworkSettingMapper.selectGitNetworkSettingListByDomain(domain); + Optional mirrorConfig = settings.stream() + .filter(config -> GitCloneAccelerateType.mirror.name().equalsIgnoreCase(config.getType())) + .findFirst(); + if (mirrorConfig.isPresent()) { + for (String submodulePath : gitModulesProps.stringPropertyNames()) { + if ("url".equals(submodulePath)) { + + String submoduleURL = gitModulesProps.getProperty(submodulePath); + + // 将相对路径转换为绝对路径 + final String absoluteSubmoduleURL = resolvedAbsGitPath(gitRepositoryUrl, submoduleURL); + + // 在这里根据配置将 absoluteSubmoduleURL 替换为镜像地址 + String newSubmoduleURL = buildActualUrl(absoluteSubmoduleURL, mirrorConfig.get()); + + // 更新子模块的 URL + gitModulesProps.setProperty(submodulePath, newSubmoduleURL); + } + } + // 5. 保存 .gitmodules 文件 +// try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(gitModulesFile.getPath()), StandardCharsets.UTF_8)) { +// gitModulesProps.store(writer, ""); +// } + // 5. 保存 .gitmodules 文件 + try (BufferedWriter writer = new BufferedWriter(new FileWriter(gitModulesFile))) { + for (String submodulePath : gitModulesProps.stringPropertyNames()) { + String propertyValue = gitModulesProps.getProperty(submodulePath); + if(submodulePath.startsWith("[submodule")){ + writer.write(submodulePath + " " + propertyValue); + }else{ + writer.write(submodulePath + "=" + propertyValue); + } + writer.newLine(); + } + } + } + // 6. 初始化和更新子模块 + SubmoduleInitCommand submoduleInit = git.submoduleInit(); + submoduleInit.call(); + + SubmoduleUpdateCommand submoduleUpdate = git.submoduleUpdate(); + submoduleUpdate.call(); + } catch (Exception e) { + throw new RuntimeException("更新子模块git地址为镜像加速地址时遇到错误", e); + } + } + + public static String resolvedAbsGitPath(String mainRepoURI, String submoduleURI) throws URISyntaxException { + if (!submoduleURI.startsWith("../")) { + return submoduleURI; + } + mainRepoURI = removeLastSlashAndFollowing(mainRepoURI); + submoduleURI = submoduleURI.substring(3); + return mainRepoURI + "/" + submoduleURI; + } + + public static String removeLastSlashAndFollowing(String input) { + int lastSlashIndex = input.lastIndexOf('/'); + if (lastSlashIndex >= 0) { + return input.substring(0, lastSlashIndex); + } + return input; + } + + public String accelerateGitClone(String gitRepositoryUrl) { + String domain = getDomain(gitRepositoryUrl); // 获取域名(gitee.com、github.com等) + + List settings = gitNetworkSettingMapper.selectGitNetworkSettingListByDomain(domain); + + if (settings.isEmpty()) { + // 没有匹配的配置,直接返回 + return gitRepositoryUrl; + } + // 设置代理 + setProxy(settings); + // 设置镜像 + String actualUrl = gitRepositoryUrl; + Optional mirrorConfig = settings.stream() + .filter(config -> GitCloneAccelerateType.mirror.name().equalsIgnoreCase(config.getType())) + .findFirst(); + if (mirrorConfig.isPresent()) { + actualUrl = buildActualUrl(gitRepositoryUrl, mirrorConfig.get()); + } + return actualUrl; + } + + + // 构建实际的Git仓库URL + private static String buildActualUrl(String originalUrl, GitNetworkSetting config) { + if (GitMirrorAddressRule.direct.name().equalsIgnoreCase(config.getAddressRule())) { + return config.getUrl() + "/" + originalUrl; + } else if (GitMirrorAddressRule.replace_domain.name().equalsIgnoreCase(config.getAddressRule())) { + // 进行域名替换 + return originalUrl.replace(config.getDomain(), config.getUrl()); + } else { + // 其他规则 + return originalUrl; + } + } + + // 设置代理 + private static void setProxy(List settings) { + ProxySelector.setDefault(new ProxySelector() { + final ProxySelector delegate = ProxySelector.getDefault(); + + @Override + public List select(URI uri) { + // 根据需要过滤需要代理的 URI + for (GitNetworkSetting setting : settings) { + if (uri.toString().contains(setting.getDomain())) { + Proxy.Type type = GitCloneAccelerateType.http.name().equals(setting.getType()) ? Proxy.Type.HTTP : + Proxy.Type.SOCKS; + final UrlInfo urlInfo = parseUrl(setting.getUrl()); + return Arrays.asList(new Proxy(type, new InetSocketAddress(urlInfo.getUrl(), urlInfo.getPort()))); + } + } + // 返回默认的代理设置 + return delegate == null ? Arrays.asList(Proxy.NO_PROXY) : delegate.select(uri); + } + + @Override + public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { + if (uri == null || sa == null || ioe == null) { + throw new IllegalArgumentException("Arguments can't be null."); + } + } + }); + } + + public static UrlInfo parseUrl(String urlString) { + UrlInfo urlInfo = new UrlInfo(); + try { + URL url = new URL(urlString); + urlInfo.url = urlString; + urlInfo.port = url.getPort() == -1 ? url.getDefaultPort() : url.getPort(); + } catch (Exception e) { + e.printStackTrace(); + } + return urlInfo; + } + + @Data + static class UrlInfo { + String url; + int port; + } + + // 获取域名 + public static String getDomain(String url) { + try { + URI uri = new URI(url); + String host = uri.getHost(); + if (host != null) { + return host; + } + } catch (URISyntaxException e) { + e.printStackTrace(); + } + return ""; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/http/OkHttpService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/http/OkHttpService.java new file mode 100644 index 0000000000000000000000000000000000000000..90cf1ab7d19c58847dea3fe0bcf20780b31e686b --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/fileStorage/http/OkHttpService.java @@ -0,0 +1,136 @@ +package com.RVSmartPorting.core.system.fileStorage.http; + +import com.RVSmartPorting.common.utils.http.FileDownloadListener; +import com.RVSmartPorting.core.system.service.ISysConfigService; +import lombok.extern.slf4j.Slf4j; +import okhttp3.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +@Slf4j +@Service +public class OkHttpService { + private static final OkHttpClient OK_HTTP_CLIENT; + + @Autowired + ISysConfigService sysConfigService; + static { + // 创建okHttpClient + OK_HTTP_CLIENT = new OkHttpClient + .Builder() + .connectTimeout(30*4, TimeUnit.SECONDS) + .writeTimeout(30*4, TimeUnit.SECONDS) + .readTimeout(30*4, TimeUnit.SECONDS) + .build(); + } + private static Map activeDownloads = new ConcurrentHashMap<>(); + + public static Map getActiveDownloads(){ + return activeDownloads; + } + /** + * 下载文件 + * 异步请求 + * + * @param url 下载连接 + * @param destFileDir 下载的文件储存目录 + * @param destFileName 下载文件名称,后面记得拼接后缀 + * @param listener 下载监听 + */ + public String downloadFilesAsynchronous(String url, String destFileDir, String destFileName, + FileDownloadListener listener) { + + Request request = new Request.Builder() + .url(url) + .build(); + // 创建 ScheduledExecutorService + ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); + // 返回用于此下载请求的唯一标识符 + String requestId = generateUniqueRequestId(); // 需要实现此方法 + log.info("Generating unique downloadFilesAsynchronous request, id: " + requestId); + // 异步请求 + final Call call = OK_HTTP_CLIENT.newCall(request); + activeDownloads.put(requestId, call); + call.enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + // 下载失败监听回调 + listener.onDownloadFailed(e); + // 取消定时任务 + executorService.shutdown(); + } + @Override + public void onResponse(Call call, Response response) throws IOException { + InputStream is = null; + byte[] buf = new byte[2048]; + int len = 0; + FileOutputStream fos = null; + // 储存下载文件的目录 + File dir = new File(destFileDir); + if (!dir.exists()) { + dir.mkdirs(); + } + listener.onDownloadStart(); + File file = new File(dir, destFileName); + try { + is = response.body().byteStream(); + long total = response.body().contentLength(); + fos = new FileOutputStream(file); + long sum = 0; + while ((len = is.read(buf)) != -1) { + fos.write(buf, 0, len); + sum += len; + int progress = (int) (sum * 1.0f / total * 100); + // 下载中更新进度条 + listener.onDownloading(progress); + } + fos.flush(); + // 下载完成 + listener.onDownloadSuccess(file); + } catch (Exception e) { + listener.onDownloadFailed(e); + } finally { + try { + if (is != null) { + is.close(); + } + if (fos != null) { + fos.close(); + } + } catch (IOException e) { + + } + // 取消定时任务 + executorService.shutdown(); + } + } + }); + final Long maxTimeoutDuration = Long.valueOf( + sysConfigService.selectConfigByKey("sys.codeProject.link.maxTimeoutDuration")); + // 添加超时定时任务 + executorService.schedule(() -> { + // 触发超时回调 + listener.onDownloadTimeout(new Exception("Download timeout")); + // 取消异步请求 + OK_HTTP_CLIENT.dispatcher().cancelAll(); + }, maxTimeoutDuration, TimeUnit.SECONDS); // 设置超时时长 + return requestId; + } + + + private static String generateUniqueRequestId() { + return UUID.randomUUID().toString(); + } + +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/CodeProjectMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/CodeProjectMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..421229b8280330c2a64108c6d99aa58e326dafe3 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/CodeProjectMapper.java @@ -0,0 +1,66 @@ +package com.RVSmartPorting.core.system.mapper; + +import com.RVSmartPorting.core.system.domain.CodeProject; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 代码项目信息Mapper接口 + * + * @author xuqiangli + * @date 2023-08-24 + */ +@Mapper +public interface CodeProjectMapper +{ + /** + * 查询代码项目信息 + * + * @param codeProjectId 代码项目信息主键 + * @return 代码项目信息 + */ + public CodeProject selectCodeProjectByCodeProjectId(Long codeProjectId); + + /** + * 查询代码项目信息列表 + * + * @param codeProject 代码项目信息 + * @return 代码项目信息集合 + */ + public List selectCodeProjectList(CodeProject codeProject); + + /** + * 新增代码项目信息 + * + * @param codeProject 代码项目信息 + * @return 结果 + */ + public int insertCodeProject(CodeProject codeProject); + + /** + * 修改代码项目信息 + * + * @param codeProject 代码项目信息 + * @return 结果 + */ + public int updateCodeProject(CodeProject codeProject); + + /** + * 删除代码项目信息 + * + * @param codeProjectId 代码项目信息主键 + * @return 结果 + */ + public int deleteCodeProjectByCodeProjectId(Long codeProjectId); + + /** + * 批量删除代码项目信息 + * + * @param codeProjectIds 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteCodeProjectByCodeProjectIds(Long[] codeProjectIds); + + void resetCodeProjectFileInfo(CodeProject codeProject); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/GitNetworkSettingMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/GitNetworkSettingMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..0bcd0907f16bd599ff827c0b83fa881edc3643dc --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/GitNetworkSettingMapper.java @@ -0,0 +1,67 @@ +package com.RVSmartPorting.core.system.mapper; + +import java.util.List; +import com.RVSmartPorting.core.system.domain.GitNetworkSetting; +import org.apache.ibatis.annotations.Mapper; + +/** + * git网络镜像代理配置Mapper接口 + * + * @author ruoyi + * @date 2023-09-09 + */ +@Mapper +public interface GitNetworkSettingMapper +{ + /** + * 查询git网络镜像代理配置 + * + * @param gitNetworkSettingId git网络镜像代理配置主键 + * @return git网络镜像代理配置 + */ + public GitNetworkSetting selectGitNetworkSettingByGitNetworkSettingId(Long gitNetworkSettingId); + + /** + * 查询git网络镜像代理配置列表 + * + * @param gitNetworkSetting git网络镜像代理配置 + * @return git网络镜像代理配置集合 + */ + public List selectGitNetworkSettingList(GitNetworkSetting gitNetworkSetting); + + + public List selectGitNetworkSettingListByDomain(String domain); + + + /** + * 新增git网络镜像代理配置 + * + * @param gitNetworkSetting git网络镜像代理配置 + * @return 结果 + */ + public int insertGitNetworkSetting(GitNetworkSetting gitNetworkSetting); + + /** + * 修改git网络镜像代理配置 + * + * @param gitNetworkSetting git网络镜像代理配置 + * @return 结果 + */ + public int updateGitNetworkSetting(GitNetworkSetting gitNetworkSetting); + + /** + * 删除git网络镜像代理配置 + * + * @param gitNetworkSettingId git网络镜像代理配置主键 + * @return 结果 + */ + public int deleteGitNetworkSettingByGitNetworkSettingId(Long gitNetworkSettingId); + + /** + * 批量删除git网络镜像代理配置 + * + * @param gitNetworkSettingIds 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteGitNetworkSettingByGitNetworkSettingIds(Long[] gitNetworkSettingIds); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/RuleMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/RuleMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..8ab1e488f04b3178715bfad1dde886de83094deb --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/RuleMapper.java @@ -0,0 +1,64 @@ +package com.RVSmartPorting.core.system.mapper; + +import com.RVSmartPorting.core.system.domain.Rule; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 规则信息Mapper接口 + * + * @author ruoyi + * @date 2023-08-15 + */ +@Mapper +public interface RuleMapper +{ + /** + * 查询规则信息 + * + * @param ruleId 规则信息主键 + * @return 规则信息 + */ + public Rule selectRuleByRuleId(Long ruleId); + + /** + * 查询规则信息列表 + * + * @param rule 规则信息 + * @return 规则信息集合 + */ + public List selectRuleList(Rule rule); + + /** + * 新增规则信息 + * + * @param rule 规则信息 + * @return 结果 + */ + public int insertRule(Rule rule); + + /** + * 修改规则信息 + * + * @param rule 规则信息 + * @return 结果 + */ + public int updateRule(Rule rule); + + /** + * 删除规则信息 + * + * @param ruleId 规则信息主键 + * @return 结果 + */ + public int deleteRuleByRuleId(Long ruleId); + + /** + * 批量删除规则信息 + * + * @param ruleIds 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteRuleByRuleIds(Long[] ruleIds); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/RuleSet2RuleMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/RuleSet2RuleMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..dc6ab0711bb7b7d05ad8353e33afb58168aec7e9 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/RuleSet2RuleMapper.java @@ -0,0 +1,9 @@ +package com.RVSmartPorting.core.system.mapper; + +/** + * @author xuqiangli + * @create 2023-08-18 11:14 + */ +public interface RuleSet2RuleMapper { + +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/RuleSetMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/RuleSetMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..4bb8041ebe49806e9d8c7229ea330eb5288ecd47 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/RuleSetMapper.java @@ -0,0 +1,64 @@ +package com.RVSmartPorting.core.system.mapper; + +import java.util.List; + +import com.RVSmartPorting.core.system.domain.RuleSet; +import org.apache.ibatis.annotations.Mapper; + +/** + * 规则集信息Mapper接口 + * + * @author ruoyi + * @date 2023-08-16 + */ +@Mapper +public interface RuleSetMapper +{ + /** + * 查询规则集信息 + * + * @param ruleSetId 规则集信息主键 + * @return 规则集信息 + */ + public RuleSet selectRuleSetByRuleSetId(Long ruleSetId); + + /** + * 查询规则集信息列表 + * + * @param ruleSet 规则集信息 + * @return 规则集信息集合 + */ + public List selectRuleSetList(RuleSet ruleSet); + + /** + * 新增规则集信息 + * + * @param ruleSet 规则集信息 + * @return 结果 + */ + public int insertRuleSet(RuleSet ruleSet); + + /** + * 修改规则集信息 + * + * @param ruleSet 规则集信息 + * @return 结果 + */ + public int updateRuleSet(RuleSet ruleSet); + + /** + * 删除规则集信息 + * + * @param ruleSetId 规则集信息主键 + * @return 结果 + */ + public int deleteRuleSetByRuleSetId(Long ruleSetId); + + /** + * 批量删除规则集信息 + * + * @param ruleSetIds 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteRuleSetByRuleSetIds(Long[] ruleSetIds); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/ScanTaskMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/ScanTaskMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..99d5d7044af6d4440656ed893dbcfa9942148b25 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/ScanTaskMapper.java @@ -0,0 +1,64 @@ +package com.RVSmartPorting.core.system.mapper; + +import com.RVSmartPorting.core.system.domain.ScanTask; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 代码扫描任务信息Mapper接口 + * + * @author ruoyi + * @date 2023-09-17 + */ +@Mapper +public interface ScanTaskMapper +{ + /** + * 查询代码扫描任务信息 + * + * @param taskId 代码扫描任务信息主键 + * @return 代码扫描任务信息 + */ + public ScanTask selectScanTaskByTaskId(Long taskId); + + /** + * 查询代码扫描任务信息列表 + * + * @param scanTask 代码扫描任务信息 + * @return 代码扫描任务信息集合 + */ + public List selectScanTaskList(ScanTask scanTask); + + /** + * 新增代码扫描任务信息 + * + * @param scanTask 代码扫描任务信息 + * @return 结果 + */ + public int insertScanTask(ScanTask scanTask); + + /** + * 修改代码扫描任务信息 + * + * @param scanTask 代码扫描任务信息 + * @return 结果 + */ + public int updateScanTask(ScanTask scanTask); + + /** + * 删除代码扫描任务信息 + * + * @param taskId 代码扫描任务信息主键 + * @return 结果 + */ + public int deleteScanTaskByTaskId(Long taskId); + + /** + * 批量删除代码扫描任务信息 + * + * @param taskIds 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteScanTaskByTaskIds(Long[] taskIds); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/ScanToolConfigMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/ScanToolConfigMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..877f07d16da141bbaf753daa787a1c3988751cd4 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/ScanToolConfigMapper.java @@ -0,0 +1,64 @@ +package com.RVSmartPorting.core.system.mapper; + +import com.RVSmartPorting.core.system.domain.ScanToolConfig; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 扫描工具配置Mapper接口 + * + * @author xuqiangli + * @date 2023-09-22 + */ +@Mapper +public interface ScanToolConfigMapper +{ + /** + * 查询扫描工具配置 + * + * @param scanToolConfigId 扫描工具配置主键 + * @return 扫描工具配置 + */ + public ScanToolConfig selectScanToolConfigByScanToolConfigId(Long scanToolConfigId); + + /** + * 查询扫描工具配置列表 + * + * @param scanToolConfig 扫描工具配置 + * @return 扫描工具配置集合 + */ + public List selectScanToolConfigList(ScanToolConfig scanToolConfig); + + /** + * 新增扫描工具配置 + * + * @param scanToolConfig 扫描工具配置 + * @return 结果 + */ + public int insertScanToolConfig(ScanToolConfig scanToolConfig); + + /** + * 修改扫描工具配置 + * + * @param scanToolConfig 扫描工具配置 + * @return 结果 + */ + public int updateScanToolConfig(ScanToolConfig scanToolConfig); + + /** + * 删除扫描工具配置 + * + * @param scanToolConfigId 扫描工具配置主键 + * @return 结果 + */ + public int deleteScanToolConfigByScanToolConfigId(Long scanToolConfigId); + + /** + * 批量删除扫描工具配置 + * + * @param scanToolConfigIds 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteScanToolConfigByScanToolConfigIds(Long[] scanToolConfigIds); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/ScanToolMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/ScanToolMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..4a8137ebd5c45b5d72b3bd46fc8c6f215dfe40b5 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/ScanToolMapper.java @@ -0,0 +1,64 @@ +package com.RVSmartPorting.core.system.mapper; + +import com.RVSmartPorting.core.system.domain.ScanTool; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 扫描工具Mapper接口 + * + * @author ruoyi + * @date 2023-09-17 + */ +@Mapper +public interface ScanToolMapper +{ + /** + * 查询扫描工具 + * + * @param scanToolId 扫描工具主键 + * @return 扫描工具 + */ + public ScanTool selectScanToolByScanToolId(Long scanToolId); + + /** + * 查询扫描工具列表 + * + * @param scanTool 扫描工具 + * @return 扫描工具集合 + */ + public List selectScanToolList(ScanTool scanTool); + + /** + * 新增扫描工具 + * + * @param scanTool 扫描工具 + * @return 结果 + */ + public int insertScanTool(ScanTool scanTool); + + /** + * 修改扫描工具 + * + * @param scanTool 扫描工具 + * @return 结果 + */ + public int updateScanTool(ScanTool scanTool); + + /** + * 删除扫描工具 + * + * @param scanToolId 扫描工具主键 + * @return 结果 + */ + public int deleteScanToolByScanToolId(Long scanToolId); + + /** + * 批量删除扫描工具 + * + * @param scanToolIds 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteScanToolByScanToolIds(Long[] scanToolIds); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysConfigMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysConfigMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..54804b264032638e13546f281107d333955ca41d --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysConfigMapper.java @@ -0,0 +1,80 @@ +package com.RVSmartPorting.core.system.mapper; + + +import com.RVSmartPorting.core.system.domain.SysConfig; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 参数配置 数据层 + * + * @author ruoyi + */ +@Mapper +public interface SysConfigMapper +{ + /** + * 查询参数配置信息 + * + * @param config 参数配置信息 + * @return 参数配置信息 + */ + public SysConfig selectConfig(SysConfig config); + + /** + * 通过ID查询配置 + * + * @param configId 参数ID + * @return 参数配置信息 + */ + public SysConfig selectConfigById(Long configId); + + /** + * 查询参数配置列表 + * + * @param config 参数配置信息 + * @return 参数配置集合 + */ + public List selectConfigList(SysConfig config); + + /** + * 根据键名查询参数配置信息 + * + * @param configKey 参数键名 + * @return 参数配置信息 + */ + public SysConfig checkConfigKeyUnique(String configKey); + + /** + * 新增参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + public int insertConfig(SysConfig config); + + /** + * 修改参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + public int updateConfig(SysConfig config); + + /** + * 删除参数配置 + * + * @param configId 参数ID + * @return 结果 + */ + public int deleteConfigById(Long configId); + + /** + * 批量删除参数信息 + * + * @param configIds 需要删除的参数ID + * @return 结果 + */ + public int deleteConfigByIds(Long[] configIds); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysDeptMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysDeptMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..5b21be49b0550e6643d295927881c63aaec70d5e --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysDeptMapper.java @@ -0,0 +1,121 @@ +package com.RVSmartPorting.core.system.mapper; + +import com.RVSmartPorting.common.core.domain.entity.SysDept; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 部门管理 数据层 + * + * @author ruoyi + */ +@Mapper +public interface SysDeptMapper +{ + /** + * 查询部门管理数据 + * + * @param dept 部门信息 + * @return 部门信息集合 + */ + public List selectDeptList(SysDept dept); + + /** + * 根据角色ID查询部门树信息 + * + * @param roleId 角色ID + * @param deptCheckStrictly 部门树选择项是否关联显示 + * @return 选中部门列表 + */ + public List selectDeptListByRoleId(@Param("roleId") Long roleId, @Param("deptCheckStrictly") boolean deptCheckStrictly); + + /** + * 根据部门ID查询信息 + * + * @param deptId 部门ID + * @return 部门信息 + */ + public SysDept selectDeptById(Long deptId); + + /** + * 根据ID查询所有子部门 + * + * @param deptId 部门ID + * @return 部门列表 + */ + public List selectChildrenDeptById(Long deptId); + + /** + * 根据ID查询所有子部门(正常状态) + * + * @param deptId 部门ID + * @return 子部门数 + */ + public int selectNormalChildrenDeptById(Long deptId); + + /** + * 是否存在子节点 + * + * @param deptId 部门ID + * @return 结果 + */ + public int hasChildByDeptId(Long deptId); + + /** + * 查询部门是否存在用户 + * + * @param deptId 部门ID + * @return 结果 + */ + public int checkDeptExistUser(Long deptId); + + /** + * 校验部门名称是否唯一 + * + * @param deptName 部门名称 + * @param parentId 父部门ID + * @return 结果 + */ + public SysDept checkDeptNameUnique(@Param("deptName") String deptName, @Param("parentId") Long parentId); + + /** + * 新增部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + public int insertDept(SysDept dept); + + /** + * 修改部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + public int updateDept(SysDept dept); + + /** + * 修改所在部门正常状态 + * + * @param deptIds 部门ID组 + */ + public void updateDeptStatusNormal(Long[] deptIds); + + /** + * 修改子元素关系 + * + * @param depts 子元素 + * @return 结果 + */ + public int updateDeptChildren(@Param("depts") List depts); + + /** + * 删除部门管理信息 + * + * @param deptId 部门ID + * @return 结果 + */ + public int deleteDeptById(Long deptId); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysDictDataMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysDictDataMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..009411f2fafcf62ed1d0be6b5b56cea3b733892a --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysDictDataMapper.java @@ -0,0 +1,99 @@ +package com.RVSmartPorting.core.system.mapper; + +import com.RVSmartPorting.common.core.domain.entity.SysDictData; +import com.RVSmartPorting.common.core.domain.entity.SysDictData; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 字典表 数据层 + * + * @author ruoyi + */ +@Mapper +public interface SysDictDataMapper +{ + /** + * 根据条件分页查询字典数据 + * + * @param dictData 字典数据信息 + * @return 字典数据集合信息 + */ + public List selectDictDataList(SysDictData dictData); + + /** + * 根据字典类型查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据集合信息 + */ + public List selectDictDataByType(String dictType); + + /** + * 根据字典类型和字典键值查询字典数据信息 + * + * @param dictType 字典类型 + * @param dictValue 字典键值 + * @return 字典标签 + */ + public String selectDictLabel(@Param("dictType") String dictType, @Param("dictValue") String dictValue); + + /** + * 根据字典数据ID查询信息 + * + * @param dictCode 字典数据ID + * @return 字典数据 + */ + public SysDictData selectDictDataById(Long dictCode); + + /** + * 查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据 + */ + public int countDictDataByType(String dictType); + + /** + * 通过字典ID删除字典数据信息 + * + * @param dictCode 字典数据ID + * @return 结果 + */ + public int deleteDictDataById(Long dictCode); + + /** + * 批量删除字典数据信息 + * + * @param dictCodes 需要删除的字典数据ID + * @return 结果 + */ + public int deleteDictDataByIds(Long[] dictCodes); + + /** + * 新增字典数据信息 + * + * @param dictData 字典数据信息 + * @return 结果 + */ + public int insertDictData(SysDictData dictData); + + /** + * 修改字典数据信息 + * + * @param dictData 字典数据信息 + * @return 结果 + */ + public int updateDictData(SysDictData dictData); + + /** + * 同步修改字典类型 + * + * @param oldDictType 旧字典类型 + * @param newDictType 新旧字典类型 + * @return 结果 + */ + public int updateDictDataType(@Param("oldDictType") String oldDictType, @Param("newDictType") String newDictType); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysDictTypeMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysDictTypeMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..924292c1d260bf2bbda01d8d64198fd4e5155c09 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysDictTypeMapper.java @@ -0,0 +1,86 @@ +package com.RVSmartPorting.core.system.mapper; + +import com.RVSmartPorting.common.core.domain.entity.SysDictType; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 字典表 数据层 + * + * @author ruoyi + */ +@Mapper +public interface SysDictTypeMapper +{ + /** + * 根据条件分页查询字典类型 + * + * @param dictType 字典类型信息 + * @return 字典类型集合信息 + */ + public List selectDictTypeList(SysDictType dictType); + + /** + * 根据所有字典类型 + * + * @return 字典类型集合信息 + */ + public List selectDictTypeAll(); + + /** + * 根据字典类型ID查询信息 + * + * @param dictId 字典类型ID + * @return 字典类型 + */ + public SysDictType selectDictTypeById(Long dictId); + + /** + * 根据字典类型查询信息 + * + * @param dictType 字典类型 + * @return 字典类型 + */ + public SysDictType selectDictTypeByType(String dictType); + + /** + * 通过字典ID删除字典信息 + * + * @param dictId 字典ID + * @return 结果 + */ + public int deleteDictTypeById(Long dictId); + + /** + * 批量删除字典类型信息 + * + * @param dictIds 需要删除的字典ID + * @return 结果 + */ + public int deleteDictTypeByIds(Long[] dictIds); + + /** + * 新增字典类型信息 + * + * @param dictType 字典类型信息 + * @return 结果 + */ + public int insertDictType(SysDictType dictType); + + /** + * 修改字典类型信息 + * + * @param dictType 字典类型信息 + * @return 结果 + */ + public int updateDictType(SysDictType dictType); + + /** + * 校验字典类型称是否唯一 + * + * @param dictType 字典类型 + * @return 结果 + */ + public SysDictType checkDictTypeUnique(String dictType); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysLogininforMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysLogininforMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..950962e70dc6b9e8cd21953e8d00e95d6d7543b6 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysLogininforMapper.java @@ -0,0 +1,46 @@ +package com.RVSmartPorting.core.system.mapper; + + +import com.RVSmartPorting.core.system.domain.SysLogininfor; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 系统访问日志情况信息 数据层 + * + * @author ruoyi + */ +@Mapper +public interface SysLogininforMapper +{ + /** + * 新增系统登录日志 + * + * @param logininfor 访问日志对象 + */ + public void insertLogininfor(SysLogininfor logininfor); + + /** + * 查询系统登录日志集合 + * + * @param logininfor 访问日志对象 + * @return 登录记录集合 + */ + public List selectLogininforList(SysLogininfor logininfor); + + /** + * 批量删除系统登录日志 + * + * @param infoIds 需要删除的登录日志ID + * @return 结果 + */ + public int deleteLogininforByIds(Long[] infoIds); + + /** + * 清空系统登录日志 + * + * @return 结果 + */ + public int cleanLogininfor(); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysMenuMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysMenuMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..c223647afeed652a7d279c6f98b9eeb5588741f3 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysMenuMapper.java @@ -0,0 +1,128 @@ +package com.RVSmartPorting.core.system.mapper; + +import com.RVSmartPorting.common.core.domain.entity.SysMenu; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 菜单表 数据层 + * + * @author ruoyi + */ +@Mapper +public interface SysMenuMapper +{ + /** + * 查询系统菜单列表 + * + * @param menu 菜单信息 + * @return 菜单列表 + */ + public List selectMenuList(SysMenu menu); + + /** + * 根据用户所有权限 + * + * @return 权限列表 + */ + public List selectMenuPerms(); + + /** + * 根据用户查询系统菜单列表 + * + * @param menu 菜单信息 + * @return 菜单列表 + */ + public List selectMenuListByUserId(SysMenu menu); + + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + public List selectMenuPermsByRoleId(Long roleId); + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + public List selectMenuPermsByUserId(Long userId); + + /** + * 根据用户ID查询菜单 + * + * @return 菜单列表 + */ + public List selectMenuTreeAll(); + + /** + * 根据用户ID查询菜单 + * + * @param userId 用户ID + * @return 菜单列表 + */ + public List selectMenuTreeByUserId(Long userId); + + /** + * 根据角色ID查询菜单树信息 + * + * @param roleId 角色ID + * @param menuCheckStrictly 菜单树选择项是否关联显示 + * @return 选中菜单列表 + */ + public List selectMenuListByRoleId(@Param("roleId") Long roleId, @Param("menuCheckStrictly") boolean menuCheckStrictly); + + /** + * 根据菜单ID查询信息 + * + * @param menuId 菜单ID + * @return 菜单信息 + */ + public SysMenu selectMenuById(Long menuId); + + /** + * 是否存在菜单子节点 + * + * @param menuId 菜单ID + * @return 结果 + */ + public int hasChildByMenuId(Long menuId); + + /** + * 新增菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + public int insertMenu(SysMenu menu); + + /** + * 修改菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + public int updateMenu(SysMenu menu); + + /** + * 删除菜单管理信息 + * + * @param menuId 菜单ID + * @return 结果 + */ + public int deleteMenuById(Long menuId); + + /** + * 校验菜单名称是否唯一 + * + * @param menuName 菜单名称 + * @param parentId 父菜单ID + * @return 结果 + */ + public SysMenu checkMenuNameUnique(@Param("menuName") String menuName, @Param("parentId") Long parentId); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysNoticeMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysNoticeMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..d14c4a9e8b3081e8f6b6ca06f3efd7aae25f5825 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysNoticeMapper.java @@ -0,0 +1,64 @@ +package com.RVSmartPorting.core.system.mapper; + + +import com.RVSmartPorting.core.system.domain.SysNotice; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 通知公告表 数据层 + * + * @author ruoyi + */ +@Mapper +public interface SysNoticeMapper +{ + /** + * 查询公告信息 + * + * @param noticeId 公告ID + * @return 公告信息 + */ + public SysNotice selectNoticeById(Long noticeId); + + /** + * 查询公告列表 + * + * @param notice 公告信息 + * @return 公告集合 + */ + public List selectNoticeList(SysNotice notice); + + /** + * 新增公告 + * + * @param notice 公告信息 + * @return 结果 + */ + public int insertNotice(SysNotice notice); + + /** + * 修改公告 + * + * @param notice 公告信息 + * @return 结果 + */ + public int updateNotice(SysNotice notice); + + /** + * 批量删除公告 + * + * @param noticeId 公告ID + * @return 结果 + */ + public int deleteNoticeById(Long noticeId); + + /** + * 批量删除公告信息 + * + * @param noticeIds 需要删除的公告ID + * @return 结果 + */ + public int deleteNoticeByIds(Long[] noticeIds); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysOperLogMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysOperLogMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..07f1d9474a9bba2d861fed43bf3d23b9ae064c1a --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysOperLogMapper.java @@ -0,0 +1,52 @@ +package com.RVSmartPorting.core.system.mapper; + + +import com.RVSmartPorting.core.system.domain.SysOperLog; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 操作日志 数据层 + * + * @author ruoyi + */ +@Mapper +public interface SysOperLogMapper +{ + /** + * 新增操作日志 + * + * @param operLog 操作日志对象 + */ + public void insertOperlog(SysOperLog operLog); + + /** + * 查询系统操作日志集合 + * + * @param operLog 操作日志对象 + * @return 操作日志集合 + */ + public List selectOperLogList(SysOperLog operLog); + + /** + * 批量删除系统操作日志 + * + * @param operIds 需要删除的操作日志ID + * @return 结果 + */ + public int deleteOperLogByIds(Long[] operIds); + + /** + * 查询操作日志详细 + * + * @param operId 操作ID + * @return 操作日志对象 + */ + public SysOperLog selectOperLogById(Long operId); + + /** + * 清空操作日志 + */ + public void cleanOperLog(); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysPostMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysPostMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..7d20a5c8cff35707768398d01dd8daca527e7169 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysPostMapper.java @@ -0,0 +1,102 @@ +package com.RVSmartPorting.core.system.mapper; + +import com.RVSmartPorting.core.system.domain.SysPost; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 岗位信息 数据层 + * + * @author ruoyi + */ +@Mapper +public interface SysPostMapper +{ + /** + * 查询岗位数据集合 + * + * @param post 岗位信息 + * @return 岗位数据集合 + */ + public List selectPostList(SysPost post); + + /** + * 查询所有岗位 + * + * @return 岗位列表 + */ + public List selectPostAll(); + + /** + * 通过岗位ID查询岗位信息 + * + * @param postId 岗位ID + * @return 角色对象信息 + */ + public SysPost selectPostById(Long postId); + + /** + * 根据用户ID获取岗位选择框列表 + * + * @param userId 用户ID + * @return 选中岗位ID列表 + */ + public List selectPostListByUserId(Long userId); + + /** + * 查询用户所属岗位组 + * + * @param userName 用户名 + * @return 结果 + */ + public List selectPostsByUserName(String userName); + + /** + * 删除岗位信息 + * + * @param postId 岗位ID + * @return 结果 + */ + public int deletePostById(Long postId); + + /** + * 批量删除岗位信息 + * + * @param postIds 需要删除的岗位ID + * @return 结果 + */ + public int deletePostByIds(Long[] postIds); + + /** + * 修改岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + public int updatePost(SysPost post); + + /** + * 新增岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + public int insertPost(SysPost post); + + /** + * 校验岗位名称 + * + * @param postName 岗位名称 + * @return 结果 + */ + public SysPost checkPostNameUnique(String postName); + + /** + * 校验岗位编码 + * + * @param postCode 岗位编码 + * @return 结果 + */ + public SysPost checkPostCodeUnique(String postCode); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysRoleDeptMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysRoleDeptMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..8fb03ddb7b7406f98d0de85288bd456af798aa3b --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysRoleDeptMapper.java @@ -0,0 +1,48 @@ +package com.RVSmartPorting.core.system.mapper; + + +import com.RVSmartPorting.core.system.domain.SysRoleDept; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 角色与部门关联表 数据层 + * + * @author ruoyi + */ +@Mapper +public interface SysRoleDeptMapper +{ + /** + * 通过角色ID删除角色和部门关联 + * + * @param roleId 角色ID + * @return 结果 + */ + public int deleteRoleDeptByRoleId(Long roleId); + + /** + * 批量删除角色部门关联信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteRoleDept(Long[] ids); + + /** + * 查询部门使用数量 + * + * @param deptId 部门ID + * @return 结果 + */ + public int selectCountRoleDeptByDeptId(Long deptId); + + /** + * 批量新增角色部门信息 + * + * @param roleDeptList 角色部门列表 + * @return 结果 + */ + public int batchRoleDept(List roleDeptList); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysRoleMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysRoleMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..e6f8e4ee80b80d04fd34ec1ba642731a946f1ef7 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysRoleMapper.java @@ -0,0 +1,110 @@ +package com.RVSmartPorting.core.system.mapper; + +import com.RVSmartPorting.common.core.domain.entity.SysRole; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 角色表 数据层 + * + * @author ruoyi + */ +@Mapper +public interface SysRoleMapper +{ + /** + * 根据条件分页查询角色数据 + * + * @param role 角色信息 + * @return 角色数据集合信息 + */ + public List selectRoleList(SysRole role); + + /** + * 根据用户ID查询角色 + * + * @param userId 用户ID + * @return 角色列表 + */ + public List selectRolePermissionByUserId(Long userId); + + /** + * 查询所有角色 + * + * @return 角色列表 + */ + public List selectRoleAll(); + + /** + * 根据用户ID获取角色选择框列表 + * + * @param userId 用户ID + * @return 选中角色ID列表 + */ + public List selectRoleListByUserId(Long userId); + + /** + * 通过角色ID查询角色 + * + * @param roleId 角色ID + * @return 角色对象信息 + */ + public SysRole selectRoleById(Long roleId); + + /** + * 根据用户ID查询角色 + * + * @param userName 用户名 + * @return 角色列表 + */ + public List selectRolesByUserName(String userName); + + /** + * 校验角色名称是否唯一 + * + * @param roleName 角色名称 + * @return 角色信息 + */ + public SysRole checkRoleNameUnique(String roleName); + + /** + * 校验角色权限是否唯一 + * + * @param roleKey 角色权限 + * @return 角色信息 + */ + public SysRole checkRoleKeyUnique(String roleKey); + + /** + * 修改角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + public int updateRole(SysRole role); + + /** + * 新增角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + public int insertRole(SysRole role); + + /** + * 通过角色ID删除角色 + * + * @param roleId 角色ID + * @return 结果 + */ + public int deleteRoleById(Long roleId); + + /** + * 批量删除角色信息 + * + * @param roleIds 需要删除的角色ID + * @return 结果 + */ + public int deleteRoleByIds(Long[] roleIds); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysRoleMenuMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysRoleMenuMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..eb07f8ad6ec58fa3bb55e692d63f10a95e2cfbe6 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysRoleMenuMapper.java @@ -0,0 +1,48 @@ +package com.RVSmartPorting.core.system.mapper; + + +import com.RVSmartPorting.core.system.domain.SysRoleMenu; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 角色与菜单关联表 数据层 + * + * @author ruoyi + */ +@Mapper +public interface SysRoleMenuMapper +{ + /** + * 查询菜单使用数量 + * + * @param menuId 菜单ID + * @return 结果 + */ + public int checkMenuExistRole(Long menuId); + + /** + * 通过角色ID删除角色和菜单关联 + * + * @param roleId 角色ID + * @return 结果 + */ + public int deleteRoleMenuByRoleId(Long roleId); + + /** + * 批量删除角色菜单关联信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteRoleMenu(Long[] ids); + + /** + * 批量新增角色菜单信息 + * + * @param roleMenuList 角色菜单列表 + * @return 结果 + */ + public int batchRoleMenu(List roleMenuList); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysUserMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysUserMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..480caae4319c8e4fd1554ec38fae037b154057f3 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysUserMapper.java @@ -0,0 +1,130 @@ +package com.RVSmartPorting.core.system.mapper; + +import com.RVSmartPorting.common.core.domain.entity.SysUser; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户表 数据层 + * + * @author ruoyi + */ +@Mapper +public interface SysUserMapper +{ + /** + * 根据条件分页查询用户列表 + * + * @param sysUser 用户信息 + * @return 用户信息集合信息 + */ + public List selectUserList(SysUser sysUser); + + /** + * 根据条件分页查询已配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + public List selectAllocatedList(SysUser user); + + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + public List selectUnallocatedList(SysUser user); + + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + public SysUser selectUserByUserName(String userName); + + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + public SysUser selectUserById(Long userId); + + /** + * 新增用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + public int insertUser(SysUser user); + + /** + * 修改用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + public int updateUser(SysUser user); + + /** + * 修改用户头像 + * + * @param userName 用户名 + * @param avatar 头像地址 + * @return 结果 + */ + public int updateUserAvatar(@Param("userName") String userName, @Param("avatar") String avatar); + + /** + * 重置用户密码 + * + * @param userName 用户名 + * @param password 密码 + * @return 结果 + */ + public int resetUserPwd(@Param("userName") String userName, @Param("password") String password); + + /** + * 通过用户ID删除用户 + * + * @param userId 用户ID + * @return 结果 + */ + public int deleteUserById(Long userId); + + /** + * 批量删除用户信息 + * + * @param userIds 需要删除的用户ID + * @return 结果 + */ + public int deleteUserByIds(Long[] userIds); + + /** + * 校验用户名称是否唯一 + * + * @param userName 用户名称 + * @return 结果 + */ + public SysUser checkUserNameUnique(String userName); + + /** + * 校验手机号码是否唯一 + * + * @param phonenumber 手机号码 + * @return 结果 + */ + public SysUser checkPhoneUnique(String phonenumber); + + /** + * 校验email是否唯一 + * + * @param email 用户邮箱 + * @return 结果 + */ + public SysUser checkEmailUnique(String email); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysUserPostMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysUserPostMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..ec7856b4434d53296130f7437e949b4801fe33d3 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysUserPostMapper.java @@ -0,0 +1,48 @@ +package com.RVSmartPorting.core.system.mapper; + + +import com.RVSmartPorting.core.system.domain.SysUserPost; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 用户与岗位关联表 数据层 + * + * @author ruoyi + */ +@Mapper +public interface SysUserPostMapper +{ + /** + * 通过用户ID删除用户和岗位关联 + * + * @param userId 用户ID + * @return 结果 + */ + public int deleteUserPostByUserId(Long userId); + + /** + * 通过岗位ID查询岗位使用数量 + * + * @param postId 岗位ID + * @return 结果 + */ + public int countUserPostById(Long postId); + + /** + * 批量删除用户和岗位关联 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteUserPost(Long[] ids); + + /** + * 批量新增用户岗位信息 + * + * @param userPostList 用户角色列表 + * @return 结果 + */ + public int batchUserPost(List userPostList); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysUserRoleMapper.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysUserRoleMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..0ef9b5ef2e10614debc4f8d7a95e9aaa7b6039ee --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/mapper/SysUserRoleMapper.java @@ -0,0 +1,65 @@ +package com.RVSmartPorting.core.system.mapper; + +import com.RVSmartPorting.core.system.domain.SysUserRole; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户与角色关联表 数据层 + * + * @author ruoyi + */ +@Mapper +public interface SysUserRoleMapper +{ + /** + * 通过用户ID删除用户和角色关联 + * + * @param userId 用户ID + * @return 结果 + */ + public int deleteUserRoleByUserId(Long userId); + + /** + * 批量删除用户和角色关联 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteUserRole(Long[] ids); + + /** + * 通过角色ID查询角色使用数量 + * + * @param roleId 角色ID + * @return 结果 + */ + public int countUserRoleByRoleId(Long roleId); + + /** + * 批量新增用户角色信息 + * + * @param userRoleList 用户角色列表 + * @return 结果 + */ + public int batchUserRole(List userRoleList); + + /** + * 删除用户和角色关联信息 + * + * @param userRole 用户和角色关联信息 + * @return 结果 + */ + public int deleteUserRoleInfo(SysUserRole userRole); + + /** + * 批量取消授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要删除的用户数据ID + * @return 结果 + */ + public int deleteUserRoleInfos(@Param("roleId") Long roleId, @Param("userIds") Long[] userIds); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ICodeProjectService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ICodeProjectService.java new file mode 100644 index 0000000000000000000000000000000000000000..06f4a1e92686d05ddbd4d1cebeece640cd02eec3 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ICodeProjectService.java @@ -0,0 +1,96 @@ +package com.RVSmartPorting.core.system.service; + +import java.util.List; + +import com.RVSmartPorting.common.core.domain.entity.SysUser; +import com.RVSmartPorting.common.utils.http.FileDownloadListener; +import com.RVSmartPorting.core.system.domain.CodeProject; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +/** + * 代码项目信息Service接口 + * + * @author ruoyi + * @date 2023-08-24 + */ +public interface ICodeProjectService { + /** + * 查询代码项目信息 + * + * @param codeProjectId 代码项目信息主键 + * @return 代码项目信息 + */ + public CodeProject selectCodeProjectByCodeProjectId(Long codeProjectId); + + String upload(SysUser user, MultipartFile file, String uploadType, Long codeProjectId, String repositoryType, + String projectRepositoryURL, + String branchName, + String downloadLink, + String authenticationMethod, + String username, + String password, + String personalAccessToken) throws Exception; + + /** + * 下载文件方法 + * 异步请求 + * + * @param url 下载连接 + * @param destFileDir 下载的文件储存目录 + * @param destFileName 下载文件名称,后面记得拼接后缀 + */ + public String downloadFilesAsynchronous(String url, String destFileDir, String destFileName, String userUUID, + CodeProject codeProject); + + + public String gitDownloadFilesAsynchronous(String remoteRepositoryURI, String localRepositoryPath, + String branchName, + String authenticationMethod, + String username, + String password, + String personalAccessToken, + String userUUID, + CodeProject codeProject, + String repositoryType) throws Exception; + + /** + * 查询代码项目信息列表 + * + * @param codeProject 代码项目信息 + * @return 代码项目信息集合 + */ + public List selectCodeProjectList(CodeProject codeProject); + + /** + * 新增代码项目信息 + * + * @param codeProject 代码项目信息 + * @return 结果 + */ + public int insertCodeProject(CodeProject codeProject); + + /** + * 修改代码项目信息 + * + * @param codeProject 代码项目信息 + * @return 结果 + */ + public int updateCodeProject(CodeProject codeProject); + + /** + * 批量删除代码项目信息 + * + * @param codeProjectIds 需要删除的代码项目信息主键集合 + * @return 结果 + */ + public int deleteCodeProjectByCodeProjectIds(Long[] codeProjectIds); + + /** + * 删除代码项目信息信息 + * + * @param codeProjectId 代码项目信息主键 + * @return 结果 + */ + public int deleteCodeProjectByCodeProjectId(Long codeProjectId); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/IGitNetworkSettingService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/IGitNetworkSettingService.java new file mode 100644 index 0000000000000000000000000000000000000000..b6fc0b7c0e1838ae654f4b598b189d99401ce41b --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/IGitNetworkSettingService.java @@ -0,0 +1,62 @@ +package com.RVSmartPorting.core.system.service; + +import java.util.List; +import com.RVSmartPorting.core.system.domain.GitNetworkSetting; + +/** + * git网络镜像代理配置Service接口 + * + * @author ruoyi + * @date 2023-09-09 + */ +public interface IGitNetworkSettingService +{ + /** + * 查询git网络镜像代理配置 + * + * @param gitNetworkSettingId git网络镜像代理配置主键 + * @return git网络镜像代理配置 + */ + public GitNetworkSetting selectGitNetworkSettingByGitNetworkSettingId(Long gitNetworkSettingId); + + /** + * 查询git网络镜像代理配置列表 + * + * @param gitNetworkSetting git网络镜像代理配置 + * @return git网络镜像代理配置集合 + */ + public List selectGitNetworkSettingList(GitNetworkSetting gitNetworkSetting); + + + /** + * 新增git网络镜像代理配置 + * + * @param gitNetworkSetting git网络镜像代理配置 + * @return 结果 + */ + public int insertGitNetworkSetting(GitNetworkSetting gitNetworkSetting); + + /** + * 修改git网络镜像代理配置 + * + * @param gitNetworkSetting git网络镜像代理配置 + * @return 结果 + */ + public int updateGitNetworkSetting(GitNetworkSetting gitNetworkSetting); + + /** + * 批量删除git网络镜像代理配置 + * + * @param gitNetworkSettingIds 需要删除的git网络镜像代理配置主键集合 + * @return 结果 + */ + public int deleteGitNetworkSettingByGitNetworkSettingIds(Long[] gitNetworkSettingIds); + + /** + * 删除git网络镜像代理配置信息 + * + * @param gitNetworkSettingId git网络镜像代理配置主键 + * @return 结果 + */ + public int deleteGitNetworkSettingByGitNetworkSettingId(Long gitNetworkSettingId); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/IRuleService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/IRuleService.java new file mode 100644 index 0000000000000000000000000000000000000000..785eb1994a9b264fce2afc5fda4adc925ecbfc76 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/IRuleService.java @@ -0,0 +1,62 @@ +package com.RVSmartPorting.core.system.service; + +import com.RVSmartPorting.core.system.domain.Rule; + +import java.util.List; + +/** + * 规则信息Service接口 + * + * @author ruoyi + * @date 2023-08-15 + */ +public interface IRuleService +{ + /** + * 查询规则信息 + * + * @param ruleId 规则信息主键 + * @return 规则信息 + */ + public Rule selectRuleByRuleId(Long ruleId); + + /** + * 查询规则信息列表 + * + * @param rule 规则信息 + * @return 规则信息集合 + */ + public List selectRuleList(Rule rule); + + /** + * 新增规则信息 + * + * @param rule 规则信息 + * @return 结果 + */ + public int insertRule(Rule rule); + + /** + * 修改规则信息 + * + * @param rule 规则信息 + * @return 结果 + */ + public int updateRule(Rule rule); + + /** + * 批量删除规则信息 + * + * @param ruleIds 需要删除的规则信息主键集合 + * @return 结果 + */ + public int deleteRuleByRuleIds(Long[] ruleIds); + + /** + * 删除规则信息信息 + * + * @param ruleId 规则信息主键 + * @return 结果 + */ + public int deleteRuleByRuleId(Long ruleId); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/IRuleSetService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/IRuleSetService.java new file mode 100644 index 0000000000000000000000000000000000000000..48ae77b86faa2ad30fb143e405c7b97db323b452 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/IRuleSetService.java @@ -0,0 +1,62 @@ +package com.RVSmartPorting.core.system.service; + +import java.util.List; + +import com.RVSmartPorting.core.system.domain.RuleSet; + +/** + * 规则集信息Service接口 + * + * @author ruoyi + * @date 2023-08-16 + */ +public interface IRuleSetService +{ + /** + * 查询规则集信息 + * + * @param ruleSetId 规则集信息主键 + * @return 规则集信息 + */ + public RuleSet selectRuleSetByRuleSetId(Long ruleSetId); + + /** + * 查询规则集信息列表 + * + * @param ruleSet 规则集信息 + * @return 规则集信息集合 + */ + public List selectRuleSetList(RuleSet ruleSet); + + /** + * 新增规则集信息 + * + * @param ruleSet 规则集信息 + * @return 结果 + */ + public int insertRuleSet(RuleSet ruleSet); + + /** + * 修改规则集信息 + * + * @param ruleSet 规则集信息 + * @return 结果 + */ + public int updateRuleSet(RuleSet ruleSet); + + /** + * 批量删除规则集信息 + * + * @param ruleSetIds 需要删除的规则集信息主键集合 + * @return 结果 + */ + public int deleteRuleSetByRuleSetIds(Long[] ruleSetIds); + + /** + * 删除规则集信息信息 + * + * @param ruleSetId 规则集信息主键 + * @return 结果 + */ + public int deleteRuleSetByRuleSetId(Long ruleSetId); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/IScanTaskService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/IScanTaskService.java new file mode 100644 index 0000000000000000000000000000000000000000..1c8ed7060a439ae064dfa526bf3a064718fecf85 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/IScanTaskService.java @@ -0,0 +1,68 @@ +package com.RVSmartPorting.core.system.service; + +import com.RVSmartPorting.core.system.domain.ScanTask; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +/** + * 代码扫描任务信息Service接口 + * + * @author ruoyi + * @date 2023-09-17 + */ +public interface IScanTaskService +{ + /** + * 查询代码扫描任务信息 + * + * @param taskId 代码扫描任务信息主键 + * @return 代码扫描任务信息 + */ + public ScanTask selectScanTaskByTaskId(Long taskId); + + + public Map getScanToolConfigVariablesMap(ScanTask scanTask); + public Map getNotCustomizableEnabledScanToolConfigVariablesMap(ScanTask scanTask); + + /** + * 查询代码扫描任务信息列表 + * + * @param scanTask 代码扫描任务信息 + * @return 代码扫描任务信息集合 + */ + public List selectScanTaskList(ScanTask scanTask); + + /** + * 新增代码扫描任务信息 + * + * @param scanTask 代码扫描任务信息 + * @return 结果 + */ + public int insertScanTask(ScanTask scanTask); + + /** + * 修改代码扫描任务信息 + * + * @param scanTask 代码扫描任务信息 + * @return 结果 + */ + public int updateScanTask(ScanTask scanTask); + + /** + * 批量删除代码扫描任务信息 + * + * @param taskIds 需要删除的代码扫描任务信息主键集合 + * @return 结果 + */ + public int deleteScanTaskByTaskIds(Long[] taskIds); + + /** + * 删除代码扫描任务信息信息 + * + * @param taskId 代码扫描任务信息主键 + * @return 结果 + */ + public int deleteScanTaskByTaskId(Long taskId); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/IScanToolConfigService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/IScanToolConfigService.java new file mode 100644 index 0000000000000000000000000000000000000000..4e0d02574f5c31052a0f07bb42a70ba0ef36f204 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/IScanToolConfigService.java @@ -0,0 +1,62 @@ +package com.RVSmartPorting.core.system.service; + +import com.RVSmartPorting.core.system.domain.ScanToolConfig; + +import java.util.List; + +/** + * 扫描工具配置Service接口 + * + * @author xuqiangli + * @date 2023-09-22 + */ +public interface IScanToolConfigService +{ + /** + * 查询扫描工具配置 + * + * @param scanToolConfigId 扫描工具配置主键 + * @return 扫描工具配置 + */ + public ScanToolConfig selectScanToolConfigByScanToolConfigId(Long scanToolConfigId); + + /** + * 查询扫描工具配置列表 + * + * @param scanToolConfig 扫描工具配置 + * @return 扫描工具配置集合 + */ + public List selectScanToolConfigList(ScanToolConfig scanToolConfig); + + /** + * 新增扫描工具配置 + * + * @param scanToolConfig 扫描工具配置 + * @return 结果 + */ + public int insertScanToolConfig(ScanToolConfig scanToolConfig); + + /** + * 修改扫描工具配置 + * + * @param scanToolConfig 扫描工具配置 + * @return 结果 + */ + public int updateScanToolConfig(ScanToolConfig scanToolConfig); + + /** + * 批量删除扫描工具配置 + * + * @param scanToolConfigIds 需要删除的扫描工具配置主键集合 + * @return 结果 + */ + public int deleteScanToolConfigByScanToolConfigIds(Long[] scanToolConfigIds); + + /** + * 删除扫描工具配置信息 + * + * @param scanToolConfigId 扫描工具配置主键 + * @return 结果 + */ + public int deleteScanToolConfigByScanToolConfigId(Long scanToolConfigId); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/IScanToolService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/IScanToolService.java new file mode 100644 index 0000000000000000000000000000000000000000..a903d9a1b5d0543196592e4aedee47021a788149 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/IScanToolService.java @@ -0,0 +1,62 @@ +package com.RVSmartPorting.core.system.service; + +import com.RVSmartPorting.core.system.domain.ScanTool; + +import java.util.List; + +/** + * 扫描工具Service接口 + * + * @author ruoyi + * @date 2023-09-17 + */ +public interface IScanToolService +{ + /** + * 查询扫描工具 + * + * @param scanToolId 扫描工具主键 + * @return 扫描工具 + */ + public ScanTool selectScanToolByScanToolId(Long scanToolId); + + /** + * 查询扫描工具列表 + * + * @param scanTool 扫描工具 + * @return 扫描工具集合 + */ + public List selectScanToolList(ScanTool scanTool); + + /** + * 新增扫描工具 + * + * @param scanTool 扫描工具 + * @return 结果 + */ + public int insertScanTool(ScanTool scanTool); + + /** + * 修改扫描工具 + * + * @param scanTool 扫描工具 + * @return 结果 + */ + public int updateScanTool(ScanTool scanTool); + + /** + * 批量删除扫描工具 + * + * @param scanToolIds 需要删除的扫描工具主键集合 + * @return 结果 + */ + public int deleteScanToolByScanToolIds(Long[] scanToolIds); + + /** + * 删除扫描工具信息 + * + * @param scanToolId 扫描工具主键 + * @return 结果 + */ + public int deleteScanToolByScanToolId(Long scanToolId); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysConfigService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysConfigService.java new file mode 100644 index 0000000000000000000000000000000000000000..2577a217b02d161505454ebf75cb698d8e17768d --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysConfigService.java @@ -0,0 +1,90 @@ +package com.RVSmartPorting.core.system.service; + +import com.RVSmartPorting.core.system.domain.SysConfig; + +import java.util.List; + +/** + * 参数配置 服务层 + * + * @author ruoyi + */ +public interface ISysConfigService +{ + /** + * 查询参数配置信息 + * + * @param configId 参数配置ID + * @return 参数配置信息 + */ + public SysConfig selectConfigById(Long configId); + + /** + * 根据键名查询参数配置信息 + * + * @param configKey 参数键名 + * @return 参数键值 + */ + public String selectConfigByKey(String configKey); + + /** + * 获取验证码开关 + * + * @return true开启,false关闭 + */ + public boolean selectCaptchaEnabled(); + + /** + * 查询参数配置列表 + * + * @param config 参数配置信息 + * @return 参数配置集合 + */ + public List selectConfigList(SysConfig config); + + /** + * 新增参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + public int insertConfig(SysConfig config); + + /** + * 修改参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + public int updateConfig(SysConfig config); + + /** + * 批量删除参数信息 + * + * @param configIds 需要删除的参数ID + */ + public void deleteConfigByIds(Long[] configIds); + + /** + * 加载参数缓存数据 + */ + public void loadingConfigCache(); + + /** + * 清空参数缓存数据 + */ + public void clearConfigCache(); + + /** + * 重置参数缓存数据 + */ + public void resetConfigCache(); + + /** + * 校验参数键名是否唯一 + * + * @param config 参数信息 + * @return 结果 + */ + public boolean checkConfigKeyUnique(SysConfig config); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysDeptService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysDeptService.java new file mode 100644 index 0000000000000000000000000000000000000000..2339069fd609db73e46ba239491df5c0b470671f --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysDeptService.java @@ -0,0 +1,127 @@ +package com.RVSmartPorting.core.system.service; + +import com.RVSmartPorting.common.core.domain.TreeSelect; +import com.RVSmartPorting.common.core.domain.entity.SysDept; +import com.RVSmartPorting.common.core.domain.TreeSelect; +import com.RVSmartPorting.common.core.domain.entity.SysDept; + +import java.util.List; + +/** + * 部门管理 服务层 + * + * @author ruoyi + */ +public interface ISysDeptService +{ + /** + * 查询部门管理数据 + * + * @param dept 部门信息 + * @return 部门信息集合 + */ + public List selectDeptList(SysDept dept); + + /** + * 查询部门树结构信息 + * + * @param dept 部门信息 + * @return 部门树信息集合 + */ + public List selectDeptTreeList(SysDept dept); + + /** + * 构建前端所需要树结构 + * + * @param depts 部门列表 + * @return 树结构列表 + */ + public List buildDeptTree(List depts); + + /** + * 构建前端所需要下拉树结构 + * + * @param depts 部门列表 + * @return 下拉树结构列表 + */ + public List buildDeptTreeSelect(List depts); + + /** + * 根据角色ID查询部门树信息 + * + * @param roleId 角色ID + * @return 选中部门列表 + */ + public List selectDeptListByRoleId(Long roleId); + + /** + * 根据部门ID查询信息 + * + * @param deptId 部门ID + * @return 部门信息 + */ + public SysDept selectDeptById(Long deptId); + + /** + * 根据ID查询所有子部门(正常状态) + * + * @param deptId 部门ID + * @return 子部门数 + */ + public int selectNormalChildrenDeptById(Long deptId); + + /** + * 是否存在部门子节点 + * + * @param deptId 部门ID + * @return 结果 + */ + public boolean hasChildByDeptId(Long deptId); + + /** + * 查询部门是否存在用户 + * + * @param deptId 部门ID + * @return 结果 true 存在 false 不存在 + */ + public boolean checkDeptExistUser(Long deptId); + + /** + * 校验部门名称是否唯一 + * + * @param dept 部门信息 + * @return 结果 + */ + public boolean checkDeptNameUnique(SysDept dept); + + /** + * 校验部门是否有数据权限 + * + * @param deptId 部门id + */ + public void checkDeptDataScope(Long deptId); + + /** + * 新增保存部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + public int insertDept(SysDept dept); + + /** + * 修改保存部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + public int updateDept(SysDept dept); + + /** + * 删除部门管理信息 + * + * @param deptId 部门ID + * @return 结果 + */ + public int deleteDeptById(Long deptId); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysDictDataService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysDictDataService.java new file mode 100644 index 0000000000000000000000000000000000000000..2141c16eaf730bd4b024941bf990e307f6feef7b --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysDictDataService.java @@ -0,0 +1,61 @@ +package com.RVSmartPorting.core.system.service; + +import com.RVSmartPorting.common.core.domain.entity.SysDictData; + +import java.util.List; + +/** + * 字典 业务层 + * + * @author ruoyi + */ +public interface ISysDictDataService +{ + /** + * 根据条件分页查询字典数据 + * + * @param dictData 字典数据信息 + * @return 字典数据集合信息 + */ + public List selectDictDataList(SysDictData dictData); + + /** + * 根据字典类型和字典键值查询字典数据信息 + * + * @param dictType 字典类型 + * @param dictValue 字典键值 + * @return 字典标签 + */ + public String selectDictLabel(String dictType, String dictValue); + + /** + * 根据字典数据ID查询信息 + * + * @param dictCode 字典数据ID + * @return 字典数据 + */ + public SysDictData selectDictDataById(Long dictCode); + + /** + * 批量删除字典数据信息 + * + * @param dictCodes 需要删除的字典数据ID + */ + public void deleteDictDataByIds(Long[] dictCodes); + + /** + * 新增保存字典数据信息 + * + * @param dictData 字典数据信息 + * @return 结果 + */ + public int insertDictData(SysDictData dictData); + + /** + * 修改保存字典数据信息 + * + * @param dictData 字典数据信息 + * @return 结果 + */ + public int updateDictData(SysDictData dictData); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysDictTypeService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysDictTypeService.java new file mode 100644 index 0000000000000000000000000000000000000000..ed364002b7ee611b537d09bf1c9950f549b2c42c --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysDictTypeService.java @@ -0,0 +1,99 @@ +package com.RVSmartPorting.core.system.service; + +import com.RVSmartPorting.common.core.domain.entity.SysDictData; +import com.RVSmartPorting.common.core.domain.entity.SysDictType; + +import java.util.List; + +/** + * 字典 业务层 + * + * @author ruoyi + */ +public interface ISysDictTypeService +{ + /** + * 根据条件分页查询字典类型 + * + * @param dictType 字典类型信息 + * @return 字典类型集合信息 + */ + public List selectDictTypeList(SysDictType dictType); + + /** + * 根据所有字典类型 + * + * @return 字典类型集合信息 + */ + public List selectDictTypeAll(); + + /** + * 根据字典类型查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据集合信息 + */ + public List selectDictDataByType(String dictType); + + /** + * 根据字典类型ID查询信息 + * + * @param dictId 字典类型ID + * @return 字典类型 + */ + public SysDictType selectDictTypeById(Long dictId); + + /** + * 根据字典类型查询信息 + * + * @param dictType 字典类型 + * @return 字典类型 + */ + public SysDictType selectDictTypeByType(String dictType); + + /** + * 批量删除字典信息 + * + * @param dictIds 需要删除的字典ID + */ + public void deleteDictTypeByIds(Long[] dictIds); + + /** + * 加载字典缓存数据 + */ + public void loadingDictCache(); + + /** + * 清空字典缓存数据 + */ + public void clearDictCache(); + + /** + * 重置字典缓存数据 + */ + public void resetDictCache(); + + /** + * 新增保存字典类型信息 + * + * @param dictType 字典类型信息 + * @return 结果 + */ + public int insertDictType(SysDictType dictType); + + /** + * 修改保存字典类型信息 + * + * @param dictType 字典类型信息 + * @return 结果 + */ + public int updateDictType(SysDictType dictType); + + /** + * 校验字典类型称是否唯一 + * + * @param dictType 字典类型 + * @return 结果 + */ + public boolean checkDictTypeUnique(SysDictType dictType); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysLogininforService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysLogininforService.java new file mode 100644 index 0000000000000000000000000000000000000000..42a73e59187b4509ad480fbd228a4ddabecd357e --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysLogininforService.java @@ -0,0 +1,41 @@ +package com.RVSmartPorting.core.system.service; + +import com.RVSmartPorting.core.system.domain.SysLogininfor; + +import java.util.List; + +/** + * 系统访问日志情况信息 服务层 + * + * @author ruoyi + */ +public interface ISysLogininforService +{ + /** + * 新增系统登录日志 + * + * @param logininfor 访问日志对象 + */ + public void insertLogininfor(SysLogininfor logininfor); + + /** + * 查询系统登录日志集合 + * + * @param logininfor 访问日志对象 + * @return 登录记录集合 + */ + public List selectLogininforList(SysLogininfor logininfor); + + /** + * 批量删除系统登录日志 + * + * @param infoIds 需要删除的登录日志ID + * @return 结果 + */ + public int deleteLogininforByIds(Long[] infoIds); + + /** + * 清空系统登录日志 + */ + public void cleanLogininfor(); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysMenuService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysMenuService.java new file mode 100644 index 0000000000000000000000000000000000000000..0f1f9fcf2c57abff3802ae442419b6a6535b7c78 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysMenuService.java @@ -0,0 +1,145 @@ +package com.RVSmartPorting.core.system.service; + +import com.RVSmartPorting.common.core.domain.TreeSelect; +import com.RVSmartPorting.common.core.domain.entity.SysMenu; +import com.RVSmartPorting.core.system.domain.vo.RouterVo; + +import java.util.List; +import java.util.Set; + +/** + * 菜单 业务层 + * + * @author ruoyi + */ +public interface ISysMenuService +{ + /** + * 根据用户查询系统菜单列表 + * + * @param userId 用户ID + * @return 菜单列表 + */ + public List selectMenuList(Long userId); + + /** + * 根据用户查询系统菜单列表 + * + * @param menu 菜单信息 + * @param userId 用户ID + * @return 菜单列表 + */ + public List selectMenuList(SysMenu menu, Long userId); + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + public Set selectMenuPermsByUserId(Long userId); + + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + public Set selectMenuPermsByRoleId(Long roleId); + + /** + * 根据用户ID查询菜单树信息 + * + * @param userId 用户ID + * @return 菜单列表 + */ + public List selectMenuTreeByUserId(Long userId); + + /** + * 根据角色ID查询菜单树信息 + * + * @param roleId 角色ID + * @return 选中菜单列表 + */ + public List selectMenuListByRoleId(Long roleId); + + /** + * 构建前端路由所需要的菜单 + * + * @param menus 菜单列表 + * @return 路由列表 + */ + public List buildMenus(List menus); + + /** + * 构建前端所需要树结构 + * + * @param menus 菜单列表 + * @return 树结构列表 + */ + public List buildMenuTree(List menus); + + /** + * 构建前端所需要下拉树结构 + * + * @param menus 菜单列表 + * @return 下拉树结构列表 + */ + public List buildMenuTreeSelect(List menus); + + /** + * 根据菜单ID查询信息 + * + * @param menuId 菜单ID + * @return 菜单信息 + */ + public SysMenu selectMenuById(Long menuId); + + /** + * 是否存在菜单子节点 + * + * @param menuId 菜单ID + * @return 结果 true 存在 false 不存在 + */ + public boolean hasChildByMenuId(Long menuId); + + /** + * 查询菜单是否存在角色 + * + * @param menuId 菜单ID + * @return 结果 true 存在 false 不存在 + */ + public boolean checkMenuExistRole(Long menuId); + + /** + * 新增保存菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + public int insertMenu(SysMenu menu); + + /** + * 修改保存菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + public int updateMenu(SysMenu menu); + + /** + * 删除菜单管理信息 + * + * @param menuId 菜单ID + * @return 结果 + */ + public int deleteMenuById(Long menuId); + + /** + * 校验菜单名称是否唯一 + * + * @param menu 菜单信息 + * @return 结果 + */ + public boolean checkMenuNameUnique(SysMenu menu); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysNoticeService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysNoticeService.java new file mode 100644 index 0000000000000000000000000000000000000000..12399609cc57fbfb4549f85256a5419739e9032c --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysNoticeService.java @@ -0,0 +1,61 @@ +package com.RVSmartPorting.core.system.service; + +import com.RVSmartPorting.core.system.domain.SysNotice; + +import java.util.List; + +/** + * 公告 服务层 + * + * @author ruoyi + */ +public interface ISysNoticeService +{ + /** + * 查询公告信息 + * + * @param noticeId 公告ID + * @return 公告信息 + */ + public SysNotice selectNoticeById(Long noticeId); + + /** + * 查询公告列表 + * + * @param notice 公告信息 + * @return 公告集合 + */ + public List selectNoticeList(SysNotice notice); + + /** + * 新增公告 + * + * @param notice 公告信息 + * @return 结果 + */ + public int insertNotice(SysNotice notice); + + /** + * 修改公告 + * + * @param notice 公告信息 + * @return 结果 + */ + public int updateNotice(SysNotice notice); + + /** + * 删除公告信息 + * + * @param noticeId 公告ID + * @return 结果 + */ + public int deleteNoticeById(Long noticeId); + + /** + * 批量删除公告信息 + * + * @param noticeIds 需要删除的公告ID + * @return 结果 + */ + public int deleteNoticeByIds(Long[] noticeIds); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysOperLogService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysOperLogService.java new file mode 100644 index 0000000000000000000000000000000000000000..ce9a1bd1c88f8b5923f9e4f36bc571e346f9592e --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysOperLogService.java @@ -0,0 +1,49 @@ +package com.RVSmartPorting.core.system.service; + +import com.RVSmartPorting.core.system.domain.SysOperLog; + +import java.util.List; + +/** + * 操作日志 服务层 + * + * @author ruoyi + */ +public interface ISysOperLogService +{ + /** + * 新增操作日志 + * + * @param operLog 操作日志对象 + */ + public void insertOperlog(SysOperLog operLog); + + /** + * 查询系统操作日志集合 + * + * @param operLog 操作日志对象 + * @return 操作日志集合 + */ + public List selectOperLogList(SysOperLog operLog); + + /** + * 批量删除系统操作日志 + * + * @param operIds 需要删除的操作日志ID + * @return 结果 + */ + public int deleteOperLogByIds(Long[] operIds); + + /** + * 查询操作日志详细 + * + * @param operId 操作ID + * @return 操作日志对象 + */ + public SysOperLog selectOperLogById(Long operId); + + /** + * 清空操作日志 + */ + public void cleanOperLog(); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysPostService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysPostService.java new file mode 100644 index 0000000000000000000000000000000000000000..235f79b1b4ed9154b95165f849be59d68ea47340 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysPostService.java @@ -0,0 +1,100 @@ +package com.RVSmartPorting.core.system.service; + +import com.RVSmartPorting.core.system.domain.SysPost; + +import java.util.List; + +/** + * 岗位信息 服务层 + * + * @author ruoyi + */ +public interface ISysPostService +{ + /** + * 查询岗位信息集合 + * + * @param post 岗位信息 + * @return 岗位列表 + */ + public List selectPostList(SysPost post); + + /** + * 查询所有岗位 + * + * @return 岗位列表 + */ + public List selectPostAll(); + + /** + * 通过岗位ID查询岗位信息 + * + * @param postId 岗位ID + * @return 角色对象信息 + */ + public SysPost selectPostById(Long postId); + + /** + * 根据用户ID获取岗位选择框列表 + * + * @param userId 用户ID + * @return 选中岗位ID列表 + */ + public List selectPostListByUserId(Long userId); + + /** + * 校验岗位名称 + * + * @param post 岗位信息 + * @return 结果 + */ + public boolean checkPostNameUnique(SysPost post); + + /** + * 校验岗位编码 + * + * @param post 岗位信息 + * @return 结果 + */ + public boolean checkPostCodeUnique(SysPost post); + + /** + * 通过岗位ID查询岗位使用数量 + * + * @param postId 岗位ID + * @return 结果 + */ + public int countUserPostById(Long postId); + + /** + * 删除岗位信息 + * + * @param postId 岗位ID + * @return 结果 + */ + public int deletePostById(Long postId); + + /** + * 批量删除岗位信息 + * + * @param postIds 需要删除的岗位ID + * @return 结果 + */ + public int deletePostByIds(Long[] postIds); + + /** + * 新增保存岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + public int insertPost(SysPost post); + + /** + * 修改保存岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + public int updatePost(SysPost post); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysRoleService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysRoleService.java new file mode 100644 index 0000000000000000000000000000000000000000..2f744e62345519c5f8c01e9c3e508ba95b54e06b --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysRoleService.java @@ -0,0 +1,174 @@ +package com.RVSmartPorting.core.system.service; + +import com.RVSmartPorting.common.core.domain.entity.SysRole; +import com.RVSmartPorting.core.system.domain.SysUserRole; + +import java.util.List; +import java.util.Set; + +/** + * 角色业务层 + * + * @author ruoyi + */ +public interface ISysRoleService +{ + /** + * 根据条件分页查询角色数据 + * + * @param role 角色信息 + * @return 角色数据集合信息 + */ + public List selectRoleList(SysRole role); + + /** + * 根据用户ID查询角色列表 + * + * @param userId 用户ID + * @return 角色列表 + */ + public List selectRolesByUserId(Long userId); + + /** + * 根据用户ID查询角色权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + public Set selectRolePermissionByUserId(Long userId); + + /** + * 查询所有角色 + * + * @return 角色列表 + */ + public List selectRoleAll(); + + /** + * 根据用户ID获取角色选择框列表 + * + * @param userId 用户ID + * @return 选中角色ID列表 + */ + public List selectRoleListByUserId(Long userId); + + /** + * 通过角色ID查询角色 + * + * @param roleId 角色ID + * @return 角色对象信息 + */ + public SysRole selectRoleById(Long roleId); + + /** + * 校验角色名称是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + public boolean checkRoleNameUnique(SysRole role); + + /** + * 校验角色权限是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + public boolean checkRoleKeyUnique(SysRole role); + + /** + * 校验角色是否允许操作 + * + * @param role 角色信息 + */ + public void checkRoleAllowed(SysRole role); + + /** + * 校验角色是否有数据权限 + * + * @param roleId 角色id + */ + public void checkRoleDataScope(Long roleId); + + /** + * 通过角色ID查询角色使用数量 + * + * @param roleId 角色ID + * @return 结果 + */ + public int countUserRoleByRoleId(Long roleId); + + /** + * 新增保存角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + public int insertRole(SysRole role); + + /** + * 修改保存角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + public int updateRole(SysRole role); + + /** + * 修改角色状态 + * + * @param role 角色信息 + * @return 结果 + */ + public int updateRoleStatus(SysRole role); + + /** + * 修改数据权限信息 + * + * @param role 角色信息 + * @return 结果 + */ + public int authDataScope(SysRole role); + + /** + * 通过角色ID删除角色 + * + * @param roleId 角色ID + * @return 结果 + */ + public int deleteRoleById(Long roleId); + + /** + * 批量删除角色信息 + * + * @param roleIds 需要删除的角色ID + * @return 结果 + */ + public int deleteRoleByIds(Long[] roleIds); + + /** + * 取消授权用户角色 + * + * @param userRole 用户和角色关联信息 + * @return 结果 + */ + public int deleteAuthUser(SysUserRole userRole); + + /** + * 批量取消授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要取消授权的用户数据ID + * @return 结果 + */ + public int deleteAuthUsers(Long roleId, Long[] userIds); + + /** + * 批量选择授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要删除的用户数据ID + * @return 结果 + */ + public int insertAuthUsers(Long roleId, Long[] userIds); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysUserOnlineService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysUserOnlineService.java new file mode 100644 index 0000000000000000000000000000000000000000..3aecd3eb064de4f0954e48ba9b0a421fa1037f2a --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysUserOnlineService.java @@ -0,0 +1,48 @@ +package com.RVSmartPorting.core.system.service; + +import com.RVSmartPorting.common.core.domain.model.LoginUser; +import com.RVSmartPorting.core.system.domain.SysUserOnline; + +/** + * 在线用户 服务层 + * + * @author ruoyi + */ +public interface ISysUserOnlineService +{ + /** + * 通过登录地址查询信息 + * + * @param ipaddr 登录地址 + * @param user 用户信息 + * @return 在线用户信息 + */ + public SysUserOnline selectOnlineByIpaddr(String ipaddr, LoginUser user); + + /** + * 通过用户名称查询信息 + * + * @param userName 用户名称 + * @param user 用户信息 + * @return 在线用户信息 + */ + public SysUserOnline selectOnlineByUserName(String userName, LoginUser user); + + /** + * 通过登录地址/用户名称查询信息 + * + * @param ipaddr 登录地址 + * @param userName 用户名称 + * @param user 用户信息 + * @return 在线用户信息 + */ + public SysUserOnline selectOnlineByInfo(String ipaddr, String userName, LoginUser user); + + /** + * 设置在线用户信息 + * + * @param user 用户信息 + * @return 在线用户 + */ + public SysUserOnline loginUserToUserOnline(LoginUser user); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysUserService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysUserService.java new file mode 100644 index 0000000000000000000000000000000000000000..4d150afe86affd8f32014bca0ff61ae5c944e1fd --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ISysUserService.java @@ -0,0 +1,207 @@ +package com.RVSmartPorting.core.system.service; + +import com.RVSmartPorting.common.core.domain.entity.SysUser; + +import java.util.List; + +/** + * 用户 业务层 + * + * @author ruoyi + */ +public interface ISysUserService +{ + /** + * 根据条件分页查询用户列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + public List selectUserList(SysUser user); + + /** + * 根据条件分页查询已分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + public List selectAllocatedList(SysUser user); + + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + public List selectUnallocatedList(SysUser user); + + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + public SysUser selectUserByUserName(String userName); + + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + public SysUser selectUserById(Long userId); + + /** + * 根据用户ID查询用户所属角色组 + * + * @param userName 用户名 + * @return 结果 + */ + public String selectUserRoleGroup(String userName); + + /** + * 根据用户ID查询用户所属岗位组 + * + * @param userName 用户名 + * @return 结果 + */ + public String selectUserPostGroup(String userName); + + /** + * 校验用户名称是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + public boolean checkUserNameUnique(SysUser user); + + /** + * 校验手机号码是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + public boolean checkPhoneUnique(SysUser user); + + /** + * 校验email是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + public boolean checkEmailUnique(SysUser user); + + /** + * 校验用户是否允许操作 + * + * @param user 用户信息 + */ + public void checkUserAllowed(SysUser user); + + /** + * 校验用户是否有数据权限 + * + * @param userId 用户id + */ + public void checkUserDataScope(Long userId); + + /** + * 新增用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + public int insertUser(SysUser user); + + /** + * 注册用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + public boolean registerUser(SysUser user); + + /** + * 修改用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + public int updateUser(SysUser user); + + /** + * 用户授权角色 + * + * @param userId 用户ID + * @param roleIds 角色组 + */ + public void insertUserAuth(Long userId, Long[] roleIds); + + /** + * 修改用户状态 + * + * @param user 用户信息 + * @return 结果 + */ + public int updateUserStatus(SysUser user); + + /** + * 修改用户基本信息 + * + * @param user 用户信息 + * @return 结果 + */ + public int updateUserProfile(SysUser user); + + /** + * 修改用户头像 + * + * @param userName 用户名 + * @param avatar 头像地址 + * @return 结果 + */ + public boolean updateUserAvatar(String userName, String avatar); + + /** + * 重置用户密码 + * + * @param user 用户信息 + * @return 结果 + */ + public int resetPwd(SysUser user); + + /** + * 重置用户密码 + * + * @param userName 用户名 + * @param password 密码 + * @return 结果 + */ + public int resetUserPwd(String userName, String password); + + /** + * 通过用户ID删除用户 + * + * @param userId 用户ID + * @return 结果 + */ + public int deleteUserById(Long userId); + + /** + * 批量删除用户信息 + * + * @param userIds 需要删除的用户ID + * @return 结果 + */ + public int deleteUserByIds(Long[] userIds); + + /** + * 导入用户数据 + * + * @param userList 用户数据列表 + * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据 + * @param operName 操作用户 + * @return 结果 + */ + public String importUser(List userList, Boolean isUpdateSupport, String operName); +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ScanTaskServiceImpl.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ScanTaskServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..f100e99a617cc93f046a0044af7ae8ee71df5fe6 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/ScanTaskServiceImpl.java @@ -0,0 +1,171 @@ +package com.RVSmartPorting.core.system.service; + +import com.RVSmartPorting.common.utils.DateUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.core.system.domain.CodeProject; +import com.RVSmartPorting.core.system.domain.ScanTask; +import com.RVSmartPorting.core.system.domain.ScanTool; +import com.RVSmartPorting.core.system.domain.ScanToolConfig; +import com.RVSmartPorting.core.system.mapper.CodeProjectMapper; +import com.RVSmartPorting.core.system.mapper.ScanTaskMapper; +import com.RVSmartPorting.core.system.mapper.ScanToolConfigMapper; +import com.RVSmartPorting.core.system.mapper.ScanToolMapper; +import com.alibaba.fastjson2.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * 代码扫描任务信息Service业务层处理 + * + * @author ruoyi + * @date 2023-09-17 + */ +@Service +@Slf4j +public class ScanTaskServiceImpl implements IScanTaskService { + + @Autowired + private ScanTaskMapper scanTaskMapper; + + @Autowired + private CodeProjectMapper codeProjectMapper; + + @Autowired + ScanToolMapper scanToolMapper; + + @Autowired + ScanToolConfigMapper scanToolConfigMapper; + + /** + * 查询代码扫描任务信息 + * + * @param taskId 代码扫描任务信息主键 + * @return 代码扫描任务信息 + */ + @Override + public ScanTask selectScanTaskByTaskId(Long taskId) { + final ScanTask scanTask = scanTaskMapper.selectScanTaskByTaskId(taskId); + if (null != scanTask && null != scanTask.getCodeProjectId()) { + final CodeProject codeProject = codeProjectMapper.selectCodeProjectByCodeProjectId(scanTask.getCodeProjectId()); + scanTask.setCodeProject(codeProject); + } + + if (null != scanTask && null != scanTask.getScanToolId()) { + ScanTool scanTool = scanToolMapper.selectScanToolByScanToolId(scanTask.getScanToolId()); + scanTask.setScanTool(scanTool); + } + return scanTask; + } + + + @Override + public Map getScanToolConfigVariablesMap(ScanTask scanTask) { + ScanToolConfig scanToolConfig = new ScanToolConfig(); + scanToolConfig.setCustomizableEnabled("1"); + List scanToolConfigList = scanToolConfigMapper.selectScanToolConfigList(scanToolConfig); + HashMap enabledConfigMap = new HashMap<>(); + String scanParameters = scanTask.getScanParameters(); + JSONObject json = JSONObject.parseObject(scanParameters); + if (json == null) { + return new HashMap<>(); + } + for (Map.Entry keyValueEntry : json.entrySet()) { + String key = keyValueEntry.getKey(); + Object value = keyValueEntry.getValue(); + if (key.endsWith("$enabled") && value.toString().equals("1")) { + // 提取对应的配置项名 + String configName = key.substring(0, key.length() - "$enabled".length()); + Optional matchingConfig = scanToolConfigList.stream() + .filter(config -> configName.equals(config.getConfigName())) + .findFirst(); + if (matchingConfig.isPresent()) { + ScanToolConfig foundConfig = matchingConfig.get(); + // 将配置项名和对应的值放入 enabledConfigMap + enabledConfigMap.put(foundConfig.getVariableName(), json.get(configName).toString()); + } else { + throw new RuntimeException(StringUtils.format("not found config {} in scan_task_config", configName)); + } + } + } + log.info("enabledConfigMap:{}", enabledConfigMap); + return enabledConfigMap; + } + + @Override + public Map getNotCustomizableEnabledScanToolConfigVariablesMap(ScanTask scanTask) { + ScanToolConfig scanToolConfig = new ScanToolConfig(); + scanToolConfig.setCustomizableEnabled("0"); + List scanToolConfigList = scanToolConfigMapper.selectScanToolConfigList(scanToolConfig); + HashMap enabledConfigMap = new HashMap<>(); + for (ScanToolConfig config : scanToolConfigList) { + if (config.getDefaultEnabled().equals("1")) { + enabledConfigMap.put(config.getVariableName(), config.getDefaultValue()); + } + } + log.info("enabledConfigMap:{}", enabledConfigMap); + return enabledConfigMap; + } + + /** + * 查询代码扫描任务信息列表 + * + * @param scanTask 代码扫描任务信息 + * @return 代码扫描任务信息 + */ + @Override + public List selectScanTaskList(ScanTask scanTask) { + return scanTaskMapper.selectScanTaskList(scanTask); + } + + /** + * 新增代码扫描任务信息 + * + * @param scanTask 代码扫描任务信息 + * @return 结果 + */ + @Override + public int insertScanTask(ScanTask scanTask) { + scanTask.setCreateTime(DateUtils.getNowDate()); + return scanTaskMapper.insertScanTask(scanTask); + } + + /** + * 修改代码扫描任务信息 + * + * @param scanTask 代码扫描任务信息 + * @return 结果 + */ + @Override + public int updateScanTask(ScanTask scanTask) { + scanTask.setUpdateTime(DateUtils.getNowDate()); + return scanTaskMapper.updateScanTask(scanTask); + } + + /** + * 批量删除代码扫描任务信息 + * + * @param taskIds 需要删除的代码扫描任务信息主键 + * @return 结果 + */ + @Override + public int deleteScanTaskByTaskIds(Long[] taskIds) { + return scanTaskMapper.deleteScanTaskByTaskIds(taskIds); + } + + /** + * 删除代码扫描任务信息信息 + * + * @param taskId 代码扫描任务信息主键 + * @return 结果 + */ + @Override + public int deleteScanTaskByTaskId(Long taskId) { + return scanTaskMapper.deleteScanTaskByTaskId(taskId); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/CodeProjectServiceImpl.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/CodeProjectServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..9e5a0b4817d1bb51bc3e8cbc711cef679b96f05f --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/CodeProjectServiceImpl.java @@ -0,0 +1,389 @@ +package com.RVSmartPorting.core.system.service.impl; + +import java.io.File; +import java.util.List; + +import com.RVSmartPorting.common.config.CSPConfig; +import com.RVSmartPorting.common.constant.Constants; +import com.RVSmartPorting.common.core.domain.entity.SysUser; +import com.RVSmartPorting.common.enums.UploadType; +import com.RVSmartPorting.common.utils.DateUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.file.*; +import com.RVSmartPorting.common.utils.http.FileDownloadListener; +import com.RVSmartPorting.common.utils.ip.IpUtils; +import com.RVSmartPorting.common.utils.uuid.IdUtils; +import com.RVSmartPorting.core.system.domain.CodeProject; +import com.RVSmartPorting.core.system.fileStorage.AbstractFileStorage; +import com.RVSmartPorting.core.system.fileStorage.FileStorageFactory; +import com.RVSmartPorting.core.system.fileStorage.LocalFileStorage; +import com.RVSmartPorting.core.system.fileStorage.git.GitDownloadProcessListener; +import com.RVSmartPorting.core.system.fileStorage.git.GitService; +import com.RVSmartPorting.core.system.fileStorage.http.OkHttpService; +import com.RVSmartPorting.core.system.mapper.CodeProjectMapper; +import com.RVSmartPorting.core.system.service.ICodeProjectService; +import com.RVSmartPorting.core.system.service.ISysConfigService; +import com.RVSmartPorting.core.system.sse.DownloadSseMessageType; +import com.RVSmartPorting.core.system.sse.SseServer; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +/** + * 代码项目信息Service业务层处理 + * + * @author ruoyi + * @date 2023-08-24 + */ +@Service +@Slf4j +public class CodeProjectServiceImpl implements ICodeProjectService { + @Autowired + private CodeProjectMapper codeProjectMapper; + + @Autowired + FileStorageFactory fileStorageFactory; + + @Autowired + private ISysConfigService configService; + + + @Autowired + OkHttpService okHttpService; + + @Autowired + GitService gitService; + + /** + * 查询代码项目信息 + * + * @param codeProjectId 代码项目信息主键 + * @return 代码项目信息 + */ + @Override + public CodeProject selectCodeProjectByCodeProjectId(Long codeProjectId) { + return codeProjectMapper.selectCodeProjectByCodeProjectId(codeProjectId); + } + + + /** + * 代码存储路径为:{CSPConfig.uploadTmpFolder}/{userUUID}/{projectUUID}/{uploadTimeStamp} + * 其中: + * {CSPConfig.uploadTmpFolder} 是可配置的上传临时文件夹 + * {userUUID} 是用户唯一标识符 + * {projectUUID} 是项目唯一标识符 + * {uploadTimeStamp} 是上传时的毫秒级时间戳 + *

+ * HDFS存储路径为:{CSPConfig.codePackStorageRoot}/{hash{0,1}}/{hash{2,3}}/{hash} + * 其中: + * {CSPConfig.codePackStorageRoot} 是可配置的 代码压缩包 存储根目录 + * {hash{0,1}} 是 代码压缩包 哈希值的第 1-2 位 + * {hash{2,3}} 是 代码压缩包 哈希值的第 3-4 位 + * {hash} 是 代码压缩包 的完整哈希值 + * + * @param user + * @param file + * @param uploadType + * @param codeProjectId + * @param repositoryType + * @param projectRepositoryURL + * @param branchName + * @param username + * @param password + * @return + * @throws Exception + */ + @Override + public String upload(SysUser user, MultipartFile file, String uploadType, Long codeProjectId, String repositoryType, + String projectRepositoryURL, + String branchName, + String downloadLink, + String authenticationMethod, + String username, + String password, + String personalAccessToken) throws Exception { + final CodeProject codeProject = codeProjectMapper.selectCodeProjectByCodeProjectId(codeProjectId); + long currentTimestamp = System.currentTimeMillis(); + final AbstractFileStorage fileStorage = fileStorageFactory.getFileStorage(); + // 代码存储路径为:{CSPConfig.uploadTmpFolder}/{userUUID}/{projectUUID}/{uploadTimeStamp} + String uploadTmpFolderPath = StringUtils.format("{}{}{}{}{}{}{}", + CSPConfig.getUploadTmpFolderPath(), '/', + user.getUserUUID(), '/', + codeProject.getProjectUUID(), '/', + currentTimestamp); + if (UploadType.Local.matches(uploadType)) { + if (file == null || file.isEmpty()) { + throw new RuntimeException("上传文件为空,请联系管理员"); + } + final String codePackAbsTmpStoragePath = FileUploadUtils.uploadCodePack2TmpFolder(uploadTmpFolderPath, + file, MimeTypeUtils.COMPRESS_EXTENSION); + String codePackStoragePath = getCodePackStoragePath(file.getOriginalFilename(), codePackAbsTmpStoragePath); + fileStorage.uploadFile(codePackAbsTmpStoragePath, codePackStoragePath); + codeProjectMapper.resetCodeProjectFileInfo(codeProject); + codeProject.setCodeUploadType((long) UploadType.Local.ordinal()); + codeProject.setCodeCachePath(codePackAbsTmpStoragePath); + codeProject.setHdfsPath(codePackStoragePath); + codeProjectMapper.updateCodeProject(codeProject); + } else if (UploadType.Git.matches(uploadType)) { + // 检查下载链接是否符合白名单和黑名单规则 + checkGitDownloadLinkAgainstLists(projectRepositoryURL); + // 合法的下载,继续执行下载逻辑 + String requestId = gitDownloadFilesAsynchronous(projectRepositoryURL, uploadTmpFolderPath, branchName, authenticationMethod, + username, password, personalAccessToken, user.getUserUUID(),codeProject,repositoryType); + log.info("after gitDownloadFilesAsynchronous"); + return requestId; + } else if (UploadType.Link.matches(uploadType)) { + // 检查下载链接是否符合白名单和黑名单规则 + checkDownloadLinkAgainstLists(downloadLink); + // 合法的下载,继续执行下载逻辑 + String fileName = FileUtils.extractFileNameFromUrl(downloadLink); + String requestId = downloadFilesAsynchronous(downloadLink, uploadTmpFolderPath, fileName, + user.getUserUUID(), codeProject); + return requestId; + } else { + throw new RuntimeException("上传方式异常,请联系管理员"); + } + return uploadTmpFolderPath; + } + + public void checkDownloadLinkAgainstLists(String downloadLink) { + String urlBlackList = configService.selectConfigByKey("sys.codeProject.link.urlBlackList"); + String urlWhiteList = configService.selectConfigByKey(" sys.codeProject.link.urlWhiteList"); + // 检查黑名单 + if (IpUtils.isMatchedIpAndDomain(urlBlackList, downloadLink)) { + // 在黑名单中,拒绝下载 + throw new RuntimeException(StringUtils.format("URL:{} is in the blacklist", downloadLink)); + } + // 检查白名单 + if (StringUtils.isNotBlank(urlWhiteList) && IpUtils.isMatchedIpAndDomain(urlBlackList, downloadLink)) { + // 不在白名单中,拒绝下载 + throw new RuntimeException(StringUtils.format("URL:{} is not in the whitelist", downloadLink)); + } + } + + public void checkGitDownloadLinkAgainstLists(String downloadLink) { + String urlBlackList = configService.selectConfigByKey("sys.codeProject.git.urlBlackList"); + String urlWhiteList = configService.selectConfigByKey("sys.codeProject.git.urlWhiteList"); + // 检查黑名单 + if (IpUtils.isMatchedIpAndDomain(urlBlackList, downloadLink)) { + // 在黑名单中,拒绝下载 + throw new RuntimeException(StringUtils.format("URL:{} is in the blacklist", downloadLink)); + } + // 检查白名单 + if (StringUtils.isNotBlank(urlWhiteList) && IpUtils.isMatchedIpAndDomain(urlBlackList, downloadLink)) { + // 不在白名单中,拒绝下载 + throw new RuntimeException(StringUtils.format("URL:{} is not in the whitelist", downloadLink)); + } + } + + private String getCodePackStoragePath(String fileName, String codePackAbsTmpStoragePath) throws Exception { + final String fileHash = FileHashUtil.calculateHash(new File(codePackAbsTmpStoragePath), FileHashUtil.HashAlgorithm.SHA1); + // 提取第 1-2 位字符 + String firstTwoChars = fileHash.substring(0, 2); + // 提取第 3-4 位字符 + String thirdFourthChars = fileHash.substring(2, 4); + // 最终存储路径为:{CSPConfig.codePackStorageRoot}/{hash{0,1}}/{hash{2,3}}/{hash}/{file} + String codePackStoragePath = StringUtils.format("{}{}{}{}{}{}{}{}{}", + CSPConfig.getCodePackStorageRoot(), '/', + firstTwoChars, '/', + thirdFourthChars, '/', + fileHash, '/', + fileName); + final AbstractFileStorage fileStorage = fileStorageFactory.getFileStorage(); + if (fileStorage instanceof LocalFileStorage) { + codePackStoragePath = PathConverterUtil.convertPath(codePackStoragePath); + } + return codePackStoragePath; + } + + + @Override + public String downloadFilesAsynchronous(String url, String destFileDir, String destFileName, String userUUID, + CodeProject codeProject) { + String messageId = Constants.HTTP_MESSAGE_ID_PREFIX + userUUID; + return okHttpService.downloadFilesAsynchronous(url, destFileDir, destFileName, new FileDownloadListener() { + @Override + public void onDownloadStart() { + log.info("downloadFiles onDownloadStart:" + userUUID); + SseServer.sendMessage(messageId, DownloadSseMessageType.onDownloadStart, null); + } + + @Override + public void onDownloadSuccess(File file) { + log.info("downloadFiles onDownloadSuccess:{}", file.getName()); + SseServer.sendMessage(messageId, DownloadSseMessageType.onDownloadSuccess, null); + try { + String codePackAbsTmpStoragePath = file.getAbsolutePath(); + final String codePackStoragePath = getCodePackStoragePath(destFileName, codePackAbsTmpStoragePath); + final AbstractFileStorage fileStorage = fileStorageFactory.getFileStorage(); + fileStorage.uploadFile(codePackAbsTmpStoragePath, codePackStoragePath); + codeProjectMapper.resetCodeProjectFileInfo(codeProject); + codeProject.setCodeUploadType((long) UploadType.Link.ordinal()); + codeProject.setCodeCachePath(codePackAbsTmpStoragePath); + codeProject.setHdfsPath(codePackStoragePath); + codeProjectMapper.updateCodeProject(codeProject); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void onDownloading(int progress) { + // 打印过于频繁 +// log.info("downloadFiles onDownloading process:{}", progress); + SseServer.sendMessage(messageId, DownloadSseMessageType.onDownloading, String.valueOf(progress)); + } + + @Override + public void onDownloadFailed(Exception e) { + log.info("downloadFiles onDownloadFailed:", e); + SseServer.sendMessage(messageId, DownloadSseMessageType.onDownloadFailed, null); + } + + @Override + public void onDownloadTimeout(Exception e) { + log.info("downloadFiles onDownloadFailed:", e); + SseServer.sendMessage(messageId, DownloadSseMessageType.onDownloadTimeout, null); + } + }); + } + + + @Override + public String gitDownloadFilesAsynchronous(String remoteRepositoryURI, String localRepositoryPath, + String branchName, + String authenticationMethod, + String username, + String password, + String personalAccessToken, + String userUUID, + CodeProject codeProject, + String repositoryType) throws Exception { + String messageId = Constants.GIT_MESSAGE_ID_PREFIX + userUUID; + + return gitService.gitDownloadFilesAsynchronous(remoteRepositoryURI, localRepositoryPath, branchName, + authenticationMethod, username, password, personalAccessToken, new GitDownloadProcessListener() { + @Override + public void onDownloadStart() { + log.info("gitDownloadFiles onDownloadStart"); + SseServer.sendMessage(messageId, DownloadSseMessageType.onDownloadStart, null); + } + + @Override + public void onDownloadSuccess() { + log.info("gitDownloadFiles onDownloadSuccess"); + SseServer.sendMessage(messageId, DownloadSseMessageType.onDownloadSuccess, null); + // 删除.git、.gitee文件夹及其内部的所有子文件 + deleteGitRepository(localRepositoryPath); + // 压缩代码文件夹 + final String codePackAbsTmpStoragePath = + FileCompressUtil.compressDirectory(localRepositoryPath); + String compressedCodePackName = new File(codePackAbsTmpStoragePath).getName(); + try { + final String codePackStoragePath = getCodePackStoragePath(compressedCodePackName, codePackAbsTmpStoragePath); + final AbstractFileStorage fileStorage = fileStorageFactory.getFileStorage(); + fileStorage.uploadFile(codePackAbsTmpStoragePath, codePackStoragePath); + codeProjectMapper.resetCodeProjectFileInfo(codeProject); + codeProject.setCodeUploadType((long) UploadType.Git.ordinal()); + codeProject.setCodeRepoType(repositoryType); + codeProject.setCodeCachePath(codePackAbsTmpStoragePath); + codeProject.setHdfsPath(codePackStoragePath); + codeProject.setCodeRepoUrl(remoteRepositoryURI); + codeProject.setCodeBranch(branchName); + codeProject.setCodeRepoUsername(username); + codeProject.setCodeRepoPassword(password); + codeProjectMapper.updateCodeProject(codeProject); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void onDownloading(int progress, String currentTaskName) { + log.info("gitDownloadFiles onDownloading process:{},currentTaskName:{}", progress, currentTaskName); + SseServer.sendMessage(messageId, DownloadSseMessageType.onDownloading, + String.valueOf(progress), currentTaskName); + } + + @Override + public void onDownloadFailed(Exception e) { + log.info("gitDownloadFiles onDownloadFailed:", e); + SseServer.sendMessage(messageId, DownloadSseMessageType.onDownloadFailed, e.getMessage()); + } + + @Override + public void onDownloadTimeout(Exception e) { + log.info("gitDownloadFiles onDownloadTimeout:", e); + SseServer.sendMessage(messageId, DownloadSseMessageType.onDownloadTimeout, null); + } + }); + + } + + public static void deleteGitRepository(String localRepositoryPath) { + File gitDir = new File(localRepositoryPath, ".git"); + FileUtils.deleteDirectory(gitDir); + File giteeDir = new File(localRepositoryPath, ".gitee"); + FileUtils.deleteDirectory(giteeDir); + } + + + /** + * 查询代码项目信息列表 + * + * @param codeProject 代码项目信息 + * @return 代码项目信息 + */ + @Override + public List selectCodeProjectList(CodeProject codeProject) { + return codeProjectMapper.selectCodeProjectList(codeProject); + } + + /** + * 新增代码项目信息 + * + * @param codeProject 代码项目信息 + * @return 结果 + */ + @Override + public int insertCodeProject(CodeProject codeProject) { + codeProject.setCreateTime(DateUtils.getNowDate()); + codeProject.setProjectUUID(IdUtils.randomUUID()); + return codeProjectMapper.insertCodeProject(codeProject); + } + + /** + * 修改代码项目信息 + * + * @param codeProject 代码项目信息 + * @return 结果 + */ + @Override + public int updateCodeProject(CodeProject codeProject) { + codeProject.setUpdateTime(DateUtils.getNowDate()); + return codeProjectMapper.updateCodeProject(codeProject); + } + + /** + * 批量删除代码项目信息 + * + * @param codeProjectIds 需要删除的代码项目信息主键 + * @return 结果 + */ + @Override + public int deleteCodeProjectByCodeProjectIds(Long[] codeProjectIds) { + return codeProjectMapper.deleteCodeProjectByCodeProjectIds(codeProjectIds); + } + + /** + * 删除代码项目信息信息 + * + * @param codeProjectId 代码项目信息主键 + * @return 结果 + */ + @Override + public int deleteCodeProjectByCodeProjectId(Long codeProjectId) { + return codeProjectMapper.deleteCodeProjectByCodeProjectId(codeProjectId); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/GitNetworkSettingServiceImpl.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/GitNetworkSettingServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..8c6345d7bd6a47e6c5c5a388900d09c86fb36dce --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/GitNetworkSettingServiceImpl.java @@ -0,0 +1,97 @@ +package com.RVSmartPorting.core.system.service.impl; + +import java.util.List; + +import com.RVSmartPorting.common.utils.DateUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.RVSmartPorting.core.system.mapper.GitNetworkSettingMapper; +import com.RVSmartPorting.core.system.domain.GitNetworkSetting; +import com.RVSmartPorting.core.system.service.IGitNetworkSettingService; + +/** + * git网络镜像代理配置Service业务层处理 + * + * @author ruoyi + * @date 2023-09-09 + */ +@Service +public class GitNetworkSettingServiceImpl implements IGitNetworkSettingService +{ + @Autowired + private GitNetworkSettingMapper gitNetworkSettingMapper; + + /** + * 查询git网络镜像代理配置 + * + * @param gitNetworkSettingId git网络镜像代理配置主键 + * @return git网络镜像代理配置 + */ + @Override + public GitNetworkSetting selectGitNetworkSettingByGitNetworkSettingId(Long gitNetworkSettingId) + { + return gitNetworkSettingMapper.selectGitNetworkSettingByGitNetworkSettingId(gitNetworkSettingId); + } + + /** + * 查询git网络镜像代理配置列表 + * + * @param gitNetworkSetting git网络镜像代理配置 + * @return git网络镜像代理配置 + */ + @Override + public List selectGitNetworkSettingList(GitNetworkSetting gitNetworkSetting) + { + return gitNetworkSettingMapper.selectGitNetworkSettingList(gitNetworkSetting); + } + + /** + * 新增git网络镜像代理配置 + * + * @param gitNetworkSetting git网络镜像代理配置 + * @return 结果 + */ + @Override + public int insertGitNetworkSetting(GitNetworkSetting gitNetworkSetting) + { + gitNetworkSetting.setCreateTime(DateUtils.getNowDate()); + return gitNetworkSettingMapper.insertGitNetworkSetting(gitNetworkSetting); + } + + /** + * 修改git网络镜像代理配置 + * + * @param gitNetworkSetting git网络镜像代理配置 + * @return 结果 + */ + @Override + public int updateGitNetworkSetting(GitNetworkSetting gitNetworkSetting) + { + gitNetworkSetting.setUpdateTime(DateUtils.getNowDate()); + return gitNetworkSettingMapper.updateGitNetworkSetting(gitNetworkSetting); + } + + /** + * 批量删除git网络镜像代理配置 + * + * @param gitNetworkSettingIds 需要删除的git网络镜像代理配置主键 + * @return 结果 + */ + @Override + public int deleteGitNetworkSettingByGitNetworkSettingIds(Long[] gitNetworkSettingIds) + { + return gitNetworkSettingMapper.deleteGitNetworkSettingByGitNetworkSettingIds(gitNetworkSettingIds); + } + + /** + * 删除git网络镜像代理配置信息 + * + * @param gitNetworkSettingId git网络镜像代理配置主键 + * @return 结果 + */ + @Override + public int deleteGitNetworkSettingByGitNetworkSettingId(Long gitNetworkSettingId) + { + return gitNetworkSettingMapper.deleteGitNetworkSettingByGitNetworkSettingId(gitNetworkSettingId); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/RuleServiceImpl.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/RuleServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..d3069275cfdcdfa2e29516f9be68fa8b1df2f5ad --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/RuleServiceImpl.java @@ -0,0 +1,97 @@ +package com.RVSmartPorting.core.system.service.impl; + +import java.util.List; + +import com.RVSmartPorting.common.utils.DateUtils; +import com.RVSmartPorting.core.system.domain.Rule; +import com.RVSmartPorting.core.system.mapper.RuleMapper; +import com.RVSmartPorting.core.system.service.IRuleService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 规则信息Service业务层处理 + * + * @author ruoyi + * @date 2023-08-15 + */ +@Service +public class RuleServiceImpl implements IRuleService +{ + @Autowired + private RuleMapper ruleMapper; + + /** + * 查询规则信息 + * + * @param ruleId 规则信息主键 + * @return 规则信息 + */ + @Override + public Rule selectRuleByRuleId(Long ruleId) + { + return ruleMapper.selectRuleByRuleId(ruleId); + } + + /** + * 查询规则信息列表 + * + * @param rule 规则信息 + * @return 规则信息 + */ + @Override + public List selectRuleList(Rule rule) + { + return ruleMapper.selectRuleList(rule); + } + + /** + * 新增规则信息 + * + * @param rule 规则信息 + * @return 结果 + */ + @Override + public int insertRule(Rule rule) + { + rule.setCreateTime(DateUtils.getNowDate()); + return ruleMapper.insertRule(rule); + } + + /** + * 修改规则信息 + * + * @param rule 规则信息 + * @return 结果 + */ + @Override + public int updateRule(Rule rule) + { + rule.setUpdateTime(DateUtils.getNowDate()); + return ruleMapper.updateRule(rule); + } + + /** + * 批量删除规则信息 + * + * @param ruleIds 需要删除的规则信息主键 + * @return 结果 + */ + @Override + public int deleteRuleByRuleIds(Long[] ruleIds) + { + return ruleMapper.deleteRuleByRuleIds(ruleIds); + } + + /** + * 删除规则信息信息 + * + * @param ruleId 规则信息主键 + * @return 结果 + */ + @Override + public int deleteRuleByRuleId(Long ruleId) + { + return ruleMapper.deleteRuleByRuleId(ruleId); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/RuleSetServiceImpl.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/RuleSetServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..89abfe819ef109238b4a87e882d43c68b9dbf40c --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/RuleSetServiceImpl.java @@ -0,0 +1,100 @@ +package com.RVSmartPorting.core.system.service.impl; + +import java.util.List; + +import com.RVSmartPorting.common.utils.DateUtils; +import com.RVSmartPorting.core.system.domain.RuleSet; +import com.RVSmartPorting.core.system.mapper.RuleSetMapper; +import com.RVSmartPorting.core.system.service.IRuleSetService; +import com.alibaba.fastjson2.schema.ValidateResult; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 规则集信息Service业务层处理 + * + * @author ruoyi + * @date 2023-08-16 + */ +@Service +public class RuleSetServiceImpl implements IRuleSetService +{ + @Autowired + private RuleSetMapper ruleSetMapper; + + /** + * 查询规则集信息 + * + * @param ruleSetId 规则集信息主键 + * @return 规则集信息 + */ + @Override + public RuleSet selectRuleSetByRuleSetId(Long ruleSetId) + { + final RuleSet ruleSet = ruleSetMapper.selectRuleSetByRuleSetId(ruleSetId); + ruleSet.setRulesCount((long) ruleSet.getRuleList().size()); + return ruleSetMapper.selectRuleSetByRuleSetId(ruleSetId); + } + + /** + * 查询规则集信息列表 + * + * @param ruleSet 规则集信息 + * @return 规则集信息 + */ + @Override + public List selectRuleSetList(RuleSet ruleSet) + { + return ruleSetMapper.selectRuleSetList(ruleSet); + } + + /** + * 新增规则集信息 + * + * @param ruleSet 规则集信息 + * @return 结果 + */ + @Override + public int insertRuleSet(RuleSet ruleSet) + { + ruleSet.setCreateTime(DateUtils.getNowDate()); + return ruleSetMapper.insertRuleSet(ruleSet); + } + + /** + * 修改规则集信息 + * + * @param ruleSet 规则集信息 + * @return 结果 + */ + @Override + public int updateRuleSet(RuleSet ruleSet) + { + ruleSet.setUpdateTime(DateUtils.getNowDate()); + return ruleSetMapper.updateRuleSet(ruleSet); + } + + /** + * 批量删除规则集信息 + * + * @param ruleSetIds 需要删除的规则集信息主键 + * @return 结果 + */ + @Override + public int deleteRuleSetByRuleSetIds(Long[] ruleSetIds) + { + return ruleSetMapper.deleteRuleSetByRuleSetIds(ruleSetIds); + } + + /** + * 删除规则集信息信息 + * + * @param ruleSetId 规则集信息主键 + * @return 结果 + */ + @Override + public int deleteRuleSetByRuleSetId(Long ruleSetId) + { + return ruleSetMapper.deleteRuleSetByRuleSetId(ruleSetId); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/ScanToolConfigServiceImpl.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/ScanToolConfigServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..61e1c18338e589dd5c0c612aca583d182e23922c --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/ScanToolConfigServiceImpl.java @@ -0,0 +1,113 @@ +package com.RVSmartPorting.core.system.service.impl; + +import com.RVSmartPorting.common.utils.DateUtils; +import com.RVSmartPorting.core.system.domain.ScanToolConfig; +import com.RVSmartPorting.core.system.mapper.ScanToolConfigMapper; +import com.RVSmartPorting.core.system.service.IScanToolConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 扫描工具配置Service业务层处理 + * + * @author xuqiangli + * @date 2023-09-22 + */ +@Service +public class ScanToolConfigServiceImpl implements IScanToolConfigService +{ + @Autowired + private ScanToolConfigMapper scanToolConfigMapper; + + /** + * 查询扫描工具配置 + * + * @param scanToolConfigId 扫描工具配置主键 + * @return 扫描工具配置 + */ + @Override + public ScanToolConfig selectScanToolConfigByScanToolConfigId(Long scanToolConfigId) + { + return scanToolConfigMapper.selectScanToolConfigByScanToolConfigId(scanToolConfigId); + } + + /** + * 查询扫描工具配置列表 + * + * @param scanToolConfig 扫描工具配置 + * @return 扫描工具配置 + */ + @Override + public List selectScanToolConfigList(ScanToolConfig scanToolConfig) + { + List scanToolConfigList = scanToolConfigMapper.selectScanToolConfigList(scanToolConfig); + // 遍历 scanToolConfigList + for (ScanToolConfig config : scanToolConfigList) { + String enumOptions = config.getEnumOptions(); + + // 检查 enumOptions 是否为空 + if (enumOptions != null && !enumOptions.isEmpty()) { + // 去除所有空格并按逗号分隔成列表 + List enumOptionList = Arrays.stream(enumOptions.split(",")) + .map(String::trim) + .collect(Collectors.toList()); + config.setEnumOptionList(enumOptionList); + } + } + return scanToolConfigList; + } + + /** + * 新增扫描工具配置 + * + * @param scanToolConfig 扫描工具配置 + * @return 结果 + */ + @Override + public int insertScanToolConfig(ScanToolConfig scanToolConfig) + { + scanToolConfig.setCreateTime(DateUtils.getNowDate()); + return scanToolConfigMapper.insertScanToolConfig(scanToolConfig); + } + + /** + * 修改扫描工具配置 + * + * @param scanToolConfig 扫描工具配置 + * @return 结果 + */ + @Override + public int updateScanToolConfig(ScanToolConfig scanToolConfig) + { + scanToolConfig.setUpdateTime(DateUtils.getNowDate()); + return scanToolConfigMapper.updateScanToolConfig(scanToolConfig); + } + + /** + * 批量删除扫描工具配置 + * + * @param scanToolConfigIds 需要删除的扫描工具配置主键 + * @return 结果 + */ + @Override + public int deleteScanToolConfigByScanToolConfigIds(Long[] scanToolConfigIds) + { + return scanToolConfigMapper.deleteScanToolConfigByScanToolConfigIds(scanToolConfigIds); + } + + /** + * 删除扫描工具配置信息 + * + * @param scanToolConfigId 扫描工具配置主键 + * @return 结果 + */ + @Override + public int deleteScanToolConfigByScanToolConfigId(Long scanToolConfigId) + { + return scanToolConfigMapper.deleteScanToolConfigByScanToolConfigId(scanToolConfigId); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/ScanToolServiceImpl.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/ScanToolServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..378e0fa12f62aa48c586bd63c20a263c88d9aa24 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/ScanToolServiceImpl.java @@ -0,0 +1,97 @@ +package com.RVSmartPorting.core.system.service.impl; + +import com.RVSmartPorting.common.utils.DateUtils; +import com.RVSmartPorting.core.system.domain.ScanTool; +import com.RVSmartPorting.core.system.mapper.ScanToolMapper; +import com.RVSmartPorting.core.system.service.IScanToolService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 扫描工具Service业务层处理 + * + * @author ruoyi + * @date 2023-09-17 + */ +@Service +public class ScanToolServiceImpl implements IScanToolService +{ + @Autowired + private ScanToolMapper scanToolMapper; + + /** + * 查询扫描工具 + * + * @param scanToolId 扫描工具主键 + * @return 扫描工具 + */ + @Override + public ScanTool selectScanToolByScanToolId(Long scanToolId) + { + return scanToolMapper.selectScanToolByScanToolId(scanToolId); + } + + /** + * 查询扫描工具列表 + * + * @param scanTool 扫描工具 + * @return 扫描工具 + */ + @Override + public List selectScanToolList(ScanTool scanTool) + { + return scanToolMapper.selectScanToolList(scanTool); + } + + /** + * 新增扫描工具 + * + * @param scanTool 扫描工具 + * @return 结果 + */ + @Override + public int insertScanTool(ScanTool scanTool) + { + scanTool.setCreateTime(DateUtils.getNowDate()); + return scanToolMapper.insertScanTool(scanTool); + } + + /** + * 修改扫描工具 + * + * @param scanTool 扫描工具 + * @return 结果 + */ + @Override + public int updateScanTool(ScanTool scanTool) + { + scanTool.setUpdateTime(DateUtils.getNowDate()); + return scanToolMapper.updateScanTool(scanTool); + } + + /** + * 批量删除扫描工具 + * + * @param scanToolIds 需要删除的扫描工具主键 + * @return 结果 + */ + @Override + public int deleteScanToolByScanToolIds(Long[] scanToolIds) + { + return scanToolMapper.deleteScanToolByScanToolIds(scanToolIds); + } + + /** + * 删除扫描工具信息 + * + * @param scanToolId 扫描工具主键 + * @return 结果 + */ + @Override + public int deleteScanToolByScanToolId(Long scanToolId) + { + return scanToolMapper.deleteScanToolByScanToolId(scanToolId); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysConfigServiceImpl.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysConfigServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..300b01ecc5381e52a060bd4816dbee42ac302485 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysConfigServiceImpl.java @@ -0,0 +1,233 @@ +package com.RVSmartPorting.core.system.service.impl; + +import com.RVSmartPorting.common.annotation.DataSource; +import com.RVSmartPorting.common.constant.CacheConstants; +import com.RVSmartPorting.common.constant.UserConstants; +import com.RVSmartPorting.common.enums.DataSourceType; +import com.RVSmartPorting.common.exception.ServiceException; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.redis.RedisCache; +import com.RVSmartPorting.common.core.text.Convert; +import com.RVSmartPorting.core.system.domain.SysConfig; +import com.RVSmartPorting.core.system.mapper.SysConfigMapper; +import com.RVSmartPorting.core.system.service.ISysConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.util.Collection; +import java.util.List; + +/** + * 参数配置 服务层实现 + * + * @author ruoyi + */ +@Service +public class SysConfigServiceImpl implements ISysConfigService +{ + @Autowired + private SysConfigMapper configMapper; + + @Autowired + private RedisCache redisCache; + + /** + * 项目启动时,初始化参数到缓存 + */ + @PostConstruct + public void init() + { + loadingConfigCache(); + } + + /** + * 查询参数配置信息 + * + * @param configId 参数配置ID + * @return 参数配置信息 + */ + @Override + @DataSource(DataSourceType.MASTER) + public SysConfig selectConfigById(Long configId) + { + SysConfig config = new SysConfig(); + config.setConfigId(configId); + return configMapper.selectConfig(config); + } + + /** + * 根据键名查询参数配置信息 + * + * @param configKey 参数key + * @return 参数键值 + */ + @Override + public String selectConfigByKey(String configKey) + { + String configValue = Convert.toStr(redisCache.getCacheObject(getCacheKey(configKey))); + if (StringUtils.isNotEmpty(configValue)) + { + return configValue; + } + SysConfig config = new SysConfig(); + config.setConfigKey(configKey); + SysConfig retConfig = configMapper.selectConfig(config); + if (StringUtils.isNotNull(retConfig)) + { + redisCache.setCacheObject(getCacheKey(configKey), retConfig.getConfigValue()); + return retConfig.getConfigValue(); + } + return StringUtils.EMPTY; + } + + /** + * 获取验证码开关 + * + * @return true开启,false关闭 + */ + @Override + public boolean selectCaptchaEnabled() + { + String captchaEnabled = selectConfigByKey("sys.account.captchaEnabled"); + if (StringUtils.isEmpty(captchaEnabled)) + { + return true; + } + return Convert.toBool(captchaEnabled); + } + + /** + * 查询参数配置列表 + * + * @param config 参数配置信息 + * @return 参数配置集合 + */ + @Override + public List selectConfigList(SysConfig config) + { + return configMapper.selectConfigList(config); + } + + /** + * 新增参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + @Override + public int insertConfig(SysConfig config) + { + int row = configMapper.insertConfig(config); + if (row > 0) + { + redisCache.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue()); + } + return row; + } + + /** + * 修改参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + @Override + public int updateConfig(SysConfig config) + { + SysConfig temp = configMapper.selectConfigById(config.getConfigId()); + if (!StringUtils.equals(temp.getConfigKey(), config.getConfigKey())) + { + redisCache.deleteObject(getCacheKey(temp.getConfigKey())); + } + + int row = configMapper.updateConfig(config); + if (row > 0) + { + redisCache.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue()); + } + return row; + } + + /** + * 批量删除参数信息 + * + * @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())); + } + configMapper.deleteConfigById(configId); + redisCache.deleteObject(getCacheKey(config.getConfigKey())); + } + } + + /** + * 加载参数缓存数据 + */ + @Override + public void loadingConfigCache() + { + List configsList = configMapper.selectConfigList(new SysConfig()); + for (SysConfig config : configsList) + { + redisCache.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue()); + } + } + + /** + * 清空参数缓存数据 + */ + @Override + public void clearConfigCache() + { + Collection keys = redisCache.keys(CacheConstants.SYS_CONFIG_KEY + "*"); + redisCache.deleteObject(keys); + } + + /** + * 重置参数缓存数据 + */ + @Override + public void resetConfigCache() + { + clearConfigCache(); + loadingConfigCache(); + } + + /** + * 校验参数键名是否唯一 + * + * @param config 参数配置信息 + * @return 结果 + */ + @Override + public boolean checkConfigKeyUnique(SysConfig config) + { + Long configId = StringUtils.isNull(config.getConfigId()) ? -1L : config.getConfigId(); + SysConfig info = configMapper.checkConfigKeyUnique(config.getConfigKey()); + if (StringUtils.isNotNull(info) && info.getConfigId().longValue() != configId.longValue()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 设置cache key + * + * @param configKey 参数键 + * @return 缓存键key + */ + private String getCacheKey(String configKey) + { + return CacheConstants.SYS_CONFIG_KEY + configKey; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysDeptServiceImpl.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysDeptServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..67406d47c6d6949d1d0fd86a69cda922e2969fc0 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysDeptServiceImpl.java @@ -0,0 +1,339 @@ +package com.RVSmartPorting.core.system.service.impl; + +import com.RVSmartPorting.common.annotation.DataScope; +import com.RVSmartPorting.common.constant.UserConstants; +import com.RVSmartPorting.common.core.domain.TreeSelect; +import com.RVSmartPorting.common.core.domain.entity.SysDept; +import com.RVSmartPorting.common.core.domain.entity.SysRole; +import com.RVSmartPorting.common.core.domain.entity.SysUser; +import com.RVSmartPorting.common.exception.ServiceException; +import com.RVSmartPorting.common.utils.SecurityUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.spring.SpringUtils; +import com.RVSmartPorting.common.core.text.Convert; +import com.RVSmartPorting.core.system.mapper.SysDeptMapper; +import com.RVSmartPorting.core.system.mapper.SysRoleMapper; +import com.RVSmartPorting.core.system.service.ISysDeptService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 部门管理 服务实现 + * + * @author ruoyi + */ +@Service +public class SysDeptServiceImpl implements ISysDeptService +{ + @Autowired + private SysDeptMapper deptMapper; + + @Autowired + private SysRoleMapper roleMapper; + + /** + * 查询部门管理数据 + * + * @param dept 部门信息 + * @return 部门信息集合 + */ + @Override + @DataScope(deptAlias = "d") + public List selectDeptList(SysDept dept) + { + return deptMapper.selectDeptList(dept); + } + + /** + * 查询部门树结构信息 + * + * @param dept 部门信息 + * @return 部门树信息集合 + */ + @Override + public List selectDeptTreeList(SysDept dept) + { + List depts = SpringUtils.getAopProxy(this).selectDeptList(dept); + return buildDeptTreeSelect(depts); + } + + /** + * 构建前端所需要树结构 + * + * @param depts 部门列表 + * @return 树结构列表 + */ + @Override + public List buildDeptTree(List depts) + { + List returnList = new ArrayList(); + List tempList = depts.stream().map(SysDept::getDeptId).collect(Collectors.toList()); + for (SysDept dept : depts) + { + // 如果是顶级节点, 遍历该父节点的所有子节点 + if (!tempList.contains(dept.getParentId())) + { + recursionFn(depts, dept); + returnList.add(dept); + } + } + if (returnList.isEmpty()) + { + returnList = depts; + } + return returnList; + } + + /** + * 构建前端所需要下拉树结构 + * + * @param depts 部门列表 + * @return 下拉树结构列表 + */ + @Override + public List buildDeptTreeSelect(List depts) + { + List deptTrees = buildDeptTree(depts); + return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList()); + } + + /** + * 根据角色ID查询部门树信息 + * + * @param roleId 角色ID + * @return 选中部门列表 + */ + @Override + public List selectDeptListByRoleId(Long roleId) + { + SysRole role = roleMapper.selectRoleById(roleId); + return deptMapper.selectDeptListByRoleId(roleId, role.isDeptCheckStrictly()); + } + + /** + * 根据部门ID查询信息 + * + * @param deptId 部门ID + * @return 部门信息 + */ + @Override + public SysDept selectDeptById(Long deptId) + { + return deptMapper.selectDeptById(deptId); + } + + /** + * 根据ID查询所有子部门(正常状态) + * + * @param deptId 部门ID + * @return 子部门数 + */ + @Override + public int selectNormalChildrenDeptById(Long deptId) + { + return deptMapper.selectNormalChildrenDeptById(deptId); + } + + /** + * 是否存在子节点 + * + * @param deptId 部门ID + * @return 结果 + */ + @Override + public boolean hasChildByDeptId(Long deptId) + { + int result = deptMapper.hasChildByDeptId(deptId); + return result > 0; + } + + /** + * 查询部门是否存在用户 + * + * @param deptId 部门ID + * @return 结果 true 存在 false 不存在 + */ + @Override + public boolean checkDeptExistUser(Long deptId) + { + int result = deptMapper.checkDeptExistUser(deptId); + return result > 0; + } + + /** + * 校验部门名称是否唯一 + * + * @param dept 部门信息 + * @return 结果 + */ + @Override + public boolean checkDeptNameUnique(SysDept dept) + { + Long deptId = StringUtils.isNull(dept.getDeptId()) ? -1L : dept.getDeptId(); + SysDept info = deptMapper.checkDeptNameUnique(dept.getDeptName(), dept.getParentId()); + if (StringUtils.isNotNull(info) && info.getDeptId().longValue() != deptId.longValue()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 校验部门是否有数据权限 + * + * @param deptId 部门id + */ + @Override + public void checkDeptDataScope(Long deptId) + { + if (!SysUser.isAdmin(SecurityUtils.getUserId())) + { + SysDept dept = new SysDept(); + dept.setDeptId(deptId); + List depts = SpringUtils.getAopProxy(this).selectDeptList(dept); + if (StringUtils.isEmpty(depts)) + { + throw new ServiceException("没有权限访问部门数据!"); + } + } + } + + /** + * 新增保存部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + @Override + public int insertDept(SysDept dept) + { + SysDept info = deptMapper.selectDeptById(dept.getParentId()); + // 如果父节点不为正常状态,则不允许新增子节点 + if (!UserConstants.DEPT_NORMAL.equals(info.getStatus())) + { + throw new ServiceException("部门停用,不允许新增"); + } + dept.setAncestors(info.getAncestors() + "," + dept.getParentId()); + return deptMapper.insertDept(dept); + } + + /** + * 修改保存部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + @Override + public int updateDept(SysDept dept) + { + SysDept newParentDept = deptMapper.selectDeptById(dept.getParentId()); + SysDept oldDept = deptMapper.selectDeptById(dept.getDeptId()); + if (StringUtils.isNotNull(newParentDept) && StringUtils.isNotNull(oldDept)) + { + String newAncestors = newParentDept.getAncestors() + "," + newParentDept.getDeptId(); + String oldAncestors = oldDept.getAncestors(); + dept.setAncestors(newAncestors); + updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors); + } + int result = deptMapper.updateDept(dept); + if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors()) + && !StringUtils.equals("0", dept.getAncestors())) + { + // 如果该部门是启用状态,则启用该部门的所有上级部门 + updateParentDeptStatusNormal(dept); + } + return result; + } + + /** + * 修改该部门的父级部门状态 + * + * @param dept 当前部门 + */ + private void updateParentDeptStatusNormal(SysDept dept) + { + String ancestors = dept.getAncestors(); + Long[] deptIds = Convert.toLongArray(ancestors); + deptMapper.updateDeptStatusNormal(deptIds); + } + + /** + * 修改子元素关系 + * + * @param deptId 被修改的部门ID + * @param newAncestors 新的父ID集合 + * @param oldAncestors 旧的父ID集合 + */ + public void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors) + { + List children = deptMapper.selectChildrenDeptById(deptId); + for (SysDept child : children) + { + child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors)); + } + if (children.size() > 0) + { + deptMapper.updateDeptChildren(children); + } + } + + /** + * 删除部门管理信息 + * + * @param deptId 部门ID + * @return 结果 + */ + @Override + public int deleteDeptById(Long deptId) + { + return deptMapper.deleteDeptById(deptId); + } + + /** + * 递归列表 + */ + private void recursionFn(List list, SysDept t) + { + // 得到子节点列表 + List childList = getChildList(list, t); + t.setChildren(childList); + for (SysDept tChild : childList) + { + if (hasChild(list, tChild)) + { + recursionFn(list, tChild); + } + } + } + + /** + * 得到子节点列表 + */ + private List getChildList(List list, SysDept t) + { + List tlist = new ArrayList(); + Iterator it = list.iterator(); + while (it.hasNext()) + { + SysDept n = (SysDept) it.next(); + if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getDeptId().longValue()) + { + tlist.add(n); + } + } + return tlist; + } + + /** + * 判断是否有子节点 + */ + private boolean hasChild(List list, SysDept t) + { + return getChildList(list, t).size() > 0; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysDictDataServiceImpl.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysDictDataServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..270678d10a91b73e8e1045ef4b272f3fd75ffcc9 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysDictDataServiceImpl.java @@ -0,0 +1,112 @@ +package com.RVSmartPorting.core.system.service.impl; + +import com.RVSmartPorting.common.core.domain.entity.SysDictData; +import com.RVSmartPorting.common.utils.DictUtils; +import com.RVSmartPorting.core.system.mapper.SysDictDataMapper; +import com.RVSmartPorting.core.system.service.ISysDictDataService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 字典 业务层处理 + * + * @author ruoyi + */ +@Service +public class SysDictDataServiceImpl implements ISysDictDataService +{ + @Autowired + private SysDictDataMapper dictDataMapper; + + /** + * 根据条件分页查询字典数据 + * + * @param dictData 字典数据信息 + * @return 字典数据集合信息 + */ + @Override + public List selectDictDataList(SysDictData dictData) + { + return dictDataMapper.selectDictDataList(dictData); + } + + /** + * 根据字典类型和字典键值查询字典数据信息 + * + * @param dictType 字典类型 + * @param dictValue 字典键值 + * @return 字典标签 + */ + @Override + public String selectDictLabel(String dictType, String dictValue) + { + return dictDataMapper.selectDictLabel(dictType, dictValue); + } + + /** + * 根据字典数据ID查询信息 + * + * @param dictCode 字典数据ID + * @return 字典数据 + */ + @Override + public SysDictData selectDictDataById(Long dictCode) + { + return dictDataMapper.selectDictDataById(dictCode); + } + + /** + * 批量删除字典数据信息 + * + * @param dictCodes 需要删除的字典数据ID + */ + @Override + public void deleteDictDataByIds(Long[] dictCodes) + { + for (Long dictCode : dictCodes) + { + SysDictData data = selectDictDataById(dictCode); + dictDataMapper.deleteDictDataById(dictCode); + List dictDatas = dictDataMapper.selectDictDataByType(data.getDictType()); + DictUtils.setDictCache(data.getDictType(), dictDatas); + } + } + + /** + * 新增保存字典数据信息 + * + * @param data 字典数据信息 + * @return 结果 + */ + @Override + public int insertDictData(SysDictData data) + { + int row = dictDataMapper.insertDictData(data); + if (row > 0) + { + List dictDatas = dictDataMapper.selectDictDataByType(data.getDictType()); + DictUtils.setDictCache(data.getDictType(), dictDatas); + } + return row; + } + + /** + * 修改保存字典数据信息 + * + * @param data 字典数据信息 + * @return 结果 + */ + @Override + public int updateDictData(SysDictData data) + { + int row = dictDataMapper.updateDictData(data); + if (row > 0) + { + List dictDatas = dictDataMapper.selectDictDataByType(data.getDictType()); + DictUtils.setDictCache(data.getDictType(), dictDatas); + } + return row; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysDictTypeServiceImpl.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysDictTypeServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..d3a93efec47a6cf5c3d38e49353dfdb7c3b93c18 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysDictTypeServiceImpl.java @@ -0,0 +1,224 @@ +package com.RVSmartPorting.core.system.service.impl; + +import com.RVSmartPorting.common.constant.UserConstants; +import com.RVSmartPorting.common.core.domain.entity.SysDictData; +import com.RVSmartPorting.common.core.domain.entity.SysDictType; +import com.RVSmartPorting.common.exception.ServiceException; +import com.RVSmartPorting.common.utils.DictUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.core.system.mapper.SysDictDataMapper; +import com.RVSmartPorting.core.system.mapper.SysDictTypeMapper; +import com.RVSmartPorting.core.system.service.ISysDictTypeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.PostConstruct; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 字典 业务层处理 + * + * @author ruoyi + */ +@Service +public class SysDictTypeServiceImpl implements ISysDictTypeService +{ + @Autowired + private SysDictTypeMapper dictTypeMapper; + + @Autowired + private SysDictDataMapper dictDataMapper; + + /** + * 项目启动时,初始化字典到缓存 + */ + @PostConstruct + public void init() + { + loadingDictCache(); + } + + /** + * 根据条件分页查询字典类型 + * + * @param dictType 字典类型信息 + * @return 字典类型集合信息 + */ + @Override + public List selectDictTypeList(SysDictType dictType) + { + return dictTypeMapper.selectDictTypeList(dictType); + } + + /** + * 根据所有字典类型 + * + * @return 字典类型集合信息 + */ + @Override + public List selectDictTypeAll() + { + return dictTypeMapper.selectDictTypeAll(); + } + + /** + * 根据字典类型查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据集合信息 + */ + @Override + public List selectDictDataByType(String dictType) + { + List dictDatas = DictUtils.getDictCache(dictType); + if (StringUtils.isNotEmpty(dictDatas)) + { + return dictDatas; + } + dictDatas = dictDataMapper.selectDictDataByType(dictType); + if (StringUtils.isNotEmpty(dictDatas)) + { + DictUtils.setDictCache(dictType, dictDatas); + return dictDatas; + } + return null; + } + + /** + * 根据字典类型ID查询信息 + * + * @param dictId 字典类型ID + * @return 字典类型 + */ + @Override + public SysDictType selectDictTypeById(Long dictId) + { + return dictTypeMapper.selectDictTypeById(dictId); + } + + /** + * 根据字典类型查询信息 + * + * @param dictType 字典类型 + * @return 字典类型 + */ + @Override + public SysDictType selectDictTypeByType(String dictType) + { + return dictTypeMapper.selectDictTypeByType(dictType); + } + + /** + * 批量删除字典类型信息 + * + * @param dictIds 需要删除的字典ID + */ + @Override + public void deleteDictTypeByIds(Long[] dictIds) + { + for (Long dictId : dictIds) + { + SysDictType dictType = selectDictTypeById(dictId); + if (dictDataMapper.countDictDataByType(dictType.getDictType()) > 0) + { + throw new ServiceException(String.format("%1$s已分配,不能删除", dictType.getDictName())); + } + dictTypeMapper.deleteDictTypeById(dictId); + DictUtils.removeDictCache(dictType.getDictType()); + } + } + + /** + * 加载字典缓存数据 + */ + @Override + public void loadingDictCache() + { + SysDictData dictData = new SysDictData(); + dictData.setStatus("0"); + Map> dictDataMap = dictDataMapper.selectDictDataList(dictData).stream().collect(Collectors.groupingBy(SysDictData::getDictType)); + for (Map.Entry> entry : dictDataMap.entrySet()) + { + DictUtils.setDictCache(entry.getKey(), entry.getValue().stream().sorted(Comparator.comparing(SysDictData::getDictSort)).collect(Collectors.toList())); + } + } + + /** + * 清空字典缓存数据 + */ + @Override + public void clearDictCache() + { + DictUtils.clearDictCache(); + } + + /** + * 重置字典缓存数据 + */ + @Override + public void resetDictCache() + { + clearDictCache(); + loadingDictCache(); + } + + /** + * 新增保存字典类型信息 + * + * @param dict 字典类型信息 + * @return 结果 + */ + @Override + public int insertDictType(SysDictType dict) + { + int row = dictTypeMapper.insertDictType(dict); + if (row > 0) + { + DictUtils.setDictCache(dict.getDictType(), null); + } + return row; + } + + /** + * 修改保存字典类型信息 + * + * @param dict 字典类型信息 + * @return 结果 + */ + @Override + @Transactional + public int updateDictType(SysDictType dict) + { + SysDictType oldDict = dictTypeMapper.selectDictTypeById(dict.getDictId()); + dictDataMapper.updateDictDataType(oldDict.getDictType(), dict.getDictType()); + int row = dictTypeMapper.updateDictType(dict); + if (row > 0) + { + List dictDatas = dictDataMapper.selectDictDataByType(dict.getDictType()); + DictUtils.setDictCache(dict.getDictType(), dictDatas); + } + return row; + } + + /** + * 校验字典类型称是否唯一 + * + * @param dict 字典类型 + * @return 结果 + */ + @Override + public boolean checkDictTypeUnique(SysDictType dict) + { + Long dictId = StringUtils.isNull(dict.getDictId()) ? -1L : dict.getDictId(); + SysDictType dictType = dictTypeMapper.checkDictTypeUnique(dict.getDictType()); + if (StringUtils.isNotNull(dictType) && dictType.getDictId().longValue() != dictId.longValue()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysLogininforServiceImpl.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysLogininforServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..683f62f52352762cb0035de5e26cf0dc988ae2d1 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysLogininforServiceImpl.java @@ -0,0 +1,66 @@ +package com.RVSmartPorting.core.system.service.impl; + +import com.RVSmartPorting.core.system.domain.SysLogininfor; +import com.RVSmartPorting.core.system.mapper.SysLogininforMapper; +import com.RVSmartPorting.core.system.service.ISysLogininforService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 系统访问日志情况信息 服务层处理 + * + * @author ruoyi + */ +@Service +public class SysLogininforServiceImpl implements ISysLogininforService +{ + + @Autowired + private SysLogininforMapper logininforMapper; + + /** + * 新增系统登录日志 + * + * @param logininfor 访问日志对象 + */ + @Override + public void insertLogininfor(SysLogininfor logininfor) + { + logininforMapper.insertLogininfor(logininfor); + } + + /** + * 查询系统登录日志集合 + * + * @param logininfor 访问日志对象 + * @return 登录记录集合 + */ + @Override + public List selectLogininforList(SysLogininfor logininfor) + { + return logininforMapper.selectLogininforList(logininfor); + } + + /** + * 批量删除系统登录日志 + * + * @param infoIds 需要删除的登录日志ID + * @return 结果 + */ + @Override + public int deleteLogininforByIds(Long[] infoIds) + { + return logininforMapper.deleteLogininforByIds(infoIds); + } + + /** + * 清空系统登录日志 + */ + @Override + public void cleanLogininfor() + { + logininforMapper.cleanLogininfor(); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysMenuServiceImpl.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysMenuServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..b2197a8844fb4c4f2a69345a9407196a2844f1fb --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysMenuServiceImpl.java @@ -0,0 +1,526 @@ +package com.RVSmartPorting.core.system.service.impl; + +import com.RVSmartPorting.common.constant.Constants; +import com.RVSmartPorting.common.constant.UserConstants; +import com.RVSmartPorting.common.core.domain.TreeSelect; +import com.RVSmartPorting.common.core.domain.entity.SysMenu; +import com.RVSmartPorting.common.core.domain.entity.SysRole; +import com.RVSmartPorting.common.core.domain.entity.SysUser; +import com.RVSmartPorting.common.utils.SecurityUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.core.system.domain.vo.MetaVo; +import com.RVSmartPorting.core.system.domain.vo.RouterVo; +import com.RVSmartPorting.core.system.mapper.SysMenuMapper; +import com.RVSmartPorting.core.system.mapper.SysRoleMapper; +import com.RVSmartPorting.core.system.mapper.SysRoleMenuMapper; +import com.RVSmartPorting.core.system.service.ISysMenuService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 菜单 业务层处理 + * + * @author ruoyi + */ +@Service +public class SysMenuServiceImpl implements ISysMenuService +{ + public static final String PREMISSION_STRING = "perms[\"{0}\"]"; + + @Autowired + private SysMenuMapper menuMapper; + + @Autowired + private SysRoleMapper roleMapper; + + @Autowired + private 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 (SysUser.isAdmin(userId)) + { + menuList = menuMapper.selectMenuList(menu); + } + else + { + menu.getParams().put("userId", userId); + menuList = menuMapper.selectMenuListByUserId(menu); + } + return menuList; + } + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + @Override + public Set selectMenuPermsByUserId(Long userId) + { + List perms = menuMapper.selectMenuPermsByUserId(userId); + Set permsSet = new HashSet<>(); + for (String perm : perms) + { + if (StringUtils.isNotEmpty(perm)) + { + permsSet.addAll(Arrays.asList(perm.trim().split(","))); + } + } + return permsSet; + } + + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + @Override + public Set selectMenuPermsByRoleId(Long roleId) + { + List perms = menuMapper.selectMenuPermsByRoleId(roleId); + Set permsSet = new HashSet<>(); + for (String perm : perms) + { + if (StringUtils.isNotEmpty(perm)) + { + permsSet.addAll(Arrays.asList(perm.trim().split(","))); + } + } + return permsSet; + } + + /** + * 根据用户ID查询菜单 + * + * @param userId 用户名称 + * @return 菜单列表 + */ + @Override + public List selectMenuTreeByUserId(Long userId) + { + List menus = null; + if (SecurityUtils.isAdmin(userId)) + { + menus = menuMapper.selectMenuTreeAll(); + } + else + { + menus = menuMapper.selectMenuTreeByUserId(userId); + } + return getChildPerms(menus, 0); + } + + /** + * 根据角色ID查询菜单树信息 + * + * @param roleId 角色ID + * @return 选中菜单列表 + */ + @Override + public List selectMenuListByRoleId(Long roleId) + { + SysRole role = roleMapper.selectRoleById(roleId); + return menuMapper.selectMenuListByRoleId(roleId, role.isMenuCheckStrictly()); + } + + /** + * 构建前端路由所需要的菜单 + * + * @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.getQuery()); + router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath())); + List cMenus = menu.getChildren(); + if (StringUtils.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.getQuery()); + 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 buildMenuTree(List menus) + { + List returnList = new ArrayList(); + List tempList = menus.stream().map(SysMenu::getMenuId).collect(Collectors.toList()); + for (Iterator iterator = menus.iterator(); iterator.hasNext();) + { + SysMenu menu = (SysMenu) iterator.next(); + // 如果是顶级节点, 遍历该父节点的所有子节点 + if (!tempList.contains(menu.getParentId())) + { + recursionFn(menus, menu); + returnList.add(menu); + } + } + if (returnList.isEmpty()) + { + returnList = menus; + } + return returnList; + } + + /** + * 构建前端所需要下拉树结构 + * + * @param menus 菜单列表 + * @return 下拉树结构列表 + */ + @Override + public List buildMenuTreeSelect(List menus) + { + List menuTrees = buildMenuTree(menus); + return menuTrees.stream().map(TreeSelect::new).collect(Collectors.toList()); + } + + /** + * 根据菜单ID查询信息 + * + * @param menuId 菜单ID + * @return 菜单信息 + */ + @Override + public SysMenu selectMenuById(Long menuId) + { + return menuMapper.selectMenuById(menuId); + } + + /** + * 是否存在菜单子节点 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public boolean hasChildByMenuId(Long menuId) + { + int result = menuMapper.hasChildByMenuId(menuId); + return result > 0; + } + + /** + * 查询菜单使用数量 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public boolean checkMenuExistRole(Long menuId) + { + int result = roleMenuMapper.checkMenuExistRole(menuId); + return result > 0; + } + + /** + * 新增保存菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + @Override + public int insertMenu(SysMenu menu) + { + return menuMapper.insertMenu(menu); + } + + /** + * 修改保存菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + @Override + public int updateMenu(SysMenu menu) + { + return menuMapper.updateMenu(menu); + } + + /** + * 删除菜单管理信息 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public int deleteMenuById(Long menuId) + { + return menuMapper.deleteMenuById(menuId); + } + + /** + * 校验菜单名称是否唯一 + * + * @param menu 菜单信息 + * @return 结果 + */ + @Override + public boolean checkMenuNameUnique(SysMenu menu) + { + Long menuId = StringUtils.isNull(menu.getMenuId()) ? -1L : menu.getMenuId(); + SysMenu info = menuMapper.checkMenuNameUnique(menu.getMenuName(), menu.getParentId()); + if (StringUtils.isNotNull(info) && info.getMenuId().longValue() != menuId.longValue()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 获取路由名称 + * + * @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 (Iterator iterator = list.iterator(); iterator.hasNext();) + { + SysMenu t = (SysMenu) iterator.next(); + // 一、根据传入的某个父节点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) + { + List tlist = new ArrayList(); + Iterator it = list.iterator(); + while (it.hasNext()) + { + SysMenu n = (SysMenu) it.next(); + if (n.getParentId().longValue() == t.getMenuId().longValue()) + { + tlist.add(n); + } + } + return tlist; + } + + /** + * 判断是否有子节点 + */ + private boolean hasChild(List list, SysMenu t) + { + return getChildList(list, t).size() > 0; + } + + /** + * 内链域名特殊字符替换 + * + * @return 替换后的内链域名 + */ + public String innerLinkReplaceEach(String path) + { + return StringUtils.replaceEach(path, new String[] { Constants.HTTP, Constants.HTTPS, Constants.WWW, "." }, + new String[] { "", "", "", "/" }); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysNoticeServiceImpl.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysNoticeServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..404b7e079ad21290a6b61b35790c79edd58df7e5 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysNoticeServiceImpl.java @@ -0,0 +1,94 @@ +package com.RVSmartPorting.core.system.service.impl; + + +import com.RVSmartPorting.core.system.domain.SysNotice; +import com.RVSmartPorting.core.system.mapper.SysNoticeMapper; +import com.RVSmartPorting.core.system.service.ISysNoticeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 公告 服务层实现 + * + * @author ruoyi + */ +@Service +public class SysNoticeServiceImpl implements ISysNoticeService +{ + @Autowired + private SysNoticeMapper noticeMapper; + + /** + * 查询公告信息 + * + * @param noticeId 公告ID + * @return 公告信息 + */ + @Override + public SysNotice selectNoticeById(Long noticeId) + { + return noticeMapper.selectNoticeById(noticeId); + } + + /** + * 查询公告列表 + * + * @param notice 公告信息 + * @return 公告集合 + */ + @Override + public List selectNoticeList(SysNotice notice) + { + return noticeMapper.selectNoticeList(notice); + } + + /** + * 新增公告 + * + * @param notice 公告信息 + * @return 结果 + */ + @Override + public int insertNotice(SysNotice notice) + { + return noticeMapper.insertNotice(notice); + } + + /** + * 修改公告 + * + * @param notice 公告信息 + * @return 结果 + */ + @Override + public int updateNotice(SysNotice notice) + { + return noticeMapper.updateNotice(notice); + } + + /** + * 删除公告对象 + * + * @param noticeId 公告ID + * @return 结果 + */ + @Override + public int deleteNoticeById(Long noticeId) + { + return noticeMapper.deleteNoticeById(noticeId); + } + + /** + * 批量删除公告信息 + * + * @param noticeIds 需要删除的公告ID + * @return 结果 + */ + @Override + public int deleteNoticeByIds(Long[] noticeIds) + { + return noticeMapper.deleteNoticeByIds(noticeIds); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysOperLogServiceImpl.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysOperLogServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..ef977c03e8a4506443ba02c0f0622be47aa5f752 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysOperLogServiceImpl.java @@ -0,0 +1,77 @@ +package com.RVSmartPorting.core.system.service.impl; + +import com.RVSmartPorting.core.system.domain.SysOperLog; +import com.RVSmartPorting.core.system.mapper.SysOperLogMapper; +import com.RVSmartPorting.core.system.service.ISysOperLogService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 操作日志 服务层处理 + * + * @author ruoyi + */ +@Service +public class SysOperLogServiceImpl implements ISysOperLogService +{ + @Autowired + private SysOperLogMapper operLogMapper; + + /** + * 新增操作日志 + * + * @param operLog 操作日志对象 + */ + @Override + public void insertOperlog(SysOperLog operLog) + { + operLogMapper.insertOperlog(operLog); + } + + /** + * 查询系统操作日志集合 + * + * @param operLog 操作日志对象 + * @return 操作日志集合 + */ + @Override + public List selectOperLogList(SysOperLog operLog) + { + return operLogMapper.selectOperLogList(operLog); + } + + /** + * 批量删除系统操作日志 + * + * @param operIds 需要删除的操作日志ID + * @return 结果 + */ + @Override + public int deleteOperLogByIds(Long[] operIds) + { + return operLogMapper.deleteOperLogByIds(operIds); + } + + /** + * 查询操作日志详细 + * + * @param operId 操作ID + * @return 操作日志对象 + */ + @Override + public SysOperLog selectOperLogById(Long operId) + { + return operLogMapper.selectOperLogById(operId); + } + + /** + * 清空操作日志 + */ + @Override + public void cleanOperLog() + { + operLogMapper.cleanOperLog(); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysPostServiceImpl.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysPostServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..19e8c55a1daf5a277daf687da78d73222b87f0d0 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysPostServiceImpl.java @@ -0,0 +1,179 @@ +package com.RVSmartPorting.core.system.service.impl; + +import com.RVSmartPorting.common.constant.UserConstants; +import com.RVSmartPorting.common.exception.ServiceException; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.core.system.domain.SysPost; +import com.RVSmartPorting.core.system.mapper.SysPostMapper; +import com.RVSmartPorting.core.system.mapper.SysUserPostMapper; +import com.RVSmartPorting.core.system.service.ISysPostService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 岗位信息 服务层处理 + * + * @author ruoyi + */ +@Service +public class SysPostServiceImpl implements ISysPostService +{ + @Autowired + private SysPostMapper postMapper; + + @Autowired + private SysUserPostMapper userPostMapper; + + /** + * 查询岗位信息集合 + * + * @param post 岗位信息 + * @return 岗位信息集合 + */ + @Override + public List selectPostList(SysPost post) + { + return postMapper.selectPostList(post); + } + + /** + * 查询所有岗位 + * + * @return 岗位列表 + */ + @Override + public List selectPostAll() + { + return postMapper.selectPostAll(); + } + + /** + * 通过岗位ID查询岗位信息 + * + * @param postId 岗位ID + * @return 角色对象信息 + */ + @Override + public SysPost selectPostById(Long postId) + { + return postMapper.selectPostById(postId); + } + + /** + * 根据用户ID获取岗位选择框列表 + * + * @param userId 用户ID + * @return 选中岗位ID列表 + */ + @Override + public List selectPostListByUserId(Long userId) + { + return postMapper.selectPostListByUserId(userId); + } + + /** + * 校验岗位名称是否唯一 + * + * @param post 岗位信息 + * @return 结果 + */ + @Override + public boolean checkPostNameUnique(SysPost post) + { + Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId(); + SysPost info = postMapper.checkPostNameUnique(post.getPostName()); + if (StringUtils.isNotNull(info) && info.getPostId().longValue() != postId.longValue()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 校验岗位编码是否唯一 + * + * @param post 岗位信息 + * @return 结果 + */ + @Override + public boolean checkPostCodeUnique(SysPost post) + { + Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId(); + SysPost info = postMapper.checkPostCodeUnique(post.getPostCode()); + if (StringUtils.isNotNull(info) && info.getPostId().longValue() != postId.longValue()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 通过岗位ID查询岗位使用数量 + * + * @param postId 岗位ID + * @return 结果 + */ + @Override + public int countUserPostById(Long postId) + { + return userPostMapper.countUserPostById(postId); + } + + /** + * 删除岗位信息 + * + * @param postId 岗位ID + * @return 结果 + */ + @Override + public int deletePostById(Long postId) + { + return postMapper.deletePostById(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 postMapper.deletePostByIds(postIds); + } + + /** + * 新增保存岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + @Override + public int insertPost(SysPost post) + { + return postMapper.insertPost(post); + } + + /** + * 修改保存岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + @Override + public int updatePost(SysPost post) + { + return postMapper.updatePost(post); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysRoleServiceImpl.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysRoleServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..6b838f382a58523519b4b53fe5d57e38ef5d5eb5 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysRoleServiceImpl.java @@ -0,0 +1,422 @@ +package com.RVSmartPorting.core.system.service.impl; + +import com.RVSmartPorting.common.annotation.DataScope; +import com.RVSmartPorting.common.constant.UserConstants; +import com.RVSmartPorting.common.core.domain.entity.SysRole; +import com.RVSmartPorting.common.core.domain.entity.SysUser; +import com.RVSmartPorting.common.exception.ServiceException; +import com.RVSmartPorting.common.utils.SecurityUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.spring.SpringUtils; +import com.RVSmartPorting.core.system.domain.SysRoleDept; +import com.RVSmartPorting.core.system.domain.SysRoleMenu; +import com.RVSmartPorting.core.system.domain.SysUserRole; +import com.RVSmartPorting.core.system.mapper.SysRoleDeptMapper; +import com.RVSmartPorting.core.system.mapper.SysRoleMapper; +import com.RVSmartPorting.core.system.mapper.SysRoleMenuMapper; +import com.RVSmartPorting.core.system.mapper.SysUserRoleMapper; +import com.RVSmartPorting.core.system.service.ISysRoleService; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +/** + * 角色 业务层处理 + * + * @author ruoyi + */ +@Service +public class SysRoleServiceImpl implements ISysRoleService +{ + @Autowired + private SysRoleMapper roleMapper; + + @Autowired + private SysRoleMenuMapper roleMenuMapper; + + @Autowired + private SysUserRoleMapper userRoleMapper; + + @Autowired + private SysRoleDeptMapper roleDeptMapper; + + /** + * 根据条件分页查询角色数据 + * + * @param role 角色信息 + * @return 角色数据集合信息 + */ + @Override + @DataScope(deptAlias = "d") + public List selectRoleList(SysRole role) + { + return roleMapper.selectRoleList(role); + } + + /** + * 根据用户ID查询角色 + * + * @param userId 用户ID + * @return 角色列表 + */ + @Override + public List selectRolesByUserId(Long userId) + { + List userRoles = roleMapper.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 = roleMapper.selectRolePermissionByUserId(userId); + Set permsSet = new HashSet<>(); + for (SysRole perm : perms) + { + if (StringUtils.isNotNull(perm)) + { + permsSet.addAll(Arrays.asList(perm.getRoleKey().trim().split(","))); + } + } + return permsSet; + } + + /** + * 查询所有角色 + * + * @return 角色列表 + */ + @Override + public List selectRoleAll() + { + return SpringUtils.getAopProxy(this).selectRoleList(new SysRole()); + } + + /** + * 根据用户ID获取角色选择框列表 + * + * @param userId 用户ID + * @return 选中角色ID列表 + */ + @Override + public List selectRoleListByUserId(Long userId) + { + return roleMapper.selectRoleListByUserId(userId); + } + + /** + * 通过角色ID查询角色 + * + * @param roleId 角色ID + * @return 角色对象信息 + */ + @Override + public SysRole selectRoleById(Long roleId) + { + return roleMapper.selectRoleById(roleId); + } + + /** + * 校验角色名称是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + public boolean checkRoleNameUnique(SysRole role) + { + Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId(); + SysRole info = roleMapper.checkRoleNameUnique(role.getRoleName()); + if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 校验角色权限是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + public boolean checkRoleKeyUnique(SysRole role) + { + Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId(); + SysRole info = roleMapper.checkRoleKeyUnique(role.getRoleKey()); + if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 校验角色是否允许操作 + * + * @param role 角色信息 + */ + @Override + public void checkRoleAllowed(SysRole role) + { + if (StringUtils.isNotNull(role.getRoleId()) && role.isAdmin()) + { + throw new ServiceException("不允许操作超级管理员角色"); + } + } + + /** + * 校验角色是否有数据权限 + * + * @param roleId 角色id + */ + @Override + public void checkRoleDataScope(Long roleId) + { + if (!SysUser.isAdmin(SecurityUtils.getUserId())) + { + SysRole role = new SysRole(); + role.setRoleId(roleId); + List roles = SpringUtils.getAopProxy(this).selectRoleList(role); + if (StringUtils.isEmpty(roles)) + { + throw new ServiceException("没有权限访问角色数据!"); + } + } + } + + /** + * 通过角色ID查询角色使用数量 + * + * @param roleId 角色ID + * @return 结果 + */ + @Override + public int countUserRoleByRoleId(Long roleId) + { + return userRoleMapper.countUserRoleByRoleId(roleId); + } + + /** + * 新增保存角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + @Transactional + public int insertRole(SysRole role) + { + // 新增角色信息 + roleMapper.insertRole(role); + return insertRoleMenu(role); + } + + /** + * 修改保存角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + @Transactional + public int updateRole(SysRole role) + { + // 修改角色信息 + roleMapper.updateRole(role); + // 删除角色与菜单关联 + roleMenuMapper.deleteRoleMenuByRoleId(role.getRoleId()); + return insertRoleMenu(role); + } + + /** + * 修改角色状态 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + public int updateRoleStatus(SysRole role) + { + return roleMapper.updateRole(role); + } + + /** + * 修改数据权限信息 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + @Transactional + public int authDataScope(SysRole role) + { + // 修改角色信息 + roleMapper.updateRole(role); + // 删除角色与部门关联 + roleDeptMapper.deleteRoleDeptByRoleId(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.batchRoleMenu(list); + } + 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.batchRoleDept(list); + } + return rows; + } + + /** + * 通过角色ID删除角色 + * + * @param roleId 角色ID + * @return 结果 + */ + @Override + @Transactional + public int deleteRoleById(Long roleId) + { + // 删除角色与菜单关联 + roleMenuMapper.deleteRoleMenuByRoleId(roleId); + // 删除角色与部门关联 + roleDeptMapper.deleteRoleDeptByRoleId(roleId); + return roleMapper.deleteRoleById(roleId); + } + + /** + * 批量删除角色信息 + * + * @param roleIds 需要删除的角色ID + * @return 结果 + */ + @Override + @Transactional + 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())); + } + } + // 删除角色与菜单关联 + roleMenuMapper.deleteRoleMenu(roleIds); + // 删除角色与部门关联 + roleDeptMapper.deleteRoleDept(roleIds); + return roleMapper.deleteRoleByIds(roleIds); + } + + /** + * 取消授权用户角色 + * + * @param userRole 用户和角色关联信息 + * @return 结果 + */ + @Override + public int deleteAuthUser(SysUserRole userRole) + { + return userRoleMapper.deleteUserRoleInfo(userRole); + } + + /** + * 批量取消授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要取消授权的用户数据ID + * @return 结果 + */ + @Override + public int deleteAuthUsers(Long roleId, Long[] userIds) + { + return userRoleMapper.deleteUserRoleInfos(roleId, userIds); + } + + /** + * 批量选择授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要授权的用户数据ID + * @return 结果 + */ + @Override + public int insertAuthUsers(Long roleId, Long[] userIds) + { + // 新增用户与角色管理 + List list = new ArrayList(); + for (Long userId : userIds) + { + SysUserRole ur = new SysUserRole(); + ur.setUserId(userId); + ur.setRoleId(roleId); + list.add(ur); + } + return userRoleMapper.batchUserRole(list); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysUserOnlineServiceImpl.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysUserOnlineServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..cea30902928626448aa84b3ef8e58b07c7ac4e2f --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysUserOnlineServiceImpl.java @@ -0,0 +1,96 @@ +package com.RVSmartPorting.core.system.service.impl; + +import com.RVSmartPorting.common.core.domain.model.LoginUser; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.core.system.domain.SysUserOnline; +import com.RVSmartPorting.core.system.service.ISysUserOnlineService; +import org.springframework.stereotype.Service; + +/** + * 在线用户 服务层处理 + * + * @author ruoyi + */ +@Service +public class SysUserOnlineServiceImpl implements ISysUserOnlineService +{ + /** + * 通过登录地址查询信息 + * + * @param ipaddr 登录地址 + * @param user 用户信息 + * @return 在线用户信息 + */ + @Override + public SysUserOnline selectOnlineByIpaddr(String ipaddr, LoginUser user) + { + if (StringUtils.equals(ipaddr, user.getIpaddr())) + { + return loginUserToUserOnline(user); + } + return null; + } + + /** + * 通过用户名称查询信息 + * + * @param userName 用户名称 + * @param user 用户信息 + * @return 在线用户信息 + */ + @Override + public SysUserOnline selectOnlineByUserName(String userName, LoginUser user) + { + if (StringUtils.equals(userName, user.getUsername())) + { + return loginUserToUserOnline(user); + } + return null; + } + + /** + * 通过登录地址/用户名称查询信息 + * + * @param ipaddr 登录地址 + * @param userName 用户名称 + * @param user 用户信息 + * @return 在线用户信息 + */ + @Override + public SysUserOnline selectOnlineByInfo(String ipaddr, String userName, LoginUser user) + { + if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername())) + { + return loginUserToUserOnline(user); + } + return null; + } + + /** + * 设置在线用户信息 + * + * @param user 用户信息 + * @return 在线用户 + */ + @Override + public SysUserOnline loginUserToUserOnline(LoginUser user) + { + if (StringUtils.isNull(user) || StringUtils.isNull(user.getUser())) + { + return null; + } + SysUserOnline sysUserOnline = new SysUserOnline(); + sysUserOnline.setTokenId(user.getToken()); + sysUserOnline.setUserName(user.getUsername()); + sysUserOnline.setIpaddr(user.getIpaddr()); + sysUserOnline.setLoginLocation(user.getLoginLocation()); + sysUserOnline.setBrowser(user.getBrowser()); + sysUserOnline.setOs(user.getOs()); + sysUserOnline.setLoginTime(user.getLoginTime()); + if (StringUtils.isNotNull(user.getUser().getDept())) + { + sysUserOnline.setDeptName(user.getUser().getDept().getDeptName()); + } + return sysUserOnline; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysUserServiceImpl.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysUserServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..78c3cfc6dbba9a5867db85544a40392ce45e6f4b --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/service/impl/SysUserServiceImpl.java @@ -0,0 +1,543 @@ +package com.RVSmartPorting.core.system.service.impl; + +import com.RVSmartPorting.common.annotation.DataScope; +import com.RVSmartPorting.common.constant.UserConstants; +import com.RVSmartPorting.common.core.domain.entity.SysRole; +import com.RVSmartPorting.common.core.domain.entity.SysUser; +import com.RVSmartPorting.common.exception.ServiceException; +import com.RVSmartPorting.common.utils.SecurityUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.bean.BeanValidators; +import com.RVSmartPorting.common.utils.spring.SpringUtils; +import com.RVSmartPorting.common.utils.uuid.IdUtils; +import com.RVSmartPorting.core.system.domain.SysPost; +import com.RVSmartPorting.core.system.domain.SysUserPost; +import com.RVSmartPorting.core.system.domain.SysUserRole; +import com.RVSmartPorting.core.system.mapper.*; +import com.RVSmartPorting.core.system.service.ISysConfigService; +import com.RVSmartPorting.core.system.service.ISysUserService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import javax.validation.Validator; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 用户 业务层处理 + * + * @author ruoyi + */ +@Service +public class SysUserServiceImpl implements ISysUserService +{ + private static final Logger log = LoggerFactory.getLogger(SysUserServiceImpl.class); + + @Autowired + private SysUserMapper userMapper; + + @Autowired + private SysRoleMapper roleMapper; + + @Autowired + private SysPostMapper postMapper; + + @Autowired + private SysUserRoleMapper userRoleMapper; + + @Autowired + private SysUserPostMapper userPostMapper; + + @Autowired + private ISysConfigService configService; + + @Autowired + protected Validator validator; + + /** + * 根据条件分页查询用户列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + @DataScope(deptAlias = "d", userAlias = "u") + public List selectUserList(SysUser user) + { + return userMapper.selectUserList(user); + } + + /** + * 根据条件分页查询已分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + @DataScope(deptAlias = "d", userAlias = "u") + public List selectAllocatedList(SysUser user) + { + return userMapper.selectAllocatedList(user); + } + + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + @DataScope(deptAlias = "d", userAlias = "u") + public List selectUnallocatedList(SysUser user) + { + return userMapper.selectUnallocatedList(user); + } + + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + @Override + public SysUser selectUserByUserName(String userName) + { + return userMapper.selectUserByUserName(userName); + } + + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + @Override + public SysUser selectUserById(Long userId) + { + return userMapper.selectUserById(userId); + } + + /** + * 查询用户所属角色组 + * + * @param userName 用户名 + * @return 结果 + */ + @Override + public String selectUserRoleGroup(String userName) + { + List list = roleMapper.selectRolesByUserName(userName); + if (CollectionUtils.isEmpty(list)) + { + return StringUtils.EMPTY; + } + return list.stream().map(SysRole::getRoleName).collect(Collectors.joining(",")); + } + + /** + * 查询用户所属岗位组 + * + * @param userName 用户名 + * @return 结果 + */ + @Override + public String selectUserPostGroup(String userName) + { + List list = postMapper.selectPostsByUserName(userName); + if (CollectionUtils.isEmpty(list)) + { + return StringUtils.EMPTY; + } + return list.stream().map(SysPost::getPostName).collect(Collectors.joining(",")); + } + + /** + * 校验用户名称是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public boolean checkUserNameUnique(SysUser user) + { + Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId(); + SysUser info = userMapper.checkUserNameUnique(user.getUserName()); + if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 校验手机号码是否唯一 + * + * @param user 用户信息 + * @return + */ + @Override + public boolean checkPhoneUnique(SysUser user) + { + Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId(); + SysUser info = userMapper.checkPhoneUnique(user.getPhonenumber()); + if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 校验email是否唯一 + * + * @param user 用户信息 + * @return + */ + @Override + public boolean checkEmailUnique(SysUser user) + { + Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId(); + SysUser info = userMapper.checkEmailUnique(user.getEmail()); + if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 校验用户是否允许操作 + * + * @param user 用户信息 + */ + @Override + public void checkUserAllowed(SysUser user) + { + if (StringUtils.isNotNull(user.getUserId()) && user.isAdmin()) + { + throw new ServiceException("不允许操作超级管理员用户"); + } + } + + /** + * 校验用户是否有数据权限 + * + * @param userId 用户id + */ + @Override + public void checkUserDataScope(Long userId) + { + if (!SysUser.isAdmin(SecurityUtils.getUserId())) + { + SysUser user = new SysUser(); + user.setUserId(userId); + List users = SpringUtils.getAopProxy(this).selectUserList(user); + if (StringUtils.isEmpty(users)) + { + throw new ServiceException("没有权限访问用户数据!"); + } + } + } + + /** + * 新增保存用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + @Transactional + public int insertUser(SysUser user) + { + // 新增用户信息 + int rows = userMapper.insertUser(user); + // 新增用户岗位关联 + insertUserPost(user); + // 新增用户与角色管理 + insertUserRole(user); + return rows; + } + + /** + * 注册用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public boolean registerUser(SysUser user) + { + return userMapper.insertUser(user) > 0; + } + + /** + * 修改保存用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + @Transactional + public int updateUser(SysUser user) + { + Long userId = user.getUserId(); + // 删除用户与角色关联 + userRoleMapper.deleteUserRoleByUserId(userId); + // 新增用户与角色管理 + insertUserRole(user); + // 删除用户与岗位关联 + userPostMapper.deleteUserPostByUserId(userId); + // 新增用户与岗位管理 + insertUserPost(user); + return userMapper.updateUser(user); + } + + /** + * 用户授权角色 + * + * @param userId 用户ID + * @param roleIds 角色组 + */ + @Override + @Transactional + public void insertUserAuth(Long userId, Long[] roleIds) + { + userRoleMapper.deleteUserRoleByUserId(userId); + insertUserRole(userId, roleIds); + } + + /** + * 修改用户状态 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public int updateUserStatus(SysUser user) + { + return userMapper.updateUser(user); + } + + /** + * 修改用户基本信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public int updateUserProfile(SysUser user) + { + return userMapper.updateUser(user); + } + + /** + * 修改用户头像 + * + * @param userName 用户名 + * @param avatar 头像地址 + * @return 结果 + */ + @Override + public boolean updateUserAvatar(String userName, String avatar) + { + return userMapper.updateUserAvatar(userName, avatar) > 0; + } + + /** + * 重置用户密码 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public int resetPwd(SysUser user) + { + return userMapper.updateUser(user); + } + + /** + * 重置用户密码 + * + * @param userName 用户名 + * @param password 密码 + * @return 结果 + */ + @Override + public int resetUserPwd(String userName, String password) + { + return userMapper.resetUserPwd(userName, password); + } + + /** + * 新增用户角色信息 + * + * @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 (StringUtils.isNotEmpty(posts)) + { + // 新增用户与岗位管理 + List list = new ArrayList(posts.length); + for (Long postId : posts) + { + SysUserPost up = new SysUserPost(); + up.setUserId(user.getUserId()); + up.setPostId(postId); + list.add(up); + } + userPostMapper.batchUserPost(list); + } + } + + /** + * 新增用户角色信息 + * + * @param userId 用户ID + * @param roleIds 角色组 + */ + public void insertUserRole(Long userId, Long[] roleIds) + { + if (StringUtils.isNotEmpty(roleIds)) + { + // 新增用户与角色管理 + List list = new ArrayList(roleIds.length); + for (Long roleId : roleIds) + { + SysUserRole ur = new SysUserRole(); + ur.setUserId(userId); + ur.setRoleId(roleId); + list.add(ur); + } + userRoleMapper.batchUserRole(list); + } + } + + /** + * 通过用户ID删除用户 + * + * @param userId 用户ID + * @return 结果 + */ + @Override + @Transactional + public int deleteUserById(Long userId) + { + // 删除用户与角色关联 + userRoleMapper.deleteUserRoleByUserId(userId); + // 删除用户与岗位表 + userPostMapper.deleteUserPostByUserId(userId); + return userMapper.deleteUserById(userId); + } + + /** + * 批量删除用户信息 + * + * @param userIds 需要删除的用户ID + * @return 结果 + */ + @Override + @Transactional + public int deleteUserByIds(Long[] userIds) + { + for (Long userId : userIds) + { + checkUserAllowed(new SysUser(userId)); + checkUserDataScope(userId); + } + // 删除用户与角色关联 + userRoleMapper.deleteUserRole(userIds); + // 删除用户与岗位关联 + userPostMapper.deleteUserPost(userIds); + return userMapper.deleteUserByIds(userIds); + } + + /** + * 导入用户数据 + * + * @param userList 用户数据列表 + * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据 + * @param operName 操作用户 + * @return 结果 + */ + @Override + public String importUser(List userList, Boolean isUpdateSupport, String operName) + { + if (StringUtils.isNull(userList) || userList.size() == 0) + { + throw new ServiceException("导入用户数据不能为空!"); + } + int successNum = 0; + int failureNum = 0; + StringBuilder successMsg = new StringBuilder(); + StringBuilder failureMsg = new StringBuilder(); + String password = configService.selectConfigByKey("sys.user.initPassword"); + for (SysUser user : userList) + { + try + { + // 验证是否存在这个用户 + SysUser u = userMapper.selectUserByUserName(user.getUserName()); + if (StringUtils.isNull(u)) + { + BeanValidators.validateWithException(validator, user); + user.setPassword(SecurityUtils.encryptPassword(password)); + user.setCreateBy(operName); + user.setUserUUID(IdUtils.randomUUID()); + userMapper.insertUser(user); + successNum++; + successMsg.append("
" + successNum + "、账号 " + user.getUserName() + " 导入成功"); + } + else if (isUpdateSupport) + { + BeanValidators.validateWithException(validator, user); + checkUserAllowed(u); + checkUserDataScope(u.getUserId()); + user.setUserId(u.getUserId()); + user.setUpdateBy(operName); + userMapper.updateUser(user); + successNum++; + successMsg.append("
" + successNum + "、账号 " + user.getUserName() + " 更新成功"); + } + else + { + failureNum++; + failureMsg.append("
" + failureNum + "、账号 " + user.getUserName() + " 已存在"); + } + } + catch (Exception e) + { + failureNum++; + String msg = "
" + failureNum + "、账号 " + user.getUserName() + " 导入失败:"; + failureMsg.append(msg + e.getMessage()); + log.error(msg, e); + } + } + if (failureNum > 0) + { + failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); + throw new ServiceException(failureMsg.toString()); + } + else + { + successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:"); + } + return successMsg.toString(); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/sse/DownloadSseMessageType.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/sse/DownloadSseMessageType.java new file mode 100644 index 0000000000000000000000000000000000000000..f63e41a18fa0e4a115201e464e43f7b2e5129827 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/sse/DownloadSseMessageType.java @@ -0,0 +1,9 @@ +package com.RVSmartPorting.core.system.sse; + +public enum DownloadSseMessageType { + onDownloadStart, + onDownloadSuccess, + onDownloading, + onDownloadFailed, + onDownloadTimeout +} \ No newline at end of file diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/sse/SseMessage.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/sse/SseMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..4f2292e92847adb330a9851a38f82f2f23164c23 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/sse/SseMessage.java @@ -0,0 +1,26 @@ +package com.RVSmartPorting.core.system.sse; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * @author xuqiangli + * @create 2023-09-01 16:38 + */ +@Data +public class SseMessage { + String messageType; + String message; + String currentTaskName; + + public SseMessage(String messageType, String message) { + this.messageType = messageType; + this.message = message; + } + + public SseMessage(String messageType, String message, String currentTaskName) { + this.messageType = messageType; + this.message = message; + this.currentTaskName = currentTaskName; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/system/sse/SseServer.java b/CSP-core/src/main/java/com/RVSmartPorting/core/system/sse/SseServer.java new file mode 100644 index 0000000000000000000000000000000000000000..6269a9171fbb2ce41c91cf13919e7d704655a942 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/system/sse/SseServer.java @@ -0,0 +1,236 @@ +package com.RVSmartPorting.core.system.sse; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.MapUtils; +import org.springframework.http.MediaType; +import org.springframework.util.CollectionUtils; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +/** + * SseServer业务封装类来操作SEE + */ +@Slf4j +public class SseServer { + + /** + * 当前连接总数 + */ + private static AtomicInteger currentConnectTotal = new AtomicInteger(0); + + /** + * messageId的 SseEmitter对象映射集 + */ + private static Map sseEmitterMap = new ConcurrentHashMap<>(); + + /** + * 创建sse连接 + * + * @param messageId - 消息id(唯一) + * @return + */ + public static SseEmitter createConnect(String messageId) { + /** + * 设置连接超时时间。0表示不过期,默认是30秒,超过时间未完成会抛出异常 + */ + SseEmitter sseEmitter = new SseEmitter(0L); + // 注册回调 + sseEmitter.onCompletion(completionCallBack(messageId)); + sseEmitter.onTimeout(timeOutCallBack(messageId)); + sseEmitter.onError(errorCallBack(messageId)); + sseEmitterMap.put(messageId, sseEmitter); + //记录一下连接总数。数量+1 + int count = currentConnectTotal.incrementAndGet(); + log.info("创建sse连接成功 ==> 当前连接总数={}, messageId={}", count, messageId); + return sseEmitter; + } + + /** + * 给指定 messageId发消息 + * + * @param messageId - 消息id(唯一) + * @param message - 消息文本 + */ + public static void sendMessage(String messageId, String message) { + if (sseEmitterMap.containsKey(messageId)) { + try { + sseEmitterMap.get(messageId).send(message); + } catch (IOException e) { + log.error("发送消息异常 ==> messageId={}, 异常信息:", messageId, e); + e.printStackTrace(); + } + } else { + throw new RuntimeException("连接不存在或者超时, messageId=" + messageId); + } + } + + /** + * 给指定 messageId发带有type的消息 + * + * @param messageId - 消息id(唯一) + * @param message - 消息文本 + */ + public static void sendMessage(String messageId, DownloadSseMessageType messageType, String message) { + if (sseEmitterMap.containsKey(messageId)) { + try { + sseEmitterMap.get(messageId).send(new SseMessage(messageType.name(), message)); + } catch (IOException e) { + log.error("发送消息异常 ==> messageId={}, 异常信息:", messageId, e); + e.printStackTrace(); + } + } else { + throw new RuntimeException("连接不存在或者超时, messageId=" + messageId); + } + } + + /** + * 给指定 messageId发带有type和currentTaskName的消息 + * + * @param messageId - 消息id(唯一) + * @param message - 消息文本 + */ + public static void sendMessage(String messageId, DownloadSseMessageType messageType, String message, String currentTaskName) { + if (sseEmitterMap.containsKey(messageId)) { + try { + sseEmitterMap.get(messageId).send(new SseMessage(messageType.name(), message, currentTaskName)); + } catch (IOException e) { + log.error("发送消息异常 ==> messageId={}, 异常信息:", messageId, e); + e.printStackTrace(); + } + } else { + throw new RuntimeException("连接不存在或者超时, messageId=" + messageId); + } + } + + /** + * 给所有 messageId广播发送消息 + * + * @param message + */ + public static void batchAllSendMessage(String message) { + sseEmitterMap.forEach((messageId, sseEmitter) -> { + try { + sseEmitter.send(message, MediaType.APPLICATION_JSON); + } catch (IOException e) { + log.error("广播发送消息异常 ==> messageId={}, 异常信息:", messageId, e); + removeMessageId(messageId); + } + }); + } + + /** + * 给指定 messageId集合群发消息 + * + * @param messageIds + * @param message + */ + public static void batchSendMessage(List messageIds, String message) { + if (CollectionUtils.isEmpty(messageIds)) { + return; + } + // 去重 + messageIds = messageIds.stream().distinct().collect(Collectors.toList()); + messageIds.forEach(userId -> sendMessage(userId, message)); + } + + + /** + * 给指定组群发消息(即组播,我们让 messageId满足我们的组命名确定即可) + * + * @param groupId + * @param message + */ + public static void groupSendMessage(String groupId, String message) { + if (MapUtils.isEmpty(sseEmitterMap)) { + return; + } + sseEmitterMap.forEach((messageId, sseEmitter) -> { + try { + // 这里 groupId作为前缀 + if (messageId.startsWith(groupId)) { + sseEmitter.send(message, MediaType.APPLICATION_JSON); + } + } catch (IOException e) { + log.error("组播发送消息异常 ==> groupId={}, 异常信息:", groupId, e.getMessage()); + removeMessageId(messageId); + } + }); + } + + /** + * 移除 MessageId + * + * @param messageId + */ + public static void removeMessageId(String messageId) { + sseEmitterMap.remove(messageId); + //数量-1 + currentConnectTotal.getAndDecrement(); + log.info("remove messageId={}", messageId); + } + + /** + * 获取所有的 MessageId集合 + * + * @return + */ + public static List getMessageIds() { + return new ArrayList<>(sseEmitterMap.keySet()); + } + + /** + * 获取当前连接总数 + * + * @return + */ + public static int getConnectTotal() { + return currentConnectTotal.intValue(); + } + + /** + * 断开SSE连接时的回调 + * + * @param messageId + * @return + */ + private static Runnable completionCallBack(String messageId) { + return () -> { + log.info("结束连接 ==> messageId={}", messageId); + removeMessageId(messageId); + }; + } + + /** + * 连接超时时回调触发 + * + * @param messageId + * @return + */ + private static Runnable timeOutCallBack(String messageId) { + return () -> { + log.info("连接超时 ==> messageId={}", messageId); + removeMessageId(messageId); + }; + } + + /** + * 连接报错时回调触发。 + * + * @param messageId + * @return + */ + private static Consumer errorCallBack(String messageId) { + return throwable -> { + log.error("连接异常 ==> messageId={}", messageId); + removeMessageId(messageId); + }; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/web/domain/Server.java b/CSP-core/src/main/java/com/RVSmartPorting/core/web/domain/Server.java new file mode 100644 index 0000000000000000000000000000000000000000..f7f9e6498682a7d66377ff3d416e028b972f7418 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/web/domain/Server.java @@ -0,0 +1,237 @@ +package com.RVSmartPorting.core.web.domain; + +import com.RVSmartPorting.common.utils.Arith; +import com.RVSmartPorting.common.utils.ip.IpUtils; +import com.RVSmartPorting.core.web.domain.server.*; +import oshi.SystemInfo; +import oshi.hardware.CentralProcessor; +import oshi.hardware.CentralProcessor.TickType; +import oshi.hardware.GlobalMemory; +import oshi.hardware.HardwareAbstractionLayer; +import oshi.software.os.FileSystem; +import oshi.software.os.OSFileStore; +import oshi.software.os.OperatingSystem; +import oshi.util.Util; + +import java.net.UnknownHostException; +import java.util.LinkedList; +import java.util.List; +import java.util.Properties; + +/** + * 服务器相关信息 + * + * @author ruoyi + */ +public class Server +{ + private static final int OSHI_WAIT_SECOND = 1000; + + /** + * CPU相关信息 + */ + private Cpu cpu = new Cpu(); + + /** + * 內存相关信息 + */ + private Mem mem = new Mem(); + + /** + * JVM相关信息 + */ + private Jvm jvm = new Jvm(); + + /** + * 服务器相关信息 + */ + private Sys sys = new Sys(); + + /** + * 磁盘相关信息 + */ + private List sysFiles = new LinkedList(); + + public Cpu getCpu() + { + return cpu; + } + + public void setCpu(Cpu cpu) + { + this.cpu = cpu; + } + + public Mem getMem() + { + return mem; + } + + public void setMem(Mem mem) + { + this.mem = mem; + } + + public Jvm getJvm() + { + return jvm; + } + + public void setJvm(Jvm jvm) + { + this.jvm = jvm; + } + + public Sys getSys() + { + return sys; + } + + public void setSys(Sys sys) + { + this.sys = sys; + } + + public List getSysFiles() + { + return sysFiles; + } + + public void setSysFiles(List sysFiles) + { + this.sysFiles = sysFiles; + } + + public void copyTo() throws Exception + { + SystemInfo si = new SystemInfo(); + HardwareAbstractionLayer hal = si.getHardware(); + + setCpuInfo(hal.getProcessor()); + + setMemInfo(hal.getMemory()); + + setSysInfo(); + + setJvmInfo(); + + setSysFiles(si.getOperatingSystem()); + } + + /** + * 设置CPU信息 + */ + private void setCpuInfo(CentralProcessor processor) + { + // CPU信息 + long[] prevTicks = processor.getSystemCpuLoadTicks(); + Util.sleep(OSHI_WAIT_SECOND); + long[] ticks = processor.getSystemCpuLoadTicks(); + long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()]; + long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()]; + long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()]; + long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()]; + long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()]; + long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()]; + long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()]; + long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()]; + long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal; + cpu.setCpuNum(processor.getLogicalProcessorCount()); + cpu.setTotal(totalCpu); + cpu.setSys(cSys); + cpu.setUsed(user); + cpu.setWait(iowait); + cpu.setFree(idle); + } + + /** + * 设置内存信息 + */ + private void setMemInfo(GlobalMemory memory) + { + mem.setTotal(memory.getTotal()); + mem.setUsed(memory.getTotal() - memory.getAvailable()); + mem.setFree(memory.getAvailable()); + } + + /** + * 设置服务器信息 + */ + private void setSysInfo() + { + Properties props = System.getProperties(); + sys.setComputerName(IpUtils.getHostName()); + sys.setComputerIp(IpUtils.getHostIp()); + sys.setOsName(props.getProperty("os.name")); + sys.setOsArch(props.getProperty("os.arch")); + sys.setUserDir(props.getProperty("user.dir")); + } + + /** + * 设置Java虚拟机 + */ + private void setJvmInfo() throws UnknownHostException + { + Properties props = System.getProperties(); + jvm.setTotal(Runtime.getRuntime().totalMemory()); + jvm.setMax(Runtime.getRuntime().maxMemory()); + jvm.setFree(Runtime.getRuntime().freeMemory()); + jvm.setVersion(props.getProperty("java.version")); + jvm.setHome(props.getProperty("java.home")); + } + + /** + * 设置磁盘信息 + */ + private void setSysFiles(OperatingSystem os) + { + FileSystem fileSystem = os.getFileSystem(); + List fsArray = fileSystem.getFileStores(); + for (OSFileStore fs : fsArray) + { + long free = fs.getUsableSpace(); + long total = fs.getTotalSpace(); + long used = total - free; + SysFile sysFile = new SysFile(); + sysFile.setDirName(fs.getMount()); + sysFile.setSysTypeName(fs.getType()); + sysFile.setTypeName(fs.getName()); + sysFile.setTotal(convertFileSize(total)); + sysFile.setFree(convertFileSize(free)); + sysFile.setUsed(convertFileSize(used)); + sysFile.setUsage(Arith.mul(Arith.div(used, total, 4), 100)); + sysFiles.add(sysFile); + } + } + + /** + * 字节转换 + * + * @param size 字节大小 + * @return 转换后值 + */ + public String convertFileSize(long size) + { + long kb = 1024; + long mb = kb * 1024; + long gb = mb * 1024; + if (size >= gb) + { + return String.format("%.1f GB", (float) size / gb); + } + else if (size >= mb) + { + float f = (float) size / mb; + return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f); + } + else if (size >= kb) + { + float f = (float) size / kb; + return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f); + } + else + { + return String.format("%d B", size); + } + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/web/domain/server/Cpu.java b/CSP-core/src/main/java/com/RVSmartPorting/core/web/domain/server/Cpu.java new file mode 100644 index 0000000000000000000000000000000000000000..5568faee4a42358f220616e23e0e7b288ea65952 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/web/domain/server/Cpu.java @@ -0,0 +1,102 @@ +package com.RVSmartPorting.core.web.domain.server; + + +import com.RVSmartPorting.common.utils.Arith; + +/** + * CPU相关信息 + * + * @author ruoyi + */ +public class Cpu +{ + /** + * 核心数 + */ + private int cpuNum; + + /** + * CPU总的使用率 + */ + private double total; + + /** + * CPU系统使用率 + */ + private double sys; + + /** + * CPU用户使用率 + */ + private double used; + + /** + * CPU当前等待率 + */ + private double wait; + + /** + * CPU当前空闲率 + */ + private double free; + + public int getCpuNum() + { + return cpuNum; + } + + public void setCpuNum(int cpuNum) + { + this.cpuNum = cpuNum; + } + + public double getTotal() + { + return Arith.round(Arith.mul(total, 100), 2); + } + + public void setTotal(double total) + { + this.total = total; + } + + public double getSys() + { + return Arith.round(Arith.mul(sys / total, 100), 2); + } + + public void setSys(double sys) + { + this.sys = sys; + } + + public double getUsed() + { + return Arith.round(Arith.mul(used / total, 100), 2); + } + + public void setUsed(double used) + { + this.used = used; + } + + public double getWait() + { + return Arith.round(Arith.mul(wait / total, 100), 2); + } + + public void setWait(double wait) + { + this.wait = wait; + } + + public double getFree() + { + return Arith.round(Arith.mul(free / total, 100), 2); + } + + public void setFree(double free) + { + this.free = free; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/web/domain/server/Jvm.java b/CSP-core/src/main/java/com/RVSmartPorting/core/web/domain/server/Jvm.java new file mode 100644 index 0000000000000000000000000000000000000000..982afdb1c04f7efaa6c31586f14f553a10abee38 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/web/domain/server/Jvm.java @@ -0,0 +1,131 @@ +package com.RVSmartPorting.core.web.domain.server; + +import com.RVSmartPorting.common.utils.Arith; +import com.RVSmartPorting.common.utils.DateUtils; + +import java.lang.management.ManagementFactory; + +/** + * JVM相关信息 + * + * @author ruoyi + */ +public class Jvm +{ + /** + * 当前JVM占用的内存总数(M) + */ + private double total; + + /** + * JVM最大可用内存总数(M) + */ + private double max; + + /** + * JVM空闲内存(M) + */ + private double free; + + /** + * JDK版本 + */ + private String version; + + /** + * JDK路径 + */ + private String home; + + public double getTotal() + { + return Arith.div(total, (1024 * 1024), 2); + } + + public void setTotal(double total) + { + this.total = total; + } + + public double getMax() + { + return Arith.div(max, (1024 * 1024), 2); + } + + public void setMax(double max) + { + this.max = max; + } + + public double getFree() + { + return Arith.div(free, (1024 * 1024), 2); + } + + public void setFree(double free) + { + this.free = free; + } + + public double getUsed() + { + return Arith.div(total - free, (1024 * 1024), 2); + } + + public double getUsage() + { + return Arith.mul(Arith.div(total - free, total, 4), 100); + } + + /** + * 获取JDK名称 + */ + public String getName() + { + return ManagementFactory.getRuntimeMXBean().getVmName(); + } + + public String getVersion() + { + return version; + } + + public void setVersion(String version) + { + this.version = version; + } + + public String getHome() + { + return home; + } + + public void setHome(String home) + { + this.home = home; + } + + /** + * JDK启动时间 + */ + public String getStartTime() + { + return DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.getServerStartDate()); + } + + /** + * JDK运行时间 + */ + public String getRunTime() + { + return DateUtils.timeDistance(DateUtils.getNowDate(), DateUtils.getServerStartDate()); + } + + /** + * 运行参数 + */ + public String getInputArgs() + { + return ManagementFactory.getRuntimeMXBean().getInputArguments().toString(); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/web/domain/server/Mem.java b/CSP-core/src/main/java/com/RVSmartPorting/core/web/domain/server/Mem.java new file mode 100644 index 0000000000000000000000000000000000000000..2e6e450beb151927786135c04640918bd30221a3 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/web/domain/server/Mem.java @@ -0,0 +1,61 @@ +package com.RVSmartPorting.core.web.domain.server; + +import com.RVSmartPorting.common.utils.Arith; + +/** + * 內存相关信息 + * + * @author ruoyi + */ +public class Mem +{ + /** + * 内存总量 + */ + private double total; + + /** + * 已用内存 + */ + private double used; + + /** + * 剩余内存 + */ + private double free; + + public double getTotal() + { + return Arith.div(total, (1024 * 1024 * 1024), 2); + } + + public void setTotal(long total) + { + this.total = total; + } + + public double getUsed() + { + return Arith.div(used, (1024 * 1024 * 1024), 2); + } + + public void setUsed(long used) + { + this.used = used; + } + + public double getFree() + { + return Arith.div(free, (1024 * 1024 * 1024), 2); + } + + public void setFree(long free) + { + this.free = free; + } + + public double getUsage() + { + return Arith.mul(Arith.div(used, total, 4), 100); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/web/domain/server/Sys.java b/CSP-core/src/main/java/com/RVSmartPorting/core/web/domain/server/Sys.java new file mode 100644 index 0000000000000000000000000000000000000000..ffe278a0fdc88ffa77236f2bf031547ced4f350d --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/web/domain/server/Sys.java @@ -0,0 +1,84 @@ +package com.RVSmartPorting.core.web.domain.server; + +/** + * 系统相关信息 + * + * @author ruoyi + */ +public class Sys +{ + /** + * 服务器名称 + */ + private String computerName; + + /** + * 服务器Ip + */ + private String computerIp; + + /** + * 项目路径 + */ + private String userDir; + + /** + * 操作系统 + */ + private String osName; + + /** + * 系统架构 + */ + private String osArch; + + public String getComputerName() + { + return computerName; + } + + public void setComputerName(String computerName) + { + this.computerName = computerName; + } + + public String getComputerIp() + { + return computerIp; + } + + public void setComputerIp(String computerIp) + { + this.computerIp = computerIp; + } + + public String getUserDir() + { + return userDir; + } + + public void setUserDir(String userDir) + { + this.userDir = userDir; + } + + public String getOsName() + { + return osName; + } + + public void setOsName(String osName) + { + this.osName = osName; + } + + public String getOsArch() + { + return osArch; + } + + public void setOsArch(String osArch) + { + this.osArch = osArch; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/web/domain/server/SysFile.java b/CSP-core/src/main/java/com/RVSmartPorting/core/web/domain/server/SysFile.java new file mode 100644 index 0000000000000000000000000000000000000000..24299e43a95d50cfa5aa63ad9ac3b8ab71bae537 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/web/domain/server/SysFile.java @@ -0,0 +1,114 @@ +package com.RVSmartPorting.core.web.domain.server; + +/** + * 系统文件相关信息 + * + * @author ruoyi + */ +public class SysFile +{ + /** + * 盘符路径 + */ + private String dirName; + + /** + * 盘符类型 + */ + private String sysTypeName; + + /** + * 文件类型 + */ + private String typeName; + + /** + * 总大小 + */ + private String total; + + /** + * 剩余大小 + */ + private String free; + + /** + * 已经使用量 + */ + private String used; + + /** + * 资源的使用率 + */ + private double usage; + + public String getDirName() + { + return dirName; + } + + public void setDirName(String dirName) + { + this.dirName = dirName; + } + + public String getSysTypeName() + { + return sysTypeName; + } + + public void setSysTypeName(String sysTypeName) + { + this.sysTypeName = sysTypeName; + } + + public String getTypeName() + { + return typeName; + } + + public void setTypeName(String typeName) + { + this.typeName = typeName; + } + + public String getTotal() + { + return total; + } + + public void setTotal(String total) + { + this.total = total; + } + + public String getFree() + { + return free; + } + + public void setFree(String free) + { + this.free = free; + } + + public String getUsed() + { + return used; + } + + public void setUsed(String used) + { + this.used = used; + } + + public double getUsage() + { + return usage; + } + + public void setUsage(double usage) + { + this.usage = usage; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/web/exception/GlobalExceptionHandler.java b/CSP-core/src/main/java/com/RVSmartPorting/core/web/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..a835fd307d59e62bf349de5280e1cb1611b0c3fb --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/web/exception/GlobalExceptionHandler.java @@ -0,0 +1,139 @@ +package com.RVSmartPorting.core.web.exception; + +import com.RVSmartPorting.common.constant.HttpStatus; +import com.RVSmartPorting.common.core.domain.AjaxResult; +import com.RVSmartPorting.common.exception.DemoModeException; +import com.RVSmartPorting.common.exception.ServiceException; +import com.RVSmartPorting.common.utils.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.validation.BindException; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.MissingPathVariableException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; + +import javax.servlet.http.HttpServletRequest; + +/** + * 全局异常处理器 + * + * @author ruoyi + */ +@RestControllerAdvice +public class GlobalExceptionHandler +{ + private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); + + /** + * 权限校验异常 + */ + @ExceptionHandler(AccessDeniedException.class) + public AjaxResult handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request) + { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',权限校验失败'{}'", requestURI, e.getMessage()); + return AjaxResult.error(HttpStatus.FORBIDDEN, "没有权限,请联系管理员授权"); + } + + /** + * 请求方式不支持 + */ + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e, + HttpServletRequest request) + { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod()); + return AjaxResult.error(e.getMessage()); + } + + /** + * 业务异常 + */ + @ExceptionHandler(ServiceException.class) + public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request) + { + log.error(e.getMessage(), e); + Integer code = e.getCode(); + return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage()); + } + + /** + * 请求路径中缺少必需的路径变量 + */ + @ExceptionHandler(MissingPathVariableException.class) + public AjaxResult handleMissingPathVariableException(MissingPathVariableException e, HttpServletRequest request) + { + String requestURI = request.getRequestURI(); + log.error("请求路径中缺少必需的路径变量'{}',发生系统异常.", requestURI, e); + return AjaxResult.error(String.format("请求路径中缺少必需的路径变量[%s]", e.getVariableName())); + } + + /** + * 请求参数类型不匹配 + */ + @ExceptionHandler(MethodArgumentTypeMismatchException.class) + public AjaxResult handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request) + { + String requestURI = request.getRequestURI(); + log.error("请求参数类型不匹配'{}',发生系统异常.", requestURI, e); + return AjaxResult.error(String.format("请求参数类型不匹配,参数[%s]要求类型为:'%s',但输入值为:'%s'", e.getName(), e.getRequiredType().getName(), e.getValue())); + } + + /** + * 拦截未知的运行时异常 + */ + @ExceptionHandler(RuntimeException.class) + public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request) + { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',发生未知异常.", requestURI, e); + return AjaxResult.error(e.getMessage()); + } + + /** + * 系统异常 + */ + @ExceptionHandler(Exception.class) + public AjaxResult handleException(Exception e, HttpServletRequest request) + { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',发生系统异常.", requestURI, e); + return AjaxResult.error(e.getMessage()); + } + + /** + * 自定义验证异常 + */ + @ExceptionHandler(BindException.class) + public AjaxResult handleBindException(BindException e) + { + log.error(e.getMessage(), e); + String message = e.getAllErrors().get(0).getDefaultMessage(); + return AjaxResult.error(message); + } + + /** + * 自定义验证异常 + */ + @ExceptionHandler(MethodArgumentNotValidException.class) + public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) + { + log.error(e.getMessage(), e); + String message = e.getBindingResult().getFieldError().getDefaultMessage(); + return AjaxResult.error(message); + } + + /** + * 演示模式异常 + */ + @ExceptionHandler(DemoModeException.class) + public AjaxResult handleDemoModeException(DemoModeException e) + { + return AjaxResult.error("演示模式,不允许操作"); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/web/service/PermissionService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/web/service/PermissionService.java new file mode 100644 index 0000000000000000000000000000000000000000..8af248314b60955417b5f5a37e33366c4bb35fdd --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/web/service/PermissionService.java @@ -0,0 +1,169 @@ +package com.RVSmartPorting.core.web.service; + +import com.RVSmartPorting.common.core.domain.entity.SysRole; +import com.RVSmartPorting.common.core.domain.model.LoginUser; +import com.RVSmartPorting.common.utils.SecurityUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.core.security.context.PermissionContextHolder; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.Set; + +/** + * RuoYi首创 自定义权限实现,ss取自SpringSecurity首字母 + * + * @author ruoyi + */ +@Service("ss") +public class PermissionService +{ + /** 所有权限标识 */ + private static final String ALL_PERMISSION = "*:*:*"; + + /** 管理员角色权限标识 */ + private static final String SUPER_ADMIN = "admin"; + + private static final String ROLE_DELIMETER = ","; + + private static final String PERMISSION_DELIMETER = ","; + + /** + * 验证用户是否具备某权限 + * + * @param permission 权限字符串 + * @return 用户是否具备某权限 + */ + public boolean hasPermi(String permission) + { + if (StringUtils.isEmpty(permission)) + { + return false; + } + LoginUser loginUser = SecurityUtils.getLoginUser(); + if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())) + { + return false; + } + PermissionContextHolder.setContext(permission); + return hasPermissions(loginUser.getPermissions(), permission); + } + + /** + * 验证用户是否不具备某权限,与 hasPermi逻辑相反 + * + * @param permission 权限字符串 + * @return 用户是否不具备某权限 + */ + public boolean lacksPermi(String permission) + { + return hasPermi(permission) != true; + } + + /** + * 验证用户是否具有以下任意一个权限 + * + * @param permissions 以 PERMISSION_DELIMETER 为分隔符的权限列表 + * @return 用户是否具有以下任意一个权限 + */ + public boolean hasAnyPermi(String permissions) + { + if (StringUtils.isEmpty(permissions)) + { + return false; + } + LoginUser loginUser = SecurityUtils.getLoginUser(); + if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())) + { + return false; + } + PermissionContextHolder.setContext(permissions); + Set authorities = loginUser.getPermissions(); + for (String permission : permissions.split(PERMISSION_DELIMETER)) + { + if (permission != null && hasPermissions(authorities, permission)) + { + return true; + } + } + return false; + } + + /** + * 判断用户是否拥有某个角色 + * + * @param role 角色字符串 + * @return 用户是否具备某角色 + */ + public boolean hasRole(String role) + { + if (StringUtils.isEmpty(role)) + { + return false; + } + LoginUser loginUser = SecurityUtils.getLoginUser(); + if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles())) + { + return false; + } + for (SysRole sysRole : loginUser.getUser().getRoles()) + { + String roleKey = sysRole.getRoleKey(); + if (SUPER_ADMIN.equals(roleKey) || roleKey.equals(StringUtils.trim(role))) + { + return true; + } + } + return false; + } + + /** + * 验证用户是否不具备某角色,与 isRole逻辑相反。 + * + * @param role 角色名称 + * @return 用户是否不具备某角色 + */ + public boolean lacksRole(String role) + { + return hasRole(role) != true; + } + + /** + * 验证用户是否具有以下任意一个角色 + * + * @param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表 + * @return 用户是否具有以下任意一个角色 + */ + public boolean hasAnyRoles(String roles) + { + if (StringUtils.isEmpty(roles)) + { + return false; + } + LoginUser loginUser = SecurityUtils.getLoginUser(); + if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles())) + { + return false; + } + for (String role : roles.split(ROLE_DELIMETER)) + { + if (hasRole(role)) + { + return true; + } + } + return false; + } + + /** + * 判断是否包含权限 + * + * @param permissions 权限列表 + * @param permission 权限字符串 + * @return 用户是否具备某权限 + */ + private boolean hasPermissions(Set permissions, String permission) + { + return permissions.contains(ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission)); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/web/service/SysLoginService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/web/service/SysLoginService.java new file mode 100644 index 0000000000000000000000000000000000000000..d6ae3ff4855cf6fe3bbadec08070f75f9b676488 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/web/service/SysLoginService.java @@ -0,0 +1,178 @@ +package com.RVSmartPorting.core.web.service; + +import com.RVSmartPorting.common.constant.CacheConstants; +import com.RVSmartPorting.common.constant.Constants; +import com.RVSmartPorting.common.constant.UserConstants; +import com.RVSmartPorting.common.core.domain.entity.SysUser; +import com.RVSmartPorting.common.core.domain.model.LoginUser; +import com.RVSmartPorting.common.exception.ServiceException; +import com.RVSmartPorting.common.exception.user.*; +import com.RVSmartPorting.common.utils.DateUtils; +import com.RVSmartPorting.common.utils.MessageUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.ip.IpUtils; +import com.RVSmartPorting.common.utils.redis.RedisCache; +import com.RVSmartPorting.core.manager.AsyncManager; +import com.RVSmartPorting.core.manager.factory.AsyncFactory; +import com.RVSmartPorting.core.security.context.AuthenticationContextHolder; +import com.RVSmartPorting.core.system.service.ISysConfigService; +import com.RVSmartPorting.core.system.service.ISysUserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 登录校验方法 + * + * @author ruoyi + */ +@Component +public class SysLoginService +{ + @Autowired + private TokenService tokenService; + + @Resource + private AuthenticationManager authenticationManager; + + @Autowired + private RedisCache redisCache; + + @Autowired + private ISysUserService userService; + + @Autowired + private ISysConfigService configService; + + /** + * 登录验证 + * + * @param username 用户名 + * @param password 密码 + * @param code 验证码 + * @param uuid 唯一标识 + * @return 结果 + */ + public String login(String username, String password, String code, String uuid) + { + // 验证码校验 + validateCaptcha(username, code, uuid); + // 登录前置校验 + loginPreCheck(username, password); + // 用户验证 + Authentication authentication = null; + try + { + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password); + AuthenticationContextHolder.setContext(authenticationToken); + // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername + authentication = authenticationManager.authenticate(authenticationToken); + } + catch (Exception e) + { + if (e instanceof BadCredentialsException) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); + throw new UserPasswordNotMatchException(); + } + else + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage())); + throw new ServiceException(e.getMessage()); + } + } + finally + { + AuthenticationContextHolder.clearContext(); + } + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"))); + LoginUser loginUser = (LoginUser) authentication.getPrincipal(); + recordLoginInfo(loginUser.getUserId()); + // 生成token + return tokenService.createToken(loginUser); + } + + /** + * 校验验证码 + * + * @param username 用户名 + * @param code 验证码 + * @param uuid 唯一标识 + * @return 结果 + */ + public void validateCaptcha(String username, String code, String uuid) + { + boolean captchaEnabled = configService.selectCaptchaEnabled(); + if (captchaEnabled) + { + String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, ""); + String captcha = redisCache.getCacheObject(verifyKey); + redisCache.deleteObject(verifyKey); + if (captcha == null) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"))); + throw new CaptchaExpireException(); + } + if (!code.equalsIgnoreCase(captcha)) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"))); + throw new CaptchaException(); + } + } + } + + /** + * 登录前置校验 + * @param username 用户名 + * @param password 用户密码 + */ + public void loginPreCheck(String username, String password) + { + // 用户名或密码为空 错误 + if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null"))); + throw new UserNotExistsException(); + } + // 密码如果不在指定范围内 错误 + if (password.length() < UserConstants.PASSWORD_MIN_LENGTH + || password.length() > UserConstants.PASSWORD_MAX_LENGTH) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); + throw new UserPasswordNotMatchException(); + } + // 用户名不在指定范围内 错误 + if (username.length() < UserConstants.USERNAME_MIN_LENGTH + || username.length() > UserConstants.USERNAME_MAX_LENGTH) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); + throw new UserPasswordNotMatchException(); + } + // IP黑名单校验 + String blackStr = configService.selectConfigByKey("sys.login.blackIPList"); + if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr())) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("login.blocked"))); + throw new BlackListException(); + } + } + + /** + * 记录登录信息 + * + * @param userId 用户ID + */ + public void recordLoginInfo(Long userId) + { + SysUser sysUser = new SysUser(); + sysUser.setUserId(userId); + sysUser.setLoginIp(IpUtils.getIpAddr()); + sysUser.setLoginDate(DateUtils.getNowDate()); + userService.updateUserProfile(sysUser); + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/web/service/SysPasswordService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/web/service/SysPasswordService.java new file mode 100644 index 0000000000000000000000000000000000000000..ea9dd5613267a9231014bdcb57cc28fcd9f16e8d --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/web/service/SysPasswordService.java @@ -0,0 +1,95 @@ +package com.RVSmartPorting.core.web.service; + +import com.RVSmartPorting.common.constant.CacheConstants; +import com.RVSmartPorting.common.constant.Constants; +import com.RVSmartPorting.common.core.domain.entity.SysUser; +import com.RVSmartPorting.common.exception.user.UserPasswordNotMatchException; +import com.RVSmartPorting.common.exception.user.UserPasswordRetryLimitExceedException; +import com.RVSmartPorting.common.utils.MessageUtils; +import com.RVSmartPorting.common.utils.SecurityUtils; +import com.RVSmartPorting.common.utils.redis.RedisCache; +import com.RVSmartPorting.core.manager.AsyncManager; +import com.RVSmartPorting.core.manager.factory.AsyncFactory; +import com.RVSmartPorting.core.security.context.AuthenticationContextHolder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Component; + +import java.util.concurrent.TimeUnit; + +/** + * 登录密码方法 + * + * @author ruoyi + */ +@Component +public class SysPasswordService +{ + @Autowired + private RedisCache redisCache; + + @Value(value = "${user.password.maxRetryCount}") + private int maxRetryCount; + + @Value(value = "${user.password.lockTime}") + private int lockTime; + + /** + * 登录账户密码错误次数缓存键名 + * + * @param username 用户名 + * @return 缓存键key + */ + private String getCacheKey(String username) + { + return CacheConstants.PWD_ERR_CNT_KEY + username; + } + + public void validate(SysUser user) + { + Authentication usernamePasswordAuthenticationToken = AuthenticationContextHolder.getContext(); + String username = usernamePasswordAuthenticationToken.getName(); + String password = usernamePasswordAuthenticationToken.getCredentials().toString(); + + Integer retryCount = redisCache.getCacheObject(getCacheKey(username)); + + if (retryCount == null) + { + retryCount = 0; + } + + if (retryCount >= Integer.valueOf(maxRetryCount).intValue()) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, + MessageUtils.message("user.password.retry.limit.exceed", maxRetryCount, lockTime))); + throw new UserPasswordRetryLimitExceedException(maxRetryCount, lockTime); + } + + if (!matches(user, password)) + { + retryCount = retryCount + 1; + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, + MessageUtils.message("user.password.retry.limit.count", retryCount))); + redisCache.setCacheObject(getCacheKey(username), retryCount, lockTime, TimeUnit.MINUTES); + throw new UserPasswordNotMatchException(); + } + else + { + clearLoginRecordCache(username); + } + } + + public boolean matches(SysUser user, String rawPassword) + { + return SecurityUtils.matchesPassword(rawPassword, user.getPassword()); + } + + public void clearLoginRecordCache(String loginName) + { + if (redisCache.hasKey(getCacheKey(loginName))) + { + redisCache.deleteObject(getCacheKey(loginName)); + } + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/web/service/SysPermissionService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/web/service/SysPermissionService.java new file mode 100644 index 0000000000000000000000000000000000000000..d2b36ddd0145fc5bf315046f5ed5552ca241f84e --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/web/service/SysPermissionService.java @@ -0,0 +1,84 @@ +package com.RVSmartPorting.core.web.service; + +import com.RVSmartPorting.common.core.domain.entity.SysRole; +import com.RVSmartPorting.common.core.domain.entity.SysUser; +import com.RVSmartPorting.core.system.service.ISysMenuService; +import com.RVSmartPorting.core.system.service.ISysRoleService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * 用户权限处理 + * + * @author ruoyi + */ +@Component +public class SysPermissionService +{ + @Autowired + private ISysRoleService roleService; + + @Autowired + private 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 + { + List roles = user.getRoles(); + if (!CollectionUtils.isEmpty(roles)) + { + // 多角色设置permissions属性,以便数据权限匹配权限 + for (SysRole role : roles) + { + Set rolePerms = menuService.selectMenuPermsByRoleId(role.getRoleId()); + role.setPermissions(rolePerms); + perms.addAll(rolePerms); + } + } + else + { + perms.addAll(menuService.selectMenuPermsByUserId(user.getUserId())); + } + } + return perms; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/web/service/SysRegisterService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/web/service/SysRegisterService.java new file mode 100644 index 0000000000000000000000000000000000000000..052932cee246fe9399ee32e5d88699c1c260f693 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/web/service/SysRegisterService.java @@ -0,0 +1,117 @@ +package com.RVSmartPorting.core.web.service; + +import com.RVSmartPorting.common.constant.CacheConstants; +import com.RVSmartPorting.common.constant.Constants; +import com.RVSmartPorting.common.constant.UserConstants; +import com.RVSmartPorting.common.core.domain.entity.SysUser; +import com.RVSmartPorting.common.core.domain.model.RegisterBody; +import com.RVSmartPorting.common.exception.user.CaptchaException; +import com.RVSmartPorting.common.exception.user.CaptchaExpireException; +import com.RVSmartPorting.common.utils.MessageUtils; +import com.RVSmartPorting.common.utils.SecurityUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.redis.RedisCache; +import com.RVSmartPorting.common.utils.uuid.IdUtils; +import com.RVSmartPorting.core.manager.AsyncManager; +import com.RVSmartPorting.core.manager.factory.AsyncFactory; +import com.RVSmartPorting.core.system.service.ISysConfigService; +import com.RVSmartPorting.core.system.service.ISysUserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * 注册校验方法 + * + * @author ruoyi + */ +@Component +public class SysRegisterService +{ + @Autowired + private ISysUserService userService; + + @Autowired + private ISysConfigService configService; + + @Autowired + private RedisCache redisCache; + + /** + * 注册 + */ + public String register(RegisterBody registerBody) + { + String msg = "", username = registerBody.getUsername(), password = registerBody.getPassword(); + SysUser sysUser = new SysUser(); + sysUser.setUserName(username); + + // 验证码开关 + boolean captchaEnabled = configService.selectCaptchaEnabled(); + if (captchaEnabled) + { + validateCaptcha(username, registerBody.getCode(), registerBody.getUuid()); + } + + if (StringUtils.isEmpty(username)) + { + msg = "用户名不能为空"; + } + else if (StringUtils.isEmpty(password)) + { + msg = "用户密码不能为空"; + } + else if (username.length() < UserConstants.USERNAME_MIN_LENGTH + || username.length() > UserConstants.USERNAME_MAX_LENGTH) + { + msg = "账户长度必须在2到20个字符之间"; + } + else if (password.length() < UserConstants.PASSWORD_MIN_LENGTH + || password.length() > UserConstants.PASSWORD_MAX_LENGTH) + { + msg = "密码长度必须在5到20个字符之间"; + } + else if (!userService.checkUserNameUnique(sysUser)) + { + msg = "保存用户'" + username + "'失败,注册账号已存在"; + } + else + { + sysUser.setNickName(username); + sysUser.setPassword(SecurityUtils.encryptPassword(password)); + sysUser.setUserUUID(IdUtils.randomUUID()); + boolean regFlag = userService.registerUser(sysUser); + if (!regFlag) + { + msg = "注册失败,请联系系统管理人员"; + } + else + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.REGISTER, MessageUtils.message("user.register.success"))); + } + } + return msg; + } + + /** + * 校验验证码 + * + * @param username 用户名 + * @param code 验证码 + * @param uuid 唯一标识 + * @return 结果 + */ + public void validateCaptcha(String username, String code, String uuid) + { + String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, ""); + String captcha = redisCache.getCacheObject(verifyKey); + redisCache.deleteObject(verifyKey); + if (captcha == null) + { + throw new CaptchaExpireException(); + } + if (!code.equalsIgnoreCase(captcha)) + { + throw new CaptchaException(); + } + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/web/service/TokenService.java b/CSP-core/src/main/java/com/RVSmartPorting/core/web/service/TokenService.java new file mode 100644 index 0000000000000000000000000000000000000000..c3226d9a05aafb6f1fef9bb0bfab5a59be3b1271 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/web/service/TokenService.java @@ -0,0 +1,227 @@ +package com.RVSmartPorting.core.web.service; + +import com.RVSmartPorting.common.constant.CacheConstants; +import com.RVSmartPorting.common.constant.Constants; +import com.RVSmartPorting.common.core.domain.model.LoginUser; +import com.RVSmartPorting.common.utils.ServletUtils; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.common.utils.ip.AddressUtils; +import com.RVSmartPorting.common.utils.ip.IpUtils; +import com.RVSmartPorting.common.utils.redis.RedisCache; +import com.RVSmartPorting.common.utils.uuid.IdUtils; +import eu.bitwalker.useragentutils.UserAgent; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * token验证处理 + * + * @author ruoyi + */ +@Component +public class TokenService +{ + // 令牌自定义标识 + @Value("${token.header}") + private String header; + + // 令牌秘钥 + @Value("${token.secret}") + private String secret; + + // 令牌有效期(默认30分钟) + @Value("${token.expireTime}") + private int expireTime; + + protected static final long MILLIS_SECOND = 1000; + + protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND; + + private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L; + + @Autowired + private RedisCache redisCache; + + /** + * 获取用户身份信息 + * + * @return 用户信息 + */ + public LoginUser getLoginUser(HttpServletRequest request) + { + // 获取请求携带的令牌 + String token = getToken(request); + if (StringUtils.isNotEmpty(token)) + { + try + { + Claims claims = parseToken(token); + // 解析对应的权限以及用户信息 + String uuid = (String) claims.get(Constants.LOGIN_USER_KEY); + String userKey = getTokenKey(uuid); + LoginUser user = redisCache.getCacheObject(userKey); + return user; + } + catch (Exception e) + { + } + } + return null; + } + + /** + * 设置用户身份信息 + */ + public void setLoginUser(LoginUser loginUser) + { + if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken())) + { + refreshToken(loginUser); + } + } + + /** + * 删除用户身份信息 + */ + public void delLoginUser(String token) + { + if (StringUtils.isNotEmpty(token)) + { + String userKey = getTokenKey(token); + redisCache.deleteObject(userKey); + } + } + + /** + * 创建令牌 + * + * @param loginUser 用户信息 + * @return 令牌 + */ + public String createToken(LoginUser loginUser) + { + String token = IdUtils.fastUUID(); + loginUser.setToken(token); + setUserAgent(loginUser); + refreshToken(loginUser); + + Map claims = new HashMap<>(); + claims.put(Constants.LOGIN_USER_KEY, token); + return createToken(claims); + } + + /** + * 验证令牌有效期,相差不足20分钟,自动刷新缓存 + * + * @param loginUser + * @return 令牌 + */ + public void verifyToken(LoginUser loginUser) + { + long expireTime = loginUser.getExpireTime(); + long currentTime = System.currentTimeMillis(); + if (expireTime - currentTime <= MILLIS_MINUTE_TEN) + { + refreshToken(loginUser); + } + } + + /** + * 刷新令牌有效期 + * + * @param loginUser 登录信息 + */ + public void refreshToken(LoginUser loginUser) + { + loginUser.setLoginTime(System.currentTimeMillis()); + loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE); + // 根据uuid将loginUser缓存 + String userKey = getTokenKey(loginUser.getToken()); + redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES); + } + + /** + * 设置用户代理信息 + * + * @param loginUser 登录信息 + */ + public void setUserAgent(LoginUser loginUser) + { + UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent")); + String ip = IpUtils.getIpAddr(); + loginUser.setIpaddr(ip); + loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip)); + loginUser.setBrowser(userAgent.getBrowser().getName()); + loginUser.setOs(userAgent.getOperatingSystem().getName()); + } + + /** + * 从数据声明生成令牌 + * + * @param claims 数据声明 + * @return 令牌 + */ + private String createToken(Map claims) + { + String token = Jwts.builder() + .setClaims(claims) + .signWith(SignatureAlgorithm.HS512, secret).compact(); + return token; + } + + /** + * 从令牌中获取数据声明 + * + * @param token 令牌 + * @return 数据声明 + */ + private Claims parseToken(String token) + { + return Jwts.parser() + .setSigningKey(secret) + .parseClaimsJws(token) + .getBody(); + } + + /** + * 从令牌中获取用户名 + * + * @param token 令牌 + * @return 用户名 + */ + public String getUsernameFromToken(String token) + { + Claims claims = parseToken(token); + return claims.getSubject(); + } + + /** + * 获取请求token + * + * @param request + * @return token + */ + private String getToken(HttpServletRequest request) + { + String token = request.getHeader(header); + if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)) + { + token = token.replace(Constants.TOKEN_PREFIX, ""); + } + return token; + } + + private String getTokenKey(String uuid) + { + return CacheConstants.LOGIN_TOKEN_KEY + uuid; + } +} diff --git a/CSP-core/src/main/java/com/RVSmartPorting/core/web/service/UserDetailsServiceImpl.java b/CSP-core/src/main/java/com/RVSmartPorting/core/web/service/UserDetailsServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..7f1737772726215d6dfb37e036f7075092021296 --- /dev/null +++ b/CSP-core/src/main/java/com/RVSmartPorting/core/web/service/UserDetailsServiceImpl.java @@ -0,0 +1,65 @@ +package com.RVSmartPorting.core.web.service; + +import com.RVSmartPorting.common.core.domain.entity.SysUser; +import com.RVSmartPorting.common.core.domain.model.LoginUser; +import com.RVSmartPorting.common.enums.UserStatus; +import com.RVSmartPorting.common.exception.ServiceException; +import com.RVSmartPorting.common.utils.StringUtils; +import com.RVSmartPorting.core.system.service.ISysUserService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +/** + * 用户验证处理 + * + * @author ruoyi + */ +@Service +public class UserDetailsServiceImpl implements UserDetailsService +{ + private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class); + + @Autowired + private ISysUserService userService; + + @Autowired + private SysPasswordService passwordService; + + @Autowired + private SysPermissionService permissionService; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException + { + SysUser user = userService.selectUserByUserName(username); + if (StringUtils.isNull(user)) + { + log.info("登录用户:{} 不存在.", username); + throw new ServiceException("登录用户:" + username + " 不存在"); + } + else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) + { + log.info("登录用户:{} 已被删除.", username); + throw new ServiceException("对不起,您的账号:" + username + " 已被删除"); + } + else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) + { + log.info("登录用户:{} 已被停用.", username); + throw new ServiceException("对不起,您的账号:" + username + " 已停用"); + } + + passwordService.validate(user); + + return createLoginUser(user); + } + + public UserDetails createLoginUser(SysUser user) + { + return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user)); + } +} diff --git a/CSP-core/src/main/resources/mapper/system/CodeProjectMapper.xml b/CSP-core/src/main/resources/mapper/system/CodeProjectMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..909c58d6b2f61d45f0a386f545bdab4bbc117c52 --- /dev/null +++ b/CSP-core/src/main/resources/mapper/system/CodeProjectMapper.xml @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select code_project_id, project_name, project_description, project_type, project_members, project_labels, + project_icon, user_id, code_cache_path, hdfs_path, code_upload_type, code_repo_type, code_repo_url, + code_branch, code_repo_username, code_repo_password, del_flag,project_uuid, create_by, create_time, update_by, + update_time, remark from code_project + + + + + + + + insert into code_project + + project_name, + project_description, + project_type, + project_members, + project_labels, + project_icon, + user_id, + code_cache_path, + hdfs_path, + code_upload_type, + code_repo_type, + code_repo_url, + code_branch, + code_repo_username, + code_repo_password, + del_flag, + create_by, + create_time, + update_by, + update_time, + remark, + project_uuid, + + + #{projectName}, + #{projectDescription}, + #{projectType}, + #{projectMembers}, + #{projectLabels}, + #{projectIcon}, + #{userId}, + #{codeCachePath}, + #{hdfsPath}, + #{codeUploadType}, + #{codeRepoType}, + #{codeRepoUrl}, + #{codeBranch}, + #{codeRepoUsername}, + #{codeRepoPassword}, + #{delFlag}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + #{remark}, + #{projectUUID}, + + + + + update code_project + + project_name = #{projectName}, + project_description = #{projectDescription}, + project_type = #{projectType}, + project_members = #{projectMembers}, + project_labels = #{projectLabels}, + project_icon = #{projectIcon}, + user_id = #{userId}, + code_cache_path = #{codeCachePath}, + hdfs_path = #{hdfsPath}, + code_upload_type = #{codeUploadType}, + code_repo_type = #{codeRepoType}, + code_repo_url = #{codeRepoUrl}, + code_branch = #{codeBranch}, + code_repo_username = #{codeRepoUsername}, + code_repo_password = #{codeRepoPassword}, + del_flag = #{delFlag}, + create_by = #{createBy}, + create_time = #{createTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + + where code_project_id = #{codeProjectId} + + + + delete from code_project where code_project_id = #{codeProjectId} + + + + delete from code_project where code_project_id in + + #{codeProjectId} + + + + UPDATE code_project + SET + code_repo_type = null, + code_cache_path = null, + hdfs_path = null, + code_upload_type = null, + code_repo_url = null, + code_branch = null, + code_repo_username = null, + code_repo_password = null + WHERE code_project_id = #{codeProjectId} + + + \ No newline at end of file diff --git a/CSP-core/src/main/resources/mapper/system/GitNetworkSettingMapper.xml b/CSP-core/src/main/resources/mapper/system/GitNetworkSettingMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..51748f339ce45e7780fb433c3f5c62af36c9af24 --- /dev/null +++ b/CSP-core/src/main/resources/mapper/system/GitNetworkSettingMapper.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + select git_network_setting_id, domain, type, url, address_rule, status, del_flag, create_by, create_time, update_by, update_time from git_network_setting + + + + + + + + + + + insert into git_network_setting + + domain, + type, + url, + address_rule, + status, + del_flag, + create_by, + create_time, + update_by, + update_time, + + + #{domain}, + #{type}, + #{url}, + #{addressRule}, + #{status}, + #{delFlag}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + + + + + update git_network_setting + + domain = #{domain}, + type = #{type}, + url = #{url}, + address_rule = #{addressRule}, + status = #{status}, + del_flag = #{delFlag}, + create_by = #{createBy}, + create_time = #{createTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + + where git_network_setting_id = #{gitNetworkSettingId} + + + + delete from git_network_setting where git_network_setting_id = #{gitNetworkSettingId} + + + + delete from git_network_setting where git_network_setting_id in + + #{gitNetworkSettingId} + + + \ No newline at end of file diff --git a/CSP-core/src/main/resources/mapper/system/RuleMapper.xml b/CSP-core/src/main/resources/mapper/system/RuleMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..d7046bcfe151ecb265cfa9390ba030e9e6b83c5d --- /dev/null +++ b/CSP-core/src/main/resources/mapper/system/RuleMapper.xml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + select rule_id, name, language, userTag, comments, goodExample, badExample, recommend, severity, create_by, create_time, update_by, update_time, remark from rule + + + + + + + + insert into rule + + name, + language, + userTag, + comments, + goodExample, + badExample, + recommend, + severity, + create_by, + create_time, + update_by, + update_time, + remark, + + + #{name}, + #{language}, + #{userTag}, + #{comments}, + #{goodExample}, + #{badExample}, + #{recommend}, + #{severity}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + #{remark}, + + + + + update rule + + name = #{name}, + language = #{language}, + userTag = #{userTag}, + comments = #{comments}, + goodExample = #{goodExample}, + badExample = #{badExample}, + recommend = #{recommend}, + severity = #{severity}, + create_by = #{createBy}, + create_time = #{createTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + + where rule_id = #{ruleId} + + + + delete from rule where rule_id = #{ruleId} + + + + delete from rule where rule_id in + + #{ruleId} + + + \ No newline at end of file diff --git a/CSP-core/src/main/resources/mapper/system/RuleSetMapper.xml b/CSP-core/src/main/resources/mapper/system/RuleSetMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..c28818093d5845dcb19d959388dbc21d677691f2 --- /dev/null +++ b/CSP-core/src/main/resources/mapper/system/RuleSetMapper.xml @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select rule_set_id, `name`, `language`, comments, `type`, create_by, create_time, update_by, update_time, + remark from rule_set + + + + + + + + insert into rule_set + + name, + language, + comments, + type, + create_by, + create_time, + update_by, + update_time, + remark, + + + #{name}, + #{language}, + #{comments}, + #{type}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + #{remark}, + + + + + update rule_set + + name = #{name}, + language = #{language}, + comments = #{comments}, + type = #{type}, + create_by = #{createBy}, + create_time = #{createTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + + where rule_set_id = #{ruleSetId} + + + + delete from rule_set where rule_set_id = #{ruleSetId} + + + + delete from rule_set where rule_set_id in + + #{ruleSetId} + + + \ No newline at end of file diff --git a/CSP-core/src/main/resources/mapper/system/ScanTaskMapper.xml b/CSP-core/src/main/resources/mapper/system/ScanTaskMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..c05ad66b3ae3f6a693f81626780fff2de60f5974 --- /dev/null +++ b/CSP-core/src/main/resources/mapper/system/ScanTaskMapper.xml @@ -0,0 +1,215 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select task_id, task_name, tool_selection, rule_set, rule_set_type, scan_tool_id, scan_parameters, scan_start_time, scan_end_time, task_status, scan_results, reporting_credentials, task_owner, task_description, task_priority, task_progress, scan_report_path, scan_server_scan_report_path, task_logs, task_log_path, scan_server_task_log_path, attachments, user_id, jobId, languages, instanceId, code_project_id, task_created_at, task_updated_at, del_flag, create_by, create_time, update_by, update_time, remark from scan_task + + + + + + + + insert into scan_task + + task_name, + tool_selection, + rule_set, + rule_set_type, + scan_tool_id, + scan_parameters, + scan_start_time, + scan_end_time, + task_status, + scan_results, + reporting_credentials, + task_owner, + task_description, + task_priority, + task_progress, + scan_report_path, + scan_server_scan_report_path, + task_logs, + task_log_path, + scan_server_task_log_path, + attachments, + user_id, + jobId, + languages, + instanceId, + code_project_id, + task_created_at, + task_updated_at, + del_flag, + create_by, + create_time, + update_by, + update_time, + remark, + + + #{taskName}, + #{toolSelection}, + #{ruleSet}, + #{ruleSetType}, + #{scanToolId}, + #{scanParameters}, + #{scanStartTime}, + #{scanEndTime}, + #{taskStatus}, + #{scanResults}, + #{reportingCredentials}, + #{taskOwner}, + #{taskDescription}, + #{taskPriority}, + #{taskProgress}, + #{scanReportPath}, + #{scanServerScanReportPath}, + #{taskLogs}, + #{taskLogPath}, + #{scanServerTaskLogPath}, + #{attachments}, + #{userId}, + #{jobId}, + #{languages}, + #{instanceId}, + #{codeProjectId}, + #{taskCreatedAt}, + #{taskUpdatedAt}, + #{delFlag}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + #{remark}, + + + + + update scan_task + + task_name = #{taskName}, + tool_selection = #{toolSelection}, + rule_set = #{ruleSet}, + rule_set_type = #{ruleSetType}, + scan_tool_id = #{scanToolId}, + scan_parameters = #{scanParameters}, + scan_start_time = #{scanStartTime}, + scan_end_time = #{scanEndTime}, + task_status = #{taskStatus}, + scan_results = #{scanResults}, + reporting_credentials = #{reportingCredentials}, + task_owner = #{taskOwner}, + task_description = #{taskDescription}, + task_priority = #{taskPriority}, + task_progress = #{taskProgress}, + scan_report_path = #{scanReportPath}, + scan_server_scan_report_path = #{scanServerScanReportPath}, + task_logs = #{taskLogs}, + task_log_path = #{taskLogPath}, + scan_server_task_log_path = #{scanServerTaskLogPath}, + attachments = #{attachments}, + user_id = #{userId}, + jobId = #{jobId}, + languages = #{languages}, + instanceId = #{instanceId}, + code_project_id = #{codeProjectId}, + task_created_at = #{taskCreatedAt}, + task_updated_at = #{taskUpdatedAt}, + del_flag = #{delFlag}, + create_by = #{createBy}, + create_time = #{createTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + + where task_id = #{taskId} + + + + delete from scan_task where task_id = #{taskId} + + + + delete from scan_task where task_id in + + #{taskId} + + + \ No newline at end of file diff --git a/CSP-core/src/main/resources/mapper/system/ScanToolConfigMapper.xml b/CSP-core/src/main/resources/mapper/system/ScanToolConfigMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..764c720ee852304155d924e385380aff2f8df2a6 --- /dev/null +++ b/CSP-core/src/main/resources/mapper/system/ScanToolConfigMapper.xml @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + select scan_tool_config_id, customizable_enabled, display_name, config_name, variable_name, config_type, enum_options, config_value_check_expression, default_value, default_enabled, associated_config_id, del_flag, create_by, create_time, update_by, update_time from scan_tool_config + + + + + + + + insert into scan_tool_config + + customizable_enabled, + display_name, + config_name, + variable_name, + config_type, + enum_options, + config_value_check_expression, + default_value, + default_enabled, + associated_config_id, + del_flag, + create_by, + create_time, + update_by, + update_time, + + + #{customizableEnabled}, + #{displayName}, + #{configName}, + #{variableName}, + #{configType}, + #{enumOptions}, + #{configValueCheckExpression}, + #{defaultValue}, + #{defaultEnabled}, + #{associatedConfigId}, + #{delFlag}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + + + + + update scan_tool_config + + customizable_enabled = #{customizableEnabled}, + display_name = #{displayName}, + config_name = #{configName}, + variable_name = #{variableName}, + config_type = #{configType}, + enum_options = #{enumOptions}, + config_value_check_expression = #{configValueCheckExpression}, + default_value = #{defaultValue}, + default_enabled = #{defaultEnabled}, + associated_config_id = #{associatedConfigId}, + del_flag = #{delFlag}, + create_by = #{createBy}, + create_time = #{createTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + + where scan_tool_config_id = #{scanToolConfigId} + + + + delete from scan_tool_config where scan_tool_config_id = #{scanToolConfigId} + + + + delete from scan_tool_config where scan_tool_config_id in + + #{scanToolConfigId} + + + \ No newline at end of file diff --git a/CSP-core/src/main/resources/mapper/system/ScanToolMapper.xml b/CSP-core/src/main/resources/mapper/system/ScanToolMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..456e52a233ea694c407f589ecc44459c74dfc3dc --- /dev/null +++ b/CSP-core/src/main/resources/mapper/system/ScanToolMapper.xml @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select scan_tool_id, tool_name, tool_version, tool_description, configuration_file_path, rule_set, rule_set_type, scan_target, scan_parameters, scan_output_path, notification_settings, supported_languages, container_startup_params, image_source, docker_compose_template, del_flag, create_by, create_time, update_by, update_time from scan_tool + + + + + + + + insert into scan_tool + + tool_name, + tool_version, + tool_description, + configuration_file_path, + rule_set, + rule_set_type, + scan_target, + scan_parameters, + scan_output_path, + notification_settings, + supported_languages, + container_startup_params, + image_source, + docker_compose_template, + del_flag, + create_by, + create_time, + update_by, + update_time, + + + #{toolName}, + #{toolVersion}, + #{toolDescription}, + #{configurationFilePath}, + #{ruleSet}, + #{ruleSetType}, + #{scanTarget}, + #{scanParameters}, + #{scanOutputPath}, + #{notificationSettings}, + #{supportedLanguages}, + #{containerStartupParams}, + #{imageSource}, + #{dockerComposeTemplate}, + #{delFlag}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + + + + + update scan_tool + + tool_name = #{toolName}, + tool_version = #{toolVersion}, + tool_description = #{toolDescription}, + configuration_file_path = #{configurationFilePath}, + rule_set = #{ruleSet}, + rule_set_type = #{ruleSetType}, + scan_target = #{scanTarget}, + scan_parameters = #{scanParameters}, + scan_output_path = #{scanOutputPath}, + notification_settings = #{notificationSettings}, + supported_languages = #{supportedLanguages}, + container_startup_params = #{containerStartupParams}, + image_source = #{imageSource}, + docker_compose_template = #{dockerComposeTemplate}, + del_flag = #{delFlag}, + create_by = #{createBy}, + create_time = #{createTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + + where scan_tool_id = #{scanToolId} + + + + delete from scan_tool where scan_tool_id = #{scanToolId} + + + + delete from scan_tool where scan_tool_id in + + #{scanToolId} + + + \ No newline at end of file diff --git a/CSP-core/src/main/resources/mapper/system/SysConfigMapper.xml b/CSP-core/src/main/resources/mapper/system/SysConfigMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..e453fb6e1e985840df93304564530408e06f12a7 --- /dev/null +++ b/CSP-core/src/main/resources/mapper/system/SysConfigMapper.xml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + select config_id, config_name, config_key, config_value, config_type, create_by, create_time, update_by, update_time, remark + from sys_config + + + + + + + and config_id = #{configId} + + + and config_key = #{configKey} + + + + + + + + + + + + + + insert into sys_config ( + config_name, + config_key, + config_value, + config_type, + create_by, + remark, + create_time + )values( + #{configName}, + #{configKey}, + #{configValue}, + #{configType}, + #{createBy}, + #{remark}, + sysdate() + ) + + + + update sys_config + + config_name = #{configName}, + config_key = #{configKey}, + config_value = #{configValue}, + config_type = #{configType}, + update_by = #{updateBy}, + remark = #{remark}, + update_time = sysdate() + + where config_id = #{configId} + + + + delete from sys_config where config_id = #{configId} + + + + delete from sys_config where config_id in + + #{configId} + + + + \ No newline at end of file diff --git a/CSP-core/src/main/resources/mapper/system/SysDeptMapper.xml b/CSP-core/src/main/resources/mapper/system/SysDeptMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..ed0e6ed4e36ab93614ac4343088bec11ed002898 --- /dev/null +++ b/CSP-core/src/main/resources/mapper/system/SysDeptMapper.xml @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.del_flag, d.create_by, d.create_time + from sys_dept d + + + + + + + + + + + + + + + + + + + + insert into sys_dept( + dept_id, + parent_id, + dept_name, + ancestors, + order_num, + leader, + phone, + email, + status, + create_by, + create_time + )values( + #{deptId}, + #{parentId}, + #{deptName}, + #{ancestors}, + #{orderNum}, + #{leader}, + #{phone}, + #{email}, + #{status}, + #{createBy}, + sysdate() + ) + + + + update sys_dept + + parent_id = #{parentId}, + dept_name = #{deptName}, + ancestors = #{ancestors}, + order_num = #{orderNum}, + leader = #{leader}, + phone = #{phone}, + email = #{email}, + status = #{status}, + update_by = #{updateBy}, + update_time = sysdate() + + where dept_id = #{deptId} + + + + update sys_dept set ancestors = + + when #{item.deptId} then #{item.ancestors} + + where dept_id in + + #{item.deptId} + + + + + update sys_dept set status = '0' where dept_id in + + #{deptId} + + + + + update sys_dept set del_flag = '2' where dept_id = #{deptId} + + + \ No newline at end of file diff --git a/CSP-core/src/main/resources/mapper/system/SysDictDataMapper.xml b/CSP-core/src/main/resources/mapper/system/SysDictDataMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..a0f98e6c25a1acdc0d2efb5552b6ea62a8be4d8e --- /dev/null +++ b/CSP-core/src/main/resources/mapper/system/SysDictDataMapper.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + select dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark + from sys_dict_data + + + + + + + + + + + + + + delete from sys_dict_data where dict_code = #{dictCode} + + + + delete from sys_dict_data where dict_code in + + #{dictCode} + + + + + update sys_dict_data + + dict_sort = #{dictSort}, + dict_label = #{dictLabel}, + dict_value = #{dictValue}, + dict_type = #{dictType}, + css_class = #{cssClass}, + list_class = #{listClass}, + is_default = #{isDefault}, + status = #{status}, + remark = #{remark}, + update_by = #{updateBy}, + update_time = sysdate() + + where dict_code = #{dictCode} + + + + update sys_dict_data set dict_type = #{newDictType} where dict_type = #{oldDictType} + + + + insert into sys_dict_data( + dict_sort, + dict_label, + dict_value, + dict_type, + css_class, + list_class, + is_default, + status, + remark, + create_by, + create_time + )values( + #{dictSort}, + #{dictLabel}, + #{dictValue}, + #{dictType}, + #{cssClass}, + #{listClass}, + #{isDefault}, + #{status}, + #{remark}, + #{createBy}, + sysdate() + ) + + + \ No newline at end of file diff --git a/CSP-core/src/main/resources/mapper/system/SysDictTypeMapper.xml b/CSP-core/src/main/resources/mapper/system/SysDictTypeMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..14b59fe74961df692352e738a5a4b6d4ac3a3421 --- /dev/null +++ b/CSP-core/src/main/resources/mapper/system/SysDictTypeMapper.xml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + select dict_id, dict_name, dict_type, status, create_by, create_time, remark + from sys_dict_type + + + + + + + + + + + + + + delete from sys_dict_type where dict_id = #{dictId} + + + + delete from sys_dict_type where dict_id in + + #{dictId} + + + + + update sys_dict_type + + dict_name = #{dictName}, + dict_type = #{dictType}, + status = #{status}, + remark = #{remark}, + update_by = #{updateBy}, + update_time = sysdate() + + where dict_id = #{dictId} + + + + insert into sys_dict_type( + dict_name, + dict_type, + status, + remark, + create_by, + create_time + )values( + #{dictName}, + #{dictType}, + #{status}, + #{remark}, + #{createBy}, + sysdate() + ) + + + \ No newline at end of file diff --git a/CSP-core/src/main/resources/mapper/system/SysLogininforMapper.xml b/CSP-core/src/main/resources/mapper/system/SysLogininforMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..6ba3bddb6f258b0597e98dac5ee5f9023610bf2c --- /dev/null +++ b/CSP-core/src/main/resources/mapper/system/SysLogininforMapper.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + insert into sys_logininfor (user_name, status, ipaddr, login_location, browser, os, msg, login_time) + values (#{userName}, #{status}, #{ipaddr}, #{loginLocation}, #{browser}, #{os}, #{msg}, sysdate()) + + + + + + delete from sys_logininfor where info_id in + + #{infoId} + + + + + truncate table sys_logininfor + + + \ No newline at end of file diff --git a/CSP-core/src/main/resources/mapper/system/SysMenuMapper.xml b/CSP-core/src/main/resources/mapper/system/SysMenuMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..551adeef37a8286469baf6c8043960ca485da104 --- /dev/null +++ b/CSP-core/src/main/resources/mapper/system/SysMenuMapper.xml @@ -0,0 +1,202 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select menu_id, menu_name, parent_id, order_num, path, component, `query`, is_frame, is_cache, menu_type, visible, status, ifnull(perms,'') as perms, icon, create_time + from sys_menu + + + + + + + + + + + + + + + + + + + + + + + + + + update sys_menu + + menu_name = #{menuName}, + parent_id = #{parentId}, + order_num = #{orderNum}, + path = #{path}, + component = #{component}, + `query` = #{query}, + is_frame = #{isFrame}, + is_cache = #{isCache}, + menu_type = #{menuType}, + visible = #{visible}, + status = #{status}, + perms = #{perms}, + icon = #{icon}, + remark = #{remark}, + update_by = #{updateBy}, + update_time = sysdate() + + where menu_id = #{menuId} + + + + insert into sys_menu( + menu_id, + parent_id, + menu_name, + order_num, + path, + component, + `query`, + is_frame, + is_cache, + menu_type, + visible, + status, + perms, + icon, + remark, + create_by, + create_time + )values( + #{menuId}, + #{parentId}, + #{menuName}, + #{orderNum}, + #{path}, + #{component}, + #{query}, + #{isFrame}, + #{isCache}, + #{menuType}, + #{visible}, + #{status}, + #{perms}, + #{icon}, + #{remark}, + #{createBy}, + sysdate() + ) + + + + delete from sys_menu where menu_id = #{menuId} + + + \ No newline at end of file diff --git a/CSP-core/src/main/resources/mapper/system/SysNoticeMapper.xml b/CSP-core/src/main/resources/mapper/system/SysNoticeMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..53d0353a577cd138ac29eedb89bfbe8d20264316 --- /dev/null +++ b/CSP-core/src/main/resources/mapper/system/SysNoticeMapper.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + select notice_id, notice_title, notice_type, cast(notice_content as char) as notice_content, status, create_by, create_time, update_by, update_time, remark + from sys_notice + + + + + + + + insert into sys_notice ( + notice_title, + notice_type, + notice_content, + status, + remark, + create_by, + create_time + )values( + #{noticeTitle}, + #{noticeType}, + #{noticeContent}, + #{status}, + #{remark}, + #{createBy}, + sysdate() + ) + + + + update sys_notice + + notice_title = #{noticeTitle}, + notice_type = #{noticeType}, + notice_content = #{noticeContent}, + status = #{status}, + update_by = #{updateBy}, + update_time = sysdate() + + where notice_id = #{noticeId} + + + + delete from sys_notice where notice_id = #{noticeId} + + + + delete from sys_notice where notice_id in + + #{noticeId} + + + + \ No newline at end of file diff --git a/CSP-core/src/main/resources/mapper/system/SysOperLogMapper.xml b/CSP-core/src/main/resources/mapper/system/SysOperLogMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..21bd2a840ec602cea05e9f92828ff10dc30c1e29 --- /dev/null +++ b/CSP-core/src/main/resources/mapper/system/SysOperLogMapper.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + select oper_id, title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_location, oper_param, json_result, status, error_msg, oper_time, cost_time + from sys_oper_log + + + + insert into sys_oper_log(title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_location, oper_param, json_result, status, error_msg, cost_time, oper_time) + values (#{title}, #{businessType}, #{method}, #{requestMethod}, #{operatorType}, #{operName}, #{deptName}, #{operUrl}, #{operIp}, #{operLocation}, #{operParam}, #{jsonResult}, #{status}, #{errorMsg}, #{costTime}, sysdate()) + + + + + + delete from sys_oper_log where oper_id in + + #{operId} + + + + + + + truncate table sys_oper_log + + + \ No newline at end of file diff --git a/CSP-core/src/main/resources/mapper/system/SysPostMapper.xml b/CSP-core/src/main/resources/mapper/system/SysPostMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..b91885219c9b3cbfa4f1d5d6bb41823cf23e2c60 --- /dev/null +++ b/CSP-core/src/main/resources/mapper/system/SysPostMapper.xml @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + select post_id, post_code, post_name, post_sort, status, create_by, create_time, remark + from sys_post + + + + + + + + + + + + + + + + + + update sys_post + + post_code = #{postCode}, + post_name = #{postName}, + post_sort = #{postSort}, + status = #{status}, + remark = #{remark}, + update_by = #{updateBy}, + update_time = sysdate() + + where post_id = #{postId} + + + + insert into sys_post( + post_id, + post_code, + post_name, + post_sort, + status, + remark, + create_by, + create_time + )values( + #{postId}, + #{postCode}, + #{postName}, + #{postSort}, + #{status}, + #{remark}, + #{createBy}, + sysdate() + ) + + + + delete from sys_post where post_id = #{postId} + + + + delete from sys_post where post_id in + + #{postId} + + + + \ No newline at end of file diff --git a/CSP-core/src/main/resources/mapper/system/SysRoleDeptMapper.xml b/CSP-core/src/main/resources/mapper/system/SysRoleDeptMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..88a2db779e1bf1760c07068f3702ef53e657fdbd --- /dev/null +++ b/CSP-core/src/main/resources/mapper/system/SysRoleDeptMapper.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + delete from sys_role_dept where role_id=#{roleId} + + + + + + delete from sys_role_dept where role_id in + + #{roleId} + + + + + insert into sys_role_dept(role_id, dept_id) values + + (#{item.roleId},#{item.deptId}) + + + + \ No newline at end of file diff --git a/CSP-core/src/main/resources/mapper/system/SysRoleMapper.xml b/CSP-core/src/main/resources/mapper/system/SysRoleMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..b1fb2425b47e3dbd626003f0f112dba112746ae4 --- /dev/null +++ b/CSP-core/src/main/resources/mapper/system/SysRoleMapper.xml @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + 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 ur on ur.role_id = r.role_id + left join sys_user u on u.user_id = ur.user_id + left join sys_dept d on u.dept_id = d.dept_id + + + + + + + + + + + + + + + + + + + + insert into sys_role( + role_id, + role_name, + role_key, + role_sort, + data_scope, + menu_check_strictly, + dept_check_strictly, + status, + remark, + create_by, + create_time + )values( + #{roleId}, + #{roleName}, + #{roleKey}, + #{roleSort}, + #{dataScope}, + #{menuCheckStrictly}, + #{deptCheckStrictly}, + #{status}, + #{remark}, + #{createBy}, + sysdate() + ) + + + + update sys_role + + role_name = #{roleName}, + role_key = #{roleKey}, + role_sort = #{roleSort}, + data_scope = #{dataScope}, + menu_check_strictly = #{menuCheckStrictly}, + dept_check_strictly = #{deptCheckStrictly}, + status = #{status}, + remark = #{remark}, + update_by = #{updateBy}, + update_time = sysdate() + + where role_id = #{roleId} + + + + update sys_role set del_flag = '2' where role_id = #{roleId} + + + + update sys_role set del_flag = '2' where role_id in + + #{roleId} + + + + \ No newline at end of file diff --git a/CSP-core/src/main/resources/mapper/system/SysRoleMenuMapper.xml b/CSP-core/src/main/resources/mapper/system/SysRoleMenuMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..8dd35919603ceed50752ef178e354c89071cc67f --- /dev/null +++ b/CSP-core/src/main/resources/mapper/system/SysRoleMenuMapper.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + delete from sys_role_menu where role_id=#{roleId} + + + + delete from sys_role_menu where role_id in + + #{roleId} + + + + + insert into sys_role_menu(role_id, menu_id) values + + (#{item.roleId},#{item.menuId}) + + + + \ No newline at end of file diff --git a/CSP-core/src/main/resources/mapper/system/SysUserMapper.xml b/CSP-core/src/main/resources/mapper/system/SysUserMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..de7de7235a680248293b0efe7e3246b0624d264c --- /dev/null +++ b/CSP-core/src/main/resources/mapper/system/SysUserMapper.xml @@ -0,0 +1,228 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, + u.status, u.del_flag,u.user_uuid, 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 ur on u.user_id = ur.user_id + left join sys_role r on r.role_id = ur.role_id + + + + + + + + + + + + + + + + + + + + insert into sys_user( + user_id, + dept_id, + user_name, + nick_name, + email, + avatar, + phonenumber, + sex, + password, + status, + create_by, + remark, + user_uuid, + create_time + )values( + #{userId}, + #{deptId}, + #{userName}, + #{nickName}, + #{email}, + #{avatar}, + #{phonenumber}, + #{sex}, + #{password}, + #{status}, + #{createBy}, + #{remark}, + #{userUUID}, + sysdate() + ) + + + + update sys_user + + dept_id = #{deptId}, + user_name = #{userName}, + nick_name = #{nickName}, + email = #{email}, + phonenumber = #{phonenumber}, + sex = #{sex}, + avatar = #{avatar}, + password = #{password}, + status = #{status}, + login_ip = #{loginIp}, + login_date = #{loginDate}, + update_by = #{updateBy}, + remark = #{remark}, + update_time = sysdate() + + where user_id = #{userId} + + + + update sys_user set status = #{status} where user_id = #{userId} + + + + update sys_user set avatar = #{avatar} where user_name = #{userName} + + + + update sys_user set password = #{password} where user_name = #{userName} + + + + update sys_user set del_flag = '2' where user_id = #{userId} + + + + update sys_user set del_flag = '2' where user_id in + + #{userId} + + + + \ No newline at end of file diff --git a/CSP-core/src/main/resources/mapper/system/SysUserPostMapper.xml b/CSP-core/src/main/resources/mapper/system/SysUserPostMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..d12e761b102218a2c294df01e4e899a68c212f2a --- /dev/null +++ b/CSP-core/src/main/resources/mapper/system/SysUserPostMapper.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + delete from sys_user_post where user_id=#{userId} + + + + + + delete from sys_user_post where user_id in + + #{userId} + + + + + insert into sys_user_post(user_id, post_id) values + + (#{item.userId},#{item.postId}) + + + + \ No newline at end of file diff --git a/CSP-core/src/main/resources/mapper/system/SysUserRoleMapper.xml b/CSP-core/src/main/resources/mapper/system/SysUserRoleMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..93a87c57bb4cf7e257b051a48ee03ef57f3c11b2 --- /dev/null +++ b/CSP-core/src/main/resources/mapper/system/SysUserRoleMapper.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + delete from sys_user_role where user_id=#{userId} + + + + + + delete from sys_user_role where user_id in + + #{userId} + + + + + insert into sys_user_role(user_id, role_id) values + + (#{item.userId},#{item.roleId}) + + + + + delete from sys_user_role where user_id=#{userId} and role_id=#{roleId} + + + + delete from sys_user_role where role_id=#{roleId} and user_id in + + #{userId} + + + \ No newline at end of file diff --git a/CSP-core/src/test/java/com/RVSmartPorting/core/system/service/impl/RuleSetServiceImplTest.java b/CSP-core/src/test/java/com/RVSmartPorting/core/system/service/impl/RuleSetServiceImplTest.java new file mode 100644 index 0000000000000000000000000000000000000000..07a2ed5ae0c67d0e6baf6b2581f3b9ac8306f35b --- /dev/null +++ b/CSP-core/src/test/java/com/RVSmartPorting/core/system/service/impl/RuleSetServiceImplTest.java @@ -0,0 +1,20 @@ +package com.RVSmartPorting.core.system.service.impl; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author xuqiangli + * @create 2023-08-21 12:10 + */ +class RuleSetServiceImplTest { + + @Test + void selectRuleSetByRuleSetId() { + } + + @Test + void selectRuleSetList() { + } +} \ No newline at end of file diff --git a/CSP-frontend/.editorconfig b/CSP-frontend/.editorconfig new file mode 100644 index 0000000000000000000000000000000000000000..7034f9bf32aa33d5009acc956bde9663e93ae848 --- /dev/null +++ b/CSP-frontend/.editorconfig @@ -0,0 +1,22 @@ +# 告诉EditorConfig插件,这是根文件,不用继续往上查找 +root = true + +# 匹配全部文件 +[*] +# 设置字符集 +charset = utf-8 +# 缩进风格,可选space、tab +indent_style = space +# 缩进的空格数 +indent_size = 2 +# 结尾换行符,可选lf、cr、crlf +end_of_line = lf +# 在文件结尾插入新行 +insert_final_newline = true +# 删除一行中的前后空格 +trim_trailing_whitespace = true + +# 匹配md结尾的文件 +[*.md] +insert_final_newline = false +trim_trailing_whitespace = false diff --git a/CSP-frontend/.env.development b/CSP-frontend/.env.development new file mode 100644 index 0000000000000000000000000000000000000000..6fe93c1e6bd4156d4209c9d57a7e2d034d8d7281 --- /dev/null +++ b/CSP-frontend/.env.development @@ -0,0 +1,11 @@ +# 页面标题 +VUE_APP_TITLE = 在线代码扫描服务平台 + +# 开发环境配置 +ENV = 'development' + +# 在线代码扫描服务平台/开发环境 +VUE_APP_BASE_API = '/dev-api' + +# 路由懒加载 +VUE_CLI_BABEL_TRANSPILE_MODULES = true diff --git a/CSP-frontend/.env.production b/CSP-frontend/.env.production new file mode 100644 index 0000000000000000000000000000000000000000..013f120f3b4001742be300609d4977babf9e51cc --- /dev/null +++ b/CSP-frontend/.env.production @@ -0,0 +1,8 @@ +# 页面标题 +VUE_APP_TITLE = 在线代码扫描服务平台 + +# 生产环境配置 +ENV = 'production' + +# 在线代码扫描服务平台/生产环境 +VUE_APP_BASE_API = '/prod-api' diff --git a/CSP-frontend/.env.staging b/CSP-frontend/.env.staging new file mode 100644 index 0000000000000000000000000000000000000000..6efb5180c66de359779d342434bbf7f89b5eb1c5 --- /dev/null +++ b/CSP-frontend/.env.staging @@ -0,0 +1,10 @@ +# 页面标题 +VUE_APP_TITLE = 在线代码扫描服务平台 + +NODE_ENV = production + +# 测试环境配置 +ENV = 'staging' + +# 在线代码扫描服务平台/测试环境 +VUE_APP_BASE_API = '/stage-api' diff --git a/CSP-frontend/.eslintignore b/CSP-frontend/.eslintignore new file mode 100644 index 0000000000000000000000000000000000000000..89be6f6596352653bf50bfdf3e8794dc6d90e366 --- /dev/null +++ b/CSP-frontend/.eslintignore @@ -0,0 +1,10 @@ +# 忽略build目录下类型为js的文件的语法检查 +build/*.js +# 忽略src/assets目录下文件的语法检查 +src/assets +# 忽略public目录下文件的语法检查 +public +# 忽略当前目录下为js的文件的语法检查 +*.js +# 忽略当前目录下为vue的文件的语法检查 +*.vue \ No newline at end of file diff --git a/CSP-frontend/.eslintrc.js b/CSP-frontend/.eslintrc.js new file mode 100644 index 0000000000000000000000000000000000000000..82bbdeea60fec5062fad77c9cc110c6f831afc71 --- /dev/null +++ b/CSP-frontend/.eslintrc.js @@ -0,0 +1,199 @@ +// ESlint 检查配置 +module.exports = { + root: true, + parserOptions: { + parser: 'babel-eslint', + sourceType: 'module' + }, + env: { + browser: true, + node: true, + es6: true, + }, + extends: ['plugin:vue/recommended', 'eslint:recommended'], + + // add your custom rules here + //it is base on https://github.com/vuejs/eslint-config-vue + rules: { + "vue/max-attributes-per-line": [2, { + "singleline": 10, + "multiline": { + "max": 1, + "allowFirstLine": false + } + }], + "vue/singleline-html-element-content-newline": "off", + "vue/multiline-html-element-content-newline":"off", + "vue/name-property-casing": ["error", "PascalCase"], + "vue/no-v-html": "off", + 'accessor-pairs': 2, + 'arrow-spacing': [2, { + 'before': true, + 'after': true + }], + 'block-spacing': [2, 'always'], + 'brace-style': [2, '1tbs', { + 'allowSingleLine': true + }], + 'camelcase': [0, { + 'properties': 'always' + }], + 'comma-dangle': [2, 'never'], + 'comma-spacing': [2, { + 'before': false, + 'after': true + }], + 'comma-style': [2, 'last'], + 'constructor-super': 2, + 'curly': [2, 'multi-line'], + 'dot-location': [2, 'property'], + 'eol-last': 2, + 'eqeqeq': ["error", "always", {"null": "ignore"}], + 'generator-star-spacing': [2, { + 'before': true, + 'after': true + }], + 'handle-callback-err': [2, '^(err|error)$'], + 'indent': [2, 2, { + 'SwitchCase': 1 + }], + 'jsx-quotes': [2, 'prefer-single'], + 'key-spacing': [2, { + 'beforeColon': false, + 'afterColon': true + }], + 'keyword-spacing': [2, { + 'before': true, + 'after': true + }], + 'new-cap': [2, { + 'newIsCap': true, + 'capIsNew': false + }], + 'new-parens': 2, + 'no-array-constructor': 2, + 'no-caller': 2, + 'no-console': 'off', + 'no-class-assign': 2, + 'no-cond-assign': 2, + 'no-const-assign': 2, + 'no-control-regex': 0, + 'no-delete-var': 2, + 'no-dupe-args': 2, + 'no-dupe-class-members': 2, + 'no-dupe-keys': 2, + 'no-duplicate-case': 2, + 'no-empty-character-class': 2, + 'no-empty-pattern': 2, + 'no-eval': 2, + 'no-ex-assign': 2, + 'no-extend-native': 2, + 'no-extra-bind': 2, + 'no-extra-boolean-cast': 2, + 'no-extra-parens': [2, 'functions'], + 'no-fallthrough': 2, + 'no-floating-decimal': 2, + 'no-func-assign': 2, + 'no-implied-eval': 2, + 'no-inner-declarations': [2, 'functions'], + 'no-invalid-regexp': 2, + 'no-irregular-whitespace': 2, + 'no-iterator': 2, + 'no-label-var': 2, + 'no-labels': [2, { + 'allowLoop': false, + 'allowSwitch': false + }], + 'no-lone-blocks': 2, + 'no-mixed-spaces-and-tabs': 2, + 'no-multi-spaces': 2, + 'no-multi-str': 2, + 'no-multiple-empty-lines': [2, { + 'max': 1 + }], + 'no-native-reassign': 2, + 'no-negated-in-lhs': 2, + 'no-new-object': 2, + 'no-new-require': 2, + 'no-new-symbol': 2, + 'no-new-wrappers': 2, + 'no-obj-calls': 2, + 'no-octal': 2, + 'no-octal-escape': 2, + 'no-path-concat': 2, + 'no-proto': 2, + 'no-redeclare': 2, + 'no-regex-spaces': 2, + 'no-return-assign': [2, 'except-parens'], + 'no-self-assign': 2, + 'no-self-compare': 2, + 'no-sequences': 2, + 'no-shadow-restricted-names': 2, + 'no-spaced-func': 2, + 'no-sparse-arrays': 2, + 'no-this-before-super': 2, + 'no-throw-literal': 2, + 'no-trailing-spaces': 2, + 'no-undef': 2, + 'no-undef-init': 2, + 'no-unexpected-multiline': 2, + 'no-unmodified-loop-condition': 2, + 'no-unneeded-ternary': [2, { + 'defaultAssignment': false + }], + 'no-unreachable': 2, + 'no-unsafe-finally': 2, + 'no-unused-vars': [2, { + 'vars': 'all', + 'args': 'none' + }], + 'no-useless-call': 2, + 'no-useless-computed-key': 2, + 'no-useless-constructor': 2, + 'no-useless-escape': 0, + 'no-whitespace-before-property': 2, + 'no-with': 2, + 'one-var': [2, { + 'initialized': 'never' + }], + 'operator-linebreak': [2, 'after', { + 'overrides': { + '?': 'before', + ':': 'before' + } + }], + 'padded-blocks': [2, 'never'], + 'quotes': [2, 'single', { + 'avoidEscape': true, + 'allowTemplateLiterals': true + }], + 'semi': [2, 'never'], + 'semi-spacing': [2, { + 'before': false, + 'after': true + }], + 'space-before-blocks': [2, 'always'], + 'space-before-function-paren': [2, 'never'], + 'space-in-parens': [2, 'never'], + 'space-infix-ops': 2, + 'space-unary-ops': [2, { + 'words': true, + 'nonwords': false + }], + 'spaced-comment': [2, 'always', { + 'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ','] + }], + 'template-curly-spacing': [2, 'never'], + 'use-isnan': 2, + 'valid-typeof': 2, + 'wrap-iife': [2, 'any'], + 'yield-star-spacing': [2, 'both'], + 'yoda': [2, 'never'], + 'prefer-const': 2, + 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, + 'object-curly-spacing': [2, 'always', { + objectsInObjects: false + }], + 'array-bracket-spacing': [2, 'never'] + } +} diff --git a/CSP-frontend/.gitignore b/CSP-frontend/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..78a752d87e8427f84570300f62bdfb5b183a9931 --- /dev/null +++ b/CSP-frontend/.gitignore @@ -0,0 +1,23 @@ +.DS_Store +node_modules/ +dist/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +**/*.log + +tests/**/coverage/ +tests/e2e/reports +selenium-debug.log + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.local + +package-lock.json +yarn.lock diff --git a/CSP-frontend/babel.config.js b/CSP-frontend/babel.config.js new file mode 100644 index 0000000000000000000000000000000000000000..c8267b2ddf4d74b926d2fe7f19d5c69ff5868590 --- /dev/null +++ b/CSP-frontend/babel.config.js @@ -0,0 +1,13 @@ +module.exports = { + presets: [ + // https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app + '@vue/cli-plugin-babel/preset' + ], + 'env': { + 'development': { + // babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require(). + // This plugin can significantly increase the speed of hot updates, when you have a large number of pages. + 'plugins': ['dynamic-import-node'] + } + } +} \ No newline at end of file diff --git a/CSP-frontend/bin/build.bat b/CSP-frontend/bin/build.bat new file mode 100644 index 0000000000000000000000000000000000000000..dda590d22434f988c9292b25aa7a3504d32880c0 --- /dev/null +++ b/CSP-frontend/bin/build.bat @@ -0,0 +1,12 @@ +@echo off +echo. +echo [Ϣ] Weḅdistļ +echo. + +%~d0 +cd %~dp0 + +cd .. +npm run build:prod + +pause \ No newline at end of file diff --git a/CSP-frontend/bin/package.bat b/CSP-frontend/bin/package.bat new file mode 100644 index 0000000000000000000000000000000000000000..0e5bc0fb50a96a7df7a02c92029a392168e0dd98 --- /dev/null +++ b/CSP-frontend/bin/package.bat @@ -0,0 +1,12 @@ +@echo off +echo. +echo [Ϣ] װWeḅnode_modulesļ +echo. + +%~d0 +cd %~dp0 + +cd .. +npm install --registry=https://registry.npmmirror.com + +pause \ No newline at end of file diff --git a/CSP-frontend/bin/run-web.bat b/CSP-frontend/bin/run-web.bat new file mode 100644 index 0000000000000000000000000000000000000000..d30deae795675dd10f239f63648719c0a63980b3 --- /dev/null +++ b/CSP-frontend/bin/run-web.bat @@ -0,0 +1,12 @@ +@echo off +echo. +echo [Ϣ] ʹ Vue CLI Web ̡ +echo. + +%~d0 +cd %~dp0 + +cd .. +npm run dev + +pause \ No newline at end of file diff --git a/CSP-frontend/build/index.js b/CSP-frontend/build/index.js new file mode 100644 index 0000000000000000000000000000000000000000..0c57de2aad9ee533046b71c08b56943be304d867 --- /dev/null +++ b/CSP-frontend/build/index.js @@ -0,0 +1,35 @@ +const { run } = require('runjs') +const chalk = require('chalk') +const config = require('../vue.config.js') +const rawArgv = process.argv.slice(2) +const args = rawArgv.join(' ') + +if (process.env.npm_config_preview || rawArgv.includes('--preview')) { + const report = rawArgv.includes('--report') + + run(`vue-cli-service build ${args}`) + + const port = 9526 + const publicPath = config.publicPath + + var connect = require('connect') + var serveStatic = require('serve-static') + const app = connect() + + app.use( + publicPath, + serveStatic('./dist', { + index: ['index.html', '/'] + }) + ) + + app.listen(port, function () { + console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`)) + if (report) { + console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`)) + } + + }) +} else { + run(`vue-cli-service build ${args}`) +} diff --git a/CSP-frontend/package.json b/CSP-frontend/package.json new file mode 100644 index 0000000000000000000000000000000000000000..a8485282ac82902c6c97b6b1a1182f00a8203849 --- /dev/null +++ b/CSP-frontend/package.json @@ -0,0 +1,92 @@ +{ + "name": "CodeScanningPlatform", + "version": "1.0.0", + "description": "在线代码扫描服务平台", + "author": "RVSmartPorting", + "license": "MIT", + "scripts": { + "dev": "vue-cli-service serve", + "build:prod": "vue-cli-service build", + "build:stage": "vue-cli-service build --mode staging", + "preview": "node build/index.js --preview", + "lint": "eslint --ext .js,.vue src" + }, + "husky": { + "hooks": { + "pre-commit": "lint-staged" + } + }, + "lint-staged": { + "src/**/*.{js,vue}": [ + "eslint --fix", + "git add" + ] + }, + "keywords": [ + "vue", + "admin", + "dashboard", + "element-ui", + "boilerplate", + "admin-template", + "management-system" + ], + "repository": { + "type": "git", + "url": "https://github.com/CodeScanningPlatform/CodeScanningPlatform-Frontend" + }, + "dependencies": { + "@riophae/vue-treeselect": "0.4.0", + "axios": "0.24.0", + "clipboard": "2.0.8", + "codemirror": "^5.0.1", + "core-js": "3.25.3", + "echarts": "5.4.0", + "element-ui": "2.15.13", + "file-saver": "2.0.5", + "fuse.js": "6.4.3", + "highlight.js": "9.18.5", + "js-beautify": "1.13.0", + "js-cookie": "3.0.1", + "js-yaml": "^4.1.0", + "jsencrypt": "3.0.0-rc.1", + "nprogress": "0.2.0", + "quill": "1.3.7", + "screenfull": "5.0.2", + "sortablejs": "1.10.2", + "vue": "2.6.12", + "vue-count-to": "1.0.13", + "vue-cropper": "0.5.5", + "vue-meta": "2.4.0", + "vue-router": "3.4.9", + "vuedraggable": "2.24.3", + "vuex": "3.6.0" + }, + "devDependencies": { + "@vue/cli-plugin-babel": "4.4.6", + "@vue/cli-plugin-eslint": "4.4.6", + "@vue/cli-service": "4.4.6", + "babel-eslint": "10.1.0", + "babel-plugin-dynamic-import-node": "2.3.3", + "chalk": "4.1.0", + "compression-webpack-plugin": "5.0.2", + "connect": "3.6.6", + "eslint": "7.15.0", + "eslint-plugin-vue": "7.2.0", + "lint-staged": "10.5.3", + "runjs": "4.4.2", + "sass": "1.32.13", + "sass-loader": "10.1.1", + "script-ext-html-webpack-plugin": "2.1.5", + "svg-sprite-loader": "5.1.1", + "vue-template-compiler": "2.6.12" + }, + "engines": { + "node": ">=8.9", + "npm": ">= 3.0.0" + }, + "browserslist": [ + "> 1%", + "last 2 versions" + ] +} diff --git a/CSP-frontend/public/favicon.ico b/CSP-frontend/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..e26376026420542212ed58d90d0ed34f554fa4ae Binary files /dev/null and b/CSP-frontend/public/favicon.ico differ diff --git a/CSP-frontend/public/html/ie.html b/CSP-frontend/public/html/ie.html new file mode 100644 index 0000000000000000000000000000000000000000..052ffcd6411b536576f9086af2757612bf68f682 --- /dev/null +++ b/CSP-frontend/public/html/ie.html @@ -0,0 +1,46 @@ + + + + + + 请升级您的浏览器 + + + + + + +

请升级您的浏览器,以便我们更好的为您提供服务!

+

您正在使用 Internet Explorer 的早期版本(IE11以下版本或使用该内核的浏览器)。这意味着在升级浏览器前,您将无法访问此网站。

+
+

请注意:微软公司对Windows XP 及 Internet Explorer 早期版本的支持已经结束

+

自 2016 年 1 月 12 日起,Microsoft 不再为 IE 11 以下版本提供相应支持和更新。没有关键的浏览器安全更新,您的电脑可能易受有害病毒、间谍软件和其他恶意软件的攻击,它们可以窃取或损害您的业务数据和信息。请参阅 微软对 Internet Explorer 早期版本的支持将于 2016 年 1 月 12 日结束的说明

+
+

您可以选择更先进的浏览器

+

推荐使用以下浏览器的最新版本。如果您的电脑已有以下浏览器的最新版本则直接使用该浏览器访问即可。

+ +
+ + \ No newline at end of file diff --git a/CSP-frontend/public/index.html b/CSP-frontend/public/index.html new file mode 100644 index 0000000000000000000000000000000000000000..925455cafd927242a4904510e4ae79b0693062bf --- /dev/null +++ b/CSP-frontend/public/index.html @@ -0,0 +1,208 @@ + + + + + + + + + <%= webpackConfig.name %> + + + + +
+
+
+
+
+
正在加载系统资源,请耐心等待
+
+
+ + diff --git a/CSP-frontend/public/robots.txt b/CSP-frontend/public/robots.txt new file mode 100644 index 0000000000000000000000000000000000000000..77470cb39f05f70a5b709b68304d0756bab75a0d --- /dev/null +++ b/CSP-frontend/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / \ No newline at end of file diff --git a/CSP-frontend/src/App.vue b/CSP-frontend/src/App.vue new file mode 100644 index 0000000000000000000000000000000000000000..29de49f15c6244e8437ac0c816c33a8049585593 --- /dev/null +++ b/CSP-frontend/src/App.vue @@ -0,0 +1,28 @@ + + + + diff --git a/CSP-frontend/src/api/login.js b/CSP-frontend/src/api/login.js new file mode 100644 index 0000000000000000000000000000000000000000..649f59c81a61f745b4f25680cd15281375684fed --- /dev/null +++ b/CSP-frontend/src/api/login.js @@ -0,0 +1,59 @@ +import request from '@/utils/request' + +// 登录方法 +export function login(username, password, code, uuid) { + const data = { + username, + password, + code, + uuid + } + return request({ + url: '/login', + headers: { + isToken: false + }, + method: 'post', + data: data + }) +} + +// 注册方法 +export function register(data) { + return request({ + url: '/register', + headers: { + isToken: false + }, + method: 'post', + data: data + }) +} + +// 获取用户详细信息 +export function getInfo() { + return request({ + url: '/getInfo', + method: 'get' + }) +} + +// 退出方法 +export function logout() { + return request({ + url: '/logout', + method: 'post' + }) +} + +// 获取验证码 +export function getCodeImg() { + return request({ + url: '/captchaImage', + headers: { + isToken: false + }, + method: 'get', + timeout: 20000 + }) +} \ No newline at end of file diff --git a/CSP-frontend/src/api/menu.js b/CSP-frontend/src/api/menu.js new file mode 100644 index 0000000000000000000000000000000000000000..faef101c4e8c3cf76a048f3981a7456edc432b19 --- /dev/null +++ b/CSP-frontend/src/api/menu.js @@ -0,0 +1,9 @@ +import request from '@/utils/request' + +// 获取路由 +export const getRouters = () => { + return request({ + url: '/getRouters', + method: 'get' + }) +} \ No newline at end of file diff --git a/CSP-frontend/src/api/monitor/cache.js b/CSP-frontend/src/api/monitor/cache.js new file mode 100644 index 0000000000000000000000000000000000000000..72c5f6a3ec9f4058fb18fedf046d1395d32164ca --- /dev/null +++ b/CSP-frontend/src/api/monitor/cache.js @@ -0,0 +1,57 @@ +import request from '@/utils/request' + +// 查询缓存详细 +export function getCache() { + return request({ + url: '/monitor/cache', + method: 'get' + }) +} + +// 查询缓存名称列表 +export function listCacheName() { + return request({ + url: '/monitor/cache/getNames', + method: 'get' + }) +} + +// 查询缓存键名列表 +export function listCacheKey(cacheName) { + return request({ + url: '/monitor/cache/getKeys/' + cacheName, + method: 'get' + }) +} + +// 查询缓存内容 +export function getCacheValue(cacheName, cacheKey) { + return request({ + url: '/monitor/cache/getValue/' + cacheName + '/' + cacheKey, + method: 'get' + }) +} + +// 清理指定名称缓存 +export function clearCacheName(cacheName) { + return request({ + url: '/monitor/cache/clearCacheName/' + cacheName, + method: 'delete' + }) +} + +// 清理指定键名缓存 +export function clearCacheKey(cacheKey) { + return request({ + url: '/monitor/cache/clearCacheKey/' + cacheKey, + method: 'delete' + }) +} + +// 清理全部缓存 +export function clearCacheAll() { + return request({ + url: '/monitor/cache/clearCacheAll', + method: 'delete' + }) +} diff --git a/CSP-frontend/src/api/monitor/job.js b/CSP-frontend/src/api/monitor/job.js new file mode 100644 index 0000000000000000000000000000000000000000..38155693a08ba6eb0a54a027e1f951928d7c3217 --- /dev/null +++ b/CSP-frontend/src/api/monitor/job.js @@ -0,0 +1,71 @@ +import request from '@/utils/request' + +// 查询定时任务调度列表 +export function listJob(query) { + return request({ + url: '/monitor/job/list', + method: 'get', + params: query + }) +} + +// 查询定时任务调度详细 +export function getJob(jobId) { + return request({ + url: '/monitor/job/' + jobId, + method: 'get' + }) +} + +// 新增定时任务调度 +export function addJob(data) { + return request({ + url: '/monitor/job', + method: 'post', + data: data + }) +} + +// 修改定时任务调度 +export function updateJob(data) { + return request({ + url: '/monitor/job', + method: 'put', + data: data + }) +} + +// 删除定时任务调度 +export function delJob(jobId) { + return request({ + url: '/monitor/job/' + jobId, + method: 'delete' + }) +} + +// 任务状态修改 +export function changeJobStatus(jobId, status) { + const data = { + jobId, + status + } + return request({ + url: '/monitor/job/changeStatus', + method: 'put', + data: data + }) +} + + +// 定时任务立即执行一次 +export function runJob(jobId, jobGroup) { + const data = { + jobId, + jobGroup + } + return request({ + url: '/monitor/job/run', + method: 'put', + data: data + }) +} \ No newline at end of file diff --git a/CSP-frontend/src/api/monitor/jobLog.js b/CSP-frontend/src/api/monitor/jobLog.js new file mode 100644 index 0000000000000000000000000000000000000000..6e0be616660ca604184a539ba3eb9683e80b84b7 --- /dev/null +++ b/CSP-frontend/src/api/monitor/jobLog.js @@ -0,0 +1,26 @@ +import request from '@/utils/request' + +// 查询调度日志列表 +export function listJobLog(query) { + return request({ + url: '/monitor/jobLog/list', + method: 'get', + params: query + }) +} + +// 删除调度日志 +export function delJobLog(jobLogId) { + return request({ + url: '/monitor/jobLog/' + jobLogId, + method: 'delete' + }) +} + +// 清空调度日志 +export function cleanJobLog() { + return request({ + url: '/monitor/jobLog/clean', + method: 'delete' + }) +} diff --git a/CSP-frontend/src/api/monitor/logininfor.js b/CSP-frontend/src/api/monitor/logininfor.js new file mode 100644 index 0000000000000000000000000000000000000000..4d112b78a1cc1eb561ffe5b1028d207b76343f64 --- /dev/null +++ b/CSP-frontend/src/api/monitor/logininfor.js @@ -0,0 +1,34 @@ +import request from '@/utils/request' + +// 查询登录日志列表 +export function list(query) { + return request({ + url: '/monitor/logininfor/list', + method: 'get', + params: query + }) +} + +// 删除登录日志 +export function delLogininfor(infoId) { + return request({ + url: '/monitor/logininfor/' + infoId, + method: 'delete' + }) +} + +// 解锁用户登录状态 +export function unlockLogininfor(userName) { + return request({ + url: '/monitor/logininfor/unlock/' + userName, + method: 'get' + }) +} + +// 清空登录日志 +export function cleanLogininfor() { + return request({ + url: '/monitor/logininfor/clean', + method: 'delete' + }) +} diff --git a/CSP-frontend/src/api/monitor/online.js b/CSP-frontend/src/api/monitor/online.js new file mode 100644 index 0000000000000000000000000000000000000000..bd22137809c26f7202b4794822c7829ff3577139 --- /dev/null +++ b/CSP-frontend/src/api/monitor/online.js @@ -0,0 +1,18 @@ +import request from '@/utils/request' + +// 查询在线用户列表 +export function list(query) { + return request({ + url: '/monitor/online/list', + method: 'get', + params: query + }) +} + +// 强退用户 +export function forceLogout(tokenId) { + return request({ + url: '/monitor/online/' + tokenId, + method: 'delete' + }) +} diff --git a/CSP-frontend/src/api/monitor/operlog.js b/CSP-frontend/src/api/monitor/operlog.js new file mode 100644 index 0000000000000000000000000000000000000000..a04bca84002706b7dffdaca9e1427cb08a6dcc6f --- /dev/null +++ b/CSP-frontend/src/api/monitor/operlog.js @@ -0,0 +1,26 @@ +import request from '@/utils/request' + +// 查询操作日志列表 +export function list(query) { + return request({ + url: '/monitor/operlog/list', + method: 'get', + params: query + }) +} + +// 删除操作日志 +export function delOperlog(operId) { + return request({ + url: '/monitor/operlog/' + operId, + method: 'delete' + }) +} + +// 清空操作日志 +export function cleanOperlog() { + return request({ + url: '/monitor/operlog/clean', + method: 'delete' + }) +} diff --git a/CSP-frontend/src/api/monitor/server.js b/CSP-frontend/src/api/monitor/server.js new file mode 100644 index 0000000000000000000000000000000000000000..e1f9ca214fa0f2b43202167ba74e1e52188010c8 --- /dev/null +++ b/CSP-frontend/src/api/monitor/server.js @@ -0,0 +1,9 @@ +import request from '@/utils/request' + +// 获取服务信息 +export function getServer() { + return request({ + url: '/monitor/server', + method: 'get' + }) +} \ No newline at end of file diff --git a/CSP-frontend/src/api/system/codeProject.js b/CSP-frontend/src/api/system/codeProject.js new file mode 100644 index 0000000000000000000000000000000000000000..5fbfdac93a8f9a9452820cddfc0772276c9bf496 --- /dev/null +++ b/CSP-frontend/src/api/system/codeProject.js @@ -0,0 +1,66 @@ +import request from '@/utils/request' + +// 查询代码项目信息列表 +export function listCodeProject(query) { + return request({ + url: '/system/codeProject/list', + method: 'get', + params: query + }) +} + +// 查询代码项目信息详细 +export function getCodeProject(codeProjectId) { + return request({ + url: '/system/codeProject/' + codeProjectId, + method: 'get' + }) +} + +// 新增代码项目信息 +export function addCodeProject(data) { + return request({ + url: '/system/codeProject', + method: 'post', + data: data + }) +} + +// 修改代码项目信息 +export function updateCodeProject(data) { + return request({ + url: '/system/codeProject', + method: 'put', + data: data + }) +} + +// 删除代码项目信息 +export function delCodeProject(codeProjectId) { + return request({ + url: '/system/codeProject/' + codeProjectId, + method: 'delete' + }) +} + +// 上传项目代码文件 +export function uploadCodeProjectFile(data) { + return request({ + url: '/system/codeProject/upload', + method: 'post', + data: data + }) +} + +export function cancelDownloadFromLink(requestId){ + return request({ + url: '/system/codeProject/cancelDownloadFromLink/'+requestId, + method: 'post', + }) +} +export function cancelGitDownloadFromLink(requestId){ + return request({ + url: '/system/codeProject/cancelGitDownloadFromLink/'+requestId, + method: 'post', + }) +} diff --git a/CSP-frontend/src/api/system/config.js b/CSP-frontend/src/api/system/config.js new file mode 100644 index 0000000000000000000000000000000000000000..a404d8254eaf08feb6b791b66c365b07662bf777 --- /dev/null +++ b/CSP-frontend/src/api/system/config.js @@ -0,0 +1,60 @@ +import request from '@/utils/request' + +// 查询参数列表 +export function listConfig(query) { + return request({ + url: '/system/config/list', + method: 'get', + params: query + }) +} + +// 查询参数详细 +export function getConfig(configId) { + return request({ + url: '/system/config/' + configId, + method: 'get' + }) +} + +// 根据参数键名查询参数值 +export function getConfigKey(configKey) { + return request({ + url: '/system/config/configKey/' + configKey, + method: 'get' + }) +} + +// 新增参数配置 +export function addConfig(data) { + return request({ + url: '/system/config', + method: 'post', + data: data + }) +} + +// 修改参数配置 +export function updateConfig(data) { + return request({ + url: '/system/config', + method: 'put', + data: data + }) +} + +// 删除参数配置 +export function delConfig(configId) { + return request({ + url: '/system/config/' + configId, + method: 'delete' + }) +} + +// 刷新参数缓存 +export function refreshCache() { + return request({ + url: '/system/config/refreshCache', + method: 'delete' + }) +} diff --git a/CSP-frontend/src/api/system/dept.js b/CSP-frontend/src/api/system/dept.js new file mode 100644 index 0000000000000000000000000000000000000000..fc943cd41fe7ae4e1274f9d9f28bcb9219c39eb8 --- /dev/null +++ b/CSP-frontend/src/api/system/dept.js @@ -0,0 +1,52 @@ +import request from '@/utils/request' + +// 查询部门列表 +export function listDept(query) { + return request({ + url: '/system/dept/list', + method: 'get', + params: query + }) +} + +// 查询部门列表(排除节点) +export function listDeptExcludeChild(deptId) { + return request({ + url: '/system/dept/list/exclude/' + deptId, + method: 'get' + }) +} + +// 查询部门详细 +export function getDept(deptId) { + return request({ + url: '/system/dept/' + deptId, + method: 'get' + }) +} + +// 新增部门 +export function addDept(data) { + return request({ + url: '/system/dept', + method: 'post', + data: data + }) +} + +// 修改部门 +export function updateDept(data) { + return request({ + url: '/system/dept', + method: 'put', + data: data + }) +} + +// 删除部门 +export function delDept(deptId) { + return request({ + url: '/system/dept/' + deptId, + method: 'delete' + }) +} \ No newline at end of file diff --git a/CSP-frontend/src/api/system/dict/data.js b/CSP-frontend/src/api/system/dict/data.js new file mode 100644 index 0000000000000000000000000000000000000000..6c9eb79b4d98af0a82361826dd078abfa8e02c98 --- /dev/null +++ b/CSP-frontend/src/api/system/dict/data.js @@ -0,0 +1,52 @@ +import request from '@/utils/request' + +// 查询字典数据列表 +export function listData(query) { + return request({ + url: '/system/dict/data/list', + method: 'get', + params: query + }) +} + +// 查询字典数据详细 +export function getData(dictCode) { + return request({ + url: '/system/dict/data/' + dictCode, + method: 'get' + }) +} + +// 根据字典类型查询字典数据信息 +export function getDicts(dictType) { + return request({ + url: '/system/dict/data/type/' + dictType, + method: 'get' + }) +} + +// 新增字典数据 +export function addData(data) { + return request({ + url: '/system/dict/data', + method: 'post', + data: data + }) +} + +// 修改字典数据 +export function updateData(data) { + return request({ + url: '/system/dict/data', + method: 'put', + data: data + }) +} + +// 删除字典数据 +export function delData(dictCode) { + return request({ + url: '/system/dict/data/' + dictCode, + method: 'delete' + }) +} diff --git a/CSP-frontend/src/api/system/dict/type.js b/CSP-frontend/src/api/system/dict/type.js new file mode 100644 index 0000000000000000000000000000000000000000..a7a6e01fcb3e1085b6e96a76bee14a90e110e48e --- /dev/null +++ b/CSP-frontend/src/api/system/dict/type.js @@ -0,0 +1,60 @@ +import request from '@/utils/request' + +// 查询字典类型列表 +export function listType(query) { + return request({ + url: '/system/dict/type/list', + method: 'get', + params: query + }) +} + +// 查询字典类型详细 +export function getType(dictId) { + return request({ + url: '/system/dict/type/' + dictId, + method: 'get' + }) +} + +// 新增字典类型 +export function addType(data) { + return request({ + url: '/system/dict/type', + method: 'post', + data: data + }) +} + +// 修改字典类型 +export function updateType(data) { + return request({ + url: '/system/dict/type', + method: 'put', + data: data + }) +} + +// 删除字典类型 +export function delType(dictId) { + return request({ + url: '/system/dict/type/' + dictId, + method: 'delete' + }) +} + +// 刷新字典缓存 +export function refreshCache() { + return request({ + url: '/system/dict/type/refreshCache', + method: 'delete' + }) +} + +// 获取字典选择框列表 +export function optionselect() { + return request({ + url: '/system/dict/type/optionselect', + method: 'get' + }) +} \ No newline at end of file diff --git a/CSP-frontend/src/api/system/gitNetworkSetting.js b/CSP-frontend/src/api/system/gitNetworkSetting.js new file mode 100644 index 0000000000000000000000000000000000000000..ae285507f75f093fd015513dcdfee9996b72b642 --- /dev/null +++ b/CSP-frontend/src/api/system/gitNetworkSetting.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询git网络镜像代理配置列表 +export function listGitNetworkSetting(query) { + return request({ + url: '/system/gitNetworkSetting/list', + method: 'get', + params: query + }) +} + +// 查询git网络镜像代理配置详细 +export function getGitNetworkSetting(gitNetworkSettingId) { + return request({ + url: '/system/gitNetworkSetting/' + gitNetworkSettingId, + method: 'get' + }) +}`` + +// 新增git网络镜像代理配置 +export function addGitNetworkSetting(data) { + return request({ + url: '/system/gitNetworkSetting', + method: 'post', + data: data + }) +} + +// 修改git网络镜像代理配置 +export function updateGitNetworkSetting(data) { + return request({ + url: '/system/gitNetworkSetting', + method: 'put', + data: data + }) +} + +// 删除git网络镜像代理配置 +export function delGitNetworkSetting(gitNetworkSettingId) { + return request({ + url: '/system/gitNetworkSetting/' + gitNetworkSettingId, + method: 'delete' + }) +} diff --git a/CSP-frontend/src/api/system/menu.js b/CSP-frontend/src/api/system/menu.js new file mode 100644 index 0000000000000000000000000000000000000000..f6415c65604a27f6487f89133267c7dcf6895d30 --- /dev/null +++ b/CSP-frontend/src/api/system/menu.js @@ -0,0 +1,60 @@ +import request from '@/utils/request' + +// 查询菜单列表 +export function listMenu(query) { + return request({ + url: '/system/menu/list', + method: 'get', + params: query + }) +} + +// 查询菜单详细 +export function getMenu(menuId) { + return request({ + url: '/system/menu/' + menuId, + method: 'get' + }) +} + +// 查询菜单下拉树结构 +export function treeselect() { + return request({ + url: '/system/menu/treeselect', + method: 'get' + }) +} + +// 根据角色ID查询菜单下拉树结构 +export function roleMenuTreeselect(roleId) { + return request({ + url: '/system/menu/roleMenuTreeselect/' + roleId, + method: 'get' + }) +} + +// 新增菜单 +export function addMenu(data) { + return request({ + url: '/system/menu', + method: 'post', + data: data + }) +} + +// 修改菜单 +export function updateMenu(data) { + return request({ + url: '/system/menu', + method: 'put', + data: data + }) +} + +// 删除菜单 +export function delMenu(menuId) { + return request({ + url: '/system/menu/' + menuId, + method: 'delete' + }) +} \ No newline at end of file diff --git a/CSP-frontend/src/api/system/notice.js b/CSP-frontend/src/api/system/notice.js new file mode 100644 index 0000000000000000000000000000000000000000..c274ea5bae6f8de003befa266d9f7e0bf0f901b1 --- /dev/null +++ b/CSP-frontend/src/api/system/notice.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询公告列表 +export function listNotice(query) { + return request({ + url: '/system/notice/list', + method: 'get', + params: query + }) +} + +// 查询公告详细 +export function getNotice(noticeId) { + return request({ + url: '/system/notice/' + noticeId, + method: 'get' + }) +} + +// 新增公告 +export function addNotice(data) { + return request({ + url: '/system/notice', + method: 'post', + data: data + }) +} + +// 修改公告 +export function updateNotice(data) { + return request({ + url: '/system/notice', + method: 'put', + data: data + }) +} + +// 删除公告 +export function delNotice(noticeId) { + return request({ + url: '/system/notice/' + noticeId, + method: 'delete' + }) +} \ No newline at end of file diff --git a/CSP-frontend/src/api/system/post.js b/CSP-frontend/src/api/system/post.js new file mode 100644 index 0000000000000000000000000000000000000000..1a8e9ca048f5c666506eb37479d180501316d6c8 --- /dev/null +++ b/CSP-frontend/src/api/system/post.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询岗位列表 +export function listPost(query) { + return request({ + url: '/system/post/list', + method: 'get', + params: query + }) +} + +// 查询岗位详细 +export function getPost(postId) { + return request({ + url: '/system/post/' + postId, + method: 'get' + }) +} + +// 新增岗位 +export function addPost(data) { + return request({ + url: '/system/post', + method: 'post', + data: data + }) +} + +// 修改岗位 +export function updatePost(data) { + return request({ + url: '/system/post', + method: 'put', + data: data + }) +} + +// 删除岗位 +export function delPost(postId) { + return request({ + url: '/system/post/' + postId, + method: 'delete' + }) +} diff --git a/CSP-frontend/src/api/system/role.js b/CSP-frontend/src/api/system/role.js new file mode 100644 index 0000000000000000000000000000000000000000..f13e6f4044c9285063a14dbf8190452beeac237a --- /dev/null +++ b/CSP-frontend/src/api/system/role.js @@ -0,0 +1,119 @@ +import request from '@/utils/request' + +// 查询角色列表 +export function listRole(query) { + return request({ + url: '/system/role/list', + method: 'get', + params: query + }) +} + +// 查询角色详细 +export function getRole(roleId) { + return request({ + url: '/system/role/' + roleId, + method: 'get' + }) +} + +// 新增角色 +export function addRole(data) { + return request({ + url: '/system/role', + method: 'post', + data: data + }) +} + +// 修改角色 +export function updateRole(data) { + return request({ + url: '/system/role', + method: 'put', + data: data + }) +} + +// 角色数据权限 +export function dataScope(data) { + return request({ + url: '/system/role/dataScope', + method: 'put', + data: data + }) +} + +// 角色状态修改 +export function changeRoleStatus(roleId, status) { + const data = { + roleId, + status + } + return request({ + url: '/system/role/changeStatus', + method: 'put', + data: data + }) +} + +// 删除角色 +export function delRole(roleId) { + return request({ + url: '/system/role/' + roleId, + method: 'delete' + }) +} + +// 查询角色已授权用户列表 +export function allocatedUserList(query) { + return request({ + url: '/system/role/authUser/allocatedList', + method: 'get', + params: query + }) +} + +// 查询角色未授权用户列表 +export function unallocatedUserList(query) { + return request({ + url: '/system/role/authUser/unallocatedList', + method: 'get', + params: query + }) +} + +// 取消用户授权角色 +export function authUserCancel(data) { + return request({ + url: '/system/role/authUser/cancel', + method: 'put', + data: data + }) +} + +// 批量取消用户授权角色 +export function authUserCancelAll(data) { + return request({ + url: '/system/role/authUser/cancelAll', + method: 'put', + params: data + }) +} + +// 授权用户选择 +export function authUserSelectAll(data) { + return request({ + url: '/system/role/authUser/selectAll', + method: 'put', + params: data + }) +} + +// 根据角色ID查询部门树结构 +export function deptTreeSelect(roleId) { + return request({ + url: '/system/role/deptTree/' + roleId, + method: 'get' + }) +} diff --git a/CSP-frontend/src/api/system/rule.js b/CSP-frontend/src/api/system/rule.js new file mode 100644 index 0000000000000000000000000000000000000000..3230c60816f03ab4c8fd0e024ec8470e0cf410ea --- /dev/null +++ b/CSP-frontend/src/api/system/rule.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询规则信息列表 +export function listRule(query) { + return request({ + url: '/system/rule/list', + method: 'get', + params: query + }) +} + +// 查询规则信息详细 +export function getRule(ruleId) { + return request({ + url: '/system/rule/' + ruleId, + method: 'get' + }) +} + +// 新增规则信息 +export function addRule(data) { + return request({ + url: '/system/rule', + method: 'post', + data: data + }) +} + +// 修改规则信息 +export function updateRule(data) { + return request({ + url: '/system/rule', + method: 'put', + data: data + }) +} + +// 删除规则信息 +export function delRule(ruleId) { + return request({ + url: '/system/rule/' + ruleId, + method: 'delete' + }) +} diff --git a/CSP-frontend/src/api/system/ruleSet.js b/CSP-frontend/src/api/system/ruleSet.js new file mode 100644 index 0000000000000000000000000000000000000000..575024a7193e9cb0bc3b9b47bc6c8b635702174e --- /dev/null +++ b/CSP-frontend/src/api/system/ruleSet.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询规则集信息列表 +export function listSet(query) { + return request({ + url: '/system/ruleSet/list', + method: 'get', + params: query + }) +} + +// 查询规则集信息详细 +export function getRuleSet(ruleSetId) { + return request({ + url: '/system/ruleSet/' + ruleSetId, + method: 'get' + }) +} + +// 新增规则集信息 +export function addRuleSet(data) { + return request({ + url: '/system/ruleSet', + method: 'post', + data: data + }) +} + +// 修改规则集信息 +export function updateRuleSet(data) { + return request({ + url: '/system/ruleSet', + method: 'put', + data: data + }) +} + +// 删除规则集信息 +export function delRuleSet(ruleSetId) { + return request({ + url: '/system/ruleSet/' + ruleSetId, + method: 'delete' + }) +} diff --git a/CSP-frontend/src/api/system/scanTask.js b/CSP-frontend/src/api/system/scanTask.js new file mode 100644 index 0000000000000000000000000000000000000000..724b143a606c4490b2a51305276956c5cd3c5df1 --- /dev/null +++ b/CSP-frontend/src/api/system/scanTask.js @@ -0,0 +1,84 @@ +import request from '@/utils/request' +import scanGatewayRequest from "@/utils/scanGatewayRequest"; + +// 查询代码扫描任务信息列表 +export function listScanTask(query) { + return request({ + url: '/system/scanTask/list', + method: 'get', + params: query + }) +} + +// 查询代码扫描任务信息详细 +export function getScanTask(taskId) { + return request({ + url: '/system/scanTask/' + taskId, + method: 'get' + }) +} + +// 新增代码扫描任务信息 +export function addScanTask(data) { + return request({ + url: '/system/scanTask', + method: 'post', + data: data + }) +} + +// 修改代码扫描任务信息 +export function updateScanTask(data) { + return request({ + url: '/system/scanTask', + method: 'put', + data: data + }) +} + +// 删除代码扫描任务信息 +export function delScanTask(taskId) { + return request({ + url: '/system/scanTask/' + taskId, + method: 'delete' + }) +} + +export function addAndRunScanJob(taskId) { + return scanGatewayRequest({ + url: '/system/job/addAndRunScanJob/' + taskId, + method: 'post' + }) +} + +// 日志详情接口 +export function logDetailCat(query) { + return scanGatewayRequest({ + url: '/system/job/logDetailCat', + method: 'get', + params: query + }) +} +// 获取最新一条的任务执行日志 +export function getLatestJobLogByJobId(query) { + return scanGatewayRequest({ + url: '/system/job/getLatestJobLogByJobId', + method: 'get', + params: query + }) +} + +export function getLogFileStoragePath(query) { + return scanGatewayRequest({ + url: '/system/job/getLogFileStoragePath', + method: 'get', + params: query + }) +} +export function getScanReportContent(query) { + return scanGatewayRequest({ + url: '/system/job/getScanReportContent', + method: 'get', + params: query + }) +} diff --git a/CSP-frontend/src/api/system/scanTool.js b/CSP-frontend/src/api/system/scanTool.js new file mode 100644 index 0000000000000000000000000000000000000000..c4a140c84e8df57bd5e0c5c4771706f23e7a79f1 --- /dev/null +++ b/CSP-frontend/src/api/system/scanTool.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询扫描工具列表 +export function listScanTool(query) { + return request({ + url: '/system/scanTool/list', + method: 'get', + params: query + }) +} + +// 查询扫描工具详细 +export function getScanTool(scanToolId) { + return request({ + url: '/system/scanTool/' + scanToolId, + method: 'get' + }) +} + +// 新增扫描工具 +export function addScanTool(data) { + return request({ + url: '/system/scanTool', + method: 'post', + data: data + }) +} + +// 修改扫描工具 +export function updateScanTool(data) { + return request({ + url: '/system/scanTool', + method: 'put', + data: data + }) +} + +// 删除扫描工具 +export function delScanTool(scanToolId) { + return request({ + url: '/system/scanTool/' + scanToolId, + method: 'delete' + }) +} diff --git a/CSP-frontend/src/api/system/scanToolConfig.js b/CSP-frontend/src/api/system/scanToolConfig.js new file mode 100644 index 0000000000000000000000000000000000000000..81514ac9bf666deafe6f2bbc9dd4d4839304b9a1 --- /dev/null +++ b/CSP-frontend/src/api/system/scanToolConfig.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询扫描工具配置列表 +export function listScanToolConfig(query) { + return request({ + url: '/system/scanToolConfig/list', + method: 'get', + params: query + }) +} + +// 查询扫描工具配置详细 +export function getScanToolConfig(scanToolConfigId) { + return request({ + url: '/system/scanToolConfig/' + scanToolConfigId, + method: 'get' + }) +} + +// 新增扫描工具配置 +export function addScanToolConfig(data) { + return request({ + url: '/system/scanToolConfig', + method: 'post', + data: data + }) +} + +// 修改扫描工具配置 +export function updateScanToolConfig(data) { + return request({ + url: '/system/scanToolConfig', + method: 'put', + data: data + }) +} + +// 删除扫描工具配置 +export function delScanToolConfig(scanToolConfigId) { + return request({ + url: '/system/scanToolConfig/' + scanToolConfigId, + method: 'delete' + }) +} diff --git a/CSP-frontend/src/api/system/user.js b/CSP-frontend/src/api/system/user.js new file mode 100644 index 0000000000000000000000000000000000000000..f2f76ef9fed4310e3028afd0fd17f269b2178a54 --- /dev/null +++ b/CSP-frontend/src/api/system/user.js @@ -0,0 +1,135 @@ +import request from '@/utils/request' +import { parseStrEmpty } from "@/utils/ruoyi"; + +// 查询用户列表 +export function listUser(query) { + return request({ + url: '/system/user/list', + method: 'get', + params: query + }) +} + +// 查询用户详细 +export function getUser(userId) { + return request({ + url: '/system/user/' + parseStrEmpty(userId), + method: 'get' + }) +} + +// 新增用户 +export function addUser(data) { + return request({ + url: '/system/user', + method: 'post', + data: data + }) +} + +// 修改用户 +export function updateUser(data) { + return request({ + url: '/system/user', + method: 'put', + data: data + }) +} + +// 删除用户 +export function delUser(userId) { + return request({ + url: '/system/user/' + userId, + method: 'delete' + }) +} + +// 用户密码重置 +export function resetUserPwd(userId, password) { + const data = { + userId, + password + } + return request({ + url: '/system/user/resetPwd', + method: 'put', + data: data + }) +} + +// 用户状态修改 +export function changeUserStatus(userId, status) { + const data = { + userId, + status + } + return request({ + url: '/system/user/changeStatus', + method: 'put', + data: data + }) +} + +// 查询用户个人信息 +export function getUserProfile() { + return request({ + url: '/system/user/profile', + method: 'get' + }) +} + +// 修改用户个人信息 +export function updateUserProfile(data) { + return request({ + url: '/system/user/profile', + method: 'put', + data: data + }) +} + +// 用户密码重置 +export function updateUserPwd(oldPassword, newPassword) { + const data = { + oldPassword, + newPassword + } + return request({ + url: '/system/user/profile/updatePwd', + method: 'put', + params: data + }) +} + +// 用户头像上传 +export function uploadAvatar(data) { + return request({ + url: '/system/user/profile/avatar', + method: 'post', + data: data + }) +} + +// 查询授权角色 +export function getAuthRole(userId) { + return request({ + url: '/system/user/authRole/' + userId, + method: 'get' + }) +} + +// 保存授权角色 +export function updateAuthRole(data) { + return request({ + url: '/system/user/authRole', + method: 'put', + params: data + }) +} + +// 查询部门下拉树结构 +export function deptTreeSelect() { + return request({ + url: '/system/user/deptTree', + method: 'get' + }) +} diff --git a/CSP-frontend/src/api/tool/gen.js b/CSP-frontend/src/api/tool/gen.js new file mode 100644 index 0000000000000000000000000000000000000000..45069278fa93ac8cd748ffae138dc2777cd5bd00 --- /dev/null +++ b/CSP-frontend/src/api/tool/gen.js @@ -0,0 +1,76 @@ +import request from '@/utils/request' + +// 查询生成表数据 +export function listTable(query) { + return request({ + url: '/tool/gen/list', + method: 'get', + params: query + }) +} +// 查询db数据库列表 +export function listDbTable(query) { + return request({ + url: '/tool/gen/db/list', + method: 'get', + params: query + }) +} + +// 查询表详细信息 +export function getGenTable(tableId) { + return request({ + url: '/tool/gen/' + tableId, + method: 'get' + }) +} + +// 修改代码生成信息 +export function updateGenTable(data) { + return request({ + url: '/tool/gen', + method: 'put', + data: data + }) +} + +// 导入表 +export function importTable(data) { + return request({ + url: '/tool/gen/importTable', + method: 'post', + params: data + }) +} + +// 预览生成代码 +export function previewTable(tableId) { + return request({ + url: '/tool/gen/preview/' + tableId, + method: 'get' + }) +} + +// 删除表数据 +export function delTable(tableId) { + return request({ + url: '/tool/gen/' + tableId, + method: 'delete' + }) +} + +// 生成代码(自定义路径) +export function genCode(tableName) { + return request({ + url: '/tool/gen/genCode/' + tableName, + method: 'get' + }) +} + +// 同步数据库 +export function synchDb(tableName) { + return request({ + url: '/tool/gen/synchDb/' + tableName, + method: 'get' + }) +} diff --git a/CSP-frontend/src/assets/401_images/401.gif b/CSP-frontend/src/assets/401_images/401.gif new file mode 100644 index 0000000000000000000000000000000000000000..cd6e0d9433421b3f29d0ec0c40f755e354728000 Binary files /dev/null and b/CSP-frontend/src/assets/401_images/401.gif differ diff --git a/CSP-frontend/src/assets/404_images/404.png b/CSP-frontend/src/assets/404_images/404.png new file mode 100644 index 0000000000000000000000000000000000000000..3d8e2305cc973ad2121403aee4bf08728f76c461 Binary files /dev/null and b/CSP-frontend/src/assets/404_images/404.png differ diff --git a/CSP-frontend/src/assets/404_images/404_cloud.png b/CSP-frontend/src/assets/404_images/404_cloud.png new file mode 100644 index 0000000000000000000000000000000000000000..c6281d09013e0a2c5f8e699a0a6038d9480291e5 Binary files /dev/null and b/CSP-frontend/src/assets/404_images/404_cloud.png differ diff --git a/CSP-frontend/src/assets/icons/index.js b/CSP-frontend/src/assets/icons/index.js new file mode 100644 index 0000000000000000000000000000000000000000..2c6b309c96cc2e43761a691860858f232f6d5d1a --- /dev/null +++ b/CSP-frontend/src/assets/icons/index.js @@ -0,0 +1,9 @@ +import Vue from 'vue' +import SvgIcon from '@/components/SvgIcon'// svg component + +// register globally +Vue.component('svg-icon', SvgIcon) + +const req = require.context('./svg', false, /\.svg$/) +const requireAll = requireContext => requireContext.keys().map(requireContext) +requireAll(req) diff --git a/CSP-frontend/src/assets/icons/svg/404.svg b/CSP-frontend/src/assets/icons/svg/404.svg new file mode 100644 index 0000000000000000000000000000000000000000..6df50190aab43bd3a727b580fe2699ba36a4712c --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/404.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/bug.svg b/CSP-frontend/src/assets/icons/svg/bug.svg new file mode 100644 index 0000000000000000000000000000000000000000..05a150dc3905ef7516e1b57b32bc49510c0f8763 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/bug.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/build.svg b/CSP-frontend/src/assets/icons/svg/build.svg new file mode 100644 index 0000000000000000000000000000000000000000..97c468863287f37a472112dd18e717cd94471ee6 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/build.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/button.svg b/CSP-frontend/src/assets/icons/svg/button.svg new file mode 100644 index 0000000000000000000000000000000000000000..904fddc854ad072e887306b5d6e6539dca960f2b --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/button.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/cascader.svg b/CSP-frontend/src/assets/icons/svg/cascader.svg new file mode 100644 index 0000000000000000000000000000000000000000..e256024f9dd4142bef13a999df669d88ee9200f4 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/cascader.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/chart.svg b/CSP-frontend/src/assets/icons/svg/chart.svg new file mode 100644 index 0000000000000000000000000000000000000000..27728fb0baae52c4430ef9d0332d1f0bbedaa564 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/chart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/checkbox.svg b/CSP-frontend/src/assets/icons/svg/checkbox.svg new file mode 100644 index 0000000000000000000000000000000000000000..013fd3a273eec2b45ea72843d7b3334c5d750530 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/checkbox.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/clipboard.svg b/CSP-frontend/src/assets/icons/svg/clipboard.svg new file mode 100644 index 0000000000000000000000000000000000000000..90923ff6282ec6aa403936bbe44b68e134cb9bcf --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/clipboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/code.svg b/CSP-frontend/src/assets/icons/svg/code.svg new file mode 100644 index 0000000000000000000000000000000000000000..5f9c5abd596f90c0795cf879df38c82964ddc5ad --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/code.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/color.svg b/CSP-frontend/src/assets/icons/svg/color.svg new file mode 100644 index 0000000000000000000000000000000000000000..44a81aab1bb9de3907ec9fadaf2d9e616979390f --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/color.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/component.svg b/CSP-frontend/src/assets/icons/svg/component.svg new file mode 100644 index 0000000000000000000000000000000000000000..29c345809974665d96ed42e261734bc56c37b826 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/component.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/dashboard.svg b/CSP-frontend/src/assets/icons/svg/dashboard.svg new file mode 100644 index 0000000000000000000000000000000000000000..5317d37029218281b4da78eccf40ce9e94941301 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/dashboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/date-range.svg b/CSP-frontend/src/assets/icons/svg/date-range.svg new file mode 100644 index 0000000000000000000000000000000000000000..fda571e700372418697293910f77957c07290cfe --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/date-range.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/date.svg b/CSP-frontend/src/assets/icons/svg/date.svg new file mode 100644 index 0000000000000000000000000000000000000000..52dc73eecfaca2c315b54d99ba7030a79e549f36 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/date.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/dict.svg b/CSP-frontend/src/assets/icons/svg/dict.svg new file mode 100644 index 0000000000000000000000000000000000000000..484937730750b9adb201df69abef2503760f7229 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/dict.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/documentation.svg b/CSP-frontend/src/assets/icons/svg/documentation.svg new file mode 100644 index 0000000000000000000000000000000000000000..704312289e6ad2f65a3ace229e73fb5c7f3e94e9 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/documentation.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/download.svg b/CSP-frontend/src/assets/icons/svg/download.svg new file mode 100644 index 0000000000000000000000000000000000000000..c8969513493e7ac96725dcf2f01400e7c2c63df6 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/download.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/drag.svg b/CSP-frontend/src/assets/icons/svg/drag.svg new file mode 100644 index 0000000000000000000000000000000000000000..4185d3cee36930abb40838829058537388cc6dc6 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/drag.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/druid.svg b/CSP-frontend/src/assets/icons/svg/druid.svg new file mode 100644 index 0000000000000000000000000000000000000000..a2b4b4ed2481975a127506a9516e5c12417ac93e --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/druid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/edit.svg b/CSP-frontend/src/assets/icons/svg/edit.svg new file mode 100644 index 0000000000000000000000000000000000000000..d26101f29893ee07c575d62caf1d0d684e76b3bc --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/edit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/education.svg b/CSP-frontend/src/assets/icons/svg/education.svg new file mode 100644 index 0000000000000000000000000000000000000000..7bfb01d180f9ac9cf45429412129a7b7be4d8daf --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/education.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/email.svg b/CSP-frontend/src/assets/icons/svg/email.svg new file mode 100644 index 0000000000000000000000000000000000000000..74d25e21a6f98b90b34b2b8d2ce2dd90b38eb000 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/email.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/example.svg b/CSP-frontend/src/assets/icons/svg/example.svg new file mode 100644 index 0000000000000000000000000000000000000000..46f42b5323d11686c44b573729db0df115343d5c --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/example.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/excel.svg b/CSP-frontend/src/assets/icons/svg/excel.svg new file mode 100644 index 0000000000000000000000000000000000000000..74d97b802f8bf84caf4c623e77f890f74516d50f --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/excel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/exit-fullscreen.svg b/CSP-frontend/src/assets/icons/svg/exit-fullscreen.svg new file mode 100644 index 0000000000000000000000000000000000000000..485c128b6133188ae755c275a1c667634e4129b6 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/exit-fullscreen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/eye-open.svg b/CSP-frontend/src/assets/icons/svg/eye-open.svg new file mode 100644 index 0000000000000000000000000000000000000000..88dcc98e6c80d145e3807f00a6e5ed91ce5371e4 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/eye-open.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/eye.svg b/CSP-frontend/src/assets/icons/svg/eye.svg new file mode 100644 index 0000000000000000000000000000000000000000..16ed2d872d1cadeb36fc9101cbf77397fbf4fd70 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/eye.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/form.svg b/CSP-frontend/src/assets/icons/svg/form.svg new file mode 100644 index 0000000000000000000000000000000000000000..dcbaa185a845cdf01a7fdfb849c224ce9c4af011 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/form.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/fullscreen.svg b/CSP-frontend/src/assets/icons/svg/fullscreen.svg new file mode 100644 index 0000000000000000000000000000000000000000..0e86b6fa803dbe964cae74f4432622d435b007bf --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/fullscreen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/github.svg b/CSP-frontend/src/assets/icons/svg/github.svg new file mode 100644 index 0000000000000000000000000000000000000000..db0a0d4304731d60794b853cd8c06f4556fc95e9 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/github.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/guide.svg b/CSP-frontend/src/assets/icons/svg/guide.svg new file mode 100644 index 0000000000000000000000000000000000000000..b2710017933e9088e002873cde651bac54cea449 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/guide.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/icon.svg b/CSP-frontend/src/assets/icons/svg/icon.svg new file mode 100644 index 0000000000000000000000000000000000000000..82be8eeedb3d3cc9161f4a4094ac20d2f91e3970 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/input.svg b/CSP-frontend/src/assets/icons/svg/input.svg new file mode 100644 index 0000000000000000000000000000000000000000..ab91381e6df0ec6307d677f0dce75b9c9d95e5d5 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/input.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/international.svg b/CSP-frontend/src/assets/icons/svg/international.svg new file mode 100644 index 0000000000000000000000000000000000000000..e9b56eee2c59774f0431186b9af2ba7593bffcc0 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/international.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/job.svg b/CSP-frontend/src/assets/icons/svg/job.svg new file mode 100644 index 0000000000000000000000000000000000000000..2a93a25195e29eba9c76d7ce5bdd6f1a71f9aee4 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/job.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/language.svg b/CSP-frontend/src/assets/icons/svg/language.svg new file mode 100644 index 0000000000000000000000000000000000000000..0082b577ab28523f353fa71c00cb338446b2bb9c --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/language.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/link.svg b/CSP-frontend/src/assets/icons/svg/link.svg new file mode 100644 index 0000000000000000000000000000000000000000..48197ba4da7b4314a16a19a698fe96c1b2a7ad0b --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/link.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/list.svg b/CSP-frontend/src/assets/icons/svg/list.svg new file mode 100644 index 0000000000000000000000000000000000000000..20259eddb7c0cf77efe9cb1c561d2df8961094f5 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/list.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/lock.svg b/CSP-frontend/src/assets/icons/svg/lock.svg new file mode 100644 index 0000000000000000000000000000000000000000..74fee543dd1d9bc0ceb3310cc87bf65e268bf364 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/lock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/log.svg b/CSP-frontend/src/assets/icons/svg/log.svg new file mode 100644 index 0000000000000000000000000000000000000000..d879d33b6cd96ae370e104d58589915441e1bcb3 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/log.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/logininfor.svg b/CSP-frontend/src/assets/icons/svg/logininfor.svg new file mode 100644 index 0000000000000000000000000000000000000000..267f84474266c8ebe6ae61925a7c1cb4e3814079 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/logininfor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/message.svg b/CSP-frontend/src/assets/icons/svg/message.svg new file mode 100644 index 0000000000000000000000000000000000000000..14ca81728a3de16e103a858b4ce31f8e0f550bce --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/message.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/money.svg b/CSP-frontend/src/assets/icons/svg/money.svg new file mode 100644 index 0000000000000000000000000000000000000000..c1580de10e1f1c504f7bfcaba4f41b24d816d8f2 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/money.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/monitor.svg b/CSP-frontend/src/assets/icons/svg/monitor.svg new file mode 100644 index 0000000000000000000000000000000000000000..bc308cb0f5f7afff5ba4b17fca06c721de14764e --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/monitor.svg @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/nested.svg b/CSP-frontend/src/assets/icons/svg/nested.svg new file mode 100644 index 0000000000000000000000000000000000000000..06713a86c6a3db0cd5eeb26cf81ffb27b538e9a1 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/nested.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/number.svg b/CSP-frontend/src/assets/icons/svg/number.svg new file mode 100644 index 0000000000000000000000000000000000000000..ad5ce9af2aaf54c43444a81535a599c7cd004be1 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/number.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/online.svg b/CSP-frontend/src/assets/icons/svg/online.svg new file mode 100644 index 0000000000000000000000000000000000000000..330a202935b887236b34200b163f6a421bad592f --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/online.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/password.svg b/CSP-frontend/src/assets/icons/svg/password.svg new file mode 100644 index 0000000000000000000000000000000000000000..6c64defe396d998bc5c995d79b661b11411cced1 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/password.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/pdf.svg b/CSP-frontend/src/assets/icons/svg/pdf.svg new file mode 100644 index 0000000000000000000000000000000000000000..957aa0cc3597c1277ded6367716067c9874552e0 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/pdf.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/people.svg b/CSP-frontend/src/assets/icons/svg/people.svg new file mode 100644 index 0000000000000000000000000000000000000000..2bd54aeb728197066e987e8d8d98364f50ed5be6 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/people.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/peoples.svg b/CSP-frontend/src/assets/icons/svg/peoples.svg new file mode 100644 index 0000000000000000000000000000000000000000..aab852e52a33a5823fcdd5302111b45f4a4e13a7 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/peoples.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/phone.svg b/CSP-frontend/src/assets/icons/svg/phone.svg new file mode 100644 index 0000000000000000000000000000000000000000..ab8e8c4e5b3765c92e98fd2ecfeeda892661ac17 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/phone.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/post.svg b/CSP-frontend/src/assets/icons/svg/post.svg new file mode 100644 index 0000000000000000000000000000000000000000..2922c613bddb847c6f411e27b5ad874f577a633f --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/post.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/qq.svg b/CSP-frontend/src/assets/icons/svg/qq.svg new file mode 100644 index 0000000000000000000000000000000000000000..ee13d4ec2e54dbbe64009db689c502b05629721a --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/qq.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/question.svg b/CSP-frontend/src/assets/icons/svg/question.svg new file mode 100644 index 0000000000000000000000000000000000000000..cf75bd4bea55c98003ca97828fcb3e37d5c4450e --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/question.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/radio.svg b/CSP-frontend/src/assets/icons/svg/radio.svg new file mode 100644 index 0000000000000000000000000000000000000000..0cde34521ae7b5bddaaa2372a4472fc05f9135a4 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/radio.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/rate.svg b/CSP-frontend/src/assets/icons/svg/rate.svg new file mode 100644 index 0000000000000000000000000000000000000000..aa3b14d7de73af3e7d4a6c9dc41836a11003208e --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/rate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/redis-list.svg b/CSP-frontend/src/assets/icons/svg/redis-list.svg new file mode 100644 index 0000000000000000000000000000000000000000..98a15b2a6fbfafd2e689f97a7048b6a9bf7bddc4 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/redis-list.svg @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/redis.svg b/CSP-frontend/src/assets/icons/svg/redis.svg new file mode 100644 index 0000000000000000000000000000000000000000..2f1d62dfc373a4921815fa1058c73916ca15aca2 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/redis.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/row.svg b/CSP-frontend/src/assets/icons/svg/row.svg new file mode 100644 index 0000000000000000000000000000000000000000..07809922264539672115e4866d65c3e1e6032df9 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/row.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/search.svg b/CSP-frontend/src/assets/icons/svg/search.svg new file mode 100644 index 0000000000000000000000000000000000000000..84233ddaa98a45d407cacdc869d9b7634f72d390 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/select.svg b/CSP-frontend/src/assets/icons/svg/select.svg new file mode 100644 index 0000000000000000000000000000000000000000..d6283828bac413d2a10d4f6e267d7ba2f5f10aea --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/select.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/server.svg b/CSP-frontend/src/assets/icons/svg/server.svg new file mode 100644 index 0000000000000000000000000000000000000000..eb287e36c30d75f3899cab00d9ca3cce9ff0d2d4 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/server.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/shopping.svg b/CSP-frontend/src/assets/icons/svg/shopping.svg new file mode 100644 index 0000000000000000000000000000000000000000..87513e7c5fdd4260e48f7ead3501e0b9f9798c2a --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/shopping.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/size.svg b/CSP-frontend/src/assets/icons/svg/size.svg new file mode 100644 index 0000000000000000000000000000000000000000..ddb25b8d58c52f1f0323483b1cbfd7a113512e0d --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/size.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/skill.svg b/CSP-frontend/src/assets/icons/svg/skill.svg new file mode 100644 index 0000000000000000000000000000000000000000..a3b7312186fbd305a0c0ab902e2cc01e2f804f32 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/skill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/slider.svg b/CSP-frontend/src/assets/icons/svg/slider.svg new file mode 100644 index 0000000000000000000000000000000000000000..fbe4f39f004ef8415e039234eaf4bf11b4d9985a --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/slider.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/star.svg b/CSP-frontend/src/assets/icons/svg/star.svg new file mode 100644 index 0000000000000000000000000000000000000000..6cf86e66add37b5562fc4793dd9a218163f485b4 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/star.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/swagger.svg b/CSP-frontend/src/assets/icons/svg/swagger.svg new file mode 100644 index 0000000000000000000000000000000000000000..05d4e7bcee9829539a977c51c36560c4aad98c80 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/swagger.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/switch.svg b/CSP-frontend/src/assets/icons/svg/switch.svg new file mode 100644 index 0000000000000000000000000000000000000000..0ba61e38d72b9af4c6e5a400baa0561f06d8d0c0 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/switch.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/system.svg b/CSP-frontend/src/assets/icons/svg/system.svg new file mode 100644 index 0000000000000000000000000000000000000000..5992593e091dd578a966a096d5036ae7b8da7993 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/system.svg @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/tab.svg b/CSP-frontend/src/assets/icons/svg/tab.svg new file mode 100644 index 0000000000000000000000000000000000000000..b4b48e48085bb21b18da5386a6d4692a70301977 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/tab.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/table.svg b/CSP-frontend/src/assets/icons/svg/table.svg new file mode 100644 index 0000000000000000000000000000000000000000..0e3dc9dea5a0ff92d617cdfee4f10ef600a02433 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/table.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/textarea.svg b/CSP-frontend/src/assets/icons/svg/textarea.svg new file mode 100644 index 0000000000000000000000000000000000000000..2709f292ea23aa87ba87d5ee2622c94994c1fbfb --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/textarea.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/theme.svg b/CSP-frontend/src/assets/icons/svg/theme.svg new file mode 100644 index 0000000000000000000000000000000000000000..5982a2f784052994f07138239eae96d8024531e9 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/theme.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/time-range.svg b/CSP-frontend/src/assets/icons/svg/time-range.svg new file mode 100644 index 0000000000000000000000000000000000000000..13c1202bdafa11c73c89ee472f3c810e834dfeca --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/time-range.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/time.svg b/CSP-frontend/src/assets/icons/svg/time.svg new file mode 100644 index 0000000000000000000000000000000000000000..b376e32a608f33f906cda57da3df809c0413a44e --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/time.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/tool.svg b/CSP-frontend/src/assets/icons/svg/tool.svg new file mode 100644 index 0000000000000000000000000000000000000000..48e0e35738cb59eb0f19fc2878544b698ae9ad64 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/tool.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/tree-table.svg b/CSP-frontend/src/assets/icons/svg/tree-table.svg new file mode 100644 index 0000000000000000000000000000000000000000..8aafdb829ebbe289f352a533d9764c4f9395e533 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/tree-table.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/tree.svg b/CSP-frontend/src/assets/icons/svg/tree.svg new file mode 100644 index 0000000000000000000000000000000000000000..dd4b7dd22fe06076831935066592caec48e323b0 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/tree.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/upload.svg b/CSP-frontend/src/assets/icons/svg/upload.svg new file mode 100644 index 0000000000000000000000000000000000000000..bae49c0a50e7bc0683d82e3af2e0064adc4108ad --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/upload.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/user.svg b/CSP-frontend/src/assets/icons/svg/user.svg new file mode 100644 index 0000000000000000000000000000000000000000..0ba0716a62a92f7cb2f2e6f3c745ace2be6b3b31 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/user.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/validCode.svg b/CSP-frontend/src/assets/icons/svg/validCode.svg new file mode 100644 index 0000000000000000000000000000000000000000..cfb10214c53ee9e021a97733c9b5b5c39e388787 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/validCode.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/wechat.svg b/CSP-frontend/src/assets/icons/svg/wechat.svg new file mode 100644 index 0000000000000000000000000000000000000000..c586e5511722843f9c741d7530db146dfab864a4 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/wechat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svg/zip.svg b/CSP-frontend/src/assets/icons/svg/zip.svg new file mode 100644 index 0000000000000000000000000000000000000000..f806fc4825739224caf820e6edf54e808961b1a6 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svg/zip.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CSP-frontend/src/assets/icons/svgo.yml b/CSP-frontend/src/assets/icons/svgo.yml new file mode 100644 index 0000000000000000000000000000000000000000..d11906aec26dd14372dd1b298f72270c38cce1b7 --- /dev/null +++ b/CSP-frontend/src/assets/icons/svgo.yml @@ -0,0 +1,22 @@ +# replace default config + +# multipass: true +# full: true + +plugins: + + # - name + # + # or: + # - name: false + # - name: true + # + # or: + # - name: + # param1: 1 + # param2: 2 + +- removeAttrs: + attrs: + - 'fill' + - 'fill-rule' diff --git a/CSP-frontend/src/assets/images/dark.svg b/CSP-frontend/src/assets/images/dark.svg new file mode 100644 index 0000000000000000000000000000000000000000..f646bd7ea2c452c81afa15ae2e2693cda6ffbc28 --- /dev/null +++ b/CSP-frontend/src/assets/images/dark.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CSP-frontend/src/assets/images/light.svg b/CSP-frontend/src/assets/images/light.svg new file mode 100644 index 0000000000000000000000000000000000000000..ab7cc088fac34b349141bba5eeeed5cf68922667 --- /dev/null +++ b/CSP-frontend/src/assets/images/light.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CSP-frontend/src/assets/images/login-background.jpg b/CSP-frontend/src/assets/images/login-background.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8a89eb8291d5cb7d9f37ec4f275deab911c9e28e Binary files /dev/null and b/CSP-frontend/src/assets/images/login-background.jpg differ diff --git a/CSP-frontend/src/assets/images/pay.png b/CSP-frontend/src/assets/images/pay.png new file mode 100644 index 0000000000000000000000000000000000000000..bb8b9672381a3e4119fcd33e6ddc21973672e273 Binary files /dev/null and b/CSP-frontend/src/assets/images/pay.png differ diff --git a/CSP-frontend/src/assets/images/profile.jpg b/CSP-frontend/src/assets/images/profile.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b3a940b21cc9dcea01e62d94e243eebcf76d96bc Binary files /dev/null and b/CSP-frontend/src/assets/images/profile.jpg differ diff --git a/CSP-frontend/src/assets/logo/logo.png b/CSP-frontend/src/assets/logo/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e26376026420542212ed58d90d0ed34f554fa4ae Binary files /dev/null and b/CSP-frontend/src/assets/logo/logo.png differ diff --git a/CSP-frontend/src/assets/styles/btn.scss b/CSP-frontend/src/assets/styles/btn.scss new file mode 100644 index 0000000000000000000000000000000000000000..e6ba1a8e197532a3435f0d028717b21fc2c30c9f --- /dev/null +++ b/CSP-frontend/src/assets/styles/btn.scss @@ -0,0 +1,99 @@ +@import './variables.scss'; + +@mixin colorBtn($color) { + background: $color; + + &:hover { + color: $color; + + &:before, + &:after { + background: $color; + } + } +} + +.blue-btn { + @include colorBtn($blue) +} + +.light-blue-btn { + @include colorBtn($light-blue) +} + +.red-btn { + @include colorBtn($red) +} + +.pink-btn { + @include colorBtn($pink) +} + +.green-btn { + @include colorBtn($green) +} + +.tiffany-btn { + @include colorBtn($tiffany) +} + +.yellow-btn { + @include colorBtn($yellow) +} + +.pan-btn { + font-size: 14px; + color: #fff; + padding: 14px 36px; + border-radius: 8px; + border: none; + outline: none; + transition: 600ms ease all; + position: relative; + display: inline-block; + + &:hover { + background: #fff; + + &:before, + &:after { + width: 100%; + transition: 600ms ease all; + } + } + + &:before, + &:after { + content: ''; + position: absolute; + top: 0; + right: 0; + height: 2px; + width: 0; + transition: 400ms ease all; + } + + &::after { + right: inherit; + top: inherit; + left: 0; + bottom: 0; + } +} + +.custom-button { + display: inline-block; + line-height: 1; + white-space: nowrap; + cursor: pointer; + background: #fff; + color: #fff; + -webkit-appearance: none; + text-align: center; + box-sizing: border-box; + outline: 0; + margin: 0; + padding: 10px 15px; + font-size: 14px; + border-radius: 4px; +} diff --git a/CSP-frontend/src/assets/styles/element-ui.scss b/CSP-frontend/src/assets/styles/element-ui.scss new file mode 100644 index 0000000000000000000000000000000000000000..363092a63eecc5111160e681b2ced42af8ba30aa --- /dev/null +++ b/CSP-frontend/src/assets/styles/element-ui.scss @@ -0,0 +1,92 @@ +// cover some element-ui styles + +.el-breadcrumb__inner, +.el-breadcrumb__inner a { + font-weight: 400 !important; +} + +.el-upload { + input[type="file"] { + display: none !important; + } +} + +.el-upload__input { + display: none; +} + +.cell { + .el-tag { + margin-right: 0px; + } +} + +.small-padding { + .cell { + padding-left: 5px; + padding-right: 5px; + } +} + +.fixed-width { + .el-button--mini { + padding: 7px 10px; + width: 60px; + } +} + +.status-col { + .cell { + padding: 0 10px; + text-align: center; + + .el-tag { + margin-right: 0px; + } + } +} + +// to fixed https://github.com/ElemeFE/element/issues/2461 +.el-dialog { + transform: none; + left: 0; + position: relative; + margin: 0 auto; +} + +// refine element ui upload +.upload-container { + .el-upload { + width: 100%; + + .el-upload-dragger { + width: 100%; + height: 200px; + } + } +} + +// dropdown +.el-dropdown-menu { + a { + display: block + } +} + +// fix date-picker ui bug in filter-item +.el-range-editor.el-input__inner { + display: inline-flex !important; +} + +// to fix el-date-picker css style +.el-range-separator { + box-sizing: content-box; +} + +.el-menu--collapse + > div + > .el-submenu + > .el-submenu__title + .el-submenu__icon-arrow { + display: none; +} \ No newline at end of file diff --git a/CSP-frontend/src/assets/styles/element-variables.scss b/CSP-frontend/src/assets/styles/element-variables.scss new file mode 100644 index 0000000000000000000000000000000000000000..1615ff28926da47f0ec78487e51dc891a549ae23 --- /dev/null +++ b/CSP-frontend/src/assets/styles/element-variables.scss @@ -0,0 +1,31 @@ +/** +* I think element-ui's default theme color is too light for long-term use. +* So I modified the default color and you can modify it to your liking. +**/ + +/* theme color */ +$--color-primary: #1890ff; +$--color-success: #13ce66; +$--color-warning: #ffba00; +$--color-danger: #ff4949; +// $--color-info: #1E1E1E; + +$--button-font-weight: 400; + +// $--color-text-regular: #1f2d3d; + +$--border-color-light: #dfe4ed; +$--border-color-lighter: #e6ebf5; + +$--table-border: 1px solid #dfe6ec; + +/* icon font path, required */ +$--font-path: '~element-ui/lib/theme-chalk/fonts'; + +@import "~element-ui/packages/theme-chalk/src/index"; + +// the :export directive is the magic sauce for webpack +// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass +:export { + theme: $--color-primary; +} diff --git a/CSP-frontend/src/assets/styles/index.scss b/CSP-frontend/src/assets/styles/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..2f3b9ef9c3d69628cdefc69f63b9ff30a70dddd3 --- /dev/null +++ b/CSP-frontend/src/assets/styles/index.scss @@ -0,0 +1,182 @@ +@import './variables.scss'; +@import './mixin.scss'; +@import './transition.scss'; +@import './element-ui.scss'; +@import './sidebar.scss'; +@import './btn.scss'; + +body { + height: 100%; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; + font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; +} + +label { + font-weight: 700; +} + +html { + height: 100%; + box-sizing: border-box; +} + +#app { + height: 100%; +} + +*, +*:before, +*:after { + box-sizing: inherit; +} + +.no-padding { + padding: 0px !important; +} + +.padding-content { + padding: 4px 0; +} + +a:focus, +a:active { + outline: none; +} + +a, +a:focus, +a:hover { + cursor: pointer; + color: inherit; + text-decoration: none; +} + +div:focus { + outline: none; +} + +.fr { + float: right; +} + +.fl { + float: left; +} + +.pr-5 { + padding-right: 5px; +} + +.pl-5 { + padding-left: 5px; +} + +.block { + display: block; +} + +.pointer { + cursor: pointer; +} + +.inlineBlock { + display: block; +} + +.clearfix { + &:after { + visibility: hidden; + display: block; + font-size: 0; + content: " "; + clear: both; + height: 0; + } +} + +aside { + background: #eef1f6; + padding: 8px 24px; + margin-bottom: 20px; + border-radius: 2px; + display: block; + line-height: 32px; + font-size: 16px; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; + color: #2c3e50; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + a { + color: #337ab7; + cursor: pointer; + + &:hover { + color: rgb(32, 160, 255); + } + } +} + +//main-container全局样式 +.app-container { + padding: 20px; +} + +.components-container { + margin: 30px 50px; + position: relative; +} + +.pagination-container { + margin-top: 30px; +} + +.text-center { + text-align: center +} + +.sub-navbar { + height: 50px; + line-height: 50px; + position: relative; + width: 100%; + text-align: right; + padding-right: 20px; + transition: 600ms ease position; + background: linear-gradient(90deg, rgba(32, 182, 249, 1) 0%, rgba(32, 182, 249, 1) 0%, rgba(33, 120, 241, 1) 100%, rgba(33, 120, 241, 1) 100%); + + .subtitle { + font-size: 20px; + color: #fff; + } + + &.draft { + background: #d0d0d0; + } + + &.deleted { + background: #d0d0d0; + } +} + +.link-type, +.link-type:focus { + color: #337ab7; + cursor: pointer; + + &:hover { + color: rgb(32, 160, 255); + } +} + +.filter-container { + padding-bottom: 10px; + + .filter-item { + display: inline-block; + vertical-align: middle; + margin-bottom: 10px; + } +} diff --git a/CSP-frontend/src/assets/styles/mixin.scss b/CSP-frontend/src/assets/styles/mixin.scss new file mode 100644 index 0000000000000000000000000000000000000000..06fa06125834695b9ca9b679faaf46c574168c46 --- /dev/null +++ b/CSP-frontend/src/assets/styles/mixin.scss @@ -0,0 +1,66 @@ +@mixin clearfix { + &:after { + content: ""; + display: table; + clear: both; + } +} + +@mixin scrollBar { + &::-webkit-scrollbar-track-piece { + background: #d3dce6; + } + + &::-webkit-scrollbar { + width: 6px; + } + + &::-webkit-scrollbar-thumb { + background: #99a9bf; + border-radius: 20px; + } +} + +@mixin relative { + position: relative; + width: 100%; + height: 100%; +} + +@mixin pct($pct) { + width: #{$pct}; + position: relative; + margin: 0 auto; +} + +@mixin triangle($width, $height, $color, $direction) { + $width: $width/2; + $color-border-style: $height solid $color; + $transparent-border-style: $width solid transparent; + height: 0; + width: 0; + + @if $direction==up { + border-bottom: $color-border-style; + border-left: $transparent-border-style; + border-right: $transparent-border-style; + } + + @else if $direction==right { + border-left: $color-border-style; + border-top: $transparent-border-style; + border-bottom: $transparent-border-style; + } + + @else if $direction==down { + border-top: $color-border-style; + border-left: $transparent-border-style; + border-right: $transparent-border-style; + } + + @else if $direction==left { + border-right: $color-border-style; + border-top: $transparent-border-style; + border-bottom: $transparent-border-style; + } +} diff --git a/CSP-frontend/src/assets/styles/ruoyi.scss b/CSP-frontend/src/assets/styles/ruoyi.scss new file mode 100644 index 0000000000000000000000000000000000000000..db8c29bafdab4ba7ab241695db9970d3760530da --- /dev/null +++ b/CSP-frontend/src/assets/styles/ruoyi.scss @@ -0,0 +1,277 @@ + /** + * 通用css样式布局处理 + * Copyright (c) 2019 ruoyi + */ + + /** 基础通用 **/ +.pt5 { + padding-top: 5px; +} +.pr5 { + padding-right: 5px; +} +.pb5 { + padding-bottom: 5px; +} +.mt5 { + margin-top: 5px; +} +.mr5 { + margin-right: 5px; +} +.mb5 { + margin-bottom: 5px; +} +.mb8 { + margin-bottom: 8px; +} +.ml5 { + margin-left: 5px; +} +.mt10 { + margin-top: 10px; +} +.mr10 { + margin-right: 10px; +} +.mb10 { + margin-bottom: 10px; +} +.ml10 { + margin-left: 10px; +} +.mt20 { + margin-top: 20px; +} +.mr20 { + margin-right: 20px; +} +.mb20 { + margin-bottom: 20px; +} +.ml20 { + margin-left: 20px; +} + +.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 { + font-family: inherit; + font-weight: 500; + line-height: 1.1; + color: inherit; +} + +.el-message-box__status + .el-message-box__message{ + word-break: break-word; +} + +.el-dialog:not(.is-fullscreen) { + margin-top: 6vh !important; +} + +.el-dialog__wrapper.scrollbar .el-dialog .el-dialog__body { + overflow: auto; + overflow-x: hidden; + max-height: 70vh; + padding: 10px 20px 0; +} + +.el-table { + .el-table__header-wrapper, .el-table__fixed-header-wrapper { + th { + word-break: break-word; + background-color: #f8f8f9; + color: #515a6e; + height: 40px; + font-size: 13px; + } + } + .el-table__body-wrapper { + .el-button [class*="el-icon-"] + span { + margin-left: 1px; + } + } +} + +/** 表单布局 **/ +.form-header { + font-size:15px; + color:#6379bb; + border-bottom:1px solid #ddd; + margin:8px 10px 25px 10px; + padding-bottom:5px +} + +/** 表格布局 **/ +.pagination-container { + position: relative; + height: 25px; + margin-bottom: 10px; + margin-top: 15px; + padding: 10px 20px !important; +} + +/* tree border */ +.tree-border { + margin-top: 5px; + border: 1px solid #e5e6e7; + background: #FFFFFF none; + border-radius:4px; +} + +.pagination-container .el-pagination { + right: 0; + position: absolute; +} + +@media ( max-width : 768px) { + .pagination-container .el-pagination > .el-pagination__jump { + display: none !important; + } + .pagination-container .el-pagination > .el-pagination__sizes { + display: none !important; + } +} + +.el-table .fixed-width .el-button--mini { + padding-left: 0; + padding-right: 0; + width: inherit; +} + +/** 表格更多操作下拉样式 */ +.el-table .el-dropdown-link,.el-table .el-dropdown-selfdefine { + cursor: pointer; + margin-left: 5px; +} + +.el-table .el-dropdown, .el-icon-arrow-down { + font-size: 12px; +} + +.el-tree-node__content > .el-checkbox { + margin-right: 8px; +} + +.list-group-striped > .list-group-item { + border-left: 0; + border-right: 0; + border-radius: 0; + padding-left: 0; + padding-right: 0; +} + +.list-group { + padding-left: 0px; + list-style: none; +} + +.list-group-item { + border-bottom: 1px solid #e7eaec; + border-top: 1px solid #e7eaec; + margin-bottom: -1px; + padding: 11px 0px; + font-size: 13px; +} + +.pull-right { + float: right !important; +} + +.el-card__header { + padding: 14px 15px 7px; + min-height: 40px; +} + +.el-card__body { + padding: 15px 20px 20px 20px; +} + +.card-box { + padding-right: 15px; + padding-left: 15px; + margin-bottom: 10px; +} + +/* button color */ +.el-button--cyan.is-active, +.el-button--cyan:active { + background: #20B2AA; + border-color: #20B2AA; + color: #FFFFFF; +} + +.el-button--cyan:focus, +.el-button--cyan:hover { + background: #48D1CC; + border-color: #48D1CC; + color: #FFFFFF; +} + +.el-button--cyan { + background-color: #20B2AA; + border-color: #20B2AA; + color: #FFFFFF; +} + +/* text color */ +.text-navy { + color: #1ab394; +} + +.text-primary { + color: inherit; +} + +.text-success { + color: #1c84c6; +} + +.text-info { + color: #23c6c8; +} + +.text-warning { + color: #f8ac59; +} + +.text-danger { + color: #ed5565; +} + +.text-muted { + color: #888888; +} + +/* image */ +.img-circle { + border-radius: 50%; +} + +.img-lg { + width: 120px; + height: 120px; +} + +.avatar-upload-preview { + position: relative; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 200px; + height: 200px; + border-radius: 50%; + box-shadow: 0 0 4px #ccc; + overflow: hidden; +} + +/* 拖拽列样式 */ +.sortable-ghost{ + opacity: .8; + color: #fff!important; + background: #42b983!important; +} + +.top-right-btn { + position: relative; + float: right; +} diff --git a/CSP-frontend/src/assets/styles/sidebar.scss b/CSP-frontend/src/assets/styles/sidebar.scss new file mode 100644 index 0000000000000000000000000000000000000000..abe5b6317741f27c5541591db83487798721bc72 --- /dev/null +++ b/CSP-frontend/src/assets/styles/sidebar.scss @@ -0,0 +1,227 @@ +#app { + + .main-container { + height: 100%; + transition: margin-left .28s; + margin-left: $base-sidebar-width; + position: relative; + } + + .sidebarHide { + margin-left: 0!important; + } + + .sidebar-container { + -webkit-transition: width .28s; + transition: width 0.28s; + width: $base-sidebar-width !important; + background-color: $base-menu-background; + height: 100%; + position: fixed; + font-size: 0px; + top: 0; + bottom: 0; + left: 0; + z-index: 1001; + overflow: hidden; + -webkit-box-shadow: 2px 0 6px rgba(0,21,41,.35); + box-shadow: 2px 0 6px rgba(0,21,41,.35); + + // reset element-ui css + .horizontal-collapse-transition { + transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out; + } + + .scrollbar-wrapper { + overflow-x: hidden !important; + } + + .el-scrollbar__bar.is-vertical { + right: 0px; + } + + .el-scrollbar { + height: 100%; + } + + &.has-logo { + .el-scrollbar { + height: calc(100% - 50px); + } + } + + .is-horizontal { + display: none; + } + + a { + display: inline-block; + width: 100%; + overflow: hidden; + } + + .svg-icon { + margin-right: 16px; + } + + .el-menu { + border: none; + height: 100%; + width: 100% !important; + } + + .el-menu-item, .el-submenu__title { + overflow: hidden !important; + text-overflow: ellipsis !important; + white-space: nowrap !important; + } + + // menu hover + .submenu-title-noDropdown, + .el-submenu__title { + &:hover { + background-color: rgba(0, 0, 0, 0.06) !important; + } + } + + & .theme-dark .is-active > .el-submenu__title { + color: $base-menu-color-active !important; + } + + & .nest-menu .el-submenu>.el-submenu__title, + & .el-submenu .el-menu-item { + min-width: $base-sidebar-width !important; + + &:hover { + background-color: rgba(0, 0, 0, 0.06) !important; + } + } + + & .theme-dark .nest-menu .el-submenu>.el-submenu__title, + & .theme-dark .el-submenu .el-menu-item { + background-color: $base-sub-menu-background !important; + + &:hover { + background-color: $base-sub-menu-hover !important; + } + } + } + + .hideSidebar { + .sidebar-container { + width: 54px !important; + } + + .main-container { + margin-left: 54px; + } + + .submenu-title-noDropdown { + padding: 0 !important; + position: relative; + + .el-tooltip { + padding: 0 !important; + + .svg-icon { + margin-left: 20px; + } + } + } + + .el-submenu { + overflow: hidden; + + &>.el-submenu__title { + padding: 0 !important; + + .svg-icon { + margin-left: 20px; + } + + } + } + + .el-menu--collapse { + .el-submenu { + &>.el-submenu__title { + &>span { + height: 0; + width: 0; + overflow: hidden; + visibility: hidden; + display: inline-block; + } + } + } + } + } + + .el-menu--collapse .el-menu .el-submenu { + min-width: $base-sidebar-width !important; + } + + // mobile responsive + .mobile { + .main-container { + margin-left: 0px; + } + + .sidebar-container { + transition: transform .28s; + width: $base-sidebar-width !important; + } + + &.hideSidebar { + .sidebar-container { + pointer-events: none; + transition-duration: 0.3s; + transform: translate3d(-$base-sidebar-width, 0, 0); + } + } + } + + .withoutAnimation { + + .main-container, + .sidebar-container { + transition: none; + } + } +} + +// when menu collapsed +.el-menu--vertical { + &>.el-menu { + .svg-icon { + margin-right: 16px; + } + } + + .nest-menu .el-submenu>.el-submenu__title, + .el-menu-item { + &:hover { + // you can use $subMenuHover + background-color: rgba(0, 0, 0, 0.06) !important; + } + } + + // the scroll bar appears when the subMenu is too long + >.el-menu--popup { + max-height: 100vh; + overflow-y: auto; + + &::-webkit-scrollbar-track-piece { + background: #d3dce6; + } + + &::-webkit-scrollbar { + width: 6px; + } + + &::-webkit-scrollbar-thumb { + background: #99a9bf; + border-radius: 20px; + } + } +} diff --git a/CSP-frontend/src/assets/styles/transition.scss b/CSP-frontend/src/assets/styles/transition.scss new file mode 100644 index 0000000000000000000000000000000000000000..073f8c6ce27c63240f6cf1e832ead8b8bc91d8c6 --- /dev/null +++ b/CSP-frontend/src/assets/styles/transition.scss @@ -0,0 +1,49 @@ +// global transition css + +/* fade */ +.fade-enter-active, +.fade-leave-active { + transition: opacity 0.28s; +} + +.fade-enter, +.fade-leave-active { + opacity: 0; +} + +/* fade-transform */ +.fade-transform--move, +.fade-transform-leave-active, +.fade-transform-enter-active { + transition: all .5s; +} + +.fade-transform-enter { + opacity: 0; + transform: translateX(-30px); +} + +.fade-transform-leave-to { + opacity: 0; + transform: translateX(30px); +} + +/* breadcrumb transition */ +.breadcrumb-enter-active, +.breadcrumb-leave-active { + transition: all .5s; +} + +.breadcrumb-enter, +.breadcrumb-leave-active { + opacity: 0; + transform: translateX(20px); +} + +.breadcrumb-move { + transition: all .5s; +} + +.breadcrumb-leave-active { + position: absolute; +} diff --git a/CSP-frontend/src/assets/styles/variables.scss b/CSP-frontend/src/assets/styles/variables.scss new file mode 100644 index 0000000000000000000000000000000000000000..34484d47efc492182bd2c29331b90d1d1810524b --- /dev/null +++ b/CSP-frontend/src/assets/styles/variables.scss @@ -0,0 +1,54 @@ +// base color +$blue:#324157; +$light-blue:#3A71A8; +$red:#C03639; +$pink: #E65D6E; +$green: #30B08F; +$tiffany: #4AB7BD; +$yellow:#FEC171; +$panGreen: #30B08F; + +// 默认菜单主题风格 +$base-menu-color:#bfcbd9; +$base-menu-color-active:#f4f4f5; +$base-menu-background:#304156; +$base-logo-title-color: #ffffff; + +$base-menu-light-color:rgba(0,0,0,.70); +$base-menu-light-background:#ffffff; +$base-logo-light-title-color: #001529; + +$base-sub-menu-background:#1f2d3d; +$base-sub-menu-hover:#001528; + +// 自定义暗色菜单风格 +/** +$base-menu-color:hsla(0,0%,100%,.65); +$base-menu-color-active:#fff; +$base-menu-background:#001529; +$base-logo-title-color: #ffffff; + +$base-menu-light-color:rgba(0,0,0,.70); +$base-menu-light-background:#ffffff; +$base-logo-light-title-color: #001529; + +$base-sub-menu-background:#000c17; +$base-sub-menu-hover:#001528; +*/ + +$base-sidebar-width: 200px; + +// the :export directive is the magic sauce for webpack +// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass +:export { + menuColor: $base-menu-color; + menuLightColor: $base-menu-light-color; + menuColorActive: $base-menu-color-active; + menuBackground: $base-menu-background; + menuLightBackground: $base-menu-light-background; + subMenuBackground: $base-sub-menu-background; + subMenuHover: $base-sub-menu-hover; + sideBarWidth: $base-sidebar-width; + logoTitleColor: $base-logo-title-color; + logoLightTitleColor: $base-logo-light-title-color +} diff --git a/CSP-frontend/src/components/Breadcrumb/index.vue b/CSP-frontend/src/components/Breadcrumb/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..1696f54719db39bc2ace0cfde2cbb0183ec91745 --- /dev/null +++ b/CSP-frontend/src/components/Breadcrumb/index.vue @@ -0,0 +1,74 @@ + + + + + diff --git a/CSP-frontend/src/components/CSP/Doc/index.vue b/CSP-frontend/src/components/CSP/Doc/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..f6589f207d12fc6abdc4d6031fb1a4ece63e22da --- /dev/null +++ b/CSP-frontend/src/components/CSP/Doc/index.vue @@ -0,0 +1,21 @@ + + + diff --git a/CSP-frontend/src/components/CSP/Git/index.vue b/CSP-frontend/src/components/CSP/Git/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..7b6a9fae4786336a1998f770a6d83c8a58b58115 --- /dev/null +++ b/CSP-frontend/src/components/CSP/Git/index.vue @@ -0,0 +1,21 @@ + + + diff --git a/CSP-frontend/src/components/Crontab/day.vue b/CSP-frontend/src/components/Crontab/day.vue new file mode 100644 index 0000000000000000000000000000000000000000..fe3eaf0c4c70baa744767649e3e51f1f06fc9f6e --- /dev/null +++ b/CSP-frontend/src/components/Crontab/day.vue @@ -0,0 +1,161 @@ + + + diff --git a/CSP-frontend/src/components/Crontab/hour.vue b/CSP-frontend/src/components/Crontab/hour.vue new file mode 100644 index 0000000000000000000000000000000000000000..4b1f1fcdb3705554e6844c7cdf0a572f3f247fd2 --- /dev/null +++ b/CSP-frontend/src/components/Crontab/hour.vue @@ -0,0 +1,114 @@ + + + diff --git a/CSP-frontend/src/components/Crontab/index.vue b/CSP-frontend/src/components/Crontab/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..3963df28e6dd733e02b73a7d72ddbc146db67f5f --- /dev/null +++ b/CSP-frontend/src/components/Crontab/index.vue @@ -0,0 +1,430 @@ + + + + diff --git a/CSP-frontend/src/components/Crontab/min.vue b/CSP-frontend/src/components/Crontab/min.vue new file mode 100644 index 0000000000000000000000000000000000000000..43cab900d338e2f3c400ef8168d5140e309f65cb --- /dev/null +++ b/CSP-frontend/src/components/Crontab/min.vue @@ -0,0 +1,116 @@ + + + \ No newline at end of file diff --git a/CSP-frontend/src/components/Crontab/month.vue b/CSP-frontend/src/components/Crontab/month.vue new file mode 100644 index 0000000000000000000000000000000000000000..fd0ac384fbe2667e20c5975dd536189ece0ecbbb --- /dev/null +++ b/CSP-frontend/src/components/Crontab/month.vue @@ -0,0 +1,114 @@ + + + diff --git a/CSP-frontend/src/components/Crontab/result.vue b/CSP-frontend/src/components/Crontab/result.vue new file mode 100644 index 0000000000000000000000000000000000000000..aea6e0e46130d1ee694e44596c4b11dbd44cc292 --- /dev/null +++ b/CSP-frontend/src/components/Crontab/result.vue @@ -0,0 +1,559 @@ + + + diff --git a/CSP-frontend/src/components/Crontab/second.vue b/CSP-frontend/src/components/Crontab/second.vue new file mode 100644 index 0000000000000000000000000000000000000000..e7b776171d4509d1d5118d418de4e51a134b9350 --- /dev/null +++ b/CSP-frontend/src/components/Crontab/second.vue @@ -0,0 +1,117 @@ + + + diff --git a/CSP-frontend/src/components/Crontab/week.vue b/CSP-frontend/src/components/Crontab/week.vue new file mode 100644 index 0000000000000000000000000000000000000000..1cec700e8ba89f396b909f78e04d34b0a5fa4ab2 --- /dev/null +++ b/CSP-frontend/src/components/Crontab/week.vue @@ -0,0 +1,202 @@ + + + diff --git a/CSP-frontend/src/components/Crontab/year.vue b/CSP-frontend/src/components/Crontab/year.vue new file mode 100644 index 0000000000000000000000000000000000000000..5487a6c7fde04ebde11b8c45d0b3bd151501d311 --- /dev/null +++ b/CSP-frontend/src/components/Crontab/year.vue @@ -0,0 +1,131 @@ + + + diff --git a/CSP-frontend/src/components/DictData/index.js b/CSP-frontend/src/components/DictData/index.js new file mode 100644 index 0000000000000000000000000000000000000000..7b85d4aaa3fec01f1210c0757629b428957524d9 --- /dev/null +++ b/CSP-frontend/src/components/DictData/index.js @@ -0,0 +1,49 @@ +import Vue from 'vue' +import store from '@/store' +import DataDict from '@/utils/dict' +import { getDicts as getDicts } from '@/api/system/dict/data' + +function searchDictByKey(dict, key) { + if (key == null && key == "") { + return null + } + try { + for (let i = 0; i < dict.length; i++) { + if (dict[i].key == key) { + return dict[i].value + } + } + } catch (e) { + return null + } +} + +function install() { + Vue.use(DataDict, { + metas: { + '*': { + labelField: 'dictLabel', + valueField: 'dictValue', + request(dictMeta) { + const storeDict = searchDictByKey(store.getters.dict, dictMeta.type) + if (storeDict) { + return new Promise(resolve => { resolve(storeDict) }) + } else { + return new Promise((resolve, reject) => { + getDicts(dictMeta.type).then(res => { + store.dispatch('dict/setDict', { key: dictMeta.type, value: res.data }) + resolve(res.data) + }).catch(error => { + reject(error) + }) + }) + } + }, + }, + }, + }) +} + +export default { + install, +} \ No newline at end of file diff --git a/CSP-frontend/src/components/DictTag/index.vue b/CSP-frontend/src/components/DictTag/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..a0fd66f3b1e4da5f96ac960577ee7e186c9abfa1 --- /dev/null +++ b/CSP-frontend/src/components/DictTag/index.vue @@ -0,0 +1,92 @@ + + + + diff --git a/CSP-frontend/src/components/Editor/index.vue b/CSP-frontend/src/components/Editor/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..6bb5a18d37010bfad15b2fa9ada3f8329f33122e --- /dev/null +++ b/CSP-frontend/src/components/Editor/index.vue @@ -0,0 +1,272 @@ + + + + + diff --git a/CSP-frontend/src/components/FileUpload/index.vue b/CSP-frontend/src/components/FileUpload/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..6c583cf9d77c7147df9ba1072c9cca846acc1cad --- /dev/null +++ b/CSP-frontend/src/components/FileUpload/index.vue @@ -0,0 +1,215 @@ + + + + + diff --git a/CSP-frontend/src/components/Hamburger/index.vue b/CSP-frontend/src/components/Hamburger/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..368b002154ef7dfb2625e15a43d2ad264bfa040c --- /dev/null +++ b/CSP-frontend/src/components/Hamburger/index.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/CSP-frontend/src/components/HeaderSearch/index.vue b/CSP-frontend/src/components/HeaderSearch/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..c4d76bbb96127de86292609a553bd33c2bc02aee --- /dev/null +++ b/CSP-frontend/src/components/HeaderSearch/index.vue @@ -0,0 +1,189 @@ + + + + + diff --git a/CSP-frontend/src/components/IconSelect/index.vue b/CSP-frontend/src/components/IconSelect/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..8dadc028ab3e33f114fd9dbda60f016f74eb487d --- /dev/null +++ b/CSP-frontend/src/components/IconSelect/index.vue @@ -0,0 +1,104 @@ + + + + + + diff --git a/CSP-frontend/src/components/IconSelect/requireIcons.js b/CSP-frontend/src/components/IconSelect/requireIcons.js new file mode 100644 index 0000000000000000000000000000000000000000..99e5c54cc7fd824e01a5e6acf3d311d2fb97fe5f --- /dev/null +++ b/CSP-frontend/src/components/IconSelect/requireIcons.js @@ -0,0 +1,11 @@ + +const req = require.context('../../assets/icons/svg', false, /\.svg$/) +const requireAll = requireContext => requireContext.keys() + +const re = /\.\/(.*)\.svg/ + +const icons = requireAll(req).map(i => { + return i.match(re)[1] +}) + +export default icons diff --git a/CSP-frontend/src/components/ImagePreview/index.vue b/CSP-frontend/src/components/ImagePreview/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..3c770c70370cf97d272ddb1c2814c8075fc881e6 --- /dev/null +++ b/CSP-frontend/src/components/ImagePreview/index.vue @@ -0,0 +1,90 @@ + + + + + diff --git a/CSP-frontend/src/components/ImageUpload/index.vue b/CSP-frontend/src/components/ImageUpload/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..b57a15e7ba4cd7ff3a8d57295708e38eb44e4b49 --- /dev/null +++ b/CSP-frontend/src/components/ImageUpload/index.vue @@ -0,0 +1,226 @@ + + + + + diff --git a/CSP-frontend/src/components/Pagination/index.vue b/CSP-frontend/src/components/Pagination/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..56f5a6b9da18e6b5f9361a08ccf99caf87f6fd5c --- /dev/null +++ b/CSP-frontend/src/components/Pagination/index.vue @@ -0,0 +1,114 @@ + + + + + diff --git a/CSP-frontend/src/components/PanThumb/index.vue b/CSP-frontend/src/components/PanThumb/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..1bcf41709c2dbe47a053530b78dc945411765670 --- /dev/null +++ b/CSP-frontend/src/components/PanThumb/index.vue @@ -0,0 +1,142 @@ + + + + + diff --git a/CSP-frontend/src/components/ParentView/index.vue b/CSP-frontend/src/components/ParentView/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..7bf614897817801459ca0a2ec2abf5b2b7403d02 --- /dev/null +++ b/CSP-frontend/src/components/ParentView/index.vue @@ -0,0 +1,3 @@ + diff --git a/CSP-frontend/src/components/RightPanel/index.vue b/CSP-frontend/src/components/RightPanel/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..5abeecb006bde634ab7c2097f613c1acfc9bf7e5 --- /dev/null +++ b/CSP-frontend/src/components/RightPanel/index.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/CSP-frontend/src/components/RightToolbar/index.vue b/CSP-frontend/src/components/RightToolbar/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..527e07c174bebafc5f2617b038c915c5aeb56c9a --- /dev/null +++ b/CSP-frontend/src/components/RightToolbar/index.vue @@ -0,0 +1,104 @@ + + + diff --git a/CSP-frontend/src/components/Screenfull/index.vue b/CSP-frontend/src/components/Screenfull/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..d4e539c26a2843d26b60b56c5ecf1c8680073eb0 --- /dev/null +++ b/CSP-frontend/src/components/Screenfull/index.vue @@ -0,0 +1,57 @@ + + + + + diff --git a/CSP-frontend/src/components/SizeSelect/index.vue b/CSP-frontend/src/components/SizeSelect/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..069b5de9b8c6c0b5a7df931a315de576fa030193 --- /dev/null +++ b/CSP-frontend/src/components/SizeSelect/index.vue @@ -0,0 +1,56 @@ + + + diff --git a/CSP-frontend/src/components/SvgIcon/index.vue b/CSP-frontend/src/components/SvgIcon/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..e4bf5ade1d877f716cbdc1026eade627963635ed --- /dev/null +++ b/CSP-frontend/src/components/SvgIcon/index.vue @@ -0,0 +1,61 @@ + + + + + diff --git a/CSP-frontend/src/components/ThemePicker/index.vue b/CSP-frontend/src/components/ThemePicker/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..1714e1f391e72233b0c87fbb5a02956280dabf2f --- /dev/null +++ b/CSP-frontend/src/components/ThemePicker/index.vue @@ -0,0 +1,173 @@ + + + + + diff --git a/CSP-frontend/src/components/TopNav/index.vue b/CSP-frontend/src/components/TopNav/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..9fb8dd81d5f7eb7799c6b450d22687ca877e7ca6 --- /dev/null +++ b/CSP-frontend/src/components/TopNav/index.vue @@ -0,0 +1,191 @@ + + + + + diff --git a/CSP-frontend/src/components/XmlEditor/index.vue b/CSP-frontend/src/components/XmlEditor/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..1f4c69a959fc47139a32f96e9e929f1796478437 --- /dev/null +++ b/CSP-frontend/src/components/XmlEditor/index.vue @@ -0,0 +1,79 @@ +