├── .gitignore
├── Dockerfile
├── LICENSE
├── README.md
├── db
├── Dockerfile
└── tumo_boot.sql
├── docker-compose.yml
├── generate
├── EasyCodeConfig.json
└── README.md
├── imgs
├── image-20211019010331915.png
├── image-20211019010617453.png
├── image-20211019010644809.png
├── image-20211019010703801.png
├── image-20211019010720167.png
└── image-20211019010743832.png
├── pom.xml
├── script
├── assembly
│ ├── assembly.xml
│ └── bin
│ │ ├── start.sh
│ │ └── stop.sh
└── docker-compose.yml
└── src
├── main
├── java
│ └── cn
│ │ └── tycoding
│ │ └── boot
│ │ ├── TumoBootApp.java
│ │ ├── common
│ │ ├── auth
│ │ │ ├── AuthAutoConfiguration.java
│ │ │ ├── filter
│ │ │ │ └── CaptchaFilter.java
│ │ │ ├── props
│ │ │ │ └── AuthProperties.java
│ │ │ └── utils
│ │ │ │ ├── AuthService.java
│ │ │ │ └── AuthUtil.java
│ │ ├── core
│ │ │ ├── api
│ │ │ │ ├── HttpCode.java
│ │ │ │ ├── QueryPage.java
│ │ │ │ └── R.java
│ │ │ ├── config
│ │ │ │ └── JacksonConfiguration.java
│ │ │ ├── constant
│ │ │ │ ├── ApiConstant.java
│ │ │ │ ├── AuthConstant.java
│ │ │ │ ├── CacheConstant.java
│ │ │ │ ├── CaptchaConstant.java
│ │ │ │ └── CommonConstant.java
│ │ │ ├── launch
│ │ │ │ └── StartEventListener.java
│ │ │ └── utils
│ │ │ │ ├── BeanUtil.java
│ │ │ │ ├── IpUtil.java
│ │ │ │ ├── Is.java
│ │ │ │ └── ServletUtil.java
│ │ ├── log
│ │ │ ├── LogAutoConfiguration.java
│ │ │ ├── annotation
│ │ │ │ └── ApiLog.java
│ │ │ ├── aspect
│ │ │ │ ├── ApiLogAspect.java
│ │ │ │ └── RequestLogAspect.java
│ │ │ ├── event
│ │ │ │ ├── LogEvent.java
│ │ │ │ └── LogListener.java
│ │ │ ├── exception
│ │ │ │ ├── GlobalExceptionTranslator.java
│ │ │ │ ├── RestExceptionTranslator.java
│ │ │ │ └── ServiceException.java
│ │ │ ├── props
│ │ │ │ └── LogProperties.java
│ │ │ └── utils
│ │ │ │ ├── SpringContextHolder.java
│ │ │ │ └── SysLogUtil.java
│ │ ├── mybatis
│ │ │ ├── MybatisAutoConfiguration.java
│ │ │ ├── config
│ │ │ │ └── MybatisPlusConfig.java
│ │ │ ├── constant
│ │ │ │ └── MybatisConstant.java
│ │ │ ├── intercept
│ │ │ │ └── SqlLogInterceptor.java
│ │ │ ├── props
│ │ │ │ └── MybatisProperties.java
│ │ │ └── utils
│ │ │ │ └── MybatisUtil.java
│ │ ├── oss
│ │ │ ├── OssAutoConfiguration.java
│ │ │ ├── props
│ │ │ │ └── LocalFileProperties.java
│ │ │ └── utils
│ │ │ │ └── OssUtil.java
│ │ └── redis
│ │ │ ├── component
│ │ │ └── RedisComponent.java
│ │ │ └── utils
│ │ │ ├── RedisUtil.java
│ │ │ └── TokenInfo.java
│ │ └── modules
│ │ ├── auth
│ │ ├── component
│ │ │ ├── ResourceAuthExceptionEntryPoint.java
│ │ │ ├── TumoAuth2ExceptionSerializer.java
│ │ │ └── TumoWebResponseExceptionTranslator.java
│ │ ├── config
│ │ │ ├── AuthorizationServerConfig.java
│ │ │ ├── ResourceServerConfig.java
│ │ │ └── WebSecurityConfig.java
│ │ ├── dto
│ │ │ ├── TumoUser.java
│ │ │ └── UserInfo.java
│ │ ├── endpoint
│ │ │ └── AuthTokenEndpoint.java
│ │ ├── exception
│ │ │ └── TumoAuth2Exception.java
│ │ └── service
│ │ │ └── UserDetailsServiceImpl.java
│ │ ├── system
│ │ ├── controller
│ │ │ ├── OssFileController.java
│ │ │ ├── SysDictController.java
│ │ │ ├── SysDictItemController.java
│ │ │ └── SysLogController.java
│ │ ├── endpoint
│ │ │ └── OssEndpoint.java
│ │ ├── entity
│ │ │ ├── OssFile.java
│ │ │ ├── SysDict.java
│ │ │ ├── SysDictItem.java
│ │ │ └── SysLog.java
│ │ ├── mapper
│ │ │ ├── OssFileMapper.java
│ │ │ ├── SysDictItemMapper.java
│ │ │ ├── SysDictMapper.java
│ │ │ └── SysLogMapper.java
│ │ └── service
│ │ │ ├── OssFileService.java
│ │ │ ├── OssService.java
│ │ │ ├── SysDictItemService.java
│ │ │ ├── SysDictService.java
│ │ │ ├── SysLogService.java
│ │ │ └── impl
│ │ │ ├── OssFileServiceImpl.java
│ │ │ ├── OssServiceImpl.java
│ │ │ ├── SysDictItemServiceImpl.java
│ │ │ ├── SysDictServiceImpl.java
│ │ │ └── SysLogServiceImpl.java
│ │ └── upms
│ │ ├── controller
│ │ ├── SysDeptController.java
│ │ ├── SysMenuController.java
│ │ ├── SysRoleController.java
│ │ └── SysUserController.java
│ │ ├── dto
│ │ ├── MenuMeta.java
│ │ ├── MenuTree.java
│ │ ├── MenuTreeUtil.java
│ │ ├── SysRoleDTO.java
│ │ └── SysUserDTO.java
│ │ ├── entity
│ │ ├── SysDept.java
│ │ ├── SysMenu.java
│ │ ├── SysRole.java
│ │ ├── SysRoleMenu.java
│ │ ├── SysUser.java
│ │ └── SysUserRole.java
│ │ ├── mapper
│ │ ├── SysDeptMapper.java
│ │ ├── SysMenuMapper.java
│ │ ├── SysRoleMapper.java
│ │ ├── SysRoleMenuMapper.java
│ │ ├── SysUserMapper.java
│ │ └── SysUserRoleMapper.java
│ │ └── service
│ │ ├── SysDeptService.java
│ │ ├── SysMenuService.java
│ │ ├── SysRoleMenuService.java
│ │ ├── SysRoleService.java
│ │ ├── SysUserRoleService.java
│ │ ├── SysUserService.java
│ │ └── impl
│ │ ├── SysDeptServiceImpl.java
│ │ ├── SysMenuServiceImpl.java
│ │ ├── SysRoleMenuServiceImpl.java
│ │ ├── SysRoleServiceImpl.java
│ │ ├── SysUserRoleServiceImpl.java
│ │ └── SysUserServiceImpl.java
└── resources
│ ├── META-INF
│ └── spring.factories
│ ├── application-dev.yml
│ ├── application-prod.yml
│ ├── application.yml
│ ├── banner.txt
│ ├── logback-spring.xml
│ ├── mapper
│ └── upms
│ │ ├── SysMenuMapper.xml
│ │ ├── SysUserMapper.xml
│ │ └── SysUserRoleMapper.xml
│ └── static
│ └── default.png
└── test
└── java
└── cn
└── tycoding
└── boot
└── TumoTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | ### gradle ###
2 | .gradle
3 | /build/
4 | !gradle/wrapper/gradle-wrapper.jar
5 |
6 | ### STS ###
7 | .settings/
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 |
15 | ### IntelliJ IDEA ###
16 | .idea
17 | *.iws
18 | *.iml
19 | *.ipr
20 | rebel.xml
21 |
22 | ### NetBeans ###
23 | nbproject/private/
24 | build/
25 | nbbuild/
26 | nbdist/
27 | .nb-gradle/
28 |
29 | ### maven ###
30 | target/
31 | *.war
32 | *.ear
33 | *.zip
34 | *.tar
35 | *.tar.gz
36 |
37 | ### logs ####
38 | /logs/
39 | *.sysLog
40 |
41 | ### temp ignore ###
42 | *.cache
43 | *.diff
44 | *.patch
45 | *.tmp
46 | *.java~
47 | *.properties~
48 | *.xml~
49 |
50 | ### system ignore ###
51 | .DS_Store
52 | Thumbs.db
53 | Servers
54 | .metadata
55 | gen_code
56 | dump.rdb
57 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openjdk:8-jre
2 | MAINTAINER tycoding@sina.com
3 |
4 | WORKDIR /build
5 |
6 | ADD ./target/tumo-boot.jar ./app.jar
7 |
8 | EXPOSE 8010
9 |
10 | ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
11 |
12 | CMD ["--spring.profiles.active=prod"]
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020-present TyCoding
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Tumo Team —— Tumo-Boot
7 |
8 |
9 |
10 | ## 项目介绍
11 |
12 | **[Tumo-Boot](https://github.com/Tumo-Team/tumo-boot)** 是基于SpringBoot2.x、SpringSecurity的RBAC项目脚手架,前端基于Node、Vue3.x、Ant-Design-Vue2.x、Vite、TypeScript。
13 |
14 | 如果你已经熟悉了RBAC单体项目开发,你可以学习 **Tumo-Cloud:** [https://github.com/Tumo-Team/tumo-cloud](https://github.com/Tumo-Team/tumo-cloud)。
15 |
16 | ## 项目地址
17 |
18 | - Tumo-Boot项目预览:[http://boot.tycoding.cn](http://boot.tycoding.cn)
19 | - Tumo-Boot文档预览:[http://docs.boot.tycoding.cn](http://docs.boot.tycoding.cn)
20 | - Tumo-Boot后端源码:[https://github.com/Tumo-Team/tumo-boot](https://github.com/Tumo-Team/tumo-boot)
21 | - Tumo-Boot前端源码:[https://github.com/Tumo-Team/tumo-boot-ui](https://github.com/Tumo-Team/tumo-boot-ui)
22 | - Tumo-Boot文档源码:[https://github.com/Tumo-Team/tumo-boot-docs](https://github.com/Tumo-Team/tumo-boot-docs)
23 |
24 | ## 技术栈
25 |
26 | **环境**
27 |
28 | | Name | Version |
29 | | ----- |-----------|
30 | | JDK | 1.8 |
31 | | MySql | 8.x |
32 | | OS | MacOS13.x |
33 | | IDEA | 2022.x |
34 |
35 | **后端**
36 |
37 | | Name | Version | Document |
38 | | --------------- |---------| ------------------------------------------------------------ |
39 | | Spring Boot | 2.x | [https://github.com/spring-projects/spring-boot](https://github.com/spring-projects/spring-boot) |
40 | | Mybatis-Plus | 3.x | [https://baomidou.com/guide/](https://baomidou.com/guide/) |
41 | | Hutool | 5.x | [https://hutool.cn/docs/#/](https://hutool.cn/docs/#/) |
42 |
43 | **前端**
44 |
45 | | Name | Version | Document |
46 | | -------------- |-------| ------------------------------------------------------------ |
47 | | Vben | 2.x | [https://github.com/anncwb/vue-vben-admin](https://github.com/anncwb/vue-vben-admin) |
48 | | Vue.js | 3.x | [https://cn.vuejs.org/v2/guide/](https://cn.vuejs.org/v2/guide/) |
49 | | Ant-Design-Vue | 2.x | [https://www.antdv.com/docs/vue/introduce-cn/](https://www.antdv.com/docs/vue/introduce-cn/) |
50 |
51 | ## 运行项目
52 |
53 | 详细的文档请看:[http://docs.boot.tycoding.cn](http://docs.boot.tycoding.cn)
54 |
55 | ## 图片预览
56 |
57 |
58 | 
59 |
60 | 
61 |
62 | 
63 |
64 | 
65 |
66 | 
67 |
68 | 
69 |
70 | # 联系
71 |
72 | - 个人博客:[http://tycoding.cn](http://tycoding.cn/)
73 | - GitHub:https://github.com/tycoding
74 | - 微信公众号:程序员涂陌
75 | - QQ交流群:866685601
76 |
77 | ## License
78 |
79 | [MIT](https://github.com/Tumo-Team/tumo-boot/blob/master/LICENSE)
80 |
81 | Copyright (c) 2021-present TyCoding
82 |
83 |
--------------------------------------------------------------------------------
/db/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mysql:5.7.34
2 |
3 | ENV TZ=Asia/Shanghai
4 |
5 | RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
6 |
7 | COPY ./tumo_boot.sql /docker-entrypoint-initdb.d
8 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.5"
2 |
3 | services:
4 | tumo-boot-mysql:
5 | image: tumo-boot-mysql
6 | build:
7 | context: ./db
8 | environment:
9 | MYSQL_ROOT_PASSWORD: root
10 | restart: always
11 | container_name: tumo-boot-mysql
12 | ports:
13 | - 3306:3306
14 |
15 | tumo-boot-redis:
16 | image: redis:6.0
17 | restart: always
18 | hostname: tumo-boot-redis
19 | container_name: tumo-boot-redis
20 | privileged: true
21 | command: "redis-server --appendonly yes"
22 | environment:
23 | - TZ=Asia/Shanghai
24 | ports:
25 | - 6379:6379
26 | networks:
27 | - tumo_boot_net
28 |
29 | tumo-boot:
30 | image: tumo-boot
31 | build:
32 | context: ./
33 | restart: always
34 | container_name: tumo-boot
35 | hostname: tumo-boot
36 | ports:
37 | - 8090:8090
38 | environment:
39 | - TZ=Asia/Shanghai
40 | networks:
41 | tumo_boot_net:
42 | ipv4_address: 172.30.0.80
43 |
44 | networks:
45 | tumo_boot_net:
46 | driver: bridge
47 | ipam:
48 | config:
49 | - subnet: 172.30.0.0/16
50 |
--------------------------------------------------------------------------------
/generate/README.md:
--------------------------------------------------------------------------------
1 | # 代码生成
2 |
3 |
--------------------------------------------------------------------------------
/imgs/image-20211019010331915.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tumo-Team/tumo-boot/f110e7741ae70c2a9c21e368965aa0acfacf39cd/imgs/image-20211019010331915.png
--------------------------------------------------------------------------------
/imgs/image-20211019010617453.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tumo-Team/tumo-boot/f110e7741ae70c2a9c21e368965aa0acfacf39cd/imgs/image-20211019010617453.png
--------------------------------------------------------------------------------
/imgs/image-20211019010644809.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tumo-Team/tumo-boot/f110e7741ae70c2a9c21e368965aa0acfacf39cd/imgs/image-20211019010644809.png
--------------------------------------------------------------------------------
/imgs/image-20211019010703801.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tumo-Team/tumo-boot/f110e7741ae70c2a9c21e368965aa0acfacf39cd/imgs/image-20211019010703801.png
--------------------------------------------------------------------------------
/imgs/image-20211019010720167.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tumo-Team/tumo-boot/f110e7741ae70c2a9c21e368965aa0acfacf39cd/imgs/image-20211019010720167.png
--------------------------------------------------------------------------------
/imgs/image-20211019010743832.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tumo-Team/tumo-boot/f110e7741ae70c2a9c21e368965aa0acfacf39cd/imgs/image-20211019010743832.png
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.7.7
9 |
10 |
11 |
12 | tumo-boot
13 | cn.tycoding.boot
14 | tumo-boot
15 | jar
16 | http://docs.boot.tycoding.cn
17 |
18 |
19 | 1.8
20 | 2.6.8
21 | 1.2.15
22 | 3.5.3.1
23 | 3.12.0
24 | 5.8.11
25 | 1.5.4
26 |
27 |
28 |
29 |
30 |
31 | org.springframework.boot
32 | spring-boot-starter-web
33 |
34 |
35 |
36 | spring-boot-starter-tomcat
37 | org.springframework.boot
38 |
39 |
40 |
41 |
42 |
43 | org.springframework.boot
44 | spring-boot-starter-undertow
45 |
46 |
47 |
48 |
49 | mysql
50 | mysql-connector-java
51 | runtime
52 |
53 |
54 |
55 | com.baomidou
56 | mybatis-plus-boot-starter
57 | ${mybatis-plus.version}
58 |
59 |
60 | com.zaxxer
61 | HikariCP
62 |
63 |
64 |
65 |
66 |
67 | com.alibaba
68 | druid-spring-boot-starter
69 | ${druid.version}
70 |
71 |
72 |
73 |
74 | org.springframework.security.oauth.boot
75 | spring-security-oauth2-autoconfigure
76 | ${security-oauth2-autoconfigure.version}
77 |
78 |
79 | org.springframework.boot
80 | spring-boot-starter-security
81 |
82 |
83 |
84 | org.springframework.boot
85 | spring-boot-starter-aop
86 |
87 |
88 |
89 |
90 | org.springframework.boot
91 | spring-boot-starter-data-redis
92 |
93 |
94 |
95 |
96 | cn.hutool
97 | hutool-all
98 | ${hutool.version}
99 |
100 |
101 |
102 |
103 | ma.glasnost.orika
104 | orika-core
105 | ${orika.version}
106 |
107 |
108 |
109 |
110 | org.apache.commons
111 | commons-lang3
112 | ${commons-lang3.version}
113 |
114 |
115 |
116 |
117 | org.projectlombok
118 | lombok
119 | true
120 |
121 |
122 |
123 |
124 | org.springframework.boot
125 | spring-boot-configuration-processor
126 | true
127 |
128 |
129 |
130 |
131 | org.springframework.boot
132 | spring-boot-devtools
133 | runtime
134 | true
135 |
136 |
137 |
138 | org.springframework.boot
139 | spring-boot-starter-test
140 | test
141 |
142 |
143 | junit
144 | junit
145 | test
146 |
147 |
148 |
149 |
150 | ${project.name}
151 |
152 |
153 | org.springframework.boot
154 | spring-boot-maven-plugin
155 |
156 | ${project.build.finalName}
157 |
158 | true
159 |
160 |
161 |
162 |
163 |
164 | repackage
165 |
166 |
167 |
168 |
169 |
170 | org.apache.maven.plugins
171 | maven-assembly-plugin
172 | 3.3.0
173 |
174 |
175 |
176 | cn.tycoding.boot.TumoBootApp
177 |
178 |
179 |
180 | /script/assembly/assembly.xml
181 |
182 |
183 |
184 |
185 | make-assembly
186 | package
187 |
188 | single
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
--------------------------------------------------------------------------------
/script/assembly/assembly.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 | bin
8 |
9 |
10 | tar.gz
11 |
12 |
13 | true
14 |
15 |
16 |
20 |
21 |
22 | script/assembly/bin
23 | bin
24 | 0755
25 |
26 | unix
27 | true
28 |
29 |
30 |
31 | script/assembly/config
32 | config
33 | 0644
34 |
35 |
36 |
37 | src/main/resources
38 | /config
39 |
40 | **/*.properties
41 | **/*.yml
42 | banner.txt
43 |
44 | true
45 |
46 |
47 |
48 | target
49 | lib
50 |
51 | *.jar
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/script/assembly/bin/start.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # 项目名称
4 | SERVER_NAME="${project.artifactId}"
5 |
6 | # jar名称
7 | JAR_NAME="${project.build.finalName}.jar"
8 |
9 | # 进入bin目录
10 | cd `dirname $0`
11 | # bin目录绝对路径
12 | BIN_DIR=`pwd`
13 | # 返回到上一级项目根目录路径
14 | cd ..
15 | # 打印项目根目录绝对路径
16 | # `pwd` 执行系统命令并获得结果
17 | DEPLOY_DIR=`pwd`
18 |
19 | # 外部配置文件绝对目录,如果是目录需要/结尾,也可以直接指定文件
20 | # 如果指定的是目录,spring则会读取目录中的所有配置文件
21 | CONF_DIR=$DEPLOY_DIR/config
22 | # SERVER_PORT=`sed '/server.port/!d;s/.*=//' config/application.properties | tr -d '\r'`
23 | # 获取应用的端口号
24 | SERVER_PORT=`sed -nr '/port: [0-9]+/ s/.*port: +([0-9]+).*/\1/p' config/application.yml`
25 |
26 | PIDS=`ps -f | grep java | grep "$CONF_DIR" |awk '{print $2}'`
27 | if [ "$1" = "status" ]; then
28 | if [ -n "$PIDS" ]; then
29 | echo "The $SERVER_NAME is running...!"
30 | echo "PID: $PIDS"
31 | exit 0
32 | else
33 | echo "The $SERVER_NAME is stopped"
34 | exit 0
35 | fi
36 | fi
37 |
38 | if [ -n "$PIDS" ]; then
39 | echo "ERROR: The $SERVER_NAME already started!"
40 | echo "PID: $PIDS"
41 | exit 1
42 | fi
43 |
44 | if [ -n "$SERVER_PORT" ]; then
45 | SERVER_PORT_COUNT=`netstat -tln | grep $SERVER_PORT | wc -l`
46 | if [ $SERVER_PORT_COUNT -gt 0 ]; then
47 | echo "ERROR: The $SERVER_NAME port $SERVER_PORT already used!"
48 | exit 1
49 | fi
50 | fi
51 |
52 | # 项目日志输出绝对路径
53 | LOGS_DIR=$DEPLOY_DIR/logs
54 | # 如果logs文件夹不存在,则创建文件夹
55 | if [ ! -d $LOGS_DIR ]; then
56 | mkdir $LOGS_DIR
57 | fi
58 | STDOUT_FILE=$LOGS_DIR/catalina.log
59 |
60 | # JVM Configuration
61 | JAVA_OPTS=" -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true "
62 | JAVA_DEBUG_OPTS=""
63 | if [ "$1" = "debug" ]; then
64 | JAVA_DEBUG_OPTS=" -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n "
65 | fi
66 |
67 | JAVA_JMX_OPTS=""
68 | if [ "$1" = "jmx" ]; then
69 | JAVA_JMX_OPTS=" -Dcom.sun.management.jmxremote.port=1099 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false "
70 | fi
71 |
72 | JAVA_MEM_OPTS=""
73 | BITS=`java -version 2>&1 | grep -i 64-bit`
74 | if [ -n "$BITS" ]; then
75 | JAVA_MEM_OPTS=" -server -Xmx512m -Xms512m -Xmn256m -Xss256k -XX:+DisableExplicitGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 "
76 | else
77 | JAVA_MEM_OPTS=" -server -Xms512m -Xmx512m -XX:SurvivorRatio=2 -XX:+UseParallelGC "
78 | fi
79 |
80 | # 加载外部log4j2文件的配置
81 | LOG_IMPL_FILE=log4j2.xml
82 | LOGGING_CONFIG=""
83 | if [ -f "$CONF_DIR/$LOG_IMPL_FILE" ]
84 | then
85 | LOGGING_CONFIG="-Dlogging.config=$CONF_DIR/$LOG_IMPL_FILE"
86 | fi
87 | CONFIG_FILES=" -Dlogging.path=$LOGS_DIR $LOGGING_CONFIG -Dspring.config.location=$CONF_DIR/ "
88 | echo -e "Starting the $SERVER_NAME ..."
89 | nohup java $JAVA_OPTS $JAVA_MEM_OPTS $JAVA_DEBUG_OPTS $JAVA_JMX_OPTS $CONFIG_FILES -jar $DEPLOY_DIR/lib/$JAR_NAME > $STDOUT_FILE 2>&1 &
90 |
91 | COUNT=0
92 | while [ $COUNT -lt 1 ]; do
93 | echo -e ".\c"
94 | sleep 1
95 | if [ -n "$SERVER_PORT" ]; then
96 | COUNT=`netstat -an | grep $SERVER_PORT | wc -l`
97 | else
98 | COUNT=`ps -f | grep java | grep "$DEPLOY_DIR" | awk '{print $2}' | wc -l`
99 | fi
100 | if [ $COUNT -gt 0 ]; then
101 | break
102 | fi
103 | done
104 |
105 |
106 | echo "OK!"
107 | PIDS=`ps -f | grep java | grep "$DEPLOY_DIR" | awk '{print $2}'`
108 | echo "PID: $PIDS"
109 | echo "STDOUT: $STDOUT_FILE"
110 |
--------------------------------------------------------------------------------
/script/assembly/bin/stop.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # 项目名称
4 | APPLICATION="${project.artifactId}"
5 |
6 | # 项目启动jar包名称
7 | APPLICATION_JAR="${project.build.finalName}.jar"
8 |
9 | # 通过项目名称查找到PI,然后kill -9 pid
10 | PID=$(ps -ef | grep "${APPLICATION_JAR}" | grep -v grep | awk '{ print $2 }')
11 | if [[ -z "$PID" ]]
12 | then
13 | echo ${APPLICATION} is already stopped
14 | else
15 | echo kill ${PID}
16 | kill -9 ${PID}
17 | echo ${APPLICATION} stopped successfully
18 | fi
--------------------------------------------------------------------------------
/script/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.5"
2 |
3 | services:
4 | tumo-boot-mysql:
5 | image: registry.cn-hangzhou.aliyuncs.com/tumo/tumo-boot-mysql
6 | environment:
7 | MYSQL_ROOT_PASSWORD: root
8 | restart: always
9 | container_name: tumo-boot-mysql
10 | volumes:
11 | - ./mysql_data:/var/lib/mysql
12 | ports:
13 | - 3306:3306
14 | networks:
15 | - tumo_boot_net
16 |
17 | tumo-boot-redis:
18 | image: redis:6.0
19 | restart: always
20 | hostname: tumo-boot-redis
21 | container_name: tumo-boot-redis
22 | privileged: true
23 | command: "redis-server --appendonly yes"
24 | volumes:
25 | - ./redis_data:/data
26 | environment:
27 | - TZ=Asia/Shanghai
28 | ports:
29 | - 6379:6379
30 | networks:
31 | - tumo_boot_net
32 |
33 | tumo-boot:
34 | image: registry.cn-hangzhou.aliyuncs.com/tumo/tumo-boot
35 | restart: always
36 | container_name: tumo-boot
37 | hostname: tumo-boot
38 | volumes:
39 | - ./logs:/build/logs
40 | ports:
41 | - 8090:8090
42 | environment:
43 | - TZ=Asia/Shanghai
44 | networks:
45 | tumo_boot_net:
46 | ipv4_address: 172.30.0.80
47 |
48 | tumo-boot-ui:
49 | image: registry.cn-hangzhou.aliyuncs.com/tumo/tumo-boot-ui
50 | restart: always
51 | container_name: tumo-boot-ui
52 | ports:
53 | - 8091:80
54 | networks:
55 | - tumo_boot_net
56 |
57 | networks:
58 | tumo_boot_net:
59 | driver: bridge
60 | ipam:
61 | config:
62 | - subnet: 172.30.0.0/16
63 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/TumoBootApp.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | /**
7 | * SpringBoot启动器类
8 | *
9 | * @author tycoding
10 | * @since 2021/5/21
11 | */
12 | @SpringBootApplication
13 | public class TumoBootApp {
14 |
15 | public static void main(String[] args) {
16 | SpringApplication.run(TumoBootApp.class, args);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/auth/AuthAutoConfiguration.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.auth;
2 |
3 | import cn.tycoding.boot.common.auth.props.AuthProperties;
4 | import cn.tycoding.boot.common.auth.utils.AuthService;
5 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
6 | import org.springframework.context.annotation.Bean;
7 | import org.springframework.context.annotation.Configuration;
8 |
9 | /**
10 | * Auth 配置注入
11 | *
12 | * @author tycoding
13 | * @since 2021/5/21
14 | */
15 | @Configuration
16 | @EnableConfigurationProperties({AuthProperties.class})
17 | public class AuthAutoConfiguration {
18 |
19 | @Bean("auth")
20 | public AuthService authService(AuthProperties authProperties) {
21 | return new AuthService(authProperties);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/auth/filter/CaptchaFilter.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.auth.filter;
2 |
3 | import cn.tycoding.boot.common.core.api.HttpCode;
4 | import cn.tycoding.boot.common.core.constant.ApiConstant;
5 | import cn.tycoding.boot.common.auth.utils.AuthUtil;
6 | import cn.tycoding.boot.common.core.api.R;
7 | import cn.tycoding.boot.common.core.constant.CacheConstant;
8 | import cn.tycoding.boot.common.core.utils.ServletUtil;
9 | import lombok.RequiredArgsConstructor;
10 | import lombok.extern.slf4j.Slf4j;
11 | import org.springframework.data.redis.core.RedisTemplate;
12 | import org.springframework.stereotype.Component;
13 | import org.springframework.web.bind.ServletRequestUtils;
14 | import org.springframework.web.filter.OncePerRequestFilter;
15 |
16 | import javax.servlet.FilterChain;
17 | import javax.servlet.ServletException;
18 | import javax.servlet.http.HttpServletRequest;
19 | import javax.servlet.http.HttpServletResponse;
20 | import java.io.IOException;
21 |
22 | /**
23 | * 验证码过滤器
24 | *
25 | * @author tycoding
26 | * @since 2021/5/21
27 | */
28 | @Slf4j
29 | @Component
30 | @RequiredArgsConstructor
31 | public class CaptchaFilter extends OncePerRequestFilter {
32 |
33 | private final RedisTemplate redisTemplate;
34 |
35 | @Override
36 | protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
37 | if (ApiConstant.API_OAUTH_TOKEN.equals(request.getRequestURI())) {
38 | String headerKey = request.getHeader(AuthUtil.CAPTCHA_HEADER_KEY);
39 | if (headerKey == null) {
40 | // 特殊处理,对于类似Swagger中直接获取认证Token时不带验证码
41 | log.info("正在进行请求授权,未携带Captcha-Key请求头,不进行验证码校验");
42 | chain.doFilter(request, response);
43 | return;
44 | }
45 |
46 | String code = ServletRequestUtils.getStringParameter(request, AuthUtil.CAPTCHA_FORM_KEY);
47 | String redisCode = (String) redisTemplate.opsForValue().get(CacheConstant.CAPTCHA_PREFIX + headerKey);
48 | if (code == null || !code.toLowerCase().equals(redisCode)) {
49 | ServletUtil.write(response, new R<>(HttpCode.FAILURE.getCode(), AuthUtil.CAPTCHA_ERROR_INFO));
50 | return;
51 | }
52 | }
53 | chain.doFilter(request, response);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/auth/props/AuthProperties.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.auth.props;
2 |
3 | import lombok.Data;
4 | import org.springframework.boot.context.properties.ConfigurationProperties;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | /**
10 | * 自定义Auth模块 YML配置映射实体
11 | *
12 | * @author tycoding
13 | * @since 2021/5/21
14 | */
15 | @Data
16 | @ConfigurationProperties("tumo-boot.auth")
17 | public class AuthProperties {
18 |
19 | /**
20 | * 默认忽略拦截的URL集合
21 | */
22 | private List skipUrl = new ArrayList();
23 |
24 | /**
25 | * 是否开启演示环境
26 | */
27 | private Boolean isDemoEnv;
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/auth/utils/AuthService.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.auth.utils;
2 |
3 | import cn.tycoding.boot.common.auth.props.AuthProperties;
4 | import lombok.AllArgsConstructor;
5 | import org.springframework.security.core.Authentication;
6 | import org.springframework.security.core.GrantedAuthority;
7 | import org.springframework.util.PatternMatchUtils;
8 | import org.springframework.util.StringUtils;
9 |
10 | import java.util.Collection;
11 |
12 | /**
13 | * 接口权限校验
14 | *
15 | * @author tycoding
16 | * @since 2021/6/11
17 | */
18 | @AllArgsConstructor
19 | public class AuthService {
20 |
21 | private final AuthProperties authProperties;
22 |
23 | /**
24 | * 校验当前登录的用户是否拥有指定权限
25 | *
26 | * @param perms 需要校验权限列表
27 | * @return 校验结果
28 | */
29 | public boolean hasAuth(String... perms) {
30 | if (perms.length == 0) {
31 | return false;
32 | }
33 | // 演示环境禁用操作
34 | if (authProperties.getIsDemoEnv() && AuthUtil.getRoleNames().contains(AuthUtil.DEMO_ENV)) {
35 | return false;
36 | }
37 |
38 | Authentication authentication = AuthUtil.getAuthentication();
39 | if (authentication == null) {
40 | return false;
41 | }
42 | Collection extends GrantedAuthority> authorities = authentication.getAuthorities();
43 | return authorities.stream().map(GrantedAuthority::getAuthority).filter(StringUtils::hasText)
44 | .anyMatch(p -> PatternMatchUtils.simpleMatch(perms, p));
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/auth/utils/AuthUtil.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.auth.utils;
2 |
3 | import cn.tycoding.boot.common.core.constant.AuthConstant;
4 | import cn.tycoding.boot.modules.auth.dto.TumoUser;
5 | import org.apache.commons.lang3.StringUtils;
6 | import org.springframework.security.core.Authentication;
7 | import org.springframework.security.core.GrantedAuthority;
8 | import org.springframework.security.core.context.SecurityContextHolder;
9 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
10 | import org.springframework.web.context.request.RequestContextHolder;
11 | import org.springframework.web.context.request.ServletRequestAttributes;
12 |
13 | import javax.servlet.http.HttpServletRequest;
14 | import javax.servlet.http.HttpServletResponse;
15 | import java.util.ArrayList;
16 | import java.util.Collection;
17 | import java.util.List;
18 | import java.util.Objects;
19 |
20 | /**
21 | * 权限相关方法
22 | *
23 | * @author tycoding
24 | * @since 2021/5/21
25 | */
26 | public class AuthUtil {
27 |
28 | /**
29 | * 系统预制固定超级管理员角色别名
30 | * 作用:提供一个角色摆脱权限体系的控制,允许词角色访问所有菜单权限
31 | * 使用:所有涉及根据角色查询的地方都排除对此角色的限制
32 | */
33 | public static final String ADMINISTRATOR = "administrator";
34 |
35 | /**
36 | * 系统默认演示环境角色别名
37 | * 作用:在 tumo-boot.auth.isDemoEnv 配置开启后,将会对所有按钮级权限拦截并提示前端
38 | */
39 | public static final String DEMO_ENV = "demo_env";
40 |
41 | /* 登录表单验证码Key标识 */
42 | public static final String CAPTCHA_FORM_KEY = "captcha";
43 | /* 登录验证码Header Key标识 */
44 | public static final String CAPTCHA_HEADER_KEY = "Captcha-Key";
45 | /* 验证码错误信息 */
46 | public static final String CAPTCHA_ERROR_INFO = "验证码不正确";
47 | /* 没有查询到用户名 */
48 | public static final String NOT_ROLE_ERROR = "没有查询到用户角色信息";
49 |
50 | /**
51 | * 获取Request对象
52 | */
53 | public static HttpServletRequest getRequest() {
54 | return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
55 | }
56 |
57 | /**
58 | * 获取Response对象
59 | */
60 | public static HttpServletResponse getResponse() {
61 | return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getResponse();
62 | }
63 |
64 | /**
65 | * 获取Authentication对象
66 | */
67 | public static Authentication getAuthentication() {
68 | return SecurityContextHolder.getContext().getAuthentication();
69 | }
70 |
71 | /**
72 | * 截取前端Token字符串中不包含`Bearer`的部分
73 | */
74 | public static String getToken(String token) {
75 | if (token != null && token.toLowerCase().startsWith("bearer")) {
76 | return token.replace("bearer", "").trim();
77 | }
78 | return token;
79 | }
80 |
81 | /**
82 | * 获取用户对象
83 | */
84 | public static TumoUser getUser() {
85 | Authentication authentication = getAuthentication();
86 | if (authentication == null) {
87 | return null;
88 | }
89 | Object principal = authentication.getPrincipal();
90 | if (principal instanceof TumoUser) {
91 | return (TumoUser) principal;
92 | }
93 | return null;
94 | }
95 |
96 | /**
97 | * 获取用户名
98 | */
99 | public static String getUsername() {
100 | Authentication authentication = getAuthentication();
101 | if (authentication == null) {
102 | return null;
103 | }
104 | return authentication.getName();
105 | }
106 |
107 | /**
108 | * 获取登录用户ID
109 | */
110 | public static Long getUserId() {
111 | TumoUser user = getUser();
112 | if (user != null) {
113 | return user.getId();
114 | }
115 | return null;
116 | }
117 |
118 | /**
119 | * 获取用户角色Id集合
120 | */
121 | public static List getRoleIds() {
122 | List roleIds = new ArrayList<>();
123 | Authentication authentication = getAuthentication();
124 | if (authentication == null) {
125 | return roleIds;
126 | }
127 | Collection extends GrantedAuthority> authorities = authentication.getAuthorities();
128 | authorities.stream().filter(granted -> StringUtils.startsWith(granted.getAuthority(), AuthConstant.ROLE_PREFIX)).forEach(granted -> {
129 | String id = StringUtils.substringBetween(granted.getAuthority(), AuthConstant.ROLE_PREFIX, AuthConstant.ROLE_SUFFIX);
130 | roleIds.add(Long.parseLong(id));
131 | });
132 | return roleIds;
133 | }
134 |
135 | /**
136 | * 获取用户角色Alias集合
137 | */
138 | public static List getRoleNames() {
139 | List roleNames = new ArrayList<>();
140 | Authentication authentication = getAuthentication();
141 | if (authentication == null) {
142 | return roleNames;
143 | }
144 | Collection extends GrantedAuthority> authorities = authentication.getAuthorities();
145 | authorities.stream().filter(granted -> StringUtils.startsWith(granted.getAuthority(), AuthConstant.ROLE_PREFIX)).forEach(granted -> {
146 | String name = StringUtils.substringAfter(granted.getAuthority(), AuthConstant.ROLE_SUFFIX);
147 | roleNames.add(name);
148 | });
149 | return roleNames;
150 | }
151 |
152 | /**
153 | * 密码加密
154 | *
155 | * @param password password为空则用默认密码加密
156 | */
157 | public static String encode(String password) {
158 | BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
159 | if (password == null || password.isEmpty()) {
160 | return passwordEncoder.encode(AuthConstant.DEFAULT_PASS);
161 | }
162 | return passwordEncoder.encode(password);
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/core/api/HttpCode.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.core.api;
2 |
3 | /**
4 | * 统一定义请求响应状态码
5 | *
6 | * @author tycoding
7 | * @since 2021/5/21
8 | */
9 | @SuppressWarnings("all")
10 | public enum HttpCode {
11 | SUCCESS(200, "操作成功"),
12 | FAILURE(400, "业务异常"),
13 | UN_AUTHORIZED(401, "请求未授权"),
14 | AUTH_UN_AUTHORIZED(400, "用户名或密码错误"),
15 | CLIENT_UN_AUTHORIZED(401, "客户端请求未授权"),
16 | INVALID_GRANT(401, "用户名或密码错误"),
17 | FORBIDDEN(403, "没有访问权限"),
18 | NOT_FOUND(404, "404 没找到请求"),
19 | MSG_NOT_READABLE(400, "消息不能读取"),
20 | METHOD_NOT_SUPPORTED(405, "不支持当前请求方法"),
21 | MEDIA_TYPE_NOT_SUPPORTED(415, "不支持当前媒体类型"),
22 | REQ_REJECT(403, "请求被拒绝"),
23 | INTERNAL_SERVER_ERROR(500, "服务器异常"),
24 | PARAM_MISS(400, "缺少必要的请求参数"),
25 | PARAM_TYPE_ERROR(400, "请求参数类型错误"),
26 | PARAM_BIND_ERROR(400, "请求参数绑定错误"),
27 | PARAM_VALID_ERROR(400, "参数校验失败");
28 |
29 | final int code;
30 | final String msg;
31 |
32 | public int getCode() {
33 | return this.code;
34 | }
35 |
36 | public String getMsg() {
37 | return this.msg;
38 | }
39 |
40 | private HttpCode(final int code, final String msg) {
41 | this.code = code;
42 | this.msg = msg;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/core/api/QueryPage.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.core.api;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 |
6 | import java.io.Serializable;
7 |
8 | /**
9 | * 统一定义分页查询接口分页格式
10 | *
11 | * @author tycoding
12 | * @since 2021/5/21
13 | */
14 | @Data
15 | @AllArgsConstructor
16 | public class QueryPage implements Serializable {
17 | private static final long serialVersionUID = 1L;
18 |
19 | /**
20 | * 当前页
21 | */
22 | private int page;
23 |
24 | /**
25 | * 每页的记录数
26 | */
27 | private int limit;
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/core/api/R.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.core.api;
2 |
3 | import lombok.Data;
4 |
5 | import java.io.Serializable;
6 |
7 | /**
8 | * 统一定义请求响应数据格式
9 | *
10 | * @author tycoding
11 | * @since 2021/5/21
12 | */
13 | @Data
14 | public class R implements Serializable {
15 | private static final long serialVersionUID = 1L;
16 |
17 | private int code = HttpCode.SUCCESS.code;
18 |
19 | private String msg = HttpCode.SUCCESS.msg;
20 |
21 | private T data;
22 |
23 | public R() {
24 | super();
25 | }
26 |
27 | public R(int code, String msg) {
28 | this.code = code;
29 | this.msg = msg;
30 | }
31 |
32 | public static R ok(T data) {
33 | return new R(data);
34 | }
35 |
36 | public static R ok(T data, HttpCode httpCode) {
37 | return new R(data, httpCode);
38 | }
39 |
40 | public static R ok() {
41 | return new R<>();
42 | }
43 |
44 | public static R ok(String msg) {
45 | return new R<>(HttpCode.SUCCESS.getCode(), msg);
46 | }
47 |
48 | public static R ok(HttpCode httpCode) {
49 | return new R<>(httpCode);
50 | }
51 |
52 | public static R fail(String msg) {
53 | return new R<>(HttpCode.FAILURE.getCode(), msg);
54 | }
55 |
56 | public static R fail(int code, String msg) {
57 | return new R<>(code, msg);
58 | }
59 |
60 | public static R fail(HttpCode httpCode) {
61 | return new R<>(httpCode);
62 | }
63 |
64 | public static R fail(Throwable e) {
65 | return new R<>(e);
66 | }
67 |
68 | protected R(T data) {
69 | this.data = data;
70 | }
71 |
72 | protected R(HttpCode httpCode) {
73 | this.code = httpCode.code;
74 | this.msg = httpCode.msg;
75 | }
76 |
77 | protected R(T data, HttpCode httpCode) {
78 | this.data = data;
79 | this.code = httpCode.code;
80 | this.msg = httpCode.msg;
81 | }
82 |
83 | protected R(Throwable e) {
84 | super();
85 | this.code = HttpCode.INTERNAL_SERVER_ERROR.code;
86 | this.msg = e.getMessage();
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/core/config/JacksonConfiguration.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.core.config;
2 |
3 | import cn.hutool.core.date.DatePattern;
4 | import com.fasterxml.jackson.databind.ObjectMapper;
5 | import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
6 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
7 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
8 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
9 | import org.springframework.boot.autoconfigure.AutoConfigureBefore;
10 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
11 | import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
12 | import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
13 | import org.springframework.context.annotation.Bean;
14 | import org.springframework.context.annotation.Configuration;
15 |
16 | import java.time.LocalDate;
17 | import java.time.LocalDateTime;
18 | import java.time.LocalTime;
19 | import java.time.ZoneId;
20 | import java.time.format.DateTimeFormatter;
21 | import java.util.Locale;
22 | import java.util.TimeZone;
23 |
24 | /**
25 | * 全局配置Jackson序列化
26 | *
27 | * @author tycoding
28 | * @since 2021/5/21
29 | */
30 | @Configuration(proxyBeanMethods = false)
31 | @ConditionalOnClass(ObjectMapper.class)
32 | @AutoConfigureBefore(JacksonAutoConfiguration.class)
33 | public class JacksonConfiguration {
34 |
35 | @Bean
36 | public Jackson2ObjectMapperBuilderCustomizer customizer() {
37 | return builder -> {
38 | // 本地化
39 | builder.locale(Locale.CHINA);
40 | // 时区
41 | builder.timeZone(TimeZone.getTimeZone(ZoneId.systemDefault()));
42 | // 全局Long类型序列化为字符串
43 | builder.serializerByType(Long.class, ToStringSerializer.instance);
44 |
45 | // 时间类型序列化
46 | builder.simpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);
47 | builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
48 | builder.serializerByType(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
49 | builder.serializerByType(LocalTime.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
50 |
51 | builder.deserializerByType(LocalDateTime.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
52 | builder.deserializerByType(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
53 | builder.deserializerByType(LocalTime.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
54 | };
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/core/constant/ApiConstant.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.core.constant;
2 |
3 | /**
4 | * API接口常量值
5 | *
6 | * @author tycoding
7 | * @since 2021/5/21
8 | */
9 | public interface ApiConstant {
10 |
11 | /**
12 | * 基础API接口前缀
13 | */
14 | String API_BASE = "/tumo-boot";
15 |
16 | /**
17 | * 自定义OAuth Token端点地址
18 | */
19 | String API_OAUTH_TOKEN = "/tumo-boot/auth/oauth/token";
20 |
21 | /**
22 | * API接口前缀 - Auth模块
23 | */
24 | String API_AUTH_PREFIX = "/tumo-boot/auth";
25 |
26 | /**
27 | * API接口前缀 - Upms模块
28 | */
29 | String API_UPMS_PREFIX = "/tumo-boot/upms";
30 |
31 | /**
32 | * API接口前缀 - System模块
33 | */
34 | String API_SYSTEM_PREFIX = "/tumo-boot/system";
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/core/constant/AuthConstant.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.core.constant;
2 |
3 | /**
4 | * OAuth2 存储数据前缀
5 | *
6 | * @author tycoding
7 | * @since 2021/5/21
8 | */
9 | public interface AuthConstant {
10 |
11 | /**
12 | * 角色前缀名
13 | */
14 | String ROLE_PREFIX = "ROLE_PREFIX_";
15 |
16 | /**
17 | * 角色后缀名
18 | */
19 | String ROLE_SUFFIX = "_ROLE_SUFFIX_";
20 |
21 | /**
22 | * 默认密码(重置密码)
23 | */
24 | String DEFAULT_PASS = "123456";
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/core/constant/CacheConstant.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.core.constant;
2 |
3 | /**
4 | * 缓存常量
5 | *
6 | * @author tycoding
7 | * @since 2021/5/21
8 | */
9 | public interface CacheConstant {
10 |
11 | /**
12 | * 系统所有Redis缓存Key前缀 prefix
13 | */
14 | String REDIS_KEY_PREFIX = "tumo-boot:";
15 |
16 | /**
17 | * OAuth缓存前缀
18 | */
19 | String OAUTH_PREFIX = REDIS_KEY_PREFIX + "auth:oauth:";
20 |
21 | /**
22 | * 验证码缓存前缀
23 | */
24 | String CAPTCHA_PREFIX = REDIS_KEY_PREFIX + "auth:captcha:";
25 |
26 | /**
27 | * 用户信息缓存
28 | */
29 | String USER_DETAIL_KEY = REDIS_KEY_PREFIX + "user_details";
30 |
31 | /**
32 | * 菜单权限缓存
33 | */
34 | String MENU_DETAIL_KEY = REDIS_KEY_PREFIX + "menu_details";
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/core/constant/CaptchaConstant.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.core.constant;
2 |
3 | /**
4 | * 图片验证码常量
5 | *
6 | * @author tycoding
7 | * @since 2021/5/21
8 | */
9 | public interface CaptchaConstant {
10 |
11 | /**
12 | * 验证码图片高度
13 | */
14 | int CAPTCHA_HEIGHT = 32;
15 |
16 | /**
17 | * 验证码图片宽度
18 | */
19 | int CAPTCHA_WIDTH = 110;
20 |
21 | /**
22 | * 验证码图片字符数量
23 | */
24 | int CAPTCHA_COUNT = 4;
25 |
26 | /**
27 | * 验证码图片干扰线数量
28 | */
29 | int CAPTCHA_CIRCLE_COUNT = 10;
30 |
31 | /**
32 | * 验证码过期时间(分钟)
33 | */
34 | int CAPTCHA_TIMEOUT = 10;
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/core/constant/CommonConstant.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.core.constant;
2 |
3 | /**
4 | * 系统公共常量
5 | *
6 | * @author tycoding
7 | * @since 2021/5/21
8 | */
9 | public interface CommonConstant {
10 |
11 | /**
12 | * UTF-8 编码
13 | */
14 | String UTF_8 = "utf-8";
15 |
16 | /**
17 | * JSON 请求响应格式
18 | */
19 | String CONTENT_TYPE = "application/json; charset=utf-8";
20 |
21 | /**
22 | * 菜单类型:menu
23 | */
24 | String MENU_TYPE_MENU = "menu";
25 |
26 | /**
27 | * 菜单类型:button
28 | */
29 | String MENU_TYPE_BUTTON = "button";
30 |
31 | /**
32 | * 菜单:默认Icon图标
33 | */
34 | String MENU_ICON = "alert";
35 |
36 | /**
37 | * 默认用户头像路径
38 | */
39 | String DEFAULT_AVATAR = "/default.png";
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/core/launch/StartEventListener.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.core.launch;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.boot.web.context.WebServerInitializedEvent;
5 | import org.springframework.context.annotation.Configuration;
6 | import org.springframework.context.event.EventListener;
7 | import org.springframework.core.env.Environment;
8 | import org.springframework.scheduling.annotation.Async;
9 | import org.springframework.util.StringUtils;
10 |
11 | import java.net.UnknownHostException;
12 |
13 | /**
14 | * 自定义启动日志
15 | *
16 | * @author tycoding
17 | * @since 2021/5/21
18 | */
19 | @Slf4j
20 | @Configuration
21 | public class StartEventListener {
22 |
23 | public StartEventListener() {
24 | }
25 |
26 | @Async
27 | @EventListener({WebServerInitializedEvent.class})
28 | public void afterStart(WebServerInitializedEvent event) throws UnknownHostException {
29 | Environment environment = event.getApplicationContext().getEnvironment();
30 | String appName = environment.getProperty("spring.application.name");
31 | int port = event.getWebServer().getPort();
32 | String profile = StringUtils.arrayToCommaDelimitedString(environment.getActiveProfiles());
33 | log.info("----[{}]----启动完成。当前使用端口:[{}],环境变量:[{}]", appName, port, profile);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/core/utils/BeanUtil.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.core.utils;
2 |
3 | import ma.glasnost.orika.MapperFacade;
4 | import ma.glasnost.orika.impl.DefaultMapperFactory;
5 |
6 | import java.util.Collection;
7 | import java.util.Collections;
8 | import java.util.List;
9 |
10 | /**
11 | * Orika Bean拷贝工具的简单封装
12 | *
13 | * @author tycoding
14 | * @since 2021/5/21
15 | */
16 | public class BeanUtil {
17 |
18 | private static final MapperFacade MAPPER;
19 |
20 | static {
21 | DefaultMapperFactory factory = new DefaultMapperFactory.Builder().build();
22 | MAPPER = factory.getMapperFacade();
23 | }
24 |
25 | public static T copy(Object source, T target) {
26 | if (source == null) {
27 | return null;
28 | }
29 | MAPPER.map(source, target);
30 | return target;
31 | }
32 |
33 | public static T copy(Object source, Class targetClass) {
34 | if (source == null) {
35 | return null;
36 | }
37 | return MAPPER.map(source, targetClass);
38 | }
39 |
40 | public static List copy(Collection> source, Class targetClass) {
41 | if (source != null && source.size() > 0) {
42 | return MAPPER.mapAsList(source, targetClass);
43 | } else {
44 | return Collections.emptyList();
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/core/utils/IpUtil.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.core.utils;
2 |
3 | import java.net.InetAddress;
4 | import java.net.NetworkInterface;
5 | import java.util.Enumeration;
6 |
7 | /**
8 | * 获取服务IP地址
9 | *
10 | * @author tycoding
11 | * @since 2021/5/26
12 | */
13 | public class IpUtil {
14 |
15 | public static InetAddress getAddress() {
16 | try {
17 | InetAddress candidateAddress = null;
18 |
19 | Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces();
20 | while (networkInterfaces.hasMoreElements()) {
21 | NetworkInterface iface = networkInterfaces.nextElement();
22 | // 该网卡接口下的ip会有多个,也需要一个个的遍历,找到自己所需要的
23 | for (Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); ) {
24 | InetAddress inetAddr = inetAddrs.nextElement();
25 | // 排除loopback回环类型地址(不管是IPv4还是IPv6 只要是回环地址都会返回true)
26 | if (!inetAddr.isLoopbackAddress()) {
27 | if (inetAddr.isSiteLocalAddress()) {
28 | // 如果是site-local地址,就是它了 就是我们要找的
29 | // ~~~~~~~~~~~~~绝大部分情况下都会在此处返回你的ip地址值~~~~~~~~~~~~~
30 | return inetAddr;
31 | }
32 |
33 | // 若不是site-local地址 那就记录下该地址当作候选
34 | if (candidateAddress == null) {
35 | candidateAddress = inetAddr;
36 | }
37 | }
38 | }
39 | }
40 |
41 | // 如果出去loopback回环地之外无其它地址了,那就回退到原始方案吧
42 | return candidateAddress == null ? InetAddress.getLocalHost() : candidateAddress;
43 | } catch (Exception e) {
44 | e.printStackTrace();
45 | }
46 | return null;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/core/utils/Is.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.core.utils;
2 |
3 | import java.util.List;
4 | import java.util.regex.Pattern;
5 |
6 | /**
7 | * 校验工具类
8 | *
9 | * @author tycoding
10 | * @since 2021/5/21
11 | */
12 | public class Is {
13 |
14 | public static boolean isUrl(String url) {
15 | String reg = "(ht|f)tp(s?)\\:\\/\\/[0-9a-zA-Z]([-.\\w]*[0-9a-zA-Z])*(:(0-9)*)*(\\/?)([a-zA-Z0-9\\-\\.\\?\\,\\'\\/\\\\&%\\+\\$#_=]*)?";
16 | Pattern pattern = Pattern.compile(reg);
17 | return pattern.matcher(url).matches();
18 | }
19 |
20 | public static boolean isEmpty(List list) {
21 | return list == null || list.size() == 0;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/core/utils/ServletUtil.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.core.utils;
2 |
3 | import cn.hutool.json.JSONUtil;
4 | import cn.tycoding.boot.common.core.api.R;
5 | import cn.tycoding.boot.common.core.constant.CommonConstant;
6 | import lombok.SneakyThrows;
7 |
8 | import javax.servlet.http.HttpServletResponse;
9 |
10 | /**
11 | * Servlet工具类
12 | *
13 | * @author tycoding
14 | * @since 2021/5/21
15 | */
16 | public class ServletUtil {
17 |
18 | @SneakyThrows
19 | public static void write(HttpServletResponse response, R data) {
20 | response.setStatus(data.getCode());
21 | response.setHeader("Content-type", "application/json;charset=" + CommonConstant.UTF_8);
22 | response.setCharacterEncoding(CommonConstant.UTF_8);
23 | response.getWriter().write(JSONUtil.toJsonStr(data));
24 | }
25 |
26 | @SneakyThrows
27 | public static void write(HttpServletResponse response, int status, R data) {
28 | response.setStatus(status);
29 | response.setHeader("Content-type", "application/json;charset=" + CommonConstant.UTF_8);
30 | response.setCharacterEncoding(CommonConstant.UTF_8);
31 | response.getWriter().write(JSONUtil.toJsonStr(data));
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/log/LogAutoConfiguration.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.log;
2 |
3 | import cn.tycoding.boot.common.log.aspect.ApiLogAspect;
4 | import cn.tycoding.boot.common.log.event.LogListener;
5 | import cn.tycoding.boot.common.log.props.LogProperties;
6 | import cn.tycoding.boot.modules.system.service.SysLogService;
7 | import lombok.RequiredArgsConstructor;
8 | import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
9 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
10 | import org.springframework.context.annotation.Bean;
11 | import org.springframework.context.annotation.Configuration;
12 |
13 | /**
14 | * Log模块配置注入
15 | *
16 | * @author tycoding
17 | * @since 2021/5/21
18 | */
19 | @Configuration
20 | @RequiredArgsConstructor
21 | @ConditionalOnWebApplication
22 | @EnableConfigurationProperties({LogProperties.class})
23 | public class LogAutoConfiguration {
24 |
25 | @Bean
26 | public LogListener logListener(SysLogService sysLogService) {
27 | return new LogListener(sysLogService);
28 | }
29 |
30 | @Bean
31 | public ApiLogAspect logAspect() {
32 | return new ApiLogAspect();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/log/annotation/ApiLog.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.log.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 | * @author tycoding
12 | * @since 2021/5/21
13 | */
14 | @Target(ElementType.METHOD)
15 | @Retention(RetentionPolicy.RUNTIME)
16 | public @interface ApiLog {
17 |
18 | String value() default "";
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/log/aspect/ApiLogAspect.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.log.aspect;
2 |
3 | import cn.tycoding.boot.common.log.utils.SpringContextHolder;
4 | import cn.tycoding.boot.common.log.event.LogEvent;
5 | import cn.tycoding.boot.common.log.utils.SysLogUtil;
6 | import cn.tycoding.boot.modules.system.entity.SysLog;
7 | import lombok.extern.slf4j.Slf4j;
8 | import org.aspectj.lang.ProceedingJoinPoint;
9 | import org.aspectj.lang.annotation.Around;
10 | import org.aspectj.lang.annotation.Aspect;
11 |
12 | /**
13 | * 自定义日志记录切面
14 | *
15 | * @author tycoding
16 | * @since 2021/5/21
17 | */
18 | @Slf4j
19 | @Aspect
20 | public class ApiLogAspect {
21 |
22 | @Around("@annotation(apiLog)")
23 | public Object around(ProceedingJoinPoint point, cn.tycoding.boot.common.log.annotation.ApiLog apiLog) throws Throwable {
24 | String className = point.getTarget().getClass().getName();
25 | String methodName = point.getSignature().getName();
26 |
27 | long beginTime = System.currentTimeMillis();
28 | long time = System.currentTimeMillis() - beginTime;
29 |
30 | String method = className + "." + methodName + "()";
31 | SysLog sysLog = SysLogUtil.build(SysLogUtil.TYPE_OK, apiLog.value(), method, time);
32 |
33 | SpringContextHolder.publishEvent(new LogEvent(sysLog));
34 | return point.proceed();
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/log/aspect/RequestLogAspect.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.log.aspect;
2 |
3 | import cn.hutool.json.JSONObject;
4 | import cn.tycoding.boot.common.auth.utils.AuthUtil;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.aspectj.lang.ProceedingJoinPoint;
7 | import org.aspectj.lang.annotation.Around;
8 | import org.aspectj.lang.annotation.Aspect;
9 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
10 | import org.springframework.context.annotation.Configuration;
11 | import org.springframework.http.HttpHeaders;
12 |
13 | import javax.servlet.http.HttpServletRequest;
14 |
15 | /**
16 | * 全局拦截Controller接口,打印请求日志
17 | *
18 | * @author tycoding
19 | * @since 2021/5/21
20 | */
21 | @Slf4j
22 | @Aspect
23 | @Configuration
24 | @ConditionalOnProperty(value = {"tumo-boot.log.enable"}, matchIfMissing = true)
25 | public class RequestLogAspect {
26 |
27 | @Around("(@within(org.springframework.security.oauth2.provider.endpoint.FrameworkEndpoint)) || (execution(!static cn.tycoding.boot.common.core.api.R *(..)) && (@within(org.springframework.stereotype.Controller) || @within(org.springframework.web.bind.annotation.RestController)))")
28 | public Object around(ProceedingJoinPoint point) throws Throwable {
29 | HttpServletRequest request = AuthUtil.getRequest();
30 | String beforeLog = "\n\n================ Request Start ================" +
31 | "\n===General=== Request URL: " + request.getRequestURL() +
32 | "\n===General=== Request Method: " + request.getMethod() +
33 | "\n===General=== Remote Address: " + request.getRemoteAddr() +
34 | "\n\n===Headers=== Accept: " + request.getHeader(HttpHeaders.ACCEPT) +
35 | "\n===Headers=== Authorization: " + request.getHeader(HttpHeaders.AUTHORIZATION) +
36 | "\n===Headers=== Host: " + request.getHeader(HttpHeaders.HOST) +
37 | "\n===Headers=== User-Agent: " + request.getHeader(HttpHeaders.USER_AGENT) +
38 | "\n===Headers=== Parameters: " + new JSONObject(request.getParameterMap()).toString() +
39 | // 打印响应结果,内容过长会影响效率
40 | // "\n\n===Result=== " + new JSONObject(result).toString() +
41 | "\n================ Request End ================\n";
42 | log.info(beforeLog);
43 | return point.proceed();
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/log/event/LogEvent.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.log.event;
2 |
3 | import org.springframework.context.ApplicationEvent;
4 |
5 | /**
6 | * 自定义定义 Log事件
7 | *
8 | * @author tycoding
9 | * @since 2021/5/21
10 | */
11 | public class LogEvent extends ApplicationEvent {
12 |
13 | public LogEvent(Object source) {
14 | super(source);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/log/event/LogListener.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.log.event;
2 |
3 | import cn.tycoding.boot.modules.system.entity.SysLog;
4 | import cn.tycoding.boot.modules.system.service.SysLogService;
5 | import lombok.RequiredArgsConstructor;
6 | import org.springframework.context.event.EventListener;
7 | import org.springframework.core.annotation.Order;
8 | import org.springframework.scheduling.annotation.Async;
9 |
10 | /**
11 | * 监听自定义Log 事件
12 | *
13 | * @author tycoding
14 | * @since 2021/5/21
15 | */
16 | @RequiredArgsConstructor
17 | public class LogListener {
18 |
19 | private final SysLogService sysLogService;
20 |
21 | @Async
22 | @Order
23 | @EventListener(LogEvent.class)
24 | public void saveLog(LogEvent event) {
25 | SysLog sysLog = (SysLog) event.getSource();
26 | sysLogService.add(sysLog);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/log/exception/GlobalExceptionTranslator.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.log.exception;
2 |
3 | import cn.tycoding.boot.common.auth.props.AuthProperties;
4 | import cn.tycoding.boot.common.auth.utils.AuthUtil;
5 | import cn.tycoding.boot.common.core.api.HttpCode;
6 | import cn.tycoding.boot.common.core.api.R;
7 | import cn.tycoding.boot.common.log.utils.SysLogUtil;
8 | import cn.tycoding.boot.modules.auth.exception.TumoAuth2Exception;
9 | import io.lettuce.core.RedisConnectionException;
10 | import lombok.RequiredArgsConstructor;
11 | import lombok.extern.slf4j.Slf4j;
12 | import org.springframework.data.redis.RedisConnectionFailureException;
13 | import org.springframework.http.HttpStatus;
14 | import org.springframework.security.access.AccessDeniedException;
15 | import org.springframework.web.bind.annotation.ExceptionHandler;
16 | import org.springframework.web.bind.annotation.ResponseStatus;
17 | import org.springframework.web.bind.annotation.RestControllerAdvice;
18 | import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
19 |
20 | /**
21 | * 全局异常拦截(注意:这种方式只能拦截经过Controller的异常,未经过Controller的异常拦截不到)
22 | *
23 | * @author tycoding
24 | * @since 2021/5/21
25 | */
26 | @Slf4j
27 | @RequiredArgsConstructor
28 | @RestControllerAdvice
29 | public class GlobalExceptionTranslator {
30 |
31 | private final AuthProperties authProperties;
32 |
33 | @ExceptionHandler({ServiceException.class})
34 | @ResponseStatus(HttpStatus.BAD_REQUEST)
35 | public R handleError(ServiceException e) {
36 | log.error("----------业务异常----------");
37 | e.printStackTrace();
38 | SysLogUtil.publish(SysLogUtil.TYPE_FAIL, "业务异常");
39 | return R.fail(e.getHttpCode().getCode(), e.getMessage());
40 | }
41 |
42 | @ExceptionHandler({AccessDeniedException.class})
43 | @ResponseStatus(HttpStatus.FORBIDDEN)
44 | public R handleError(AccessDeniedException e) {
45 | log.error("----------没有访问权限----------");
46 | e.printStackTrace();
47 | if (authProperties.getIsDemoEnv() && AuthUtil.getRoleNames().contains(AuthUtil.DEMO_ENV)) {
48 | SysLogUtil.publish(SysLogUtil.TYPE_FAIL, "演示环境,请勿操作!");
49 | return R.fail(HttpCode.FORBIDDEN.getCode(), "演示环境,请勿操作!");
50 | }
51 | SysLogUtil.publish(SysLogUtil.TYPE_FAIL, "没有访问权限");
52 | return R.fail(HttpCode.FORBIDDEN);
53 | }
54 |
55 | @ExceptionHandler({TumoAuth2Exception.class})
56 | @ResponseStatus(HttpStatus.UNAUTHORIZED)
57 | public R handleError(TumoAuth2Exception e) {
58 | log.error("----------认证异常----------");
59 | e.printStackTrace();
60 | SysLogUtil.publish(SysLogUtil.TYPE_FAIL, "认证异常");
61 | return R.fail(e);
62 | }
63 |
64 | @ExceptionHandler({RedisConnectionFailureException.class, RedisConnectionException.class})
65 | @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
66 | public R handleError(RedisConnectionFailureException e) {
67 | log.error("----------Redis连接异常----------");
68 | SysLogUtil.publish(SysLogUtil.TYPE_FAIL, "Redis连接异常");
69 | return R.fail("Redis连接异常");
70 | }
71 |
72 | @ExceptionHandler({Exception.class})
73 | @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
74 | public R handleError(Exception e) {
75 | log.error("----------服务器异常----------");
76 | e.printStackTrace();
77 | SysLogUtil.publish(SysLogUtil.TYPE_FAIL, "服务器异常");
78 | return R.fail(e);
79 | }
80 |
81 | @ExceptionHandler({MethodArgumentTypeMismatchException.class})
82 | @ResponseStatus(HttpStatus.BAD_REQUEST)
83 | public R handleError(MethodArgumentTypeMismatchException e) {
84 | log.error("----------参数类型不匹配异常----------");
85 | e.printStackTrace();
86 | return R.fail(e);
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/log/exception/RestExceptionTranslator.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.log.exception;
2 |
3 | import cn.tycoding.boot.common.core.api.HttpCode;
4 | import cn.tycoding.boot.common.core.api.R;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
7 | import org.springframework.context.annotation.Configuration;
8 | import org.springframework.http.HttpStatus;
9 | import org.springframework.web.bind.annotation.ExceptionHandler;
10 | import org.springframework.web.bind.annotation.ResponseStatus;
11 | import org.springframework.web.bind.annotation.RestControllerAdvice;
12 | import org.springframework.web.servlet.DispatcherServlet;
13 | import org.springframework.web.servlet.NoHandlerFoundException;
14 |
15 | import javax.servlet.Servlet;
16 |
17 | /**
18 | * 自定义Rest请求异常
19 | *
20 | * @author tycoding
21 | * @since 2021/5/21
22 | */
23 | @Slf4j
24 | @Configuration
25 | @ConditionalOnClass({Servlet.class, DispatcherServlet.class})
26 | @RestControllerAdvice
27 | public class RestExceptionTranslator {
28 |
29 | public RestExceptionTranslator() {
30 | }
31 |
32 | @ExceptionHandler({NoHandlerFoundException.class})
33 | @ResponseStatus(HttpStatus.NOT_FOUND)
34 | public R handleError(NoHandlerFoundException e) {
35 | log.error(HttpCode.NOT_FOUND.getMsg(), e.getMessage());
36 | return R.fail(HttpCode.NOT_FOUND);
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/log/exception/ServiceException.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.log.exception;
2 |
3 | import cn.tycoding.boot.common.core.api.HttpCode;
4 | import lombok.Getter;
5 |
6 | /**
7 | * 自定义异常
8 | *
9 | * @author tycoding
10 | * @since 2021/6/10
11 | */
12 | public class ServiceException extends RuntimeException {
13 | private static final long serialVersionUID = -1068765335343416833L;
14 |
15 | @Getter
16 | private final HttpCode httpCode;
17 |
18 | public ServiceException(String message) {
19 | super(message);
20 | this.httpCode = HttpCode.FAILURE;
21 | }
22 |
23 | public ServiceException(HttpCode httpCode) {
24 | this.httpCode = httpCode;
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/log/props/LogProperties.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.log.props;
2 |
3 | import lombok.Data;
4 | import org.springframework.boot.context.properties.ConfigurationProperties;
5 |
6 | /**
7 | * 自定义Log模块 YML配置映射实体
8 | *
9 | * @author tycoding
10 | * @since 2021/5/21
11 | */
12 | @Data
13 | @ConfigurationProperties("tumo-boot.log")
14 | public class LogProperties {
15 |
16 | /**
17 | * 是否打印API请求日志
18 | */
19 | private Boolean enable;
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/log/utils/SpringContextHolder.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.log.utils;
2 |
3 | import org.springframework.beans.BeansException;
4 | import org.springframework.context.ApplicationContext;
5 | import org.springframework.context.ApplicationContextAware;
6 | import org.springframework.context.ApplicationEvent;
7 | import org.springframework.stereotype.Service;
8 |
9 | /**
10 | * 自定义Spring事件监听
11 | *
12 | * @author tycoding
13 | * @since 2021/5/21
14 | */
15 | @Service
16 | public class SpringContextHolder implements ApplicationContextAware {
17 |
18 | private static ApplicationContext applicationContext = null;
19 |
20 | @Override
21 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
22 | SpringContextHolder.applicationContext = applicationContext;
23 | }
24 |
25 | public static void publishEvent(ApplicationEvent event) {
26 | if (applicationContext == null) {
27 | return;
28 | }
29 | applicationContext.publishEvent(event);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/log/utils/SysLogUtil.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.log.utils;
2 |
3 | import cn.hutool.core.util.URLUtil;
4 | import cn.hutool.extra.servlet.ServletUtil;
5 | import cn.hutool.http.HttpUtil;
6 | import cn.tycoding.boot.common.auth.utils.AuthUtil;
7 | import cn.tycoding.boot.common.log.event.LogEvent;
8 | import cn.tycoding.boot.modules.system.entity.SysLog;
9 | import lombok.SneakyThrows;
10 | import org.springframework.web.context.request.RequestContextHolder;
11 | import org.springframework.web.context.request.ServletRequestAttributes;
12 |
13 | import javax.servlet.http.HttpServletRequest;
14 | import java.util.Date;
15 | import java.util.Objects;
16 |
17 | /**
18 | * 构建Log实体类信息
19 | *
20 | * @author tycoding
21 | * @since 2021/5/21
22 | */
23 | public class SysLogUtil {
24 |
25 | /**
26 | * 字典表类型标识
27 | */
28 | public static final String DICT_TYPE = "sys_type";
29 | /**
30 | * 成功日志类型
31 | */
32 | public static final int TYPE_OK = 1;
33 | /**
34 | * 错误日志类型
35 | */
36 | public static final int TYPE_FAIL = 2;
37 |
38 | /**
39 | * 构建日志Log类信息
40 | *
41 | * @param type 日志类型
42 | * @param operation 日志描述
43 | * @param method 操作方法
44 | * @param time 耗时
45 | * @return Log类
46 | */
47 | @SneakyThrows
48 | public static SysLog build(Integer type, String operation, String method, Long time) {
49 | HttpServletRequest request = ((ServletRequestAttributes)
50 | Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
51 |
52 | return new SysLog()
53 | .setType(type)
54 | .setUsername(AuthUtil.getUsername())
55 | .setOperation(operation)
56 | .setCreateTime(new Date())
57 | .setIp(ServletUtil.getClientIP(request))
58 | .setUrl(URLUtil.getPath(request.getRequestURI()))
59 | .setMethod(method)
60 | .setParams(HttpUtil.toParams(request.getParameterMap()))
61 | .setUserAgent(request.getHeader("user-agent"))
62 | .setTime(time);
63 | }
64 |
65 | /**
66 | * Spring事件发布:发布日志,写入到数据库
67 | *
68 | * @param type 日志类型
69 | * @param operation 描述
70 | */
71 | public static void publish(int type, String operation) {
72 | SysLog sysLog = SysLogUtil.build(type, operation, null, null);
73 | SpringContextHolder.publishEvent(new LogEvent(sysLog));
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/mybatis/MybatisAutoConfiguration.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.mybatis;
2 |
3 | import cn.tycoding.boot.common.mybatis.props.MybatisProperties;
4 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
5 | import org.springframework.context.annotation.Configuration;
6 | import org.springframework.core.annotation.Order;
7 |
8 | /**
9 | * Mybatis配置注入
10 | *
11 | * @author tycoding
12 | * @since 2021/5/21
13 | */
14 | @Order
15 | @Configuration
16 | @EnableConfigurationProperties({MybatisProperties.class})
17 | public class MybatisAutoConfiguration {
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/mybatis/config/MybatisPlusConfig.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.mybatis.config;
2 |
3 | import cn.tycoding.boot.common.mybatis.intercept.SqlLogInterceptor;
4 | import com.baomidou.mybatisplus.annotation.DbType;
5 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
6 | import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
7 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
8 | import org.springframework.context.annotation.Bean;
9 | import org.springframework.context.annotation.Configuration;
10 |
11 | /**
12 | * MybatisPlus插件配置
13 | *
14 | * @author tycoding
15 | * @since 2021/5/21
16 | */
17 | @Configuration
18 | public class MybatisPlusConfig {
19 |
20 | /**
21 | * 分页插件
22 | */
23 | @Bean
24 | public MybatisPlusInterceptor mybatisPlusInterceptor() {
25 | MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
26 | interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
27 | return interceptor;
28 | }
29 |
30 | /**
31 | * SQL 日志打印
32 | */
33 | @Bean
34 | @ConditionalOnProperty(value = {"tumo-boot.mybatis.enable"}, matchIfMissing = true)
35 | public SqlLogInterceptor sqlLogInterceptor() {
36 | return new SqlLogInterceptor();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/mybatis/constant/MybatisConstant.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.mybatis.constant;
2 |
3 | /**
4 | * 针对MybatisPlus的常量
5 | *
6 | * @author tycoding
7 | * @since 2021/5/21
8 | */
9 | public interface MybatisConstant {
10 |
11 | /**
12 | * 分页结果集中承载分页数据的属性名
13 | */
14 | String PAGE_ROWS = "rows";
15 |
16 | /**
17 | * 分页结果集中总数量total名称
18 | */
19 | String PAGE_TOTAL = "total";
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/mybatis/intercept/SqlLogInterceptor.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.mybatis.intercept;
2 |
3 | import cn.hutool.core.text.StrFormatter;
4 | import cn.hutool.core.util.StrUtil;
5 | import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
6 | import com.baomidou.mybatisplus.core.toolkit.SystemClock;
7 | import org.apache.ibatis.executor.statement.StatementHandler;
8 | import org.apache.ibatis.mapping.MappedStatement;
9 | import org.apache.ibatis.plugin.Interceptor;
10 | import org.apache.ibatis.plugin.Intercepts;
11 | import org.apache.ibatis.plugin.Invocation;
12 | import org.apache.ibatis.plugin.Signature;
13 | import org.apache.ibatis.reflection.MetaObject;
14 | import org.apache.ibatis.reflection.SystemMetaObject;
15 | import org.apache.ibatis.session.ResultHandler;
16 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
17 |
18 | import java.lang.reflect.Method;
19 | import java.lang.reflect.Proxy;
20 | import java.sql.Statement;
21 |
22 | /**
23 | * SQL 拦截
24 | *
25 | * @author tycoding
26 | * @since 2021/5/21
27 | */
28 | @Intercepts({@Signature(
29 | type = StatementHandler.class,
30 | method = "query",
31 | args = {Statement.class, ResultHandler.class}
32 | )})
33 | public class SqlLogInterceptor implements Interceptor {
34 |
35 | private Method druidGetSqlMethod;
36 |
37 | @Override
38 | public Object intercept(Invocation invocation) throws Throwable {
39 | Object firstArg = invocation.getArgs()[0];
40 | Statement statement;
41 | if (Proxy.isProxyClass(firstArg.getClass())) {
42 | statement = (Statement) SystemMetaObject.forObject(firstArg).getValue("h.statement");
43 | } else {
44 | statement = (Statement) firstArg;
45 | }
46 |
47 | String originalSql = null;
48 | String stmtClassName = statement.getClass().getName();
49 | Class clazz;
50 | Object stmtSql;
51 | if ("com.alibaba.druid.pool.DruidPooledPreparedStatement".equals(stmtClassName)) {
52 | try {
53 | if (this.druidGetSqlMethod == null) {
54 | clazz = Class.forName("com.alibaba.druid.pool.DruidPooledPreparedStatement");
55 | this.druidGetSqlMethod = clazz.getMethod("getSql");
56 | }
57 |
58 | stmtSql = this.druidGetSqlMethod.invoke(statement);
59 | if (stmtSql instanceof String) {
60 | originalSql = (String) stmtSql;
61 | }
62 | } catch (Exception e) {
63 | e.printStackTrace();
64 | }
65 | }
66 |
67 | if (originalSql == null) {
68 | originalSql = statement.toString();
69 | }
70 |
71 | long start = SystemClock.now();
72 | Object result = invocation.proceed();
73 | long timing = SystemClock.now() - start;
74 | Object target = PluginUtils.realTarget(invocation.getTarget());
75 | MetaObject metaObject = SystemMetaObject.forObject(target);
76 | MappedStatement ms = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
77 | System.err.println(StrFormatter.format("\n============== Sql Start ==============\nExecute ID :{}\nExecute SQL :{}\nExecute Time:{} ms\n============== Sql End ==============\n", ms.getId(), StrUtil.replaceChars(originalSql, "\n", " "), timing));
78 | return result;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/mybatis/props/MybatisProperties.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.mybatis.props;
2 |
3 | import lombok.Data;
4 | import org.springframework.boot.context.properties.ConfigurationProperties;
5 |
6 | /**
7 | * 自定义Mybatis模块 YML配置映射实体
8 | *
9 | * @author tycoding
10 | * @since 2021/5/21
11 | */
12 | @Data
13 | @ConfigurationProperties("tumo-boot.mybatis")
14 | public class MybatisProperties {
15 |
16 | /**
17 | * 是否打印Mybatis SQL日志
18 | */
19 | private Boolean enable;
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/mybatis/utils/MybatisUtil.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.mybatis.utils;
2 |
3 | import cn.hutool.core.lang.Dict;
4 | import cn.tycoding.boot.common.core.api.QueryPage;
5 | import cn.tycoding.boot.common.mybatis.constant.MybatisConstant;
6 | import com.baomidou.mybatisplus.core.metadata.IPage;
7 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
8 |
9 | /**
10 | * Mybatis 工具类
11 | *
12 | * @author tycoding
13 | * @since 2021/5/21
14 | */
15 | public class MybatisUtil {
16 |
17 | /**
18 | * 分页查询:格式化响应数据结构
19 | *
20 | * @param page 分页数据
21 | * @return 格式化后的Map对象
22 | */
23 | public static Dict getData(IPage> page) {
24 | return Dict.create().set(MybatisConstant.PAGE_ROWS, page.getRecords())
25 | .set(MybatisConstant.PAGE_TOTAL, (int) page.getTotal());
26 | }
27 |
28 | /**
29 | * QueryPage对象转换为Page对象
30 | */
31 | public static IPage wrap(T t, QueryPage query) {
32 | return new Page(query.getPage(), query.getLimit());
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/oss/OssAutoConfiguration.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.oss;
2 |
3 | import cn.tycoding.boot.common.oss.props.LocalFileProperties;
4 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
5 | import org.springframework.context.annotation.Configuration;
6 | import org.springframework.core.annotation.Order;
7 |
8 | /**
9 | * Oss配置注入
10 | *
11 | * @author tycoding
12 | * @since 2021/5/21
13 | */
14 | @Order
15 | @Configuration
16 | @EnableConfigurationProperties({LocalFileProperties.class})
17 | public class OssAutoConfiguration {
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/oss/props/LocalFileProperties.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.oss.props;
2 |
3 | import lombok.Data;
4 | import org.springframework.boot.context.properties.ConfigurationProperties;
5 |
6 | /**
7 | * 本地文件上传配置
8 | *
9 | * @author tycoding
10 | * @since 2021/6/3
11 | */
12 | @Data
13 | @ConfigurationProperties("tumo-boot.file")
14 | public class LocalFileProperties {
15 |
16 | /**
17 | * 文件上传地址
18 | */
19 | private String uploadPath = System.getProperty("user.dir") + "/target/classes/static/upload";
20 |
21 | /**
22 | * 文件访问地址
23 | */
24 | private String remotePath = "http://127.0.0.1:8090/upload";
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/oss/utils/OssUtil.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.oss.utils;
2 |
3 | import cn.hutool.core.date.DatePattern;
4 | import cn.hutool.core.date.DateUtil;
5 | import cn.hutool.core.io.FileUtil;
6 | import cn.hutool.core.util.URLUtil;
7 | import com.baomidou.mybatisplus.core.toolkit.IdWorker;
8 |
9 | import java.util.Date;
10 |
11 | /**
12 | * Oss工具类
13 | *
14 | * @author tycoding
15 | * @since 2021/6/3
16 | */
17 | public class OssUtil {
18 |
19 | /**
20 | * 获取Bucket文件夹名称
21 | *
22 | * @return 根据日期格式化的文件夹名称
23 | */
24 | public static String getBucket() {
25 | return "/" + DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN);
26 | }
27 |
28 | /**
29 | * 根据随机值组建文件名称
30 | *
31 | * @param originFile 原始文件名称
32 | * @return 通过雪花算法获取新文件名称
33 | */
34 | public static String getName(String originFile) {
35 | String suffix = FileUtil.getSuffix(originFile);
36 | return IdWorker.getIdStr() + "." + suffix;
37 | }
38 |
39 | /**
40 | * 获取文件访问URL地址
41 | *
42 | * @param url 文件上传服务地址
43 | * @param bucket Bucket文件夹路径
44 | * @param fileName 新文件名称
45 | * @return 拼接后的文件访问地址
46 | */
47 | public static String getUrl(String url, String bucket, String fileName) {
48 | if (url.endsWith("/")) {
49 | url = url.substring(0, url.length() - 1);
50 | }
51 | return URLUtil.normalize(url + bucket + "/" + fileName);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/redis/component/RedisComponent.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.redis.component;
2 |
3 | import lombok.RequiredArgsConstructor;
4 | import org.springframework.cache.annotation.EnableCaching;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.data.redis.connection.RedisConnectionFactory;
7 | import org.springframework.data.redis.core.RedisTemplate;
8 | import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
9 | import org.springframework.data.redis.serializer.StringRedisSerializer;
10 | import org.springframework.stereotype.Component;
11 |
12 | /**
13 | * 自定义Redis配置
14 | *
15 | * @author tycoding
16 | * @since 2021/5/21
17 | */
18 | @Component
19 | @EnableCaching
20 | @RequiredArgsConstructor
21 | public class RedisComponent {
22 |
23 | private final RedisConnectionFactory connectionFactory;
24 |
25 | @Bean(name = {"redisTemplate"})
26 | public RedisTemplate redisTemplate() {
27 | RedisTemplate redisTemplate = new RedisTemplate<>();
28 | redisTemplate.setKeySerializer(new StringRedisSerializer());
29 | redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
30 | redisTemplate.setConnectionFactory(connectionFactory);
31 | return redisTemplate;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/redis/utils/RedisUtil.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.redis.utils;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.data.redis.core.ConvertingCursor;
5 | import org.springframework.data.redis.core.Cursor;
6 | import org.springframework.data.redis.core.RedisTemplate;
7 | import org.springframework.data.redis.core.ScanOptions;
8 | import org.springframework.data.redis.serializer.RedisSerializer;
9 |
10 | import java.util.ArrayList;
11 | import java.util.List;
12 | import java.util.UUID;
13 |
14 | /**
15 | * Redis工具类
16 | *
17 | * @author tycoding
18 | * @since 2021/5/21
19 | */
20 | @Slf4j
21 | public class RedisUtil {
22 |
23 | /**
24 | * 获取随机Key
25 | *
26 | * @return 随机字符串值
27 | */
28 | public static String getKey() {
29 | return UUID.randomUUID().toString();
30 | }
31 |
32 | /**
33 | * 根据指定Key前缀分页查询Key列表
34 | *
35 | * @param redisTemplate RedisTemplate对象
36 | * @param patternKey 指定前缀规则的Key
37 | * @param page 页码
38 | * @param limit 每页多少条
39 | * @return 分页后的列表
40 | */
41 | public static List getKeysPage(RedisTemplate redisTemplate, String patternKey, int page, int limit) {
42 | List list = new ArrayList<>();
43 | ScanOptions options = ScanOptions.scanOptions().count(1000).match(patternKey).build();
44 | RedisSerializer redisSerializer = redisTemplate.getKeySerializer();
45 |
46 | Cursor cursor = (Cursor) redisTemplate.executeWithStickyConnection(redisConnection ->
47 | new ConvertingCursor<>(redisConnection.scan(options), redisSerializer::deserialize));
48 |
49 | if (cursor == null) {
50 | return list;
51 | }
52 |
53 | int flagIndex = 0;
54 | int startIndex = (page - 1) * limit;
55 | int endIndex = page * limit;
56 | while (cursor.hasNext()) {
57 | if (flagIndex >= startIndex && flagIndex < endIndex) {
58 | list.add(cursor.next().toString());
59 | flagIndex++;
60 | continue;
61 | }
62 | if (flagIndex >= endIndex) {
63 | break;
64 | }
65 | flagIndex++;
66 | cursor.next();
67 | }
68 | cursor.close();
69 | return list;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/common/redis/utils/TokenInfo.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.common.redis.utils;
2 |
3 | import lombok.Data;
4 | import org.springframework.security.oauth2.common.OAuth2RefreshToken;
5 |
6 | import java.io.Serializable;
7 | import java.util.Date;
8 | import java.util.Set;
9 |
10 | /**
11 | * 对Redis中Token信息的扩展封装
12 | *
13 | * @author tycoding
14 | * @see org.springframework.security.oauth2.common.DefaultOAuth2AccessToken
15 | * @since 2021/6/12
16 | */
17 | @Data
18 | public class TokenInfo implements Serializable {
19 | private static final long serialVersionUID = -1331900349298552602L;
20 |
21 | /**
22 | * Token值
23 | */
24 | private String value;
25 |
26 | /**
27 | * 过期时间
28 | */
29 | private Date expiration;
30 |
31 | /**
32 | * Token类型
33 | */
34 | private String tokenType;
35 |
36 | /**
37 | * 刷新Token
38 | */
39 | private OAuth2RefreshToken refreshToken;
40 |
41 | /**
42 | * Scope
43 | */
44 | private Set scope;
45 |
46 | /**
47 | * 用户信息
48 | */
49 | private Object principal;
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/auth/component/ResourceAuthExceptionEntryPoint.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.auth.component;
2 |
3 | import cn.hutool.core.util.URLUtil;
4 | import cn.tycoding.boot.common.log.utils.SpringContextHolder;
5 | import cn.tycoding.boot.common.core.api.HttpCode;
6 | import cn.tycoding.boot.common.core.api.R;
7 | import cn.tycoding.boot.common.core.constant.CommonConstant;
8 | import cn.tycoding.boot.common.log.event.LogEvent;
9 | import cn.tycoding.boot.common.log.utils.SysLogUtil;
10 | import cn.tycoding.boot.modules.system.entity.SysLog;
11 | import com.fasterxml.jackson.databind.ObjectMapper;
12 | import lombok.RequiredArgsConstructor;
13 | import lombok.extern.slf4j.Slf4j;
14 | import org.springframework.security.core.AuthenticationException;
15 | import org.springframework.security.web.AuthenticationEntryPoint;
16 | import org.springframework.stereotype.Component;
17 |
18 | import javax.servlet.ServletException;
19 | import javax.servlet.http.HttpServletRequest;
20 | import javax.servlet.http.HttpServletResponse;
21 | import java.io.IOException;
22 | import java.io.PrintWriter;
23 |
24 | /**
25 | * 自定义资源服务器未授权异常
26 | *
27 | * @author tycoding
28 | * @since 2021/5/21
29 | */
30 | @Slf4j
31 | @Component
32 | @RequiredArgsConstructor
33 | public class ResourceAuthExceptionEntryPoint implements AuthenticationEntryPoint {
34 |
35 | private final ObjectMapper objectMapper;
36 |
37 | @Override
38 | public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
39 | response.setStatus(HttpCode.UN_AUTHORIZED.getCode());
40 | response.setCharacterEncoding(CommonConstant.UTF_8);
41 | response.setContentType(CommonConstant.CONTENT_TYPE);
42 | PrintWriter writer = response.getWriter();
43 | R result = new R<>();
44 | result.setCode(HttpCode.UN_AUTHORIZED.getCode());
45 | result.setMsg(HttpCode.UN_AUTHORIZED.getMsg());
46 | log.error(HttpCode.UN_AUTHORIZED.getMsg() + ", URL: {}", URLUtil.getPath(request.getRequestURI()));
47 | writer.append(objectMapper.writeValueAsString(result));
48 |
49 | SysLog sysLog = SysLogUtil.build(SysLogUtil.TYPE_FAIL, HttpCode.UN_AUTHORIZED.getMsg(), null, null);
50 | SpringContextHolder.publishEvent(new LogEvent(sysLog));
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/auth/component/TumoAuth2ExceptionSerializer.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.auth.component;
2 |
3 | import cn.tycoding.boot.modules.auth.exception.TumoAuth2Exception;
4 | import com.fasterxml.jackson.core.JsonGenerator;
5 | import com.fasterxml.jackson.databind.SerializerProvider;
6 | import com.fasterxml.jackson.databind.ser.std.StdSerializer;
7 |
8 | import java.io.IOException;
9 |
10 | /**
11 | * 自定义Oauth2异常响应格式
12 | *
13 | * @author tycoding
14 | * @see org.springframework.security.oauth2.common.exceptions.OAuth2ExceptionJackson2Serializer
15 | * @since 2021/5/21
16 | */
17 | public class TumoAuth2ExceptionSerializer extends StdSerializer {
18 | private static final long serialVersionUID = 2241320471807860252L;
19 |
20 | protected TumoAuth2ExceptionSerializer() {
21 | super(TumoAuth2Exception.class);
22 | }
23 |
24 | @Override
25 | public void serialize(TumoAuth2Exception e, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
26 | jsonGenerator.writeStartObject();
27 | jsonGenerator.writeNumberField("code", e.getHttpErrorCode());
28 | jsonGenerator.writeStringField("msg", e.getMessage());
29 | jsonGenerator.writeStringField("data", null);
30 | jsonGenerator.writeEndObject();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/auth/component/TumoWebResponseExceptionTranslator.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.auth.component;
2 |
3 | import cn.tycoding.boot.common.core.api.HttpCode;
4 | import cn.tycoding.boot.modules.auth.exception.*;
5 | import org.springframework.http.HttpHeaders;
6 | import org.springframework.http.HttpStatus;
7 | import org.springframework.http.ResponseEntity;
8 | import org.springframework.security.access.AccessDeniedException;
9 | import org.springframework.security.core.AuthenticationException;
10 | import org.springframework.security.oauth2.common.DefaultThrowableAnalyzer;
11 | import org.springframework.security.oauth2.common.exceptions.InsufficientScopeException;
12 | import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
13 | import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
14 | import org.springframework.security.web.util.ThrowableAnalyzer;
15 | import org.springframework.web.HttpRequestMethodNotSupportedException;
16 |
17 | import java.io.IOException;
18 |
19 | /**
20 | * 重写Oauth2异常处理器
21 | *
22 | * @author tycoding
23 | * @since 2021/5/21
24 | */
25 | public class TumoWebResponseExceptionTranslator implements WebResponseExceptionTranslator {
26 |
27 | private ThrowableAnalyzer throwableAnalyzer = new DefaultThrowableAnalyzer();
28 |
29 | /**
30 | * @author tycoding
31 | * @see org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator
32 | * @since 2020/10/16
33 | */
34 | @Override
35 | public ResponseEntity translate(Exception e) throws Exception {
36 | Throwable[] causeChain = this.throwableAnalyzer.determineCauseChain(e);
37 |
38 | // 请求未授权
39 | Exception ase = (AuthenticationException) this.throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class, causeChain);
40 | if (ase != null) {
41 | return this.handleOAuth2Exception(new UnauthorizedException(e.getMessage(), e));
42 | }
43 |
44 | // 拒绝访问异常
45 | ase = (AccessDeniedException) this.throwableAnalyzer.getFirstThrowableOfType(AccessDeniedException.class, causeChain);
46 | if (ase != null) {
47 | return this.handleOAuth2Exception(new ForbiddenException(ase.getMessage(), ase));
48 | }
49 |
50 | // Token失效异常
51 | ase = (org.springframework.security.oauth2.common.exceptions.InvalidGrantException) throwableAnalyzer.getFirstThrowableOfType(org.springframework.security.oauth2.common.exceptions.InvalidGrantException.class, causeChain);
52 | if (ase != null) {
53 | return handleOAuth2Exception(new InvalidGrantException(ase.getMessage(), ase));
54 | }
55 |
56 | // 请求方法不支持异常
57 | ase = (HttpRequestMethodNotSupportedException) throwableAnalyzer.getFirstThrowableOfType(HttpRequestMethodNotSupportedException.class, causeChain);
58 | if (ase != null) {
59 | return handleOAuth2Exception(new MethodNotAllowedException(ase.getMessage(), ase));
60 | }
61 |
62 | // OAuth2Exception异常
63 | ase = (OAuth2Exception) throwableAnalyzer.getFirstThrowableOfType(OAuth2Exception.class, causeChain);
64 | if (ase != null) {
65 | return this.handleOAuth2Exception((OAuth2Exception) ase);
66 | }
67 |
68 | return handleOAuth2Exception(new ServerErrorException(HttpCode.INTERNAL_SERVER_ERROR.getMsg(), e));
69 | }
70 |
71 | private ResponseEntity handleOAuth2Exception(OAuth2Exception e) throws IOException {
72 | int code = e.getHttpErrorCode();
73 | HttpHeaders headers = new HttpHeaders();
74 | headers.set("Cache-Control", "no-store");
75 | headers.set("Pragma", "no-cache");
76 | if (code == HttpStatus.UNAUTHORIZED.value() || e instanceof InsufficientScopeException) {
77 | headers.set("WWW-Authenticate", String.format("%s %s", "Bearer", e.getSummary()));
78 | }
79 | TumoAuth2Exception auth2Exception = new TumoAuth2Exception(e.getMessage(), e.getCause(), code);
80 | return new ResponseEntity<>(auth2Exception, headers, HttpStatus.valueOf(code));
81 | }
82 |
83 | private static class UnauthorizedException extends TumoAuth2Exception {
84 |
85 | public UnauthorizedException(String msg, Throwable t) {
86 | super(msg);
87 | }
88 |
89 | @Override
90 | public String getOAuth2ErrorCode() {
91 | return HttpCode.UN_AUTHORIZED.getMsg();
92 | }
93 |
94 | @Override
95 | public int getHttpErrorCode() {
96 | return HttpCode.UN_AUTHORIZED.getCode();
97 | }
98 | }
99 |
100 | private static class ForbiddenException extends TumoAuth2Exception {
101 |
102 | public ForbiddenException(String msg, Throwable t) {
103 | super(msg);
104 | }
105 |
106 | @Override
107 | public String getOAuth2ErrorCode() {
108 | return HttpCode.FORBIDDEN.getMsg();
109 | }
110 |
111 | @Override
112 | public int getHttpErrorCode() {
113 | return HttpCode.FORBIDDEN.getCode();
114 | }
115 | }
116 |
117 | private static class InvalidGrantException extends TumoAuth2Exception {
118 |
119 | public InvalidGrantException(String msg, Throwable e) {
120 | super(msg);
121 | }
122 |
123 | @Override
124 | public String getOAuth2ErrorCode() {
125 | return HttpCode.INVALID_GRANT.getMsg();
126 | }
127 |
128 | @Override
129 | public int getHttpErrorCode() {
130 | return HttpCode.INVALID_GRANT.getCode();
131 | }
132 | }
133 |
134 | private static class ServerErrorException extends TumoAuth2Exception {
135 |
136 | public ServerErrorException(String msg, Throwable t) {
137 | super(msg);
138 | }
139 |
140 | @Override
141 | public String getOAuth2ErrorCode() {
142 | return HttpCode.INTERNAL_SERVER_ERROR.getMsg();
143 | }
144 |
145 | @Override
146 | public int getHttpErrorCode() {
147 | return HttpCode.INTERNAL_SERVER_ERROR.getCode();
148 | }
149 | }
150 |
151 | private static class MethodNotAllowedException extends TumoAuth2Exception {
152 |
153 | public MethodNotAllowedException(String msg, Throwable e) {
154 | super(msg);
155 | }
156 |
157 | @Override
158 | public String getOAuth2ErrorCode() {
159 | return HttpCode.METHOD_NOT_SUPPORTED.getMsg();
160 | }
161 |
162 | @Override
163 | public int getHttpErrorCode() {
164 | return HttpCode.METHOD_NOT_SUPPORTED.getCode();
165 | }
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/auth/config/AuthorizationServerConfig.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.auth.config;
2 |
3 | import cn.tycoding.boot.common.core.constant.ApiConstant;
4 | import cn.tycoding.boot.common.core.constant.CacheConstant;
5 | import cn.tycoding.boot.modules.auth.component.TumoWebResponseExceptionTranslator;
6 | import lombok.RequiredArgsConstructor;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 | import org.springframework.data.redis.connection.RedisConnectionFactory;
10 | import org.springframework.http.HttpMethod;
11 | import org.springframework.security.authentication.AuthenticationManager;
12 | import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
13 | import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
14 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
15 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
16 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
17 | import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
18 | import org.springframework.security.oauth2.provider.token.TokenStore;
19 | import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
20 |
21 | import javax.sql.DataSource;
22 |
23 | /**
24 | * Oauth2 认证服务器配置(负责Token层面处理)
25 | *
26 | * @author tycoding
27 | * @since 2021/5/21
28 | */
29 | @Configuration
30 | @RequiredArgsConstructor
31 | @EnableAuthorizationServer
32 | public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
33 |
34 | private final DataSource dataSource;
35 | private final RedisConnectionFactory redisConnectionFactory;
36 | private final AuthenticationManager authenticationManager;
37 |
38 | @Bean
39 | public TokenStore tokenStore() {
40 | RedisTokenStore tokenStore = new RedisTokenStore(redisConnectionFactory);
41 | tokenStore.setPrefix(CacheConstant.OAUTH_PREFIX);
42 | return tokenStore;
43 | }
44 |
45 | @Override
46 | public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
47 | clients.withClientDetails(new JdbcClientDetailsService(dataSource));
48 | }
49 |
50 | @Override
51 | public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
52 | endpoints
53 | .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
54 | .pathMapping("/oauth/token", ApiConstant.API_OAUTH_TOKEN)
55 | .tokenStore(tokenStore())
56 | .authenticationManager(authenticationManager)
57 | .exceptionTranslator(new TumoWebResponseExceptionTranslator());
58 | }
59 |
60 | @Override
61 | public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
62 | security
63 | .allowFormAuthenticationForClients()
64 | .checkTokenAccess("permitAll()");
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/auth/config/ResourceServerConfig.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.auth.config;
2 |
3 | import cn.tycoding.boot.common.auth.props.AuthProperties;
4 | import cn.tycoding.boot.modules.auth.component.ResourceAuthExceptionEntryPoint;
5 | import lombok.RequiredArgsConstructor;
6 | import org.springframework.context.annotation.Configuration;
7 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
9 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
10 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
11 | import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
12 |
13 | /**
14 | * Oauth2 资源服务器配置(负责传递Token后接口层面处理)
15 | *
16 | * @author tycoding
17 | * @since 2021/5/21
18 | */
19 | @Configuration
20 | @RequiredArgsConstructor
21 | @EnableResourceServer
22 | @EnableGlobalMethodSecurity(prePostEnabled = true)
23 | public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
24 | private final AuthProperties authProperties;
25 | private final ResourceAuthExceptionEntryPoint resourceAuthExceptionEntryPoint;
26 |
27 | @Override
28 | public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
29 | resources.authenticationEntryPoint(resourceAuthExceptionEntryPoint);
30 | }
31 |
32 | @Override
33 | public void configure(HttpSecurity http) throws Exception {
34 | http
35 | .authorizeRequests()
36 | .antMatchers(authProperties.getSkipUrl().toArray(new String[0]))
37 | .permitAll()
38 |
39 | .anyRequest()
40 | .authenticated()
41 |
42 | .and()
43 | .csrf().disable();
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/auth/config/WebSecurityConfig.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.auth.config;
2 |
3 | import cn.tycoding.boot.common.auth.filter.CaptchaFilter;
4 | import cn.tycoding.boot.modules.auth.service.UserDetailsServiceImpl;
5 | import lombok.RequiredArgsConstructor;
6 | import org.springframework.context.annotation.Bean;
7 | import org.springframework.context.annotation.Configuration;
8 | import org.springframework.security.authentication.AuthenticationManager;
9 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
10 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
11 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
12 | import org.springframework.security.core.userdetails.UserDetailsService;
13 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
14 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
15 |
16 | /**
17 | * 安全配置(配合Oauth2 授权服务器层面)
18 | *
19 | * @author tycoding
20 | * @since 2021/5/21
21 | */
22 | @Configuration
23 | @RequiredArgsConstructor
24 | public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
25 |
26 | private final CaptchaFilter captchaFilter;
27 |
28 | @Bean
29 | public BCryptPasswordEncoder passwordEncoder() {
30 | return new BCryptPasswordEncoder();
31 | }
32 |
33 | @Bean
34 | @Override
35 | protected AuthenticationManager authenticationManager() throws Exception {
36 | return super.authenticationManager();
37 | }
38 |
39 | @Bean
40 | @Override
41 | protected UserDetailsService userDetailsService() {
42 | return new UserDetailsServiceImpl();
43 | }
44 |
45 | @Override
46 | protected void configure(AuthenticationManagerBuilder auth) throws Exception {
47 | auth.userDetailsService(userDetailsService());
48 | }
49 |
50 | @Override
51 | protected void configure(HttpSecurity http) throws Exception {
52 | http
53 | .logout()
54 | .deleteCookies("JSESSIONID")
55 |
56 | .and()
57 | .authorizeRequests()
58 |
59 | .anyRequest()
60 | .authenticated()
61 |
62 | .and()
63 | .csrf().disable();
64 |
65 | http.addFilterBefore(captchaFilter, UsernamePasswordAuthenticationFilter.class);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/auth/dto/TumoUser.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.auth.dto;
2 |
3 | import lombok.Getter;
4 | import org.springframework.security.core.GrantedAuthority;
5 | import org.springframework.security.core.userdetails.User;
6 |
7 | import java.util.Collection;
8 |
9 | /**
10 | * 扩展SpringSecurity User属性
11 | *
12 | * @author tycoding
13 | * @since 2021/5/21
14 | */
15 | public class TumoUser extends User {
16 | private static final long serialVersionUID = -1462618142392426177L;
17 |
18 | @Getter
19 | private final Long id;
20 |
21 | @Getter
22 | private final Long deptId;
23 |
24 | public TumoUser(Long id, Long deptId, String username, String password, boolean enabled,
25 | boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked,
26 | Collection extends GrantedAuthority> authorities) {
27 | super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
28 | this.id = id;
29 | this.deptId = deptId;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/auth/dto/UserInfo.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.auth.dto;
2 |
3 | import cn.tycoding.boot.modules.upms.entity.SysDept;
4 | import cn.tycoding.boot.modules.upms.entity.SysRole;
5 | import cn.tycoding.boot.modules.upms.entity.SysUser;
6 | import lombok.Data;
7 | import lombok.experimental.Accessors;
8 |
9 | import java.io.Serializable;
10 | import java.util.List;
11 | import java.util.Set;
12 |
13 | /**
14 | * 自定义Oauth2 授权成功后存储的用户数据
15 | *
16 | * @author tycoding
17 | * @since 2021/5/21
18 | */
19 | @Data
20 | @Accessors(chain = true)
21 | public class UserInfo implements Serializable {
22 | private static final long serialVersionUID = 547891924677981054L;
23 |
24 | /**
25 | * 用户基本信息
26 | */
27 | private SysUser user;
28 |
29 | /**
30 | * 用户所属部门
31 | */
32 | private SysDept dept;
33 |
34 | /**
35 | * 用户角色列表
36 | */
37 | private List roles;
38 |
39 | /**
40 | * 用户权限标识
41 | */
42 | private Set perms;
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/auth/endpoint/AuthTokenEndpoint.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.auth.endpoint;
2 |
3 | import cn.hutool.captcha.CaptchaUtil;
4 | import cn.hutool.captcha.CircleCaptcha;
5 | import cn.hutool.core.lang.Dict;
6 | import cn.tycoding.boot.common.core.constant.ApiConstant;
7 | import cn.tycoding.boot.common.core.constant.CaptchaConstant;
8 | import cn.tycoding.boot.common.auth.utils.AuthUtil;
9 | import cn.tycoding.boot.common.core.api.QueryPage;
10 | import cn.tycoding.boot.common.core.api.R;
11 | import cn.tycoding.boot.common.core.constant.CacheConstant;
12 | import cn.tycoding.boot.common.core.utils.BeanUtil;
13 | import cn.tycoding.boot.common.mybatis.utils.MybatisUtil;
14 | import cn.tycoding.boot.common.redis.utils.RedisUtil;
15 | import cn.tycoding.boot.common.redis.utils.TokenInfo;
16 | import cn.tycoding.boot.modules.auth.dto.TumoUser;
17 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
18 | import lombok.RequiredArgsConstructor;
19 | import org.apache.commons.lang3.StringUtils;
20 | import org.springframework.cache.CacheManager;
21 | import org.springframework.data.redis.core.RedisTemplate;
22 | import org.springframework.http.HttpHeaders;
23 | import org.springframework.security.access.prepost.PreAuthorize;
24 | import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
25 | import org.springframework.security.oauth2.common.OAuth2AccessToken;
26 | import org.springframework.security.oauth2.provider.OAuth2Authentication;
27 | import org.springframework.security.oauth2.provider.token.TokenStore;
28 | import org.springframework.web.bind.annotation.*;
29 |
30 | import java.time.Duration;
31 | import java.util.List;
32 |
33 | /**
34 | * 自定义授权相关的接口
35 | *
36 | * @author tycoding
37 | * @since 2021/5/21
38 | */
39 | @RestController
40 | @RequiredArgsConstructor
41 | @RequestMapping(ApiConstant.API_AUTH_PREFIX)
42 | public class AuthTokenEndpoint {
43 |
44 | private final TokenStore tokenStore;
45 | private final RedisTemplate redisTemplate;
46 | private final CacheManager cacheManager;
47 |
48 | /**
49 | * 获取验证码
50 | */
51 | @GetMapping("/captcha")
52 | public R getCaptcha() {
53 | CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(CaptchaConstant.CAPTCHA_WIDTH, CaptchaConstant.CAPTCHA_HEIGHT, CaptchaConstant.CAPTCHA_COUNT, CaptchaConstant.CAPTCHA_CIRCLE_COUNT);
54 | String code = captcha.getCode().toLowerCase();
55 | String key = RedisUtil.getKey();
56 | redisTemplate.opsForValue().set(CacheConstant.CAPTCHA_PREFIX + key, code, Duration.ofMinutes(CaptchaConstant.CAPTCHA_TIMEOUT));
57 | return R.ok(Dict.create().set("key", key).set("image", captcha.getImageBase64()));
58 | }
59 |
60 | /**
61 | * 注销登录并清除Token
62 | */
63 | @DeleteMapping("/logout")
64 | public R logout(@RequestHeader(value = HttpHeaders.AUTHORIZATION, required = false) String token) {
65 | clear(AuthUtil.getToken(token));
66 | return R.ok();
67 | }
68 |
69 | private void clear(String token) {
70 | OAuth2AccessToken accessToken = tokenStore.readAccessToken(token);
71 | if (accessToken == null || StringUtils.isEmpty(accessToken.getValue())) {
72 | return;
73 | }
74 | OAuth2Authentication authentication = tokenStore.readAuthentication(accessToken);
75 | // 清空access_token
76 | tokenStore.removeAccessToken(accessToken);
77 | // 清空refresh_token
78 | tokenStore.removeRefreshToken(accessToken.getRefreshToken());
79 |
80 | // 清空User Details
81 | cacheManager.getCache(CacheConstant.USER_DETAIL_KEY).evict(authentication.getName());
82 | // 清空Menu Details
83 | TumoUser principal = (TumoUser) authentication.getPrincipal();
84 | cacheManager.getCache(CacheConstant.MENU_DETAIL_KEY).evict(principal.getId());
85 | }
86 |
87 | /**
88 | * 强制下线
89 | */
90 | @DeleteMapping("/token/{token}")
91 | @PreAuthorize("@auth.hasAuth('system:token:delete')")
92 | public R tokenDel(@PathVariable String token) {
93 | clear(token);
94 | return R.ok();
95 | }
96 |
97 | /**
98 | * 分页获取在线Token
99 | */
100 | @GetMapping("/token/page")
101 | public R tokenPage(QueryPage queryPage) {
102 | String key = String.format("%sauth_to_access:*", CacheConstant.OAUTH_PREFIX);
103 | List keysPage = RedisUtil.getKeysPage(redisTemplate, key, 1, 10);
104 | List list = redisTemplate.opsForValue().multiGet(keysPage);
105 | List tokenInfoList = BeanUtil.copy(list, TokenInfo.class);
106 |
107 | tokenInfoList.forEach(info -> {
108 | OAuth2Authentication authentication = tokenStore.readAuthentication(info.getValue());
109 | info.setPrincipal(authentication.getPrincipal());
110 | });
111 |
112 | int total = redisTemplate.keys(key).size();
113 | Page page = new Page(queryPage.getPage(), queryPage.getLimit(), total);
114 | page.setRecords(tokenInfoList);
115 | return R.ok(MybatisUtil.getData(page));
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/auth/exception/TumoAuth2Exception.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.auth.exception;
2 |
3 | import cn.tycoding.boot.modules.auth.component.TumoAuth2ExceptionSerializer;
4 | import com.fasterxml.jackson.databind.annotation.JsonSerialize;
5 | import lombok.Getter;
6 | import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
7 |
8 | /**
9 | * 重写 OAuth2 异常类
10 | *
11 | * @author tycoding
12 | * @since 2021/5/21
13 | */
14 | @JsonSerialize(using = TumoAuth2ExceptionSerializer.class)
15 | public class TumoAuth2Exception extends OAuth2Exception {
16 |
17 | @Getter
18 | private int code;
19 |
20 | public TumoAuth2Exception(String msg) {
21 | super(msg);
22 | }
23 |
24 | public TumoAuth2Exception(String msg, int code) {
25 | super(msg);
26 | this.code = code;
27 | }
28 |
29 | public TumoAuth2Exception(String msg, Throwable t, int code) {
30 | super(msg, t);
31 | this.code = code;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/auth/service/UserDetailsServiceImpl.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.auth.service;
2 |
3 | import cn.tycoding.boot.common.core.constant.AuthConstant;
4 | import cn.tycoding.boot.common.auth.utils.AuthUtil;
5 | import cn.tycoding.boot.common.core.constant.CacheConstant;
6 | import cn.tycoding.boot.modules.auth.dto.TumoUser;
7 | import cn.tycoding.boot.modules.auth.dto.UserInfo;
8 | import cn.tycoding.boot.modules.auth.exception.TumoAuth2Exception;
9 | import cn.tycoding.boot.modules.upms.entity.SysRole;
10 | import cn.tycoding.boot.modules.upms.service.SysUserService;
11 | import lombok.extern.slf4j.Slf4j;
12 | import org.springframework.beans.factory.annotation.Autowired;
13 | import org.springframework.cache.Cache;
14 | import org.springframework.cache.CacheManager;
15 | import org.springframework.security.core.GrantedAuthority;
16 | import org.springframework.security.core.authority.AuthorityUtils;
17 | import org.springframework.security.core.userdetails.UserDetails;
18 | import org.springframework.security.core.userdetails.UserDetailsService;
19 | import org.springframework.security.core.userdetails.UsernameNotFoundException;
20 | import org.springframework.stereotype.Service;
21 |
22 | import java.util.HashSet;
23 | import java.util.List;
24 | import java.util.Set;
25 |
26 | /**
27 | * 封装授权时如何加载用户信息
28 | *
29 | * @author tycoding
30 | * @since 2021/5/21
31 | */
32 | @Slf4j
33 | @Service
34 | public class UserDetailsServiceImpl implements UserDetailsService {
35 |
36 | @Autowired
37 | private SysUserService sysUserService;
38 |
39 | @Autowired
40 | private CacheManager cacheManager;
41 |
42 | /**
43 | * 加载用户信息,在这里可做登录用户的权限、角色判断
44 | *
45 | * @param username 用户名
46 | * @return UserDetails对象
47 | * @throws UsernameNotFoundException 用户名没有找到异常
48 | */
49 | @Override
50 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
51 | Cache cache = cacheManager.getCache(CacheConstant.USER_DETAIL_KEY);
52 | if (cache != null && cache.get(username) != null) {
53 | UserInfo info = (UserInfo) cache.get(username).get();
54 | return getUserDetails(info);
55 | }
56 | UserInfo info = sysUserService.info(username);
57 | return getUserDetails(info);
58 | }
59 |
60 | private UserDetails getUserDetails(UserInfo userInfo) {
61 | if (userInfo == null) {
62 | throw new UsernameNotFoundException("用户不存在");
63 | }
64 |
65 | Set authSet = new HashSet<>();
66 |
67 | List sysRoles = userInfo.getRoles();
68 | if (sysRoles == null || sysRoles.size() == 0) {
69 | throw new TumoAuth2Exception(AuthUtil.NOT_ROLE_ERROR);
70 | }
71 | sysRoles.forEach(role -> authSet.add(AuthConstant.ROLE_PREFIX + role.getId() + AuthConstant.ROLE_SUFFIX + role.getAlias()));
72 |
73 | Set perms = userInfo.getPerms();
74 | if (perms != null && perms.size() > 0) {
75 | authSet.addAll(perms);
76 | }
77 |
78 | List authorities = AuthorityUtils.createAuthorityList(authSet.toArray(new String[0]));
79 |
80 | return new TumoUser(userInfo.getUser().getId(),
81 | userInfo.getDept() == null ? null : userInfo.getDept().getId(),
82 | userInfo.getUser().getUsername(),
83 | userInfo.getUser().getPassword(),
84 | true,
85 | true,
86 | true,
87 | true,
88 | authorities);
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/controller/OssFileController.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.controller;
2 |
3 | import cn.tycoding.boot.common.core.api.QueryPage;
4 | import cn.tycoding.boot.common.core.api.R;
5 | import cn.tycoding.boot.common.core.constant.ApiConstant;
6 | import cn.tycoding.boot.common.mybatis.utils.MybatisUtil;
7 | import cn.tycoding.boot.modules.system.entity.OssFile;
8 | import cn.tycoding.boot.modules.system.service.OssFileService;
9 | import lombok.RequiredArgsConstructor;
10 | import org.springframework.security.access.prepost.PreAuthorize;
11 | import org.springframework.web.bind.annotation.*;
12 |
13 | import java.util.List;
14 |
15 | /**
16 | * 资源文件表(OssFile)控制器
17 | *
18 | * @author tycoding
19 | * @since 2021/5/21
20 | */
21 | @RestController
22 | @RequiredArgsConstructor
23 | @RequestMapping(ApiConstant.API_SYSTEM_PREFIX + "/oss")
24 | public class OssFileController {
25 |
26 | private final OssFileService ossFileService;
27 |
28 | @GetMapping("/page")
29 | public R list(OssFile ossFile, QueryPage queryPage) {
30 | return R.ok(MybatisUtil.getData(ossFileService.page(ossFile, queryPage)));
31 | }
32 |
33 | @GetMapping("/{id}")
34 | public R getById(@PathVariable Long id) {
35 | return R.ok(ossFileService.getById(id));
36 | }
37 |
38 | @PostMapping
39 | @PreAuthorize("@auth.hasAuth('system:oss:add')")
40 | public R add(@RequestBody OssFile ossFile) {
41 | ossFileService.save(ossFile);
42 | return R.ok();
43 | }
44 |
45 | @PostMapping("/put-list")
46 | @PreAuthorize("@auth.hasAuth('system:oss:add')")
47 | public R addList(@RequestBody List list) {
48 | ossFileService.saveBatch(list);
49 | return R.ok();
50 | }
51 |
52 | @PutMapping
53 | @PreAuthorize("@auth.hasAuth('system:oss:update')")
54 | public R update(@RequestBody OssFile ossFile) {
55 | ossFileService.updateById(ossFile);
56 | return R.ok();
57 | }
58 |
59 | @DeleteMapping("/{id}")
60 | @PreAuthorize("@auth.hasAuth('system:oss:delete')")
61 | public R delete(@PathVariable Long id) {
62 | ossFileService.delete(id);
63 | return R.ok();
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/controller/SysDictController.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.controller;
2 |
3 | import cn.tycoding.boot.common.core.api.QueryPage;
4 | import cn.tycoding.boot.common.core.api.R;
5 | import cn.tycoding.boot.common.core.constant.ApiConstant;
6 | import cn.tycoding.boot.common.log.exception.ServiceException;
7 | import cn.tycoding.boot.common.mybatis.utils.MybatisUtil;
8 | import cn.tycoding.boot.modules.system.entity.SysDict;
9 | import cn.tycoding.boot.modules.system.service.SysDictService;
10 | import com.baomidou.mybatisplus.core.toolkit.Wrappers;
11 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
12 | import lombok.RequiredArgsConstructor;
13 | import org.apache.commons.lang3.StringUtils;
14 | import org.springframework.security.access.prepost.PreAuthorize;
15 | import org.springframework.web.bind.annotation.*;
16 |
17 | import java.util.List;
18 |
19 | /**
20 | * 字典表(SysDict)表控制层
21 | *
22 | * @author TyCoding
23 | * @since 2021-08-06
24 | */
25 | @RestController
26 | @RequiredArgsConstructor
27 | @RequestMapping(ApiConstant.API_SYSTEM_PREFIX + "/dict")
28 | public class SysDictController {
29 |
30 | private final SysDictService sysDictService;
31 |
32 | @GetMapping("/list")
33 | public R> list(SysDict sysDict) {
34 | return R.ok(sysDictService.list());
35 | }
36 |
37 | @GetMapping("/page")
38 | public R list(SysDict sysDict, QueryPage queryPage) {
39 | Page page = new Page<>(queryPage.getPage(), queryPage.getLimit());
40 | return R.ok(MybatisUtil.getData(sysDictService.page(page, Wrappers.query().lambda()
41 | .like(StringUtils.isNotEmpty(sysDict.getName()), SysDict::getName, sysDict.getName())
42 | .orderByDesc(SysDict::getSort))));
43 | }
44 |
45 | @GetMapping("/{id}")
46 | public R findById(@PathVariable Long id) {
47 | return R.ok(sysDictService.getById(id));
48 | }
49 |
50 | @PostMapping
51 | @PreAuthorize("@auth.hasAuth('system:dict:add')")
52 | public R add(@RequestBody SysDict sysDict) {
53 | sysDictService.save(sysDict);
54 | return R.ok();
55 | }
56 |
57 | @PutMapping
58 | @PreAuthorize("@auth.hasAuth('system:dict:update')")
59 | public R update(@RequestBody SysDict sysDict) {
60 | sysDictService.updateById(sysDict);
61 | return R.ok();
62 | }
63 |
64 | @DeleteMapping("/{id}")
65 | @PreAuthorize("@auth.hasAuth('system:dict:delete')")
66 | public R delete(@PathVariable Long id) {
67 | SysDict sysDict = sysDictService.getById(id);
68 | if (sysDict != null && sysDict.getIsSystem()) {
69 | throw new ServiceException("系统字典,不可删除");
70 | }
71 | sysDictService.removeById(id);
72 | return R.ok();
73 | }
74 |
75 | }
76 |
77 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/controller/SysDictItemController.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.controller;
2 |
3 | import cn.tycoding.boot.common.core.api.QueryPage;
4 | import cn.tycoding.boot.common.core.api.R;
5 | import cn.tycoding.boot.common.core.constant.ApiConstant;
6 | import cn.tycoding.boot.common.log.exception.ServiceException;
7 | import cn.tycoding.boot.common.mybatis.utils.MybatisUtil;
8 | import cn.tycoding.boot.modules.system.entity.SysDictItem;
9 | import cn.tycoding.boot.modules.system.service.SysDictItemService;
10 | import com.baomidou.mybatisplus.core.toolkit.Wrappers;
11 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
12 | import lombok.RequiredArgsConstructor;
13 | import org.apache.commons.lang3.StringUtils;
14 | import org.springframework.security.access.prepost.PreAuthorize;
15 | import org.springframework.web.bind.annotation.*;
16 |
17 | import java.util.List;
18 |
19 | /**
20 | * 字典项表(SysDictItem)表控制层
21 | *
22 | * @author TyCoding
23 | * @since 2021-08-07 13:58:33
24 | */
25 | @RestController
26 | @RequiredArgsConstructor
27 | @RequestMapping(ApiConstant.API_SYSTEM_PREFIX + "/dict/item")
28 | public class SysDictItemController {
29 |
30 | private final SysDictItemService sysDictItemService;
31 |
32 | @GetMapping("/list")
33 | public R> list(SysDictItem sysDictItem) {
34 | return R.ok(sysDictItemService.list(Wrappers.query().lambda()
35 | .eq(StringUtils.isNotEmpty(sysDictItem.getType()), SysDictItem::getType, sysDictItem.getType())));
36 | }
37 |
38 | @GetMapping("/page")
39 | public R list(@RequestParam Long dictId, QueryPage queryPage) {
40 | Page page = new Page<>(queryPage.getPage(), queryPage.getLimit());
41 | return R.ok(MybatisUtil.getData(sysDictItemService.page(page, Wrappers.query().lambda()
42 | .eq(SysDictItem::getDictId, dictId)
43 | .orderByDesc(SysDictItem::getSort))));
44 | }
45 |
46 | @GetMapping("/{id}")
47 | public R findById(@PathVariable Long id) {
48 | return R.ok(sysDictItemService.getById(id));
49 | }
50 |
51 | @PostMapping
52 | @PreAuthorize("@auth.hasAuth('system:dict:item:add')")
53 | public R add(@RequestBody SysDictItem sysDictItem) {
54 | sysDictItemService.addDictItem(sysDictItem);
55 | return R.ok();
56 | }
57 |
58 | @PutMapping
59 | @PreAuthorize("@auth.hasAuth('system:dict:item:update')")
60 | public R update(@RequestBody SysDictItem sysDictItem) {
61 | sysDictItemService.updateById(sysDictItem);
62 | return R.ok();
63 | }
64 |
65 | @DeleteMapping("/{id}")
66 | @PreAuthorize("@auth.hasAuth('system:dict:item:delete')")
67 | public R delete(@PathVariable Long id) {
68 | SysDictItem sysDictItem = sysDictItemService.getById(id);
69 | if (sysDictItem != null && sysDictItem.getIsSystem()) {
70 | throw new ServiceException("系统字典,不可删除");
71 | }
72 | sysDictItemService.removeById(id);
73 | return R.ok();
74 | }
75 | }
76 |
77 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/controller/SysLogController.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.controller;
2 |
3 | import cn.hutool.core.lang.Dict;
4 | import cn.tycoding.boot.common.core.constant.ApiConstant;
5 | import cn.tycoding.boot.common.core.api.QueryPage;
6 | import cn.tycoding.boot.common.core.api.R;
7 | import cn.tycoding.boot.common.mybatis.utils.MybatisUtil;
8 | import cn.tycoding.boot.modules.system.entity.SysLog;
9 | import cn.tycoding.boot.modules.system.service.SysLogService;
10 | import lombok.RequiredArgsConstructor;
11 | import org.springframework.security.access.prepost.PreAuthorize;
12 | import org.springframework.web.bind.annotation.*;
13 |
14 | /**
15 | * 系统日志表(Log)表控制层
16 | *
17 | * @author tycoding
18 | * @since 2021/5/21
19 | */
20 | @RestController
21 | @RequiredArgsConstructor
22 | @RequestMapping(ApiConstant.API_SYSTEM_PREFIX + "/log")
23 | public class SysLogController {
24 |
25 | private final SysLogService sysLogService;
26 |
27 | @GetMapping("/page")
28 | public R list(SysLog sysLog, QueryPage queryPage) {
29 | return R.ok(MybatisUtil.getData(sysLogService.list(sysLog, queryPage)));
30 | }
31 |
32 | @GetMapping("/{id}")
33 | public R findById(@PathVariable Long id) {
34 | return R.ok(sysLogService.getById(id));
35 | }
36 |
37 | @DeleteMapping("/{id}")
38 | @PreAuthorize("@auth.hasAuth('system:log:delete')")
39 | public R delete(@PathVariable Long id) {
40 | sysLogService.delete(id);
41 | return R.ok();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/endpoint/OssEndpoint.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.endpoint;
2 |
3 | import cn.tycoding.boot.common.core.api.R;
4 | import cn.tycoding.boot.common.core.constant.ApiConstant;
5 | import cn.tycoding.boot.modules.system.service.OssService;
6 | import lombok.RequiredArgsConstructor;
7 | import org.springframework.web.bind.annotation.PostMapping;
8 | import org.springframework.web.bind.annotation.RequestMapping;
9 | import org.springframework.web.bind.annotation.RestController;
10 | import org.springframework.web.multipart.MultipartFile;
11 |
12 | /**
13 | * 单独定义文件上传端点接口
14 | *
15 | * @author tycoding
16 | * @since 2021/5/25
17 | */
18 | @RestController
19 | @RequiredArgsConstructor
20 | @RequestMapping(ApiConstant.API_BASE + "/oss")
21 | public class OssEndpoint {
22 |
23 | private final OssService ossService;
24 |
25 | @PostMapping("/put")
26 | public R put(MultipartFile file) {
27 | return R.ok(ossService.put(file));
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/entity/OssFile.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableId;
5 | import com.baomidou.mybatisplus.annotation.TableName;
6 | import lombok.Data;
7 |
8 | import java.io.Serializable;
9 | import java.util.Date;
10 |
11 | /**
12 | * 资源文件表(OssFile)实体类
13 | *
14 | * @author tycoding
15 | * @since 2021/5/21
16 | */
17 | @Data
18 | @TableName("oss_file")
19 | public class OssFile implements Serializable {
20 | private static final long serialVersionUID = -7225974227659141556L;
21 |
22 | /**
23 | * 主键
24 | */
25 | @TableId(type = IdType.ASSIGN_ID)
26 | private Long id;
27 |
28 | /**
29 | * 文件原始名称
30 | */
31 | private String originName;
32 |
33 | /**
34 | * 文件存储名称
35 | */
36 | private String targetName;
37 |
38 | /**
39 | * 桶路径
40 | */
41 | private String bucket;
42 |
43 | /**
44 | * 文件地址
45 | */
46 | private String url;
47 |
48 | /**
49 | * 文件类型
50 | */
51 | private String type;
52 |
53 | /**
54 | * 文件大小
55 | */
56 | private Long size;
57 |
58 | /**
59 | * 文件描述
60 | */
61 | private String des;
62 |
63 | /**
64 | * 创建时间
65 | */
66 | private Date createTime;
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/entity/SysDict.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableId;
5 | import com.baomidou.mybatisplus.annotation.TableName;
6 | import lombok.Data;
7 |
8 | import java.io.Serializable;
9 |
10 | /**
11 | * 字典表(SysDict)实体类
12 | *
13 | * @author TyCoding
14 | * @since 2021-08-06
15 | */
16 | @Data
17 | @TableName("sys_dict")
18 | public class SysDict implements Serializable {
19 | private static final long serialVersionUID = -66073261152467734L;
20 |
21 | /**
22 | * 主键
23 | */
24 | @TableId(type = IdType.ASSIGN_ID)
25 | private Long id;
26 |
27 | /**
28 | * 类型
29 | */
30 | private String type;
31 |
32 | /**
33 | * 名称
34 | */
35 | private String name;
36 |
37 | /**
38 | * 描述
39 | */
40 | private String des;
41 |
42 | /**
43 | * 排序
44 | */
45 | private Integer sort;
46 |
47 | /**
48 | * 是否是系统内置
49 | */
50 | private Boolean isSystem;
51 |
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/entity/SysDictItem.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableId;
5 | import com.baomidou.mybatisplus.annotation.TableName;
6 | import lombok.Data;
7 |
8 | import java.io.Serializable;
9 |
10 | /**
11 | * 字典项表(SysDictItem)实体类
12 | *
13 | * @author TyCoding
14 | * @since 2021-08-06
15 | */
16 | @Data
17 | @TableName("sys_dict_item")
18 | public class SysDictItem implements Serializable {
19 | private static final long serialVersionUID = 859322231277654399L;
20 |
21 | /**
22 | * 主键
23 | */
24 | @TableId(type = IdType.ASSIGN_ID)
25 | private Long id;
26 |
27 | /**
28 | * 字典表主键
29 | */
30 | private Long dictId;
31 |
32 | /**
33 | * 字典值
34 | */
35 | private String value;
36 |
37 | /**
38 | * 显示名称
39 | */
40 | private String label;
41 |
42 | /**
43 | * 字典类型
44 | */
45 | private String type;
46 |
47 | /**
48 | * 排序
49 | */
50 | private Integer sort;
51 |
52 | /**
53 | * 描述
54 | */
55 | private String des;
56 |
57 | /**
58 | * 是否是系统内置
59 | */
60 | private Boolean isSystem;
61 |
62 | }
63 |
64 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/entity/SysLog.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableId;
5 | import com.baomidou.mybatisplus.annotation.TableName;
6 | import lombok.Data;
7 | import lombok.experimental.Accessors;
8 |
9 | import java.io.Serializable;
10 | import java.util.Date;
11 |
12 | /**
13 | * 系统日志表(Log)实体类
14 | *
15 | * @author tycoding
16 | * @since 2021/5/21
17 | */
18 | @Data
19 | @TableName("sys_log")
20 | @Accessors(chain = true)
21 | public class SysLog implements Serializable {
22 | private static final long serialVersionUID = -39039111282732175L;
23 |
24 | /**
25 | * 主键
26 | */
27 | @TableId(type = IdType.ASSIGN_ID)
28 | private Long id;
29 |
30 | /**
31 | * 操作用户
32 | */
33 | private String username;
34 |
35 | /**
36 | * 日志类型
37 | */
38 | private Integer type;
39 |
40 | /**
41 | * 操作描述
42 | */
43 | private String operation;
44 |
45 | /**
46 | * 请求URL
47 | */
48 | private String url;
49 |
50 | /**
51 | * 耗时(毫秒)
52 | */
53 | private Long time;
54 |
55 | /**
56 | * 操作方法
57 | */
58 | private String method;
59 |
60 | /**
61 | * 操作参数
62 | */
63 | private String params;
64 |
65 | /**
66 | * IP地址
67 | */
68 | private String ip;
69 |
70 | /**
71 | * 用户代理
72 | */
73 | private String userAgent;
74 |
75 | /**
76 | * 操作时间
77 | */
78 | private Date createTime;
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/mapper/OssFileMapper.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.mapper;
2 |
3 | import cn.tycoding.boot.modules.system.entity.OssFile;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 | import org.apache.ibatis.annotations.Mapper;
6 |
7 | /**
8 | * 资源文件表(OssFile)数据访问层
9 | *
10 | * @author tycoding
11 | * @since 2021/5/20
12 | */
13 | @Mapper
14 | public interface OssFileMapper extends BaseMapper {
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/mapper/SysDictItemMapper.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.mapper;
2 |
3 | import cn.tycoding.boot.modules.system.entity.SysDictItem;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 | import org.apache.ibatis.annotations.Mapper;
6 |
7 | /**
8 | * 字典项表(SysDictItem)表数据库访问层
9 | *
10 | * @author TyCoding
11 | * @since 2021-08-06
12 | */
13 | @Mapper
14 | public interface SysDictItemMapper extends BaseMapper {
15 |
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/mapper/SysDictMapper.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.mapper;
2 |
3 | import cn.tycoding.boot.modules.system.entity.SysDict;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 | import org.apache.ibatis.annotations.Mapper;
6 |
7 | /**
8 | * 字典表(SysDict)表数据库访问层
9 | *
10 | * @author TyCoding
11 | * @since 2021-08-06
12 | */
13 | @Mapper
14 | public interface SysDictMapper extends BaseMapper {
15 |
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/mapper/SysLogMapper.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.mapper;
2 |
3 | import cn.tycoding.boot.modules.system.entity.SysLog;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 | import org.apache.ibatis.annotations.Mapper;
6 |
7 | /**
8 | * 系统日志表(Log)表数据库访问层
9 | *
10 | * @author tycoding
11 | * @since 2021/5/21
12 | */
13 | @Mapper
14 | public interface SysLogMapper extends BaseMapper {
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/service/OssFileService.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.service;
2 |
3 | import cn.tycoding.boot.common.core.api.QueryPage;
4 | import cn.tycoding.boot.modules.system.entity.OssFile;
5 | import com.baomidou.mybatisplus.core.metadata.IPage;
6 | import com.baomidou.mybatisplus.extension.service.IService;
7 |
8 | /**
9 | * 资源文件表(OssFile)服务接口
10 | *
11 | * @author tycoding
12 | * @since 2021/5/20
13 | */
14 | public interface OssFileService extends IService {
15 |
16 | /**
17 | * 分页查询
18 | */
19 | IPage page(OssFile ossFile, QueryPage queryPage);
20 |
21 | /**
22 | * 删除文件
23 | */
24 | void delete(Long id);
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/service/OssService.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.service;
2 |
3 | import cn.tycoding.boot.modules.system.entity.OssFile;
4 | import org.springframework.web.multipart.MultipartFile;
5 |
6 | /**
7 | * @author tycoding
8 | * @since 2021/5/25
9 | */
10 | public interface OssService {
11 |
12 | OssFile put(MultipartFile file);
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/service/SysDictItemService.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.service;
2 |
3 | import cn.tycoding.boot.modules.system.entity.SysDictItem;
4 | import com.baomidou.mybatisplus.extension.service.IService;
5 |
6 | /**
7 | * 字典项表(SysDictItem)表服务接口
8 | *
9 | * @author TyCoding
10 | * @since 2021-08-06
11 | */
12 | public interface SysDictItemService extends IService {
13 |
14 | /**
15 | * 新增字典项
16 | *
17 | * @param sysDictItem 字典项信息
18 | */
19 | void addDictItem(SysDictItem sysDictItem);
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/service/SysDictService.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.service;
2 |
3 | import cn.tycoding.boot.modules.system.entity.SysDict;
4 | import com.baomidou.mybatisplus.extension.service.IService;
5 |
6 | /**
7 | * 字典表(SysDict)表服务接口
8 | *
9 | * @author TyCoding
10 | * @since 2021-08-06
11 | */
12 | public interface SysDictService extends IService {
13 |
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/service/SysLogService.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.service;
2 |
3 | import cn.tycoding.boot.common.core.api.QueryPage;
4 | import cn.tycoding.boot.modules.system.entity.SysLog;
5 | import com.baomidou.mybatisplus.core.metadata.IPage;
6 | import com.baomidou.mybatisplus.extension.service.IService;
7 |
8 | /**
9 | * 系统日志表(Log)表服务接口
10 | *
11 | * @author tycoding
12 | * @since 2021/5/21
13 | */
14 | public interface SysLogService extends IService {
15 |
16 | /**
17 | * 分页、条件查询
18 | */
19 | IPage list(SysLog sysLog, QueryPage queryPage);
20 |
21 | /**
22 | * 新增
23 | */
24 | void add(SysLog sysLog);
25 | /**
26 | * 删除
27 | */
28 | void delete(Long id);
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/service/impl/OssFileServiceImpl.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.service.impl;
2 |
3 | import cn.hutool.core.io.FileUtil;
4 | import cn.tycoding.boot.common.core.api.QueryPage;
5 | import cn.tycoding.boot.common.mybatis.utils.MybatisUtil;
6 | import cn.tycoding.boot.common.oss.props.LocalFileProperties;
7 | import cn.tycoding.boot.modules.system.entity.OssFile;
8 | import cn.tycoding.boot.modules.system.mapper.OssFileMapper;
9 | import cn.tycoding.boot.modules.system.service.OssFileService;
10 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
11 | import com.baomidou.mybatisplus.core.metadata.IPage;
12 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
13 | import lombok.RequiredArgsConstructor;
14 | import lombok.SneakyThrows;
15 | import org.apache.commons.lang3.StringUtils;
16 | import org.springframework.stereotype.Service;
17 |
18 | import java.io.File;
19 |
20 | /**
21 | * 资源文件表(OssFile)服务实现类
22 | *
23 | * @author tycoding
24 | * @since 2021/5/20
25 | */
26 | @Service
27 | @RequiredArgsConstructor
28 | public class OssFileServiceImpl extends ServiceImpl implements OssFileService {
29 |
30 | private final LocalFileProperties properties;
31 |
32 | @Override
33 | public IPage page(OssFile ossFile, QueryPage queryPage) {
34 | return baseMapper.selectPage(MybatisUtil.wrap(ossFile, queryPage), new LambdaQueryWrapper()
35 | .like(StringUtils.isNotEmpty(ossFile.getOriginName()), OssFile::getOriginName, ossFile.getOriginName()));
36 | }
37 |
38 | @Override
39 | @SneakyThrows
40 | public void delete(Long id) {
41 | OssFile ossFile = baseMapper.selectById(id);
42 | if (ossFile != null) {
43 | // 删除数据库
44 | baseMapper.deleteById(id);
45 | // 删除磁盘文件
46 | String path = properties.getUploadPath() + ossFile.getBucket() + "/" + ossFile.getOriginName();
47 | FileUtil.del(new File(path));
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/service/impl/OssServiceImpl.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.service.impl;
2 |
3 | import cn.hutool.core.io.FileUtil;
4 | import cn.tycoding.boot.common.log.exception.ServiceException;
5 | import cn.tycoding.boot.common.oss.props.LocalFileProperties;
6 | import cn.tycoding.boot.common.oss.utils.OssUtil;
7 | import cn.tycoding.boot.modules.system.entity.OssFile;
8 | import cn.tycoding.boot.modules.system.service.OssService;
9 | import lombok.RequiredArgsConstructor;
10 | import lombok.SneakyThrows;
11 | import lombok.extern.slf4j.Slf4j;
12 | import org.springframework.stereotype.Service;
13 | import org.springframework.web.multipart.MultipartFile;
14 |
15 | import java.io.File;
16 | import java.util.Date;
17 |
18 | /**
19 | * 文件上传服务类
20 | *
21 | * @author tycoding
22 | * @since 2021/5/25
23 | */
24 | @Slf4j
25 | @Service
26 | @RequiredArgsConstructor
27 | public class OssServiceImpl implements OssService {
28 |
29 | private final LocalFileProperties properties;
30 |
31 | @Override
32 | public OssFile put(MultipartFile file) {
33 | if (file == null) {
34 | throw new ServiceException("文件列表为空");
35 | }
36 | return transfer(file);
37 | }
38 |
39 | /**
40 | * 写入文件
41 | */
42 | @SneakyThrows
43 | private OssFile transfer(MultipartFile file) {
44 | String bucket = OssUtil.getBucket();
45 | // 目标上传地址
46 | String targetPath = properties.getUploadPath() + bucket;
47 | // 创建文件夹
48 | if (!FileUtil.isDirectory(targetPath)) {
49 | FileUtil.mkdir(targetPath);
50 | }
51 | // 目标文件名
52 | String targetName = OssUtil.getName(file.getOriginalFilename());
53 | // 目标文件
54 | File targetFile = new File(targetPath, targetName);
55 |
56 | // 写入数据
57 | OssFile ossFile = new OssFile();
58 | ossFile.setOriginName(file.getOriginalFilename());
59 | ossFile.setTargetName(targetName);
60 | ossFile.setBucket(bucket);
61 | ossFile.setUrl(OssUtil.getUrl(properties.getRemotePath(), bucket, targetName));
62 | ossFile.setSize(file.getSize());
63 | ossFile.setType(FileUtil.getSuffix(targetName));
64 | ossFile.setDes(file.getOriginalFilename());
65 | ossFile.setCreateTime(new Date());
66 |
67 | // 写入文件
68 | file.transferTo(targetFile);
69 | log.info("[OSS 文件写入成功,文件路径:{},访问地址:{}", targetFile.getPath(), ossFile.getUrl());
70 | return ossFile;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/service/impl/SysDictItemServiceImpl.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.service.impl;
2 |
3 | import cn.tycoding.boot.modules.system.entity.SysDict;
4 | import cn.tycoding.boot.modules.system.entity.SysDictItem;
5 | import cn.tycoding.boot.modules.system.mapper.SysDictItemMapper;
6 | import cn.tycoding.boot.modules.system.mapper.SysDictMapper;
7 | import cn.tycoding.boot.modules.system.service.SysDictItemService;
8 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
9 | import lombok.RequiredArgsConstructor;
10 | import org.springframework.stereotype.Service;
11 |
12 | /**
13 | * 字典项表(SysDictItem)表服务实现类
14 | *
15 | * @author TyCoding
16 | * @since 2021-08-06
17 | */
18 | @Service
19 | @RequiredArgsConstructor
20 | public class SysDictItemServiceImpl extends ServiceImpl implements SysDictItemService {
21 |
22 | private final SysDictMapper sysDictMapper;
23 | private final SysDictItemMapper sysDictItemMapper;
24 |
25 | @Override
26 | public void addDictItem(SysDictItem sysDictItem) {
27 | SysDict sysDict = sysDictMapper.selectById(sysDictItem.getDictId());
28 | if (sysDict != null) {
29 | sysDictItem.setDictId(sysDict.getId());
30 | sysDictItem.setIsSystem(sysDict.getIsSystem());
31 |
32 | sysDictItemMapper.insert(sysDictItem);
33 | }
34 | }
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/service/impl/SysDictServiceImpl.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.service.impl;
2 |
3 | import cn.tycoding.boot.modules.system.entity.SysDict;
4 | import cn.tycoding.boot.modules.system.mapper.SysDictMapper;
5 | import cn.tycoding.boot.modules.system.service.SysDictService;
6 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
7 | import lombok.RequiredArgsConstructor;
8 | import org.springframework.stereotype.Service;
9 |
10 | /**
11 | * 字典表(SysDict)表服务实现类
12 | *
13 | * @author TyCoding
14 | * @since 2021-08-06
15 | */
16 | @Service
17 | @RequiredArgsConstructor
18 | public class SysDictServiceImpl extends ServiceImpl implements SysDictService {
19 |
20 | private final SysDictMapper sysDictMapper;
21 |
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/system/service/impl/SysLogServiceImpl.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.system.service.impl;
2 |
3 | import cn.tycoding.boot.common.core.api.QueryPage;
4 | import cn.tycoding.boot.common.mybatis.utils.MybatisUtil;
5 | import cn.tycoding.boot.modules.system.entity.SysLog;
6 | import cn.tycoding.boot.modules.system.mapper.SysLogMapper;
7 | import cn.tycoding.boot.modules.system.service.SysLogService;
8 | import com.baomidou.mybatisplus.core.metadata.IPage;
9 | import com.baomidou.mybatisplus.core.toolkit.Wrappers;
10 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
11 | import lombok.RequiredArgsConstructor;
12 | import org.apache.commons.lang3.StringUtils;
13 | import org.springframework.stereotype.Service;
14 | import org.springframework.transaction.annotation.Transactional;
15 |
16 | /**
17 | * 系统日志表(Log)表服务实现类
18 | *
19 | * @author tycoding
20 | * @since 2021/5/21
21 | */
22 | @Service
23 | @RequiredArgsConstructor
24 | public class SysLogServiceImpl extends ServiceImpl implements SysLogService {
25 |
26 | @Override
27 | public IPage list(SysLog sysLog, QueryPage queryPage) {
28 | return baseMapper.selectPage(MybatisUtil.wrap(sysLog, queryPage),
29 | Wrappers.lambdaQuery()
30 | .eq(sysLog.getType() != null, SysLog::getType, sysLog.getType())
31 | .like(StringUtils.isNotEmpty(sysLog.getOperation()), SysLog::getOperation, sysLog.getOperation())
32 | .orderByDesc(SysLog::getCreateTime)
33 | );
34 | }
35 |
36 | @Override
37 | @Transactional(rollbackFor = Exception.class)
38 | public void add(SysLog sysLog) {
39 | baseMapper.insert(sysLog);
40 | }
41 |
42 | @Override
43 | @Transactional(rollbackFor = Exception.class)
44 | public void delete(Long id) {
45 | baseMapper.deleteById(id);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/controller/SysDeptController.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.controller;
2 |
3 | import cn.hutool.core.lang.tree.Tree;
4 | import cn.tycoding.boot.common.core.constant.ApiConstant;
5 | import cn.tycoding.boot.common.core.api.R;
6 | import cn.tycoding.boot.common.log.annotation.ApiLog;
7 | import cn.tycoding.boot.modules.upms.entity.SysDept;
8 | import cn.tycoding.boot.modules.upms.service.SysDeptService;
9 | import lombok.RequiredArgsConstructor;
10 | import org.springframework.security.access.prepost.PreAuthorize;
11 | import org.springframework.web.bind.annotation.*;
12 |
13 | import java.util.List;
14 |
15 | /**
16 | * 部门表(Dept)表控制层
17 | *
18 | * @author tycoding
19 | * @since 2021/5/21
20 | */
21 | @RestController
22 | @RequiredArgsConstructor
23 | @RequestMapping(ApiConstant.API_UPMS_PREFIX + "/dept")
24 | public class SysDeptController {
25 |
26 | private final SysDeptService sysDeptService;
27 |
28 | @GetMapping("/list")
29 | public R> list(SysDept sysDept) {
30 | return R.ok(sysDeptService.list(sysDept));
31 | }
32 |
33 | @GetMapping("/tree")
34 | public R>> tree(SysDept sysDept) {
35 | return R.ok(sysDeptService.tree(sysDept));
36 | }
37 |
38 | @GetMapping("/{id}")
39 | public R findById(@PathVariable Long id) {
40 | return R.ok(sysDeptService.getById(id));
41 | }
42 |
43 | @PostMapping
44 | @ApiLog("新增部门")
45 | @PreAuthorize("@auth.hasAuth('upms:dept:add')")
46 | public R add(@RequestBody SysDept sysDept) {
47 | sysDept.setParentId(sysDept.getParentId() == null ? 0L : sysDept.getParentId());
48 | sysDeptService.save(sysDept);
49 | return R.ok();
50 | }
51 |
52 | @PutMapping
53 | @ApiLog("修改部门")
54 | @PreAuthorize("@auth.hasAuth('upms:dept:update')")
55 | public R update(@RequestBody SysDept sysDept) {
56 | sysDept.setParentId(sysDept.getParentId() == null ? 0L : sysDept.getParentId());
57 | sysDeptService.updateById(sysDept);
58 | return R.ok();
59 | }
60 |
61 | @DeleteMapping("/{id}")
62 | @ApiLog("删除部门")
63 | @PreAuthorize("@auth.hasAuth('upms:dept:delete')")
64 | public R delete(@PathVariable Long id) {
65 | sysDeptService.delete(id);
66 | return R.ok();
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/controller/SysMenuController.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.controller;
2 |
3 | import cn.tycoding.boot.common.auth.utils.AuthUtil;
4 | import cn.tycoding.boot.common.core.api.R;
5 | import cn.tycoding.boot.common.core.constant.ApiConstant;
6 | import cn.tycoding.boot.common.log.annotation.ApiLog;
7 | import cn.tycoding.boot.modules.upms.dto.MenuTree;
8 | import cn.tycoding.boot.modules.upms.entity.SysMenu;
9 | import cn.tycoding.boot.modules.upms.service.SysMenuService;
10 | import lombok.RequiredArgsConstructor;
11 | import org.springframework.security.access.prepost.PreAuthorize;
12 | import org.springframework.web.bind.annotation.*;
13 |
14 | import java.util.List;
15 |
16 | /**
17 | * 菜单表(Menu)表控制层
18 | *
19 | * @author tycoding
20 | * @since 2021/5/21
21 | */
22 | @RestController
23 | @RequiredArgsConstructor
24 | @RequestMapping(ApiConstant.API_UPMS_PREFIX + "/menu")
25 | public class SysMenuController {
26 |
27 | private final SysMenuService sysMenuService;
28 |
29 | @GetMapping("/tree")
30 | public R>> tree(SysMenu sysMenu) {
31 | return R.ok(sysMenuService.tree(sysMenu));
32 | }
33 |
34 | @GetMapping("/build")
35 | public R>> build() {
36 | return R.ok(sysMenuService.build(AuthUtil.getUserId()));
37 | }
38 |
39 | @GetMapping("/list")
40 | public R> list(SysMenu sysMenu) {
41 | return R.ok(sysMenuService.list(sysMenu));
42 | }
43 |
44 | @GetMapping("/{id}")
45 | public R findById(@PathVariable Long id) {
46 | return R.ok(sysMenuService.getById(id));
47 | }
48 |
49 | @PostMapping
50 | @ApiLog("新增菜单")
51 | @PreAuthorize("@auth.hasAuth('upms:menu:add')")
52 | public R add(@RequestBody SysMenu sysMenu) {
53 | sysMenuService.add(sysMenu);
54 | return R.ok();
55 | }
56 |
57 | @PutMapping
58 | @ApiLog("修改菜单")
59 | @PreAuthorize("@auth.hasAuth('upms:menu:update')")
60 | public R update(@RequestBody SysMenu sysMenu) {
61 | sysMenuService.update(sysMenu);
62 | return R.ok();
63 | }
64 |
65 | @DeleteMapping("/{id}")
66 | @ApiLog("删除菜单")
67 | @PreAuthorize("@auth.hasAuth('upms:menu:delete')")
68 | public R delete(@PathVariable Long id) {
69 | sysMenuService.delete(id);
70 | return R.ok();
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/controller/SysRoleController.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.controller;
2 |
3 | import cn.hutool.core.lang.tree.Tree;
4 | import cn.tycoding.boot.common.auth.utils.AuthUtil;
5 | import cn.tycoding.boot.common.core.constant.ApiConstant;
6 | import cn.tycoding.boot.common.core.api.R;
7 | import cn.tycoding.boot.common.log.annotation.ApiLog;
8 | import cn.tycoding.boot.modules.upms.dto.SysRoleDTO;
9 | import cn.tycoding.boot.modules.upms.entity.SysRole;
10 | import cn.tycoding.boot.modules.upms.service.SysRoleService;
11 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
12 | import lombok.RequiredArgsConstructor;
13 | import org.springframework.security.access.prepost.PreAuthorize;
14 | import org.springframework.web.bind.annotation.*;
15 |
16 | import java.util.List;
17 |
18 | /**
19 | * 角色表(Role)表控制层
20 | *
21 | * @author tycoding
22 | * @since 2021/5/21
23 | */
24 | @RestController
25 | @RequiredArgsConstructor
26 | @RequestMapping(ApiConstant.API_UPMS_PREFIX + "/role")
27 | public class SysRoleController {
28 |
29 | private final SysRoleService sysRoleService;
30 |
31 | @GetMapping("/list")
32 | public R> list(SysRole sysRole) {
33 | return R.ok(sysRoleService.list(new LambdaQueryWrapper()
34 | .ne(SysRole::getAlias, AuthUtil.ADMINISTRATOR)
35 | .eq(SysRole::getStatus, true)));
36 | }
37 |
38 | @GetMapping("/tree")
39 | public R>> tree(SysRole sysRole) {
40 | return R.ok(sysRoleService.tree(sysRole));
41 | }
42 |
43 | @GetMapping("/{id}")
44 | public R findById(@PathVariable Long id) {
45 | return R.ok(sysRoleService.findById(id));
46 | }
47 |
48 | @PostMapping
49 | @ApiLog("新增角色")
50 | @PreAuthorize("@auth.hasAuth('upms:role:add')")
51 | public R add(@RequestBody SysRoleDTO sysRole) {
52 | sysRoleService.add(sysRole);
53 | return R.ok();
54 | }
55 |
56 | @PutMapping
57 | @ApiLog("修改角色")
58 | @PreAuthorize("@auth.hasAuth('upms:role:update')")
59 | public R update(@RequestBody SysRoleDTO sysRole) {
60 | sysRoleService.update(sysRole);
61 | return R.ok();
62 | }
63 |
64 | @DeleteMapping("/{id}")
65 | @ApiLog("删除角色")
66 | @PreAuthorize("@auth.hasAuth('upms:role:delete')")
67 | public R delete(@PathVariable Long id) {
68 | sysRoleService.delete(id);
69 | return R.ok();
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/controller/SysUserController.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.controller;
2 |
3 | import cn.hutool.core.lang.Dict;
4 | import cn.tycoding.boot.common.core.constant.ApiConstant;
5 | import cn.tycoding.boot.common.auth.utils.AuthUtil;
6 | import cn.tycoding.boot.common.core.api.QueryPage;
7 | import cn.tycoding.boot.common.core.api.R;
8 | import cn.tycoding.boot.common.log.annotation.ApiLog;
9 | import cn.tycoding.boot.common.mybatis.utils.MybatisUtil;
10 | import cn.tycoding.boot.modules.auth.dto.UserInfo;
11 | import cn.tycoding.boot.modules.upms.dto.SysUserDTO;
12 | import cn.tycoding.boot.modules.upms.entity.SysUser;
13 | import cn.tycoding.boot.modules.upms.service.SysUserService;
14 | import lombok.RequiredArgsConstructor;
15 | import org.springframework.security.access.prepost.PreAuthorize;
16 | import org.springframework.web.bind.annotation.*;
17 |
18 | import java.util.List;
19 |
20 | /**
21 | * 用户表(User)表控制层
22 | *
23 | * @author tycoding
24 | * @since 2021/5/21
25 | */
26 | @RestController
27 | @RequiredArgsConstructor
28 | @RequestMapping(ApiConstant.API_UPMS_PREFIX + "/user")
29 | public class SysUserController {
30 |
31 | private final SysUserService sysUserService;
32 |
33 | @GetMapping("/info")
34 | public R info() {
35 | UserInfo userInfo = sysUserService.info(AuthUtil.getUsername());
36 | userInfo.getUser().setPassword(null);
37 | return R.ok(userInfo);
38 | }
39 |
40 | @GetMapping("/checkName")
41 | public R checkName(SysUserDTO sysUser) {
42 | return R.ok(sysUserService.checkName(sysUser));
43 | }
44 |
45 | @GetMapping("/list")
46 | public R> list(SysUser sysUser) {
47 | return R.ok(sysUserService.list(sysUser));
48 | }
49 |
50 | @GetMapping("/page")
51 | public R page(SysUserDTO user, QueryPage queryPage) {
52 | return R.ok(MybatisUtil.getData(sysUserService.page(user, queryPage)));
53 | }
54 |
55 | @GetMapping("/{id}")
56 | public R findById(@PathVariable Long id) {
57 | return R.ok(sysUserService.findById(id));
58 | }
59 |
60 | @PostMapping
61 | @ApiLog("新增用户")
62 | @PreAuthorize("@auth.hasAuth('upms:user:add')")
63 | public R add(@RequestBody SysUserDTO user) {
64 | sysUserService.add(user);
65 | return R.ok();
66 | }
67 |
68 | @PutMapping
69 | @ApiLog("修改用户")
70 | @PreAuthorize("@auth.hasAuth('upms:user:update')")
71 | public R update(@RequestBody SysUserDTO user) {
72 | sysUserService.update(user);
73 | return R.ok();
74 | }
75 |
76 | @DeleteMapping("/{id}")
77 | @ApiLog("删除用户")
78 | @PreAuthorize("@auth.hasAuth('upms:user:delete')")
79 | public R delete(@PathVariable Long id) {
80 | SysUser user = sysUserService.getById(id);
81 | if (user != null) {
82 | sysUserService.delete(id, user.getUsername());
83 | }
84 | return R.ok();
85 | }
86 |
87 | @GetMapping("/reset")
88 | @ApiLog("重置密码")
89 | @PreAuthorize("@auth.hasAuth('upms:user:reset')")
90 | public R reset(@RequestParam Long id, String password) {
91 | SysUser user = sysUserService.getById(id);
92 | if (user != null) {
93 | sysUserService.reset(id, password, user.getUsername());
94 | }
95 | return R.ok();
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/dto/MenuMeta.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.dto;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 |
6 | import java.io.Serializable;
7 |
8 | /**
9 | * 封装前端路由所需的路径名称、图标格式
10 | *
11 | * @author tycoding
12 | * @since 2021/5/21
13 | */
14 | @Data
15 | @AllArgsConstructor
16 | public class MenuMeta implements Serializable {
17 | private static final long serialVersionUID = 547891924677981054L;
18 |
19 | /**
20 | * 标题
21 | */
22 | private String title;
23 |
24 | /**
25 | * 图标名称
26 | */
27 | private String icon;
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/dto/MenuTree.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.dto;
2 |
3 | import com.fasterxml.jackson.annotation.JsonInclude;
4 | import lombok.Data;
5 | import lombok.experimental.Accessors;
6 |
7 | import java.io.Serializable;
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | /**
12 | * 按照前端路由格式封装
13 | *
14 | * @author tycoding
15 | * @since 2021/5/21
16 | */
17 | @Data
18 | @Accessors(chain = true)
19 | @JsonInclude(JsonInclude.Include.NON_EMPTY)
20 | public class MenuTree implements Serializable {
21 | private static final long serialVersionUID = 547891924677981054L;
22 |
23 | /**
24 | * 节点ID
25 | */
26 | private Long id;
27 |
28 | /**
29 | * 父节点ID
30 | */
31 | private Long parentId;
32 |
33 | /**
34 | * 路由名称
35 | */
36 | private String name;
37 |
38 | /**
39 | * 路由地址
40 | */
41 | private String path;
42 |
43 | /**
44 | * 类型
45 | */
46 | private String type;
47 |
48 | /**
49 | * 组件路径
50 | */
51 | private String component;
52 |
53 | /**
54 | * 权限标识
55 | */
56 | private String perms;
57 |
58 | /**
59 | * 重定向地址
60 | */
61 | private String redirect;
62 |
63 | /**
64 | * icon && title 信息
65 | */
66 | private MenuMeta meta;
67 |
68 | /**
69 | * 排序
70 | */
71 | private Integer orderNo;
72 |
73 | /**
74 | * 是否禁用
75 | */
76 | private Boolean disabled;
77 |
78 | /**
79 | * 是否外链
80 | */
81 | private Boolean isExt;
82 |
83 | /**
84 | * 是否缓存
85 | */
86 | private Boolean keepalive;
87 |
88 | /**
89 | * 是否缓存
90 | */
91 | private Boolean show;
92 |
93 | /**
94 | * 子节点
95 | */
96 | private List> children = new ArrayList<>();
97 | }
98 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/dto/MenuTreeUtil.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.dto;
2 |
3 | import cn.tycoding.boot.modules.upms.entity.SysMenu;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | /**
9 | * 自定义封装Menu Tree 工具类
10 | *
11 | * @author tycoding
12 | * @since 2021/5/21
13 | */
14 | public class MenuTreeUtil {
15 |
16 | private static List> init(List list) {
17 | List> treeList = new ArrayList<>();
18 | list.forEach(menu -> {
19 | MenuTree tree = new MenuTree<>();
20 | tree.setId(menu.getId());
21 | tree.setParentId(menu.getParentId());
22 | tree.setName(menu.getName());
23 | tree.setPath(menu.getPath());
24 | tree.setType(menu.getType());
25 | tree.setComponent(menu.getComponent());
26 | tree.setPerms(menu.getPerms());
27 | tree.setMeta(new MenuMeta(menu.getName(), menu.getIcon()));
28 | tree.setOrderNo(menu.getOrderNo());
29 | tree.setDisabled(menu.getIsDisabled());
30 | tree.setIsExt(menu.getIsExt());
31 | tree.setKeepalive(menu.getIsKeepalive());
32 | tree.setShow(menu.getIsShow());
33 | treeList.add(tree);
34 | });
35 | return treeList;
36 | }
37 |
38 |
39 | public static List> build(List list) {
40 | List> nodes = init(list);
41 | List> tree = new ArrayList<>();
42 | nodes.forEach(node -> {
43 | Long pid = node.getParentId();
44 | if (pid == null || pid.equals(0L)) {
45 | // 父级节点
46 | if (node.getIsExt()) {
47 | node.setComponent("IFrame");
48 | }
49 | tree.add(node);
50 | return;
51 | }
52 | for (MenuTree c : nodes) {
53 | Long id = c.getId();
54 | if (id != null && id.equals(pid)) {
55 | c.getChildren().add(node);
56 | return;
57 | }
58 | }
59 | });
60 | return tree;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/dto/SysRoleDTO.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.dto;
2 |
3 | import cn.tycoding.boot.modules.upms.entity.SysRole;
4 | import lombok.Data;
5 | import lombok.EqualsAndHashCode;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | * SysRole DTO封装
11 | *
12 | * @author tycoding
13 | * @since 2021/5/21
14 | */
15 | @Data
16 | @EqualsAndHashCode(callSuper = true)
17 | public class SysRoleDTO extends SysRole {
18 | private static final long serialVersionUID = -5792577217091151552L;
19 |
20 | /**
21 | * 菜单ID集合
22 | */
23 | private List menuIds;
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/dto/SysUserDTO.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.dto;
2 |
3 | import cn.tycoding.boot.modules.upms.entity.SysRole;
4 | import cn.tycoding.boot.modules.upms.entity.SysUser;
5 | import lombok.Data;
6 | import lombok.EqualsAndHashCode;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * SysUser DTO封装
12 | *
13 | * @author tycoding
14 | * @since 2021/5/21
15 | */
16 | @Data
17 | @EqualsAndHashCode(callSuper = true)
18 | public class SysUserDTO extends SysUser {
19 | private static final long serialVersionUID = 6173751370282753777L;
20 |
21 | /**
22 | * 部门名称
23 | */
24 | private String deptName;
25 |
26 | /**
27 | * 角色信息
28 | */
29 | private List roles;
30 |
31 | /**
32 | * 角色ID列表
33 | */
34 | private List roleIds;
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/entity/SysDept.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableId;
5 | import com.baomidou.mybatisplus.annotation.TableName;
6 | import lombok.Data;
7 |
8 | import java.io.Serializable;
9 |
10 | /**
11 | * 部门表(Dept)实体类
12 | *
13 | * @author tycoding
14 | * @since 2021/5/21
15 | */
16 | @Data
17 | @TableName("sys_dept")
18 | public class SysDept implements Serializable {
19 | private static final long serialVersionUID = -94917153262781949L;
20 |
21 | /**
22 | * 主键
23 | */
24 | @TableId(type = IdType.ASSIGN_ID)
25 | private Long id;
26 |
27 | /**
28 | * 上级部门ID
29 | */
30 | private Long parentId;
31 |
32 | /**
33 | * 部门名称
34 | */
35 | private String name;
36 |
37 | /**
38 | * 排序
39 | */
40 | private Integer orderNo;
41 |
42 | /**
43 | * 描述
44 | */
45 | private String des;
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/entity/SysMenu.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableId;
5 | import com.baomidou.mybatisplus.annotation.TableName;
6 | import lombok.Data;
7 |
8 | import java.io.Serializable;
9 |
10 | /**
11 | * 菜单表(Menu)实体类
12 | *
13 | * @author tycoding
14 | * @since 2021/5/21
15 | */
16 | @Data
17 | @TableName("sys_menu")
18 | public class SysMenu implements Serializable {
19 | private static final long serialVersionUID = 427935315704878694L;
20 |
21 | /**
22 | * 主键
23 | */
24 | @TableId(type = IdType.ASSIGN_ID)
25 | private Long id;
26 |
27 | /**
28 | * 资源名称
29 | */
30 | private String name;
31 |
32 | /**
33 | * 父级ID
34 | */
35 | private Long parentId;
36 |
37 | /**
38 | * 路由地址
39 | */
40 | private String path;
41 |
42 | /**
43 | * 权限标识
44 | */
45 | private String perms;
46 |
47 | /**
48 | * 菜单类型:如button按钮 menu菜单
49 | */
50 | private String type;
51 |
52 | /**
53 | * 菜单图标
54 | */
55 | private String icon;
56 |
57 | /**
58 | * 组件路径
59 | */
60 | private String component;
61 |
62 | /**
63 | * 排序
64 | */
65 | private Integer orderNo;
66 |
67 | /**
68 | * 是否禁用
69 | */
70 | private Boolean isDisabled;
71 |
72 | /**
73 | * 是否外链
74 | */
75 | private Boolean isExt;
76 |
77 | /**
78 | * 是否缓存
79 | */
80 | private Boolean isKeepalive;
81 |
82 | /**
83 | * 是否缓存
84 | */
85 | private Boolean isShow;
86 | }
87 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/entity/SysRole.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableId;
5 | import com.baomidou.mybatisplus.annotation.TableName;
6 | import lombok.Data;
7 |
8 | import java.io.Serializable;
9 |
10 | /**
11 | * 角色表(Role)实体类
12 | *
13 | * @author tycoding
14 | * @since 2021/5/21
15 | */
16 | @Data
17 | @TableName("sys_role")
18 | public class SysRole implements Serializable {
19 | private static final long serialVersionUID = 547891924677981054L;
20 |
21 | /**
22 | * 主键
23 | */
24 | @TableId(type = IdType.ASSIGN_ID)
25 | private Long id;
26 |
27 | /**
28 | * 上级节点
29 | */
30 | private Long parentId;
31 |
32 | /**
33 | * 角色名称
34 | */
35 | private String name;
36 |
37 | /**
38 | * 角色别名
39 | */
40 | private String alias;
41 |
42 | /**
43 | * 描述
44 | */
45 | private String des;
46 |
47 | /**
48 | * 状态
49 | */
50 | private Boolean status;
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/entity/SysRoleMenu.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.TableName;
4 | import lombok.Data;
5 | import lombok.experimental.Accessors;
6 |
7 | import java.io.Serializable;
8 |
9 | /**
10 | * 角色资源关联表(RoleMenu)实体类
11 | *
12 | * @author tycoding
13 | * @since 2021/5/21
14 | */
15 | @Data
16 | @TableName("sys_role_menu")
17 | @Accessors(chain = true)
18 | public class SysRoleMenu implements Serializable {
19 | private static final long serialVersionUID = 854296054659457976L;
20 |
21 | /**
22 | * 角色ID
23 | */
24 | private Long roleId;
25 |
26 | /**
27 | * 菜单ID
28 | */
29 | private Long menuId;
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/entity/SysUser.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableId;
5 | import com.baomidou.mybatisplus.annotation.TableName;
6 | import lombok.Data;
7 |
8 | import java.io.Serializable;
9 | import java.util.Date;
10 |
11 | /**
12 | * 用户表(User)实体类
13 | *
14 | * @author tycoding
15 | * @since 2021/5/21
16 | */
17 | @Data
18 | @TableName("sys_user")
19 | public class SysUser implements Serializable {
20 | private static final long serialVersionUID = -94827981963832107L;
21 |
22 | /**
23 | * 主键
24 | */
25 | @TableId(type = IdType.ASSIGN_ID)
26 | private Long id;
27 |
28 | /**
29 | * 用户名
30 | */
31 | private String username;
32 |
33 | /**
34 | * 密码
35 | */
36 | private String password;
37 |
38 | /**
39 | * 真实姓名
40 | */
41 | private String realName;
42 |
43 | /**
44 | * 性别
45 | */
46 | private String sex;
47 |
48 | /**
49 | * 邮箱
50 | */
51 | private String email;
52 |
53 | /**
54 | * 部门ID
55 | */
56 | private Long deptId;
57 |
58 | /**
59 | * 头像
60 | */
61 | private String avatar;
62 |
63 | /**
64 | * 手机
65 | */
66 | private String phone;
67 |
68 | /**
69 | * 状态 0锁定 1有效
70 | */
71 | private Boolean status;
72 |
73 | /**
74 | * 创建时间
75 | */
76 | private Date createTime;
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/entity/SysUserRole.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.TableName;
4 | import lombok.Data;
5 | import lombok.experimental.Accessors;
6 |
7 | import java.io.Serializable;
8 |
9 | /**
10 | * 用户角色关联表(UserRole)实体类
11 | *
12 | * @author tycoding
13 | * @since 2021/5/21
14 | */
15 | @Data
16 | @TableName("sys_user_role")
17 | @Accessors(chain = true)
18 | public class SysUserRole implements Serializable {
19 | private static final long serialVersionUID = -24775118196826771L;
20 |
21 | /**
22 | * 用户ID
23 | */
24 | private Long userId;
25 |
26 | /**
27 | * 角色ID
28 | */
29 | private Long roleId;
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/mapper/SysDeptMapper.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.mapper;
2 |
3 | import cn.tycoding.boot.modules.upms.entity.SysDept;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 | import org.apache.ibatis.annotations.Mapper;
6 |
7 | /**
8 | * 部门表(Dept)表数据库访问层
9 | *
10 | * @author tycoding
11 | * @since 2021/5/21
12 | */
13 | @Mapper
14 | public interface SysDeptMapper extends BaseMapper {
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/mapper/SysMenuMapper.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.mapper;
2 |
3 | import cn.tycoding.boot.modules.upms.entity.SysMenu;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 | import org.apache.ibatis.annotations.Mapper;
6 | import org.apache.ibatis.annotations.Param;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * 菜单表(Menu)表数据库访问层
12 | *
13 | * @author tycoding
14 | * @since 2021/5/21
15 | */
16 | @Mapper
17 | public interface SysMenuMapper extends BaseMapper {
18 |
19 | List build(@Param("roleIds") List roleIds, @Param("type") String type);
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/mapper/SysRoleMapper.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.mapper;
2 |
3 | import cn.tycoding.boot.modules.upms.entity.SysRole;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 | import org.apache.ibatis.annotations.Mapper;
6 |
7 | /**
8 | * @author tycoding
9 | * @since 2021/5/21
10 | */
11 | @Mapper
12 | public interface SysRoleMapper extends BaseMapper {
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/mapper/SysRoleMenuMapper.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.mapper;
2 |
3 | import cn.tycoding.boot.modules.upms.entity.SysRoleMenu;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 | import org.apache.ibatis.annotations.Mapper;
6 |
7 | /**
8 | * 角色资源关联表(RoleMenu)表数据库访问层
9 | *
10 | * @author tycoding
11 | * @since 2021/5/21
12 | */
13 | @Mapper
14 | public interface SysRoleMenuMapper extends BaseMapper {
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/mapper/SysUserMapper.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.mapper;
2 |
3 | import cn.tycoding.boot.modules.upms.dto.SysUserDTO;
4 | import cn.tycoding.boot.modules.upms.entity.SysUser;
5 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
6 | import com.baomidou.mybatisplus.core.metadata.IPage;
7 | import org.apache.ibatis.annotations.Mapper;
8 |
9 | /**
10 | * 用户表(User)表数据库访问层
11 | *
12 | * @author tycoding
13 | * @since 2021/5/21
14 | */
15 | @Mapper
16 | public interface SysUserMapper extends BaseMapper {
17 |
18 | IPage page(IPage page, SysUserDTO user, Long ignoreId, String ignoreName);
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/mapper/SysUserRoleMapper.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.mapper;
2 |
3 | import cn.tycoding.boot.modules.upms.entity.SysRole;
4 | import cn.tycoding.boot.modules.upms.entity.SysUser;
5 | import cn.tycoding.boot.modules.upms.entity.SysUserRole;
6 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
7 | import org.apache.ibatis.annotations.Mapper;
8 |
9 | import java.util.List;
10 |
11 | /**
12 | * 用户角色关联表(UserRole)表数据库访问层
13 | *
14 | * @author tycoding
15 | * @since 2021/5/21
16 | */
17 | @Mapper
18 | public interface SysUserRoleMapper extends BaseMapper {
19 |
20 | /**
21 | * 根据RoleID查询User集合
22 | */
23 | List getUserListByRoleId(Long roleId);
24 |
25 | /**
26 | * 根据UserID查询Role集合
27 | */
28 | List getRoleListByUserId(Long userId);
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/service/SysDeptService.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.service;
2 |
3 | import cn.hutool.core.lang.tree.Tree;
4 | import cn.tycoding.boot.modules.upms.entity.SysDept;
5 | import com.baomidou.mybatisplus.extension.service.IService;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | * 部门表(Dept)表服务接口
11 | *
12 | * @author tycoding
13 | * @since 2021/5/21
14 | */
15 | public interface SysDeptService extends IService {
16 |
17 | /**
18 | * 条件查询
19 | */
20 | List list(SysDept sysDept);
21 |
22 | /**
23 | * 获取部门Tree
24 | */
25 | List> tree(SysDept sysDept);
26 |
27 | /**
28 | * 删除
29 | */
30 | void delete(Long id);
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/service/SysMenuService.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.service;
2 |
3 | import cn.tycoding.boot.modules.upms.dto.MenuTree;
4 | import cn.tycoding.boot.modules.upms.entity.SysMenu;
5 | import cn.tycoding.boot.modules.upms.entity.SysRole;
6 | import com.baomidou.mybatisplus.extension.service.IService;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * 菜单表(Menu)表服务接口
12 | *
13 | * @author tycoding
14 | * @since 2021/5/21
15 | */
16 | public interface SysMenuService extends IService {
17 |
18 | /**
19 | * 构建菜单Tree树
20 | */
21 | List> tree(SysMenu sysMenu);
22 |
23 | /**
24 | * 构建左侧权限菜单
25 | */
26 | List> build(Long userId);
27 |
28 | /**
29 | * 根据用户ID查询权限信息
30 | */
31 | List getUserMenuList(List sysRoleList);
32 |
33 | /**
34 | * 条件查询
35 | */
36 | List list(SysMenu sysMenu);
37 |
38 | /**
39 | * 新增
40 | */
41 | void add(SysMenu sysMenu);
42 |
43 | /**
44 | * 修改
45 | */
46 | void update(SysMenu sysMenu);
47 |
48 | /**
49 | * 删除
50 | */
51 | void delete(Long id);
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/service/SysRoleMenuService.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.service;
2 |
3 | import cn.tycoding.boot.modules.upms.entity.SysRoleMenu;
4 | import com.baomidou.mybatisplus.extension.service.IService;
5 |
6 | /**
7 | * 角色资源关联表(RoleMenu)表服务接口
8 | *
9 | * @author tycoding
10 | * @since 2021/5/21
11 | */
12 | public interface SysRoleMenuService extends IService {
13 |
14 | /**
15 | * 根据角色ID删除该角色的权限关联信息
16 | */
17 | void deleteRoleMenusByRoleId(Long roleId);
18 |
19 | /**
20 | * 根据权限ID删除角色权限关联信息
21 | */
22 | void deleteRoleMenusByMenuId(Long menuId);
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/service/SysRoleService.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.service;
2 |
3 | import cn.hutool.core.lang.tree.Tree;
4 | import cn.tycoding.boot.modules.upms.dto.SysRoleDTO;
5 | import cn.tycoding.boot.modules.upms.entity.SysRole;
6 | import com.baomidou.mybatisplus.extension.service.IService;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * 角色表(Role)表服务接口
12 | *
13 | * @author tycoding
14 | * @since 2021/5/21
15 | */
16 | public interface SysRoleService extends IService {
17 |
18 | /**
19 | * 根据用户ID查询其关联的所有角色
20 | */
21 | List findRolesByUserId(Long id);
22 |
23 | /**
24 | * 获取角色Tree集合
25 | */
26 | List> tree(SysRole sysRole);
27 |
28 | /**
29 | * 根据ID查询
30 | */
31 | SysRoleDTO findById(Long roleId);
32 |
33 | /**
34 | * 新增角色
35 | */
36 | void add(SysRoleDTO sysRole);
37 |
38 | /**
39 | * 修改角色
40 | */
41 | void update(SysRoleDTO sysRole);
42 |
43 | /**
44 | * 删除
45 | */
46 | void delete(Long id);
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/service/SysUserRoleService.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.service;
2 |
3 | import cn.tycoding.boot.modules.upms.entity.SysRole;
4 | import cn.tycoding.boot.modules.upms.entity.SysUser;
5 | import cn.tycoding.boot.modules.upms.entity.SysUserRole;
6 | import com.baomidou.mybatisplus.extension.service.IService;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * 用户角色关联表(UserRole)表服务接口
12 | *
13 | * @author tycoding
14 | * @since 2021/5/21
15 | */
16 | public interface SysUserRoleService extends IService {
17 |
18 | /**
19 | * 根据RoleID查询User集合
20 | */
21 | List getUserListByRoleId(Long roleId);
22 |
23 | /**
24 | * 根据UserID查询Role集合
25 | */
26 | List getRoleListByUserId(Long userId);
27 |
28 | /**
29 | * 根据用户ID删除该用户的角色关联信息
30 | */
31 | void deleteUserRolesByUserId(Long userId);
32 |
33 | /**
34 | * 根据角色ID删除该用户的角色关联信息
35 | */
36 | void deleteUserRolesByRoleId(Long roleId);
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/service/SysUserService.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.service;
2 |
3 | import cn.tycoding.boot.common.core.api.QueryPage;
4 | import cn.tycoding.boot.modules.auth.dto.UserInfo;
5 | import cn.tycoding.boot.modules.upms.dto.SysUserDTO;
6 | import cn.tycoding.boot.modules.upms.entity.SysUser;
7 | import com.baomidou.mybatisplus.core.metadata.IPage;
8 | import com.baomidou.mybatisplus.extension.service.IService;
9 |
10 | import java.util.List;
11 |
12 | /**
13 | * 用户表(User)表服务接口
14 | *
15 | * @author tycoding
16 | * @since 2021/5/21
17 | */
18 | public interface SysUserService extends IService {
19 |
20 | /**
21 | * 根据用户名查询
22 | */
23 | SysUser findByName(String username);
24 |
25 | /**
26 | * 根据ID查询
27 | */
28 | SysUserDTO findById(Long userId);
29 |
30 | /**
31 | * 根据用户名封装:用户信息、角色、部门、权限
32 | */
33 | UserInfo info(String username);
34 |
35 | /**
36 | * 条件查询
37 | */
38 | List list(SysUser sysUser);
39 |
40 | /**
41 | * 分页、条件查询
42 | */
43 | IPage page(SysUserDTO user, QueryPage queryPage);
44 |
45 | /**
46 | * 校验用户名是否存在
47 | */
48 | boolean checkName(SysUserDTO sysUser);
49 |
50 | /**
51 | * 新增
52 | */
53 | void add(SysUserDTO user);
54 |
55 | /**
56 | * 修改
57 | */
58 | void update(SysUserDTO user);
59 |
60 | /**
61 | * 删除
62 | */
63 | void delete(Long id, String username);
64 |
65 | /**
66 | * 重置密码
67 | */
68 | void reset(Long id, String password, String username);
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/java/cn/tycoding/boot/modules/upms/service/impl/SysDeptServiceImpl.java:
--------------------------------------------------------------------------------
1 | package cn.tycoding.boot.modules.upms.service.impl;
2 |
3 | import cn.hutool.core.collection.CollUtil;
4 | import cn.hutool.core.lang.Dict;
5 | import cn.hutool.core.lang.tree.Tree;
6 | import cn.hutool.core.lang.tree.TreeNode;
7 | import cn.hutool.core.lang.tree.TreeUtil;
8 | import cn.tycoding.boot.common.log.exception.ServiceException;
9 | import cn.tycoding.boot.modules.upms.entity.SysDept;
10 | import cn.tycoding.boot.modules.upms.mapper.SysDeptMapper;
11 | import cn.tycoding.boot.modules.upms.service.SysDeptService;
12 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
13 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
14 | import lombok.RequiredArgsConstructor;
15 | import org.springframework.stereotype.Service;
16 | import org.springframework.transaction.annotation.Transactional;
17 |
18 | import java.util.List;
19 |
20 | /**
21 | * 部门表(Dept)表服务实现类
22 | *
23 | * @author tycoding
24 | * @since 2021/5/21
25 | */
26 | @Service
27 | @RequiredArgsConstructor
28 | public class SysDeptServiceImpl extends ServiceImpl implements SysDeptService {
29 |
30 | @Override
31 | public List list(SysDept sysDept) {
32 | return baseMapper.selectList(new LambdaQueryWrapper()
33 | .orderByAsc(SysDept::getOrderNo));
34 | }
35 |
36 | @Override
37 | public List> tree(SysDept sysDept) {
38 | List sysDeptList = baseMapper.selectList(new LambdaQueryWrapper()
39 | .ne(sysDept.getId() != null, SysDept::getId, sysDept.getId()));
40 |
41 | // 构建树形结构
42 | List> nodeList = CollUtil.newArrayList();
43 | sysDeptList.forEach(t -> {
44 | TreeNode