├── .github └── workflows │ └── build.yml ├── .gitignore ├── README.md ├── pom.xml ├── sql └── db.sql ├── template-generator ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── step │ │ └── generator │ │ └── Generator.java │ └── resources │ └── templates │ ├── controller.java.ftl │ ├── entity.java.ftl │ ├── mapper.java.ftl │ ├── mapper.xml.ftl │ ├── service.java.ftl │ └── svo.java.ftl └── template-main ├── Dockerfile ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── step │ │ └── template │ │ └── main │ │ ├── TemplateApplication.java │ │ ├── base │ │ ├── BaseEntity.java │ │ ├── BaseLogEntity.java │ │ ├── BaseService.java │ │ └── BaseSvo.java │ │ ├── config │ │ ├── AuthAspect.java │ │ ├── MvcConfig.java │ │ ├── ProjectParam.java │ │ ├── Swagger2.java │ │ ├── annotation │ │ │ ├── Auth.java │ │ │ └── NoAuth.java │ │ └── mybatis │ │ │ ├── MyMetaObjectHandler.java │ │ │ └── MybatisPlusConfig.java │ │ ├── controller │ │ ├── AccountController.java │ │ ├── DeptController.java │ │ ├── DeviceController.java │ │ ├── PermissionController.java │ │ ├── RoleController.java │ │ └── UserController.java │ │ ├── entity │ │ ├── Dept.java │ │ ├── Device.java │ │ ├── Permission.java │ │ ├── Role.java │ │ └── User.java │ │ ├── exception │ │ ├── MyException.java │ │ ├── NoAuthException.java │ │ └── UnauthorizedException.java │ │ ├── mapper │ │ ├── DeptMapper.java │ │ ├── DeviceMapper.java │ │ ├── PermissionMapper.java │ │ ├── RoleMapper.java │ │ └── UserMapper.java │ │ ├── service │ │ ├── AccountService.java │ │ ├── DeptService.java │ │ ├── DeviceService.java │ │ ├── PermissionService.java │ │ ├── RoleService.java │ │ └── UserService.java │ │ ├── svo │ │ ├── DeviceSvo.java │ │ └── UserSvo.java │ │ ├── util │ │ ├── BCrypt.java │ │ ├── CommonUtil.java │ │ ├── Constant.java │ │ ├── JacksonUtil.java │ │ ├── JwtUtil.java │ │ ├── MyDateUtil.java │ │ └── ScopeUtil.java │ │ └── vo │ │ ├── DeviceVo.java │ │ ├── MyScope.java │ │ ├── TreeNode.java │ │ └── UserVo.java └── resources │ ├── application-dev.properties │ ├── application.properties │ ├── logback.xml │ └── mapper │ ├── DeviceMapper.xml │ ├── PermissionMapper.xml │ ├── RoleMapper.xml │ └── UserMapper.xml └── test └── java └── com └── step └── template └── main └── TemplateApplicationTests.java /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | types: [opened, synchronize, reopened] 8 | jobs: 9 | build: 10 | name: Build 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | with: 15 | fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis 16 | - name: Set up JDK 11 17 | uses: actions/setup-java@v1 18 | with: 19 | java-version: 11 20 | - name: Cache SonarCloud packages 21 | uses: actions/cache@v1 22 | with: 23 | path: ~/.sonar/cache 24 | key: ${{ runner.os }}-sonar 25 | restore-keys: ${{ runner.os }}-sonar 26 | - name: Cache Maven packages 27 | uses: actions/cache@v1 28 | with: 29 | path: ~/.m2 30 | key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} 31 | restore-keys: ${{ runner.os }}-m2 32 | - name: Build and analyze 33 | env: 34 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any 35 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 36 | run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=liu-xinhui_spring-boot-template 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 6 | application-loc.properties 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | 17 | ### IntelliJ IDEA ### 18 | .idea 19 | *.iws 20 | *.iml 21 | *.ipr 22 | 23 | ### NetBeans ### 24 | /nbproject/private/ 25 | /nbbuild/ 26 | /dist/ 27 | /nbdist/ 28 | /.nb-gradle/ 29 | build/ 30 | 31 | ### VS Code ### 32 | .vscode/ 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Spring Boot Template(项目模板)](https://github.com/liunewshine/spring-boot-template.git) 2 | 3 | 4 | ### 配合使用的`vue`前端项目和截图,请移步[vue-admin-template](https://github.com/liunewshine/vue-admin-template.git) 5 | 6 | 7 | ### 项目演示:[地址](http://118.25.44.86:8011) 账号密码默认填充(admin,a123456) 8 | 9 | ### 若文档不能正常查看,请移步 [文档地址](https://www.yuque.com/docs/share/e7e73f84-692c-41d2-9e29-3e3a06c3daa9) 10 | 11 | ## 简介 12 | 13 | 14 | 多个`spring boot前后端分离管理系统`开发经验总结而成,使用`restful`风格`API`, 15 | 包含`角色` `权限` `代码生成` `增删改查示例`, 16 | 集成`mybatis plus`无需书写`sql`即可实现大部分接口。 17 | 18 | 19 | 项目功能完整,结构特别简单易懂,未做多余封装,上手难度极地。可作为模板项目使用,大大提高开发效率。 20 | 21 | 22 | 特别适合`中小型项目`、`新手`和`个人开发者`参考及使用,一天开发一个项目不是梦。 23 | 24 | 25 | ## 开发环境 26 | 27 | 28 | - **JDK 1.8 +** 29 | - **Maven 3.5 +** 30 | - **IntelliJ IDEA ULTIMATE 或者 Eclipse** (_安装 _`_lombok_`_ 插件_) 31 | - **Mysql 5.7 +**(_mysql8 驱动名称和之前不一样,项目示例为mysql8驱动名称_) 32 | 33 | 34 | 35 | ## 技术选型 36 | | 名称 | 介绍 | 37 | | --- | --- | 38 | | Spring Boot 2.2.1.RELEASE | 无 | 39 | | [mybatis-plus 3.2.0](https://github.com/baomidou/mybatis-plus) | 用着超爽的`mybatis` 40 | 插件,可在`baseService` 41 | 中实现常用的数据库操作 | 42 | | [jwt-token](https://github.com/auth0/java-jwt) | 使用`jwt` 43 | 生成`token` 44 | ,实现登录认证 | 45 | | [swagger 2.9.2](https://github.com/swagger-api/swagger-ui) | 生成项目文档,供app和前端使用 | 46 | 47 | 48 | 49 | ## 工程结构 50 | 51 | 52 | ``` 53 | template-api 54 | ├── template-generator -- 代码生成器 55 | │ └── Generator.java -- 运行此java生成代码 56 | └── template-main -- 业务模块 57 | ├── base包 -- 常用父类 58 | │ ├── BaseEntity.java -- 包含一个id,所有Entity的父类 59 | │ ├── BaseLogEntity.java -- 继承BaseEntity,包含createBy,createTime,updateBy.updateTime四个日志相关的field 60 | │ ├── BaseService.java -- 继承自mybatis plus,包含常用的增删改查方法,具体使用参考mybatis plus文档 61 | │ └── BaseSvo.java -- svo为search vo简写,用于接收前端传递查询条件,包含pageNum和pageSize 62 | ├── config包 -- 项目配置 63 | │ ├── @Auth.java -- 此注解用于实现权限验证,添加到@Auth("permission")到controller方法鉴权 64 | │ ├── @NoAuth.java -- 默认所有的controller方法需要登录,使用这个注解排除登录,例如登录注册接口 65 | │ ├── MybatisPlusConfig.java -- mybatis plus配置文件,分页在此配置 66 | │ ├── MyMetaObjectHandler.java -- mybatis plus自动填充功能,可以自动插入createBy,createTime,updateBy.updateTime值 67 | │ ├── AuthAspect.java -- aop实现鉴权,和访问日志 68 | │ ├── MvcConfig.java -- spring mvc常用配置,包含跨域,时间格式化等等 69 | │ ├── ProjectParam.java -- 此项目的配置文件映射,自动读取application.properties中的私有配置 70 | │ └── Swagger2.java -- Swagger2配置文件 71 | ├── controller包 -- 使用restfull风格api 72 | │ ├── AccountController.java -- 账户相关,登录、修改密码等 73 | │ ├── DeptController.java -- 部门,树形结构的参考此模块,自动转换为前端通用数据结构 74 | │ ├── DeviceController.java -- 增删改查示例模块 75 | │ ├── PermissionController.java -- 权限 76 | │ ├── RoleController.java -- 角色 77 | │ ├── UserController.java -- 用户 78 | │ └── 角色 权限 用户模块因为 多对多中间表 问题,写了好多sql,其他模块使用通用方法基本都能解决 79 | ├── entity包 -- 和数据库对应,继承BaseEntity.java或者BaseLogEntity.java 80 | ├── exception包 -- 异常类 81 | │ ├── MyException.java -- 常见的异常,例如参数校验,是否存在等抛出此异常,前端httpstatus自动为400 82 | │ ├── NoAuthException.java -- 未登录访问接口抛出此异常,前端httpstatus自动为401 83 | │ └── UnauthorizedException.java -- 登录但是无具体权限抛出此异常,前端httpstatus自动为403 84 | ├── mapper包 -- mybatis mapper 85 | ├── service包 -- 服务类,继承BaseService.java 86 | ├── svo包 -- svo为search vo简写,用于接收前端传递查询条件,继承BaseSvo.java 87 | ├── util包 -- 工具类,包含BCrypt密码加密、树形结构转换、jwt token生成,日期工具,获取当前用户工具,json工具等 88 | └── vo包 -- 相当于dto包,集成字entity,用于传递entity中不包含的参数给前端 89 | ``` 90 | 91 | 92 | ## 运行项目 93 | 94 | 95 | 1. clone或者下载项目 96 | 2. 使用`Intellij idea`或者`Eclipse`导入`maven`项目 97 | 3. 创建`mysql`数据库,执行`项目根目录/sql/db.sql` 98 | 4. 修改`application-dev.properties`中的数据库连接参数 99 | 5. 运行`template-main`中的`TemplateApplication.java`即可启动项目 **(请运行前端项目查看实际界面效果)** 100 | [vue-admin-template](https://github.com/liunewshine/vue-admin-template.git) 101 | 6. 更改名称,由于是模板项目,所有的`项目名称`、`包名`、`artifactId`、`modules`、`Dockerfile`、 102 | `代码生成器`等均为`template`,建议按照自己的项目名称修改,也可以不改。 103 | 104 | 105 | 106 | ## 部署项目 107 | 108 | 109 | #### 使用docker部署 110 | 111 | 112 | ``` 113 | #进入项目目录 114 | cd template-api 115 | 116 | #打包(可在本地打包,提交jar后,到服务器运行docker命令) 117 | mvn install 118 | 119 | #进入Dockerfile所在文件夹 120 | cd template-main 121 | 122 | #docker打包镜像 123 | docker build -t template-api:latest . 124 | 125 | #启动docker容器,可使用-e SPRING_PROFILES_ACTIVE=${env}指定环境,不指定则默认为dev 126 | docker run -itd --name template-api -e SPRING_PROFILES_ACTIVE=dev template-api:latest 127 | ``` 128 | 129 | 130 | #### 若您的docker服务器开放了远程访问(外网记得启用TLS,否则不安全),可直接使用idea推送至服务器 131 | 132 | 133 | 配置参考 134 | 135 | 136 | ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12878014/1626314873276-6f38cb54-e02a-4466-ac87-360772afbfe8.png#clientId=u73c290d9-a3c4-4&from=paste&id=uec8d5c8a&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1333&originWidth=1920&originalType=url&ratio=1&size=452100&status=done&style=none&taskId=u88006a68-2960-4eba-b14e-35700cd762e) 137 | 138 | 139 | #### 使用docker+jenkins部署 140 | 141 | 142 | 参考我的文章 143 | [最优雅的Docker+Jenkins pipeline部署Spring boot项目](https://juejin.im/post/5d906c40e51d45780e4ce9d2) 144 | 145 | 146 | #### 直接部署 147 | 148 | 149 | ``` 150 | #进入项目目录 151 | cd template-api 152 | 153 | #打包 154 | mvn install 155 | 156 | #linux 在jar所在目录执行 157 | nohup java -jar template-api.jar --spring.profiles.active=dev >log.txt & 158 | 159 | #windows 在jar所在目录执行 160 | java -jar template-api.jar --spring.profiles.active=dev 161 | ``` 162 | 163 | 164 | ## mybatis-plus使用 165 | 166 | 167 | 特别强大的mybatis工具,封装了大量通用方法,写很少的sql即可完成一个项目。 168 | 169 | 170 | - 自动填充通用字段 171 | - 逻辑删除 172 | - 多租户(saas服务) 173 | - 分页 174 | - 等等 175 | 176 | 177 | 178 | 详细文档[MyBatis-Plus文档](https://mp.baomidou.com/guide/) 179 | 180 | 181 | ## 代码生成器使用 182 | 183 | 184 | 代码生成器由[mybatis-plus](https://github.com/baomidou/mybatis-plus)提供,详情请参考 185 | [mybatis-plus 代码生成器](https://mp.baomidou.com/guide/generator.html#%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B) 186 | 187 | 188 | 1. 修改com.step.generator.Generator.java中的配置参数 189 | - ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12878014/1626314895087-03108c37-67f4-47b0-a97b-91901d2e1aa8.png#clientId=u73c290d9-a3c4-4&from=paste&id=ue91d855e&margin=%5Bobject%20Object%5D&name=image.png&originHeight=987&originWidth=2657&originalType=url&ratio=1&size=145135&status=done&style=none&taskId=u78b04315-3ed8-4058-9221-7edee45e34a) 190 | 2. 执行main函数 191 | 3. 控制台输入表名 192 | 193 | - ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12878014/1626314905259-f258ce4b-d894-43f4-b5bb-ab0ee25eafe1.png#clientId=u73c290d9-a3c4-4&from=paste&id=u1093ed9e&margin=%5Bobject%20Object%5D&name=image.png&originHeight=294&originWidth=750&originalType=url&ratio=1&size=19577&status=done&style=none&taskId=u80522c59-ca41-474c-8731-06c9a5a0a1f) 194 | 195 | 196 | 197 | ## swagger2文档使用 198 | 199 | 200 | 文档配置文件`com.step.template.main.config.Swagger2` 201 | 202 | 203 | 只有`dev`和`test`环境会生成文档,可以修改配置文件的@Profile注解自定义 204 | 205 | 206 | 文档默认访问地址`http://localhost:8020/swagger-ui.html` 207 | 208 | 209 | 未添加`@NoAuth`的api需要设置token后才可访问 210 | ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12878014/1626314926947-1b18a2a3-e5ee-4cb3-bdf3-dc283cc6875b.png#clientId=u73c290d9-a3c4-4&from=paste&id=uffd3ff97&margin=%5Bobject%20Object%5D&name=image.png&originHeight=876&originWidth=1802&originalType=url&ratio=1&size=89358&status=done&style=none&taskId=u90dfa76f-ba6d-40c1-a201-887f7567b39) 211 | 212 | 213 | ## 权限注解使用方法 214 | 215 | 216 | - `@NoAuth` -- 默认所有的`controller`方法需要登录,使用这个注解排除登录,例如登录注册接口 217 | - `@Auth` -- 此注解用于实现权限验证,添加到`@Auth("permissionName")`到`controller方法中`鉴权 218 | - `permissionName`建议权限值采用`user:query,user:edit`类似的形式,参考数据库中的`permission`表 219 | - `com.step.template.main.config.AuthAspect`中会拦截所有`controller`方法,根据注解进行相应的处理 220 | 221 | 222 | 223 | ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12878014/1626314937485-a5652193-bfb3-4492-8081-303e975e489c.png#clientId=u73c290d9-a3c4-4&from=paste&id=ub99edfcd&margin=%5Bobject%20Object%5D&name=image.png&originHeight=961&originWidth=2056&originalType=url&ratio=1&size=155334&status=done&style=none&taskId=u86d65765-6357-475c-9351-1719da285a8) 224 | ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12878014/1626314942380-65afcddf-608e-4d9c-9e2f-2064cd219499.png#clientId=u73c290d9-a3c4-4&from=paste&id=u8c34abbf&margin=%5Bobject%20Object%5D&name=image.png&originHeight=544&originWidth=1056&originalType=url&ratio=1&size=69753&status=done&style=none&taskId=u90b2a7a0-5465-4024-b0a1-78753bff792) 225 | 226 | 227 | ## 权限管理系统设计思路 228 | 229 | 230 | #### 我们先说一种权限管理最简单的做法 231 | 232 | 233 | - 既然权限管理系统,必须有`用户表`和`权限表` 234 | - 一个`用户`可以有多个`权限`,一个`权限`可以分配给多个`用户`,所以是`多对多`关系。 235 | - `多对多`会产生关联表,表示如下: 236 | 237 | ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12878014/1626314953095-b6bdfb35-3780-431b-bbd9-7a14f4cbb6fe.png#clientId=u73c290d9-a3c4-4&from=paste&id=u12a360be&margin=%5Bobject%20Object%5D&name=image.png&originHeight=432&originWidth=575&originalType=url&ratio=1&size=25586&status=done&style=none&taskId=u8e125899-4612-4e20-acff-ccd8724b8e0) 238 | 239 | 240 | 这种设计已经可以满足小型管理系统的需求,使用和开发都特别简单。 241 | 但是如果用户数增大,运营人员需要为每个用户分配权限,会浪费大量的精力,而且容易出错。 242 | 用户多,但是用户的`角色`比如`经理`、`运维`等却很少,所以应该增加一层角色。 243 | 244 | 245 | #### RBAC基于角色的权限访问控制(Role-Based Access Control) 246 | 247 | 248 | 取消了`用户`和`权限`的直接关联,改为通过`用户关联角色`、`角色关联权限`的方法来间接地赋予用户权限。 249 | 当新增用户时只需分配已有的角色,大大减少运营人员工作量和出错率。 250 | 251 | 252 | - 三张表分别为多对多关系 253 | ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12878014/1626314962935-202a0f43-8f3a-45a1-87cd-2bdeddb9c18a.png#clientId=u73c290d9-a3c4-4&from=paste&id=u4d04b711&margin=%5Bobject%20Object%5D&name=image.png&originHeight=114&originWidth=900&originalType=url&ratio=1&size=17854&status=done&style=none&taskId=ue75d1b8b-1686-47af-aabe-72cb5c50ffd) 254 | - 生成关联网之后的结构如下 255 | ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12878014/1626314967341-d5ec452b-97f0-46e9-8d6b-a807ce1cfb90.png#clientId=u73c290d9-a3c4-4&from=paste&id=ua0eed0d0&margin=%5Bobject%20Object%5D&name=image.png&originHeight=993&originWidth=908&originalType=url&ratio=1&size=88964&status=done&style=none&taskId=u8fc112cc-fb54-45ac-890a-8f5c5264df9) 256 | 257 | 258 | 259 | ## 提示 260 | 261 | 262 | - 仔细查看[MyBatis-Plus文档](https://mp.baomidou.com/guide/) 263 | - 仔细查看`工程结构`中项目结构介绍 264 | - 除了查询列表(往往带有分页和模糊查询)自己写sql以外,其他情况尽量使用BaseService中的通用方法。 265 | 单个查询的使用多个service中的通用方法组合,而不是写sql,单个数据不会有性能问题。 266 | - 数据库表和字段一定要添加comment,代码生成会根据comment生成swagger2文档 267 | - Controller中接口返回的json数据未做包装,直接返回数据。 268 | - 本项目根据http status判断是否成功,200等2开头的状态为成功,400,500等为失败。 269 | 前端ajax,axios会自动走到catch方法,处理特别简单。 270 | - 如需外层包装成功失败状态,建议在aop或者拦截器中实现。 271 | 272 | 273 | 274 | ``` 275 | #本项目成功时返回结果如下 276 | { 277 | "name": "姓名", 278 | "deptName": "部门名称" 279 | } 280 | #失败时 281 | { 282 | "name": "姓名", 283 | "deptName": "部门名称" 284 | } 285 | #而不是 286 | { 287 | "error": 0, 288 | "msg": "success", 289 | "data": { 290 | "name": "姓名", 291 | "deptName": "部门名称" 292 | } 293 | } 294 | ``` 295 | 296 | 297 | - `com.step.template.main.util.ScopeUtil`中可获取当前用户 298 | - 使用构造器注入,避免在`private`字段上写`@Autowired`,这么写idea会提示警告 299 | `Field injection is not recommended`。构造器注入配合lombok写法很简洁。 300 | ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12878014/1626314978222-01418dbc-5530-4483-a888-780e1c69f4a3.png#clientId=u73c290d9-a3c4-4&from=paste&id=uf0ad52ba&margin=%5Bobject%20Object%5D&name=image.png&originHeight=477&originWidth=1107&originalType=url&ratio=1&size=39251&status=done&style=none&taskId=u9d806465-40a9-453e-9df1-225fcf211ec) 301 | - `BaseService`提供字段唯一性检测,参考`userService`里的`phone`唯一检测 302 | ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12878014/1626314983601-743f92a4-0dd7-4452-9b90-523034060478.png#clientId=u73c290d9-a3c4-4&from=paste&id=ucf01fb54&margin=%5Bobject%20Object%5D&name=image.png&originHeight=948&originWidth=1809&originalType=url&ratio=1&size=119955&status=done&style=none&taskId=u79fc51d8-c0ec-4e49-9710-876981342b6) 303 | 304 | 305 | 306 | ## 欢迎start,有疑问、建议、bug请提issue 307 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | pom 6 | 7 | template-main 8 | template-generator 9 | 10 | 11 | org.springframework.boot 12 | spring-boot-starter-parent 13 | 2.3.1.RELEASE 14 | 15 | 16 | com.step 17 | template 18 | 0.0.1-SNAPSHOT 19 | template 20 | Spring Boot模板 21 | 22 | 23 | 1.8 24 | true 25 | liu-xinhui 26 | https://sonarcloud.io 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /sql/db.sql: -------------------------------------------------------------------------------- 1 | -- MySQL dump 10.13 Distrib 8.0.18, for Win64 (x86_64) 2 | -- 3 | -- Database: template 4 | -- ------------------------------------------------------ 5 | -- Server version 8.0.18 6 | 7 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 8 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 9 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 10 | /*!50503 SET NAMES utf8 */; 11 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; 12 | /*!40103 SET TIME_ZONE='+00:00' */; 13 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; 14 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 15 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 16 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; 17 | 18 | -- 19 | -- Table structure for table `dept` 20 | -- 21 | 22 | DROP TABLE IF EXISTS `dept`; 23 | /*!40101 SET @saved_cs_client = @@character_set_client */; 24 | /*!50503 SET character_set_client = utf8mb4 */; 25 | CREATE TABLE `dept` ( 26 | `id` int(11) NOT NULL AUTO_INCREMENT, 27 | `deleted` int(11) DEFAULT '0', 28 | `createBy` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, 29 | `createTime` datetime DEFAULT NULL, 30 | `updateBy` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, 31 | `updateTime` datetime DEFAULT NULL, 32 | `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, 33 | `parentId` int(11) DEFAULT NULL, 34 | PRIMARY KEY (`id`) 35 | ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='部门'; 36 | /*!40101 SET character_set_client = @saved_cs_client */; 37 | 38 | -- 39 | -- Dumping data for table `dept` 40 | -- 41 | 42 | LOCK TABLES `dept` WRITE; 43 | /*!40000 ALTER TABLE `dept` DISABLE KEYS */; 44 | INSERT INTO `dept` VALUES (1,0,'超级管理员','2019-11-21 13:49:41','超级管理员','2019-11-21 13:49:41','电气事业部',0),(2,1,'超级管理员','2019-11-21 13:49:52','超级管理员','2019-11-21 13:50:34','软件开发',1); 45 | /*!40000 ALTER TABLE `dept` ENABLE KEYS */; 46 | UNLOCK TABLES; 47 | 48 | -- 49 | -- Table structure for table `device` 50 | -- 51 | 52 | DROP TABLE IF EXISTS `device`; 53 | /*!40101 SET @saved_cs_client = @@character_set_client */; 54 | /*!50503 SET character_set_client = utf8mb4 */; 55 | CREATE TABLE `device` ( 56 | `id` int(11) NOT NULL AUTO_INCREMENT, 57 | `deleted` int(11) DEFAULT '0', 58 | `createBy` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, 59 | `createTime` datetime DEFAULT NULL, 60 | `updateBy` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, 61 | `updateTime` datetime DEFAULT NULL, 62 | `no` varchar(50) DEFAULT NULL, 63 | `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, 64 | `model` varchar(50) DEFAULT NULL, 65 | `maintUserId` int(11) DEFAULT NULL COMMENT '维保工,关联用户表id', 66 | PRIMARY KEY (`id`) 67 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='增删改查模板'; 68 | /*!40101 SET character_set_client = @saved_cs_client */; 69 | 70 | -- 71 | -- Dumping data for table `device` 72 | -- 73 | 74 | LOCK TABLES `device` WRITE; 75 | /*!40000 ALTER TABLE `device` DISABLE KEYS */; 76 | INSERT INTO `device` VALUES (1,0,'超级管理员','2019-11-15 16:28:39','测试','2019-11-21 16:21:29','测试编号1','测试名称1','m2',1); 77 | /*!40000 ALTER TABLE `device` ENABLE KEYS */; 78 | UNLOCK TABLES; 79 | 80 | -- 81 | -- Table structure for table `permission` 82 | -- 83 | 84 | DROP TABLE IF EXISTS `permission`; 85 | /*!40101 SET @saved_cs_client = @@character_set_client */; 86 | /*!50503 SET character_set_client = utf8mb4 */; 87 | CREATE TABLE `permission` ( 88 | `id` int(11) NOT NULL, 89 | `code` varchar(50) NOT NULL, 90 | `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 91 | `parentId` int(11) DEFAULT NULL, 92 | PRIMARY KEY (`id`), 93 | UNIQUE KEY `permission_id_uindex` (`id`) 94 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 95 | /*!40101 SET character_set_client = @saved_cs_client */; 96 | 97 | -- 98 | -- Dumping data for table `permission` 99 | -- 100 | 101 | LOCK TABLES `permission` WRITE; 102 | /*!40000 ALTER TABLE `permission` DISABLE KEYS */; 103 | INSERT INTO `permission` VALUES (1,'1','系统管理',0),(2,'2','DEMO管理',0),(100,'user:query','用户管理-查看',1),(101,'user:edit','用户管理-增删改',1),(110,'role:query','角色管理-查看',1),(111,'role:edit','角色管理-增删改',1),(120,'dept:query','部门管理-查看',1),(121,'dept:edit','部门管理-增删改',1),(130,'device:query','设备管理-查看',2),(131,'device:edit','设备管理-增删改',2); 104 | /*!40000 ALTER TABLE `permission` ENABLE KEYS */; 105 | UNLOCK TABLES; 106 | 107 | -- 108 | -- Table structure for table `role` 109 | -- 110 | 111 | DROP TABLE IF EXISTS `role`; 112 | /*!40101 SET @saved_cs_client = @@character_set_client */; 113 | /*!50503 SET character_set_client = utf8mb4 */; 114 | CREATE TABLE `role` ( 115 | `id` int(11) NOT NULL AUTO_INCREMENT, 116 | `createBy` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, 117 | `createTime` datetime DEFAULT NULL, 118 | `updateBy` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, 119 | `updateTime` datetime DEFAULT NULL, 120 | `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 121 | `note` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, 122 | PRIMARY KEY (`id`), 123 | UNIQUE KEY `role_id_uindex` (`id`) 124 | ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='角色'; 125 | /*!40101 SET character_set_client = @saved_cs_client */; 126 | 127 | -- 128 | -- Dumping data for table `role` 129 | -- 130 | 131 | LOCK TABLES `role` WRITE; 132 | /*!40000 ALTER TABLE `role` DISABLE KEYS */; 133 | INSERT INTO `role` VALUES (1,'超级管理员','2019-11-21 12:15:14','超级管理员','2019-11-21 14:08:58','管理员','123'),(2,'超级管理员','2019-11-21 16:17:49','超级管理员','2019-11-21 16:47:29','设备管理',''); 134 | /*!40000 ALTER TABLE `role` ENABLE KEYS */; 135 | UNLOCK TABLES; 136 | 137 | -- 138 | -- Table structure for table `role_permission` 139 | -- 140 | 141 | DROP TABLE IF EXISTS `role_permission`; 142 | /*!40101 SET @saved_cs_client = @@character_set_client */; 143 | /*!50503 SET character_set_client = utf8mb4 */; 144 | CREATE TABLE `role_permission` ( 145 | `id` int(11) NOT NULL AUTO_INCREMENT, 146 | `roleId` int(11) DEFAULT NULL, 147 | `permissionId` int(11) DEFAULT NULL, 148 | PRIMARY KEY (`id`) 149 | ) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='角色权限关联'; 150 | /*!40101 SET character_set_client = @saved_cs_client */; 151 | 152 | -- 153 | -- Dumping data for table `role_permission` 154 | -- 155 | 156 | LOCK TABLES `role_permission` WRITE; 157 | /*!40000 ALTER TABLE `role_permission` DISABLE KEYS */; 158 | INSERT INTO `role_permission` VALUES (1,1,100),(2,1,120),(3,1,121),(4,1,101),(5,1,110),(6,1,111),(7,1,131),(8,1,130),(9,1,100),(10,1,120),(11,1,121),(12,1,101),(13,1,110),(14,1,111),(15,1,131),(16,1,130),(17,2,130),(18,2,131),(19,2,130),(20,2,131),(21,2,100); 159 | /*!40000 ALTER TABLE `role_permission` ENABLE KEYS */; 160 | UNLOCK TABLES; 161 | 162 | -- 163 | -- Table structure for table `user` 164 | -- 165 | 166 | DROP TABLE IF EXISTS `user`; 167 | /*!40101 SET @saved_cs_client = @@character_set_client */; 168 | /*!50503 SET character_set_client = utf8mb4 */; 169 | CREATE TABLE `user` ( 170 | `id` int(11) NOT NULL AUTO_INCREMENT, 171 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1删除,0正常', 172 | `createBy` varchar(20) DEFAULT NULL COMMENT '创建人', 173 | `createTime` datetime DEFAULT NULL COMMENT '创建时间', 174 | `updateBy` varchar(20) DEFAULT NULL COMMENT '最后修改人', 175 | `updateTime` datetime DEFAULT NULL COMMENT '最后修改时间', 176 | `username` varchar(30) NOT NULL COMMENT '用户名', 177 | `phone` varchar(30) NOT NULL COMMENT '电话', 178 | `password` varchar(100) NOT NULL COMMENT '密码', 179 | `name` varchar(30) NOT NULL COMMENT '姓名', 180 | `status` varchar(30) DEFAULT NULL COMMENT '状态', 181 | PRIMARY KEY (`id`) 182 | ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户'; 183 | /*!40101 SET character_set_client = @saved_cs_client */; 184 | 185 | -- 186 | -- Dumping data for table `user` 187 | -- 188 | 189 | LOCK TABLES `user` WRITE; 190 | /*!40000 ALTER TABLE `user` DISABLE KEYS */; 191 | INSERT INTO `user` VALUES (1,_binary '\0','系统','2019-11-15 15:26:40','超级管理员','2019-11-21 15:54:59','admin','10000000000','$2a$10$gsNlpjlKbOT30QNZ/23knO/ymgYZtWc2zpCdzWoqTCE9g3Ys9zVN6','超级管理员','enabled'),(2,_binary '\0','超级管理员','2019-11-21 16:16:27','超级管理员','2019-11-21 16:18:08','hgdyecdokzom','18918296251','$2a$10$yrYXaMcryY4be9U1d8UnR.lHWYQqGqiqBd5Vo/gQMbfVM0ur9PkSO','测试','enabled'); 192 | /*!40000 ALTER TABLE `user` ENABLE KEYS */; 193 | UNLOCK TABLES; 194 | 195 | -- 196 | -- Table structure for table `user_role` 197 | -- 198 | 199 | DROP TABLE IF EXISTS `user_role`; 200 | /*!40101 SET @saved_cs_client = @@character_set_client */; 201 | /*!50503 SET character_set_client = utf8mb4 */; 202 | CREATE TABLE `user_role` ( 203 | `id` int(11) NOT NULL AUTO_INCREMENT, 204 | `userId` int(11) DEFAULT NULL, 205 | `roleId` int(11) DEFAULT NULL, 206 | PRIMARY KEY (`id`) 207 | ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户角色关联'; 208 | /*!40101 SET character_set_client = @saved_cs_client */; 209 | 210 | -- 211 | -- Dumping data for table `user_role` 212 | -- 213 | 214 | LOCK TABLES `user_role` WRITE; 215 | /*!40000 ALTER TABLE `user_role` DISABLE KEYS */; 216 | INSERT INTO `user_role` VALUES (3,2,2); 217 | /*!40000 ALTER TABLE `user_role` ENABLE KEYS */; 218 | UNLOCK TABLES; 219 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; 220 | 221 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; 222 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; 223 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; 224 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 225 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 226 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 227 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; 228 | 229 | -- Dump completed on 2019-11-22 16:57:18 230 | -------------------------------------------------------------------------------- /template-generator/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | template 7 | com.step 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | template-generator 13 | 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-freemarker 18 | 19 | 20 | mysql 21 | mysql-connector-java 22 | runtime 23 | 24 | 25 | 26 | com.baomidou 27 | mybatis-plus-generator 28 | 3.3.2 29 | 30 | 31 | org.atteo 32 | evo-inflector 33 | 1.2.2 34 | 35 | 36 | org.apache.commons 37 | commons-text 38 | 1.8 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /template-generator/src/main/java/com/step/generator/Generator.java: -------------------------------------------------------------------------------- 1 | package com.step.generator; 2 | 3 | import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException; 4 | import com.baomidou.mybatisplus.core.toolkit.StringPool; 5 | import com.baomidou.mybatisplus.core.toolkit.StringUtils; 6 | import com.baomidou.mybatisplus.generator.AutoGenerator; 7 | import com.baomidou.mybatisplus.generator.InjectionConfig; 8 | import com.baomidou.mybatisplus.generator.config.*; 9 | import com.baomidou.mybatisplus.generator.config.po.TableField; 10 | import com.baomidou.mybatisplus.generator.config.po.TableInfo; 11 | import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; 12 | import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; 13 | import org.atteo.evo.inflector.English; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | import java.util.Map; 18 | import java.util.Scanner; 19 | 20 | /** 21 | * 代码生成器 22 | */ 23 | public class Generator { 24 | /** 25 | * 数据库参数配置,下面示例为mysql8.0数据库驱动,8以下请修改驱动名称 26 | */ 27 | private static final String dbUrl = "jdbc:mysql://118.25.44.86:3306/template?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai"; 28 | private static final String dbDriverName = "com.mysql.cj.jdbc.Driver"; 29 | private static final String dbUsername = "dev"; 30 | private static final String dbPassword = "hold123456"; 31 | 32 | /** 33 | * 模块名称 34 | */ 35 | private static final String targetModuleName = "template-main"; 36 | /** 37 | * 包名 38 | */ 39 | private static final String parentPackage = "com.step.template.main"; 40 | 41 | /** 42 | * 读取控制台内容 43 | */ 44 | private static String scanner(String tip) { 45 | Scanner scanner = new Scanner(System.in); 46 | System.out.println(("请输入" + tip + ":")); 47 | if (scanner.hasNext()) { 48 | String ipt = scanner.next(); 49 | if (StringUtils.isNotEmpty(ipt)) { 50 | return ipt; 51 | } 52 | } 53 | throw new MybatisPlusException("请输入正确的" + tip + "!"); 54 | } 55 | 56 | /** 57 | * RUN THIS 58 | */ 59 | public static void main(String[] args) { 60 | // 代码生成器 61 | AutoGenerator mpg = new AutoGenerator(); 62 | // 全局配置 63 | GlobalConfig gc = new GlobalConfig(); 64 | String projectPath = System.getProperty("user.dir"); 65 | gc.setOutputDir(projectPath + "/" + targetModuleName + "/src/main/java"); 66 | gc.setAuthor(""); 67 | gc.setOpen(false); 68 | gc.setFileOverride(true); 69 | gc.setSwagger2(true); 70 | String entityName = "%s"; 71 | gc.setEntityName(entityName); 72 | gc.setControllerName(entityName + "Controller"); 73 | gc.setServiceName(entityName + "Service"); 74 | gc.setMapperName(entityName + "Mapper"); 75 | gc.setBaseResultMap(false); 76 | mpg.setGlobalConfig(gc); 77 | 78 | // 数据源配置 79 | DataSourceConfig dsc = new DataSourceConfig(); 80 | dsc.setUrl(dbUrl); 81 | // dsc.setSchemaName("public"); 82 | dsc.setDriverName(dbDriverName); 83 | dsc.setUsername(dbUsername); 84 | dsc.setPassword(dbPassword); 85 | mpg.setDataSource(dsc); 86 | 87 | // 包配置 88 | PackageConfig pc = new PackageConfig(); 89 | //pc.setModuleName(scanner("模块名")); 90 | pc.setParent(parentPackage); 91 | mpg.setPackageInfo(pc); 92 | 93 | // 自定义配置 94 | InjectionConfig cfg = new InjectionConfig() { 95 | @Override 96 | public void initMap() { 97 | } 98 | 99 | @Override 100 | public Map prepareObjectMap(Map objectMap) { 101 | objectMap.put("svoPackage", parentPackage + ".svo"); 102 | objectMap.put("superSvoClass", parentPackage + ".base.BaseSvo"); 103 | TableInfo tableInfo = (TableInfo) objectMap.get("table"); 104 | objectMap.put("restUrl", English.plural(tableInfo.getEntityPath())); 105 | tableInfo.getImportPackages().remove("java.io.Serializable"); 106 | //公共字段 107 | List commonFields = new ArrayList<>(); 108 | List newFields = new ArrayList<>(); 109 | List fields = tableInfo.getFields(); 110 | StrategyConfig strategy = new StrategyConfig(); 111 | strategy.setSuperEntityColumns("createBy", "createTime", "updateBy", "updateTime"); 112 | for (TableField field : fields) { 113 | if (strategy.includeSuperEntityColumns(field.getName())) { 114 | commonFields.add(field); 115 | } else { 116 | newFields.add(field); 117 | } 118 | } 119 | if (commonFields.size() == 4) { 120 | tableInfo.setFields(newFields); 121 | objectMap.put("superEntityClassPackage", parentPackage + ".base.BaseLogEntity"); 122 | objectMap.put("superEntityClass", "BaseLogEntity"); 123 | } else { 124 | objectMap.put("superEntityClassPackage", parentPackage + ".base.BaseEntity"); 125 | objectMap.put("superEntityClass", "BaseEntity"); 126 | } 127 | return objectMap; 128 | } 129 | }; 130 | List focList = new ArrayList<>(); 131 | focList.add(new FileOutConfig("/templates/mapper.xml.ftl") { 132 | @Override 133 | public String outputFile(TableInfo tableInfo) { 134 | // 自定义输入文件名称 135 | return projectPath + "/" + targetModuleName + "/src/main/resources/mapper/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML; 136 | } 137 | }); 138 | focList.add(new FileOutConfig("/templates/svo.java.ftl") { 139 | @Override 140 | public String outputFile(TableInfo tableInfo) { 141 | String parentPackagePath = parentPackage.replace(".", "/"); 142 | String svoName = tableInfo.getEntityName() + "Svo" + StringPool.DOT_JAVA; 143 | return gc.getOutputDir() + "/" + parentPackagePath + "/svo/" + svoName; 144 | } 145 | }); 146 | cfg.setFileOutConfigList(focList); 147 | mpg.setCfg(cfg); 148 | mpg.setTemplate(new TemplateConfig().setXml(null).setServiceImpl(null)); 149 | 150 | // 策略配置 151 | StrategyConfig strategy = new StrategyConfig(); 152 | strategy.setNaming(NamingStrategy.underline_to_camel); 153 | strategy.setColumnNaming(NamingStrategy.no_change); 154 | //strategy.setSuperEntityClass("com.step.test.base.BaseEntity"); 155 | strategy.setEntityLombokModel(true); 156 | //strategy.setSuperControllerClass("com.baomidou.mybatisplus.samples.generator.common.BaseController"); 157 | strategy.setSuperServiceClass(parentPackage + ".base.BaseService"); 158 | strategy.setInclude(scanner("表名,如user;注意会覆盖已有文件")); 159 | strategy.setSuperEntityColumns("id"); 160 | strategy.setControllerMappingHyphenStyle(true); 161 | strategy.setLogicDeleteFieldName("deleted"); 162 | //strategy.setTablePrefix(pc.getModuleName() + "_"); 163 | mpg.setStrategy(strategy); 164 | // 选择 freemarker 引擎需要指定如下加,注意 pom 依赖必须有! 165 | mpg.setTemplateEngine(new FreemarkerTemplateEngine()); 166 | mpg.execute(); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /template-generator/src/main/resources/templates/controller.java.ftl: -------------------------------------------------------------------------------- 1 | package ${package.Controller}; 2 | 3 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 4 | import ${package.Entity}.${entity}; 5 | import ${package.Service}.${table.serviceName}; 6 | import ${svoPackage}.${entity}Svo; 7 | import io.swagger.annotations.Api; 8 | import io.swagger.annotations.ApiOperation; 9 | import lombok.AllArgsConstructor; 10 | import org.springframework.web.bind.annotation.*; 11 | <#if superControllerClassPackage??> 12 | import ${superControllerClassPackage}; 13 | 14 | 15 | @Api(tags = "${table.comment!}") 16 | @AllArgsConstructor 17 | @RestController 18 | @RequestMapping("${restUrl}") 19 | <#if kotlin> 20 | class ${table.controllerName}<#if superControllerClass??> : ${superControllerClass}() 21 | <#else> 22 | <#if superControllerClass??> 23 | public class ${table.controllerName} extends ${superControllerClass} { 24 | <#else> 25 | public class ${table.controllerName} { 26 | 27 | <#assign serviceNameLow = table.serviceName?uncap_first> 28 | <#assign entityLow = entity?uncap_first> 29 | 30 | private final ${table.serviceName} ${serviceNameLow}; 31 | 32 | @ApiOperation("获取列表") 33 | @GetMapping 34 | public Page<${entity}> selectWithPage(${entity}Svo svo) { 35 | return ${serviceNameLow}.selectWithPage(svo); 36 | } 37 | 38 | @ApiOperation("获取单个数据") 39 | @GetMapping("{id}") 40 | public ${entity} selectById(@PathVariable Integer id) { 41 | return ${serviceNameLow}.getById(id); 42 | } 43 | 44 | @ApiOperation("创建") 45 | @PostMapping 46 | public void insert(@RequestBody ${entity} ${entityLow}) { 47 | ${serviceNameLow}.save(${entityLow}); 48 | } 49 | 50 | @ApiOperation("编辑") 51 | @PutMapping 52 | public void updateById(@RequestBody ${entity} ${entityLow}) { 53 | ${serviceNameLow}.updateById(${entityLow}); 54 | } 55 | 56 | @ApiOperation("删除") 57 | @DeleteMapping("{id}") 58 | public void deleteById(@PathVariable Integer id) { 59 | ${serviceNameLow}.removeById(id); 60 | } 61 | } 62 | 63 | -------------------------------------------------------------------------------- /template-generator/src/main/resources/templates/entity.java.ftl: -------------------------------------------------------------------------------- 1 | package ${package.Entity}; 2 | 3 | <#list table.importPackages as pkg> 4 | import ${pkg}; 5 | 6 | import ${superEntityClassPackage}; 7 | <#if swagger2> 8 | import io.swagger.annotations.ApiModel; 9 | import io.swagger.annotations.ApiModelProperty; 10 | 11 | <#if entityLombokModel> 12 | import lombok.Getter; 13 | import lombok.Setter; 14 | import lombok.experimental.Accessors; 15 | 16 | 17 | <#if swagger2> 18 | @ApiModel("${table.comment!}Entity") 19 | 20 | <#if entityLombokModel> 21 | @Getter 22 | @Setter 23 | @Accessors(chain = true) 24 | 25 | <#if table.convert> 26 | @TableName("${table.name}") 27 | 28 | <#if superEntityClass??> 29 | public class ${entity} extends ${superEntityClass}<#if activeRecord><${entity}> { 30 | <#elseif activeRecord> 31 | public class ${entity} extends Model<${entity}> { 32 | <#else> 33 | public class ${entity} implements Serializable { 34 | 35 | <#-- ---------- BEGIN 字段循环遍历 ----------> 36 | <#list table.fields as field> 37 | <#if field.keyFlag> 38 | <#assign keyPropertyName="${field.propertyName}"/> 39 | 40 | 41 | <#if field.comment!?length gt 0> 42 | <#if swagger2> 43 | @ApiModelProperty("${field.comment}") 44 | <#else> 45 | /** 46 | * ${field.comment} 47 | */ 48 | 49 | 50 | <#if field.keyFlag> 51 | <#-- 主键 --> 52 | <#if field.keyIdentityFlag> 53 | @TableId(value = "${field.name}", type = IdType.AUTO) 54 | <#elseif idType??> 55 | @TableId(value = "${field.name}", type = IdType.${idType}) 56 | <#elseif field.convert> 57 | @TableId("${field.name}") 58 | 59 | <#-- 普通字段 --> 60 | <#elseif field.fill??> 61 | <#-- ----- 存在字段填充设置 -----> 62 | <#if field.convert> 63 | @TableField(value = "${field.name}", fill = FieldFill.${field.fill}) 64 | <#else> 65 | @TableField(fill = FieldFill.${field.fill}) 66 | 67 | <#elseif field.convert> 68 | @TableField("${field.name}") 69 | 70 | <#-- 乐观锁注解 --> 71 | <#if (versionFieldName!"") == field.name> 72 | @Version 73 | 74 | <#-- 逻辑删除注解 --> 75 | <#if (logicDeleteFieldName!"") == field.name> 76 | @TableLogic 77 | 78 | private ${field.propertyType} ${field.propertyName}; 79 | 80 | <#------------ END 字段循环遍历 ----------> 81 | <#if !entityLombokModel> 82 | <#list table.fields as field> 83 | <#if field.propertyType == "boolean"> 84 | <#assign getprefix="is"/> 85 | <#else> 86 | <#assign getprefix="get"/> 87 | 88 | public ${field.propertyType} ${getprefix}${field.capitalName}() { 89 | return ${field.propertyName}; 90 | } 91 | 92 | <#if entityBuilderModel> 93 | public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) { 94 | <#else> 95 | public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) { 96 | 97 | this.${field.propertyName} = ${field.propertyName}; 98 | <#if entityBuilderModel> 99 | return this; 100 | 101 | } 102 | 103 | 104 | 105 | <#if entityColumnConstant> 106 | <#list table.fields as field> 107 | public static final String ${field.name?upper_case} = "${field.name}"; 108 | 109 | 110 | 111 | <#if activeRecord> 112 | @Override 113 | protected Serializable pkVal() { 114 | <#if keyPropertyName??> 115 | return this.${keyPropertyName}; 116 | <#else> 117 | return null; 118 | 119 | } 120 | 121 | <#if !entityLombokModel> 122 | @Override 123 | public String toString() { 124 | return "${entity}{" + 125 | <#list table.fields as field> 126 | <#if field_index==0> 127 | "${field.propertyName}=" + ${field.propertyName} + 128 | <#else> 129 | ", ${field.propertyName}=" + ${field.propertyName} + 130 | 131 | 132 | "}"; 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /template-generator/src/main/resources/templates/mapper.java.ftl: -------------------------------------------------------------------------------- 1 | package ${package.Mapper}; 2 | 3 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 4 | import ${package.Entity}.${entity}; 5 | import ${superMapperClassPackage}; 6 | import ${svoPackage}.${entity}Svo; 7 | import org.apache.ibatis.annotations.Param; 8 | import org.springframework.stereotype.Repository; 9 | 10 | <#if kotlin> 11 | interface ${table.mapperName} : ${superMapperClass}<${entity}> 12 | <#else> 13 | @Repository 14 | public interface ${table.mapperName} extends ${superMapperClass}<${entity}> { 15 | //todo xml自行实现,不需要则删除 16 | Page<${entity}> selectWithPage(Page<${entity}> page, @Param("svo") ${entity}Svo svo); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /template-generator/src/main/resources/templates/mapper.xml.ftl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <#if enableCache> 6 | 7 | 8 | 9 | 10 | <#if baseResultMap> 11 | 12 | 13 | <#list table.fields as field> 14 | <#if field.keyFlag><#--生成主键排在第一位--> 15 | 16 | 17 | 18 | <#list table.commonFields as field><#--生成公共字段 --> 19 | 20 | 21 | <#list table.fields as field> 22 | <#if !field.keyFlag><#--生成普通字段 --> 23 | 24 | 25 | 26 | 27 | 28 | 29 | <#if baseColumnList> 30 | 31 | 32 | <#list table.commonFields as field> 33 | ${field.name}, 34 | 35 | ${table.fieldNames} 36 | 37 | 38 | 39 | 43 | 44 | -------------------------------------------------------------------------------- /template-generator/src/main/resources/templates/service.java.ftl: -------------------------------------------------------------------------------- 1 | package ${package.Service}; 2 | 3 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 4 | import ${svoPackage}.${entity}Svo; 5 | import ${package.Entity}.${entity}; 6 | import ${package.Mapper}.${table.mapperName}; 7 | import ${superServiceClassPackage}; 8 | import org.springframework.stereotype.Service; 9 | import org.springframework.transaction.annotation.Transactional; 10 | import lombok.AllArgsConstructor; 11 | 12 | /** 13 | * ${table.comment!} 服务类 14 | */ 15 | <#if kotlin> 16 | interface ${table.serviceName} : ${superServiceClass}<${entity}> 17 | <#else> 18 | @Service 19 | @Transactional 20 | @AllArgsConstructor 21 | public class ${table.serviceName} extends ${superServiceClass}<${entity}> { 22 | <#assign mapperNameLow = table.mapperName?uncap_first> 23 | 24 | private final ${table.mapperName} ${mapperNameLow}; 25 | 26 | //todo 自行修改 27 | public Page<${entity}> selectWithPage(${entity}Svo svo) { 28 | return ${mapperNameLow}.selectWithPage(svo.getPage(), svo); 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /template-generator/src/main/resources/templates/svo.java.ftl: -------------------------------------------------------------------------------- 1 | package ${svoPackage}; 2 | 3 | import ${superSvoClass}; 4 | import io.swagger.annotations.ApiModel; 5 | import io.swagger.annotations.ApiModelProperty; 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | 9 | @ApiModel("查询条件") 10 | @Getter 11 | @Setter 12 | public class ${entity}Svo extends BaseSvo{ 13 | 14 | //todo 此字段仅供参考,请更改 15 | @ApiModelProperty("搜索-字段名称") 16 | private String demo; 17 | } -------------------------------------------------------------------------------- /template-main/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jre-alpine 2 | MAINTAINER liunewshine@qq.com 3 | 4 | ENV TZ=Asia/Shanghai 5 | RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && mkdir -p /my-app 6 | WORKDIR /my-app 7 | 8 | EXPOSE 8020 9 | 10 | ADD ./target/template-main.jar ./ 11 | CMD java -Djava.security.egd=file:/dev/./urandom -jar template-main.jar 12 | -------------------------------------------------------------------------------- /template-main/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | template 7 | com.step 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | template-main 13 | 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-web 18 | 19 | 20 | org.mybatis.spring.boot 21 | mybatis-spring-boot-starter 22 | 2.1.3 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-aop 27 | 28 | 29 | mysql 30 | mysql-connector-java 31 | runtime 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-configuration-processor 36 | true 37 | 38 | 39 | org.projectlombok 40 | lombok 41 | true 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-starter-test 46 | test 47 | 48 | 49 | org.junit.vintage 50 | junit-vintage-engine 51 | 52 | 53 | 54 | 55 | 56 | com.auth0 57 | java-jwt 58 | 3.10.3 59 | 60 | 61 | 62 | org.apache.commons 63 | commons-lang3 64 | 3.10 65 | 66 | 67 | io.springfox 68 | springfox-swagger2 69 | 2.9.2 70 | 71 | 72 | io.springfox 73 | springfox-swagger-ui 74 | 2.9.2 75 | 76 | 77 | 78 | com.baomidou 79 | mybatis-plus-boot-starter 80 | 3.3.2 81 | 82 | 83 | 84 | 85 | ${project.name} 86 | 87 | 88 | org.springframework.boot 89 | spring-boot-maven-plugin 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/TemplateApplication.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.boot.CommandLineRunner; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.ansi.AnsiColor; 8 | import org.springframework.boot.ansi.AnsiOutput; 9 | import org.springframework.boot.autoconfigure.SpringBootApplication; 10 | import org.springframework.cache.annotation.EnableCaching; 11 | import org.springframework.scheduling.annotation.EnableScheduling; 12 | 13 | @Slf4j 14 | @AllArgsConstructor 15 | @EnableCaching 16 | @EnableScheduling 17 | @SpringBootApplication 18 | public class TemplateApplication implements CommandLineRunner { 19 | 20 | public static void main(String[] args) { 21 | SpringApplication.run(TemplateApplication.class, args); 22 | } 23 | 24 | @Override 25 | public void run(String... strings) { 26 | log.info(AnsiOutput.toString(AnsiColor.GREEN, "-------------------平台启动成功-------------------")); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/base/BaseEntity.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.base; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | import com.step.template.main.exception.MyException; 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | import org.springframework.beans.BeanUtils; 9 | 10 | /** 11 | * 实体父类 12 | */ 13 | @Getter 14 | @Setter 15 | public class BaseEntity { 16 | @TableId(type = IdType.AUTO) 17 | private Integer id; 18 | 19 | /** 20 | * model和vo互转 21 | */ 22 | public D toBean(Class clazz) { 23 | try { 24 | D d = clazz.getDeclaredConstructor().newInstance(); 25 | BeanUtils.copyProperties(this, d); 26 | return d; 27 | } catch (Exception e) { 28 | throw new MyException(e); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/base/BaseLogEntity.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.base; 2 | 3 | import com.baomidou.mybatisplus.annotation.FieldFill; 4 | import com.baomidou.mybatisplus.annotation.FieldStrategy; 5 | import com.baomidou.mybatisplus.annotation.TableField; 6 | import io.swagger.annotations.ApiModelProperty; 7 | import lombok.Getter; 8 | import lombok.Setter; 9 | 10 | import java.time.LocalDateTime; 11 | 12 | /** 13 | * 实体父类 14 | */ 15 | @Getter 16 | @Setter 17 | public class BaseLogEntity extends BaseEntity { 18 | 19 | @ApiModelProperty("创建人") 20 | @TableField(fill = FieldFill.INSERT, updateStrategy = FieldStrategy.NEVER) 21 | private String createBy; 22 | 23 | @TableField(fill = FieldFill.INSERT, updateStrategy = FieldStrategy.NEVER) 24 | private LocalDateTime createTime; 25 | 26 | @ApiModelProperty("修改人") 27 | @TableField(fill = FieldFill.INSERT_UPDATE) 28 | private String updateBy; 29 | 30 | @TableField(fill = FieldFill.INSERT_UPDATE) 31 | private LocalDateTime updateTime; 32 | } 33 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/base/BaseService.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.base; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 4 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 5 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 6 | import com.baomidou.mybatisplus.core.toolkit.support.SFunction; 7 | import com.baomidou.mybatisplus.extension.service.IService; 8 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 9 | import com.step.template.main.exception.MyException; 10 | import org.apache.commons.lang3.StringUtils; 11 | import org.springframework.core.GenericTypeResolver; 12 | import org.springframework.lang.Nullable; 13 | 14 | import java.math.BigDecimal; 15 | import java.util.Collection; 16 | 17 | public class BaseService extends ServiceImpl, T> implements IService { 18 | 19 | /** 20 | * 判断非空 21 | */ 22 | protected static boolean isNotEmpty(Integer value) { 23 | return value != null; 24 | } 25 | 26 | /** 27 | * 判断非空 28 | */ 29 | protected static boolean isNotEmpty(BigDecimal value) { 30 | return value != null; 31 | } 32 | 33 | /** 34 | * 字符串判断非空 35 | */ 36 | protected static boolean isNotEmpty(String str) { 37 | return StringUtils.isNotEmpty(str); 38 | } 39 | 40 | /** 41 | * 集合判断是否非空 42 | */ 43 | protected static boolean isNotEmpty(Collection collection) { 44 | return !isEmpty(collection); 45 | } 46 | 47 | /** 48 | * 集合判断是否空 49 | */ 50 | protected static boolean isEmpty(Collection collection) { 51 | return collection == null || collection.isEmpty(); 52 | } 53 | 54 | /** 55 | * 判断某个字段是否唯一,不唯一抛出异常 56 | * 57 | * @param fn 要检查的字段 58 | * @param value 要检查的字段值 59 | * @param excludeId 要排除的id,可以为null,新增不用排除自身 60 | * @param errorMsg 错误提示文字 61 | */ 62 | public void checkUnique(SFunction fn, Object value, @Nullable Integer excludeId, String errorMsg) { 63 | QueryWrapper queryWrapper = new QueryWrapper<>(); 64 | if (excludeId != null) { 65 | queryWrapper.ne("id", excludeId); 66 | } 67 | LambdaQueryWrapper lambdaQueryWrapper = queryWrapper.lambda(); 68 | lambdaQueryWrapper.eq(fn, value); 69 | int count = this.count(lambdaQueryWrapper); 70 | if (count > 0) { 71 | throw new MyException(errorMsg); 72 | } 73 | } 74 | 75 | /** 76 | * 覆写mybatis-plus获取泛型class方式,防止多重继承时无法获取class 77 | */ 78 | @SuppressWarnings("unchecked") 79 | @Override 80 | protected Class currentModelClass() { 81 | return (Class) GenericTypeResolver.resolveTypeArgument(getClass(), BaseService.class); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/base/BaseSvo.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.base; 2 | 3 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | @Getter 8 | @Setter 9 | public class BaseSvo { 10 | private int pageNum = 1; 11 | private int pageSize = 10; 12 | 13 | public Page getPage() { 14 | return new Page<>(pageNum, pageSize); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/config/AuthAspect.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.config; 2 | 3 | import com.step.template.main.config.annotation.Auth; 4 | import com.step.template.main.exception.NoAuthException; 5 | import com.step.template.main.exception.UnauthorizedException; 6 | import com.step.template.main.service.AccountService; 7 | import com.step.template.main.util.Constant; 8 | import com.step.template.main.util.JwtUtil; 9 | import com.step.template.main.vo.MyScope; 10 | import lombok.AllArgsConstructor; 11 | import lombok.extern.slf4j.Slf4j; 12 | import org.apache.commons.lang3.StringUtils; 13 | import org.aspectj.lang.JoinPoint; 14 | import org.aspectj.lang.ProceedingJoinPoint; 15 | import org.aspectj.lang.annotation.Around; 16 | import org.aspectj.lang.annotation.Aspect; 17 | import org.aspectj.lang.annotation.Before; 18 | import org.aspectj.lang.reflect.MethodSignature; 19 | import org.springframework.stereotype.Component; 20 | import org.springframework.web.context.request.RequestContextHolder; 21 | import org.springframework.web.context.request.ServletRequestAttributes; 22 | 23 | import javax.servlet.http.HttpServletRequest; 24 | import java.lang.reflect.Method; 25 | import java.util.Arrays; 26 | import java.util.Objects; 27 | import java.util.Set; 28 | 29 | import static com.step.template.main.util.Constant.ADMIN_ID; 30 | import static com.step.template.main.util.Constant.AUTHORIZATION; 31 | 32 | @Slf4j 33 | @AllArgsConstructor 34 | @Aspect 35 | @Component 36 | public class AuthAspect { 37 | 38 | private final AccountService accountService; 39 | 40 | @Before("execution(* com.step.template.main.controller..*.*(..))") 41 | public void doBefore(JoinPoint joinPoint) { 42 | ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); 43 | if (attributes != null) { 44 | HttpServletRequest request = attributes.getRequest(); 45 | String content = "收到请求 | URL:" + request.getRequestURL() + 46 | " | HTTP_METHOD:" + request.getMethod() + 47 | " | IP:" + request.getRemoteAddr() + 48 | " | CLASS_METHOD:" + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName() + 49 | " | ARGS:" + Arrays.toString(joinPoint.getArgs()); 50 | log.info(content); 51 | } 52 | } 53 | 54 | @Around("execution(* com.step.template.main.controller..*.*(..)) && !@annotation(com.step.template.main.config.annotation.NoAuth)") 55 | public Object around(ProceedingJoinPoint joinPoint) throws Throwable { 56 | ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); 57 | HttpServletRequest request = Objects.requireNonNull(attributes).getRequest(); 58 | String token = request.getHeader(AUTHORIZATION); 59 | if (StringUtils.isEmpty(token)) { 60 | throw new UnauthorizedException(); 61 | } 62 | int userId; 63 | try { 64 | userId = JwtUtil.getUserId(token); 65 | } catch (Exception e) { 66 | throw new UnauthorizedException(); 67 | } 68 | MyScope scope = accountService.cacheScope(userId); 69 | request.setAttribute(Constant.SCOPE, scope); 70 | //admin有所有权限 71 | if (ADMIN_ID.equals(scope.getUserId())) { 72 | return joinPoint.proceed(); 73 | } 74 | MethodSignature methodSignature = (MethodSignature) joinPoint.getStaticPart().getSignature(); 75 | Method method = methodSignature.getMethod(); 76 | Auth auth = method.getAnnotation(Auth.class); 77 | if (auth != null) { 78 | String[] authNames = auth.value(); 79 | Set permissions = scope.getPermissions(); 80 | boolean hasAuth = false; 81 | for (String authName : authNames) { 82 | if (permissions.contains(authName)) { 83 | hasAuth = true; 84 | break; 85 | } 86 | } 87 | if (!hasAuth) { 88 | throw new NoAuthException(); 89 | } 90 | } 91 | return joinPoint.proceed(); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/config/MvcConfig.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.config; 2 | 3 | import com.fasterxml.jackson.core.JsonGenerator; 4 | import com.fasterxml.jackson.databind.DeserializationFeature; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import com.fasterxml.jackson.databind.SerializationFeature; 7 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 8 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; 9 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; 10 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; 11 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; 12 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; 13 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; 14 | import lombok.extern.slf4j.Slf4j; 15 | import org.springframework.context.annotation.Bean; 16 | import org.springframework.context.annotation.Configuration; 17 | import org.springframework.format.FormatterRegistry; 18 | import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar; 19 | import org.springframework.scheduling.TaskScheduler; 20 | import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; 21 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 22 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 23 | 24 | import java.time.LocalDate; 25 | import java.time.LocalDateTime; 26 | import java.time.LocalTime; 27 | 28 | import static com.step.template.main.util.MyDateUtil.*; 29 | 30 | 31 | /** 32 | * WebMVC配置 33 | */ 34 | @Slf4j 35 | @Configuration 36 | public class MvcConfig implements WebMvcConfigurer { 37 | 38 | /** 39 | * ajax跨域请求 40 | */ 41 | @Override 42 | public void addCorsMappings(CorsRegistry registry) { 43 | registry.addMapping("/**") 44 | .allowedOrigins("*") 45 | .allowedMethods("*") 46 | .allowedHeaders("*"); 47 | } 48 | 49 | 50 | /** 51 | * get方法接收日期类型的参数 52 | */ 53 | @Override 54 | public void addFormatters(FormatterRegistry registry) { 55 | DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar(); 56 | registrar.setDateTimeFormatter(PATTERN_DATE_TIME); 57 | registrar.setDateFormatter(PATTERN_DATE); 58 | registrar.setTimeFormatter(PATTERN_TIME); 59 | registrar.registerFormatters(registry); 60 | } 61 | 62 | /** 63 | * 更改jackson默认配置 64 | */ 65 | @Bean 66 | public ObjectMapper ObjectMapper() { 67 | ObjectMapper objectMapper = new ObjectMapper(); 68 | // 对于空的对象转json的时候不抛出错误 69 | objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); 70 | // 禁用遇到未知属性抛出异常 71 | objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); 72 | // 序列化BigDecimal时不使用科学计数法输出 73 | objectMapper.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true); 74 | // 日期和时间格式化 75 | JavaTimeModule javaTimeModule = new JavaTimeModule(); 76 | javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(PATTERN_DATE_TIME)); 77 | javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(PATTERN_DATE)); 78 | javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(PATTERN_TIME)); 79 | javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(PATTERN_DATE_TIME)); 80 | javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(PATTERN_DATE)); 81 | javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(PATTERN_TIME)); 82 | objectMapper.registerModule(javaTimeModule); 83 | return objectMapper; 84 | } 85 | 86 | /** 87 | * 定时任务线程池更改,防止多个任务并行 88 | */ 89 | @Bean 90 | public TaskScheduler taskScheduler() { 91 | final ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); 92 | scheduler.setPoolSize(5); 93 | return scheduler; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/config/ProjectParam.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.config; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Data 8 | @Component 9 | @ConfigurationProperties("project") 10 | public class ProjectParam { 11 | private String demoParam; 12 | } 13 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/config/Swagger2.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.config; 2 | 3 | import com.google.common.collect.Lists; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.context.annotation.Profile; 7 | import org.springframework.http.ResponseEntity; 8 | import springfox.documentation.builders.ApiInfoBuilder; 9 | import springfox.documentation.builders.PathSelectors; 10 | import springfox.documentation.builders.RequestHandlerSelectors; 11 | import springfox.documentation.service.ApiInfo; 12 | import springfox.documentation.service.ApiKey; 13 | import springfox.documentation.service.AuthorizationScope; 14 | import springfox.documentation.service.SecurityReference; 15 | import springfox.documentation.spi.DocumentationType; 16 | import springfox.documentation.spi.service.contexts.SecurityContext; 17 | import springfox.documentation.spring.web.plugins.Docket; 18 | import springfox.documentation.swagger.web.SecurityConfiguration; 19 | import springfox.documentation.swagger.web.SecurityConfigurationBuilder; 20 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 21 | 22 | import java.time.LocalDate; 23 | import java.util.Collections; 24 | import java.util.List; 25 | 26 | @Profile({"dev", "test"}) 27 | @Configuration 28 | @EnableSwagger2 29 | public class Swagger2 { 30 | 31 | @Bean 32 | public Docket swaggerPlugin() { 33 | return new Docket(DocumentationType.SWAGGER_2) 34 | .select() 35 | .paths(PathSelectors.any()) 36 | .apis(RequestHandlerSelectors.basePackage("com.step.template.main.controller")) 37 | .build().directModelSubstitute(LocalDate.class, String.class) 38 | .genericModelSubstitutes(ResponseEntity.class) 39 | .apiInfo(apiInfo()) 40 | .securitySchemes(Lists.newArrayList(apiKey())) 41 | .securityContexts(Collections.singletonList(securityContext())); 42 | } 43 | 44 | private ApiInfo apiInfo() { 45 | return new ApiInfoBuilder() 46 | .title("Template API") 47 | .version("1.0") 48 | .build(); 49 | } 50 | 51 | @Bean 52 | public SecurityConfiguration security() { 53 | return SecurityConfigurationBuilder.builder().scopeSeparator(",") 54 | .additionalQueryStringParams(null) 55 | .useBasicAuthenticationWithAccessCodeGrant(false).build(); 56 | } 57 | 58 | private ApiKey apiKey() { 59 | return new ApiKey("apiKey", "Authorization", "header"); 60 | } 61 | 62 | private SecurityContext securityContext() { 63 | return SecurityContext.builder().securityReferences(defaultAuth()) 64 | .forPaths(PathSelectors.any()).build(); 65 | } 66 | 67 | private List defaultAuth() { 68 | AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); 69 | AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; 70 | authorizationScopes[0] = authorizationScope; 71 | return Collections.singletonList(new SecurityReference("apiKey", authorizationScopes)); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/config/annotation/Auth.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.config.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Target(ElementType.METHOD) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface Auth { 11 | 12 | /** 13 | * 权限名称,为空表示只需要登录不需要权限,多个权限为或者关系 14 | */ 15 | String[] value() default {}; 16 | } 17 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/config/annotation/NoAuth.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.config.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * 不需要拦截验证权限的方法加上这个注解 10 | */ 11 | @Target(ElementType.METHOD) 12 | @Retention(RetentionPolicy.RUNTIME) 13 | public @interface NoAuth { 14 | } 15 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/config/mybatis/MyMetaObjectHandler.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.config.mybatis; 2 | 3 | import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; 4 | import com.step.template.main.util.ScopeUtil; 5 | import com.step.template.main.vo.MyScope; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.apache.ibatis.reflection.MetaObject; 8 | import org.springframework.stereotype.Component; 9 | 10 | import java.time.LocalDateTime; 11 | 12 | /** 13 | * 填充器 14 | */ 15 | @Slf4j 16 | @Component 17 | public class MyMetaObjectHandler implements MetaObjectHandler { 18 | 19 | @Override 20 | public void insertFill(MetaObject metaObject) { 21 | log.info("start insert fill ...."); 22 | try { 23 | MyScope scope = ScopeUtil.getScope(); 24 | this.setFieldValByName("createBy", scope.getName(), metaObject); 25 | this.setFieldValByName("createTime", LocalDateTime.now(), metaObject); 26 | this.setFieldValByName("updateBy", scope.getName(), metaObject); 27 | this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject); 28 | } catch (Exception e) { 29 | log.error(e.getMessage()); 30 | } 31 | } 32 | 33 | @Override 34 | public void updateFill(MetaObject metaObject) { 35 | log.info("start update fill ...."); 36 | try { 37 | MyScope scope = ScopeUtil.getScope(); 38 | this.setFieldValByName("updateBy", scope.getName(), metaObject); 39 | this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject); 40 | } catch (Exception e) { 41 | log.error(e.getMessage()); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/config/mybatis/MybatisPlusConfig.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.config.mybatis; 2 | 3 | import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; 4 | import org.mybatis.spring.annotation.MapperScan; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.transaction.annotation.EnableTransactionManagement; 8 | 9 | @EnableTransactionManagement 10 | @Configuration 11 | @MapperScan("com.step.template.main.mapper") 12 | public class MybatisPlusConfig { 13 | 14 | @Bean 15 | public PaginationInterceptor paginationInterceptor() { 16 | return new PaginationInterceptor(); 17 | } 18 | } -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/controller/AccountController.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.controller; 2 | 3 | import com.step.template.main.config.annotation.NoAuth; 4 | import com.step.template.main.service.AccountService; 5 | import io.swagger.annotations.Api; 6 | import io.swagger.annotations.ApiOperation; 7 | import io.swagger.annotations.ApiParam; 8 | import lombok.AllArgsConstructor; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RequestParam; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import java.util.Map; 15 | 16 | @Api(tags = "认证") 17 | @AllArgsConstructor 18 | @RestController 19 | @RequestMapping("account") 20 | public class AccountController { 21 | 22 | private final AccountService accountService; 23 | 24 | @NoAuth 25 | @ApiOperation("登录") 26 | @GetMapping("login") 27 | public Map login(@RequestParam @ApiParam(value = "账号", required = true) String phone, 28 | @RequestParam @ApiParam(value = "密码", required = true) String password) { 29 | return accountService.login(phone, password); 30 | } 31 | 32 | @ApiOperation("修改密码") 33 | @GetMapping("changePassword") 34 | public void changePassword(@RequestParam @ApiParam(value = "原密码", required = true) String oldPassword, 35 | @RequestParam @ApiParam(value = "新密码", required = true) String newPassword) { 36 | accountService.changePassword(oldPassword, newPassword); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/controller/DeptController.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.controller; 2 | 3 | import com.step.template.main.config.annotation.Auth; 4 | import com.step.template.main.entity.Dept; 5 | import com.step.template.main.service.DeptService; 6 | import com.step.template.main.vo.TreeNode; 7 | import io.swagger.annotations.Api; 8 | import io.swagger.annotations.ApiOperation; 9 | import lombok.AllArgsConstructor; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | import java.util.List; 13 | 14 | @Api(tags = "部门") 15 | @AllArgsConstructor 16 | @RestController 17 | @RequestMapping("depts") 18 | public class DeptController { 19 | 20 | private final DeptService deptService; 21 | 22 | @ApiOperation("获取部门树") 23 | @GetMapping 24 | public List selectAll() { 25 | return deptService.selectAll(); 26 | } 27 | 28 | @ApiOperation("获取单个数据") 29 | @GetMapping("{id}") 30 | public Dept selectById(@PathVariable Integer id) { 31 | return deptService.getById(id); 32 | } 33 | 34 | @Auth("dept:edit") 35 | @ApiOperation("创建") 36 | @PostMapping 37 | public void insert(@RequestBody Dept dept) { 38 | deptService.save(dept); 39 | } 40 | 41 | @Auth("dept:edit") 42 | @ApiOperation("编辑") 43 | @PutMapping 44 | public void updateById(@RequestBody Dept dept) { 45 | deptService.updateById(dept); 46 | } 47 | 48 | @Auth("dept:edit") 49 | @ApiOperation("删除") 50 | @DeleteMapping("{id}") 51 | public void deleteById(@PathVariable Integer id) { 52 | deptService.deleteById(id); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/controller/DeviceController.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.controller; 2 | 3 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 4 | import com.step.template.main.config.annotation.Auth; 5 | import com.step.template.main.entity.Device; 6 | import com.step.template.main.service.DeviceService; 7 | import com.step.template.main.svo.DeviceSvo; 8 | import com.step.template.main.vo.DeviceVo; 9 | import io.swagger.annotations.Api; 10 | import io.swagger.annotations.ApiOperation; 11 | import lombok.AllArgsConstructor; 12 | import org.springframework.web.bind.annotation.*; 13 | 14 | @Api(tags = "增删改查测试") 15 | @AllArgsConstructor 16 | @RestController 17 | @RequestMapping("devices") 18 | public class DeviceController { 19 | 20 | private final DeviceService deviceService; 21 | 22 | @Auth("device:query") 23 | @ApiOperation("获取列表") 24 | @GetMapping 25 | public Page selectWithPage(DeviceSvo svo) { 26 | return deviceService.selectWithPage(svo); 27 | } 28 | 29 | @Auth("device:query") 30 | @ApiOperation("获取单个数据") 31 | @GetMapping("{id}") 32 | public DeviceVo selectById(@PathVariable Integer id) { 33 | return deviceService.getVoById(id); 34 | } 35 | 36 | @Auth("device:edit") 37 | @ApiOperation("创建") 38 | @PostMapping 39 | public void insert(@RequestBody Device device) { 40 | deviceService.save(device); 41 | } 42 | 43 | @Auth("device:edit") 44 | @ApiOperation("编辑") 45 | @PutMapping 46 | public void updateById(@RequestBody Device device) { 47 | deviceService.updateById(device); 48 | } 49 | 50 | @Auth("device:edit") 51 | @ApiOperation("删除") 52 | @DeleteMapping("{id}") 53 | public void deleteById(@PathVariable Integer id) { 54 | deviceService.removeById(id); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/controller/PermissionController.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.controller; 2 | 3 | import com.step.template.main.service.PermissionService; 4 | import com.step.template.main.vo.TreeNode; 5 | import io.swagger.annotations.Api; 6 | import io.swagger.annotations.ApiOperation; 7 | import lombok.AllArgsConstructor; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | import java.util.List; 14 | import java.util.Set; 15 | 16 | @Api(tags = "权限") 17 | @AllArgsConstructor 18 | @RestController 19 | @RequestMapping("permissions") 20 | public class PermissionController { 21 | 22 | private final PermissionService permissionService; 23 | 24 | @ApiOperation("获取列表") 25 | @GetMapping 26 | public List selectAll() { 27 | return permissionService.selectAll(); 28 | } 29 | 30 | @ApiOperation("获取某个用户的权限列表") 31 | @GetMapping("userId/{userId}") 32 | public Set selectByUserId(@PathVariable Integer userId) { 33 | return permissionService.selectByUseId(userId); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/controller/RoleController.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.controller; 2 | 3 | import com.baomidou.mybatisplus.core.metadata.IPage; 4 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 5 | import com.step.template.main.base.BaseSvo; 6 | import com.step.template.main.config.annotation.Auth; 7 | import com.step.template.main.entity.Role; 8 | import com.step.template.main.service.RoleService; 9 | import io.swagger.annotations.Api; 10 | import io.swagger.annotations.ApiOperation; 11 | import lombok.AllArgsConstructor; 12 | import org.springframework.web.bind.annotation.*; 13 | 14 | import java.util.List; 15 | 16 | @Api(tags = "角色") 17 | @AllArgsConstructor 18 | @RestController 19 | @RequestMapping("roles") 20 | public class RoleController { 21 | 22 | private final RoleService roleService; 23 | 24 | @Auth("role:query") 25 | @ApiOperation("获取列表") 26 | @GetMapping 27 | public IPage findWithPage(BaseSvo svo) { 28 | return roleService.page(new Page<>(svo.getPageNum(), svo.getPageSize())); 29 | } 30 | 31 | @Auth("role:query") 32 | @ApiOperation("获取全部列表") 33 | @GetMapping("all") 34 | public List selectAll() { 35 | return roleService.list(); 36 | } 37 | 38 | @Auth("role:query") 39 | @ApiOperation("获取详情") 40 | @GetMapping("{id}") 41 | public Role selectById(@PathVariable Integer id) { 42 | return roleService.selectById(id); 43 | } 44 | 45 | @Auth("role:edit") 46 | @ApiOperation("创建") 47 | @PostMapping 48 | public void insert(@RequestBody Role role) { 49 | roleService.insertRole(role); 50 | } 51 | 52 | @Auth("role:edit") 53 | @ApiOperation("编辑") 54 | @PutMapping 55 | public void updateByPrimaryKey(@RequestBody Role role) { 56 | roleService.updateRole(role); 57 | } 58 | 59 | @Auth("role:edit") 60 | @ApiOperation("删除") 61 | @DeleteMapping("{id}") 62 | public void deleteByPrimaryKey(@PathVariable Integer id) { 63 | roleService.deleteRole(id); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.controller; 2 | 3 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 4 | import com.step.template.main.config.annotation.Auth; 5 | import com.step.template.main.entity.User; 6 | import com.step.template.main.exception.MyException; 7 | import com.step.template.main.service.UserService; 8 | import com.step.template.main.svo.UserSvo; 9 | import com.step.template.main.vo.UserVo; 10 | import io.swagger.annotations.Api; 11 | import io.swagger.annotations.ApiOperation; 12 | import lombok.AllArgsConstructor; 13 | import org.springframework.web.bind.annotation.*; 14 | 15 | import static com.step.template.main.util.Constant.ADMIN_ID; 16 | 17 | @Api(tags = "用户") 18 | @AllArgsConstructor 19 | @RestController 20 | @RequestMapping("users") 21 | public class UserController { 22 | 23 | private final UserService userService; 24 | 25 | @Auth("user:query") 26 | @ApiOperation("获取列表") 27 | @GetMapping 28 | public Page findWithPage(UserSvo svo) { 29 | return userService.selectWithPage(svo); 30 | } 31 | 32 | @Auth("user:query") 33 | @ApiOperation("获取详情") 34 | @GetMapping("{id}") 35 | public UserVo selectByPrimaryKey(@PathVariable Integer id) { 36 | return userService.getVoById(id); 37 | } 38 | 39 | @Auth("user:edit") 40 | @ApiOperation("创建") 41 | @PostMapping 42 | public void insert(@RequestBody User user) { 43 | userService.insertUser(user); 44 | } 45 | 46 | @Auth("user:edit") 47 | @ApiOperation("编辑") 48 | @PutMapping 49 | public void updateByPrimaryKey(@RequestBody User user) { 50 | checkIsAdmin(user.getId()); 51 | userService.updateUser(user); 52 | } 53 | 54 | @Auth("user:edit") 55 | @ApiOperation("禁用启用账号") 56 | @PutMapping("{id}/toggleStatus") 57 | public void toggleStatus(@PathVariable Integer id) { 58 | checkIsAdmin(id); 59 | userService.toggleStatus(id); 60 | } 61 | 62 | @Auth("user:edit") 63 | @ApiOperation("重置密码为template123456") 64 | @PutMapping("{id}/resetPassword") 65 | public void resetPassword(@PathVariable Integer id) { 66 | userService.updatePassword(id, "template123456"); 67 | } 68 | 69 | @Auth("user:edit") 70 | @ApiOperation("删除") 71 | @DeleteMapping("{id}") 72 | public void deleteById(@PathVariable Integer id) { 73 | checkIsAdmin(id); 74 | userService.removeById(id); 75 | } 76 | 77 | private void checkIsAdmin(Integer id) { 78 | if (ADMIN_ID.equals(id)) { 79 | throw new MyException("不允许修改超级管理员"); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/entity/Dept.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableLogic; 4 | import com.baomidou.mybatisplus.annotation.TableName; 5 | import com.step.template.main.base.BaseLogEntity; 6 | import io.swagger.annotations.ApiModel; 7 | import lombok.Getter; 8 | import lombok.Setter; 9 | import lombok.experimental.Accessors; 10 | 11 | @ApiModel("部门Entity") 12 | @Getter 13 | @Setter 14 | @Accessors(chain = true) 15 | @TableName("dept") 16 | public class Dept extends BaseLogEntity { 17 | 18 | @TableLogic 19 | private Integer deleted; 20 | 21 | private String name; 22 | 23 | private Integer parentId; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/entity/Device.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import com.step.template.main.base.BaseLogEntity; 5 | import io.swagger.annotations.ApiModel; 6 | import io.swagger.annotations.ApiModelProperty; 7 | import lombok.Getter; 8 | import lombok.Setter; 9 | import lombok.experimental.Accessors; 10 | 11 | @ApiModel("DemoEntity") 12 | @Getter 13 | @Setter 14 | @Accessors(chain = true) 15 | @TableName("device") 16 | public class Device extends BaseLogEntity { 17 | 18 | @ApiModelProperty("编号") 19 | private String no; 20 | 21 | @ApiModelProperty("名称") 22 | private String name; 23 | 24 | @ApiModelProperty("型号") 25 | private String model; 26 | 27 | @ApiModelProperty("维保工,关联用户表id") 28 | private Integer maintUserId; 29 | } 30 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/entity/Permission.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import com.step.template.main.base.BaseEntity; 5 | import io.swagger.annotations.ApiModel; 6 | import io.swagger.annotations.ApiModelProperty; 7 | import lombok.Getter; 8 | import lombok.Setter; 9 | 10 | @ApiModel("系统权限") 11 | @Getter 12 | @Setter 13 | @TableName("permission") 14 | public class Permission extends BaseEntity { 15 | 16 | @ApiModelProperty("编号") 17 | private String code; 18 | 19 | @ApiModelProperty("名称") 20 | private String name; 21 | 22 | @ApiModelProperty("父级ID") 23 | private Integer parentId; 24 | } 25 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/entity/Role.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import com.step.template.main.base.BaseLogEntity; 5 | import io.swagger.annotations.ApiModel; 6 | import io.swagger.annotations.ApiModelProperty; 7 | import lombok.Getter; 8 | import lombok.Setter; 9 | 10 | import java.util.List; 11 | 12 | @ApiModel("系统角色") 13 | @Getter 14 | @Setter 15 | @TableName("role") 16 | public class Role extends BaseLogEntity { 17 | @ApiModelProperty("名称") 18 | private String name; 19 | 20 | @ApiModelProperty("备注") 21 | private String note; 22 | 23 | @ApiModelProperty("权限列表") 24 | private transient List Permissions; 25 | } 26 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableLogic; 4 | import com.baomidou.mybatisplus.annotation.TableName; 5 | import com.step.template.main.base.BaseLogEntity; 6 | import io.swagger.annotations.ApiModel; 7 | import io.swagger.annotations.ApiModelProperty; 8 | import lombok.Getter; 9 | import lombok.Setter; 10 | 11 | import java.util.List; 12 | 13 | @ApiModel("系统用户") 14 | @Getter 15 | @Setter 16 | @TableName("user") 17 | public class User extends BaseLogEntity { 18 | @ApiModelProperty("删除标志") 19 | @TableLogic 20 | private Integer deleted; 21 | 22 | @ApiModelProperty("登录名,备用字段,目前随机自动生成") 23 | private String username; 24 | 25 | @ApiModelProperty("密码") 26 | private String password; 27 | 28 | @ApiModelProperty("姓名") 29 | private String name; 30 | 31 | @ApiModelProperty("手机号") 32 | private String phone; 33 | 34 | @ApiModelProperty("状态") 35 | private String status; 36 | 37 | @ApiModelProperty("包含的角色") 38 | private transient List roles; 39 | } 40 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/exception/MyException.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.exception; 2 | 3 | import org.apache.commons.lang3.exception.DefaultExceptionContext; 4 | import org.springframework.boot.web.servlet.error.DefaultErrorAttributes; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.web.server.ResponseStatusException; 7 | 8 | public class MyException extends ResponseStatusException { 9 | 10 | public MyException() { 11 | super(HttpStatus.BAD_REQUEST); 12 | } 13 | 14 | public MyException(String reason) { 15 | super(HttpStatus.BAD_REQUEST, reason); 16 | } 17 | 18 | public MyException(HttpStatus status, String reason) { 19 | super(status, reason); 20 | } 21 | 22 | public MyException(int status, String reason) { 23 | super(HttpStatus.valueOf(status), reason); 24 | } 25 | 26 | public MyException(Throwable t) { 27 | super(HttpStatus.BAD_REQUEST, t.getMessage(), t); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/exception/NoAuthException.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.exception; 2 | 3 | import org.springframework.http.HttpStatus; 4 | import org.springframework.web.server.ResponseStatusException; 5 | 6 | public class NoAuthException extends ResponseStatusException { 7 | public NoAuthException() { 8 | super(HttpStatus.FORBIDDEN, "无权限"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/exception/UnauthorizedException.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.exception; 2 | 3 | import org.springframework.http.HttpStatus; 4 | import org.springframework.web.server.ResponseStatusException; 5 | 6 | public class UnauthorizedException extends ResponseStatusException { 7 | public UnauthorizedException() { 8 | super(HttpStatus.UNAUTHORIZED, "未认证或者认证过期,请重新登录"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/mapper/DeptMapper.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.step.template.main.entity.Dept; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface DeptMapper extends BaseMapper { 9 | } 10 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/mapper/DeviceMapper.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 5 | import com.step.template.main.entity.Device; 6 | import com.step.template.main.svo.DeviceSvo; 7 | import com.step.template.main.vo.DeviceVo; 8 | import org.apache.ibatis.annotations.Param; 9 | import org.springframework.stereotype.Repository; 10 | 11 | @Repository 12 | public interface DeviceMapper extends BaseMapper { 13 | Page selectWithPage(Page page, @Param("svo") DeviceSvo svo); 14 | } 15 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/mapper/PermissionMapper.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.step.template.main.entity.Permission; 5 | import org.apache.ibatis.annotations.Param; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import java.util.Set; 9 | 10 | @Repository 11 | public interface PermissionMapper extends BaseMapper { 12 | 13 | Set selectByUserId(@Param("userId") Integer userId); 14 | } 15 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/mapper/RoleMapper.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.step.template.main.entity.Permission; 5 | import com.step.template.main.entity.Role; 6 | import org.apache.ibatis.annotations.Param; 7 | import org.springframework.stereotype.Repository; 8 | 9 | import java.util.List; 10 | 11 | @Repository 12 | public interface RoleMapper extends BaseMapper { 13 | Role getById(@Param("id") Integer id); 14 | 15 | void insertRolePermission(@Param("roleId") Integer roleId, @Param("permissions") List permissions); 16 | 17 | void deleteRolePermission(@Param("roleId") Integer roleId); 18 | } 19 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/mapper/UserMapper.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 5 | import com.step.template.main.entity.Role; 6 | import com.step.template.main.entity.User; 7 | import com.step.template.main.svo.UserSvo; 8 | import com.step.template.main.vo.UserVo; 9 | import org.apache.ibatis.annotations.Param; 10 | import org.springframework.stereotype.Repository; 11 | 12 | import java.util.List; 13 | 14 | @Repository 15 | public interface UserMapper extends BaseMapper { 16 | Page selectWithPage(Page page, @Param("svo") UserSvo svo); 17 | 18 | UserVo getVoById(@Param("id") Integer id); 19 | 20 | void insertUserRole(@Param("userId") Integer userId, @Param("roles") List roles); 21 | 22 | void deleteUserRole(@Param("userId") Integer userId); 23 | } 24 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/service/AccountService.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.service; 2 | 3 | import com.step.template.main.entity.User; 4 | import com.step.template.main.exception.MyException; 5 | import com.step.template.main.util.BCrypt; 6 | import com.step.template.main.util.Constant; 7 | import com.step.template.main.util.JwtUtil; 8 | import com.step.template.main.util.ScopeUtil; 9 | import com.step.template.main.vo.MyScope; 10 | import lombok.AllArgsConstructor; 11 | import org.springframework.cache.Cache; 12 | import org.springframework.cache.CacheManager; 13 | import org.springframework.cache.annotation.Cacheable; 14 | import org.springframework.stereotype.Service; 15 | import org.springframework.transaction.annotation.Transactional; 16 | 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | import java.util.Set; 20 | 21 | @AllArgsConstructor 22 | @Service 23 | @Transactional 24 | public class AccountService { 25 | private final UserService userService; 26 | private final PermissionService permissionService; 27 | private final CacheManager cacheManager; 28 | 29 | /** 30 | * 登录 31 | */ 32 | public Map login(String phone, String password) { 33 | User user = userService.selectByPhone(phone); 34 | checkUser(user); 35 | //验证密码 36 | if (BCrypt.checkpw(password, user.getPassword())) { 37 | MyScope myScope = cacheScope(user.getId()); 38 | Map result = new HashMap<>(); 39 | result.put("userId", myScope.getUserId()); 40 | result.put("username", myScope.getUsername()); 41 | result.put("phone", myScope.getPhone()); 42 | result.put("name", myScope.getName()); 43 | result.put("token", JwtUtil.createToken(user.getId())); 44 | result.put("permissions", myScope.getPermissions()); 45 | //清除缓存 46 | Cache myScopeCache = cacheManager.getCache(Constant.SCOPE); 47 | if (myScopeCache != null) { 48 | myScopeCache.evict(user.getId()); 49 | } 50 | return result; 51 | } else { 52 | throw new MyException("密码错误"); 53 | } 54 | } 55 | 56 | /** 57 | * 修改密码 58 | */ 59 | public void changePassword(String oldPassword, String newPassword) { 60 | User user = userService.getById(ScopeUtil.getUserId()); 61 | if (BCrypt.checkpw(oldPassword, user.getPassword())) { 62 | userService.updatePassword(user.getId(), newPassword); 63 | } else { 64 | throw new MyException("原密码错误"); 65 | } 66 | } 67 | 68 | /** 69 | * 初始化MyScope,并放入缓存中 70 | */ 71 | @Cacheable(Constant.SCOPE) 72 | public MyScope cacheScope(Integer userId) { 73 | User user = userService.getById(userId); 74 | Set permissions = permissionService.selectByUseId(user.getId()); 75 | MyScope scope = new MyScope(); 76 | scope.setName(user.getName()); 77 | scope.setUsername(user.getUsername()); 78 | scope.setUserId(user.getId()); 79 | scope.setPhone(user.getPhone()); 80 | scope.setPermissions(permissions); 81 | return scope; 82 | } 83 | 84 | private void checkUser(User user) { 85 | if (user == null) { 86 | throw new RuntimeException("用户不存在"); 87 | } 88 | if (Constant.UserStatus.disabled.name().equals(user.getStatus())) { 89 | throw new MyException("用户已被禁用"); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/service/DeptService.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.service; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 4 | import com.step.template.main.base.BaseService; 5 | import com.step.template.main.entity.Dept; 6 | import com.step.template.main.exception.MyException; 7 | import com.step.template.main.util.CommonUtil; 8 | import com.step.template.main.vo.TreeNode; 9 | import org.springframework.stereotype.Service; 10 | import org.springframework.transaction.annotation.Transactional; 11 | 12 | import java.util.List; 13 | import java.util.stream.Collectors; 14 | 15 | /** 16 | * 部门 服务类 17 | */ 18 | @Service 19 | @Transactional 20 | public class DeptService extends BaseService { 21 | 22 | public List selectAll() { 23 | List depts = super.list(); 24 | //转化为TreeNodeList 25 | List treeNodes = depts.stream().map(item -> new TreeNode(item.getId(), item.getParentId(), item.getName(), item)).collect(Collectors.toList()); 26 | //转化为树 27 | return CommonUtil.listToTree(treeNodes); 28 | } 29 | 30 | public void deleteById(int id) { 31 | int childrenCount = super.count(new LambdaQueryWrapper().eq(Dept::getParentId, id)); 32 | if (childrenCount > 0) { 33 | throw new MyException("该部门有下级部门,无法删除"); 34 | } 35 | super.removeById(id); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/service/DeviceService.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.service; 2 | 3 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 4 | import com.step.template.main.base.BaseService; 5 | import com.step.template.main.entity.Device; 6 | import com.step.template.main.entity.User; 7 | import com.step.template.main.mapper.DeviceMapper; 8 | import com.step.template.main.svo.DeviceSvo; 9 | import com.step.template.main.vo.DeviceVo; 10 | import lombok.AllArgsConstructor; 11 | import org.springframework.stereotype.Service; 12 | import org.springframework.transaction.annotation.Transactional; 13 | 14 | /** 15 | * Demo 服务类 16 | */ 17 | @Service 18 | @Transactional 19 | @AllArgsConstructor 20 | public class DeviceService extends BaseService { 21 | 22 | private final DeviceMapper deviceMapper; 23 | private final UserService userService; 24 | 25 | public Page selectWithPage(DeviceSvo svo) { 26 | return deviceMapper.selectWithPage(svo.getPage(), svo); 27 | } 28 | 29 | public DeviceVo getVoById(Integer id) { 30 | Device device = super.getById(id); 31 | DeviceVo deviceVo = device.toBean(DeviceVo.class); 32 | if (device.getMaintUserId() != null) { 33 | User user = userService.getById(device.getMaintUserId()); 34 | if (user != null) { 35 | deviceVo.setMaintUserName(user.getName()); 36 | } 37 | } 38 | return deviceVo; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/service/PermissionService.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.service; 2 | 3 | 4 | import com.step.template.main.base.BaseService; 5 | import com.step.template.main.entity.Permission; 6 | import com.step.template.main.mapper.PermissionMapper; 7 | import com.step.template.main.util.CommonUtil; 8 | import com.step.template.main.vo.TreeNode; 9 | import lombok.AllArgsConstructor; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.stereotype.Service; 12 | import org.springframework.transaction.annotation.Transactional; 13 | 14 | import java.util.List; 15 | import java.util.Set; 16 | import java.util.stream.Collectors; 17 | 18 | @Slf4j 19 | @AllArgsConstructor 20 | @Service 21 | @Transactional(rollbackFor = Exception.class) 22 | public class PermissionService extends BaseService { 23 | private final PermissionMapper permissionMapper; 24 | 25 | public List selectAll() { 26 | List permissions = super.list(); 27 | //转化为TreeNodeList 28 | List treeNodes = permissions.stream().map(item -> new TreeNode(item.getId(), item.getParentId(), item.getName(), item)).collect(Collectors.toList()); 29 | //转化为树 30 | return CommonUtil.listToTree(treeNodes); 31 | } 32 | 33 | public Set selectByUseId(Integer userId) { 34 | return permissionMapper.selectByUserId(userId); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/service/RoleService.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.service; 2 | 3 | import com.step.template.main.base.BaseService; 4 | import com.step.template.main.entity.Permission; 5 | import com.step.template.main.entity.Role; 6 | import com.step.template.main.mapper.RoleMapper; 7 | import lombok.AllArgsConstructor; 8 | import org.springframework.stereotype.Service; 9 | import org.springframework.transaction.annotation.Transactional; 10 | 11 | import java.util.List; 12 | 13 | @AllArgsConstructor 14 | @Service 15 | @Transactional 16 | public class RoleService extends BaseService { 17 | 18 | private final RoleMapper roleMapper; 19 | 20 | /** 21 | * 查询角色,同时查询包含的权限 22 | */ 23 | public Role selectById(Integer id) { 24 | return roleMapper.getById(id); 25 | } 26 | 27 | /** 28 | * 插入角色,同时插入包含的权限 29 | */ 30 | public void insertRole(Role role) { 31 | super.save(role); 32 | //插入权限 33 | List permissions = role.getPermissions(); 34 | if (isNotEmpty(permissions)) { 35 | roleMapper.insertRolePermission(role.getId(), permissions); 36 | } 37 | } 38 | 39 | /** 40 | * 更新角色,同时更新包含的权限 41 | */ 42 | public void updateRole(Role role) { 43 | super.updateById(role); 44 | //先删除旧的权限 45 | roleMapper.deleteRolePermission(role.getId()); 46 | //插入新的权限 47 | if (isNotEmpty(role.getPermissions())) { 48 | roleMapper.insertRolePermission(role.getId(), role.getPermissions()); 49 | } 50 | } 51 | 52 | /** 53 | * 删除权限角色 54 | */ 55 | public void deleteRole(Integer roleId) { 56 | super.removeById(roleId); 57 | //删除权限 58 | roleMapper.deleteRolePermission(roleId); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.service; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 4 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 5 | import com.step.template.main.base.BaseService; 6 | import com.step.template.main.entity.User; 7 | import com.step.template.main.mapper.UserMapper; 8 | import com.step.template.main.svo.UserSvo; 9 | import com.step.template.main.util.BCrypt; 10 | import com.step.template.main.util.Constant; 11 | import com.step.template.main.vo.UserVo; 12 | import lombok.AllArgsConstructor; 13 | import lombok.extern.slf4j.Slf4j; 14 | import org.apache.commons.lang3.RandomStringUtils; 15 | import org.springframework.stereotype.Service; 16 | import org.springframework.transaction.annotation.Transactional; 17 | 18 | @Slf4j 19 | @AllArgsConstructor 20 | @Service 21 | @Transactional 22 | public class UserService extends BaseService { 23 | 24 | private final UserMapper userMapper; 25 | 26 | public Page selectWithPage(UserSvo svo) { 27 | return userMapper.selectWithPage(svo.getPage(), svo); 28 | } 29 | 30 | /** 31 | * 新增用户,同时插入角色 32 | */ 33 | public void insertUser(User user) { 34 | String phone = user.getPhone(); 35 | checkUnique(User::getPhone, phone, null, "手机号已经存在,请更换"); 36 | //随机生成12位字母作为用户名 37 | user.setUsername(RandomStringUtils.randomAlphabetic(12).toLowerCase()); 38 | user.setPassword(BCrypt.hashpw(user.getPassword(), BCrypt.gensalt())); 39 | user.setStatus(Constant.UserStatus.enabled.name()); 40 | super.save(user); 41 | //插入角色 42 | if (isNotEmpty(user.getRoles())) { 43 | userMapper.insertUserRole(user.getId(), user.getRoles()); 44 | } 45 | } 46 | 47 | /** 48 | * 更新用户,不允许更新用户名,密码 49 | */ 50 | public void updateUser(User user) { 51 | checkUnique(User::getPhone, user.getPhone(), user.getId(), "手机号已经存在,请更换"); 52 | //不更新字段设置为null 53 | user.setUsername(null); 54 | user.setPassword(null); 55 | user.setStatus(null); 56 | super.updateById(user); 57 | //先删除旧的权限 58 | userMapper.deleteUserRole(user.getId()); 59 | //插入新的权限 60 | if (isNotEmpty(user.getRoles())) { 61 | userMapper.insertUserRole(user.getId(), user.getRoles()); 62 | } 63 | } 64 | 65 | public void toggleStatus(int userId) { 66 | User userOld = super.getById(userId); 67 | String status = Constant.UserStatus.enabled.name().equals(userOld.getStatus()) ? Constant.UserStatus.disabled.name() : Constant.UserStatus.enabled.name(); 68 | userOld.setStatus(status); 69 | super.updateById(userOld); 70 | } 71 | 72 | /** 73 | * 根据id查询 74 | */ 75 | public UserVo getVoById(Integer id) { 76 | return userMapper.getVoById(id); 77 | } 78 | 79 | /** 80 | * 根据phone获取用户 81 | */ 82 | public User selectByPhone(String phone) { 83 | return super.getOne(new LambdaQueryWrapper().eq(User::getPhone, phone)); 84 | } 85 | 86 | /** 87 | * 设置某个用户的密码 88 | */ 89 | public void updatePassword(Integer id, String password) { 90 | User user = new User(); 91 | user.setId(id); 92 | user.setPassword(BCrypt.hashpw(password, BCrypt.gensalt())); 93 | super.updateById(user); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/svo/DeviceSvo.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.svo; 2 | 3 | import com.step.template.main.base.BaseSvo; 4 | import io.swagger.annotations.ApiModel; 5 | import io.swagger.annotations.ApiModelProperty; 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | 9 | @ApiModel("查询条件") 10 | @Getter 11 | @Setter 12 | public class DeviceSvo extends BaseSvo { 13 | 14 | @ApiModelProperty("搜索-编号") 15 | private String no; 16 | 17 | @ApiModelProperty("搜索-名称") 18 | private String name; 19 | 20 | @ApiModelProperty("搜索-型号") 21 | private String model; 22 | 23 | @ApiModelProperty("搜索-安装地址") 24 | private String address; 25 | 26 | @ApiModelProperty("搜索-使用单位") 27 | private String customer; 28 | } -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/svo/UserSvo.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.svo; 2 | 3 | import com.step.template.main.base.BaseSvo; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | 8 | @Getter 9 | @Setter 10 | public class UserSvo extends BaseSvo { 11 | 12 | @ApiModelProperty("搜索-手机号") 13 | private String phone; 14 | 15 | @ApiModelProperty("搜索-用户姓名") 16 | private String name; 17 | } 18 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/util/BCrypt.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2006 Damien Miller 2 | // 3 | // Permission to use, copy, modify, and distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | package com.step.template.main.util; 15 | 16 | import java.io.ByteArrayOutputStream; 17 | import java.io.UnsupportedEncodingException; 18 | import java.security.SecureRandom; 19 | 20 | /** 21 | * BCrypt implements OpenBSD-style Blowfish password hashing using the scheme described in 22 | * "A Future-Adaptable Password Scheme" by Niels Provos and David Mazieres. 23 | *

