Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
B
basic-api-boot
概览
概览
详情
活动
周期分析
版本库
存储库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
Basic
basic-api-boot
Commits
be944c68
提交
be944c68
authored
9月 23, 2022
作者:
方治民
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: 依赖升级、大量代码重构及优化、新增图片预处理、WebSocket、I18n 模块等
上级
611f6b3f
隐藏空白字符变更
内嵌
并排
正在显示
67 个修改的文件
包含
1530 行增加
和
356 行删除
+1530
-356
.gitlab-ci.yml
.gitlab-ci.yml
+11
-4
README.md
README.md
+2
-1
build.gradle
app/build.gradle
+15
-5
Application.java
app/src/main/java/com/yiring/app/Application.java
+0
-2
GlobalExceptionHandler.java
...in/java/com/yiring/app/config/GlobalExceptionHandler.java
+24
-12
Code.java
app/src/main/java/com/yiring/app/constant/Code.java
+1
-1
TestTable.java
app/src/main/java/com/yiring/app/domain/TestTable.java
+0
-49
TestTableMapper.java
app/src/main/java/com/yiring/app/mapper/TestTableMapper.java
+0
-12
package-info.java
app/src/main/java/com/yiring/app/mapper/package-info.java
+0
-7
UploadProcessServiceImpl.java
...m/yiring/app/service/upload/UploadProcessServiceImpl.java
+167
-0
ExampleController.java
...in/java/com/yiring/app/web/example/ExampleController.java
+2
-12
application-beta.yml
app/src/main/resources/application-beta.yml
+19
-17
application-conf-patch.yml
app/src/main/resources/application-conf-patch.yml
+6
-0
application-dev-mysql.yml
app/src/main/resources/application-dev-mysql.yml
+14
-13
application-dev-postgresql.yml
app/src/main/resources/application-dev-postgresql.yml
+12
-11
application-mock.yml
app/src/main/resources/application-mock.yml
+12
-12
application.yml
app/src/main/resources/application.yml
+8
-5
messages.properties
app/src/main/resources/i18n/messages/messages.properties
+1
-0
messages_zh_CN.properties
...rc/main/resources/i18n/messages/messages_zh_CN.properties
+5
-0
MapperSampleTest.java
app/src/test/java/com/yiring/MapperSampleTest.java
+0
-29
build.gradle
basic-auth/build.gradle
+1
-1
AuthIgnore.java
.../src/main/java/com/yiring/auth/annotation/AuthIgnore.java
+2
-0
SaTokenConfigure.java
...rc/main/java/com/yiring/auth/config/SaTokenConfigure.java
+8
-12
StpInterfaceImpl.java
...rc/main/java/com/yiring/auth/config/StpInterfaceImpl.java
+3
-1
Permission.java
...in/java/com/yiring/auth/domain/permission/Permission.java
+6
-8
Role.java
...-auth/src/main/java/com/yiring/auth/domain/role/Role.java
+3
-0
RoleRepository.java
...main/java/com/yiring/auth/domain/role/RoleRepository.java
+3
-0
Auths.java
basic-auth/src/main/java/com/yiring/auth/util/Auths.java
+48
-0
Permissions.java
...-auth/src/main/java/com/yiring/auth/util/Permissions.java
+24
-1
MenuVo.java
...h/src/main/java/com/yiring/auth/vo/permission/MenuVo.java
+1
-1
PermissionVo.java
...main/java/com/yiring/auth/vo/permission/PermissionVo.java
+1
-1
UserInfoVo.java
...uth/src/main/java/com/yiring/auth/vo/user/UserInfoVo.java
+3
-0
AuthController.java
...rc/main/java/com/yiring/auth/web/auth/AuthController.java
+6
-0
PermissionController.java
.../yiring/auth/web/sys/permission/PermissionController.java
+24
-12
RoleController.java
...ain/java/com/yiring/auth/web/sys/role/RoleController.java
+8
-17
UserController.java
...ain/java/com/yiring/auth/web/sys/user/UserController.java
+80
-0
UserViewController.java
...ain/java/com/yiring/auth/web/user/UserViewController.java
+3
-51
build.gradle
basic-common/core/build.gradle
+5
-1
RequestAspect.java
...src/main/java/com/yiring/common/aspect/RequestAspect.java
+7
-4
EnvConfig.java
...ore/src/main/java/com/yiring/common/config/EnvConfig.java
+40
-2
BasicEntity.java
...e/src/main/java/com/yiring/common/domain/BasicEntity.java
+8
-4
IdsParam.java
.../core/src/main/java/com/yiring/common/param/IdsParam.java
+3
-2
OptionalPageParam.java
.../main/java/com/yiring/common/param/OptionalPageParam.java
+7
-1
PageVo.java
...ommon/core/src/main/java/com/yiring/common/vo/PageVo.java
+32
-3
SwaggerConfig.java
...rc/main/java/com/yiring/common/swagger/SwaggerConfig.java
+10
-5
build.gradle
basic-common/i18n/build.gradle
+3
-0
I18nConfig.java
...8n/src/main/java/com/yiring/common/config/I18nConfig.java
+28
-0
I18n.java
...ommon/i18n/src/main/java/com/yiring/common/core/I18n.java
+67
-0
MinioConfig.java
...o/src/main/java/com/yiring/common/config/MinioConfig.java
+14
-3
Minio.java
...mon/minio/src/main/java/com/yiring/common/core/Minio.java
+34
-2
DownloadParam.java
.../src/main/java/com/yiring/common/param/DownloadParam.java
+1
-1
UploadProcessService.java
.../java/com/yiring/common/service/UploadProcessService.java
+28
-0
MinioController.java
.../src/main/java/com/yiring/common/web/MinioController.java
+51
-16
FileUtils.java
.../util/src/main/java/com/yiring/common/util/FileUtils.java
+38
-0
ImageInfo.java
...on/util/src/main/java/com/yiring/common/vo/ImageInfo.java
+64
-0
build.gradle
basic-websocket/build.gradle
+15
-0
WebSocketStompConfig.java
...ava/com/yiring/websocket/config/WebSocketStompConfig.java
+96
-0
RedisKey.java
...src/main/java/com/yiring/websocket/constant/RedisKey.java
+15
-0
StompPrincipal.java
...main/java/com/yiring/websocket/domain/StompPrincipal.java
+53
-0
ClientInboundChannelInterceptor.java
...ebsocket/interceptor/ClientInboundChannelInterceptor.java
+92
-0
ClientOutboundChannelInterceptor.java
...bsocket/interceptor/ClientOutboundChannelInterceptor.java
+41
-0
CustomStompUserRegistry.java
...om/yiring/websocket/registry/CustomStompUserRegistry.java
+94
-0
StompUserRegistry.java
...java/com/yiring/websocket/registry/StompUserRegistry.java
+48
-0
StompReceiver.java
...src/main/java/com/yiring/websocket/web/StompReceiver.java
+97
-0
build.gradle
build.gradle
+12
-14
gradle-wrapper.properties
gradle/wrapper/gradle-wrapper.properties
+1
-1
settings.gradle
settings.gradle
+3
-0
没有找到文件。
.gitlab-ci.yml
浏览文件 @
be944c68
...
@@ -33,7 +33,7 @@ build-job:
...
@@ -33,7 +33,7 @@ build-job:
before_script
:
before_script
:
-
chmod +x ./gradlew
-
chmod +x ./gradlew
script
:
script
:
-
./gradlew app:assemble -Dskip-hooks
-
./gradlew
:
app:assemble -Dskip-hooks
artifacts
:
artifacts
:
# 配置构建结果过期时间
# 配置构建结果过期时间
expire_in
:
1 day
expire_in
:
1 day
...
@@ -54,12 +54,19 @@ deploy-job:
...
@@ -54,12 +54,19 @@ deploy-job:
tags
:
tags
:
-
YR-CD
-
YR-CD
script
:
script
:
# 容器名
-
NAME=$CONTAINER_NAME-$CI_BUILD_REF_NAME
# 尝试停止并删除上一个容器
-
id=$(docker ps -aqf name=$NAME) && [ "$id" ] && docker stop $id && docker rm -f $id ||
true
# 尝试删除镜像(先删除再构建,避免产生 <none> image)
-
iid=$(docker images -aq $TAG) && [ "$iid" ] && docker rmi -f $iid ||
true
# 基于 Dockerfile 构建镜像
# 基于 Dockerfile 构建镜像
-
docker build -t $TAG .
-
docker build -t $TAG .
# 尝试删除上一个容器
# 条件判断
-
id=$(docker ps -aqf name=$CONTAINER_NAME) && [ "$id" ] && docker rm -f $id ||
true
-
PORT=$EXPOSE_PORT
-
echo "Branch:" $CI_BUILD_REF_NAME "PORT:" $PORT "Container:" $NAME
# 在本地运行构建好的镜像
# 在本地运行构建好的镜像
-
docker run -d --name $
CONTAINER_NAME -p $EXPOSE_
PORT:8081 -e TZ="Asia/Shanghai" $TAG
-
docker run -d --name $
NAME -p $
PORT:8081 -e TZ="Asia/Shanghai" $TAG
variables
:
variables
:
# 设置镜像 tag,使用 git tag 标识作为镜像 tag
# 设置镜像 tag,使用 git tag 标识作为镜像 tag
TAG
:
$REGISTRY_REMOTE/basic/$CONTAINER_NAME:$CI_BUILD_REF_NAME
TAG
:
$REGISTRY_REMOTE/basic/$CONTAINER_NAME:$CI_BUILD_REF_NAME
README.md
浏览文件 @
be944c68
...
@@ -26,6 +26,7 @@
...
@@ -26,6 +26,7 @@
-
[
x
]
完成项目构建,开发文档编写
-
[
x
]
完成项目构建,开发文档编写
-
[
x
]
[
conventional-changelog
]
(https://www.cnblogs.com/mengfangui/p/12634845.html)
-
[
x
]
[
conventional-changelog
]
(https://www.cnblogs.com/mengfangui/p/12634845.html)
-
[
x
]
用户及权限模块(目录/菜单/按钮),预览初始化权限配置
[
SQL 脚本
](
./basic-auth/src/main/resources/init-test-mysql.sql
)
-
[
x
]
用户及权限模块(目录/菜单/按钮),预览初始化权限配置
[
SQL 脚本
](
./basic-auth/src/main/resources/init-test-mysql.sql
)
-
[
x
]
通用文件上传模块
-
[
x
]
通用文件上传模块,支持对图片/PDF/MP3/MP4 等文件进行预处理
-
[
x
]
WebSocket 模块
-
[
]
通用字典管理模块
-
[
]
通用字典管理模块
-
[
]
XXL-JOB 定时任务模块
-
[
]
XXL-JOB 定时任务模块
app/build.gradle
浏览文件 @
be944c68
...
@@ -22,6 +22,9 @@ dependencies {
...
@@ -22,6 +22,9 @@ dependencies {
implementation
project
(
":basic-common:core"
)
implementation
project
(
":basic-common:core"
)
implementation
project
(
":basic-common:util"
)
implementation
project
(
":basic-common:util"
)
// Optional: I18n 消息, 包括参数校验、失败的请求提示等
implementation
project
(
":basic-common:i18n"
)
// Optional: Redis
// Optional: Redis
implementation
project
(
":basic-common:redis"
)
implementation
project
(
":basic-common:redis"
)
...
@@ -33,22 +36,29 @@ dependencies {
...
@@ -33,22 +36,29 @@ dependencies {
implementation
project
(
":basic-auth"
)
implementation
project
(
":basic-auth"
)
implementation
"cn.dev33:sa-token-spring-boot-starter:${saTokenVersion}"
implementation
"cn.dev33:sa-token-spring-boot-starter:${saTokenVersion}"
// Optional: WebSocket && STOMP 依赖 Auth + Redis 模块
implementation
project
(
":basic-websocket"
)
// Optional: Minio S3
// Optional: Minio S3
implementation
project
(
":basic-common:minio"
)
implementation
project
(
":basic-common:minio"
)
// FIX: minio dep
// FIX: minio dep
implementation
"io.minio:minio:${minioVersion}"
implementation
"com.squareup.okhttp3:okhttp:${okhttpVersion}"
implementation
"com.squareup.okhttp3:okhttp:${okhttpVersion}"
// Optional: 扩展实现在文件上传时对文件进行预处理,依赖 Minio 模块
// Optional: MyBatis Plus
// https://mvnrepository.com/artifact/org.bytedeco/javacv
implementation
"com.baomidou:mybatis-plus-boot-starter:${mybatisPlusVersion}"
implementation
'org.bytedeco:javacv:1.5.7'
// https://mvnrepository.com/artifact/org.bytedeco/ffmpeg-platform
implementation
'org.bytedeco:ffmpeg-platform:5.0-1.5.7'
// https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox
implementation
'org.apache.pdfbox:pdfbox:2.0.26'
// fastjson
// fastjson
implementation
"com.alibaba
:fastjson
:${fastJsonVersion}"
implementation
"com.alibaba
.fastjson2:fastjson2
:${fastJsonVersion}"
// hutool
// hutool
implementation
"cn.hutool:hutool-core:${hutoolVersion}"
implementation
"cn.hutool:hutool-core:${hutoolVersion}"
implementation
"cn.hutool:hutool-extra:${hutoolVersion}"
implementation
"cn.hutool:hutool-extra:${hutoolVersion}"
// https://github.com/vladmihalcea/hibernate-types
// https://github.com/vladmihalcea/hibernate-types
// hibernate-types-55
implementation
"com.vladmihalcea:hibernate-types-55:${hibernateTypesVersion}"
implementation
"com.vladmihalcea:hibernate-types-55:${hibernateTypesVersion}"
}
}
app/src/main/java/com/yiring/app/Application.java
浏览文件 @
be944c68
/* (C) 2021 YiRing, Inc. */
/* (C) 2021 YiRing, Inc. */
package
com
.
yiring
.
app
;
package
com
.
yiring
.
app
;
import
org.mybatis.spring.annotation.MapperScan
;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.boot.autoconfigure.SpringBootApplication
;
import
org.springframework.boot.autoconfigure.SpringBootApplication
;
import
org.springframework.boot.autoconfigure.domain.EntityScan
;
import
org.springframework.boot.autoconfigure.domain.EntityScan
;
import
org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters
;
import
org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters
;
import
org.springframework.data.jpa.repository.config.EnableJpaRepositories
;
import
org.springframework.data.jpa.repository.config.EnableJpaRepositories
;
@MapperScan
(
basePackages
=
Application
.
BASE_PACKAGES
+
".app.mapper"
)
@EnableJpaRepositories
(
basePackages
=
Application
.
BASE_PACKAGES
)
@EnableJpaRepositories
(
basePackages
=
Application
.
BASE_PACKAGES
)
@EntityScan
(
@EntityScan
(
basePackageClasses
=
{
Application
.
class
,
Jsr310JpaConverters
.
class
},
basePackageClasses
=
{
Application
.
class
,
Jsr310JpaConverters
.
class
},
...
...
app/src/main/java/com/yiring/app/config/GlobalExceptionHandler.java
浏览文件 @
be944c68
...
@@ -4,20 +4,26 @@ package com.yiring.app.config;
...
@@ -4,20 +4,26 @@ package com.yiring.app.config;
import
cn.dev33.satoken.exception.NotLoginException
;
import
cn.dev33.satoken.exception.NotLoginException
;
import
com.yiring.app.constant.Code
;
import
com.yiring.app.constant.Code
;
import
com.yiring.app.exception.CodeException
;
import
com.yiring.app.exception.CodeException
;
import
com.yiring.common.core.I18n
;
import
com.yiring.common.core.Result
;
import
com.yiring.common.core.Result
;
import
com.yiring.common.core.Status
;
import
com.yiring.common.core.Status
;
import
com.yiring.common.exception.FailStatusException
;
import
com.yiring.common.exception.FailStatusException
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.validation.ConstraintViolationException
;
import
javax.validation.ConstraintViolationException
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.catalina.connector.ClientAbortException
;
import
org.apache.catalina.connector.ClientAbortException
;
import
org.aspectj.bridge.AbortException
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.converter.HttpMessageNotWritableException
;
import
org.springframework.validation.BindException
;
import
org.springframework.validation.BindException
;
import
org.springframework.validation.BindingResult
;
import
org.springframework.validation.BindingResult
;
import
org.springframework.validation.ObjectError
;
import
org.springframework.web.HttpRequestMethodNotSupportedException
;
import
org.springframework.web.HttpRequestMethodNotSupportedException
;
import
org.springframework.web.bind.MethodArgumentNotValidException
;
import
org.springframework.web.bind.MethodArgumentNotValidException
;
import
org.springframework.web.bind.annotation.ControllerAdvice
;
import
org.springframework.web.bind.annotation.ControllerAdvice
;
import
org.springframework.web.bind.annotation.ExceptionHandler
;
import
org.springframework.web.bind.annotation.ExceptionHandler
;
import
org.springframework.web.bind.annotation.ResponseBody
;
import
org.springframework.web.bind.annotation.ResponseBody
;
import
org.springframework.web.bind.annotation.ResponseStatus
;
/**
/**
* 全局错误处理
* 全局错误处理
...
@@ -28,8 +34,11 @@ import org.springframework.web.bind.annotation.ResponseBody;
...
@@ -28,8 +34,11 @@ import org.springframework.web.bind.annotation.ResponseBody;
@Slf4j
@Slf4j
@ControllerAdvice
@ControllerAdvice
@ResponseBody
@ResponseBody
@RequiredArgsConstructor
public
class
GlobalExceptionHandler
{
public
class
GlobalExceptionHandler
{
final
I18n
i18n
;
/**
/**
* 参数校验异常
* 参数校验异常
*
*
...
@@ -40,7 +49,7 @@ public class GlobalExceptionHandler {
...
@@ -40,7 +49,7 @@ public class GlobalExceptionHandler {
value
=
{
BindException
.
class
,
MethodArgumentNotValidException
.
class
,
ConstraintViolationException
.
class
}
value
=
{
BindException
.
class
,
MethodArgumentNotValidException
.
class
,
ConstraintViolationException
.
class
}
)
)
public
Result
<
String
>
bindErrorHandler
(
Exception
e
)
{
public
Result
<
String
>
bindErrorHandler
(
Exception
e
)
{
String
error
=
"未知参数校验错误"
;
String
error
=
null
;
if
(
e
instanceof
ConstraintViolationException
)
{
if
(
e
instanceof
ConstraintViolationException
)
{
error
=
((
ConstraintViolationException
)
e
).
getConstraintViolations
().
iterator
().
next
().
getMessage
();
error
=
((
ConstraintViolationException
)
e
).
getConstraintViolations
().
iterator
().
next
().
getMessage
();
...
@@ -53,7 +62,8 @@ public class GlobalExceptionHandler {
...
@@ -53,7 +62,8 @@ public class GlobalExceptionHandler {
}
}
if
(
result
!=
null
)
{
if
(
result
!=
null
)
{
error
=
result
.
getAllErrors
().
iterator
().
next
().
getDefaultMessage
();
ObjectError
next
=
result
.
getAllErrors
().
iterator
().
next
();
error
=
i18n
.
get
(
next
);
}
}
}
}
...
@@ -66,7 +76,7 @@ public class GlobalExceptionHandler {
...
@@ -66,7 +76,7 @@ public class GlobalExceptionHandler {
* @param e 异常信息
* @param e 异常信息
* @return 异常信息反馈 {@link Status#METHOD_NOT_ALLOWED
* @return 异常信息反馈 {@link Status#METHOD_NOT_ALLOWED
*/
*/
@ExceptionHandler
(
value
=
HttpRequestMethodNotSupportedException
.
class
)
@ExceptionHandler
(
HttpRequestMethodNotSupportedException
.
class
)
public
Result
<
String
>
httpRequestMethodNotSupportedErrorHandler
(
Exception
e
)
{
public
Result
<
String
>
httpRequestMethodNotSupportedErrorHandler
(
Exception
e
)
{
return
Result
.
no
(
Status
.
METHOD_NOT_ALLOWED
,
e
.
getMessage
());
return
Result
.
no
(
Status
.
METHOD_NOT_ALLOWED
,
e
.
getMessage
());
}
}
...
@@ -76,7 +86,7 @@ public class GlobalExceptionHandler {
...
@@ -76,7 +86,7 @@ public class GlobalExceptionHandler {
*
*
* @return 异常信息反馈 {@link Status#UNAUTHORIZED
* @return 异常信息反馈 {@link Status#UNAUTHORIZED
*/
*/
@ExceptionHandler
(
value
=
NotLoginException
.
class
)
@ExceptionHandler
(
NotLoginException
.
class
)
public
Result
<
String
>
notLoginErrorHandler
()
{
public
Result
<
String
>
notLoginErrorHandler
()
{
return
Result
.
no
(
Status
.
UNAUTHORIZED
);
return
Result
.
no
(
Status
.
UNAUTHORIZED
);
}
}
...
@@ -84,7 +94,7 @@ public class GlobalExceptionHandler {
...
@@ -84,7 +94,7 @@ public class GlobalExceptionHandler {
/**
/**
* 自定义业务异常
* 自定义业务异常
*/
*/
@ExceptionHandler
(
value
=
CodeException
.
class
)
@ExceptionHandler
(
CodeException
.
class
)
public
Result
<
String
>
customCodeExceptionHandler
(
CodeException
e
)
{
public
Result
<
String
>
customCodeExceptionHandler
(
CodeException
e
)
{
Code
code
=
e
.
getCode
();
Code
code
=
e
.
getCode
();
return
Result
.
no
(
Status
.
BAD_REQUEST
,
code
.
value
(),
code
.
reason
(),
null
);
return
Result
.
no
(
Status
.
BAD_REQUEST
,
code
.
value
(),
code
.
reason
(),
null
);
...
@@ -93,15 +103,17 @@ public class GlobalExceptionHandler {
...
@@ -93,15 +103,17 @@ public class GlobalExceptionHandler {
/**
/**
* 失败状态异常
* 失败状态异常
*/
*/
@ExceptionHandler
(
value
=
FailStatusException
.
class
)
@ExceptionHandler
(
FailStatusException
.
class
)
public
Result
<
String
>
failStatusExceptionHandler
(
FailStatusException
e
)
{
public
Result
<
String
>
failStatusExceptionHandler
(
FailStatusException
e
)
{
return
Result
.
no
(
e
.
getStatus
(),
e
.
getMessage
(
));
return
Result
.
no
(
e
.
getStatus
(),
i18n
.
get
(
e
.
getMessage
(),
e
.
getStatus
().
getReasonPhrase
()
));
}
}
/**
/**
* 取消请求异常(忽略)
* 取消请求异常(忽略)
*/
*/
@ExceptionHandler
(
value
=
ClientAbortException
.
class
)
@ExceptionHandler
(
value
=
{
ClientAbortException
.
class
,
AbortException
.
class
,
HttpMessageNotWritableException
.
class
}
)
public
void
clientAbortExceptionHandler
()
{}
public
void
clientAbortExceptionHandler
()
{}
/**
/**
...
@@ -110,9 +122,9 @@ public class GlobalExceptionHandler {
...
@@ -110,9 +122,9 @@ public class GlobalExceptionHandler {
* @param e 异常信息
* @param e 异常信息
* @return 统一的500异常信息 {@link Status#INTERNAL_SERVER_ERROR
* @return 统一的500异常信息 {@link Status#INTERNAL_SERVER_ERROR
*/
*/
@
ExceptionHandler
(
value
=
Exception
.
class
)
@
ResponseStatus
(
code
=
HttpStatus
.
INTERNAL_SERVER_ERROR
)
public
Result
<
String
>
defaultErrorHandler
(
Exception
e
,
HttpServletResponse
response
)
{
@ExceptionHandler
(
Exception
.
class
)
response
.
setStatus
(
Status
.
INTERNAL_SERVER_ERROR
.
value
());
public
Result
<
String
>
defaultErrorHandler
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
log
.
error
(
e
.
getMessage
(),
e
);
return
Result
.
no
(
Status
.
INTERNAL_SERVER_ERROR
,
e
);
return
Result
.
no
(
Status
.
INTERNAL_SERVER_ERROR
,
e
);
}
}
...
...
app/src/main/java/com/yiring/app/constant/Code.java
浏览文件 @
be944c68
...
@@ -5,7 +5,7 @@ import com.yiring.app.exception.CodeException;
...
@@ -5,7 +5,7 @@ import com.yiring.app.exception.CodeException;
import
io.swagger.annotations.ApiModel
;
import
io.swagger.annotations.ApiModel
;
/**
/**
* 业务状态码
* 业务状态码
(TODO: 结合 spring message i18n)
* eg: <code>throw new CodeException(Code.FAIL)</code>
* eg: <code>throw new CodeException(Code.FAIL)</code>
*
*
* @author Jim
* @author Jim
...
...
app/src/main/java/com/yiring/app/domain/TestTable.java
deleted
100644 → 0
浏览文件 @
611f6b3f
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
app
.
domain
;
import
com.baomidou.mybatisplus.annotation.TableName
;
import
java.io.Serial
;
import
java.io.Serializable
;
import
javax.persistence.Entity
;
import
javax.persistence.Id
;
import
javax.persistence.Table
;
import
lombok.*
;
import
lombok.experimental.FieldDefaults
;
import
lombok.experimental.FieldNameConstants
;
import
org.hibernate.annotations.Comment
;
/**
* 测试表
*
* @author Jim
* @version 0.1
* 2022/4/15 18:34
*/
@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@FieldDefaults
(
level
=
AccessLevel
.
PRIVATE
)
@Entity
@TableName
(
"TEST_TABLE"
)
@Table
(
name
=
"TEST_TABLE"
)
@Comment
(
"测试表"
)
public
class
TestTable
implements
Serializable
{
@Serial
private
static
final
long
serialVersionUID
=
-
6168070383092874608L
;
@Comment
(
"主键"
)
@Id
String
id
;
@Comment
(
"姓名"
)
String
name
;
@Comment
(
"年龄"
)
Integer
age
;
}
app/src/main/java/com/yiring/app/mapper/TestTableMapper.java
deleted
100644 → 0
浏览文件 @
611f6b3f
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
app
.
mapper
;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
import
com.yiring.app.domain.TestTable
;
/**
* @author Jim
* @version 0.1
* 2022/4/15 17:25
*/
public
interface
TestTableMapper
extends
BaseMapper
<
TestTable
>
{}
app/src/main/java/com/yiring/app/mapper/package-info.java
deleted
100644 → 0
浏览文件 @
611f6b3f
/**
* @author Jim
* @version 0.1
* 2022/4/5 16:57
*/
package
com
.
yiring
.
app
.
mapper
;
// MyBatis Mapper/XML 目录
app/src/main/java/com/yiring/app/service/upload/UploadProcessServiceImpl.java
0 → 100644
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
app
.
service
.
upload
;
import
cn.hutool.core.io.FileUtil
;
import
com.yiring.common.core.Minio
;
import
com.yiring.common.service.UploadProcessService
;
import
java.awt.image.BufferedImage
;
import
java.awt.image.RenderedImage
;
import
java.io.ByteArrayInputStream
;
import
java.io.ByteArrayOutputStream
;
import
java.io.InputStream
;
import
java.util.List
;
import
javax.imageio.ImageIO
;
import
lombok.Cleanup
;
import
lombok.RequiredArgsConstructor
;
import
lombok.SneakyThrows
;
import
org.apache.pdfbox.pdmodel.PDDocument
;
import
org.apache.pdfbox.rendering.PDFRenderer
;
import
org.bytedeco.javacv.FFmpegFrameGrabber
;
import
org.bytedeco.javacv.Frame
;
import
org.bytedeco.javacv.Java2DFrameConverter
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnClass
;
import
org.springframework.http.MediaType
;
import
org.springframework.stereotype.Component
;
/**
* @author Jim
* @version 0.1
* 2022/9/23 16:44
*/
@ConditionalOnClass
({
PDDocument
.
class
,
FFmpegFrameGrabber
.
class
})
@Component
@RequiredArgsConstructor
public
class
UploadProcessServiceImpl
implements
UploadProcessService
{
final
Minio
minio
;
@Override
public
String
handle
(
String
object
,
InputStream
is
)
{
String
suffix
=
FileUtil
.
getSuffix
(
object
);
// Image: 在文件名上追加图片物理像素
if
(
isSupportiveImage
(
suffix
))
{
object
=
handleImage
(
object
,
is
);
}
// PDF: 在文件名上追加页数,同时在同目录生成 PDF 每一页的图片
if
(
isPdf
(
suffix
))
{
object
=
handlePdf
(
object
,
is
);
}
// Video/Audio: 在文件名上追加时长,视频生成封面图
if
(
isSupportiveMedia
(
suffix
))
{
object
=
handleMedia
(
object
,
suffix
,
is
);
}
return
object
;
}
@SneakyThrows
public
String
handleImage
(
String
object
,
InputStream
is
)
{
BufferedImage
image
=
ImageIO
.
read
(
is
);
return
fillSuffix
(
object
,
image
.
getWidth
()
+
"x"
+
image
.
getHeight
());
}
@SneakyThrows
public
String
handlePdf
(
String
object
,
InputStream
is
)
{
PDDocument
doc
=
PDDocument
.
load
(
is
);
int
pages
=
doc
.
getNumberOfPages
();
// 构建具有 PDF 页数标记的存储地址
String
filepath
=
fillSuffix
(
object
,
"P"
+
pages
);
// 将 PDF 解析成图片上传
String
format
=
"jpg"
;
PDFRenderer
renderer
=
new
PDFRenderer
(
doc
);
for
(
int
i
=
0
;
i
<
pages
;
i
++)
{
@Cleanup
ByteArrayOutputStream
os
=
new
ByteArrayOutputStream
();
BufferedImage
image
=
renderer
.
renderImageWithDPI
(
i
,
144
);
ImageIO
.
write
(
image
,
format
,
os
);
@Cleanup
InputStream
io
=
new
ByteArrayInputStream
(
os
.
toByteArray
());
minio
.
putObject
(
io
,
MediaType
.
IMAGE_JPEG_VALUE
,
filepath
+
"."
+
(
i
+
1
)
+
"."
+
format
);
}
return
filepath
;
}
@SneakyThrows
public
String
handleMedia
(
String
object
,
String
suffix
,
InputStream
is
)
{
// 判断是否为视频
@Cleanup
FFmpegFrameGrabber
ff
=
new
FFmpegFrameGrabber
(
is
);
ff
.
start
();
// 构建具有时长(秒)标记的存储地址
String
filepath
=
fillSuffix
(
object
,
"T"
+
(
ff
.
getLengthInTime
()
/
(
1000
*
1000
)));
// 视频截取首帧可见画面作为封面
if
(
isSupportiveVideo
(
suffix
))
{
// 获取视频可见画面帧
Frame
frame
=
getPictureFrame
(
ff
);
// 将截取的封面并存储
String
format
=
"jpg"
;
@Cleanup
ByteArrayOutputStream
os
=
new
ByteArrayOutputStream
();
ImageIO
.
write
(
frameToBufferedImage
(
frame
),
format
,
os
);
@Cleanup
InputStream
io
=
new
ByteArrayInputStream
(
os
.
toByteArray
());
minio
.
putObject
(
io
,
MediaType
.
IMAGE_JPEG_VALUE
,
filepath
+
"."
+
format
);
}
ff
.
stop
();
return
filepath
;
}
public
static
Frame
getPictureFrame
(
FFmpegFrameGrabber
grabber
)
throws
FFmpegFrameGrabber
.
Exception
{
int
ftp
=
grabber
.
getLengthInFrames
();
int
flag
=
0
;
Frame
frame
=
null
;
while
(
flag
<=
ftp
)
{
//获取帧
frame
=
grabber
.
grabImage
();
//过滤前3帧,避免出现全黑图片
if
((
flag
>
3
)
&&
(
frame
!=
null
))
{
break
;
}
flag
++;
}
return
frame
;
}
public
static
RenderedImage
frameToBufferedImage
(
Frame
frame
)
{
@Cleanup
Java2DFrameConverter
converter
=
new
Java2DFrameConverter
();
return
converter
.
getBufferedImage
(
frame
);
}
public
static
boolean
isSupportiveMedia
(
String
suffix
)
{
return
isSupportiveVideo
(
suffix
)
||
isSupportiveAudio
(
suffix
);
}
public
static
boolean
isSupportiveVideo
(
String
suffix
)
{
return
List
.
of
(
"mp4"
,
"flv"
,
"avi"
,
"rmvb"
,
"rm"
,
"wmv"
,
"mkv"
,
"mpg"
,
"mpeg"
).
contains
(
suffix
.
toLowerCase
());
}
public
static
boolean
isSupportiveAudio
(
String
suffix
)
{
return
List
.
of
(
"mp3"
,
"wav"
).
contains
(
suffix
.
toLowerCase
());
}
public
static
boolean
isSupportiveImage
(
String
suffix
)
{
return
List
.
of
(
"png"
,
"jpg"
,
"webp"
,
"gif"
,
"tif"
,
"svg"
,
"bmp"
).
contains
(
suffix
.
toLowerCase
());
}
public
static
boolean
isPdf
(
String
suffix
)
{
return
"pdf"
.
equalsIgnoreCase
(
suffix
);
}
public
static
String
fillSuffix
(
String
object
,
String
fill
)
{
String
suffix
=
FileUtil
.
getSuffix
(
object
);
String
regex
=
"^(.*)\\."
+
suffix
+
"$"
;
return
object
.
replaceAll
(
regex
,
"$1."
+
fill
+
"."
+
suffix
);
}
}
app/src/main/java/com/yiring/app/web/example/ExampleController.java
浏览文件 @
be944c68
...
@@ -2,13 +2,10 @@
...
@@ -2,13 +2,10 @@
package
com
.
yiring
.
app
.
web
.
example
;
package
com
.
yiring
.
app
.
web
.
example
;
import
cn.dev33.satoken.annotation.SaCheckLogin
;
import
cn.dev33.satoken.annotation.SaCheckLogin
;
import
cn.hutool.extra.spring.SpringUtil
;
import
com.github.xiaoymin.knife4j.annotations.ApiSupport
;
import
com.github.xiaoymin.knife4j.annotations.ApiSupport
;
import
com.yiring.app.constant.Code
;
import
com.yiring.app.constant.Code
;
import
com.yiring.app.domain.TestTable
;
import
com.yiring.app.domain.user.UserExtension
;
import
com.yiring.app.domain.user.UserExtension
;
import
com.yiring.app.domain.user.UserExtensionRepository
;
import
com.yiring.app.domain.user.UserExtensionRepository
;
import
com.yiring.app.mapper.TestTableMapper
;
import
com.yiring.app.vo.user.UserExtensionVo
;
import
com.yiring.app.vo.user.UserExtensionVo
;
import
com.yiring.auth.annotation.AuthIgnore
;
import
com.yiring.auth.annotation.AuthIgnore
;
import
com.yiring.auth.domain.user.User
;
import
com.yiring.auth.domain.user.User
;
...
@@ -25,7 +22,6 @@ import java.util.Arrays;
...
@@ -25,7 +22,6 @@ import java.util.Arrays;
import
java.util.List
;
import
java.util.List
;
import
java.util.Optional
;
import
java.util.Optional
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.validation.Valid
;
import
lombok.RequiredArgsConstructor
;
import
lombok.RequiredArgsConstructor
;
import
lombok.SneakyThrows
;
import
lombok.SneakyThrows
;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
...
@@ -70,8 +66,9 @@ public class ExampleController {
...
@@ -70,8 +66,9 @@ public class ExampleController {
throw
Code
.
FAIL
.
exception
();
throw
Code
.
FAIL
.
exception
();
}
}
@SaCheckLogin
@GetMapping
(
"page"
)
@GetMapping
(
"page"
)
public
Result
<
PageVo
<
String
>>
page
(
@Valid
PageParam
pageParam
)
{
public
Result
<
PageVo
<
String
>>
page
(
@Valid
ated
PageParam
pageParam
)
{
log
.
info
(
"PageParam: {}"
,
pageParam
);
log
.
info
(
"PageParam: {}"
,
pageParam
);
List
<
String
>
data
=
Arrays
.
asList
(
text
.
split
(
" "
));
List
<
String
>
data
=
Arrays
.
asList
(
text
.
split
(
" "
));
...
@@ -88,13 +85,6 @@ public class ExampleController {
...
@@ -88,13 +85,6 @@ public class ExampleController {
FileUtils
.
download
(
response
,
resource
.
getFile
());
FileUtils
.
download
(
response
,
resource
.
getFile
());
}
}
@ApiOperation
(
"测试 MyBatis Plus 查询"
)
@GetMapping
(
"test"
)
public
Result
<
String
>
test
()
{
List
<
TestTable
>
tests
=
SpringUtil
.
getBean
(
TestTableMapper
.
class
).
selectList
(
null
);
return
Result
.
ok
(
tests
.
stream
().
map
(
TestTable:
:
getName
).
reduce
((
a
,
b
)
->
a
+
","
+
b
).
orElse
(
""
));
}
@SaCheckLogin
@SaCheckLogin
@ApiOperation
(
"查询用户属性"
)
@ApiOperation
(
"查询用户属性"
)
@GetMapping
(
"findUserExtensionInfo"
)
@GetMapping
(
"findUserExtensionInfo"
)
...
...
app/src/main/resources/application-beta.yml
浏览文件 @
be944c68
# 环境变量
# 环境变量
env
:
env
:
host
:
192.168.0.156
host
:
192.168.0.156
prod
:
false
extra
:
username
:
admin
password
:
Hd)XZgtCa&NG~oe@
spring
:
spring
:
datasource
:
datasource
:
url
:
jdbc:
mysql://${env.host}:3306/basic_app?useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
url
:
jdbc:
postgresql://${env.host}:5432/basic_app
username
:
root
username
:
${env.extra.username}
password
:
123456
password
:
${env.extra.password}
jpa
:
jpa
:
database-platform
:
org.hibernate.dialect.
MySQL8
Dialect
database-platform
:
org.hibernate.dialect.
PostgreSQL10
Dialect
open-in-view
:
true
open-in-view
:
true
hibernate
:
hibernate
:
ddl-auto
:
update
ddl-auto
:
update
show-sql
:
fals
e
show-sql
:
tru
e
properties
:
properties
:
hibernate
:
hibernate
:
format_sql
:
true
format_sql
:
true
...
@@ -20,32 +24,30 @@ spring:
...
@@ -20,32 +24,30 @@ spring:
database
:
5
database
:
5
host
:
${env.host}
host
:
${env.host}
port
:
6379
port
:
6379
password
:
${env.extra.password}
# Optional: MyBatis Plus
mybatis-plus
:
global-config
:
banner
:
false
# knife4j
# knife4j
knife4j
:
knife4j
:
enable
:
true
enable
:
true
basic
:
basic
:
enable
:
false
enable
:
false
username
:
admin
username
:
${env.extra.username}
password
:
123456
password
:
${env.extra.password}
setting
:
setting
:
enableOpenApi
:
fals
e
enableOpenApi
:
tru
e
enableDebug
:
true
enableDebug
:
true
# minio
# minio
minio
:
minio
:
access-key
:
minioadmin
access-key
:
${env.extra.username}
secret-key
:
minioadmin
secret-key
:
${env.extra.password}
end-point
:
"
http://${env.host}:18100"
end-point
:
"
http://${env.host}:18100"
bucket
:
public
bucket
:
public
domain
:
${minio.endpoint}
domain
:
${minio.end
-
point}
logging
:
logging
:
level
:
level
:
# sql bind parameter
# sql bind parameter
org.hibernate.type.descriptor.sql.BasicBinder
:
fatal
org.hibernate.type.descriptor.sql.BasicBinder
:
trace
# request log
com.yiring.common.aspect.RequestAspect
:
info
app/src/main/resources/application-conf-patch.yml
浏览文件 @
be944c68
...
@@ -8,8 +8,14 @@ spring:
...
@@ -8,8 +8,14 @@ spring:
hibernate
:
hibernate
:
# 关闭 hibernate-types banner 日志信息
# 关闭 hibernate-types banner 日志信息
types.print.banner
:
false
types.print.banner
:
false
data
:
redis
:
repositories
:
enabled
:
false
logging
:
logging
:
level
:
level
:
# 关闭接口扫描 CachingOperationNameGenerator 日志
# 关闭接口扫描 CachingOperationNameGenerator 日志
springfox.documentation.spring.web.readers.operation.CachingOperationNameGenerator
:
WARN
springfox.documentation.spring.web.readers.operation.CachingOperationNameGenerator
:
WARN
# 关闭接口扫描 ApiListingReferenceScanner 日志
springfox.documentation.spring.web.scanners.ApiListingReferenceScanner
:
WARN
app/src/main/resources/application-dev-mysql.yml
浏览文件 @
be944c68
# 环境变量
# 环境变量
env
:
env
:
host
:
127.0.0.1
host
:
127.0.0.1
prod
:
false
extra
:
username
:
admin
password
:
Hd)XZgtCa&NG~oe@
spring
:
spring
:
datasource
:
datasource
:
url
:
jdbc:mysql://${env.host}:3306/basic_app?useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
url
:
jdbc:mysql://${env.host}:3306/basic_app?useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username
:
root
username
:
${env.extra.username}
password
:
123456
password
:
${env.extra.password}
jpa
:
jpa
:
database-platform
:
org.hibernate.dialect.MySQL8Dialect
database-platform
:
org.hibernate.dialect.MySQL8Dialect
open-in-view
:
true
open-in-view
:
true
...
@@ -20,33 +24,30 @@ spring:
...
@@ -20,33 +24,30 @@ spring:
database
:
5
database
:
5
host
:
${env.host}
host
:
${env.host}
port
:
6379
port
:
6379
password
:
123456
password
:
${env.extra.password}
# Optional: MyBatis Plus
mybatis-plus
:
global-config
:
banner
:
false
# knife4j
# knife4j
knife4j
:
knife4j
:
enable
:
true
enable
:
true
basic
:
basic
:
enable
:
false
enable
:
false
username
:
admin
username
:
${env.extra.username}
password
:
123456
password
:
${env.extra.password}
setting
:
setting
:
enableOpenApi
:
false
enableOpenApi
:
false
enableDebug
:
true
enableDebug
:
true
# minio
# minio
minio
:
minio
:
access-key
:
minioadmin
access-key
:
${env.extra.username}
secret-key
:
minioadmin
secret-key
:
${env.extra.password}
end-point
:
"
http://${env.host}:18100"
end-point
:
"
http://${env.host}:18100"
bucket
:
public
bucket
:
public
domain
:
${minio.endpoint}
domain
:
${minio.end
-
point}
logging
:
logging
:
level
:
level
:
# sql bind parameter
# sql bind parameter
org.hibernate.type.descriptor.sql.BasicBinder
:
trace
org.hibernate.type.descriptor.sql.BasicBinder
:
trace
# request log
com.yiring.common.aspect.RequestAspect
:
info
app/src/main/resources/application-dev-postgresql.yml
浏览文件 @
be944c68
# 环境变量
# 环境变量
env
:
env
:
host
:
192.168.0.156
host
:
192.168.0.156
prod
:
false
extra
:
username
:
admin
password
:
123456
spring
:
spring
:
datasource
:
datasource
:
url
:
jdbc:postgresql://${env.host}:5432/basic_app
url
:
jdbc:postgresql://${env.host}:5432/basic_app
username
:
admin
username
:
${env.extra.username}
password
:
123456
password
:
${env.extra.password}
jpa
:
jpa
:
database-platform
:
org.hibernate.dialect.PostgreSQL10Dialect
database-platform
:
org.hibernate.dialect.PostgreSQL10Dialect
open-in-view
:
true
open-in-view
:
true
...
@@ -20,20 +24,15 @@ spring:
...
@@ -20,20 +24,15 @@ spring:
database
:
5
database
:
5
host
:
${env.host}
host
:
${env.host}
port
:
6379
port
:
6379
password
:
123456
password
:
${env.extra.password}
# Optional: MyBatis Plus
mybatis-plus
:
global-config
:
banner
:
false
# knife4j
# knife4j
knife4j
:
knife4j
:
enable
:
true
enable
:
true
basic
:
basic
:
enable
:
false
enable
:
false
username
:
admin
username
:
${env.extra.username}
password
:
123456
password
:
${env.extra.password}
setting
:
setting
:
enableOpenApi
:
true
enableOpenApi
:
true
enableDebug
:
true
enableDebug
:
true
...
@@ -44,9 +43,11 @@ minio:
...
@@ -44,9 +43,11 @@ minio:
secret-key
:
minioadmin
secret-key
:
minioadmin
end-point
:
"
http://${env.host}:18100"
end-point
:
"
http://${env.host}:18100"
bucket
:
public
bucket
:
public
domain
:
${minio.endpoint}
domain
:
${minio.end
-
point}
logging
:
logging
:
level
:
level
:
# sql bind parameter
# sql bind parameter
org.hibernate.type.descriptor.sql.BasicBinder
:
trace
org.hibernate.type.descriptor.sql.BasicBinder
:
trace
# request log
com.yiring.common.aspect.RequestAspect
:
info
app/src/main/resources/application-mock.yml
浏览文件 @
be944c68
# 环境变量
# 环境变量
env
:
env
:
host
:
127.0.0.1
host
:
127.0.0.1
prod
:
false
extra
:
username
:
admin
password
:
Hd)XZgtCa&NG~oe@
spring
:
spring
:
datasource
:
datasource
:
...
@@ -20,34 +24,30 @@ spring:
...
@@ -20,34 +24,30 @@ spring:
database
:
5
database
:
5
host
:
${env.host}
host
:
${env.host}
port
:
6379
port
:
6379
password
:
123456
password
:
${env.extra.password}
# Optional: MyBatis Plus
mybatis-plus
:
global-config
:
banner
:
false
# knife4j
# knife4j
knife4j
:
knife4j
:
enable
:
true
enable
:
true
basic
:
basic
:
enable
:
false
enable
:
false
username
:
admin
username
:
${env.extra.username}
password
:
123456
password
:
${env.extra.password}
setting
:
setting
:
enableOpenApi
:
true
enableOpenApi
:
true
enableDebug
:
true
enableDebug
:
true
# minio
# minio
minio
:
minio
:
access-key
:
minioadmin
access-key
:
${env.extra.username}
secret-key
:
minioadmin
secret-key
:
${env.extra.password}
end-point
:
"
http://${env.host}:18100"
end-point
:
"
http://${env.host}:18100"
bucket
:
public
bucket
:
public
domain
:
${minio.endpoint}
domain
:
${minio.end
-
point}
logging
:
logging
:
level
:
level
:
# sql bind parameter
# sql bind parameter
org.hibernate.type.descriptor.sql.BasicBinder
:
trace
org.hibernate.type.descriptor.sql.BasicBinder
:
trace
# request log
com.yiring.common.aspect.RequestAspect
:
info
app/src/main/resources/application.yml
浏览文件 @
be944c68
...
@@ -2,15 +2,18 @@ server:
...
@@ -2,15 +2,18 @@ server:
port
:
8081
port
:
8081
servlet
:
servlet
:
context-path
:
/api
context-path
:
/api
tomcat
:
max-http-form-post-size
:
20MB
spring
:
spring
:
servlet
:
# 文件上传大小限制
multipart
:
max-file-size
:
10MB
max-request-size
:
30MB
application
:
application
:
name
:
"
basic-api-app"
name
:
"
basic-api-app"
messages
:
basename
:
i18n/messages
servlet
:
multipart
:
max-file-size
:
50MB
max-request-size
:
100MB
profiles
:
profiles
:
include
:
auth, conf-patch
include
:
auth, conf-patch
active
:
dev-postgresql
active
:
dev-postgresql
...
...
app/src/main/resources/i18n/messages/messages.properties
0 → 100644
浏览文件 @
be944c68
common.result.success
=
OK
app/src/main/resources/i18n/messages/messages_zh_CN.properties
0 → 100644
浏览文件 @
be944c68
common.result.success
=
\u6210\u
529F
upload.filename.null
=
\u
4E0A
\u
4F20
\u6587\u
4EF6
\u
6CA1
\u6709\u6587\u
4EF6
\u
540D
NotEmpty.downloadParam.object
=
\u6587\u
4EF6
\u
5BF9
\u
8C61
\u
4E0D
\u
80FD
\u
4E3A
\u
7A7A
app/src/test/java/com/yiring/MapperSampleTest.java
deleted
100644 → 0
浏览文件 @
611f6b3f
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
;
import
com.yiring.app.domain.TestTable
;
import
com.yiring.app.mapper.TestTableMapper
;
import
java.util.List
;
import
javax.annotation.Resource
;
import
org.junit.jupiter.api.Test
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
org.springframework.util.Assert
;
/**
* @author Jim
* @version 0.1
* 2022/4/15 17:25
*/
@SpringBootTest
public
class
MapperSampleTest
{
@Resource
TestTableMapper
testTableMapper
;
@Test
public
void
testSelect
()
{
List
<
TestTable
>
tests
=
testTableMapper
.
selectList
(
null
);
Assert
.
isTrue
(
tests
.
size
()
>
0
,
"查询失败"
);
}
}
basic-auth/build.gradle
浏览文件 @
be944c68
...
@@ -16,7 +16,7 @@ dependencies {
...
@@ -16,7 +16,7 @@ dependencies {
implementation
"cn.dev33:sa-token-dao-redis-jackson:${saTokenVersion}"
implementation
"cn.dev33:sa-token-dao-redis-jackson:${saTokenVersion}"
// fastjson
// fastjson
implementation
"com.alibaba
:fastjson
:${fastJsonVersion}"
implementation
"com.alibaba
.fastjson2:fastjson2
:${fastJsonVersion}"
// hutool-core
// hutool-core
implementation
"cn.hutool:hutool-core:${hutoolVersion}"
implementation
"cn.hutool:hutool-core:${hutoolVersion}"
...
...
basic-auth/src/main/java/com/yiring/auth/annotation/AuthIgnore.java
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
auth
.
annotation
;
package
com
.
yiring
.
auth
.
annotation
;
import
cn.dev33.satoken.annotation.SaIgnore
;
import
java.lang.annotation.*
;
import
java.lang.annotation.*
;
/**
/**
...
@@ -16,5 +17,6 @@ import java.lang.annotation.*;
...
@@ -16,5 +17,6 @@ import java.lang.annotation.*;
@Target
({
ElementType
.
METHOD
})
@Target
({
ElementType
.
METHOD
})
@Retention
(
RetentionPolicy
.
RUNTIME
)
@Retention
(
RetentionPolicy
.
RUNTIME
)
@Documented
@Documented
@SaIgnore
public
@interface
AuthIgnore
{
public
@interface
AuthIgnore
{
}
}
basic-auth/src/main/java/com/yiring/auth/config/SaTokenConfigure.java
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
auth
.
config
;
package
com
.
yiring
.
auth
.
config
;
import
cn.dev33.satoken.interceptor.Sa
Route
Interceptor
;
import
cn.dev33.satoken.interceptor.SaInterceptor
;
import
cn.dev33.satoken.router.SaHttpMethod
;
import
cn.dev33.satoken.router.SaHttpMethod
;
import
cn.dev33.satoken.router.SaRouter
;
import
cn.dev33.satoken.router.SaRouter
;
import
cn.dev33.satoken.stp.StpUtil
;
import
cn.dev33.satoken.stp.StpUtil
;
import
com.yiring.auth.
annotation.AuthIgnore
;
import
com.yiring.auth.
util.Auths
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.web.method.HandlerMethod
;
import
org.springframework.web.servlet.config.annotation.InterceptorRegistry
;
import
org.springframework.web.servlet.config.annotation.InterceptorRegistry
;
import
org.springframework.web.servlet.config.annotation.WebMvcConfigurer
;
import
org.springframework.web.servlet.config.annotation.WebMvcConfigurer
;
...
@@ -24,26 +23,23 @@ public class SaTokenConfigure implements WebMvcConfigurer {
...
@@ -24,26 +23,23 @@ public class SaTokenConfigure implements WebMvcConfigurer {
@Override
@Override
public
void
addInterceptors
(
InterceptorRegistry
registry
)
{
public
void
addInterceptors
(
InterceptorRegistry
registry
)
{
// 注册
Sa-Token的
路由拦截器
// 注册
Sa-Token
路由拦截器
registry
registry
.
addInterceptor
(
.
addInterceptor
(
new
Sa
RouteInterceptor
((
req
,
res
,
handler
)
->
{
new
Sa
Interceptor
(
handle
->
{
// 登录认证 -- 拦截所有路由,并排除 /auth/** 用于开放授权相关, 以及 swagger 相关
// 登录认证 -- 拦截所有路由,并排除 /auth/** 用于开放授权相关, 以及 swagger 相关
SaRouter
SaRouter
.
match
(
"/**"
)
.
match
(
"/**"
)
.
notMatchMethod
(
SaHttpMethod
.
OPTIONS
.
name
())
.
notMatchMethod
(
SaHttpMethod
.
OPTIONS
.
name
())
// 实现用户权限相关后应移除下行代码
// TODO
// .notMatch("/**")
// .notMatch("/**")
// 示例接口
.
notMatch
(
"/example/**"
)
// .notMatch("/example/**")
// 授权相关接口(登录、登出、注册等)
.
notMatch
(
"/auth/**"
)
.
notMatch
(
"/auth/**"
)
.
notMatch
(
"/favicon.ico"
,
"/**/*.html"
,
"/**/*.js"
,
"/**/*.css"
)
.
notMatch
(
"/favicon.ico"
,
"/**/*.html"
,
"/**/*.js"
,
"/**/*.css"
)
.
notMatch
(
"/v2/api-docs/**"
,
"/v3/api-docs/**"
,
"/swagger-resources/**"
)
.
notMatch
(
"/v2/api-docs/**"
,
"/v3/api-docs/**"
,
"/swagger-resources/**"
)
// 自定义注解忽略接口鉴权
.
notMatch
(
r
->
((
HandlerMethod
)
handler
).
hasMethodAnnotation
(
AuthIgnore
.
class
))
.
check
(
r
->
StpUtil
.
checkLogin
());
.
check
(
r
->
StpUtil
.
checkLogin
());
// 管理员权限才可访问的路由地址
SaRouter
.
match
(
"/sys/**"
,
r
->
StpUtil
.
checkRoleOr
(
Auths
.
ADMIN_ROLES
.
toArray
(
new
String
[
0
])));
})
})
)
)
.
addPathPatterns
(
"/**"
);
.
addPathPatterns
(
"/**"
);
...
...
basic-auth/src/main/java/com/yiring/auth/config/StpInterfaceImpl.java
浏览文件 @
be944c68
...
@@ -6,6 +6,7 @@ import com.yiring.auth.domain.permission.Permission;
...
@@ -6,6 +6,7 @@ import com.yiring.auth.domain.permission.Permission;
import
com.yiring.auth.domain.role.Role
;
import
com.yiring.auth.domain.role.Role
;
import
com.yiring.auth.domain.user.User
;
import
com.yiring.auth.domain.user.User
;
import
com.yiring.auth.domain.user.UserRepository
;
import
com.yiring.auth.domain.user.UserRepository
;
import
com.yiring.common.core.Status
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Objects
;
import
java.util.Objects
;
import
java.util.Optional
;
import
java.util.Optional
;
...
@@ -36,6 +37,7 @@ public class StpInterfaceImpl implements StpInterface {
...
@@ -36,6 +37,7 @@ public class StpInterfaceImpl implements StpInterface {
.
stream
()
.
stream
()
.
map
(
Role:
:
getPermissions
)
.
map
(
Role:
:
getPermissions
)
.
flatMap
(
Set:
:
stream
)
.
flatMap
(
Set:
:
stream
)
.
distinct
()
.
map
(
Permission:
:
getUid
)
.
map
(
Permission:
:
getUid
)
.
collect
(
Collectors
.
toList
());
.
collect
(
Collectors
.
toList
());
}
}
...
@@ -55,7 +57,7 @@ public class StpInterfaceImpl implements StpInterface {
...
@@ -55,7 +57,7 @@ public class StpInterfaceImpl implements StpInterface {
String
id
=
Objects
.
toString
(
loginId
);
String
id
=
Objects
.
toString
(
loginId
);
Optional
<
User
>
optional
=
userRepository
.
findById
(
id
);
Optional
<
User
>
optional
=
userRepository
.
findById
(
id
);
if
(
optional
.
isEmpty
())
{
if
(
optional
.
isEmpty
())
{
throw
new
RuntimeE
xception
(
"用户不存在"
);
throw
Status
.
NOT_FOUND
.
e
xception
(
"用户不存在"
);
}
}
return
optional
.
get
();
return
optional
.
get
();
...
...
basic-auth/src/main/java/com/yiring/auth/domain/permission/Permission.java
浏览文件 @
be944c68
...
@@ -4,20 +4,19 @@ package com.yiring.auth.domain.permission;
...
@@ -4,20 +4,19 @@ package com.yiring.auth.domain.permission;
import
static
com
.
yiring
.
auth
.
domain
.
permission
.
Permission
.
DELETE_SQL
;
import
static
com
.
yiring
.
auth
.
domain
.
permission
.
Permission
.
DELETE_SQL
;
import
static
com
.
yiring
.
auth
.
domain
.
permission
.
Permission
.
TABLE_NAME
;
import
static
com
.
yiring
.
auth
.
domain
.
permission
.
Permission
.
TABLE_NAME
;
import
com.alibaba.fastjson.JSONObject
;
import
com.alibaba.fastjson2.JSONObject
;
import
com.vladmihalcea.hibernate.type.json.JsonType
;
import
com.yiring.common.domain.BasicEntity
;
import
com.yiring.common.domain.BasicEntity
;
import
java.io.Serial
;
import
java.io.Serial
;
import
java.io.Serializable
;
import
java.io.Serializable
;
import
javax.persistence.*
;
import
javax.persistence.*
;
import
javax.persistence.Entity
;
import
javax.persistence.Index
;
import
javax.persistence.Table
;
import
lombok.*
;
import
lombok.*
;
import
lombok.experimental.FieldDefaults
;
import
lombok.experimental.FieldDefaults
;
import
lombok.experimental.FieldNameConstants
;
import
lombok.experimental.FieldNameConstants
;
import
lombok.experimental.SuperBuilder
;
import
lombok.experimental.SuperBuilder
;
import
org.hibernate.annotations.*
;
import
org.hibernate.annotations.Comment
;
import
org.hibernate.annotations.SQLDelete
;
import
org.hibernate.annotations.SQLDeleteAll
;
import
org.hibernate.annotations.Where
;
/**
/**
* 权限
* 权限
...
@@ -38,7 +37,6 @@ import org.hibernate.annotations.*;
...
@@ -38,7 +37,6 @@ import org.hibernate.annotations.*;
@SQLDeleteAll
(
sql
=
DELETE_SQL
)
@SQLDeleteAll
(
sql
=
DELETE_SQL
)
@Where
(
clause
=
BasicEntity
.
Where
.
EXIST
)
@Where
(
clause
=
BasicEntity
.
Where
.
EXIST
)
@Entity
@Entity
@TypeDef
(
name
=
"json"
,
typeClass
=
JsonType
.
class
)
@Table
(
@Table
(
name
=
TABLE_NAME
,
name
=
TABLE_NAME
,
indexes
=
{
indexes
=
{
...
@@ -128,7 +126,7 @@ public class Permission extends BasicEntity implements Serializable {
...
@@ -128,7 +126,7 @@ public class Permission extends BasicEntity implements Serializable {
* @return JSON 格式 Meta 元数据
* @return JSON 格式 Meta 元数据
*/
*/
public
JSONObject
getMetaJson
()
{
public
JSONObject
getMetaJson
()
{
JSONObject
meta
=
new
JSONObject
(
true
);
JSONObject
meta
=
new
JSONObject
();
meta
.
put
(
"title"
,
this
.
name
);
meta
.
put
(
"title"
,
this
.
name
);
meta
.
put
(
"icon"
,
this
.
icon
);
meta
.
put
(
"icon"
,
this
.
icon
);
meta
.
put
(
"orderNo"
,
this
.
serial
);
meta
.
put
(
"orderNo"
,
this
.
serial
);
...
...
basic-auth/src/main/java/com/yiring/auth/domain/role/Role.java
浏览文件 @
be944c68
...
@@ -62,6 +62,9 @@ public class Role extends BasicEntity implements Serializable {
...
@@ -62,6 +62,9 @@ public class Role extends BasicEntity implements Serializable {
@Column
(
nullable
=
false
)
@Column
(
nullable
=
false
)
String
name
;
String
name
;
@Comment
(
"是否启用"
)
Boolean
enable
;
@JsonIgnore
@JsonIgnore
@Builder
.
Default
@Builder
.
Default
@Comment
(
"权限集合"
)
@Comment
(
"权限集合"
)
...
...
basic-auth/src/main/java/com/yiring/auth/domain/role/RoleRepository.java
浏览文件 @
be944c68
...
@@ -3,6 +3,7 @@ package com.yiring.auth.domain.role;
...
@@ -3,6 +3,7 @@ package com.yiring.auth.domain.role;
import
java.io.Serializable
;
import
java.io.Serializable
;
import
org.springframework.data.jpa.repository.JpaRepository
;
import
org.springframework.data.jpa.repository.JpaRepository
;
import
org.springframework.stereotype.Repository
;
/**
/**
* 角色接口
* 角色接口
...
@@ -10,4 +11,6 @@ import org.springframework.data.jpa.repository.JpaRepository;
...
@@ -10,4 +11,6 @@ import org.springframework.data.jpa.repository.JpaRepository;
* @author ifzm
* @author ifzm
* 2018/9/4 8:49
* 2018/9/4 8:49
*/
*/
@Repository
public
interface
RoleRepository
extends
JpaRepository
<
Role
,
Serializable
>
{}
public
interface
RoleRepository
extends
JpaRepository
<
Role
,
Serializable
>
{}
basic-auth/src/main/java/com/yiring/auth/util/Auths.java
浏览文件 @
be944c68
...
@@ -6,6 +6,7 @@ import cn.dev33.satoken.stp.StpUtil;
...
@@ -6,6 +6,7 @@ import cn.dev33.satoken.stp.StpUtil;
import
com.yiring.auth.domain.user.User
;
import
com.yiring.auth.domain.user.User
;
import
com.yiring.auth.domain.user.UserRepository
;
import
com.yiring.auth.domain.user.UserRepository
;
import
com.yiring.common.core.Status
;
import
com.yiring.common.core.Status
;
import
java.util.List
;
import
java.util.Objects
;
import
java.util.Objects
;
import
java.util.Optional
;
import
java.util.Optional
;
import
javax.annotation.Resource
;
import
javax.annotation.Resource
;
...
@@ -28,6 +29,11 @@ public class Auths {
...
@@ -28,6 +29,11 @@ public class Auths {
UserRepository
userRepository
;
UserRepository
userRepository
;
/**
/**
* 管理员角色标识
*/
public
static
final
List
<
String
>
ADMIN_ROLES
=
List
.
of
(
"admin"
,
"super-admin"
,
"platform-admin"
,
"data-admin"
);
/**
* 根据 Token 获取用户信息
* 根据 Token 获取用户信息
* 如果用户未登录或校验失败会抛出 NotLoginException {@link Status#UNAUTHORIZED}
* 如果用户未登录或校验失败会抛出 NotLoginException {@link Status#UNAUTHORIZED}
* @param token token
* @param token token
...
@@ -61,4 +67,46 @@ public class Auths {
...
@@ -61,4 +67,46 @@ public class Auths {
return
getUserByToken
(
token
);
return
getUserByToken
(
token
);
}
}
/**
* 踢出这个用户 id 所有登录状态(可能有多人重复登录了一个账号的情况)
* @param userId 用户 id
*/
public
void
logoutAll
(
String
userId
)
{
List
<
String
>
tokens
=
StpUtil
.
getTokenValueListByLoginId
(
userId
);
for
(
String
token
:
tokens
)
{
StpUtil
.
logoutByTokenValue
(
token
);
}
}
/**
* 判断用户是否为超级管理员
* @param userId 用户 ID
* @return 是否为管理员
*/
public
boolean
isAdmin
(
String
userId
)
{
Optional
<
User
>
optional
=
userRepository
.
findById
(
userId
);
return
optional
.
filter
(
this
::
isAdmin
).
isPresent
();
}
/**
* 检查用户是否为管理员(检查用户是否拥有包含 admin 字符的角色)
* @param user 用户
* @return 是否为管理员
*/
public
boolean
isAdmin
(
User
user
)
{
return
user
.
getRoles
()
.
stream
()
.
anyMatch
(
role
->
Boolean
.
TRUE
.
equals
(
role
.
getEnable
())
&&
ADMIN_ROLES
.
contains
(
role
.
getUid
()));
}
/**
* 检查当前登录用户是否为管理员
* {@link this.isAdmin}
* @return 是否为管理员
*/
public
boolean
checkLoginUserIsAdmin
()
{
return
isAdmin
(
getLoginUser
());
}
}
}
basic-auth/src/main/java/com/yiring/auth/util/Permissions.java
浏览文件 @
be944c68
...
@@ -70,7 +70,29 @@ public class Permissions {
...
@@ -70,7 +70,29 @@ public class Permissions {
}
}
});
});
return
roots
;
return
new
ArrayList
<>(
sortMenuTreeVo
(
roots
));
}
/**
* 菜单树递归排序
* @param menus 菜单集合
* @return 排序后的菜单集合
*/
public
static
List
<
MenuVo
>
sortMenuTreeVo
(
@Nullable
List
<
MenuVo
>
menus
)
{
return
menus
.
stream
()
.
sorted
(
Comparator
.
comparing
(
item
->
item
.
getMeta
().
getIntValue
(
"orderNo"
),
Comparator
.
nullsFirst
(
Comparator
.
naturalOrder
())
)
)
.
peek
(
item
->
{
if
(!
Commons
.
isNullOrEmpty
(
item
.
getChildren
()))
{
item
.
setChildren
(
sortMenuTreeVo
(
item
.
getChildren
()));
}
})
.
toList
();
}
}
/**
/**
...
@@ -101,6 +123,7 @@ public class Permissions {
...
@@ -101,6 +123,7 @@ public class Permissions {
.
stream
()
.
stream
()
.
map
(
Role:
:
getPermissions
)
.
map
(
Role:
:
getPermissions
)
.
flatMap
(
Set:
:
stream
)
.
flatMap
(
Set:
:
stream
)
.
distinct
()
.
sorted
(
Comparator
.
comparing
(
Permission:
:
getTree
,
Comparator
.
comparingInt
(
String:
:
length
)))
.
sorted
(
Comparator
.
comparing
(
Permission:
:
getTree
,
Comparator
.
comparingInt
(
String:
:
length
)))
.
collect
(
Collectors
.
toList
());
.
collect
(
Collectors
.
toList
());
}
}
...
...
basic-auth/src/main/java/com/yiring/auth/vo/permission/MenuVo.java
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
auth
.
vo
.
permission
;
package
com
.
yiring
.
auth
.
vo
.
permission
;
import
com.alibaba.fastjson.JSONObject
;
import
com.alibaba.fastjson
2
.JSONObject
;
import
com.fasterxml.jackson.annotation.JsonIgnore
;
import
com.fasterxml.jackson.annotation.JsonIgnore
;
import
com.fasterxml.jackson.annotation.JsonInclude
;
import
com.fasterxml.jackson.annotation.JsonInclude
;
import
io.swagger.annotations.ApiModel
;
import
io.swagger.annotations.ApiModel
;
...
...
basic-auth/src/main/java/com/yiring/auth/vo/permission/PermissionVo.java
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
auth
.
vo
.
permission
;
package
com
.
yiring
.
auth
.
vo
.
permission
;
import
com.alibaba.fastjson.JSONObject
;
import
com.alibaba.fastjson
2
.JSONObject
;
import
com.fasterxml.jackson.annotation.JsonInclude
;
import
com.fasterxml.jackson.annotation.JsonInclude
;
import
com.yiring.auth.domain.permission.Permission
;
import
com.yiring.auth.domain.permission.Permission
;
import
io.swagger.annotations.ApiModel
;
import
io.swagger.annotations.ApiModel
;
...
...
basic-auth/src/main/java/com/yiring/auth/vo/user/UserInfoVo.java
浏览文件 @
be944c68
...
@@ -31,6 +31,9 @@ public class UserInfoVo implements Serializable {
...
@@ -31,6 +31,9 @@ public class UserInfoVo implements Serializable {
@ApiModelProperty
(
value
=
"主键"
,
example
=
"1"
)
@ApiModelProperty
(
value
=
"主键"
,
example
=
"1"
)
String
userId
;
String
userId
;
@ApiModelProperty
(
value
=
"手机号"
,
example
=
"15616260195"
)
String
mobile
;
@ApiModelProperty
(
value
=
"真实姓名"
,
example
=
"超级用户"
)
@ApiModelProperty
(
value
=
"真实姓名"
,
example
=
"超级用户"
)
String
realName
;
String
realName
;
...
...
basic-auth/src/main/java/com/yiring/auth/web/auth/AuthController.java
浏览文件 @
be944c68
...
@@ -126,6 +126,12 @@ public class AuthController {
...
@@ -126,6 +126,12 @@ public class AuthController {
return
Result
.
ok
(
vo
);
return
Result
.
ok
(
vo
);
}
}
@ApiOperation
(
value
=
"检查登录状态"
)
@GetMapping
(
"valid"
)
public
Result
<
Boolean
>
valid
()
{
return
Result
.
ok
(
StpUtil
.
isLogin
());
}
@ApiOperation
(
value
=
"登出"
)
@ApiOperation
(
value
=
"登出"
)
@GetMapping
(
"logout"
)
@GetMapping
(
"logout"
)
public
Result
<
String
>
logout
()
{
public
Result
<
String
>
logout
()
{
...
...
basic-auth/src/main/java/com/yiring/auth/web/permission/PermissionController.java
→
basic-auth/src/main/java/com/yiring/auth/web/
sys/
permission/PermissionController.java
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
auth
.
web
.
permission
;
package
com
.
yiring
.
auth
.
web
.
sys
.
permission
;
import
cn.hutool.core.util.StrUtil
;
import
cn.hutool.core.util.StrUtil
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson2.JSON
;
import
com.alibaba.fastjson2.JSONValidator
;
import
com.github.xiaoymin.knife4j.annotations.ApiSupport
;
import
com.github.xiaoymin.knife4j.annotations.ApiSupport
;
import
com.yiring.auth.domain.permission.Permission
;
import
com.yiring.auth.domain.permission.Permission
;
import
com.yiring.auth.domain.permission.PermissionRepository
;
import
com.yiring.auth.domain.permission.PermissionRepository
;
...
@@ -46,7 +47,7 @@ import org.springframework.web.bind.annotation.RestController;
...
@@ -46,7 +47,7 @@ import org.springframework.web.bind.annotation.RestController;
@ApiSupport
(
order
=
-
97
)
@ApiSupport
(
order
=
-
97
)
@Api
(
tags
=
"权限管理"
,
description
=
"Permission"
)
@Api
(
tags
=
"权限管理"
,
description
=
"Permission"
)
@RestController
@RestController
@RequestMapping
(
"/
manage
/permission/"
)
@RequestMapping
(
"/
sys
/permission/"
)
@RequiredArgsConstructor
@RequiredArgsConstructor
public
class
PermissionController
{
public
class
PermissionController
{
...
@@ -60,10 +61,7 @@ public class PermissionController {
...
@@ -60,10 +61,7 @@ public class PermissionController {
}
}
Permission
entity
=
new
Permission
();
Permission
entity
=
new
Permission
();
BeanUtils
.
copyProperties
(
param
,
entity
);
save
(
entity
,
param
);
entity
.
setTree
(
getTreeNode
(
param
.
getPid
()));
entity
.
setMeta
(
JSON
.
parseObject
(
param
.
getMeta
()));
permissionRepository
.
saveAndFlush
(
entity
);
return
Result
.
ok
();
return
Result
.
ok
();
}
}
...
@@ -83,10 +81,7 @@ public class PermissionController {
...
@@ -83,10 +81,7 @@ public class PermissionController {
}
}
}
}
BeanUtils
.
copyProperties
(
param
,
entity
);
save
(
entity
,
param
);
entity
.
setTree
(
getTreeNode
(
param
.
getPid
()));
entity
.
setMeta
(
JSON
.
parseObject
(
param
.
getMeta
()));
permissionRepository
.
saveAndFlush
(
entity
);
return
Result
.
ok
();
return
Result
.
ok
();
}
}
...
@@ -111,8 +106,10 @@ public class PermissionController {
...
@@ -111,8 +106,10 @@ public class PermissionController {
return
Result
.
no
(
Status
.
NOT_FOUND
);
return
Result
.
no
(
Status
.
NOT_FOUND
);
}
}
Permission
permission
=
optional
.
get
();
PermissionVo
vo
=
new
PermissionVo
();
PermissionVo
vo
=
new
PermissionVo
();
BeanUtils
.
copyProperties
(
optional
.
get
(),
vo
);
BeanUtils
.
copyProperties
(
optional
.
get
(),
vo
,
Permission
.
Fields
.
meta
);
vo
.
setMeta
(
permission
.
getMetaJson
());
return
Result
.
ok
(
vo
);
return
Result
.
ok
(
vo
);
}
}
...
@@ -159,4 +156,19 @@ public class PermissionController {
...
@@ -159,4 +156,19 @@ public class PermissionController {
Permission
entity
=
Permission
.
builder
().
uid
(
uid
).
build
();
Permission
entity
=
Permission
.
builder
().
uid
(
uid
).
build
();
return
permissionRepository
.
count
(
Example
.
of
(
entity
))
>
0
;
return
permissionRepository
.
count
(
Example
.
of
(
entity
))
>
0
;
}
}
/**
* 新增或修改权限菜单
*
* @param entity 实体对象
* @param param 参数
*/
private
void
save
(
Permission
entity
,
PermissionParam
param
)
{
BeanUtils
.
copyProperties
(
param
,
entity
,
Permission
.
Fields
.
meta
);
entity
.
setTree
(
getTreeNode
(
param
.
getPid
()));
if
(
JSONValidator
.
from
(
param
.
getMeta
()).
validate
())
{
entity
.
setMeta
(
JSON
.
parseObject
(
param
.
getMeta
()));
}
permissionRepository
.
saveAndFlush
(
entity
);
}
}
}
basic-auth/src/main/java/com/yiring/auth/web/role/RoleController.java
→
basic-auth/src/main/java/com/yiring/auth/web/
sys/
role/RoleController.java
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
auth
.
web
.
role
;
package
com
.
yiring
.
auth
.
web
.
sys
.
role
;
import
com.github.xiaoymin.knife4j.annotations.ApiSupport
;
import
com.github.xiaoymin.knife4j.annotations.ApiSupport
;
import
com.yiring.auth.domain.permission.Permission
;
import
com.yiring.auth.domain.permission.Permission
;
...
@@ -17,8 +17,8 @@ import com.yiring.common.param.PageParam;
...
@@ -17,8 +17,8 @@ import com.yiring.common.param.PageParam;
import
com.yiring.common.vo.PageVo
;
import
com.yiring.common.vo.PageVo
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiOperation
;
import
io.swagger.annotations.ApiOperation
;
import
java.io.Serializable
;
import
java.util.*
;
import
java.util.*
;
import
java.util.stream.Collectors
;
import
javax.validation.Valid
;
import
javax.validation.Valid
;
import
lombok.RequiredArgsConstructor
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
...
@@ -45,7 +45,7 @@ import org.springframework.web.bind.annotation.RestController;
...
@@ -45,7 +45,7 @@ import org.springframework.web.bind.annotation.RestController;
@ApiSupport
(
order
=
-
96
)
@ApiSupport
(
order
=
-
96
)
@Api
(
tags
=
"角色管理"
,
description
=
"Role"
)
@Api
(
tags
=
"角色管理"
,
description
=
"Role"
)
@RestController
@RestController
@RequestMapping
(
"/
manage
/role/"
)
@RequestMapping
(
"/
sys
/role/"
)
@RequiredArgsConstructor
@RequiredArgsConstructor
public
class
RoleController
{
public
class
RoleController
{
...
@@ -95,12 +95,8 @@ public class RoleController {
...
@@ -95,12 +95,8 @@ public class RoleController {
}
}
// 查询权限集合
// 查询权限集合
Set
<
String
>
ids
=
idsParam
.
toIds
();
Collection
<
Serializable
>
ids
=
idsParam
.
toIds
();
Set
<
Permission
>
permissions
=
permissionRepository
Set
<
Permission
>
permissions
=
new
HashSet
<>(
permissionRepository
.
findAllById
(
ids
));
.
findAll
()
.
stream
()
.
filter
(
permission
->
ids
.
contains
(
permission
.
getId
()))
.
collect
(
Collectors
.
toSet
());
Role
entity
=
optional
.
get
();
Role
entity
=
optional
.
get
();
entity
.
setPermissions
(
permissions
);
entity
.
setPermissions
(
permissions
);
...
@@ -110,14 +106,9 @@ public class RoleController {
...
@@ -110,14 +106,9 @@ public class RoleController {
@ApiOperation
(
value
=
"删除"
)
@ApiOperation
(
value
=
"删除"
)
@PostMapping
(
"deleted"
)
@PostMapping
(
"deleted"
)
public
Result
<
String
>
deleted
(
@Valid
IdParam
param
)
{
public
Result
<
String
>
deleted
(
@Valid
IdsParam
param
)
{
Optional
<
Role
>
optional
=
roleRepository
.
findById
(
param
.
getId
());
List
<
Role
>
roles
=
roleRepository
.
findAllById
(
param
.
toIds
());
if
(
optional
.
isEmpty
())
{
roleRepository
.
deleteAll
(
roles
);
return
Result
.
no
(
Status
.
NOT_FOUND
);
}
Role
entity
=
optional
.
get
();
roleRepository
.
delete
(
entity
);
return
Result
.
ok
();
return
Result
.
ok
();
}
}
...
...
basic-auth/src/main/java/com/yiring/auth/web/sys/user/UserController.java
0 → 100644
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
auth
.
web
.
sys
.
user
;
import
com.github.xiaoymin.knife4j.annotations.ApiSupport
;
import
com.yiring.auth.domain.role.Role
;
import
com.yiring.auth.domain.role.RoleRepository
;
import
com.yiring.auth.domain.user.User
;
import
com.yiring.auth.domain.user.UserRepository
;
import
com.yiring.auth.vo.user.UserVo
;
import
com.yiring.common.core.Result
;
import
com.yiring.common.core.Status
;
import
com.yiring.common.param.IdParam
;
import
com.yiring.common.param.IdsParam
;
import
com.yiring.common.param.PageParam
;
import
com.yiring.common.util.Commons
;
import
com.yiring.common.vo.PageVo
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiOperation
;
import
java.io.Serializable
;
import
java.util.*
;
import
java.util.stream.Collectors
;
import
javax.validation.Valid
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.data.domain.Page
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
/**
* 系统用户控制器
*
* @author Jim
* @version 0.1
* 2022/1/24 14:13
*/
@Slf4j
@Validated
@SuppressWarnings
({
"deprecation"
})
@ApiSupport
(
order
=
-
95
)
@Api
(
tags
=
"用户管理"
,
description
=
"User"
)
@RestController
@RequestMapping
(
"/sys/user/"
)
@RequiredArgsConstructor
public
class
UserController
{
final
UserRepository
userRepository
;
final
RoleRepository
roleRepository
;
@ApiOperation
(
value
=
"分配角色"
)
@PostMapping
(
"assign"
)
public
Result
<
String
>
assign
(
@Valid
IdParam
idParam
,
@Valid
IdsParam
idsParam
)
{
Optional
<
User
>
optional
=
userRepository
.
findById
(
idParam
.
getId
());
if
(
optional
.
isEmpty
())
{
return
Result
.
no
(
Status
.
NOT_FOUND
);
}
// 查询角色集合
Collection
<
Serializable
>
ids
=
idsParam
.
toIds
();
Set
<
Role
>
roles
=
new
HashSet
<>(
roleRepository
.
findAllById
(
ids
));
User
entity
=
optional
.
get
();
entity
.
setRoles
(
roles
);
userRepository
.
saveAndFlush
(
entity
);
return
Result
.
ok
();
}
@ApiOperation
(
value
=
"分页查询"
)
@GetMapping
(
"page"
)
public
Result
<
PageVo
<
UserVo
>>
page
(
@Valid
PageParam
param
)
{
Page
<
User
>
page
=
userRepository
.
findAll
(
PageParam
.
toPageable
(
param
));
List
<
UserVo
>
data
=
page
.
get
().
map
(
user
->
Commons
.
transform
(
user
,
UserVo
.
class
)).
collect
(
Collectors
.
toList
());
PageVo
<
UserVo
>
vo
=
PageVo
.
build
(
data
,
page
.
getTotalElements
());
return
Result
.
ok
(
vo
);
}
}
basic-auth/src/main/java/com/yiring/auth/web/user/UserController.java
→
basic-auth/src/main/java/com/yiring/auth/web/user/User
View
Controller.java
浏览文件 @
be944c68
...
@@ -3,36 +3,21 @@ package com.yiring.auth.web.user;
...
@@ -3,36 +3,21 @@ package com.yiring.auth.web.user;
import
com.github.xiaoymin.knife4j.annotations.ApiSupport
;
import
com.github.xiaoymin.knife4j.annotations.ApiSupport
;
import
com.yiring.auth.domain.permission.Permission
;
import
com.yiring.auth.domain.permission.Permission
;
import
com.yiring.auth.domain.role.Role
;
import
com.yiring.auth.domain.role.RoleRepository
;
import
com.yiring.auth.domain.user.User
;
import
com.yiring.auth.domain.user.User
;
import
com.yiring.auth.domain.user.UserRepository
;
import
com.yiring.auth.util.Auths
;
import
com.yiring.auth.util.Auths
;
import
com.yiring.auth.util.Permissions
;
import
com.yiring.auth.util.Permissions
;
import
com.yiring.auth.vo.permission.MenuVo
;
import
com.yiring.auth.vo.permission.MenuVo
;
import
com.yiring.auth.vo.user.UserInfoVo
;
import
com.yiring.auth.vo.user.UserInfoVo
;
import
com.yiring.auth.vo.user.UserVo
;
import
com.yiring.common.core.Result
;
import
com.yiring.common.core.Result
;
import
com.yiring.common.core.Status
;
import
com.yiring.common.param.IdParam
;
import
com.yiring.common.param.IdsParam
;
import
com.yiring.common.param.PageParam
;
import
com.yiring.common.util.Commons
;
import
com.yiring.common.vo.PageVo
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiOperation
;
import
io.swagger.annotations.ApiOperation
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Optional
;
import
java.util.Set
;
import
java.util.stream.Collectors
;
import
java.util.stream.Collectors
;
import
javax.validation.Valid
;
import
lombok.RequiredArgsConstructor
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.data.domain.Page
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.bind.annotation.RestController
;
...
@@ -48,15 +33,13 @@ import org.springframework.web.bind.annotation.RestController;
...
@@ -48,15 +33,13 @@ import org.springframework.web.bind.annotation.RestController;
@Validated
@Validated
@SuppressWarnings
({
"deprecation"
})
@SuppressWarnings
({
"deprecation"
})
@ApiSupport
(
order
=
-
95
)
@ApiSupport
(
order
=
-
95
)
@Api
(
tags
=
"用户
管理"
,
description
=
"User
"
)
@Api
(
tags
=
"用户
信息"
,
description
=
"UserView
"
)
@RestController
@RestController
@RequestMapping
(
"/user/"
)
@RequestMapping
(
"/user/"
)
@RequiredArgsConstructor
@RequiredArgsConstructor
public
class
UserController
{
public
class
User
View
Controller
{
final
Auths
auths
;
final
Auths
auths
;
final
UserRepository
userRepository
;
final
RoleRepository
roleRepository
;
@ApiOperation
(
value
=
"获取登录用户信息"
)
@ApiOperation
(
value
=
"获取登录用户信息"
)
@GetMapping
(
"getUserInfo"
)
@GetMapping
(
"getUserInfo"
)
...
@@ -65,6 +48,7 @@ public class UserController {
...
@@ -65,6 +48,7 @@ public class UserController {
UserInfoVo
userInfoVo
=
UserInfoVo
UserInfoVo
userInfoVo
=
UserInfoVo
.
builder
()
.
builder
()
.
userId
(
user
.
getId
())
.
userId
(
user
.
getId
())
.
mobile
(
user
.
getMobile
())
.
username
(
user
.
getUsername
())
.
username
(
user
.
getUsername
())
.
realName
(
user
.
getRealName
())
.
realName
(
user
.
getRealName
())
.
avatar
(
user
.
getAvatar
())
.
avatar
(
user
.
getAvatar
())
...
@@ -95,36 +79,4 @@ public class UserController {
...
@@ -95,36 +79,4 @@ public class UserController {
List
<
String
>
codes
=
permissions
.
stream
().
map
(
Permission:
:
getUid
).
collect
(
Collectors
.
toList
());
List
<
String
>
codes
=
permissions
.
stream
().
map
(
Permission:
:
getUid
).
collect
(
Collectors
.
toList
());
return
Result
.
ok
((
ArrayList
<
String
>)
codes
);
return
Result
.
ok
((
ArrayList
<
String
>)
codes
);
}
}
@ApiOperation
(
value
=
"分配角色"
)
@PostMapping
(
"/manage/assign"
)
public
Result
<
String
>
assign
(
@Valid
IdParam
idParam
,
@Valid
IdsParam
idsParam
)
{
Optional
<
User
>
optional
=
userRepository
.
findById
(
idParam
.
getId
());
if
(
optional
.
isEmpty
())
{
return
Result
.
no
(
Status
.
NOT_FOUND
);
}
// 查询权限集合
Set
<
String
>
ids
=
idsParam
.
toIds
();
Set
<
Role
>
roles
=
roleRepository
.
findAll
()
.
stream
()
.
filter
(
role
->
ids
.
contains
(
role
.
getId
()))
.
collect
(
Collectors
.
toSet
());
User
entity
=
optional
.
get
();
entity
.
setRoles
(
roles
);
userRepository
.
saveAndFlush
(
entity
);
return
Result
.
ok
();
}
@ApiOperation
(
value
=
"分页查询"
)
@GetMapping
(
"/manage/page"
)
public
Result
<
PageVo
<
UserVo
>>
page
(
@Valid
PageParam
param
)
{
Page
<
User
>
page
=
userRepository
.
findAll
(
PageParam
.
toPageable
(
param
));
List
<
UserVo
>
data
=
page
.
get
().
map
(
user
->
Commons
.
transform
(
user
,
UserVo
.
class
)).
collect
(
Collectors
.
toList
());
PageVo
<
UserVo
>
vo
=
PageVo
.
build
(
data
,
page
.
getTotalElements
());
return
Result
.
ok
(
vo
);
}
}
}
basic-common/core/build.gradle
浏览文件 @
be944c68
...
@@ -16,11 +16,15 @@ dependencies {
...
@@ -16,11 +16,15 @@ dependencies {
implementation
"cn.hutool:hutool-extra:${hutoolVersion}"
implementation
"cn.hutool:hutool-extra:${hutoolVersion}"
// fastjson
// fastjson
implementation
"com.alibaba
:fastjson
:${fastJsonVersion}"
implementation
"com.alibaba
.fastjson2:fastjson2
:${fastJsonVersion}"
// JTS 几何对象操作库
// JTS 几何对象操作库
implementation
"org.locationtech.jts:jts-core:${jtsVersion}"
implementation
"org.locationtech.jts:jts-core:${jtsVersion}"
// https://github.com/vladmihalcea/hibernate-types
// hibernate-types-55
implementation
"com.vladmihalcea:hibernate-types-55:${hibernateTypesVersion}"
// https://mvnrepository.com/artifact/org.n52.jackson/jackson-datatype-jts/1.2.10
// https://mvnrepository.com/artifact/org.n52.jackson/jackson-datatype-jts/1.2.10
implementation
(
"org.n52.jackson:jackson-datatype-jts:1.2.10"
)
{
implementation
(
"org.n52.jackson:jackson-datatype-jts:1.2.10"
)
{
exclude
group:
'com.fasterxml.jackson.core'
exclude
group:
'com.fasterxml.jackson.core'
...
...
basic-common/core/src/main/java/com/yiring/common/aspect/RequestAspect.java
浏览文件 @
be944c68
...
@@ -2,8 +2,8 @@
...
@@ -2,8 +2,8 @@
package
com
.
yiring
.
common
.
aspect
;
package
com
.
yiring
.
common
.
aspect
;
import
cn.hutool.extra.servlet.ServletUtil
;
import
cn.hutool.extra.servlet.ServletUtil
;
import
com.alibaba.fastjson.JSONObject
;
import
com.alibaba.fastjson
2
.JSONObject
;
import
com.alibaba.fastjson
.serializer.SerializerFeature
;
import
com.alibaba.fastjson
2.JSONWriter
;
import
com.yiring.common.constant.DateFormatter
;
import
com.yiring.common.constant.DateFormatter
;
import
com.yiring.common.core.Result
;
import
com.yiring.common.core.Result
;
import
com.yiring.common.util.Commons
;
import
com.yiring.common.util.Commons
;
...
@@ -55,8 +55,11 @@ public class RequestAspect {
...
@@ -55,8 +55,11 @@ public class RequestAspect {
// 获取接口请求扩展信息,Header, Params
// 获取接口请求扩展信息,Header, Params
String
extra
=
""
;
String
extra
=
""
;
if
(
Boolean
.
TRUE
.
equals
(
debug
))
{
if
(
Boolean
.
TRUE
.
equals
(
debug
))
{
String
headers
=
JSONObject
.
toJSONString
(
ServletUtil
.
getHeaderMap
(
request
),
SerializerFeature
.
PrettyFormat
);
String
headers
=
JSONObject
.
toJSONString
(
String
params
=
JSONObject
.
toJSONString
(
ServletUtil
.
getParamMap
(
request
),
SerializerFeature
.
PrettyFormat
);
ServletUtil
.
getHeaderMap
(
request
),
JSONWriter
.
Feature
.
PrettyFormat
);
String
params
=
JSONObject
.
toJSONString
(
ServletUtil
.
getParamMap
(
request
),
JSONWriter
.
Feature
.
PrettyFormat
);
extra
+=
String
.
format
(
"\nHeaders: %s"
,
headers
);
extra
+=
String
.
format
(
"\nHeaders: %s"
,
headers
);
extra
+=
String
.
format
(
"\nParams: %s"
,
params
);
extra
+=
String
.
format
(
"\nParams: %s"
,
params
);
if
(
result
instanceof
Result
)
{
if
(
result
instanceof
Result
)
{
...
...
basic-common/core/src/main/java/com/yiring/common/config/EnvConfig.java
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
common
.
config
;
package
com
.
yiring
.
common
.
config
;
import
java.io.Serial
;
import
java.io.Serializable
;
import
lombok.AccessLevel
;
import
lombok.AccessLevel
;
import
lombok.Data
;
import
lombok.Data
;
import
lombok.experimental.FieldDefaults
;
import
lombok.experimental.FieldDefaults
;
...
@@ -17,12 +19,48 @@ import org.springframework.context.annotation.Configuration;
...
@@ -17,12 +19,48 @@ import org.springframework.context.annotation.Configuration;
@Data
@Data
@FieldDefaults
(
level
=
AccessLevel
.
PRIVATE
)
@FieldDefaults
(
level
=
AccessLevel
.
PRIVATE
)
@Configuration
@Configuration
(
"env.config"
)
@ConfigurationProperties
(
prefix
=
"env"
)
@ConfigurationProperties
(
prefix
=
"env"
)
public
class
EnvConfig
{
public
class
EnvConfig
implements
Serializable
{
@Serial
private
static
final
long
serialVersionUID
=
1017213697767634790L
;
/**
/**
* host,用来共享一些资源(如:数据库、文件存储等相关的依赖源)
* host,用来共享一些资源(如:数据库、文件存储等相关的依赖源)
*/
*/
String
host
;
String
host
;
/**
* 是否为生产环境
*/
boolean
prod
;
/**
* 扩展配置
*/
Extra
extra
;
/**
* 扩展环境配置变量
*/
@Data
@FieldDefaults
(
level
=
AccessLevel
.
PRIVATE
)
@Configuration
(
"env.config.extra"
)
@ConfigurationProperties
(
prefix
=
"env.extra"
)
public
static
class
Extra
implements
Serializable
{
@Serial
private
static
final
long
serialVersionUID
=
-
521508901960998020L
;
/**
* 公共用户名
*/
String
username
;
/**
* 公共密码
*/
String
password
;
}
}
}
basic-common/core/src/main/java/com/yiring/common/domain/BasicEntity.java
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
common
.
domain
;
package
com
.
yiring
.
common
.
domain
;
import
com.vladmihalcea.hibernate.type.json.JsonBinaryType
;
import
com.vladmihalcea.hibernate.type.json.JsonType
;
import
java.time.LocalDateTime
;
import
java.time.LocalDateTime
;
import
javax.persistence.*
;
import
javax.persistence.*
;
import
lombok.*
;
import
lombok.*
;
import
lombok.experimental.FieldDefaults
;
import
lombok.experimental.FieldDefaults
;
import
lombok.experimental.FieldNameConstants
;
import
lombok.experimental.FieldNameConstants
;
import
lombok.experimental.SuperBuilder
;
import
lombok.experimental.SuperBuilder
;
import
org.hibernate.annotations.Comment
;
import
org.hibernate.annotations.*
;
import
org.hibernate.annotations.CreationTimestamp
;
import
org.hibernate.annotations.GenericGenerator
;
import
org.hibernate.annotations.UpdateTimestamp
;
import
org.hibernate.snowflake.SnowflakeId
;
import
org.hibernate.snowflake.SnowflakeId
;
/**
/**
...
@@ -29,6 +28,11 @@ import org.hibernate.snowflake.SnowflakeId;
...
@@ -29,6 +28,11 @@ import org.hibernate.snowflake.SnowflakeId;
@FieldNameConstants
@FieldNameConstants
@FieldDefaults
(
level
=
AccessLevel
.
PRIVATE
)
@FieldDefaults
(
level
=
AccessLevel
.
PRIVATE
)
@SuperBuilder
(
toBuilder
=
true
)
@SuperBuilder
(
toBuilder
=
true
)
@TypeDefs
(
value
=
{
@TypeDef
(
name
=
"json"
,
typeClass
=
JsonType
.
class
),
@TypeDef
(
name
=
"jsonb"
,
typeClass
=
JsonBinaryType
.
class
),
}
)
@MappedSuperclass
@MappedSuperclass
public
abstract
class
BasicEntity
{
public
abstract
class
BasicEntity
{
...
...
basic-common/core/src/main/java/com/yiring/common/param/IdsParam.java
浏览文件 @
be944c68
...
@@ -6,7 +6,7 @@ import io.swagger.annotations.ApiModelProperty;
...
@@ -6,7 +6,7 @@ import io.swagger.annotations.ApiModelProperty;
import
java.io.Serial
;
import
java.io.Serial
;
import
java.io.Serializable
;
import
java.io.Serializable
;
import
java.util.Arrays
;
import
java.util.Arrays
;
import
java.util.
Set
;
import
java.util.
Collection
;
import
java.util.stream.Collectors
;
import
java.util.stream.Collectors
;
import
javax.validation.Valid
;
import
javax.validation.Valid
;
import
javax.validation.constraints.NotEmpty
;
import
javax.validation.constraints.NotEmpty
;
...
@@ -38,9 +38,10 @@ public class IdsParam implements Serializable {
...
@@ -38,9 +38,10 @@ public class IdsParam implements Serializable {
/**
/**
* 获取 String 类型的 ID 集合
* 获取 String 类型的 ID 集合
*
* @return ID 集合
* @return ID 集合
*/
*/
public
Set
<
String
>
toIds
()
{
public
Collection
<
Serializable
>
toIds
()
{
return
Arrays
.
stream
(
this
.
ids
.
split
(
","
)).
collect
(
Collectors
.
toSet
());
return
Arrays
.
stream
(
this
.
ids
.
split
(
","
)).
collect
(
Collectors
.
toSet
());
}
}
}
}
basic-common/core/src/main/java/com/yiring/common/param/OptionalPageParam.java
浏览文件 @
be944c68
...
@@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModel;
...
@@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModel;
import
io.swagger.annotations.ApiModelProperty
;
import
io.swagger.annotations.ApiModelProperty
;
import
java.io.Serial
;
import
java.io.Serial
;
import
java.io.Serializable
;
import
java.io.Serializable
;
import
java.util.Objects
;
import
javax.validation.constraints.DecimalMin
;
import
javax.validation.constraints.DecimalMin
;
import
lombok.AccessLevel
;
import
lombok.AccessLevel
;
import
lombok.AllArgsConstructor
;
import
lombok.AllArgsConstructor
;
...
@@ -12,6 +13,7 @@ import lombok.Data;
...
@@ -12,6 +13,7 @@ import lombok.Data;
import
lombok.NoArgsConstructor
;
import
lombok.NoArgsConstructor
;
import
lombok.experimental.FieldDefaults
;
import
lombok.experimental.FieldDefaults
;
import
lombok.experimental.SuperBuilder
;
import
lombok.experimental.SuperBuilder
;
import
org.springframework.data.domain.PageRequest
;
import
org.springframework.data.domain.Pageable
;
import
org.springframework.data.domain.Pageable
;
import
org.springframework.data.domain.Sort
;
import
org.springframework.data.domain.Sort
;
...
@@ -58,6 +60,10 @@ public class OptionalPageParam implements Serializable {
...
@@ -58,6 +60,10 @@ public class OptionalPageParam implements Serializable {
return
Pageable
.
unpaged
();
return
Pageable
.
unpaged
();
}
}
return
PageParam
.
toPageable
(
param
.
getSortField
(),
param
.
getSortOrder
(),
param
.
pageSize
,
param
.
getPageNo
());
Sort
sort
=
Sort
.
unsorted
();
if
(
Objects
.
nonNull
(
param
.
getSortField
()))
{
sort
=
Sort
.
by
(
new
Sort
.
Order
(
param
.
getSortOrder
(),
param
.
getSortField
()));
}
return
PageRequest
.
of
(
param
.
getPageNo
()
-
1
,
param
.
getPageSize
(),
sort
);
}
}
}
}
basic-common/core/src/main/java/com/yiring/common/vo/PageVo.java
浏览文件 @
be944c68
/* (C) 2021 YiRing, Inc. */
/* (C) 2021 YiRing, Inc. */
package
com
.
yiring
.
common
.
vo
;
package
com
.
yiring
.
common
.
vo
;
import
com.yiring.common.util.Commons
;
import
io.swagger.annotations.ApiModel
;
import
io.swagger.annotations.ApiModel
;
import
io.swagger.annotations.ApiModelProperty
;
import
io.swagger.annotations.ApiModelProperty
;
import
java.io.Serial
;
import
java.io.Serial
;
...
@@ -10,6 +11,7 @@ import java.util.Collections;
...
@@ -10,6 +11,7 @@ import java.util.Collections;
import
java.util.List
;
import
java.util.List
;
import
lombok.*
;
import
lombok.*
;
import
lombok.experimental.FieldDefaults
;
import
lombok.experimental.FieldDefaults
;
import
org.springframework.data.domain.Page
;
/**
/**
* 分页查询响应公共类
* 分页查询响应公共类
...
@@ -41,7 +43,19 @@ public class PageVo<T extends Serializable> implements Serializable {
...
@@ -41,7 +43,19 @@ public class PageVo<T extends Serializable> implements Serializable {
/**
/**
* 构建一个 PageVo
* 构建一个 PageVo
*
* @param data 数据
* @param data 数据
* @return PageVo
*/
@SuppressWarnings
({
"unused"
})
public
static
<
R
extends
Serializable
>
PageVo
<
R
>
build
(
List
<
R
>
data
)
{
return
build
(
data
,
data
.
size
());
}
/**
* 构建一个 PageVo
*
* @param data 数据
* @param total 总数据量
* @param total 总数据量
* @return PageVo
* @return PageVo
*/
*/
...
@@ -52,8 +66,9 @@ public class PageVo<T extends Serializable> implements Serializable {
...
@@ -52,8 +66,9 @@ public class PageVo<T extends Serializable> implements Serializable {
/**
/**
* 构建一个 PageVo
* 构建一个 PageVo
* @param data 数据
*
* @param total 总数据量
* @param data 数据
* @param total 总数据量
* @param latest 数据最新时间
* @param latest 数据最新时间
* @return PageVo
* @return PageVo
*/
*/
...
@@ -67,9 +82,23 @@ public class PageVo<T extends Serializable> implements Serializable {
...
@@ -67,9 +82,23 @@ public class PageVo<T extends Serializable> implements Serializable {
}
}
/**
/**
* 构建一个空的分页查询结果
* 提取 Page 查询结果并转换成 Vo
*
* @param page Page 查询结果
* @param type Vo 类
* @param <S> 数据实体表
* @param <T> Vo 表
* @return PageVo
* @return PageVo
*/
*/
@SuppressWarnings
({
"unused"
})
public
static
<
S
,
T
extends
Serializable
>
PageVo
<
T
>
toPageVo
(
Page
<
S
>
page
,
Class
<
T
>
type
)
{
List
<
T
>
data
=
Commons
.
transform
(
page
.
toList
(),
type
);
return
build
(
data
,
page
.
getTotalElements
());
}
/**
* @return 空的分页查询结果
*/
@SuppressWarnings
(
"unused"
)
@SuppressWarnings
(
"unused"
)
public
static
<
T
extends
Serializable
>
PageVo
<
T
>
empty
()
{
public
static
<
T
extends
Serializable
>
PageVo
<
T
>
empty
()
{
return
PageVo
.
build
(
Collections
.
emptyList
(),
0
);
return
PageVo
.
build
(
Collections
.
emptyList
(),
0
);
...
...
basic-common/doc/src/main/java/com/yiring/common/swagger/SwaggerConfig.java
浏览文件 @
be944c68
...
@@ -60,23 +60,28 @@ public class SwaggerConfig implements CommandLineRunner {
...
@@ -60,23 +60,28 @@ public class SwaggerConfig implements CommandLineRunner {
OpenApiExtensionResolver
openApiExtensionResolver
;
OpenApiExtensionResolver
openApiExtensionResolver
;
@Bean
(
name
=
"api.all"
)
@Bean
(
name
=
"api.all"
)
public
Docket
a
pi
()
{
public
Docket
a
ll
()
{
return
api
(
"
@All
"
,
List
.
of
(
""
),
PathSelectors
.
any
());
return
api
(
"
① 全部
"
,
List
.
of
(
""
),
PathSelectors
.
any
());
}
}
@Bean
(
name
=
"api.auth"
)
@Bean
(
name
=
"api.auth"
)
public
Docket
auth
()
{
public
Docket
auth
()
{
return
api
(
"
Auth"
,
List
.
of
(
"com.yiring.auth.web.auth"
),
PathSelectors
.
any
(
));
return
api
(
"
② Auth"
,
List
.
of
(
"com.yiring.auth.web"
),
Predicate
.
not
(
PathSelectors
.
ant
(
path
+
"/sys/**"
)
));
}
}
@Bean
(
name
=
"api.common"
)
@Bean
(
name
=
"api.common"
)
public
Docket
common
()
{
public
Docket
common
()
{
return
api
(
"公共"
,
List
.
of
(
"com.yiring.common.web"
,
"com.yiring.app.web.common"
),
PathSelectors
.
any
());
return
api
(
"③ 公共"
,
List
.
of
(
"com.yiring.common.web"
,
"com.yiring.app.web.common"
),
PathSelectors
.
any
());
}
@Bean
(
name
=
"api.manage"
)
public
Docket
manage
()
{
return
api
(
"④ 系统管理"
,
List
.
of
(
"com.yiring.auth.web.sys"
),
PathSelectors
.
any
());
}
}
@Bean
(
name
=
"api.example"
)
@Bean
(
name
=
"api.example"
)
public
Docket
example
()
{
public
Docket
example
()
{
return
api
(
"示例"
,
List
.
of
(
"com.yiring.app.web.example"
),
PathSelectors
.
any
());
return
api
(
"
⑤
示例"
,
List
.
of
(
"com.yiring.app.web.example"
),
PathSelectors
.
any
());
}
}
private
Docket
api
(
String
group
,
List
<
String
>
basePackages
,
Predicate
<
String
>
paths
)
{
private
Docket
api
(
String
group
,
List
<
String
>
basePackages
,
Predicate
<
String
>
paths
)
{
...
...
basic-common/i18n/build.gradle
0 → 100644
浏览文件 @
be944c68
dependencies
{
implementation
'org.springframework.boot:spring-boot-starter-web'
}
basic-common/i18n/src/main/java/com/yiring/common/config/I18nConfig.java
0 → 100644
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
common
.
config
;
import
java.util.Locale
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.web.servlet.LocaleResolver
;
import
org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
;
/**
* 国际化配置
*
* @author Jim
* @version 0.1
* 2022/8/17 10:33
*/
@Configuration
public
class
I18nConfig
{
@Bean
public
LocaleResolver
localeResolver
()
{
// header accept-language
AcceptHeaderLocaleResolver
resolver
=
new
AcceptHeaderLocaleResolver
();
resolver
.
setDefaultLocale
(
Locale
.
SIMPLIFIED_CHINESE
);
return
resolver
;
}
}
basic-common/i18n/src/main/java/com/yiring/common/core/I18n.java
0 → 100644
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
common
.
core
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.context.MessageSource
;
import
org.springframework.context.MessageSourceResolvable
;
import
org.springframework.context.i18n.LocaleContextHolder
;
import
org.springframework.stereotype.Component
;
/**
* 国际化
*
* @author Jim
* @version 0.1
* 2022/8/17 10:40
*/
@Slf4j
@Component
@RequiredArgsConstructor
public
class
I18n
{
final
MessageSource
messageSource
;
/**
* 根据 MessageSourceResolvable 获取 I18n 消息
* @param resolvable MessageSourceResolvable
* @return 消息内容
*/
@SuppressWarnings
(
"unused"
)
public
String
get
(
MessageSourceResolvable
resolvable
)
{
return
messageSource
.
getMessage
(
resolvable
,
LocaleContextHolder
.
getLocale
());
}
/**
* 根据 code 和注入参数获取 I18n 消息
* eg:
* default.nonnull = {0}不能为空
* message.username.not-empty = 用户姓名不能为空
* I18n.get("default.nonnull", "用户姓名")
* I18n.get("message.username.not-empty")
* @param code 消息标识
* @param args 注入参数
* @return 消息内容
*/
@SuppressWarnings
(
"unused"
)
public
String
get
(
String
code
,
Object
...
args
)
{
return
messageSource
.
getMessage
(
code
,
args
,
LocaleContextHolder
.
getLocale
());
}
/**
* 根据 code 和注入参数获取 I18n 消息
* eg:
* default.nonnull = {0}不能为空
* I18n.get("default.nonnull", "用户姓名")
* I18n.get("message.username.not-empty", "用户姓名不能为空")
* @param code 消息标识
* @param defaultMessage 默认消息
* @param args 注入参数
* @return 消息内容
*/
@SuppressWarnings
(
"unused"
)
public
String
get
(
String
code
,
String
defaultMessage
,
Object
...
args
)
{
return
messageSource
.
getMessage
(
code
,
args
,
defaultMessage
,
LocaleContextHolder
.
getLocale
());
}
}
basic-common/minio/src/main/java/com/yiring/common/config/MinioConfig.java
浏览文件 @
be944c68
...
@@ -23,15 +23,26 @@ import org.springframework.context.annotation.Configuration;
...
@@ -23,15 +23,26 @@ import org.springframework.context.annotation.Configuration;
@ConfigurationProperties
(
prefix
=
"minio"
)
@ConfigurationProperties
(
prefix
=
"minio"
)
public
class
MinioConfig
{
public
class
MinioConfig
{
/**
* 通常是内网地址
*/
String
endpoint
;
String
endpoint
;
/**
* 账户/访问标识
*/
String
accessKey
;
String
accessKey
;
/**
* 密码/认证密钥
*/
String
secretKey
;
String
secretKey
;
/**
* 默认储存桶名称
*/
String
bucket
;
String
bucket
;
String
domain
;
/**
/**
*
外部
地址
*
通常是和 endpoint 相对的外网
地址
*/
*/
String
externalPoint
;
String
domain
;
@Bean
@Bean
public
MinioClient
getClient
()
{
public
MinioClient
getClient
()
{
...
...
basic-common/minio/src/main/java/com/yiring/common/core/Minio.java
浏览文件 @
be944c68
...
@@ -9,6 +9,10 @@ import java.io.File;
...
@@ -9,6 +9,10 @@ import java.io.File;
import
java.io.InputStream
;
import
java.io.InputStream
;
import
java.nio.file.Files
;
import
java.nio.file.Files
;
import
java.nio.file.Path
;
import
java.nio.file.Path
;
import
java.time.LocalDateTime
;
import
java.time.format.DateTimeFormatter
;
import
java.util.Objects
;
import
lombok.NonNull
;
import
org.springframework.stereotype.Component
;
import
org.springframework.stereotype.Component
;
import
org.springframework.web.multipart.MultipartFile
;
import
org.springframework.web.multipart.MultipartFile
;
...
@@ -32,6 +36,7 @@ public record Minio(MinioConfig config, MinioClient client) {
...
@@ -32,6 +36,7 @@ public record Minio(MinioConfig config, MinioClient client) {
* 获取文件访问地址
* 获取文件访问地址
*
*
* @param object 文件相对地址(含路径)
* @param object 文件相对地址(含路径)
* @param bucket 存储桶名称
* @return URI
* @return URI
*/
*/
public
String
getURI
(
String
object
,
String
bucket
)
{
public
String
getURI
(
String
object
,
String
bucket
)
{
...
@@ -39,6 +44,35 @@ public record Minio(MinioConfig config, MinioClient client) {
...
@@ -39,6 +44,35 @@ public record Minio(MinioConfig config, MinioClient client) {
}
}
/**
/**
* 获取文件访问地址(默认桶)
*
* @param object 文件相对地址(含路径)
* @return URI
*/
public
String
getDefaultURI
(
String
object
)
{
return
String
.
join
(
"/"
,
config
.
getDomain
(),
config
.
getBucket
(),
object
);
}
/**
* 构建文件上传地址
*
* @param name 名称
* @param suffix 后缀,可以是空字符串
* @param folder 前缀目录,支持多层级
* @return 文件 object 相对地址
*/
public
String
buildUploadPath
(
@NonNull
String
name
,
@NonNull
String
suffix
,
String
...
folder
)
{
String
date
=
LocalDateTime
.
now
().
format
(
DateTimeFormatter
.
ofPattern
(
"yyyy/M/d"
));
String
prefix
=
"upload/"
+
date
;
if
(
Objects
.
nonNull
(
folder
)
&&
folder
.
length
>
0
)
{
prefix
+=
"/"
+
String
.
join
(
"/"
,
folder
);
}
return
prefix
+
"/"
+
name
+
suffix
;
}
/**
* 上传文件流
* 上传文件流
*
*
* @param is 文件流
* @param is 文件流
...
@@ -146,9 +180,7 @@ public record Minio(MinioConfig config, MinioClient client) {
...
@@ -146,9 +180,7 @@ public record Minio(MinioConfig config, MinioClient client) {
*/
*/
public
void
copyObject
(
String
bucket
,
String
source
,
String
target
)
throws
Exception
{
public
void
copyObject
(
String
bucket
,
String
source
,
String
target
)
throws
Exception
{
CopySource
copySource
=
CopySource
.
builder
().
bucket
(
bucket
).
object
(
source
).
build
();
CopySource
copySource
=
CopySource
.
builder
().
bucket
(
bucket
).
object
(
source
).
build
();
CopyObjectArgs
args
=
CopyObjectArgs
.
builder
().
bucket
(
bucket
).
object
(
target
).
source
(
copySource
).
build
();
CopyObjectArgs
args
=
CopyObjectArgs
.
builder
().
bucket
(
bucket
).
object
(
target
).
source
(
copySource
).
build
();
client
.
copyObject
(
args
);
client
.
copyObject
(
args
);
}
}
...
...
basic-common/minio/src/main/java/com/yiring/common/param/DownloadParam.java
浏览文件 @
be944c68
...
@@ -35,6 +35,6 @@ public class DownloadParam implements Serializable {
...
@@ -35,6 +35,6 @@ public class DownloadParam implements Serializable {
String
bucket
;
String
bucket
;
@ApiModelProperty
(
value
=
"object"
,
example
=
"cat.jpg"
,
required
=
true
)
@ApiModelProperty
(
value
=
"object"
,
example
=
"cat.jpg"
,
required
=
true
)
@NotEmpty
(
message
=
"文件对象不能为空"
)
@NotEmpty
String
object
;
String
object
;
}
}
basic-common/minio/src/main/java/com/yiring/common/service/UploadProcessService.java
0 → 100644
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
common
.
service
;
import
java.io.InputStream
;
/**
* 文件上传媒体文件预处理服务
*
* @author Jim
* @version 0.1
* 2022/9/23 16:31
*/
public
interface
UploadProcessService
{
/**
* 对文件进行预处理,例如:
* 图片:haha.png -> haha.89x120.png 记录图片宽高,宽 = 89px,高 = 120px
* PDF:haha.pdf -> haha.P12.pdf 记录 PDF 文件总页数,P12 即代表 PDF 总共 12 页,同时可通过 haha.P12.pdf.1.jpg... 按序号读取到每一页 PDF 对应的图片
* 音视频:haha.mp3/4 -> haha.T12.mp3/4 记录音视频的时长(秒),T12 即代表音视频时长为 12 秒
* 视频封面:haha.mp4 -> haha.mp4.jpg 截取视频封面
* @param object 上传文件存储地址
* @param is 文件流
* @return 预处理后的文件地址(可能对文件名追加了时长、页数、分辨率等标识)
*/
@SuppressWarnings
(
"unused"
)
default
String
handle
(
String
object
,
InputStream
is
)
{
return
object
;
}
}
basic-common/minio/src/main/java/com/yiring/common/web/MinioController.java
浏览文件 @
be944c68
...
@@ -2,27 +2,25 @@
...
@@ -2,27 +2,25 @@
package
com
.
yiring
.
common
.
web
;
package
com
.
yiring
.
common
.
web
;
import
cn.hutool.core.io.FileUtil
;
import
cn.hutool.core.io.FileUtil
;
import
cn.hutool.core.lang.Snowflake
;
import
cn.hutool.core.util.IdUtil
;
import
cn.hutool.core.util.IdUtil
;
import
com.github.xiaoymin.knife4j.annotations.ApiSupport
;
import
com.github.xiaoymin.knife4j.annotations.ApiSupport
;
import
com.yiring.common.config.MinioConfig
;
import
com.yiring.common.core.Minio
;
import
com.yiring.common.core.Minio
;
import
com.yiring.common.core.Result
;
import
com.yiring.common.core.Result
;
import
com.yiring.common.core.Status
;
import
com.yiring.common.core.Status
;
import
com.yiring.common.exception.FailStatusException
;
import
com.yiring.common.param.DownloadParam
;
import
com.yiring.common.param.DownloadParam
;
import
com.yiring.common.service.UploadProcessService
;
import
com.yiring.common.util.FileUtils
;
import
com.yiring.common.util.FileUtils
;
import
com.yiring.common.vo.ImageInfo
;
import
io.minio.GetObjectResponse
;
import
io.minio.GetObjectResponse
;
import
io.minio.ObjectWriteResponse
;
import
io.minio.StatObjectResponse
;
import
io.minio.StatObjectResponse
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiImplicitParam
;
import
io.swagger.annotations.ApiOperation
;
import
io.swagger.annotations.ApiOperation
;
import
io.swagger.annotations.ApiParam
;
import
io.swagger.annotations.ApiParam
;
import
java.sql.Timestamp
;
import
java.sql.Timestamp
;
import
java.time.LocalDateTime
;
import
java.time.format.DateTimeFormatter
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.validation.Valid
;
import
javax.validation.Valid
;
import
javax.validation.constraints.NotBlank
;
import
lombok.RequiredArgsConstructor
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpHeaders
;
...
@@ -47,7 +45,7 @@ import org.springframework.web.multipart.MultipartFile;
...
@@ -47,7 +45,7 @@ import org.springframework.web.multipart.MultipartFile;
public
class
MinioController
{
public
class
MinioController
{
final
Minio
minio
;
final
Minio
minio
;
final
MinioConfig
minioConfig
;
final
UploadProcessService
service
;
/**
/**
* minio 上传文件,成功返回文件 url
* minio 上传文件,成功返回文件 url
...
@@ -56,15 +54,52 @@ public class MinioController {
...
@@ -56,15 +54,52 @@ public class MinioController {
@PostMapping
(
value
=
"upload"
,
headers
=
HttpHeaders
.
CONTENT_TYPE
+
"="
+
MediaType
.
MULTIPART_FORM_DATA_VALUE
)
@PostMapping
(
value
=
"upload"
,
headers
=
HttpHeaders
.
CONTENT_TYPE
+
"="
+
MediaType
.
MULTIPART_FORM_DATA_VALUE
)
public
Result
<
String
>
upload
(
@ApiParam
(
value
=
"文件"
,
required
=
true
)
@RequestPart
(
"file"
)
MultipartFile
file
)
{
public
Result
<
String
>
upload
(
@ApiParam
(
value
=
"文件"
,
required
=
true
)
@RequestPart
(
"file"
)
MultipartFile
file
)
{
try
{
try
{
Snowflake
snowflake
=
IdUtil
.
getSnowflake
(
1
,
1
);
// 获取文件名信息
long
uuid
=
snowflake
.
nextId
();
String
filename
=
file
.
getOriginalFilename
();
if
(
filename
==
null
)
{
throw
Status
.
BAD_REQUEST
.
exception
(
"upload.filename.null"
);
}
// 文件上传
// 获取文件信息以及默认存储地址
String
date
=
LocalDateTime
.
now
().
format
(
DateTimeFormatter
.
ofPattern
(
"yyyy/M/d"
));
String
uuid
=
IdUtil
.
fastSimpleUUID
();
String
folder
=
"upload/"
+
date
+
"/"
+
uuid
;
String
object
=
minio
.
buildUploadPath
(
filename
,
""
,
uuid
);
ObjectWriteResponse
response
=
minio
.
putObject
(
file
,
folder
);
String
uri
=
minio
.
getURI
(
response
.
object
(),
minioConfig
.
getBucket
());
// 预处理(默认不做任何处理,具体逻辑需自行在外部实现)
return
Result
.
ok
(
uri
);
object
=
service
.
handle
(
object
,
file
.
getInputStream
());
// 上传原文件
minio
.
putObject
(
file
.
getInputStream
(),
file
.
getContentType
(),
object
);
return
Result
.
ok
(
minio
.
getDefaultURI
(
object
));
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
return
Result
.
no
(
Status
.
BAD_REQUEST
,
"上传失败"
);
}
}
@ApiOperation
(
value
=
"Base64 图片上传"
)
@ApiImplicitParam
(
name
=
"base64Image"
,
value
=
"Base64 图片信息"
,
example
=
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAALCAYAAABYpyyrAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAAATSURBVBhXYzAwNP6PjIeKgPF/ABj+RUX4hZfVAAAAAElFTkSuQmCC"
,
required
=
true
,
paramType
=
"query"
)
@PostMapping
(
value
=
"uploadBase64Image"
)
public
Result
<
String
>
uploadBase64Image
(
@NotBlank
(
message
=
"图片 Base64 信息不能为空"
)
String
base64Image
)
{
try
{
// 解析 Base64 图片信息
ImageInfo
image
=
FileUtils
.
parseBase64ImageText
(
base64Image
);
// 获取文件信息以及默认存储地址
String
uuid
=
IdUtil
.
getSnowflakeNextIdStr
();
String
object
=
minio
.
buildUploadPath
(
uuid
,
"."
+
image
.
getWidth
()
+
"x"
+
image
.
getHeight
()
+
"."
+
image
.
getSuffix
()
);
// 上传原文件
minio
.
putObject
(
image
.
getStream
(),
image
.
getContentType
(),
object
);
return
Result
.
ok
(
minio
.
getDefaultURI
(
object
));
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
log
.
error
(
e
.
getMessage
(),
e
);
return
Result
.
no
(
Status
.
BAD_REQUEST
,
"上传失败"
);
return
Result
.
no
(
Status
.
BAD_REQUEST
,
"上传失败"
);
...
@@ -92,7 +127,7 @@ public class MinioController {
...
@@ -92,7 +127,7 @@ public class MinioController {
lastModified
lastModified
);
);
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
throw
new
FailStatusException
(
Status
.
BAD_REQUEST
,
e
.
getMessage
());
throw
Status
.
BAD_REQUEST
.
exception
(
e
.
getMessage
());
}
}
}
}
}
}
basic-common/util/src/main/java/com/yiring/common/util/FileUtils.java
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
common
.
util
;
package
com
.
yiring
.
common
.
util
;
import
cn.hutool.core.codec.Base64
;
import
cn.hutool.core.io.FileUtil
;
import
cn.hutool.core.io.FileUtil
;
import
cn.hutool.core.io.file.FileReader
;
import
cn.hutool.core.io.file.FileReader
;
import
com.yiring.common.vo.ImageInfo
;
import
java.awt.image.BufferedImage
;
import
java.io.ByteArrayInputStream
;
import
java.io.File
;
import
java.io.File
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStream
;
...
@@ -10,7 +14,9 @@ import java.net.URLEncoder;
...
@@ -10,7 +14,9 @@ import java.net.URLEncoder;
import
java.nio.charset.StandardCharsets
;
import
java.nio.charset.StandardCharsets
;
import
java.nio.file.Files
;
import
java.nio.file.Files
;
import
java.nio.file.attribute.BasicFileAttributes
;
import
java.nio.file.attribute.BasicFileAttributes
;
import
javax.imageio.ImageIO
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.servlet.http.HttpServletResponse
;
import
lombok.SneakyThrows
;
import
lombok.experimental.UtilityClass
;
import
lombok.experimental.UtilityClass
;
import
org.apache.tomcat.util.http.fileupload.IOUtils
;
import
org.apache.tomcat.util.http.fileupload.IOUtils
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpHeaders
;
...
@@ -69,4 +75,36 @@ public class FileUtils {
...
@@ -69,4 +75,36 @@ public class FileUtils {
IOUtils
.
copy
(
object
,
response
.
getOutputStream
());
IOUtils
.
copy
(
object
,
response
.
getOutputStream
());
object
.
close
();
object
.
close
();
}
}
/**
* 解析 Base64 Image 文内容
*
* @param base64 图片 Base64 编码内容,含 data:image/xxx;base64, 前缀
* @return 图片信息
*/
@SneakyThrows
public
ImageInfo
parseBase64ImageText
(
String
base64
)
{
if
(!
base64
.
startsWith
(
"data:image"
))
{
throw
new
RuntimeException
(
"Base64 Image 格式错误, 前缀应是 data:image"
);
}
// 解析数据
String
type
=
base64
.
replaceAll
(
"data:image/(.*);.*"
,
"$1"
);
String
contentType
=
"image/"
+
type
;
String
content
=
base64
.
substring
(
base64
.
indexOf
(
","
)
+
1
);
byte
[]
bytes
=
Base64
.
decode
(
content
);
BufferedImage
image
=
ImageIO
.
read
(
new
ByteArrayInputStream
(
bytes
));
// 构建结果
return
ImageInfo
.
builder
()
.
stream
(
new
ByteArrayInputStream
(
bytes
))
.
image
(
image
)
.
width
(
image
.
getWidth
())
.
height
(
image
.
getHeight
())
.
suffix
(
type
)
.
size
(
bytes
.
length
)
.
contentType
(
contentType
)
.
build
();
}
}
}
basic-common/util/src/main/java/com/yiring/common/vo/ImageInfo.java
0 → 100644
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
common
.
vo
;
import
java.awt.image.BufferedImage
;
import
java.io.InputStream
;
import
java.io.Serial
;
import
java.io.Serializable
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
/**
* Image 信息
*
* @author Jim
* @version 0.1
* 2022/8/15 10:02
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
ImageInfo
implements
Serializable
{
@Serial
private
static
final
long
serialVersionUID
=
4042804283860857802L
;
/**
*
*/
BufferedImage
image
;
/**
* IO
*/
InputStream
stream
;
/**
* 内容大小
*/
long
size
;
/**
* 类型,eg: image/png
*/
String
contentType
;
/**
* 后缀,eg: png
*/
String
suffix
;
/**
* 图片宽度
*/
int
width
;
/**
* 图片高度
*/
int
height
;
}
basic-websocket/build.gradle
0 → 100644
浏览文件 @
be944c68
dependencies
{
implementation
project
(
':basic-auth'
)
implementation
project
(
':basic-common:core'
)
implementation
project
(
':basic-common:redis'
)
implementation
"org.springframework.boot:spring-boot-starter-websocket"
implementation
"org.springframework.boot:spring-boot-starter-reactor-netty"
// hutool
implementation
"cn.hutool:hutool-core:${hutoolVersion}"
implementation
"cn.hutool:hutool-extra:${hutoolVersion}"
// fastjson
implementation
"com.alibaba.fastjson2:fastjson2:${fastJsonVersion}"
}
basic-websocket/src/main/java/com/yiring/websocket/config/WebSocketStompConfig.java
0 → 100644
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
websocket
.
config
;
import
cn.hutool.core.convert.Convert
;
import
cn.hutool.extra.spring.SpringUtil
;
import
com.yiring.common.core.Redis
;
import
com.yiring.websocket.constant.RedisKey
;
import
com.yiring.websocket.interceptor.ClientInboundChannelInterceptor
;
import
com.yiring.websocket.interceptor.ClientOutboundChannelInterceptor
;
import
java.util.Objects
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.boot.autoconfigure.amqp.RabbitProperties
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.messaging.simp.config.ChannelRegistration
;
import
org.springframework.messaging.simp.config.MessageBrokerRegistry
;
import
org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker
;
import
org.springframework.web.socket.config.annotation.StompEndpointRegistry
;
import
org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer
;
import
org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor
;
/**
* WebSocketStompConfig
*
* @author ifzm
* @version 0.1
* 2019/9/25 20:12
*/
@Slf4j
@Configuration
@EnableWebSocketMessageBroker
@RequiredArgsConstructor
public
class
WebSocketStompConfig
implements
WebSocketMessageBrokerConfigurer
{
final
Redis
redis
;
final
ClientInboundChannelInterceptor
clientInboundChannelInterceptor
;
final
ClientOutboundChannelInterceptor
clientOutboundChannelInterceptor
;
@Override
public
void
registerStompEndpoints
(
StompEndpointRegistry
registry
)
{
registry
.
addEndpoint
(
"/stomp/sock-js"
)
.
setAllowedOriginPatterns
(
"*"
)
.
addInterceptors
(
new
HttpSessionHandshakeInterceptor
())
.
withSockJS
();
registry
.
addEndpoint
(
"/stomp/ws"
)
.
setAllowedOriginPatterns
(
"*"
)
.
addInterceptors
(
new
HttpSessionHandshakeInterceptor
());
log
.
info
(
"Init STOMP Endpoints Success."
);
}
@Override
public
void
configureMessageBroker
(
MessageBrokerRegistry
registry
)
{
// 启动前先删除掉可能存在的残留STOMP连接缓存数据
redis
.
del
(
RedisKey
.
STOMP_ONLINE_USERS
);
log
.
info
(
"Clear STOMP online user info cache of redis."
);
registry
.
setPreservePublishOrder
(
true
);
registry
.
setUserDestinationPrefix
(
"/user"
);
registry
.
setApplicationDestinationPrefixes
(
"/app"
);
String
stompPort
=
SpringUtil
.
getProperty
(
"spring.rabbitmq.stomp-port"
);
if
(
Objects
.
isNull
(
stompPort
))
{
// 1. 使用内存方式处理消息
registry
.
enableSimpleBroker
(
"/topic"
,
"/queue"
);
}
else
{
// 2. 使用 RabbitMQ 处理消息(需要安装 STOMP 插件)
RabbitProperties
rabbitProperties
=
SpringUtil
.
getBean
(
RabbitProperties
.
class
);
registry
.
enableStompBrokerRelay
(
"/topic"
,
"/queue"
)
.
setRelayPort
(
Convert
.
toInt
(
stompPort
))
.
setRelayHost
(
rabbitProperties
.
getHost
())
.
setVirtualHost
(
rabbitProperties
.
getVirtualHost
())
.
setClientLogin
(
rabbitProperties
.
getUsername
())
.
setClientPasscode
(
rabbitProperties
.
getPassword
())
.
setSystemLogin
(
rabbitProperties
.
getUsername
())
.
setSystemPasscode
(
rabbitProperties
.
getPassword
());
}
log
.
info
(
"Init RabbitMQ STOMP MessageBroker Success."
);
}
@Override
public
void
configureClientInboundChannel
(
ChannelRegistration
registration
)
{
registration
.
interceptors
(
clientInboundChannelInterceptor
);
}
@Override
public
void
configureClientOutboundChannel
(
ChannelRegistration
registration
)
{
registration
.
interceptors
(
clientOutboundChannelInterceptor
);
}
}
basic-websocket/src/main/java/com/yiring/websocket/constant/RedisKey.java
0 → 100644
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
websocket
.
constant
;
/**
* Redis Key 常量类
*
* @author fangzhimin
* 2018/9/4 15:51
*/
public
interface
RedisKey
{
/**
* STOMP 在线用户关键数据
*/
String
STOMP_ONLINE_USERS
=
"STOMP_ONLINE_USERS"
;
}
basic-websocket/src/main/java/com/yiring/websocket/domain/StompPrincipal.java
0 → 100644
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
websocket
.
domain
;
import
com.alibaba.fastjson2.JSONObject
;
import
java.io.Serial
;
import
java.io.Serializable
;
import
java.security.Principal
;
import
lombok.AccessLevel
;
import
lombok.AllArgsConstructor
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
lombok.experimental.FieldDefaults
;
import
lombok.experimental.FieldNameConstants
;
/**
* StompPrincipal
*
* @author ifzm
* @version 0.1
* 2019/9/28 21:28
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@FieldDefaults
(
level
=
AccessLevel
.
PRIVATE
)
public
class
StompPrincipal
implements
Principal
,
Serializable
{
@Serial
private
static
final
long
serialVersionUID
=
5351052642945180737L
;
Type
type
;
String
user
;
String
session
;
JSONObject
options
;
@Override
public
String
getName
()
{
return
this
.
session
;
}
public
enum
Type
{
/**
* 游客用户
*/
GUEST_USER
,
/**
* 登录用户
*/
LOGIN_USER
,
}
}
basic-websocket/src/main/java/com/yiring/websocket/interceptor/ClientInboundChannelInterceptor.java
0 → 100644
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
websocket
.
interceptor
;
import
com.yiring.auth.domain.user.User
;
import
com.yiring.auth.util.Auths
;
import
com.yiring.common.core.Redis
;
import
com.yiring.websocket.constant.RedisKey
;
import
com.yiring.websocket.domain.StompPrincipal
;
import
java.util.LinkedList
;
import
java.util.Map
;
import
lombok.NonNull
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.messaging.Message
;
import
org.springframework.messaging.MessageChannel
;
import
org.springframework.messaging.simp.SimpMessageHeaderAccessor
;
import
org.springframework.messaging.simp.stomp.StompCommand
;
import
org.springframework.messaging.simp.stomp.StompHeaderAccessor
;
import
org.springframework.messaging.support.ChannelInterceptor
;
import
org.springframework.messaging.support.MessageHeaderAccessor
;
import
org.springframework.messaging.support.NativeMessageHeaderAccessor
;
import
org.springframework.stereotype.Component
;
/**
* ClientInboundChannelInterceptor
* 接收客户端消息的拦截器
*
* @author ifzm
* @version 0.1
* 2019/9/28 20:58
*/
@Slf4j
@Component
@RequiredArgsConstructor
public
class
ClientInboundChannelInterceptor
implements
ChannelInterceptor
{
final
Redis
redis
;
final
Auths
auths
;
private
final
Object
lock
=
new
Object
();
@Override
public
Message
<?>
preSend
(
@NonNull
Message
<?>
message
,
@NonNull
MessageChannel
channel
)
{
StompHeaderAccessor
accessor
=
MessageHeaderAccessor
.
getAccessor
(
message
,
StompHeaderAccessor
.
class
);
assert
accessor
!=
null
;
if
(
StompCommand
.
CONNECT
.
equals
(
accessor
.
getCommand
()))
{
Object
raw
=
message
.
getHeaders
().
get
(
NativeMessageHeaderAccessor
.
NATIVE_HEADERS
);
if
(
raw
instanceof
Map
)
{
StompPrincipal
principal
=
new
StompPrincipal
();
principal
.
setSession
(
accessor
.
getSessionId
());
Object
tokens
=
((
Map
<?,
?>)
raw
).
get
(
"token"
);
if
(
tokens
instanceof
LinkedList
)
{
String
token
=
((
LinkedList
<?>)
tokens
).
getFirst
().
toString
();
User
user
=
auths
.
getUserByToken
(
token
);
principal
.
setUser
(
user
.
getUsername
());
principal
.
setType
(
StompPrincipal
.
Type
.
LOGIN_USER
);
}
else
{
principal
.
setUser
(
"Guest."
+
principal
.
getSession
());
principal
.
setType
(
StompPrincipal
.
Type
.
GUEST_USER
);
}
accessor
.
setUser
(
principal
);
synchronized
(
lock
)
{
redis
.
hset
(
RedisKey
.
STOMP_ONLINE_USERS
,
principal
.
getSession
(),
principal
);
log
.
info
(
"STOMP Online Users: {} (incr: +1, session: {}, user: `{}`)"
,
redis
.
hsize
(
RedisKey
.
STOMP_ONLINE_USERS
),
principal
.
getSession
(),
principal
.
getUser
()
);
}
}
}
else
if
(
StompCommand
.
DISCONNECT
.
equals
(
accessor
.
getCommand
()))
{
StompPrincipal
principal
=
(
StompPrincipal
)
accessor
.
getUser
();
if
(
principal
!=
null
&&
!
message
.
getHeaders
().
containsKey
(
SimpMessageHeaderAccessor
.
HEART_BEAT_HEADER
))
{
synchronized
(
lock
)
{
redis
.
hdel
(
RedisKey
.
STOMP_ONLINE_USERS
,
principal
.
getSession
());
log
.
info
(
"STOMP Online Users: {} (incr: -1, session: {}, user: `{}`)"
,
redis
.
hsize
(
RedisKey
.
STOMP_ONLINE_USERS
),
principal
.
getSession
(),
principal
.
getUser
()
);
}
}
}
return
message
;
}
}
basic-websocket/src/main/java/com/yiring/websocket/interceptor/ClientOutboundChannelInterceptor.java
0 → 100644
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
websocket
.
interceptor
;
import
com.alibaba.fastjson2.JSON
;
import
com.yiring.websocket.domain.StompPrincipal
;
import
lombok.NonNull
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.messaging.Message
;
import
org.springframework.messaging.MessageChannel
;
import
org.springframework.messaging.simp.stomp.StompCommand
;
import
org.springframework.messaging.simp.stomp.StompHeaderAccessor
;
import
org.springframework.messaging.support.ChannelInterceptor
;
import
org.springframework.messaging.support.MessageBuilder
;
import
org.springframework.messaging.support.MessageHeaderAccessor
;
import
org.springframework.stereotype.Component
;
/**
* ClientOutboundChannelInterceptor
* 向客户端输出消息的拦截器
*
* @author ifzm
* @version 0.1
* 2019/10/12 11:05
*/
@Slf4j
@Component
public
class
ClientOutboundChannelInterceptor
implements
ChannelInterceptor
{
@Override
public
Message
<?>
preSend
(
@NonNull
Message
<?>
message
,
@NonNull
MessageChannel
channel
)
{
StompHeaderAccessor
accessor
=
MessageHeaderAccessor
.
getAccessor
(
message
,
StompHeaderAccessor
.
class
);
assert
accessor
!=
null
;
if
(
StompCommand
.
CONNECTED
.
equals
(
accessor
.
getCommand
()))
{
StompPrincipal
principal
=
(
StompPrincipal
)
accessor
.
getUser
();
return
MessageBuilder
.
createMessage
(
JSON
.
toJSONBytes
(
principal
),
message
.
getHeaders
());
}
return
message
;
}
}
basic-websocket/src/main/java/com/yiring/websocket/registry/CustomStompUserRegistry.java
0 → 100644
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
websocket
.
registry
;
import
com.yiring.websocket.domain.StompPrincipal
;
import
java.security.Principal
;
import
java.util.HashSet
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.concurrent.ConcurrentHashMap
;
import
lombok.NonNull
;
import
org.springframework.context.ApplicationEvent
;
import
org.springframework.context.event.SmartApplicationListener
;
import
org.springframework.messaging.Message
;
import
org.springframework.messaging.simp.SimpMessageHeaderAccessor
;
import
org.springframework.messaging.support.MessageHeaderAccessor
;
import
org.springframework.stereotype.Component
;
import
org.springframework.util.Assert
;
import
org.springframework.web.socket.messaging.AbstractSubProtocolEvent
;
import
org.springframework.web.socket.messaging.SessionConnectedEvent
;
import
org.springframework.web.socket.messaging.SessionDisconnectEvent
;
/**
* 自定义STOMP在线用户信息统计与操作
*
* @author ifzm
* @version 0.1
* 2019/10/10 21:19
*/
@Component
public
class
CustomStompUserRegistry
implements
StompUserRegistry
,
SmartApplicationListener
{
/**
* sessionId, Principal
*/
private
final
Map
<
String
,
StompPrincipal
>
users
=
new
ConcurrentHashMap
<>();
private
final
Object
lock
=
new
Object
();
@Override
public
boolean
supportsEventType
(
@NonNull
Class
<?
extends
ApplicationEvent
>
eventType
)
{
return
AbstractSubProtocolEvent
.
class
.
isAssignableFrom
(
eventType
);
}
@Override
public
void
onApplicationEvent
(
@NonNull
ApplicationEvent
event
)
{
AbstractSubProtocolEvent
subProtocolEvent
=
(
AbstractSubProtocolEvent
)
event
;
Message
<?>
message
=
subProtocolEvent
.
getMessage
();
SimpMessageHeaderAccessor
accessor
=
MessageHeaderAccessor
.
getAccessor
(
message
,
SimpMessageHeaderAccessor
.
class
);
Assert
.
state
(
accessor
!=
null
,
"No SimpMessageHeaderAccessor"
);
String
sessionId
=
accessor
.
getSessionId
();
Assert
.
state
(
sessionId
!=
null
,
"No session id"
);
if
(
event
instanceof
SessionConnectedEvent
)
{
Principal
user
=
subProtocolEvent
.
getUser
();
synchronized
(
lock
)
{
this
.
users
.
put
(
sessionId
,
(
StompPrincipal
)
user
);
}
}
else
if
(
event
instanceof
SessionDisconnectEvent
)
{
synchronized
(
lock
)
{
this
.
users
.
remove
(
sessionId
);
}
}
}
@Override
public
Set
<
StompPrincipal
>
getUsers
()
{
return
new
HashSet
<>(
this
.
users
.
values
());
}
@Override
public
int
getUserCount
()
{
return
this
.
users
.
size
();
}
@Override
public
StompPrincipal
getUser
(
String
sessionId
)
{
return
this
.
users
.
get
(
sessionId
);
}
@Override
public
void
updateUser
(
String
sessionId
,
StompPrincipal
principal
)
{
synchronized
(
lock
)
{
if
(
this
.
users
.
containsKey
(
sessionId
))
{
this
.
users
.
put
(
sessionId
,
principal
);
}
}
}
}
basic-websocket/src/main/java/com/yiring/websocket/registry/StompUserRegistry.java
0 → 100644
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
websocket
.
registry
;
import
com.yiring.websocket.domain.StompPrincipal
;
import
java.util.Set
;
/**
* STOMP 用户注册器
*
* @author ifzm
* @version 0.1
* 2019/10/10 21:57
*/
public
interface
StompUserRegistry
{
/**
* 获取所有在线的用户信息
*
* @return 用户信息集合
*/
@SuppressWarnings
(
"unused"
)
Set
<
StompPrincipal
>
getUsers
();
/**
* 获取所有在线用户的数量
*
* @return 在线用户的数量
*/
@SuppressWarnings
(
"unused"
)
int
getUserCount
();
/**
* 根据SessionId获取用户信息
*
* @param sessionId sessionId
* @return StompPrincipal
*/
@SuppressWarnings
(
"unused"
)
StompPrincipal
getUser
(
String
sessionId
);
/**
* 更新用户信息
*
* @param sessionId sessionId
* @param principal StompPrincipal
*/
void
updateUser
(
String
sessionId
,
StompPrincipal
principal
);
}
basic-websocket/src/main/java/com/yiring/websocket/web/StompReceiver.java
0 → 100644
浏览文件 @
be944c68
/* (C) 2022 YiRing, Inc. */
package
com
.
yiring
.
websocket
.
web
;
import
cn.hutool.core.lang.UUID
;
import
com.alibaba.fastjson2.JSON
;
import
com.yiring.auth.domain.user.User
;
import
com.yiring.auth.util.Auths
;
import
com.yiring.common.core.Result
;
import
com.yiring.common.core.Status
;
import
com.yiring.websocket.domain.StompPrincipal
;
import
com.yiring.websocket.registry.StompUserRegistry
;
import
java.util.Objects
;
import
java.util.Set
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.messaging.handler.annotation.MessageMapping
;
import
org.springframework.messaging.simp.SimpMessagingTemplate
;
import
org.springframework.messaging.simp.stomp.StompHeaderAccessor
;
import
org.springframework.messaging.simp.user.SimpUser
;
import
org.springframework.messaging.simp.user.SimpUserRegistry
;
import
org.springframework.stereotype.Controller
;
/**
* STOMP Receiver Controller
*
* @author ifzm
* @version 0.1
* 2019/9/28 23:13
*/
@Slf4j
@Controller
@RequiredArgsConstructor
public
class
StompReceiver
{
final
Auths
auths
;
final
SimpMessagingTemplate
simpMessagingTemplate
;
final
SimpUserRegistry
simpUserRegistry
;
final
StompUserRegistry
stompUserRegistry
;
/**
* 登录
*
* @param accessor StompHeaderAccessor
*/
@MessageMapping
(
"/login"
)
public
void
login
(
StompHeaderAccessor
accessor
,
String
token
)
{
try
{
User
user
=
auths
.
getUserByToken
(
token
);
StompPrincipal
principal
=
(
StompPrincipal
)
accessor
.
getUser
();
assert
principal
!=
null
;
principal
.
setType
(
StompPrincipal
.
Type
.
LOGIN_USER
);
principal
.
setUser
(
user
.
getUsername
());
accessor
.
setUser
(
principal
);
stompUserRegistry
.
updateUser
(
accessor
.
getSessionId
(),
principal
);
log
.
info
(
"STOMP user `{}` login success."
,
principal
.
getUser
());
}
catch
(
Exception
e
)
{
simpMessagingTemplate
.
convertAndSendToUser
(
Objects
.
requireNonNull
(
accessor
.
getSessionId
()),
"/topic/notice"
,
Result
.
no
(
Status
.
UNAUTHORIZED
)
);
}
}
/**
* 更新用户状态
*
* @param accessor 访问器
*/
@MessageMapping
(
"/state"
)
public
void
state
(
StompHeaderAccessor
accessor
,
String
message
)
{
log
.
info
(
"收到来自 STOMP Client `/app/state` 消息:{}"
,
message
);
StompPrincipal
principal
=
(
StompPrincipal
)
accessor
.
getUser
();
assert
principal
!=
null
;
principal
.
setOptions
(
JSON
.
parseObject
(
message
));
accessor
.
setUser
(
principal
);
log
.
info
(
"principal info: {}"
,
principal
);
stompUserRegistry
.
updateUser
(
accessor
.
getSessionId
(),
principal
);
}
@MessageMapping
(
"/test"
)
public
void
test
(
StompHeaderAccessor
accessor
,
String
message
)
{
log
.
info
(
"收到来自 STOMP Client `/app/test` 消息:{}"
,
message
);
Set
<
SimpUser
>
users
=
simpUserRegistry
.
getUsers
();
log
.
info
(
"{}"
,
users
);
simpMessagingTemplate
.
convertAndSendToUser
(
Objects
.
requireNonNull
(
accessor
.
getSessionId
()),
"/topic/reply"
,
Result
.
ok
(
UUID
.
fastUUID
().
toString
(
true
))
);
}
}
build.gradle
浏览文件 @
be944c68
plugins
{
plugins
{
id
'java'
id
'java'
// https://start.spring.io
// https://start.spring.io
id
'org.springframework.boot'
version
'2.6.
9
'
id
'org.springframework.boot'
version
'2.6.
12
'
// https://plugins.gradle.org/plugin/io.spring.dependency-management
// https://plugins.gradle.org/plugin/io.spring.dependency-management
id
'io.spring.dependency-management'
version
'1.0.1
2
.RELEASE'
id
'io.spring.dependency-management'
version
'1.0.1
3
.RELEASE'
// https://plugins.gradle.org/plugin/com.diffplug.spotless
// https://plugins.gradle.org/plugin/com.diffplug.spotless
id
"com.diffplug.spotless"
version
"6.3.0"
id
"com.diffplug.spotless"
version
"6.3.0"
}
}
...
@@ -17,7 +17,7 @@ ext {
...
@@ -17,7 +17,7 @@ ext {
// SpringCloud
// SpringCloud
// https://start.spring.io/
// https://start.spring.io/
springCloudVersion
=
'2021.0.
3
'
springCloudVersion
=
'2021.0.
4
'
// Dependencies
// Dependencies
// https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-spring-boot-starter
// https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-spring-boot-starter
...
@@ -25,27 +25,25 @@ ext {
...
@@ -25,27 +25,25 @@ ext {
// https://mvnrepository.com/artifact/io.swagger/swagger-annotations
// https://mvnrepository.com/artifact/io.swagger/swagger-annotations
swaggerAnnotationsVersion
=
'1.6.6'
swaggerAnnotationsVersion
=
'1.6.6'
// https://mvnrepository.com/artifact/cn.dev33/sa-token-spring-boot-starter
// https://mvnrepository.com/artifact/cn.dev33/sa-token-spring-boot-starter
saTokenVersion
=
'1.3
0
.0'
saTokenVersion
=
'1.3
1
.0'
// https://mvnrepository.com/artifact/cn.hutool/hutool-all
// https://mvnrepository.com/artifact/cn.hutool/hutool-all
hutoolVersion
=
'5.8.
4
'
hutoolVersion
=
'5.8.
7
'
// https://mvnrepository.com/artifact/com.alibaba
/fastjson
// https://mvnrepository.com/artifact/com.alibaba
.fastjson2/fastjson2
fastJsonVersion
=
'2.0.1
0
'
fastJsonVersion
=
'2.0.1
4
'
// https://mvnrepository.com/artifact/com.xuxueli/xxl-job-core
// https://mvnrepository.com/artifact/com.xuxueli/xxl-job-core
xxlJobVersion
=
'2.3.1'
xxlJobVersion
=
'2.3.1'
// https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp
// https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp
okhttpVersion
=
'4.
9.3
'
okhttpVersion
=
'4.
10.0
'
// https://mvnrepository.com/artifact/io.minio/minio
// https://mvnrepository.com/artifact/io.minio/minio
minioVersion
=
'8.4.
3
'
minioVersion
=
'8.4.
4
'
// https://mvnrepository.com/artifact/com.vladmihalcea/hibernate-types-55
// https://mvnrepository.com/artifact/com.vladmihalcea/hibernate-types-55
hibernateTypesVersion
=
'2.1
6.3
'
hibernateTypesVersion
=
'2.1
9.2
'
// https://mvnrepository.com/artifact/org.hibernate/hibernate-spatial
// https://mvnrepository.com/artifact/org.hibernate/hibernate-spatial
hibernateSpatialVersion
=
'5.6.1
0
.Final'
hibernateSpatialVersion
=
'5.6.1
1
.Final'
// https://mvnrepository.com/artifact/org.locationtech.jts/jts-core
// https://mvnrepository.com/artifact/org.locationtech.jts/jts-core
jtsVersion
=
'1.19.0'
jtsVersion
=
'1.19.0'
// https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter
mybatisPlusVersion
=
'3.5.2'
// https://mvnrepository.com/artifact/com.github.liaochong/myexcel
// https://mvnrepository.com/artifact/com.github.liaochong/myexcel
myexcelVersion
=
'4.2.
1
'
myexcelVersion
=
'4.2.
2
'
}
}
allprojects
{
allprojects
{
...
...
gradle/wrapper/gradle-wrapper.properties
浏览文件 @
be944c68
distributionBase
=
GRADLE_USER_HOME
distributionBase
=
GRADLE_USER_HOME
distributionPath
=
wrapper/dists
distributionPath
=
wrapper/dists
distributionUrl
=
https
\:
//services.gradle.org/distributions/gradle-7.
4.1
-bin.zip
distributionUrl
=
https
\:
//services.gradle.org/distributions/gradle-7.
5
-bin.zip
zipStoreBase
=
GRADLE_USER_HOME
zipStoreBase
=
GRADLE_USER_HOME
zipStorePath
=
wrapper/dists
zipStorePath
=
wrapper/dists
settings.gradle
浏览文件 @
be944c68
...
@@ -4,12 +4,15 @@ pluginManagement {
...
@@ -4,12 +4,15 @@ pluginManagement {
gradlePluginPortal
()
gradlePluginPortal
()
}
}
}
}
rootProject
.
name
=
'basic-api'
rootProject
.
name
=
'basic-api'
include
'app'
include
'app'
include
'basic-auth'
include
'basic-auth'
include
'basic-websocket'
include
'basic-common:core'
include
'basic-common:core'
include
'basic-common:util'
include
'basic-common:util'
include
'basic-common:doc'
include
'basic-common:doc'
include
'basic-common:minio'
include
'basic-common:minio'
include
'basic-common:redis'
include
'basic-common:redis'
include
'basic-common:i18n'
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论