From 3bdd789335a0eb4f30dc4aaf03bc906a8d0e7427 Mon Sep 17 00:00:00 2001 From: pcm Date: Fri, 8 Nov 2024 16:53:23 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9Elog=E8=84=B1=E6=95=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- springboot-log/README.md | 43 +++ springboot-log/build-dev.bat | 1 + springboot-log/build-dev.xml | 55 +++ springboot-log/db/pcm.sql | 42 +++ springboot-log/easycode/EasyCodeConfig.json | 155 +++++++++ springboot-log/git-info.bat | 13 + springboot-log/pom.xml | 237 +++++++++++++ .../src/main/java/com/pancm/Application.java | 40 +++ .../java/com/pancm/config/CorsFilter.java | 49 +++ .../pancm/config/DemoDefenderStrategy.java | 24 ++ .../com/pancm/config/PancmConfiguration.java | 120 +++++++ .../main/java/com/pancm/config/PluginOne.java | 17 + .../com/pancm/config/SpringBeanFactory.java | 50 +++ .../java/com/pancm/config/SwaggerConfig.java | 64 ++++ .../com/pancm/controller/HomeController.java | 53 +++ .../pancm/controller/TSysUserController.java | 103 ++++++ .../com/pancm/controller/UserController.java | 103 ++++++ .../main/java/com/pancm/dao/TSysUserDao.java | 87 +++++ .../src/main/java/com/pancm/dao/UserDao.java | 88 +++++ .../pancm/enums/SimpleDefenderStrategy.java | 24 ++ .../main/java/com/pancm/model/TSysUser.java | 61 ++++ .../src/main/java/com/pancm/model/User.java | 71 ++++ .../com/pancm/service/ITSysUserService.java | 62 ++++ .../java/com/pancm/service/IUserService.java | 60 ++++ .../service/impl/TSysUserServiceImpl.java | 97 ++++++ .../pancm/service/impl/UserServiceImpl.java | 96 ++++++ .../main/java/com/pancm/util/FileHelper.java | 321 ++++++++++++++++++ .../java/com/pancm/util/GetProperties.java | 94 +++++ .../src/main/java/com/pancm/vo/ApiResult.java | 92 +++++ .../main/java/com/pancm/vo/BaseConstants.java | 42 +++ .../src/main/java/com/pancm/vo/BasePage.java | 74 ++++ .../main/java/com/pancm/vo/PageResult.java | 30 ++ .../main/java/com/pancm/vo/TSysUserVO.java | 61 ++++ .../src/main/java/com/pancm/vo/UserVO.java | 71 ++++ .../src/main/resources/application-dev.yml | 14 + .../src/main/resources/application-local.yml | 14 + .../src/main/resources/application.yml | 15 + .../src/main/resources/build.properties | 4 + springboot-log/src/main/resources/logback.xml | 85 +++++ .../pancm/mapper/DbVersionMapper.xml | 8 + .../resources/pancm/mapper/TSysUserMapper.xml | 128 +++++++ .../resources/pancm/mapper/UserMapper.xml | 148 ++++++++ .../main/resources/pancm/mybatis-config.xml | 15 + springboot-log/src/main/resources/version.txt | 1 + springboot-log/start.sh | 11 + springboot-log/stop.sh | 13 + .../spring-configuration-metadata.json | 12 + .../target/classes/application-dev.yml | 14 + .../target/classes/application-local.yml | 14 + springboot-log/target/classes/application.yml | 15 + .../target/classes/build.properties | 4 + springboot-log/target/classes/logback.xml | 85 +++++ .../classes/pancm/mapper/DbVersionMapper.xml | 8 + .../classes/pancm/mapper/TSysUserMapper.xml | 128 +++++++ .../classes/pancm/mapper/UserMapper.xml | 148 ++++++++ .../target/classes/pancm/mybatis-config.xml | 15 + springboot-log/target/classes/version.txt | 1 + .../target/maven-archiver/pom.properties | 3 + .../compile/default-compile/createdFiles.lst | 1 + .../compile/default-compile/inputFiles.lst | 24 ++ .../target/springboot-log.jar.original | Bin 0 -> 48481 bytes 61 files changed, 3528 insertions(+) create mode 100644 springboot-log/README.md create mode 100644 springboot-log/build-dev.bat create mode 100644 springboot-log/build-dev.xml create mode 100644 springboot-log/db/pcm.sql create mode 100644 springboot-log/easycode/EasyCodeConfig.json create mode 100644 springboot-log/git-info.bat create mode 100644 springboot-log/pom.xml create mode 100644 springboot-log/src/main/java/com/pancm/Application.java create mode 100644 springboot-log/src/main/java/com/pancm/config/CorsFilter.java create mode 100644 springboot-log/src/main/java/com/pancm/config/DemoDefenderStrategy.java create mode 100644 springboot-log/src/main/java/com/pancm/config/PancmConfiguration.java create mode 100644 springboot-log/src/main/java/com/pancm/config/PluginOne.java create mode 100644 springboot-log/src/main/java/com/pancm/config/SpringBeanFactory.java create mode 100644 springboot-log/src/main/java/com/pancm/config/SwaggerConfig.java create mode 100644 springboot-log/src/main/java/com/pancm/controller/HomeController.java create mode 100644 springboot-log/src/main/java/com/pancm/controller/TSysUserController.java create mode 100644 springboot-log/src/main/java/com/pancm/controller/UserController.java create mode 100644 springboot-log/src/main/java/com/pancm/dao/TSysUserDao.java create mode 100644 springboot-log/src/main/java/com/pancm/dao/UserDao.java create mode 100644 springboot-log/src/main/java/com/pancm/enums/SimpleDefenderStrategy.java create mode 100644 springboot-log/src/main/java/com/pancm/model/TSysUser.java create mode 100644 springboot-log/src/main/java/com/pancm/model/User.java create mode 100644 springboot-log/src/main/java/com/pancm/service/ITSysUserService.java create mode 100644 springboot-log/src/main/java/com/pancm/service/IUserService.java create mode 100644 springboot-log/src/main/java/com/pancm/service/impl/TSysUserServiceImpl.java create mode 100644 springboot-log/src/main/java/com/pancm/service/impl/UserServiceImpl.java create mode 100644 springboot-log/src/main/java/com/pancm/util/FileHelper.java create mode 100644 springboot-log/src/main/java/com/pancm/util/GetProperties.java create mode 100644 springboot-log/src/main/java/com/pancm/vo/ApiResult.java create mode 100644 springboot-log/src/main/java/com/pancm/vo/BaseConstants.java create mode 100644 springboot-log/src/main/java/com/pancm/vo/BasePage.java create mode 100644 springboot-log/src/main/java/com/pancm/vo/PageResult.java create mode 100644 springboot-log/src/main/java/com/pancm/vo/TSysUserVO.java create mode 100644 springboot-log/src/main/java/com/pancm/vo/UserVO.java create mode 100644 springboot-log/src/main/resources/application-dev.yml create mode 100644 springboot-log/src/main/resources/application-local.yml create mode 100644 springboot-log/src/main/resources/application.yml create mode 100644 springboot-log/src/main/resources/build.properties create mode 100644 springboot-log/src/main/resources/logback.xml create mode 100644 springboot-log/src/main/resources/pancm/mapper/DbVersionMapper.xml create mode 100644 springboot-log/src/main/resources/pancm/mapper/TSysUserMapper.xml create mode 100644 springboot-log/src/main/resources/pancm/mapper/UserMapper.xml create mode 100644 springboot-log/src/main/resources/pancm/mybatis-config.xml create mode 100644 springboot-log/src/main/resources/version.txt create mode 100644 springboot-log/start.sh create mode 100644 springboot-log/stop.sh create mode 100644 springboot-log/target/classes/META-INF/spring-configuration-metadata.json create mode 100644 springboot-log/target/classes/application-dev.yml create mode 100644 springboot-log/target/classes/application-local.yml create mode 100644 springboot-log/target/classes/application.yml create mode 100644 springboot-log/target/classes/build.properties create mode 100644 springboot-log/target/classes/logback.xml create mode 100644 springboot-log/target/classes/pancm/mapper/DbVersionMapper.xml create mode 100644 springboot-log/target/classes/pancm/mapper/TSysUserMapper.xml create mode 100644 springboot-log/target/classes/pancm/mapper/UserMapper.xml create mode 100644 springboot-log/target/classes/pancm/mybatis-config.xml create mode 100644 springboot-log/target/classes/version.txt create mode 100644 springboot-log/target/maven-archiver/pom.properties create mode 100644 springboot-log/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst create mode 100644 springboot-log/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst create mode 100644 springboot-log/target/springboot-log.jar.original diff --git a/springboot-log/README.md b/springboot-log/README.md new file mode 100644 index 0000000..e35eead --- /dev/null +++ b/springboot-log/README.md @@ -0,0 +1,43 @@ +## springBoot-demo + +springBoot-demo 是一个SpringBoot的基础框架项目,可以在此项目上进行扩展。 + +## 开发环境 + +- Java 8+ +- Maven 3.5.4+ +- SpringBoot 2.3.12.RELEASE +- mysql5.7+ +- ant1.9+ (非必须,打包可用) + + +## 快速开始 + +**使用** + +- git clone https://github.com/xuwujing/springBoot-study/springBoot-demo.git + +**使用** + +秉着开箱即用的原则,更改相应的配置(MySql、Es、Redis等地址配置),运行main方法,即可启动! + +**注意** + + EasyCode模板生成的xml若是没有逗号,则需要将全局模版velocityHasNext修改为foreach.hasNext。 + +## 项目结构 + +``` +springBoot-demo +├── pom.xml +├── README.md +├── build-dev.bat ant打包脚本启动命令 +├── build-dev.xml ant打包脚本 +├── git-info.bat git信息获取 +├── start.sh linux启动脚本 +├── stop.sh linux停止动脚本 +└── src + ├── main + │   ├── java + │   │   └── com + │   │   └── pancm \ No newline at end of file diff --git a/springboot-log/build-dev.bat b/springboot-log/build-dev.bat new file mode 100644 index 0000000..3178c7c --- /dev/null +++ b/springboot-log/build-dev.bat @@ -0,0 +1 @@ +ant -f build-dev.xml \ No newline at end of file diff --git a/springboot-log/build-dev.xml b/springboot-log/build-dev.xml new file mode 100644 index 0000000..abf9d50 --- /dev/null +++ b/springboot-log/build-dev.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/springboot-log/db/pcm.sql b/springboot-log/db/pcm.sql new file mode 100644 index 0000000..83bc610 --- /dev/null +++ b/springboot-log/db/pcm.sql @@ -0,0 +1,42 @@ +/* + Navicat Premium Data Transfer + + Source Server : 本地-mysql + Source Server Type : MySQL + Source Server Version : 50744 + Source Host : localhost:3306 + Source Schema : pcm + + Target Server Type : MySQL + Target Server Version : 50744 + File Encoding : 65001 + + Date: 15/01/2024 15:40:52 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for user +-- ---------------------------- +DROP TABLE IF EXISTS `user`; +CREATE TABLE `user` ( + `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '姓名', + `sex` tinyint(1) NULL DEFAULT 1 COMMENT '性别', + `age` int(4) NULL DEFAULT NULL COMMENT '年龄', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `create_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人', + `update_time` datetime NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `update_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of user +-- ---------------------------- +INSERT INTO `user` VALUES (1, '张三', 1, 18, '2020-02-15 14:35:46', 'admin', '2021-01-15 14:36:28', 'admin'); +INSERT INTO `user` VALUES (2, '小红', 2, 26, '2022-02-16 14:36:10', 'admin', '2021-01-15 14:36:39', 'admin'); + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/springboot-log/easycode/EasyCodeConfig.json b/springboot-log/easycode/EasyCodeConfig.json new file mode 100644 index 0000000..8f4740b --- /dev/null +++ b/springboot-log/easycode/EasyCodeConfig.json @@ -0,0 +1,155 @@ +{ + "author" : "pancm", + "version" : "1.2.8", + "userSecure" : "", + "currTypeMapperGroupName" : "Default", + "currTemplateGroupName" : "pancm_mybatis_plus", + "currColumnConfigGroupName" : "Default", + "currGlobalConfigGroupName" : "Default", + "typeMapper" : { + "Default" : { + "name" : "Default", + "elementList" : [ { + "matchType" : "REGEX", + "columnType" : "varchar(\\(\\d+\\))?", + "javaType" : "java.lang.String" + }, { + "matchType" : "REGEX", + "columnType" : "char(\\(\\d+\\))?", + "javaType" : "java.lang.String" + }, { + "matchType" : "REGEX", + "columnType" : "(tiny|medium|long)*text", + "javaType" : "java.lang.String" + }, { + "matchType" : "REGEX", + "columnType" : "decimal(\\(\\d+,\\d+\\))?", + "javaType" : "java.lang.Double" + }, { + "matchType" : "ORDINARY", + "columnType" : "integer", + "javaType" : "java.lang.Integer" + }, { + "matchType" : "REGEX", + "columnType" : "(tiny|small|medium)*int(\\(\\d+\\))?", + "javaType" : "java.lang.Integer" + }, { + "matchType" : "ORDINARY", + "columnType" : "int4", + "javaType" : "java.lang.Integer" + }, { + "matchType" : "ORDINARY", + "columnType" : "int8", + "javaType" : "java.lang.Long" + }, { + "matchType" : "REGEX", + "columnType" : "bigint(\\(\\d+\\))?", + "javaType" : "java.lang.Long" + }, { + "matchType" : "ORDINARY", + "columnType" : "date", + "javaType" : "java.util.Date" + }, { + "matchType" : "ORDINARY", + "columnType" : "datetime", + "javaType" : "java.util.Date" + }, { + "matchType" : "ORDINARY", + "columnType" : "timestamp", + "javaType" : "java.util.Date" + }, { + "matchType" : "ORDINARY", + "columnType" : "time", + "javaType" : "java.time.LocalTime" + }, { + "matchType" : "ORDINARY", + "columnType" : "boolean", + "javaType" : "java.lang.Boolean" + } ] + } + }, + "template" : { + "pancm" : { + "name" : "pancm", + "elementList" : [ { + "name" : "controller.java", + "code" : "##定义初始变量\n#set($tableName = $tool.append($tableInfo.name, \"Controller\"))\n##设置回调\n$!callback.setFileName($tool.append($tableName, \".java\"))\n$!callback.setSavePath($tool.append($tableInfo.savePath, \"/controller\"))\n##拿到主键\n#if(!$tableInfo.pkColumn.isEmpty())\n #set($pk = $tableInfo.pkColumn.get(0))\n#end\n\n#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}controller;\n\nimport $!{tableInfo.savePackageName}.vo.$!{tableInfo.name}VO;\nimport $!{tableInfo.savePackageName}.service.I$!{tableInfo.name}Service;\nimport org.springframework.web.bind.annotation.*;\n\n\nimport com.pancm.vo.ApiResult;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport javax.servlet.http.HttpServletRequest;\n\n\n\n/**\n* @Title: $!{tableInfo.comment}($!{tableInfo.name})表控制层\n* @Description: \n* @Version:1.0.0 \n* @Since:jdk1.8 \n* @author $author\n* @date $!time.currTime()\n*/\n@Api(tags = \"$!{tableInfo.comment}($!{tableInfo.name})\")\n@RestController\n@RequestMapping(\"$!tool.firstLowerCase($tableInfo.name)\")\npublic class $!{tableName} {\n /**\n * 服务对象\n */\n @Autowired\n private I$!{tableInfo.name}Service $!tool.firstLowerCase($tableInfo.name)Service;\n\n\n /**\n * 新增一条数据\n *\n * @param $!tool.firstLowerCase($tableInfo.name)VO 实体类\n * @return Response对象\n */\n @ApiOperation(value = \"$!{tableInfo.comment}新增\",notes = \"$!{tableInfo.comment}新增\")\n @RequestMapping(value = \"save\", method = RequestMethod.POST)\n public ApiResult insert(@RequestBody $!{tableInfo.name}VO $!tool.firstLowerCase($tableInfo.name)VO, HttpServletRequest httpRequest) {\n int result = $!{tool.firstLowerCase($tableInfo.name)}Service.insert($!tool.firstLowerCase($tableInfo.name)VO);\n if (result > 0) {\n return ApiResult.success();\n }\n return ApiResult.error(\"新增失败\");\n }\n\n /**\n * 修改一条数据\n *\n * @param $!tool.firstLowerCase($tableInfo.name)VO 实体类\n * @return Response对象\n */\n @ApiOperation(value = \"$!{tableInfo.comment}修改\",notes = \"$!{tableInfo.comment}修改\")\n @RequestMapping(value = \"edit\", method = RequestMethod.POST)\n public ApiResult update(@RequestBody $!{tableInfo.name}VO $!tool.firstLowerCase($tableInfo.name)VO, HttpServletRequest httpRequest) {\n $!{tool.firstLowerCase($tableInfo.name)}Service.update($!tool.firstLowerCase($tableInfo.name)VO); \n return ApiResult.success();\n }\n\n /**\n * 删除一条数据\n *\n * @param $!tool.firstLowerCase($tableInfo.name)VO 参数对象\n * @return Response对象\n */\n @ApiOperation(value = \"$!{tableInfo.comment}删除\",notes = \"$!{tableInfo.comment}删除\") \n @RequestMapping(value = \"del\", method = RequestMethod.POST)\n public ApiResult delete(@RequestBody $!{tableInfo.name}VO $!tool.firstLowerCase($tableInfo.name)VO, HttpServletRequest httpRequest) {\n $!{tool.firstLowerCase($tableInfo.name)}Service.deleteById($!{tool.firstLowerCase($tableInfo.name)}VO.getId());\n return ApiResult.success(); \n }\n\n \n\n /**\n * 分页查询\n *\n */\n @ApiOperation(value = \"$!{tableInfo.comment}查询\",notes = \"$!{tableInfo.comment}查询\")\n @RequestMapping(value = \"list\", method = RequestMethod.POST)\n public ApiResult list(@RequestBody $!{tableInfo.name}VO $!tool.firstLowerCase($tableInfo.name)VO) {\n return $!{tool.firstLowerCase($tableInfo.name)}Service.list($!tool.firstLowerCase($tableInfo.name)VO);\n }\n\n /**\n * 详情查询\n *\n */ \n @ApiOperation(value = \"$!{tableInfo.comment}详情\",notes = \"$!{tableInfo.comment}详情\") \n @RequestMapping(value = \"view\", method = RequestMethod.GET)\n public ApiResult view( @RequestParam(\"id\") Long id) {\n return ApiResult.success($!{tool.firstLowerCase($tableInfo.name)}Service.queryById(id)); \n }\n}" + }, { + "name" : "service.java", + "code" : "##定义初始变量\n#set($tableName = $tool.append(\"I\",$tableInfo.name, \"Service\"))\n##设置回调\n$!callback.setFileName($tool.append($tableName, \".java\"))\n$!callback.setSavePath($tool.append($tableInfo.savePath, \"/service\"))\n\n##拿到主键\n#if(!$tableInfo.pkColumn.isEmpty())\n #set($pk = $tableInfo.pkColumn.get(0))\n#end\n\n#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}service;\n$!autoImport\nimport $!{tableInfo.savePackageName}.vo.$!{tableInfo.name}VO;\nimport com.pancm.vo.ApiResult;\nimport java.util.List;\n\n\n /**\n* @Title: $!{tableInfo.comment}($!{tableInfo.name})表服务接口\n* @Description: \n* @Version:1.0.0 \n* @Since:jdk1.8 \n* @author $author\n* @date $!time.currTime()\n*/\npublic interface $!{tableName} {\n\n /**\n * 通过ID查询单条数据\n *\n * @param $!pk.name 主键\n * @return 实例对象\n */\n $!{tableInfo.name}VO queryById($!pk.shortType $!pk.name);\n\n \n /**\n * 通过实体作为筛选条件查询\n *\n * @param $!tool.firstLowerCase($!{tableInfo.name})VO 实例对象\n * @return 对象列表\n */\n ApiResult list($!{tableInfo.name}VO $!tool.firstLowerCase($!{tableInfo.name})VO);\n\n \n /**\n * 新增数据\n *\n * @param $!tool.firstLowerCase($!{tableInfo.name})VO 实例对象\n * @return 实例对象\n */\n int insert($!{tableInfo.name}VO $!tool.firstLowerCase($!{tableInfo.name})VO);\n\n /**\n * 修改数据\n *\n * @param $!tool.firstLowerCase($!{tableInfo.name})VO 实例对象\n * @return 实例对象\n */\n int update($!{tableInfo.name}VO $!tool.firstLowerCase($!{tableInfo.name})VO);\n\n /**\n * 通过主键删除数据\n *\n * @param $!pk.name 主键\n * @return 是否成功\n */\n boolean deleteById($!pk.shortType $!pk.name);\n\n}" + }, { + "name" : "serviceImpl.java", + "code" : "##定义初始变量\n#set($tableName = $tool.append($tableInfo.name, \"ServiceImpl\"))\n##设置回调\n$!callback.setFileName($tool.append($tableName, \".java\"))\n$!callback.setSavePath($tool.append($tableInfo.savePath, \"/service/impl\"))\n\n##拿到主键\n#if(!$tableInfo.pkColumn.isEmpty())\n #set($pk = $tableInfo.pkColumn.get(0))\n#end\n\n#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}service.impl;\n$!autoImport\n\nimport $!{tableInfo.savePackageName}.vo.$!{tableInfo.name}VO;\nimport $!{tableInfo.savePackageName}.model.$!{tableInfo.name};\nimport $!{tableInfo.savePackageName}.dao.$!{tableInfo.name}Dao;\nimport $!{tableInfo.savePackageName}.service.I$!{tableInfo.name}Service;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.pancm.vo.ApiResult;\nimport com.pancm.vo.PageResult;\nimport org.springframework.stereotype.Service;\nimport org.springframework.beans.BeanUtils;\nimport javax.annotation.Resource;\nimport java.util.List;\n\n\n\n/**\n* @Title: $!{tableInfo.comment}($!{tableInfo.name})表服务实现类\n* @Description: \n* @Version:1.0.0 \n* @Since:jdk1.8 \n* @author $author\n* @date $!time.currTime()\n*/\n@Service(\"$!tool.firstLowerCase($!{tableInfo.name})Service\")\npublic class $!{tableName} implements I$!{tableInfo.name}Service {\n @Resource\n private $!{tableInfo.name}Dao $!tool.firstLowerCase($!{tableInfo.name})Dao;\n\n /**\n * 通过ID查询单条数据\n *\n * @param $!pk.name 主键\n * @return 实例对象\n */\n @Override\n public $!{tableInfo.name}VO queryById($!pk.shortType $!pk.name) {\n return this.$!{tool.firstLowerCase($!{tableInfo.name})}Dao.queryById($!pk.name);\n }\n\n \n /**\n * 根据条件查询\n *\n * @return 实例对象的集合\n */\n @Override\n public ApiResult list($!{tableInfo.name}VO $!{tool.firstLowerCase($!{tableInfo.name})}) {\n int pageNum = $!{tool.firstLowerCase($!{tableInfo.name})}.getPageNum();\n int pageSize = $!{tool.firstLowerCase($!{tableInfo.name})}.getPageSize();\n Page page = PageHelper.startPage(pageNum, pageSize);\n List<$!{tableInfo.name}VO> result = $!{tool.firstLowerCase($!{tableInfo.name})}Dao.queryAll($!{tool.firstLowerCase($!{tableInfo.name})});\n return ApiResult.success(new PageResult<>(page.getTotal(), result, pageSize, pageNum));\n \n }\n \n /**\n * 新增数据\n *\n * @param $!tool.firstLowerCase($!{tableInfo.name})VO 实例对象\n * @return 实例对象\n */\n @Override\n public int insert($!{tableInfo.name}VO $!tool.firstLowerCase($!{tableInfo.name})VO) {\n $!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}) = new $!{tableInfo.name}();\n BeanUtils.copyProperties($!tool.firstLowerCase($!{tableInfo.name})VO,$!tool.firstLowerCase($!{tableInfo.name}));\n return $!{tool.firstLowerCase($!{tableInfo.name})}Dao.insert($!tool.firstLowerCase($!{tableInfo.name}));\n }\n\n /**\n * 修改数据\n *\n * @param $!tool.firstLowerCase($!{tableInfo.name})VO 实例对象\n * @return 实例对象\n */\n @Override\n public int update($!{tableInfo.name}VO $!tool.firstLowerCase($!{tableInfo.name})VO) {\n $!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}) = new $!{tableInfo.name}();\n BeanUtils.copyProperties($!tool.firstLowerCase($!{tableInfo.name})VO,$!tool.firstLowerCase($!{tableInfo.name}));\n return $!{tool.firstLowerCase($!{tableInfo.name})}Dao.update($!tool.firstLowerCase($!{tableInfo.name}));\n }\n\n /**\n * 通过主键删除数据\n *\n * @param $!pk.name 主键\n * @return 是否成功\n */\n @Override\n public boolean deleteById($!pk.shortType $!pk.name) {\n return this.$!{tool.firstLowerCase($!{tableInfo.name})}Dao.deleteById($!pk.name) > 0;\n }\n}" + }, { + "name" : "dao.java", + "code" : "##定义初始变量\n#set($tableName = $tool.append($tableInfo.name, \"Dao\"))\n##设置回调\n$!callback.setFileName($tool.append($tableName, \".java\"))\n$!callback.setSavePath($tool.append($tableInfo.savePath, \"/dao\"))\n\n##拿到主键\n#if(!$tableInfo.pkColumn.isEmpty())\n #set($pk = $tableInfo.pkColumn.get(0))\n#end\n\n#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}dao;\n\nimport $!{tableInfo.savePackageName}.model.$!{tableInfo.name};\nimport $!{tableInfo.savePackageName}.vo.$!{tableInfo.name}VO;\nimport org.apache.ibatis.annotations.Param;\nimport org.apache.ibatis.annotations.Mapper;\nimport java.util.List;\n\n /**\n* @Title: $!{tableInfo.comment}($!{tableInfo.name})表数据库访问层\n* @Description: \n* @Version:1.0.0 \n* @Since:jdk1.8 \n* @author $author\n* @date $!time.currTime()\n*/\n@Mapper\npublic interface $!{tableName} {\n\n /**\n * 通过ID查询单条数据\n *\n * @param $!pk.name 主键\n * @return 实例对象\n */\n $!{tableInfo.name}VO queryById($!pk.shortType $!pk.name);\n\n \n /**\n * 通过实体查询一条数据\n *\n * @param $!tool.firstLowerCase($!{tableInfo.name})VO 实例对象\n * @return 对象列表\n */\n $!{tableInfo.name}VO findOne($!{tableInfo.name}VO $!tool.firstLowerCase($!{tableInfo.name})VO);\n\n /**\n * 通过实体作为筛选条件查询\n *\n * @param $!tool.firstLowerCase($!{tableInfo.name})VO 实例对象\n * @return 对象列表\n */\n List<$!{tableInfo.name}VO> queryAll($!{tableInfo.name}VO $!tool.firstLowerCase($!{tableInfo.name})VO);\n\n /**\n * 新增数据\n *\n * @param $!tool.firstLowerCase($!{tableInfo.name}) 实例对象\n * @return 影响行数\n */\n int insert($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}));\n\n /**\n * 批量新增数据(MyBatis原生foreach方法)\n *\n * @param entities List<$!{tableInfo.name}> 实例对象列表\n * @return 影响行数\n */\n int insertBatch(@Param(\"entities\") List<$!{tableInfo.name}> entities);\n\n /**\n * 批量新增或按主键更新数据(MyBatis原生foreach方法)\n *\n * @param entities List<$!{tableInfo.name}> 实例对象列表\n * @return 影响行数\n */\n int insertOrUpdateBatch(@Param(\"entities\") List<$!{tableInfo.name}> entities);\n\n /**\n * 修改数据\n *\n * @param $!tool.firstLowerCase($!{tableInfo.name}) 实例对象\n * @return 影响行数\n */\n int update($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}));\n\n /**\n * 通过主键删除数据\n *\n * @param $!pk.name 主键\n * @return 影响行数\n */\n int deleteById($!pk.shortType $!pk.name);\n\n}\n" + }, { + "name" : "vo.java", + "code" : "##引入宏定义\n$!define\n#set($tableName = $tool.append($tableInfo.name, \"VO\"))\n##设置回调\n$!callback.setFileName($tool.append($tableName, \".java\"))\n$!callback.setSavePath($tool.append($tableInfo.savePath, \"/vo\"))\n\n#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}vo;\n##使用全局变量实现默认包导入\n$!autoImport\nimport java.io.Serializable;\nimport com.alibaba.fastjson.JSONObject;\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;\nimport lombok.Data;\nimport java.sql.Date;\nimport com.pancm.vo.BasePage;\n\n/**\n* @Title: $!{tableInfo.comment}($!{tableInfo.name})请求响应对象\n* @Description: \n* @Version:1.0.0 \n* @Since:jdk1.8 \n* @author $author\n* @date $!time.currTime()\n*/\n@ApiModel(value = \"$!{tableInfo.name}\", description = \"$!{tableInfo.comment}\")\n@Data\npublic class $!{tableInfo.name}VO extends BasePage implements Serializable {\n private static final long serialVersionUID = $!tool.serial();\n#foreach($column in $tableInfo.fullColumn)\n #if(${column.comment})\n /**\n * ${column.comment}\n */\n #end\n @ApiModelProperty(value = \"${column.comment}\")\n private $!{tool.getClsNameByFullName($column.type)} $!{column.name};\n #end\n\n\n\n @Override\n public String toString(){\n return JSONObject.toJSONString(this);\n }\n\n}" + }, { + "name" : "model.java", + "code" : "\n##导入宏定义\n$!{define.vm}\n\n##保存文件(宏定义)\n#save(\"/model\", \".java\")\n\n##包路径(宏定义)\n#setPackageSuffix(\"model\")\n\n\nimport com.alibaba.fastjson.JSONObject;\nimport lombok.Data;\n\nimport javax.persistence.Column;\nimport javax.persistence.Table;\nimport java.io.Serializable;\nimport java.sql.Date;\n\n /**\n* @Title: $!{tableInfo.comment}($!{tableInfo.name})实体类\n* @Description: \n* @Version:1.0.0 \n* @Since:jdk1.8 \n* @author $author\n* @date $!time.currTime()\n*/\n@Data\n@Table(name = \"$tableInfo.obj.name\")\npublic class $!{tableInfo.name} implements Serializable {\n private static final long serialVersionUID = $!tool.serial();\n#foreach($column in $tableInfo.fullColumn)\n #if(${column.comment})\n /**\n * ${column.comment}\n */\n #end\n @Column(name = \"$column.obj.name\")\n private $!{tool.getClsNameByFullName($column.type)} $!{column.name};\n#end\n\n\n @Override\n public String toString(){\n return JSONObject.toJSONString(this);\n }\n\n}" + }, { + "name" : "mapper.xml.vm", + "code" : "##引入mybatis支持\n$!{mybatisSupport.vm}\n\n##设置保存名称与保存位置\n$!callback.setFileName($tool.append($!{tableInfo.name}, \"Mapper.xml\"))\n$!callback.setSavePath($tool.append($modulePath, \"/src/main/resources/pancm/mapper\"))\n\n##拿到主键\n#if(!$tableInfo.pkColumn.isEmpty())\n #set($pk = $tableInfo.pkColumn.get(0))\n#end\n\n\n\n\n\n \n#foreach($column in $tableInfo.fullColumn)\n \n#end\n \n\n \n \n \n \n \n\n \n \n\n \n \n insert into $!{tableInfo.obj.name}(#foreach($column in $tableInfo.otherColumn)$!column.obj.name#if($foreach.hasNext), #end#end)\n values (#foreach($column in $tableInfo.otherColumn)#{$!{column.name}}#if($foreach.hasNext), #end#end)\n \n\n \n insert into $!{tableInfo.obj.name}(#foreach($column in $tableInfo.otherColumn)$!column.obj.name#if($foreach.hasNext), #end#end)\n values\n \n (#foreach($column in $tableInfo.otherColumn)#{entity.$!{column.name}}#if($foreach.hasNext), #end#end)\n \n \n\n \n insert into $!{tableInfo.obj.name}(#foreach($column in $tableInfo.otherColumn)$!column.obj.name#if($foreach.hasNext), #end#end)\n values\n \n (#foreach($column in $tableInfo.otherColumn)#{entity.$!{column.name}}#if($foreach.hasNext), #end#end)\n \n on duplicate key update\n #foreach($column in $tableInfo.otherColumn)$!column.obj.name = values($!column.obj.name) #if($foreach.hasNext), #end#end\n \n\n \n \n update $!{tableInfo.obj.name}\n \n#foreach($column in $tableInfo.otherColumn)\n \n $!column.obj.name = #{$!column.name},\n \n#end\n \n where $!pk.obj.name = #{$!pk.name}\n \n\n \n \n delete from $!{tableInfo.obj.name} where $!pk.obj.name = #{$!pk.name}\n \n\n\n" + } ] + }, + "pancm_mybatis_plus" : { + "name" : "pancm_mybatis_plus", + "elementList" : [ { + "name" : "controller.java", + "code" : "##定义初始变量\n#set($tableName = $tool.append($tableInfo.name, \"Controller\"))\n##设置回调\n$!callback.setFileName($tool.append($tableName, \".java\"))\n$!callback.setSavePath($tool.append($tableInfo.savePath, \"/controller\"))\n##拿到主键\n#if(!$tableInfo.pkColumn.isEmpty())\n #set($pk = $tableInfo.pkColumn.get(0))\n#end\n\n#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}controller;\n\nimport $!{tableInfo.savePackageName}.vo.$!{tableInfo.name}VO;\nimport $!{tableInfo.savePackageName}.service.I$!{tableInfo.name}Service;\nimport org.springframework.web.bind.annotation.*;\n\n\nimport com.pancm.vo.ApiResult;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport javax.servlet.http.HttpServletRequest;\n\n\n\n/**\n* @Title: $!{tableInfo.comment}($!{tableInfo.name})表控制层\n* @Description: \n* @Version:1.0.0 \n* @Since:jdk1.8 \n* @author $author\n* @date $!time.currTime()\n*/\n@Api(tags = \"$!{tableInfo.comment}($!{tableInfo.name})\")\n@RestController\n@RequestMapping(\"$!tool.firstLowerCase($tableInfo.name)\")\npublic class $!{tableName} {\n /**\n * 服务对象\n */\n @Autowired\n private I$!{tableInfo.name}Service $!tool.firstLowerCase($tableInfo.name)Service;\n\n\n /**\n * 新增一条数据\n *\n * @param $!tool.firstLowerCase($tableInfo.name)VO 实体类\n * @return Response对象\n */\n @ApiOperation(value = \"$!{tableInfo.comment}新增\",notes = \"$!{tableInfo.comment}新增\")\n @RequestMapping(value = \"save\", method = RequestMethod.POST)\n public ApiResult insert(@RequestBody $!{tableInfo.name}VO $!tool.firstLowerCase($tableInfo.name)VO, HttpServletRequest httpRequest) {\n int result = $!{tool.firstLowerCase($tableInfo.name)}Service.insert($!tool.firstLowerCase($tableInfo.name)VO);\n if (result > 0) {\n return ApiResult.success();\n }\n return ApiResult.error(\"新增失败\");\n }\n\n /**\n * 修改一条数据\n *\n * @param $!tool.firstLowerCase($tableInfo.name)VO 实体类\n * @return Response对象\n */\n @ApiOperation(value = \"$!{tableInfo.comment}修改\",notes = \"$!{tableInfo.comment}修改\")\n @RequestMapping(value = \"edit\", method = RequestMethod.POST)\n public ApiResult update(@RequestBody $!{tableInfo.name}VO $!tool.firstLowerCase($tableInfo.name)VO, HttpServletRequest httpRequest) {\n $!{tool.firstLowerCase($tableInfo.name)}Service.update($!tool.firstLowerCase($tableInfo.name)VO); \n return ApiResult.success();\n }\n\n /**\n * 删除一条数据\n *\n * @param $!tool.firstLowerCase($tableInfo.name)VO 参数对象\n * @return Response对象\n */\n @ApiOperation(value = \"$!{tableInfo.comment}删除\",notes = \"$!{tableInfo.comment}删除\") \n @RequestMapping(value = \"del\", method = RequestMethod.POST)\n public ApiResult delete(@RequestBody $!{tableInfo.name}VO $!tool.firstLowerCase($tableInfo.name)VO, HttpServletRequest httpRequest) {\n $!{tool.firstLowerCase($tableInfo.name)}Service.deleteById($!{tool.firstLowerCase($tableInfo.name)}VO.getId());\n return ApiResult.success(); \n }\n\n \n\n /**\n * 分页查询\n *\n */\n @ApiOperation(value = \"$!{tableInfo.comment}查询\",notes = \"$!{tableInfo.comment}查询\")\n @RequestMapping(value = \"list\", method = RequestMethod.POST)\n public ApiResult list(@RequestBody $!{tableInfo.name}VO $!tool.firstLowerCase($tableInfo.name)VO) {\n return $!{tool.firstLowerCase($tableInfo.name)}Service.list($!tool.firstLowerCase($tableInfo.name)VO);\n }\n\n /**\n * 详情查询\n *\n */ \n @ApiOperation(value = \"$!{tableInfo.comment}详情\",notes = \"$!{tableInfo.comment}详情\") \n @RequestMapping(value = \"view\", method = RequestMethod.GET)\n public ApiResult view( @RequestParam(\"id\") Long id) {\n return ApiResult.success($!{tool.firstLowerCase($tableInfo.name)}Service.queryById(id)); \n }\n}" + }, { + "name" : "service.java", + "code" : "##定义初始变量\n#set($tableName = $tool.append(\"I\",$tableInfo.name, \"Service\"))\n##设置回调\n$!callback.setFileName($tool.append($tableName, \".java\"))\n$!callback.setSavePath($tool.append($tableInfo.savePath, \"/service\"))\n\n##拿到主键\n#if(!$tableInfo.pkColumn.isEmpty())\n #set($pk = $tableInfo.pkColumn.get(0))\n#end\n\n#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}service;\n$!autoImport\nimport $!{tableInfo.savePackageName}.vo.$!{tableInfo.name}VO;\nimport $!{tableInfo.savePackageName}.model.$!{tableInfo.name};\nimport com.pancm.vo.ApiResult;\nimport java.util.List;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\n\n /**\n* @Title: $!{tableInfo.comment}($!{tableInfo.name})表服务接口\n* @Description: \n* @Version:1.0.0 \n* @Since:jdk1.8 \n* @author $author\n* @date $!time.currTime()\n*/\npublic interface $!{tableName} extends IService<$!tableInfo.name>{\n\n /**\n * 通过ID查询单条数据\n *\n * @param $!pk.name 主键\n * @return 实例对象\n */\n $!{tableInfo.name}VO queryById($!pk.shortType $!pk.name);\n\n \n /**\n * 通过实体作为筛选条件查询\n *\n * @param $!tool.firstLowerCase($!{tableInfo.name})VO 实例对象\n * @return 对象列表\n */\n ApiResult list($!{tableInfo.name}VO $!tool.firstLowerCase($!{tableInfo.name})VO);\n\n \n /**\n * 新增数据\n *\n * @param $!tool.firstLowerCase($!{tableInfo.name})VO 实例对象\n * @return 实例对象\n */\n int insert($!{tableInfo.name}VO $!tool.firstLowerCase($!{tableInfo.name})VO);\n\n /**\n * 修改数据\n *\n * @param $!tool.firstLowerCase($!{tableInfo.name})VO 实例对象\n * @return 实例对象\n */\n int update($!{tableInfo.name}VO $!tool.firstLowerCase($!{tableInfo.name})VO);\n\n /**\n * 通过主键删除数据\n *\n * @param $!pk.name 主键\n * @return 是否成功\n */\n boolean deleteById($!pk.shortType $!pk.name);\n\n}" + }, { + "name" : "serviceImpl.java", + "code" : "##定义初始变量\n#set($tableName = $tool.append($tableInfo.name, \"ServiceImpl\"))\n##设置回调\n$!callback.setFileName($tool.append($tableName, \".java\"))\n$!callback.setSavePath($tool.append($tableInfo.savePath, \"/service/impl\"))\n\n##拿到主键\n#if(!$tableInfo.pkColumn.isEmpty())\n #set($pk = $tableInfo.pkColumn.get(0))\n#end\n\n#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}service.impl;\n$!autoImport\n\nimport $!{tableInfo.savePackageName}.vo.$!{tableInfo.name}VO;\nimport $!{tableInfo.savePackageName}.model.$!{tableInfo.name};\nimport $!{tableInfo.savePackageName}.dao.$!{tableInfo.name}Dao;\nimport $!{tableInfo.savePackageName}.service.I$!{tableInfo.name}Service;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.pancm.vo.ApiResult;\nimport com.pancm.vo.PageResult;\nimport org.springframework.stereotype.Service;\nimport org.springframework.beans.BeanUtils;\nimport javax.annotation.Resource;\nimport java.util.List;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\n\n\n\n/**\n* @Title: $!{tableInfo.comment}($!{tableInfo.name})表服务实现类\n* @Description: \n* @Version:1.0.0 \n* @Since:jdk1.8 \n* @author $author\n* @date $!time.currTime()\n*/\n@Service(\"$!tool.firstLowerCase($!{tableInfo.name})Service\")\npublic class $!{tableName} extends ServiceImpl<$!{tableInfo.name}Dao, $!{tableInfo.name}> implements I$!{tableInfo.name}Service {\n @Resource\n private $!{tableInfo.name}Dao $!tool.firstLowerCase($!{tableInfo.name})Dao;\n\n /**\n * 通过ID查询单条数据\n *\n * @param $!pk.name 主键\n * @return 实例对象\n */\n @Override\n public $!{tableInfo.name}VO queryById($!pk.shortType $!pk.name) {\n return this.$!{tool.firstLowerCase($!{tableInfo.name})}Dao.queryById($!pk.name);\n }\n\n \n /**\n * 根据条件查询\n *\n * @return 实例对象的集合\n */\n @Override\n public ApiResult list($!{tableInfo.name}VO $!{tool.firstLowerCase($!{tableInfo.name})}) {\n int pageNum = $!{tool.firstLowerCase($!{tableInfo.name})}.getPageNum();\n int pageSize = $!{tool.firstLowerCase($!{tableInfo.name})}.getPageSize();\n Page page = PageHelper.startPage(pageNum, pageSize);\n List<$!{tableInfo.name}VO> result = $!{tool.firstLowerCase($!{tableInfo.name})}Dao.queryAll($!{tool.firstLowerCase($!{tableInfo.name})});\n return ApiResult.success(new PageResult<>(page.getTotal(), result, pageSize, pageNum));\n \n }\n \n /**\n * 新增数据\n *\n * @param $!tool.firstLowerCase($!{tableInfo.name})VO 实例对象\n * @return 实例对象\n */\n @Override\n public int insert($!{tableInfo.name}VO $!tool.firstLowerCase($!{tableInfo.name})VO) {\n $!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}) = new $!{tableInfo.name}();\n BeanUtils.copyProperties($!tool.firstLowerCase($!{tableInfo.name})VO,$!tool.firstLowerCase($!{tableInfo.name}));\n return $!{tool.firstLowerCase($!{tableInfo.name})}Dao.insert($!tool.firstLowerCase($!{tableInfo.name}));\n }\n\n /**\n * 修改数据\n *\n * @param $!tool.firstLowerCase($!{tableInfo.name})VO 实例对象\n * @return 实例对象\n */\n @Override\n public int update($!{tableInfo.name}VO $!tool.firstLowerCase($!{tableInfo.name})VO) {\n $!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}) = new $!{tableInfo.name}();\n BeanUtils.copyProperties($!tool.firstLowerCase($!{tableInfo.name})VO,$!tool.firstLowerCase($!{tableInfo.name}));\n return $!{tool.firstLowerCase($!{tableInfo.name})}Dao.update($!tool.firstLowerCase($!{tableInfo.name}));\n }\n\n /**\n * 通过主键删除数据\n *\n * @param $!pk.name 主键\n * @return 是否成功\n */\n @Override\n public boolean deleteById($!pk.shortType $!pk.name) {\n return this.$!{tool.firstLowerCase($!{tableInfo.name})}Dao.deleteById($!pk.name) > 0;\n }\n}" + }, { + "name" : "dao.java", + "code" : "##定义初始变量\n#set($tableName = $tool.append($tableInfo.name, \"Dao\"))\n##设置回调\n$!callback.setFileName($tool.append($tableName, \".java\"))\n$!callback.setSavePath($tool.append($tableInfo.savePath, \"/dao\"))\n\n##拿到主键\n#if(!$tableInfo.pkColumn.isEmpty())\n #set($pk = $tableInfo.pkColumn.get(0))\n#end\n\n#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}dao;\n\nimport $!{tableInfo.savePackageName}.model.$!{tableInfo.name};\nimport $!{tableInfo.savePackageName}.vo.$!{tableInfo.name}VO;\nimport org.apache.ibatis.annotations.Param;\nimport org.apache.ibatis.annotations.Mapper;\nimport java.util.List;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\n\n /**\n* @Title: $!{tableInfo.comment}($!{tableInfo.name})表数据库访问层\n* @Description: \n* @Version:1.0.0 \n* @Since:jdk1.8 \n* @author $author\n* @date $!time.currTime()\n*/\n@Mapper\npublic interface $!{tableName} extends BaseMapper<$!tableInfo.name> {\n\n /**\n * 通过ID查询单条数据\n *\n * @param $!pk.name 主键\n * @return 实例对象\n */\n $!{tableInfo.name}VO queryById($!pk.shortType $!pk.name);\n\n \n /**\n * 通过实体查询一条数据\n *\n * @param $!tool.firstLowerCase($!{tableInfo.name})VO 实例对象\n * @return 对象列表\n */\n $!{tableInfo.name}VO findOne($!{tableInfo.name}VO $!tool.firstLowerCase($!{tableInfo.name})VO);\n\n /**\n * 通过实体作为筛选条件查询\n *\n * @param $!tool.firstLowerCase($!{tableInfo.name})VO 实例对象\n * @return 对象列表\n */\n List<$!{tableInfo.name}VO> queryAll($!{tableInfo.name}VO $!tool.firstLowerCase($!{tableInfo.name})VO);\n\n /**\n * 新增数据\n *\n * @param $!tool.firstLowerCase($!{tableInfo.name}) 实例对象\n * @return 影响行数\n */\n int insert($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}));\n\n /**\n * 批量新增数据(MyBatis原生foreach方法)\n *\n * @param entities List<$!{tableInfo.name}> 实例对象列表\n * @return 影响行数\n */\n int insertBatch(@Param(\"entities\") List<$!{tableInfo.name}> entities);\n\n /**\n * 批量新增或按主键更新数据(MyBatis原生foreach方法)\n *\n * @param entities List<$!{tableInfo.name}> 实例对象列表\n * @return 影响行数\n */\n int insertOrUpdateBatch(@Param(\"entities\") List<$!{tableInfo.name}> entities);\n\n /**\n * 修改数据\n *\n * @param $!tool.firstLowerCase($!{tableInfo.name}) 实例对象\n * @return 影响行数\n */\n int update($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}));\n\n /**\n * 通过主键删除数据\n *\n * @param $!pk.name 主键\n * @return 影响行数\n */\n int deleteById($!pk.shortType $!pk.name);\n\n}\n" + }, { + "name" : "vo.java", + "code" : "##引入宏定义\n$!define\n#set($tableName = $tool.append($tableInfo.name, \"VO\"))\n##设置回调\n$!callback.setFileName($tool.append($tableName, \".java\"))\n$!callback.setSavePath($tool.append($tableInfo.savePath, \"/vo\"))\n\n#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}vo;\n##使用全局变量实现默认包导入\n$!autoImport\nimport java.io.Serializable;\nimport com.alibaba.fastjson.JSONObject;\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;\nimport lombok.Data;\nimport java.sql.Date;\nimport com.pancm.vo.BasePage;\n\n/**\n* @Title: $!{tableInfo.comment}($!{tableInfo.name})请求响应对象\n* @Description: \n* @Version:1.0.0 \n* @Since:jdk1.8 \n* @author $author\n* @date $!time.currTime()\n*/\n@ApiModel(value = \"$!{tableInfo.name}\", description = \"$!{tableInfo.comment}\")\n@Data\npublic class $!{tableInfo.name}VO extends BasePage implements Serializable {\n private static final long serialVersionUID = $!tool.serial();\n#foreach($column in $tableInfo.fullColumn)\n #if(${column.comment})\n /**\n * ${column.comment}\n */\n #end\n @ApiModelProperty(value = \"${column.comment}\")\n private $!{tool.getClsNameByFullName($column.type)} $!{column.name};\n #end\n\n\n\n @Override\n public String toString(){\n return JSONObject.toJSONString(this);\n }\n\n}" + }, { + "name" : "model.java", + "code" : "\n##导入宏定义\n$!{define.vm}\n\n##保存文件(宏定义)\n#save(\"/model\", \".java\")\n\n##包路径(宏定义)\n#setPackageSuffix(\"model\")\n\n\nimport com.alibaba.fastjson.JSONObject;\nimport lombok.Data;\n\nimport javax.persistence.Column;\nimport javax.persistence.Table;\nimport java.io.Serializable;\nimport java.sql.Date;\n\n /**\n* @Title: $!{tableInfo.comment}($!{tableInfo.name})实体类\n* @Description: \n* @Version:1.0.0 \n* @Since:jdk1.8 \n* @author $author\n* @date $!time.currTime()\n*/\n@Data\n@Table(name = \"$tableInfo.obj.name\")\npublic class $!{tableInfo.name} implements Serializable {\n private static final long serialVersionUID = $!tool.serial();\n#foreach($column in $tableInfo.fullColumn)\n #if(${column.comment})\n /**\n * ${column.comment}\n */\n #end\n @Column(name = \"$column.obj.name\")\n private $!{tool.getClsNameByFullName($column.type)} $!{column.name};\n#end\n\n\n @Override\n public String toString(){\n return JSONObject.toJSONString(this);\n }\n\n}" + }, { + "name" : "mapper.xml.vm", + "code" : "##引入mybatis支持\n$!{mybatisSupport.vm}\n\n##设置保存名称与保存位置\n$!callback.setFileName($tool.append($!{tableInfo.name}, \"Mapper.xml\"))\n$!callback.setSavePath($tool.append($modulePath, \"/src/main/resources/pancm/mapper\"))\n\n##拿到主键\n#if(!$tableInfo.pkColumn.isEmpty())\n #set($pk = $tableInfo.pkColumn.get(0))\n#end\n\n\n\n\n\n \n#foreach($column in $tableInfo.fullColumn)\n \n#end\n \n\n \n \n \n \n \n\n \n \n\n \n \n insert into $!{tableInfo.obj.name}(#foreach($column in $tableInfo.otherColumn)$!column.obj.name#if($foreach.hasNext), #end#end)\n values (#foreach($column in $tableInfo.otherColumn)#{$!{column.name}}#if($foreach.hasNext), #end#end)\n \n\n \n insert into $!{tableInfo.obj.name}(#foreach($column in $tableInfo.otherColumn)$!column.obj.name#if($foreach.hasNext), #end#end)\n values\n \n (#foreach($column in $tableInfo.otherColumn)#{entity.$!{column.name}}#if($foreach.hasNext), #end#end)\n \n \n\n \n insert into $!{tableInfo.obj.name}(#foreach($column in $tableInfo.otherColumn)$!column.obj.name#if($foreach.hasNext), #end#end)\n values\n \n (#foreach($column in $tableInfo.otherColumn)#{entity.$!{column.name}}#if($foreach.hasNext), #end#end)\n \n on duplicate key update\n #foreach($column in $tableInfo.otherColumn)$!column.obj.name = values($!column.obj.name) #if($foreach.hasNext), #end#end\n \n\n \n \n update $!{tableInfo.obj.name}\n \n#foreach($column in $tableInfo.otherColumn)\n \n $!column.obj.name = #{$!column.name},\n \n#end\n \n where $!pk.obj.name = #{$!pk.name}\n \n\n \n \n delete from $!{tableInfo.obj.name} where $!pk.obj.name = #{$!pk.name}\n \n\n\n" + } ] + } + }, + "columnConfig" : { + "Default" : { + "name" : "Default", + "elementList" : [ { + "title" : "disable", + "type" : "BOOLEAN", + "selectValue" : "" + }, { + "title" : "support", + "type" : "SELECT", + "selectValue" : "add,edit,query,del,ui" + } ] + } + }, + "globalConfig" : { + "Default" : { + "name" : "Default", + "elementList" : [ { + "name" : "autoImport.vm", + "value" : "##自动导入包(仅导入实体属性需要的包,通常用于实体类)\n#foreach($import in $importList)\nimport $!import;\n#end" + }, { + "name" : "define.vm", + "value" : "##(Velocity宏定义)\n\n##定义设置表名后缀的宏定义,调用方式:#setTableSuffix(\"Test\")\n#macro(setTableSuffix $suffix)\n #set($tableName = $!tool.append($tableInfo.name, $suffix))\n#end\n\n##定义设置包名后缀的宏定义,调用方式:#setPackageSuffix(\"Test\")\n#macro(setPackageSuffix $suffix)\n#if($suffix!=\"\")package #end#if($tableInfo.savePackageName!=\"\")$!{tableInfo.savePackageName}.#{end}$!suffix;\n#end\n\n##定义直接保存路径与文件名简化的宏定义,调用方式:#save(\"/entity\", \".java\")\n#macro(save $path $fileName)\n $!callback.setSavePath($tool.append($tableInfo.savePath, $path))\n $!callback.setFileName($tool.append($tableInfo.name, $fileName))\n#end\n\n##定义表注释的宏定义,调用方式:#tableComment(\"注释信息\")\n#macro(tableComment $desc)\n/**\n * $!{tableInfo.comment}($!{tableInfo.name})$desc\n *\n * @author $!author\n * @since $!time.currTime()\n */\n#end\n\n##定义GET,SET方法的宏定义,调用方式:#getSetMethod($column)\n#macro(getSetMethod $column)\n\n public $!{tool.getClsNameByFullName($column.type)} get$!{tool.firstUpperCase($column.name)}() {\n return $!{column.name};\n }\n\n public void set$!{tool.firstUpperCase($column.name)}($!{tool.getClsNameByFullName($column.type)} $!{column.name}) {\n this.$!{column.name} = $!{column.name};\n }\n#end" + }, { + "name" : "init.vm", + "value" : "##初始化区域\n\n##去掉表的t_前缀\n$!tableInfo.setName($tool.getClassName($tableInfo.obj.name.replaceFirst(\"book_\",\"\")))\n\n##参考阿里巴巴开发手册,POJO 类中布尔类型的变量,都不要加 is 前缀,否则部分框架解析会引起序列化错误\n#foreach($column in $tableInfo.fullColumn)\n#if($column.name.startsWith(\"is\") && $column.type.equals(\"java.lang.Boolean\"))\n $!column.setName($tool.firstLowerCase($column.name.substring(2)))\n#end\n#end\n\n##实现动态排除列\n#set($temp = $tool.newHashSet(\"testCreateTime\", \"otherColumn\"))\n#foreach($item in $temp)\n #set($newList = $tool.newArrayList())\n #foreach($column in $tableInfo.fullColumn)\n #if($column.name!=$item)\n ##带有反回值的方法调用时使用$tool.call来消除返回值\n $tool.call($newList.add($column))\n #end\n #end\n ##重新保存\n $tableInfo.setFullColumn($newList)\n#end\n\n##对importList进行篡改\n#set($temp = $tool.newHashSet())\n#foreach($column in $tableInfo.fullColumn)\n #if(!$column.type.startsWith(\"java.lang.\"))\n ##带有反回值的方法调用时使用$tool.call来消除返回值\n $tool.call($temp.add($column.type))\n #end\n#end\n##覆盖\n#set($importList = $temp)" + }, { + "name" : "mybatisSupport.vm", + "value" : "##针对Mybatis 进行支持,主要用于生成xml文件\n#foreach($column in $tableInfo.fullColumn)\n ##储存列类型\n $tool.call($column.ext.put(\"sqlType\", $tool.getField($column.obj.dataType, \"typeName\")))\n #if($tool.newHashSet(\"java.lang.String\").contains($column.type))\n #set($jdbcType=\"VARCHAR\")\n #elseif($tool.newHashSet(\"java.lang.Boolean\", \"boolean\").contains($column.type))\n #set($jdbcType=\"BOOLEAN\")\n #elseif($tool.newHashSet(\"java.lang.Byte\", \"byte\").contains($column.type))\n #set($jdbcType=\"BYTE\")\n #elseif($tool.newHashSet(\"java.lang.Integer\", \"int\", \"java.lang.Short\", \"short\").contains($column.type))\n #set($jdbcType=\"INTEGER\")\n #elseif($tool.newHashSet(\"java.lang.Long\", \"long\").contains($column.type))\n #set($jdbcType=\"INTEGER\")\n #elseif($tool.newHashSet(\"java.lang.Float\", \"float\", \"java.lang.Double\", \"double\").contains($column.type))\n #set($jdbcType=\"NUMERIC\")\n #elseif($tool.newHashSet(\"java.util.Date\", \"java.sql.Timestamp\", \"java.time.Instant\", \"java.time.LocalDateTime\", \"java.time.OffsetDateTime\", \"\tjava.time.ZonedDateTime\").contains($column.type))\n #set($jdbcType=\"TIMESTAMP\")\n #elseif($tool.newHashSet(\"java.sql.Date\", \"java.time.LocalDate\").contains($column.type))\n #set($jdbcType=\"TIMESTAMP\")\n #else\n ##其他类型\n #set($jdbcType=\"VARCHAR\")\n #end\n $tool.call($column.ext.put(\"jdbcType\", $jdbcType))\n#end\n\n##定义宏,查询所有列\n#macro(allSqlColumn)#foreach($column in $tableInfo.fullColumn)$column.obj.name#if($foreach.hasNext), #end#end#end\n" + } ] + } + } +} \ No newline at end of file diff --git a/springboot-log/git-info.bat b/springboot-log/git-info.bat new file mode 100644 index 0000000..abc88de --- /dev/null +++ b/springboot-log/git-info.bat @@ -0,0 +1,13 @@ +@echo off +set time=%date:~0,4%-%date:~5,2%-%date:~8,2% %time:~0,2%:%time:~3,2%:%time:~6,2% +set app=springboot-demo +for /F %%i in ('git rev-parse --short HEAD') do ( set commit_id=%%i) +for /F %%i in ('git rev-parse --abbrev-ref HEAD') do ( set branch_id=%%i) +echo build_app = %app% > ./src/main/resources/build.properties +echo build_time = %time% >> ./src/main/resources/build.properties +echo git_commit = %commit_id% >> ./src/main/resources/build.properties +echo git_branch = %branch_id% >> ./src/main/resources/build.properties +echo start %app% at %date:~0,4%-%date:~5,2%-%date:~8,2% %time:~0,2%:%time:~3,2%:%time:~6,2% +::echo "build_version = '${version}'" > ./src/main/resources/build.properties +::echo "upload %app%" +::echo "done %app% %time% at $(date "+%Y-%m-%d %H:%M:%S")" diff --git a/springboot-log/pom.xml b/springboot-log/pom.xml new file mode 100644 index 0000000..be8f940 --- /dev/null +++ b/springboot-log/pom.xml @@ -0,0 +1,237 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.1.13.RELEASE + + + com.pancm + springboot-log + 0.0.1-SNAPSHOT + springboot-log + Demo project for Spring Boot + + + 1.8 + 1.7.25 + 1.2.3 + 3.5.0 + 2.6.2 + 2.9.2 + 1.5.21 + 1.9.6 + 1.2.62 + 5.1.41 + 1.1.12 + 4.0.3 + 1.3.1 + 1.1.4 + 2.9.2 + 1.5.21 + 1.9.6 + + + + + + local + + local + + + + true + + + + + dev + + dev + + + + + prod + + prod + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.springframework.boot + spring-boot-starter-jdbc + + + org.apache.tomcat + tomcat-jdbc + + + org.springframework.boot + spring-boot-starter-logging + + + + + mysql + mysql-connector-java + ${mysql.connector.version} + + + com.alibaba + druid + ${alibaba.druid.version} + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + ${mybatis.spring.boot.version} + + + tk.mybatis + mapper-spring-boot-starter + ${tk.mybatis.boot.version} + + + com.baomidou + mybatis-plus-boot-starter + 3.0.5 + + + + org.mybatis.generator + mybatis-generator-core + 1.3.5 + + + com.github.pagehelper + pagehelper + ${pagehelper.version} + + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + ch.qos.logback + logback-classic + ${logback.version} + + + ch.qos.logback + logback-core + ${logback.version} + + + + org.springframework.boot + spring-boot-starter-websocket + + + + + javax.servlet + servlet-api + 2.5 + provided + + + + + + com.alibaba + fastjson + ${alibaba.fastjson} + + + + + io.springfox + springfox-swagger2 + ${swagger.version} + + + io.swagger + swagger-models + + + + + + io.swagger + swagger-models + ${swagger.model.version} + + + io.springfox + springfox-swagger-ui + ${swagger.version} + + + + com.github.xiaoymin + swagger-bootstrap-ui + ${swagger.bootstrap.ui.version} + + + + + com.idea-aedi + logback-defender + 1.0.0 + + + + + + + + springboot-log + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + diff --git a/springboot-log/src/main/java/com/pancm/Application.java b/springboot-log/src/main/java/com/pancm/Application.java new file mode 100644 index 0000000..413880d --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/Application.java @@ -0,0 +1,40 @@ +package com.pancm; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.servlet.ServletComponentScan; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.Environment; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** +* @Title: Application +* @Description: main +* @Version:1.0.0 +* @Since:jdk1.8 +* @author pancm +* @Date 2021/10/15 +**/ +@ServletComponentScan +@SpringBootApplication +@Slf4j +public class Application { + + public static void main(String[] args) throws UnknownHostException { + ConfigurableApplicationContext application = SpringApplication.run(Application.class, args); + Environment env = application.getEnvironment(); + String ip = InetAddress.getLocalHost().getHostAddress(); + String port = env.getProperty("server.port"); + String path = env.getProperty("server.servlet.context-path"); + log.info("\n----------------------------------------------------------\n\t" + + "Application springboot-demo is running! Access URLs:\n\t" + + "Local: \t\thttp://localhost:" + port + path + "/\n\t" + + "External: \thttp://" + ip + ":" + port + path + "/\n\t" + + "Swagger文档: \thttp://" + ip + ":" + port + path + "/doc.html\n" + + "----------------------------------------------------------"); + } + +} diff --git a/springboot-log/src/main/java/com/pancm/config/CorsFilter.java b/springboot-log/src/main/java/com/pancm/config/CorsFilter.java new file mode 100644 index 0000000..05e8191 --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/config/CorsFilter.java @@ -0,0 +1,49 @@ +package com.pancm.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.util.StringUtils; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @Author pancm + * @Description + * @Date 2019/2/17 + * @Param + * @return + **/ +@Configuration +public class CorsFilter implements Filter { + + @Override + public void init(FilterConfig filterConfig) { + + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse; + String origin = ((HttpServletRequest) servletRequest).getHeader("Origin"); + if (StringUtils.isEmpty(origin)) { + origin = "*"; + } + String rh = ((HttpServletRequest) servletRequest).getHeader("Access-Control-Request-Headers"); + if (StringUtils.isEmpty(origin)) { + rh = "DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control," + + "Content-Type,Authorization,SessionToken,Content-Disposition"; + } + httpServletResponse.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); + httpServletResponse.setHeader("Access-Control-Allow-Origin", origin); + httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true"); + httpServletResponse.setHeader("Access-Control-Allow-Headers", rh); + filterChain.doFilter(servletRequest, servletResponse); + } + + @Override + public void destroy() { + + } +} diff --git a/springboot-log/src/main/java/com/pancm/config/DemoDefenderStrategy.java b/springboot-log/src/main/java/com/pancm/config/DemoDefenderStrategy.java new file mode 100644 index 0000000..f8dc36b --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/config/DemoDefenderStrategy.java @@ -0,0 +1,24 @@ +package com.pancm.config; + +@Component("demoDefenderStrategy") +public class DemoDefenderStrategy implements DefenderStrategy{ + @Override + public String category() { + return "name"; + } + + @Override + public int retainPrefixCount() { + return 1; + } + + @Override + public int retainSuffixCount() { + return 1; + } + + @Override + public char replaceChar() { + return '$'; + } +} \ No newline at end of file diff --git a/springboot-log/src/main/java/com/pancm/config/PancmConfiguration.java b/springboot-log/src/main/java/com/pancm/config/PancmConfiguration.java new file mode 100644 index 0000000..9b7e58f --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/config/PancmConfiguration.java @@ -0,0 +1,120 @@ +package com.pancm.config; + +import com.alibaba.druid.pool.DruidDataSource; +import com.github.pagehelper.PageHelper; +import org.apache.ibatis.plugin.Interceptor; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.mybatis.spring.SqlSessionTemplate; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +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 org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; + +import javax.sql.DataSource; +import java.util.Objects; +import java.util.Properties; + +import static com.pancm.config.PancmConfiguration.PACKAGE; + +/** + * @Author pancm + * @Description + * @Date 2019/2/17 + * @Param + * @return + **/ +@Configuration +@MapperScan(basePackages = {PACKAGE}, sqlSessionFactoryRef = "pancmSqlSessionFactory") +public class PancmConfiguration { + + static final String PACKAGE = "com.pancm.dao"; + static final String MAPPER_LOCATION = "classpath:pancm/mapper/*.xml"; + static final String CONFIG_LOCATION = "classpath:pancm/mybatis-config.xml"; + + + + @Value("${spring.datasource.pancm.driver-class-name}") + private String driverClassName; + + @Value("${spring.datasource.pancm.url}") + private String url; + + @Value("${spring.datasource.pancm.username}") + private String username; + + @Value("${spring.datasource.pancm.password}") + private String password; + + + @Bean(name = "pancmDataSource") + @ConfigurationProperties(prefix = "spring.datasource.pancm") + @Primary + public DataSource pancmDataSource() { + DruidDataSource dataSource = new DruidDataSource(); + dataSource.setDriverClassName(driverClassName); + dataSource.setUrl(url); + dataSource.setUsername(username); + dataSource.setPassword(password); + dataSource.setInitialSize(10); + dataSource.setMinIdle(10); + dataSource.setMaxActive(30); + dataSource.setMaxWait(30000); + dataSource.setRemoveAbandoned(true); + dataSource.setRemoveAbandonedTimeout(1800); + dataSource.setLogAbandoned(false); + dataSource.setTimeBetweenEvictionRunsMillis(60000); + dataSource.setMinEvictableIdleTimeMillis(300000); + dataSource.setValidationQuery("SELECT 1"); + dataSource.setTestWhileIdle(true); + dataSource.setTestOnBorrow(false); + dataSource.setTestOnReturn(false); + dataSource.setPoolPreparedStatements(true); + dataSource.setMaxPoolPreparedStatementPerConnectionSize(500); + dataSource.setKeepAlive(true); + dataSource.setDbType("mysql"); + return dataSource; + } + + @Bean(name = "pancmSqlSessionFactory") + @Primary + public SqlSessionFactory pancmSqlSessionFactory(@Qualifier("pancmDataSource") DataSource dataSource) throws Exception { + SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); + bean.setDataSource(dataSource); + + //分页插件 + PageHelper pageHelper = new PageHelper(); + Properties properties = new Properties(); + properties.setProperty("reasonable", "true"); + properties.setProperty("supportMethodsArguments", "true"); + properties.setProperty("returnPageInfo", "check"); + properties.setProperty("params", "count=countSql"); + pageHelper.setProperties(properties); + + //添加插件 + bean.setPlugins(new Interceptor[]{pageHelper}); + + bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_LOCATION)); + bean.setConfigLocation(new PathMatchingResourcePatternResolver().getResource(CONFIG_LOCATION)); + Objects.requireNonNull(bean.getObject()).getConfiguration().setMapUnderscoreToCamelCase(true); + return bean.getObject(); + } + + @Bean(name = "pancmTransactionManager") + @Primary + public DataSourceTransactionManager testTransactionManager(@Qualifier("pancmDataSource") DataSource dataSource) { + return new DataSourceTransactionManager(dataSource); + } + + @Bean(name = "pancmSqlSessionTemplate") + @Primary + public SqlSessionTemplate testSqlSessionTemplate(@Qualifier("pancmSqlSessionFactory") SqlSessionFactory sqlSessionFactory) + throws Exception { + return new SqlSessionTemplate(sqlSessionFactory); + } +} diff --git a/springboot-log/src/main/java/com/pancm/config/PluginOne.java b/springboot-log/src/main/java/com/pancm/config/PluginOne.java new file mode 100644 index 0000000..2530c79 --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/config/PluginOne.java @@ -0,0 +1,17 @@ +package com.pancm.config; + +@Component + public class PluginOne implements LogbackMessageDefender { + + public static final String HANDLE_BY_PLUGIN = "PluginOneAbc"; + + @Override + public boolean support(ILoggingEvent event) { + return event.getMDCPropertyMap().containsKey(HANDLE_BY_PLUGIN); + } + + @Override + public void desensitize(ILoggingEvent event, String message, StringBuilder buffer) { + buffer.append("[O_O] ").append(event.getFormattedMessage()).append(" [O_O]"); + } + } \ No newline at end of file diff --git a/springboot-log/src/main/java/com/pancm/config/SpringBeanFactory.java b/springboot-log/src/main/java/com/pancm/config/SpringBeanFactory.java new file mode 100644 index 0000000..9a6ed7a --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/config/SpringBeanFactory.java @@ -0,0 +1,50 @@ +package com.pancm.config; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +/** + * @Title: SpringBeanFactory + * @Description: + * @Version:1.0.0 + * @Since:jdk1.8 + * @author pancm + * @Date 2021/7/2 + **/ +@Component +public class SpringBeanFactory implements ApplicationContextAware { + + // Spring应用上下文环境 + private static ApplicationContext applicationContext; + + /** + * 实现ApplicationContextAware接口的回调方法,设置上下文环境 + */ + @Override + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + SpringBeanFactory.applicationContext = applicationContext; + } + + public static ApplicationContext getApplicationContext() { + return applicationContext; + } + + /** + * 获取对象 这里重写了bean方法,起主要作用 + */ + public static Object getBean(String beanId) throws BeansException { + if (applicationContext == null) return null; + return applicationContext.getBean(beanId); + } + + /** + * 获取当前环境 + */ + public static String getActiveProfile() { + return applicationContext.getEnvironment().getActiveProfiles()[0]; + } + +} diff --git a/springboot-log/src/main/java/com/pancm/config/SwaggerConfig.java b/springboot-log/src/main/java/com/pancm/config/SwaggerConfig.java new file mode 100644 index 0000000..1a93d99 --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/config/SwaggerConfig.java @@ -0,0 +1,64 @@ +package com.pancm.config; + +import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrapUI; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.bind.annotation.RequestMethod; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.ParameterBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.schema.ModelRef; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.Contact; +import springfox.documentation.service.Parameter; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +import java.util.ArrayList; +import java.util.List; + +/** + * @Author pancm + * @Description + * @Date 2019/2/17 + * @Param + * @return + **/ +@Configuration +@EnableSwagger2 +@EnableSwaggerBootstrapUI +public class SwaggerConfig { + + @Bean + public Docket createRestApi() { + //添加head参数start + ParameterBuilder tokenPar = new ParameterBuilder(); + List pars = new ArrayList(); + tokenPar.name("token").description("令牌").modelRef(new ModelRef("string")).parameterType("header").required(false).build(); + pars.add(tokenPar.build()); + //添加head参数end + + + return new Docket(DocumentationType.SWAGGER_2) + .apiInfo(apiInfo()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.pancm.controller")) + .paths(PathSelectors.any()) + .build() + .globalOperationParameters(pars) + ; + } + + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title("pancm-swagger2") + .description("Restful-API-Doc") + .termsOfServiceUrl("https://www.cnblogs.com/xuwujing") + .contact(new Contact("虚无境的博客", "https://www.cnblogs.com/xuwujing", "xxx@qq.com")) + .version("1.0") + .build(); + } +} diff --git a/springboot-log/src/main/java/com/pancm/controller/HomeController.java b/springboot-log/src/main/java/com/pancm/controller/HomeController.java new file mode 100644 index 0000000..527f9a6 --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/controller/HomeController.java @@ -0,0 +1,53 @@ +package com.pancm.controller; + +import com.alibaba.fastjson.JSONObject; +import com.pancm.util.FileHelper; +import com.pancm.util.GetProperties; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * @Author pancm + * @Description + * @Date 2019/2/17 + * @Param + * @return + **/ +@RestController +@RequestMapping("/home") +@Slf4j +@Api(tags = "首页相关接口") +public class HomeController { + + + @Value("${spring.profiles.active}") + String active; + + private final static String VERSION_NAME = "version.txt"; + + @ApiOperation(value = "/version", notes = "版本信息") + @RequestMapping(value = "/version", method = {RequestMethod.GET}) + public JSONObject version(HttpServletRequest request){ + Map map = GetProperties.getAppSettings(); + JSONObject result = new JSONObject(); + result.put("git_branch", map.get("git_branch")); + result.put("build_time", map.get("build_time")); + result.put("git_commit", map.get("git_commit")); + result.put("app_name", map.get("build_app")); + result.put("profile", active); + result.put("version", FileHelper.readResourcesFile(VERSION_NAME)); + return result; + } + + + + +} diff --git a/springboot-log/src/main/java/com/pancm/controller/TSysUserController.java b/springboot-log/src/main/java/com/pancm/controller/TSysUserController.java new file mode 100644 index 0000000..8483569 --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/controller/TSysUserController.java @@ -0,0 +1,103 @@ +package com.pancm.controller; + +import com.pancm.vo.TSysUserVO; +import com.pancm.service.ITSysUserService; +import org.springframework.web.bind.annotation.*; + + +import com.pancm.vo.ApiResult; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; + + + +/** +* @Title: 用户表(TSysUser)表控制层 +* @Description: +* @Version:1.0.0 +* @Since:jdk1.8 +* @author pancm +* @date 2024-04-01 09:30:51 +*/ +@Api(tags = "用户表(TSysUser)") +@RestController +@RequestMapping("tSysUser") +public class TSysUserController { + /** + * 服务对象 + */ + @Autowired + private ITSysUserService tSysUserService; + + + /** + * 新增一条数据 + * + * @param tSysUserVO 实体类 + * @return Response对象 + */ + @ApiOperation(value = "用户表新增",notes = "用户表新增") + @RequestMapping(value = "save", method = RequestMethod.POST) + public ApiResult insert(@RequestBody TSysUserVO tSysUserVO, HttpServletRequest httpRequest) { + int result = tSysUserService.insert(tSysUserVO); + if (result > 0) { + return ApiResult.success(); + } + return ApiResult.error("新增失败"); + } + + /** + * 修改一条数据 + * + * @param tSysUserVO 实体类 + * @return Response对象 + */ + @ApiOperation(value = "用户表修改",notes = "用户表修改") + @RequestMapping(value = "edit", method = RequestMethod.POST) + public ApiResult update(@RequestBody TSysUserVO tSysUserVO, HttpServletRequest httpRequest) { + tSysUserService.update(tSysUserVO); + return ApiResult.success(); + } + + /** + * 删除一条数据 + * + * @param tSysUserVO 参数对象 + * @return Response对象 + */ + @ApiOperation(value = "用户表删除",notes = "用户表删除") + @RequestMapping(value = "del", method = RequestMethod.POST) + public ApiResult delete(@RequestBody TSysUserVO tSysUserVO, HttpServletRequest httpRequest) { + tSysUserService.deleteById(tSysUserVO.getId()); + return ApiResult.success(); + } + + + + /** + * 分页查询 + * + */ + @ApiOperation(value = "用户表查询",notes = "用户表查询") + @RequestMapping(value = "list", method = RequestMethod.POST) + public ApiResult list(@RequestBody TSysUserVO tSysUserVO) { + return tSysUserService.list(tSysUserVO); + } + + /** + * 详情查询 + * + */ + @ApiOperation(value = "用户表详情",notes = "用户表详情") + @RequestMapping(value = "view", method = RequestMethod.GET) + public ApiResult view( @RequestParam("id") String id) { + return ApiResult.success(tSysUserService.queryById(id)); + } +} diff --git a/springboot-log/src/main/java/com/pancm/controller/UserController.java b/springboot-log/src/main/java/com/pancm/controller/UserController.java new file mode 100644 index 0000000..94fa064 --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/controller/UserController.java @@ -0,0 +1,103 @@ +package com.pancm.controller; + +import com.pancm.vo.UserVO; +import com.pancm.service.IUserService; +import org.springframework.web.bind.annotation.*; + + +import com.pancm.vo.ApiResult; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; + + + +/** +* @Title: 用户表(User)表控制层 +* @Description: +* @Version:1.0.0 +* @Since:jdk1.8 +* @author pancm +* @date 2024-01-15 15:27:02 +*/ +@Api(tags = "用户表(User)") +@RestController +@RequestMapping("user") +public class UserController { + /** + * 服务对象 + */ + @Autowired + private IUserService userService; + + + /** + * 新增一条数据 + * + * @param userVO 实体类 + * @return Response对象 + */ + @ApiOperation(value = "用户表新增",notes = "用户表新增") + @RequestMapping(value = "save", method = RequestMethod.POST) + public ApiResult insert(@RequestBody UserVO userVO, HttpServletRequest httpRequest) { + int result = userService.insert(userVO); + if (result > 0) { + return ApiResult.success(); + } + return ApiResult.error("新增失败"); + } + + /** + * 修改一条数据 + * + * @param userVO 实体类 + * @return Response对象 + */ + @ApiOperation(value = "用户表修改",notes = "用户表修改") + @RequestMapping(value = "edit", method = RequestMethod.POST) + public ApiResult update(@RequestBody UserVO userVO, HttpServletRequest httpRequest) { + userService.update(userVO); + return ApiResult.success(); + } + + /** + * 删除一条数据 + * + * @param userVO 参数对象 + * @return Response对象 + */ + @ApiOperation(value = "用户表删除",notes = "用户表删除") + @RequestMapping(value = "del", method = RequestMethod.POST) + public ApiResult delete(@RequestBody UserVO userVO, HttpServletRequest httpRequest) { + userService.deleteById(userVO.getId()); + return ApiResult.success(); + } + + + + /** + * 分页查询 + * + */ + @ApiOperation(value = "用户表查询",notes = "用户表查询") + @RequestMapping(value = "list", method = RequestMethod.POST) + public ApiResult list(@RequestBody UserVO userVO) { + return userService.list(userVO); + } + + /** + * 详情查询 + * + */ + @ApiOperation(value = "用户表详情",notes = "用户表详情") + @RequestMapping(value = "view", method = RequestMethod.GET) + public ApiResult view( @RequestParam("id") Long id) { + return ApiResult.success(userService.queryById(id)); + } +} diff --git a/springboot-log/src/main/java/com/pancm/dao/TSysUserDao.java b/springboot-log/src/main/java/com/pancm/dao/TSysUserDao.java new file mode 100644 index 0000000..c067c6f --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/dao/TSysUserDao.java @@ -0,0 +1,87 @@ +package com.pancm.dao; + +import com.pancm.model.TSysUser; +import com.pancm.vo.TSysUserVO; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Mapper; +import java.util.List; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + + /** +* @Title: 用户表(TSysUser)表数据库访问层 +* @Description: +* @Version:1.0.0 +* @Since:jdk1.8 +* @author pancm +* @date 2024-04-01 09:30:54 +*/ +@Mapper +public interface TSysUserDao extends BaseMapper { + + /** + * 通过ID查询单条数据 + * + * @param id 主键 + * @return 实例对象 + */ + TSysUserVO queryById(String id); + + + /** + * 通过实体查询一条数据 + * + * @param tSysUserVO 实例对象 + * @return 对象列表 + */ + TSysUserVO findOne(TSysUserVO tSysUserVO); + + /** + * 通过实体作为筛选条件查询 + * + * @param tSysUserVO 实例对象 + * @return 对象列表 + */ + List queryAll(TSysUserVO tSysUserVO); + + /** + * 新增数据 + * + * @param tSysUser 实例对象 + * @return 影响行数 + */ + int insert(TSysUser tSysUser); + + /** + * 批量新增数据(MyBatis原生foreach方法) + * + * @param entities List 实例对象列表 + * @return 影响行数 + */ + int insertBatch(@Param("entities") List entities); + + /** + * 批量新增或按主键更新数据(MyBatis原生foreach方法) + * + * @param entities List 实例对象列表 + * @return 影响行数 + */ + int insertOrUpdateBatch(@Param("entities") List entities); + + /** + * 修改数据 + * + * @param tSysUser 实例对象 + * @return 影响行数 + */ + int update(TSysUser tSysUser); + + /** + * 通过主键删除数据 + * + * @param id 主键 + * @return 影响行数 + */ + int deleteById(String id); + +} + diff --git a/springboot-log/src/main/java/com/pancm/dao/UserDao.java b/springboot-log/src/main/java/com/pancm/dao/UserDao.java new file mode 100644 index 0000000..4992e68 --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/dao/UserDao.java @@ -0,0 +1,88 @@ +package com.pancm.dao; + +import com.pancm.model.User; +import com.pancm.vo.UserVO; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Mapper; +import tk.mybatis.mapper.common.BaseMapper; + +import java.util.List; + + /** +* @Title: 用户表(User)表数据库访问层 +* @Description: +* @Version:1.0.0 +* @Since:jdk1.8 +* @author pancm +* @date 2024-01-15 15:27:04 +*/ +@Mapper +public interface UserDao { + + /** + * 通过ID查询单条数据 + * + * @param id 主键 + * @return 实例对象 + */ + UserVO queryById(Long id); + + + /** + * 通过实体查询一条数据 + * + * @param userVO 实例对象 + * @return 对象列表 + */ + UserVO findOne(UserVO userVO); + + /** + * 通过实体作为筛选条件查询 + * + * @param userVO 实例对象 + * @return 对象列表 + */ + List queryAll(UserVO userVO); + + /** + * 新增数据 + * + * @param user 实例对象 + * @return 影响行数 + */ + int insert(User user); + + /** + * 批量新增数据(MyBatis原生foreach方法) + * + * @param entities List 实例对象列表 + * @return 影响行数 + */ + int insertBatch(@Param("entities") List entities); + + /** + * 批量新增或按主键更新数据(MyBatis原生foreach方法) + * + * @param entities List 实例对象列表 + * @return 影响行数 + */ + int insertOrUpdateBatch(@Param("entities") List entities); + + /** + * 修改数据 + * + * @param user 实例对象 + * @return 影响行数 + */ + int update(User user); + + /** + * 通过主键删除数据 + * + * @param id 主键 + * @return 影响行数 + */ + int deleteById(Long id); + +} + diff --git a/springboot-log/src/main/java/com/pancm/enums/SimpleDefenderStrategy.java b/springboot-log/src/main/java/com/pancm/enums/SimpleDefenderStrategy.java new file mode 100644 index 0000000..a92ad22 --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/enums/SimpleDefenderStrategy.java @@ -0,0 +1,24 @@ +package com.pancm.enums; + +public enum SimpleDefenderStrategy implements DefenderStrategy { + + /** 姓名类脱敏策略 */ + NAME("name", 1, 1, '*'), + + /** 账号类脱敏策略 */ + ACCOUNT_NO("accountNo", 2, 2, '*'), + + /** 邮箱类脱敏策略 */ + EMAIL("email", 2, 7, '*'), + + /** 身份证号类脱敏策略 */ + ID_CARD("idCard", 6, 4, '*'), + + /** 手机号码类脱敏策略 */ + PHONE_NUMBER("phoneNumber", 3, 4, '*'), + + /** 住址类脱敏策略 */ + ADDRESS("address", 3, 4, '*'); + + // 省略... +} \ No newline at end of file diff --git a/springboot-log/src/main/java/com/pancm/model/TSysUser.java b/springboot-log/src/main/java/com/pancm/model/TSysUser.java new file mode 100644 index 0000000..5ded285 --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/model/TSysUser.java @@ -0,0 +1,61 @@ +package com.pancm.model; + + +import com.alibaba.fastjson.JSONObject; +import lombok.Data; + +import javax.persistence.Column; +import javax.persistence.Table; +import java.io.Serializable; +import java.sql.Date; + + /** +* @Title: 用户表(TSysUser)实体类 +* @Description: +* @Version:1.0.0 +* @Since:jdk1.8 +* @author pancm +* @date 2024-04-01 09:30:55 +*/ +@Data +@Table(name = "t_sys_user") +public class TSysUser implements Serializable { + private static final long serialVersionUID = -56958960669065369L; + /** + * 主键 + */ + @Column(name = "id") + private String id; + /** + * 用户账号 + */ + @Column(name = "username") + private String username; + /** + * 用户密码 + */ + @Column(name = "password") + private String password; + /** + * 昵称 + */ + @Column(name = "nickname") + private String nickname; + /** + * 部门id + */ + @Column(name = "dep_id") + private Integer depId; + /** + * 岗位id + */ + @Column(name = "pos_id") + private String posId; + + + @Override + public String toString(){ + return JSONObject.toJSONString(this); + } + +} diff --git a/springboot-log/src/main/java/com/pancm/model/User.java b/springboot-log/src/main/java/com/pancm/model/User.java new file mode 100644 index 0000000..d440a6c --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/model/User.java @@ -0,0 +1,71 @@ +package com.pancm.model; + + +import com.alibaba.fastjson.JSONObject; +import lombok.Data; + +import javax.persistence.Column; +import javax.persistence.Table; +import java.io.Serializable; +import java.sql.Date; + + /** +* @Title: 用户表(User)实体类 +* @Description: +* @Version:1.0.0 +* @Since:jdk1.8 +* @author pancm +* @date 2024-01-15 15:27:05 +*/ +@Data +@Table(name = "user") +public class User implements Serializable { + private static final long serialVersionUID = -59671741667391987L; + /** + * ID + */ + @Column(name = "id") + private Long id; + /** + * 姓名 + */ + @Column(name = "name") + private String name; + /** + * 性别 + */ + @Column(name = "sex") + private Integer sex; + /** + * 年龄 + */ + @Column(name = "age") + private Integer age; + /** + * 创建时间 + */ + @Column(name = "create_time") + private Date createTime; + /** + * 创建人 + */ + @Column(name = "create_by") + private String createBy; + /** + * 更新时间 + */ + @Column(name = "update_time") + private Date updateTime; + /** + * 更新人 + */ + @Column(name = "update_by") + private String updateBy; + + + @Override + public String toString(){ + return JSONObject.toJSONString(this); + } + +} diff --git a/springboot-log/src/main/java/com/pancm/service/ITSysUserService.java b/springboot-log/src/main/java/com/pancm/service/ITSysUserService.java new file mode 100644 index 0000000..77d97b4 --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/service/ITSysUserService.java @@ -0,0 +1,62 @@ +package com.pancm.service; + +import com.pancm.vo.TSysUserVO; +import com.pancm.model.TSysUser; +import com.pancm.vo.ApiResult; +import java.util.List; +import com.baomidou.mybatisplus.extension.service.IService; + + + /** +* @Title: 用户表(TSysUser)表服务接口 +* @Description: +* @Version:1.0.0 +* @Since:jdk1.8 +* @author pancm +* @date 2024-04-01 09:30:53 +*/ +public interface ITSysUserService extends IService{ + + /** + * 通过ID查询单条数据 + * + * @param id 主键 + * @return 实例对象 + */ + TSysUserVO queryById(String id); + + + /** + * 通过实体作为筛选条件查询 + * + * @param tSysUserVO 实例对象 + * @return 对象列表 + */ + ApiResult list(TSysUserVO tSysUserVO); + + + /** + * 新增数据 + * + * @param tSysUserVO 实例对象 + * @return 实例对象 + */ + int insert(TSysUserVO tSysUserVO); + + /** + * 修改数据 + * + * @param tSysUserVO 实例对象 + * @return 实例对象 + */ + int update(TSysUserVO tSysUserVO); + + /** + * 通过主键删除数据 + * + * @param id 主键 + * @return 是否成功 + */ + boolean deleteById(String id); + +} diff --git a/springboot-log/src/main/java/com/pancm/service/IUserService.java b/springboot-log/src/main/java/com/pancm/service/IUserService.java new file mode 100644 index 0000000..f87a804 --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/service/IUserService.java @@ -0,0 +1,60 @@ +package com.pancm.service; + +import com.pancm.vo.UserVO; +import com.pancm.vo.ApiResult; +import java.util.List; + + + /** +* @Title: 用户表(User)表服务接口 +* @Description: +* @Version:1.0.0 +* @Since:jdk1.8 +* @author pancm +* @date 2024-01-15 15:27:03 +*/ +public interface IUserService { + + /** + * 通过ID查询单条数据 + * + * @param id 主键 + * @return 实例对象 + */ + UserVO queryById(Long id); + + + /** + * 通过实体作为筛选条件查询 + * + * @param userVO 实例对象 + * @return 对象列表 + */ + ApiResult list(UserVO userVO); + + + /** + * 新增数据 + * + * @param userVO 实例对象 + * @return 实例对象 + */ + int insert(UserVO userVO); + + /** + * 修改数据 + * + * @param userVO 实例对象 + * @return 实例对象 + */ + int update(UserVO userVO); + + /** + * 通过主键删除数据 + * + * @param id 主键 + * @return 是否成功 + */ + boolean deleteById(Long id); + +} diff --git a/springboot-log/src/main/java/com/pancm/service/impl/TSysUserServiceImpl.java b/springboot-log/src/main/java/com/pancm/service/impl/TSysUserServiceImpl.java new file mode 100644 index 0000000..da98bb8 --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/service/impl/TSysUserServiceImpl.java @@ -0,0 +1,97 @@ +package com.pancm.service.impl; + + +import com.pancm.vo.TSysUserVO; +import com.pancm.model.TSysUser; +import com.pancm.dao.TSysUserDao; +import com.pancm.service.ITSysUserService; + +import com.github.pagehelper.Page; +import com.github.pagehelper.PageHelper; +import com.pancm.vo.ApiResult; +import com.pancm.vo.PageResult; +import org.springframework.stereotype.Service; +import org.springframework.beans.BeanUtils; +import javax.annotation.Resource; +import java.util.List; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + + + +/** +* @Title: 用户表(TSysUser)表服务实现类 +* @Description: +* @Version:1.0.0 +* @Since:jdk1.8 +* @author pancm +* @date 2024-04-01 09:30:54 +*/ +@Service("tSysUserService") +public class TSysUserServiceImpl extends ServiceImpl implements ITSysUserService { + @Resource + private TSysUserDao tSysUserDao; + + /** + * 通过ID查询单条数据 + * + * @param id 主键 + * @return 实例对象 + */ + @Override + public TSysUserVO queryById(String id) { + return this.tSysUserDao.queryById(id); + } + + + /** + * 根据条件查询 + * + * @return 实例对象的集合 + */ + @Override + public ApiResult list(TSysUserVO tSysUser) { + int pageNum = tSysUser.getPageNum(); + int pageSize = tSysUser.getPageSize(); + Page page = PageHelper.startPage(pageNum, pageSize); + List result = tSysUserDao.queryAll(tSysUser); + return ApiResult.success(new PageResult<>(page.getTotal(), result, pageSize, pageNum)); + + } + + /** + * 新增数据 + * + * @param tSysUserVO 实例对象 + * @return 实例对象 + */ + @Override + public int insert(TSysUserVO tSysUserVO) { + TSysUser tSysUser = new TSysUser(); + BeanUtils.copyProperties(tSysUserVO,tSysUser); + return tSysUserDao.insert(tSysUser); + } + + /** + * 修改数据 + * + * @param tSysUserVO 实例对象 + * @return 实例对象 + */ + @Override + public int update(TSysUserVO tSysUserVO) { + TSysUser tSysUser = new TSysUser(); + BeanUtils.copyProperties(tSysUserVO,tSysUser); + return tSysUserDao.update(tSysUser); + } + + /** + * 通过主键删除数据 + * + * @param id 主键 + * @return 是否成功 + */ + @Override + public boolean deleteById(String id) { + return this.tSysUserDao.deleteById(id) > 0; + } +} diff --git a/springboot-log/src/main/java/com/pancm/service/impl/UserServiceImpl.java b/springboot-log/src/main/java/com/pancm/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..a7a5268 --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/service/impl/UserServiceImpl.java @@ -0,0 +1,96 @@ +package com.pancm.service.impl; + + +import com.pancm.vo.UserVO; +import com.pancm.model.User; +import com.pancm.dao.UserDao; +import com.pancm.service.IUserService; + +import com.github.pagehelper.Page; +import com.github.pagehelper.PageHelper; +import com.pancm.vo.ApiResult; +import com.pancm.vo.PageResult; +import org.springframework.stereotype.Service; +import org.springframework.beans.BeanUtils; +import javax.annotation.Resource; +import java.util.List; + + + +/** +* @Title: 用户表(User)表服务实现类 +* @Description: +* @Version:1.0.0 +* @Since:jdk1.8 +* @author pancm +* @date 2024-01-15 15:27:04 +*/ +@Service("userService") +public class UserServiceImpl implements IUserService { + @Resource + private UserDao userDao; + + /** + * 通过ID查询单条数据 + * + * @param id 主键 + * @return 实例对象 + */ + @Override + public UserVO queryById(Long id) { + return this.userDao.queryById(id); + } + + + /** + * 根据条件查询 + * + * @return 实例对象的集合 + */ + @Override + public ApiResult list(UserVO user) { + int pageNum = user.getPageNum(); + int pageSize = user.getPageSize(); + Page page = PageHelper.startPage(pageNum, pageSize); + List result = userDao.queryAll(user); + return ApiResult.success(new PageResult<>(page.getTotal(), result, pageSize, pageNum)); + + } + + /** + * 新增数据 + * + * @param userVO 实例对象 + * @return 实例对象 + */ + @Override + public int insert(UserVO userVO) { + User user = new User(); + BeanUtils.copyProperties(userVO,user); + return userDao.insert(user); + } + + /** + * 修改数据 + * + * @param userVO 实例对象 + * @return 实例对象 + */ + @Override + public int update(UserVO userVO) { + User user = new User(); + BeanUtils.copyProperties(userVO,user); + return userDao.update(user); + } + + /** + * 通过主键删除数据 + * + * @param id 主键 + * @return 是否成功 + */ + @Override + public boolean deleteById(Long id) { + return this.userDao.deleteById(id) > 0; + } +} diff --git a/springboot-log/src/main/java/com/pancm/util/FileHelper.java b/springboot-log/src/main/java/com/pancm/util/FileHelper.java new file mode 100644 index 0000000..b5fa52c --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/util/FileHelper.java @@ -0,0 +1,321 @@ +package com.pancm.util; + +import com.alibaba.fastjson.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.nio.charset.StandardCharsets; + + +/** + * @Author pancm + * @Description + * @Date 2019/2/17 + * @Param + * @return + **/ +public class FileHelper { + + private final static Logger log = LoggerFactory.getLogger(FileHelper.class); + + /** + * 行为单位读取文件,常用于读面向行的格式化文件 + * + * @param folder 文件目录 + * @param fileName 文件名 + * @return 文件内容,字符串格式 + */ + public static String readFileToString(String folder, String fileName) { + return readFileToString(folder + "/" + fileName); + } + + /** + * 以行为单位读取文件,常用于读面向行的格式化文件 + * + * @param filePath 文件路径 + * @return 文件内容,字符串 + */ + public static String readFileToString(String filePath) { + File file = new File(filePath); + BufferedReader reader = null; + StringBuilder builder = new StringBuilder(); + try { + reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)); + String tempString = null; + int line = 1; + // 一次读入一行,直到读入null为文件结束 + while ((tempString = reader.readLine()) != null) { + // 显示行号 + builder.append(tempString); + } + reader.close(); + } catch (IOException e) { + throw new RuntimeException("file error#" + filePath, e); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException e1) { + } + } + } + return builder.toString(); + } + + /** + * 读取文件,处理成 JSON格式 + * + * @param filePath 文件绝对路径 + * @return json格式 + */ + public static Object readFileToJson(String filePath) { + String content = FileHelper.readFileToString(filePath); + return JSONObject.parse(content); + } + + /** + * 相对路径转换为绝对路径 + * + * @param folderInput 相对路径,如./ + * @return 文件目录的绝对路径 + */ + public static String convertFolder(String folderInput) { + String folder = folderInput; + if (folderInput.startsWith("./")) { + String relativeFolder = folderInput.replace("./", ""); + String dir = System.getProperty("user.dir"); + folder = dir + "/" + relativeFolder; + } + return folder; + } + + + /** + * @return boolean + * @Author pancm + * @Description 创建文件夹--多层 + * @Date 2021/2/24 + * @Param [dir] + **/ + public static boolean createMultilayerFile(String dir) { + try { + File dirPath = new File(dir); + if (!dirPath.exists()) { + dirPath.mkdirs(); + } + } catch (Exception e) { + log.error("创建多层目录操作出错: " + e.getMessage()); + return false; + } + return true; + } + + + /** + * 文件本地存储 + * + * @param file 上传文件格式 + * @param destFolder 目标目录 + * @param destFileName 目标文件名 + * @return + */ + public static boolean saveFile(MultipartFile file, String destFolder, String destFileName) { + File dest = new File(destFolder + "/" + destFileName); +// if(!dest.getParentFile().exists()){ +// dest.getParentFile().mkdir(); +// } + createMultilayerFile(destFolder); + try { + file.transferTo(dest); + return true; + } catch (Exception e) { + log.error("file save error", e); + } + return false; + } + + + public static boolean saveFile(byte[] buf, String filePath, String fileName) { + BufferedOutputStream bos = null; + FileOutputStream fos = null; + File file = null; + try { + createMultilayerFile(filePath); + file = new File(filePath + File.separator + fileName); + fos = new FileOutputStream(file); + bos = new BufferedOutputStream(fos); + bos.write(buf); + } catch (Exception e) { + log.error("file save error", e); + return false; + } finally { + if (bos != null) { + try { + bos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return true; + } + + + /** + * 文件大小,单位 MB + * + * @param size 文件大小,单位byte + * @return 文件大小,MB + */ + public static long getSizeInMb(long size) { + return size / 1024 / 1024; + } + + /** + * 文件大小,单位 GB + * + * @param size 文件大小,单位byte + * @return 文件大小,GB + */ + public static long getSizeInGb(long size) { + return size / 1024 / 1024 / 1024; + } + + /** + * 获得文件扩展名 + * + * @param fileName 文件名 + * @return 扩展名,dot 后面的,如xls + */ + public static String getFileExtension(String fileName) { + if (fileName == null) { + return null; + } + int index = fileName.lastIndexOf("."); + if (index == -1) { + return null; + } + return fileName.substring(index + 1); + } + + /** + * 删除文件 + * + * @param folder 目录 + * @param fileName 文件名 + * @return 删除是否成功 + */ + public static boolean deleteFile(String folder, String fileName) { + return deleteFile(folder + "/" + fileName); + } + + /** + * 删除文件 + * + * @param filePath 文件的绝对路径 + * @return 删除是否成功 + */ + public static boolean deleteFile(String filePath) { + if (filePath == null) { + return false; + } + try { + File f = new File(filePath); + if (f.exists()) { + return f.delete(); + } + } catch (Exception ex) { + log.error("delete file error#" + filePath, ex); + } + return false; + } + + + public static String readResourcesFile(String path) { + StringBuilder sb = new StringBuilder(); + try (InputStream in = FileHelper.class.getClassLoader().getResourceAsStream(path)) { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + String msg = null; + while ((msg = reader.readLine()) != null) { + sb.append(msg); +// .append("\n") + } + + } catch (IOException e) { + log.error("read file error#", e); + } + return sb.toString(); + } + + + /** + * @Author beixing + * @Description 文件夹复制 + * @Date 2021/4/27 + * @Param + * @return + **/ + public static void copyFolder(String src, String des) { + //初始化文件复制 + File file1 = new File(src); + //把文件里面内容放进数组 + File[] fs = file1.listFiles(); + //初始化文件粘贴 + File file2 = new File(des); + //判断是否有这个文件有不管没有创建 + if (!file2.exists()) { + file2.mkdirs(); + } + //遍历文件及文件夹 + for (File f : fs) { + if (f.isFile()) { + ///调用文件拷贝的方法 + fileCopy(f.getPath(), des + File.separator + f.getName()); + } else if (f.isDirectory()) { + //文件夹 + copyFolder(f.getPath(), des + File.separator + f.getName()); + } + } + + } + + /** + * 文件复制的具体方法 + */ + public static void fileCopy(String src, String des) { + //io流固定格式 + try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(src)); + BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(des))) { + int i = -1;//记录获取长度 + byte[] bt = new byte[2014];//缓冲区 + while ((i = bis.read(bt)) != -1) { + bos.write(bt, 0, i); + } + } catch (IOException e) { + log.error("read file error#", e); + } + } + + + public static void main(String[] args) { + String source = "D:\\video\\ceshi\\2021\\4\\26\\18\\34020000001310000001"; + String target = "D:\\video\\diagnosis\\2021\\4\\26\\18\\34020000001310000001"; +// copyFolder(source,target); + + String srcFile = "D:\\video\\ceshi\\2021\\5\\7\\10\\34020000001310000001\\34020000001310000001_20210507105454_00001.jpg"; + String desFile = "D:\\video\\34020000001310000001_20210507105454_测试.jpg"; + fileCopy(srcFile,desFile); + + } + + +} diff --git a/springboot-log/src/main/java/com/pancm/util/GetProperties.java b/springboot-log/src/main/java/com/pancm/util/GetProperties.java new file mode 100644 index 0000000..7c580e8 --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/util/GetProperties.java @@ -0,0 +1,94 @@ +package com.pancm.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.util.*; +import java.util.Map.Entry; + +/** + * Title: getProperties + * Description: 获取配置文件 + * Version:1.0.0 + * + * @author pancm + * @date 2018年1月4日 + */ +public class GetProperties { + private static Map appSettings = new HashMap(); + private static final Logger LOG = LoggerFactory.getLogger(GetProperties.class); + private String pathName="build.properties"; + /** + * 初始化系统默认参数 + */ + private GetProperties(){ + init(); + } + + private void init(){ + InputStream in = null; + try{ + //获取resource中的配置 + in=this.getClass().getClassLoader().getResourceAsStream(pathName); + //获取项目同级的配置 +// in=new FileInputStream(new File(pathName)); + Properties prop = new Properties(); + prop.load(in); + Set> buf = prop.entrySet(); + Iterator> it = buf.iterator(); + while(it.hasNext()){ + Entry t = it.next(); + appSettings.put((String)t.getKey(), (String)t.getValue()); + } + }catch(IOException e){ + LOG.error("加载系统参数失败!",e); + }finally{ + if(null != in){ + try { + in.close(); + } catch (IOException e) { + LOG.error("加载系统参数失败!",e); + } + } + } + } + + /** + * 获取配置文件 + * + * @param + * @return app settings + */ + public synchronized static Map getAppSettings() { + if(null == appSettings || appSettings.isEmpty()){ + new GetProperties(); + } + return appSettings; + } + + /** + * Sets app settings. + * + * @param appSettings the app settings + * @param name the name + */ + public synchronized static void setAppSettings(Map appSettings,String name) { + if(null == appSettings || appSettings.isEmpty()){ + new GetProperties(); + } + GetProperties.appSettings = appSettings; + } + + /** + * 方法测试 + * + * @param args the input arguments + */ + public static void main(String[] args) { + Map conf = GetProperties.getAppSettings(); + System.out.println(conf); + } + +} diff --git a/springboot-log/src/main/java/com/pancm/vo/ApiResult.java b/springboot-log/src/main/java/com/pancm/vo/ApiResult.java new file mode 100644 index 0000000..cbd77fe --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/vo/ApiResult.java @@ -0,0 +1,92 @@ +package com.pancm.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +import static com.pancm.vo.BaseConstants.CODE_ERROR_UNKNOWN; +import static com.pancm.vo.BaseConstants.CODE_SUCCESS; +/** + * @Author pancm + * @Description + * @Date 2019/2/17 + * @Param + * @return + **/ +@Data +@ApiModel(value = "返回值", description="通用返回值") +public class ApiResult implements Serializable { + + private static final long serialVersionUID = 10000000L; + + @ApiModelProperty(value = "返回状态码;0:成功;其它,失败") + private int code; + + @ApiModelProperty(value = "补充信息,显示给前端用户") + private String message; + + @ApiModelProperty(value = "接口请求结果") + private T data; + + @ApiModelProperty(value = "异常的堆栈信息") + private Object stackTrace; + + public ApiResult message(String input) { + this.setMessage(input); + return this; + } + + public ApiResult appendMessage(String input) { + this.message += " " + input; + return this; + } + + public ApiResult data(T input) { + this.setData(input); + return this; + } + + public static ApiResult success() { + ApiResult resultMsg = new ApiResult(); + resultMsg.setCode(CODE_SUCCESS); + resultMsg.setMessage(""); + return resultMsg; + } + + public static ApiResult success(Object data) { + ApiResult resultMsg = new ApiResult(); + resultMsg.setCode(CODE_SUCCESS); + resultMsg.setData(data); + resultMsg.setMessage(""); + return resultMsg; + } + + public static ApiResult error(String message) { + return error(CODE_ERROR_UNKNOWN, message); + } + + public static ApiResult error(int code, String message) { + ApiResult resultMsg = new ApiResult(); + resultMsg.setCode(code); + resultMsg.setMessage(message); + return resultMsg; + } + + + public static ApiResult error(int code, String message, Object... data) { + ApiResult resultMsg = new ApiResult(); + resultMsg.setCode(code); + resultMsg.setMessage(message); + if (data != null) { + if (data.length >= 1) { + resultMsg.setData(data[0]); + } + if (data.length >= 2) { + resultMsg.setStackTrace(data[1]); + } + } + return resultMsg; + } +} diff --git a/springboot-log/src/main/java/com/pancm/vo/BaseConstants.java b/springboot-log/src/main/java/com/pancm/vo/BaseConstants.java new file mode 100644 index 0000000..9a467e5 --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/vo/BaseConstants.java @@ -0,0 +1,42 @@ +package com.pancm.vo; + +/** + * @Author pancm + * @Description + * @Date 2019/2/17 + * @Param + * @return + **/ +public class BaseConstants { + + public static String CONSTANT_MODULE_TYPE_STRING = "string"; + public static String CONSTANT_MODULE_TYPE_INT = "int"; + + public static String SEPARATOR_SPACE = " "; + public static String SEPARATOR_COMMA = ", "; + public static String SEPARATOR_DOT = "."; + public static String SEPARATOR_LINE = "\n"; + + public static int DATE_RANGE_ARRAY_SIZE = 2; + + /** + * excel 相关 + */ + public static final int EXCEL_MAX_EMPTY_HEADER_COUNT = 50; + public static final int EXCEL_ROW_TYPE_SKIP = 1; + public static final int EXCEL_ROW_TYPE_NORMAL = 0; + + public static final String IP_SPLIT_SEPARATOR = "\\."; + + /** + * 校验类,合法的mac地址长度 + */ + public static int VALID_MAC_LENGTH = 17; + public static int VALID_MIN_MAC_LENGTH = 12; + public static int VALID_IP_MAX_LENGTH = 15; + + public static int IP_ASSIGN_LAST = 254; + + public static int CODE_ERROR_UNKNOWN = 5000; + public static int CODE_SUCCESS = 0; +} diff --git a/springboot-log/src/main/java/com/pancm/vo/BasePage.java b/springboot-log/src/main/java/com/pancm/vo/BasePage.java new file mode 100644 index 0000000..ae705bd --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/vo/BasePage.java @@ -0,0 +1,74 @@ +package com.pancm.vo; + +import com.alibaba.fastjson.annotation.JSONField; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springframework.util.StringUtils; + + +import java.util.List; + +@ApiModel +@Data +public class BasePage { + + /** + * 页码 + * 必须定义为 protected or public,否则子类不可见 + */ + @ApiModelProperty(name = "page_num",value = "分页 - 第几页") + protected Integer pageNum=1; + + /** + * 页大小 + */ + @ApiModelProperty(name = "page_num",value = "分页 - 每页记录数") + protected Integer pageSize=10; + + /** + * 排序字段名称 + */ + @ApiModelProperty(name = "sort_name",value = "分页 - 排序列名") + protected String sortName; + + /** + * 排序方式 + */ + @ApiModelProperty(name = "sort_order",value = "分页 - 排序方式,asc/desc") + protected String sortOrder; + + @ApiModelProperty(name = "date", value = "起止日期") + @JSONField(name = "date") + protected List dateRange; + + protected String startDate; + + protected String endDate; + + /** + * 默认排序 + */ + protected String defaultOrder; + + /** + * 排序字符串 + */ + protected String orderString; + + public String getOrderBy() { + if (!StringUtils.isEmpty(this.sortName) && !StringUtils.isEmpty(this.sortOrder)) { + String orderBy = this.sortName + " " + this.sortOrder; + if (!StringUtils.isEmpty(this.defaultOrder) && !orderBy.equals(defaultOrder)) { + orderBy += ", " + defaultOrder; + } + return orderBy.replaceAll(".*([';]+|(--)+).*", " "); + } + if (!StringUtils.isEmpty(this.defaultOrder)) { + return defaultOrder.replaceAll(".*([';]+|(--)+).*", " "); + } + return null; + } + +} diff --git a/springboot-log/src/main/java/com/pancm/vo/PageResult.java b/springboot-log/src/main/java/com/pancm/vo/PageResult.java new file mode 100644 index 0000000..63b76f6 --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/vo/PageResult.java @@ -0,0 +1,30 @@ +package com.pancm.vo; + +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +@Data +public class PageResult implements Serializable { + + private static final long serialVersionUID = 10000001L; + + @JSONField(name = "total") + private long totalNum; + + private List list; + + private int pageSize; + + @JSONField(name = "currentPage") + private int pageNum; + + public PageResult(long totalNum, List list, int pageSize, int pageNum) { + this.totalNum = totalNum; + this.list = list; + this.pageSize = pageSize; + this.pageNum = pageNum; + } +} diff --git a/springboot-log/src/main/java/com/pancm/vo/TSysUserVO.java b/springboot-log/src/main/java/com/pancm/vo/TSysUserVO.java new file mode 100644 index 0000000..5bcfc34 --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/vo/TSysUserVO.java @@ -0,0 +1,61 @@ +package com.pancm.vo; + +import java.io.Serializable; +import com.alibaba.fastjson.JSONObject; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import java.sql.Date; +import com.pancm.vo.BasePage; + +/** +* @Title: 用户表(TSysUser)请求响应对象 +* @Description: +* @Version:1.0.0 +* @Since:jdk1.8 +* @author pancm +* @date 2024-04-01 09:30:54 +*/ +@ApiModel(value = "TSysUser", description = "用户表") +@Data +public class TSysUserVO extends BasePage implements Serializable { + private static final long serialVersionUID = 855666123415935768L; + /** + * 主键 + */ + @ApiModelProperty(value = "主键") + private String id; + /** + * 用户账号 + */ + @ApiModelProperty(value = "用户账号") + private String username; + /** + * 用户密码 + */ + @ApiModelProperty(value = "用户密码") + private String password; + /** + * 昵称 + */ + @ApiModelProperty(value = "昵称") + private String nickname; + /** + * 部门id + */ + @ApiModelProperty(value = "部门id") + private Integer depId; + /** + * 岗位id + */ + @ApiModelProperty(value = "岗位id") + private String posId; + + + + @Override + public String toString(){ + return JSONObject.toJSONString(this); + } + +} diff --git a/springboot-log/src/main/java/com/pancm/vo/UserVO.java b/springboot-log/src/main/java/com/pancm/vo/UserVO.java new file mode 100644 index 0000000..3a3e035 --- /dev/null +++ b/springboot-log/src/main/java/com/pancm/vo/UserVO.java @@ -0,0 +1,71 @@ +package com.pancm.vo; + +import java.io.Serializable; +import com.alibaba.fastjson.JSONObject; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import java.sql.Date; +import com.pancm.vo.BasePage; + +/** +* @Title: 用户表(User)请求响应对象 +* @Description: +* @Version:1.0.0 +* @Since:jdk1.8 +* @author pancm +* @date 2024-01-15 15:27:05 +*/ +@ApiModel(value = "User", description = "用户表") +@Data +public class UserVO extends BasePage implements Serializable { + private static final long serialVersionUID = 887744157417771761L; + /** + * ID + */ + @ApiModelProperty(value = "ID") + private Long id; + /** + * 姓名 + */ + @ApiModelProperty(value = "姓名") + private String name; + /** + * 性别 + */ + @ApiModelProperty(value = "性别") + private Integer sex; + /** + * 年龄 + */ + @ApiModelProperty(value = "年龄") + private Integer age; + /** + * 创建时间 + */ + @ApiModelProperty(value = "创建时间") + private Date createTime; + /** + * 创建人 + */ + @ApiModelProperty(value = "创建人") + private String createBy; + /** + * 更新时间 + */ + @ApiModelProperty(value = "更新时间") + private Date updateTime; + /** + * 更新人 + */ + @ApiModelProperty(value = "更新人") + private String updateBy; + + + + @Override + public String toString(){ + return JSONObject.toJSONString(this); + } + +} diff --git a/springboot-log/src/main/resources/application-dev.yml b/springboot-log/src/main/resources/application-dev.yml new file mode 100644 index 0000000..e1f3514 --- /dev/null +++ b/springboot-log/src/main/resources/application-dev.yml @@ -0,0 +1,14 @@ +server: + port: 9876 + servlet: + context-path: /api + + +spring: + datasource: + pancm: + driver-class-name: com.mysql.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/pcm?autoReconnect=true&failOverReadOnly=false&characterEncoding=utf-8&useUnicode=true&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai&useSSL=false + username: root + password: 123456 + diff --git a/springboot-log/src/main/resources/application-local.yml b/springboot-log/src/main/resources/application-local.yml new file mode 100644 index 0000000..e1f3514 --- /dev/null +++ b/springboot-log/src/main/resources/application-local.yml @@ -0,0 +1,14 @@ +server: + port: 9876 + servlet: + context-path: /api + + +spring: + datasource: + pancm: + driver-class-name: com.mysql.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/pcm?autoReconnect=true&failOverReadOnly=false&characterEncoding=utf-8&useUnicode=true&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai&useSSL=false + username: root + password: 123456 + diff --git a/springboot-log/src/main/resources/application.yml b/springboot-log/src/main/resources/application.yml new file mode 100644 index 0000000..e19fcd9 --- /dev/null +++ b/springboot-log/src/main/resources/application.yml @@ -0,0 +1,15 @@ +spring: + profiles: + active: local + application: + name: springboot-log +log: + defender: + enable: true # 启用logback-defender + include-logger-prefix: com.ideaaedi.logback # 通过logger所属类的全类名前缀,指定脱敏范围(,多个实用逗号分割) + opt: default_json # 指定脱敏器 + config-json: + strategies: # 指定脱敏策略 + com.ideaaedi.logback.defender.strategy.SimpleDefenderStrategy__ACCOUNT_NO: account,accountNo + com.ideaaedi.logback.defender.strategy.SimpleDefenderStrategy__EMAIL: email,mail,emailList + com.ideaaedi.logback.defender.strategy.SimpleDefenderStrategy__PHONE_NUMBER: phone,mobile,telphone diff --git a/springboot-log/src/main/resources/build.properties b/springboot-log/src/main/resources/build.properties new file mode 100644 index 0000000..0ab57c4 --- /dev/null +++ b/springboot-log/src/main/resources/build.properties @@ -0,0 +1,4 @@ +build_app = springboot-demo +build_time = 2024-01-15 15:48:50 +git_commit = +git_branch = diff --git a/springboot-log/src/main/resources/logback.xml b/springboot-log/src/main/resources/logback.xml new file mode 100644 index 0000000..a17046c --- /dev/null +++ b/springboot-log/src/main/resources/logback.xml @@ -0,0 +1,85 @@ + + + + + + + + + + |%d{yyyy-MM-dd HH:mm:ss.SSS}|[%thread]|%-5level|%replace(%caller{1}){'\t|Caller.{1}0|\r\n', ''}|-%msg%n| + + + + + + + ${LOG_HOME}/msgInfo-%d{yyyy-MM-dd}.%i.log + + 10MB + 15 + 10GB + + + + |%d{yyyy-MM-dd HH:mm:ss.SSS}|[%thread]|%-5level|%logger{50}|-%msg%n + + + + + + + + + ${LOG_HOME}/msgDebug-%d{yyyy-MM-dd}.%i.log + + 10MB + 7 + 10GB + + + DEBUG + ACCEPT + DENY + + + + |%d{yyyy-MM-dd HH:mm:ss.SSS}|[%thread]|%-5level|%logger{50}|-%msg%n + + + + + + + + + ${LOG_HOME}/msgError-%d{yyyy-MM-dd}.%i.log + + 10MB + 7 + 10GB + + + ERROR + ACCEPT + DENY + + + + |%d{yyyy-MM-dd HH:mm:ss.SSS}|[%thread]|%-5level|%logger{50}|-%msg%n + + + + + + + + + + + + + diff --git a/springboot-log/src/main/resources/pancm/mapper/DbVersionMapper.xml b/springboot-log/src/main/resources/pancm/mapper/DbVersionMapper.xml new file mode 100644 index 0000000..6302933 --- /dev/null +++ b/springboot-log/src/main/resources/pancm/mapper/DbVersionMapper.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/springboot-log/src/main/resources/pancm/mapper/TSysUserMapper.xml b/springboot-log/src/main/resources/pancm/mapper/TSysUserMapper.xml new file mode 100644 index 0000000..5682b64 --- /dev/null +++ b/springboot-log/src/main/resources/pancm/mapper/TSysUserMapper.xml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + insert into t_sys_user(username, password, nickname, dep_id, pos_id) + values (#{username}, #{password}, #{nickname}, #{depId}, #{posId}) + + + + insert into t_sys_user(username, password, nickname, dep_id, pos_id) + values + + (#{entity.username}, #{entity.password}, #{entity.nickname}, #{entity.depId}, #{entity.posId}) + + + + + insert into t_sys_user(username, password, nickname, dep_id, pos_id) + values + + (#{entity.username}, #{entity.password}, #{entity.nickname}, #{entity.depId}, #{entity.posId}) + + on duplicate key update +username = values(username) , password = values(password) , nickname = values(nickname) , dep_id = values(dep_id) , pos_id = values(pos_id) + + + + update t_sys_user + + + username = #{username}, + + + password = #{password}, + + + nickname = #{nickname}, + + + dep_id = #{depId}, + + + pos_id = #{posId}, + + + where id = #{id} + + + + + delete from t_sys_user where id = #{id} + + + + diff --git a/springboot-log/src/main/resources/pancm/mapper/UserMapper.xml b/springboot-log/src/main/resources/pancm/mapper/UserMapper.xml new file mode 100644 index 0000000..7a9342f --- /dev/null +++ b/springboot-log/src/main/resources/pancm/mapper/UserMapper.xml @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + insert into user(name, sex, age, create_time, create_by, update_time, update_by) + values (#{name}, #{sex}, #{age}, #{createTime}, #{createBy}, #{updateTime}, #{updateBy}) + + + + insert into user(name, sex, age, create_time, create_by, update_time, update_by) + values + + (#{entity.name}, #{entity.sex}, #{entity.age}, #{entity.createTime}, #{entity.createBy}, #{entity.updateTime}, #{entity.updateBy}) + + + + + insert into user(name, sex, age, create_time, create_by, update_time, update_by) + values + + (#{entity.name}, #{entity.sex}, #{entity.age}, #{entity.createTime}, #{entity.createBy}, #{entity.updateTime}, #{entity.updateBy}) + + on duplicate key update +name = values(name) , sex = values(sex) , age = values(age) , create_time = values(create_time) , create_by = values(create_by) , update_time = values(update_time) , update_by = values(update_by) + + + + update user + + + name = #{name}, + + + sex = #{sex}, + + + age = #{age}, + + + create_time = #{createTime}, + + + create_by = #{createBy}, + + + update_time = #{updateTime}, + + + update_by = #{updateBy}, + + + where id = #{id} + + + + + delete from user where id = #{id} + + + + diff --git a/springboot-log/src/main/resources/pancm/mybatis-config.xml b/springboot-log/src/main/resources/pancm/mybatis-config.xml new file mode 100644 index 0000000..bd2d7b7 --- /dev/null +++ b/springboot-log/src/main/resources/pancm/mybatis-config.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/springboot-log/src/main/resources/version.txt b/springboot-log/src/main/resources/version.txt new file mode 100644 index 0000000..621cb01 --- /dev/null +++ b/springboot-log/src/main/resources/version.txt @@ -0,0 +1 @@ +V1.0.1 diff --git a/springboot-log/start.sh b/springboot-log/start.sh new file mode 100644 index 0000000..a9c873b --- /dev/null +++ b/springboot-log/start.sh @@ -0,0 +1,11 @@ +APPDIR=`pwd` +PIDFILE=$APPDIR/springboot-demo.pid +if [ -f "$PIDFILE" ] && kill -0 $(cat "$PIDFILE"); then +echo "springboot-demo is already running..." +exit 1 +fi +nohup java -jar $APPDIR/springboot-demo.jar >/dev/null 2>&1 & +echo $! > $PIDFILE +echo "start springboot-demo..." + + diff --git a/springboot-log/stop.sh b/springboot-log/stop.sh new file mode 100644 index 0000000..69dbc4c --- /dev/null +++ b/springboot-log/stop.sh @@ -0,0 +1,13 @@ +APPDIR=`pwd` +PIDFILE=$APPDIR/springboot-demo.pid +if [ ! -f "$PIDFILE" ] || ! kill -0 "$(cat "$PIDFILE")"; then +echo "springboot-demo not running..." +else +echo "stopping springboot-demo..." +PID="$(cat "$PIDFILE")" +kill -9 $PID +rm "$PIDFILE" +echo "...springboot-demo stopped" +fi + + diff --git a/springboot-log/target/classes/META-INF/spring-configuration-metadata.json b/springboot-log/target/classes/META-INF/spring-configuration-metadata.json new file mode 100644 index 0000000..11229f9 --- /dev/null +++ b/springboot-log/target/classes/META-INF/spring-configuration-metadata.json @@ -0,0 +1,12 @@ +{ + "groups": [ + { + "name": "spring.datasource.pancm", + "type": "javax.sql.DataSource", + "sourceType": "com.pancm.config.PancmConfiguration", + "sourceMethod": "pancmDataSource()" + } + ], + "properties": [], + "hints": [] +} \ No newline at end of file diff --git a/springboot-log/target/classes/application-dev.yml b/springboot-log/target/classes/application-dev.yml new file mode 100644 index 0000000..e1f3514 --- /dev/null +++ b/springboot-log/target/classes/application-dev.yml @@ -0,0 +1,14 @@ +server: + port: 9876 + servlet: + context-path: /api + + +spring: + datasource: + pancm: + driver-class-name: com.mysql.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/pcm?autoReconnect=true&failOverReadOnly=false&characterEncoding=utf-8&useUnicode=true&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai&useSSL=false + username: root + password: 123456 + diff --git a/springboot-log/target/classes/application-local.yml b/springboot-log/target/classes/application-local.yml new file mode 100644 index 0000000..e1f3514 --- /dev/null +++ b/springboot-log/target/classes/application-local.yml @@ -0,0 +1,14 @@ +server: + port: 9876 + servlet: + context-path: /api + + +spring: + datasource: + pancm: + driver-class-name: com.mysql.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/pcm?autoReconnect=true&failOverReadOnly=false&characterEncoding=utf-8&useUnicode=true&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai&useSSL=false + username: root + password: 123456 + diff --git a/springboot-log/target/classes/application.yml b/springboot-log/target/classes/application.yml new file mode 100644 index 0000000..e19fcd9 --- /dev/null +++ b/springboot-log/target/classes/application.yml @@ -0,0 +1,15 @@ +spring: + profiles: + active: local + application: + name: springboot-log +log: + defender: + enable: true # 启用logback-defender + include-logger-prefix: com.ideaaedi.logback # 通过logger所属类的全类名前缀,指定脱敏范围(,多个实用逗号分割) + opt: default_json # 指定脱敏器 + config-json: + strategies: # 指定脱敏策略 + com.ideaaedi.logback.defender.strategy.SimpleDefenderStrategy__ACCOUNT_NO: account,accountNo + com.ideaaedi.logback.defender.strategy.SimpleDefenderStrategy__EMAIL: email,mail,emailList + com.ideaaedi.logback.defender.strategy.SimpleDefenderStrategy__PHONE_NUMBER: phone,mobile,telphone diff --git a/springboot-log/target/classes/build.properties b/springboot-log/target/classes/build.properties new file mode 100644 index 0000000..0ab57c4 --- /dev/null +++ b/springboot-log/target/classes/build.properties @@ -0,0 +1,4 @@ +build_app = springboot-demo +build_time = 2024-01-15 15:48:50 +git_commit = +git_branch = diff --git a/springboot-log/target/classes/logback.xml b/springboot-log/target/classes/logback.xml new file mode 100644 index 0000000..a17046c --- /dev/null +++ b/springboot-log/target/classes/logback.xml @@ -0,0 +1,85 @@ + + + + + + + + + + |%d{yyyy-MM-dd HH:mm:ss.SSS}|[%thread]|%-5level|%replace(%caller{1}){'\t|Caller.{1}0|\r\n', ''}|-%msg%n| + + + + + + + ${LOG_HOME}/msgInfo-%d{yyyy-MM-dd}.%i.log + + 10MB + 15 + 10GB + + + + |%d{yyyy-MM-dd HH:mm:ss.SSS}|[%thread]|%-5level|%logger{50}|-%msg%n + + + + + + + + + ${LOG_HOME}/msgDebug-%d{yyyy-MM-dd}.%i.log + + 10MB + 7 + 10GB + + + DEBUG + ACCEPT + DENY + + + + |%d{yyyy-MM-dd HH:mm:ss.SSS}|[%thread]|%-5level|%logger{50}|-%msg%n + + + + + + + + + ${LOG_HOME}/msgError-%d{yyyy-MM-dd}.%i.log + + 10MB + 7 + 10GB + + + ERROR + ACCEPT + DENY + + + + |%d{yyyy-MM-dd HH:mm:ss.SSS}|[%thread]|%-5level|%logger{50}|-%msg%n + + + + + + + + + + + + + diff --git a/springboot-log/target/classes/pancm/mapper/DbVersionMapper.xml b/springboot-log/target/classes/pancm/mapper/DbVersionMapper.xml new file mode 100644 index 0000000..6302933 --- /dev/null +++ b/springboot-log/target/classes/pancm/mapper/DbVersionMapper.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/springboot-log/target/classes/pancm/mapper/TSysUserMapper.xml b/springboot-log/target/classes/pancm/mapper/TSysUserMapper.xml new file mode 100644 index 0000000..5682b64 --- /dev/null +++ b/springboot-log/target/classes/pancm/mapper/TSysUserMapper.xml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + insert into t_sys_user(username, password, nickname, dep_id, pos_id) + values (#{username}, #{password}, #{nickname}, #{depId}, #{posId}) + + + + insert into t_sys_user(username, password, nickname, dep_id, pos_id) + values + + (#{entity.username}, #{entity.password}, #{entity.nickname}, #{entity.depId}, #{entity.posId}) + + + + + insert into t_sys_user(username, password, nickname, dep_id, pos_id) + values + + (#{entity.username}, #{entity.password}, #{entity.nickname}, #{entity.depId}, #{entity.posId}) + + on duplicate key update +username = values(username) , password = values(password) , nickname = values(nickname) , dep_id = values(dep_id) , pos_id = values(pos_id) + + + + update t_sys_user + + + username = #{username}, + + + password = #{password}, + + + nickname = #{nickname}, + + + dep_id = #{depId}, + + + pos_id = #{posId}, + + + where id = #{id} + + + + + delete from t_sys_user where id = #{id} + + + + diff --git a/springboot-log/target/classes/pancm/mapper/UserMapper.xml b/springboot-log/target/classes/pancm/mapper/UserMapper.xml new file mode 100644 index 0000000..7a9342f --- /dev/null +++ b/springboot-log/target/classes/pancm/mapper/UserMapper.xml @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + insert into user(name, sex, age, create_time, create_by, update_time, update_by) + values (#{name}, #{sex}, #{age}, #{createTime}, #{createBy}, #{updateTime}, #{updateBy}) + + + + insert into user(name, sex, age, create_time, create_by, update_time, update_by) + values + + (#{entity.name}, #{entity.sex}, #{entity.age}, #{entity.createTime}, #{entity.createBy}, #{entity.updateTime}, #{entity.updateBy}) + + + + + insert into user(name, sex, age, create_time, create_by, update_time, update_by) + values + + (#{entity.name}, #{entity.sex}, #{entity.age}, #{entity.createTime}, #{entity.createBy}, #{entity.updateTime}, #{entity.updateBy}) + + on duplicate key update +name = values(name) , sex = values(sex) , age = values(age) , create_time = values(create_time) , create_by = values(create_by) , update_time = values(update_time) , update_by = values(update_by) + + + + update user + + + name = #{name}, + + + sex = #{sex}, + + + age = #{age}, + + + create_time = #{createTime}, + + + create_by = #{createBy}, + + + update_time = #{updateTime}, + + + update_by = #{updateBy}, + + + where id = #{id} + + + + + delete from user where id = #{id} + + + + diff --git a/springboot-log/target/classes/pancm/mybatis-config.xml b/springboot-log/target/classes/pancm/mybatis-config.xml new file mode 100644 index 0000000..bd2d7b7 --- /dev/null +++ b/springboot-log/target/classes/pancm/mybatis-config.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/springboot-log/target/classes/version.txt b/springboot-log/target/classes/version.txt new file mode 100644 index 0000000..621cb01 --- /dev/null +++ b/springboot-log/target/classes/version.txt @@ -0,0 +1 @@ +V1.0.1 diff --git a/springboot-log/target/maven-archiver/pom.properties b/springboot-log/target/maven-archiver/pom.properties new file mode 100644 index 0000000..78e5456 --- /dev/null +++ b/springboot-log/target/maven-archiver/pom.properties @@ -0,0 +1,3 @@ +version=0.0.1-SNAPSHOT +groupId=com.pancm +artifactId=springboot-log diff --git a/springboot-log/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/springboot-log/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..e7bb86b --- /dev/null +++ b/springboot-log/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1 @@ +META-INF\spring-configuration-metadata.json diff --git a/springboot-log/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/springboot-log/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..2ec449d --- /dev/null +++ b/springboot-log/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,24 @@ +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\controller\UserController.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\model\User.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\vo\BaseConstants.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\config\SwaggerConfig.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\config\CorsFilter.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\service\impl\TSysUserServiceImpl.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\Application.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\controller\HomeController.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\vo\UserVO.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\util\FileHelper.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\model\TSysUser.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\vo\BasePage.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\vo\ApiResult.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\service\ITSysUserService.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\vo\TSysUserVO.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\controller\TSysUserController.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\config\SpringBeanFactory.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\service\IUserService.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\service\impl\UserServiceImpl.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\config\PancmConfiguration.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\vo\PageResult.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\dao\TSysUserDao.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\dao\UserDao.java +D:\pcm\MyProject\springBoot-study\springboot-log\src\main\java\com\pancm\util\GetProperties.java diff --git a/springboot-log/target/springboot-log.jar.original b/springboot-log/target/springboot-log.jar.original new file mode 100644 index 0000000000000000000000000000000000000000..8c2e5a4c3a07b58320c5f68f1878587aba101ba8 GIT binary patch literal 48481 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