24 | * This password hashing system tries to thwart off-line password cracking using a 25 | * computationally-intensive hashing algorithm, based on Bruce Schneier's Blowfish cipher. 26 | * The work factor of the algorithm is parameterised, so it can be increased as computers 27 | * get faster. 28 | *

29 | * Usage is really simple. To hash a password for the first time, call the hashpw method 30 | * with a random salt, like this: 31 | *

32 | * 33 | * String pw_hash = BCrypt.hashpw(plain_password, BCrypt.gensalt());
34 | *
35 | *

36 | * To check whether a plaintext password matches one that has been hashed previously, use 37 | * the checkpw method: 38 | *

39 | * 40 | * if (BCrypt.checkpw(candidate_password, stored_hash))
41 | *     System.out.println("It matches");
42 | * else
43 | *     System.out.println("It does not match");
44 | *
45 | *

46 | * The gensalt() method takes an optional parameter (log_rounds) that determines the 47 | * computational complexity of the hashing: 48 | *

49 | * 50 | * String strong_salt = BCrypt.gensalt(10)
51 | * String stronger_salt = BCrypt.gensalt(12)
52 | *
53 | *

54 | * The amount of work increases exponentially (2**log_rounds), so each increment is twice 55 | * as much work. The default log_rounds is 10, and the valid range is 4 to 31. 56 | * 57 | * @author Damien Miller 58 | */ 59 | public class BCrypt { 60 | // BCrypt parameters 61 | 62 | static final int MIN_LOG_ROUNDS = 4; 63 | static final int MAX_LOG_ROUNDS = 31; 64 | private static final int GENSALT_DEFAULT_LOG2_ROUNDS = 10; 65 | private static final int BCRYPT_SALT_LEN = 16; 66 | // Blowfish parameters 67 | private static final int BLOWFISH_NUM_ROUNDS = 16; 68 | // Initial contents of key schedule 69 | private static final int P_orig[] = {0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 70 | 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 71 | 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 72 | 0x9216d5d9, 0x8979fb1b}; 73 | private static final int S_orig[] = {0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 74 | 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 75 | 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 76 | 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 77 | 0x9c30d539, 0x2af26013, 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 78 | 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 79 | 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 80 | 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 81 | 0xb3ee1411, 0x636fbc2a, 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 82 | 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 83 | 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 84 | 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 85 | 0x0f6d6ff3, 0x83f44239, 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 86 | 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 87 | 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 88 | 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 89 | 0x7d84a5c3, 0x3b8b5ebe, 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 90 | 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 91 | 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 92 | 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 93 | 0x5e5c9ec2, 0x196a2463, 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 94 | 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 95 | 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 96 | 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 97 | 0x8ea5e9f8, 0xdb3222f8, 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 98 | 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 99 | 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 100 | 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 101 | 0x4afcb56c, 0x2dd1d35b, 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 102 | 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 103 | 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 104 | 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 105 | 0x8888b812, 0x900df01c, 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 106 | 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 107 | 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 108 | 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 109 | 0xc75442f5, 0xfb9d35cf, 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 110 | 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 111 | 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 112 | 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 113 | 0x1b510052, 0x9a532915, 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 114 | 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 115 | 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, 116 | 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 117 | 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 118 | 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, 119 | 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, 120 | 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 121 | 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 122 | 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, 123 | 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, 124 | 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 125 | 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 126 | 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, 127 | 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 128 | 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 129 | 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 130 | 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, 131 | 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, 132 | 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 133 | 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 134 | 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, 135 | 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, 136 | 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 137 | 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 138 | 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, 139 | 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, 140 | 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 141 | 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 142 | 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, 143 | 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 144 | 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 145 | 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 146 | 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, 147 | 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, 148 | 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 149 | 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 150 | 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, 151 | 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, 152 | 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 153 | 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 154 | 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, 155 | 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, 156 | 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 157 | 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 158 | 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, 0xe93d5a68, 0x948140f7, 159 | 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, 160 | 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 161 | 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 162 | 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, 0x96eb27b3, 0x55fd3941, 163 | 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, 164 | 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 165 | 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 166 | 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, 0x1dc9faf7, 0x4b6d1856, 167 | 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, 168 | 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 169 | 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 170 | 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, 0xfdf8e802, 0x04272f70, 171 | 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, 172 | 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 173 | 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 174 | 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, 0x6b2395e0, 0x333e92e1, 175 | 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, 176 | 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 177 | 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 178 | 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, 0xc67b5510, 0x6d672c37, 179 | 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, 180 | 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 181 | 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 182 | 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, 0x6a124237, 0xb79251e7, 183 | 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, 184 | 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 185 | 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 186 | 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, 0x83426b33, 0xf01eab71, 187 | 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, 188 | 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 189 | 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 190 | 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, 0xb90bace1, 0xbb8205d0, 191 | 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, 192 | 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 193 | 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 194 | 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, 0x9af88c27, 0x773f8641, 195 | 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, 196 | 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 197 | 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 198 | 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, 0xed545578, 0x08fca5b5, 199 | 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, 200 | 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 201 | 0x670efa8e, 0x406000e0, 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 202 | 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 203 | 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 204 | 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 205 | 0xd5730a1d, 0x4cd04dc6, 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 206 | 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 207 | 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 208 | 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 209 | 0x3f046f69, 0x77fa0a59, 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 210 | 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 211 | 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 212 | 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 213 | 0xf8d56629, 0x79132e28, 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 214 | 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 215 | 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 216 | 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 217 | 0xabcc5167, 0xccad925f, 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 218 | 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 219 | 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 220 | 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 221 | 0xccd2017f, 0x6bb4e3bb, 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 222 | 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 223 | 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 224 | 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 225 | 0x06b89fb4, 0xce6ea048, 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 226 | 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 227 | 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 228 | 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 229 | 0x8df9317c, 0xe0b12b4f, 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 230 | 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 231 | 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 232 | 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 233 | 0xd3a0342b, 0x8971f21e, 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 234 | 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 235 | 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 236 | 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 237 | 0x6e163697, 0x88d273cc, 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 238 | 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 239 | 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 240 | 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 241 | 0x77afa1c5, 0x20756060, 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 242 | 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 243 | 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6}; 244 | // bcrypt IV: "OrpheanBeholderScryDoubt" 245 | static private final int bf_crypt_ciphertext[] = {0x4f727068, 0x65616e42, 246 | 0x65686f6c, 0x64657253, 0x63727944, 0x6f756274}; 247 | // Table for Base64 encoding 248 | static private final char base64_code[] = {'.', '/', 'A', 'B', 'C', 'D', 'E', 'F', 249 | 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 250 | 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 251 | 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 252 | 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; 253 | // Table for Base64 decoding 254 | static private final byte index_64[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 255 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 256 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 54, 55, 257 | 56, 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, -1, -1, -1, 2, 3, 4, 5, 6, 7, 258 | 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 259 | -1, -1, -1, -1, -1, -1, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 260 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, -1, -1, -1, -1, -1}; 261 | // Expanded Blowfish key 262 | private int P[]; 263 | private int S[]; 264 | 265 | /** 266 | * Encode a byte array using bcrypt's slightly-modified base64 encoding scheme. Note 267 | * that this is not compatible with the standard MIME-base64 268 | * encoding. 269 | * 270 | * @param d the byte array to encode 271 | * @param len the number of bytes to encode 272 | * @param rs the destination buffer for the base64-encoded string 273 | * @throws IllegalArgumentException if the length is invalid 274 | */ 275 | static void encode_base64(byte d[], int len, StringBuilder rs) 276 | throws IllegalArgumentException { 277 | int off = 0; 278 | int c1, c2; 279 | 280 | if (len <= 0 || len > d.length) { 281 | throw new IllegalArgumentException("Invalid len"); 282 | } 283 | 284 | while (off < len) { 285 | c1 = d[off++] & 0xff; 286 | rs.append(base64_code[(c1 >> 2) & 0x3f]); 287 | c1 = (c1 & 0x03) << 4; 288 | if (off >= len) { 289 | rs.append(base64_code[c1 & 0x3f]); 290 | break; 291 | } 292 | c2 = d[off++] & 0xff; 293 | c1 |= (c2 >> 4) & 0x0f; 294 | rs.append(base64_code[c1 & 0x3f]); 295 | c1 = (c2 & 0x0f) << 2; 296 | if (off >= len) { 297 | rs.append(base64_code[c1 & 0x3f]); 298 | break; 299 | } 300 | c2 = d[off++] & 0xff; 301 | c1 |= (c2 >> 6) & 0x03; 302 | rs.append(base64_code[c1 & 0x3f]); 303 | rs.append(base64_code[c2 & 0x3f]); 304 | } 305 | } 306 | 307 | /** 308 | * Look up the 3 bits base64-encoded by the specified character, range-checking 309 | * against conversion table 310 | * 311 | * @param x the base64-encoded value 312 | * @return the decoded value of x 313 | */ 314 | private static byte char64(char x) { 315 | if (x > index_64.length) { 316 | return -1; 317 | } 318 | return index_64[x]; 319 | } 320 | 321 | /** 322 | * Decode a string encoded using bcrypt's base64 scheme to a byte array. Note that 323 | * this is *not* compatible with the standard MIME-base64 encoding. 324 | * 325 | * @param s the string to decode 326 | * @param maxolen the maximum number of bytes to decode 327 | * @return an array containing the decoded bytes 328 | * @throws IllegalArgumentException if maxolen is invalid 329 | */ 330 | static byte[] decode_base64(String s, int maxolen) throws IllegalArgumentException { 331 | ByteArrayOutputStream out = new ByteArrayOutputStream(maxolen); 332 | int off = 0, slen = s.length(), olen = 0; 333 | byte c1, c2, c3, c4, o; 334 | 335 | if (maxolen <= 0) { 336 | throw new IllegalArgumentException("Invalid maxolen"); 337 | } 338 | 339 | while (off < slen - 1 && olen < maxolen) { 340 | c1 = char64(s.charAt(off++)); 341 | c2 = char64(s.charAt(off++)); 342 | if (c1 == -1 || c2 == -1) { 343 | break; 344 | } 345 | o = (byte) (c1 << 2); 346 | o |= (c2 & 0x30) >> 4; 347 | out.write(o); 348 | if (++olen >= maxolen || off >= slen) { 349 | break; 350 | } 351 | c3 = char64(s.charAt(off++)); 352 | if (c3 == -1) { 353 | break; 354 | } 355 | o = (byte) ((c2 & 0x0f) << 4); 356 | o |= (c3 & 0x3c) >> 2; 357 | out.write(o); 358 | if (++olen >= maxolen || off >= slen) { 359 | break; 360 | } 361 | c4 = char64(s.charAt(off++)); 362 | o = (byte) ((c3 & 0x03) << 6); 363 | o |= c4; 364 | out.write(o); 365 | ++olen; 366 | } 367 | 368 | return out.toByteArray(); 369 | } 370 | 371 | /** 372 | * Cycically extract a word of key material 373 | * 374 | * @param data the string to extract the data from 375 | * @param offp a "pointer" (as a one-entry array) to the current offset into data 376 | * @return the next word of material from data 377 | */ 378 | private static int streamtoword(byte data[], int offp[]) { 379 | int i; 380 | int word = 0; 381 | int off = offp[0]; 382 | 383 | for (i = 0; i < 4; i++) { 384 | word = (word << 8) | (data[off] & 0xff); 385 | off = (off + 1) % data.length; 386 | } 387 | 388 | offp[0] = off; 389 | return word; 390 | } 391 | 392 | static long roundsForLogRounds(int log_rounds) { 393 | if (log_rounds < 4 || log_rounds > 31) { 394 | throw new IllegalArgumentException("Bad number of rounds"); 395 | } 396 | return 1L << log_rounds; 397 | } 398 | 399 | /** 400 | * Hash a password using the OpenBSD bcrypt scheme 401 | * 402 | * @param password the password to hash 403 | * @param salt the salt to hash with (perhaps generated using BCrypt.gensalt) 404 | * @return the hashed password 405 | * @throws IllegalArgumentException if invalid salt is passed 406 | */ 407 | public static String hashpw(String password, String salt) throws IllegalArgumentException { 408 | BCrypt B; 409 | String real_salt; 410 | byte passwordb[], saltb[], hashed[]; 411 | char minor = (char) 0; 412 | int rounds, off = 0; 413 | StringBuilder rs = new StringBuilder(); 414 | 415 | if (salt == null) { 416 | throw new IllegalArgumentException("salt cannot be null"); 417 | } 418 | 419 | int saltLength = salt.length(); 420 | 421 | if (saltLength < 28) { 422 | throw new IllegalArgumentException("Invalid salt"); 423 | } 424 | 425 | if (salt.charAt(0) != '$' || salt.charAt(1) != '2') { 426 | throw new IllegalArgumentException("Invalid salt version"); 427 | } 428 | if (salt.charAt(2) == '$') { 429 | off = 3; 430 | } else { 431 | minor = salt.charAt(2); 432 | if (minor != 'a' || salt.charAt(3) != '$') { 433 | throw new IllegalArgumentException("Invalid salt revision"); 434 | } 435 | off = 4; 436 | } 437 | 438 | if (saltLength - off < 25) { 439 | throw new IllegalArgumentException("Invalid salt"); 440 | } 441 | 442 | // Extract number of rounds 443 | if (salt.charAt(off + 2) > '$') { 444 | throw new IllegalArgumentException("Missing salt rounds"); 445 | } 446 | rounds = Integer.parseInt(salt.substring(off, off + 2)); 447 | 448 | real_salt = salt.substring(off + 3, off + 25); 449 | try { 450 | passwordb = (password + (minor >= 'a' ? "\000" : "")).getBytes("UTF-8"); 451 | } catch (UnsupportedEncodingException uee) { 452 | throw new AssertionError("UTF-8 is not supported"); 453 | } 454 | 455 | saltb = decode_base64(real_salt, BCRYPT_SALT_LEN); 456 | 457 | B = new BCrypt(); 458 | hashed = B.crypt_raw(passwordb, saltb, rounds); 459 | 460 | rs.append("$2"); 461 | if (minor >= 'a') { 462 | rs.append(minor); 463 | } 464 | rs.append("$"); 465 | if (rounds < 10) { 466 | rs.append("0"); 467 | } 468 | rs.append(rounds); 469 | rs.append("$"); 470 | encode_base64(saltb, saltb.length, rs); 471 | encode_base64(hashed, bf_crypt_ciphertext.length * 4 - 1, rs); 472 | return rs.toString(); 473 | } 474 | 475 | /** 476 | * Generate a salt for use with the BCrypt.hashpw() method 477 | * 478 | * @param log_rounds the log2 of the number of rounds of hashing to apply - the work 479 | * factor therefore increases as 2**log_rounds. Minimum 4, maximum 31. 480 | * @param random an instance of SecureRandom to use 481 | * @return an encoded salt value 482 | */ 483 | public static String gensalt(int log_rounds, SecureRandom random) { 484 | if (log_rounds < MIN_LOG_ROUNDS || log_rounds > MAX_LOG_ROUNDS) { 485 | throw new IllegalArgumentException("Bad number of rounds"); 486 | } 487 | StringBuilder rs = new StringBuilder(); 488 | byte rnd[] = new byte[BCRYPT_SALT_LEN]; 489 | 490 | random.nextBytes(rnd); 491 | 492 | rs.append("$2a$"); 493 | if (log_rounds < 10) { 494 | rs.append("0"); 495 | } 496 | rs.append(log_rounds); 497 | rs.append("$"); 498 | encode_base64(rnd, rnd.length, rs); 499 | return rs.toString(); 500 | } 501 | 502 | /** 503 | * Generate a salt for use with the BCrypt.hashpw() method 504 | * 505 | * @param log_rounds the log2 of the number of rounds of hashing to apply - the work 506 | * factor therefore increases as 2**log_rounds. Minimum 4, maximum 31. 507 | * @return an encoded salt value 508 | */ 509 | public static String gensalt(int log_rounds) { 510 | return gensalt(log_rounds, new SecureRandom()); 511 | } 512 | 513 | /** 514 | * Generate a salt for use with the BCrypt.hashpw() method, selecting a reasonable 515 | * default for the number of hashing rounds to apply 516 | * 517 | * @return an encoded salt value 518 | */ 519 | public static String gensalt() { 520 | return gensalt(GENSALT_DEFAULT_LOG2_ROUNDS); 521 | } 522 | 523 | /** 524 | * Check that a plaintext password matches a previously hashed one 525 | * 526 | * @param plaintext the plaintext password to verify 527 | * @param hashed the previously-hashed password 528 | * @return true if the passwords match, false otherwise 529 | */ 530 | public static boolean checkpw(String plaintext, String hashed) { 531 | return equalsNoEarlyReturn(hashed, hashpw(plaintext, hashed)); 532 | } 533 | 534 | static boolean equalsNoEarlyReturn(String a, String b) { 535 | char[] caa = a.toCharArray(); 536 | char[] cab = b.toCharArray(); 537 | 538 | if (caa.length != cab.length) { 539 | return false; 540 | } 541 | 542 | byte ret = 0; 543 | for (int i = 0; i < caa.length; i++) { 544 | ret |= caa[i] ^ cab[i]; 545 | } 546 | return ret == 0; 547 | } 548 | 549 | /** 550 | * Blowfish encipher a single 64-bit block encoded as two 32-bit halves 551 | * 552 | * @param lr an array containing the two 32-bit half blocks 553 | * @param off the position in the array of the blocks 554 | */ 555 | private final void encipher(int lr[], int off) { 556 | int i, n, l = lr[off], r = lr[off + 1]; 557 | 558 | l ^= P[0]; 559 | for (i = 0; i <= BLOWFISH_NUM_ROUNDS - 2; ) { 560 | // Feistel substitution on left word 561 | n = S[(l >> 24) & 0xff]; 562 | n += S[0x100 | ((l >> 16) & 0xff)]; 563 | n ^= S[0x200 | ((l >> 8) & 0xff)]; 564 | n += S[0x300 | (l & 0xff)]; 565 | r ^= n ^ P[++i]; 566 | 567 | // Feistel substitution on right word 568 | n = S[(r >> 24) & 0xff]; 569 | n += S[0x100 | ((r >> 16) & 0xff)]; 570 | n ^= S[0x200 | ((r >> 8) & 0xff)]; 571 | n += S[0x300 | (r & 0xff)]; 572 | l ^= n ^ P[++i]; 573 | } 574 | lr[off] = r ^ P[BLOWFISH_NUM_ROUNDS + 1]; 575 | lr[off + 1] = l; 576 | } 577 | 578 | /** 579 | * Initialise the Blowfish key schedule 580 | */ 581 | private void init_key() { 582 | P = (int[]) P_orig.clone(); 583 | S = (int[]) S_orig.clone(); 584 | } 585 | 586 | /** 587 | * Key the Blowfish cipher 588 | * 589 | * @param key an array containing the key 590 | */ 591 | private void key(byte key[]) { 592 | int i; 593 | int koffp[] = {0}; 594 | int lr[] = {0, 0}; 595 | int plen = P.length, slen = S.length; 596 | 597 | for (i = 0; i < plen; i++) { 598 | P[i] = P[i] ^ streamtoword(key, koffp); 599 | } 600 | 601 | for (i = 0; i < plen; i += 2) { 602 | encipher(lr, 0); 603 | P[i] = lr[0]; 604 | P[i + 1] = lr[1]; 605 | } 606 | 607 | for (i = 0; i < slen; i += 2) { 608 | encipher(lr, 0); 609 | S[i] = lr[0]; 610 | S[i + 1] = lr[1]; 611 | } 612 | } 613 | 614 | /** 615 | * Perform the "enhanced key schedule" step described by Provos and Mazieres in 616 | * "A Future-Adaptable Password Scheme" https://www.openbsd.org/papers/bcrypt-paper.ps 617 | * 618 | * @param data salt information 619 | * @param key password information 620 | */ 621 | private void ekskey(byte data[], byte key[]) { 622 | int i; 623 | int koffp[] = {0}, doffp[] = {0}; 624 | int lr[] = {0, 0}; 625 | int plen = P.length, slen = S.length; 626 | 627 | for (i = 0; i < plen; i++) { 628 | P[i] = P[i] ^ streamtoword(key, koffp); 629 | } 630 | 631 | for (i = 0; i < plen; i += 2) { 632 | lr[0] ^= streamtoword(data, doffp); 633 | lr[1] ^= streamtoword(data, doffp); 634 | encipher(lr, 0); 635 | P[i] = lr[0]; 636 | P[i + 1] = lr[1]; 637 | } 638 | 639 | for (i = 0; i < slen; i += 2) { 640 | lr[0] ^= streamtoword(data, doffp); 641 | lr[1] ^= streamtoword(data, doffp); 642 | encipher(lr, 0); 643 | S[i] = lr[0]; 644 | S[i + 1] = lr[1]; 645 | } 646 | } 647 | 648 | /** 649 | * Perform the central password hashing step in the bcrypt scheme 650 | * 651 | * @param password the password to hash 652 | * @param salt the binary salt to hash with the password 653 | * @param log_rounds the binary logarithm of the number of rounds of hashing to apply 654 | * @return an array containing the binary hashed password 655 | */ 656 | private byte[] crypt_raw(byte password[], byte salt[], int log_rounds) { 657 | int cdata[] = (int[]) bf_crypt_ciphertext.clone(); 658 | int clen = cdata.length; 659 | byte ret[]; 660 | 661 | long rounds = roundsForLogRounds(log_rounds); 662 | 663 | init_key(); 664 | ekskey(salt, password); 665 | for (long i = 0; i < rounds; i++) { 666 | key(password); 667 | key(salt); 668 | } 669 | 670 | for (int i = 0; i < 64; i++) { 671 | for (int j = 0; j < (clen >> 1); j++) { 672 | encipher(cdata, j << 1); 673 | } 674 | } 675 | 676 | ret = new byte[clen * 4]; 677 | for (int i = 0, j = 0; i < clen; i++) { 678 | ret[j++] = (byte) ((cdata[i] >> 24) & 0xff); 679 | ret[j++] = (byte) ((cdata[i] >> 16) & 0xff); 680 | ret[j++] = (byte) ((cdata[i] >> 8) & 0xff); 681 | ret[j++] = (byte) (cdata[i] & 0xff); 682 | } 683 | return ret; 684 | } 685 | } 686 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/util/CommonUtil.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.util; 2 | 3 | 4 | import com.step.template.main.vo.TreeNode; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | public class CommonUtil { 10 | 11 | public static List listToTree(List list) { 12 | //用递归找子 13 | List treeList = new ArrayList<>(); 14 | for (TreeNode tree : list) { 15 | if ("0".equals(tree.getParentId().toString())) { 16 | tree.setLevel(1); 17 | treeList.add(findChildren(tree, list)); 18 | } 19 | } 20 | return treeList; 21 | } 22 | 23 | private static TreeNode findChildren(TreeNode tree, List list) { 24 | for (TreeNode node : list) { 25 | if (node.getParentId().equals(tree.getId())) { 26 | if (tree.getChildren() == null) { 27 | tree.setChildren(new ArrayList<>()); 28 | } 29 | node.setLevel(tree.getLevel() + 1); 30 | tree.getChildren().add(findChildren(node, list)); 31 | } 32 | } 33 | return tree; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/util/Constant.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.util; 2 | 3 | import lombok.Getter; 4 | 5 | public class Constant { 6 | /** 7 | * 超级管理员id,会对此id忽略权限校验 8 | */ 9 | public static final Integer ADMIN_ID = 1; 10 | 11 | /** 12 | * 认证请求头名称 13 | */ 14 | public static final String AUTHORIZATION = "Authorization"; 15 | /** 16 | * 当前用户信息Attribute name 17 | */ 18 | public static final String SCOPE = "myScope"; 19 | 20 | /** 21 | * 用户状态 22 | */ 23 | public enum UserStatus { 24 | disabled("禁用"), enabled("启用"); 25 | @Getter 26 | private String desc; 27 | 28 | UserStatus(String desc) { 29 | this.desc = desc; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/util/JacksonUtil.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.util; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.JavaType; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import org.apache.commons.lang3.StringUtils; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Component; 9 | 10 | import java.io.IOException; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | /** 15 | * Jackson工具类,切勿使用Gson 16 | */ 17 | @Component 18 | public class JacksonUtil { 19 | /** 20 | * 获取spring管理的实例,切勿自己new,否则无法获默认配置 21 | */ 22 | private static ObjectMapper mapper = new ObjectMapper(); 23 | 24 | /** 25 | * 对象转化为json字符串 26 | */ 27 | public static String toJson(Object obj) { 28 | try { 29 | return mapper.writeValueAsString(obj); 30 | } catch (JsonProcessingException e) { 31 | throw new RuntimeException(e); 32 | } 33 | } 34 | 35 | /** 36 | * 对象转化为json字符串,美化 37 | */ 38 | public static String toJsonPretty(Object obj) { 39 | try { 40 | return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj); 41 | } catch (JsonProcessingException e) { 42 | throw new RuntimeException(e); 43 | } 44 | } 45 | 46 | /** 47 | * json字符串转化为对象 48 | */ 49 | public static T fromJson(String json, Class clazz) { 50 | if (!StringUtils.isBlank(json)) { 51 | try { 52 | return mapper.readValue(json, clazz); 53 | } catch (IOException e) { 54 | throw new RuntimeException(e); 55 | } 56 | } else { 57 | throw new NullPointerException("json不能为null或者空字符串"); 58 | } 59 | } 60 | 61 | /** 62 | * json字符串转为list 63 | */ 64 | public static List json2List(final String json, Class clazz) { 65 | if (StringUtils.isBlank(json)) { 66 | throw new NullPointerException("json不能为null或者空字符串"); 67 | } else { 68 | try { 69 | JavaType javaType = mapper.getTypeFactory().constructCollectionType(ArrayList.class, clazz); 70 | return mapper.readValue(json, javaType); 71 | } catch (IOException e) { 72 | throw new RuntimeException(e); 73 | } 74 | } 75 | } 76 | 77 | public static T object2Bean(Object obj, Class clazz) { 78 | return mapper.convertValue(obj, clazz); 79 | } 80 | 81 | @Autowired 82 | public void setMapper(ObjectMapper mapper) { 83 | JacksonUtil.mapper = mapper; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/util/JwtUtil.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.util; 2 | 3 | import com.auth0.jwt.JWT; 4 | import com.auth0.jwt.JWTVerifier; 5 | import com.auth0.jwt.algorithms.Algorithm; 6 | import com.auth0.jwt.interfaces.Claim; 7 | import com.auth0.jwt.interfaces.DecodedJWT; 8 | import org.apache.commons.lang3.time.DateUtils; 9 | 10 | import java.util.Date; 11 | 12 | /** 13 | * https://github.com/auth0/java-jwt 14 | */ 15 | public class JwtUtil { 16 | private static final String SECRET = "STEP_template"; 17 | 18 | /** 19 | * 新建token 20 | */ 21 | public static String createToken(int userId) { 22 | Date expiresDate = DateUtils.addDays(new Date(), 7);//过期时间七天 23 | Algorithm algorithm = Algorithm.HMAC256(SECRET); 24 | return JWT.create() 25 | .withIssuer("step") 26 | .withExpiresAt(expiresDate) 27 | .withClaim("userId", userId) 28 | .sign(algorithm); 29 | } 30 | 31 | /** 32 | * 获取userId 33 | */ 34 | public static int getUserId(String token) { 35 | Algorithm algorithm = Algorithm.HMAC256(SECRET); 36 | JWTVerifier verifier = JWT.require(algorithm) 37 | .withIssuer("step") 38 | .build(); 39 | DecodedJWT jwt = verifier.verify(token); 40 | Claim claim = jwt.getClaim("userId"); 41 | return claim.asInt(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/util/MyDateUtil.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.util; 2 | 3 | import java.time.LocalDate; 4 | import java.time.LocalDateTime; 5 | import java.time.ZoneOffset; 6 | import java.time.format.DateTimeFormatter; 7 | import java.time.temporal.ChronoUnit; 8 | 9 | public class MyDateUtil { 10 | /** 11 | * 标准长日期时间字符串格式 12 | */ 13 | public static final DateTimeFormatter PATTERN_DATE_TIME = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); 14 | /** 15 | * 标准短日期字符串格式 16 | */ 17 | public static final DateTimeFormatter PATTERN_DATE = DateTimeFormatter.ofPattern("yyyy-MM-dd"); 18 | /** 19 | * 标准时间字符串格式 20 | */ 21 | public static final DateTimeFormatter PATTERN_TIME = DateTimeFormatter.ofPattern("HH:mm:ss"); 22 | 23 | /** 24 | * 获取n天/年/月...后的日期时间,可以使用负数获取之前的日期时间 25 | */ 26 | public static LocalDateTime plus(LocalDateTime beginDateTime, long amountToAdd, ChronoUnit unit) { 27 | return beginDateTime.plus(amountToAdd, unit); 28 | } 29 | 30 | /** 31 | * 获取n天/年/月...后的日期时间,可以使用负数获取之前的日期时间 32 | */ 33 | public static LocalDateTime plus(long amountToAdd, ChronoUnit unit) { 34 | return plus(LocalDateTime.now(), amountToAdd, unit); 35 | } 36 | 37 | /** 38 | * 两个日期之间的间隔,传单位区分时间类型 39 | */ 40 | public static long between(LocalDateTime beginDateTime, LocalDateTime endDateTime, ChronoUnit unit) { 41 | return unit.between(beginDateTime, endDateTime); 42 | } 43 | 44 | /** 45 | * LocalDateTime转时间戳 46 | */ 47 | public static long toTimestamp(LocalDateTime localDateTime) { 48 | return localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli(); 49 | } 50 | 51 | /** 52 | * 字符串转LocalDateTime 53 | * 54 | * @param dateStr 格式必须为{@link MyDateUtil#PATTERN_DATE_TIME} 55 | */ 56 | public static LocalDateTime toLocalDateTime(String dateStr) { 57 | return LocalDateTime.parse(dateStr, PATTERN_DATE_TIME); 58 | } 59 | 60 | /** 61 | * 获取指定时间的指定格式 62 | * 如传入LocalDateTime.now(),{@link MyDateUtil#PATTERN_DATE_TIME} 63 | * 得到2018-02-03 13:42:40 64 | */ 65 | public static String formatLocalDateTime(LocalDateTime time) { 66 | return time.format(PATTERN_DATE_TIME); 67 | } 68 | 69 | /** 70 | * 获取指定时间的指定格式 71 | * 如传入LocalDateTime.now(),{@link MyDateUtil#PATTERN_DATE_TIME} 72 | * 得到2018-02-03 13:42:40 73 | */ 74 | public static String formatLocalDateTime(LocalDateTime time, String PATTERN) { 75 | return time.format(DateTimeFormatter.ofPattern(PATTERN)); 76 | } 77 | 78 | /** 79 | * 获取指定时间的指定格式 80 | * 如传入LocalDate.now(),{@link MyDateUtil#PATTERN_DATE} 81 | * 得到2018-02-03 82 | */ 83 | public static String formatLocalDate(LocalDate time) { 84 | return time.format(PATTERN_DATE); 85 | } 86 | 87 | /** 88 | * 标准北京时间,时区为东八区,自1970年1月1日 0点0分0秒以来的秒数。注意:部分系统取到的值为毫秒级,需要转换成秒(10位数字)。 89 | */ 90 | public static Long getSecondTimestamp() { 91 | return System.currentTimeMillis() / 1000; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/util/ScopeUtil.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.util; 2 | 3 | import com.step.template.main.exception.UnauthorizedException; 4 | import com.step.template.main.vo.MyScope; 5 | import org.springframework.web.context.request.RequestAttributes; 6 | import org.springframework.web.context.request.RequestContextHolder; 7 | import org.springframework.web.context.request.ServletRequestAttributes; 8 | 9 | /** 10 | * 获取当前用户 11 | */ 12 | public class ScopeUtil { 13 | 14 | public static MyScope getScope() { 15 | ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); 16 | if (requestAttributes != null) { 17 | return (MyScope) requestAttributes.getAttribute(Constant.SCOPE, RequestAttributes.SCOPE_REQUEST); 18 | } 19 | throw new UnauthorizedException(); 20 | } 21 | 22 | public static Integer getUserId() { 23 | return getScope().getUserId(); 24 | } 25 | 26 | public static String getPhone() { 27 | return getScope().getPhone(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/vo/DeviceVo.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.vo; 2 | 3 | import com.step.template.main.entity.Device; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | 8 | @Getter 9 | @Setter 10 | public class DeviceVo extends Device { 11 | 12 | @ApiModelProperty("维保工名字") 13 | private String maintUserName; 14 | } 15 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/vo/MyScope.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.vo; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | import java.util.Set; 7 | 8 | /** 9 | * 当前用户 10 | */ 11 | @Getter 12 | @Setter 13 | public class MyScope { 14 | private Integer userId; 15 | private String username; 16 | private String phone; 17 | private String name; 18 | private Integer tenantId; 19 | private Set permissions; 20 | } 21 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/vo/TreeNode.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.vo; 2 | 3 | import io.swagger.annotations.ApiModelProperty; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import lombok.experimental.Accessors; 7 | 8 | import java.util.List; 9 | 10 | @Getter 11 | @Setter 12 | @Accessors(chain = true) 13 | public class TreeNode { 14 | private Object id; 15 | private Object parentId; 16 | 17 | @ApiModelProperty("节点名称") 18 | private String label; 19 | 20 | @ApiModelProperty("值,和ID一样") 21 | private Object value; 22 | 23 | @ApiModelProperty("等级") 24 | private Integer level; 25 | 26 | @ApiModelProperty("其他信息") 27 | private Object other; 28 | 29 | private List children; 30 | 31 | public TreeNode(Object id, Object parentId, String label) { 32 | this(id, parentId, label, null); 33 | } 34 | 35 | public TreeNode(Object id, Object parentId, String label, Object other) { 36 | this.id = id; 37 | this.value = id; 38 | this.parentId = parentId; 39 | this.label = label; 40 | this.other = other; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /template-main/src/main/java/com/step/template/main/vo/UserVo.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main.vo; 2 | 3 | import com.step.template.main.entity.User; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | 8 | @Getter 9 | @Setter 10 | public class UserVo extends User { 11 | 12 | @ApiModelProperty("公司名字") 13 | private String deviceName; 14 | } 15 | -------------------------------------------------------------------------------- /template-main/src/main/resources/application-dev.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-xinhui/spring-boot-template/a7dbd5626f293e814fb5f2386752c4f15c57f8ed/template-main/src/main/resources/application-dev.properties -------------------------------------------------------------------------------- /template-main/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-xinhui/spring-boot-template/a7dbd5626f293e814fb5f2386752c4f15c57f8ed/template-main/src/main/resources/application.properties -------------------------------------------------------------------------------- /template-main/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | %d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) [%thread] %cyan(%logger{100}) - %msg%n 9 | 10 | 11 | 12 | 13 | ${LOG_PATH}/error.log 14 | 15 | ${LOG_PATH}/error.%d{yyyy-MM-dd}.%i.log 16 | 20MB 17 | 15 18 | 2GB 19 | 20 | 21 | %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{100} - %msg%n 22 | 23 | 24 | ERROR 25 | ACCEPT 26 | DENY 27 | 28 | 29 | WARN 30 | ACCEPT 31 | DENY 32 | 33 | 34 | 35 | 36 | 37 | ${LOG_PATH}/info.log 38 | 39 | ${LOG_PATH}/info.%d{yyyy-MM-dd}.%i.log 40 | 20MB 41 | 7 42 | 2GB 43 | 44 | 45 | %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{100} - %msg%n 46 | 47 | 48 | INFO 49 | ACCEPT 50 | DENY 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /template-main/src/main/resources/mapper/DeviceMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 22 | 23 | -------------------------------------------------------------------------------- /template-main/src/main/resources/mapper/PermissionMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 15 | 16 | -------------------------------------------------------------------------------- /template-main/src/main/resources/mapper/RoleMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 27 | 28 | 29 | 30 | insert into 31 | role_permission 32 | (roleId, permissionId) 33 | values 34 | 35 | ( #{roleId},#{permission.id} ) 36 | 37 | 38 | 39 | 40 | 41 | delete 42 | from role_permission 43 | where permissionId = #{roleId} 44 | 45 | 46 | -------------------------------------------------------------------------------- /template-main/src/main/resources/mapper/UserMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 36 | 37 | 38 | 47 | 48 | 49 | 50 | insert into 51 | user_role 52 | (userId, roleId) 53 | values 54 | 55 | ( #{userId},#{role.id} ) 56 | 57 | 58 | 59 | 60 | 61 | delete 62 | from user_role 63 | where userId = #{userId} 64 | 65 | 66 | -------------------------------------------------------------------------------- /template-main/src/test/java/com/step/template/main/TemplateApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.step.template.main; 2 | 3 | 4 | import org.junit.jupiter.api.Test; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | 7 | @SpringBootTest 8 | public class TemplateApplicationTests { 9 | 10 | @Test 11 | public void contextLoads() { 12 | } 13 | 14 | } 15 | --------------------------------------------------------------------------------