diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dbbf18a --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +*.java.hsp +*.sonarj +*.sw* +.DS_Store +.settings +.springBeans +bin +build.sh +integration-repo +ivy-cache +jxl.log +jmx.log +derby.log +spring-test/test-output/ +.gradle +argfile* +activemq-data/ + +classes/ +/build +buildSrc/build +/spring-*/build +/src/asciidoc/build +target/ + +# Projects not in this branch +integration-tests/ +spring-core/kotlin-coroutines/ + +# Eclipse artifacts, including WTP generated manifests +.classpath +.project +spring-*/src/main/java/META-INF/MANIFEST.MF + +# IDEA artifacts and output dirs +*.iml +*.ipr +*.iws +.idea +out +test-output +atlassian-ide-plugin.xml +.gradletasknamecache diff --git a/README.en.md b/README.en.md new file mode 100644 index 0000000..9e3ae76 --- /dev/null +++ b/README.en.md @@ -0,0 +1,36 @@ +# nladmin + +#### Description +{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**} + +#### Software Architecture +Software architecture description + +#### Installation + +1. xxxx +2. xxxx +3. xxxx + +#### Instructions + +1. xxxx +2. xxxx +3. xxxx + +#### Contribution + +1. Fork the repository +2. Create Feat_xxx branch +3. Commit your code +4. Create Pull Request + + +#### Gitee Feature + +1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md +2. Gitee blog [blog.gitee.com](https://blog.gitee.com) +3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) +4. The most valuable open source project [GVP](https://gitee.com/gvp) +5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) +6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README.md b/README.md index 8b58040..54cc8de 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,2 @@ # jt_agv -集团agv点对点项目 \ No newline at end of file diff --git a/nladmin-system/pom.xml b/nladmin-system/pom.xml new file mode 100644 index 0000000..4ff25e8 --- /dev/null +++ b/nladmin-system/pom.xml @@ -0,0 +1,258 @@ + + + + jt_agv + org.nl + 1.0-SNAPSHOT + + 4.0.0 + + nladmin-system + 核心模块 + + + 0.11.1 + + 5.5.0 + 7.6.1 + + + + + edu.brown.cs.burlap + java_rosbridge + 2.0.1 + + + + edu.wpi.rail + jrosbridge + 0.2.0 + + + + org.reflections + reflections + 0.9.10 + + + + org.springframework.boot + spring-boot-starter-data-elasticsearch + + + org.elasticsearch + jna + + + + + com.squareup.okhttp3 + okhttp + 4.8.1 + + + + + org.apache.lucene + lucene-core + 8.4.0 + + + org.apache.lucene + lucene-analyzers-common + 8.4.0 + + + org.apache.lucene + lucene-analyzers-smartcn + 8.4.0 + + + + + com.alibaba + easyexcel + 2.2.6 + + + + + org.apache.commons + commons-csv + 1.8 + + + commons-io + commons-io + 2.8.0 + + + + + org.nl + nladmin-generator + 2.6 + + + org.nl + nladmin-common + + + + + + + + + + org.nl + nladmin-tools + 2.6 + + + bcprov-jdk15on + org.bouncycastle + + + + + + + org.springframework.boot + spring-boot-starter-websocket + + + + + io.jsonwebtoken + jjwt-api + ${jjwt.version} + + + io.jsonwebtoken + jjwt-impl + ${jjwt.version} + + + io.jsonwebtoken + jjwt-jackson + ${jjwt.version} + + + + + org.quartz-scheduler + quartz + + + + + ch.ethz.ganymed + ganymed-ssh2 + build210 + + + com.jcraft + jsch + 0.1.55 + + + + + com.github.oshi + oshi-core + 5.0.1 + + + + org.nl + nladmin-wql + 2.6 + + + commons-lang + commons-lang + + + + + com.google.guava + guava + 20.0 + compile + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.nl.AppRun + + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + + + + + + + + ${basedir}/src/main/java + + **/*.* + + + + ${basedir}/src/main/resources + + **/*.* + + + + + + + + + + + + + diff --git a/nladmin-system/src/main/java/org/nl/AppRun.java b/nladmin-system/src/main/java/org/nl/AppRun.java new file mode 100644 index 0000000..6db3e94 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/AppRun.java @@ -0,0 +1,61 @@ +package org.nl; + +import io.swagger.annotations.Api; +import org.nl.annotation.rest.AnonymousGetMapping; +import org.nl.utils.SpringContextHolder; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; +import org.springframework.boot.web.servlet.ServletComponentScan; +import org.springframework.boot.web.servlet.server.ServletWebServerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.web.bind.annotation.RestController; + +/** + * 开启审计功能 -> @EnableJpaAuditing + * https://www.cnblogs.com/niceyoo/p/10908647.html + * + * @author ldjun + * @date 2021/2/22 9:20:19 + */ +@EnableAsync +@RestController +@Api(hidden = true) +@SpringBootApplication(exclude = { + org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class +}) +@ServletComponentScan +@EnableTransactionManagement +@EnableJpaAuditing(auditorAwareRef = "auditorAware") +public class AppRun { + + public static void main(String[] args) { + SpringApplication.run(AppRun.class, args); + } + + @Bean + public SpringContextHolder springContextHolder() { + return new SpringContextHolder(); + } + + @Bean + public ServletWebServerFactory webServerFactory() { + TomcatServletWebServerFactory fa = new TomcatServletWebServerFactory(); + fa.addConnectorCustomizers(connector -> connector.setProperty("relaxedQueryChars", "[]{}")); + return fa; + } + + /** + * 访问首页提示 + * + * @return / + */ + @AnonymousGetMapping("/") + public String index() { + return "Backend service started successfully"; + } +} + diff --git a/nladmin-system/src/main/java/org/nl/agv/TaskSendBackStatusEnum.java b/nladmin-system/src/main/java/org/nl/agv/TaskSendBackStatusEnum.java new file mode 100644 index 0000000..058f35c --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/agv/TaskSendBackStatusEnum.java @@ -0,0 +1,47 @@ +package org.nl.agv; + +/** + * 0 "发送成功" + * -1 "无法找到起点" + * -2 "无法规划路径" + * -3 "无法导出任务" + * -4 "无法搜索PathID" + * -100 "未知异常" + * -200 "手动状态,显示屏无法控制" + * -201 "固定流程使能,无法采用显示屏控制" + * -202 "上位机调度使能,无法采用显示屏控制" + * -203 "任务正在执行,无法下达新任务" + * -204 "任务包非空,无法下达新任务" + */ +enum TaskTypeEnum { + C0(0, "0", "发送成功"), + C1(-1, "-1", "无法找到起点"), + C2(-2, "-2", "无法规划路径"), + C3(-3, "-3", "无法导出任务"), + C4(-4, "-4", "无法搜索PathID"), + C100(-100, "-100", "未知异常"), + C200(-200, "-200", "手动状态,显示屏无法控制"), + C201(-201, "-201", "固定流程使能,无法采用显示屏控制"), + C202(-202, "-202", "上位机调度使能,无法采用显示屏控制"), + C203(-203, "-203", "任务正在执行,无法下达新任务"), + C204(-204, "-204", "任务包非空,无法下达新任务"); + + private int index; + private String code; + private String name; + + public String getCode() { + return code; + } + + public String getName() { + return name; + } + + TaskTypeEnum(int index, String code, String name) { + this.index = index; + this.code = code; + this.name = name; + } + +} diff --git a/nladmin-system/src/main/java/org/nl/agv/enu/TaskSendBackStatusEnum.java b/nladmin-system/src/main/java/org/nl/agv/enu/TaskSendBackStatusEnum.java new file mode 100644 index 0000000..948a0ec --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/agv/enu/TaskSendBackStatusEnum.java @@ -0,0 +1,59 @@ +package org.nl.agv.enu; + +/** + * 0 "发送成功" + * -1 "无法找到起点" + * -2 "无法规划路径" + * -3 "无法导出任务" + * -4 "无法搜索PathID" + * -100 "未知异常" + * -200 "手动状态,显示屏无法控制" + * -201 "固定流程使能,无法采用显示屏控制" + * -202 "上位机调度使能,无法采用显示屏控制" + * -203 "任务正在执行,无法下达新任务" + * -204 "任务包非空,无法下达新任务" + */ + +/** + * 任务下发时候反馈的状态码 + */ +public enum TaskSendBackStatusEnum { + C0(0, "0", "发送成功"), + C1(-1, "-1", "无法找到起点"), + C2(-2, "-2", "无法规划路径"), + C3(-3, "-3", "无法导出任务"), + C4(-4, "-4", "无法搜索PathID"), + C100(-100, "-100", "未知异常"), + C200(-200, "-200", "手动状态,显示屏无法控制"), + C201(-201, "-201", "固定流程使能,无法采用显示屏控制"), + C202(-202, "-202", "上位机调度使能,无法采用显示屏控制"), + C203(-203, "-203", "任务正在执行,无法下达新任务"), + C204(-204, "-204", "任务包非空,无法下达新任务"); + + private int index; + private String code; + private String name; + + public String getCode() { + return code; + } + + public String getName() { + return name; + } + + TaskSendBackStatusEnum(int index, String code, String name) { + this.index = index; + this.code = code; + this.name = name; + } + + public static String getName(String code) { + for (TaskSendBackStatusEnum ietm : TaskSendBackStatusEnum.values()) { + if (ietm.getCode().equals(code)) { + return ietm.getName(); + } + } + return "未知错误"; + } +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/agv/rest/DeveloperController.java b/nladmin-system/src/main/java/org/nl/agv/rest/DeveloperController.java new file mode 100644 index 0000000..70cf516 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/agv/rest/DeveloperController.java @@ -0,0 +1,92 @@ +package org.nl.agv.rest; + + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.nl.agv.service.DevelopService; +import org.nl.annotation.Log; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +/** + * @author ldjun + * @date 2021-07-26 + **/ +@RestController +@RequiredArgsConstructor +@Api(tags = "AGV开发者选项") +@RequestMapping("/api/developer") +@Slf4j +public class DeveloperController { + + private final DevelopService developService; + + @PostMapping("/getIP") + @Log("开发者选项查询Ifconfig参数") + @ApiOperation("开发者选项查询Ifconfig参数") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity getIP(@RequestBody Map whereJson) { + return new ResponseEntity<>(developService.getIP(whereJson), HttpStatus.OK); + } + @PostMapping("/getLogList") + @Log("开发者选项查询日志列表") + @ApiOperation("开发者选项查询日志列表") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity getLogList(@RequestBody Map whereJson) { + return new ResponseEntity<>(developService.getLogList(whereJson), HttpStatus.OK); + } + @PostMapping("/getROSNodeList") + @Log("开发者选项查询ros请求列表") + @ApiOperation("开发者选项查询ros请求列表") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity getROSNodeList(@RequestBody Map whereJson) { + return new ResponseEntity<>(developService.getROSNodeList(whereJson), HttpStatus.OK); + } + + @PostMapping("/temperature") + @Log("开发者选项查询芯片温度") + @ApiOperation("开发者选项查询芯片温度") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity temperature(@RequestBody Map whereJson) { + return new ResponseEntity<>(developService.temperature(whereJson), HttpStatus.OK); + } + + @PostMapping("/debugInfo") + @Log("开发者选项查询调试信息") + @ApiOperation("开发者选项查询调试信息") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity debugInfo(@RequestBody Map whereJson) { + return new ResponseEntity<>(developService.debugInfo(whereJson), HttpStatus.OK); + } + + @PostMapping("/parameterSetting") + @Log("开发者选项系统参数设置") + @ApiOperation("开发者选项系统参数设置") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity parameterSetting(@RequestBody Map whereJson) { + return new ResponseEntity<>(developService.parameterSetting(whereJson), HttpStatus.OK); + } + @PostMapping("/queryPassword") + @Log("查询密码") + @ApiOperation("查询密码") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity queryPassword(@RequestBody Map whereJson) { + return new ResponseEntity<>(developService.queryPassword(whereJson), HttpStatus.OK); + } + @PostMapping("/softwareVersion") + @Log("查询软硬件版本") + @ApiOperation("查询软硬件版本") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity softwareVersion(@RequestBody Map whereJson) { + return new ResponseEntity<>(developService.softwareVersion(whereJson), HttpStatus.OK); + } + +} diff --git a/nladmin-system/src/main/java/org/nl/agv/rest/ErrorController.java b/nladmin-system/src/main/java/org/nl/agv/rest/ErrorController.java new file mode 100644 index 0000000..1e59d4a --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/agv/rest/ErrorController.java @@ -0,0 +1,40 @@ +package org.nl.agv.rest; + + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.nl.agv.service.ErrorService; +import org.nl.agv.service.TaskService; +import org.nl.annotation.Log; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +/** + * @author qinx + * @date 2021-07-26 + **/ +@RestController +@RequiredArgsConstructor +@Api(tags = "AGV故障管理") +@RequestMapping("/api/error") +@Slf4j +public class ErrorController { + + private final ErrorService errorService; + + @PostMapping("/querryError") + @Log("") + @ApiOperation("查询故障信息") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity querryError(@RequestBody Map whereJson) { + return new ResponseEntity<>(errorService.querryError(whereJson), HttpStatus.OK); + } +} diff --git a/nladmin-system/src/main/java/org/nl/agv/rest/HomeController.java b/nladmin-system/src/main/java/org/nl/agv/rest/HomeController.java new file mode 100644 index 0000000..e2971f7 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/agv/rest/HomeController.java @@ -0,0 +1,54 @@ +package org.nl.agv.rest; + + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.nl.agv.service.HomeService; +import org.nl.annotation.Log; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +/** + * @author qinx + * @date 2021-07-26 + **/ +@RestController +@RequiredArgsConstructor +@Api(tags = "AGV任务管理") +@RequestMapping("/api/home") +@Slf4j +public class HomeController { + + private final HomeService homeService; + + @PostMapping("/queryHead") + @Log("查询头部") + @ApiOperation("查询头部") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity queryHead(@RequestBody Map whereJson) { + return new ResponseEntity<>(homeService.queryHead(whereJson), HttpStatus.OK); + } + @PostMapping("/queryHomePage") + @Log("查询首页") + @ApiOperation("查询首页") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity queryHomePage(@RequestBody Map whereJson) { + return new ResponseEntity<>(homeService.queryHomePage(whereJson), HttpStatus.OK); + } + @PostMapping("/clickSave") + @Log("首页确定按钮") + @ApiOperation("首页确定按钮") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity clickSave(@RequestBody Map whereJson) { + return new ResponseEntity<>(homeService.clickSave(whereJson), HttpStatus.OK); + } + +} diff --git a/nladmin-system/src/main/java/org/nl/agv/rest/TaskController.java b/nladmin-system/src/main/java/org/nl/agv/rest/TaskController.java new file mode 100644 index 0000000..243cc33 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/agv/rest/TaskController.java @@ -0,0 +1,77 @@ +package org.nl.agv.rest; + + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.sf.json.JSONArray; +import org.nl.agv.service.DevelopService; +import org.nl.agv.service.TaskService; +import org.nl.annotation.Log; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +/** + * @author qinx + * @date 2021-07-26 + **/ +@RestController +@RequiredArgsConstructor +@Api(tags = "AGV任务管理") +@RequestMapping("/api/task") +@Slf4j +public class TaskController { + + private final TaskService taskService; + + @PostMapping("/queryPoint") + @Log("任务管理查询站点") + @ApiOperation("任务管理查询站点") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity queryPoint(@RequestBody Map whereJson) { + return new ResponseEntity<>(taskService.queryPoint(whereJson), HttpStatus.OK); + } + @PostMapping("/confirmPoint") + @Log("选择站点确认") + @ApiOperation("选择站点确认") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity confirmPoint(@RequestBody Map whereJson) { + return new ResponseEntity<>(taskService.confirmPoint(whereJson), HttpStatus.OK); + } + @PostMapping("/queryTaskList") + @Log("查询任务列表") + @ApiOperation("查询任务列表") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity queryTaskList(@RequestBody Map whereJson) { + return new ResponseEntity<>(taskService.queryTaskList(whereJson), HttpStatus.OK); + } + + @PostMapping("/deleteTask") + @Log("删除任务列表") + @ApiOperation("删除任务列表") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity deleteTask(@RequestBody Map whereJson) { + return new ResponseEntity<>(taskService.deleteTask(whereJson), HttpStatus.OK); + } + @PostMapping("/updateTask") + @Log("调整任务顺序") + @ApiOperation("调整任务顺序") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity updateTask(@RequestBody Map jsonObject) { + return new ResponseEntity<>(taskService.updateTask(jsonObject), HttpStatus.OK); + } + @PostMapping("/check") + @Log("校验密码") + @ApiOperation("校验密码") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity check(@RequestBody Map whereJson) { + return new ResponseEntity<>(taskService.check(whereJson), HttpStatus.OK); + } +} diff --git a/nladmin-system/src/main/java/org/nl/agv/rest/VehicleInfoController.java b/nladmin-system/src/main/java/org/nl/agv/rest/VehicleInfoController.java new file mode 100644 index 0000000..d307773 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/agv/rest/VehicleInfoController.java @@ -0,0 +1,96 @@ +package org.nl.agv.rest; + + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.nl.agv.service.VehicleInfoService; +import org.nl.annotation.Log; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +/** + * @author qinx + * @date 2021-07-26 + **/ +@RestController +@RequiredArgsConstructor +@Api(tags = "车辆信息管理") +@RequestMapping("/api/vehicle") +@Slf4j +public class VehicleInfoController { + private final VehicleInfoService vehicleInfoService; + @PostMapping("/queryRestPoint") + @Log("车辆信息查询初始化坐标") + @ApiOperation("车辆信息查询初始化坐标") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity getIP(@RequestBody Map whereJson) { + return new ResponseEntity<>(vehicleInfoService.queryRestPoint(whereJson), HttpStatus.OK); + } + + @PostMapping("/restCoordinate") + @Log("初始化坐标确定") + @ApiOperation("初始化坐标确定") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity restCoordinate(@RequestBody Map whereJson) { + return new ResponseEntity<>(vehicleInfoService.restCoordinate(whereJson), HttpStatus.OK); + } + @PostMapping("/Shut_down") + @Log("关机") + @ApiOperation("关机") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity Shut_down(@RequestBody Map whereJson) { + return new ResponseEntity<>(vehicleInfoService.Shut_down(whereJson), HttpStatus.OK); + } + @PostMapping("/skipStartPoint") + @Log("跳过起点") + @ApiOperation("跳过起点") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity skipStartPoint(@RequestBody Map whereJson) { + return new ResponseEntity<>(vehicleInfoService.skipStartPoint(whereJson), HttpStatus.OK); + } + @PostMapping("/softStart") + @Log("软启动") + @ApiOperation("软启动") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity softStart(@RequestBody Map whereJson) { + return new ResponseEntity<>(vehicleInfoService.softStart(whereJson), HttpStatus.OK); + } + @PostMapping("/quitNow") + @Log("退出") + @ApiOperation("退出") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity quitNow(@RequestBody Map whereJson) { + return new ResponseEntity<>(vehicleInfoService.quitNow(whereJson), HttpStatus.OK); + } + + @PostMapping("/queryVehicleStatus") + @Log("查询车辆状态") + @ApiOperation("查询车辆状态") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity queryVehicleStatus(@RequestBody Map whereJson) { + return new ResponseEntity<>(vehicleInfoService.queryVehicleStatus(whereJson), HttpStatus.OK); + } + @PostMapping("/querrySensor") + @Log("查询传感器状态") + @ApiOperation("查询传感器状态") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity querrySensor(@RequestBody Map whereJson) { + return new ResponseEntity<>(vehicleInfoService.querrySensor(whereJson), HttpStatus.OK); + } + @PostMapping("/queryAgv_Status") + @Log("查询agv状态") + @ApiOperation("查询agv状态") + //@PreAuthorize("@el.check('sect:list')") + public ResponseEntity queryAgv_Status(@RequestBody Map whereJson) { + return new ResponseEntity<>(vehicleInfoService.queryAgv_Status(whereJson), HttpStatus.OK); + } + +} diff --git a/nladmin-system/src/main/java/org/nl/agv/service/DevelopService.java b/nladmin-system/src/main/java/org/nl/agv/service/DevelopService.java new file mode 100644 index 0000000..500cf8d --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/agv/service/DevelopService.java @@ -0,0 +1,70 @@ + +package org.nl.agv.service; + +import org.springframework.data.domain.Pageable; + +import java.util.Map; + +/** + * @author qinx + * @description 服务接口 + * @date 2021-09-02 + **/ +public interface DevelopService { + /** + * 开发者选项查询Ifconfig参数 + * + * @param + * @return Map + */ + Map getIP(Map jsonObject); + /** + * 开发者选项查询日志列表 + * + * @param + * @return Map + */ + Map getLogList(Map jsonObject); + /** + * 开发者选项查询ros请求列表 + * + * @param + * @return Map + */ + Map getROSNodeList(Map jsonObject); + /** + * 开发者选项查询芯片温度 + * + * @param + * @return Map + */ + Map temperature(Map jsonObject); + /** + * 开发者选项查询调试信息 + * + * @param + * @return Map + */ + Map debugInfo(Map jsonObject); + /** + * 开发者选项系统参数设置 + * + * @param + * @return Map + */ + Map parameterSetting(Map jsonObject); + /** + * 查询密码 + * + * @param + * @return Map + */ + Map queryPassword(Map jsonObject); + /** + * 查询软硬件版本 + * + * @param + * @return Map + */ + Map softwareVersion(Map jsonObject); +} diff --git a/nladmin-system/src/main/java/org/nl/agv/service/ErrorService.java b/nladmin-system/src/main/java/org/nl/agv/service/ErrorService.java new file mode 100644 index 0000000..6d86c63 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/agv/service/ErrorService.java @@ -0,0 +1,20 @@ + +package org.nl.agv.service; + +import java.util.Map; + +/** + * @author qinx + * @description 服务接口 + * @date 2021-09-02 + **/ +public interface ErrorService { + /** + * 查询头部 + * + * @param + * @return Map + */ + Map querryError(Map jsonObject); + +} diff --git a/nladmin-system/src/main/java/org/nl/agv/service/HomeService.java b/nladmin-system/src/main/java/org/nl/agv/service/HomeService.java new file mode 100644 index 0000000..6213814 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/agv/service/HomeService.java @@ -0,0 +1,34 @@ + +package org.nl.agv.service; + +import java.util.Map; + +/** + * @author qinx + * @description 服务接口 + * @date 2021-09-02 + **/ +public interface HomeService { + /** + * 查询头部 + * + * @param + * @return Map + */ + Map queryHead(Map jsonObject); + /** + * 查询首页 + * + * @param + * @return Map + */ + Map queryHomePage(Map jsonObject); + /** + * 首页确定按钮 + * + * @param + * @return Map + */ + Map clickSave(Map jsonObject); + +} diff --git a/nladmin-system/src/main/java/org/nl/agv/service/TaskService.java b/nladmin-system/src/main/java/org/nl/agv/service/TaskService.java new file mode 100644 index 0000000..ee24636 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/agv/service/TaskService.java @@ -0,0 +1,57 @@ + +package org.nl.agv.service; + +import net.sf.json.JSONArray; + +import java.util.Map; + +/** + * @author qinx + * @description 服务接口 + * @date 2021-09-02 + **/ +public interface TaskService { + /** + * 查询头部agv状态 + * + * @param + * @return Map + */ + Map queryPoint(Map jsonObject); + /** + * 选择站点确认 + * + * @param + * @return Map + */ + Map confirmPoint(Map jsonObject); + /** + * 查询任务列表 + * + * @param + * @return Map + */ + Map queryTaskList(Map jsonObject); + /** + * 删除任务列表 + * + * @param + * @return Map + */ + Map deleteTask(Map jsonObject); + /** + * 调整任务顺序 + * + * @param + * @return Map + */ + Map updateTask( Map jsonObject); + /** + * 校验密码 + * + * @param + * @return Map + */ + Map check( Map jsonObject); + +} diff --git a/nladmin-system/src/main/java/org/nl/agv/service/VehicleInfoService.java b/nladmin-system/src/main/java/org/nl/agv/service/VehicleInfoService.java new file mode 100644 index 0000000..82fe488 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/agv/service/VehicleInfoService.java @@ -0,0 +1,76 @@ + +package org.nl.agv.service; + +import java.util.Map; + +/** + * @author qinx + * @description 服务接口 + * @date 2021-09-02 + **/ +public interface VehicleInfoService { + /** + * 查询初始化坐标信息 + * + * @param + * @return Map + */ + Map queryRestPoint(Map jsonObject); + /** + * 初始化坐标确定 + * + * @param + * @return Map + */ + Map restCoordinate(Map jsonObject); + /** + * 关机 + * + * @param + * @return Map + */ + Map Shut_down(Map jsonObject); + /** + * 跳过起点 + * + * @param + * @return Map + */ + Map skipStartPoint(Map jsonObject); + /** + * 软起动 + * + * @param + * @return Map + */ + Map softStart(Map jsonObject); + /** + * 退出 + * + * @param + * @return Map + */ + Map quitNow(Map jsonObject); + /** + * 查询车辆状态 + * + * @param + * @return Map + */ + Map queryVehicleStatus(Map jsonObject); + /** + * 查询传感器状态 + * + * @param + * @return Map + */ + Map querrySensor(Map jsonObject); + /** + * 查询agv状态 + * + * @param + * @return Map + */ + Map queryAgv_Status(Map jsonObject); + +} diff --git a/nladmin-system/src/main/java/org/nl/agv/service/impl/DevelopServiceImpl.java b/nladmin-system/src/main/java/org/nl/agv/service/impl/DevelopServiceImpl.java new file mode 100644 index 0000000..b870e0b --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/agv/service/impl/DevelopServiceImpl.java @@ -0,0 +1,179 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.agv.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import edu.wpi.rail.jrosbridge.Ros; +import edu.wpi.rail.jrosbridge.Topic; +import edu.wpi.rail.jrosbridge.callback.TopicCallback; +import edu.wpi.rail.jrosbridge.messages.Message; +import edu.wpi.rail.jrosbridge.services.ServiceRequest; +import edu.wpi.rail.jrosbridge.services.ServiceResponse; +import lombok.RequiredArgsConstructor; +import net.sf.json.JSONObject; +import org.nl.agv.service.DevelopService; +import org.nl.agv.unit.sendToAgvUtil; +import org.nl.exception.BadRequestException; +import org.nl.wql.core.bean.WQLObject; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.Iterator; +import java.util.Map; + +/** + * @author zhanghouying + * @date 2019-08-24 + */ +@Service +@RequiredArgsConstructor +public class DevelopServiceImpl implements DevelopService { + + @Override + public Map getIP(Map jsonObject) { + JSONObject returnjo = new JSONObject(); + ServiceResponse response = sendToAgvUtil.send("GetIP"); + String result_info = JSONObject.fromObject(response.toString()).optString("ROS_String_Output"); + JSONObject jsonObject1 = new JSONObject(); + jsonObject1.put("result_info", result_info); + returnjo.put("code", "1"); + returnjo.put("desc", "查询成功!"); + returnjo.put("result", jsonObject1); + return returnjo; + } + + @Override + public Map getLogList(Map jsonObject) { + JSONObject returnjo = new JSONObject(); + ServiceResponse response = sendToAgvUtil.send("GetLogList"); + String result_info = JSONObject.fromObject(response.toString()).optString("ROS_String_Output"); + JSONObject jsonObject1 = new JSONObject(); + jsonObject1.put("result_info", result_info); + returnjo.put("code", "1"); + returnjo.put("desc", "查询成功!"); + returnjo.put("result", jsonObject1); + return returnjo; + } + + @Override + public Map getROSNodeList(Map jsonObject) { + JSONObject returnjo = new JSONObject(); + ServiceResponse response = sendToAgvUtil.send("GetROSNodeList"); + String result_info = JSONObject.fromObject(response.toString()).optString("ROS_String_Output"); + JSONObject jsonObject1 = new JSONObject(); + jsonObject1.put("result_info", result_info); + returnjo.put("code", "1"); + returnjo.put("desc", "查询成功!"); + returnjo.put("result", jsonObject1); + return returnjo; + } + + @Override + public Map temperature(Map jsonObject) { + JSONObject returnjo = new JSONObject(); + ServiceResponse response = sendToAgvUtil.send("Temperature"); + String result_info = JSONObject.fromObject(response.toString()).optString("ROS_String_Output"); + JSONObject jsonObject1 = new JSONObject(); + jsonObject1.put("result_info", result_info); + returnjo.put("code", "1"); + returnjo.put("desc", "查询成功!"); + returnjo.put("result", jsonObject1); + return returnjo; + } + + @Override + public Map debugInfo(Map jsonObject) { + //先执行这个方法确保debugger有数据 + HomeServiceImpl impl = new HomeServiceImpl(); + do { + impl.QueryDebuggerInfo(); + } while (ObjectUtil.isEmpty(HomeServiceImpl.debugInfoJson)); + JSONObject returnjo = new JSONObject(); + JSONObject map = HomeServiceImpl.debugInfoJson; + + Iterator iter = map.entrySet().iterator(); + StringBuilder sb = new StringBuilder(); + while (iter.hasNext()) { + Map.Entry entry = (Map.Entry) iter.next(); + String key = (String) entry.getKey(); + Object val = entry.getValue(); + + if (StrUtil.equals("Car_Global_rx", key) + || StrUtil.equals("Car_Global_ry", key) + || StrUtil.equals("Car_Global_Theta", key) + || StrUtil.equals("Lateral_Deviation_m", key) + || StrUtil.equals("Vertical_Deviation_deg", key) + || StrUtil.equals("Min_Dist", key) + || StrUtil.equals("SVreal_angle", key) + || StrUtil.equals("Speedm_Tmp", key) + ) { + BigDecimal Lateral_Deviation_m = new BigDecimal(map.optString(key)); + val = Lateral_Deviation_m.setScale(3, BigDecimal.ROUND_HALF_UP); + + } + sb.append(key + "=" + String.valueOf(val) + "\n"); + } + JSONObject jo = new JSONObject(); + jo.put("result_info", sb.toString()); + returnjo.put("code", "1"); + returnjo.put("desc", "查询成功!"); + returnjo.put("result", jo); + return returnjo; + } + + @Override + public Map parameterSetting(Map jsonObject) { + String maxTaskNun = (String) jsonObject.get("maxTaskNun"); + String password = (String) jsonObject.get("password"); + if (StrUtil.isEmpty(maxTaskNun)) { + throw new BadRequestException("最大任务数不能为空!"); + } + if (StrUtil.isEmpty(password)) { + throw new BadRequestException("密码不能为空!"); + } + JSONObject row = WQLObject.getWQLObject("st_system_param").query("1=1").uniqueResult(0); + row.put("max_task_num", maxTaskNun); + row.put("password", password); + WQLObject.getWQLObject("st_system_param").update(row); + JSONObject returnjo = new JSONObject(); + returnjo.put("code", "1"); + returnjo.put("desc", "更新成功"); + return returnjo; + } + + @Override + public Map queryPassword(Map jsonObject) { + JSONObject jo = WQLObject.getWQLObject("st_system_param").query("1=1").uniqueResult(0); + JSONObject returnjo = new JSONObject(); + returnjo.put("code", "1"); + returnjo.put("desc", "查询成功!"); + returnjo.put("result", jo); + return returnjo; + } + + @Override + public Map softwareVersion(Map jsonObject) { + String Env_SoftwareVersion = HomeServiceImpl.debugInfoJson.optString("Env_SoftwareVersion"); + JSONObject result = new JSONObject(); + result.put("result_info", Env_SoftwareVersion); + JSONObject returnjo = new JSONObject(); + returnjo.put("code", "1"); + returnjo.put("desc", "更新成功!"); + returnjo.put("result", result); + return returnjo; + } +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/agv/service/impl/ErrorServiceImpl.java b/nladmin-system/src/main/java/org/nl/agv/service/impl/ErrorServiceImpl.java new file mode 100644 index 0000000..c3710f0 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/agv/service/impl/ErrorServiceImpl.java @@ -0,0 +1,132 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.agv.service.impl; + +import cn.hutool.core.util.StrUtil; +import edu.wpi.rail.jrosbridge.Ros; +import edu.wpi.rail.jrosbridge.Topic; +import edu.wpi.rail.jrosbridge.callback.TopicCallback; +import edu.wpi.rail.jrosbridge.messages.Message; +import lombok.RequiredArgsConstructor; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; +import org.nl.agv.service.ErrorService; +import org.nl.agv.service.HomeService; +import org.nl.agv.unit.sendToAgvUtil; +import org.nl.wql.WQL; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author zhanghouying + * @date 2019-08-24 + */ +@Service +@RequiredArgsConstructor +public class ErrorServiceImpl implements ErrorService { + + @Override + public Map querryError(Map jsonObject) { + String error_status = "无故障"; + JSONObject debugInfoJson = HomeServiceImpl.debugInfoJson; + int Warning_Code = debugInfoJson.optInt("Warning_Code"); + //int Warning_Code = 524305; + int ObstacleTouchState = debugInfoJson.optInt("ObstacleTouchState"); + JSONArray ja = new JSONArray(); + String error_code = ""; + //bit0 障碍物报警 barrier + if (Warning_Code % 2 == 1) { + error_status="有故障"; + error_code = "barrier"; + JSONObject row = WQL.getWO("QAGVERROR").addParam("flag", "1").addParam("error_code", error_code).process().uniqueResult(0); + ja.add(row); + } + //bit1 起点报警 startPoint + if ((Warning_Code >> 2) % 2 == 1) { + error_status="有故障"; + error_code = "startPoint"; + JSONObject row = WQL.getWO("QAGVERROR").addParam("flag", "1").addParam("error_code", error_code).process().uniqueResult(0); + ja.add(row); + } + //bit2 急停开关报警 stop + if ((Warning_Code >> 10) % 2 == 1) { + error_status="有故障"; + error_code = "stop"; + JSONObject row = WQL.getWO("QAGVERROR").addParam("flag", "1").addParam("error_code", error_code).process().uniqueResult(0); + ja.add(row); + } + //bit3 触边开关报警 touchSwith + if ((ObstacleTouchState >> 1) % 2 == 1) { + error_status="有故障"; + error_code = "touchSwith"; + JSONObject row = WQL.getWO("QAGVERROR").addParam("flag", "1").addParam("error_code", error_code).process().uniqueResult(0); + ja.add(row); + } + //bit0 速度异常 speedError + if ((Warning_Code >> 6) % 2 == 1) { + error_status="有故障"; + error_code = "speedError"; + JSONObject row = WQL.getWO("QAGVERROR").addParam("flag", "1").addParam("error_code", error_code).process().uniqueResult(0); + ja.add(row); + } //bit0 定位异常 locationError + if ((Warning_Code >> 7) % 2 == 1) { + error_status="是"; + error_code = "startPoint"; + JSONObject row = WQL.getWO("QAGVERROR").addParam("flag", "1").addParam("error_code", error_code).process().uniqueResult(0); + ja.add(row); + } + //bit0 路径异常 wayError + if ((Warning_Code >> 8) % 2 == 1) { + error_status="有故障"; + error_code = "wayError"; + JSONObject row = WQL.getWO("QAGVERROR").addParam("flag", "1").addParam("error_code", error_code).process().uniqueResult(0); + ja.add(row); + } + //电池异常 batteryError + if ((Warning_Code >> 11) % 2 == 1) { + error_status="有故障"; + error_code = "batteryError"; + JSONObject row = WQL.getWO("QAGVERROR").addParam("flag", "1").addParam("error_code", error_code).process().uniqueResult(0); + row.put("error_content",debugInfoJson.optString("PWR_Warn")); + ja.add(row); + } + //CURTIS异常 CURTIS + if ((Warning_Code >> 24) % 2 == 1) { + error_status="有故障"; + error_code = "CURTIS"; + JSONObject row = WQL.getWO("QAGVERROR").addParam("flag", "1").addParam("error_code", error_code).process().uniqueResult(0); + row.put("error_content",debugInfoJson.optString("Curtis_Warning_Code_Speed")); + ja.add(row); + } + + //CAN通讯异常 CAN + if ((Warning_Code >> 19) % 2 == 1) { + error_status="有故障"; + error_code = "CAN"; + JSONObject row = WQL.getWO("QAGVERROR").addParam("flag", "1").addParam("error_code", error_code).process().uniqueResult(0); + row.put("error_content",debugInfoJson.optString("VehicleCtrl_CAN_Err_Info")); + ja.add(row); + } + JSONObject returnjo = new JSONObject(); + returnjo.put("code", "1"); + returnjo.put("desc", "查询成功"); + returnjo.put("result", ja); + returnjo.put("error_status",error_status); + return returnjo; + } +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/agv/service/impl/HomeServiceImpl.java b/nladmin-system/src/main/java/org/nl/agv/service/impl/HomeServiceImpl.java new file mode 100644 index 0000000..7e518ca --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/agv/service/impl/HomeServiceImpl.java @@ -0,0 +1,434 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.agv.service.impl; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpUtil; +import edu.wpi.rail.jrosbridge.Ros; +import edu.wpi.rail.jrosbridge.Topic; +import edu.wpi.rail.jrosbridge.callback.TopicCallback; +import edu.wpi.rail.jrosbridge.messages.Message; +import edu.wpi.rail.jrosbridge.services.ServiceResponse; +import lombok.RequiredArgsConstructor; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; +import org.nl.agv.enu.TaskSendBackStatusEnum; +import org.nl.agv.service.HomeService; +import org.nl.agv.unit.RosUtil; +import org.nl.agv.unit.sendToAgvUtil; +import org.nl.exception.BadRequestException; +import org.nl.modules.system.util.CodeUtil; +import org.nl.wql.core.bean.WQLObject; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author qinx + * @date 2021-09-23 + */ +@Service +@RequiredArgsConstructor +public class HomeServiceImpl implements HomeService { + //定时器查询调试信息,放入json其他地方直接调用; + public static JSONObject debugInfoJson = new JSONObject(); + + public void QueryDebuggerInfo() { + String url = "http://192.168.137.41:9999"; + String result1 = HttpUtil.get(url); + JSONObject json = JSONObject.fromObject(result1); + JSONObject jo = JSONObject.fromObject(json.optString("Msg_DisplayState")); + + debugInfoJson.put("Msg_Timestamp", jo.getJSONObject("header").getJSONObject("stamp").optString("sec")); + debugInfoJson.put("AGV_ID", jo.optString("AGV_ID")); + debugInfoJson.put("Sys_Mode", jo.optString("Sys_Mode")); + debugInfoJson.put("VehicleCtrlExpThrottle", jo.optString("VehicleCtrlExpThrottle")); + debugInfoJson.put("Warning_Code", jo.optString("Warning_Code")); + debugInfoJson.put("Car_Global_rx", jo.optString("Car_Global_rx")); + debugInfoJson.put("Car_Global_ry", jo.optString("Car_Global_ry")); + debugInfoJson.put("Car_Global_Theta", jo.optString("Car_Global_Theta")); + debugInfoJson.put("Lateral_Deviation_m", jo.optString("Lateral_Deviation_m")); + debugInfoJson.put("Vertical_Deviation_deg", jo.optString("Vertical_Deviation_deg")); + debugInfoJson.put("Out_Of_Path_Times", jo.optString("Out_Of_Path_Times")); + debugInfoJson.put("PLC_Warning_Code", jo.optString("PLC_Warning_Code")); + debugInfoJson.put("Min_Dist", jo.optString("Min_Dist")); + debugInfoJson.put("Auto_In_Line_State", jo.opt("Auto_In_Line_State")); + debugInfoJson.put("PathFollow_Enable", jo.optString("PathFollow_Enable")); + debugInfoJson.put("StartNode", jo.optString("StartNode")); + debugInfoJson.put("EndNode", jo.optString("EndNode")); + debugInfoJson.put("RealAutoChargeState", jo.optString("RealAutoChargeState")); + debugInfoJson.put("PWR_Percent", jo.optString("PWR_Percent")); + debugInfoJson.put("SVreal_angle", jo.optString("SVreal_angle")); + debugInfoJson.put("Speedm_Tmp", jo.optString("Speedm_Tmp")); + debugInfoJson.put("VehicleCtrlRealAltitude_mm", jo.optString("VehicleCtrlRealAltitude_mm")); + debugInfoJson.put("ReachState", jo.optString("ReachState")); + debugInfoJson.put("ObstacleDetectState", jo.optString("ObstacleDetectState")); + debugInfoJson.put("ObstacleTouchState", jo.optString("ObstacleTouchState")); + debugInfoJson.put("PWR_Warn", jo.optString("PWR_Warn")); + debugInfoJson.put("VehicleCtrl_CAN_Err_Info", jo.optString("VehicleCtrl_CAN_Err_Info")); + debugInfoJson.put("Curtis_Warning_Code_Speed", jo.optString("Curtis_Warning_Code_Speed")); + debugInfoJson.put("Curtis_Warning_Code_Steer", jo.optString("Curtis_Warning_Code_Steer")); + debugInfoJson.put("VehicleCtrlRealCustomStateByte0", jo.optString("VehicleCtrlRealCustomStateByte0")); + debugInfoJson.put("VehicleCtrlRealCustomStateByte1", jo.optString("VehicleCtrlRealCustomStateByte1")); + debugInfoJson.put("VehicleCtrlRealCustomStateByte2", jo.optString("VehicleCtrlRealCustomStateByte2")); + debugInfoJson.put("VehicleCtrlRealCustomStateByte3", jo.optString("VehicleCtrlRealCustomStateByte3")); + debugInfoJson.put("LastAltitudeExpectValue_mm", jo.optString("LastAltitudeExpectValue_mm")); + debugInfoJson.put("Get_Nav350_Curr_Layer", jo.optString("Get_Nav350_Curr_Layer")); + debugInfoJson.put("Update_Sch", jo.optString("Update_Sch")); + debugInfoJson.put("Update_State", jo.optString("Update_State")); + debugInfoJson.put("Task_Sch", jo.optString("Task_Sch")); + debugInfoJson.put("Task_State", jo.optString("Task_State")); + debugInfoJson.put("PFC_Sch", jo.optString("PFC_Sch")); + debugInfoJson.put("PFC_State", jo.optString("PFC_State")); + debugInfoJson.put("License_Info", jo.optString("License_Info")); + debugInfoJson.put("Env_CustomName", jo.optString("Env_CustomName")); + debugInfoJson.put("Env_VehicleType", jo.optString("Env_VehicleType")); + debugInfoJson.put("Env_SoftwareVersion", jo.optString("Env_SoftwareVersion")); + String PathFollow_Enable = jo.optString("PathFollow_Enable"); + if (StrUtil.equals("0", PathFollow_Enable)) { + JSONObject taskjo = WQLObject.getWQLObject("st_task_info").query("is_delete='0'and task_status='01'").uniqueResult(0); + if (ObjectUtil.isNotEmpty(taskjo)) { + taskjo.put("task_status", "02"); + taskjo.put("task_status_name", "任务完成"); + taskjo.put("update_time", DateUtil.now()); + WQLObject.getWQLObject("st_task_info").update(taskjo); + } + + + } + debugInfoJson.put("PathFollow_Enable", PathFollow_Enable); + } + + public void QueryDebuggerInfo2() { + debugInfoJson = new JSONObject(); + Ros ros = RosUtil.getRos(); + Topic echoBack = new Topic(ros, "/Topic_Display_State", "lu_ps20l_msgs/Msg_DisplayState"); + do { + echoBack.subscribe(new TopicCallback() { + @Override + public void handleMessage(Message message) { + JSONObject jo = JSONObject.fromObject(message.toString()); + debugInfoJson.put("Msg_Timestamp", jo.getJSONObject("header").getJSONObject("stamp").optString("secs")); + debugInfoJson.put("AGV_ID", jo.optString("AGV_ID")); + debugInfoJson.put("Sys_Mode", jo.optString("Sys_Mode")); + debugInfoJson.put("VehicleCtrlExpThrottle", jo.optString("VehicleCtrlExpThrottle")); + debugInfoJson.put("Warning_Code", jo.optString("Warning_Code")); + debugInfoJson.put("Car_Global_rx", jo.optString("Car_Global_rx")); + debugInfoJson.put("Car_Global_ry", jo.optString("Car_Global_ry")); + debugInfoJson.put("Car_Global_Theta", jo.optString("Car_Global_Theta")); + debugInfoJson.put("Lateral_Deviation_m", jo.optString("Lateral_Deviation_m")); + debugInfoJson.put("Vertical_Deviation_deg", jo.optString("Vertical_Deviation_deg")); + debugInfoJson.put("Out_Of_Path_Times", jo.optString("Out_Of_Path_Times")); + debugInfoJson.put("PLC_Warning_Code", jo.optString("PLC_Warning_Code")); + debugInfoJson.put("Min_Dist", jo.optString("Min_Dist")); + debugInfoJson.put("Auto_In_Line_State", jo.opt("Auto_In_Line_State")); + debugInfoJson.put("PathFollow_Enable", jo.optString("PathFollow_Enable")); + debugInfoJson.put("StartNode", jo.optString("StartNode")); + debugInfoJson.put("EndNode", jo.optString("EndNode")); + debugInfoJson.put("RealAutoChargeState", jo.optString("RealAutoChargeState")); + debugInfoJson.put("PWR_Percent", jo.optString("PWR_Percent")); + debugInfoJson.put("SVreal_angle", jo.optString("SVreal_angle")); + debugInfoJson.put("Speedm_Tmp", jo.optString("Speedm_Tmp")); + debugInfoJson.put("VehicleCtrlRealAltitude_mm", jo.optString("VehicleCtrlRealAltitude_mm")); + debugInfoJson.put("ReachState", jo.optString("ReachState")); + debugInfoJson.put("ObstacleDetectState", jo.optString("ObstacleDetectState")); + debugInfoJson.put("ObstacleTouchState", jo.optString("ObstacleTouchState")); + debugInfoJson.put("PWR_Warn", jo.optString("PWR_Warn")); + debugInfoJson.put("VehicleCtrl_CAN_Err_Info", jo.optString("VehicleCtrl_CAN_Err_Info")); + debugInfoJson.put("Curtis_Warning_Code_Speed", jo.optString("Curtis_Warning_Code_Speed")); + debugInfoJson.put("Curtis_Warning_Code_Steer", jo.optString("Curtis_Warning_Code_Steer")); + debugInfoJson.put("VehicleCtrlRealCustomStateByte0", jo.optString("VehicleCtrlRealCustomStateByte0")); + debugInfoJson.put("VehicleCtrlRealCustomStateByte1", jo.optString("VehicleCtrlRealCustomStateByte1")); + debugInfoJson.put("VehicleCtrlRealCustomStateByte2", jo.optString("VehicleCtrlRealCustomStateByte2")); + debugInfoJson.put("VehicleCtrlRealCustomStateByte3", jo.optString("VehicleCtrlRealCustomStateByte3")); + debugInfoJson.put("LastAltitudeExpectValue_mm", jo.optString("LastAltitudeExpectValue_mm")); + debugInfoJson.put("Get_Nav350_Curr_Layer", jo.optString("Get_Nav350_Curr_Layer")); + debugInfoJson.put("Update_Sch", jo.optString("Update_Sch")); + debugInfoJson.put("Update_State", jo.optString("Update_State")); + debugInfoJson.put("Task_Sch", jo.optString("Task_Sch")); + debugInfoJson.put("Task_State", jo.optString("Task_State")); + debugInfoJson.put("PFC_Sch", jo.optString("PFC_Sch")); + debugInfoJson.put("PFC_State", jo.optString("PFC_State")); + debugInfoJson.put("License_Info", jo.optString("License_Info")); + debugInfoJson.put("Env_CustomName", jo.optString("Env_CustomName")); + debugInfoJson.put("Env_VehicleType", jo.optString("Env_VehicleType")); + debugInfoJson.put("Env_SoftwareVersion", jo.optString("Env_SoftwareVersion")); + String PathFollow_Enable = jo.optString("PathFollow_Enable"); + if (StrUtil.equals("false", PathFollow_Enable)) { + JSONObject taskjo = WQLObject.getWQLObject("st_task_info").query("is_delete='0'and task_status='01'").uniqueResult(0); + if (ObjectUtil.isNotEmpty(taskjo)) { + taskjo.put("task_status", "02"); + taskjo.put("task_status_name", "任务完成"); + taskjo.put("update_time", DateUtil.now()); + WQLObject.getWQLObject("st_task_info").update(taskjo); + } + + + } + debugInfoJson.put("PathFollow_Enable", PathFollow_Enable); + echoBack.unsubscribe(); + } + + }); + } while (ObjectUtil.isEmpty(debugInfoJson)); + } + + + @Override + public Map queryHead(Map jsonObject) { + JSONObject returnjo = new JSONObject(); + JSONObject result = new JSONObject(); + String agvrun_status_name = ""; + String automatic_status_name = ""; + //车辆运行还是待机是PathFollow_Enable 1为运行 0为待机 + String agvrun_status = debugInfoJson.optString("PathFollow_Enable"); + if (StrUtil.equals(agvrun_status, "1")) { + automatic_status_name = "运行"; + } + if (StrUtil.equals(agvrun_status, "0")) { + automatic_status_name = "待机"; + } + + //手自动是Sys_Mode 3 REMA手动 4自动 5 IO手持方式的手动,这个车不装 + String automatic_status = debugInfoJson.optString("Sys_Mode"); + if (StrUtil.equals(automatic_status, "3")) { + automatic_status_name = "REMA手动"; + } + if (StrUtil.equals(automatic_status, "4")) { + automatic_status_name = "自动"; + } + if (StrUtil.equals(automatic_status, "5")) { + automatic_status_name = "IO手持方式的手动"; + } + result.put("agvrun_status", agvrun_status); + result.put("agvrun_status_name", agvrun_status_name); + result.put("automatic_status", automatic_status); + result.put("automatic_status_name", automatic_status_name); + returnjo.put("code", "1"); + returnjo.put("desc", "操作成功"); + returnjo.put("result", result); + return returnjo; + } + + @Override + public Map queryHomePage(Map jsonObject) { + JSONObject returnjo = new JSONObject(); + JSONObject row = new JSONObject(); + JSONObject tasking = WQLObject.getWQLObject("st_task_info").query("is_delete= 0 and task_status='01' and task_type='1'").uniqueResult(0); + // 1 无任务 2 有任务未执行 3 执行中 + String task_status = ""; + //1确认完成 2确认完成继续下个任务 3继续搬运,4返回休息点 + String button_code = ""; + String button_name = ""; + String date = DateUtil.today(); + JSONObject today_task = WQLObject.getWQLObject("st_task_info").query("is_delete= 0 and date='" + date + "'and task_type='1'").uniqueResult(0); + if (tasking == null) { + task_status = "无任务"; + } + JSONObject tasked = WQLObject.getWQLObject("st_task_info").query("is_delete= 0 and task_status='00'and task_type='1'").uniqueResult(0); + if (tasked != null) { + task_status = "有任务未执行"; + } + if (tasking != null) { + task_status = "执行中"; + } + JSONObject unManFinishTask = WQLObject.getWQLObject("st_task_info").query("is_delete= 0 and task_status='02' and is_manualfinished='0'and task_type='1'").uniqueResult(0); + if (unManFinishTask != null && tasked == null) { + button_code = "1"; + button_name = "确认完成"; + } + if (unManFinishTask != null && tasked != null) { + button_code = "2"; + button_name = "确认完成继续下个任务"; + } + //任务都完成了,但是还有未完成的任务 + if (unManFinishTask == null && tasked != null) { + button_code = "3"; + button_name = "继续搬运"; + } + if (unManFinishTask == null && tasked == null) { + button_code = "4"; + button_name = "返回休息点"; + //假如所有的任务都完成,包括返回休息点的任务,且最后一个完成任务的时间是返回休息电的任务也不显示 + JSONObject doingtaskjo = WQLObject.getWQLObject("st_task_info").query("is_delete= 0 ", "update_time desc").uniqueResult(0); + if (doingtaskjo != null && doingtaskjo.optString("task_type").equals("2")) { + button_code = ""; + button_name = ""; + } + } + //假如有执行中的任务,则不显示 + JSONObject doingtaskjo = WQLObject.getWQLObject("st_task_info").query("is_delete= 0 and task_status='01' and is_manualfinished='0'").uniqueResult(0); + if (doingtaskjo != null) { + button_code = ""; + button_name = ""; + } + //假如电量低于30 ,则返回休息电 + int electric = debugInfoJson.optInt("PWR_Percent"); + if (electric < 30) { + button_code = "4"; + button_name = "返回休息点"; + } + String task_num = "待执行0"; + //分母 今天所有的任务,分子今天未完成的任务 + JSONArray alltaskja = WQLObject.getWQLObject("st_task_info").query("is_delete= 0 and task_type='1' and date ='" + date + "'").getResultJSONArray(0); + if (alltaskja.size() > 0) { + JSONArray todaytaskja = WQLObject.getWQLObject("st_task_info").query("is_delete= 0 and task_type='1' and date ='" + date + "' and task_status='00'").getResultJSONArray(0); + String alltask_num = String.valueOf(alltaskja.size()); + String todaytask_num = String.valueOf(todaytaskja.size()); + task_num = "待执行" + todaytask_num + "/" + alltask_num; + } + ErrorServiceImpl errorServiceImpl = new ErrorServiceImpl(); + Map error = errorServiceImpl.querryError(new JSONObject()); + String Env_CustomName = debugInfoJson.optString("Env_CustomName"); + String Env_VehicleType = debugInfoJson.optString("Env_VehicleType"); + String device_info = Env_CustomName + Env_VehicleType; + row.put("device_info", device_info); + row.put("task_status", task_status); + row.put("task_num", task_num); + row.put("agv_error", (String) error.get("error_status")); + row.put("button_code", button_code); + row.put("button_name", button_name); + row.put("electric", electric); + + returnjo.put("code", "1"); + returnjo.put("desc", "操作成功"); + returnjo.put("result", row); + return returnjo; + } + + @Override + public Map clickSave(Map jsonObject) { + //1确认完成 2确认完成继续下个任务 3继续搬运,4返回休息点 + + WQLObject taskTable = WQLObject.getWQLObject("st_task_info"); + String button_code = (String) jsonObject.get("button_code"); + JSONObject returnjo = new JSONObject(); + + + if (StrUtil.equals(button_code, "1")) { + JSONObject taskjo = taskTable.query("is_delete='0' and task_status='02' and task_type ='1' and is_manualfinished='0'").uniqueResult(0); + if (ObjectUtil.isEmpty(taskjo)) { + throw new BadRequestException("未找到任务"); + } + taskjo.put("is_manualfinished", "1"); + taskTable.update(taskjo); + } + + if (StrUtil.equals(button_code, "2")) { + JSONObject taskjo = taskTable.query("is_delete='0' and task_status='02' and task_type ='1' and is_manualfinished='0'").uniqueResult(0); + if (ObjectUtil.isEmpty(taskjo)) { + returnjo.put("code", "1"); + returnjo.put("desc", "未找到任务"); + return returnjo; + } + taskjo.put("is_manualfinished", "1"); + taskTable.update(taskjo); + //下发下一个任务 + JSONObject nexttaskjo = taskTable.query("is_delete='0' and task_status='00' and task_type ='1' ", "seq_num").uniqueResult(0); + if (ObjectUtil.isEmpty(nexttaskjo)) { + returnjo.put("code", "1"); + returnjo.put("desc", "未找到任务"); + return returnjo; + } + String a = "HMIStepOrRTPathFollow:0;" + nexttaskjo.optString("next_point_code") + ";1#"; + ServiceResponse send = sendToAgvUtil.send(a); + JSONObject resjo = JSONObject.fromObject(send.toString()); + String resultflag = resjo.optString("result"); + if (StrUtil.equals("0", resultflag)) { + //改变任务的状态 + nexttaskjo.put("task_status", "01"); + nexttaskjo.put("task_status_name", "执行中"); + WQLObject.getWQLObject("st_task_info").update(nexttaskjo); + } else { + returnjo.put("code", "1"); + returnjo.put("desc", TaskSendBackStatusEnum.getName(resultflag)); + return returnjo; + } + + } + if (StrUtil.equals(button_code, "3")) { + JSONObject nexttaskjo = taskTable.query("is_delete='0' and task_status='00' and task_type ='1' ", "seq_num").uniqueResult(0); + if (ObjectUtil.isEmpty(nexttaskjo)) { + throw new BadRequestException("未找到任务"); + } + //下发这个任务 + String a = "HMIStepOrRTPathFollow:0;" + nexttaskjo.optString("next_point_code") + ";1#"; + ServiceResponse send = sendToAgvUtil.send(a); + JSONObject resjo = JSONObject.fromObject(send.toString()); + String resultflag = resjo.optString("result"); + if (StrUtil.equals("0", resultflag)) { + //改变任务的状态 + nexttaskjo.put("task_status", "01"); + nexttaskjo.put("task_status_name", "执行中"); + WQLObject.getWQLObject("st_task_info").update(nexttaskjo); + } else { + returnjo.put("code", "1"); + returnjo.put("desc", TaskSendBackStatusEnum.getName(resultflag)); + return returnjo; + } + } + if (StrUtil.equals(button_code, "4")) { + TaskServiceServiceImpl taskServiceServiceImpl = new TaskServiceServiceImpl(); + //查询有没有正在执行的任务,假如有不能返回生成任务 + JSONObject doingtaskjo = WQLObject.getWQLObject("st_task_info").query("is_delete= 0 and task_status='01' ").uniqueResult(0); + if (ObjectUtil.isNotEmpty(doingtaskjo)) { + returnjo.put("code", "0"); + returnjo.put("desc", "有正在执行的任务,不能生产返回休息点的任务"); + return returnjo; + } + + String rest_pointcode = (String) taskServiceServiceImpl.queryPoint(new HashMap<>()).get("rest_pointcode"); + JSONObject taskjo = new JSONObject(); + taskjo.put("task_uuid", IdUtil.simpleUUID()); + taskjo.put("task_code", CodeUtil.getNewCode("TASK_NO")); + taskjo.put("task_status", "00"); + taskjo.put("task_status_name", "生成未执行"); + taskjo.put("next_point_code", rest_pointcode); + taskjo.put("task_type", "2"); + taskjo.put("is_delete", "0"); + taskjo.put("seq_num", "1"); + taskjo.put("date", DateUtil.today()); + taskjo.put("create_time", DateUtil.now()); + taskjo.put("is_agvfinished", "0"); + taskjo.put("is_manualfinished", "0"); + + //下发这个任务 + String a = "HMIStepOrRTPathFollow:0;" + taskjo.optString("next_point_code") + ";1#"; + ServiceResponse send = sendToAgvUtil.send(a); + JSONObject resjo = JSONObject.fromObject(send.toString()); + String resultflag = resjo.optString("result"); + if (StrUtil.equals("0", resultflag)) { + //改变任务的状态 + taskjo.put("task_status", "01"); + taskjo.put("task_status_name", "执行中"); + } else { + returnjo.put("code", "1"); + returnjo.put("desc", TaskSendBackStatusEnum.getName(resultflag)); + return returnjo; + } + + + WQLObject.getWQLObject("st_task_info").insert(taskjo); + } + returnjo.put("code", "1"); + returnjo.put("desc", "操作成功"); + return returnjo; + } +} diff --git a/nladmin-system/src/main/java/org/nl/agv/service/impl/TaskServiceServiceImpl.java b/nladmin-system/src/main/java/org/nl/agv/service/impl/TaskServiceServiceImpl.java new file mode 100644 index 0000000..e474346 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/agv/service/impl/TaskServiceServiceImpl.java @@ -0,0 +1,230 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.agv.service.impl; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.HexUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import edu.wpi.rail.jrosbridge.Ros; +import edu.wpi.rail.jrosbridge.Topic; +import edu.wpi.rail.jrosbridge.callback.TopicCallback; +import edu.wpi.rail.jrosbridge.messages.Message; +import edu.wpi.rail.jrosbridge.services.ServiceResponse; +import lombok.RequiredArgsConstructor; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; +import org.nl.agv.service.DevelopService; +import org.nl.agv.service.TaskService; +import org.nl.agv.unit.sendToAgvUtil; +import org.nl.exception.BadRequestException; +import org.nl.modules.system.util.CodeUtil; +import org.nl.wql.WQL; +import org.nl.wql.core.bean.WQLObject; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author zhanghouying + * @date 2019-08-24 + */ +@Service +@RequiredArgsConstructor +public class TaskServiceServiceImpl implements TaskService { + public static JSONObject pointJson = new JSONObject(); + + @Override + public Map queryPoint(Map jsonObject) { + JSONObject returnjo = new JSONObject(); + String rest_pointcode = ""; + ServiceResponse response = sendToAgvUtil.send("GetStationFloorIndexTable"); + String result_info = JSONObject.fromObject(response.toString()).optString("ROS_String_Output"); + String[] split = result_info.split("\\n"); + for (int i = 0; i < split.length; i++) { + String row = split[i]; + String[] rowArr = row.split("\\s+"); + pointJson.put(rowArr[3], rowArr[4].contains("<") ? "" : rowArr[4]); + } + JSONArray arr = new JSONArray(); + for (Object key : pointJson.keySet()) { + String value = (String) pointJson.get(key); + System.out.println("Key = " + key + ", Value = " + value); + JSONObject row = new JSONObject(); + row.put("point_code", key); + row.put("point_name", value); + row.put("code_name", key + "-" + value); + if (StrUtil.equals("休息", value)) { + rest_pointcode = (String) key; + } + arr.add(row); + } + JSONObject jsonObject1 = new JSONObject(); + jsonObject1.put("result_info", result_info); + returnjo.put("code", "1"); + returnjo.put("desc", "查询成功!"); + returnjo.put("rest_pointcode", rest_pointcode); + returnjo.put("result", arr); + return returnjo; + } + + @Override + public Map confirmPoint(Map jsonObject) { + String point_code = (String) jsonObject.get("point_code"); + JSONObject returnjo = new JSONObject(); + if (StrUtil.isEmpty(point_code)) { + throw new BadRequestException("站点不能为空!"); + } + //查询未完成的指令有多少条 + int num = WQL.getWO("QAGVERROR").addParam("flag", "3").process().uniqueResult(0).optInt("num"); + //查询最多的任务数量 + int max_task_num = WQLObject.getWQLObject("ST_SYSTEM_PARAM").query("1=1").uniqueResult(0).optInt("max_task_num"); + if (num >= max_task_num) { + returnjo.put("code", "1"); + returnjo.put("desc", "未执行的任务数量达到上限!"); + return returnjo; + } + JSONObject taskjo = new JSONObject(); + int seq_num = 1; + String task_status = "00"; + String task_status_name = "生成未执行"; + //查询未完成最大的顺序号 + JSONObject taskrow = WQLObject.getWQLObject("ST_TASK_INFO").query("is_manualfinished=0", "seq_num desc").uniqueResult(0); + if (ObjectUtil.isNotEmpty(taskrow)) { + seq_num = taskrow.optInt("seq_num") + 1; + + } + if (ObjectUtil.isEmpty(taskrow)) { + + //只有第一条下发给agv + String a ="HMIStepOrRTPathFollow:0;"+point_code+";1#"; + ServiceResponse send = sendToAgvUtil.send(a); + JSONObject resjo = JSONObject.fromObject(send.toString()); + if (StrUtil.equals("0",resjo.optString("result"))){ + task_status_name = "执行中"; + task_status = "01"; + } + //JSONObject change = sendToAgvUtil.change(point_code); + //sendToAgvUtil.sendtask(change.optString("first"), change.optString("last")); + } + + + taskjo.put("task_uuid", IdUtil.simpleUUID()); + taskjo.put("task_code", CodeUtil.getNewCode("TASK_NO")); + taskjo.put("task_status", task_status); + taskjo.put("task_status_name", task_status_name); + taskjo.put("next_point_code", point_code); + taskjo.put("task_type", "1"); + taskjo.put("is_delete", "0"); + taskjo.put("seq_num", seq_num); + taskjo.put("date", DateUtil.today()); + taskjo.put("create_time", DateUtil.now()); + taskjo.put("is_agvfinished", "0"); + taskjo.put("is_manualfinished", "0"); + WQLObject.getWQLObject("ST_TASK_INFO").insert(taskjo); + returnjo.put("code", "1"); + returnjo.put("desc", "新增成功!"); + return returnjo; + } + + @Override + public Map queryTaskList(Map jsonObject) { + JSONArray resultJSONArray = WQL.getWO("QAGVERROR").addParam("flag", "2").process().getResultJSONArray(0); + JSONObject returnjo = new JSONObject(); + returnjo.put("code", "1"); + returnjo.put("desc", "查询成功!"); + returnjo.put("result", resultJSONArray); + + return returnjo; + } + + @Override + public Map deleteTask(Map jsonObject) { + String task_num = (String) jsonObject.get("task_num"); + if (StrUtil.isEmpty(task_num)) { + throw new BadRequestException("任务号不能为空"); + } + WQLObject taskTable = WQLObject.getWQLObject("ST_TASK_INFO"); + JSONObject taskjo = taskTable.query("task_code='" + task_num + "'").uniqueResult(0); + taskjo.put("is_delete", "1"); + taskTable.update(taskjo); + JSONObject returnjo = new JSONObject(); + returnjo.put("code", "1"); + returnjo.put("desc", "删除成功!"); + return returnjo; + + } + + @Override + public Map updateTask(Map jsonObject) { + JSONArray jsonArray = JSONObject.fromObject(jsonObject).optJSONArray("param"); + WQLObject taskTable = WQLObject.getWQLObject("ST_TASK_INFO"); + //更新之前删除之前的所有未完成任务 + JSONArray taskrows = taskTable.query("task_status='00' or task_status='01'").getResultJSONArray(0); + for (int i = 0; i < taskrows.size(); i++) { + JSONObject taskrow = taskrows.getJSONObject(i); + taskrow.put("is_delete", "1"); + taskTable.update(taskrow); + } + + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject taskjo = jsonArray.getJSONObject(i); + String task_num = taskjo.optString("task_num"); + String seq_num = taskjo.optString("seq_num"); + JSONObject taskrow = taskTable.query("task_code='" + task_num + "'").uniqueResult(0); + /* String task_status = taskjo.optString("task_status"); + if (StrUtil.equals(task_status,"01")){ + taskrow.put("seq_num", 1); + }else{ + taskrow.put("seq_num", i + 2); + }*/ + taskrow.put("seq_num", i + 1); + taskrow.put("is_delete","0"); + taskTable.update(taskrow); + } + JSONObject returnjo = new JSONObject(); + returnjo.put("code", "1"); + returnjo.put("desc", "更新成功!"); + return returnjo; + } + + @Override + public Map check(Map jsonObject) { + String password = (String) jsonObject.get("password"); + if (StrUtil.isEmpty(password)) { + throw new BadRequestException("密码不能空!"); + } + //1代表正确,2 代表不正确 + String is_correct; + JSONObject paramjo = WQLObject.getWQLObject("st_system_param").query("1=1").uniqueResult(0); + String super_password = paramjo.optString("super_password"); + String passworddb = paramjo.optString("password"); + JSONObject returnjo = new JSONObject(); + if (StrUtil.equals(password, super_password) || StrUtil.equals(passworddb, password)) { + is_correct = "1"; + returnjo.put("code", "1"); + returnjo.put("desc", "密码校验成功!"); + } else { + returnjo.put("code", "0"); + returnjo.put("desc", "密码不正确!"); + } + + return returnjo; + + } +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/agv/service/impl/VehicleInfoServiceImpl.java b/nladmin-system/src/main/java/org/nl/agv/service/impl/VehicleInfoServiceImpl.java new file mode 100644 index 0000000..c25f821 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/agv/service/impl/VehicleInfoServiceImpl.java @@ -0,0 +1,310 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.agv.service.impl; + +import cn.hutool.core.util.StrUtil; +import edu.wpi.rail.jrosbridge.services.ServiceResponse; +import lombok.RequiredArgsConstructor; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; +import org.nl.agv.service.TaskService; +import org.nl.agv.service.VehicleInfoService; +import org.nl.agv.unit.sendToAgvUtil; +import org.nl.exception.BadRequestException; +import org.nl.wql.core.bean.WQLObject; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.sql.Struct; +import java.util.HashMap; +import java.util.Map; + +/** + * @author qinx + * @date 2019-08-24 + */ +@Service +@RequiredArgsConstructor +public class VehicleInfoServiceImpl implements VehicleInfoService { + @Override + public Map queryRestPoint(Map jsonObject) { + ServiceResponse response = sendToAgvUtil.send("GetNodePointManagerTable"); + String result_info = response.toString(); + String s = JSONObject.fromObject(response.toString()).optString("ROS_String_Output"); + String[] split = s.split("\\n"); + JSONArray rows = new JSONArray(); + TaskServiceServiceImpl taskServiceServiceimpl = new TaskServiceServiceImpl(); + //执行这个方法,使得pointJson 有值 + taskServiceServiceimpl.queryPoint(new HashMap<>()); + for (int i = 0; i < split.length; i++) { + JSONObject json = new JSONObject(); + String row = split[i]; + String[] rowArr = row.split("\\s+"); + json.put("point_code", rowArr[1]); + String point_name = TaskServiceServiceImpl.pointJson.optString(rowArr[1]); + json.put("point_name", point_name); + json.put("x", rowArr[3]); + json.put("y", rowArr[4]); + json.put("t", rowArr[5]); + rows.add(json); + System.out.println(json); + } + JSONObject returnjo = new JSONObject(); + returnjo.put("code", "1"); + returnjo.put("desc", "查询成功!"); + returnjo.put("result", rows); + return returnjo; + } + + @Override + public Map restCoordinate(Map jsonObject) { + String x = (String) jsonObject.get("x"); + String y = (String) jsonObject.get("y"); + String t = (String) jsonObject.get("t"); + String methodName = "BoschLocalizationSetSeedByNode:" + x + ";" + y + ";" + t + "#"; + sendToAgvUtil.send(methodName); + JSONObject returnjo = new JSONObject(); + returnjo.put("code", "1"); + returnjo.put("desc", "成功 !"); + return returnjo; + + } + + @Override + public Map Shut_down(Map jsonObject) { + ServiceResponse response = sendToAgvUtil.send("PowerOff"); + JSONObject returnjo = new JSONObject(); + returnjo.put("code", "1"); + returnjo.put("desc", "正在关机"); + return returnjo; + } + + @Override + public Map skipStartPoint(Map jsonObject) { + String a = "{\n" + + " \"header\": {\n" + + " \"stamp\": {\n" + + " \"secs\": 0,\n" + + " \"nsecs\": 0\n" + + " },\n" + + " \"frame_id\": \"\",\n" + + " \"seq\": 0\n" + + " },\n" + + " \"id\": 257,\n" + + " \"is_rtr\": false,\n" + + " \"is_extended\": false,\n" + + " \"is_error\": false,\n" + + " \"dlc\": 8,\n" + + " \"data\": [32, 0, 0, 1, 0, 0, 0, 1]\n" + + "}"; + ServiceResponse response = sendToAgvUtil.topicSend(a); + JSONObject returnjo = new JSONObject(); + returnjo.put("code", "1"); + returnjo.put("desc", "跳过起点成功"); + return returnjo; + } + + @Override + public Map softStart(Map jsonObject) { + String a = "{\n" + + " \"header\": {\n" + + " \"stamp\": {\n" + + " \"secs\": 0,\n" + + " \"nsecs\": 0\n" + + " },\n" + + " \"frame_id\": \"\",\n" + + " \"seq\": 0\n" + + " },\n" + + " \"id\": 257,\n" + + " \"is_rtr\": false,\n" + + " \"is_extended\": false,\n" + + " \"is_error\": false,\n" + + " \"dlc\": 8,\n" + + " \"data\": [32, 0, 0, 1, 0, 0, 0, 2]\n" + + "}"; + ServiceResponse response = sendToAgvUtil.topicSend(a); + JSONObject returnjo = new JSONObject(); + returnjo.put("code", "1"); + returnjo.put("desc", "全启动成功"); + return returnjo; + } + + @Override + public Map quitNow(Map jsonObject) { + ServiceResponse response = sendToAgvUtil.send("QuitNow"); + JSONObject returnjo = new JSONObject(); + returnjo.put("code", "1"); + returnjo.put("desc", "正在退出"); + return returnjo; + } + + @Override + public Map queryVehicleStatus(Map jsonObject) { + JSONObject row = new JSONObject(); + JSONObject debugInfoJson = HomeServiceImpl.debugInfoJson; + JSONObject returnjo = new JSONObject(); + //错误码为Warning_Code,为0表示正常,不为0表示异常 + String Warning_Code = debugInfoJson.optString("Warning_Code"); + String working_status = ""; + String vehicle_status = ""; + if (StrUtil.equals(Warning_Code, "0")) { + working_status = "正常"; + } else { + working_status = "异常"; + } + //车辆运行还是待机是PathFollow_Enable 1为运行 0为待机 + String PathFollow_Enable = debugInfoJson.optString("PathFollow_Enable"); + if (StrUtil.equals(PathFollow_Enable, "0")) { + vehicle_status = "待机"; + } + if (StrUtil.equals(PathFollow_Enable, "1")) { + vehicle_status = "运行"; + } + row.put("working_status", working_status); + row.put("vehicle_status", vehicle_status); + BigDecimal x = new BigDecimal(debugInfoJson.optString("Car_Global_rx")); + //保留两位小数且四舍五入 + x = x.setScale(3, BigDecimal.ROUND_HALF_UP); + row.put("x", x); + + BigDecimal y = new BigDecimal(debugInfoJson.optString("Car_Global_ry")); + //保留两位小数且四舍五入 + y = y.setScale(3, BigDecimal.ROUND_HALF_UP); + row.put("y", y); + row.put("z", debugInfoJson.optString("Car_Global_Theta")); + row.put("send_speed", debugInfoJson.optString("VehicleCtrlExpThrottle")); + row.put("real_speed", debugInfoJson.optString("Speedm_Tmp")); + //保留3位小数 + //舵轮角度 + row.put("carrier", debugInfoJson.optString("SVreal_angle")); + //保留3位小数 + //横向偏差 + BigDecimal Lateral_Deviation_m = new BigDecimal(debugInfoJson.optString("Lateral_Deviation_m")); + Lateral_Deviation_m = Lateral_Deviation_m.setScale(3, BigDecimal.ROUND_HALF_UP); + row.put("landscape_deviation", Lateral_Deviation_m); + //航向偏差 + BigDecimal Vertical_Deviation_deg = new BigDecimal(debugInfoJson.optString("Vertical_Deviation_deg")); + Lateral_Deviation_m = Lateral_Deviation_m.setScale(3, BigDecimal.ROUND_HALF_UP); + row.put("course_deviation", debugInfoJson.optString("Vertical_Deviation_deg")); + returnjo.put("code", "1"); + returnjo.put("desc", "查询成功!"); + returnjo.put("result", row); + return returnjo; + } + + @Override + public Map querrySensor(Map jsonObject) { + JSONObject returnjo = new JSONObject(); + JSONObject row = new JSONObject(); + JSONObject debugInfoJson = HomeServiceImpl.debugInfoJson; + int ObstacleTouchState = debugInfoJson.optInt("ObstacleTouchState"); + int ObstacleDetectState = debugInfoJson.optInt("ObstacleDetectState"); + int VehicleCtrlRealCustomStateByte0 = debugInfoJson.optInt("VehicleCtrlRealCustomStateByte0"); + + //急停按钮 + String stopButton_status = "0"; + //避障减速 + String speedReduction_status = "0"; + //复位按钮 + String resetButton_status = "0"; + //避障停车 + String speedStop_status = "0"; + // 安全触边 + String securityTentacle_status = "0"; + //ObstacleTouchState bit0 为 叉腿端部的安全开关触发信号 1 触发 0 未触发 + //ObstacleTouchState bit1 为 触边条安全开关触发信号 1 触发 0 未触发 + //ObstacleTouchState bit2 为 两侧急停按钮触发信号 1 触发 0 未触发 + //ObstacleTouchState bit3 为 上位机请求急停触发信号 1 触发 0 未触发 + //ObstacleTouchState bit4 为导航雷达pfr2000或NAV350 防护触发信号 1 触发 0 未触发 + //避障停车 + if (ObstacleDetectState % 2 == 1) { + speedStop_status = "1"; + } + //避障减速 + if ((ObstacleDetectState >> 1) % 2 == 1) { + speedReduction_status = "1"; + } + //复位按钮 + if (VehicleCtrlRealCustomStateByte0 % 2 == 1) { + resetButton_status = "1"; + } + //安全触边 + if ((ObstacleTouchState >> 1) % 2 == 1) { + securityTentacle_status = "1"; + } + ////急停按钮 + if ((ObstacleTouchState >> 2) % 2 == 1) { + stopButton_status = "1"; + } + //// + if ((ObstacleTouchState >> 3) % 2 == 1) { + } + //// + if ((ObstacleTouchState >> 4) % 2 == 1) { + + } + + + row.put("stopButton_status", stopButton_status); + row.put("speedReduction_status", speedReduction_status); + row.put("resetButton_status", resetButton_status); + row.put("speedStop_status", speedStop_status); + row.put("securityTentacle_status", securityTentacle_status); + + returnjo.put("code", "1"); + returnjo.put("desc", "查询成功!"); + returnjo.put("result", row); + return returnjo; + } + + @Override + public Map queryAgv_Status(Map jsonObject) { + JSONObject returnjo = new JSONObject(); + JSONObject row = new JSONObject(); + String inLineStatus; + String inLineStatus_name; + String UpdateStatus; + String UpdateStatus_name; + String Update_Sch = HomeServiceImpl.debugInfoJson.optString("Update_Sch"); + String Auto_In_Line_State = HomeServiceImpl.debugInfoJson.optString("Auto_In_Line_State"); + if (StrUtil.equals("true", Auto_In_Line_State)) { + inLineStatus = "0"; + inLineStatus_name = "正常"; + } else { + inLineStatus = "1"; + inLineStatus_name = "偏离"; + } + if (StrUtil.equals("0", Update_Sch)) { + UpdateStatus = "1"; + UpdateStatus_name = "更新完成"; + } else { + UpdateStatus = "0"; + UpdateStatus_name = "更新中"; + } + + row.put("inLineStatus", inLineStatus); + row.put("inLineStatus_name", inLineStatus_name); + row.put("UpdateStatus", UpdateStatus); + row.put("UpdateStatus_name", UpdateStatus_name); + returnjo.put("code", "1"); + returnjo.put("desc", "查询成功!"); + returnjo.put("result", row); + return returnjo; + + } + + +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/agv/unit/RosUtil.java b/nladmin-system/src/main/java/org/nl/agv/unit/RosUtil.java new file mode 100644 index 0000000..840c95c --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/agv/unit/RosUtil.java @@ -0,0 +1,19 @@ +package org.nl.agv.unit; + +import edu.wpi.rail.jrosbridge.Ros; + +public class RosUtil { + final static String hostName = "192.168.137.41"; + final static int port = 9290; + public static Ros ros = new Ros(hostName, port); + + public static Ros getRos() { + if (ros == null) { + ros = new Ros(hostName, port); + } + if (!ros.isConnected()) { + ros.connect(); + } + return ros; + } +} diff --git a/nladmin-system/src/main/java/org/nl/agv/unit/sendToAgvUtil.java b/nladmin-system/src/main/java/org/nl/agv/unit/sendToAgvUtil.java new file mode 100644 index 0000000..19719d1 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/agv/unit/sendToAgvUtil.java @@ -0,0 +1,127 @@ +package org.nl.agv.unit; + +import cn.hutool.core.util.StrUtil; +import edu.wpi.rail.jrosbridge.Ros; +import edu.wpi.rail.jrosbridge.Service; +import edu.wpi.rail.jrosbridge.Topic; +import edu.wpi.rail.jrosbridge.messages.Message; +import edu.wpi.rail.jrosbridge.services.ServiceRequest; +import edu.wpi.rail.jrosbridge.services.ServiceResponse; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; +import org.nl.exception.BadRequestException; + +import java.math.BigDecimal; + +public class sendToAgvUtil { + + public static ServiceResponse send(String methondName) { + if (StrUtil.isEmpty(methondName)) { + throw new BadRequestException("请求方法名不能为空!"); + } + Ros ros = new Ros(RosUtil.hostName, RosUtil.port); + ros.connect(); + // Ros ros = RosUtil.getRos(); + Service addTwoInts = new Service(ros, "/Service_HMIString", "lu_ps20l_msgs/Srv_HMIString"); + JSONObject json = new JSONObject(); + //IFCONFIG + //json.put("HMI_String_Input", "GetIP"); + //日志列表 + //json.put("HMI_String_Input", "GetLogList"); + //ros请求列表 + //json.put("HMI_String_Input", "GetROSNodeList"); + //芯片温度 + // json.put("HMI_String_Input", "Temperature"); + //获取站点 + // json.put("HMI_String_Input", "GetStationFloorIndexTable"); + //初始化坐标确定按钮方法 (xyt ,初始化坐标里面的xyt,格式按照下面书写) + // json.put("HMI_String_Input", "BoschLocalizationSetSeedByNode:x;y;t#"); + //关机 + //获取站点(刘先源写正则表达式) + //json.put("HMI_String_Input", "GetStationFloorIndexTable"); + //获取坐标(第二个) + //json.put("HMI_String_Input", "GetNodePointManagerTable"); + json.put("HMI_String_Input", methondName); + ServiceRequest request = new ServiceRequest(json.toString()); + ServiceResponse response = addTwoInts.callServiceAndWait(request); + ros.disconnect(); + return response; + } + + public static ServiceResponse sendtask(String first, String last) { + //Ros ros = RosUtil.getRos(); + Ros ros = new Ros(RosUtil.hostName, RosUtil.port); + ros.connect(); + Topic echo = new Topic(ros, "/js_can", "lu_ps20l_msgs/Msg_CANFrame"); + JSONArray data = new JSONArray(); + data.add(16); + data.add(1); + data.add(3); + data.add(1); + data.add(0); + data.add(0); + data.add(Integer.parseInt(first)); + data.add(Integer.parseInt(last)); + String a = "{\n" + + " \"header\": {\n" + + " \"stamp\": {\n" + + " \"secs\": 0,\n" + + " \"nsecs\": 0\n" + + " },\n" + + " \"frame_id\": \"\",\n" + + " \"seq\": 0\n" + + " },\n" + + " \"id\": 257,\n" + + " \"is_rtr\": false,\n" + + " \"is_extended\": false,\n" + + " \"is_error\": false,\n" + + " \"dlc\": 8,\n" + + " \"data\": [16, 1, 3, 1, 0, 0, 0, 7]\n" + + "}"; + JSONObject taskjo = JSONObject.fromObject(a); + taskjo.put("data", data); + Message toSend = new Message(taskjo.toString()); + echo.publish(toSend); + ros.disconnect(); + return null; + } + + public static JSONObject change(String point_code) { + //范围是-32768 ~ 32767 + JSONObject returnjo = new JSONObject(); +// String s = HexUtil.toHex(Integer.valueOf(point_code)); +// String first = "0"; +// String last = ""; +// if (s.length() <= 2) { +// last = point_code; +// } +// if (s.length() > 2) { +// last = s.substring(s.length() - 2, s.length()); +// first = s.substring(0, s.length() - 2); +// } + BigDecimal big = new BigDecimal(point_code); + BigDecimal big1 = new BigDecimal(256); + BigDecimal[] bigDecimals = big.divideAndRemainder(big1); + int first = bigDecimals[0].intValue(); + int last = bigDecimals[1].intValue(); + returnjo.put("first", first); + returnjo.put("last", last); + return returnjo; + } + + public static ServiceResponse topicSend(String requestString) { + if (StrUtil.isEmpty(requestString)) { + throw new BadRequestException("请求字符串不能为空!"); + } + Ros ros = new Ros(RosUtil.hostName, RosUtil.port); + ros.connect(); + // Ros ros = RosUtil.getRos(); + //std_msgs:https://blog.csdn.net/wengge987/article/details/50614957 + Topic echo = new Topic(ros, "/js_can", "lu_ps20l_msgs/Msg_CANFrame"); + Message toSend = new Message(JSONObject.fromObject(requestString).toString()); + echo.publish(toSend); + ros.disconnect(); + return null; + } + +} diff --git a/nladmin-system/src/main/java/org/nl/agv/wql/QAGVERROR.wql b/nladmin-system/src/main/java/org/nl/agv/wql/QAGVERROR.wql new file mode 100644 index 0000000..7eb0b69 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/agv/wql/QAGVERROR.wql @@ -0,0 +1,93 @@ +[交易说明] + 交易名: 销售订单 + 所属模块: + 功能简述: + 版权所有: + 表引用: + 版本经历: + +[数据库] + --指定数据库,为空采用默认值,默认为db.properties中列出的第一个库 + +[IO定义] + ################################################# + ## 表字段对应输入参数 + ################################################# + 输入.flag TYPEAS s_string + 输入.error_code TYPEAS s_string + + +[临时表] + --这边列出来的临时表就会在运行期动态创建 + +[临时变量] + --所有中间过程变量均可在此处定义 + +[业务过程] + + ########################################## + # 1、输入输出检查 # + ########################################## + + + ########################################## + # 2、主过程前处理 # + ########################################## + + + ########################################## + # 3、业务主过程 # + ########################################## + + + IF 输入.flag = "1" + QUERY + SELECT + * + FROM + ST_AGV_ERROR as agv + WHERE + 1=1 + OPTION 输入.error_code <> "" + agv.error_code = 输入.error_code + + ENDOPTION + ENDSELECT + ENDQUERY +ENDIF + + IF 输入.flag = "2" + QUERY + SELECT + task.task_uuid, + task.task_code AS task_num, + task.next_point_code AS target_point, + task.next_point_code AS target_point, + task.task_status, + task.task_status_name, + task.seq_num, + task.create_time + FROM + ST_TASK_INFO AS task + WHERE + 1 = 1 + AND task.is_delete = "0" + AND task.task_status <> "02" + ORDER BY + task.seq_num + ENDSELECT + ENDQUERY +ENDIF + IF 输入.flag = "3" + QUERY + SELECT + count(*) as num + FROM + ST_TASK_INFO as task + WHERE + 1=1 + and task.is_manualfinished="0" + and task.is_delete="0" + ENDSELECT + ENDQUERY +ENDIF diff --git a/nladmin-system/src/main/java/org/nl/agv/wql/agv.xls b/nladmin-system/src/main/java/org/nl/agv/wql/agv.xls new file mode 100644 index 0000000..ce593b3 Binary files /dev/null and b/nladmin-system/src/main/java/org/nl/agv/wql/agv.xls differ diff --git a/nladmin-system/src/main/java/org/nl/agv/wql/sys.xls b/nladmin-system/src/main/java/org/nl/agv/wql/sys.xls new file mode 100644 index 0000000..7c69402 Binary files /dev/null and b/nladmin-system/src/main/java/org/nl/agv/wql/sys.xls differ diff --git a/nladmin-system/src/main/java/org/nl/config/ConfigurerAdapter.java b/nladmin-system/src/main/java/org/nl/config/ConfigurerAdapter.java new file mode 100644 index 0000000..78797f5 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/config/ConfigurerAdapter.java @@ -0,0 +1,65 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * WebMvcConfigurer + * + * @author Zheng Jie + * @date 2018-11-30 + */ +@Configuration +@EnableWebMvc +public class ConfigurerAdapter implements WebMvcConfigurer { + + /** 文件配置 */ + private final FileProperties properties; + + public ConfigurerAdapter(FileProperties properties) { + this.properties = properties; + } + + @Bean + public CorsFilter corsFilter() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + CorsConfiguration config = new CorsConfiguration(); + config.setAllowCredentials(true); + config.addAllowedOrigin("*"); + config.addAllowedHeader("*"); + config.addAllowedMethod("*"); + source.registerCorsConfiguration("/**", config); + return new CorsFilter(source); + } + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + FileProperties.ElPath path = properties.getPath(); + String avatarUtl = "file:" + path.getAvatar().replace("\\","/"); + String pathUtl = "file:" + path.getPath().replace("\\","/"); + registry.addResourceHandler("/avatar/**").addResourceLocations(avatarUtl).setCachePeriod(0); + registry.addResourceHandler("/file/**").addResourceLocations(pathUtl).setCachePeriod(0); + registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/").setCachePeriod(0); + } +} diff --git a/nladmin-system/src/main/java/org/nl/config/DataBaseConfig.java b/nladmin-system/src/main/java/org/nl/config/DataBaseConfig.java new file mode 100644 index 0000000..38ac807 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/config/DataBaseConfig.java @@ -0,0 +1,25 @@ +package org.nl.config; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.util.StringUtils; +import lombok.extern.slf4j.Slf4j; +import org.nl.modules.mnt.util.DataTypeEnum; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; + +import javax.sql.DataSource; +import java.sql.DriverManager; +import java.sql.SQLException; + +@Configuration +@Slf4j +public class DataBaseConfig { + @Primary + @Bean(name = "dataSource") + @ConfigurationProperties(prefix = "spring.datasource.druid") + public DataSource dataSource() { + return new DruidDataSource(); + } +} diff --git a/nladmin-system/src/main/java/org/nl/config/WebSocketConfig.java b/nladmin-system/src/main/java/org/nl/config/WebSocketConfig.java new file mode 100644 index 0000000..28a447c --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/config/WebSocketConfig.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.server.standard.ServerEndpointExporter; + +/** + * @author ZhangHouYing + * @date 2019-08-24 15:44 + */ +@Configuration +public class WebSocketConfig { + + @Bean + public ServerEndpointExporter serverEndpointExporter() { + return new ServerEndpointExporter(); + } +} diff --git a/nladmin-system/src/main/java/org/nl/config/thread/AsyncTaskExecutePool.java b/nladmin-system/src/main/java/org/nl/config/thread/AsyncTaskExecutePool.java new file mode 100644 index 0000000..62c7dd6 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/config/thread/AsyncTaskExecutePool.java @@ -0,0 +1,69 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.config.thread; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.AsyncConfigurer; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * 异步任务线程池装配类 + * @author https://juejin.im/entry/5abb8f6951882555677e9da2 + * @date 2019年10月31日15:06:18 + */ +@Slf4j +@Configuration +public class AsyncTaskExecutePool implements AsyncConfigurer { + + /** 注入配置类 */ + private final AsyncTaskProperties config; + + public AsyncTaskExecutePool(AsyncTaskProperties config) { + this.config = config; + } + + @Override + public Executor getAsyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + //核心线程池大小 + executor.setCorePoolSize(config.getCorePoolSize()); + //最大线程数 + executor.setMaxPoolSize(config.getMaxPoolSize()); + //队列容量 + executor.setQueueCapacity(config.getQueueCapacity()); + //活跃时间 + executor.setKeepAliveSeconds(config.getKeepAliveSeconds()); + //线程名字前缀 + executor.setThreadNamePrefix("el-async-"); + // setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务 + // CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行 + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + executor.initialize(); + return executor; + } + + @Override + public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { + return (throwable, method, objects) -> { + log.error("===="+throwable.getMessage()+"====", throwable); + log.error("exception method:"+method.getName()); + }; + } +} diff --git a/nladmin-system/src/main/java/org/nl/config/thread/AsyncTaskProperties.java b/nladmin-system/src/main/java/org/nl/config/thread/AsyncTaskProperties.java new file mode 100644 index 0000000..3a1541e --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/config/thread/AsyncTaskProperties.java @@ -0,0 +1,39 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.config.thread; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 线程池配置属性类 + * @author https://juejin.im/entry/5abb8f6951882555677e9da2 + * @date 2019年10月31日14:58:18 + */ +@Data +@Component +@ConfigurationProperties(prefix = "task.pool") +public class AsyncTaskProperties { + + private int corePoolSize; + + private int maxPoolSize; + + private int keepAliveSeconds; + + private int queueCapacity; +} diff --git a/nladmin-system/src/main/java/org/nl/config/thread/TheadFactoryName.java b/nladmin-system/src/main/java/org/nl/config/thread/TheadFactoryName.java new file mode 100644 index 0000000..c4676b6 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/config/thread/TheadFactoryName.java @@ -0,0 +1,63 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.config.thread; + +import org.springframework.stereotype.Component; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * 自定义线程名称 + * @author Zheng Jie + * @date 2019年10月31日17:49:55 + */ +@Component +public class TheadFactoryName implements ThreadFactory { + + private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1); + private final ThreadGroup group; + private final AtomicInteger threadNumber = new AtomicInteger(1); + private final String namePrefix; + + public TheadFactoryName() { + this("el-pool"); + } + + private TheadFactoryName(String name){ + SecurityManager s = System.getSecurityManager(); + group = (s != null) ? s.getThreadGroup() : + Thread.currentThread().getThreadGroup(); + //此时namePrefix就是 name + 第几个用这个工厂创建线程池的 + this.namePrefix = name + + POOL_NUMBER.getAndIncrement(); + } + + @Override + public Thread newThread(Runnable r) { + //此时线程的名字 就是 namePrefix + -thread- + 这个线程池中第几个执行的线程 + Thread t = new Thread(group, r, + namePrefix + "-thread-"+threadNumber.getAndIncrement(), + 0); + if (t.isDaemon()) { + t.setDaemon(false); + } + if (t.getPriority() != Thread.NORM_PRIORITY) { + t.setPriority(Thread.NORM_PRIORITY); + } + return t; + } +} diff --git a/nladmin-system/src/main/java/org/nl/config/thread/ThreadPoolExecutorUtil.java b/nladmin-system/src/main/java/org/nl/config/thread/ThreadPoolExecutorUtil.java new file mode 100644 index 0000000..bbd4735 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/config/thread/ThreadPoolExecutorUtil.java @@ -0,0 +1,42 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.config.thread; + +import org.nl.utils.SpringContextHolder; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * 用于获取自定义线程池 + * @author Zheng Jie + * @date 2019年10月31日18:16:47 + */ +public class ThreadPoolExecutorUtil { + + public static ThreadPoolExecutor getPoll(){ + AsyncTaskProperties properties = SpringContextHolder.getBean(AsyncTaskProperties.class); + return new ThreadPoolExecutor( + properties.getCorePoolSize(), + properties.getMaxPoolSize(), + properties.getKeepAliveSeconds(), + TimeUnit.SECONDS, + new ArrayBlockingQueue<>(properties.getQueueCapacity()), + new TheadFactoryName() + ); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/domain/App.java b/nladmin-system/src/main/java/org/nl/modules/mnt/domain/App.java new file mode 100644 index 0000000..b06cfd3 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/domain/App.java @@ -0,0 +1,68 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.domain; + +import io.swagger.annotations.ApiModelProperty; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.bean.copier.CopyOptions; +import lombok.Getter; +import lombok.Setter; +import org.nl.base.BaseEntity; + +import javax.persistence.*; +import java.io.Serializable; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Entity +@Getter +@Setter +@Table(name="mnt_app") +public class App extends BaseEntity implements Serializable { + + @Id + @Column(name = "app_id") + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ApiModelProperty(value = "名称") + private String name; + + @ApiModelProperty(value = "端口") + private int port; + + @ApiModelProperty(value = "上传路径") + private String uploadPath; + + @ApiModelProperty(value = "部署路径") + private String deployPath; + + @ApiModelProperty(value = "备份路径") + private String backupPath; + + @ApiModelProperty(value = "启动脚本") + private String startScript; + + @ApiModelProperty(value = "部署脚本") + private String deployScript; + + public void copy(App source){ + BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true)); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/domain/Database.java b/nladmin-system/src/main/java/org/nl/modules/mnt/domain/Database.java new file mode 100644 index 0000000..4243eb9 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/domain/Database.java @@ -0,0 +1,58 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.domain; + +import io.swagger.annotations.ApiModelProperty; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.bean.copier.CopyOptions; +import lombok.Getter; +import lombok.Setter; +import org.nl.base.BaseEntity; + +import javax.persistence.*; +import java.io.Serializable; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Entity +@Getter +@Setter +@Table(name="mnt_database") +public class Database extends BaseEntity implements Serializable { + + @Id + @Column(name = "db_id") + @ApiModelProperty(value = "ID", hidden = true) + private String id; + + @ApiModelProperty(value = "数据库名称") + private String name; + + @ApiModelProperty(value = "数据库连接地址") + private String jdbcUrl; + + @ApiModelProperty(value = "数据库密码") + private String pwd; + + @ApiModelProperty(value = "用户名") + private String userName; + + public void copy(Database source){ + BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true)); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/domain/Deploy.java b/nladmin-system/src/main/java/org/nl/modules/mnt/domain/Deploy.java new file mode 100644 index 0000000..029d7a7 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/domain/Deploy.java @@ -0,0 +1,63 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.domain; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.bean.copier.CopyOptions; +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.NotFound; +import org.hibernate.annotations.NotFoundAction; +import org.nl.base.BaseEntity; + +import javax.persistence.*; +import java.io.Serializable; +import java.util.Set; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Entity +@Getter +@Setter +@Table(name="mnt_deploy") +public class Deploy extends BaseEntity implements Serializable { + + @Id + @Column(name = "deploy_id") + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToMany + @ApiModelProperty(name = "服务器", hidden = true) + @JoinTable(name = "mnt_deploy_server", + joinColumns = {@JoinColumn(name = "deploy_id",referencedColumnName = "deploy_id")}, + inverseJoinColumns = {@JoinColumn(name = "server_id",referencedColumnName = "server_id")}) + private Set deploys; + + @ManyToOne + @JoinColumn(name = "app_id") + @ApiModelProperty(value = "应用编号") + @NotFound(action= NotFoundAction.IGNORE) + private App app; + + public void copy(Deploy source){ + BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true)); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/domain/DeployHistory.java b/nladmin-system/src/main/java/org/nl/modules/mnt/domain/DeployHistory.java new file mode 100644 index 0000000..7a64721 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/domain/DeployHistory.java @@ -0,0 +1,62 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.domain; + +import io.swagger.annotations.ApiModelProperty; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.bean.copier.CopyOptions; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.CreationTimestamp; +import javax.persistence.*; +import java.io.Serializable; +import java.sql.Timestamp; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Entity +@Getter +@Setter +@Table(name="mnt_deploy_history") +public class DeployHistory implements Serializable { + + @Id + @Column(name = "history_id") + @ApiModelProperty(value = "ID", hidden = true) + private String id; + + @ApiModelProperty(value = "应用名称") + private String appName; + + @ApiModelProperty(value = "IP") + private String ip; + + @CreationTimestamp + @ApiModelProperty(value = "部署时间") + private Timestamp deployDate; + + @ApiModelProperty(value = "部署者") + private String deployUser; + + @ApiModelProperty(value = "部署ID") + private Long deployId; + + public void copy(DeployHistory source){ + BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true)); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/domain/ServerDeploy.java b/nladmin-system/src/main/java/org/nl/modules/mnt/domain/ServerDeploy.java new file mode 100644 index 0000000..ad676d1 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/domain/ServerDeploy.java @@ -0,0 +1,80 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.domain; + +import io.swagger.annotations.ApiModelProperty; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.bean.copier.CopyOptions; +import lombok.Getter; +import lombok.Setter; +import org.nl.base.BaseEntity; +import javax.persistence.*; +import java.io.Serializable; +import java.util.Objects; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Entity +@Getter +@Setter +@Table(name="mnt_server") +public class ServerDeploy extends BaseEntity implements Serializable { + + @Id + @Column(name = "server_id") + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ApiModelProperty(value = "服务器名称") + private String name; + + @ApiModelProperty(value = "IP") + private String ip; + + @ApiModelProperty(value = "端口") + private Integer port; + + @ApiModelProperty(value = "账号") + private String account; + + @ApiModelProperty(value = "密码") + private String password; + + public void copy(ServerDeploy source){ + BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true)); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ServerDeploy that = (ServerDeploy) o; + return Objects.equals(id, that.id) && + Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/repository/AppRepository.java b/nladmin-system/src/main/java/org/nl/modules/mnt/repository/AppRepository.java new file mode 100644 index 0000000..a0fd979 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/repository/AppRepository.java @@ -0,0 +1,27 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.repository; + +import org.nl.modules.mnt.domain.App; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +public interface AppRepository extends JpaRepository, JpaSpecificationExecutor { +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/repository/DatabaseRepository.java b/nladmin-system/src/main/java/org/nl/modules/mnt/repository/DatabaseRepository.java new file mode 100644 index 0000000..08cedda --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/repository/DatabaseRepository.java @@ -0,0 +1,27 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.repository; + +import org.nl.modules.mnt.domain.Database; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +public interface DatabaseRepository extends JpaRepository, JpaSpecificationExecutor { +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/repository/DeployHistoryRepository.java b/nladmin-system/src/main/java/org/nl/modules/mnt/repository/DeployHistoryRepository.java new file mode 100644 index 0000000..a2b3136 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/repository/DeployHistoryRepository.java @@ -0,0 +1,27 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.repository; + +import org.nl.modules.mnt.domain.DeployHistory; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +public interface DeployHistoryRepository extends JpaRepository, JpaSpecificationExecutor { +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/repository/DeployRepository.java b/nladmin-system/src/main/java/org/nl/modules/mnt/repository/DeployRepository.java new file mode 100644 index 0000000..6ae5964 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/repository/DeployRepository.java @@ -0,0 +1,27 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.repository; + +import org.nl.modules.mnt.domain.Deploy; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +public interface DeployRepository extends JpaRepository, JpaSpecificationExecutor { +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/repository/ServerDeployRepository.java b/nladmin-system/src/main/java/org/nl/modules/mnt/repository/ServerDeployRepository.java new file mode 100644 index 0000000..89c3701 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/repository/ServerDeployRepository.java @@ -0,0 +1,34 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.repository; + +import org.nl.modules.mnt.domain.ServerDeploy; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +public interface ServerDeployRepository extends JpaRepository, JpaSpecificationExecutor { + + /** + * 根据IP查询 + * @param ip / + * @return / + */ + ServerDeploy findByIp(String ip); +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/rest/AppController.java b/nladmin-system/src/main/java/org/nl/modules/mnt/rest/AppController.java new file mode 100644 index 0000000..c3e47b8 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/rest/AppController.java @@ -0,0 +1,87 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.rest; + +import org.nl.annotation.Log; +import org.nl.modules.mnt.service.dto.AppQueryCriteria; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.nl.modules.mnt.domain.App; +import org.nl.modules.mnt.service.AppService; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +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.io.IOException; +import java.util.Set; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@RestController +@RequiredArgsConstructor +@Api(tags = "运维:应用管理") +@RequestMapping("/api/app") +public class AppController { + + private final AppService appService; + + @ApiOperation("导出应用数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('app:list')") + public void download(HttpServletResponse response, AppQueryCriteria criteria) throws IOException { + appService.download(appService.queryAll(criteria), response); + } + + @ApiOperation(value = "查询应用") + @GetMapping + @PreAuthorize("@el.check('app:list')") + public ResponseEntity query(AppQueryCriteria criteria, Pageable pageable){ + return new ResponseEntity<>(appService.queryAll(criteria,pageable),HttpStatus.OK); + } + + @Log("新增应用") + @ApiOperation(value = "新增应用") + @PostMapping + @PreAuthorize("@el.check('app:add')") + public ResponseEntity create(@Validated @RequestBody App resources){ + appService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改应用") + @ApiOperation(value = "修改应用") + @PutMapping + @PreAuthorize("@el.check('app:edit')") + public ResponseEntity update(@Validated @RequestBody App resources){ + appService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除应用") + @ApiOperation(value = "删除应用") + @DeleteMapping + @PreAuthorize("@el.check('app:del')") + public ResponseEntity delete(@RequestBody Set ids){ + appService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/rest/DatabaseController.java b/nladmin-system/src/main/java/org/nl/modules/mnt/rest/DatabaseController.java new file mode 100644 index 0000000..90bbc97 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/rest/DatabaseController.java @@ -0,0 +1,123 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.rest; + +import org.nl.annotation.Log; +import org.nl.exception.BadRequestException; +import org.nl.modules.mnt.service.dto.DatabaseQueryCriteria; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.nl.modules.mnt.domain.Database; +import org.nl.modules.mnt.service.DatabaseService; +import org.nl.modules.mnt.service.dto.DatabaseDto; +import org.nl.modules.mnt.util.SqlUtils; +import org.nl.utils.FileUtil; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +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.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; +import java.util.Set; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Api(tags = "运维:数据库管理") +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/database") +public class DatabaseController { + + private final String fileSavePath = FileUtil.getTmpDirPath()+"/"; + private final DatabaseService databaseService; + + @ApiOperation("导出数据库数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('database:list')") + public void download(HttpServletResponse response, DatabaseQueryCriteria criteria) throws IOException { + databaseService.download(databaseService.queryAll(criteria), response); + } + + @ApiOperation(value = "查询数据库") + @GetMapping + @PreAuthorize("@el.check('database:list')") + public ResponseEntity query(DatabaseQueryCriteria criteria, Pageable pageable){ + return new ResponseEntity<>(databaseService.queryAll(criteria,pageable),HttpStatus.OK); + } + + @Log("新增数据库") + @ApiOperation(value = "新增数据库") + @PostMapping + @PreAuthorize("@el.check('database:add')") + public ResponseEntity create(@Validated @RequestBody Database resources){ + databaseService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改数据库") + @ApiOperation(value = "修改数据库") + @PutMapping + @PreAuthorize("@el.check('database:edit')") + public ResponseEntity update(@Validated @RequestBody Database resources){ + databaseService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除数据库") + @ApiOperation(value = "删除数据库") + @DeleteMapping + @PreAuthorize("@el.check('database:del')") + public ResponseEntity delete(@RequestBody Set ids){ + databaseService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } + + @Log("测试数据库链接") + @ApiOperation(value = "测试数据库链接") + @PostMapping("/testConnect") + @PreAuthorize("@el.check('database:testConnect')") + public ResponseEntity testConnect(@Validated @RequestBody Database resources){ + return new ResponseEntity<>(databaseService.testConnection(resources),HttpStatus.CREATED); + } + + @Log("执行SQL脚本") + @ApiOperation(value = "执行SQL脚本") + @PostMapping(value = "/upload") + @PreAuthorize("@el.check('database:add')") + public ResponseEntity upload(@RequestBody MultipartFile file, HttpServletRequest request)throws Exception{ + String id = request.getParameter("id"); + DatabaseDto database = databaseService.findById(id); + String fileName; + if(database != null){ + fileName = file.getOriginalFilename(); + File executeFile = new File(fileSavePath+fileName); + FileUtil.del(executeFile); + file.transferTo(executeFile); + String result = SqlUtils.executeFile(database.getJdbcUrl(), database.getUserName(), database.getPwd(), executeFile); + return new ResponseEntity<>(result,HttpStatus.OK); + }else{ + throw new BadRequestException("Database not exist"); + } + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/rest/DeployController.java b/nladmin-system/src/main/java/org/nl/modules/mnt/rest/DeployController.java new file mode 100644 index 0000000..cf9dd7c --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/rest/DeployController.java @@ -0,0 +1,153 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.rest; + +import org.nl.annotation.Log; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.nl.modules.mnt.domain.Deploy; +import org.nl.modules.mnt.domain.DeployHistory; +import org.nl.modules.mnt.service.DeployService; +import org.nl.modules.mnt.service.dto.DeployQueryCriteria; +import org.nl.utils.FileUtil; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +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.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@RestController +@Api(tags = "运维:部署管理") +@RequiredArgsConstructor +@RequestMapping("/api/deploy") +public class DeployController { + + private final String fileSavePath = FileUtil.getTmpDirPath()+"/"; + private final DeployService deployService; + + + @ApiOperation("导出部署数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('database:list')") + public void download(HttpServletResponse response, DeployQueryCriteria criteria) throws IOException { + deployService.download(deployService.queryAll(criteria), response); + } + + @ApiOperation(value = "查询部署") + @GetMapping + @PreAuthorize("@el.check('deploy:list')") + public ResponseEntity query(DeployQueryCriteria criteria, Pageable pageable){ + return new ResponseEntity<>(deployService.queryAll(criteria,pageable),HttpStatus.OK); + } + + @Log("新增部署") + @ApiOperation(value = "新增部署") + @PostMapping + @PreAuthorize("@el.check('deploy:add')") + public ResponseEntity create(@Validated @RequestBody Deploy resources){ + deployService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改部署") + @ApiOperation(value = "修改部署") + @PutMapping + @PreAuthorize("@el.check('deploy:edit')") + public ResponseEntity update(@Validated @RequestBody Deploy resources){ + deployService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除部署") + @ApiOperation(value = "删除部署") + @DeleteMapping + @PreAuthorize("@el.check('deploy:del')") + public ResponseEntity delete(@RequestBody Set ids){ + deployService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } + + @Log("上传文件部署") + @ApiOperation(value = "上传文件部署") + @PostMapping(value = "/upload") + @PreAuthorize("@el.check('deploy:edit')") + public ResponseEntity upload(@RequestBody MultipartFile file, HttpServletRequest request)throws Exception{ + Long id = Long.valueOf(request.getParameter("id")); + String fileName = ""; + if(file != null){ + fileName = file.getOriginalFilename(); + File deployFile = new File(fileSavePath+fileName); + FileUtil.del(deployFile); + file.transferTo(deployFile); + //文件下一步要根据文件名字来 + deployService.deploy(fileSavePath+fileName ,id); + }else{ + System.out.println("没有找到相对应的文件"); + } + System.out.println("文件上传的原名称为:"+ Objects.requireNonNull(file).getOriginalFilename()); + Map map = new HashMap<>(2); + map.put("errno",0); + map.put("id",fileName); + return new ResponseEntity<>(map,HttpStatus.OK); + } + @Log("系统还原") + @ApiOperation(value = "系统还原") + @PostMapping(value = "/serverReduction") + @PreAuthorize("@el.check('deploy:edit')") + public ResponseEntity serverReduction(@Validated @RequestBody DeployHistory resources){ + String result = deployService.serverReduction(resources); + return new ResponseEntity<>(result,HttpStatus.OK); + } + @Log("服务运行状态") + @ApiOperation(value = "服务运行状态") + @PostMapping(value = "/serverStatus") + @PreAuthorize("@el.check('deploy:edit')") + public ResponseEntity serverStatus(@Validated @RequestBody Deploy resources){ + String result = deployService.serverStatus(resources); + return new ResponseEntity<>(result,HttpStatus.OK); + } + @Log("启动服务") + @ApiOperation(value = "启动服务") + @PostMapping(value = "/startServer") + @PreAuthorize("@el.check('deploy:edit')") + public ResponseEntity startServer(@Validated @RequestBody Deploy resources){ + String result = deployService.startServer(resources); + return new ResponseEntity<>(result,HttpStatus.OK); + } + @Log("停止服务") + @ApiOperation(value = "停止服务") + @PostMapping(value = "/stopServer") + @PreAuthorize("@el.check('deploy:edit')") + public ResponseEntity stopServer(@Validated @RequestBody Deploy resources){ + String result = deployService.stopServer(resources); + return new ResponseEntity<>(result,HttpStatus.OK); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/rest/DeployHistoryController.java b/nladmin-system/src/main/java/org/nl/modules/mnt/rest/DeployHistoryController.java new file mode 100644 index 0000000..9fbc2ee --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/rest/DeployHistoryController.java @@ -0,0 +1,67 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.rest; + +import org.nl.annotation.Log; +import org.nl.modules.mnt.service.dto.DeployHistoryQueryCriteria; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.nl.modules.mnt.service.DeployHistoryService; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Set; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@RestController +@RequiredArgsConstructor +@Api(tags = "运维:部署历史管理") +@RequestMapping("/api/deployHistory") +public class DeployHistoryController { + + private final DeployHistoryService deployhistoryService; + + @ApiOperation("导出部署历史数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('deployHistory:list')") + public void download(HttpServletResponse response, DeployHistoryQueryCriteria criteria) throws IOException { + deployhistoryService.download(deployhistoryService.queryAll(criteria), response); + } + + @ApiOperation(value = "查询部署历史") + @GetMapping + @PreAuthorize("@el.check('deployHistory:list')") + public ResponseEntity query(DeployHistoryQueryCriteria criteria, Pageable pageable){ + return new ResponseEntity<>(deployhistoryService.queryAll(criteria,pageable),HttpStatus.OK); + } + + @Log("删除DeployHistory") + @ApiOperation(value = "删除部署历史") + @DeleteMapping + @PreAuthorize("@el.check('deployHistory:del')") + public ResponseEntity delete(@RequestBody Set ids){ + deployhistoryService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/rest/ServerDeployController.java b/nladmin-system/src/main/java/org/nl/modules/mnt/rest/ServerDeployController.java new file mode 100644 index 0000000..b0d9f94 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/rest/ServerDeployController.java @@ -0,0 +1,95 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.rest; + +import org.nl.annotation.Log; +import org.nl.modules.mnt.domain.ServerDeploy; +import org.nl.modules.mnt.service.ServerDeployService; +import org.nl.modules.mnt.service.dto.ServerDeployQueryCriteria; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +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.io.IOException; +import java.util.Set; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@RestController +@Api(tags = "运维:服务器管理") +@RequiredArgsConstructor +@RequestMapping("/api/serverDeploy") +public class ServerDeployController { + + private final ServerDeployService serverDeployService; + + @ApiOperation("导出服务器数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('serverDeploy:list')") + public void download(HttpServletResponse response, ServerDeployQueryCriteria criteria) throws IOException { + serverDeployService.download(serverDeployService.queryAll(criteria), response); + } + + @ApiOperation(value = "查询服务器") + @GetMapping + @PreAuthorize("@el.check('serverDeploy:list')") + public ResponseEntity query(ServerDeployQueryCriteria criteria, Pageable pageable){ + return new ResponseEntity<>(serverDeployService.queryAll(criteria,pageable),HttpStatus.OK); + } + + @Log("新增服务器") + @ApiOperation(value = "新增服务器") + @PostMapping + @PreAuthorize("@el.check('serverDeploy:add')") + public ResponseEntity create(@Validated @RequestBody ServerDeploy resources){ + serverDeployService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改服务器") + @ApiOperation(value = "修改服务器") + @PutMapping + @PreAuthorize("@el.check('serverDeploy:edit')") + public ResponseEntity update(@Validated @RequestBody ServerDeploy resources){ + serverDeployService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除服务器") + @ApiOperation(value = "删除Server") + @DeleteMapping + @PreAuthorize("@el.check('serverDeploy:del')") + public ResponseEntity delete(@RequestBody Set ids){ + serverDeployService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } + + @Log("测试连接服务器") + @ApiOperation(value = "测试连接服务器") + @PostMapping("/testConnect") + @PreAuthorize("@el.check('serverDeploy:add')") + public ResponseEntity testConnect(@Validated @RequestBody ServerDeploy resources){ + return new ResponseEntity<>(serverDeployService.testConnect(resources),HttpStatus.CREATED); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/AppService.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/AppService.java new file mode 100644 index 0000000..cac9fc3 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/AppService.java @@ -0,0 +1,81 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service; + +import org.nl.modules.mnt.domain.App; +import org.nl.modules.mnt.service.dto.AppDto; +import org.nl.modules.mnt.service.dto.AppQueryCriteria; +import org.springframework.data.domain.Pageable; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +public interface AppService { + + /** + * 分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Object queryAll(AppQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部数据 + * @param criteria 条件 + * @return / + */ + List queryAll(AppQueryCriteria criteria); + + /** + * 根据ID查询 + * @param id / + * @return / + */ + AppDto findById(Long id); + + /** + * 创建 + * @param resources / + */ + void create(App resources); + + /** + * 编辑 + * @param resources / + */ + void update(App resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set ids); + + /** + * 导出数据 + * @param queryAll / + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/DatabaseService.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/DatabaseService.java new file mode 100644 index 0000000..43f31b6 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/DatabaseService.java @@ -0,0 +1,88 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service; + +import org.nl.modules.mnt.domain.Database; +import org.nl.modules.mnt.service.dto.DatabaseDto; +import org.nl.modules.mnt.service.dto.DatabaseQueryCriteria; +import org.springframework.data.domain.Pageable; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** + * @author ZhangHouYing + * @date 2019-08-24 + */ +public interface DatabaseService { + + /** + * 分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Object queryAll(DatabaseQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部 + * @param criteria 条件 + * @return / + */ + List queryAll(DatabaseQueryCriteria criteria); + + /** + * 根据ID查询 + * @param id / + * @return / + */ + DatabaseDto findById(String id); + + /** + * 创建 + * @param resources / + */ + void create(Database resources); + + /** + * 编辑 + * @param resources / + */ + void update(Database resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set ids); + + /** + * 测试连接数据库 + * @param resources / + * @return / + */ + boolean testConnection(Database resources); + + /** + * 导出数据 + * @param queryAll / + * @param response / + * @throws IOException e + */ + void download(List queryAll, HttpServletResponse response) throws IOException; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/DeployHistoryService.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/DeployHistoryService.java new file mode 100644 index 0000000..6dd1ed6 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/DeployHistoryService.java @@ -0,0 +1,74 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service; + +import org.nl.modules.mnt.domain.DeployHistory; +import org.nl.modules.mnt.service.dto.DeployHistoryDto; +import org.nl.modules.mnt.service.dto.DeployHistoryQueryCriteria; +import org.springframework.data.domain.Pageable; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** + * @author zhanghouying + */ +public interface DeployHistoryService { + + /** + * 分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Object queryAll(DeployHistoryQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部 + * @param criteria 条件 + * @return / + */ + List queryAll(DeployHistoryQueryCriteria criteria); + + /** + * 根据ID查询 + * @param id / + * @return / + */ + DeployHistoryDto findById(String id); + + /** + * 创建 + * @param resources / + */ + void create(DeployHistory resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set ids); + + /** + * 导出数据 + * @param queryAll / + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/DeployService.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/DeployService.java new file mode 100644 index 0000000..df9e29a --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/DeployService.java @@ -0,0 +1,116 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service; + +import org.nl.modules.mnt.domain.Deploy; +import org.nl.modules.mnt.domain.DeployHistory; +import org.nl.modules.mnt.service.dto.DeployDto; +import org.nl.modules.mnt.service.dto.DeployQueryCriteria; +import org.springframework.data.domain.Pageable; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +public interface DeployService { + + /** + * 分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Object queryAll(DeployQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部数据 + * @param criteria 条件 + * @return / + */ + List queryAll(DeployQueryCriteria criteria); + + /** + * 根据ID查询 + * @param id / + * @return / + */ + DeployDto findById(Long id); + + /** + * 创建 + * @param resources / + */ + void create(Deploy resources); + + + /** + * 编辑 + * @param resources / + */ + void update(Deploy resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set ids); + + /** + * 部署文件到服务器 + * @param fileSavePath 文件路径 + * @param appId 应用ID + */ + void deploy(String fileSavePath, Long appId); + + /** + * 查询部署状态 + * @param resources / + * @return / + */ + String serverStatus(Deploy resources); + /** + * 启动服务 + * @param resources / + * @return / + */ + String startServer(Deploy resources); + /** + * 停止服务 + * @param resources / + * @return / + */ + String stopServer(Deploy resources); + + /** + * 停止服务 + * @param resources / + * @return / + */ + String serverReduction(DeployHistory resources); + + /** + * 导出数据 + * @param queryAll / + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/ServerDeployService.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/ServerDeployService.java new file mode 100644 index 0000000..2e451e4 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/ServerDeployService.java @@ -0,0 +1,95 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service; + +import org.nl.modules.mnt.domain.ServerDeploy; +import org.nl.modules.mnt.service.dto.ServerDeployDto; +import org.nl.modules.mnt.service.dto.ServerDeployQueryCriteria; +import org.springframework.data.domain.Pageable; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +public interface ServerDeployService { + + /** + * 分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Object queryAll(ServerDeployQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部数据 + * @param criteria 条件 + * @return / + */ + List queryAll(ServerDeployQueryCriteria criteria); + + /** + * 根据ID查询 + * @param id / + * @return / + */ + ServerDeployDto findById(Long id); + + /** + * 创建 + * @param resources / + */ + void create(ServerDeploy resources); + + /** + * 编辑 + * @param resources / + */ + void update(ServerDeploy resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set ids); + + /** + * 根据IP查询 + * @param ip / + * @return / + */ + ServerDeployDto findByIp(String ip); + + /** + * 测试登录服务器 + * @param resources / + * @return / + */ + Boolean testConnect(ServerDeploy resources); + + /** + * 导出数据 + * @param queryAll / + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/AppDto.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/AppDto.java new file mode 100644 index 0000000..1d72983 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/AppDto.java @@ -0,0 +1,71 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service.dto; + +import lombok.Getter; +import lombok.Setter; +import org.nl.base.BaseDTO; +import java.io.Serializable; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Getter +@Setter +public class AppDto extends BaseDTO implements Serializable { + + /** + * 应用编号 + */ + private Long id; + + /** + * 应用名称 + */ + private String name; + + /** + * 端口 + */ + private Integer port; + + /** + * 上传目录 + */ + private String uploadPath; + + /** + * 部署目录 + */ + private String deployPath; + + /** + * 备份目录 + */ + private String backupPath; + + /** + * 启动脚本 + */ + private String startScript; + + /** + * 部署脚本 + */ + private String deployScript; + +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/AppQueryCriteria.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/AppQueryCriteria.java new file mode 100644 index 0000000..2255c21 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/AppQueryCriteria.java @@ -0,0 +1,38 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service.dto; + +import lombok.Data; +import org.nl.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Data +public class AppQueryCriteria{ + + /** + * 模糊 + */ + @Query(type = Query.Type.INNER_LIKE) + private String name; + + @Query(type = Query.Type.BETWEEN) + private List createTime; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/DatabaseDto.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/DatabaseDto.java new file mode 100644 index 0000000..4abffce --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/DatabaseDto.java @@ -0,0 +1,55 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service.dto; + +import lombok.Getter; +import lombok.Setter; +import org.nl.base.BaseDTO; +import java.io.Serializable; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Getter +@Setter +public class DatabaseDto extends BaseDTO implements Serializable { + + /** + * id + */ + private String id; + + /** + * 数据库名称 + */ + private String name; + + /** + * 数据库连接地址 + */ + private String jdbcUrl; + + /** + * 数据库密码 + */ + private String pwd; + + /** + * 用户名 + */ + private String userName; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/DatabaseQueryCriteria.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/DatabaseQueryCriteria.java new file mode 100644 index 0000000..1735a3d --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/DatabaseQueryCriteria.java @@ -0,0 +1,44 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service.dto; + +import lombok.Data; +import org.nl.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Data +public class DatabaseQueryCriteria{ + + /** + * 模糊 + */ + @Query(type = Query.Type.INNER_LIKE) + private String name; + + /** + * 精确 + */ + @Query + private String jdbcUrl; + + @Query(type = Query.Type.BETWEEN) + private List createTime; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/DeployDto.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/DeployDto.java new file mode 100644 index 0000000..2ccb5fa --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/DeployDto.java @@ -0,0 +1,78 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service.dto; + +import cn.hutool.core.collection.CollectionUtil; +import lombok.Getter; +import lombok.Setter; +import org.nl.base.BaseDTO; +import java.io.Serializable; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Getter +@Setter +public class DeployDto extends BaseDTO implements Serializable { + + /** + * 部署编号 + */ + private String id; + + private AppDto app; + + /** + * 服务器 + */ + private Set deploys; + + private String servers; + + /** + * 服务状态 + */ + private String status; + + public String getServers() { + if(CollectionUtil.isNotEmpty(deploys)){ + return deploys.stream().map(ServerDeployDto::getName).collect(Collectors.joining(",")); + } + return servers; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DeployDto deployDto = (DeployDto) o; + return Objects.equals(id, deployDto.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/DeployHistoryDto.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/DeployHistoryDto.java new file mode 100644 index 0000000..6eb099c --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/DeployHistoryDto.java @@ -0,0 +1,58 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service.dto; + +import lombok.Data; +import java.io.Serializable; +import java.sql.Timestamp; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Data +public class DeployHistoryDto implements Serializable { + + /** + * 编号 + */ + private String id; + + /** + * 应用名称 + */ + private String appName; + + /** + * 部署IP + */ + private String ip; + + /** + * 部署时间 + */ + private Timestamp deployDate; + + /** + * 部署人员 + */ + private String deployUser; + + /** + * 部署编号 + */ + private Long deployId; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/DeployHistoryQueryCriteria.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/DeployHistoryQueryCriteria.java new file mode 100644 index 0000000..91d39d1 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/DeployHistoryQueryCriteria.java @@ -0,0 +1,41 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service.dto; + +import lombok.Data; +import org.nl.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Data +public class DeployHistoryQueryCriteria{ + + /** + * 精确 + */ + @Query(blurry = "appName,ip,deployUser") + private String blurry; + + @Query + private Long deployId; + + @Query(type = Query.Type.BETWEEN) + private List deployDate; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/DeployQueryCriteria.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/DeployQueryCriteria.java new file mode 100644 index 0000000..85d2fa9 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/DeployQueryCriteria.java @@ -0,0 +1,39 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service.dto; + +import lombok.Data; +import org.nl.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Data +public class DeployQueryCriteria{ + + /** + * 模糊 + */ + @Query(type = Query.Type.INNER_LIKE, propName = "name", joinName = "app") + private String appName; + + @Query(type = Query.Type.BETWEEN) + private List createTime; + +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/ServerDeployDto.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/ServerDeployDto.java new file mode 100644 index 0000000..5626c45 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/ServerDeployDto.java @@ -0,0 +1,61 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service.dto; + +import lombok.Getter; +import lombok.Setter; +import org.nl.base.BaseDTO; +import java.io.Serializable; +import java.util.Objects; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Getter +@Setter +public class ServerDeployDto extends BaseDTO implements Serializable { + + private Long id; + + private String name; + + private String ip; + + private Integer port; + + private String account; + + private String password; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ServerDeployDto that = (ServerDeployDto) o; + return Objects.equals(id, that.id) && + Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/ServerDeployQueryCriteria.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/ServerDeployQueryCriteria.java new file mode 100644 index 0000000..423e2a3 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/dto/ServerDeployQueryCriteria.java @@ -0,0 +1,38 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service.dto; + +import lombok.Data; +import org.nl.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Data +public class ServerDeployQueryCriteria{ + + /** + * 模糊 + */ + @Query(blurry = "name,ip,account") + private String blurry; + + @Query(type = Query.Type.BETWEEN) + private List createTime; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/impl/AppServiceImpl.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/impl/AppServiceImpl.java new file mode 100644 index 0000000..aff6957 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/impl/AppServiceImpl.java @@ -0,0 +1,123 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service.impl; + +import lombok.RequiredArgsConstructor; +import org.nl.modules.mnt.domain.App; +import org.nl.modules.mnt.repository.AppRepository; +import org.nl.modules.mnt.service.AppService; +import org.nl.modules.mnt.service.dto.AppDto; +import org.nl.modules.mnt.service.dto.AppQueryCriteria; +import org.nl.modules.mnt.service.mapstruct.AppMapper; +import org.nl.utils.FileUtil; +import org.nl.utils.PageUtil; +import org.nl.utils.QueryHelp; +import org.nl.utils.ValidationUtil; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Service +@RequiredArgsConstructor +public class AppServiceImpl implements AppService { + + private final AppRepository appRepository; + private final AppMapper appMapper; + + @Override + public Object queryAll(AppQueryCriteria criteria, Pageable pageable){ + Page page = appRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable); + return PageUtil.toPage(page.map(appMapper::toDto)); + } + + @Override + public List queryAll(AppQueryCriteria criteria){ + return appMapper.toDto(appRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder))); + } + + @Override + public AppDto findById(Long id) { + App app = appRepository.findById(id).orElseGet(App::new); + ValidationUtil.isNull(app.getId(),"App","id",id); + return appMapper.toDto(app); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(App resources) { + verification(resources); + appRepository.save(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(App resources) { + verification(resources); + App app = appRepository.findById(resources.getId()).orElseGet(App::new); + ValidationUtil.isNull(app.getId(),"App","id",resources.getId()); + app.copy(resources); + appRepository.save(app); + } + + private void verification(App resources){ + String opt = "/opt"; + String home = "/home"; + /* if (!(resources.getUploadPath().startsWith(opt) || resources.getUploadPath().startsWith(home))) { + throw new BadRequestException("文件只能上传在opt目录或者home目录 "); + } + if (!(resources.getDeployPath().startsWith(opt) || resources.getDeployPath().startsWith(home))) { + throw new BadRequestException("文件只能部署在opt目录或者home目录 "); + } + if (!(resources.getBackupPath().startsWith(opt) || resources.getBackupPath().startsWith(home))) { + throw new BadRequestException("文件只能备份在opt目录或者home目录 "); + }*/ + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set ids) { + for (Long id : ids) { + appRepository.deleteById(id); + } + } + + @Override + public void download(List queryAll, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (AppDto appDto : queryAll) { + Map map = new LinkedHashMap<>(); + map.put("应用名称", appDto.getName()); + map.put("端口", appDto.getPort()); + map.put("上传目录", appDto.getUploadPath()); + map.put("部署目录", appDto.getDeployPath()); + map.put("备份目录", appDto.getBackupPath()); + map.put("启动脚本", appDto.getStartScript()); + map.put("部署脚本", appDto.getDeployScript()); + map.put("创建日期", appDto.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/impl/DatabaseServiceImpl.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/impl/DatabaseServiceImpl.java new file mode 100644 index 0000000..04cb2fe --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/impl/DatabaseServiceImpl.java @@ -0,0 +1,117 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service.impl; + +import cn.hutool.core.util.IdUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.nl.modules.mnt.domain.Database; +import org.nl.modules.mnt.repository.DatabaseRepository; +import org.nl.modules.mnt.service.DatabaseService; +import org.nl.modules.mnt.service.dto.DatabaseDto; +import org.nl.modules.mnt.service.dto.DatabaseQueryCriteria; +import org.nl.modules.mnt.service.mapstruct.DatabaseMapper; +import org.nl.modules.mnt.util.SqlUtils; +import org.nl.utils.FileUtil; +import org.nl.utils.PageUtil; +import org.nl.utils.QueryHelp; +import org.nl.utils.ValidationUtil; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Slf4j +@Service +@RequiredArgsConstructor +public class DatabaseServiceImpl implements DatabaseService { + + private final DatabaseRepository databaseRepository; + private final DatabaseMapper databaseMapper; + + @Override + public Object queryAll(DatabaseQueryCriteria criteria, Pageable pageable){ + Page page = databaseRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable); + return PageUtil.toPage(page.map(databaseMapper::toDto)); + } + + @Override + public List queryAll(DatabaseQueryCriteria criteria){ + return databaseMapper.toDto(databaseRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder))); + } + + @Override + public DatabaseDto findById(String id) { + Database database = databaseRepository.findById(id).orElseGet(Database::new); + ValidationUtil.isNull(database.getId(),"Database","id",id); + return databaseMapper.toDto(database); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(Database resources) { + resources.setId(IdUtil.simpleUUID()); + databaseRepository.save(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(Database resources) { + Database database = databaseRepository.findById(resources.getId()).orElseGet(Database::new); + ValidationUtil.isNull(database.getId(),"Database","id",resources.getId()); + database.copy(resources); + databaseRepository.save(database); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set ids) { + for (String id : ids) { + databaseRepository.deleteById(id); + } + } + + @Override + public boolean testConnection(Database resources) { + try { + return SqlUtils.testConnection(resources.getJdbcUrl(), resources.getUserName(), resources.getPwd()); + } catch (Exception e) { + log.error(e.getMessage()); + return false; + } + } + + @Override + public void download(List queryAll, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (DatabaseDto databaseDto : queryAll) { + Map map = new LinkedHashMap<>(); + map.put("数据库名称", databaseDto.getName()); + map.put("数据库连接地址", databaseDto.getJdbcUrl()); + map.put("用户名", databaseDto.getUserName()); + map.put("创建日期", databaseDto.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/impl/DeployHistoryServiceImpl.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/impl/DeployHistoryServiceImpl.java new file mode 100644 index 0000000..3d311d9 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/impl/DeployHistoryServiceImpl.java @@ -0,0 +1,96 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service.impl; + +import cn.hutool.core.util.IdUtil; +import lombok.RequiredArgsConstructor; +import org.nl.modules.mnt.domain.DeployHistory; +import org.nl.modules.mnt.repository.DeployHistoryRepository; +import org.nl.modules.mnt.service.DeployHistoryService; +import org.nl.modules.mnt.service.dto.DeployHistoryDto; +import org.nl.modules.mnt.service.dto.DeployHistoryQueryCriteria; +import org.nl.modules.mnt.service.mapstruct.DeployHistoryMapper; +import org.nl.utils.FileUtil; +import org.nl.utils.PageUtil; +import org.nl.utils.QueryHelp; +import org.nl.utils.ValidationUtil; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Service +@RequiredArgsConstructor +public class DeployHistoryServiceImpl implements DeployHistoryService { + + private final DeployHistoryRepository deployhistoryRepository; + private final DeployHistoryMapper deployhistoryMapper; + + @Override + public Object queryAll(DeployHistoryQueryCriteria criteria, Pageable pageable){ + Page page = deployhistoryRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable); + return PageUtil.toPage(page.map(deployhistoryMapper::toDto)); + } + + @Override + public List queryAll(DeployHistoryQueryCriteria criteria){ + return deployhistoryMapper.toDto(deployhistoryRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder))); + } + + @Override + public DeployHistoryDto findById(String id) { + DeployHistory deployhistory = deployhistoryRepository.findById(id).orElseGet(DeployHistory::new); + ValidationUtil.isNull(deployhistory.getId(),"DeployHistory","id",id); + return deployhistoryMapper.toDto(deployhistory); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(DeployHistory resources) { + resources.setId(IdUtil.simpleUUID()); + deployhistoryRepository.save(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set ids) { + for (String id : ids) { + deployhistoryRepository.deleteById(id); + } + } + + @Override + public void download(List queryAll, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (DeployHistoryDto deployHistoryDto : queryAll) { + Map map = new LinkedHashMap<>(); + map.put("部署编号", deployHistoryDto.getDeployId()); + map.put("应用名称", deployHistoryDto.getAppName()); + map.put("部署IP", deployHistoryDto.getIp()); + map.put("部署时间", deployHistoryDto.getDeployDate()); + map.put("部署人员", deployHistoryDto.getDeployUser()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/impl/DeployServiceImpl.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/impl/DeployServiceImpl.java new file mode 100644 index 0000000..6b9f7b6 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/impl/DeployServiceImpl.java @@ -0,0 +1,431 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service.impl; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.nl.exception.BadRequestException; +import org.nl.modules.mnt.domain.App; +import org.nl.modules.mnt.domain.Deploy; +import org.nl.modules.mnt.domain.DeployHistory; +import org.nl.modules.mnt.domain.ServerDeploy; +import org.nl.modules.mnt.repository.DeployRepository; +import org.nl.modules.mnt.service.DeployHistoryService; +import org.nl.modules.mnt.service.DeployService; +import org.nl.modules.mnt.service.ServerDeployService; +import org.nl.modules.mnt.service.dto.AppDto; +import org.nl.modules.mnt.service.dto.DeployDto; +import org.nl.modules.mnt.service.dto.DeployQueryCriteria; +import org.nl.modules.mnt.service.dto.ServerDeployDto; +import org.nl.modules.mnt.service.mapstruct.DeployMapper; +import org.nl.modules.mnt.util.ExecuteShellUtil; +import org.nl.modules.mnt.util.ScpClientUtil; +import org.nl.modules.mnt.websocket.MsgType; +import org.nl.modules.mnt.websocket.SocketMsg; +import org.nl.modules.mnt.websocket.WebSocketServer; + +import org.nl.utils.*; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + +/** + * @author zhanghouying + * @date 2019-08-24 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class DeployServiceImpl implements DeployService { + + private final String FILE_SEPARATOR = "/"; + private final DeployRepository deployRepository; + private final DeployMapper deployMapper; + private final ServerDeployService serverDeployService; + private final DeployHistoryService deployHistoryService; + /** + * 循环次数 + */ + private final Integer count = 30; + + + @Override + public Object queryAll(DeployQueryCriteria criteria, Pageable pageable) { + Page page = deployRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable); + return PageUtil.toPage(page.map(deployMapper::toDto)); + } + + @Override + public List queryAll(DeployQueryCriteria criteria) { + return deployMapper.toDto(deployRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder))); + } + + @Override + public DeployDto findById(Long id) { + Deploy deploy = deployRepository.findById(id).orElseGet(Deploy::new); + ValidationUtil.isNull(deploy.getId(), "Deploy", "id", id); + return deployMapper.toDto(deploy); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(Deploy resources) { + deployRepository.save(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(Deploy resources) { + Deploy deploy = deployRepository.findById(resources.getId()).orElseGet(Deploy::new); + ValidationUtil.isNull(deploy.getId(), "Deploy", "id", resources.getId()); + deploy.copy(resources); + deployRepository.save(deploy); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set ids) { + for (Long id : ids) { + deployRepository.deleteById(id); + } + } + + @Override + public void deploy(String fileSavePath, Long id) { + deployApp(fileSavePath, id); + } + + /** + * @param fileSavePath 本机路径 + * @param id ID + */ + private void deployApp(String fileSavePath, Long id) { + + DeployDto deploy = findById(id); + if (deploy == null) { + sendMsg("部署信息不存在", MsgType.ERROR); + throw new BadRequestException("部署信息不存在"); + } + AppDto app = deploy.getApp(); + if (app == null) { + sendMsg("包对应应用信息不存在", MsgType.ERROR); + throw new BadRequestException("包对应应用信息不存在"); + } + int port = app.getPort(); + //这个是服务器部署路径 + String uploadPath = app.getUploadPath(); + StringBuilder sb = new StringBuilder(); + String msg; + Set deploys = deploy.getDeploys(); + for (ServerDeployDto deployDTO : deploys) { + String ip = deployDTO.getIp(); + ExecuteShellUtil executeShellUtil = getExecuteShellUtil(ip); + //判断是否第一次部署 + boolean flag = checkFile(executeShellUtil, app); + //第一步要确认服务器上有这个目录 + executeShellUtil.execute("mkdir -p " + app.getUploadPath()); + executeShellUtil.execute("mkdir -p " + app.getBackupPath()); + executeShellUtil.execute("mkdir -p " + app.getDeployPath()); + //上传文件 + msg = String.format("登陆到服务器:%s", ip); + ScpClientUtil scpClientUtil = getScpClientUtil(ip); + log.info(msg); + sendMsg(msg, MsgType.INFO); + msg = String.format("上传文件到服务器:%s
目录:%s下,请稍等...", ip, uploadPath); + sendMsg(msg, MsgType.INFO); + scpClientUtil.putFile(fileSavePath, uploadPath); + if (flag) { + sendMsg("停止原来应用", MsgType.INFO); + //停止应用 + stopApp(port, executeShellUtil); + sendMsg("备份原来应用", MsgType.INFO); + //备份应用 + backupApp(executeShellUtil, ip, app.getDeployPath()+FILE_SEPARATOR, app.getName(), app.getBackupPath()+FILE_SEPARATOR, id); + } + sendMsg("部署应用", MsgType.INFO); + //部署文件,并启动应用 + String deployScript = app.getDeployScript(); + executeShellUtil.execute(deployScript); + sleep(3); + sendMsg("应用部署中,请耐心等待部署结果,或者稍后手动查看部署状态", MsgType.INFO); + int i = 0; + boolean result = false; + // 由于启动应用需要时间,所以需要循环获取状态,如果超过30次,则认为是启动失败 + while (i++ < count){ + result = checkIsRunningStatus(port, executeShellUtil); + if(result){ + break; + } + // 休眠6秒 + sleep(6); + } + sb.append("服务器:").append(deployDTO.getName()).append("
应用:").append(app.getName()); + sendResultMsg(result, sb); + executeShellUtil.close(); + } + } + + private void sleep(int second) { + try { + Thread.sleep(second * 1000); + } catch (InterruptedException e) { + log.error(e.getMessage(),e); + } + } + + private void backupApp(ExecuteShellUtil executeShellUtil, String ip, String fileSavePath, String appName, String backupPath, Long id) { + String deployDate = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN); + StringBuilder sb = new StringBuilder(); + backupPath += appName + FILE_SEPARATOR + deployDate + "\n"; + sb.append("mkdir -p ").append(backupPath); + sb.append("mv -f ").append(fileSavePath); + sb.append(appName).append(" ").append(backupPath); + log.info("备份应用脚本:" + sb.toString()); + executeShellUtil.execute(sb.toString()); + //还原信息入库 + DeployHistory deployHistory = new DeployHistory(); + deployHistory.setAppName(appName); + deployHistory.setDeployUser(SecurityUtils.getCurrentUsername()); + deployHistory.setIp(ip); + deployHistory.setDeployId(id); + deployHistoryService.create(deployHistory); + } + + /** + * 停App + * + * @param port 端口 + * @param executeShellUtil / + */ + private void stopApp(int port, ExecuteShellUtil executeShellUtil) { + //发送停止命令 + executeShellUtil.execute(String.format("lsof -i :%d|grep -v \"PID\"|awk '{print \"kill -9\",$2}'|sh", port)); + + } + + /** + * 指定端口程序是否在运行 + * + * @param port 端口 + * @param executeShellUtil / + * @return true 正在运行 false 已经停止 + */ + private boolean checkIsRunningStatus(int port, ExecuteShellUtil executeShellUtil) { + String result = executeShellUtil.executeForResult(String.format("fuser -n tcp %d", port)); + return result.indexOf("/tcp:")>0; + } + + private void sendMsg(String msg, MsgType msgType) { + try { + WebSocketServer.sendInfo(new SocketMsg(msg, msgType), "deploy"); + } catch (IOException e) { + log.error(e.getMessage(),e); + } + } + + @Override + public String serverStatus(Deploy resources) { + Set serverDeploys = resources.getDeploys(); + App app = resources.getApp(); + for (ServerDeploy serverDeploy : serverDeploys) { + StringBuilder sb = new StringBuilder(); + ExecuteShellUtil executeShellUtil = getExecuteShellUtil(serverDeploy.getIp()); + sb.append("服务器:").append(serverDeploy.getName()).append("
应用:").append(app.getName()); + boolean result = checkIsRunningStatus(app.getPort(), executeShellUtil); + if (result) { + sb.append("
正在运行"); + sendMsg(sb.toString(), MsgType.INFO); + } else { + sb.append("
已停止!"); + sendMsg(sb.toString(), MsgType.ERROR); + } + log.info(sb.toString()); + executeShellUtil.close(); + } + return "执行完毕"; + } + + private boolean checkFile(ExecuteShellUtil executeShellUtil, AppDto appDTO) { + String result = executeShellUtil.executeForResult("find " + appDTO.getDeployPath() + " -name " + appDTO.getName()); + return result.indexOf(appDTO.getName())>0; + } + + /** + * 启动服务 + * @param resources / + * @return / + */ + @Override + public String startServer(Deploy resources) { + Set deploys = resources.getDeploys(); + App app = resources.getApp(); + for (ServerDeploy deploy : deploys) { + StringBuilder sb = new StringBuilder(); + ExecuteShellUtil executeShellUtil = getExecuteShellUtil(deploy.getIp()); + //为了防止重复启动,这里先停止应用 + stopApp(app.getPort(), executeShellUtil); + sb.append("服务器:").append(deploy.getName()).append("
应用:").append(app.getName()); + sendMsg("下发启动命令", MsgType.INFO); + executeShellUtil.execute(app.getStartScript()); + sleep(3); + sendMsg("应用启动中,请耐心等待启动结果,或者稍后手动查看运行状态", MsgType.INFO); + int i = 0; + boolean result = false; + // 由于启动应用需要时间,所以需要循环获取状态,如果超过30次,则认为是启动失败 + while (i++ < count){ + result = checkIsRunningStatus(app.getPort(), executeShellUtil); + if(result){ + break; + } + // 休眠6秒 + sleep(6); + } + sendResultMsg(result, sb); + log.info(sb.toString()); + executeShellUtil.close(); + } + return "执行完毕"; + } + + /** + * 停止服务 + * @param resources / + * @return / + */ + @Override + public String stopServer(Deploy resources) { + Set deploys = resources.getDeploys(); + App app = resources.getApp(); + for (ServerDeploy deploy : deploys) { + StringBuilder sb = new StringBuilder(); + ExecuteShellUtil executeShellUtil = getExecuteShellUtil(deploy.getIp()); + sb.append("服务器:").append(deploy.getName()).append("
应用:").append(app.getName()); + sendMsg("下发停止命令", MsgType.INFO); + //停止应用 + stopApp(app.getPort(), executeShellUtil); + sleep(1); + boolean result = checkIsRunningStatus(app.getPort(), executeShellUtil); + if (result) { + sb.append("
关闭失败!"); + sendMsg(sb.toString(), MsgType.ERROR); + } else { + sb.append("
关闭成功!"); + sendMsg(sb.toString(), MsgType.INFO); + } + log.info(sb.toString()); + executeShellUtil.close(); + } + return "执行完毕"; + } + + @Override + public String serverReduction(DeployHistory resources) { + Long deployId = resources.getDeployId(); + Deploy deployInfo = deployRepository.findById(deployId).orElseGet(Deploy::new); + String deployDate = DateUtil.format(resources.getDeployDate(), DatePattern.PURE_DATETIME_PATTERN); + App app = deployInfo.getApp(); + if (app == null) { + sendMsg("应用信息不存在:" + resources.getAppName(), MsgType.ERROR); + throw new BadRequestException("应用信息不存在:" + resources.getAppName()); + } + String backupPath = app.getBackupPath()+FILE_SEPARATOR; + backupPath += resources.getAppName() + FILE_SEPARATOR + deployDate; + //这个是服务器部署路径 + String deployPath = app.getDeployPath(); + String ip = resources.getIp(); + ExecuteShellUtil executeShellUtil = getExecuteShellUtil(ip); + String msg; + + msg = String.format("登陆到服务器:%s", ip); + log.info(msg); + sendMsg(msg, MsgType.INFO); + sendMsg("停止原来应用", MsgType.INFO); + //停止应用 + stopApp(app.getPort(), executeShellUtil); + //删除原来应用 + sendMsg("删除应用", MsgType.INFO); + executeShellUtil.execute("rm -rf " + deployPath + FILE_SEPARATOR + resources.getAppName()); + //还原应用 + sendMsg("还原应用", MsgType.INFO); + executeShellUtil.execute("cp -r " + backupPath + "/. " + deployPath); + sendMsg("启动应用", MsgType.INFO); + executeShellUtil.execute(app.getStartScript()); + sendMsg("应用启动中,请耐心等待启动结果,或者稍后手动查看启动状态", MsgType.INFO); + int i = 0; + boolean result = false; + // 由于启动应用需要时间,所以需要循环获取状态,如果超过30次,则认为是启动失败 + while (i++ < count){ + result = checkIsRunningStatus(app.getPort(), executeShellUtil); + if(result){ + break; + } + // 休眠6秒 + sleep(6); + } + StringBuilder sb = new StringBuilder(); + sb.append("服务器:").append(ip).append("
应用:").append(resources.getAppName()); + sendResultMsg(result, sb); + executeShellUtil.close(); + return ""; + } + + private ExecuteShellUtil getExecuteShellUtil(String ip) { + ServerDeployDto serverDeployDTO = serverDeployService.findByIp(ip); + if (serverDeployDTO == null) { + sendMsg("IP对应服务器信息不存在:" + ip, MsgType.ERROR); + throw new BadRequestException("IP对应服务器信息不存在:" + ip); + } + return new ExecuteShellUtil(ip, serverDeployDTO.getAccount(), serverDeployDTO.getPassword(),serverDeployDTO.getPort()); + } + + private ScpClientUtil getScpClientUtil(String ip) { + ServerDeployDto serverDeployDTO = serverDeployService.findByIp(ip); + if (serverDeployDTO == null) { + sendMsg("IP对应服务器信息不存在:" + ip, MsgType.ERROR); + throw new BadRequestException("IP对应服务器信息不存在:" + ip); + } + return ScpClientUtil.getInstance(ip, serverDeployDTO.getPort(), serverDeployDTO.getAccount(), serverDeployDTO.getPassword()); + } + + private void sendResultMsg(boolean result, StringBuilder sb) { + if (result) { + sb.append("
启动成功!"); + sendMsg(sb.toString(), MsgType.INFO); + } else { + sb.append("
启动失败!"); + sendMsg(sb.toString(), MsgType.ERROR); + } + } + + @Override + public void download(List queryAll, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (DeployDto deployDto : queryAll) { + Map map = new LinkedHashMap<>(); + map.put("应用名称", deployDto.getApp().getName()); + map.put("服务器", deployDto.getServers()); + map.put("部署日期", deployDto.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/impl/ServerDeployServiceImpl.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/impl/ServerDeployServiceImpl.java new file mode 100644 index 0000000..83f5f62 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/impl/ServerDeployServiceImpl.java @@ -0,0 +1,125 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service.impl; + +import lombok.RequiredArgsConstructor; +import org.nl.modules.mnt.domain.ServerDeploy; +import org.nl.modules.mnt.repository.ServerDeployRepository; +import org.nl.modules.mnt.service.ServerDeployService; +import org.nl.modules.mnt.service.dto.ServerDeployDto; +import org.nl.modules.mnt.service.dto.ServerDeployQueryCriteria; +import org.nl.modules.mnt.service.mapstruct.ServerDeployMapper; +import org.nl.modules.mnt.util.ExecuteShellUtil; +import org.nl.utils.FileUtil; +import org.nl.utils.PageUtil; +import org.nl.utils.QueryHelp; +import org.nl.utils.ValidationUtil; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Service +@RequiredArgsConstructor +public class ServerDeployServiceImpl implements ServerDeployService { + + private final ServerDeployRepository serverDeployRepository; + private final ServerDeployMapper serverDeployMapper; + + @Override + public Object queryAll(ServerDeployQueryCriteria criteria, Pageable pageable){ + Page page = serverDeployRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable); + return PageUtil.toPage(page.map(serverDeployMapper::toDto)); + } + + @Override + public List queryAll(ServerDeployQueryCriteria criteria){ + return serverDeployMapper.toDto(serverDeployRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder))); + } + + @Override + public ServerDeployDto findById(Long id) { + ServerDeploy server = serverDeployRepository.findById(id).orElseGet(ServerDeploy::new); + ValidationUtil.isNull(server.getId(),"ServerDeploy","id",id); + return serverDeployMapper.toDto(server); + } + + @Override + public ServerDeployDto findByIp(String ip) { + ServerDeploy deploy = serverDeployRepository.findByIp(ip); + return serverDeployMapper.toDto(deploy); + } + + @Override + public Boolean testConnect(ServerDeploy resources) { + ExecuteShellUtil executeShellUtil = null; + try { + executeShellUtil = new ExecuteShellUtil(resources.getIp(), resources.getAccount(), resources.getPassword(),resources.getPort()); + return executeShellUtil.execute("ls")==0; + } catch (Exception e) { + return false; + }finally { + if (executeShellUtil != null) { + executeShellUtil.close(); + } + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(ServerDeploy resources) { + serverDeployRepository.save(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(ServerDeploy resources) { + ServerDeploy serverDeploy = serverDeployRepository.findById(resources.getId()).orElseGet(ServerDeploy::new); + ValidationUtil.isNull( serverDeploy.getId(),"ServerDeploy","id",resources.getId()); + serverDeploy.copy(resources); + serverDeployRepository.save(serverDeploy); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set ids) { + for (Long id : ids) { + serverDeployRepository.deleteById(id); + } + } + + @Override + public void download(List queryAll, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (ServerDeployDto deployDto : queryAll) { + Map map = new LinkedHashMap<>(); + map.put("服务器名称", deployDto.getName()); + map.put("服务器IP", deployDto.getIp()); + map.put("端口", deployDto.getPort()); + map.put("账号", deployDto.getAccount()); + map.put("创建日期", deployDto.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/mapstruct/AppMapper.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/mapstruct/AppMapper.java new file mode 100644 index 0000000..ed68a2c --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/mapstruct/AppMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service.mapstruct; + +import org.nl.base.BaseMapper; +import org.nl.modules.mnt.domain.App; +import org.nl.modules.mnt.service.dto.AppDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Mapper(componentModel = "spring",uses = {},unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface AppMapper extends BaseMapper { + +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/mapstruct/DatabaseMapper.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/mapstruct/DatabaseMapper.java new file mode 100644 index 0000000..4af2bd3 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/mapstruct/DatabaseMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service.mapstruct; + +import org.nl.base.BaseMapper; +import org.nl.modules.mnt.domain.Database; +import org.nl.modules.mnt.service.dto.DatabaseDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface DatabaseMapper extends BaseMapper { + +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/mapstruct/DeployHistoryMapper.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/mapstruct/DeployHistoryMapper.java new file mode 100644 index 0000000..03cb5ab --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/mapstruct/DeployHistoryMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service.mapstruct; + +import org.nl.base.BaseMapper; +import org.nl.modules.mnt.domain.DeployHistory; +import org.nl.modules.mnt.service.dto.DeployHistoryDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Mapper(componentModel = "spring",uses = {},unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface DeployHistoryMapper extends BaseMapper { + +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/mapstruct/DeployMapper.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/mapstruct/DeployMapper.java new file mode 100644 index 0000000..faf5de7 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/mapstruct/DeployMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service.mapstruct; + +import org.nl.base.BaseMapper; +import org.nl.modules.mnt.domain.Deploy; +import org.nl.modules.mnt.service.dto.DeployDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Mapper(componentModel = "spring",uses = {AppMapper.class, ServerDeployMapper.class},unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface DeployMapper extends BaseMapper { + +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/service/mapstruct/ServerDeployMapper.java b/nladmin-system/src/main/java/org/nl/modules/mnt/service/mapstruct/ServerDeployMapper.java new file mode 100644 index 0000000..53b4b55 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/service/mapstruct/ServerDeployMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.service.mapstruct; + +import org.nl.base.BaseMapper; +import org.nl.modules.mnt.domain.ServerDeploy; +import org.nl.modules.mnt.service.dto.ServerDeployDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author zhanghouying +* @date 2019-08-24 +*/ +@Mapper(componentModel = "spring",uses = {},unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface ServerDeployMapper extends BaseMapper { + +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/util/DataTypeEnum.java b/nladmin-system/src/main/java/org/nl/modules/mnt/util/DataTypeEnum.java new file mode 100644 index 0000000..d02b179 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/util/DataTypeEnum.java @@ -0,0 +1,140 @@ +/* + * << + * Davinci + * == + * Copyright (C) 2016 - 2019 EDP + * == + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * >> + * + */ + +package org.nl.modules.mnt.util; +import lombok.extern.slf4j.Slf4j; + +/** + * @author / + */ +@Slf4j +@SuppressWarnings({"unchecked","all"}) +public enum DataTypeEnum { + + /** mysql */ + MYSQL("mysql", "mysql", "com.mysql.jdbc.Driver", "`", "`", "'", "'"), + + /** oracle */ + ORACLE("oracle", "oracle", "oracle.jdbc.driver.OracleDriver", "\"", "\"", "\"", "\""), + + /** sql server */ + SQLSERVER("sqlserver", "sqlserver", "com.microsoft.sqlserver.jdbc.SQLServerDriver", "\"", "\"", "\"", "\""), + + /** h2 */ + H2("h2", "h2", "org.h2.Driver", "`", "`", "\"", "\""), + + /** phoenix */ + PHOENIX("phoenix", "hbase phoenix", "org.apache.phoenix.jdbc.PhoenixDriver", "", "", "\"", "\""), + + /** mongo */ + MONGODB("mongo", "mongodb", "mongodb.jdbc.MongoDriver", "`", "`", "\"", "\""), + + /** sql4es */ + ELASTICSEARCH("sql4es", "elasticsearch", "nl.anchormen.sql4es.jdbc.ESDriver", "", "", "'", "'"), + + /** presto */ + PRESTO("presto", "presto", "com.facebook.presto.jdbc.PrestoDriver", "", "", "\"", "\""), + + /** moonbox */ + MOONBOX("moonbox", "moonbox", "moonbox.jdbc.MbDriver", "`", "`", "`", "`"), + + /** cassandra */ + CASSANDRA("cassandra", "cassandra", "com.github.adejanovski.cassandra.jdbc.CassandraDriver", "", "", "'", "'"), + + /** click house */ + CLICKHOUSE("clickhouse", "clickhouse", "ru.yandex.clickhouse.ClickHouseDriver", "", "", "\"", "\""), + + /** kylin */ + KYLIN("kylin", "kylin", "org.apache.kylin.jdbc.Driver", "\"", "\"", "\"", "\""), + + /** vertica */ + VERTICA("vertica", "vertica", "com.vertica.jdbc.Driver", "", "", "'", "'"), + + /** sap */ + HANA("sap", "sap hana", "com.sap.db.jdbc.Driver", "", "", "'", "'"), + + /** impala */ + IMPALA("impala", "impala", "com.cloudera.impala.jdbc41.Driver", "", "", "'", "'"); + + private String feature; + private String desc; + private String driver; + private String keywordPrefix; + private String keywordSuffix; + private String aliasPrefix; + private String aliasSuffix; + + private static final String JDBC_URL_PREFIX = "jdbc:"; + + DataTypeEnum(String feature, String desc, String driver, String keywordPrefix, String keywordSuffix, String aliasPrefix, String aliasSuffix) { + this.feature = feature; + this.desc = desc; + this.driver = driver; + this.keywordPrefix = keywordPrefix; + this.keywordSuffix = keywordSuffix; + this.aliasPrefix = aliasPrefix; + this.aliasSuffix = aliasSuffix; + } + + public static DataTypeEnum urlOf(String jdbcUrl) { + String url = jdbcUrl.toLowerCase().trim(); + for (DataTypeEnum dataTypeEnum : values()) { + if (url.startsWith(JDBC_URL_PREFIX + dataTypeEnum.feature)) { + try { + Class aClass = Class.forName(dataTypeEnum.getDriver()); + if (null == aClass) { + throw new RuntimeException("Unable to get driver instance for jdbcUrl: " + jdbcUrl); + } + } catch (ClassNotFoundException e) { + throw new RuntimeException("Unable to get driver instance: " + jdbcUrl); + } + return dataTypeEnum; + } + } + return null; + } + + public String getFeature() { + return feature; + } + + public String getDesc() { + return desc; + } + + public String getDriver() { + return driver; + } + + public String getKeywordPrefix() { + return keywordPrefix; + } + + public String getKeywordSuffix() { + return keywordSuffix; + } + + public String getAliasPrefix() { + return aliasPrefix; + } + + public String getAliasSuffix() { + return aliasSuffix; + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/util/ExecuteShellUtil.java b/nladmin-system/src/main/java/org/nl/modules/mnt/util/ExecuteShellUtil.java new file mode 100644 index 0000000..5840143 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/util/ExecuteShellUtil.java @@ -0,0 +1,101 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.util; + +import cn.hutool.core.io.IoUtil; +import com.jcraft.jsch.ChannelShell; +import com.jcraft.jsch.JSch; +import com.jcraft.jsch.Session; +import lombok.extern.slf4j.Slf4j; + +import java.io.*; +import java.util.Vector; + +/** + * 执行shell命令 + * + * @author: ZhangHouYing + * @date: 2019/8/10 + */ +@Slf4j +public class ExecuteShellUtil { + + private Vector stdout; + + Session session; + + public ExecuteShellUtil(final String ipAddress, final String username, final String password,int port) { + try { + JSch jsch = new JSch(); + session = jsch.getSession(username, ipAddress, port); + session.setPassword(password); + session.setConfig("StrictHostKeyChecking", "no"); + session.connect(3000); + } catch (Exception e) { + log.error(e.getMessage(),e); + } + + } + + public int execute(final String command) { + int returnCode = 0; + ChannelShell channel = null; + PrintWriter printWriter = null; + BufferedReader input = null; + stdout = new Vector(); + try { + channel = (ChannelShell) session.openChannel("shell"); + channel.connect(); + input = new BufferedReader(new InputStreamReader(channel.getInputStream())); + printWriter = new PrintWriter(channel.getOutputStream()); + printWriter.println(command); + printWriter.println("exit"); + printWriter.flush(); + log.info("The remote command is: "); + String line; + while ((line = input.readLine()) != null) { + stdout.add(line); + System.out.println(line); + } + } catch (Exception e) { + log.error(e.getMessage(),e); + return -1; + }finally { + IoUtil.close(printWriter); + IoUtil.close(input); + if (channel != null) { + channel.disconnect(); + } + } + return returnCode; + } + + public void close(){ + if (session != null) { + session.disconnect(); + } + } + + public String executeForResult(String command) { + execute(command); + StringBuilder sb = new StringBuilder(); + for (String str : stdout) { + sb.append(str); + } + return sb.toString(); + } + +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/util/ScpClientUtil.java b/nladmin-system/src/main/java/org/nl/modules/mnt/util/ScpClientUtil.java new file mode 100644 index 0000000..f76191d --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/util/ScpClientUtil.java @@ -0,0 +1,105 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.util; + +import ch.ethz.ssh2.Connection; +import ch.ethz.ssh2.SCPClient; +import com.google.common.collect.Maps; + +import java.io.IOException; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * 远程执行linux命令 + * @author: ZhangHouYing + * @date: 2019-08-10 10:06 + */ +public class ScpClientUtil { + + static private Map instance = Maps.newHashMap(); + + static synchronized public ScpClientUtil getInstance(String ip, int port, String username, String password) { + if (instance.get(ip) == null) { + instance.put(ip, new ScpClientUtil(ip, port, username, password)); + } + return instance.get(ip); + } + + public ScpClientUtil(String ip, int port, String username, String password) { + this.ip = ip; + this.port = port; + this.username = username; + this.password = password; + } + + public void getFile(String remoteFile, String localTargetDirectory) { + Connection conn = new Connection(ip, port); + try { + conn.connect(); + boolean isAuthenticated = conn.authenticateWithPassword(username, password); + if (!isAuthenticated) { + System.err.println("authentication failed"); + } + SCPClient client = new SCPClient(conn); + client.get(remoteFile, localTargetDirectory); + } catch (IOException ex) { + Logger.getLogger(SCPClient.class.getName()).log(Level.SEVERE, null, ex); + }finally{ + conn.close(); + } + } + + public void putFile(String localFile, String remoteTargetDirectory) { + putFile(localFile, null, remoteTargetDirectory); + } + + public void putFile(String localFile, String remoteFileName, String remoteTargetDirectory) { + putFile(localFile, remoteFileName, remoteTargetDirectory,null); + } + + public void putFile(String localFile, String remoteFileName, String remoteTargetDirectory, String mode) { + Connection conn = new Connection(ip, port); + try { + conn.connect(); + boolean isAuthenticated = conn.authenticateWithPassword(username, password); + if (!isAuthenticated) { + System.err.println("authentication failed"); + } + SCPClient client = new SCPClient(conn); + if ((mode == null) || (mode.length() == 0)) { + mode = "0600"; + } + if (remoteFileName == null) { + client.put(localFile, remoteTargetDirectory); + } else { + client.put(localFile, remoteFileName, remoteTargetDirectory, mode); + } + } catch (IOException ex) { + Logger.getLogger(ScpClientUtil.class.getName()).log(Level.SEVERE, null, ex); + }finally{ + conn.close(); + } + } + + private String ip; + private int port; + private String username; + private String password; + + +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/util/SqlUtils.java b/nladmin-system/src/main/java/org/nl/modules/mnt/util/SqlUtils.java new file mode 100644 index 0000000..08269be --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/util/SqlUtils.java @@ -0,0 +1,206 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.util; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.util.StringUtils; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; + +import javax.sql.DataSource; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.sql.*; +import java.util.List; + +/** + * @author / + */ +@Slf4j +public class SqlUtils { + + public static final String COLON = ":"; + + + /** + * 获取数据源 + * + * @param jdbcUrl / + * @param userName / + * @param password / + * @return DataSource + */ + private static DataSource getDataSource(String jdbcUrl, String userName, String password) { + DruidDataSource druidDataSource = new DruidDataSource(); + String className; + try { + className = DriverManager.getDriver(jdbcUrl.trim()).getClass().getName(); + } catch (SQLException e) { + throw new RuntimeException("Get class name error: =" + jdbcUrl); + } + if (StringUtils.isEmpty(className)) { + DataTypeEnum dataTypeEnum = DataTypeEnum.urlOf(jdbcUrl); + if (null == dataTypeEnum) { + throw new RuntimeException("Not supported data type: jdbcUrl=" + jdbcUrl); + } + druidDataSource.setDriverClassName(dataTypeEnum.getDriver()); + } else { + druidDataSource.setDriverClassName(className); + } + + + druidDataSource.setUrl(jdbcUrl); + druidDataSource.setUsername(userName); + druidDataSource.setPassword(password); + // 配置获取连接等待超时的时间 + druidDataSource.setMaxWait(3000); + // 配置初始化大小、最小、最大 + druidDataSource.setInitialSize(1); + druidDataSource.setMinIdle(1); + druidDataSource.setMaxActive(1); + + // 如果链接出现异常则直接判定为失败而不是一直重试 + druidDataSource.setBreakAfterAcquireFailure(true); + try { + druidDataSource.init(); + } catch (SQLException e) { + log.error("Exception during pool initialization", e); + throw new RuntimeException(e.getMessage()); + } + + return druidDataSource; + } + + private static Connection getConnection(String jdbcUrl, String userName, String password) { + DataSource dataSource = getDataSource(jdbcUrl, userName, password); + Connection connection = null; + try { + connection = dataSource.getConnection(); + } catch (Exception ignored) {} + try { + int timeOut = 5; + if (null == connection || connection.isClosed() || !connection.isValid(timeOut)) { + log.info("connection is closed or invalid, retry get connection!"); + connection = dataSource.getConnection(); + } + } catch (Exception e) { + log.error("create connection error, jdbcUrl: {}", jdbcUrl); + throw new RuntimeException("create connection error, jdbcUrl: " + jdbcUrl); + } + return connection; + } + + private static void releaseConnection(Connection connection) { + if (null != connection) { + try { + connection.close(); + } catch (Exception e) { + log.error(e.getMessage(),e); + log.error("connection close error:" + e.getMessage()); + } + } + } + + + public static void closeResult(ResultSet rs) { + if (rs != null) { + try { + rs.close(); + } catch (Exception e) { + log.error(e.getMessage(),e); + } + } + } + + public static boolean testConnection(String jdbcUrl, String userName, String password) { + Connection connection = null; + try { + connection = getConnection(jdbcUrl, userName, password); + if (null != connection) { + return true; + } + } catch (Exception e) { + log.info("Get connection failed:" + e.getMessage()); + } finally { + releaseConnection(connection); + } + return false; + } + + public static String executeFile(String jdbcUrl, String userName, String password, File sqlFile) { + Connection connection = getConnection(jdbcUrl, userName, password); + try { + batchExecute(connection, readSqlList(sqlFile)); + } catch (Exception e) { + log.error("sql脚本执行发生异常:{}",e.getMessage()); + return e.getMessage(); + }finally { + releaseConnection(connection); + } + return "success"; + } + + + /** + * 批量执行sql + * @param connection / + * @param sqlList / + */ + public static void batchExecute(Connection connection, List sqlList) throws SQLException { + Statement st = connection.createStatement(); + for (String sql : sqlList) { + if (sql.endsWith(";")) { + sql = sql.substring(0, sql.length() - 1); + } + st.addBatch(sql); + } + st.executeBatch(); + } + + /** + * 将文件中的sql语句以;为单位读取到列表中 + * @param sqlFile / + * @return / + * @throws Exception e + */ + private static List readSqlList(File sqlFile) throws Exception { + List sqlList = Lists.newArrayList(); + StringBuilder sb = new StringBuilder(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader( + new FileInputStream(sqlFile), StandardCharsets.UTF_8))) { + String tmp; + while ((tmp = reader.readLine()) != null) { + log.info("line:{}", tmp); + if (tmp.endsWith(";")) { + sb.append(tmp); + sqlList.add(sb.toString()); + sb.delete(0, sb.length()); + } else { + sb.append(tmp); + } + } + if (!"".endsWith(sb.toString().trim())) { + sqlList.add(sb.toString()); + } + } + + return sqlList; + } + +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/util/ZipUtils.java b/nladmin-system/src/main/java/org/nl/modules/mnt/util/ZipUtils.java new file mode 100644 index 0000000..8abee48 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/util/ZipUtils.java @@ -0,0 +1,159 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.util; + +import java.io.*; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; +import java.util.zip.ZipInputStream; + +/** + * @author: ZhangHouYing + * @date: 2019-08-10 13:34 + */ +public class ZipUtils { + /** + * 解压文件 + * + * @param zipFilePath 解压文件路径 + * @param outputFolder 输出解压文件路径 + */ + public static void unZipIt(String zipFilePath, String outputFolder) { + byte[] buffer = new byte[1024]; + + File folder = new File(outputFolder); + if (!folder.exists()) { + folder.mkdir(); + } + try { + //get the zip file content + ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFilePath)); + ZipEntry ze = zis.getNextEntry(); + while (ze != null) { + String fileName = ze.getName(); + File newFile = new File(outputFolder + File.separator + fileName); + System.out.println("file unzip : " + newFile.getAbsoluteFile()); + //大部分网络上的源码,这里没有判断子目录 + if (ze.isDirectory()) { + if (!newFile.mkdirs()) { + System.out.println("was not successful."); + } + } else { + if (!new File(newFile.getParent()).mkdirs()) { + System.out.println("was not successful."); + } + FileOutputStream fos = new FileOutputStream(newFile); + int len; + while ((len = zis.read(buffer)) != -1) { + fos.write(buffer, 0, len); + } + fos.close(); + } + ze = zis.getNextEntry(); + } + zis.closeEntry(); + zis.close(); + System.out.println("Done"); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void unzip(File source, String out) throws IOException { + try (ZipInputStream zis = new ZipInputStream(new FileInputStream(source))) { + + ZipEntry entry = zis.getNextEntry(); + + while (entry != null) { + + File file = new File(out, entry.getName()); + + if (entry.isDirectory()) { + if (!file.mkdirs()) { + System.out.println("was not successful."); + } + } else { + File parent = file.getParentFile(); + + if (!parent.exists()) { + if (!parent.mkdirs()) { + System.out.println("was not successful."); + } + } + + try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file))) { + + byte[] buffer = new byte[Math.toIntExact(entry.getSize())]; + + int location; + + while ((location = zis.read(buffer)) != -1) { + bos.write(buffer, 0, location); + } + } + } + entry = zis.getNextEntry(); + } + } + } + + /** + * 把所有文件都直接解压到指定目录(忽略子文件夹) + * + * @param zipFile + * @param folderPath + * @throws ZipException + * @throws IOException + */ + public static void upZipFile(File zipFile, String folderPath) throws ZipException, IOException { + File desDir = new File(folderPath); + if (!desDir.exists()) { + if (!desDir.mkdirs()) { + System.out.println("was not successful."); + } + } + ZipFile zf = new ZipFile(zipFile); + for (Enumeration entries = zf.entries(); entries.hasMoreElements(); ) { + ZipEntry entry = ((ZipEntry) entries.nextElement()); + InputStream in = zf.getInputStream(entry); + String str = folderPath; + File desFile = new File(str, java.net.URLEncoder.encode(entry.getName(), "UTF-8")); + + if (!desFile.exists()) { + File fileParentDir = desFile.getParentFile(); + if (!fileParentDir.exists()) { + if (!fileParentDir.mkdirs()) { + System.out.println("was not successful."); + } + } + } + + OutputStream out = new FileOutputStream(desFile); + byte[] buffer = new byte[1024 * 1024]; + int realLength = in.read(buffer); + while (realLength != -1) { + out.write(buffer, 0, realLength); + realLength = in.read(buffer); + } + + out.close(); + in.close(); + + } + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/websocket/MsgType.java b/nladmin-system/src/main/java/org/nl/modules/mnt/websocket/MsgType.java new file mode 100644 index 0000000..7ee6e83 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/websocket/MsgType.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.websocket; + +/** + * @author ZhangHouYing + * @date 2019-08-10 9:56 + */ +public enum MsgType { + /** 连接 */ + CONNECT, + /** 关闭 */ + CLOSE, + /** 信息 */ + INFO, + /** 错误 */ + ERROR +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/websocket/SocketMsg.java b/nladmin-system/src/main/java/org/nl/modules/mnt/websocket/SocketMsg.java new file mode 100644 index 0000000..9b5345f --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/websocket/SocketMsg.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.websocket; + +import lombok.Data; + +/** + * @author ZhangHouYing + * @date 2019-08-10 9:55 + */ +@Data +public class SocketMsg { + private Object msg; + private MsgType msgType; + + public SocketMsg(Object msg, MsgType msgType) { + this.msg = msg; + this.msgType = msgType; + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/mnt/websocket/WebSocketServer.java b/nladmin-system/src/main/java/org/nl/modules/mnt/websocket/WebSocketServer.java new file mode 100644 index 0000000..a162993 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/mnt/websocket/WebSocketServer.java @@ -0,0 +1,147 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.mnt.websocket; + +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.websocket.*; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; +import java.io.IOException; +import java.util.Objects; +import java.util.concurrent.CopyOnWriteArraySet; + +/** + * @author ZhangHouYing + * @date 2019-08-10 15:46 + */ +@ServerEndpoint("/webSocket/{sid}") +@Slf4j +@Component +public class WebSocketServer { + + /** + * concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。 + */ + private static CopyOnWriteArraySet webSocketSet = new CopyOnWriteArraySet(); + + /** + * 与某个客户端的连接会话,需要通过它来给客户端发送数据 + */ + private Session session; + + /** + * 接收sid + */ + private String sid = ""; + + /** + * 连接建立成功调用的方法 + */ + @OnOpen + public void onOpen(Session session, @PathParam("sid") String sid) { + System.out.println("websokcet_onOpen:" + sid); + this.session = session; + //如果存在就先删除一个,防止重复推送消息 + for (WebSocketServer webSocket : webSocketSet) { + if (webSocket.sid.equals(sid)) { + webSocketSet.remove(webSocket); + } + } + webSocketSet.add(this); + this.sid = sid; + } + + /** + * 连接关闭调用的方法 + */ + @OnClose + public void onClose() { + webSocketSet.remove(this); + } + + /** + * 收到客户端消息后调用的方法 + * + * @param message 客户端发送过来的消息 + */ + @OnMessage + public void onMessage(String message, Session session) { + System.out.println("收到来" + sid + "的信息:" + message); + log.info("收到来" + sid + "的信息:" + message); + //群发消息 + for (WebSocketServer item : webSocketSet) { + try { + item.sendMessage(message); + } catch (IOException e) { + log.error(e.getMessage(), e); + } + } + } + + @OnError + public void onError(Session session, Throwable error) { + log.error("发生错误"); + error.printStackTrace(); + } + + /** + * 实现服务器主动推送 + */ + private void sendMessage(String message) throws IOException { + this.session.getBasicRemote().sendText(message); + } + + + /** + * 群发自定义消息 + */ + public static void sendInfo(SocketMsg socketMsg, @PathParam("sid") String sid) throws IOException { + String message = JSONObject.toJSONString(socketMsg); + log.info("推送消息到" + sid + ",推送内容:" + message); + for (WebSocketServer item : webSocketSet) { + try { + //这里可以设定只推送给这个sid的,为null则全部推送 + if (sid == null) { + item.sendMessage(message); + } else if (item.sid.equals(sid)) { + item.sendMessage(message); + } + } catch (IOException ignored) { + } + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + WebSocketServer that = (WebSocketServer) o; + return Objects.equals(session, that.session) && + Objects.equals(sid, that.sid); + } + + @Override + public int hashCode() { + return Objects.hash(session, sid); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/quartz/config/JobRunner.java b/nladmin-system/src/main/java/org/nl/modules/quartz/config/JobRunner.java new file mode 100644 index 0000000..8eb12eb --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/quartz/config/JobRunner.java @@ -0,0 +1,50 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.quartz.config; + +import lombok.RequiredArgsConstructor; +import org.nl.modules.quartz.repository.QuartzJobRepository; +import org.nl.modules.quartz.utils.QuartzManage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; + +/** + * @author Zheng Jie + * @date 2019-01-07 + */ +@Component +@RequiredArgsConstructor +public class JobRunner implements ApplicationRunner { + private static final Logger log = LoggerFactory.getLogger(JobRunner.class); + private final QuartzJobRepository quartzJobRepository; + private final QuartzManage quartzManage; + + /** + * 项目启动时重新激活启用的定时任务 + * + * @param applicationArguments / + */ + @Override + public void run(ApplicationArguments applicationArguments) { + /* log.info("--------------------注入定时任务---------------------"); + List quartzJobs = quartzJobRepository.findByIsPauseIsFalse(); + quartzJobs.forEach(quartzManage::addJob); + log.info("--------------------定时任务注入完成---------------------");*/ + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/quartz/config/QuartzConfig.java b/nladmin-system/src/main/java/org/nl/modules/quartz/config/QuartzConfig.java new file mode 100644 index 0000000..27baea9 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/quartz/config/QuartzConfig.java @@ -0,0 +1,72 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.quartz.config; + +import org.quartz.Scheduler; +import org.quartz.spi.TriggerFiredBundle; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.quartz.AdaptableJobFactory; +import org.springframework.scheduling.quartz.SchedulerFactoryBean; +import org.springframework.stereotype.Component; + +/** + * 定时任务配置 + * @author / + * @date 2019-01-07 + */ +@Configuration +public class QuartzConfig { + + /** + * 解决Job中注入Spring Bean为null的问题 + */ + @Component("quartzJobFactory") + public static class QuartzJobFactory extends AdaptableJobFactory { + + private final AutowireCapableBeanFactory capableBeanFactory; + + public QuartzJobFactory(AutowireCapableBeanFactory capableBeanFactory) { + this.capableBeanFactory = capableBeanFactory; + } + + @Override + protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { + + //调用父类的方法 + Object jobInstance = super.createJobInstance(bundle); + capableBeanFactory.autowireBean(jobInstance); + return jobInstance; + } + } + + /** + * 注入scheduler到spring + * @param quartzJobFactory / + * @return Scheduler + * @throws Exception / + */ + @Bean(name = "scheduler") + public Scheduler scheduler(QuartzJobFactory quartzJobFactory) throws Exception { + SchedulerFactoryBean factoryBean=new SchedulerFactoryBean(); + factoryBean.setJobFactory(quartzJobFactory); + factoryBean.afterPropertiesSet(); + Scheduler scheduler=factoryBean.getScheduler(); + scheduler.start(); + return scheduler; + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/quartz/domain/QuartzJob.java b/nladmin-system/src/main/java/org/nl/modules/quartz/domain/QuartzJob.java new file mode 100644 index 0000000..995417b --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/quartz/domain/QuartzJob.java @@ -0,0 +1,85 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.quartz.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import org.nl.base.BaseEntity; +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + * @author Zheng Jie + * @date 2019-01-07 + */ +@Getter +@Setter +@Entity +@Table(name = "sys_quartz_job") +public class QuartzJob extends BaseEntity implements Serializable { + + public static final String JOB_KEY = "JOB_KEY"; + + @Id + @Column(name = "job_id") + @NotNull(groups = {Update.class}) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Transient + @ApiModelProperty(value = "用于子任务唯一标识", hidden = true) + private String uuid; + + @ApiModelProperty(value = "定时器名称") + private String jobName; + + @NotBlank + @ApiModelProperty(value = "Bean名称") + private String beanName; + + @NotBlank + @ApiModelProperty(value = "方法名称") + private String methodName; + + @ApiModelProperty(value = "参数") + private String params; + + @NotBlank + @ApiModelProperty(value = "cron表达式") + private String cronExpression; + + @ApiModelProperty(value = "状态,暂时或启动") + private Boolean isPause = false; + + @ApiModelProperty(value = "负责人") + private String personInCharge; + + @ApiModelProperty(value = "报警邮箱") + private String email; + + @ApiModelProperty(value = "子任务") + private String subTask; + + @ApiModelProperty(value = "失败后暂停") + private Boolean pauseAfterFailure; + + @NotBlank + @ApiModelProperty(value = "备注") + private String description; +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/quartz/domain/QuartzLog.java b/nladmin-system/src/main/java/org/nl/modules/quartz/domain/QuartzLog.java new file mode 100644 index 0000000..047bb92 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/quartz/domain/QuartzLog.java @@ -0,0 +1,67 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.quartz.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.hibernate.annotations.CreationTimestamp; +import javax.persistence.*; +import java.io.Serializable; +import java.sql.Timestamp; + +/** + * @author Zheng Jie + * @date 2019-01-07 + */ +@Entity +@Data +@Table(name = "sys_quartz_log") +public class QuartzLog implements Serializable { + + @Id + @Column(name = "log_id") + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ApiModelProperty(value = "任务名称", hidden = true) + private String jobName; + + @ApiModelProperty(value = "bean名称", hidden = true) + private String beanName; + + @ApiModelProperty(value = "方法名称", hidden = true) + private String methodName; + + @ApiModelProperty(value = "参数", hidden = true) + private String params; + + @ApiModelProperty(value = "cron表达式", hidden = true) + private String cronExpression; + + @ApiModelProperty(value = "状态", hidden = true) + private Boolean isSuccess; + + @ApiModelProperty(value = "异常详情", hidden = true) + private String exceptionDetail; + + @ApiModelProperty(value = "执行耗时", hidden = true) + private Long time; + + @CreationTimestamp + @ApiModelProperty(value = "创建时间", hidden = true) + private Timestamp createTime; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/quartz/repository/QuartzJobRepository.java b/nladmin-system/src/main/java/org/nl/modules/quartz/repository/QuartzJobRepository.java new file mode 100644 index 0000000..4d3d542 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/quartz/repository/QuartzJobRepository.java @@ -0,0 +1,34 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.quartz.repository; + +import org.nl.modules.quartz.domain.QuartzJob; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import java.util.List; + +/** + * @author Zheng Jie + * @date 2019-01-07 + */ +public interface QuartzJobRepository extends JpaRepository, JpaSpecificationExecutor { + + /** + * 查询启用的任务 + * @return List + */ + List findByIsPauseIsFalse(); +} diff --git a/nladmin-system/src/main/java/org/nl/modules/quartz/repository/QuartzLogRepository.java b/nladmin-system/src/main/java/org/nl/modules/quartz/repository/QuartzLogRepository.java new file mode 100644 index 0000000..54c5101 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/quartz/repository/QuartzLogRepository.java @@ -0,0 +1,28 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.quartz.repository; + +import org.nl.modules.quartz.domain.QuartzLog; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** + * @author Zheng Jie + * @date 2019-01-07 + */ +public interface QuartzLogRepository extends JpaRepository, JpaSpecificationExecutor { + +} diff --git a/nladmin-system/src/main/java/org/nl/modules/quartz/rest/QuartzJobController.java b/nladmin-system/src/main/java/org/nl/modules/quartz/rest/QuartzJobController.java new file mode 100644 index 0000000..267da59 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/quartz/rest/QuartzJobController.java @@ -0,0 +1,126 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.quartz.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.nl.annotation.Log; +import org.nl.exception.BadRequestException; +import org.nl.modules.quartz.domain.QuartzJob; +import org.nl.modules.quartz.service.QuartzJobService; +import org.nl.modules.quartz.service.dto.JobQueryCriteria; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +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.io.IOException; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2019-01-07 + */ +@Slf4j +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/jobs") +@Api(tags = "系统:定时任务管理") +public class QuartzJobController { + + private static final String ENTITY_NAME = "quartzJob"; + private final QuartzJobService quartzJobService; + + @ApiOperation("查询定时任务") + @GetMapping + @PreAuthorize("@el.check('timing:list')") + public ResponseEntity query(JobQueryCriteria criteria, Pageable pageable){ + return new ResponseEntity<>(quartzJobService.queryAll(criteria,pageable), HttpStatus.OK); + } + + @ApiOperation("导出任务数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('timing:list')") + public void download(HttpServletResponse response, JobQueryCriteria criteria) throws IOException { + quartzJobService.download(quartzJobService.queryAll(criteria), response); + } + + @ApiOperation("导出日志数据") + @GetMapping(value = "/logs/download") + @PreAuthorize("@el.check('timing:list')") + public void downloadLog(HttpServletResponse response, JobQueryCriteria criteria) throws IOException { + quartzJobService.downloadLog(quartzJobService.queryAllLog(criteria), response); + } + + @ApiOperation("查询任务执行日志") + @GetMapping(value = "/logs") + @PreAuthorize("@el.check('timing:list')") + public ResponseEntity queryJobLog(JobQueryCriteria criteria, Pageable pageable){ + return new ResponseEntity<>(quartzJobService.queryAllLog(criteria,pageable), HttpStatus.OK); + } + + @Log("新增定时任务") + @ApiOperation("新增定时任务") + @PostMapping + @PreAuthorize("@el.check('timing:add')") + public ResponseEntity create(@Validated @RequestBody QuartzJob resources){ + if (resources.getId() != null) { + throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID"); + } + quartzJobService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改定时任务") + @ApiOperation("修改定时任务") + @PutMapping + @PreAuthorize("@el.check('timing:edit')") + public ResponseEntity update(@Validated(QuartzJob.Update.class) @RequestBody QuartzJob resources){ + quartzJobService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("更改定时任务状态") + @ApiOperation("更改定时任务状态") + @PutMapping(value = "/{id}") + @PreAuthorize("@el.check('timing:edit')") + public ResponseEntity update(@PathVariable Long id){ + quartzJobService.updateIsPause(quartzJobService.findById(id)); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("执行定时任务") + @ApiOperation("执行定时任务") + @PutMapping(value = "/exec/{id}") + @PreAuthorize("@el.check('timing:edit')") + public ResponseEntity execution(@PathVariable Long id){ + quartzJobService.execution(quartzJobService.findById(id)); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除定时任务") + @ApiOperation("删除定时任务") + @DeleteMapping + @PreAuthorize("@el.check('timing:del')") + public ResponseEntity delete(@RequestBody Set ids){ + quartzJobService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/quartz/service/QuartzJobService.java b/nladmin-system/src/main/java/org/nl/modules/quartz/service/QuartzJobService.java new file mode 100644 index 0000000..171fe3d --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/quartz/service/QuartzJobService.java @@ -0,0 +1,122 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.quartz.service; + +import org.nl.modules.quartz.domain.QuartzJob; +import org.nl.modules.quartz.domain.QuartzLog; +import org.nl.modules.quartz.service.dto.JobQueryCriteria; +import org.springframework.data.domain.Pageable; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2019-01-07 + */ +public interface QuartzJobService { + + /** + * 分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Object queryAll(JobQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部 + * @param criteria 条件 + * @return / + */ + List queryAll(JobQueryCriteria criteria); + + /** + * 分页查询日志 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Object queryAllLog(JobQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部 + * @param criteria 条件 + * @return / + */ + List queryAllLog(JobQueryCriteria criteria); + + /** + * 创建 + * @param resources / + */ + void create(QuartzJob resources); + + /** + * 编辑 + * @param resources / + */ + void update(QuartzJob resources); + + /** + * 删除任务 + * @param ids / + */ + void delete(Set ids); + + /** + * 根据ID查询 + * @param id ID + * @return / + */ + QuartzJob findById(Long id); + + /** + * 更改定时任务状态 + * @param quartzJob / + */ + void updateIsPause(QuartzJob quartzJob); + + /** + * 立即执行定时任务 + * @param quartzJob / + */ + void execution(QuartzJob quartzJob); + + /** + * 导出定时任务 + * @param queryAll 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; + + /** + * 导出定时任务日志 + * @param queryAllLog 待导出的数据 + * @param response / + * @throws IOException / + */ + void downloadLog(List queryAllLog, HttpServletResponse response) throws IOException; + + /** + * 执行子任务 + * @param tasks / + * @throws InterruptedException / + */ + void executionSubJob(String[] tasks) throws InterruptedException; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/quartz/service/dto/JobQueryCriteria.java b/nladmin-system/src/main/java/org/nl/modules/quartz/service/dto/JobQueryCriteria.java new file mode 100644 index 0000000..ba5953e --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/quartz/service/dto/JobQueryCriteria.java @@ -0,0 +1,38 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.quartz.service.dto; + +import lombok.Data; +import org.nl.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** + * @author Zheng Jie + * @date 2019-6-4 10:33:02 + */ +@Data +public class JobQueryCriteria { + + @Query(type = Query.Type.INNER_LIKE) + private String jobName; + + @Query + private Boolean isSuccess; + + @Query(type = Query.Type.BETWEEN) + private List createTime; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/quartz/service/impl/QuartzJobServiceImpl.java b/nladmin-system/src/main/java/org/nl/modules/quartz/service/impl/QuartzJobServiceImpl.java new file mode 100644 index 0000000..93646e6 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/quartz/service/impl/QuartzJobServiceImpl.java @@ -0,0 +1,193 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.quartz.service.impl; + +import cn.hutool.core.util.IdUtil; +import lombok.RequiredArgsConstructor; +import org.nl.exception.BadRequestException; +import org.nl.modules.quartz.domain.QuartzJob; +import org.nl.modules.quartz.domain.QuartzLog; +import org.nl.modules.quartz.repository.QuartzJobRepository; +import org.nl.modules.quartz.repository.QuartzLogRepository; +import org.nl.modules.quartz.service.QuartzJobService; +import org.nl.modules.quartz.service.dto.JobQueryCriteria; +import org.nl.modules.quartz.utils.QuartzManage; + +import org.nl.utils.*; +import org.quartz.CronExpression; +import org.springframework.data.domain.Pageable; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + +/** + * @author Zheng Jie + * @date 2019-01-07 + */ +@RequiredArgsConstructor +@Service(value = "quartzJobService") +public class QuartzJobServiceImpl implements QuartzJobService { + + private final QuartzJobRepository quartzJobRepository; + private final QuartzLogRepository quartzLogRepository; + private final QuartzManage quartzManage; + private final RedisUtils redisUtils; + + @Override + public Object queryAll(JobQueryCriteria criteria, Pageable pageable){ + return PageUtil.toPage(quartzJobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable)); + } + + @Override + public Object queryAllLog(JobQueryCriteria criteria, Pageable pageable){ + return PageUtil.toPage(quartzLogRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable)); + } + + @Override + public List queryAll(JobQueryCriteria criteria) { + return quartzJobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)); + } + + @Override + public List queryAllLog(JobQueryCriteria criteria) { + return quartzLogRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)); + } + + @Override + public QuartzJob findById(Long id) { + QuartzJob quartzJob = quartzJobRepository.findById(id).orElseGet(QuartzJob::new); + ValidationUtil.isNull(quartzJob.getId(),"QuartzJob","id",id); + return quartzJob; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(QuartzJob resources) { + if (!CronExpression.isValidExpression(resources.getCronExpression())){ + throw new BadRequestException("cron表达式格式错误"); + } + resources = quartzJobRepository.save(resources); + quartzManage.addJob(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(QuartzJob resources) { + if (!CronExpression.isValidExpression(resources.getCronExpression())){ + throw new BadRequestException("cron表达式格式错误"); + } + if(StringUtils.isNotBlank(resources.getSubTask())){ + List tasks = Arrays.asList(resources.getSubTask().split("[,,]")); + if (tasks.contains(resources.getId().toString())) { + throw new BadRequestException("子任务中不能添加当前任务ID"); + } + } + resources = quartzJobRepository.save(resources); + quartzManage.updateJobCron(resources); + } + + @Override + public void updateIsPause(QuartzJob quartzJob) { + if (quartzJob.getIsPause()) { + quartzManage.resumeJob(quartzJob); + quartzJob.setIsPause(false); + } else { + quartzManage.pauseJob(quartzJob); + quartzJob.setIsPause(true); + } + quartzJobRepository.save(quartzJob); + } + + @Override + public void execution(QuartzJob quartzJob) { + quartzManage.runJobNow(quartzJob); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set ids) { + for (Long id : ids) { + QuartzJob quartzJob = findById(id); + quartzManage.deleteJob(quartzJob); + quartzJobRepository.delete(quartzJob); + } + } + + @Async + @Override + @Transactional(rollbackFor = Exception.class) + public void executionSubJob(String[] tasks) throws InterruptedException { + for (String id : tasks) { + QuartzJob quartzJob = findById(Long.parseLong(id)); + // 执行任务 + String uuid = IdUtil.simpleUUID(); + quartzJob.setUuid(uuid); + // 执行任务 + execution(quartzJob); + // 获取执行状态,如果执行失败则停止后面的子任务执行 + Boolean result = (Boolean) redisUtils.get(uuid); + /*while (result == null) { + // 休眠5秒,再次获取子任务执行情况 + Thread.sleep(5000); + result = (Boolean) redisUtils.get(uuid); + } + if(!result){ + redisUtils.del(uuid); + break; + }*/ + } + } + + @Override + public void download(List quartzJobs, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (QuartzJob quartzJob : quartzJobs) { + Map map = new LinkedHashMap<>(); + map.put("任务名称", quartzJob.getJobName()); + map.put("Bean名称", quartzJob.getBeanName()); + map.put("执行方法", quartzJob.getMethodName()); + map.put("参数", quartzJob.getParams()); + map.put("表达式", quartzJob.getCronExpression()); + map.put("状态", quartzJob.getIsPause() ? "暂停中" : "运行中"); + map.put("描述", quartzJob.getDescription()); + map.put("创建日期", quartzJob.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } + + @Override + public void downloadLog(List queryAllLog, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (QuartzLog quartzLog : queryAllLog) { + Map map = new LinkedHashMap<>(); + map.put("任务名称", quartzLog.getJobName()); + map.put("Bean名称", quartzLog.getBeanName()); + map.put("执行方法", quartzLog.getMethodName()); + map.put("参数", quartzLog.getParams()); + map.put("表达式", quartzLog.getCronExpression()); + map.put("异常详情", quartzLog.getExceptionDetail()); + map.put("耗时/毫秒", quartzLog.getTime()); + map.put("状态", quartzLog.getIsSuccess() ? "成功" : "失败"); + map.put("创建日期", quartzLog.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/quartz/task/TestSch.java b/nladmin-system/src/main/java/org/nl/modules/quartz/task/TestSch.java new file mode 100644 index 0000000..cea383f --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/quartz/task/TestSch.java @@ -0,0 +1,12 @@ +package org.nl.modules.quartz.task; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class TestSch { + public void run() { + log.info("run 执行成功"); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/quartz/task/TestTask.java b/nladmin-system/src/main/java/org/nl/modules/quartz/task/TestTask.java new file mode 100644 index 0000000..0d67ce0 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/quartz/task/TestTask.java @@ -0,0 +1,41 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.quartz.task; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 测试用 + * @author Zheng Jie + * @date 2019-01-08 + */ +@Slf4j +@Component +public class TestTask { + + public void run(){ + log.info("run 执行成功"); + } + + public void run1(String str){ + log.info("run1 执行成功,参数为: {}" + str); + } + + public void run2(){ + log.info("run2 执行成功"); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/quartz/task/TestWebSocket.java b/nladmin-system/src/main/java/org/nl/modules/quartz/task/TestWebSocket.java new file mode 100644 index 0000000..1ce212b --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/quartz/task/TestWebSocket.java @@ -0,0 +1,33 @@ +package org.nl.modules.quartz.task; + +import lombok.extern.slf4j.Slf4j; +import net.sf.json.JSONObject; +import org.nl.modules.mnt.websocket.MsgType; +import org.nl.modules.mnt.websocket.SocketMsg; +import org.nl.modules.mnt.websocket.WebSocketServer; +import org.springframework.stereotype.Component; + +import java.io.IOException; +@Slf4j +@Component +public class TestWebSocket { + public void run() { + System.out.println("testWebsocket"); + try { + JSONObject json = new JSONObject(); + json.put("a","我是a1"); + SocketMsg deviceInfo = new SocketMsg(json, MsgType.INFO); + WebSocketServer.sendInfo(deviceInfo, "10"); + } catch (IOException e) { + e.printStackTrace(); + } + try { + JSONObject json = new JSONObject(); + json.put("a","我是a1"); + SocketMsg deviceInfo = new SocketMsg(json, MsgType.INFO); + WebSocketServer.sendInfo(deviceInfo, "11"); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/quartz/utils/ExecutionJob.java b/nladmin-system/src/main/java/org/nl/modules/quartz/utils/ExecutionJob.java new file mode 100644 index 0000000..7b12e32 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/quartz/utils/ExecutionJob.java @@ -0,0 +1,137 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.quartz.utils; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.template.Template; +import cn.hutool.extra.template.TemplateConfig; +import cn.hutool.extra.template.TemplateEngine; +import cn.hutool.extra.template.TemplateUtil; +import org.nl.config.thread.ThreadPoolExecutorUtil; +import org.nl.domain.vo.EmailVo; +import org.nl.modules.quartz.domain.QuartzJob; +import org.nl.modules.quartz.domain.QuartzLog; +import org.nl.modules.quartz.repository.QuartzLogRepository; +import org.nl.modules.quartz.service.QuartzJobService; +import org.nl.service.EmailService; +import org.nl.utils.RedisUtils; +import org.nl.utils.SpringContextHolder; +import org.nl.utils.StringUtils; +import org.nl.utils.ThrowableUtil; +import org.quartz.JobExecutionContext; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.quartz.QuartzJobBean; + +import java.util.*; +import java.util.concurrent.*; + +/** + * 参考人人开源,https://gitee.com/renrenio/renren-security + * + * @author / + * @date 2019-01-07 + */ +@Async +@SuppressWarnings({"unchecked", "all"}) +public class ExecutionJob extends QuartzJobBean { + + /** + * 该处仅供参考 + */ + private final static ThreadPoolExecutor EXECUTOR = ThreadPoolExecutorUtil.getPoll(); + + @Override + public void executeInternal(JobExecutionContext context) { + QuartzJob quartzJob = (QuartzJob) context.getMergedJobDataMap().get(QuartzJob.JOB_KEY); + // 获取spring bean + QuartzLogRepository quartzLogRepository = SpringContextHolder.getBean(QuartzLogRepository.class); + QuartzJobService quartzJobService = SpringContextHolder.getBean(QuartzJobService.class); + //RedisUtils redisUtils = SpringContextHolder.getBean(RedisUtils.class); + + String uuid = quartzJob.getUuid(); + + QuartzLog log = new QuartzLog(); + log.setJobName(quartzJob.getJobName()); + log.setBeanName(quartzJob.getBeanName()); + log.setMethodName(quartzJob.getMethodName()); + log.setParams(quartzJob.getParams()); + long startTime = System.currentTimeMillis(); + log.setCronExpression(quartzJob.getCronExpression()); + try { + // 执行任务 + System.out.println("--------------------------------------------------------------"); + System.out.println("任务开始执行,任务名称:" + quartzJob.getJobName()); + QuartzRunnable task = new QuartzRunnable(quartzJob.getBeanName(), quartzJob.getMethodName(), + quartzJob.getParams()); + Future future = EXECUTOR.submit(task); + future.get(); + long times = System.currentTimeMillis() - startTime; + log.setTime(times); + /*if (StringUtils.isNotBlank(uuid)) { + redisUtils.set(uuid, true); + }*/ + // 任务状态 + log.setIsSuccess(true); + System.out.println("任务执行完毕,任务名称:" + quartzJob.getJobName() + ", 执行时间:" + times + "毫秒"); + System.out.println("--------------------------------------------------------------"); + // 判断是否存在子任务 + if (StrUtil.isNotEmpty(quartzJob.getSubTask())) { + String[] tasks = quartzJob.getSubTask().split("[,,]"); + // 执行子任务 + quartzJobService.executionSubJob(tasks); + } + } catch (Exception e) { + /*if (StringUtils.isNotBlank(uuid)) { + redisUtils.set(uuid, false); + }*/ + System.out.println("任务执行失败,任务名称:" + quartzJob.getJobName()); + System.out.println("--------------------------------------------------------------"); + long times = System.currentTimeMillis() - startTime; + log.setTime(times); + // 任务状态 0:成功 1:失败 + log.setIsSuccess(false); + log.setExceptionDetail(ThrowableUtil.getStackTrace(e)); + // 任务如果失败了则暂停 + if (quartzJob.getPauseAfterFailure() != null && quartzJob.getPauseAfterFailure()) { + quartzJob.setIsPause(false); + //更新状态 + quartzJobService.updateIsPause(quartzJob); + } + if (quartzJob.getEmail() != null) { + EmailService emailService = SpringContextHolder.getBean(EmailService.class); + // 邮箱报警 + EmailVo emailVo = taskAlarm(quartzJob, ThrowableUtil.getStackTrace(e)); + emailService.send(emailVo, emailService.find()); + } + } finally { + //quartzLogRepository.save(log); + } + } + + private EmailVo taskAlarm(QuartzJob quartzJob, String msg) { + EmailVo emailVo = new EmailVo(); + emailVo.setSubject("定时任务【" + quartzJob.getJobName() + "】执行失败,请尽快处理!"); + Map data = new HashMap<>(16); + data.put("task", quartzJob); + data.put("msg", msg); + TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH)); + Template template = engine.getTemplate("email/taskAlarm.ftl"); + emailVo.setContent(template.render(data)); + List emails = Arrays.asList(quartzJob.getEmail().split("[,,]")); + emailVo.setTos(emails); + return emailVo; + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/quartz/utils/QuartzManage.java b/nladmin-system/src/main/java/org/nl/modules/quartz/utils/QuartzManage.java new file mode 100644 index 0000000..ac560fe --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/quartz/utils/QuartzManage.java @@ -0,0 +1,173 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.quartz.utils; + +import lombok.extern.slf4j.Slf4j; +import org.nl.exception.BadRequestException; +import org.nl.modules.quartz.domain.QuartzJob; +import org.quartz.*; +import org.quartz.impl.triggers.CronTriggerImpl; +import org.springframework.stereotype.Component; +import javax.annotation.Resource; +import java.util.Date; +import static org.quartz.TriggerBuilder.newTrigger; + +/** + * @author Zheng Jie + * @date 2019-01-07 + */ +@Slf4j +@Component +public class QuartzManage { + + private static final String JOB_NAME = "TASK_"; + + @Resource(name = "scheduler") + private Scheduler scheduler; + + public void addJob(QuartzJob quartzJob){ + try { + // 构建job信息 + JobDetail jobDetail = JobBuilder.newJob(ExecutionJob.class). + withIdentity(JOB_NAME + quartzJob.getId()).build(); + + //通过触发器名和cron 表达式创建 Trigger + Trigger cronTrigger = newTrigger() + .withIdentity(JOB_NAME + quartzJob.getId()) + .startNow() + .withSchedule(CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression())) + .build(); + + cronTrigger.getJobDataMap().put(QuartzJob.JOB_KEY, quartzJob); + + //重置启动时间 + ((CronTriggerImpl)cronTrigger).setStartTime(new Date()); + + //执行定时任务 + scheduler.scheduleJob(jobDetail,cronTrigger); + + // 暂停任务 + if (quartzJob.getIsPause()) { + pauseJob(quartzJob); + } + } catch (Exception e){ + log.error("创建定时任务失败", e); + throw new BadRequestException("创建定时任务失败"); + } + } + + /** + * 更新job cron表达式 + * @param quartzJob / + */ + public void updateJobCron(QuartzJob quartzJob){ + try { + TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId()); + CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey); + // 如果不存在则创建一个定时任务 + if(trigger == null){ + addJob(quartzJob); + trigger = (CronTrigger) scheduler.getTrigger(triggerKey); + } + CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression()); + trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build(); + //重置启动时间 + ((CronTriggerImpl)trigger).setStartTime(new Date()); + trigger.getJobDataMap().put(QuartzJob.JOB_KEY,quartzJob); + + scheduler.rescheduleJob(triggerKey, trigger); + // 暂停任务 + if (quartzJob.getIsPause()) { + pauseJob(quartzJob); + } + } catch (Exception e){ + log.error("更新定时任务失败", e); + throw new BadRequestException("更新定时任务失败"); + } + + } + + /** + * 删除一个job + * @param quartzJob / + */ + public void deleteJob(QuartzJob quartzJob){ + try { + JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId()); + scheduler.pauseJob(jobKey); + scheduler.deleteJob(jobKey); + } catch (Exception e){ + log.error("删除定时任务失败", e); + throw new BadRequestException("删除定时任务失败"); + } + } + + /** + * 恢复一个job + * @param quartzJob / + */ + public void resumeJob(QuartzJob quartzJob){ + try { + TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId()); + CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey); + // 如果不存在则创建一个定时任务 + if(trigger == null) { + addJob(quartzJob); + } + JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId()); + scheduler.resumeJob(jobKey); + } catch (Exception e){ + log.error("恢复定时任务失败", e); + throw new BadRequestException("恢复定时任务失败"); + } + } + + /** + * 立即执行job + * @param quartzJob / + */ + public void runJobNow(QuartzJob quartzJob){ + try { + TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId()); + CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey); + // 如果不存在则创建一个定时任务 + if(trigger == null) { + addJob(quartzJob); + } + JobDataMap dataMap = new JobDataMap(); + dataMap.put(QuartzJob.JOB_KEY, quartzJob); + JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId()); + scheduler.triggerJob(jobKey,dataMap); + } catch (Exception e){ + log.error("定时任务执行失败", e); + throw new BadRequestException("定时任务执行失败"); + } + } + + /** + * 暂停一个job + * @param quartzJob / + */ + public void pauseJob(QuartzJob quartzJob){ + try { + JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId()); + scheduler.pauseJob(jobKey); + } catch (Exception e){ + log.error("定时任务暂停失败", e); + throw new BadRequestException("定时任务暂停失败"); + } + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/quartz/utils/QuartzRunnable.java b/nladmin-system/src/main/java/org/nl/modules/quartz/utils/QuartzRunnable.java new file mode 100644 index 0000000..41d3d79 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/quartz/utils/QuartzRunnable.java @@ -0,0 +1,58 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.quartz.utils; + +import lombok.extern.slf4j.Slf4j; +import org.nl.utils.SpringContextHolder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.util.ReflectionUtils; +import java.lang.reflect.Method; +import java.util.concurrent.Callable; + +/** + * 执行定时任务 + * @author / + */ +@Slf4j +public class QuartzRunnable implements Callable { + + private final Object target; + private final Method method; + private final String params; + + QuartzRunnable(String beanName, String methodName, String params) + throws NoSuchMethodException, SecurityException { + this.target = SpringContextHolder.getBean(beanName); + this.params = params; + + if (StringUtils.isNotBlank(params)) { + this.method = target.getClass().getDeclaredMethod(methodName, String.class); + } else { + this.method = target.getClass().getDeclaredMethod(methodName); + } + } + + @Override + public Object call() throws Exception { + ReflectionUtils.makeAccessible(method); + if (StringUtils.isNotBlank(params)) { + method.invoke(target, params); + } else { + method.invoke(target); + } + return null; + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/security/config/AjaxCorsFilter.java b/nladmin-system/src/main/java/org/nl/modules/security/config/AjaxCorsFilter.java new file mode 100644 index 0000000..f319d3f --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/security/config/AjaxCorsFilter.java @@ -0,0 +1,39 @@ +/* +package org.nl.modules.security.config; + +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +import java.util.Arrays; +import java.util.List; + +@Component +@Order(Ordered.HIGHEST_PRECEDENCE) +public class AjaxCorsFilter extends CorsFilter { + public AjaxCorsFilter() { + super(configurationSource()); + } + + private static UrlBasedCorsConfigurationSource configurationSource() { + CorsConfiguration corsConfig = new CorsConfiguration(); + List allowedHeaders = Arrays.asList("x-auth-token", "content-type", "X-Requested-With", "XMLHttpRequest"); + List exposedHeaders = Arrays.asList("x-auth-token", "content-type", "X-Requested-With", "XMLHttpRequest"); + List allowedMethods = Arrays.asList("POST", "GET", "DELETE", "PUT", "OPTIONS"); + List allowedOrigins = Arrays.asList("*"); + corsConfig.setAllowedHeaders(allowedHeaders); + corsConfig.setAllowedMethods(allowedMethods); + corsConfig.setAllowedOrigins(allowedOrigins); + corsConfig.setExposedHeaders(exposedHeaders); + corsConfig.setMaxAge(36000L); + corsConfig.setAllowCredentials(true); + + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", corsConfig); + return source; + } +} +*/ diff --git a/nladmin-system/src/main/java/org/nl/modules/security/config/ConfigBeanConfiguration.java b/nladmin-system/src/main/java/org/nl/modules/security/config/ConfigBeanConfiguration.java new file mode 100644 index 0000000..43ada7e --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/security/config/ConfigBeanConfiguration.java @@ -0,0 +1,43 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.security.config; + +import org.nl.modules.security.config.bean.LoginProperties; +import org.nl.modules.security.config.bean.SecurityProperties; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @apiNote 配置文件转换Pojo类的 统一配置 类 + * @author: liaojinlong + * @date: 2020/6/10 19:04 + */ +@Configuration +public class ConfigBeanConfiguration { + + @Bean + @ConfigurationProperties(prefix = "login", ignoreUnknownFields = true) + public LoginProperties loginProperties() { + return new LoginProperties(); + } + + @Bean + @ConfigurationProperties(prefix = "jwt", ignoreUnknownFields = true) + public SecurityProperties securityProperties() { + return new SecurityProperties(); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/security/config/SecurityConfig.java b/nladmin-system/src/main/java/org/nl/modules/security/config/SecurityConfig.java new file mode 100644 index 0000000..80a6454 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/security/config/SecurityConfig.java @@ -0,0 +1,195 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.security.config; + +import lombok.RequiredArgsConstructor; +import org.nl.annotation.AnonymousAccess; +import org.nl.modules.security.config.bean.SecurityProperties; +import org.nl.modules.security.security.JwtAccessDeniedHandler; +import org.nl.modules.security.security.JwtAuthenticationEntryPoint; +import org.nl.modules.security.security.TokenConfigurer; +import org.nl.modules.security.security.TokenProvider; +import org.nl.modules.security.service.OnlineUserService; +import org.nl.modules.security.service.UserCacheClean; +import org.nl.utils.enums.RequestMethodEnum; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +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.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.core.GrantedAuthorityDefaults; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.filter.CorsFilter; +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.*; + +/** + * @author Zheng Jie + */ +@Configuration +@EnableWebSecurity +@RequiredArgsConstructor +@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + private final TokenProvider tokenProvider; + private final CorsFilter corsFilter; + private final JwtAuthenticationEntryPoint authenticationErrorHandler; + private final JwtAccessDeniedHandler jwtAccessDeniedHandler; + private final ApplicationContext applicationContext; + private final SecurityProperties properties; + private final OnlineUserService onlineUserService; + private final UserCacheClean userCacheClean; + + @Bean + GrantedAuthorityDefaults grantedAuthorityDefaults() { + // 去除 ROLE_ 前缀 + return new GrantedAuthorityDefaults(""); + } + + @Bean + public PasswordEncoder passwordEncoder() { + // 密码加密方式 + return new BCryptPasswordEncoder(); + } + //@Override + protected void configure2(HttpSecurity http) throws Exception { + http.authorizeRequests().anyRequest().permitAll().and().logout().permitAll(); + } + + @Override + protected void configure(HttpSecurity httpSecurity) throws Exception { + // 搜寻匿名标记 url: @AnonymousAccess + Map handlerMethodMap = applicationContext.getBean(RequestMappingHandlerMapping.class).getHandlerMethods(); + // 获取匿名标记 + Map> anonymousUrls = getAnonymousUrl(handlerMethodMap); + httpSecurity + // 禁用 CSRF + .csrf().disable() + .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class) + // 授权异常 + .exceptionHandling() + .authenticationEntryPoint(authenticationErrorHandler) + .accessDeniedHandler(jwtAccessDeniedHandler) + // 防止iframe 造成跨域 + .and() + .headers() + .frameOptions() + .disable() + // 不创建会话 + .and() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + // 静态资源等等 + .antMatchers( + HttpMethod.GET, + "/*.html", + "/**/*.html", + "/**/*.css", + "/**/*.js", + "/webSocket/**" + ).permitAll() + // swagger 文档 + .antMatchers("/swagger-ui.html").permitAll() + .antMatchers("/swagger-resources/**").permitAll() + .antMatchers("/webjars/**").permitAll() + .antMatchers("/*/api-docs").permitAll() + // 文件 + .antMatchers("/avatar/**").permitAll() + .antMatchers("/file/**").permitAll() + // 阿里巴巴 druid + .antMatchers("/druid/**").permitAll() + // 放行OPTIONS请求 + .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() + // 自定义匿名访问所有url放行:允许匿名和带Token访问,细腻化到每个 Request 类型 + // GET + .antMatchers(HttpMethod.GET, anonymousUrls.get(RequestMethodEnum.GET.getType()).toArray(new String[0])).permitAll() + // POST + .antMatchers(HttpMethod.POST, anonymousUrls.get(RequestMethodEnum.POST.getType()).toArray(new String[0])).permitAll() + // PUT + .antMatchers(HttpMethod.PUT, anonymousUrls.get(RequestMethodEnum.PUT.getType()).toArray(new String[0])).permitAll() + // PATCH + .antMatchers(HttpMethod.PATCH, anonymousUrls.get(RequestMethodEnum.PATCH.getType()).toArray(new String[0])).permitAll() + // DELETE + .antMatchers(HttpMethod.DELETE, anonymousUrls.get(RequestMethodEnum.DELETE.getType()).toArray(new String[0])).permitAll() + // 所有类型的接口都放行 + .antMatchers(anonymousUrls.get(RequestMethodEnum.ALL.getType()).toArray(new String[0])).permitAll() + // 所有请求都需要认证 + //anyRequest().authenticated() + .and().apply(securityConfigurerAdapter()); + } + + private Map> getAnonymousUrl(Map handlerMethodMap) { + Map> anonymousUrls = new HashMap<>(6); + Set get = new HashSet<>(); + Set post = new HashSet<>(); + Set put = new HashSet<>(); + Set patch = new HashSet<>(); + Set delete = new HashSet<>(); + Set all = new HashSet<>(); + for (Map.Entry infoEntry : handlerMethodMap.entrySet()) { + HandlerMethod handlerMethod = infoEntry.getValue(); + AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class); + if (null != anonymousAccess) { + List requestMethods = new ArrayList<>(infoEntry.getKey().getMethodsCondition().getMethods()); + RequestMethodEnum request = RequestMethodEnum.find(requestMethods.size() == 0 ? RequestMethodEnum.ALL.getType() : requestMethods.get(0).name()); + switch (Objects.requireNonNull(request)) { + case GET: + get.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); + break; + case POST: + post.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); + break; + case PUT: + put.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); + break; + case PATCH: + patch.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); + break; + case DELETE: + delete.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); + break; + default: + all.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); + break; + } + } + } + anonymousUrls.put(RequestMethodEnum.GET.getType(), get); + anonymousUrls.put(RequestMethodEnum.POST.getType(), post); + anonymousUrls.put(RequestMethodEnum.PUT.getType(), put); + anonymousUrls.put(RequestMethodEnum.PATCH.getType(), patch); + anonymousUrls.put(RequestMethodEnum.DELETE.getType(), delete); + anonymousUrls.put(RequestMethodEnum.ALL.getType(), all); + return anonymousUrls; + } + + private TokenConfigurer securityConfigurerAdapter() { + return new TokenConfigurer(tokenProvider, properties, onlineUserService, userCacheClean); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/security/config/bean/LoginCode.java b/nladmin-system/src/main/java/org/nl/modules/security/config/bean/LoginCode.java new file mode 100644 index 0000000..46abb67 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/security/config/bean/LoginCode.java @@ -0,0 +1,61 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.security.config.bean; + +import lombok.Data; + +/** + * 登录验证码配置信息 + * + * @author: liaojinlong + * @date: 2020/6/10 18:53 + */ +@Data +public class LoginCode { + + /** + * 验证码配置 + */ + private LoginCodeEnum codeType; + /** + * 验证码有效期 分钟 + */ + private Long expiration = 2L; + /** + * 验证码内容长度 + */ + private int length = 2; + /** + * 验证码宽度 + */ + private int width = 111; + /** + * 验证码高度 + */ + private int height = 36; + /** + * 验证码字体 + */ + private String fontName; + /** + * 字体大小 + */ + private int fontSize = 25; + + public LoginCodeEnum getCodeType() { + return codeType; + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/security/config/bean/LoginCodeEnum.java b/nladmin-system/src/main/java/org/nl/modules/security/config/bean/LoginCodeEnum.java new file mode 100644 index 0000000..b2185e7 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/security/config/bean/LoginCodeEnum.java @@ -0,0 +1,43 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.security.config.bean; + +/** + * 验证码配置枚举 + * + * @author: liaojinlong + * @date: 2020/6/10 17:40 + */ + +public enum LoginCodeEnum { + /** + * 算数 + */ + arithmetic, + /** + * 中文 + */ + chinese, + /** + * 中文闪图 + */ + chinese_gif, + /** + * 闪图 + */ + gif, + spec +} diff --git a/nladmin-system/src/main/java/org/nl/modules/security/config/bean/LoginProperties.java b/nladmin-system/src/main/java/org/nl/modules/security/config/bean/LoginProperties.java new file mode 100644 index 0000000..e115e84 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/security/config/bean/LoginProperties.java @@ -0,0 +1,111 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version loginCode.length.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-loginCode.length.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.security.config.bean; + +import com.wf.captcha.*; +import com.wf.captcha.base.Captcha; +import lombok.Data; +import org.nl.exception.BadConfigurationException; +import org.nl.utils.StringUtils; + +import java.awt.*; +import java.util.Objects; + +/** + * 配置文件读取 + * + * @author liaojinlong + * @date loginCode.length0loginCode.length0/6/10 17:loginCode.length6 + */ +@Data +public class LoginProperties { + + /** + * 账号单用户 登录 + */ + private boolean singleLogin = false; + + private LoginCode loginCode; + /** + * 用户登录信息缓存 + */ + private boolean cacheEnable; + + public boolean isSingleLogin() { + return singleLogin; + } + + public boolean isCacheEnable() { + return cacheEnable; + } + + /** + * 获取验证码生产类 + * + * @return / + */ + public Captcha getCaptcha() { + if (Objects.isNull(loginCode)) { + loginCode = new LoginCode(); + if (Objects.isNull(loginCode.getCodeType())) { + loginCode.setCodeType(LoginCodeEnum.arithmetic); + } + } + return switchCaptcha(loginCode); + } + + /** + * 依据配置信息生产验证码 + * + * @param loginCode 验证码配置信息 + * @return / + */ + private Captcha switchCaptcha(LoginCode loginCode) { + Captcha captcha; + synchronized (this) { + switch (loginCode.getCodeType()) { + case arithmetic: + // 算术类型 https://gitee.com/whvse/EasyCaptcha + captcha = new ArithmeticCaptcha(loginCode.getWidth(), loginCode.getHeight()); + // 几位数运算,默认是两位 + captcha.setLen(loginCode.getLength()); + break; + case chinese: + captcha = new ChineseCaptcha(loginCode.getWidth(), loginCode.getHeight()); + captcha.setLen(loginCode.getLength()); + break; + case chinese_gif: + captcha = new ChineseGifCaptcha(loginCode.getWidth(), loginCode.getHeight()); + captcha.setLen(loginCode.getLength()); + break; + case gif: + captcha = new GifCaptcha(loginCode.getWidth(), loginCode.getHeight()); + captcha.setLen(loginCode.getLength()); + break; + case spec: + captcha = new SpecCaptcha(loginCode.getWidth(), loginCode.getHeight()); + captcha.setLen(loginCode.getLength()); + break; + default: + throw new BadConfigurationException("验证码配置信息错误!正确配置查看 LoginCodeEnum "); + } + } + if(StringUtils.isNotBlank(loginCode.getFontName())){ + captcha.setFont(new Font(loginCode.getFontName(), Font.PLAIN, loginCode.getFontSize())); + } + return captcha; + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/security/config/bean/SecurityProperties.java b/nladmin-system/src/main/java/org/nl/modules/security/config/bean/SecurityProperties.java new file mode 100644 index 0000000..fe08e80 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/security/config/bean/SecurityProperties.java @@ -0,0 +1,74 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.security.config.bean; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * Jwt参数配置 + * + * @author Zheng Jie + * @date 2019年11月28日 + */ +@Data +public class SecurityProperties { + + /** + * Request Headers : Authorization + */ + private String header; + + /** + * 令牌前缀,最后留个空格 Bearer + */ + private String tokenStartWith; + + /** + * 必须使用最少88位的Base64对该令牌进行编码 + */ + private String base64Secret; + + /** + * 令牌过期时间 此处单位/毫秒 + */ + private Long tokenValidityInSeconds; + + /** + * 在线用户 key,根据 key 查询 redis 中在线用户的数据 + */ + private String onlineKey; + + /** + * 验证码 key + */ + private String codeKey; + + /** + * token 续期检查 + */ + private Long detect; + + /** + * 续期时间 + */ + private Long renew; + + public String getTokenStartWith() { + return tokenStartWith + " "; + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/security/rest/AuthorizationController.java b/nladmin-system/src/main/java/org/nl/modules/security/rest/AuthorizationController.java new file mode 100644 index 0000000..b344e74 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/security/rest/AuthorizationController.java @@ -0,0 +1,142 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.security.rest; + +import cn.hutool.core.util.IdUtil; +import com.wf.captcha.base.Captcha; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.nl.annotation.rest.AnonymousDeleteMapping; +import org.nl.annotation.rest.AnonymousGetMapping; +import org.nl.annotation.rest.AnonymousPostMapping; +import org.nl.config.RsaProperties; +import org.nl.exception.BadRequestException; +import org.nl.modules.security.config.bean.LoginCodeEnum; +import org.nl.modules.security.config.bean.LoginProperties; +import org.nl.modules.security.config.bean.SecurityProperties; +import org.nl.modules.security.security.TokenProvider; +import org.nl.modules.security.service.dto.AuthUserDto; +import org.nl.modules.security.service.dto.JwtUserDto; +import org.nl.modules.security.service.OnlineUserService; +import org.nl.utils.RsaUtils; +import org.nl.utils.RedisUtils; +import org.nl.utils.SecurityUtils; +import org.nl.utils.StringUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * @author Zheng Jie + * @date 2018-11-23 + * 授权、根据token获取用户详细信息 + */ +@Slf4j +@RestController +@RequestMapping("/auth") +@RequiredArgsConstructor +@Api(tags = "系统:系统授权接口") +public class AuthorizationController { + private final SecurityProperties properties; + private final RedisUtils redisUtils; + private final OnlineUserService onlineUserService; + private final TokenProvider tokenProvider; + private final AuthenticationManagerBuilder authenticationManagerBuilder; + @Resource + private LoginProperties loginProperties; + + @ApiOperation("登录授权") + @AnonymousPostMapping(value = "/login") + public ResponseEntity login(@Validated @RequestBody AuthUserDto authUser, HttpServletRequest request) throws Exception { + // 密码解密 + String password = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey, authUser.getPassword()); + // 查询验证码 + String code = (String) redisUtils.get(authUser.getUuid()); + // 清除验证码 + redisUtils.del(authUser.getUuid()); + if (StringUtils.isBlank(code)) { + throw new BadRequestException("验证码不存在或已过期"); + } + if (StringUtils.isBlank(authUser.getCode()) || !authUser.getCode().equalsIgnoreCase(code)) { + throw new BadRequestException("验证码错误"); + } + UsernamePasswordAuthenticationToken authenticationToken = + new UsernamePasswordAuthenticationToken(authUser.getUsername(), password); + Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); + SecurityContextHolder.getContext().setAuthentication(authentication); + // 生成令牌 + String token = tokenProvider.createToken(authentication); + final JwtUserDto jwtUserDto = (JwtUserDto) authentication.getPrincipal(); + // 保存在线信息 + onlineUserService.save(jwtUserDto, token, request); + // 返回 token 与 用户信息 + Map authInfo = new HashMap(2) {{ + put("token", properties.getTokenStartWith() + token); + put("user", jwtUserDto); + }}; + if (loginProperties.isSingleLogin()) { + //踢掉之前已经登录的token + onlineUserService.checkLoginOnUser(authUser.getUsername(), token); + } + return ResponseEntity.ok(authInfo); + } + + @ApiOperation("获取用户信息") + @GetMapping(value = "/info") + public ResponseEntity getUserInfo() { + return ResponseEntity.ok(SecurityUtils.getCurrentUser()); + } + + @ApiOperation("获取验证码") + @AnonymousGetMapping(value = "/code") + public ResponseEntity getCode() { + // 获取运算的结果 + Captcha captcha = loginProperties.getCaptcha(); + String uuid = properties.getCodeKey() + IdUtil.simpleUUID(); + //当验证码类型为 arithmetic时且长度 >= 2 时,captcha.text()的结果有几率为浮点型 + String captchaValue = captcha.text(); + if (captcha.getCharType() - 1 == LoginCodeEnum.arithmetic.ordinal() && captchaValue.contains(".")) { + captchaValue = captchaValue.split("\\.")[0]; + } + // 保存 + redisUtils.set(uuid, captchaValue, loginProperties.getLoginCode().getExpiration(), TimeUnit.MINUTES); + // 验证码信息 + Map imgResult = new HashMap(2) {{ + put("img", captcha.toBase64()); + put("uuid", uuid); + }}; + return ResponseEntity.ok(imgResult); + } + + @ApiOperation("退出登录") + @AnonymousDeleteMapping(value = "/logout") + public ResponseEntity logout(HttpServletRequest request) { + onlineUserService.logout(tokenProvider.getToken(request)); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/security/rest/OnlineController.java b/nladmin-system/src/main/java/org/nl/modules/security/rest/OnlineController.java new file mode 100644 index 0000000..9a2a5e3 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/security/rest/OnlineController.java @@ -0,0 +1,68 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.security.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.nl.modules.security.service.OnlineUserService; +import org.nl.utils.EncryptUtils; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Set; + +/** + * @author Zheng Jie + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/auth/online") +@Api(tags = "系统:在线用户管理") +public class OnlineController { + + private final OnlineUserService onlineUserService; + + @ApiOperation("查询在线用户") + @GetMapping + @PreAuthorize("@el.check()") + public ResponseEntity query(String filter, Pageable pageable){ + return new ResponseEntity<>(onlineUserService.getAll(filter, pageable),HttpStatus.OK); + } + + @ApiOperation("导出数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check()") + public void download(HttpServletResponse response, String filter) throws IOException { + onlineUserService.download(onlineUserService.getAll(filter), response); + } + + @ApiOperation("踢出用户") + @DeleteMapping + @PreAuthorize("@el.check()") + public ResponseEntity delete(@RequestBody Set keys) throws Exception { + for (String key : keys) { + // 解密Key + key = EncryptUtils.desDecrypt(key); + onlineUserService.kickOut(key); + } + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/security/security/JwtAccessDeniedHandler.java b/nladmin-system/src/main/java/org/nl/modules/security/security/JwtAccessDeniedHandler.java new file mode 100644 index 0000000..5f7068e --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/security/security/JwtAccessDeniedHandler.java @@ -0,0 +1,37 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.security.security; + +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author Zheng Jie + */ +@Component +public class JwtAccessDeniedHandler implements AccessDeniedHandler { + + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException { + //当用户在没有授权的情况下访问受保护的REST资源时,将调用此方法发送403 Forbidden响应 + response.sendError(HttpServletResponse.SC_FORBIDDEN, accessDeniedException.getMessage()); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/security/security/JwtAuthenticationEntryPoint.java b/nladmin-system/src/main/java/org/nl/modules/security/security/JwtAuthenticationEntryPoint.java new file mode 100644 index 0000000..f992c48 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/security/security/JwtAuthenticationEntryPoint.java @@ -0,0 +1,40 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.security.security; + +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 Zheng Jie + */ +@Component +public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest request, + HttpServletResponse response, + AuthenticationException authException) throws IOException { + // 当用户尝试访问安全的REST资源而不提供任何凭据时,将调用此方法发送401 响应 + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException==null?"Unauthorized":authException.getMessage()); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/security/security/TokenConfigurer.java b/nladmin-system/src/main/java/org/nl/modules/security/security/TokenConfigurer.java new file mode 100644 index 0000000..d3f19f2 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/security/security/TokenConfigurer.java @@ -0,0 +1,43 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.security.security; + +import lombok.RequiredArgsConstructor; +import org.nl.modules.security.config.bean.SecurityProperties; +import org.nl.modules.security.service.OnlineUserService; +import org.nl.modules.security.service.UserCacheClean; +import org.springframework.security.config.annotation.SecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.web.DefaultSecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +/** + * @author / + */ +@RequiredArgsConstructor +public class TokenConfigurer extends SecurityConfigurerAdapter { + + private final TokenProvider tokenProvider; + private final SecurityProperties properties; + private final OnlineUserService onlineUserService; + private final UserCacheClean userCacheClean; + + @Override + public void configure(HttpSecurity http) { + TokenFilter customFilter = new TokenFilter(tokenProvider, properties, onlineUserService, userCacheClean); + http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/security/security/TokenFilter.java b/nladmin-system/src/main/java/org/nl/modules/security/security/TokenFilter.java new file mode 100644 index 0000000..84e5bb5 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/security/security/TokenFilter.java @@ -0,0 +1,109 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.security.security; + +import cn.hutool.core.util.StrUtil; +import io.jsonwebtoken.ExpiredJwtException; +import org.nl.modules.security.config.bean.SecurityProperties; +import org.nl.modules.security.service.UserCacheClean; +import org.nl.modules.security.service.dto.OnlineUserDto; +import org.nl.modules.security.service.OnlineUserService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.GenericFilterBean; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.Objects; + +/** + * @author / + */ +public class TokenFilter extends GenericFilterBean { + private static final Logger log = LoggerFactory.getLogger(TokenFilter.class); + + + private final TokenProvider tokenProvider; + private final SecurityProperties properties; + private final OnlineUserService onlineUserService; + private final UserCacheClean userCacheClean; + + /** + * @param tokenProvider Token + * @param properties JWT + * @param onlineUserService 用户在线 + * @param userCacheClean 用户缓存清理工具 + */ + public TokenFilter(TokenProvider tokenProvider, SecurityProperties properties, OnlineUserService onlineUserService, UserCacheClean userCacheClean) { + this.properties = properties; + this.onlineUserService = onlineUserService; + this.tokenProvider = tokenProvider; + this.userCacheClean = userCacheClean; + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException { + HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; + String token = resolveToken(httpServletRequest); + // 对于 Token 为空的不需要去查 Redis + if (StrUtil.isNotBlank(token)) { + OnlineUserDto onlineUserDto = null; + boolean cleanUserCache = false; + try { + onlineUserDto = onlineUserService.getOne(properties.getOnlineKey() + token); + } catch (ExpiredJwtException e) { + log.error(e.getMessage()); + cleanUserCache = true; + } finally { + if (cleanUserCache || Objects.isNull(onlineUserDto)) { + userCacheClean.cleanUserCache(String.valueOf(tokenProvider.getClaims(token).get(TokenProvider.AUTHORITIES_KEY))); + } + } + if (onlineUserDto != null && StringUtils.hasText(token)) { + Authentication authentication = tokenProvider.getAuthentication(token); + SecurityContextHolder.getContext().setAuthentication(authentication); + // Token 续期 + tokenProvider.checkRenewal(token); + } + } + filterChain.doFilter(servletRequest, servletResponse); + } + + /** + * 初步检测Token + * + * @param request / + * @return / + */ + private String resolveToken(HttpServletRequest request) { + String bearerToken = request.getHeader(properties.getHeader()); + if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(properties.getTokenStartWith())) { + // 去掉令牌前缀 + return bearerToken.replace(properties.getTokenStartWith(), ""); + } else { + log.debug("非法Token:{}", bearerToken); + } + return null; + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/security/security/TokenProvider.java b/nladmin-system/src/main/java/org/nl/modules/security/security/TokenProvider.java new file mode 100644 index 0000000..c789d6f --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/security/security/TokenProvider.java @@ -0,0 +1,146 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.security.security; + +import cn.hutool.core.date.DateField; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import io.jsonwebtoken.*; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; +import lombok.extern.slf4j.Slf4j; +import org.nl.modules.security.config.bean.SecurityProperties; +import org.nl.utils.RedisUtils; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import java.security.Key; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * @author / + */ +@Slf4j +@Component +public class TokenProvider implements InitializingBean { + + private final SecurityProperties properties; + private final RedisUtils redisUtils; + public static final String AUTHORITIES_KEY = "auth"; + private JwtParser jwtParser; + private JwtBuilder jwtBuilder; + + public TokenProvider(SecurityProperties properties, RedisUtils redisUtils) { + this.properties = properties; + this.redisUtils = redisUtils; + } + + @Override + public void afterPropertiesSet() { + byte[] keyBytes = Decoders.BASE64.decode(properties.getBase64Secret()); + Key key = Keys.hmacShaKeyFor(keyBytes); + jwtParser = Jwts.parserBuilder() + .setSigningKey(key) + .build(); + jwtBuilder = Jwts.builder() + .signWith(key, SignatureAlgorithm.HS512); + } + + /** + * 创建Token 设置永不过期, + * Token 的时间有效性转到Redis 维护 + * + * @param authentication / + * @return / + */ + public String createToken(Authentication authentication) { + /* + * 获取权限列表 + */ + String authorities = authentication.getAuthorities().stream() + .map(GrantedAuthority::getAuthority) + .collect(Collectors.joining(",")); + + return jwtBuilder + // 加入ID确保生成的 Token 都不一致 + .setId(IdUtil.simpleUUID()) + .claim(AUTHORITIES_KEY, authorities) + .setSubject(authentication.getName()) + .compact(); + } + + /** + * 依据Token 获取鉴权信息 + * + * @param token / + * @return / + */ + Authentication getAuthentication(String token) { + Claims claims = getClaims(token); + + // fix bug: 当前用户如果没有任何权限时,在输入用户名后,刷新验证码会抛IllegalArgumentException + Object authoritiesStr = claims.get(AUTHORITIES_KEY); + Collection authorities = + ObjectUtil.isNotEmpty(authoritiesStr) ? + Arrays.stream(authoritiesStr.toString().split(",")) + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()) : Collections.emptyList(); + User principal = new User(claims.getSubject(), "******", authorities); + return new UsernamePasswordAuthenticationToken(principal, token, authorities); + } + + public Claims getClaims(String token) { + return jwtParser + .parseClaimsJws(token) + .getBody(); + } + + /** + * @param token 需要检查的token + */ + public void checkRenewal(String token) { + // 判断是否续期token,计算token的过期时间 + long time = redisUtils.getExpire(properties.getOnlineKey() + token) * 1000; + Date expireDate = DateUtil.offset(new Date(), DateField.MILLISECOND, (int) time); + // 判断当前时间与过期时间的时间差 + long differ = expireDate.getTime() - System.currentTimeMillis(); + // 如果在续期检查的范围内,则续期 + if (differ <= properties.getDetect()) { + long renew = time + properties.getRenew(); + redisUtils.expire(properties.getOnlineKey() + token, renew, TimeUnit.MILLISECONDS); + } + } + + public String getToken(HttpServletRequest request) { + final String requestHeader = request.getHeader(properties.getHeader()); + if (requestHeader != null && requestHeader.startsWith(properties.getTokenStartWith())) { + return requestHeader.substring(7); + } + return null; + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/security/service/OnlineUserService.java b/nladmin-system/src/main/java/org/nl/modules/security/service/OnlineUserService.java new file mode 100644 index 0000000..0746a1b --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/security/service/OnlineUserService.java @@ -0,0 +1,191 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.security.service; + +import lombok.extern.slf4j.Slf4j; +import org.nl.modules.security.config.bean.SecurityProperties; +import org.nl.modules.security.service.dto.JwtUserDto; +import org.nl.modules.security.service.dto.OnlineUserDto; +import org.nl.utils.*; +import org.springframework.data.domain.Pageable; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + +/** + * @author Zheng Jie + * @date 2019年10月26日21:56:27 + */ +@Service +@Slf4j +public class OnlineUserService { + + private final SecurityProperties properties; + private final RedisUtils redisUtils; + + public OnlineUserService(SecurityProperties properties, RedisUtils redisUtils) { + this.properties = properties; + this.redisUtils = redisUtils; + } + + /** + * 保存在线用户信息 + * @param jwtUserDto / + * @param token / + * @param request / + */ + public void save(JwtUserDto jwtUserDto, String token, HttpServletRequest request){ + String dept = jwtUserDto.getUser().getDept().getName(); + String ip = StringUtils.getIp(request); + String browser = StringUtils.getBrowser(request); + String address = StringUtils.getCityInfo(ip); + OnlineUserDto onlineUserDto = null; + try { + onlineUserDto = new OnlineUserDto(jwtUserDto.getUsername(), jwtUserDto.getUser().getNickName(), dept, browser , ip, address, EncryptUtils.desEncrypt(token), new Date()); + } catch (Exception e) { + log.error(e.getMessage(),e); + } + redisUtils.set(properties.getOnlineKey() + token, onlineUserDto, properties.getTokenValidityInSeconds()/1000); + } + + /** + * 查询全部数据 + * @param filter / + * @param pageable / + * @return / + */ + public Map getAll(String filter, Pageable pageable){ + List onlineUserDtos = getAll(filter); + return PageUtil.toPage( + PageUtil.toPage(pageable.getPageNumber(),pageable.getPageSize(), onlineUserDtos), + onlineUserDtos.size() + ); + } + + /** + * 查询全部数据,不分页 + * @param filter / + * @return / + */ + public List getAll(String filter){ + List keys = redisUtils.scan(properties.getOnlineKey() + "*"); + Collections.reverse(keys); + List onlineUserDtos = new ArrayList<>(); + for (String key : keys) { + OnlineUserDto onlineUserDto = (OnlineUserDto) redisUtils.get(key); + if(StringUtils.isNotBlank(filter)){ + if(onlineUserDto.toString().contains(filter)){ + onlineUserDtos.add(onlineUserDto); + } + } else { + onlineUserDtos.add(onlineUserDto); + } + } + onlineUserDtos.sort((o1, o2) -> o2.getLoginTime().compareTo(o1.getLoginTime())); + return onlineUserDtos; + } + + /** + * 踢出用户 + * @param key / + */ + public void kickOut(String key){ + key = properties.getOnlineKey() + key; + redisUtils.del(key); + } + + /** + * 退出登录 + * @param token / + */ + public void logout(String token) { + String key = properties.getOnlineKey() + token; + redisUtils.del(key); + } + + /** + * 导出 + * @param all / + * @param response / + * @throws IOException / + */ + public void download(List all, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (OnlineUserDto user : all) { + Map map = new LinkedHashMap<>(); + map.put("用户名", user.getUserName()); + map.put("部门", user.getDept()); + map.put("登录IP", user.getIp()); + map.put("登录地点", user.getAddress()); + map.put("浏览器", user.getBrowser()); + map.put("登录日期", user.getLoginTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } + + /** + * 查询用户 + * @param key / + * @return / + */ + public OnlineUserDto getOne(String key) { + return (OnlineUserDto)redisUtils.get(key); + } + + /** + * 检测用户是否在之前已经登录,已经登录踢下线 + * @param userName 用户名 + */ + public void checkLoginOnUser(String userName, String igoreToken){ + List onlineUserDtos = getAll(userName); + if(onlineUserDtos ==null || onlineUserDtos.isEmpty()){ + return; + } + for(OnlineUserDto onlineUserDto : onlineUserDtos){ + if(onlineUserDto.getUserName().equals(userName)){ + try { + String token =EncryptUtils.desDecrypt(onlineUserDto.getKey()); + if(StringUtils.isNotBlank(igoreToken)&&!igoreToken.equals(token)){ + this.kickOut(token); + }else if(StringUtils.isBlank(igoreToken)){ + this.kickOut(token); + } + } catch (Exception e) { + log.error("checkUser is error",e); + } + } + } + } + + /** + * 根据用户名强退用户 + * @param username / + */ + @Async + public void kickOutForUsername(String username) throws Exception { + List onlineUsers = getAll(username); + for (OnlineUserDto onlineUser : onlineUsers) { + if (onlineUser.getUserName().equals(username)) { + String token =EncryptUtils.desDecrypt(onlineUser.getKey()); + kickOut(token); + } + } + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/security/service/UserCacheClean.java b/nladmin-system/src/main/java/org/nl/modules/security/service/UserCacheClean.java new file mode 100644 index 0000000..55d4eb8 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/security/service/UserCacheClean.java @@ -0,0 +1,49 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.nl.modules.security.service; + +import org.nl.utils.StringUtils; +import org.springframework.stereotype.Component; + +/** + * @author: liaojinlong + * @date: 2020/6/11 18:01 + * @apiNote: 用于清理 用户登录信息缓存,为防止Spring循环依赖与安全考虑 ,单独构成工具类 + */ +@Component +public class UserCacheClean { + + /** + * 清理特定用户缓存信息
+ * 用户信息变更时 + * + * @param userName / + */ + public void cleanUserCache(String userName) { + if (StringUtils.isNotEmpty(userName)) { + UserDetailsServiceImpl.userDtoCache.remove(userName); + } + } + + /** + * 清理所有用户的缓存信息
+ * ,如发生角色授权信息变化,可以简便的全部失效缓存 + */ + public void cleanAll() { + UserDetailsServiceImpl.userDtoCache.clear(); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/security/service/UserDetailsServiceImpl.java b/nladmin-system/src/main/java/org/nl/modules/security/service/UserDetailsServiceImpl.java new file mode 100644 index 0000000..74ffca8 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/security/service/UserDetailsServiceImpl.java @@ -0,0 +1,87 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.security.service; + +import lombok.RequiredArgsConstructor; +import org.nl.exception.BadRequestException; +import org.nl.exception.EntityNotFoundException; +import org.nl.modules.security.config.bean.LoginProperties; +import org.nl.modules.security.service.dto.JwtUserDto; +import org.nl.modules.system.service.DataService; +import org.nl.modules.system.service.RoleService; +import org.nl.modules.system.service.UserService; +import org.nl.modules.system.service.dto.UserDto; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author Zheng Jie + * @date 2018-11-22 + */ +@RequiredArgsConstructor +@Service("userDetailsService") +public class UserDetailsServiceImpl implements UserDetailsService { + private final UserService userService; + private final RoleService roleService; + private final DataService dataService; + private final LoginProperties loginProperties; + public void setEnableCache(boolean enableCache) { + this.loginProperties.setCacheEnable(enableCache); + } + + /** + * 用户信息缓存 + * + * @see {@link UserCacheClean} + */ + static Map userDtoCache = new ConcurrentHashMap<>(); + + @Override + public JwtUserDto loadUserByUsername(String username) { + boolean searchDb = true; + JwtUserDto jwtUserDto = null; + if (loginProperties.isCacheEnable() && userDtoCache.containsKey(username)) { + jwtUserDto = userDtoCache.get(username); + searchDb = false; + } + if (searchDb) { + UserDto user; + try { + user = userService.findByName(username); + } catch (EntityNotFoundException e) { + // SpringSecurity会自动转换UsernameNotFoundException为BadCredentialsException + throw new UsernameNotFoundException("", e); + } + if (user == null) { + throw new UsernameNotFoundException(""); + } else { + if (!user.getEnabled()) { + throw new BadRequestException("账号未激活!"); + } + jwtUserDto = new JwtUserDto( + user, + dataService.getDeptIds(user), + roleService.mapToGrantedAuthorities(user) + ); + userDtoCache.put(username, jwtUserDto); + } + } + return jwtUserDto; + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/security/service/dto/AuthUserDto.java b/nladmin-system/src/main/java/org/nl/modules/security/service/dto/AuthUserDto.java new file mode 100644 index 0000000..f678dbb --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/security/service/dto/AuthUserDto.java @@ -0,0 +1,39 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.security.service.dto; + +import lombok.Getter; +import lombok.Setter; +import javax.validation.constraints.NotBlank; + +/** + * @author Zheng Jie + * @date 2018-11-30 + */ +@Getter +@Setter +public class AuthUserDto { + + @NotBlank + private String username; + + @NotBlank + private String password; + + private String code; + + private String uuid = ""; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/security/service/dto/JwtUserDto.java b/nladmin-system/src/main/java/org/nl/modules/security/service/dto/JwtUserDto.java new file mode 100644 index 0000000..4e74c31 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/security/service/dto/JwtUserDto.java @@ -0,0 +1,82 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.security.service.dto; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.nl.modules.system.service.dto.UserDto; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +@Getter +@AllArgsConstructor +public class JwtUserDto implements UserDetails { + + private final UserDto user; + + private final List dataScopes; + + @JsonIgnore + private final List authorities; + + public Set getRoles() { + return authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet()); + } + + @Override + @JsonIgnore + public String getPassword() { + return user.getPassword(); + } + + @Override + @JsonIgnore + public String getUsername() { + return user.getUsername(); + } + + @JsonIgnore + @Override + public boolean isAccountNonExpired() { + return true; + } + + @JsonIgnore + @Override + public boolean isAccountNonLocked() { + return true; + } + + @JsonIgnore + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + @JsonIgnore + public boolean isEnabled() { + return user.getEnabled(); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/security/service/dto/OnlineUserDto.java b/nladmin-system/src/main/java/org/nl/modules/security/service/dto/OnlineUserDto.java new file mode 100644 index 0000000..7037032 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/security/service/dto/OnlineUserDto.java @@ -0,0 +1,73 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.security.service.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import java.util.Date; + +/** + * 在线用户 + * @author Zheng Jie + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class OnlineUserDto { + + /** + * 用户名 + */ + private String userName; + + /** + * 昵称 + */ + private String nickName; + + /** + * 岗位 + */ + private String dept; + + /** + * 浏览器 + */ + private String browser; + + /** + * IP + */ + private String ip; + + /** + * 地址 + */ + private String address; + + /** + * token + */ + private String key; + + /** + * 登录时间 + */ + private Date loginTime; + + +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/domain/Dept.java b/nladmin-system/src/main/java/org/nl/modules/system/domain/Dept.java new file mode 100644 index 0000000..cadd651 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/domain/Dept.java @@ -0,0 +1,86 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.domain; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import org.nl.base.BaseEntity; +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Objects; +import java.util.Set; + +/** +* @author Zheng Jie +* @date 2019-03-25 +*/ +@Entity +@Getter +@Setter +@Table(name="sys_dept") +public class Dept extends BaseEntity implements Serializable { + + @Id + @Column(name = "dept_id") + @NotNull(groups = Update.class) + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @JsonIgnore + @ManyToMany(mappedBy = "depts") + @ApiModelProperty(value = "角色") + private Set roles; + + @ApiModelProperty(value = "排序") + private Integer deptSort; + + @NotBlank + @ApiModelProperty(value = "部门名称") + private String name; + + @NotNull + @ApiModelProperty(value = "是否启用") + private Boolean enabled; + + @ApiModelProperty(value = "上级部门") + private Long pid; + + @ApiModelProperty(value = "子节点数目", hidden = true) + private Integer subCount = 0; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Dept dept = (Dept) o; + return Objects.equals(id, dept.id) && + Objects.equals(name, dept.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/domain/Dict.java b/nladmin-system/src/main/java/org/nl/modules/system/domain/Dict.java new file mode 100644 index 0000000..978063a --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/domain/Dict.java @@ -0,0 +1,54 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import org.nl.base.BaseEntity; +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.List; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@Entity +@Getter +@Setter +@Table(name="sys_dict") +public class Dict extends BaseEntity implements Serializable { + + @Id + @Column(name = "dict_id") + @NotNull(groups = Update.class) + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToMany(mappedBy = "dict",cascade={CascadeType.PERSIST,CascadeType.REMOVE}) + private List dictDetails; + + @NotBlank + @ApiModelProperty(value = "名称") + private String name; + + @ApiModelProperty(value = "描述") + private String description; +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/domain/DictDetail.java b/nladmin-system/src/main/java/org/nl/modules/system/domain/DictDetail.java new file mode 100644 index 0000000..cf19462 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/domain/DictDetail.java @@ -0,0 +1,61 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import org.nl.base.BaseEntity; +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@Entity +@Getter +@Setter +@Table(name="sys_dict_detail") +public class DictDetail extends BaseEntity implements Serializable { + + @Id + @Column(name = "detail_id") + @NotNull(groups = Update.class) + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @JoinColumn(name = "dict_id") + @ManyToOne(fetch=FetchType.LAZY) + @ApiModelProperty(value = "字典", hidden = true) + private Dict dict; + + @ApiModelProperty(value = "字典标签") + private String label; + + @ApiModelProperty(value = "字典名称") + private String name; + + @ApiModelProperty(value = "字典值") + private String value; + + @ApiModelProperty(value = "排序") + private Integer dictSort = 999; + + +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/domain/Job.java b/nladmin-system/src/main/java/org/nl/modules/system/domain/Job.java new file mode 100644 index 0000000..caa98f5 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/domain/Job.java @@ -0,0 +1,75 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import org.nl.base.BaseEntity; +import javax.persistence.*; +import javax.persistence.Entity; +import javax.persistence.Table; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Objects; + +/** +* @author Zheng Jie +* @date 2019-03-29 +*/ +@Entity +@Getter +@Setter +@Table(name="sys_job") +public class Job extends BaseEntity implements Serializable { + + @Id + @Column(name = "job_id") + @NotNull(groups = Update.class) + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotBlank + @ApiModelProperty(value = "岗位名称") + private String name; + + @NotNull + @ApiModelProperty(value = "岗位排序") + private Long jobSort; + + @NotNull + @ApiModelProperty(value = "是否启用") + private Boolean enabled; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Job job = (Job) o; + return Objects.equals(id, job.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/domain/Menu.java b/nladmin-system/src/main/java/org/nl/modules/system/domain/Menu.java new file mode 100644 index 0000000..df8ad13 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/domain/Menu.java @@ -0,0 +1,110 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.domain; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import org.nl.base.BaseEntity; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Objects; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2018-12-17 + */ +@Entity +@Getter +@Setter +@Table(name = "sys_menu") +public class Menu extends BaseEntity implements Serializable { + + @Id + @Column(name = "menu_id") + @NotNull(groups = {Update.class}) + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @JsonIgnore + @ManyToMany(mappedBy = "menus") + @ApiModelProperty(value = "菜单角色") + private Set roles; + + @ApiModelProperty(value = "菜单标题") + private String title; + + @Column(name = "name") + @ApiModelProperty(value = "菜单组件名称") + private String componentName; + + @ApiModelProperty(value = "排序") + private Integer menuSort = 999; + + @ApiModelProperty(value = "组件路径") + private String component; + + @ApiModelProperty(value = "路由地址") + private String path; + + @ApiModelProperty(value = "菜单类型,目录、菜单、按钮") + private Integer type; + + @ApiModelProperty(value = "权限标识") + private String permission; + + @ApiModelProperty(value = "菜单图标") + private String icon; + + @Column(columnDefinition = "bit(1) default 0") + @ApiModelProperty(value = "缓存") + private Boolean cache; + + @Column(columnDefinition = "bit(1) default 0") + @ApiModelProperty(value = "是否隐藏") + private Boolean hidden; + + @ApiModelProperty(value = "上级菜单") + private Long pid; + + @ApiModelProperty(value = "子节点数目", hidden = true) + private Integer subCount = 0; + + @ApiModelProperty(value = "外链菜单") + private Boolean iFrame; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Menu menu = (Menu) o; + return Objects.equals(id, menu.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/domain/Param.java b/nladmin-system/src/main/java/org/nl/modules/system/domain/Param.java new file mode 100644 index 0000000..48f6be5 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/domain/Param.java @@ -0,0 +1,81 @@ +package org.nl.modules.system.domain; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.bean.copier.CopyOptions; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.nl.base.BaseEntity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +/** + * @description / + * @author ldjun + * @date 2021-01-14 + **/ +@Entity +@Data +@Table(name="sys_param") +public class Param extends BaseEntity implements Serializable { + + @Id + @Column(name = "id") + @ApiModelProperty(value = "id") + private String id; + + @Column(name = "code",nullable = false) + @NotBlank + @ApiModelProperty(value = "code") + private String code; + + @Column(name = "name",nullable = false) + @NotBlank + @ApiModelProperty(value = "name") + private String name; + + @Column(name = "value",nullable = false) + @NotBlank + @ApiModelProperty(value = "value") + private String value; + + @Column(name = "remark") + @ApiModelProperty(value = "remark") + private String remark; + + @Column(name = "is_active",nullable = false) + @NotBlank + @ApiModelProperty(value = "is_active") + private String is_active; + + @Column(name = "is_delete",nullable = false) + @NotBlank + @ApiModelProperty(value = "is_delete") + private String is_delete; + + @Column(name = "create_by",nullable = false,updatable = false,insertable = false) + @NotBlank + @ApiModelProperty(value = "create_by") + private String create_by; + + @Column(name = "create_time",nullable = false,updatable = false,insertable = false) + @NotBlank + @ApiModelProperty(value = "create_time") + private String create_time; + + @Column(name = "update_by",updatable = false,insertable = false) + @ApiModelProperty(value = "update_by") + private String update_by; + + @Column(name = "update_time",updatable = false,insertable = false) + @ApiModelProperty(value = "update_time") + private String update_time; + + public void copy(Param source){ + BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true)); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/domain/Role.java b/nladmin-system/src/main/java/org/nl/modules/system/domain/Role.java new file mode 100644 index 0000000..b17c5d6 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/domain/Role.java @@ -0,0 +1,99 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.domain; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import org.nl.base.BaseEntity; +import org.nl.utils.enums.DataScopeEnum; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Objects; +import java.util.Set; + +/** + * 角色 + * @author Zheng Jie + * @date 2018-11-22 + */ +@Getter +@Setter +@Entity +@Table(name = "sys_role") +public class Role extends BaseEntity implements Serializable { + + @Id + @Column(name = "role_id") + @NotNull(groups = {Update.class}) + @GeneratedValue(strategy = GenerationType.IDENTITY) + @ApiModelProperty(value = "ID", hidden = true) + private Long id; + + @JsonIgnore + @ManyToMany(mappedBy = "roles") + @ApiModelProperty(value = "用户", hidden = true) + private Set users; + + @ManyToMany + @JoinTable(name = "sys_roles_menus", + joinColumns = {@JoinColumn(name = "role_id",referencedColumnName = "role_id")}, + inverseJoinColumns = {@JoinColumn(name = "menu_id",referencedColumnName = "menu_id")}) + @ApiModelProperty(value = "菜单", hidden = true) + private Set menus; + + @ManyToMany + @JoinTable(name = "sys_roles_depts", + joinColumns = {@JoinColumn(name = "role_id",referencedColumnName = "role_id")}, + inverseJoinColumns = {@JoinColumn(name = "dept_id",referencedColumnName = "dept_id")}) + @ApiModelProperty(value = "部门", hidden = true) + private Set depts; + + @NotBlank + @ApiModelProperty(value = "名称", hidden = true) + private String name; + + @ApiModelProperty(value = "数据权限,全部 、 本级 、 自定义") + private String dataScope = DataScopeEnum.THIS_LEVEL.getValue(); + + @Column(name = "level") + @ApiModelProperty(value = "级别,数值越小,级别越大") + private Integer level = 3; + + @ApiModelProperty(value = "描述") + private String description; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Role role = (Role) o; + return Objects.equals(id, role.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/domain/User.java b/nladmin-system/src/main/java/org/nl/modules/system/domain/User.java new file mode 100644 index 0000000..8ca99ab --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/domain/User.java @@ -0,0 +1,125 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import org.nl.base.BaseEntity; +import javax.persistence.*; +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Date; +import java.util.Objects; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2018-11-22 + */ +@Entity +@Getter +@Setter +@Table(name="sys_user") +public class User extends BaseEntity implements Serializable { + + @Id + @Column(name = "user_id") + @NotNull(groups = Update.class) + @GeneratedValue(strategy = GenerationType.IDENTITY) + @ApiModelProperty(value = "ID", hidden = true) + private Long id; + + @ManyToMany + @ApiModelProperty(value = "用户角色") + @JoinTable(name = "sys_users_roles", + joinColumns = {@JoinColumn(name = "user_id",referencedColumnName = "user_id")}, + inverseJoinColumns = {@JoinColumn(name = "role_id",referencedColumnName = "role_id")}) + private Set roles; + + @ManyToMany + @ApiModelProperty(value = "用户岗位") + @JoinTable(name = "sys_users_jobs", + joinColumns = {@JoinColumn(name = "user_id",referencedColumnName = "user_id")}, + inverseJoinColumns = {@JoinColumn(name = "job_id",referencedColumnName = "job_id")}) + private Set jobs; + + @OneToOne + @JoinColumn(name = "dept_id") + @ApiModelProperty(value = "用户部门") + private Dept dept; + + @NotBlank + @Column(unique = true) + @ApiModelProperty(value = "用户名称") + private String username; + + @NotBlank + @ApiModelProperty(value = "用户昵称") + private String nickName; + + @Email + @NotBlank + @ApiModelProperty(value = "邮箱") + private String email; + + @NotBlank + @ApiModelProperty(value = "电话号码") + private String phone; + + @ApiModelProperty(value = "用户性别") + private String gender; + + @ApiModelProperty(value = "头像真实名称",hidden = true) + private String avatarName; + + @ApiModelProperty(value = "头像存储的路径", hidden = true) + private String avatarPath; + + @ApiModelProperty(value = "密码") + private String password; + + @NotNull + @ApiModelProperty(value = "是否启用") + private Boolean enabled; + + @ApiModelProperty(value = "是否为admin账号", hidden = true) + private Boolean isAdmin = false; + + @Column(name = "pwd_reset_time") + @ApiModelProperty(value = "最后修改密码的时间", hidden = true) + private Date pwdResetTime; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + User user = (User) o; + return Objects.equals(id, user.id) && + Objects.equals(username, user.username); + } + + @Override + public int hashCode() { + return Objects.hash(id, username); + } +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/domain/vo/MenuMetaVo.java b/nladmin-system/src/main/java/org/nl/modules/system/domain/vo/MenuMetaVo.java new file mode 100644 index 0000000..e7a8031 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/domain/vo/MenuMetaVo.java @@ -0,0 +1,35 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import java.io.Serializable; + +/** + * @author Zheng Jie + * @date 2018-12-20 + */ +@Data +@AllArgsConstructor +public class MenuMetaVo implements Serializable { + + private String title; + + private String icon; + + private Boolean noCache; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/domain/vo/MenuVo.java b/nladmin-system/src/main/java/org/nl/modules/system/domain/vo/MenuVo.java new file mode 100644 index 0000000..2bb784f --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/domain/vo/MenuVo.java @@ -0,0 +1,48 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.domain.vo; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 构建前端路由时用到 + * @author Zheng Jie + * @date 2018-12-20 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public class MenuVo implements Serializable { + + private String name; + + private String path; + + private Boolean hidden; + + private String redirect; + + private String component; + + private Boolean alwaysShow; + + private MenuMetaVo meta; + + private List children; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/domain/vo/UserPassVo.java b/nladmin-system/src/main/java/org/nl/modules/system/domain/vo/UserPassVo.java new file mode 100644 index 0000000..3f4b467 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/domain/vo/UserPassVo.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.domain.vo; + +import lombok.Data; + +/** + * 修改密码的 Vo 类 + * @author Zheng Jie + * @date 2019年7月11日13:59:49 + */ +@Data +public class UserPassVo { + + private String oldPass; + + private String newPass; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/repository/DeptRepository.java b/nladmin-system/src/main/java/org/nl/modules/system/repository/DeptRepository.java new file mode 100644 index 0000000..a9d6731 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/repository/DeptRepository.java @@ -0,0 +1,69 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.repository; + +import org.nl.modules.system.domain.Dept; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import java.util.List; +import java.util.Set; + +/** +* @author Zheng Jie +* @date 2019-03-25 +*/ +public interface DeptRepository extends JpaRepository, JpaSpecificationExecutor { + + /** + * 根据 PID 查询 + * @param id pid + * @return / + */ + List findByPid(Long id); + + /** + * 获取顶级部门 + * @return / + */ + List findByPidIsNull(); + + /** + * 根据角色ID 查询 + * @param roleId 角色ID + * @return / + */ + @Query(value = "select d.* from sys_dept d, sys_roles_depts r where " + + "d.dept_id = r.dept_id and r.role_id = ?1", nativeQuery = true) + Set findByRoleId(Long roleId); + + /** + * 判断是否存在子节点 + * @param pid / + * @return / + */ + int countByPid(Long pid); + + /** + * 根据ID更新sub_count + * @param count / + * @param id / + */ + @Modifying + @Query(value = " update sys_dept set sub_count = ?1 where dept_id = ?2 ",nativeQuery = true) + void updateSubCntById(Integer count, Long id); +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/repository/DictDetailRepository.java b/nladmin-system/src/main/java/org/nl/modules/system/repository/DictDetailRepository.java new file mode 100644 index 0000000..a16ac27 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/repository/DictDetailRepository.java @@ -0,0 +1,36 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.repository; + +import org.nl.modules.system.domain.DictDetail; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +public interface DictDetailRepository extends JpaRepository, JpaSpecificationExecutor { + + /** + * 根据字典名称查询 + * @param name / + * @return / + */ + List findByDictName(String name); +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/repository/DictRepository.java b/nladmin-system/src/main/java/org/nl/modules/system/repository/DictRepository.java new file mode 100644 index 0000000..059278c --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/repository/DictRepository.java @@ -0,0 +1,43 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.repository; + +import org.nl.modules.system.domain.Dict; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; +import java.util.Set; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +public interface DictRepository extends JpaRepository, JpaSpecificationExecutor { + + /** + * 删除 + * @param ids / + */ + void deleteByIdIn(Set ids); + + /** + * 查询 + * @param ids / + * @return / + */ + List findByIdIn(Set ids); +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/repository/JobRepository.java b/nladmin-system/src/main/java/org/nl/modules/system/repository/JobRepository.java new file mode 100644 index 0000000..e29f5f6 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/repository/JobRepository.java @@ -0,0 +1,42 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.repository; + +import org.nl.modules.system.domain.Job; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.Set; + +/** +* @author Zheng Jie +* @date 2019-03-29 +*/ +public interface JobRepository extends JpaRepository, JpaSpecificationExecutor { + + /** + * 根据名称查询 + * @param name 名称 + * @return / + */ + Job findByName(String name); + + /** + * 根据Id删除 + * @param ids / + */ + void deleteAllByIdIn(Set ids); +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/repository/MenuRepository.java b/nladmin-system/src/main/java/org/nl/modules/system/repository/MenuRepository.java new file mode 100644 index 0000000..7fa8f18 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/repository/MenuRepository.java @@ -0,0 +1,85 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.repository; + +import org.nl.modules.system.domain.Menu; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2018-12-17 + */ +public interface MenuRepository extends JpaRepository, JpaSpecificationExecutor { + + /** + * 根据菜单标题查询 + * @param title 菜单标题 + * @return / + */ + Menu findByTitle(String title); + + /** + * 根据组件名称查询 + * @param name 组件名称 + * @return / + */ + Menu findByComponentName(String name); + + /** + * 根据菜单的 PID 查询 + * @param pid / + * @return / + */ + List findByPid(long pid); + + /** + * 查询顶级菜单 + * @return / + */ + List findByPidIsNull(); + + /** + * 根据角色ID与菜单类型查询菜单 + * @param roleIds roleIDs + * @param type 类型 + * @return / + */ + @Query(value = "SELECT m.* FROM sys_menu m, sys_roles_menus r WHERE " + + "m.menu_id = r.menu_id AND r.role_id IN ?1 AND type != ?2 order by m.menu_sort asc",nativeQuery = true) + LinkedHashSet findByRoleIdsAndTypeNot(Set roleIds, int type); + + /** + * 获取节点数量 + * @param id / + * @return / + */ + int countByPid(Long id); + + /** + * 更新节点数目 + * @param count / + * @param menuId / + */ + @Modifying + @Query(value = " update sys_menu set sub_count = ?1 where menu_id = ?2 ",nativeQuery = true) + void updateSubCntById(int count, Long menuId); +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/repository/ParamRepository.java b/nladmin-system/src/main/java/org/nl/modules/system/repository/ParamRepository.java new file mode 100644 index 0000000..619d3a1 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/repository/ParamRepository.java @@ -0,0 +1,13 @@ + +package org.nl.modules.system.repository; + +import org.nl.modules.system.domain.Param; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** +* @author ldjun +* @date 2021-01-13 +**/ +public interface ParamRepository extends JpaRepository, JpaSpecificationExecutor { +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/repository/RoleRepository.java b/nladmin-system/src/main/java/org/nl/modules/system/repository/RoleRepository.java new file mode 100644 index 0000000..4d59261 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/repository/RoleRepository.java @@ -0,0 +1,80 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.repository; + +import org.nl.modules.system.domain.Role; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2018-12-03 + */ +public interface RoleRepository extends JpaRepository, JpaSpecificationExecutor { + + /** + * 根据名称查询 + * @param name / + * @return / + */ + Role findByName(String name); + + /** + * 删除多个角色 + * @param ids / + */ + void deleteAllByIdIn(Set ids); + + /** + * 根据用户ID查询 + * @param id 用户ID + * @return / + */ + @Query(value = "SELECT r.* FROM sys_role r, sys_users_roles u WHERE " + + "r.role_id = u.role_id AND u.user_id = ?1",nativeQuery = true) + Set findByUserId(Long id); + + /** + * 解绑角色菜单 + * @param id 菜单ID + */ + @Modifying + @Query(value = "delete from sys_roles_menus where menu_id = ?1",nativeQuery = true) + void untiedMenu(Long id); + + /** + * 根据部门查询 + * @param deptIds / + * @return / + */ + @Query(value = "select count(1) from sys_role r, sys_roles_depts d where " + + "r.role_id = d.role_id and d.dept_id in ?1",nativeQuery = true) + int countByDepts(Set deptIds); + + /** + * 根据菜单Id查询 + * @param menuIds / + * @return / + */ + @Query(value = "SELECT r.* FROM sys_role r, sys_roles_menus m WHERE " + + "r.role_id = m.role_id AND m.menu_id in ?1",nativeQuery = true) + List findInMenuId(List menuIds); +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/repository/UserRepository.java b/nladmin-system/src/main/java/org/nl/modules/system/repository/UserRepository.java new file mode 100644 index 0000000..76fac5c --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/repository/UserRepository.java @@ -0,0 +1,132 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.repository; + +import org.nl.modules.system.domain.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import java.util.Date; +import java.util.List; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2018-11-22 + */ +public interface UserRepository extends JpaRepository, JpaSpecificationExecutor { + + /** + * 根据用户名查询 + * @param username 用户名 + * @return / + */ + User findByUsername(String username); + + /** + * 根据角色中的部门查询 + * @param deptId / + * @return / + */ + @Query(value = "SELECT u.* FROM sys_user u, sys_users_roles r, sys_roles_depts d WHERE " + + "u.user_id = r.user_id AND r.role_id = d.role_id AND d.dept_id = ?1 group by u.user_id", nativeQuery = true) + List findByRoleDeptId(Long deptId); + + /** + * 根据邮箱查询 + * @param email 邮箱 + * @return / + */ + User findByEmail(String email); + + /** + * 修改密码 + * @param username 用户名 + * @param pass 密码 + * @param lastPasswordResetTime / + */ + @Modifying + @Query(value = "update sys_user set password = ?2 , pwd_reset_time = ?3 where username = ?1",nativeQuery = true) + void updatePass(String username, String pass, Date lastPasswordResetTime); + + /** + * 修改邮箱 + * @param username 用户名 + * @param email 邮箱 + */ + @Modifying + @Query(value = "update sys_user set email = ?2 where username = ?1",nativeQuery = true) + void updateEmail(String username, String email); + + /** + * 根据角色查询用户 + * @param roleId / + * @return / + */ + @Query(value = "SELECT u.* FROM sys_user u, sys_users_roles r WHERE" + + " u.user_id = r.user_id AND r.role_id = ?1", nativeQuery = true) + List findByRoleId(Long roleId); + + /** + * 根据角色中的部门查询 + * @param id / + * @return / + */ + @Query(value = "SELECT u.* FROM sys_user u, sys_users_roles r, sys_roles_depts d WHERE " + + "u.user_id = r.user_id AND r.role_id = d.role_id AND r.role_id = ?1 group by u.user_id", nativeQuery = true) + List findByDeptRoleId(Long id); + + /** + * 根据菜单查询 + * @param id 菜单ID + * @return / + */ + @Query(value = "SELECT u.* FROM sys_user u, sys_users_roles ur, sys_roles_menus rm WHERE\n" + + "u.user_id = ur.user_id AND ur.role_id = rm.role_id AND rm.menu_id = ?1 group by u.user_id", nativeQuery = true) + List findByMenuId(Long id); + + /** + * 根据Id删除 + * @param ids / + */ + void deleteAllByIdIn(Set ids); + + /** + * 根据岗位查询 + * @param ids / + * @return / + */ + @Query(value = "SELECT count(1) FROM sys_user u, sys_users_jobs j WHERE u.user_id = j.user_id AND j.job_id IN ?1", nativeQuery = true) + int countByJobs(Set ids); + + /** + * 根据部门查询 + * @param deptIds / + * @return / + */ + @Query(value = "SELECT count(1) FROM sys_user u WHERE u.dept_id IN ?1", nativeQuery = true) + int countByDepts(Set deptIds); + + /** + * 根据角色查询 + * @param ids / + * @return / + */ + @Query(value = "SELECT count(1) FROM sys_user u, sys_users_roles r WHERE " + + "u.user_id = r.user_id AND r.role_id in ?1", nativeQuery = true) + int countByRoles(Set ids); +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/rest/AutoRunController.java b/nladmin-system/src/main/java/org/nl/modules/system/rest/AutoRunController.java new file mode 100644 index 0000000..b4eb1bc --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/rest/AutoRunController.java @@ -0,0 +1,55 @@ +package org.nl.modules.system.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.nl.annotation.Log; +import org.nl.start.auto.run.AutoRunService; +import org.nl.start.auto.run.ThreadDto; +import org.nl.utils.PageUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +/** + * @author / + * 接口限流测试类 + */ +@RestController +@RequestMapping("/api/autorun") +@Api(tags = "系统:查询自动线程") +@RequiredArgsConstructor +public class AutoRunController { + + @Autowired + private AutoRunService autoRunService; + + @ApiOperation("查询自动线程") + @Log("查询自动线程") + @GetMapping + public ResponseEntity query(Map map) throws Exception { + //List ThreadDtos = autoRunService.findByCondition(map); + List ThreadDtos = autoRunService.findAll(); + return new ResponseEntity<>(PageUtil.toPage(ThreadDtos, ThreadDtos.size()), HttpStatus.OK); + } + + @Log("启动自动线程") + @ApiOperation("启动自动线程") + @PutMapping(value = "/start/{code}") + public ResponseEntity start(@PathVariable String code) { + autoRunService.startThread(code); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("停止自动线程") + @ApiOperation("停止自动线程") + @PutMapping(value = "/stop/{code}") + public ResponseEntity execution(@PathVariable String code) { + autoRunService.stopThread(code); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/rest/CodeDetailController.java b/nladmin-system/src/main/java/org/nl/modules/system/rest/CodeDetailController.java new file mode 100644 index 0000000..b1e6233 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/rest/CodeDetailController.java @@ -0,0 +1,61 @@ +package org.nl.modules.system.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import net.sf.json.JSONObject; +import org.nl.annotation.Log; +import org.nl.modules.system.service.CodeDetailService; +import org.nl.modules.system.service.GenCodeService; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; +import java.util.Set; + +@RestController +@Api(tags = "系统:编码详情管理") +@RequiredArgsConstructor +@RequestMapping("/api/codeDetail") +public class CodeDetailController { + + private final CodeDetailService codeDetailService; + + @ApiOperation("查询编码明细") + @GetMapping + @PreAuthorize("@el.check('genCode:list')") + public ResponseEntity queryAll(@RequestParam Map form, Pageable pageable){ + return new ResponseEntity<>(codeDetailService.queryAll(form,pageable), HttpStatus.OK); + } + + @Log("新增编码") + @ApiOperation("新增编码") + @PostMapping + @PreAuthorize("@el.check('genCode:add')") + public ResponseEntity create(@Validated @RequestBody Map form){ + codeDetailService.create(form); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("删除编码") + @ApiOperation("删除编码") + @DeleteMapping(value = "/{id}") + @PreAuthorize("@el.check('genCode:del')") + public ResponseEntity delete(@PathVariable String id){ + codeDetailService.delete(id); + return new ResponseEntity<>(HttpStatus.OK); + } + + @Log("修改字典") + @ApiOperation("修改字典") + @PutMapping + @PreAuthorize("@el.check('dict:edit')") + public ResponseEntity update(@RequestBody JSONObject json){ + codeDetailService.update(json); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/rest/DeptController.java b/nladmin-system/src/main/java/org/nl/modules/system/rest/DeptController.java new file mode 100644 index 0000000..b54ce79 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/rest/DeptController.java @@ -0,0 +1,117 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.rest; + +import cn.hutool.core.collection.CollectionUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.nl.annotation.Log; +import org.nl.exception.BadRequestException; +import org.nl.modules.system.domain.Dept; +import org.nl.modules.system.service.DeptService; +import org.nl.modules.system.service.dto.DeptDto; +import org.nl.modules.system.service.dto.DeptQueryCriteria; +import org.nl.utils.PageUtil; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +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.*; + +/** +* @author Zheng Jie +* @date 2019-03-25 +*/ +@RestController +@RequiredArgsConstructor +@Api(tags = "系统:部门管理") +@RequestMapping("/api/dept") +public class DeptController { + + private final DeptService deptService; + private static final String ENTITY_NAME = "dept"; + + @ApiOperation("导出部门数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('dept:list')") + public void download(HttpServletResponse response, DeptQueryCriteria criteria) throws Exception { + deptService.download(deptService.queryAll(criteria, false), response); + } + + @ApiOperation("查询部门") + @GetMapping + @PreAuthorize("@el.check('user:list','dept:list')") + public ResponseEntity query(DeptQueryCriteria criteria) throws Exception { + List deptDtos = deptService.queryAll(criteria, true); + return new ResponseEntity<>(PageUtil.toPage(deptDtos, deptDtos.size()),HttpStatus.OK); + } + + @ApiOperation("查询部门:根据ID获取同级与上级数据") + @PostMapping("/superior") + @PreAuthorize("@el.check('user:list','dept:list')") + public ResponseEntity getSuperior(@RequestBody List ids) { + Set deptDtos = new LinkedHashSet<>(); + for (Long id : ids) { + DeptDto deptDto = deptService.findById(id); + List depts = deptService.getSuperior(deptDto, new ArrayList<>()); + deptDtos.addAll(depts); + } + return new ResponseEntity<>(deptService.buildTree(new ArrayList<>(deptDtos)),HttpStatus.OK); + } + + @Log("新增部门") + @ApiOperation("新增部门") + @PostMapping + @PreAuthorize("@el.check('dept:add')") + public ResponseEntity create(@Validated @RequestBody Dept resources){ + if (resources.getId() != null) { + throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID"); + } + deptService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改部门") + @ApiOperation("修改部门") + @PutMapping + @PreAuthorize("@el.check('dept:edit')") + public ResponseEntity update(@Validated(Dept.Update.class) @RequestBody Dept resources){ + deptService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除部门") + @ApiOperation("删除部门") + @DeleteMapping + @PreAuthorize("@el.check('dept:del')") + public ResponseEntity delete(@RequestBody Set ids){ + Set deptDtos = new HashSet<>(); + for (Long id : ids) { + List deptList = deptService.findByPid(id); + deptDtos.add(deptService.findById(id)); + if(CollectionUtil.isNotEmpty(deptList)){ + deptDtos = deptService.getDeleteDepts(deptList, deptDtos); + } + } + // 验证是否被角色或用户关联 + deptService.verification(deptDtos); + deptService.delete(deptDtos); + return new ResponseEntity<>(HttpStatus.OK); + } +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/rest/DictController.java b/nladmin-system/src/main/java/org/nl/modules/system/rest/DictController.java new file mode 100644 index 0000000..71ca1d2 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/rest/DictController.java @@ -0,0 +1,100 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.nl.annotation.Log; +import org.nl.exception.BadRequestException; +import org.nl.modules.system.domain.Dict; +import org.nl.modules.system.service.DictService; +import org.nl.modules.system.service.dto.DictQueryCriteria; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +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.io.IOException; +import java.util.Set; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@RestController +@RequiredArgsConstructor +@Api(tags = "系统:字典管理") +@RequestMapping("/api/dict") +public class DictController { + + private final DictService dictService; + private static final String ENTITY_NAME = "dict"; + + @ApiOperation("导出字典数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('dict:list')") + public void download(HttpServletResponse response, DictQueryCriteria criteria) throws IOException { + dictService.download(dictService.queryAll(criteria), response); + } + + @ApiOperation("查询字典") + @GetMapping(value = "/all") + @PreAuthorize("@el.check('dict:list')") + public ResponseEntity queryAll(){ + return new ResponseEntity<>(dictService.queryAll(new DictQueryCriteria()),HttpStatus.OK); + } + + @ApiOperation("查询字典") + @GetMapping + @PreAuthorize("@el.check('dict:list')") + public ResponseEntity query(DictQueryCriteria resources, Pageable pageable){ + return new ResponseEntity<>(dictService.queryAll(resources,pageable),HttpStatus.OK); + } + + @Log("新增字典") + @ApiOperation("新增字典") + @PostMapping + @PreAuthorize("@el.check('dict:add')") + public ResponseEntity create(@Validated @RequestBody Dict resources){ + if (resources.getId() != null) { + throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID"); + } + dictService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改字典") + @ApiOperation("修改字典") + @PutMapping + @PreAuthorize("@el.check('dict:edit')") + public ResponseEntity update(@Validated(Dict.Update.class) @RequestBody Dict resources){ + dictService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除字典") + @ApiOperation("删除字典") + @DeleteMapping + @PreAuthorize("@el.check('dict:del')") + public ResponseEntity delete(@RequestBody Set ids){ + dictService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/rest/DictDetailController.java b/nladmin-system/src/main/java/org/nl/modules/system/rest/DictDetailController.java new file mode 100644 index 0000000..839c886 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/rest/DictDetailController.java @@ -0,0 +1,106 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.nl.annotation.Log; +import org.nl.exception.BadRequestException; +import org.nl.modules.system.domain.Dict; +import org.nl.modules.system.domain.DictDetail; +import org.nl.modules.system.repository.DictRepository; +import org.nl.modules.system.service.DictDetailService; +import org.nl.modules.system.service.DictService; +import org.nl.modules.system.service.dto.DictDetailDto; +import org.nl.modules.system.service.dto.DictDetailQueryCriteria; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.web.PageableDefault; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * @author Zheng Jie + * @date 2019-04-10 + */ +@RestController +@RequiredArgsConstructor +@Api(tags = "系统:字典详情管理") +@RequestMapping("/api/dictDetail") +public class DictDetailController { + private final DictRepository dictRepository; + private final DictDetailService dictDetailService; + private static final String ENTITY_NAME = "dictDetail"; + + @ApiOperation("查询字典详情") + @GetMapping + public ResponseEntity query(DictDetailQueryCriteria criteria, + @PageableDefault(sort = {"dictSort"}, direction = Sort.Direction.ASC) Pageable pageable){ + return new ResponseEntity<>(dictDetailService.queryAll(criteria,pageable),HttpStatus.OK); + } + + @ApiOperation("查询多个字典详情") + @GetMapping(value = "/map") + public ResponseEntity getDictDetailMaps(@RequestParam String dictName){ + String[] names = dictName.split("[,,]"); + Map> dictMap = new HashMap<>(16); + for (String name : names) { + dictMap.put(name, dictDetailService.getDictByName(name)); + } + return new ResponseEntity<>(dictMap, HttpStatus.OK); + } + + @Log("新增字典详情") + @ApiOperation("新增字典详情") + @PostMapping + @PreAuthorize("@el.check('dict:add')") + public ResponseEntity create(@Validated @RequestBody DictDetail resources){ + if (resources.getId() != null) { + throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID"); + } + Optional d=dictRepository.findById(resources.getDict().getId()); + resources.setName(dictRepository.findById(resources.getDict().getId()).get().getName()); + dictDetailService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改字典详情") + @ApiOperation("修改字典详情") + @PutMapping + @PreAuthorize("@el.check('dict:edit')") + public ResponseEntity update(@Validated(DictDetail.Update.class) @RequestBody DictDetail resources){ + resources.setName(dictRepository.findById(resources.getDict().getId()).get().getName()); + dictDetailService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除字典详情") + @ApiOperation("删除字典详情") + @DeleteMapping(value = "/{id}") + @PreAuthorize("@el.check('dict:del')") + public ResponseEntity delete(@PathVariable Long id){ + dictDetailService.delete(id); + return new ResponseEntity<>(HttpStatus.OK); + } +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/rest/GenCodeController.java b/nladmin-system/src/main/java/org/nl/modules/system/rest/GenCodeController.java new file mode 100644 index 0000000..e8804ed --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/rest/GenCodeController.java @@ -0,0 +1,69 @@ +package org.nl.modules.system.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import net.sf.json.JSONObject; +import org.nl.annotation.Log; +import org.nl.modules.system.service.GenCodeService; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.Map; +import java.util.Set; + +@RestController +@Api(tags = "系统:编码生成") +@RequiredArgsConstructor +@RequestMapping("/api/genCode") +public class GenCodeController { + private final GenCodeService genCodeService; + + @ApiOperation("查询编码") + @GetMapping + @PreAuthorize("@el.check('genCode:list')") + public ResponseEntity queryAll(@RequestParam Map form, Pageable pageable) { + return new ResponseEntity<>(genCodeService.queryAll(form, pageable), HttpStatus.OK); + } + + @Log("新增编码") + @ApiOperation("新增编码") + @PostMapping + @PreAuthorize("@el.check('genCode:add')") + public ResponseEntity create(@Validated @RequestBody Map form) { + genCodeService.create(form); + + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("删除编码") + @ApiOperation("删除编码") + @DeleteMapping + @PreAuthorize("@el.check('genCode:del')") + public ResponseEntity delete(@RequestBody Set ids) { + genCodeService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } + + @Log("修改字典") + @ApiOperation("修改字典") + @PutMapping + @PreAuthorize("@el.check('genCode:edit')") + public ResponseEntity update(@RequestBody JSONObject json) { + genCodeService.update(json); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @ApiOperation("导出任务数据") + @GetMapping(value = "/codeDemo") + @PreAuthorize("@el.check('genCode:list')") + public ResponseEntity CodeDemo(@RequestParam Map form) throws IOException { + return new ResponseEntity<>(genCodeService.codeDemo(form), HttpStatus.OK); + } + +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/rest/JobController.java b/nladmin-system/src/main/java/org/nl/modules/system/rest/JobController.java new file mode 100644 index 0000000..b26d6e7 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/rest/JobController.java @@ -0,0 +1,94 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.nl.annotation.Log; +import org.nl.exception.BadRequestException; +import org.nl.modules.system.domain.Job; +import org.nl.modules.system.service.JobService; +import org.nl.modules.system.service.dto.JobQueryCriteria; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +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.io.IOException; +import java.util.Set; + +/** +* @author Zheng Jie +* @date 2019-03-29 +*/ +@RestController +@RequiredArgsConstructor +@Api(tags = "系统:岗位管理") +@RequestMapping("/api/job") +public class JobController { + + private final JobService jobService; + private static final String ENTITY_NAME = "job"; + + @ApiOperation("导出岗位数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('job:list')") + public void download(HttpServletResponse response, JobQueryCriteria criteria) throws IOException { + jobService.download(jobService.queryAll(criteria), response); + } + + @ApiOperation("查询岗位") + @GetMapping + @PreAuthorize("@el.check('job:list','user:list')") + public ResponseEntity query(JobQueryCriteria criteria, Pageable pageable){ + return new ResponseEntity<>(jobService.queryAll(criteria, pageable),HttpStatus.OK); + } + + @Log("新增岗位") + @ApiOperation("新增岗位") + @PostMapping + @PreAuthorize("@el.check('job:add')") + public ResponseEntity create(@Validated @RequestBody Job resources){ + if (resources.getId() != null) { + throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID"); + } + jobService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改岗位") + @ApiOperation("修改岗位") + @PutMapping + @PreAuthorize("@el.check('job:edit')") + public ResponseEntity update(@Validated(Job.Update.class) @RequestBody Job resources){ + jobService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除岗位") + @ApiOperation("删除岗位") + @DeleteMapping + @PreAuthorize("@el.check('job:del')") + public ResponseEntity delete(@RequestBody Set ids){ + // 验证是否被用户关联 + jobService.verification(ids); + jobService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/rest/LimitController.java b/nladmin-system/src/main/java/org/nl/modules/system/rest/LimitController.java new file mode 100644 index 0000000..ffee4d3 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/rest/LimitController.java @@ -0,0 +1,47 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.nl.annotation.Limit; +import org.nl.annotation.rest.AnonymousGetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author / + * 接口限流测试类 + */ +@RestController +@RequestMapping("/api/limit") +@Api(tags = "系统:限流测试管理") +public class LimitController { + + private static final AtomicInteger ATOMIC_INTEGER = new AtomicInteger(); + + /** + * 测试限流注解,下面配置说明该接口 60秒内最多只能访问 10次,保存到redis的键名为 limit_test, + */ + @AnonymousGetMapping + @ApiOperation("测试") + @Limit(key = "test", period = 60, count = 10, name = "testLimit", prefix = "limit") + public int test() { + return ATOMIC_INTEGER.incrementAndGet(); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/rest/MenuController.java b/nladmin-system/src/main/java/org/nl/modules/system/rest/MenuController.java new file mode 100644 index 0000000..a2b8517 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/rest/MenuController.java @@ -0,0 +1,147 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.rest; + +import cn.hutool.core.collection.CollectionUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.nl.annotation.Log; +import org.nl.modules.system.domain.Menu; +import org.nl.exception.BadRequestException; +import org.nl.modules.system.service.MenuService; +import org.nl.modules.system.service.dto.MenuDto; +import org.nl.modules.system.service.dto.MenuQueryCriteria; +import org.nl.modules.system.service.mapstruct.MenuMapper; +import org.nl.utils.PageUtil; +import org.nl.utils.SecurityUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +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.*; +import java.util.stream.Collectors; + +/** + * @author Zheng Jie + * @date 2018-12-03 + */ + +@RestController +@RequiredArgsConstructor +@Api(tags = "系统:菜单管理") +@RequestMapping("/api/menus") +public class MenuController { + + private final MenuService menuService; + private final MenuMapper menuMapper; + private static final String ENTITY_NAME = "menu"; + + @ApiOperation("导出菜单数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('menu:list')") + public void download(HttpServletResponse response, MenuQueryCriteria criteria) throws Exception { + menuService.download(menuService.queryAll(criteria, false), response); + } + + @GetMapping(value = "/build") + @ApiOperation("获取前端所需菜单") + public ResponseEntity buildMenus(){ + List menuDtoList = menuService.findByUser(SecurityUtils.getCurrentUserId()); + List menuDtos = menuService.buildTree(menuDtoList); + return new ResponseEntity<>(menuService.buildMenus(menuDtos),HttpStatus.OK); + } + + @ApiOperation("返回全部的菜单") + @GetMapping(value = "/lazy") + @PreAuthorize("@el.check('menu:list','roles:list')") + public ResponseEntity query(@RequestParam Long pid){ + return new ResponseEntity<>(menuService.getMenus(pid),HttpStatus.OK); + } + + @ApiOperation("根据菜单ID返回所有子节点ID,包含自身ID") + @GetMapping(value = "/child") + @PreAuthorize("@el.check('menu:list','roles:list')") + public ResponseEntity child(@RequestParam Long id){ + Set menuSet = new HashSet<>(); + List menuList = menuService.getMenus(id); + menuSet.add(menuService.findOne(id)); + menuSet = menuService.getChildMenus(menuMapper.toEntity(menuList), menuSet); + Set ids = menuSet.stream().map(Menu::getId).collect(Collectors.toSet()); + return new ResponseEntity<>(ids,HttpStatus.OK); + } + + @GetMapping + @ApiOperation("查询菜单") + @PreAuthorize("@el.check('menu:list')") + public ResponseEntity query(MenuQueryCriteria criteria) throws Exception { + List menuDtoList = menuService.queryAll(criteria, true); + return new ResponseEntity<>(PageUtil.toPage(menuDtoList, menuDtoList.size()),HttpStatus.OK); + } + + @ApiOperation("查询菜单:根据ID获取同级与上级数据") + @PostMapping("/superior") + @PreAuthorize("@el.check('menu:list')") + public ResponseEntity getSuperior(@RequestBody List ids) { + Set menuDtos = new LinkedHashSet<>(); + if(CollectionUtil.isNotEmpty(ids)){ + for (Long id : ids) { + MenuDto menuDto = menuService.findById(id); + menuDtos.addAll(menuService.getSuperior(menuDto, new ArrayList<>())); + } + return new ResponseEntity<>(menuService.buildTree(new ArrayList<>(menuDtos)),HttpStatus.OK); + } + return new ResponseEntity<>(menuService.getMenus(null),HttpStatus.OK); + } + + @Log("新增菜单") + @ApiOperation("新增菜单") + @PostMapping + @PreAuthorize("@el.check('menu:add')") + public ResponseEntity create(@Validated @RequestBody Menu resources){ + if (resources.getId() != null) { + throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID"); + } + menuService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改菜单") + @ApiOperation("修改菜单") + @PutMapping + @PreAuthorize("@el.check('menu:edit')") + public ResponseEntity update(@Validated(Menu.Update.class) @RequestBody Menu resources){ + menuService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除菜单") + @ApiOperation("删除菜单") + @DeleteMapping + @PreAuthorize("@el.check('menu:del')") + public ResponseEntity delete(@RequestBody Set ids){ + Set menuSet = new HashSet<>(); + for (Long id : ids) { + List menuList = menuService.getMenus(id); + menuSet.add(menuService.findOne(id)); + menuSet = menuService.getChildMenus(menuMapper.toEntity(menuList), menuSet); + } + menuService.delete(menuSet); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/rest/MonitorController.java b/nladmin-system/src/main/java/org/nl/modules/system/rest/MonitorController.java new file mode 100644 index 0000000..f5536f7 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/rest/MonitorController.java @@ -0,0 +1,45 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.nl.modules.system.service.MonitorService; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +/** + * @author Zheng Jie + * @date 2020-05-02 + */ +@RestController +@RequiredArgsConstructor +@Api(tags = "系统-服务监控管理") +@RequestMapping("/api/monitor") +public class MonitorController { + + private final MonitorService serverService; + + @GetMapping + @ApiOperation("查询服务监控") + @PreAuthorize("@el.check('monitor:list')") + public ResponseEntity query(){ + return new ResponseEntity<>(serverService.getServers(),HttpStatus.OK); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/rest/ParamController.java b/nladmin-system/src/main/java/org/nl/modules/system/rest/ParamController.java new file mode 100644 index 0000000..edb403b --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/rest/ParamController.java @@ -0,0 +1,78 @@ + +package org.nl.modules.system.rest; + + +import cn.hutool.http.Header; +import cn.hutool.http.HttpRequest; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.nl.annotation.Log; +import org.nl.modules.system.service.ParamService; +import org.nl.modules.system.service.dto.ParamDto; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Map; + +/** + * @author ldjun + * @date 2021-01-14 + **/ +@RestController +@RequiredArgsConstructor +@Api(tags = "系统参数管理") +@RequestMapping("/api/param") +@Slf4j +public class ParamController { + + private final ParamService paramService; + + @GetMapping + @Log("查询系统参数") + @ApiOperation("查询系统参数") + //@PreAuthorize("@el.check('param:list')") + public ResponseEntity query(@RequestParam Map whereJson, Pageable page){ + return new ResponseEntity<>(paramService.queryAll(whereJson,page),HttpStatus.OK); + } + @PostMapping + @Log("新增系统参数") + @ApiOperation("新增系统参数") + //@PreAuthorize("@el.check('param:add')") + public ResponseEntity create(@Validated @RequestBody ParamDto dto){ + paramService.create(dto); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @PutMapping + @Log("修改系统参数") + @ApiOperation("修改系统参数") + //@PreAuthorize("@el.check('param:edit')") + public ResponseEntity update(@Validated @RequestBody ParamDto dto){ + paramService.update(dto); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除系统参数") + @ApiOperation("删除系统参数") + //@PreAuthorize("@el.check('param:del')") + @DeleteMapping + public ResponseEntity delete(@RequestBody String[] ids) { + paramService.deleteAll(ids); + return new ResponseEntity<>(HttpStatus.OK); + } + + @Log("导出系统参数") + @ApiOperation("导出系统参数") + @GetMapping(value = "/download") + //@PreAuthorize("@el.check('param:list')") + public void download(HttpServletResponse response, Map whereJson) throws IOException { + paramService.download(paramService.queryAll(whereJson), response); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/rest/RoleController.java b/nladmin-system/src/main/java/org/nl/modules/system/rest/RoleController.java new file mode 100644 index 0000000..e8e979a --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/rest/RoleController.java @@ -0,0 +1,154 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.rest; + +import cn.hutool.core.lang.Dict; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.nl.annotation.Log; +import org.nl.modules.system.domain.Role; +import org.nl.exception.BadRequestException; +import org.nl.modules.system.service.RoleService; +import org.nl.modules.system.service.dto.RoleDto; +import org.nl.modules.system.service.dto.RoleQueryCriteria; +import org.nl.modules.system.service.dto.RoleSmallDto; +import org.nl.utils.SecurityUtils; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +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.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author Zheng Jie + * @date 2018-12-03 + */ +@RestController +@RequiredArgsConstructor +@Api(tags = "系统:角色管理") +@RequestMapping("/api/roles") +public class RoleController { + + private final RoleService roleService; + + private static final String ENTITY_NAME = "role"; + + @ApiOperation("获取单个role") + @GetMapping(value = "/{id}") + @PreAuthorize("@el.check('roles:list')") + public ResponseEntity query(@PathVariable Long id){ + return new ResponseEntity<>(roleService.findById(id), HttpStatus.OK); + } + + @ApiOperation("导出角色数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('role:list')") + public void download(HttpServletResponse response, RoleQueryCriteria criteria) throws IOException { + roleService.download(roleService.queryAll(criteria), response); + } + + @ApiOperation("返回全部的角色") + @GetMapping(value = "/all") + @PreAuthorize("@el.check('roles:list','user:add','user:edit')") + public ResponseEntity query(){ + return new ResponseEntity<>(roleService.queryAll(),HttpStatus.OK); + } + + @ApiOperation("查询角色") + @GetMapping + @PreAuthorize("@el.check('roles:list')") + public ResponseEntity query(RoleQueryCriteria criteria, Pageable pageable){ + return new ResponseEntity<>(roleService.queryAll(criteria,pageable),HttpStatus.OK); + } + + @ApiOperation("获取用户级别") + @GetMapping(value = "/level") + public ResponseEntity getLevel(){ + return new ResponseEntity<>(Dict.create().set("level", getLevels(null)),HttpStatus.OK); + } + + @Log("新增角色") + @ApiOperation("新增角色") + @PostMapping + @PreAuthorize("@el.check('roles:add')") + public ResponseEntity create(@Validated @RequestBody Role resources){ + if (resources.getId() != null) { + throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID"); + } + getLevels(resources.getLevel()); + roleService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改角色") + @ApiOperation("修改角色") + @PutMapping + @PreAuthorize("@el.check('roles:edit')") + public ResponseEntity update(@Validated(Role.Update.class) @RequestBody Role resources){ + getLevels(resources.getLevel()); + roleService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("修改角色菜单") + @ApiOperation("修改角色菜单") + @PutMapping(value = "/menu") + @PreAuthorize("@el.check('roles:edit')") + public ResponseEntity updateMenu(@RequestBody Role resources){ + RoleDto role = roleService.findById(resources.getId()); + getLevels(role.getLevel()); + roleService.updateMenu(resources,role); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除角色") + @ApiOperation("删除角色") + @DeleteMapping + @PreAuthorize("@el.check('roles:del')") + public ResponseEntity delete(@RequestBody Set ids){ + for (Long id : ids) { + RoleDto role = roleService.findById(id); + getLevels(role.getLevel()); + } + // 验证是否被用户关联 + roleService.verification(ids); + roleService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } + + /** + * 获取用户的角色级别 + * @return / + */ + private int getLevels(Integer level){ + List levels = roleService.findByUsersId(SecurityUtils.getCurrentUserId()).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList()); + int min = Collections.min(levels); + if(level != null){ + if(level < min){ + throw new BadRequestException("权限不足,你的角色级别:" + min + ",低于操作的角色级别:" + level); + } + } + return min; + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/rest/UserController.java b/nladmin-system/src/main/java/org/nl/modules/system/rest/UserController.java new file mode 100644 index 0000000..051e2f3 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/rest/UserController.java @@ -0,0 +1,200 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.rest; + +import cn.hutool.core.collection.CollectionUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.nl.annotation.Log; +import org.nl.config.RsaProperties; +import org.nl.modules.system.service.DataService; +import org.nl.modules.system.domain.User; +import org.nl.exception.BadRequestException; +import org.nl.modules.system.domain.vo.UserPassVo; +import org.nl.modules.system.service.DeptService; +import org.nl.modules.system.service.RoleService; +import org.nl.modules.system.service.dto.RoleSmallDto; +import org.nl.modules.system.service.dto.UserDto; +import org.nl.modules.system.service.dto.UserQueryCriteria; +import org.nl.modules.system.service.VerifyService; + +import org.nl.modules.system.service.UserService; +import org.nl.utils.PageUtil; +import org.nl.utils.RsaUtils; +import org.nl.utils.SecurityUtils; +import org.nl.utils.enums.CodeEnum; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; +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.io.IOException; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +@Api(tags = "系统:用户管理") +@RestController +@RequestMapping("/api/users") +@RequiredArgsConstructor +public class UserController { + + private final PasswordEncoder passwordEncoder; + private final UserService userService; + private final DataService dataService; + private final DeptService deptService; + private final RoleService roleService; + private final VerifyService verificationCodeService; + + @ApiOperation("导出用户数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('user:list')") + public void download(HttpServletResponse response, UserQueryCriteria criteria) throws IOException { + userService.download(userService.queryAll(criteria), response); + } + + @ApiOperation("查询用户") + @GetMapping + @PreAuthorize("@el.check('user:list')") + public ResponseEntity query(UserQueryCriteria criteria, Pageable pageable){ + if (!ObjectUtils.isEmpty(criteria.getDeptId())) { + criteria.getDeptIds().add(criteria.getDeptId()); + criteria.getDeptIds().addAll(deptService.getDeptChildren(deptService.findByPid(criteria.getDeptId()))); + } + // 数据权限 + List dataScopes = dataService.getDeptIds(userService.findByName(SecurityUtils.getCurrentUsername())); + // criteria.getDeptIds() 不为空并且数据权限不为空则取交集 + if (!CollectionUtils.isEmpty(criteria.getDeptIds()) && !CollectionUtils.isEmpty(dataScopes)){ + // 取交集 + criteria.getDeptIds().retainAll(dataScopes); + if(!CollectionUtil.isEmpty(criteria.getDeptIds())){ + return new ResponseEntity<>(userService.queryAll(criteria,pageable),HttpStatus.OK); + } + } else { + // 否则取并集 + criteria.getDeptIds().addAll(dataScopes); + return new ResponseEntity<>(userService.queryAll(criteria,pageable),HttpStatus.OK); + } + return new ResponseEntity<>(PageUtil.toPage(null,0),HttpStatus.OK); + } + + @Log("新增用户") + @ApiOperation("新增用户") + @PostMapping + @PreAuthorize("@el.check('user:add')") + public ResponseEntity create(@Validated @RequestBody User resources){ + checkLevel(resources); + // 默认密码 123456 + resources.setPassword(passwordEncoder.encode("123456")); + userService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改用户") + @ApiOperation("修改用户") + @PutMapping + @PreAuthorize("@el.check('user:edit')") + public ResponseEntity update(@Validated(User.Update.class) @RequestBody User resources) throws Exception { + checkLevel(resources); + userService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("修改用户:个人中心") + @ApiOperation("修改用户:个人中心") + @PutMapping(value = "center") + public ResponseEntity center(@Validated(User.Update.class) @RequestBody User resources){ + if(!resources.getId().equals(SecurityUtils.getCurrentUserId())){ + throw new BadRequestException("不能修改他人资料"); + } + userService.updateCenter(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除用户") + @ApiOperation("删除用户") + @DeleteMapping + @PreAuthorize("@el.check('user:del')") + public ResponseEntity delete(@RequestBody Set ids){ + for (Long id : ids) { + Integer currentLevel = Collections.min(roleService.findByUsersId(SecurityUtils.getCurrentUserId()).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList())); + Integer optLevel = Collections.min(roleService.findByUsersId(id).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList())); + if (currentLevel > optLevel) { + throw new BadRequestException("角色权限不足,不能删除:" + userService.findById(id).getUsername()); + } + } + userService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } + + @ApiOperation("修改密码") + @PostMapping(value = "/updatePass") + public ResponseEntity updatePass(@RequestBody UserPassVo passVo) throws Exception { + String oldPass = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey,passVo.getOldPass()); + String newPass = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey,passVo.getNewPass()); + UserDto user = userService.findByName(SecurityUtils.getCurrentUsername()); + if(!passwordEncoder.matches(oldPass, user.getPassword())){ + throw new BadRequestException("修改失败,旧密码错误"); + } + if(passwordEncoder.matches(newPass, user.getPassword())){ + throw new BadRequestException("新密码不能与旧密码相同"); + } + userService.updatePass(user.getUsername(),passwordEncoder.encode(newPass)); + return new ResponseEntity<>(HttpStatus.OK); + } + + @ApiOperation("修改头像") + @PostMapping(value = "/updateAvatar") + public ResponseEntity updateAvatar(@RequestParam MultipartFile avatar){ + return new ResponseEntity<>(userService.updateAvatar(avatar), HttpStatus.OK); + } + + @Log("修改邮箱") + @ApiOperation("修改邮箱") + @PostMapping(value = "/updateEmail/{code}") + public ResponseEntity updateEmail(@PathVariable String code,@RequestBody User user) throws Exception { + String password = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey,user.getPassword()); + UserDto userDto = userService.findByName(SecurityUtils.getCurrentUsername()); + if(!passwordEncoder.matches(password, userDto.getPassword())){ + throw new BadRequestException("密码错误"); + } + verificationCodeService.validated(CodeEnum.EMAIL_RESET_EMAIL_CODE.getKey() + user.getEmail(), code); + userService.updateEmail(userDto.getUsername(),user.getEmail()); + return new ResponseEntity<>(HttpStatus.OK); + } + + /** + * 如果当前用户的角色级别低于创建用户的角色级别,则抛出权限不足的错误 + * @param resources / + */ + private void checkLevel(User resources) { + Integer currentLevel = Collections.min(roleService.findByUsersId(SecurityUtils.getCurrentUserId()).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList())); + Integer optLevel = roleService.findByRoles(resources.getRoles()); + if (currentLevel > optLevel) { + throw new BadRequestException("角色权限不足"); + } + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/rest/VerifyController.java b/nladmin-system/src/main/java/org/nl/modules/system/rest/VerifyController.java new file mode 100644 index 0000000..41d794a --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/rest/VerifyController.java @@ -0,0 +1,76 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.nl.domain.vo.EmailVo; +import org.nl.service.EmailService; +import org.nl.modules.system.service.VerifyService; +import org.nl.utils.enums.CodeBiEnum; +import org.nl.utils.enums.CodeEnum; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import java.util.Objects; + +/** + * @author Zheng Jie + * @date 2018-12-26 + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/code") +@Api(tags = "系统:验证码管理") +public class VerifyController { + + private final VerifyService verificationCodeService; + private final EmailService emailService; + + @PostMapping(value = "/resetEmail") + @ApiOperation("重置邮箱,发送验证码") + public ResponseEntity resetEmail(@RequestParam String email){ + EmailVo emailVo = verificationCodeService.sendEmail(email, CodeEnum.EMAIL_RESET_EMAIL_CODE.getKey()); + emailService.send(emailVo,emailService.find()); + return new ResponseEntity<>(HttpStatus.OK); + } + + @PostMapping(value = "/email/resetPass") + @ApiOperation("重置密码,发送验证码") + public ResponseEntity resetPass(@RequestParam String email){ + EmailVo emailVo = verificationCodeService.sendEmail(email, CodeEnum.EMAIL_RESET_PWD_CODE.getKey()); + emailService.send(emailVo,emailService.find()); + return new ResponseEntity<>(HttpStatus.OK); + } + + @GetMapping(value = "/validated") + @ApiOperation("验证码验证") + public ResponseEntity validated(@RequestParam String email, @RequestParam String code, @RequestParam Integer codeBi){ + CodeBiEnum biEnum = CodeBiEnum.find(codeBi); + switch (Objects.requireNonNull(biEnum)){ + case ONE: + verificationCodeService.validated(CodeEnum.EMAIL_RESET_EMAIL_CODE.getKey() + email ,code); + break; + case TWO: + verificationCodeService.validated(CodeEnum.EMAIL_RESET_PWD_CODE.getKey() + email ,code); + break; + default: + break; + } + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/CodeDetailService.java b/nladmin-system/src/main/java/org/nl/modules/system/service/CodeDetailService.java new file mode 100644 index 0000000..8caf825 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/CodeDetailService.java @@ -0,0 +1,23 @@ +package org.nl.modules.system.service; + +import net.sf.json.JSONObject; +import org.springframework.data.domain.Pageable; + +import java.util.Map; +import java.util.Set; + +public interface CodeDetailService { + /** + * 分页查询 + * @param form 条件 + * @param pageable 分页参数 + * @return / + */ + JSONObject queryAll(Map form, Pageable pageable); + + public void create(Map form); + + public void delete(String id); + + public void update(JSONObject json); +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/DataService.java b/nladmin-system/src/main/java/org/nl/modules/system/service/DataService.java new file mode 100644 index 0000000..e3ab727 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/DataService.java @@ -0,0 +1,35 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service; + +import org.nl.modules.system.service.dto.UserDto; + +import java.util.List; + +/** + * 数据权限服务类 + * @author Zheng Jie + * @date 2020-05-07 + */ +public interface DataService { + + /** + * 获取数据权限 + * @param user / + * @return / + */ + List getDeptIds(UserDto user); +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/DeptService.java b/nladmin-system/src/main/java/org/nl/modules/system/service/DeptService.java new file mode 100644 index 0000000..93286a6 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/DeptService.java @@ -0,0 +1,138 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service; + +import org.nl.modules.system.domain.Dept; +import org.nl.modules.system.service.dto.DeptDto; +import org.nl.modules.system.service.dto.DeptQueryCriteria; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2019-03-25 + */ +public interface DeptService { + + /** + * 查询所有数据 + * + * @param criteria 条件 + * @param isQuery / + * @return / + * @throws Exception / + */ + List queryAll(DeptQueryCriteria criteria, Boolean isQuery) throws Exception; + + /** + * 获取 + * + * @param deptList + * @return + */ + List getDeptChildren(List deptList); + + /** + * 根据ID查询 + * + * @param id / + * @return / + */ + DeptDto findById(Long id); + + /** + * 创建 + * + * @param resources / + */ + void create(Dept resources); + + /** + * 编辑 + * + * @param resources / + */ + void update(Dept resources); + + /** + * 删除 + * + * @param deptDtos / + */ + void delete(Set deptDtos); + + /** + * 根据PID查询 + * + * @param pid / + * @return / + */ + List findByPid(long pid); + + /** + * 根据角色ID查询 + * + * @param id / + * @return / + */ + Set findByRoleId(Long id); + + /** + * 导出数据 + * + * @param queryAll 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; + + /** + * 获取待删除的部门 + * + * @param deptList / + * @param deptDtos / + * @return / + */ + Set getDeleteDepts(List deptList, Set deptDtos); + + /** + * 根据ID获取同级与上级数据 + * + * @param deptDto / + * @param depts / + * @return / + */ + List getSuperior(DeptDto deptDto, List depts); + + /** + * 构建树形数据 + * + * @param deptDtos / + * @return / + */ + Object buildTree(List deptDtos); + + + /** + * 验证是否被角色或用户关联 + * + * @param deptDtos / + */ + void verification(Set deptDtos); +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/DictDetailService.java b/nladmin-system/src/main/java/org/nl/modules/system/service/DictDetailService.java new file mode 100644 index 0000000..f15bd42 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/DictDetailService.java @@ -0,0 +1,63 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service; + +import org.nl.modules.system.domain.DictDetail; +import org.nl.modules.system.service.dto.DictDetailDto; +import org.nl.modules.system.service.dto.DictDetailQueryCriteria; +import org.springframework.data.domain.Pageable; +import java.util.List; +import java.util.Map; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +public interface DictDetailService { + + /** + * 创建 + * @param resources / + */ + void create(DictDetail resources); + + /** + * 编辑 + * @param resources / + */ + void update(DictDetail resources); + + /** + * 删除 + * @param id / + */ + void delete(Long id); + + /** + * 分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Map queryAll(DictDetailQueryCriteria criteria, Pageable pageable); + + /** + * 根据字典名称获取字典详情 + * @param name 字典名称 + * @return / + */ + List getDictByName(String name); +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/DictService.java b/nladmin-system/src/main/java/org/nl/modules/system/service/DictService.java new file mode 100644 index 0000000..9ba30f0 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/DictService.java @@ -0,0 +1,75 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service; + +import org.nl.modules.system.domain.Dict; +import org.nl.modules.system.service.dto.DictDto; +import org.nl.modules.system.service.dto.DictQueryCriteria; +import org.springframework.data.domain.Pageable; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +public interface DictService { + + /** + * 分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Map queryAll(DictQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部数据 + * @param dict / + * @return / + */ + List queryAll(DictQueryCriteria dict); + + /** + * 创建 + * @param resources / + * @return / + */ + void create(Dict resources); + + /** + * 编辑 + * @param resources / + */ + void update(Dict resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set ids); + + /** + * 导出数据 + * @param queryAll 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/GenCodeService.java b/nladmin-system/src/main/java/org/nl/modules/system/service/GenCodeService.java new file mode 100644 index 0000000..32de63b --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/GenCodeService.java @@ -0,0 +1,29 @@ +package org.nl.modules.system.service; + +import net.sf.json.JSONObject; +import org.springframework.data.domain.Pageable; + +import java.util.Map; +import java.util.Set; + +public interface GenCodeService { + /** + * 分页查询 + * + * @param form 条件 + * @param pageable 分页参数 + * @return / + */ + JSONObject queryAll(Map form, Pageable pageable); + + public void create(Map form); + + public void delete(Set ids); + + public void update(JSONObject json); + + public String codeDemo(Map form); + + public String queryIdByCode(String code); + +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/JobService.java b/nladmin-system/src/main/java/org/nl/modules/system/service/JobService.java new file mode 100644 index 0000000..0c36a27 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/JobService.java @@ -0,0 +1,88 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service; + +import org.nl.modules.system.domain.Job; +import org.nl.modules.system.service.dto.JobDto; +import org.nl.modules.system.service.dto.JobQueryCriteria; +import org.springframework.data.domain.Pageable; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** +* @author Zheng Jie +* @date 2019-03-29 +*/ +public interface JobService { + + /** + * 根据ID查询 + * @param id / + * @return / + */ + JobDto findById(Long id); + + /** + * 创建 + * @param resources / + * @return / + */ + void create(Job resources); + + /** + * 编辑 + * @param resources / + */ + void update(Job resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set ids); + + /** + * 分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Map queryAll(JobQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部数据 + * @param criteria / + * @return / + */ + List queryAll(JobQueryCriteria criteria); + + /** + * 导出数据 + * @param queryAll 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; + + /** + * 验证是否被用户关联 + * @param ids / + */ + void verification(Set ids); +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/MenuService.java b/nladmin-system/src/main/java/org/nl/modules/system/service/MenuService.java new file mode 100644 index 0000000..3753b34 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/MenuService.java @@ -0,0 +1,125 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service; + +import org.nl.modules.system.domain.Menu; +import org.nl.modules.system.service.dto.MenuDto; +import org.nl.modules.system.service.dto.MenuQueryCriteria; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2018-12-17 + */ +public interface MenuService { + + /** + * 查询全部数据 + * @param criteria 条件 + * @param isQuery / + * @throws Exception / + * @return / + */ + List queryAll(MenuQueryCriteria criteria, Boolean isQuery) throws Exception; + + /** + * 根据ID查询 + * @param id / + * @return / + */ + MenuDto findById(long id); + + /** + * 创建 + * @param resources / + */ + void create(Menu resources); + + /** + * 编辑 + * @param resources / + */ + void update(Menu resources); + + /** + * 获取所有子节点,包含自身ID + * @param menuList / + * @param menuSet / + * @return / + */ + Set getChildMenus(List menuList, Set menuSet); + + /** + * 构建菜单树 + * @param menuDtos 原始数据 + * @return / + */ + List buildTree(List menuDtos); + + /** + * 构建菜单树 + * @param menuDtos / + * @return / + */ + Object buildMenus(List menuDtos); + + /** + * 根据ID查询 + * @param id / + * @return / + */ + Menu findOne(Long id); + + /** + * 删除 + * @param menuSet / + */ + void delete(Set menuSet); + + /** + * 导出 + * @param queryAll 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; + + /** + * 懒加载菜单数据 + * @param pid / + * @return / + */ + List getMenus(Long pid); + + /** + * 根据ID获取同级与上级数据 + * @param menuDto / + * @param objects / + * @return / + */ + List getSuperior(MenuDto menuDto, List objects); + + /** + * 根据当前用户获取菜单 + * @param currentUserId / + * @return / + */ + List findByUser(Long currentUserId); +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/MonitorService.java b/nladmin-system/src/main/java/org/nl/modules/system/service/MonitorService.java new file mode 100644 index 0000000..829151a --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/MonitorService.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service; + +import java.util.Map; + +/** + * @author Zheng Jie + * @date 2020-05-02 + */ +public interface MonitorService { + + /** + * 查询数据分页 + * @return Map + */ + Map getServers(); +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/ParamService.java b/nladmin-system/src/main/java/org/nl/modules/system/service/ParamService.java new file mode 100644 index 0000000..657e3d8 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/ParamService.java @@ -0,0 +1,74 @@ + +package org.nl.modules.system.service; + +import org.nl.modules.system.service.dto.ParamDto; +import org.springframework.data.domain.Pageable; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +/** + * @description 服务接口 + * @author ldjun + * @date 2021-03-16 + **/ +public interface ParamService { + + /** + * 查询数据分页 + * @param whereJson 条件 + * @param page 分页参数 + * @return Map + */ + Map queryAll(Map whereJson, Pageable page); + + /** + * 查询所有数据不分页 + * @param whereJson 条件参数 + * @return List + */ + List queryAll(Map whereJson); + + /** + * 根据ID查询 + * @param id ID + * @return Param + */ + ParamDto findById(String id); + + /** + * 根据编码查询 + * @param code code + * @return Param + */ + ParamDto findByCode(String code); + + + /** + * 创建 + * @param dto / + */ + void create(ParamDto dto); + + /** + * 编辑 + * @param dto / + */ + void update(ParamDto dto); + + /** + * 多选删除 + * @param ids / + */ + void deleteAll(String[] ids); + + /** + * 导出数据 + * @param dtos 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List dtos, HttpServletResponse response) throws IOException; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/RoleService.java b/nladmin-system/src/main/java/org/nl/modules/system/service/RoleService.java new file mode 100644 index 0000000..8cc5bba --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/RoleService.java @@ -0,0 +1,136 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service; + +import org.nl.modules.system.domain.Role; +import org.nl.modules.system.service.dto.RoleDto; +import org.nl.modules.system.service.dto.RoleQueryCriteria; +import org.nl.modules.system.service.dto.RoleSmallDto; +import org.nl.modules.system.service.dto.UserDto; +import org.springframework.data.domain.Pageable; +import org.springframework.security.core.GrantedAuthority; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2018-12-03 + */ +public interface RoleService { + + /** + * 查询全部数据 + * @return / + */ + List queryAll(); + + /** + * 根据ID查询 + * @param id / + * @return / + */ + RoleDto findById(long id); + + /** + * 创建 + * @param resources / + */ + void create(Role resources); + + /** + * 编辑 + * @param resources / + */ + void update(Role resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set ids); + + /** + * 根据用户ID查询 + * @param id 用户ID + * @return / + */ + List findByUsersId(Long id); + + /** + * 根据角色查询角色级别 + * @param roles / + * @return / + */ + Integer findByRoles(Set roles); + + /** + * 修改绑定的菜单 + * @param resources / + * @param roleDTO / + */ + void updateMenu(Role resources, RoleDto roleDTO); + + /** + * 解绑菜单 + * @param id / + */ + void untiedMenu(Long id); + + /** + * 待条件分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Object queryAll(RoleQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部 + * @param criteria 条件 + * @return / + */ + List queryAll(RoleQueryCriteria criteria); + + /** + * 导出数据 + * @param queryAll 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; + + /** + * 获取用户权限信息 + * @param user 用户信息 + * @return 权限信息 + */ + List mapToGrantedAuthorities(UserDto user); + + /** + * 验证是否被用户关联 + * @param ids / + */ + void verification(Set ids); + + /** + * 根据菜单Id查询 + * @param menuIds / + * @return / + */ + List findInMenuId(List menuIds); +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/UserService.java b/nladmin-system/src/main/java/org/nl/modules/system/service/UserService.java new file mode 100644 index 0000000..f5e2762 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/UserService.java @@ -0,0 +1,116 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service; + +import org.nl.modules.system.domain.User; +import org.nl.modules.system.service.dto.UserDto; +import org.nl.modules.system.service.dto.UserQueryCriteria; +import org.springframework.data.domain.Pageable; +import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +public interface UserService { + + /** + * 根据ID查询 + * @param id ID + * @return / + */ + UserDto findById(long id); + + /** + * 新增用户 + * @param resources / + */ + void create(User resources); + + /** + * 编辑用户 + * @param resources / + */ + void update(User resources) throws Exception; + + /** + * 删除用户 + * @param ids / + */ + void delete(Set ids); + + /** + * 根据用户名查询 + * @param userName / + * @return / + */ + UserDto findByName(String userName); + + /** + * 修改密码 + * @param username 用户名 + * @param encryptPassword 密码 + */ + void updatePass(String username, String encryptPassword); + + /** + * 修改头像 + * @param file 文件 + * @return / + */ + Map updateAvatar(MultipartFile file); + + /** + * 修改邮箱 + * @param username 用户名 + * @param email 邮箱 + */ + void updateEmail(String username, String email); + + /** + * 查询全部 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Object queryAll(UserQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部不分页 + * @param criteria 条件 + * @return / + */ + List queryAll(UserQueryCriteria criteria); + + /** + * 导出数据 + * @param queryAll 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; + + /** + * 用户自助修改资料 + * @param resources / + */ + void updateCenter(User resources); +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/VerifyService.java b/nladmin-system/src/main/java/org/nl/modules/system/service/VerifyService.java new file mode 100644 index 0000000..40e48db --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/VerifyService.java @@ -0,0 +1,41 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service; + +import org.nl.domain.vo.EmailVo; + +/** + * @author Zheng Jie + * @date 2018-12-26 + */ +public interface VerifyService { + + /** + * 发送验证码 + * @param email / + * @param key / + * @return / + */ + EmailVo sendEmail(String email, String key); + + + /** + * 验证 + * @param code / + * @param key / + */ + void validated(String key, String code); +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DeptDto.java b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DeptDto.java new file mode 100644 index 0000000..32a1e92 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DeptDto.java @@ -0,0 +1,78 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Getter; +import lombok.Setter; +import org.nl.base.BaseDTO; +import java.io.Serializable; +import java.util.List; +import java.util.Objects; + +/** +* @author Zheng Jie +* @date 2019-03-25 +*/ +@Getter +@Setter +public class DeptDto extends BaseDTO implements Serializable { + + private Long id; + + private String name; + + private Boolean enabled; + + private Integer deptSort; + + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private List children; + + private Long pid; + + private Integer subCount; + + public Boolean getHasChildren() { + return subCount > 0; + } + + public Boolean getLeaf() { + return subCount <= 0; + } + + public String getLabel() { + return name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DeptDto deptDto = (DeptDto) o; + return Objects.equals(id, deptDto.id) && + Objects.equals(name, deptDto.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DeptQueryCriteria.java b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DeptQueryCriteria.java new file mode 100644 index 0000000..5d862aa --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DeptQueryCriteria.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.dto; + +import lombok.Data; +import org.nl.annotation.DataPermission; +import org.nl.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** +* @author Zheng Jie +* @date 2019-03-25 +*/ +@Data +@DataPermission(fieldName = "id") +public class DeptQueryCriteria{ + + @Query(type = Query.Type.INNER_LIKE) + private String name; + + @Query + private Boolean enabled; + + @Query + private Long pid; + + @Query(type = Query.Type.IS_NULL, propName = "pid") + private Boolean pidIsNull; + + @Query(type = Query.Type.BETWEEN) + private List createTime; +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DeptSmallDto.java b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DeptSmallDto.java new file mode 100644 index 0000000..8e0d033 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DeptSmallDto.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.dto; + +import lombok.Data; +import java.io.Serializable; + +/** +* @author Zheng Jie +* @date 2019-6-10 16:32:18 +*/ +@Data +public class DeptSmallDto implements Serializable { + + private Long id; + + private String name; +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DictDetailDto.java b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DictDetailDto.java new file mode 100644 index 0000000..aec4380 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DictDetailDto.java @@ -0,0 +1,40 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.dto; + +import lombok.Getter; +import lombok.Setter; +import org.nl.base.BaseDTO; +import java.io.Serializable; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@Getter +@Setter +public class DictDetailDto extends BaseDTO implements Serializable { + + private Long id; + + private DictSmallDto dict; + + private String label; + + private String value; + + private Integer dictSort; +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DictDetailQueryCriteria.java b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DictDetailQueryCriteria.java new file mode 100644 index 0000000..b540afb --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DictDetailQueryCriteria.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.dto; + +import lombok.Data; +import org.nl.annotation.Query; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@Data +public class DictDetailQueryCriteria { + + @Query(type = Query.Type.INNER_LIKE) + private String label; + + @Query(propName = "name",joinName = "dict") + private String dictName; +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DictDto.java b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DictDto.java new file mode 100644 index 0000000..9dcd068 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DictDto.java @@ -0,0 +1,39 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.dto; + +import lombok.Getter; +import lombok.Setter; +import org.nl.base.BaseDTO; +import java.io.Serializable; +import java.util.List; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@Getter +@Setter +public class DictDto extends BaseDTO implements Serializable { + + private Long id; + + private List dictDetails; + + private String name; + + private String description; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DictQueryCriteria.java b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DictQueryCriteria.java new file mode 100644 index 0000000..4e28c32 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DictQueryCriteria.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.dto; + +import lombok.Data; +import org.nl.annotation.Query; + +/** + * @author Zheng Jie + * 公共查询类 + */ +@Data +public class DictQueryCriteria { + + @Query(blurry = "name,description") + private String blurry; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DictSmallDto.java b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DictSmallDto.java new file mode 100644 index 0000000..e737bf6 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/DictSmallDto.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.dto; + +import lombok.Getter; +import lombok.Setter; +import java.io.Serializable; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@Getter +@Setter +public class DictSmallDto implements Serializable { + + private Long id; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/dto/JobDto.java b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/JobDto.java new file mode 100644 index 0000000..9a86a94 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/JobDto.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.dto; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.nl.base.BaseDTO; + +import java.io.Serializable; + +/** +* @author Zheng Jie +* @date 2019-03-29 +*/ +@Getter +@Setter +@NoArgsConstructor +public class JobDto extends BaseDTO implements Serializable { + + private Long id; + + private Integer jobSort; + + private String name; + + private Boolean enabled; + + public JobDto(String name, Boolean enabled) { + this.name = name; + this.enabled = enabled; + } +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/dto/JobQueryCriteria.java b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/JobQueryCriteria.java new file mode 100644 index 0000000..42f8b01 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/JobQueryCriteria.java @@ -0,0 +1,40 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.nl.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** +* @author Zheng Jie +* @date 2019-6-4 14:49:34 +*/ +@Data +@NoArgsConstructor +public class JobQueryCriteria { + + @Query(type = Query.Type.INNER_LIKE) + private String name; + + @Query + private Boolean enabled; + + @Query(type = Query.Type.BETWEEN) + private List createTime; +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/dto/JobSmallDto.java b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/JobSmallDto.java new file mode 100644 index 0000000..2cb21df --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/JobSmallDto.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; +import java.io.Serializable; + +/** +* @author Zheng Jie +* @date 2019-6-10 16:32:18 +*/ +@Data +@NoArgsConstructor +public class JobSmallDto implements Serializable { + + private Long id; + + private String name; +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/dto/MenuDto.java b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/MenuDto.java new file mode 100644 index 0000000..4de713b --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/MenuDto.java @@ -0,0 +1,91 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.dto; + +import lombok.Getter; +import lombok.Setter; +import org.nl.base.BaseDTO; +import java.io.Serializable; +import java.util.List; +import java.util.Objects; + +/** + * @author Zheng Jie + * @date 2018-12-17 + */ +@Getter +@Setter +public class MenuDto extends BaseDTO implements Serializable { + + private Long id; + + private List children; + + private Integer type; + + private String permission; + + private String title; + + private Integer menuSort; + + private String path; + + private String component; + + private Long pid; + + private Integer subCount; + + private Boolean iFrame; + + private Boolean cache; + + private Boolean hidden; + + private String componentName; + + private String icon; + + public Boolean getHasChildren() { + return subCount > 0; + } + + public Boolean getLeaf() { + return subCount <= 0; + } + + public String getLabel() { + return title; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MenuDto menuDto = (MenuDto) o; + return Objects.equals(id, menuDto.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/dto/MenuQueryCriteria.java b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/MenuQueryCriteria.java new file mode 100644 index 0000000..30aefee --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/MenuQueryCriteria.java @@ -0,0 +1,41 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.dto; + +import lombok.Data; +import org.nl.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** + * @author Zheng Jie + * 公共查询类 + */ +@Data +public class MenuQueryCriteria { + + @Query(blurry = "title,component,permission") + private String blurry; + + @Query(type = Query.Type.BETWEEN) + private List createTime; + + @Query(type = Query.Type.IS_NULL, propName = "pid") + private Boolean pidIsNull; + + @Query + private Long pid; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/dto/ParamDto.java b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/ParamDto.java new file mode 100644 index 0000000..9ac580e --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/ParamDto.java @@ -0,0 +1,35 @@ +package org.nl.modules.system.service.dto; + +import lombok.Data; +import java.io.Serializable; + +/** + * @description / + * @author ldjun + * @date 2021-01-14 + **/ +@Data +public class ParamDto implements Serializable { + + private String id; + + private String code; + + private String name; + + private String value; + + private String remark; + + private String is_active; + + private String is_delete; + + private String create_by; + + private String create_time; + + private String update_by; + + private String update_time; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/dto/RoleDto.java b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/RoleDto.java new file mode 100644 index 0000000..a304975 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/RoleDto.java @@ -0,0 +1,63 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.dto; + +import lombok.Getter; +import lombok.Setter; +import org.nl.base.BaseDTO; +import java.io.Serializable; +import java.util.Objects; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +@Getter +@Setter +public class RoleDto extends BaseDTO implements Serializable { + + private Long id; + + private Set menus; + + private Set depts; + + private String name; + + private String dataScope; + + private Integer level; + + private String description; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RoleDto roleDto = (RoleDto) o; + return Objects.equals(id, roleDto.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/dto/RoleQueryCriteria.java b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/RoleQueryCriteria.java new file mode 100644 index 0000000..bf41ff1 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/RoleQueryCriteria.java @@ -0,0 +1,36 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.dto; + +import lombok.Data; +import org.nl.annotation.Query; + +import java.sql.Timestamp; +import java.util.List; + +/** + * @author Zheng Jie + * 公共查询类 + */ +@Data +public class RoleQueryCriteria { + + @Query(blurry = "name,description") + private String blurry; + + @Query(type = Query.Type.BETWEEN) + private List createTime; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/dto/RoleSmallDto.java b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/RoleSmallDto.java new file mode 100644 index 0000000..eac81ca --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/RoleSmallDto.java @@ -0,0 +1,35 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.dto; + +import lombok.Data; +import java.io.Serializable; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +@Data +public class RoleSmallDto implements Serializable { + + private Long id; + + private String name; + + private Integer level; + + private String dataScope; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/dto/UserDto.java b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/UserDto.java new file mode 100644 index 0000000..93c5a5b --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/UserDto.java @@ -0,0 +1,67 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.dto; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Getter; +import lombok.Setter; +import org.nl.base.BaseDTO; +import java.io.Serializable; +import java.util.Date; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +@Getter +@Setter +public class UserDto extends BaseDTO implements Serializable { + + private Long id; + + private Set roles; + + private Set jobs; + + private DeptSmallDto dept; + + private Long deptId; + + private String username; + + private String nickName; + + private String email; + + private String phone; + + private String gender; + + private String avatarName; + + private String avatarPath; + + @JsonIgnore + private String password; + + private Boolean enabled; + + @JsonIgnore + private Boolean isAdmin = false; + + private Date pwdResetTime; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/dto/UserQueryCriteria.java b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/UserQueryCriteria.java new file mode 100644 index 0000000..2086cf2 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/dto/UserQueryCriteria.java @@ -0,0 +1,49 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.dto; + +import lombok.Data; +import org.nl.annotation.Query; +import java.io.Serializable; +import java.sql.Timestamp; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +@Data +public class UserQueryCriteria implements Serializable { + + @Query + private Long id; + + @Query(propName = "id", type = Query.Type.IN, joinName = "dept") + private Set deptIds = new HashSet<>(); + + @Query(blurry = "email,username,nickName") + private String blurry; + + @Query + private Boolean enabled; + + private Long deptId; + + @Query(type = Query.Type.BETWEEN) + private List createTime; +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/impl/CodeDetailServiceImpl.java b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/CodeDetailServiceImpl.java new file mode 100644 index 0000000..fb3310c --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/CodeDetailServiceImpl.java @@ -0,0 +1,75 @@ +package org.nl.modules.system.service.impl; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.IdUtil; +import lombok.RequiredArgsConstructor; +import net.sf.json.JSONObject; +import org.nl.modules.system.service.CodeDetailService; +import org.nl.utils.SecurityUtils; +import org.nl.wql.core.bean.ResultBean; +import org.nl.wql.core.bean.WQLObject; +import org.nl.wql.util.WqlUtil; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.Map; + +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "codeDetail") +public class CodeDetailServiceImpl implements CodeDetailService { + @Override + public JSONObject queryAll(Map form, Pageable pageable) { + String where = "code_rule_id = '"+form.get("id")+"'"; + ResultBean rb = WQLObject.getWQLObject("sys_code_rule_detail").pagequery(WqlUtil.getHttpContext(pageable), where, "sort_num desc "); + final JSONObject json = rb.pageResult(); + return json; + } + + @Override + public void create(Map form) { + JSONObject json = new JSONObject(); + String id = IdUtil.simpleUUID(); + String now = DateUtil.now(); + json.put("id",id); + json.put("type",form.get("type")); + json.put("init_value",form.get("init_value")); + json.put("current_value",form.get("init_value")); + json.put("max_value",form.get("max_value")); + json.put("step",form.get("step")); + json.put("fillchar",form.get("fillchar")); + json.put("format",form.get("format")); + json.put("length",form.get("length")); + json.put("sort_num",form.get("sort_num")+""); + json.put("remark",form.get("remark")); + Map dict = (Map) form.get("dict"); + json.put("code_rule_id",dict.get("id")); + json.put("is_active","1"); + json.put("is_delete","0"); + json.put("create_by",SecurityUtils.getCurrentUsername()); + json.put("create_time", now); + if(form.get("type").equals("02")){ + Date date = DateUtil.date(); + String format = (String) form.get("format"); + String now_date = DateUtil.format(date, format); + json.put("init_value",now_date); + json.put("current_value",now_date); + } + WQLObject.getWQLObject("sys_code_rule_detail").insert(json); + } + + @Override + public void delete(String id) { + WQLObject.getWQLObject("sys_code_rule_detail").delete("id = '"+id+"'"); + } + + @Override + public void update(JSONObject json) { + String now = DateUtil.now(); + json.put("update_time",now); + json.put("update_by", SecurityUtils.getCurrentUsername()); + WQLObject.getWQLObject("sys_code_rule_detail").update(json); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/impl/DataServiceImpl.java b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/DataServiceImpl.java new file mode 100644 index 0000000..dbe1f01 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/DataServiceImpl.java @@ -0,0 +1,91 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.impl; + +import lombok.RequiredArgsConstructor; +import org.nl.modules.system.domain.Dept; +import org.nl.modules.system.service.DataService; +import org.nl.modules.system.service.DeptService; +import org.nl.modules.system.service.RoleService; +import org.nl.modules.system.service.dto.RoleSmallDto; +import org.nl.modules.system.service.dto.UserDto; +import org.nl.utils.enums.DataScopeEnum; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import java.util.*; + +/** + * @author Zheng Jie + * @website https://el-admin.vip + * @description 数据权限服务实现 + * @date 2020-05-07 + **/ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "data") +public class DataServiceImpl implements DataService { + + private final RoleService roleService; + private final DeptService deptService; + + /** + * 用户角色改变时需清理缓存 + * @param user / + * @return / + */ + @Override + @Cacheable(key = "'user:' + #p0.id") + public List getDeptIds(UserDto user) { + // 用于存储部门id + Set deptIds = new HashSet<>(); + // 查询用户角色 + List roleSet = roleService.findByUsersId(user.getId()); + // 获取对应的部门ID + for (RoleSmallDto role : roleSet) { + DataScopeEnum dataScopeEnum = DataScopeEnum.find(role.getDataScope()); + switch (Objects.requireNonNull(dataScopeEnum)) { + case THIS_LEVEL: + deptIds.add(user.getDept().getId()); + break; + case CUSTOMIZE: + deptIds.addAll(getCustomize(deptIds, role)); + break; + default: + return new ArrayList<>(deptIds); + } + } + return new ArrayList<>(deptIds); + } + + /** + * 获取自定义的数据权限 + * @param deptIds 部门ID + * @param role 角色 + * @return 数据权限ID + */ + public Set getCustomize(Set deptIds, RoleSmallDto role){ + Set depts = deptService.findByRoleId(role.getId()); + for (Dept dept : depts) { + deptIds.add(dept.getId()); + List deptChildren = deptService.findByPid(dept.getId()); + if (deptChildren != null && deptChildren.size() != 0) { + deptIds.addAll(deptService.getDeptChildren(deptChildren)); + } + } + return deptIds; + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/impl/DeptServiceImpl.java b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/DeptServiceImpl.java new file mode 100644 index 0000000..154b9a1 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/DeptServiceImpl.java @@ -0,0 +1,283 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; + +import org.nl.exception.BadRequestException; +import org.nl.modules.system.domain.Dept; +import org.nl.modules.system.domain.User; +import org.nl.modules.system.repository.DeptRepository; +import org.nl.modules.system.repository.RoleRepository; +import org.nl.modules.system.repository.UserRepository; +import org.nl.modules.system.service.DeptService; +import org.nl.modules.system.service.dto.DeptDto; +import org.nl.modules.system.service.dto.DeptQueryCriteria; +import org.nl.modules.system.service.mapstruct.DeptMapper; +import org.nl.utils.*; +import org.nl.utils.enums.DataScopeEnum; +import org.nl.wql.core.bean.WQLObject; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author Zheng Jie + * @date 2019-03-25 + */ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "dept") +public class DeptServiceImpl implements DeptService { + + private final DeptRepository deptRepository; + private final DeptMapper deptMapper; + private final UserRepository userRepository; + private final RedisUtils redisUtils; + private final RoleRepository roleRepository; + + @Override + public List queryAll(DeptQueryCriteria criteria, Boolean isQuery) throws Exception { + Sort sort = Sort.by(Sort.Direction.ASC, "deptSort"); + String dataScopeType = SecurityUtils.getDataScopeType(); + if (isQuery) { + if(dataScopeType.equals(DataScopeEnum.ALL.getValue())){ + criteria.setPidIsNull(true); + } + List fields = QueryHelp.getAllFields(criteria.getClass(), new ArrayList<>()); + List fieldNames = new ArrayList(){{ add("pidIsNull");add("enabled");}}; + for (Field field : fields) { + //设置对象的访问权限,保证对private的属性的访问 + field.setAccessible(true); + Object val = field.get(criteria); + if(fieldNames.contains(field.getName())){ + continue; + } + if (ObjectUtil.isNotNull(val)) { + criteria.setPidIsNull(null); + break; + } + } + } + List list = deptMapper.toDto(deptRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),sort)); + // 如果为空,就代表为自定义权限或者本级权限,就需要去重,不理解可以注释掉,看查询结果 + if(StringUtils.isBlank(dataScopeType)){ + return deduplication(list); + } + return list; + } + + @Override + @Cacheable(key = "'id:' + #p0") + public DeptDto findById(Long id) { + Dept dept = deptRepository.findById(id).orElseGet(Dept::new); + ValidationUtil.isNull(dept.getId(),"Dept","id",id); + return deptMapper.toDto(dept); + } + + @Override + public List findByPid(long pid) { + return deptRepository.findByPid(pid); + } + + @Override + public Set findByRoleId(Long id) { + return deptRepository.findByRoleId(id); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(Dept resources) { + deptRepository.save(resources); + // 计算子节点数目 + resources.setSubCount(0); + // 清理缓存 + updateSubCnt(resources.getPid()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(Dept resources) { + // 旧的部门 + Long oldPid = findById(resources.getId()).getPid(); + Long newPid = resources.getPid(); + if(resources.getPid() != null && resources.getId().equals(resources.getPid())) { + throw new BadRequestException("上级不能为自己"); + } + Dept dept = deptRepository.findById(resources.getId()).orElseGet(Dept::new); + ValidationUtil.isNull( dept.getId(),"Dept","id",resources.getId()); + resources.setId(dept.getId()); + deptRepository.save(resources); + // 更新父节点中子节点数目 + updateSubCnt(oldPid); + updateSubCnt(newPid); + // 清理缓存 + delCaches(resources.getId()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set deptDtos) { + for (DeptDto deptDto : deptDtos) { + // 清理缓存 + delCaches(deptDto.getId()); + deptRepository.deleteById(deptDto.getId()); + updateSubCnt(deptDto.getPid()); + } + } + + @Override + public void download(List deptDtos, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (DeptDto deptDTO : deptDtos) { + Map map = new LinkedHashMap<>(); + map.put("部门名称", deptDTO.getName()); + map.put("部门状态", deptDTO.getEnabled() ? "启用" : "停用"); + map.put("创建日期", deptDTO.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } + + @Override + public Set getDeleteDepts(List menuList, Set deptDtos) { + for (Dept dept : menuList) { + deptDtos.add(deptMapper.toDto(dept)); + List depts = deptRepository.findByPid(dept.getId()); + if(depts!=null && depts.size()!=0){ + getDeleteDepts(depts, deptDtos); + } + } + return deptDtos; + } + + @Override + public List getSuperior(DeptDto deptDto, List depts) { + if(deptDto.getPid() == null){ + depts.addAll(deptRepository.findByPidIsNull()); + return deptMapper.toDto(depts); + } + depts.addAll(deptRepository.findByPid(deptDto.getPid())); + return getSuperior(findById(deptDto.getPid()), depts); + } + + @Override + public Object buildTree(List deptDtos) { + Set trees = new LinkedHashSet<>(); + Set depts= new LinkedHashSet<>(); + List deptNames = deptDtos.stream().map(DeptDto::getName).collect(Collectors.toList()); + boolean isChild; + for (DeptDto deptDTO : deptDtos) { + isChild = false; + if (deptDTO.getPid() == null) { + trees.add(deptDTO); + } + for (DeptDto it : deptDtos) { + if (it.getPid() != null && deptDTO.getId().equals(it.getPid())) { + isChild = true; + if (deptDTO.getChildren() == null) { + deptDTO.setChildren(new ArrayList<>()); + } + deptDTO.getChildren().add(it); + } + } + if(isChild) { + depts.add(deptDTO); + } else if(deptDTO.getPid() != null && !deptNames.contains(findById(deptDTO.getPid()).getName())) { + depts.add(deptDTO); + } + } + + if (CollectionUtil.isEmpty(trees)) { + trees = depts; + } + Map map = new HashMap<>(2); + map.put("totalElements",deptDtos.size()); + map.put("content",CollectionUtil.isEmpty(trees)? deptDtos :trees); + return map; + } + + @Override + public void verification(Set deptDtos) { + Set deptIds = deptDtos.stream().map(DeptDto::getId).collect(Collectors.toSet()); + if(userRepository.countByDepts(deptIds) > 0){ + throw new BadRequestException("所选部门存在用户关联,请解除后再试!"); + } + if(roleRepository.countByDepts(deptIds) > 0){ + throw new BadRequestException("所选部门存在角色关联,请解除后再试!"); + } + } + + private void updateSubCnt(Long deptId){ + if(deptId != null){ + int count = deptRepository.countByPid(deptId); + deptRepository.updateSubCntById(count, deptId); + } + } + + private List deduplication(List list) { + List deptDtos = new ArrayList<>(); + for (DeptDto deptDto : list) { + boolean flag = true; + for (DeptDto dto : list) { + if (dto.getId().equals(deptDto.getPid())) { + flag = false; + break; + } + } + if (flag){ + deptDtos.add(deptDto); + } + } + return deptDtos; + } + + /** + * 清理缓存 + * @param id / + */ + public void delCaches(Long id){ + List users = userRepository.findByRoleDeptId(id); + // 删除数据权限 + redisUtils.delByKeys(CacheKey.DATA_USER, users.stream().map(User::getId).collect(Collectors.toSet())); + redisUtils.del(CacheKey.DEPT_ID + id); + } + + @Override + public List getDeptChildren(List deptList) { + List list = new ArrayList<>(); + deptList.forEach(dept -> { + if (dept!=null && dept.getEnabled()) { + List depts = deptRepository.findByPid(dept.getId()); + if (deptList.size() != 0) { + list.addAll(getDeptChildren(depts)); + } + list.add(dept.getId()); + } + } + ); + return list; + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/impl/DictDetailServiceImpl.java b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/DictDetailServiceImpl.java new file mode 100644 index 0000000..21833ed --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/DictDetailServiceImpl.java @@ -0,0 +1,98 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.impl; + +import lombok.RequiredArgsConstructor; +import org.nl.modules.system.domain.Dict; +import org.nl.modules.system.domain.DictDetail; +import org.nl.modules.system.repository.DictRepository; +import org.nl.modules.system.service.dto.DictDetailQueryCriteria; +import org.nl.utils.PageUtil; +import org.nl.utils.QueryHelp; +import org.nl.utils.RedisUtils; +import org.nl.utils.ValidationUtil; +import org.nl.modules.system.repository.DictDetailRepository; +import org.nl.modules.system.service.DictDetailService; +import org.nl.modules.system.service.dto.DictDetailDto; +import org.nl.modules.system.service.mapstruct.DictDetailMapper; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import java.util.List; +import java.util.Map; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "dict") +public class DictDetailServiceImpl implements DictDetailService { + + private final DictRepository dictRepository; + private final DictDetailRepository dictDetailRepository; + private final DictDetailMapper dictDetailMapper; + private final RedisUtils redisUtils; + + @Override + public Map queryAll(DictDetailQueryCriteria criteria, Pageable pageable) { + Page page = dictDetailRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable); + return PageUtil.toPage(page.map(dictDetailMapper::toDto)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(DictDetail resources) { + dictDetailRepository.save(resources); + // 清理缓存 + delCaches(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(DictDetail resources) { + DictDetail dictDetail = dictDetailRepository.findById(resources.getId()).orElseGet(DictDetail::new); + ValidationUtil.isNull( dictDetail.getId(),"DictDetail","id",resources.getId()); + resources.setId(dictDetail.getId()); + dictDetailRepository.save(resources); + // 清理缓存 + delCaches(resources); + } + + @Override + @Cacheable(key = "'name:' + #p0") + public List getDictByName(String name) { + return dictDetailMapper.toDto(dictDetailRepository.findByDictName(name)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Long id) { + DictDetail dictDetail = dictDetailRepository.findById(id).orElseGet(DictDetail::new); + // 清理缓存 + delCaches(dictDetail); + dictDetailRepository.deleteById(id); + } + + public void delCaches(DictDetail dictDetail){ + Dict dict = dictRepository.findById(dictDetail.getDict().getId()).orElseGet(Dict::new); + redisUtils.del("dict::name:" + dict.getName()); + } +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/impl/DictServiceImpl.java b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/DictServiceImpl.java new file mode 100644 index 0000000..903f029 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/DictServiceImpl.java @@ -0,0 +1,122 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import lombok.RequiredArgsConstructor; +import org.nl.modules.system.domain.Dict; +import org.nl.modules.system.repository.DictRepository; +import org.nl.modules.system.service.DictService; +import org.nl.modules.system.service.dto.DictDetailDto; +import org.nl.modules.system.service.dto.DictDto; +import org.nl.modules.system.service.dto.DictQueryCriteria; +import org.nl.modules.system.service.mapstruct.DictMapper; +import org.nl.utils.*; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "dict") +public class DictServiceImpl implements DictService { + + private final DictRepository dictRepository; + private final DictMapper dictMapper; + private final RedisUtils redisUtils; + + @Override + public Map queryAll(DictQueryCriteria dict, Pageable pageable){ + Page page = dictRepository.findAll((root, query, cb) -> QueryHelp.getPredicate(root, dict, cb), pageable); + return PageUtil.toPage(page.map(dictMapper::toDto)); + } + + @Override + public List queryAll(DictQueryCriteria dict) { + List list = dictRepository.findAll((root, query, cb) -> QueryHelp.getPredicate(root, dict, cb)); + return dictMapper.toDto(list); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(Dict resources) { + dictRepository.save(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(Dict resources) { + // 清理缓存 + delCaches(resources); + Dict dict = dictRepository.findById(resources.getId()).orElseGet(Dict::new); + ValidationUtil.isNull( dict.getId(),"Dict","id",resources.getId()); + dict.setName(resources.getName()); + dict.setDescription(resources.getDescription()); + dictRepository.save(dict); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set ids) { + // 清理缓存 + List dicts = dictRepository.findByIdIn(ids); + for (Dict dict : dicts) { + delCaches(dict); + } + dictRepository.deleteByIdIn(ids); + } + + @Override + public void download(List dictDtos, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (DictDto dictDTO : dictDtos) { + if(CollectionUtil.isNotEmpty(dictDTO.getDictDetails())){ + for (DictDetailDto dictDetail : dictDTO.getDictDetails()) { + Map map = new LinkedHashMap<>(); + map.put("字典名称", dictDTO.getName()); + map.put("字典描述", dictDTO.getDescription()); + map.put("字典标签", dictDetail.getLabel()); + map.put("字典值", dictDetail.getValue()); + map.put("创建日期", dictDetail.getCreateTime()); + list.add(map); + } + } else { + Map map = new LinkedHashMap<>(); + map.put("字典名称", dictDTO.getName()); + map.put("字典描述", dictDTO.getDescription()); + map.put("字典标签", null); + map.put("字典值", null); + map.put("创建日期", dictDTO.getCreateTime()); + list.add(map); + } + } + FileUtil.downloadExcel(list, response); + } + + public void delCaches(Dict dict){ + redisUtils.del("dict::name:" + dict.getName()); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/impl/GenCodeServiceImpl.java b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/GenCodeServiceImpl.java new file mode 100644 index 0000000..a194bf2 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/GenCodeServiceImpl.java @@ -0,0 +1,164 @@ +package org.nl.modules.system.service.impl; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import lombok.RequiredArgsConstructor; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; +import org.nl.exception.BadRequestException; +import org.nl.modules.system.service.GenCodeService; +import org.nl.utils.SecurityUtils; +import org.nl.wql.core.bean.ResultBean; +import org.nl.wql.core.bean.WQLObject; +import org.nl.wql.util.WqlUtil; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "genCode") +public class GenCodeServiceImpl implements GenCodeService { + @Override + public JSONObject queryAll(Map form, Pageable pageable) { + String where = "1=1"; + if (form.get("blurry") != null) { + where = "code like '%" + (String) form.get("blurry") + "%' OR name = '%" + form.get("blurry") + "%'"; + } + ResultBean rb = WQLObject.getWQLObject("SYS_CODE_RULE").pagequery(WqlUtil.getHttpContext(pageable), where, "code desc "); + final JSONObject json = rb.pageResult(); + JSONArray ja = json.getJSONArray("content"); + JSONArray new_ja = new JSONArray(); + for (int i = 0; i < ja.size(); i++) { + JSONObject jo = ja.getJSONObject(i); + HashMap map = new HashMap(); + map.put("code", jo.getString("code")); + map.put("flag", "0"); + String demo = this.codeDemo(map); + jo.put("demo", demo); + new_ja.add(jo); + } + json.put("content", new_ja); + return json; + } + + @Override + public void create(Map form) { + JSONObject json = new JSONObject(); + String id = IdUtil.simpleUUID(); + String now = DateUtil.now(); + json.put("id", id); + json.put("code", form.get("code")); + json.put("name", form.get("name")); + json.put("is_active", "1"); + json.put("is_delete", "0"); + json.put("create_by", SecurityUtils.getCurrentUsername()); + json.put("create_time", now); + WQLObject.getWQLObject("SYS_CODE_RULE").insert(json); + } + + @Override + public void delete(Set ids) { + for (String code : ids) { + WQLObject.getWQLObject("SYS_CODE_RULE").delete("id = '" + code + "'"); + WQLObject.getWQLObject("SYS_CODE_RULE_DETAIL").delete("code_rule_id = '" + code + "'"); + } + } + + @Override + public void update(JSONObject json) { + String now = DateUtil.now(); + json.put("update_time", now); + json.put("update_by", SecurityUtils.getCurrentUsername()); + WQLObject.getWQLObject("SYS_CODE_RULE").update(json); + } + + @Override + public String codeDemo(Map form) { + String code = (String) form.get("code"); + String id = this.queryIdByCode(code); + //如果flag=1就执行更新数据库的操作 + String flag = (String) form.get("flag"); + WQLObject wo = WQLObject.getWQLObject("SYS_CODE_RULE_DETAIL"); + JSONArray ja = wo.query("code_rule_id = '" + id + "' order by sort_num,type").getResultJSONArray(0); + String demo = ""; + boolean is_same = true; + for (int i = 0; i < ja.size(); i++) { + String value = ""; + JSONObject jo = ja.getJSONObject(i); + //固定直接取值 + if (jo.optString("type").equals("01")) { + value = jo.optString("init_value"); + } + //日期判断数据库的值与当前值是否相同来决定顺序的值 + if (jo.optString("type").equals("02")) { + String current_value = jo.optString("current_value"); + Date date = DateUtil.date(); + String format = jo.optString("format"); + String now_date = DateUtil.format(date, format); + if (!now_date.equals(current_value)) { + is_same = false; + } + if (flag.equals("1")) { + jo.put("init_value", now_date); + jo.put("current_value", now_date); + } + value = now_date; + } + //顺序的值:如果日期一样就+步长,等于最大值就归为初始值;日期不一样就归为初始值 + if (jo.optString("type").equals("03")) { + String num_value = ""; + int step = jo.optInt("step"); + int max_value = jo.optInt("max_value"); + if (!is_same || (jo.optInt("current_value") + step > max_value)) { + num_value = jo.optString("init_value"); + } else { + num_value = (jo.optInt("current_value") + step) + ""; + } + int size = num_value.length(); + int length = jo.optInt("length"); + String fillchar = jo.optString("fillchar"); + for (int m = 0; m < (length - size); m++) { + value += fillchar; + } + value += num_value; + if (flag.equals("1")) { + if (!is_same) { + int init_value = jo.optInt("init_value"); + if (StrUtil.isEmpty((init_value + ""))) { + throw new BadRequestException("请完善编码数值的初始值!"); + } + jo.put("current_value", init_value + ""); + } else { + int num_curr = jo.optInt("current_value"); + if (num_curr >= max_value) { + num_curr = jo.optInt("init_value"); + jo.put("current_value", num_curr + ""); + }else{ + jo.put("current_value", (num_curr + step) + ""); + } + } + } + } + demo += value; + if (flag.equals("1")) { + wo.update(jo); + } + } + return demo; + } + + @Override + public String queryIdByCode(String code) { + JSONObject jo = WQLObject.getWQLObject("SYS_CODE_RULE").query("code = '" + code + "'").uniqueResult(0); + String id = jo.optString("id"); + return id; + } + +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/impl/JobServiceImpl.java b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/JobServiceImpl.java new file mode 100644 index 0000000..fcab2cb --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/JobServiceImpl.java @@ -0,0 +1,126 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.impl; + +import lombok.RequiredArgsConstructor; +import org.nl.exception.BadRequestException; +import org.nl.exception.EntityExistException; +import org.nl.modules.system.domain.Job; +import org.nl.modules.system.repository.UserRepository; +import org.nl.modules.system.service.dto.JobQueryCriteria; + +import org.nl.modules.system.repository.JobRepository; +import org.nl.modules.system.service.JobService; +import org.nl.modules.system.service.dto.JobDto; +import org.nl.modules.system.service.mapstruct.JobMapper; +import org.nl.utils.*; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + +/** +* @author Zheng Jie +* @date 2019-03-29 +*/ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "job") +public class JobServiceImpl implements JobService { + + private final JobRepository jobRepository; + private final JobMapper jobMapper; + private final RedisUtils redisUtils; + private final UserRepository userRepository; + + @Override + public Map queryAll(JobQueryCriteria criteria, Pageable pageable) { + Page page = jobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable); + return PageUtil.toPage(page.map(jobMapper::toDto).getContent(),page.getTotalElements()); + } + + @Override + public List queryAll(JobQueryCriteria criteria) { + List list = jobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)); + return jobMapper.toDto(list); + } + + @Override + @Cacheable(key = "'id:' + #p0") + public JobDto findById(Long id) { + Job job = jobRepository.findById(id).orElseGet(Job::new); + ValidationUtil.isNull(job.getId(),"Job","id",id); + return jobMapper.toDto(job); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(Job resources) { + Job job = jobRepository.findByName(resources.getName()); + if(job != null){ + throw new EntityExistException(Job.class,"name",resources.getName()); + } + jobRepository.save(resources); + } + + @Override + @CacheEvict(key = "'id:' + #p0.id") + @Transactional(rollbackFor = Exception.class) + public void update(Job resources) { + Job job = jobRepository.findById(resources.getId()).orElseGet(Job::new); + Job old = jobRepository.findByName(resources.getName()); + if(old != null && !old.getId().equals(resources.getId())){ + throw new EntityExistException(Job.class,"name",resources.getName()); + } + ValidationUtil.isNull( job.getId(),"Job","id",resources.getId()); + resources.setId(job.getId()); + jobRepository.save(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set ids) { + jobRepository.deleteAllByIdIn(ids); + // 删除缓存 + redisUtils.delByKeys("job::id:", ids); + } + + @Override + public void download(List jobDtos, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (JobDto jobDTO : jobDtos) { + Map map = new LinkedHashMap<>(); + map.put("岗位名称", jobDTO.getName()); + map.put("岗位状态", jobDTO.getEnabled() ? "启用" : "停用"); + map.put("创建日期", jobDTO.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } + + @Override + public void verification(Set ids) { + if(userRepository.countByJobs(ids) > 0){ + throw new BadRequestException("所选的岗位中存在用户关联,请解除关联再试!"); + } + } +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/impl/MenuServiceImpl.java b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/MenuServiceImpl.java new file mode 100644 index 0000000..af60a51 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/MenuServiceImpl.java @@ -0,0 +1,356 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import lombok.RequiredArgsConstructor; +import org.nl.modules.system.domain.Menu; +import org.nl.modules.system.domain.Role; +import org.nl.modules.system.domain.User; +import org.nl.modules.system.domain.vo.MenuMetaVo; +import org.nl.modules.system.domain.vo.MenuVo; +import org.nl.exception.BadRequestException; +import org.nl.exception.EntityExistException; +import org.nl.modules.system.repository.MenuRepository; +import org.nl.modules.system.repository.UserRepository; +import org.nl.modules.system.service.MenuService; +import org.nl.modules.system.service.RoleService; +import org.nl.modules.system.service.dto.MenuDto; +import org.nl.modules.system.service.dto.MenuQueryCriteria; +import org.nl.modules.system.service.dto.RoleSmallDto; +import org.nl.modules.system.service.mapstruct.MenuMapper; + +import org.nl.utils.*; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author Zheng Jie + */ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "menu") +public class MenuServiceImpl implements MenuService { + + private final MenuRepository menuRepository; + private final UserRepository userRepository; + private final MenuMapper menuMapper; + private final RoleService roleService; + private final RedisUtils redisUtils; + + @Override + public List queryAll(MenuQueryCriteria criteria, Boolean isQuery) throws Exception { + Sort sort = Sort.by(Sort.Direction.ASC, "menuSort"); + if(isQuery){ + criteria.setPidIsNull(true); + List fields = QueryHelp.getAllFields(criteria.getClass(), new ArrayList<>()); + for (Field field : fields) { + //设置对象的访问权限,保证对private的属性的访问 + field.setAccessible(true); + Object val = field.get(criteria); + if("pidIsNull".equals(field.getName())){ + continue; + } + if (ObjectUtil.isNotNull(val)) { + criteria.setPidIsNull(null); + break; + } + } + } + return menuMapper.toDto(menuRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),sort)); + } + + @Override + @Cacheable(key = "'id:' + #p0") + public MenuDto findById(long id) { + Menu menu = menuRepository.findById(id).orElseGet(Menu::new); + ValidationUtil.isNull(menu.getId(),"Menu","id",id); + return menuMapper.toDto(menu); + } + + /** + * 用户角色改变时需清理缓存 + * @param currentUserId / + * @return / + */ + @Override + @Cacheable(key = "'user:' + #p0") + public List findByUser(Long currentUserId) { + List roles = roleService.findByUsersId(currentUserId); + Set roleIds = roles.stream().map(RoleSmallDto::getId).collect(Collectors.toSet()); + LinkedHashSet menus = menuRepository.findByRoleIdsAndTypeNot(roleIds, 2); + return menus.stream().map(menuMapper::toDto).collect(Collectors.toList()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(Menu resources) { + if(menuRepository.findByTitle(resources.getTitle()) != null){ + throw new EntityExistException(Menu.class,"title",resources.getTitle()); + } + if(StringUtils.isNotBlank(resources.getComponentName())){ + if(menuRepository.findByComponentName(resources.getComponentName()) != null){ + throw new EntityExistException(Menu.class,"componentName",resources.getComponentName()); + } + } + if(resources.getPid().equals(0L)){ + resources.setPid(null); + } + if(resources.getIFrame()){ + String http = "http://", https = "https://"; + if (!(resources.getPath().toLowerCase().startsWith(http)||resources.getPath().toLowerCase().startsWith(https))) { + throw new BadRequestException("外链必须以http://或者https://开头"); + } + } + menuRepository.save(resources); + // 计算子节点数目 + resources.setSubCount(0); + // 更新父节点菜单数目 + updateSubCnt(resources.getPid()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(Menu resources) { + if(resources.getId().equals(resources.getPid())) { + throw new BadRequestException("上级不能为自己"); + } + Menu menu = menuRepository.findById(resources.getId()).orElseGet(Menu::new); + ValidationUtil.isNull(menu.getId(),"Permission","id",resources.getId()); + + if(resources.getIFrame()){ + String http = "http://", https = "https://"; + if (!(resources.getPath().toLowerCase().startsWith(http)||resources.getPath().toLowerCase().startsWith(https))) { + throw new BadRequestException("外链必须以http://或者https://开头"); + } + } + Menu menu1 = menuRepository.findByTitle(resources.getTitle()); + + if(menu1 != null && !menu1.getId().equals(menu.getId())){ + throw new EntityExistException(Menu.class,"title",resources.getTitle()); + } + + if(resources.getPid().equals(0L)){ + resources.setPid(null); + } + + // 记录的父节点ID + Long oldPid = menu.getPid(); + Long newPid = resources.getPid(); + + if(StringUtils.isNotBlank(resources.getComponentName())){ + menu1 = menuRepository.findByComponentName(resources.getComponentName()); + if(menu1 != null && !menu1.getId().equals(menu.getId())){ + throw new EntityExistException(Menu.class,"componentName",resources.getComponentName()); + } + } + menu.setTitle(resources.getTitle()); + menu.setComponent(resources.getComponent()); + menu.setPath(resources.getPath()); + menu.setIcon(resources.getIcon()); + menu.setIFrame(resources.getIFrame()); + menu.setPid(resources.getPid()); + menu.setMenuSort(resources.getMenuSort()); + menu.setCache(resources.getCache()); + menu.setHidden(resources.getHidden()); + menu.setComponentName(resources.getComponentName()); + menu.setPermission(resources.getPermission()); + menu.setType(resources.getType()); + menuRepository.save(menu); + // 计算父级菜单节点数目 + updateSubCnt(oldPid); + updateSubCnt(newPid); + // 清理缓存 + delCaches(resources.getId()); + } + + @Override + public Set getChildMenus(List menuList, Set menuSet) { + for (Menu menu : menuList) { + menuSet.add(menu); + List menus = menuRepository.findByPid(menu.getId()); + if(menus!=null && menus.size()!=0){ + getChildMenus(menus, menuSet); + } + } + return menuSet; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set menuSet) { + for (Menu menu : menuSet) { + // 清理缓存 + delCaches(menu.getId()); + roleService.untiedMenu(menu.getId()); + menuRepository.deleteById(menu.getId()); + updateSubCnt(menu.getPid()); + } + } + + @Override + public List getMenus(Long pid) { + List menus; + if(pid != null && !pid.equals(0L)){ + menus = menuRepository.findByPid(pid); + } else { + menus = menuRepository.findByPidIsNull(); + } + return menuMapper.toDto(menus); + } + + @Override + public List getSuperior(MenuDto menuDto, List menus) { + if(menuDto.getPid() == null){ + menus.addAll(menuRepository.findByPidIsNull()); + return menuMapper.toDto(menus); + } + menus.addAll(menuRepository.findByPid(menuDto.getPid())); + return getSuperior(findById(menuDto.getPid()), menus); + } + + @Override + public List buildTree(List menuDtos) { + List trees = new ArrayList<>(); + Set ids = new HashSet<>(); + for (MenuDto menuDTO : menuDtos) { + if (menuDTO.getPid() == null) { + trees.add(menuDTO); + } + for (MenuDto it : menuDtos) { + if (menuDTO.getId().equals(it.getPid())) { + if (menuDTO.getChildren() == null) { + menuDTO.setChildren(new ArrayList<>()); + } + menuDTO.getChildren().add(it); + ids.add(it.getId()); + } + } + } + if(trees.size() == 0){ + trees = menuDtos.stream().filter(s -> !ids.contains(s.getId())).collect(Collectors.toList()); + } + return trees; + } + + @Override + public List buildMenus(List menuDtos) { + List list = new LinkedList<>(); + menuDtos.forEach(menuDTO -> { + if (menuDTO!=null){ + List menuDtoList = menuDTO.getChildren(); + MenuVo menuVo = new MenuVo(); + menuVo.setName(ObjectUtil.isNotEmpty(menuDTO.getComponentName()) ? menuDTO.getComponentName() : menuDTO.getTitle()); + // 一级目录需要加斜杠,不然会报警告 + menuVo.setPath(menuDTO.getPid() == null ? "/" + menuDTO.getPath() :menuDTO.getPath()); + menuVo.setHidden(menuDTO.getHidden()); + // 如果不是外链 + if(!menuDTO.getIFrame()){ + if(menuDTO.getPid() == null){ + menuVo.setComponent(StrUtil.isEmpty(menuDTO.getComponent())?"Layout":menuDTO.getComponent()); + }else if(menuDTO.getPid() != null && menuDTO.getType() == 0) { + menuVo.setComponent(StrUtil.isEmpty(menuDTO.getComponent()) ? "ParentView" : menuDTO.getComponent()); + + }else if(!StrUtil.isEmpty(menuDTO.getComponent())){ + menuVo.setComponent(menuDTO.getComponent()); + } + } + menuVo.setMeta(new MenuMetaVo(menuDTO.getTitle(),menuDTO.getIcon(),!menuDTO.getCache())); + if(menuDtoList !=null && menuDtoList.size()!=0){ + menuVo.setAlwaysShow(true); + menuVo.setRedirect("noredirect"); + menuVo.setChildren(buildMenus(menuDtoList)); + // 处理是一级菜单并且没有子菜单的情况 + } else if(menuDTO.getPid() == null){ + MenuVo menuVo1 = new MenuVo(); + menuVo1.setMeta(menuVo.getMeta()); + // 非外链 + if(!menuDTO.getIFrame()){ + menuVo1.setPath("index"); + menuVo1.setName(menuVo.getName()); + menuVo1.setComponent(menuVo.getComponent()); + } else { + menuVo1.setPath(menuDTO.getPath()); + } + menuVo.setName(null); + menuVo.setMeta(null); + menuVo.setComponent("Layout"); + List list1 = new ArrayList<>(); + list1.add(menuVo1); + menuVo.setChildren(list1); + } + list.add(menuVo); + } + } + ); + return list; + } + + @Override + public Menu findOne(Long id) { + Menu menu = menuRepository.findById(id).orElseGet(Menu::new); + ValidationUtil.isNull(menu.getId(),"Menu","id",id); + return menu; + } + + @Override + public void download(List menuDtos, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (MenuDto menuDTO : menuDtos) { + Map map = new LinkedHashMap<>(); + map.put("菜单标题", menuDTO.getTitle()); + map.put("菜单类型", menuDTO.getType() == null ? "目录" : menuDTO.getType() == 1 ? "菜单" : "按钮"); + map.put("权限标识", menuDTO.getPermission()); + map.put("外链菜单", menuDTO.getIFrame() ? "是" : "否"); + map.put("菜单可见", menuDTO.getHidden() ? "否" : "是"); + map.put("是否缓存", menuDTO.getCache() ? "是" : "否"); + map.put("创建日期", menuDTO.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } + + private void updateSubCnt(Long menuId){ + if(menuId != null){ + int count = menuRepository.countByPid(menuId); + menuRepository.updateSubCntById(count, menuId); + } + } + + /** + * 清理缓存 + * @param id 菜单ID + */ + public void delCaches(Long id){ + List users = userRepository.findByMenuId(id); + redisUtils.del("menu::id:" +id); + redisUtils.delByKeys("menu::user:",users.stream().map(User::getId).collect(Collectors.toSet())); + // 清除 Role 缓存 + List roles = roleService.findInMenuId(new ArrayList(){{ + add(id); + }}); + redisUtils.delByKeys("role::id:",roles.stream().map(Role::getId).collect(Collectors.toSet())); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/impl/MonitorServiceImpl.java b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/MonitorServiceImpl.java new file mode 100644 index 0000000..5b8c2fc --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/MonitorServiceImpl.java @@ -0,0 +1,183 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.impl; + +import cn.hutool.core.date.BetweenFormater; +import cn.hutool.core.date.DateUtil; + +import org.nl.modules.system.service.MonitorService; +import org.nl.utils.ElAdminConstant; +import org.nl.utils.FileUtil; +import org.nl.utils.StringUtils; +import org.springframework.stereotype.Service; +import oshi.SystemInfo; +import oshi.hardware.*; +import oshi.software.os.FileSystem; +import oshi.software.os.OSFileStore; +import oshi.software.os.OperatingSystem; +import oshi.util.FormatUtil; +import oshi.util.Util; +import java.lang.management.ManagementFactory; +import java.text.DecimalFormat; +import java.util.*; + +/** + * @author Zheng Jie + * @date 2020-05-02 + */ +@Service +public class MonitorServiceImpl implements MonitorService { + + private final DecimalFormat df = new DecimalFormat("0.00"); + + @Override + public Map getServers(){ + Map resultMap = new LinkedHashMap<>(8); + try { + SystemInfo si = new SystemInfo(); + OperatingSystem os = si.getOperatingSystem(); + HardwareAbstractionLayer hal = si.getHardware(); + // 系统信息 + resultMap.put("sys", getSystemInfo(os)); + // cpu 信息 + resultMap.put("cpu", getCpuInfo(hal.getProcessor())); + // 内存信息 + resultMap.put("memory", getMemoryInfo(hal.getMemory())); + // 交换区信息 + resultMap.put("swap", getSwapInfo(hal.getMemory())); + // 磁盘 + resultMap.put("disk", getDiskInfo(os)); + resultMap.put("time", DateUtil.format(new Date(), "HH:mm:ss")); + } catch (Exception e) { + e.printStackTrace(); + } + return resultMap; + } + + /** + * 获取磁盘信息 + * @return / + */ + private Map getDiskInfo(OperatingSystem os) { + Map diskInfo = new LinkedHashMap<>(); + FileSystem fileSystem = os.getFileSystem(); + List fsArray = fileSystem.getFileStores(); + String osName = System.getProperty("os.name"); + long available = 0, total = 0; + for (OSFileStore fs : fsArray){ + // windows 需要将所有磁盘分区累加,linux 和 mac 直接累加会出现磁盘重复的问题,待修复 + if(osName.toLowerCase().startsWith(ElAdminConstant.WIN)) { + available += fs.getUsableSpace(); + total += fs.getTotalSpace(); + } else { + available = fs.getUsableSpace(); + total = fs.getTotalSpace(); + break; + } + } + long used = total - available; + diskInfo.put("total", total > 0 ? FileUtil.getSize(total) : "?"); + diskInfo.put("available", FileUtil.getSize(available)); + diskInfo.put("used", FileUtil.getSize(used)); + diskInfo.put("usageRate", df.format(used/(double)total * 100)); + return diskInfo; + } + + /** + * 获取交换区信息 + * @param memory / + * @return / + */ + private Map getSwapInfo(GlobalMemory memory) { + Map swapInfo = new LinkedHashMap<>(); + VirtualMemory virtualMemory = memory.getVirtualMemory(); + long total = virtualMemory.getSwapTotal(); + long used = virtualMemory.getSwapUsed(); + swapInfo.put("total", FormatUtil.formatBytes(total)); + swapInfo.put("used", FormatUtil.formatBytes(used)); + swapInfo.put("available", FormatUtil.formatBytes(total - used)); + if(used == 0){ + swapInfo.put("usageRate", 0); + } else { + swapInfo.put("usageRate", df.format(used/(double)total * 100)); + } + return swapInfo; + } + + /** + * 获取内存信息 + * @param memory / + * @return / + */ + private Map getMemoryInfo(GlobalMemory memory) { + Map memoryInfo = new LinkedHashMap<>(); + memoryInfo.put("total", FormatUtil.formatBytes(memory.getTotal())); + memoryInfo.put("available", FormatUtil.formatBytes(memory.getAvailable())); + memoryInfo.put("used", FormatUtil.formatBytes(memory.getTotal() - memory.getAvailable())); + memoryInfo.put("usageRate", df.format((memory.getTotal() - memory.getAvailable())/(double)memory.getTotal() * 100)); + return memoryInfo; + } + + /** + * 获取Cpu相关信息 + * @param processor / + * @return / + */ + private Map getCpuInfo(CentralProcessor processor) { + Map cpuInfo = new LinkedHashMap<>(); + cpuInfo.put("name", processor.getProcessorIdentifier().getName()); + cpuInfo.put("package", processor.getPhysicalPackageCount() + "个物理CPU"); + cpuInfo.put("core", processor.getPhysicalProcessorCount() + "个物理核心"); + cpuInfo.put("coreNumber", processor.getPhysicalProcessorCount()); + cpuInfo.put("logic", processor.getLogicalProcessorCount() + "个逻辑CPU"); + // CPU信息 + long[] prevTicks = processor.getSystemCpuLoadTicks(); + // 等待1秒... + Util.sleep(1000); + long[] ticks = processor.getSystemCpuLoadTicks(); + long user = ticks[CentralProcessor.TickType.USER.getIndex()] - prevTicks[CentralProcessor.TickType.USER.getIndex()]; + long nice = ticks[CentralProcessor.TickType.NICE.getIndex()] - prevTicks[CentralProcessor.TickType.NICE.getIndex()]; + long sys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()] - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()]; + long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()] - prevTicks[CentralProcessor.TickType.IDLE.getIndex()]; + long iowait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()] - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()]; + long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()] - prevTicks[CentralProcessor.TickType.IRQ.getIndex()]; + long softirq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()] - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()]; + long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()] - prevTicks[CentralProcessor.TickType.STEAL.getIndex()]; + long totalCpu = user + nice + sys + idle + iowait + irq + softirq + steal; + cpuInfo.put("used", df.format(100d * user / totalCpu + 100d * sys / totalCpu)); + cpuInfo.put("idle", df.format(100d * idle / totalCpu)); + return cpuInfo; + } + + /** + * 获取系统相关信息,系统、运行天数、系统IP + * @param os / + * @return / + */ + private Map getSystemInfo(OperatingSystem os){ + Map systemInfo = new LinkedHashMap<>(); + // jvm 运行时间 + long time = ManagementFactory.getRuntimeMXBean().getStartTime(); + Date date = new Date(time); + // 计算项目运行时间 + String formatBetween = DateUtil.formatBetween(date, new Date(),BetweenFormater.Level.HOUR); + // 系统信息 + systemInfo.put("os", os.toString()); + systemInfo.put("day", formatBetween); + systemInfo.put("ip", StringUtils.getLocalIp()); + return systemInfo; + } +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/impl/ParamServiceImpl.java b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/ParamServiceImpl.java new file mode 100644 index 0000000..b69a3a9 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/ParamServiceImpl.java @@ -0,0 +1,133 @@ + +package org.nl.modules.system.service.impl; + + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.IdUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; +import org.nl.exception.BadRequestException; +import org.nl.modules.system.service.ParamService; +import org.nl.modules.system.service.dto.ParamDto; +import org.nl.utils.FileUtil; +import org.nl.utils.SecurityUtils; +import org.nl.wql.core.bean.ResultBean; +import org.nl.wql.core.bean.WQLObject; +import org.nl.wql.util.WqlUtil; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * @description 服务实现 + * @author ldjun + * @date 2021-03-16 + **/ +@Service +@RequiredArgsConstructor +@Slf4j +public class ParamServiceImpl implements ParamService { + + @Override + public Map queryAll(Map whereJson, Pageable page){ + WQLObject wo = WQLObject.getWQLObject("sys_param"); + ResultBean rb = wo.pagequery(WqlUtil.getHttpContext(page), "", "update_time desc"); + final JSONObject json = rb.pageResult(); + return json; + } + + @Override + public List queryAll(Map whereJson){ + WQLObject wo = WQLObject.getWQLObject("sys_param"); + JSONArray arr = wo.query().getResultJSONArray(0); + List list = JSONArray.toList(arr, ParamDto.class); + return list; + } + + @Override + public ParamDto findById(String id) { + WQLObject wo = WQLObject.getWQLObject("sys_param"); + JSONObject json = wo.query("id ='" + id + "'").uniqueResult(0); + final ParamDto obj = (ParamDto) JSONObject.toBean(json, ParamDto.class); + return obj; + } + + @Override + public ParamDto findByCode(String code) { + WQLObject wo = WQLObject.getWQLObject("sys_param"); + JSONObject json = wo.query("code ='" + code + "'").uniqueResult(0); + final ParamDto obj = (ParamDto) JSONObject.toBean(json, ParamDto.class); + return obj; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(ParamDto dto) { + String currentUsername = SecurityUtils.getCurrentUsername(); + String now = DateUtil.now(); + + dto.setId(IdUtil.simpleUUID()); + dto.setCreate_by(currentUsername); + dto.setUpdate_by(currentUsername); + dto.setUpdate_time(now); + dto.setCreate_time(now); + + WQLObject wo = WQLObject.getWQLObject("sys_param"); + JSONObject json=JSONObject.fromObject(dto); + wo.insert(json); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(ParamDto dto) { + ParamDto entity = this.findById(dto.getId()); + if (entity == null) throw new BadRequestException("被删除或无权限,操作失败!"); + + String currentUsername = SecurityUtils.getCurrentUsername(); + String now = DateUtil.now(); + dto.setUpdate_time(now); + dto.setUpdate_by(currentUsername); + + WQLObject wo = WQLObject.getWQLObject("sys_param"); + JSONObject json=JSONObject.fromObject(dto); + wo.update(json); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteAll(String[] ids) { + WQLObject wo = WQLObject.getWQLObject("sys_param"); + for (String id: ids) { + wo.delete("id = '" + id + "'"); + } + } + + @Override + public void download(List all, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (ParamDto param : all) { + Map map = new LinkedHashMap<>(); + map.put("编码", param.getCode()); + map.put("名称", param.getName()); + map.put("值", param.getValue()); + map.put("备注", param.getRemark()); + map.put("是否启用", param.getIs_active()); + map.put("是否删除", param.getIs_delete()); + map.put("创建者", param.getCreate_by()); + map.put("创建时间", param.getCreate_time()); + map.put("修改者", param.getUpdate_by()); + map.put("修改时间", param.getUpdate_time()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/impl/RoleServiceImpl.java b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/RoleServiceImpl.java new file mode 100644 index 0000000..fd2a74a --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/RoleServiceImpl.java @@ -0,0 +1,224 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import lombok.RequiredArgsConstructor; +import org.nl.exception.BadRequestException; +import org.nl.modules.security.service.UserCacheClean; +import org.nl.modules.system.domain.Menu; +import org.nl.modules.system.domain.Role; +import org.nl.exception.EntityExistException; +import org.nl.modules.system.domain.User; +import org.nl.modules.system.repository.RoleRepository; +import org.nl.modules.system.repository.UserRepository; +import org.nl.modules.system.service.RoleService; +import org.nl.modules.system.service.dto.RoleDto; +import org.nl.modules.system.service.dto.RoleQueryCriteria; +import org.nl.modules.system.service.dto.RoleSmallDto; +import org.nl.modules.system.service.dto.UserDto; +import org.nl.modules.system.service.mapstruct.RoleMapper; +import org.nl.modules.system.service.mapstruct.RoleSmallMapper; + +import org.nl.utils.*; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author Zheng Jie + * @date 2018-12-03 + */ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "role") +public class RoleServiceImpl implements RoleService { + + private final RoleRepository roleRepository; + private final RoleMapper roleMapper; + private final RoleSmallMapper roleSmallMapper; + private final RedisUtils redisUtils; + private final UserRepository userRepository; + private final UserCacheClean userCacheClean; + + @Override + public List queryAll() { + Sort sort = Sort.by(Sort.Direction.ASC, "level"); + return roleMapper.toDto(roleRepository.findAll(sort)); + } + + @Override + public List queryAll(RoleQueryCriteria criteria) { + return roleMapper.toDto(roleRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder))); + } + + @Override + public Object queryAll(RoleQueryCriteria criteria, Pageable pageable) { + Page page = roleRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable); + return PageUtil.toPage(page.map(roleMapper::toDto)); + } + + @Override + @Cacheable(key = "'id:' + #p0") + @Transactional(rollbackFor = Exception.class) + public RoleDto findById(long id) { + Role role = roleRepository.findById(id).orElseGet(Role::new); + ValidationUtil.isNull(role.getId(), "Role", "id", id); + return roleMapper.toDto(role); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(Role resources) { + if (roleRepository.findByName(resources.getName()) != null) { + throw new EntityExistException(Role.class, "username", resources.getName()); + } + roleRepository.save(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(Role resources) { + Role role = roleRepository.findById(resources.getId()).orElseGet(Role::new); + ValidationUtil.isNull(role.getId(), "Role", "id", resources.getId()); + + Role role1 = roleRepository.findByName(resources.getName()); + + if (role1 != null && !role1.getId().equals(role.getId())) { + throw new EntityExistException(Role.class, "username", resources.getName()); + } + role.setName(resources.getName()); + role.setDescription(resources.getDescription()); + role.setDataScope(resources.getDataScope()); + role.setDepts(resources.getDepts()); + role.setLevel(resources.getLevel()); + roleRepository.save(role); + // 更新相关缓存 + delCaches(role.getId(), null); + } + + @Override + public void updateMenu(Role resources, RoleDto roleDTO) { + Role role = roleMapper.toEntity(roleDTO); + List users = userRepository.findByRoleId(role.getId()); + // 更新菜单 + role.setMenus(resources.getMenus()); + delCaches(resources.getId(), users); + roleRepository.save(role); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void untiedMenu(Long menuId) { + // 更新菜单 + roleRepository.untiedMenu(menuId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set ids) { + for (Long id : ids) { + // 更新相关缓存 + delCaches(id, null); + } + roleRepository.deleteAllByIdIn(ids); + } + + @Override + public List findByUsersId(Long id) { + return roleSmallMapper.toDto(new ArrayList<>(roleRepository.findByUserId(id))); + } + + @Override + public Integer findByRoles(Set roles) { + Set roleDtos = new HashSet<>(); + for (Role role : roles) { + roleDtos.add(findById(role.getId())); + } + return Collections.min(roleDtos.stream().map(RoleDto::getLevel).collect(Collectors.toList())); + } + + @Override + @Cacheable(key = "'auth:' + #p0.id") + public List mapToGrantedAuthorities(UserDto user) { + Set permissions = new HashSet<>(); + // 如果是管理员直接返回 + if (user.getIsAdmin()) { + permissions.add("admin"); + return permissions.stream().map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + } + Set roles = roleRepository.findByUserId(user.getId()); + permissions = roles.stream().flatMap(role -> role.getMenus().stream()) + .filter(menu -> StringUtils.isNotBlank(menu.getPermission())) + .map(Menu::getPermission).collect(Collectors.toSet()); + return permissions.stream().map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + } + + @Override + public void download(List roles, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (RoleDto role : roles) { + Map map = new LinkedHashMap<>(); + map.put("角色名称", role.getName()); + map.put("角色级别", role.getLevel()); + map.put("描述", role.getDescription()); + map.put("创建日期", role.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } + + @Override + public void verification(Set ids) { + if (userRepository.countByRoles(ids) > 0) { + throw new BadRequestException("所选角色存在用户关联,请解除关联再试!"); + } + } + + @Override + public List findInMenuId(List menuIds) { + return roleRepository.findInMenuId(menuIds); + } + + /** + * 清理缓存 + * @param id / + */ + public void delCaches(Long id, List users) { + users = CollectionUtil.isEmpty(users) ? userRepository.findByRoleId(id) : users; + if (CollectionUtil.isNotEmpty(users)) { + users.forEach(item -> userCacheClean.cleanUserCache(item.getUsername())); + Set userIds = users.stream().map(User::getId).collect(Collectors.toSet()); + redisUtils.delByKeys(CacheKey.DATA_USER, userIds); + redisUtils.delByKeys(CacheKey.MENU_USER, userIds); + redisUtils.delByKeys(CacheKey.ROLE_AUTH, userIds); + } + redisUtils.del(CacheKey.ROLE_ID + id); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/impl/UserServiceImpl.java b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..c307f95 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/UserServiceImpl.java @@ -0,0 +1,247 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.impl; + +import lombok.RequiredArgsConstructor; +import org.nl.config.FileProperties; +import org.nl.modules.security.service.OnlineUserService; +import org.nl.modules.security.service.UserCacheClean; +import org.nl.modules.system.domain.User; +import org.nl.exception.EntityExistException; +import org.nl.exception.EntityNotFoundException; +import org.nl.modules.system.repository.UserRepository; +import org.nl.modules.system.service.UserService; +import org.nl.modules.system.service.dto.JobSmallDto; +import org.nl.modules.system.service.dto.RoleSmallDto; +import org.nl.modules.system.service.dto.UserDto; +import org.nl.modules.system.service.dto.UserQueryCriteria; +import org.nl.modules.system.service.mapstruct.UserMapper; + +import org.nl.utils.*; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.NotBlank; +import java.io.File; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "user") +public class UserServiceImpl implements UserService { + + private final UserRepository userRepository; + private final UserMapper userMapper; + private final FileProperties properties; + private final RedisUtils redisUtils; + private final UserCacheClean userCacheClean; + private final OnlineUserService onlineUserService; + + @Override + public Object queryAll(UserQueryCriteria criteria, Pageable pageable) { + Page page = userRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable); + return PageUtil.toPage(page.map(userMapper::toDto)); + } + + @Override + public List queryAll(UserQueryCriteria criteria) { + List users = userRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder)); + return userMapper.toDto(users); + } + + @Override + @Cacheable(key = "'id:' + #p0") + @Transactional(rollbackFor = Exception.class) + public UserDto findById(long id) { + User user = userRepository.findById(id).orElseGet(User::new); + ValidationUtil.isNull(user.getId(), "User", "id", id); + return userMapper.toDto(user); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(User resources) { + if (userRepository.findByUsername(resources.getUsername()) != null) { + throw new EntityExistException(User.class, "username", resources.getUsername()); + } + if (userRepository.findByEmail(resources.getEmail()) != null) { + throw new EntityExistException(User.class, "email", resources.getEmail()); + } + userRepository.save(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(User resources) throws Exception{ + User user = userRepository.findById(resources.getId()).orElseGet(User::new); + ValidationUtil.isNull(user.getId(), "User", "id", resources.getId()); + User user1 = userRepository.findByUsername(resources.getUsername()); + User user2 = userRepository.findByEmail(resources.getEmail()); + + if (user1 != null && !user.getId().equals(user1.getId())) { + throw new EntityExistException(User.class, "username", resources.getUsername()); + } + + if (user2 != null && !user.getId().equals(user2.getId())) { + throw new EntityExistException(User.class, "email", resources.getEmail()); + } + // 如果用户的角色改变 + if (!resources.getRoles().equals(user.getRoles())) { + redisUtils.del(CacheKey.DATA_USER + resources.getId()); + redisUtils.del(CacheKey.MENU_USER + resources.getId()); + redisUtils.del(CacheKey.ROLE_AUTH + resources.getId()); + } + // 如果用户名称修改 + if(!resources.getUsername().equals(user.getUsername())){ + redisUtils.del("user::username:" + user.getUsername()); + } + // 如果用户被禁用,则清除用户登录信息 + if(!resources.getEnabled()){ + onlineUserService.kickOutForUsername(resources.getUsername()); + } + user.setUsername(resources.getUsername()); + user.setEmail(resources.getEmail()); + user.setEnabled(resources.getEnabled()); + user.setRoles(resources.getRoles()); + user.setDept(resources.getDept()); + user.setJobs(resources.getJobs()); + user.setPhone(resources.getPhone()); + user.setNickName(resources.getNickName()); + user.setGender(resources.getGender()); + userRepository.save(user); + // 清除缓存 + delCaches(user.getId(), user.getUsername()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateCenter(User resources) { + User user = userRepository.findById(resources.getId()).orElseGet(User::new); + user.setNickName(resources.getNickName()); + user.setPhone(resources.getPhone()); + user.setGender(resources.getGender()); + userRepository.save(user); + // 清理缓存 + delCaches(user.getId(), user.getUsername()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set ids) { + for (Long id : ids) { + // 清理缓存 + UserDto user = findById(id); + delCaches(user.getId(), user.getUsername()); + } + userRepository.deleteAllByIdIn(ids); + } + + @Override + @Cacheable(key = "'username:' + #p0") + public UserDto findByName(String userName) { + User user = userRepository.findByUsername(userName); + if (user == null) { + throw new EntityNotFoundException(User.class, "name", userName); + } else { + return userMapper.toDto(user); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updatePass(String username, String pass) { + userRepository.updatePass(username, pass, new Date()); + redisUtils.del("user::username:" + username); + flushCache(username); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Map updateAvatar(MultipartFile multipartFile) { + User user = userRepository.findByUsername(SecurityUtils.getCurrentUsername()); + String oldPath = user.getAvatarPath(); + File file = FileUtil.upload(multipartFile, properties.getPath().getAvatar()); + user.setAvatarPath(Objects.requireNonNull(file).getPath()); + user.setAvatarName(file.getName()); + userRepository.save(user); + if (StringUtils.isNotBlank(oldPath)) { + FileUtil.del(oldPath); + } + @NotBlank String username = user.getUsername(); + flushCache(username); + return new HashMap(1) {{ + put("avatar", file.getName()); + }}; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateEmail(String username, String email) { + userRepository.updateEmail(username, email); + flushCache(username); + } + + @Override + public void download(List queryAll, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (UserDto userDTO : queryAll) { + List roles = userDTO.getRoles().stream().map(RoleSmallDto::getName).collect(Collectors.toList()); + Map map = new LinkedHashMap<>(); + map.put("用户名", userDTO.getUsername()); + map.put("角色", roles); + map.put("部门", userDTO.getDept().getName()); + map.put("岗位", userDTO.getJobs().stream().map(JobSmallDto::getName).collect(Collectors.toList())); + map.put("邮箱", userDTO.getEmail()); + map.put("状态", userDTO.getEnabled() ? "启用" : "禁用"); + map.put("手机号码", userDTO.getPhone()); + map.put("修改密码的时间", userDTO.getPwdResetTime()); + map.put("创建日期", userDTO.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } + + /** + * 清理缓存 + * + * @param id / + */ + public void delCaches(Long id, String username) { + redisUtils.del(CacheKey.USER_ID + id); + flushCache(username); + } + + /** + * 清理 登陆时 用户缓存信息 + * + * @param username / + */ + private void flushCache(String username) { + userCacheClean.cleanUserCache(username); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/impl/VerifyServiceImpl.java b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/VerifyServiceImpl.java new file mode 100644 index 0000000..3e5fcd7 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/impl/VerifyServiceImpl.java @@ -0,0 +1,81 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.impl; + +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.extra.template.Template; +import cn.hutool.extra.template.TemplateConfig; +import cn.hutool.extra.template.TemplateEngine; +import cn.hutool.extra.template.TemplateUtil; +import lombok.RequiredArgsConstructor; +import org.nl.domain.vo.EmailVo; +import org.nl.exception.BadRequestException; +import org.nl.modules.system.service.VerifyService; +import org.nl.utils.RedisUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import java.util.Collections; + +/** + * @author Zheng Jie + * @date 2018-12-26 + */ +@Service +@RequiredArgsConstructor +public class VerifyServiceImpl implements VerifyService { + + @Value("${code.expiration}") + private Long expiration; + private final RedisUtils redisUtils; + + @Override + @Transactional(rollbackFor = Exception.class) + public EmailVo sendEmail(String email, String key) { + EmailVo emailVo; + String content; + String redisKey = key + email; + // 如果不存在有效的验证码,就创建一个新的 + TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH)); + Template template = engine.getTemplate("email/email.ftl"); + Object oldCode = redisUtils.get(redisKey); + if(oldCode == null){ + String code = RandomUtil.randomNumbers (6); + // 存入缓存 + if(!redisUtils.set(redisKey, code, expiration)){ + throw new BadRequestException("服务异常,请联系网站负责人"); + } + content = template.render(Dict.create().set("code",code)); + emailVo = new EmailVo(Collections.singletonList(email),"EL-ADMIN后台管理系统",content); + // 存在就再次发送原来的验证码 + } else { + content = template.render(Dict.create().set("code",oldCode)); + emailVo = new EmailVo(Collections.singletonList(email),"EL-ADMIN后台管理系统",content); + } + return emailVo; + } + + @Override + public void validated(String key, String code) { + Object value = redisUtils.get(key); + if(value == null || !value.toString().equals(code)){ + throw new BadRequestException("无效验证码"); + } else { + redisUtils.del(key); + } + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/DeptMapper.java b/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/DeptMapper.java new file mode 100644 index 0000000..2d91a1e --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/DeptMapper.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.mapstruct; + +import org.nl.base.BaseMapper; +import org.nl.modules.system.domain.Dept; +import org.nl.modules.system.service.dto.DeptDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author Zheng Jie +* @date 2019-03-25 +*/ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface DeptMapper extends BaseMapper { +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/DeptSmallMapper.java b/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/DeptSmallMapper.java new file mode 100644 index 0000000..4f4a45a --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/DeptSmallMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.mapstruct; + +import org.nl.base.BaseMapper; +import org.nl.modules.system.domain.Dept; +import org.nl.modules.system.service.dto.DeptSmallDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author Zheng Jie +* @date 2019-03-25 +*/ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface DeptSmallMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/DictDetailMapper.java b/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/DictDetailMapper.java new file mode 100644 index 0000000..5fcc4f9 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/DictDetailMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.mapstruct; + +import org.nl.base.BaseMapper; +import org.nl.modules.system.domain.DictDetail; +import org.nl.modules.system.service.dto.DictDetailDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@Mapper(componentModel = "spring", uses = {DictSmallMapper.class}, unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface DictDetailMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/DictMapper.java b/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/DictMapper.java new file mode 100644 index 0000000..eebf113 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/DictMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.mapstruct; + +import org.nl.base.BaseMapper; +import org.nl.modules.system.domain.Dict; +import org.nl.modules.system.service.dto.DictDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface DictMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/DictSmallMapper.java b/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/DictSmallMapper.java new file mode 100644 index 0000000..aa0a739 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/DictSmallMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.mapstruct; + +import org.nl.base.BaseMapper; +import org.nl.modules.system.domain.Dict; +import org.nl.modules.system.service.dto.DictSmallDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author Zheng Jie +* @date 2019-04-10 +*/ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface DictSmallMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/JobMapper.java b/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/JobMapper.java new file mode 100644 index 0000000..23a513f --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/JobMapper.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.mapstruct; + +import org.nl.base.BaseMapper; +import org.nl.modules.system.domain.Job; +import org.nl.modules.system.service.dto.JobDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author Zheng Jie +* @date 2019-03-29 +*/ +@Mapper(componentModel = "spring",uses = {DeptMapper.class},unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface JobMapper extends BaseMapper { +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/JobSmallMapper.java b/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/JobSmallMapper.java new file mode 100644 index 0000000..299edd1 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/JobSmallMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.mapstruct; + +import org.nl.base.BaseMapper; +import org.nl.modules.system.domain.Job; +import org.nl.modules.system.service.dto.JobSmallDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @author Zheng Jie +* @date 2019-03-29 +*/ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface JobSmallMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/MenuMapper.java b/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/MenuMapper.java new file mode 100644 index 0000000..671b392 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/MenuMapper.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.mapstruct; + +import org.nl.base.BaseMapper; +import org.nl.modules.system.domain.Menu; +import org.nl.modules.system.service.dto.MenuDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** + * @author Zheng Jie + * @date 2018-12-17 + */ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface MenuMapper extends BaseMapper { +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/RoleMapper.java b/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/RoleMapper.java new file mode 100644 index 0000000..3720075 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/RoleMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.mapstruct; + +import org.nl.base.BaseMapper; +import org.nl.modules.system.domain.Role; +import org.nl.modules.system.service.dto.RoleDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +@Mapper(componentModel = "spring", uses = {MenuMapper.class, DeptMapper.class}, unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface RoleMapper extends BaseMapper { + +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/RoleSmallMapper.java b/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/RoleSmallMapper.java new file mode 100644 index 0000000..08ef037 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/RoleSmallMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.mapstruct; + +import org.nl.base.BaseMapper; +import org.nl.modules.system.domain.Role; +import org.nl.modules.system.service.dto.RoleSmallDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** + * @author Zheng Jie + * @date 2019-5-23 + */ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface RoleSmallMapper extends BaseMapper { + +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/UserMapper.java b/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/UserMapper.java new file mode 100644 index 0000000..6da024f --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/service/mapstruct/UserMapper.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.modules.system.service.mapstruct; + +import org.nl.base.BaseMapper; +import org.nl.modules.system.domain.User; +import org.nl.modules.system.service.dto.UserDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +@Mapper(componentModel = "spring",uses = {RoleMapper.class, DeptMapper.class, JobMapper.class},unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface UserMapper extends BaseMapper { +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/util/CodeUtil.java b/nladmin-system/src/main/java/org/nl/modules/system/util/CodeUtil.java new file mode 100644 index 0000000..982cd1b --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/util/CodeUtil.java @@ -0,0 +1,19 @@ +package org.nl.modules.system.util; + +import org.nl.modules.system.service.GenCodeService; +import org.nl.modules.system.service.impl.GenCodeServiceImpl; + +import java.util.HashMap; + +public class CodeUtil { + + public static synchronized String getNewCode(String ruleCode){ + GenCodeService service=new GenCodeServiceImpl(); + String flag = "1"; + HashMap map = new HashMap<>(); + map.put("flag",flag); + map.put("code",ruleCode); + return service.codeDemo(map); + } + +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/util/YamlUtil.java b/nladmin-system/src/main/java/org/nl/modules/system/util/YamlUtil.java new file mode 100644 index 0000000..03d9896 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/modules/system/util/YamlUtil.java @@ -0,0 +1,11 @@ +package org.nl.modules.system.util; + +import java.util.Properties; + +public class YamlUtil { + public static Properties properties; + + public static String getValue(String key) { + return (String) properties.get(key); + } +} diff --git a/nladmin-system/src/main/java/org/nl/modules/system/wql/sys.xls b/nladmin-system/src/main/java/org/nl/modules/system/wql/sys.xls new file mode 100644 index 0000000..1e7bc29 Binary files /dev/null and b/nladmin-system/src/main/java/org/nl/modules/system/wql/sys.xls differ diff --git a/nladmin-system/src/main/java/org/nl/start/Init.java b/nladmin-system/src/main/java/org/nl/start/Init.java new file mode 100644 index 0000000..2faea56 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/start/Init.java @@ -0,0 +1,73 @@ +package org.nl.start; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.nl.modules.quartz.domain.QuartzJob; +import org.nl.modules.quartz.repository.QuartzJobRepository; +import org.nl.modules.quartz.utils.QuartzManage; +import org.nl.start.auto.initial.ApplicationAutoInitialExecuter; +import org.nl.start.auto.initial.WebAutoInitialExecuter; +import org.nl.wql.WQLCore; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; + +import javax.sql.DataSource; +import java.util.List; + +/** + * 随项目启动模块 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class Init implements ApplicationRunner { + @Autowired + ApplicationAutoInitialExecuter applicationAutoInitialExecuter; + @Autowired + WebAutoInitialExecuter webAutoInitialExecuter; + @Autowired + DataSource dataSource; + + private final QuartzJobRepository quartzJobRepository; + private final QuartzManage quartzManage; + + private void init() throws Exception { + //初始化WQL + initWql(); + //随线程启动 + initApplicationAutoInitialExecuter(); + initWebAutoInitialExecuter(); + //初始化任务调度 + initQuartz(); + System.out.println("项目启动成功!"); + } + + private void initQuartz() { + log.info("--------------------注入定时任务---------------------"); + List quartzJobs = quartzJobRepository.findByIsPauseIsFalse(); + quartzJobs.forEach(quartzManage::addJob); + log.info("--------------------定时任务注入完成---------------------"); + + } + + private void initWql() throws Exception { + WQLCore.ROOT = "org.nl"; + WQLCore.init(); + log.info("WQL初始化成功!"); + } + + private void initApplicationAutoInitialExecuter() throws Exception { + applicationAutoInitialExecuter.init(); + } + + private void initWebAutoInitialExecuter() throws Exception { + webAutoInitialExecuter.init(); + } + + @Override + public void run(ApplicationArguments args) throws Exception { + this.init(); + } +} diff --git a/nladmin-system/src/main/java/org/nl/start/auto/initial/ApplicationAutoInitial.java b/nladmin-system/src/main/java/org/nl/start/auto/initial/ApplicationAutoInitial.java new file mode 100644 index 0000000..1f57f22 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/start/auto/initial/ApplicationAutoInitial.java @@ -0,0 +1,6 @@ +package org.nl.start.auto.initial; + +//DeviceOpcProtocolRunable-----DeviceOpcSynchronizeAutoRun----AbstractAutoRunable-----AutoRunServiceImpl----- WebAutoInitialExecuter +public interface ApplicationAutoInitial { + void autoInitial() throws Exception; +} diff --git a/nladmin-system/src/main/java/org/nl/start/auto/initial/ApplicationAutoInitialExecuter.java b/nladmin-system/src/main/java/org/nl/start/auto/initial/ApplicationAutoInitialExecuter.java new file mode 100644 index 0000000..b89ccff --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/start/auto/initial/ApplicationAutoInitialExecuter.java @@ -0,0 +1,41 @@ +package org.nl.start.auto.initial; + +import org.nl.modules.system.service.ParamService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +@Component +public class ApplicationAutoInitialExecuter { + @Autowired(required = false) + List applicationAutoInitial; + @Autowired + ParamService paramService; + //是否启动 + private final static boolean IS_AUTO_THREAD_CODE = true; + + public void init() throws Exception { + if (!IS_AUTO_THREAD_CODE) { + return; + } + + List services = this.getApplicationAutoInitialService(); + Iterator it = services.iterator(); + + while (it.hasNext()) { + ApplicationAutoInitial service = (ApplicationAutoInitial) it.next(); + service.autoInitial(); + } + + + } + + private List getApplicationAutoInitialService() { + return (List) (this.applicationAutoInitial != null && this.applicationAutoInitial.size() != 0 + ? this.applicationAutoInitial + : new ArrayList()); + } +} diff --git a/nladmin-system/src/main/java/org/nl/start/auto/initial/WebAutoInitial.java b/nladmin-system/src/main/java/org/nl/start/auto/initial/WebAutoInitial.java new file mode 100644 index 0000000..8f6c557 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/start/auto/initial/WebAutoInitial.java @@ -0,0 +1,5 @@ +package org.nl.start.auto.initial; + +public interface WebAutoInitial { + void autoInitial() throws Exception; +} diff --git a/nladmin-system/src/main/java/org/nl/start/auto/initial/WebAutoInitialExecuter.java b/nladmin-system/src/main/java/org/nl/start/auto/initial/WebAutoInitialExecuter.java new file mode 100644 index 0000000..4a049ea --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/start/auto/initial/WebAutoInitialExecuter.java @@ -0,0 +1,33 @@ +package org.nl.start.auto.initial; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +@Component +@Lazy(false) +public class WebAutoInitialExecuter { + @Autowired(required = false) + List webAutoInitial; + + private List getWebAutoInitialService() { + return (List) (this.webAutoInitial != null && this.webAutoInitial.size() != 0 + ? this.webAutoInitial + : new ArrayList()); + } + + public void init() throws Exception { + List services = this.getWebAutoInitialService(); + Iterator arg1 = services.iterator(); + + while (arg1.hasNext()) { + WebAutoInitial service = (WebAutoInitial) arg1.next(); + service.autoInitial(); + } + + } +} diff --git a/nladmin-system/src/main/java/org/nl/start/auto/run/AbstractAutoRunnable.java b/nladmin-system/src/main/java/org/nl/start/auto/run/AbstractAutoRunnable.java new file mode 100644 index 0000000..8bd9de9 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/start/auto/run/AbstractAutoRunnable.java @@ -0,0 +1,104 @@ +package org.nl.start.auto.run; + +import lombok.extern.slf4j.Slf4j; + +import java.util.Date; + +@Slf4j +public abstract class AbstractAutoRunnable implements Runnable { + private ThreadStatusEnum status; + private Date startTime; + private Date stopTime; + private String stopMessage; + private ThreadUsedStatusEnum usedStatus; + @Override + public void run() { + this.setStatus(ThreadStatusEnum.run); + this.setStartTime(new Date()); + this.setStopMessage(""); + String true_clear = "执行完毕"; + + try { + this.before(); + //子类该方法是个死循环 + this.autoRun(); + this.setStopMessage(true_clear); + } catch (Throwable arg5) { + log.warn("", arg5); + // this.setStopMessage(ExceptionUtlEx.getSimpleTrace(arg5)); + } finally { + this.setStopTime(new Date()); + this.setStatus(ThreadStatusEnum.stop); + this.after(); + } + + } + + public void before() throws Exception { + } + + public void after() { + } + + public void stop() { + this.after(); + } + + public Boolean getForbidStop() { + return Boolean.valueOf(false); + } + + public Boolean getForbidDisable() { + return Boolean.valueOf(false); + } + + public abstract String getCode(); + + public abstract String getName(); + + public String getDescription() { + return this.getName(); + } + + public abstract void autoRun() throws Exception; + + public ThreadStatusEnum getStatus() { + return this.status; + } + + public void setStatus(ThreadStatusEnum status) { + this.status = status; + } + + public Date getStartTime() { + return this.startTime; + } + + public void setStartTime(Date startTime) { + this.startTime = startTime; + } + + public Date getStopTime() { + return this.stopTime; + } + + public void setStopTime(Date stopTime) { + this.stopTime = stopTime; + } + + public String getStopMessage() { + return this.stopMessage; + } + + public void setStopMessage(String stopMessage) { + this.stopMessage = stopMessage; + } + + public ThreadUsedStatusEnum getUsedStatus() { + return this.usedStatus; + } + + public void setUsedStatus(ThreadUsedStatusEnum usedStatus) { + this.usedStatus = usedStatus; + } +} diff --git a/nladmin-system/src/main/java/org/nl/start/auto/run/AutoRunService.java b/nladmin-system/src/main/java/org/nl/start/auto/run/AutoRunService.java new file mode 100644 index 0000000..02c855a --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/start/auto/run/AutoRunService.java @@ -0,0 +1,16 @@ +package org.nl.start.auto.run; + +import java.util.List; +import java.util.Map; + +public interface AutoRunService { + void startThread(String arg0); + + void stopThread(String arg0); + + ThreadDto findByCode(String arg0, String arg1); + + List findAll(); + + List findByCondition(Map whereJson); +} diff --git a/nladmin-system/src/main/java/org/nl/start/auto/run/AutoRunServiceImpl.java b/nladmin-system/src/main/java/org/nl/start/auto/run/AutoRunServiceImpl.java new file mode 100644 index 0000000..4140e97 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/start/auto/run/AutoRunServiceImpl.java @@ -0,0 +1,217 @@ +package org.nl.start.auto.run; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; +import org.nl.exception.WDKException; +import org.nl.start.auto.initial.ApplicationAutoInitial; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +@Service +@Slf4j +public class AutoRunServiceImpl implements AutoRunService, ApplicationAutoInitial { + @Autowired(required = false) + private List abstractAutoRunnableList; + private List autoRun_code_index = new ArrayList(); + private List threads = new ArrayList(); + private List thread_autoRun = new ArrayList(); + private List thread_code_index = new ArrayList(); + + @Override + public synchronized void startThread(String threadCode) { + Thread thread = this.getThreadByCode(threadCode); + if (thread == null) { + throw new WDKException("线程不存在"); + } else if (thread.isAlive()) { + throw new WDKException("已运行的无法开启运行"); + } else { + int index = this.thread_code_index.indexOf(threadCode); + thread = new Thread(this.getRunablebyCode(threadCode)); + this.threads.set(index, thread); + thread.start(); + } + } + + @Override + public synchronized void stopThread(String threadCode) { + Thread thread = this.getThreadByCode(threadCode); + if (thread == null) { + throw new WDKException("线程不存在"); + } else if (!thread.isAlive()) { + throw new WDKException("已停止的无法再次停止"); + } else { + AbstractAutoRunnable runable = this.getRunablebyCode(threadCode); + runable.stop(); + thread.stop(); + thread.interrupt(); + + try { + thread.join(); + } catch (InterruptedException arg4) { + arg4.printStackTrace(); + } + + runable.setStopMessage("人工停止"); + runable.setStopTime(new Date()); + } + } + + private Thread getThreadByCode(String code) { + int index = this.thread_code_index.indexOf(code); + return index < 0 ? null : (Thread) this.threads.get(index); + } + + private AbstractAutoRunnable getRunablebyCode(String code) { + int index = this.thread_code_index.indexOf(code); + return index < 0 ? null : (AbstractAutoRunnable) this.thread_autoRun.get(index); + } + + @Override + public List findAll() { + ArrayList list = new ArrayList(); + List list2 = this.getAllAutoThread(); + Iterator arg2 = list2.iterator(); + + AbstractAutoRunnable t; + ThreadDto e; + while (arg2.hasNext()) { + t = (AbstractAutoRunnable) arg2.next(); + if (ThreadUsedStatusEnum.unUsed.equals(t.getUsedStatus())) { + e = new ThreadDto(); + BeanUtil.copyProperties(t, e, true); + list.add(e); + } + } + + arg2 = this.thread_autoRun.iterator(); + + while (arg2.hasNext()) { + t = (AbstractAutoRunnable) arg2.next(); + e = new ThreadDto(); + BeanUtil.copyProperties(t, e, true); + Thread thread = this.getThreadByCode(t.getCode()); + e.setCode(t.getCode()); + e.setName(t.getName()); + + e.setThread_alive(Boolean.valueOf(thread.isAlive())); + e.setThread_name(thread.getName()); + e.setThread_id(thread.getId() + ""); + e.setThread_state(thread.getState().toString()); + list.add(e); + } + + return list; + } + + @Override + public List findByCondition(Map whereJson) { + List ori_threads = this.findAll(); + ArrayList return_threads = new ArrayList(); + if (CollectionUtil.isEmpty(whereJson)) { + return ori_threads; + } else { + Iterator it = ori_threads.iterator(); + + while (it.hasNext()) { + ThreadDto thread = (ThreadDto) it.next(); + Map properties = BeanUtil.beanToMap(thread); + + Iterator> entries = whereJson.entrySet().iterator(); + + while (entries.hasNext()) { + Map.Entry entry = entries.next(); + String column = entry.getKey(); + String value = (String) entry.getValue(); + if (properties.containsKey(column)) { + String propert = (String) properties.get(column); + + if (!StrUtil.isEmpty(propert) + && propert.contains(value)) { + return_threads.add(thread); + } + } + } + } + + return return_threads; + } + + } + + @Override + public ThreadDto findByCode(String thread_code, String thread_id) { + List ori_threads = this.findAll(); + Iterator arg3 = ori_threads.iterator(); + + ThreadDto thread; + do { + if (!arg3.hasNext()) { + return null; + } + + thread = (ThreadDto) arg3.next(); + } while (!StrUtil.equals(thread.getCode(), thread_code) + || !StrUtil.equals(thread.getThread_id(), thread_id)); + + return thread; + } + + + private List getAllAutoThread() { + return (List) (this.abstractAutoRunnableList != null && this.abstractAutoRunnableList.size() != 0 + ? this.abstractAutoRunnableList + : new LinkedList()); + } + + @Override + public void autoInitial() throws Exception { + List list = this.getAllAutoThread(); + Iterator it = list.iterator(); + + AbstractAutoRunnable t; + while (it.hasNext()) { + t = (AbstractAutoRunnable) it.next(); + t.setUsedStatus(ThreadUsedStatusEnum.unUsed); + String a; + if (StrUtil.isEmpty(t.getCode())) { + a = "code 因为空而未加载"; + log.warn(a); + t.setStopMessage(a); + this.autoRun_code_index.add(t.getCode()); + } else if (this.autoRun_code_index.contains(t.getCode())) { + a = String.format("code:%s 因为重复而未加载", new Object[]{t.getCode()}); + log.warn(a); + t.setStopMessage(a); + this.autoRun_code_index.add(t.getCode()); + } else { + t.setUsedStatus(ThreadUsedStatusEnum.used); + this.thread_autoRun.add(t); + this.autoRun_code_index.add(t.getCode()); + } + } + + it = this.thread_autoRun.iterator(); + + while (it.hasNext()) { + t = (AbstractAutoRunnable) it.next(); + this.threads.add(new Thread(t)); + this.thread_code_index.add(t.getCode()); + } + + for (int i = 0; i < this.threads.size(); ++i) { + Thread thread = (Thread) this.threads.get(i); + AbstractAutoRunnable runnable = (AbstractAutoRunnable) this.thread_autoRun.get(i); + if (runnable.getForbidStop().booleanValue()) { + thread.start(); + } else if (SystemConfig.thread_auto_run.booleanValue() && (!DevelopConfig.develop.booleanValue() + || !DevelopConfig.thread_auto_run_force_stop.contains(this.thread_code_index.get(i)))) { + thread.start(); + } + } + + } +} diff --git a/nladmin-system/src/main/java/org/nl/start/auto/run/DevelopConfig.java b/nladmin-system/src/main/java/org/nl/start/auto/run/DevelopConfig.java new file mode 100644 index 0000000..b80028f --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/start/auto/run/DevelopConfig.java @@ -0,0 +1,15 @@ +package org.nl.start.auto.run; + +import java.util.ArrayList; +import java.util.List; + +public class DevelopConfig { + //@DictionaryItem(description = "开发的选项只有当开发为true的时候才生效") + public static Boolean develop = Boolean.valueOf(true); + //@DictionaryItem(description = "强制关闭的自启动线程") + public static List thread_auto_run_force_stop = new ArrayList(); + + static { + thread_auto_run_force_stop.add("TaskFeedbackAutoRun"); + } +} diff --git a/nladmin-system/src/main/java/org/nl/start/auto/run/SystemConfig.java b/nladmin-system/src/main/java/org/nl/start/auto/run/SystemConfig.java new file mode 100644 index 0000000..4d80af3 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/start/auto/run/SystemConfig.java @@ -0,0 +1,12 @@ +package org.nl.start.auto.run; + +public class SystemConfig { + //@DictionaryItem(description = "当前系统编码与其他系统通信对接的时候需要用到此编码") + public static String system_code = "wcs10"; + // @DictionaryItem(description = "默认用户密码") + public static String default_password = "1"; + // @DictionaryItem(description = "默认序列创建初始值") + public static Integer sequence_initial_value = Integer.valueOf(1); + //@DictionaryItem(description = "主线程是否自动开启选项") + public static Boolean thread_auto_run = Boolean.valueOf(true); +} diff --git a/nladmin-system/src/main/java/org/nl/start/auto/run/ThreadDto.java b/nladmin-system/src/main/java/org/nl/start/auto/run/ThreadDto.java new file mode 100644 index 0000000..1bdffa8 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/start/auto/run/ThreadDto.java @@ -0,0 +1,134 @@ +package org.nl.start.auto.run; + +import java.util.Date; + +public class ThreadDto { + + private String code; + private String name; + private String description; + private ThreadStatusEnum status; + private ThreadUsedStatusEnum usedStatus; + private Date startTime; + private Date stopTime; + private String stopMessage; + private Boolean thread_alive; + private String thread_name; + private String thread_id; + private String thread_state; + private Boolean forbidStop = Boolean.valueOf(false); + private Boolean forbidDisable = Boolean.valueOf(false); + + public String getCode() { + return this.code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return this.description; + } + + public void setDescription(String description) { + this.description = description; + } + + public ThreadStatusEnum getStatus() { + return this.status; + } + + public void setStatus(ThreadStatusEnum status) { + this.status = status; + } + + public ThreadUsedStatusEnum getUsedStatus() { + return this.usedStatus; + } + + public void setUsedStatus(ThreadUsedStatusEnum usedStatus) { + this.usedStatus = usedStatus; + } + + public Date getStartTime() { + return this.startTime; + } + + public void setStartTime(Date startTime) { + this.startTime = startTime; + } + + public Date getStopTime() { + return this.stopTime; + } + + public void setStopTime(Date stopTime) { + this.stopTime = stopTime; + } + + public String getStopMessage() { + return this.stopMessage; + } + + public void setStopMessage(String stopMessage) { + this.stopMessage = stopMessage; + } + + public Boolean getThread_alive() { + return this.thread_alive; + } + + public void setThread_alive(Boolean thread_alive) { + this.thread_alive = thread_alive; + } + + public String getThread_name() { + return this.thread_name; + } + + public void setThread_name(String thread_name) { + this.thread_name = thread_name; + } + + public String getThread_id() { + return this.thread_id; + } + + public void setThread_id(String thread_id) { + this.thread_id = thread_id; + } + + public String getThread_state() { + return this.thread_state; + } + + public void setThread_state(String thread_state) { + this.thread_state = thread_state; + } + + public Boolean getForbidStop() { + return this.forbidStop; + } + + public void setForbidStop(Boolean forbidStop) { + this.forbidStop = forbidStop; + } + + public Boolean getForbidDisable() { + return this.forbidDisable; + } + + public void setForbidDisable(Boolean forbidDisable) { + this.forbidDisable = forbidDisable; + } + +} diff --git a/nladmin-system/src/main/java/org/nl/start/auto/run/ThreadStatusEnum.java b/nladmin-system/src/main/java/org/nl/start/auto/run/ThreadStatusEnum.java new file mode 100644 index 0000000..b660fc0 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/start/auto/run/ThreadStatusEnum.java @@ -0,0 +1,22 @@ +package org.nl.start.auto.run; + +public enum ThreadStatusEnum { + create("创建", 1), run("运行", 2), stop("停止", 3); + + private String description; + private int order; + + private ThreadStatusEnum(String name, int order) { + this.description = name; + this.order = order; + } + + public String description() { + return this.description; + } + + public int getOrder() { + return this.order; + } + +} diff --git a/nladmin-system/src/main/java/org/nl/start/auto/run/ThreadUsedStatusEnum.java b/nladmin-system/src/main/java/org/nl/start/auto/run/ThreadUsedStatusEnum.java new file mode 100644 index 0000000..e702a89 --- /dev/null +++ b/nladmin-system/src/main/java/org/nl/start/auto/run/ThreadUsedStatusEnum.java @@ -0,0 +1,23 @@ +package org.nl.start.auto.run; + +public enum ThreadUsedStatusEnum { + + used("使用", 1), unUsed("未使用", 2); + + private String description; + private int order; + + private ThreadUsedStatusEnum(String name, int order) { + this.description = name; + this.order = order; + } + + public String description() { + return this.description; + } + + public int getOrder() { + return this.order; + } + +} diff --git a/nladmin-system/src/main/resources/banner.txt b/nladmin-system/src/main/resources/banner.txt new file mode 100644 index 0000000..8be4ead --- /dev/null +++ b/nladmin-system/src/main/resources/banner.txt @@ -0,0 +1,8 @@ + _ _ ___________ _ _____ _ ___________ _____ +| \ | | _ | ___ \ | | ___| | | ___| ___|_ _| +| \| | | | | |_/ / | | |__ | | | |__ | |_ | | +| . ` | | | | ___ \ | | __|| | | __|| _| | | +| |\ \ \_/ / |_/ / |____| |___| |____| |___| | | | +\_| \_/\___/\____/\_____/\____/\_____/\____/\_| \_/ + + :: Spring Boot :: (v2.1.0.RELEASE) \ No newline at end of file diff --git a/nladmin-system/src/main/resources/config/application-dev.yml b/nladmin-system/src/main/resources/config/application-dev.yml new file mode 100644 index 0000000..17a3b0a --- /dev/null +++ b/nladmin-system/src/main/resources/config/application-dev.yml @@ -0,0 +1,135 @@ +server: + port: 8010 +#配置数据源 +spring: + datasource: + druid: + db-type: com.alibaba.druid.pool.DruidDataSource + driverClassName: net.sf.log4jdbc.sql.jdbcapi.DriverSpy + url: jdbc:log4jdbc:mysql://${DB_HOST:192.168.137.41}:${DB_PORT:3306}/${DB_NAME:agv}?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&useOldAliasMetadataBehavior=true&allowPublicKeyRetrieval=true&useSSL=false + username: ${DB_USER:generallu} + password: ${DB_PWD:123456} + ##password: ${DB_PWD:root} + # 初始连接数 + initial-size: 5 + # 最小连接数 + min-idle: 20 + # 最大连接数 + max-active: 50 + # 是否自动回收超时连接 + remove-abandoned: true + # 超时时间(以秒数为单位) + remove-abandoned-timeout: 180 + # 获取连接超时时间 + max-wait: 3000 + # 连接有效性检测时间 + time-between-eviction-runs-millis: 60000 + # 连接在池中最小生存的时间 + min-evictable-idle-time-millis: 300000 + # 连接在池中最大生存的时间 + max-evictable-idle-time-millis: 900000 + # 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除 + test-while-idle: true + # 指明是否在从池中取出连接前进行检验,如果检验失败, 则从池中去除连接并尝试取出另一个 + test-on-borrow: true + # 是否在归还到池中前进行检验 + test-on-return: false + # 检测连接是否有效 + validation-query: select 1 + # 配置监控统计 + webStatFilter: + enabled: true + stat-view-servlet: + enabled: true + url-pattern: /druid/* + reset-enable: false + filter: + stat: + enabled: true + # 记录慢SQL + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: true + wall: + config: + multi-statement-allow: true + redis: + #数据库索引 + database: ${REDIS_DB:10} + host: ${REDIS_HOST:localhost} + #host: ${REDIS_HOST:47.97.157.227} + port: ${REDIS_PORT:6379} + password: ${REDIS_PWD:} + #连接超时时间 + timeout: 5000 +# 登录相关配置 +login: + # 登录缓存 + cache-enable: true + # 是否限制单用户登录 + single-login: false + # 验证码 + login-code: + # 验证码类型配置 查看 LoginProperties 类 + code-type: arithmetic + # 登录图形验证码有效时间/分钟 + expiration: 2 + # 验证码高度 + width: 111 + # 验证码宽度 + heigth: 36 + # 内容长度 + length: 2 + # 字体名称,为空则使用默认字体 + font-name: + # 字体大小 + font-size: 25 + +#jwt +jwt: + header: Authorization + # 令牌前缀 + token-start-with: Bearer + # 必须使用最少88位的Base64对该令牌进行编码 + base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI= + # 令牌过期时间 此处单位/毫秒 ,默认4小时,可在此网站生成 https://www.convertworld.com/zh-hans/time/milliseconds.html + token-validity-in-seconds: 14400000 + # 在线用户key + online-key: online-token- + # 验证码 + code-key: code-key- + # token 续期检查时间范围(默认30分钟,单位毫秒),在token即将过期的一段时间内用户操作了,则给用户的token续期 + detect: 1800000 + # 续期时间范围,默认1小时,单位毫秒 + renew: 3600000 + +#是否允许生成代码,生产环境设置为false +generator: + enabled: true + +#是否开启 swagger-ui +swagger: + enabled: true + +# IP 本地解析 +ip: + local-parsing: true + +# 文件存储路径 +file: + mac: + path: ~/file/ + avatar: ~/avatar/ + linux: + path: /home/eladmin/file/ + avatar: /home/eladmin/avatar/ + windows: + path: C:\eladmin\file\ + avatar: C:\eladmin\avatar\ + # 文件大小 /M + maxSize: 100 + avatarMaxSize: 5 +logging: + file: + path: C:\logs\nlagv\ + diff --git a/nladmin-system/src/main/resources/config/application-prod.yml b/nladmin-system/src/main/resources/config/application-prod.yml new file mode 100644 index 0000000..c72222a --- /dev/null +++ b/nladmin-system/src/main/resources/config/application-prod.yml @@ -0,0 +1,140 @@ +server: + port: 8010 +#配置数据源 +spring: + datasource: + druid: + db-type: com.alibaba.druid.pool.DruidDataSource + driverClassName: net.sf.log4jdbc.sql.jdbcapi.DriverSpy + url: jdbc:log4jdbc:mysql://${DB_HOST:192.168.137.41}:${DB_PORT:3306}/${DB_NAME:agv}?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&useOldAliasMetadataBehavior=true + username: ${DB_USER:generallu} + password: ${DB_PWD:123456} + # 初始连接数 + initial-size: 5 + # 最小连接数 + min-idle: 15 + # 最大连接数 + max-active: 30 + # 获取连接超时时间 + max-wait: 5000 + # 连接有效性检测时间 + time-between-eviction-runs-millis: 60000 + # 连接在池中最小生存的时间 + min-evictable-idle-time-millis: 300000 + # 连接在池中最大生存的时间 + max-evictable-idle-time-millis: 900000 + # 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除 + test-while-idle: true + # 指明是否在从池中取出连接前进行检验,如果检验失败, 则从池中去除连接并尝试取出另一个 + test-on-borrow: true + # 是否在归还到池中前进行检验 + test-on-return: false + # 检测连接是否有效 + validation-query: select 1 + # 配置监控统计 + webStatFilter: + enabled: true + stat-view-servlet: + enabled: true + # 控制台管理用户名和密码 + url-pattern: /druid/* + reset-enable: false + login-username: admin + login-password: 123456 + filter: + stat: + enabled: true + # 记录慢SQL + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: true + wall: + config: + multi-statement-allow: true + redis: + #数据库索引 + database: ${REDIS_DB:10} + #host: ${REDIS_HOST:47.97.157.227} + host: ${REDIS_HOST:localhost} + port: ${REDIS_PORT:6379} + password: ${REDIS_PWD:} + #连接超时时间 + timeout: 5000 +# 登录相关配置 +login: + # 登录缓存 + cache-enable: true + # 是否限制单用户登录 + single-login: false + # 验证码 + login-code: + # 验证码类型配置 查看 LoginProperties 类 + code-type: arithmetic + # 登录图形验证码有效时间/分钟 + expiration: 2 + # 验证码高度 + width: 111 + # 验证码宽度 + heigth: 36 + # 内容长度 + length: 2 + # 字体名称,为空则使用默认字体,如遇到线上乱码,设置其他字体即可 + font-name: + # 字体大小 + font-size: 25 + +#jwt +jwt: + header: Authorization + # 令牌前缀 + token-start-with: Bearer + # 必须使用最少88位的Base64对该令牌进行编码 + base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI= + # 令牌过期时间 此处单位/毫秒 ,默认2小时,可在此网站生成 https://www.convertworld.com/zh-hans/time/milliseconds.html + token-validity-in-seconds: 7200000 + # 在线用户key + online-key: online-token- + # 验证码 + code-key: code-key- + # token 续期检查时间范围(默认30分钟,单位默认毫秒),在token即将过期的一段时间内用户操作了,则给用户的token续期 + detect: 1800000 + # 续期时间范围,默认 1小时,这里单位毫秒 + renew: 3600000 + +# IP 本地解析 +ip: + local-parsing: true + +#是否允许生成代码,生产环境设置为false +generator: + enabled: false + +#如果生产环境要开启swagger,需要配置请求地址 +#springfox: +# documentation: +# swagger: +# v2: +# host: # 接口域名或外网ip + +#是否开启 swagger-ui +swagger: + enabled: false + +# 文件存储路径 +file: + mac: + path: ~/file/ + avatar: ~/avatar/ + linux: + path: /home/eladmin/file/ + avatar: /home/eladmin/avatar/ + windows: + path: C:\eladmin\file\ + avatar: C:\eladmin\avatar\ + # 文件大小 /M + maxSize: 100 + avatarMaxSize: 5 +logging: + file: + path: /home/generallu/app/log + config: classpath:logback-spring.xml \ No newline at end of file diff --git a/nladmin-system/src/main/resources/config/application.yml b/nladmin-system/src/main/resources/config/application.yml new file mode 100644 index 0000000..889ab87 --- /dev/null +++ b/nladmin-system/src/main/resources/config/application.yml @@ -0,0 +1,44 @@ +spring: + freemarker: + check-template-location: false + profiles: + active: prod + jackson: + time-zone: GMT+8 + data: + redis: + repositories: + enabled: false + + #配置 Jpa + jpa: + hibernate: + ddl-auto: none + open-in-view: true + properties: + hibernate: + dialect: org.hibernate.dialect.MySQL5InnoDBDialect +task: + pool: + # 核心线程池大小 + core-pool-size: 10 + # 最大线程数 + max-pool-size: 30 + # 活跃时间 + keep-alive-seconds: 60 + # 队列容量 + queue-capacity: 50 + +#七牛云 +qiniu: + # 文件大小 /M + max-size: 15 + +#邮箱验证码有效时间/秒 +code: + expiration: 300 + +#密码加密传输,前端公钥加密,后端私钥解密 +rsa: + private_key: MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A== + diff --git a/nladmin-system/src/main/resources/generator.properties b/nladmin-system/src/main/resources/generator.properties new file mode 100644 index 0000000..2ed9370 --- /dev/null +++ b/nladmin-system/src/main/resources/generator.properties @@ -0,0 +1,27 @@ +#数据库类型转Java类型 +tinyint=Integer +smallint=Integer +mediumint=Integer +int=Integer +integer=Integer + +bigint=Long + +float=Float + +double=Double + +decimal=BigDecimal + +bit=Boolean + +char=String +varchar=String +tinytext=String +text=String +mediumtext=String +longtext=String + +date=Timestamp +datetime=Timestamp +timestamp=Timestamp \ No newline at end of file diff --git a/nladmin-system/src/main/resources/ip2region/ip2region.db b/nladmin-system/src/main/resources/ip2region/ip2region.db new file mode 100644 index 0000000..43e1daf Binary files /dev/null and b/nladmin-system/src/main/resources/ip2region/ip2region.db differ diff --git a/nladmin-system/src/main/resources/log4jdbc.log4j2.properties b/nladmin-system/src/main/resources/log4jdbc.log4j2.properties new file mode 100644 index 0000000..302525f --- /dev/null +++ b/nladmin-system/src/main/resources/log4jdbc.log4j2.properties @@ -0,0 +1,4 @@ +# If you use SLF4J. First, you need to tell log4jdbc-log4j2 that you want to use the SLF4J logger +log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator +log4jdbc.auto.load.popular.drivers=false +log4jdbc.drivers=com.mysql.cj.jdbc.Driver \ No newline at end of file diff --git a/nladmin-system/src/main/resources/logback-spring.xml b/nladmin-system/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..ba766fc --- /dev/null +++ b/nladmin-system/src/main/resources/logback-spring.xml @@ -0,0 +1,85 @@ + + + + + nlAdmin + + + + + + + + + + ${log.pattern} + ${log.charset} + + + + + + + + + + ${LOG_HOME}/%d{yyyy-MM-dd}.%i.log + + 15 + + 200MB + + 20GB + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + + + + + + + 0 + 500 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nladmin-system/src/main/resources/logback2.xml b/nladmin-system/src/main/resources/logback2.xml new file mode 100644 index 0000000..ae87c72 --- /dev/null +++ b/nladmin-system/src/main/resources/logback2.xml @@ -0,0 +1,106 @@ + + + nlAdmin + + + + + + + + + + + + ${LOG_HOME}/%d{yyyy-MM-dd}.log + + 30 + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + + + + 20MB + + + + + + + + + ${LOG_HOME}/%d{yyyy-MM-dd}.log + + 30 + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + + + + 20MB + + + + + + + ${log.pattern} + ${log.charset} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nladmin-system/src/main/resources/template/email/email.ftl b/nladmin-system/src/main/resources/template/email/email.ftl new file mode 100644 index 0000000..2f82fcb --- /dev/null +++ b/nladmin-system/src/main/resources/template/email/email.ftl @@ -0,0 +1,48 @@ + + + + + + + +
+
+

尊敬的用户,您好:

+

您正在申请邮箱验证,您的验证码为:

+

${code}

+
+
+
+ Copyright ©${.now?string("yyyy")} EL-ADMIN 后台管理系统 All Rights Reserved. +
+ +
+
+ + diff --git a/nladmin-system/src/main/resources/template/email/taskAlarm.ftl b/nladmin-system/src/main/resources/template/email/taskAlarm.ftl new file mode 100644 index 0000000..b116dec --- /dev/null +++ b/nladmin-system/src/main/resources/template/email/taskAlarm.ftl @@ -0,0 +1,69 @@ + + + + + + + +
+
+

任务信息:

+ + + + + + + + + + + + + + + + + +
任务名称Bean名称执行方法参数内容Cron表达式描述内容
${task.jobName}${task.beanName}${task.methodName}${(task.params)!""}${task.cronExpression}${(task.description)!""}
+
+
+

异常信息:

+
+                ${msg}
+            
+
+
+
+
+ Copyright ©${.now?string("yyyy")} EL-ADMIN 后台管理系统 All Rights Reserved. +
+ +
+ + + diff --git a/nladmin-system/src/main/resources/template/generator/admin/Controller.ftl b/nladmin-system/src/main/resources/template/generator/admin/Controller.ftl new file mode 100644 index 0000000..1083933 --- /dev/null +++ b/nladmin-system/src/main/resources/template/generator/admin/Controller.ftl @@ -0,0 +1,76 @@ + +package ${package}.rest; + + +import ${package}.service.dto.${className}Dto; +import ${package}.service.${className}Service; +import org.springframework.data.domain.Pageable; +import lombok.RequiredArgsConstructor; +import org.nl.annotation.Log; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import io.swagger.annotations.*; +import java.io.IOException; +import javax.servlet.http.HttpServletResponse; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; + +/** +* @author ${author} +* @date ${date} +**/ +@RestController +@RequiredArgsConstructor +@Api(tags = "${apiAlias}管理") +@RequestMapping("/api/${changeClassName}") +@Slf4j +public class ${className}Controller { + + private final ${className}Service ${changeClassName}Service; + + @GetMapping + @Log("查询${apiAlias}") + @ApiOperation("查询${apiAlias}") + //@PreAuthorize("@el.check('${changeClassName}:list')") + public ResponseEntity query(@RequestParam Map whereJson, Pageable page){ + return new ResponseEntity<>(${changeClassName}Service.queryAll(whereJson,page),HttpStatus.OK); + } + + @PostMapping + @Log("新增${apiAlias}") + @ApiOperation("新增${apiAlias}") + //@PreAuthorize("@el.check('${changeClassName}:add')") + public ResponseEntity create(@Validated @RequestBody ${className}Dto dto){ + ${changeClassName}Service.create(dto); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @PutMapping + @Log("修改${apiAlias}") + @ApiOperation("修改${apiAlias}") + //@PreAuthorize("@el.check('${changeClassName}:edit')") + public ResponseEntity update(@Validated @RequestBody ${className}Dto dto){ + ${changeClassName}Service.update(dto); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除${apiAlias}") + @ApiOperation("删除${apiAlias}") + //@PreAuthorize("@el.check('${changeClassName}:del')") + @DeleteMapping + public ResponseEntity delete(@RequestBody ${pkColumnType}[] ids) { + ${changeClassName}Service.deleteAll(ids); + return new ResponseEntity<>(HttpStatus.OK); + } + + @Log("导出${apiAlias}") + @ApiOperation("导出${apiAlias}") + @GetMapping(value = "/download") + //@PreAuthorize("@el.check('${changeClassName}:list')") + public void download(HttpServletResponse response, Map whereJson) throws IOException { + ${changeClassName}Service.download(${changeClassName}Service.queryAll(whereJson), response); + } +} diff --git a/nladmin-system/src/main/resources/template/generator/admin/Dto.ftl b/nladmin-system/src/main/resources/template/generator/admin/Dto.ftl new file mode 100644 index 0000000..edfadda --- /dev/null +++ b/nladmin-system/src/main/resources/template/generator/admin/Dto.ftl @@ -0,0 +1,38 @@ +package ${package}.service.dto; + +import lombok.Data; +<#if hasTimestamp> + import java.sql.Timestamp; + +<#if hasBigDecimal> + import java.math.BigDecimal; + +import java.io.Serializable; +<#if !auto && pkColumnType = 'Long'> + import com.fasterxml.jackson.databind.annotation.JsonSerialize; + import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; + + +/** +* @description / +* @author ${author} +* @date ${date} +**/ +@Data +public class ${className}Dto implements Serializable { +<#if columns??> + <#list columns as column> + + <#if column.remark != ''> + /** ${column.remark} */ + + <#if column.columnKey = 'PRI'> + <#if !auto && pkColumnType = 'Long'> + /** 防止精度丢失 */ + @JsonSerialize(using= ToStringSerializer.class) + + + private ${column.columnType} ${column.changeColumnName}; + + +} diff --git a/nladmin-system/src/main/resources/template/generator/admin/Entity.ftl b/nladmin-system/src/main/resources/template/generator/admin/Entity.ftl new file mode 100644 index 0000000..347e729 --- /dev/null +++ b/nladmin-system/src/main/resources/template/generator/admin/Entity.ftl @@ -0,0 +1,69 @@ +package ${package}.domain; + +import lombok.Data; +import cn.hutool.core.bean.BeanUtil; +import io.swagger.annotations.ApiModelProperty; +import cn.hutool.core.bean.copier.CopyOptions; +import javax.persistence.*; +<#if isNotNullColumns??> + import javax.validation.constraints.*; + +<#if hasDateAnnotation> + import javax.persistence.Entity; + import javax.persistence.Table; + import org.hibernate.annotations.*; + +<#if hasTimestamp> + import java.sql.Timestamp; + +<#if hasBigDecimal> + import java.math.BigDecimal; + +import java.io.Serializable; + +/** +* @description / +* @author ${author} +* @date ${date} +**/ +@Entity +@Data +@Table(name="${tableName}") +public class ${className} implements Serializable { +<#if columns??> + <#list columns as column> + + <#if column.columnKey = 'PRI'> + @Id + <#if auto> + @GeneratedValue(strategy = GenerationType.IDENTITY) + + + @Column(name = "${column.columnName}"<#if column.columnKey = 'UNI'>,unique = true<#if column.istNotNull && column.columnKey != 'PRI'>,nullable = false) + <#if column.istNotNull && column.columnKey != 'PRI'> + <#if column.columnType = 'String'> + @NotBlank + <#else> + @NotNull + + + <#if (column.dateAnnotation)?? && column.dateAnnotation != ''> + <#if column.dateAnnotation = 'CreationTimestamp'> + @CreationTimestamp + <#else> + @UpdateTimestamp + + + <#if column.remark != ''> + @ApiModelProperty(value = "${column.remark}") + <#else> + @ApiModelProperty(value = "${column.changeColumnName}") + + private ${column.columnType} ${column.changeColumnName}; + + + +public void copy(${className} source){ +BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true)); +} +} diff --git a/nladmin-system/src/main/resources/template/generator/admin/Mapper.ftl b/nladmin-system/src/main/resources/template/generator/admin/Mapper.ftl new file mode 100644 index 0000000..2386841 --- /dev/null +++ b/nladmin-system/src/main/resources/template/generator/admin/Mapper.ftl @@ -0,0 +1,17 @@ +package ${package}.service.mapstruct; + +import BaseMapper; +import ${package}.domain.${className}; +import ${package}.service.dto.${className}Dto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @website https://el-admin.vip +* @author ${author} +* @date ${date} +**/ +@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface ${className}Mapper extends BaseMapper<${className}Dto, ${className}> { + +} diff --git a/nladmin-system/src/main/resources/template/generator/admin/QueryCriteria.ftl b/nladmin-system/src/main/resources/template/generator/admin/QueryCriteria.ftl new file mode 100644 index 0000000..0ba4c80 --- /dev/null +++ b/nladmin-system/src/main/resources/template/generator/admin/QueryCriteria.ftl @@ -0,0 +1,66 @@ + +package ${package}.service.dto; + +import lombok.Data; +<#if queryHasTimestamp> +import java.sql.Timestamp; + +<#if queryHasBigDecimal> +import java.math.BigDecimal; + +<#if betweens??> +import java.util.List; + +<#if queryColumns??> +import Query; + + +/** +* @author ${author} +* @date ${date} +**/ +@Data +public class ${className}QueryCriteria{ +<#if queryColumns??> + <#list queryColumns as column> + +<#if column.queryType = '='> + /** 精确 */ + @Query + private ${column.columnType} ${column.changeColumnName}; + +<#if column.queryType = 'Like'> + /** 模糊 */ + @Query(type = Query.Type.INNER_LIKE) + private ${column.columnType} ${column.changeColumnName}; + +<#if column.queryType = '!='> + /** 不等于 */ + @Query(type = Query.Type.NOT_EQUAL) + private ${column.columnType} ${column.changeColumnName}; + +<#if column.queryType = 'NotNull'> + /** 不为空 */ + @Query(type = Query.Type.NOT_NULL) + private ${column.columnType} ${column.changeColumnName}; + +<#if column.queryType = '>='> + /** 大于等于 */ + @Query(type = Query.Type.GREATER_THAN) + private ${column.columnType} ${column.changeColumnName}; + +<#if column.queryType = '<='> + /** 小于等于 */ + @Query(type = Query.Type.LESS_THAN) + private ${column.columnType} ${column.changeColumnName}; + + + +<#if betweens??> + <#list betweens as column> + /** BETWEEN */ + @Query(type = Query.Type.BETWEEN) + private List<${column.columnType}> ${column.changeColumnName}; + + +} diff --git a/nladmin-system/src/main/resources/template/generator/admin/Repository.ftl b/nladmin-system/src/main/resources/template/generator/admin/Repository.ftl new file mode 100644 index 0000000..0ce13b2 --- /dev/null +++ b/nladmin-system/src/main/resources/template/generator/admin/Repository.ftl @@ -0,0 +1,25 @@ + +package ${package}.repository; + +import ${package}.domain.${className}; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** +* @author ${author} +* @date ${date} +**/ +public interface ${className}Repository extends JpaRepository<${className}, ${pkColumnType}>, JpaSpecificationExecutor<${className}> { +<#if columns??> + <#list columns as column> + <#if column.columnKey = 'UNI'> + /** + * 根据 ${column.capitalColumnName} 查询 + * @param ${column.columnName} / + * @return / + */ + ${className} findBy${column.capitalColumnName}(${column.columnType} ${column.columnName}); + + + +} diff --git a/nladmin-system/src/main/resources/template/generator/admin/Service.ftl b/nladmin-system/src/main/resources/template/generator/admin/Service.ftl new file mode 100644 index 0000000..8776eec --- /dev/null +++ b/nladmin-system/src/main/resources/template/generator/admin/Service.ftl @@ -0,0 +1,73 @@ + +package ${package}.service; + +import ${package}.service.dto.${className}Dto; +import org.springframework.data.domain.Pageable; +import java.util.Map; +import java.util.List; +import java.io.IOException; +import javax.servlet.http.HttpServletResponse; + +/** +* @description 服务接口 +* @author ${author} +* @date ${date} +**/ +public interface ${className}Service { + + /** + * 查询数据分页 + * @param whereJson 条件 + * @param page 分页参数 + * @return Map + */ + Map queryAll(Map whereJson, Pageable page); + + /** + * 查询所有数据不分页 + * @param whereJson 条件参数 + * @return List<${className}Dto> + */ + List<${className}Dto> queryAll(Map whereJson); + + /** + * 根据ID查询 + * @param ${pkChangeColName} ID + * @return ${className} + */ + ${className}Dto findById(${pkColumnType} ${pkChangeColName}); + + /** + * 根据编码查询 + * @param code code + * @return ${className} + */ + ${className}Dto findByCode(String code); + + + /** + * 创建 + * @param dto / + */ + void create(${className}Dto dto); + + /** + * 编辑 + * @param dto / + */ + void update(${className}Dto dto); + + /** + * 多选删除 + * @param ids / + */ + void deleteAll(${pkColumnType}[] ids); + + /** + * 导出数据 + * @param dtos 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List<${className}Dto> dtos, HttpServletResponse response) throws IOException; +} diff --git a/nladmin-system/src/main/resources/template/generator/admin/ServiceImpl.ftl b/nladmin-system/src/main/resources/template/generator/admin/ServiceImpl.ftl new file mode 100644 index 0000000..a6f195b --- /dev/null +++ b/nladmin-system/src/main/resources/template/generator/admin/ServiceImpl.ftl @@ -0,0 +1,134 @@ + +package ${package}.service.impl; + + +import lombok.RequiredArgsConstructor; +import ${package}.domain.${className}; +import ${package}.service.${className}Service; +import ${package}.service.dto.${className}Dto; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import org.springframework.data.domain.Pageable; +import java.util.List; +import java.util.Map; +import java.io.IOException; +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.LinkedHashMap; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.bean.BeanUtil; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; +import org.nl.utils.SecurityUtils; +import org.nl.wql.core.bean.ResultBean; +import org.nl.wql.core.bean.WQLObject; +import org.nl.wql.util.WqlUtil; +import org.nl.utils.FileUtil; +import lombok.extern.slf4j.Slf4j; + +/** +* @description 服务实现 +* @author ${author} +* @date ${date} +**/ +@Service +@RequiredArgsConstructor +@Slf4j +public class ${className}ServiceImpl implements ${className}Service { + + @Override + public Map queryAll(Map whereJson, Pageable page){ + WQLObject wo = WQLObject.getWQLObject("${tableName}"); + ResultBean rb = wo.pagequery(WqlUtil.getHttpContext(page), "", "update_time desc"); + final JSONObject json = rb.pageResult(); + return json; + } + + @Override + public List<${className}Dto> queryAll(Map whereJson){ + WQLObject wo = WQLObject.getWQLObject("${tableName}"); + JSONArray arr = wo.query().getResultJSONArray(0); + List<${className}Dto> list = JSONArray.toList(arr, ${className}Dto.class); + return list; + } + + @Override + public ${className}Dto findById(${pkColumnType} ${pkChangeColName}) { + WQLObject wo = WQLObject.getWQLObject("${tableName}"); + JSONObject json = wo.query("${pkChangeColName} ='" + ${pkChangeColName} + "'").uniqueResult(0); + final ${className}Dto obj = (${className}Dto) JSONObject.toBean(json, ${className}Dto.class); + return obj; + } + + @Override + public ${className}Dto findByCode(String code) { + WQLObject wo = WQLObject.getWQLObject("${tableName}"); + JSONObject json = wo.query("code ='" + code + "'").uniqueResult(0); + final ${className}Dto obj = (${className}Dto) JSONObject.toBean(json, ${className}Dto.class); + return obj; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(${className}Dto dto) { + String currentUsername = SecurityUtils.getCurrentUsername(); + String now = DateUtil.now(); + + dto.set${pkChangeColName}(IdUtil.simpleUUID()); + dto.setCreate_by(currentUsername); + dto.setUpdate_by(currentUsername); + dto.setUpdate_time(now); + dto.setCreate_time(now); + + WQLObject wo = WQLObject.getWQLObject("${tableName}"); + JSONObject json=JSONObject.fromObject(dto); + wo.insert(json); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(${className}Dto dto) { + ${className}Dto entity = this.findById(dto.getId()); + if (entity == null) throw new BadRequestException("被删除或无权限,操作失败!"); + + String currentUsername = SecurityUtils.getCurrentUsername(); + String now = DateUtil.now(); + dto.setUpdate_time(now); + dto.setUpdate_by(currentUsername); + + WQLObject wo = WQLObject.getWQLObject("${tableName}"); + JSONObject json=JSONObject.fromObject(dto); + wo.update(json); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteAll(${pkColumnType}[] ids) { + WQLObject wo = WQLObject.getWQLObject("${tableName}"); + for (${pkColumnType} ${pkChangeColName}: ids) { + wo.delete("${pkChangeColName} = '" + ${pkChangeColName} + "'"); + } + } + + @Override + public void download(List<${className}Dto> all, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (${className}Dto ${changeClassName} : all) { + Map map = new LinkedHashMap<>(); +<#list columns as column> +<#if column.columnKey != 'PRI'> + <#if column.remark != ''> + map.put("${column.remark}", ${changeClassName}.get${column.changeColumnName ? cap_first}()); + <#else> + map.put("${column.changeColumnName}", ${changeClassName}.get${column.changeColumnName ? cap_first}()); + + + + list.add(map); + } + FileUtil.downloadExcel(list, response); + } +} diff --git a/nladmin-system/src/main/resources/template/generator/front/api.ftl b/nladmin-system/src/main/resources/template/generator/front/api.ftl new file mode 100644 index 0000000..9587d0d --- /dev/null +++ b/nladmin-system/src/main/resources/template/generator/front/api.ftl @@ -0,0 +1,27 @@ +import request from '@/utils/request' + +export function add(data) { + return request({ + url: 'api/${changeClassName}', + method: 'post', + data + }) +} + +export function del(ids) { + return request({ + url: 'api/${changeClassName}/', + method: 'delete', + data: ids + }) +} + +export function edit(data) { + return request({ + url: 'api/${changeClassName}', + method: 'put', + data + }) +} + +export default { add, edit, del } diff --git a/nladmin-system/src/main/resources/template/generator/front/index.ftl b/nladmin-system/src/main/resources/template/generator/front/index.ftl new file mode 100644 index 0000000..9307821 --- /dev/null +++ b/nladmin-system/src/main/resources/template/generator/front/index.ftl @@ -0,0 +1,175 @@ +<#--noinspection ALL--> + + + + + diff --git a/nladmin-system/src/main/resources/test.xml b/nladmin-system/src/main/resources/test.xml new file mode 100644 index 0000000..88b4f47 --- /dev/null +++ b/nladmin-system/src/main/resources/test.xml @@ -0,0 +1,28 @@ + + + + + + + + + ${LOG_HOME}/AutoCreateInst/%d{yyyy-MM-dd}.%i.log + + 15 + + 200MB + + 20GB + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + + + + + + + diff --git a/nladmin-system/src/test/java/ros/Test2.java b/nladmin-system/src/test/java/ros/Test2.java new file mode 100644 index 0000000..3d87257 --- /dev/null +++ b/nladmin-system/src/test/java/ros/Test2.java @@ -0,0 +1,93 @@ +package ros; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.HexUtil; +import cn.hutool.setting.SettingUtil; +import com.mchange.v1.util.SetUtils; +import edu.wpi.rail.jrosbridge.Ros; +import edu.wpi.rail.jrosbridge.Service; +import edu.wpi.rail.jrosbridge.Topic; +import edu.wpi.rail.jrosbridge.callback.TopicCallback; +import edu.wpi.rail.jrosbridge.messages.Message; +import edu.wpi.rail.jrosbridge.services.ServiceRequest; +import edu.wpi.rail.jrosbridge.services.ServiceResponse; +import net.sf.json.JSON; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; +import org.apache.commons.collections.list.SetUniqueList; +import org.nl.agv.unit.sendToAgvUtil; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; +import java.util.function.BiConsumer; + +public class Test2 { + + public static void main(String[] args) { + // Ros ros = new Ros("192.168.137.41", 9290); + Ros ros = new Ros("192.168.137.41", 9290); + ros.connect(); + Service addTwoInts = new Service(ros, "/Service_HMIString", "lu_ps20l_msgs/Srv_HMIString"); + JSONObject json = new JSONObject(); + //IFCONFIG + json.put("HMI_String_Input", "HMIStepOrRTPathFollow:0;18;1#"); + //日志列表 + //json.put("HMI_String_Input", "GetLogList"); + //ros请求列表 + //json.put("HMI_String_Input", "GetROSNodeList"); + //芯片温度 + //json.put("HMI_String_Input", "Temperature"); + //获取站点(刘先源写正则表达式) + //json.put("HMI_String_Input", "GetStationFloorIndexTable"); + //获取坐标(第二个) + //json.put("HMI_String_Input", "GetNodePointManagerTable"); + ServiceRequest request = new ServiceRequest(json.toString()); + ServiceResponse response = addTwoInts.callServiceAndWait(request); + System.out.println(response.toString()); + ros.disconnect(); + } + + public static void main9090(String[] args) { + //调试信息 + Ros ros = new Ros("192.168.0.40", 9290); + ros.connect(); + while (true) { + Topic echoBack = new Topic(ros, "/Topic_Display_State", "lu_ps20l_msgs/Msg_DisplayState"); + echoBack.subscribe(new TopicCallback() { + @Override + public void handleMessage(Message message) { + JSONObject jo = JSONObject.fromObject(message.toString()); + System.out.println(message.toString()); + } + }); + } + } + + public static void main132(String[] args) { + ServiceResponse response = sendToAgvUtil.send("GetStationFloorIndexTable"); + String result_info = response.toString(); + String a = JSONObject.fromObject(response.toString()).optString("ROS_String_Output"); + String[] split = a.split("\\n"); + JSONObject json = new JSONObject(); + for (int i = 0; i < split.length; i++) { + String row = split[i]; + String[] rowArr = row.split("\\s+"); + json.put(rowArr[3], rowArr[4].contains("<") ? "" : rowArr[4]); + } + JSONArray arr = new JSONArray(); + for (Object key : json.keySet()) { + String value = (String) json.get(key); + System.out.println("Key = " + key + ", Value = " + value); + JSONObject row = new JSONObject(); + row.put("point_code", key); + row.put("point_name", value); + arr.add(row); + } + System.out.println(arr); + } + + + + +} diff --git a/nladmin-system/src/test/java/ros/Test3.java b/nladmin-system/src/test/java/ros/Test3.java new file mode 100644 index 0000000..b581715 --- /dev/null +++ b/nladmin-system/src/test/java/ros/Test3.java @@ -0,0 +1,55 @@ +package ros; + +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpUtil; +import net.sf.json.JSONObject; + +public class Test3 { + public static void main123(String[] args) { + String url = "http://192.168.0.40:9999"; + JSONObject json = new JSONObject(); + json.put("msg_js_can", "0x101|0x10,0x01,0x04,0x00,0x00,0x00,0x00,0x00"); + json.put("srv_HMIString", "GetIP"); + + String resultMsg = HttpRequest.post(url) + .body(String.valueOf(json)) + .execute().body(); + JSONObject result = JSONObject.fromObject(resultMsg); + System.out.println("111"); + } + public static void main111(String[] args) { + String url = "http://192.168.137.41:9290"; + JSONObject json = new JSONObject(); + json.put("msg_js_can", "0x101|0x10,0x01,0x04,0x00,0x01,0x00,0x00,0x00"); + // json.put("srv_HMIString", "GetIP"); + + while (true){ + String resultMsg = HttpRequest.post(url) + .body(String.valueOf(json)) + .execute().body(); + // JSONObject result = JSONObject.fromObject(resultMsg); + System.out.println(resultMsg); + } + + } + + public static void main234(String[] args) { + String url = "http://192.168.137.41:9999"; + String result1= HttpUtil.get(url); + System.out.println(result1); + JSONObject json = JSONObject.fromObject(result1); + JSONObject jo=JSONObject.fromObject(json.optString("Msg_DisplayState")); + System.out.println( jo.optString("AGV_ID")); + System.out.println( jo.getJSONObject("header").getJSONObject("stamp").optString("sec")); + + } + + public static void main(String[] args) { + int a = 258; + if ((258>>8)%2==1){ + System.out.println("有异常"); + } + System.out.println("测试完毕"); + } + +} diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..5d155f3 --- /dev/null +++ b/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + + org.nl + jt_agv + pom + 1.0-SNAPSHOT + 开发平台 + + nladmin + org.nl + 2.6 + + + + nladmin-system + + + + +