Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
I
image-backend
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
陈皓
image-backend
Commits
627e5035
Commit
627e5035
authored
Dec 04, 2023
by
陈皓
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
init
parent
1d4b5c8c
Hide whitespace changes
Inline
Side-by-side
Showing
98 changed files
with
6586 additions
and
469 deletions
+6586
-469
file-server/src/main/java/com/zq/file/controller/WpsCallBackController.java
+111
-0
file-server/src/main/java/com/zq/file/controller/WpsController.java
+85
-0
file-server/src/main/java/com/zq/file/utils/WpsUtil.java
+211
-0
file-server/src/main/java/com/zq/file/vo/Creator.java
+26
-0
file-server/src/main/java/com/zq/file/vo/Modifier.java
+27
-0
file-server/src/main/java/com/zq/file/vo/OnLinePreview/FileResult.java
+74
-0
file-server/src/main/java/com/zq/file/vo/OnLinePreview/OnlinePreviewEnum.java
+49
-0
file-server/src/main/java/com/zq/file/vo/OnLinePreview/OnlinePreviewResult.java
+29
-0
file-server/src/main/java/com/zq/file/vo/OnLinePreview/UserAclResult.java
+18
-0
file-server/src/main/java/com/zq/file/vo/OnLinePreview/UserResult.java
+34
-0
file-server/src/main/java/com/zq/file/vo/OnLinePreview/WatermarkResult.java
+22
-0
file-server/src/main/java/com/zq/file/vo/OnlineEdit/FileHistorieVo.java
+56
-0
file-server/src/main/java/com/zq/file/vo/OnlineEdit/GetHistoryVersionResult.java
+21
-0
file-server/src/main/java/com/zq/file/vo/OnlineEdit/GetHistoryVersionUserResult.java
+10
-0
file-server/src/main/java/com/zq/file/vo/OnlineEdit/GetVersionFileResult.java
+16
-0
file-server/src/main/java/com/zq/file/vo/OnlineEdit/HistoriesVo.java
+21
-0
file-server/src/main/java/com/zq/file/vo/OnlineEdit/OnlineEditEnum.java
+49
-0
file-server/src/main/java/com/zq/file/vo/OnlineEdit/OnlineEditMessage.java
+27
-0
file-server/src/main/java/com/zq/file/vo/OnlineEdit/OnlineEditRename.java
+20
-0
file-server/src/main/java/com/zq/file/vo/OnlineEdit/OnlineEditResult.java
+14
-0
file-server/src/main/java/com/zq/file/vo/OnlineEdit/OnlineEditUsers.java
+22
-0
file-server/src/main/java/com/zq/file/vo/OnlineEdit/OnlineEditUsersResult.java
+25
-0
file-server/src/main/java/com/zq/file/vo/OnlineEdit/OnlineEditVersion.java
+57
-0
file-server/src/main/java/com/zq/file/vo/OnlineEdit/UploadFileResult.java
+12
-0
file-server/src/main/java/com/zq/file/vo/UserAclVo.java
+37
-0
file-server/src/main/java/com/zq/file/vo/Watermark.java
+43
-0
file-server/src/main/java/com/zq/file/vo/WpsCertificateTimeVO.java
+22
-0
imgproc-server/pom.xml
+1
-1
imgproc-server/src/main/java/com/zq/imgproc/config/SwaggerConfig.java
+12
-9
imgproc-server/src/main/java/com/zq/imgproc/config/ThreadPoolConfig.java
+47
-0
imgproc-server/src/main/java/com/zq/imgproc/constant/Threshold.java
+5
-0
imgproc-server/src/main/java/com/zq/imgproc/controller/ApiController.java
+13
-124
imgproc-server/src/main/java/com/zq/imgproc/controller/ImageBatchController.java
+19
-2
imgproc-server/src/main/java/com/zq/imgproc/controller/ImageDetectionController.java
+9
-1
imgproc-server/src/main/java/com/zq/imgproc/controller/ImgProcController.java
+1
-1
imgproc-server/src/main/java/com/zq/imgproc/controller/ImgSettingController.java
+10
-1
imgproc-server/src/main/java/com/zq/imgproc/service/ApiService.java
+84
-0
imgproc-server/src/main/java/com/zq/imgproc/service/ImageDetectionService.java
+108
-32
imgproc-server/src/main/java/com/zq/imgproc/service/ImgProcService.java
+7
-7
imgproc-server/src/main/java/com/zq/imgproc/utils/BendUtil.java
+5
-4
imgproc-server/src/main/java/com/zq/imgproc/utils/DemoUtil.java
+2
-2
imgproc-server/src/main/java/com/zq/imgproc/utils/Deskew.java
+22
-30
imgproc-server/src/main/java/com/zq/imgproc/utils/ImageUtil.java
+2
-2
imgproc-server/src/main/java/com/zq/imgproc/utils/Test2.java
+2
-109
imgproc-server/src/main/java/com/zq/imgproc/utils/TestUtil.java
+9
-143
imgproc-server/src/main/java/com/zq/imgproc/vo/ApiDetectionVO.java
+53
-0
imgproc-server/src/main/java/com/zq/imgproc/vo/OptimizationReq.java
+1
-1
interface-server/pom.xml
+143
-0
interface-server/src/main/java/com/zq/im/InterfaceApplication.java
+25
-0
interface-server/src/main/java/com/zq/im/aspect/ApiLogAspect.java
+184
-0
interface-server/src/main/java/com/zq/im/aspect/OpenApi.java
+22
-0
interface-server/src/main/java/com/zq/im/config/RedisConfig.java
+213
-0
interface-server/src/main/java/com/zq/im/config/WebMvcConfig.java
+31
-0
interface-server/src/main/java/com/zq/im/config/feign/FeignConfig.java
+95
-0
interface-server/src/main/java/com/zq/im/config/feign/FeignSpringFormEncoder.java
+55
-0
interface-server/src/main/java/com/zq/im/config/mybatis/InsertBatchSqlInjector.java
+30
-0
interface-server/src/main/java/com/zq/im/config/mybatis/MybatisPlusConfig.java
+48
-0
interface-server/src/main/java/com/zq/im/constant/ApiCodeEnum.java
+94
-0
interface-server/src/main/java/com/zq/im/constant/ApiVersionEnum.java
+21
-0
interface-server/src/main/java/com/zq/im/constant/TokenConstant.java
+57
-0
interface-server/src/main/java/com/zq/im/exception/BusinessException.java
+32
-0
interface-server/src/main/java/com/zq/im/interceptor/ApiMethodInterceptor.java
+77
-0
interface-server/src/main/java/com/zq/im/modules/api/controller/ApiV1.java
+86
-0
interface-server/src/main/java/com/zq/im/modules/api/form/ApiForm.java
+145
-0
interface-server/src/main/java/com/zq/im/modules/api/form/ApiResp.java
+63
-0
interface-server/src/main/java/com/zq/im/modules/api/service/ApiManage.java
+92
-0
interface-server/src/main/java/com/zq/im/modules/api/service/IApiCommon.java
+16
-0
interface-server/src/main/java/com/zq/im/modules/api/service/IApiLogic.java
+73
-0
interface-server/src/main/java/com/zq/im/modules/api/service/impl/ApiV1Logic.java
+106
-0
interface-server/src/main/java/com/zq/im/modules/api/service/impl/ApiV2Logic.java
+17
-0
interface-server/src/main/java/com/zq/im/modules/api/service/impl/BaseApiLogic.java
+22
-0
interface-server/src/main/java/com/zq/im/modules/api/utils/ApiUtils.java
+125
-0
interface-server/src/main/java/com/zq/im/modules/api/utils/EncryptUtils.java
+138
-0
interface-server/src/main/java/com/zq/im/modules/api/utils/ReflectionUtils.java
+163
-0
interface-server/src/main/java/com/zq/im/modules/api/utils/RsaUtils.java
+240
-0
interface-server/src/main/java/com/zq/im/modules/api/vo/MethodVo.java
+43
-0
interface-server/src/main/java/com/zq/im/modules/im/controller/ImgProcController.java
+40
-0
interface-server/src/main/java/com/zq/im/modules/im/feign/ImgprocFeign.java
+23
-0
interface-server/src/main/java/com/zq/im/modules/im/req/ImageReq.java
+32
-0
interface-server/src/main/java/com/zq/im/modules/im/service/ImgProcService.java
+36
-0
interface-server/src/main/java/com/zq/im/modules/im/vo/DetectionResVo.java
+54
-0
interface-server/src/main/java/com/zq/im/modules/system/dao/ApiUserInfoDao.java
+16
-0
interface-server/src/main/java/com/zq/im/modules/system/dao/OpenApiLogDao.java
+14
-0
interface-server/src/main/java/com/zq/im/modules/system/entity/ApiUserInfo.java
+62
-0
interface-server/src/main/java/com/zq/im/modules/system/entity/OpenApiLog.java
+87
-0
interface-server/src/main/java/com/zq/im/modules/system/service/ApiUserInfoService.java
+71
-0
interface-server/src/main/java/com/zq/im/modules/system/vo/ResultVo.java
+89
-0
interface-server/src/main/java/com/zq/im/utils/AssertUtils.java
+279
-0
interface-server/src/main/java/com/zq/im/utils/IpUtil.java
+168
-0
interface-server/src/main/java/com/zq/im/utils/RedisUtil.java
+795
-0
interface-server/src/main/java/com/zq/im/utils/ThreadContextUtil.java
+77
-0
interface-server/src/main/java/com/zq/im/utils/TokenUtil.java
+161
-0
interface-server/src/main/java/com/zq/im/utils/UuidUtils.java
+35
-0
interface-server/src/main/java/com/zq/im/utils/V1Demo.java
+236
-0
interface-server/src/main/resources/application.yml
+78
-0
interface-server/src/main/resources/bootstrap.yml
+34
-0
interface-server/src/main/resources/logback-spring.xml
+192
-0
pom.xml
+1
-0
No files found.
file-server/src/main/java/com/zq/file/controller/WpsCallBackController.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
controller
;
import
cn.hutool.json.JSON
;
import
cn.hutool.json.JSONUtil
;
import
com.zq.common.annotation.rest.AnonymousGetMapping
;
import
com.zq.common.annotation.rest.AnonymousPostMapping
;
import
com.zq.file.vo.OnLinePreview.FileResult
;
import
com.zq.file.vo.OnLinePreview.OnlinePreviewResult
;
import
com.zq.file.vo.OnLinePreview.UserResult
;
import
com.zq.file.vo.OnlineEdit.OnlineEditRename
;
import
com.zq.file.vo.OnlineEdit.OnlineEditUsers
;
import
com.zq.file.vo.UserAclVo
;
import
com.zq.file.vo.Watermark
;
import
com.zq.file.vo.WpsCertificateTimeVO
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiOperation
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.multipart.MultipartFile
;
@Api
(
value
=
"WpsCallBackController"
)
@RequestMapping
(
"/file/wpsCallBack"
)
@RestController
@Slf4j
public
class
WpsCallBackController
{
// @Resource
// private ISysFileUploadService sysFileUploadService;
// @Autowired
// WpsService wpsService;
//
@ApiOperation
(
"证书信息回调"
)
@AnonymousPostMapping
(
"/certificate"
)
public
JSON
getCertificateInfo
(
@RequestBody
WpsCertificateTimeVO
vo
)
{
log
.
info
(
vo
.
toString
());
return
JSONUtil
.
parse
(
vo
);
}
@ApiOperation
(
"获取文件信息(获取在线浏览和在线编辑的回调)"
)
@AnonymousGetMapping
(
"/v1/3rd/file/info"
)
public
JSON
getFileInfo
(
@RequestParam
(
"_w_third_fileId"
)
String
fileId
,
@RequestParam
(
"_w_third_userId"
)
String
userId
)
{
log
.
info
(
"获取在线浏览文件信息(获取在线浏览和在线编辑的回调)"
);
String
tempUrl
=
"https://img.yww52.com/test/test.docx"
;
FileResult
file
=
FileResult
.
builder
()
.
id
(
fileId
).
name
(
"test.docx"
).
version
(
1
).
size
(
10017L
)
.
preview_pages
(
0
)
.
create_time
(
1136185445L
)
.
creator
(
"id0"
)
.
modifier
(
"id1000"
)
.
modify_time
(
1551409818L
)
.
download_url
(
tempUrl
)
.
user_acl
(
new
UserAclVo
()).
watermark
(
new
Watermark
()).
build
();
// 设置用户返回信息
UserResult
user
=
UserResult
.
builder
()
.
id
(
"id1000"
).
name
(
"wps-1000"
).
permission
(
"read"
).
avatar_url
(
""
)
.
build
();
OnlinePreviewResult
result
=
OnlinePreviewResult
.
builder
().
file
(
file
).
user
(
user
).
build
();
return
JSONUtil
.
parse
(
result
);
}
@ApiOperation
(
"获取用户信息(在线编辑的回调)"
)
@AnonymousPostMapping
(
"/v1/3rd/user/info"
)
public
JSON
getUsersInfo
(
@RequestBody
OnlineEditUsers
users
)
{
log
.
info
(
"获取在线浏览文件信息(获取在线浏览和在线编辑的回调"
);
return
JSONUtil
.
parse
(
null
);
// return ResultVo.success(wpsService.getUsersInfo(users));
}
@ApiOperation
(
"上传文件新版本(在线编辑的回调)"
)
@AnonymousPostMapping
(
"/v1/3rd/file/save"
)
public
JSON
saveNewFile
(
@RequestParam
(
"_w_third_fileId"
)
String
fileId
,
@RequestParam
(
"_w_third_userId"
)
String
userId
,
@RequestBody
MultipartFile
multipartFile
)
{
return
JSONUtil
.
parse
(
null
);
}
@ApiOperation
(
"文件重命名(在线编辑的回调)"
)
@PutMapping
(
"/v1/3rd/file/rename"
)
public
JSON
rename
(
@RequestParam
(
"_w_third_fileId"
)
String
fileId
,
@RequestParam
(
"_w_third_userId"
)
String
userId
,
@RequestBody
OnlineEditRename
vo
)
{
return
JSONUtil
.
parse
(
null
);
}
@ApiOperation
(
"通知此文件目前有哪些人正在协作(在线编辑的回调)"
)
@AnonymousPostMapping
(
"/v1/3rd/file/online"
)
public
JSON
onlineInfo
(
@RequestBody
OnlineEditUsers
users
)
{
return
JSONUtil
.
parse
(
null
);
}
@ApiOperation
(
"回调通知"
)
@AnonymousPostMapping
(
"/v1/3rd/onnotify"
)
public
JSON
onnotify
()
{
return
JSONUtil
.
parse
(
null
);
}
@ApiOperation
(
"获取特定版本的文件信息(在线编辑的回调)"
)
@AnonymousPostMapping
(
"/v1/3rd/file/version/{version}"
)
public
JSON
getVersionInfo
(
@RequestParam
(
"version"
)
String
version
,
@RequestParam
(
"_w_third_fileId"
)
String
fileId
)
{
return
JSONUtil
.
parse
(
null
);
}
@ApiOperation
(
"获取所有历史版本的文件信息(在线编辑的回调)"
)
@AnonymousPostMapping
(
"/v1/3rd/file/history"
)
public
JSON
getAllVersionInfo
(
@RequestParam
(
"_w_third_fileId"
)
String
fileId
)
{
return
JSONUtil
.
parse
(
null
);
}
}
file-server/src/main/java/com/zq/file/controller/WpsController.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
controller
;
import
cn.hutool.http.HttpResponse
;
import
cn.hutool.json.JSON
;
import
cn.hutool.json.JSONUtil
;
import
com.zq.common.annotation.AnonymousAccess
;
import
com.zq.common.utils.AssertUtils
;
import
com.zq.common.vo.ResultVo
;
import
com.zq.file.utils.WpsUtil
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiOperation
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang.StringEscapeUtils
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.PathVariable
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* @author ZQ
*/
@Api
(
value
=
"WpsController"
)
@RequestMapping
(
"/file/wps"
)
@RestController
@Slf4j
public
class
WpsController
{
private
final
String
WAI
=
"http://171.106.48.55:33806"
;
private
final
String
NEI
=
"http://147.1.3.220"
;
@AnonymousAccess
@ApiOperation
(
"获取在线浏览地址(在线浏览)"
)
@GetMapping
(
"/getViewUrl/{fileId}"
)
public
ResultVo
<
String
>
getViewUrl
(
@PathVariable
String
fileId
)
{
String
uri
=
WAI
+
"/open/api/preview/v1/files/"
+
"132aa30a87064"
+
"/link"
;
// String uri = DOMAIN + "/open/api/preview/v1/files/" + fileId + "/link";
// 添加参数
Map
<
String
,
String
>
params
=
new
HashMap
<>(
1
);
params
.
put
(
"type"
,
"w"
);
params
.
put
(
"preview_mode"
,
"high_definition"
);
String
result
=
""
;
try
(
HttpResponse
response
=
WpsUtil
.
httpGet
(
uri
,
params
))
{
result
=
response
.
body
();
}
catch
(
Exception
e
)
{
log
.
error
(
"获取在线浏览地址接口出现异常"
);
e
.
printStackTrace
();
}
JSON
json
=
JSONUtil
.
parseObj
(
result
);
String
code
=
json
.
getByPath
(
"code"
,
String
.
class
);
AssertUtils
.
isTrue
(
"200"
.
equals
(
code
),
"获取在线浏览地址接口出现异常 code:"
+
code
+
",msg:"
+
json
.
getByPath
(
"msg"
,
String
.
class
));
String
link
=
json
.
getByPath
(
"data.link"
,
String
.
class
);
// 反转义
link
=
StringEscapeUtils
.
unescapeJava
(
link
);
return
ResultVo
.
success
(
link
);
}
@AnonymousAccess
@ApiOperation
(
"获取在线编辑地址(在线编辑)"
)
@GetMapping
(
"/getEditUrl/{fileId}"
)
public
ResultVo
getExitUrl
(
@PathVariable
String
fileId
)
{
String
uri
=
WAI
+
"/open/api/edit/v1/files/"
+
fileId
+
"/link"
;
// 设置查询参数
Map
<
String
,
String
>
params
=
new
HashMap
<>(
3
);
params
.
put
(
"type"
,
"w"
);
params
.
put
(
"_w_third_fileId"
,
fileId
);
params
.
put
(
"_w_third_userId"
,
"78511"
);
String
result
=
""
;
try
(
HttpResponse
response
=
WpsUtil
.
httpGet
(
uri
,
params
))
{
result
=
response
.
body
();
}
catch
(
Exception
e
)
{
log
.
error
(
"获取在线编辑地址接口出现异常"
);
e
.
printStackTrace
();
}
System
.
out
.
println
(
result
);
JSON
json
=
JSONUtil
.
parseObj
(
StringEscapeUtils
.
unescapeJava
(
result
));
String
str
=
(
String
)
json
.
getByPath
(
"data.link"
);
return
ResultVo
.
success
(
str
);
}
}
file-server/src/main/java/com/zq/file/utils/WpsUtil.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
utils
;
import
cn.hutool.core.util.ObjectUtil
;
import
cn.hutool.http.HttpRequest
;
import
cn.hutool.http.HttpResponse
;
import
cn.hutool.http.Method
;
import
cn.hutool.json.JSON
;
import
cn.hutool.json.JSONUtil
;
import
com.zq.common.exception.BusinessException
;
import
com.zq.common.utils.AssertUtils
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang.StringEscapeUtils
;
import
org.apache.http.client.utils.URIBuilder
;
import
org.springframework.stereotype.Component
;
import
javax.crypto.Mac
;
import
javax.crypto.spec.SecretKeySpec
;
import
java.net.URISyntaxException
;
import
java.nio.charset.StandardCharsets
;
import
java.security.MessageDigest
;
import
java.security.NoSuchAlgorithmException
;
import
java.text.DateFormat
;
import
java.text.SimpleDateFormat
;
import
java.util.*
;
@Component
@Slf4j
public
class
WpsUtil
{
private
static
final
String
accessKey
=
"AXJIHUKKFLMGSVFA"
;
private
static
final
String
secretKey
=
"2e252285e64d4097a550468283d8c157"
;
/**
* 获取WPS-4签名
*
* @param request request请求
* @param body 内容主体,没有则传入NUll
* @return WPS-4签名
*/
public
static
String
getWpsDocsAuthorization
(
HttpRequest
request
,
byte
[]
body
,
String
accessKey
,
String
secretKey
)
{
String
ver
=
"WPS-4"
;
// 构造Wps-Docs-Authorization头部
StringBuilder
sign
=
new
StringBuilder
();
sign
.
append
(
ver
);
sign
.
append
(
request
.
getMethod
());
sign
.
append
(
getSignPath
(
request
.
getUrl
()));
sign
.
append
(
request
.
header
(
"Content-type"
));
sign
.
append
(
request
.
header
(
"Wps-Docs-Date"
));
if
(
body
!=
null
&&
body
.
length
>
0
)
{
sign
.
append
(
getSHA256StrJava
(
body
));
}
String
signTrue
;
try
{
signTrue
=
signHmacSha256
(
sign
.
toString
(),
secretKey
);
}
catch
(
Exception
e
)
{
log
.
error
(
"WPS-4签名出现异常"
,
e
);
throw
new
BusinessException
(
"WPS-4签名出现异常:"
+
e
.
getMessage
());
}
return
String
.
format
(
"WPS-4 %s:%s"
,
accessKey
,
signTrue
);
}
/**
* 利用java原生的摘要实现SHA256加密
*
* @param str 原文
* @return 加密后的报文
*/
public
static
String
getSHA256StrJava
(
byte
[]
str
)
{
MessageDigest
messageDigest
;
String
encodeStr
=
""
;
try
{
messageDigest
=
MessageDigest
.
getInstance
(
"SHA-256"
);
messageDigest
.
update
(
str
);
encodeStr
=
byte2Hex
(
messageDigest
.
digest
());
}
catch
(
NoSuchAlgorithmException
e
)
{
log
.
error
(
"WPS-4加密异常"
,
e
);
}
return
encodeStr
;
}
/**
* 将byte转为16进制
*
* @param bytes 字符数组
* @return 16进制字符串
*/
private
static
String
byte2Hex
(
byte
[]
bytes
)
{
StringBuilder
stringBuffer
=
new
StringBuilder
();
String
temp
;
for
(
byte
aByte
:
bytes
)
{
temp
=
Integer
.
toHexString
(
aByte
&
0xFF
);
if
(
temp
.
length
()
==
1
)
{
stringBuffer
.
append
(
"0"
);
}
stringBuffer
.
append
(
temp
);
}
return
stringBuffer
.
toString
();
}
/**
* 获取HAMCSHA256签名内容
*
* @param data 内容
* @param key 应用密钥,即secret_key
* @return HAMCSHA256签名内容
*/
public
static
String
signHmacSha256
(
String
data
,
String
key
)
throws
Exception
{
Mac
sign
=
Mac
.
getInstance
(
"HmacSHA256"
);
SecretKeySpec
secretKey
=
new
SecretKeySpec
(
key
.
getBytes
(
StandardCharsets
.
UTF_8
),
"HmacSHA256"
);
sign
.
init
(
secretKey
);
byte
[]
array
=
sign
.
doFinal
(
data
.
getBytes
(
StandardCharsets
.
UTF_8
));
StringBuilder
sb
=
new
StringBuilder
();
for
(
byte
item
:
array
)
{
sb
.
append
(
Integer
.
toHexString
((
item
&
0xFF
)
|
0x100
),
1
,
3
);
}
return
sb
.
toString
();
}
/**
* 给url添加查询参数
*
* @param url url
* @param params 参数列表
* @return 添加了参数之后的url
*/
public
static
String
perfectUrl
(
String
url
,
Map
<
String
,
String
>
params
)
{
if
(
params
==
null
||
params
.
isEmpty
())
{
return
url
;
}
URIBuilder
uriBuilder
;
try
{
uriBuilder
=
new
URIBuilder
(
url
);
// TODO 每个参数都要实现urlEncode
for
(
String
key
:
params
.
keySet
())
{
uriBuilder
.
addParameter
(
key
,
params
.
get
(
key
));
}
}
catch
(
URISyntaxException
e
)
{
log
.
error
(
"WPS-4参数构造出现异常"
,
e
);
throw
new
BusinessException
(
"WPS-4参数构造出现异常:"
+
e
.
getMessage
());
}
return
uriBuilder
.
toString
();
}
public
static
HttpResponse
httpGet
(
String
url
,
Map
<
String
,
String
>
params
)
{
HttpRequest
request
=
HttpRequest
.
get
(
perfectUrl
(
url
,
params
));
request
.
setMethod
(
Method
.
GET
);
DateFormat
dateFormat
=
new
SimpleDateFormat
(
"EEE, dd MMM yyyy HH:mm:ss z"
,
Locale
.
US
);
dateFormat
.
setTimeZone
(
TimeZone
.
getTimeZone
(
"GMT"
));
// 设置请求头
request
.
contentType
(
"application/json"
);
request
.
header
(
"Wps-Docs-Date"
,
dateFormat
.
format
(
new
Date
()));
request
.
header
(
"Wps-Docs-Authorization"
,
WpsUtil
.
getWpsDocsAuthorization
(
request
,
null
,
accessKey
,
secretKey
));
return
request
.
execute
();
}
public
static
HttpResponse
httpPost
(
String
url
,
Map
<
String
,
String
>
params
,
Map
<
String
,
Object
>
body
,
String
accessKey
,
String
secretKey
)
{
HttpRequest
request
=
HttpRequest
.
post
(
perfectUrl
(
url
,
params
));
DateFormat
dateFormat
=
new
SimpleDateFormat
(
"EEE, dd MMM yyyy HH:mm:ss z"
,
Locale
.
US
);
dateFormat
.
setTimeZone
(
TimeZone
.
getTimeZone
(
"GMT"
));
// 设置请求头,必需三个header
request
.
contentType
(
"application/json"
);
request
.
header
(
"Wps-Docs-Date"
,
dateFormat
.
format
(
new
Date
()));
// body转json放入签名
if
(
ObjectUtil
.
isNull
(
body
))
{
request
.
header
(
"Wps-Docs-Authorization"
,
WpsUtil
.
getWpsDocsAuthorization
(
request
,
null
,
accessKey
,
secretKey
));
}
else
{
request
.
header
(
"Wps-Docs-Authorization"
,
WpsUtil
.
getWpsDocsAuthorization
(
request
,
JSONUtil
.
toJsonStr
(
body
).
getBytes
(),
accessKey
,
secretKey
));
}
if
(!
body
.
isEmpty
())
{
request
.
body
(
JSONUtil
.
toJsonStr
(
body
));
}
return
request
.
execute
();
}
/**
* 获取URL中/open后面的内容
*
* @param url URL
* @return URL中/open后面的内容
*/
public
static
String
getSignPath
(
String
url
)
{
log
.
debug
(
"url:"
+
url
);
int
index
=
url
.
indexOf
(
"/api"
);
String
substring
=
url
.
substring
(
index
);
log
.
debug
(
"suburl:"
+
substring
);
return
substring
;
}
public
static
void
main
(
String
[]
args
)
{
Map
<
String
,
String
>
params
=
new
HashMap
<>(
2
);
params
.
put
(
"type"
,
"w"
);
params
.
put
(
"preview_mode"
,
"ordinary"
);
String
uri
=
"http://171.106.48.55:33806/open/api/preview/v1/files/"
+
"132aa30a87064"
+
"/link"
;
HttpResponse
response
=
WpsUtil
.
httpGet
(
uri
,
params
);
JSON
json
=
JSONUtil
.
parseObj
(
response
.
body
());
String
code
=
json
.
getByPath
(
"code"
,
String
.
class
);
AssertUtils
.
isTrue
(
"200"
.
equals
(
code
),
"获取在线浏览地址接口出现异常 code:"
+
code
+
",msg:"
+
json
.
getByPath
(
"msg"
,
String
.
class
));
String
link
=
json
.
getByPath
(
"data.link"
,
String
.
class
);
// 反转义
link
=
StringEscapeUtils
.
unescapeJava
(
link
);
System
.
out
.
println
(
link
);
// String uri = "http://171.106.48.55:33806/open/api/privilege/v1/licence/detail";
// HttpResponse response = WpsUtil.httpGet(uri, new HashMap<>());
// System.out.println(response.body());
}
}
file-server/src/main/java/com/zq/file/vo/Creator.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public
class
Creator
{
/**
* 创建者ID
*/
private
Long
id
;
/**
* 创建者名称
*/
private
String
name
;
/**
* 创建者的头像地址
*/
private
String
avatar_url
;
}
file-server/src/main/java/com/zq/file/vo/Modifier.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public
class
Modifier
{
/**
* 修改者ID
*/
private
Long
id
;
/**
* 修改者名称
*/
private
String
name
;
/**
* 修改者头像地址
*/
private
String
avatar_url
;
}
file-server/src/main/java/com/zq/file/vo/OnLinePreview/FileResult.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
.
OnLinePreview
;
import
com.zq.file.vo.UserAclVo
;
import
com.zq.file.vo.Watermark
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
/**
* 在线浏览的文件返回类
*
* @author ZQ
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public
class
FileResult
{
/**
* 文件id,字符串长度不超过64位
*/
private
String
id
;
/**
* 文件名必须带后缀
*/
private
String
name
;
/**
* 文档版本号,从1开始累加,位数小于11
*/
private
Integer
version
;
/**
* 文档大小,单位为字节;此处需传文件真实大小,否则会出现异常
*/
private
Long
size
;
/**
* readonly默认为 false true 开启表格筛选,支持对EXCEL表格文档筛选,但
* 不支持对EXCEL表格文档开启多人同步筛选,该预览特性见常见问题
* false 关闭表格筛选(20220707新增)
*/
private
Boolean
readonly
=
false
;
/**
* 创建者id
*/
private
String
creator
;
/**
* 创建时间
*/
private
Long
create_time
;
/**
* 修改者id
*/
private
String
modifier
;
/**
* 修改时间
*/
private
Long
modify_time
;
/**
* 下载地址
*/
private
String
download_url
;
/**
* 限制预览页数
*/
private
Integer
preview_pages
;
/**
* 用户权限
*/
private
UserAclVo
user_acl
;
/**
* 水印参数
*/
private
Watermark
watermark
;
}
file-server/src/main/java/com/zq/file/vo/OnLinePreview/OnlinePreviewEnum.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
.
OnLinePreview
;
public
enum
OnlinePreviewEnum
{
//成功
Success
(
"Success"
,
Long
.
parseLong
(
"200"
)),
//用户未登录
UserNotLogin
(
"UserNotLogin"
,
Long
.
parseLong
(
"20501001"
)),
//token过期
SessionExpired
(
"SessionExpired"
,
Long
.
parseLong
(
"20501002"
)),
//用户无权限访问
PermissionDenied
(
"PermissionDenied"
,
Long
.
parseLong
(
"20501003"
)),
//资源不存在
NotExists
(
"NotExists"
,
Long
.
parseLong
(
"20501004"
)),
//参数错误
InvalidArgument
(
"InvalidArgument"
,
Long
.
parseLong
(
"20501005"
)),
//保存空间已满
SpaceFull
(
"SpaceFull"
,
Long
.
parseLong
(
"20501006"
)),
//自定义错误提示,前端页面显示此错误
CustomMsg
(
"CustomMsg"
,
Long
.
parseLong
(
"20501007"
)),
//文件重命名冲突
FnameConflict
(
"FnameConflict"
,
Long
.
parseLong
(
"20501008"
)),
//系统内部错误
ServerError
(
"ServerError"
,
Long
.
parseLong
(
"20501999"
)),
;
private
OnlinePreviewEnum
(
String
msg
,
Long
code
)
{
this
.
msg
=
msg
;
this
.
code
=
code
;
}
private
String
msg
;
private
Long
code
;
public
String
getMsg
()
{
return
msg
;
}
public
void
setMsg
(
String
msg
)
{
this
.
msg
=
msg
;
}
public
Long
getCode
()
{
return
code
;
}
public
void
setCode
(
Long
code
)
{
this
.
code
=
code
;
}
}
file-server/src/main/java/com/zq/file/vo/OnLinePreview/OnlinePreviewResult.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
.
OnLinePreview
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
/**
* 在线浏览的返回类
*
* @author ZQ
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public
class
OnlinePreviewResult
{
/**
* 文件信息
*/
FileResult
file
;
/**
* 用户信息
*/
UserResult
user
;
}
file-server/src/main/java/com/zq/file/vo/OnLinePreview/UserAclResult.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
.
OnLinePreview
;
import
lombok.Data
;
@Data
//在线预览用户权限
public
class
UserAclResult
{
//重命名权限,1为打开该权限,0为关闭该权限,默认为0
public
Integer
rename
;
//历史版本权限,1为打开该权限,0为关闭该权限,默认为1
public
Integer
history
;
//复制,1为打开该权限,0为关闭该权限
public
Integer
copy
;
//导出,1为打开该权限,0为关闭该权限
public
Integer
export
;
//打印,1为打开该权限,0为关闭该权限
public
Integer
print
;
}
file-server/src/main/java/com/zq/file/vo/OnLinePreview/UserResult.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
.
OnLinePreview
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
/**
* 在线浏览的用户类
*
* @author ZQ
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public
class
UserResult
{
/**
* 用户id,长度不超过32位
*/
public
String
id
;
/**
* 用户名称
*/
public
String
name
;
/**
* 用户操作权限,预览固定为read
*/
public
String
permission
;
/**
* 用户头像地址,支持url和base64
*/
public
String
avatar_url
;
}
file-server/src/main/java/com/zq/file/vo/OnLinePreview/WatermarkResult.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
.
OnLinePreview
;
import
lombok.Data
;
@Data
//在线预览水印信息
public
class
WatermarkResult
{
//水印类型,0为无水印,1为文字水印
public
Integer
type
;
//文字水印的文字,当type为1时此字段必填
public
String
value
;
//水印的透明度,非必选,有默认值,格式:rgba( 192, 192, 192, 0.6 )
public
String
fillstyle
;
//水印的字体,非必选,有默认值,格式:bold 20px Serif
public
String
font
;
//水印的旋转度,非必选,有默认值
public
Float
rotate
;
//水印的水平间距,非必选,有默认值
public
Integer
horizontal
;
//水印的垂直间距,非必选,有默认值
public
Integer
vertical
;
}
file-server/src/main/java/com/zq/file/vo/OnlineEdit/FileHistorieVo.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
.
OnlineEdit
;
import
com.zq.file.vo.Creator
;
import
com.zq.file.vo.Modifier
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
/**
* 历史文件
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public
class
FileHistorieVo
{
/**
* 文件ID
*/
private
String
id
;
/**
* 文件名
*/
private
String
name
;
/**
* 文件版本号
*/
private
Integer
version
;
/**
* 文件大小
*/
private
Long
size
;
/**
* 文件下载地址
*/
private
String
download_url
;
/**
* 文件创建者
*/
private
Creator
creator
;
/**
* 文件创建时间
*/
private
Long
create_time
;
/**
* 文件修改者
*/
private
Modifier
modifier
;
/**
* 文件修改时间
*/
private
Long
modify_time
;
}
file-server/src/main/java/com/zq/file/vo/OnlineEdit/GetHistoryVersionResult.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
.
OnlineEdit
;
import
lombok.Data
;
@Data
public
class
GetHistoryVersionResult
{
public
String
id
;
public
String
name
;
public
Integer
version
;
public
Long
size
;
public
String
download_url
;
public
Long
create_time
;
public
Long
modify_time
;
public
GetHistoryVersionUserResult
creator
;
public
GetHistoryVersionUserResult
modifier
;
public
GetHistoryVersionResult
()
{
this
.
creator
=
new
GetHistoryVersionUserResult
();
this
.
modifier
=
new
GetHistoryVersionUserResult
();
}
}
file-server/src/main/java/com/zq/file/vo/OnlineEdit/GetHistoryVersionUserResult.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
.
OnlineEdit
;
import
lombok.Data
;
@Data
public
class
GetHistoryVersionUserResult
{
public
String
id
;
public
String
name
;
public
String
avatar_url
;
}
file-server/src/main/java/com/zq/file/vo/OnlineEdit/GetVersionFileResult.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
.
OnlineEdit
;
import
lombok.Data
;
@Data
public
class
GetVersionFileResult
{
public
String
id
;
public
String
name
;
public
Integer
version
;
public
Long
size
;
public
Long
create_time
;
public
String
creator
;
public
Long
modify_time
;
public
String
modifier
;
public
String
download_url
;
}
file-server/src/main/java/com/zq/file/vo/OnlineEdit/HistoriesVo.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
.
OnlineEdit
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.util.List
;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public
class
HistoriesVo
{
/**
* 历史文件列表
*/
List
<
FileHistorieVo
>
histories
;
}
file-server/src/main/java/com/zq/file/vo/OnlineEdit/OnlineEditEnum.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
.
OnlineEdit
;
public
enum
OnlineEditEnum
{
//成功
Success
(
"Success"
,
Long
.
parseLong
(
"0"
)),
//用户未登录
UserNotLogin
(
"UserNotLogin"
,
Long
.
parseLong
(
"20501001"
)),
//token过期
SessionExpired
(
"SessionExpired"
,
Long
.
parseLong
(
"20501002"
)),
//用户无权限访问
PermissionDenied
(
"PermissionDenied"
,
Long
.
parseLong
(
"20501003"
)),
//资源不存在
NotExists
(
"NotExists"
,
Long
.
parseLong
(
"20501004"
)),
//参数错误
InvalidArgument
(
"InvalidArgument"
,
Long
.
parseLong
(
"20501005"
)),
//保存空间已满
SpaceFull
(
"SpaceFull"
,
Long
.
parseLong
(
"20501006"
)),
//自定义错误提示,前端页面显示此错误
CustomMsg
(
"CustomMsg"
,
Long
.
parseLong
(
"20501007"
)),
//文件重命名冲突
FnameConflict
(
"FnameConflict"
,
Long
.
parseLong
(
"20501008"
)),
//系统内部错误
ServerError
(
"ServerError"
,
Long
.
parseLong
(
"20501999"
)),
;
private
OnlineEditEnum
(
String
msg
,
Long
code
)
{
this
.
msg
=
msg
;
this
.
code
=
code
;
}
private
String
msg
;
private
Long
code
;
public
String
getMsg
()
{
return
msg
;
}
public
void
setMsg
(
String
msg
)
{
this
.
msg
=
msg
;
}
public
Long
getCode
()
{
return
code
;
}
public
void
setCode
(
Long
code
)
{
this
.
code
=
code
;
}
}
file-server/src/main/java/com/zq/file/vo/OnlineEdit/OnlineEditMessage.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
.
OnlineEdit
;
import
com.zq.file.vo.OnLinePreview.FileResult
;
import
com.zq.file.vo.OnLinePreview.UserAclResult
;
import
com.zq.file.vo.OnLinePreview.UserResult
;
import
com.zq.file.vo.OnLinePreview.WatermarkResult
;
import
lombok.Data
;
@Data
public
class
OnlineEditMessage
{
public
OnlineEditMessage
()
{
this
.
file
=
new
FileResult
();
this
.
user
=
new
UserResult
();
this
.
user_acl
=
new
UserAclResult
();
this
.
watermark
=
new
WatermarkResult
();
}
//文件信息
public
FileResult
file
;
//用户信息
public
UserResult
user
;
//用户权限信息
public
UserAclResult
user_acl
;
//水印信息
public
WatermarkResult
watermark
;
}
file-server/src/main/java/com/zq/file/vo/OnlineEdit/OnlineEditRename.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
.
OnlineEdit
;
import
lombok.AllArgsConstructor
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
/**
* <p>
* 文件重命名接收类
* </p>
*
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public
class
OnlineEditRename
{
String
name
;
}
file-server/src/main/java/com/zq/file/vo/OnlineEdit/OnlineEditResult.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
.
OnlineEdit
;
import
lombok.Data
;
@Data
public
class
OnlineEditResult
{
public
OnlineEditResult
()
{
this
.
file
=
new
UploadFileResult
();
}
//文件信息
public
UploadFileResult
file
;
}
file-server/src/main/java/com/zq/file/vo/OnlineEdit/OnlineEditUsers.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
.
OnlineEdit
;
import
lombok.AllArgsConstructor
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.util.List
;
/**
* <p>
* 获取用户信息回调的VO
* </p>
*
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public
class
OnlineEditUsers
{
List
<
String
>
ids
;
}
file-server/src/main/java/com/zq/file/vo/OnlineEdit/OnlineEditUsersResult.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
.
OnlineEdit
;
import
com.zq.file.vo.OnLinePreview.UserResult
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.util.List
;
/**
* <p>
* 获取用户信息返回类
* </p>
*
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public
class
OnlineEditUsersResult
{
List
<
UserResult
>
users
;
}
file-server/src/main/java/com/zq/file/vo/OnlineEdit/OnlineEditVersion.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
.
OnlineEdit
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
/**
* <p>
* 获取版本文件信息接收类
* </p>
*
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public
class
OnlineEditVersion
{
/**
* 文件id,字符串长度不超过64位
*/
private
String
id
;
/**
* 文件名必须带后缀
*/
private
String
name
;
/**
* 文档版本号,从1开始累加,位数小于11
*/
private
Integer
version
;
/**
* 文档大小,单位为字节;此处需传文件真实大小,否则会出现异常
*/
private
Long
size
;
/**
* 创建者id
*/
private
String
creator
;
/**
* 创建时间
*/
private
Long
create_time
;
/**
* 修改者id
*/
private
String
modifier
;
/**
* 修改时间
*/
private
Long
modify_time
;
/**
* 下载地址
*/
private
String
download_url
;
}
file-server/src/main/java/com/zq/file/vo/OnlineEdit/UploadFileResult.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
.
OnlineEdit
;
import
lombok.Data
;
@Data
public
class
UploadFileResult
{
public
String
id
;
public
String
name
;
public
Integer
version
;
public
Long
size
;
public
String
download_url
;
}
file-server/src/main/java/com/zq/file/vo/UserAclVo.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
;
import
lombok.Data
;
/**
* 用户权限配置
*/
@Data
public
class
UserAclVo
{
/**
* 重命名权限,1为打开该权限,0为关闭该权限,默认为0
*/
private
Integer
rename
=
0
;
/**
* 历史版本权限,1为打开该权限,0为关闭该权限,默认为1
*/
private
Integer
history
=
0
;
/**
* 复制权限,1为打开该权限,0为关闭该权限,默认为1
*/
private
Integer
copy
=
0
;
/**
* 导出权限,1为打开该权限,0为关闭该权限,默认为1
*/
private
Integer
export
=
1
;
/**
* 打印权限,1为打开该权限,0为关闭该权限,默认为1
*/
private
Integer
print
=
1
;
/**
*只读情况下的可评论权限,1为打开该权限,0为关闭该权限,默认为0v6.0.2207.20220729新增
*/
private
Integer
comment
=
0
;
}
file-server/src/main/java/com/zq/file/vo/Watermark.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
;
import
lombok.Data
;
/**
* 水印配置
*/
@Data
public
class
Watermark
{
/**
* 水印类型, 0为无水印; 1为文字水印
*/
private
Integer
type
=
0
;
/**
* 文字水印的文字,支持通过 \r\n 换行,支持emoji表情,当type为1时此字段必选
*/
private
String
value
=
"禁止传阅wps-1000"
;
/**
* 水印的颜色(含透明度),非必选,有默认值。格式为:
* rgba( 192, 192, 192, 0.6 )
*/
private
String
fillstyle
=
"rgba( 192, 192, 192, 0.6 )"
;
/**
* 水印的字体,非必选,有默认值,格式为:
* bold 20px Serif
*/
private
String
font
=
"bold 20px Serif"
;
/**
* 水印的旋转度,非必选,有默认值
*/
private
Double
rotate
=
-
0.7853982
;
/**
* 水印水平间距,非必选,有默认值
*/
private
Integer
horizontal
=
50
;
/**
* 水印垂直间距,非必选,有默认值
*/
private
Integer
vertical
=
100
;
}
file-server/src/main/java/com/zq/file/vo/WpsCertificateTimeVO.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
file
.
vo
;
import
lombok.Data
;
/**
* @author ZQ
*/
@Data
public
class
WpsCertificateTimeVO
{
/**
* 证书过期时间,单位为秒
*/
private
Integer
dead_line
;
/**
* 证书距离过期天数
*/
private
Integer
licence_remaining_time
;
/**
* 消息
*/
private
String
message
;
}
imgproc-server/pom.xml
View file @
627e5035
...
@@ -128,7 +128,7 @@
...
@@ -128,7 +128,7 @@
<dependency>
<dependency>
<groupId>
cn.hutool
</groupId>
<groupId>
cn.hutool
</groupId>
<artifactId>
hutool-all
</artifactId>
<artifactId>
hutool-all
</artifactId>
<version>
5.8.
19
</version>
<version>
5.8.
23
</version>
</dependency>
</dependency>
<dependency>
<dependency>
<groupId>
com.alibaba
</groupId>
<groupId>
com.alibaba
</groupId>
...
...
imgproc-server/src/main/java/com/zq/imgproc/config/SwaggerConfig.java
View file @
627e5035
...
@@ -7,6 +7,8 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc;
...
@@ -7,6 +7,8 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import
org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry
;
import
org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry
;
import
org.springframework.web.servlet.config.annotation.WebMvcConfigurer
;
import
org.springframework.web.servlet.config.annotation.WebMvcConfigurer
;
import
springfox.documentation.builders.ApiInfoBuilder
;
import
springfox.documentation.builders.ApiInfoBuilder
;
import
springfox.documentation.builders.PathSelectors
;
import
springfox.documentation.builders.RequestHandlerSelectors
;
import
springfox.documentation.service.ApiInfo
;
import
springfox.documentation.service.ApiInfo
;
import
springfox.documentation.spi.DocumentationType
;
import
springfox.documentation.spi.DocumentationType
;
import
springfox.documentation.spring.web.plugins.Docket
;
import
springfox.documentation.spring.web.plugins.Docket
;
...
@@ -43,15 +45,16 @@ public class SwaggerConfig implements WebMvcConfigurer {
...
@@ -43,15 +45,16 @@ public class SwaggerConfig implements WebMvcConfigurer {
@Bean
@Bean
public
Docket
api
()
{
public
Docket
api
()
{
return
new
Docket
(
DocumentationType
.
SWAGGER_2
).
enable
(
false
);
return
new
Docket
(
DocumentationType
.
SWAGGER_2
)
// .groupName("项目")
// .enable(false);
// // 生产环境关闭
.
groupName
(
"项目"
)
// .enable(!"product".equals(profile))
// 生产环境关闭
// .select()
.
enable
(!
"product"
.
equals
(
profile
))
// .apis(RequestHandlerSelectors.basePackage("com.zq.imgproc.controller"))
.
select
()
// .paths(PathSelectors.any())
.
apis
(
RequestHandlerSelectors
.
basePackage
(
"com.zq.imgproc.controller"
))
// .build()
.
paths
(
PathSelectors
.
any
())
// .apiInfo(apiInfo());
.
build
()
.
apiInfo
(
apiInfo
());
}
}
private
ApiInfo
apiInfo
()
{
private
ApiInfo
apiInfo
()
{
...
...
imgproc-server/src/main/java/com/zq/imgproc/config/ThreadPoolConfig.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
imgproc
.
config
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.scheduling.annotation.EnableAsync
;
import
org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
;
import
java.util.concurrent.Executor
;
import
java.util.concurrent.ThreadPoolExecutor
;
/**
* <p>
* 线程池配置
* </P>
*
* @author chenhao
* @since 2023/5/29
*/
@EnableAsync
@Configuration
public
class
ThreadPoolConfig
{
@Bean
(
"detectionExecutor"
)
public
Executor
asyncServiceExecutor
()
{
ThreadPoolTaskExecutor
executor
=
new
ThreadPoolTaskExecutor
();
// 设置核心线程数等于系统核数
int
availableProcessors
=
Runtime
.
getRuntime
().
availableProcessors
();
executor
.
setCorePoolSize
(
availableProcessors
);
// 设置最大线程数
executor
.
setMaxPoolSize
(
availableProcessors
*
2
);
//配置队列大小
executor
.
setQueueCapacity
(
2048
);
// 设置线程活跃时间(秒)
executor
.
setKeepAliveSeconds
(
30
);
// 设置拒绝策略
executor
.
setRejectedExecutionHandler
(
new
ThreadPoolExecutor
.
AbortPolicy
());
// 设置默认线程名称
executor
.
setThreadNamePrefix
(
"detection-thread"
);
// 等待所有任务结束后再关闭线程池
executor
.
setWaitForTasksToCompleteOnShutdown
(
true
);
//执行初始化
executor
.
initialize
();
return
executor
;
}
}
imgproc-server/src/main/java/com/zq/imgproc/constant/Threshold.java
View file @
627e5035
...
@@ -43,4 +43,9 @@ public class Threshold {
...
@@ -43,4 +43,9 @@ public class Threshold {
*/
*/
public
static
final
int
BLACK
=
100
;
public
static
final
int
BLACK
=
100
;
/**
* 图片DPI
*/
public
static
final
int
DPI
=
30
;
}
}
imgproc-server/src/main/java/com/zq/imgproc/controller/ApiController.java
View file @
627e5035
package
com
.
zq
.
imgproc
.
controller
;
package
com
.
zq
.
imgproc
.
controller
;
import
cn.hutool.core.codec.Base64Encoder
;
import
cn.hutool.core.io.FileUtil
;
import
cn.hutool.http.HttpUtil
;
import
cn.hutool.json.JSONObject
;
import
cn.hutool.json.JSONUtil
;
import
com.zq.common.annotation.rest.AnonymousGetMapping
;
import
com.zq.common.annotation.rest.AnonymousGetMapping
;
import
com.zq.common.annotation.rest.AnonymousPostMapping
;
import
com.zq.common.utils.AssertUtils
;
import
com.zq.common.utils.AssertUtils
;
import
com.zq.common.utils.UuidUtils
;
import
com.zq.common.vo.ResultVo
;
import
com.zq.common.vo.ResultVo
;
import
com.zq.imgproc.server.ImgProcService
;
import
com.zq.imgproc.service.ApiService
;
import
com.zq.imgproc.utils.*
;
import
com.zq.imgproc.vo.DetectionVO
;
import
com.zq.imgproc.vo.OptimizationReq
;
import
com.zq.imgproc.vo.OptimizationReq
;
import
com.zq.imgproc.vo.OptimizationVO
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiOperation
;
import
io.swagger.annotations.ApiOperation
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.bind.annotation.RequestBody
;
import
org.springframework.web.multipart.MultipartFile
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
java.io.IOException
;
import
java.text.SimpleDateFormat
;
import
java.util.Date
;
import
java.util.HashMap
;
/**
/**
* <p>
* <p>
...
@@ -33,7 +22,7 @@ import java.util.HashMap;
...
@@ -33,7 +22,7 @@ import java.util.HashMap;
* @author chenhao
* @author chenhao
* @since 2023/3/18 9:32
* @since 2023/3/18 9:32
*/
*/
@
io
.
swagger
.
annotations
.
Api
(
tags
=
"图片处理API"
)
@Api
(
tags
=
"图片处理API"
)
@RequestMapping
(
"/imgproc/v1"
)
@RequestMapping
(
"/imgproc/v1"
)
@RestController
@RestController
public
class
ApiController
{
public
class
ApiController
{
...
@@ -43,9 +32,9 @@ public class ApiController {
...
@@ -43,9 +32,9 @@ public class ApiController {
@Value
(
"${imgconfig.deskew}"
)
@Value
(
"${imgconfig.deskew}"
)
String
deskewUrl
;
String
deskewUrl
;
private
final
ImgProc
Service
service
;
private
final
Api
Service
service
;
@Autowired
@Autowired
public
ApiController
(
ImgProc
Service
service
)
{
public
ApiController
(
Api
Service
service
)
{
this
.
service
=
service
;
this
.
service
=
service
;
}
}
...
@@ -56,111 +45,11 @@ public class ApiController {
...
@@ -56,111 +45,11 @@ public class ApiController {
}
}
@ApiOperation
(
"图片检测"
)
@ApiOperation
(
"图片检测"
)
@PostMapping
(
"/detection"
)
@AnonymousPostMapping
(
"/detection"
)
public
ResultVo
<
DetectionVO
>
detection
(
@RequestBody
OptimizationReq
req
)
throws
Exception
{
public
ResultVo
<?>
detection
(
@RequestBody
OptimizationReq
req
)
throws
Exception
{
AssertUtils
.
hasText
(
req
.
getFileContent
(),
"缺少文件内容"
);
AssertUtils
.
hasText
(
req
.
getFilename
(),
"缺少文件名"
);
return
ResultVo
.
success
(
service
.
detection2
(
req
));
}
@ApiOperation
(
"图片校正(deskew工具)"
)
@PostMapping
(
"/imageCorrection"
)
public
ResultVo
<?>
imageCorrection
(
@RequestPart
MultipartFile
file
)
{
if
(
file
.
isEmpty
())
{
return
ResultVo
.
fail
(
"文件不能为空"
);
}
String
imgPath
=
UploadUtils
.
saveTempFile
(
file
,
"api"
);
String
ext
=
FileUtil
.
extName
(
file
.
getOriginalFilename
());
String
yyyyMMdd
=
new
SimpleDateFormat
(
"/yyyyMM/dd/"
).
format
(
new
Date
());
String
savePath
=
"/file/temp"
+
yyyyMMdd
+
UuidUtils
.
uuidNoDash
()
+
"."
+
ext
;
// 图片矫正
ImageCorrectionUtil
.
deskew
(
imgPath
,
savePath
,
deskewUrl
,
false
);
return
ResultVo
.
success
(
Base64Encoder
.
encode
(
FileUtil
.
readBytes
(
savePath
)));
}
@ApiOperation
(
"去黑边"
)
@PostMapping
(
"/removeBlack"
)
public
ResultVo
<?>
removeBlack
(
@RequestPart
MultipartFile
file
)
{
if
(
file
.
isEmpty
())
{
return
ResultVo
.
fail
(
"文件不能为空"
);
}
System
.
load
(
opencvUrl
);
String
imgPath
=
UploadUtils
.
saveTempFile
(
file
,
"api"
);
String
ext
=
FileUtil
.
extName
(
file
.
getOriginalFilename
());
String
yyyyMMdd
=
new
SimpleDateFormat
(
"/yyyyMM/dd/"
).
format
(
new
Date
());
String
savePath
=
"/file/temp"
+
yyyyMMdd
+
UuidUtils
.
uuidNoDash
()
+
"."
+
ext
;
// 去黑边
RemoveBlackUtil2
.
remove
(
imgPath
,
savePath
);
return
ResultVo
.
success
(
Base64Encoder
.
encode
(
savePath
));
}
@ApiOperation
(
"图片灰度化"
)
@PostMapping
(
"/gray"
)
public
ResultVo
<?>
gray
(
@RequestPart
MultipartFile
file
)
{
if
(
file
.
isEmpty
())
{
return
ResultVo
.
fail
(
"文件不能为空"
);
}
System
.
load
(
opencvUrl
);
String
imgPath
=
UploadUtils
.
saveTempFile
(
file
,
"api"
);
String
ext
=
FileUtil
.
extName
(
file
.
getOriginalFilename
());
String
yyyyMMdd
=
new
SimpleDateFormat
(
"/yyyyMM/dd/"
).
format
(
new
Date
());
String
savePath
=
"/file/temp"
+
yyyyMMdd
+
UuidUtils
.
uuidNoDash
()
+
"."
+
ext
;
// 灰度化
ImageUtil
.
gray
(
imgPath
,
savePath
);
return
ResultVo
.
success
(
Base64Encoder
.
encode
(
FileUtil
.
readBytes
(
savePath
)));
}
@ApiOperation
(
"图片边缘检测"
)
@PostMapping
(
"/canny"
)
public
ResultVo
<?>
canny
(
@RequestPart
MultipartFile
file
)
{
if
(
file
.
isEmpty
())
{
return
ResultVo
.
fail
(
"文件不能为空"
);
}
System
.
load
(
opencvUrl
);
String
imgPath
=
UploadUtils
.
saveTempFile
(
file
,
"api"
);
String
ext
=
FileUtil
.
extName
(
file
.
getOriginalFilename
());
String
yyyyMMdd
=
new
SimpleDateFormat
(
"/yyyyMM/dd/"
).
format
(
new
Date
());
String
savePath
=
"/file/temp"
+
yyyyMMdd
+
UuidUtils
.
uuidNoDash
()
+
"."
+
ext
;
// 边缘检测
ImageUtil
.
canny
(
imgPath
,
savePath
);
return
ResultVo
.
success
(
Base64Encoder
.
encode
(
FileUtil
.
readBytes
(
savePath
)));
}
@ApiOperation
(
"图片弯曲矫正"
)
@PostMapping
(
"/correct"
)
public
ResultVo
<?>
correct
(
@RequestPart
MultipartFile
file
)
{
if
(
file
.
isEmpty
())
{
return
ResultVo
.
fail
(
"文件不能为空"
);
}
String
imgPath
=
UploadUtils
.
saveTempFile
(
file
,
"api"
);
// 图片弯曲矫正
HashMap
<
String
,
Object
>
map
=
new
HashMap
<>();
map
.
put
(
"file"
,
FileUtil
.
file
(
imgPath
));
String
response
=
HttpUtil
.
post
(
"http://ddns.gxmailu.com:18888/api/correct"
,
map
);
JSONObject
res
=
JSONUtil
.
parseObj
(
response
);
if
(
res
.
get
(
"success"
,
Boolean
.
class
))
{
String
base64
=
res
.
get
(
"data"
,
String
.
class
);
return
ResultVo
.
success
(
base64
);
}
else
{
return
ResultVo
.
fail
(
res
.
get
(
"msg"
,
String
.
class
));
}
}
@ApiOperation
(
"图片优化"
)
@PostMapping
(
"/imageOptimization"
)
public
ResultVo
<
OptimizationVO
>
imageOptimization
(
@RequestBody
OptimizationReq
req
)
throws
IOException
{
AssertUtils
.
hasText
(
req
.
getFileContent
(),
"缺少文件内容"
);
AssertUtils
.
hasText
(
req
.
getFileContent
(),
"缺少文件内容"
);
AssertUtils
.
hasText
(
req
.
getFile
n
ame
(),
"缺少文件名"
);
AssertUtils
.
hasText
(
req
.
getFile
N
ame
(),
"缺少文件名"
);
return
ResultVo
.
success
(
service
.
optimization
(
req
)
);
return
service
.
detection
(
req
);
}
}
}
}
imgproc-server/src/main/java/com/zq/imgproc/controller/ImageBatchController.java
View file @
627e5035
...
@@ -40,7 +40,7 @@ public class ImageBatchController {
...
@@ -40,7 +40,7 @@ public class ImageBatchController {
private
final
ImageDetectionDao
imageDetectionDao
;
private
final
ImageDetectionDao
imageDetectionDao
;
private
final
ImageBatchDao
imageBatchDao
;
private
final
ImageBatchDao
imageBatchDao
;
@ApiOperation
(
"根据ID查询"
)
@ApiOperation
(
"根据ID查询
不合格页数
"
)
@GetMapping
(
"/unqualified/{id}"
)
@GetMapping
(
"/unqualified/{id}"
)
public
ResultVo
<
Long
>
unqualified
(
@PathVariable
Long
id
)
{
public
ResultVo
<
Long
>
unqualified
(
@PathVariable
Long
id
)
{
return
ResultVo
.
success
(
imageDetectionDao
.
selectCount
(
return
ResultVo
.
success
(
imageDetectionDao
.
selectCount
(
...
@@ -48,8 +48,24 @@ public class ImageBatchController {
...
@@ -48,8 +48,24 @@ public class ImageBatchController {
));
));
}
}
@ApiOperation
(
"获取批号的完成百分比"
)
@GetMapping
(
"/getCompleteDegree/{id}"
)
public
ResultVo
<
Integer
>
getCompleteDegree
(
@PathVariable
Long
id
)
{
long
count
=
imageDetectionDao
.
selectCount
(
Wrappers
.
lambdaQuery
(
ImageDetection
.
builder
().
batchId
(
id
).
build
())
);
if
(
count
==
0
)
{
return
ResultVo
.
success
(
0
);
}
long
complete
=
imageDetectionDao
.
selectCount
(
Wrappers
.
lambdaQuery
(
ImageDetection
.
builder
().
batchId
(
id
).
build
()).
isNotNull
(
ImageDetection:
:
getQualified
)
);
return
ResultVo
.
success
(
Convert
.
toInt
(
complete
/
count
)
*
100
);
}
@ApiOperation
(
"根据ID查询"
)
@ApiOperation
(
"根据ID查询"
)
@GetMapping
(
"/sele/{id}"
)
@GetMapping
(
"/sele
ctOne
/{id}"
)
public
ResultVo
<
ImageBatch
>
selectOne
(
@PathVariable
Long
id
)
{
public
ResultVo
<
ImageBatch
>
selectOne
(
@PathVariable
Long
id
)
{
return
ResultVo
.
success
(
imageBatchDao
.
selectById
(
id
));
return
ResultVo
.
success
(
imageBatchDao
.
selectById
(
id
));
}
}
...
@@ -70,6 +86,7 @@ public class ImageBatchController {
...
@@ -70,6 +86,7 @@ public class ImageBatchController {
if
(
StrUtil
.
isNotBlank
(
req
.
getEndTime
()))
{
if
(
StrUtil
.
isNotBlank
(
req
.
getEndTime
()))
{
wrapper
.
lt
(
ImageBatch:
:
getCreateTime
,
req
.
getEndTime
());
wrapper
.
lt
(
ImageBatch:
:
getCreateTime
,
req
.
getEndTime
());
}
}
wrapper
.
orderByDesc
(
ImageBatch:
:
getId
);
IPage
<
ImageBatch
>
page
=
new
Page
<>(
req
.
getPage
(),
req
.
getSize
());
IPage
<
ImageBatch
>
page
=
new
Page
<>(
req
.
getPage
(),
req
.
getSize
());
page
=
imageBatchDao
.
selectPage
(
page
,
wrapper
);
page
=
imageBatchDao
.
selectPage
(
page
,
wrapper
);
return
ResultVo
.
success
(
PageVo
.
ofReqVo
(
req
,
page
.
getRecords
(),
Convert
.
toInt
(
page
.
getSize
())));
return
ResultVo
.
success
(
PageVo
.
ofReqVo
(
req
,
page
.
getRecords
(),
Convert
.
toInt
(
page
.
getSize
())));
...
...
imgproc-server/src/main/java/com/zq/imgproc/controller/ImageDetectionController.java
View file @
627e5035
...
@@ -4,7 +4,7 @@ import com.zq.common.utils.AssertUtils;
...
@@ -4,7 +4,7 @@ import com.zq.common.utils.AssertUtils;
import
com.zq.common.vo.PageVo
;
import
com.zq.common.vo.PageVo
;
import
com.zq.common.vo.ResultVo
;
import
com.zq.common.vo.ResultVo
;
import
com.zq.imgproc.entity.ImageDetection
;
import
com.zq.imgproc.entity.ImageDetection
;
import
com.zq.imgproc.serv
er
.ImageDetectionService
;
import
com.zq.imgproc.serv
ice
.ImageDetectionService
;
import
com.zq.imgproc.vo.DetectionPageReq
;
import
com.zq.imgproc.vo.DetectionPageReq
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiOperation
;
import
io.swagger.annotations.ApiOperation
;
...
@@ -54,6 +54,14 @@ public class ImageDetectionController {
...
@@ -54,6 +54,14 @@ public class ImageDetectionController {
return
service
.
detection
(
userId
,
nickName
,
batchName
,
file
);
return
service
.
detection
(
userId
,
nickName
,
batchName
,
file
);
}
}
@ApiOperation
(
"重新检测"
)
@GetMapping
(
"/reDetection/{batchId}/{userId}"
)
public
ResultVo
<?>
reDetection
(
@PathVariable
Long
batchId
,
@PathVariable
Long
userId
)
{
AssertUtils
.
notNull
(
batchId
,
"批次ID不能为空!"
);
AssertUtils
.
notNull
(
userId
,
"用户ID不能为空!"
);
return
service
.
reDetection
(
batchId
,
userId
);
}
@ApiOperation
(
"导出检测结果"
)
@ApiOperation
(
"导出检测结果"
)
@GetMapping
(
"/getDetection/{batchId}"
)
@GetMapping
(
"/getDetection/{batchId}"
)
public
ResponseEntity
<
Resource
>
getDetection
(
@PathVariable
Long
batchId
)
{
public
ResponseEntity
<
Resource
>
getDetection
(
@PathVariable
Long
batchId
)
{
...
...
imgproc-server/src/main/java/com/zq/imgproc/controller/ImgProcController.java
View file @
627e5035
...
@@ -4,7 +4,7 @@ import cn.hutool.core.io.FileUtil;
...
@@ -4,7 +4,7 @@ import cn.hutool.core.io.FileUtil;
import
cn.hutool.extra.servlet.ServletUtil
;
import
cn.hutool.extra.servlet.ServletUtil
;
import
com.zq.common.utils.AssertUtils
;
import
com.zq.common.utils.AssertUtils
;
import
com.zq.common.vo.ResultVo
;
import
com.zq.common.vo.ResultVo
;
import
com.zq.imgproc.serv
er
.ImgProcService
;
import
com.zq.imgproc.serv
ice
.ImgProcService
;
import
com.zq.imgproc.utils.DecompressUtil
;
import
com.zq.imgproc.utils.DecompressUtil
;
import
com.zq.imgproc.utils.ImageUtil
;
import
com.zq.imgproc.utils.ImageUtil
;
import
com.zq.imgproc.vo.*
;
import
com.zq.imgproc.vo.*
;
...
...
imgproc-server/src/main/java/com/zq/imgproc/controller/ImgSettingController.java
View file @
627e5035
...
@@ -30,7 +30,9 @@ public class ImgSettingController {
...
@@ -30,7 +30,9 @@ public class ImgSettingController {
@ApiOperation
(
"根据用户ID获取指标"
)
@ApiOperation
(
"根据用户ID获取指标"
)
@GetMapping
(
"/getSetting/{userId}"
)
@GetMapping
(
"/getSetting/{userId}"
)
public
ResultVo
<?>
getSetting
(
@PathVariable
long
userId
)
{
public
ResultVo
<?>
getSetting
(
@PathVariable
long
userId
)
{
ImgSetting
setting
=
imgSettingDao
.
selectOne
(
Wrappers
.
lambdaQuery
(
ImgSetting
.
builder
().
userId
(
userId
).
build
()));
ImgSetting
setting
=
imgSettingDao
.
selectOne
(
Wrappers
.
lambdaQuery
(
ImgSetting
.
builder
().
userId
(
userId
).
build
())
);
// 找寻不到用户的指标,则返回默认值
// 找寻不到用户的指标,则返回默认值
if
(
setting
==
null
)
{
if
(
setting
==
null
)
{
setting
=
ImgSetting
.
builder
()
setting
=
ImgSetting
.
builder
()
...
@@ -40,6 +42,7 @@ public class ImgSettingController {
...
@@ -40,6 +42,7 @@ public class ImgSettingController {
.
bend
(
Threshold
.
BEND
)
.
bend
(
Threshold
.
BEND
)
.
deskewAngel
(
Threshold
.
DESKEW
)
.
deskewAngel
(
Threshold
.
DESKEW
)
.
black
(
Threshold
.
BLACK
)
.
black
(
Threshold
.
BLACK
)
.
dpi
(
Threshold
.
DPI
)
.
build
();
.
build
();
}
}
return
ResultVo
.
success
(
setting
);
return
ResultVo
.
success
(
setting
);
...
@@ -52,6 +55,12 @@ public class ImgSettingController {
...
@@ -52,6 +55,12 @@ public class ImgSettingController {
return
ResultVo
.
fail
(
"用户ID不能为空!"
);
return
ResultVo
.
fail
(
"用户ID不能为空!"
);
}
}
if
(
imgSetting
.
getDpi
()
!=
null
)
{
if
(
imgSetting
.
getDpi
()
<
0
)
{
return
ResultVo
.
fail
(
"dpi不能小于0!"
);
}
}
if
(
imgSetting
.
getBrightnessStart
()
!=
null
)
{
if
(
imgSetting
.
getBrightnessStart
()
!=
null
)
{
if
(
imgSetting
.
getBrightnessStart
()
<
0
||
imgSetting
.
getBrightnessStart
()
>
255
)
{
if
(
imgSetting
.
getBrightnessStart
()
<
0
||
imgSetting
.
getBrightnessStart
()
>
255
)
{
return
ResultVo
.
fail
(
"亮度值的范围在0到255之间!"
);
return
ResultVo
.
fail
(
"亮度值的范围在0到255之间!"
);
...
...
imgproc-server/src/main/java/com/zq/imgproc/service/ApiService.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
imgproc
.
service
;
import
cn.hutool.core.codec.Base64
;
import
cn.hutool.core.convert.Convert
;
import
cn.hutool.core.io.FileUtil
;
import
com.zq.common.utils.UuidUtils
;
import
com.zq.common.vo.ResultVo
;
import
com.zq.imgproc.utils.Deskew
;
import
com.zq.imgproc.utils.ImageUtil
;
import
com.zq.imgproc.vo.ApiDetectionVO
;
import
com.zq.imgproc.vo.OptimizationReq
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.opencv.core.Mat
;
import
org.opencv.imgcodecs.Imgcodecs
;
import
org.springframework.stereotype.Service
;
import
java.io.File
;
import
java.math.BigDecimal
;
import
java.math.RoundingMode
;
/**
* <p>
*
* </p>
*
* @author chenhao
* @since 2023/12/1
*/
@Slf4j
@RequiredArgsConstructor
@Service
public
class
ApiService
{
public
ResultVo
<?>
detection
(
OptimizationReq
req
)
{
ApiDetectionVO
vo
=
new
ApiDetectionVO
();
try
{
String
ext
=
FileUtil
.
extName
(
req
.
getFileName
());
String
filePath
=
"/data/temp/"
+
UuidUtils
.
uuidNoDash
()
+
"."
+
ext
;
File
image
=
FileUtil
.
file
(
filePath
);
FileUtil
.
writeBytes
(
Base64
.
decode
(
req
.
getFileContent
()),
image
);
Mat
src
=
Imgcodecs
.
imread
(
filePath
);
vo
.
setFileName
(
req
.
getFileName
());
vo
.
setSize
(
transformMb
(
image
.
length
()));
// 检测图片的分辨率
vo
.
setWidthResolution
(
src
.
width
());
vo
.
setHeightResolution
(
src
.
height
());
// 检测图片的DPI
vo
.
setDpi
(
ImageUtil
.
getDpi
(
image
));
// 检测图片清晰度
BigDecimal
clarity
=
BigDecimal
.
valueOf
(
ImageUtil
.
tenengrad
(
src
));
vo
.
setClarity
(
clarity
.
setScale
(
2
,
RoundingMode
.
HALF_UP
).
doubleValue
());
// 检测图片的亮度
vo
.
setBrightness
(
Convert
.
toInt
(
ImageUtil
.
brightness
(
src
)));
// 检测图片倾斜角度
vo
.
setDeskewAngel
(
Math
.
abs
(
Deskew
.
getDeskewAngle
(
src
)));
// 检测图片的黑边
vo
.
setBlack
(
ImageUtil
.
blackDetection2
(
src
));
// 图片弯曲检测
// BendResult bendResult = BendUtil.getBendResult(filePath);
// vo.setBend(bendResult.getConfidence());
vo
.
setBend
(
0.0
);
FileUtil
.
del
(
filePath
);
}
catch
(
Exception
e
)
{
log
.
error
(
"图片检测出现异常"
,
e
);
return
ResultVo
.
fail
(
"图片检测出现异常!"
);
}
return
ResultVo
.
success
(
vo
);
}
/**
* 将字节数转换为MB
*/
private
double
transformMb
(
long
size
)
{
BigDecimal
sizeDecimal
=
BigDecimal
.
valueOf
(
size
);
BigDecimal
mb
=
BigDecimal
.
valueOf
(
1024
*
1024
);
return
sizeDecimal
.
divide
(
mb
,
2
,
RoundingMode
.
DOWN
).
doubleValue
();
}
}
imgproc-server/src/main/java/com/zq/imgproc/serv
er
/ImageDetectionService.java
→
imgproc-server/src/main/java/com/zq/imgproc/serv
ice
/ImageDetectionService.java
View file @
627e5035
package
com
.
zq
.
imgproc
.
serv
er
;
package
com
.
zq
.
imgproc
.
serv
ice
;
import
cn.hutool.core.convert.Convert
;
import
cn.hutool.core.convert.Convert
;
import
cn.hutool.core.date.DateUtil
;
import
cn.hutool.core.date.DateUtil
;
...
@@ -21,11 +21,15 @@ import com.zq.imgproc.utils.BendUtil;
...
@@ -21,11 +21,15 @@ import com.zq.imgproc.utils.BendUtil;
import
com.zq.imgproc.utils.DecompressUtil
;
import
com.zq.imgproc.utils.DecompressUtil
;
import
com.zq.imgproc.utils.Deskew
;
import
com.zq.imgproc.utils.Deskew
;
import
com.zq.imgproc.utils.ImageUtil
;
import
com.zq.imgproc.utils.ImageUtil
;
import
com.zq.imgproc.vo.*
;
import
com.zq.imgproc.vo.BendResult
;
import
lombok.RequiredArgsConstructor
;
import
com.zq.imgproc.vo.DetectionPageReq
;
import
com.zq.imgproc.vo.ImageDetectionDTO
;
import
com.zq.imgproc.vo.ImgVO
;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
import
org.opencv.core.Mat
;
import
org.opencv.core.Mat
;
import
org.opencv.imgcodecs.Imgcodecs
;
import
org.opencv.imgcodecs.Imgcodecs
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Qualifier
;
import
org.springframework.core.io.InputStreamResource
;
import
org.springframework.core.io.InputStreamResource
;
import
org.springframework.core.io.Resource
;
import
org.springframework.core.io.Resource
;
import
org.springframework.http.ContentDisposition
;
import
org.springframework.http.ContentDisposition
;
...
@@ -41,6 +45,7 @@ import java.math.BigDecimal;
...
@@ -41,6 +45,7 @@ import java.math.BigDecimal;
import
java.math.RoundingMode
;
import
java.math.RoundingMode
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.List
;
import
java.util.concurrent.Executor
;
/**
/**
* <p>
* <p>
...
@@ -51,13 +56,18 @@ import java.util.List;
...
@@ -51,13 +56,18 @@ import java.util.List;
* @since 2023/11/28
* @since 2023/11/28
*/
*/
@Slf4j
@Slf4j
@RequiredArgsConstructor
@Service
@Service
public
class
ImageDetectionService
{
public
class
ImageDetectionService
{
private
final
ImgSettingDao
imgSettingDao
;
@Autowired
private
final
ImageDetectionDao
imageDetectionDao
;
@Qualifier
(
"detectionExecutor"
)
private
final
ImageBatchDao
imageBatchDao
;
private
Executor
detectionExecutor
;
@Autowired
private
ImgSettingDao
imgSettingDao
;
@Autowired
private
ImageDetectionDao
imageDetectionDao
;
@Autowired
private
ImageBatchDao
imageBatchDao
;
public
ResultVo
<?>
detection
(
long
userId
,
String
nickName
,
String
batchName
,
MultipartFile
[]
file
)
throws
Exception
{
public
ResultVo
<?>
detection
(
long
userId
,
String
nickName
,
String
batchName
,
MultipartFile
[]
file
)
throws
Exception
{
ImageBatch
imageBatch
=
ImageBatch
.
builder
()
ImageBatch
imageBatch
=
ImageBatch
.
builder
()
...
@@ -83,6 +93,7 @@ public class ImageDetectionService {
...
@@ -83,6 +93,7 @@ public class ImageDetectionService {
.
bend
(
Threshold
.
BEND
)
.
bend
(
Threshold
.
BEND
)
.
deskewAngel
(
Threshold
.
DESKEW
)
.
deskewAngel
(
Threshold
.
DESKEW
)
.
black
(
Threshold
.
BLACK
)
.
black
(
Threshold
.
BLACK
)
.
dpi
(
Threshold
.
DPI
)
.
build
();
.
build
();
}
}
// 解压文件
// 解压文件
...
@@ -118,36 +129,61 @@ public class ImageDetectionService {
...
@@ -118,36 +129,61 @@ public class ImageDetectionService {
detection
.
setFileUrl
(
img
.
getUrl
());
detection
.
setFileUrl
(
img
.
getUrl
());
detection
.
setSize
(
transformMb
(
image
.
length
()));
detection
.
setSize
(
transformMb
(
image
.
length
()));
// 设置图片检测信息
Mat
src
=
Imgcodecs
.
imread
(
img
.
getUrl
());
// 检测图片的分辨率
detection
.
setWidthResolution
(
src
.
width
());
detection
.
setHeightResolution
(
src
.
height
());
// 检测图片的DPI
detection
.
setDpi
(
ImageUtil
.
getDpi
(
image
));
// 检测图片清晰度
BigDecimal
clarity
=
BigDecimal
.
valueOf
(
ImageUtil
.
tenengrad
(
src
));
detection
.
setClarity
(
clarity
.
setScale
(
2
,
RoundingMode
.
HALF_UP
).
doubleValue
());
// 检测图片的亮度
detection
.
setBrightness
(
Convert
.
toInt
(
ImageUtil
.
brightness
(
src
)));
// 检测图片倾斜角度
detection
.
setDeskewAngel
(
Math
.
abs
(
Deskew
.
getDeskewAngle
(
src
)));
// 检测图片的黑边
detection
.
setBlack
(
ImageUtil
.
blackDetection2
(
src
));
// 图片弯曲检测
BendResult
bendResult
=
BendUtil
.
getBendResult
(
img
.
getUrl
());
detection
.
setBend
(
bendResult
.
getConfidence
());
detection
.
setBend
(
0.0
);
// 检查是否合格
detection
.
setQualified
(
check
(
detection
,
imgSetting
));
detections
.
add
(
detection
);
detections
.
add
(
detection
);
}
}
// 批量插入
// 批量插入
imageDetectionDao
.
insertBatch
(
detections
);
imageDetectionDao
.
insertBatch
(
detections
);
// 进行图片检测
ImgSetting
finalImgSetting
=
imgSetting
;
List
<
ImageDetection
>
finalDetections
=
imageDetectionDao
.
selectList
(
Wrappers
.
lambdaQuery
(
ImageDetection
.
builder
().
batchId
(
imageBatch
.
getId
()).
build
())
);
for
(
ImageDetection
detection
:
finalDetections
)
{
detectionExecutor
.
execute
(()
->
{
try
{
detectionImage
(
detection
,
finalImgSetting
);
}
catch
(
Exception
e
)
{
log
.
error
(
"图片检测出错!"
,
e
);
}
});
}
return
ResultVo
.
success
(
detections
);
return
ResultVo
.
success
(
detections
);
}
}
private
void
detectionImage
(
ImageDetection
detection
,
ImgSetting
imgSetting
)
throws
Exception
{
// 设置图片检测信息
String
url
=
detection
.
getFileUrl
();
long
start
=
System
.
currentTimeMillis
();
Mat
src
=
Imgcodecs
.
imread
(
url
);
// 检测图片的分辨率
detection
.
setWidthResolution
(
src
.
width
());
detection
.
setHeightResolution
(
src
.
height
());
// 检测图片的DPI
detection
.
setDpi
(
ImageUtil
.
getDpi
(
FileUtil
.
file
(
url
)));
// 检测图片清晰度
BigDecimal
clarity
=
BigDecimal
.
valueOf
(
ImageUtil
.
tenengrad
(
src
));
detection
.
setClarity
(
clarity
.
setScale
(
2
,
RoundingMode
.
HALF_UP
).
doubleValue
());
// 检测图片的亮度
detection
.
setBrightness
(
Convert
.
toInt
(
ImageUtil
.
brightness
(
src
)));
// 检测图片倾斜角度
detection
.
setDeskewAngel
(
Math
.
abs
(
Deskew
.
getDeskewAngle
(
src
)));
long
time1
=
System
.
currentTimeMillis
()
-
start
;
// 检测图片的黑边
detection
.
setBlack
(
ImageUtil
.
blackDetection2
(
src
));
long
time2
=
System
.
currentTimeMillis
()
-
start
;
// 图片弯曲检测
BendResult
bendResult
=
BendUtil
.
getBendResult
(
url
);
detection
.
setBend
(
bendResult
.
getConfidence
());
// detection.setBend(0.0);
// 检查是否合格
detection
.
setQualified
(
check
(
detection
,
imgSetting
));
imageDetectionDao
.
updateById
(
detection
);
log
.
info
(
"{}执行图片检测, 文件大小为:{}, 检测偏离度:{}, 检测黑边:{},耗时为:{}"
,
url
,
detection
.
getSize
(),
time1
,
time2
,
System
.
currentTimeMillis
()
-
start
);
src
.
release
();
}
/**
/**
* 检查图片是否合格
* 检查图片是否合格
* 1. 亮度
* 1. 亮度
...
@@ -156,7 +192,7 @@ public class ImageDetectionService {
...
@@ -156,7 +192,7 @@ public class ImageDetectionService {
* 4. 黑边
* 4. 黑边
* 5. 弯曲
* 5. 弯曲
*/
*/
p
rivate
Integer
check
(
ImageDetection
detection
,
ImgSetting
imgSetting
)
{
p
ublic
Integer
check
(
ImageDetection
detection
,
ImgSetting
imgSetting
)
{
// 亮度
// 亮度
if
(
detection
.
getBrightness
()
<
imgSetting
.
getBrightnessStart
()
||
detection
.
getBrightness
()
>
imgSetting
.
getBrightnessEnd
())
{
if
(
detection
.
getBrightness
()
<
imgSetting
.
getBrightnessStart
()
||
detection
.
getBrightness
()
>
imgSetting
.
getBrightnessEnd
())
{
return
0
;
return
0
;
...
@@ -165,6 +201,10 @@ public class ImageDetectionService {
...
@@ -165,6 +201,10 @@ public class ImageDetectionService {
if
(
detection
.
getClarity
().
compareTo
(
imgSetting
.
getClarity
())
<
0
)
{
if
(
detection
.
getClarity
().
compareTo
(
imgSetting
.
getClarity
())
<
0
)
{
return
0
;
return
0
;
}
}
// DPI
if
(
detection
.
getDpi
()
<
imgSetting
.
getDpi
())
{
return
0
;
}
// 偏离度
// 偏离度
if
(
detection
.
getDeskewAngel
()
>
imgSetting
.
getDeskewAngel
())
{
if
(
detection
.
getDeskewAngel
()
>
imgSetting
.
getDeskewAngel
())
{
return
0
;
return
0
;
...
@@ -183,7 +223,7 @@ public class ImageDetectionService {
...
@@ -183,7 +223,7 @@ public class ImageDetectionService {
/**
/**
* 将字节数转换为MB
* 将字节数转换为MB
*/
*/
p
rivate
double
transformMb
(
long
size
)
{
p
ublic
double
transformMb
(
long
size
)
{
BigDecimal
sizeDecimal
=
BigDecimal
.
valueOf
(
size
);
BigDecimal
sizeDecimal
=
BigDecimal
.
valueOf
(
size
);
BigDecimal
mb
=
BigDecimal
.
valueOf
(
1024
*
1024
);
BigDecimal
mb
=
BigDecimal
.
valueOf
(
1024
*
1024
);
return
sizeDecimal
.
divide
(
mb
,
2
,
RoundingMode
.
DOWN
).
doubleValue
();
return
sizeDecimal
.
divide
(
mb
,
2
,
RoundingMode
.
DOWN
).
doubleValue
();
...
@@ -241,4 +281,40 @@ public class ImageDetectionService {
...
@@ -241,4 +281,40 @@ public class ImageDetectionService {
return
dtos
;
return
dtos
;
}
}
public
ResultVo
<?>
reDetection
(
Long
batchId
,
Long
userId
)
{
List
<
ImageDetection
>
finalDetections
=
imageDetectionDao
.
selectList
(
Wrappers
.
lambdaQuery
(
ImageDetection
.
builder
().
batchId
(
batchId
).
build
()).
isNull
(
ImageDetection:
:
getQualified
)
);
if
(
finalDetections
.
isEmpty
())
{
return
ResultVo
.
fail
(
"暂无未检测图片!"
);
}
// 查询用户配置
ImgSetting
imgSetting
=
imgSettingDao
.
selectOne
(
Wrappers
.
lambdaQuery
(
ImgSetting
.
builder
().
userId
(
userId
).
build
())
);
// 查询不到用户配置,使用默认值进行检测
if
(
imgSetting
==
null
)
{
imgSetting
=
ImgSetting
.
builder
()
.
clarity
(
Threshold
.
CLARITY
)
.
brightnessStart
(
Threshold
.
BRIGHTNESS_START
)
.
brightnessEnd
(
Threshold
.
BRIGHTNESS_END
)
.
bend
(
Threshold
.
BEND
)
.
deskewAngel
(
Threshold
.
DESKEW
)
.
black
(
Threshold
.
BLACK
)
.
dpi
(
Threshold
.
DPI
)
.
build
();
}
for
(
ImageDetection
detection
:
finalDetections
)
{
ImgSetting
finalImgSetting
=
imgSetting
;
detectionExecutor
.
execute
(()
->
{
try
{
detectionImage
(
detection
,
finalImgSetting
);
}
catch
(
Exception
e
)
{
log
.
error
(
"图片检测出错!"
,
e
);
}
});
}
return
ResultVo
.
success
();
}
}
}
imgproc-server/src/main/java/com/zq/imgproc/serv
er
/ImgProcService.java
→
imgproc-server/src/main/java/com/zq/imgproc/serv
ice
/ImgProcService.java
View file @
627e5035
package
com
.
zq
.
imgproc
.
serv
er
;
package
com
.
zq
.
imgproc
.
serv
ice
;
import
cn.hutool.core.codec.Base64Decoder
;
import
cn.hutool.core.codec.Base64Decoder
;
...
@@ -108,7 +108,7 @@ public class ImgProcService {
...
@@ -108,7 +108,7 @@ public class ImgProcService {
public
DetectionVO
detection2
(
OptimizationReq
req
)
throws
Exception
{
public
DetectionVO
detection2
(
OptimizationReq
req
)
throws
Exception
{
// 1. 临时保存图片
// 1. 临时保存图片
String
ext
=
FileUtil
.
extName
(
req
.
getFile
n
ame
());
String
ext
=
FileUtil
.
extName
(
req
.
getFile
N
ame
());
String
yyyyMMdd
=
new
SimpleDateFormat
(
"/yyyyMM/dd/"
).
format
(
new
Date
());
String
yyyyMMdd
=
new
SimpleDateFormat
(
"/yyyyMM/dd/"
).
format
(
new
Date
());
String
filePath
=
"/data/temp"
+
yyyyMMdd
+
UuidUtils
.
uuidNoDash
()
+
"."
+
ext
;
String
filePath
=
"/data/temp"
+
yyyyMMdd
+
UuidUtils
.
uuidNoDash
()
+
"."
+
ext
;
FileUtil
.
writeBytes
(
Base64Decoder
.
decode
(
req
.
getFileContent
()),
filePath
);
FileUtil
.
writeBytes
(
Base64Decoder
.
decode
(
req
.
getFileContent
()),
filePath
);
...
@@ -428,8 +428,8 @@ public class ImgProcService {
...
@@ -428,8 +428,8 @@ public class ImgProcService {
public
OptimizationVO
optimization
(
OptimizationReq
req
)
throws
IOException
{
public
OptimizationVO
optimization
(
OptimizationReq
req
)
throws
IOException
{
OptimizationVO
res
=
new
OptimizationVO
();
OptimizationVO
res
=
new
OptimizationVO
();
// 1. 临时保存图片
// 1. 临时保存图片
String
ext
=
FileUtil
.
extName
(
req
.
getFile
n
ame
());
String
ext
=
FileUtil
.
extName
(
req
.
getFile
N
ame
());
String
filename
=
req
.
getFile
n
ame
();
String
filename
=
req
.
getFile
N
ame
();
String
yyyyMMdd
=
new
SimpleDateFormat
(
"/yyyyMM/dd/"
).
format
(
new
Date
());
String
yyyyMMdd
=
new
SimpleDateFormat
(
"/yyyyMM/dd/"
).
format
(
new
Date
());
String
savePath
=
"/data/temp"
+
yyyyMMdd
+
UuidUtils
.
uuidNoDash
()
+
"/"
;
String
savePath
=
"/data/temp"
+
yyyyMMdd
+
UuidUtils
.
uuidNoDash
()
+
"/"
;
String
filePath
=
savePath
+
filename
;
String
filePath
=
savePath
+
filename
;
...
@@ -555,7 +555,7 @@ public class ImgProcService {
...
@@ -555,7 +555,7 @@ public class ImgProcService {
public
Boolean
recognizeRed
(
OptimizationReq
req
)
{
public
Boolean
recognizeRed
(
OptimizationReq
req
)
{
// 暂时保存
// 暂时保存
String
filename
=
req
.
getFile
n
ame
();
String
filename
=
req
.
getFile
N
ame
();
String
yyyyMMdd
=
new
SimpleDateFormat
(
"/yyyyMM/dd/"
).
format
(
new
Date
());
String
yyyyMMdd
=
new
SimpleDateFormat
(
"/yyyyMM/dd/"
).
format
(
new
Date
());
String
savePath
=
"/data/temp"
+
yyyyMMdd
+
UuidUtils
.
uuidNoDash
()
+
"/"
;
String
savePath
=
"/data/temp"
+
yyyyMMdd
+
UuidUtils
.
uuidNoDash
()
+
"/"
;
String
filePath
=
savePath
+
filename
;
String
filePath
=
savePath
+
filename
;
...
@@ -591,8 +591,8 @@ public class ImgProcService {
...
@@ -591,8 +591,8 @@ public class ImgProcService {
public
String
removeRed
(
OptimizationReq
req
)
{
public
String
removeRed
(
OptimizationReq
req
)
{
// 暂时保存
// 暂时保存
String
ext
=
FileUtil
.
extName
(
req
.
getFile
n
ame
());
String
ext
=
FileUtil
.
extName
(
req
.
getFile
N
ame
());
String
filename
=
req
.
getFile
n
ame
();
String
filename
=
req
.
getFile
N
ame
();
String
yyyyMMdd
=
new
SimpleDateFormat
(
"/yyyyMM/dd/"
).
format
(
new
Date
());
String
yyyyMMdd
=
new
SimpleDateFormat
(
"/yyyyMM/dd/"
).
format
(
new
Date
());
String
savePath
=
"/data/temp"
+
yyyyMMdd
+
UuidUtils
.
uuidNoDash
()
+
"/"
;
String
savePath
=
"/data/temp"
+
yyyyMMdd
+
UuidUtils
.
uuidNoDash
()
+
"/"
;
String
filePath
=
savePath
+
filename
;
String
filePath
=
savePath
+
filename
;
...
...
imgproc-server/src/main/java/com/zq/imgproc/utils/BendUtil.java
View file @
627e5035
...
@@ -23,9 +23,10 @@ import java.util.List;
...
@@ -23,9 +23,10 @@ import java.util.List;
@Slf4j
@Slf4j
public
class
BendUtil
{
public
class
BendUtil
{
private
final
static
String
URL
=
"http://129.204.37.121:8001/api/det/bending"
;
public
final
static
String
MAIN_URL
=
"http://147.1.3.244:8030/api/det/bending"
;
private
final
static
String
WANPRO_URL
=
"http://172.28.1.223:8030/api/det/bending"
;
public
final
static
String
URL
=
"http://129.204.37.121:8001/api/det/bending"
;
private
final
static
String
URL2
=
"http://147.1.3.244:8030/api/det/bending"
;
public
final
static
String
WANPRO_URL
=
"http://172.28.1.223:8030/api/det/bending"
;
// public final static String URL2 = "http://147.1.3.244:8030/api/det/bending";
public
static
void
main
(
String
[]
args
)
{
public
static
void
main
(
String
[]
args
)
{
System
.
out
.
println
(
getBendResult
(
"C:\\Users\\11419\\Desktop\\project\\company\\test\\9.png"
).
toString
());
System
.
out
.
println
(
getBendResult
(
"C:\\Users\\11419\\Desktop\\project\\company\\test\\9.png"
).
toString
());
...
@@ -38,7 +39,7 @@ public class BendUtil {
...
@@ -38,7 +39,7 @@ public class BendUtil {
BendResult
res
=
null
;
BendResult
res
=
null
;
try
{
try
{
String
result
=
HttpUtil
.
post
(
URL2
,
param
,
1000
*
20
);
String
result
=
HttpUtil
.
post
(
MAIN_URL
,
param
,
1000
*
20
);
res
=
parseResult
(
result
);
res
=
parseResult
(
result
);
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
log
.
error
(
"图片弯曲检测失败!"
,
e
);
log
.
error
(
"图片弯曲检测失败!"
,
e
);
...
...
imgproc-server/src/main/java/com/zq/imgproc/utils/DemoUtil.java
View file @
627e5035
...
@@ -25,7 +25,7 @@ public class DemoUtil {
...
@@ -25,7 +25,7 @@ public class DemoUtil {
String
url
=
URL
+
"detection"
;
String
url
=
URL
+
"detection"
;
OptimizationReq
req
=
new
OptimizationReq
();
OptimizationReq
req
=
new
OptimizationReq
();
req
.
setFile
n
ame
(
"3.png"
);
req
.
setFile
N
ame
(
"3.png"
);
req
.
setFileContent
(
Base64
.
encode
(
FileUtil
.
file
(
testImg
)));
req
.
setFileContent
(
Base64
.
encode
(
FileUtil
.
file
(
testImg
)));
long
start
=
System
.
currentTimeMillis
();
long
start
=
System
.
currentTimeMillis
();
HttpRequest
request
=
HttpUtil
.
createPost
(
url
)
HttpRequest
request
=
HttpUtil
.
createPost
(
url
)
...
@@ -45,7 +45,7 @@ public class DemoUtil {
...
@@ -45,7 +45,7 @@ public class DemoUtil {
String
url
=
URL
+
"imageOptimization"
;
String
url
=
URL
+
"imageOptimization"
;
OptimizationReq
req
=
new
OptimizationReq
();
OptimizationReq
req
=
new
OptimizationReq
();
req
.
setFile
n
ame
(
"4.png"
);
req
.
setFile
N
ame
(
"4.png"
);
req
.
setFileContent
(
Base64
.
encode
(
FileUtil
.
file
(
testImg
)));
req
.
setFileContent
(
Base64
.
encode
(
FileUtil
.
file
(
testImg
)));
long
start
=
System
.
currentTimeMillis
();
long
start
=
System
.
currentTimeMillis
();
HttpRequest
request
=
HttpUtil
.
createPost
(
url
)
HttpRequest
request
=
HttpUtil
.
createPost
(
url
)
...
...
imgproc-server/src/main/java/com/zq/imgproc/utils/Deskew.java
View file @
627e5035
...
@@ -14,11 +14,13 @@ public class Deskew {
...
@@ -14,11 +14,13 @@ public class Deskew {
public
static
void
main
(
String
[]
args
)
{
public
static
void
main
(
String
[]
args
)
{
System
.
load
(
"D:/project/imgproc/lib/opencv_java460.dll"
);
System
.
load
(
"D:/project/imgproc/lib/opencv_java460.dll"
);
Mat
image
=
Imgcodecs
.
imread
(
"C:/Users/11419/Desktop/Deskew/TestImages/4.png"
);
Mat
image
=
Imgcodecs
.
imread
(
"C:/Users/11419/Desktop/test/dark.png"
);
long
start
=
System
.
currentTimeMillis
();
int
angle
=
getDeskewAngle
(
image
);
int
angle
=
getDeskewAngle
(
image
);
System
.
out
.
println
(
"耗时为:"
+
String
.
valueOf
(
System
.
currentTimeMillis
()
-
start
));
System
.
out
.
println
(
angle
);
System
.
out
.
println
(
angle
);
Mat
roateMat
=
rotate
(
image
,
angle
);
Mat
roateMat
=
rotate
(
image
,
angle
);
Imgcodecs
.
imwrite
(
"C:/Users/11419/Desktop/
Deskew/TestImages/4
res.png"
,
roateMat
);
Imgcodecs
.
imwrite
(
"C:/Users/11419/Desktop/
test/bend2
res.png"
,
roateMat
);
}
}
public
static
Integer
getDeskewAngle
(
Mat
src
)
{
public
static
Integer
getDeskewAngle
(
Mat
src
)
{
...
@@ -26,46 +28,38 @@ public class Deskew {
...
@@ -26,46 +28,38 @@ public class Deskew {
Mat
gray
=
src
.
clone
();
Mat
gray
=
src
.
clone
();
Imgproc
.
cvtColor
(
src
,
gray
,
Imgproc
.
COLOR_BGR2GRAY
);
Imgproc
.
cvtColor
(
src
,
gray
,
Imgproc
.
COLOR_BGR2GRAY
);
// // 高斯模糊(?)
// 2.高斯滤波,降噪
// @Cleanup
Mat
gaussianBlur
=
gray
.
clone
();
// UMat blur = gray.clone();
Imgproc
.
GaussianBlur
(
gray
,
gaussianBlur
,
new
Size
(
3
,
3
),
0
);
// GaussianBlur(gray, blur, new Size(9, 9), 0);
// // 二值化(?)
// @Cleanup
// UMat thresh = blur.clone();
// threshold(blur, thresh, 0, 255, THRESH_BINARY_INV + THRESH_OTSU);
Mat
kernel
=
Imgproc
.
getStructuringElement
(
Imgproc
.
MORPH_RECT
,
new
Size
(
5
,
5
));
// 3. 边缘检测
Mat
canny
=
gaussianBlur
.
clone
();
Imgproc
.
Canny
(
gaussianBlur
,
canny
,
50
,
150
);
// 图片膨胀
// 4. 膨胀,连接边缘
Mat
erode
=
gray
.
clone
();
Mat
dilate
=
canny
.
clone
();
Imgproc
.
erode
(
gray
,
erode
,
kernel
);
Imgproc
.
dilate
(
canny
,
dilate
,
new
Mat
(),
new
Point
(-
1
,
-
1
),
3
,
1
,
new
Scalar
(
1
));
// 图片腐蚀
Mat
dilate
=
erode
.
clone
();
Imgproc
.
dilate
(
erode
,
dilate
,
kernel
);
// 边缘检测
Mat
canny
=
dilate
.
clone
();
Imgproc
.
Canny
(
dilate
,
canny
,
50
,
150
);
// 霍夫变换得到线条
// 霍夫变换得到线条
Mat
lines
=
new
Mat
();
Mat
lines
=
new
Mat
();
//累加器阈值参数,小于设置值不返回
//累加器阈值参数,小于设置值不返回
int
threshold
=
9
0
;
int
threshold
=
5
0
;
//最低线段长度,低于设置值则不返回
//最低线段长度,低于设置值则不返回
double
minLineLength
=
1
0
0
;
double
minLineLength
=
1
5
0
;
//间距小于该值的线当成同一条线
//间距小于该值的线当成同一条线
double
maxLineGap
=
1
0
;
double
maxLineGap
=
2
0
;
// 霍夫变换,通过步长为1,角度为PI/180来搜索可能的直线
//
5.
霍夫变换,通过步长为1,角度为PI/180来搜索可能的直线
Imgproc
.
HoughLinesP
(
canny
,
lines
,
1
,
Math
.
PI
/
180
,
threshold
,
minLineLength
,
maxLineGap
);
Imgproc
.
HoughLinesP
(
canny
,
lines
,
1
,
Math
.
PI
/
180
,
threshold
,
minLineLength
,
maxLineGap
);
// Mat mat = canny.clone();
// // 测试画图
// Mat mat = src.clone();
// Scalar color = new Scalar(0, 0, 255);
// Scalar color = new Scalar(0, 0, 255);
// for (int i = 0; i < lines.rows(); i++) {
// for (int i = 0; i < lines.rows(); i++) {
// double[] line = lines.get(i, 0);
// double[] line = lines.get(i, 0);
// Imgproc.line(mat, new Point(line[0], line[1]), new Point(line[2], line[3]), color,3, LINE_AA);
// Imgproc.line(mat, new Point(line[0], line[1]), new Point(line[2], line[3]), color,3, LINE_AA);
// }
// }
// Imgcodecs.imwrite("C:\\Users\\11419\\Desktop\\test\\bend2res.jpg", mat);
// Imgcodecs.imwrite("C:\\Users\\11419\\Desktop\\test\\bend2Test.png", mat);
// 计算倾斜角度
// 计算倾斜角度
List
<
Integer
>
angelList
=
new
ArrayList
<>();
List
<
Integer
>
angelList
=
new
ArrayList
<>();
for
(
int
i
=
0
;
i
<
lines
.
rows
();
i
++)
{
for
(
int
i
=
0
;
i
<
lines
.
rows
();
i
++)
{
...
@@ -77,8 +71,6 @@ public class Deskew {
...
@@ -77,8 +71,6 @@ public class Deskew {
return
0
;
return
0
;
}
}
gray
.
release
();
gray
.
release
();
kernel
.
release
();
erode
.
release
();
dilate
.
release
();
dilate
.
release
();
canny
.
release
();
canny
.
release
();
lines
.
release
();
lines
.
release
();
...
...
imgproc-server/src/main/java/com/zq/imgproc/utils/ImageUtil.java
View file @
627e5035
...
@@ -516,7 +516,7 @@ public class ImageUtil {
...
@@ -516,7 +516,7 @@ public class ImageUtil {
* 检测黑边数量
* 检测黑边数量
*/
*/
public
static
int
blackDetection2
(
Mat
src
)
{
public
static
int
blackDetection2
(
Mat
src
)
{
int
blackValue
=
4
0
;
int
blackValue
=
5
0
;
int
width
=
src
.
width
();
int
width
=
src
.
width
();
int
height
=
src
.
height
();
int
height
=
src
.
height
();
...
@@ -581,7 +581,7 @@ public class ImageUtil {
...
@@ -581,7 +581,7 @@ public class ImageUtil {
}
}
}
}
}
}
return
res
;
return
res
==
-
1
?
0
:
res
;
}
}
...
...
imgproc-server/src/main/java/com/zq/imgproc/utils/Test2.java
View file @
627e5035
...
@@ -5,9 +5,7 @@ import cn.hutool.core.io.FileUtil;
...
@@ -5,9 +5,7 @@ import cn.hutool.core.io.FileUtil;
import
cn.hutool.json.JSONUtil
;
import
cn.hutool.json.JSONUtil
;
import
com.zq.imgproc.vo.DetectionVO
;
import
com.zq.imgproc.vo.DetectionVO
;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
import
org.opencv.core.Core
;
import
org.opencv.core.Mat
;
import
org.opencv.core.Mat
;
import
org.opencv.core.Scalar
;
import
org.opencv.imgcodecs.Imgcodecs
;
import
org.opencv.imgcodecs.Imgcodecs
;
import
java.math.BigDecimal
;
import
java.math.BigDecimal
;
...
@@ -56,115 +54,10 @@ public class Test2 {
...
@@ -56,115 +54,10 @@ public class Test2 {
log
.
info
(
"检测图片倾斜角度耗时为:--------------{}"
,
System
.
currentTimeMillis
()
-
start
);
log
.
info
(
"检测图片倾斜角度耗时为:--------------{}"
,
System
.
currentTimeMillis
()
-
start
);
start
=
System
.
currentTimeMillis
();
start
=
System
.
currentTimeMillis
();
// 检测图片的黑边
// 检测图片的黑边
blackDetection2
(
image
);
System
.
out
.
println
(
ImageUtil
.
blackDetection2
(
image
)
);
blackDetection3
(
image
);
log
.
info
(
"检测黑边耗时为:-----------------{}"
,
System
.
currentTimeMillis
()
-
start
);
System
.
out
.
println
(
JSONUtil
.
toJsonStr
(
vo
));
System
.
out
.
println
(
JSONUtil
.
toJsonStr
(
vo
));
}
}
/**
* 黑边检测
*
* @param src 图片矩阵
* @return true表示可能存在黑边
*/
public
static
boolean
blackDetection
(
Mat
src
)
{
int
BLACK_VALUE
=
50
;
int
width
=
src
.
width
();
int
height
=
src
.
height
();
// 定义初始边界
int
top
=
0
;
int
left
=
0
;
int
right
=
width
-
1
;
int
bottom
=
height
-
1
;
// 上方黑边判断
for
(
int
row
=
0
;
row
<
height
;
row
++)
{
if
(
ImageUtil
.
sum
(
src
.
row
(
row
))
/
width
<
BLACK_VALUE
)
{
top
=
row
;
}
else
{
break
;
}
}
// 左边黑边判断
for
(
int
col
=
0
;
col
<
width
;
col
++)
{
if
(
ImageUtil
.
sum
(
src
.
col
(
col
))
/
height
<
BLACK_VALUE
)
{
left
=
col
;
}
else
{
break
;
}
}
// 右边黑边判断
for
(
int
col
=
width
-
1
;
col
>
0
;
col
--)
{
if
(
ImageUtil
.
sum
(
src
.
col
(
col
))
/
height
<
BLACK_VALUE
)
{
right
=
col
;
}
else
{
break
;
}
}
// 下方黑边判断
for
(
int
row
=
height
-
1
;
row
>
0
;
row
--)
{
if
(
ImageUtil
.
sum
(
src
.
row
(
row
))
/
width
<
BLACK_VALUE
)
{
bottom
=
row
;
}
else
{
break
;
}
}
// 若是边界没有被更新,认为不存在黑边
return
top
!=
0
||
left
!=
0
||
right
!=
width
-
1
||
bottom
!=
height
-
1
;
}
public
static
void
blackDetection2
(
Mat
src
)
{
long
start
=
System
.
currentTimeMillis
();
int
BLACK_VALUE
=
30
;
int
width
=
src
.
width
();
int
height
=
src
.
height
();
int
rows
=
0
;
int
cols
=
0
;
// 上方黑边判断
for
(
int
row
=
0
;
row
<
height
;
row
++)
{
if
(
ImageUtil
.
sum
(
src
.
row
(
row
))
/
width
<
BLACK_VALUE
)
{
rows
++;
}
}
// 左边黑边判断
for
(
int
col
=
0
;
col
<
width
;
col
++)
{
if
(
ImageUtil
.
sum
(
src
.
col
(
col
))
/
height
<
BLACK_VALUE
)
{
cols
++;
}
}
log
.
info
(
"{}, {}, {}, {}"
,
"22222"
,
rows
,
cols
,
System
.
currentTimeMillis
()
-
start
);
}
public
static
void
blackDetection3
(
Mat
src
)
{
long
start
=
System
.
currentTimeMillis
();
int
BLACK_VALUE
=
30
;
int
width
=
src
.
width
();
int
height
=
src
.
height
();
int
rows
=
0
;
int
cols
=
0
;
int
limitRows
=
500
;
int
limitCols
=
500
;
for
(
int
row
=
0
;
row
<
height
;
row
++)
{
Scalar
mean
=
Core
.
mean
(
src
.
row
(
row
));
if
(
Convert
.
toInt
(
mean
.
val
[
0
])
<
BLACK_VALUE
)
{
rows
++;
}
}
for
(
int
col
=
0
;
col
<
width
;
col
++)
{
Scalar
mean
=
Core
.
mean
(
src
.
col
(
col
));
if
(
Convert
.
toInt
(
mean
.
val
[
0
])
<
BLACK_VALUE
)
{
cols
++;
}
}
log
.
info
(
"{}, {}, {}, {}"
,
"3333333"
,
rows
,
cols
,
System
.
currentTimeMillis
()
-
start
);
}
}
}
imgproc-server/src/main/java/com/zq/imgproc/utils/TestUtil.java
View file @
627e5035
...
@@ -6,12 +6,7 @@ import com.drew.imaging.ImageMetadataReader;
...
@@ -6,12 +6,7 @@ import com.drew.imaging.ImageMetadataReader;
import
com.drew.metadata.Directory
;
import
com.drew.metadata.Directory
;
import
com.drew.metadata.Metadata
;
import
com.drew.metadata.Metadata
;
import
com.drew.metadata.Tag
;
import
com.drew.metadata.Tag
;
import
com.zq.imgproc.vo.DetectionVO
;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.imaging.ImageInfo
;
import
org.apache.commons.imaging.Imaging
;
import
org.opencv.core.Mat
;
import
org.opencv.imgcodecs.Imgcodecs
;
import
java.io.File
;
import
java.io.File
;
...
@@ -19,147 +14,18 @@ import java.io.File;
...
@@ -19,147 +14,18 @@ import java.io.File;
public
class
TestUtil
{
public
class
TestUtil
{
public
static
void
main
(
String
[]
args
)
throws
Exception
{
public
static
void
main
(
String
[]
args
)
throws
Exception
{
System
.
load
(
"D:/project/imgproc/lib/opencv_java460.dll"
);
String
path
=
"C:\\Users\\11419\\Desktop\\test\\black1.png"
;
String
src
=
"C:\\Users\\11419\\Desktop\\4.png"
;
File
file
=
FileUtil
.
file
(
path
);
String
dst
=
"C:\\Users\\11419\\Desktop\\res.png"
;
String
dest
=
"C:\\Users\\11419\\Desktop\\test\\black1.jpg"
;
// deskew(src, dst);
Metadata
metadata
=
ImageMetadataReader
.
readMetadata
(
FileUtil
.
file
(
dest
));
RemoveBlackUtil2
.
remove
(
src
,
dst
);
for
(
Directory
directory
:
metadata
.
getDirectories
())
{
// bright(src, dst);
for
(
Tag
tag
:
directory
.
getTags
())
{
// im(src, dst);
System
.
out
.
println
(
tag
.
getTagName
()
+
"--------"
+
tag
.
getDescription
());
}
if
(
"X Resolution"
.
equals
(
tag
.
getTagName
()))
{
System
.
out
.
println
(
Convert
.
toInt
(
tag
.
getDescription
()));
public
static
void
deskew
(
String
src
,
String
dst
)
{
Mat
mat
=
Imgcodecs
.
imread
(
src
);
double
skewAngle
=
Deskew
.
getDeskewAngle
(
mat
);
Mat
rotateMat
=
Deskew
.
rotate
(
mat
,
skewAngle
);
Imgcodecs
.
imwrite
(
dst
,
rotateMat
);
}
public
static
void
removeBlack
(
String
src
,
String
dst
)
{
RemoveBlackUtil2
.
remove
(
src
,
dst
);
}
public
static
void
bright
(
String
src
,
String
dst
)
{
double
brightness
=
ImageUtil
.
brightness
(
src
);
System
.
out
.
println
(
brightness
);
// 亮度异常执行亮度矫正
if
(
brightness
<
100
||
brightness
>
500
)
{
// 计算亮度调整值
double
alpha
=
300
/
brightness
;
// 执行亮度调整
Mat
grayImage
=
Imgcodecs
.
imread
(
src
);
Mat
adjustedImage
=
new
Mat
();
grayImage
.
convertTo
(
adjustedImage
,
-
1
,
alpha
,
0
);
// 保存调整后的图像
Imgcodecs
.
imwrite
(
dst
,
adjustedImage
);
}
}
public
static
void
im
(
String
src
,
String
dst
)
{
double
laplacianScore
=
ImageUtil
.
imageSharpnessDetector
(
src
);
System
.
out
.
println
(
laplacianScore
);
if
(
laplacianScore
<
500
)
{
Mat
unsharpMaskingMat
=
ImageUtil
.
unsharpMasking
(
src
);
// 保存调整后的图像
Imgcodecs
.
imwrite
(
dst
,
unsharpMaskingMat
);
}
}
public
static
DetectionVO
detection
(
String
src
)
throws
Exception
{
DetectionVO
res
=
new
DetectionVO
();
Mat
image
=
Imgcodecs
.
imread
(
src
);
// 检测图片的分辨率
res
.
setWidthResolution
(
image
.
width
());
res
.
setHeightResolution
(
image
.
height
());
// 检测图片的DPI
res
.
setDpi
(
getDpi
(
FileUtil
.
file
(
src
)));
// 检测图片清晰度
res
.
setClarity
(
ImageUtil
.
imageSharpnessDetector
(
image
));
// 检测图片的亮度
res
.
setBrightness
(
ImageUtil
.
brightness
(
image
));
// 检测图片倾斜角度
res
.
setAngle
(
Deskew
.
getDeskewAngle
(
image
));
// 检测图片的黑边
res
.
setBlack
(
blackDetection
(
image
));
return
res
;
}
/**
* 获取图片DPI
*
* @param file 图片文件
* @return [水平DPI,垂直DPI]
*/
private
static
Integer
getDpi
(
File
file
)
throws
Exception
{
int
res
;
ImageInfo
imageInfo
=
Imaging
.
getImageInfo
(
file
);
res
=
imageInfo
.
getPhysicalWidthDpi
();
if
(
res
==
-
1
)
{
Metadata
metadata
=
ImageMetadataReader
.
readMetadata
(
file
);
for
(
Directory
directory
:
metadata
.
getDirectories
())
{
for
(
Tag
tag
:
directory
.
getTags
())
{
if
(
"X Resolution"
.
equals
(
tag
.
getTagName
()))
{
res
=
Convert
.
toInt
(
tag
.
getDescription
());
}
}
}
}
}
}
}
return
res
;
}
/**
* 黑边像素阈值
*/
private
static
final
Integer
THRESHOLD
=
30
;
/**
* 黑边检测
*
* @param src 图片矩阵
* @return true表示可能存在黑边
*/
public
static
boolean
blackDetection
(
Mat
src
)
{
int
width
=
src
.
width
();
int
height
=
src
.
height
();
// 定义初始边界
int
top
=
0
;
int
left
=
0
;
int
right
=
width
-
1
;
int
bottom
=
height
-
1
;
// 上方黑边判断
for
(
int
row
=
0
;
row
<
height
;
row
++)
{
if
(
ImageUtil
.
sum
(
src
.
row
(
row
))
/
width
<
THRESHOLD
)
{
top
=
row
;
}
else
{
break
;
}
}
// 左边黑边判断
for
(
int
col
=
0
;
col
<
width
;
col
++)
{
if
(
ImageUtil
.
sum
(
src
.
col
(
col
))
/
height
<
THRESHOLD
)
{
left
=
col
;
}
else
{
break
;
}
}
// 右边黑边判断
for
(
int
col
=
width
-
1
;
col
>
0
;
col
--)
{
if
(
ImageUtil
.
sum
(
src
.
col
(
col
))
/
height
<
THRESHOLD
)
{
right
=
col
;
}
else
{
break
;
}
}
// 下方黑边判断
for
(
int
row
=
height
-
1
;
row
>
0
;
row
--)
{
if
(
ImageUtil
.
sum
(
src
.
row
(
row
))
/
width
<
THRESHOLD
)
{
bottom
=
row
;
}
else
{
break
;
}
}
// 若是边界没有被更新,认为不存在黑边
return
top
!=
0
||
left
!=
0
||
right
!=
width
-
1
||
bottom
!=
height
-
1
;
}
}
...
...
imgproc-server/src/main/java/com/zq/imgproc/vo/ApiDetectionVO.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
imgproc
.
vo
;
import
io.swagger.annotations.ApiModelProperty
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
/**
* <p>
*
* </p>
*
* @author chenhao
* @since 2023/12/1
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
ApiDetectionVO
{
@ApiModelProperty
(
"文件名称"
)
private
String
fileName
;
@ApiModelProperty
(
"图片大小"
)
private
Double
size
;
@ApiModelProperty
(
"水平分辨率"
)
private
Integer
widthResolution
;
@ApiModelProperty
(
"垂直分辨率"
)
private
Integer
heightResolution
;
@ApiModelProperty
(
"DPI"
)
private
Integer
dpi
;
@ApiModelProperty
(
"图片清晰度"
)
private
Double
clarity
;
@ApiModelProperty
(
"图片弯曲置信度"
)
private
Double
bend
;
@ApiModelProperty
(
"图片亮度值"
)
private
Integer
brightness
;
@ApiModelProperty
(
"图片偏离角度"
)
private
Integer
deskewAngel
;
@ApiModelProperty
(
"图片黑边数量"
)
private
Integer
black
;
}
imgproc-server/src/main/java/com/zq/imgproc/vo/OptimizationReq.java
View file @
627e5035
...
@@ -15,6 +15,6 @@ public class OptimizationReq {
...
@@ -15,6 +15,6 @@ public class OptimizationReq {
private
String
fileContent
;
private
String
fileContent
;
private
String
file
n
ame
;
private
String
file
N
ame
;
}
}
interface-server/pom.xml
0 → 100644
View file @
627e5035
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xmlns=
"http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<parent>
<groupId>
com.zq
</groupId>
<artifactId>
image-backend
</artifactId>
<version>
1.0.0
</version>
</parent>
<modelVersion>
4.0.0
</modelVersion>
<artifactId>
interface
</artifactId>
<version>
1.0.0
</version>
<name>
interface-server
</name>
<description>
接口服务
</description>
<properties>
<maven.compiler.source>
8
</maven.compiler.source>
<maven.compiler.target>
8
</maven.compiler.target>
<project.build.sourceEncoding>
UTF-8
</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>
org.springframework.cloud
</groupId>
<artifactId>
spring-cloud-starter-netflix-eureka-client
</artifactId>
</dependency>
<dependency>
<groupId>
org.springframework.cloud
</groupId>
<artifactId>
spring-cloud-starter-config
</artifactId>
</dependency>
<dependency>
<groupId>
org.springframework.cloud
</groupId>
<artifactId>
spring-cloud-starter-bootstrap
</artifactId>
</dependency>
<!-- AOP -->
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-aop
</artifactId>
</dependency>
<!--Spring boot Web容器-->
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-web
</artifactId>
</dependency>
<!-- 注解执行器 -->
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-configuration-processor
</artifactId>
<optional>
true
</optional>
</dependency>
<!-- redis -->
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-data-redis
</artifactId>
</dependency>
<!-- 搭配redis的对象池依赖 -->
<dependency>
<groupId>
org.apache.commons
</groupId>
<artifactId>
commons-pool2
</artifactId>
<version>
2.12.0
</version>
</dependency>
<!-- druid数据源驱动 -->
<dependency>
<groupId>
com.alibaba
</groupId>
<artifactId>
druid-spring-boot-starter
</artifactId>
<version>
1.2.6
</version>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>
com.baomidou
</groupId>
<artifactId>
mybatis-plus-boot-starter
</artifactId>
<version>
3.5.3.1
</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>
mysql
</groupId>
<artifactId>
mysql-connector-java
</artifactId>
<scope>
runtime
</scope>
</dependency>
<!-- swageer -->
<dependency>
<groupId>
io.springfox
</groupId>
<artifactId>
springfox-swagger2
</artifactId>
</dependency>
<!-- commons-io -->
<dependency>
<groupId>
commons-io
</groupId>
<artifactId>
commons-io
</artifactId>
<version>
2.11.0
</version>
</dependency>
<!-- hutool -->
<dependency>
<groupId>
cn.hutool
</groupId>
<artifactId>
hutool-all
</artifactId>
<version>
5.8.23
</version>
</dependency>
<dependency>
<groupId>
com.alibaba.fastjson2
</groupId>
<artifactId>
fastjson2
</artifactId>
<version>
2.0.41
</version>
</dependency>
<!-- jwt -->
<dependency>
<groupId>
com.auth0
</groupId>
<artifactId>
java-jwt
</artifactId>
<version>
4.2.0
</version>
</dependency>
<dependency>
<groupId>
org.springframework.cloud
</groupId>
<artifactId>
spring-cloud-starter-openfeign
</artifactId>
</dependency>
<dependency>
<groupId>
org.projectlombok
</groupId>
<artifactId>
lombok
</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-maven-plugin
</artifactId>
<configuration>
<includeSystemScope>
true
</includeSystemScope>
</configuration>
</plugin>
</plugins>
<!-- 使用@profiles.active@需要添加以下内容 -->
<resources>
<resource>
<directory>
src/main/resources
</directory>
<excludes>
<exclude>
**/*.jar
</exclude>
</excludes>
<!--开启过滤,用指定的参数替换directory下的文件中的参数-->
<filtering>
true
</filtering>
</resource>
</resources>
</build>
</project>
\ No newline at end of file
interface-server/src/main/java/com/zq/im/InterfaceApplication.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.boot.autoconfigure.SpringBootApplication
;
import
org.springframework.cloud.client.discovery.EnableDiscoveryClient
;
import
org.springframework.cloud.openfeign.EnableFeignClients
;
/**
* <p>
* 服务主启动类
* </p>
*
* @author chenhao
* @since 2022/10/12 20:57
*/
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
()
public
class
InterfaceApplication
{
public
static
void
main
(
String
[]
args
)
{
SpringApplication
.
run
(
InterfaceApplication
.
class
,
args
);
}
}
interface-server/src/main/java/com/zq/im/aspect/ApiLogAspect.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
aspect
;
import
cn.hutool.core.date.DateUtil
;
import
cn.hutool.core.net.NetUtil
;
import
cn.hutool.core.util.StrUtil
;
import
cn.hutool.extra.servlet.ServletUtil
;
import
com.auth0.jwt.interfaces.DecodedJWT
;
import
com.baomidou.mybatisplus.core.toolkit.Wrappers
;
import
com.zq.im.exception.BusinessException
;
import
com.zq.im.modules.api.form.ApiForm
;
import
com.zq.im.modules.system.dao.ApiUserInfoDao
;
import
com.zq.im.modules.system.dao.OpenApiLogDao
;
import
com.zq.im.modules.system.entity.ApiUserInfo
;
import
com.zq.im.modules.system.entity.OpenApiLog
;
import
com.zq.im.utils.IpUtil
;
import
com.zq.im.utils.TokenUtil
;
import
lombok.extern.slf4j.Slf4j
;
import
org.aspectj.lang.JoinPoint
;
import
org.aspectj.lang.ProceedingJoinPoint
;
import
org.aspectj.lang.annotation.AfterThrowing
;
import
org.aspectj.lang.annotation.Around
;
import
org.aspectj.lang.annotation.Aspect
;
import
org.aspectj.lang.annotation.Pointcut
;
import
org.aspectj.lang.reflect.MethodSignature
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.core.annotation.AnnotationUtils
;
import
org.springframework.core.annotation.Order
;
import
org.springframework.scheduling.annotation.Async
;
import
org.springframework.stereotype.Component
;
import
org.springframework.web.context.request.RequestContextHolder
;
import
org.springframework.web.context.request.ServletRequestAttributes
;
import
javax.servlet.http.HttpServletRequest
;
import
java.lang.reflect.Method
;
/**
* <p>
* 用户操作日志处理切面
* </p>
*
* @author chenhao
* @since 2022/10/15 17:23
*/
@Order
(
1
)
@Aspect
@Slf4j
@Component
public
class
ApiLogAspect
{
private
final
OpenApiLogDao
openApiLogDao
;
private
final
ApiUserInfoDao
apiUserInfoDao
;
@Autowired
public
ApiLogAspect
(
OpenApiLogDao
openApiLogDao
,
ApiUserInfoDao
apiUserInfoDao
)
{
this
.
openApiLogDao
=
openApiLogDao
;
this
.
apiUserInfoDao
=
apiUserInfoDao
;
}
ThreadLocal
<
Long
>
currentTime
=
new
ThreadLocal
<>();
/**
* 声明切入点
*/
@Pointcut
(
"@annotation(com.zq.im.aspect.OpenApi)"
)
public
void
pointCut
()
{}
/**
* 环绕通知
*/
@Around
(
"pointCut()"
)
public
Object
doAround
(
ProceedingJoinPoint
joinPoint
)
throws
Throwable
{
currentTime
.
set
(
System
.
currentTimeMillis
());
// 执行目标方法
Object
result
=
joinPoint
.
proceed
();
// 计算执行耗时
long
time
=
System
.
currentTimeMillis
()
-
currentTime
.
get
();
currentTime
.
remove
();
// 获取方法名
MethodSignature
signature
=
(
MethodSignature
)
joinPoint
.
getSignature
();
Method
signatureMethod
=
signature
.
getMethod
();
// 获取注解信息
OpenApi
openApi
=
AnnotationUtils
.
getAnnotation
(
signatureMethod
,
OpenApi
.
class
);
// 获取当前请求对象
ServletRequestAttributes
attributes
=
(
ServletRequestAttributes
)
RequestContextHolder
.
getRequestAttributes
();
HttpServletRequest
request
=
null
;
if
(
attributes
!=
null
)
{
request
=
attributes
.
getRequest
();
}
// 保存日志
insertLog
(
openApi
,
request
,
"INFO"
,
""
,
time
);
return
result
;
}
/**
* 配置异常通知
*
* @param joinPoint join point for advice
* @param e exception
*/
@AfterThrowing
(
pointcut
=
"pointCut()"
,
throwing
=
"e"
)
public
void
logAfterThrowing
(
JoinPoint
joinPoint
,
Throwable
e
)
{
// 计算执行耗时
long
time
=
System
.
currentTimeMillis
()
-
currentTime
.
get
();
currentTime
.
remove
();
String
errMsg
=
""
;
if
(
e
instanceof
BusinessException
)
{
errMsg
=
e
.
getMessage
();
}
// 获取方法名
MethodSignature
signature
=
(
MethodSignature
)
joinPoint
.
getSignature
();
Method
signatureMethod
=
signature
.
getMethod
();
// 获取注解信息
OpenApi
openApi
=
AnnotationUtils
.
getAnnotation
(
signatureMethod
,
OpenApi
.
class
);
// 获取当前请求对象
ServletRequestAttributes
attributes
=
(
ServletRequestAttributes
)
RequestContextHolder
.
getRequestAttributes
();
HttpServletRequest
request
=
null
;
if
(
attributes
!=
null
)
{
request
=
attributes
.
getRequest
();
}
// 保存日志
insertLog
(
openApi
,
request
,
"ERROR"
,
errMsg
,
time
);
}
@Async
public
void
insertLog
(
OpenApi
openApi
,
HttpServletRequest
request
,
String
logType
,
String
errMsg
,
long
timeCost
)
{
try
{
// 获取IP信息
String
clientIp
=
IpUtil
.
getIpAddr
(
request
);
// 获取请求对象
ApiForm
apiForm
=
ServletUtil
.
toBean
(
request
,
ApiForm
.
class
,
true
);
OpenApiLog
openApiLog
=
new
OpenApiLog
();
openApiLog
.
setLogType
(
logType
);
DecodedJWT
decodedJWT
=
TokenUtil
.
getUserContext
();
if
(
decodedJWT
!=
null
)
{
openApiLog
.
setAppId
(
TokenUtil
.
getAppid
(
decodedJWT
));
openApiLog
.
setApplyer
(
TokenUtil
.
getApplyer
(
decodedJWT
));
}
else
{
ApiUserInfo
apiUserInfo
=
apiUserInfoDao
.
selectOne
(
Wrappers
.
lambdaQuery
(
ApiUserInfo
.
builder
().
appId
(
apiForm
.
getAppId
()).
build
())
);
if
(
apiUserInfo
==
null
)
{
openApiLog
.
setLogType
(
"ERROR"
);
}
else
{
openApiLog
.
setAppId
(
apiUserInfo
.
getAppId
());
openApiLog
.
setApplyer
(
apiUserInfo
.
getApplyer
());
}
}
openApiLog
.
setVersion
(
getVersion
(
request
));
openApiLog
.
setMethod
(
apiForm
.
getMethod
());
openApiLog
.
setClientIp
(
clientIp
);
openApiLog
.
setDescription
(
openApi
==
null
?
""
:
openApi
.
value
());
openApiLog
.
setServerIp
(
NetUtil
.
getLocalhostStr
());
openApiLog
.
setErrMsg
(
errMsg
);
openApiLog
.
setTimeCost
(
timeCost
);
openApiLog
.
setCreateTime
(
DateUtil
.
now
());
// 保存日志
openApiLogDao
.
insert
(
openApiLog
);
}
catch
(
Exception
e
)
{
log
.
error
(
"记录日志发生错误"
,
e
);
}
}
/**
* 获取版本号
*/
public
String
getVersion
(
HttpServletRequest
request
)
{
String
requestUri
=
request
.
getRequestURI
();
if
(
StrUtil
.
isBlank
(
requestUri
))
{
log
.
warn
(
"为获取到版本号,URI [{}]"
,
request
);
return
""
;
}
return
requestUri
.
replace
(
"/api/"
,
""
).
replace
(
"/action"
,
""
);
}
}
interface-server/src/main/java/com/zq/im/aspect/OpenApi.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
aspect
;
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
/**
* <p>
* 用于标记记录用户操作日志的方法
* </P>
*
* @author yww
*/
@Target
(
ElementType
.
METHOD
)
@Retention
(
RetentionPolicy
.
RUNTIME
)
public
@interface
OpenApi
{
String
value
()
default
""
;
}
\ No newline at end of file
interface-server/src/main/java/com/zq/im/config/RedisConfig.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
config
;
import
cn.hutool.core.lang.Assert
;
import
cn.hutool.crypto.digest.DigestUtil
;
import
com.alibaba.fastjson2.JSON
;
import
com.alibaba.fastjson2.JSONReader
;
import
com.alibaba.fastjson2.JSONWriter
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang.SerializationException
;
import
org.apache.commons.lang.StringUtils
;
import
org.springframework.boot.autoconfigure.AutoConfigureBefore
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
;
import
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
;
import
org.springframework.cache.Cache
;
import
org.springframework.cache.annotation.CachingConfigurerSupport
;
import
org.springframework.cache.annotation.EnableCaching
;
import
org.springframework.cache.interceptor.CacheErrorHandler
;
import
org.springframework.cache.interceptor.KeyGenerator
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.data.redis.cache.RedisCacheConfiguration
;
import
org.springframework.data.redis.connection.RedisConnectionFactory
;
import
org.springframework.data.redis.core.RedisTemplate
;
import
org.springframework.data.redis.serializer.RedisSerializationContext
;
import
org.springframework.data.redis.serializer.RedisSerializer
;
import
reactor.util.annotation.Nullable
;
import
java.nio.charset.Charset
;
import
java.nio.charset.StandardCharsets
;
import
java.time.Duration
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* <p>
* Redis配置类
* </p>
*
* @author chenhao
* @since 2022/10/12 20:57
*/
@Slf4j
@Configuration
@EnableCaching
@AutoConfigureBefore
(
RedisAutoConfiguration
.
class
)
public
class
RedisConfig
extends
CachingConfigurerSupport
{
/**
* RedisTemplate的配置
*/
@Bean
(
name
=
"redisTemplate"
)
@ConditionalOnMissingBean
(
name
=
"redisTemplate"
)
@SuppressWarnings
(
value
=
{
"unchecked"
,
"rawtypes"
})
public
RedisTemplate
<
String
,
Object
>
redisTemplate
(
RedisConnectionFactory
connectionFactory
)
{
RedisTemplate
<
String
,
Object
>
template
=
new
RedisTemplate
<>();
template
.
setConnectionFactory
(
connectionFactory
);
// 使用FastJson2重写序列化
FastJson2JsonRedisSerializer
serializer
=
new
FastJson2JsonRedisSerializer
(
Object
.
class
);
// value值的序列化采用FastJson2重写的序列化
template
.
setValueSerializer
(
serializer
);
template
.
setHashValueSerializer
(
serializer
);
// key的序列化采用StringRedisSerializer
template
.
setKeySerializer
(
new
StringRedisSerializer
());
template
.
setHashKeySerializer
(
new
StringRedisSerializer
());
template
.
afterPropertiesSet
();
return
template
;
}
/**
* 缓存配置
* 设置 redis 数据默认过期时间,默认3小时
*/
@Bean
public
RedisCacheConfiguration
redisCacheConfiguration
()
{
FastJson2JsonRedisSerializer
<
Object
>
fastJsonRedisSerializer
=
new
FastJson2JsonRedisSerializer
<>(
Object
.
class
);
RedisCacheConfiguration
configuration
=
RedisCacheConfiguration
.
defaultCacheConfig
();
configuration
=
configuration
.
serializeValuesWith
(
RedisSerializationContext
.
SerializationPair
.
fromSerializer
(
fastJsonRedisSerializer
)).
entryTtl
(
Duration
.
ofHours
(
3
));
return
configuration
;
}
/**
* 自定义缓存key生成策略,默认将使用该策略
*/
@Bean
@Override
public
KeyGenerator
keyGenerator
()
{
return
(
target
,
method
,
params
)
->
{
Map
<
String
,
Object
>
container
=
new
HashMap
<>(
4
);
Class
<?>
targetClassClass
=
target
.
getClass
();
// 类地址
container
.
put
(
"class"
,
targetClassClass
.
toGenericString
());
// 方法名称
container
.
put
(
"methodName"
,
method
.
getName
());
// 包名称
container
.
put
(
"package"
,
targetClassClass
.
getPackage
());
// 参数列表
for
(
int
i
=
0
;
i
<
params
.
length
;
i
++)
{
container
.
put
(
String
.
valueOf
(
i
),
params
[
i
]);
}
// 转为JSON字符串
String
jsonString
=
JSON
.
toJSONString
(
container
);
// 做SHA256 Hash计算,得到一个SHA256摘要作为Key
return
DigestUtil
.
sha256Hex
(
jsonString
);
};
}
/**
* Redis的异常处理,当Redis发生异常时,打印日志
*/
@Bean
@Override
@SuppressWarnings
(
value
=
{
"all"
})
public
CacheErrorHandler
errorHandler
()
{
log
.
info
(
"初始化 -> [{}]"
,
"Redis CacheErrorHandler"
);
return
new
CacheErrorHandler
()
{
@Override
public
void
handleCacheGetError
(
RuntimeException
e
,
Cache
cache
,
Object
key
)
{
log
.
error
(
"Redis occur handleCacheGetError:key -> [{}]"
,
key
,
e
);
}
@Override
public
void
handleCachePutError
(
RuntimeException
e
,
Cache
cache
,
Object
key
,
Object
value
)
{
log
.
error
(
"Redis occur handleCachePutError:key -> [{}];value -> [{}]"
,
key
,
value
,
e
);
}
@Override
public
void
handleCacheEvictError
(
RuntimeException
e
,
Cache
cache
,
Object
key
)
{
log
.
error
(
"Redis occur handleCacheEvictError:key -> [{}]"
,
key
,
e
);
}
@Override
public
void
handleCacheClearError
(
RuntimeException
e
,
Cache
cache
)
{
log
.
error
(
"Redis occur handleCacheClearError:"
,
e
);
}
};
}
}
/**
* Value 序列化
*
* @param <T>
*/
class
FastJson2JsonRedisSerializer
<
T
>
implements
RedisSerializer
<
T
>
{
public
static
final
Charset
DEFAULT_CHARSET
=
StandardCharsets
.
UTF_8
;
private
final
Class
<
T
>
clazz
;
public
FastJson2JsonRedisSerializer
(
Class
<
T
>
clazz
)
{
super
();
this
.
clazz
=
clazz
;
}
@Override
public
byte
[]
serialize
(
T
t
)
throws
SerializationException
{
if
(
t
==
null
)
{
return
new
byte
[
0
];
}
return
JSON
.
toJSONString
(
t
,
JSONWriter
.
Feature
.
WriteClassName
).
getBytes
(
DEFAULT_CHARSET
);
}
@Override
public
T
deserialize
(
byte
[]
bytes
)
throws
SerializationException
{
if
(
bytes
==
null
||
bytes
.
length
==
0
)
{
return
null
;
}
String
str
=
new
String
(
bytes
,
DEFAULT_CHARSET
);
return
JSON
.
parseObject
(
str
,
clazz
,
JSONReader
.
Feature
.
SupportAutoType
);
}
}
/**
* 重写序列化器
*/
class
StringRedisSerializer
implements
RedisSerializer
<
Object
>
{
private
final
Charset
charset
;
StringRedisSerializer
()
{
this
(
StandardCharsets
.
UTF_8
);
}
private
StringRedisSerializer
(
Charset
charset
)
{
Assert
.
notNull
(
charset
,
"Charset must not be null!"
);
this
.
charset
=
charset
;
}
@Override
public
String
deserialize
(
byte
[]
bytes
)
{
return
(
bytes
==
null
?
null
:
new
String
(
bytes
,
charset
));
}
@Override
public
@Nullable
byte
[]
serialize
(
Object
object
)
{
String
string
=
JSON
.
toJSONString
(
object
);
if
(
StringUtils
.
isBlank
(
string
))
{
return
null
;
}
string
=
string
.
replace
(
"\""
,
""
);
return
string
.
getBytes
(
charset
);
}
}
\ No newline at end of file
interface-server/src/main/java/com/zq/im/config/WebMvcConfig.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
config
;
import
com.zq.im.interceptor.ApiMethodInterceptor
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Lazy
;
import
org.springframework.web.servlet.config.annotation.InterceptorRegistry
;
import
org.springframework.web.servlet.config.annotation.WebMvcConfigurer
;
import
javax.annotation.Resource
;
/**
* <p>
* 注册拦截器
* </p>
*
* @author chenhao
* @since 2023/11/9
*/
@Configuration
public
class
WebMvcConfig
implements
WebMvcConfigurer
{
@Lazy
@Resource
private
ApiMethodInterceptor
apiMethodInterceptor
;
@Override
public
void
addInterceptors
(
InterceptorRegistry
registry
)
{
registry
.
addInterceptor
(
apiMethodInterceptor
).
addPathPatterns
(
"/api/v1/**"
);
}
}
interface-server/src/main/java/com/zq/im/config/feign/FeignConfig.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
config
.
feign
;
import
feign.RequestInterceptor
;
import
feign.codec.Encoder
;
import
org.springframework.beans.factory.ObjectFactory
;
import
org.springframework.boot.autoconfigure.http.HttpMessageConverters
;
import
org.springframework.cloud.openfeign.support.SpringEncoder
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.web.context.request.RequestContextHolder
;
import
org.springframework.web.context.request.ServletRequestAttributes
;
import
javax.servlet.http.HttpServletRequest
;
import
java.util.Arrays
;
import
java.util.Enumeration
;
import
java.util.List
;
/**
* @author wilmiam
* @since 2021-07-09 10:34
*/
@Configuration
public
class
FeignConfig
{
/**
* 转发请求头
*/
private
static
final
List
<
String
>
FORWARD_HEADERS
=
Arrays
.
asList
(
"AUTHORIZATION"
,
"X-FORWARDED-FOR"
,
"X-FORWARDED-PROTO"
,
"X-FORWARDED-PORT"
,
"X-FORWARDED-HOST"
,
"FORWARDED"
,
"PROXY-CLIENT-IP"
,
"WL-PROXY-CLIENT-IP"
,
"HTTP_X_FORWARDED_FOR"
,
"HTTP_X_FORWARDED"
,
"HTTP_X_CLUSTER_CLIENT_IP"
,
"HTTP_CLIENT_IP"
,
"HTTP_FORWARDED_FOR"
,
"HTTP_FORWARDED"
,
"HTTP_VIA"
,
"REMOTE_ADDR"
,
"X-REAL-IP"
,
"HOST"
);
private
final
ObjectFactory
<
HttpMessageConverters
>
messageConverters
;
public
FeignConfig
(
ObjectFactory
<
HttpMessageConverters
>
messageConverters
)
{
this
.
messageConverters
=
messageConverters
;
}
public
static
HttpServletRequest
getRequest
()
{
ServletRequestAttributes
requestAttributes
=
(
ServletRequestAttributes
)
RequestContextHolder
.
getRequestAttributes
();
if
(
requestAttributes
==
null
)
{
return
null
;
}
return
requestAttributes
.
getRequest
();
}
/**
* 解决fein远程调用丢失请求头
*/
@Bean
public
RequestInterceptor
requestInterceptor
()
{
return
template
->
{
HttpServletRequest
request
=
getRequest
();
if
(
request
==
null
)
{
return
;
}
Enumeration
<
String
>
headerNames
=
request
.
getHeaderNames
();
if
(
headerNames
!=
null
)
{
while
(
headerNames
.
hasMoreElements
())
{
String
name
=
headerNames
.
nextElement
();
// 不要设置content-length
if
(
"content-length"
.
equals
(
name
))
{
continue
;
}
if
(
FORWARD_HEADERS
.
contains
(
name
.
toUpperCase
()))
{
String
values
=
request
.
getHeader
(
name
);
template
.
header
(
name
,
values
);
}
}
}
};
}
@Bean
public
Encoder
feignEncoder
()
{
return
new
FeignSpringFormEncoder
(
new
SpringEncoder
(
messageConverters
));
}
}
interface-server/src/main/java/com/zq/im/config/feign/FeignSpringFormEncoder.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
config
.
feign
;
import
feign.RequestTemplate
;
import
feign.codec.EncodeException
;
import
feign.codec.Encoder
;
import
feign.form.ContentType
;
import
feign.form.FormEncoder
;
import
feign.form.MultipartFormContentProcessor
;
import
feign.form.spring.SpringManyMultipartFilesWriter
;
import
feign.form.spring.SpringSingleMultipartFileWriter
;
import
org.springframework.web.multipart.MultipartFile
;
import
java.lang.reflect.Type
;
import
java.util.Collections
;
import
java.util.Map
;
/**
* feign 多文件上传配置
*
* @author Lander
*/
public
class
FeignSpringFormEncoder
extends
FormEncoder
{
public
FeignSpringFormEncoder
()
{
this
(
new
Default
());
}
public
FeignSpringFormEncoder
(
Encoder
delegate
)
{
super
(
delegate
);
MultipartFormContentProcessor
processor
=
(
MultipartFormContentProcessor
)
this
.
getContentProcessor
(
ContentType
.
MULTIPART
);
processor
.
addFirstWriter
(
new
SpringSingleMultipartFileWriter
());
processor
.
addFirstWriter
(
new
SpringManyMultipartFilesWriter
());
}
@Override
public
void
encode
(
Object
object
,
Type
bodyType
,
RequestTemplate
template
)
throws
EncodeException
{
if
(
bodyType
!=
null
&&
bodyType
.
equals
(
MultipartFile
[].
class
))
{
MultipartFile
[]
file
=
(
MultipartFile
[])
object
;
if
(
file
!=
null
)
{
Map
<
String
,
Object
>
data
=
Collections
.
singletonMap
(
file
.
length
==
0
?
""
:
file
[
0
].
getName
(),
object
);
super
.
encode
(
data
,
MAP_STRING_WILDCARD
,
template
);
return
;
}
}
else
if
(
bodyType
!=
null
&&
bodyType
.
equals
(
MultipartFile
.
class
))
{
MultipartFile
file
=
(
MultipartFile
)
object
;
if
(
file
!=
null
)
{
Map
<
String
,
Object
>
data
=
Collections
.
singletonMap
(
file
.
getName
(),
object
);
super
.
encode
(
data
,
MAP_STRING_WILDCARD
,
template
);
return
;
}
}
super
.
encode
(
object
,
bodyType
,
template
);
}
}
interface-server/src/main/java/com/zq/im/config/mybatis/InsertBatchSqlInjector.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
config
.
mybatis
;
import
com.baomidou.mybatisplus.core.injector.AbstractMethod
;
import
com.baomidou.mybatisplus.core.injector.DefaultSqlInjector
;
import
com.baomidou.mybatisplus.core.metadata.TableInfo
;
import
com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn
;
import
java.util.List
;
/**
* <p>
* 批量插入SQL注入器
* </P>
*
* @author chenhao
* @since 2022/10/12 20:57
*/
public
class
InsertBatchSqlInjector
extends
DefaultSqlInjector
{
@Override
public
List
<
AbstractMethod
>
getMethodList
(
Class
<?>
mapperClass
,
TableInfo
tableInfo
)
{
// 获取MybatisPlus的自带方法
List
<
AbstractMethod
>
methodList
=
super
.
getMethodList
(
mapperClass
,
tableInfo
);
// 添加自定义批量插入方法,名称为insertBatchSomeColumn
methodList
.
add
(
new
InsertBatchSomeColumn
());
return
methodList
;
}
}
\ No newline at end of file
interface-server/src/main/java/com/zq/im/config/mybatis/MybatisPlusConfig.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
config
.
mybatis
;
import
com.baomidou.mybatisplus.annotation.DbType
;
import
com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor
;
import
com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor
;
import
com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor
;
import
org.mybatis.spring.annotation.MapperScan
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.transaction.annotation.EnableTransactionManagement
;
/**
* <p>
* Mybatis-Plus配置类
* </p>
*
* @author chenhao
* @since 2022/10/12 20:57
*/
@Configuration
@EnableTransactionManagement
@MapperScan
(
"com.zq.im.modules.system.dao"
)
public
class
MybatisPlusConfig
{
/**
* 插件配置
* 1. 防全表更新与删除插件
* 2. 分页插件
*/
@Bean
public
MybatisPlusInterceptor
mybatisPlusInterceptor
()
{
MybatisPlusInterceptor
interceptor
=
new
MybatisPlusInterceptor
();
// 防全表更新与删除插件
interceptor
.
addInnerInterceptor
(
new
BlockAttackInnerInterceptor
());
// 分页插件,指定数据库为MYSQL
interceptor
.
addInnerInterceptor
(
new
PaginationInnerInterceptor
(
DbType
.
MYSQL
));
return
interceptor
;
}
/**
* 自定义批量插入 SQL 注入器
*/
@Bean
public
InsertBatchSqlInjector
insertBatchSqlInjector
()
{
return
new
InsertBatchSqlInjector
();
}
}
interface-server/src/main/java/com/zq/im/constant/ApiCodeEnum.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
constant
;
/**
* API响应码
*
* @author wilmiam
* @since 2021-07-14 11:37
*/
public
enum
ApiCodeEnum
{
/**
* 成功
*/
SUCCESS
(
"200"
,
"成功"
),
/**
* 未知错误
*/
UNKNOWN_ERROR
(
"100"
,
"未知错误"
),
/**
* 版本号错误
*/
VERSION_ERROR
(
"101"
,
"版本号错误"
),
/**
* 调用方法不存在
*/
METHOD_ERROR
(
"102"
,
"调用方法不存在"
),
/**
* 调用方法异常
*/
METHOD_HANDLER_ERROR
(
"103"
,
"调用方法异常"
),
/**
* 传递参数异常
*/
PARAM_ERROR
(
"104"
,
"传递参数异常"
),
/**
* IP黑名单拦截
*/
IP_BLACK
(
"105"
,
"IP黑名单拦截"
),
/**
* API服务维护中
*/
SERVER_MAINTAIN
(
"106"
,
"API服务维护中"
),
/**
* 签名校验失败
*/
CHECK_SIGN_VALID_ERROR
(
"107"
,
"签名校验失败"
),
/**
* 服务不可用
*/
SERVICE_NOT_AVAILABLE
(
"108"
,
"服务不可用"
),
/**
* 业务处理失败
*/
BUSINESS_ERROR
(
"400"
,
"业务处理失败"
),
/**
* 登陆验证失败
*/
LOGIN_VALID_ERROR
(
"401"
,
"登陆验证失败"
),
/**
* 服务器繁忙
*/
SERVER_ERROR
(
"500"
,
"服务器繁忙"
),
;
private
final
String
code
;
private
final
String
msg
;
ApiCodeEnum
(
String
code
,
String
msg
)
{
this
.
code
=
code
;
this
.
msg
=
msg
;
}
public
String
code
()
{
return
code
;
}
public
String
msg
()
{
return
msg
;
}
}
interface-server/src/main/java/com/zq/im/constant/ApiVersionEnum.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
constant
;
/**
* API版本
*
* @author wilmiam
* @since 2021-07-14 11:37
*/
public
enum
ApiVersionEnum
{
/**
* V1
*/
v1
,
/**
* V2
*/
v2
}
interface-server/src/main/java/com/zq/im/constant/TokenConstant.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
constant
;
/**
* <p>
* Token相关常量类
* </p>
*
* @author chenhao
*/
public
class
TokenConstant
{
/**
* Token的密钥
*/
public
static
final
String
TOKEN_SECRET
=
"HWTJ"
;
/**
* Token在请求头部的名称
*/
public
static
final
String
TOKEN_HEADER
=
"Authorization"
;
/**
* Token的前缀
*/
public
static
final
String
TOKEN_PREFIX
=
"ApiToken."
;
/**
* header的头部加密算法声明
*/
public
static
final
String
TOKEN_ALG
=
"HMAC512"
;
/**
* header的头部Token类型
*/
public
static
final
String
TOKEN_TYP
=
"JWT"
;
/**
* Token的签发者
*/
public
static
final
String
TOKEN_ISSUER
=
"HWTJ"
;
/**
* Token面向的主体
*/
public
static
final
String
TOKEN_SUBJECT
=
"api"
;
/**
* Token的接收方
*/
public
static
final
String
TOKEN_AUDIENCE
=
"api"
;
/**
* Token解析后当前用户的信息
*/
public
static
final
String
ADMIN_TOKEN
=
"current_token"
;
}
interface-server/src/main/java/com/zq/im/exception/BusinessException.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
exception
;
/**
* 业务错误
*
* @author chenhao
* @since 2022/10/12 20:57
*/
public
class
BusinessException
extends
RuntimeException
{
private
int
code
=
400
;
public
BusinessException
(
String
message
)
{
super
(
message
);
}
public
BusinessException
(
int
code
,
String
message
)
{
super
(
message
);
this
.
code
=
code
;
}
public
BusinessException
(
int
code
,
String
message
,
Throwable
cause
)
{
super
(
message
,
cause
);
this
.
code
=
code
;
}
public
int
getCode
()
{
return
code
;
}
}
\ No newline at end of file
interface-server/src/main/java/com/zq/im/interceptor/ApiMethodInterceptor.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
interceptor
;
import
cn.hutool.extra.servlet.ServletUtil
;
import
cn.hutool.http.HttpStatus
;
import
cn.hutool.json.JSONUtil
;
import
com.auth0.jwt.interfaces.DecodedJWT
;
import
com.zq.im.constant.ApiCodeEnum
;
import
com.zq.im.modules.api.form.ApiForm
;
import
com.zq.im.modules.api.service.ApiManage
;
import
com.zq.im.modules.api.utils.ApiUtils
;
import
com.zq.im.utils.IpUtil
;
import
com.zq.im.utils.RedisUtil
;
import
com.zq.im.utils.TokenUtil
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.stereotype.Component
;
import
org.springframework.web.servlet.HandlerInterceptor
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
/**
* 方法拦截器
* 主要是校验Token信息,校验成功线后程保存Token信息
*
* @author chenhao
* @since 2023-11-09
*/
@Slf4j
@Component
public
class
ApiMethodInterceptor
implements
HandlerInterceptor
{
@Autowired
private
RedisUtil
redisUtil
;
/**
* 当前环境
*/
@Value
(
"${spring.profiles.active:product}"
)
private
String
active
;
@Override
public
boolean
preHandle
(
HttpServletRequest
request
,
HttpServletResponse
response
,
Object
handler
)
{
String
ip
=
IpUtil
.
getIpAddr
(
request
);
ApiForm
form
=
ServletUtil
.
toBean
(
request
,
ApiForm
.
class
,
true
);
log
.
info
(
"from [{}] to [{}]"
,
ip
,
request
.
getRequestURI
()
+
"#"
+
form
.
getMethod
());
// 判断是否是可以在未登录状态下执行的方法名
boolean
notValid
=
ApiManage
.
isNotValid
(
form
.
getMethod
());
if
(
notValid
)
{
return
true
;
}
// 验证认证信息
String
apiToken
=
redisUtil
.
getStr
(
TokenUtil
.
getApiTokenKey
(
form
.
getAppId
()));
if
(
apiToken
==
null
)
{
response
.
setStatus
(
HttpStatus
.
HTTP_BAD_REQUEST
);
ServletUtil
.
write
(
response
,
JSONUtil
.
toJsonStr
(
ApiUtils
.
of
(
form
,
ApiCodeEnum
.
LOGIN_VALID_ERROR
)),
"application/json;charset=utf-8"
);
return
false
;
}
DecodedJWT
decodedJWT
;
try
{
decodedJWT
=
TokenUtil
.
parse
(
apiToken
);
}
catch
(
Exception
e
)
{
response
.
setStatus
(
HttpStatus
.
HTTP_BAD_REQUEST
);
ServletUtil
.
write
(
response
,
JSONUtil
.
toJsonStr
(
ApiUtils
.
of
(
form
,
ApiCodeEnum
.
LOGIN_VALID_ERROR
)),
"application/json;charset=utf-8"
);
return
false
;
}
TokenUtil
.
setUserContext
(
decodedJWT
);
return
true
;
}
}
interface-server/src/main/java/com/zq/im/modules/api/controller/ApiV1.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
api
.
controller
;
import
cn.hutool.core.exceptions.ExceptionUtil
;
import
cn.hutool.extra.servlet.ServletUtil
;
import
com.zq.im.constant.ApiCodeEnum
;
import
com.zq.im.constant.ApiVersionEnum
;
import
com.zq.im.exception.BusinessException
;
import
com.zq.im.modules.api.form.ApiForm
;
import
com.zq.im.modules.api.form.ApiResp
;
import
com.zq.im.modules.api.service.ApiManage
;
import
com.zq.im.modules.api.utils.ApiUtils
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
javax.servlet.http.HttpServletResponse
;
import
java.io.InputStream
;
/**
* API方法总入口
*
* @author chenhao
* @since 2023/11/9
*/
@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping
(
"/api/v1"
)
public
class
ApiV1
{
private
final
ApiManage
apiManage
;
@PostMapping
(
value
=
"/action"
)
public
ResponseEntity
<
ApiResp
>
action
(
ApiForm
form
,
HttpServletResponse
response
)
{
// 设置版本号
form
.
setVersion
(
ApiVersionEnum
.
v1
.
name
());
//解析业务参数
if
(!
form
.
parseBizContent
())
{
ApiResp
apiResp
=
ApiUtils
.
of
(
form
,
ApiCodeEnum
.
PARAM_ERROR
);
return
ResponseEntity
.
badRequest
().
body
(
apiResp
);
}
// 调用接口方法
ApiResp
resp
;
try
{
// 调用接口方法
resp
=
apiManage
.
action
(
form
);
}
catch
(
BusinessException
e
)
{
// 捕抓业务发生的异常
log
.
error
(
"v1调用方法业务发生错误"
,
e
);
resp
=
ApiUtils
.
fail
(
form
,
e
.
getMessage
());
}
catch
(
Exception
e
)
{
// 转化指定异常为来自或者包含指定异常
BusinessException
businessException
=
ExceptionUtil
.
convertFromOrSuppressedThrowable
(
e
,
BusinessException
.
class
,
true
);
if
(
businessException
==
null
)
{
// 不是业务异常才打印错误日志
log
.
error
(
"v1调用方法发生错误"
,
e
);
}
if
(
businessException
!=
null
)
{
resp
=
ApiUtils
.
fail
(
form
,
businessException
.
getMessage
());
}
else
{
resp
=
ApiUtils
.
of
(
form
,
ApiCodeEnum
.
METHOD_HANDLER_ERROR
);
}
}
// 没有数据输出空
if
(
resp
==
null
)
{
resp
=
ApiUtils
.
of
(
form
,
ApiCodeEnum
.
UNKNOWN_ERROR
);
}
// 如果接口返回数据为输入流,则返回输入
Object
data
=
resp
.
getData
();
if
(
data
instanceof
InputStream
)
{
InputStream
inputStream
=
(
InputStream
)
data
;
ServletUtil
.
write
(
response
,
inputStream
);
return
null
;
}
return
resp
.
isSuccess
()
?
ResponseEntity
.
ok
(
resp
)
:
ResponseEntity
.
badRequest
().
body
(
resp
);
}
}
interface-server/src/main/java/com/zq/im/modules/api/form/ApiForm.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
api
.
form
;
import
cn.hutool.core.util.ArrayUtil
;
import
cn.hutool.core.util.StrUtil
;
import
cn.hutool.crypto.SecureUtil
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONObject
;
import
com.zq.im.exception.BusinessException
;
import
com.zq.im.modules.api.utils.ApiUtils
;
import
lombok.Data
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.web.multipart.MultipartFile
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.util.Map
;
import
java.util.TreeMap
;
/**
* api 基础form
*
* @author wilmiam
* @since 2021-07-13 09:59
*/
@Slf4j
@Data
public
class
ApiForm
{
private
String
appId
;
private
String
method
;
// 请求方法
private
String
sign
;
// 签名
private
String
timestamp
;
// 时间戳, 单位: 毫秒
private
String
version
;
// 接口版本
private
String
apiNo
;
// 接口码
private
String
bizContent
;
// 请求业务参数
private
JSONObject
bizContentJson
;
// 请求业务的json对象
private
MultipartFile
file
;
// 上传文件用
private
MultipartFile
[]
fileList
;
// 上传文件用
/**
* 解析业务参数,将业务参数转为JSON字符串
*/
public
boolean
parseBizContent
()
{
try
{
// 业务参数不为空,便给参数进行BASE64解码
if
(
StrUtil
.
isNotBlank
(
bizContent
))
{
bizContent
=
ApiUtils
.
decode
(
bizContent
,
"BASE64"
);
}
// 参数为空就设置为空
if
(
bizContent
==
null
)
{
bizContent
=
""
;
}
// 参数转换为字符串
bizContentJson
=
JSON
.
parseObject
(
bizContent
);
if
(
bizContentJson
==
null
)
{
bizContentJson
=
new
JSONObject
();
}
return
true
;
}
catch
(
Exception
e
)
{
log
.
error
(
"bizContent解析失败:{}"
,
e
.
getMessage
());
return
false
;
}
}
public
<
T
>
T
toBean
(
Class
<
T
>
beanClass
)
{
JSONObject
contentJson
=
getContentJson
();
return
contentJson
.
toJavaObject
(
beanClass
);
}
/**
* 获取参数
*/
public
String
getString
(
String
key
)
{
String
value
=
getContentJson
().
getString
(
key
);
return
value
==
null
?
""
:
value
;
}
/**
* 获取业务参数的JSON字符串
*/
public
JSONObject
getContentJson
()
{
if
(
bizContentJson
!=
null
)
{
return
bizContentJson
;
}
parseBizContent
();
return
bizContentJson
;
}
/**
* 加签,其实就是拼接加上Key
*/
public
String
getSignStr
(
String
key
)
{
// 参数进行排序
TreeMap
<
String
,
String
>
treeMap
=
getSignTreeMap
();
// 参数拼接
StringBuilder
src
=
new
StringBuilder
();
for
(
Map
.
Entry
<
String
,
String
>
entry
:
treeMap
.
entrySet
())
{
src
.
append
(
entry
.
getKey
()).
append
(
"="
).
append
(
entry
.
getValue
()).
append
(
"&"
);
}
src
.
append
(
"key="
).
append
(
key
);
return
src
.
toString
();
}
/**
* 获取签名所需参数,并进行字典序排序
*/
public
TreeMap
<
String
,
String
>
getSignTreeMap
()
{
TreeMap
<
String
,
String
>
treeMap
=
new
TreeMap
<>();
treeMap
.
put
(
"apiNo"
,
this
.
apiNo
);
treeMap
.
put
(
"timestamp"
,
this
.
timestamp
);
treeMap
.
put
(
"method"
,
this
.
method
);
String
bizContent
=
StrUtil
.
isBlank
(
this
.
bizContent
)
?
""
:
this
.
bizContent
;
treeMap
.
put
(
"bizContent"
,
bizContent
);
// 如果有文件传入,并设置文件的MD5
if
(
file
!=
null
)
{
InputStream
inputStream
;
try
{
inputStream
=
file
.
getInputStream
();
}
catch
(
IOException
e
)
{
log
.
error
(
"获取文件流发生错误"
,
e
);
throw
new
BusinessException
(
"获取文件流发生错误:"
+
e
.
getMessage
());
}
treeMap
.
put
(
"fileMd5"
,
SecureUtil
.
md5
(
inputStream
));
}
// 如果有文件列表,拼接所有文件的MD5
if
(
ArrayUtil
.
isNotEmpty
(
fileList
))
{
StringBuilder
md5
=
new
StringBuilder
();
for
(
MultipartFile
multipartFile
:
fileList
)
{
InputStream
inputStream
;
try
{
inputStream
=
multipartFile
.
getInputStream
();
}
catch
(
IOException
e
)
{
log
.
error
(
"获取文件流发生错误"
,
e
);
throw
new
BusinessException
(
"获取文件流发生错误:"
+
e
.
getMessage
());
}
md5
.
append
(
SecureUtil
.
md5
(
inputStream
));
}
treeMap
.
put
(
"fileMd5"
,
md5
.
toString
());
}
return
treeMap
;
}
}
interface-server/src/main/java/com/zq/im/modules/api/form/ApiResp.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
api
.
form
;
import
com.zq.im.constant.ApiCodeEnum
;
import
lombok.Getter
;
/**
* @author wilmiam
* @since 2022-11-04 11:29
*/
@Getter
public
class
ApiResp
{
private
String
apiNo
=
""
;
private
String
code
=
ApiCodeEnum
.
SUCCESS
.
code
();
private
String
msg
=
ApiCodeEnum
.
SUCCESS
.
msg
();
private
Long
timestamp
=
System
.
currentTimeMillis
();
private
Object
data
;
public
ApiResp
(
ApiForm
form
)
{
this
.
apiNo
=
form
.
getApiNo
()
==
null
?
""
:
form
.
getApiNo
();
}
public
ApiResp
(
ApiCodeEnum
apiCodeEnum
)
{
this
.
code
=
apiCodeEnum
.
code
();
this
.
msg
=
apiCodeEnum
.
msg
();
}
public
ApiResp
(
ApiForm
form
,
ApiCodeEnum
apiCodeEnum
)
{
this
.
code
=
apiCodeEnum
.
code
();
this
.
msg
=
apiCodeEnum
.
msg
();
this
.
apiNo
=
form
.
getApiNo
();
}
public
ApiResp
setApiNo
(
String
apiNo
)
{
this
.
apiNo
=
apiNo
;
return
this
;
}
public
ApiResp
setCode
(
String
code
)
{
this
.
code
=
code
;
return
this
;
}
public
ApiResp
setMsg
(
String
msg
)
{
this
.
msg
=
msg
;
return
this
;
}
public
ApiResp
setTimestamp
(
Long
timestamp
)
{
this
.
timestamp
=
timestamp
;
return
this
;
}
public
ApiResp
setData
(
Object
data
)
{
this
.
data
=
data
;
return
this
;
}
public
Boolean
isSuccess
()
{
return
this
.
getCode
().
equals
(
ApiCodeEnum
.
SUCCESS
.
code
());
}
}
interface-server/src/main/java/com/zq/im/modules/api/service/ApiManage.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
api
.
service
;
import
com.auth0.jwt.interfaces.DecodedJWT
;
import
com.zq.im.constant.ApiCodeEnum
;
import
com.zq.im.modules.api.form.ApiForm
;
import
com.zq.im.modules.api.form.ApiResp
;
import
com.zq.im.modules.api.utils.ApiUtils
;
import
com.zq.im.modules.api.utils.ReflectionUtils
;
import
com.zq.im.utils.TokenUtil
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Service
;
import
java.lang.reflect.Method
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.List
;
/**
* @author wilmiam
* @since 2022/10/28 16:02
*/
@Slf4j
@Service
public
class
ApiManage
{
/**
* 允许用户未登录状态下执行的方法名
*/
private
static
final
List
<
String
>
ALLOW_METHOD
=
Arrays
.
asList
(
"getApiToken"
);
private
static
final
List
<
String
>
METHOD_LIST
;
static
{
METHOD_LIST
=
methodList
();
}
public
static
List
<
String
>
methodList
()
{
List
<
String
>
methodList
=
new
ArrayList
<>();
Method
[]
methods
=
IApiLogic
.
class
.
getMethods
();
for
(
Method
method
:
methods
)
{
Class
<?>[]
params
=
method
.
getParameterTypes
();
if
(
params
.
length
==
1
&&
(
params
[
0
]
==
ApiForm
.
class
))
{
methodList
.
add
(
method
.
getName
());
}
}
return
methodList
;
}
public
static
boolean
isNotValid
(
String
method
)
{
return
ALLOW_METHOD
.
contains
(
method
);
}
public
ApiResp
action
(
ApiForm
form
)
throws
Exception
{
// 如果接口方法不存在,则返回异常
if
(!
METHOD_LIST
.
contains
(
form
.
getMethod
()))
{
return
ApiUtils
.
of
(
form
,
ApiCodeEnum
.
METHOD_ERROR
);
}
// 校验签名,校验失败直接返回
ApiResp
authResp
=
signValid
(
form
);
if
(!
authResp
.
isSuccess
())
{
return
authResp
;
}
IApiLogic
apiLogic
=
ApiUtils
.
getApiLogic
(
form
);
// 调用接口方法,利用反射更简洁
Object
result
=
ReflectionUtils
.
invokeMethod
(
apiLogic
,
form
.
getMethod
(),
new
Class
<?>[]{
ApiForm
.
class
},
new
Object
[]{
form
});
return
(
ApiResp
)
result
;
}
/**
* 签名验证
*/
public
ApiResp
signValid
(
ApiForm
form
)
{
// 白名单存在该方法,直接放行
boolean
contains
=
ALLOW_METHOD
.
contains
(
form
.
getMethod
());
if
(
contains
)
{
return
ApiUtils
.
success
(
form
);
}
// 获取Token中的sessionKey
DecodedJWT
apiToken
=
TokenUtil
.
getUserContext
();
String
sessionKey
=
TokenUtil
.
getSessionkey
(
apiToken
);
// 通过sessionKey签名,并进行校验
String
sign
=
ApiUtils
.
getSign
(
form
.
getSignStr
(
sessionKey
==
null
?
""
:
sessionKey
));
if
(!
sign
.
equals
(
form
.
getSign
()))
{
return
ApiUtils
.
of
(
form
,
ApiCodeEnum
.
CHECK_SIGN_VALID_ERROR
);
}
return
ApiUtils
.
success
(
form
);
}
}
interface-server/src/main/java/com/zq/im/modules/api/service/IApiCommon.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
api
.
service
;
import
com.zq.im.modules.api.form.ApiForm
;
import
com.zq.im.modules.api.form.ApiResp
;
/**
* API通用接口
*
* @author wilmiam
* @since 2022-11-04 11:35
*/
public
interface
IApiCommon
{
ApiResp
signValid
(
ApiForm
form
);
}
interface-server/src/main/java/com/zq/im/modules/api/service/IApiLogic.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
api
.
service
;
import
com.zq.im.modules.api.form.ApiForm
;
import
com.zq.im.modules.api.form.ApiResp
;
/**
* API接口类
* 这里的注解没有用,只是为了注释说明方法
*
* @author wilmiam
* @since 2022-11-01 09:53
*/
public
interface
IApiLogic
extends
IApiCommon
{
/**
* 获取第三方调用token
*/
ApiResp
getApiToken
(
ApiForm
form
);
/**
* 图片质量检测
*/
ApiResp
detection
(
ApiForm
form
);
//
// /**
// * 图片纠偏
// *
// * @param form
// * @return
// */
// ApiResp deskew(ApiForm form);
//
// /**
// * 去黑边
// *
// * @param form
// * @return
// */
// ApiResp removeBlack(ApiForm form);
//
// /**
// * 图片灰度化
// *
// * @param form
// * @return
// */
// ApiResp gray(ApiForm form);
//
// /**
// * 图片边缘检测
// *
// * @param form
// * @return
// */
// ApiResp canny(ApiForm form);
//
// /**
// * 图片弯曲矫正
// *
// * @param form
// * @return
// */
// ApiResp correct(ApiForm form);
//
// /**
// * 图片优化
// *
// * @param form
// * @return
// */
// ApiResp imageOptimization(ApiForm form);
}
interface-server/src/main/java/com/zq/im/modules/api/service/impl/ApiV1Logic.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
api
.
service
.
impl
;
import
com.zq.im.aspect.OpenApi
;
import
com.zq.im.modules.api.form.ApiForm
;
import
com.zq.im.modules.api.form.ApiResp
;
import
com.zq.im.modules.api.service.IApiLogic
;
import
com.zq.im.modules.api.utils.ApiUtils
;
import
com.zq.im.modules.im.req.ImageReq
;
import
com.zq.im.modules.im.service.ImgProcService
;
import
com.zq.im.modules.system.service.ApiUserInfoService
;
import
com.zq.im.utils.AssertUtils
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Component
;
/**
* API实现类
*
* @author wilmiam
* @since 2022-10-31 17:16
*/
@Slf4j
@Component
public
class
ApiV1Logic
extends
BaseApiLogic
implements
IApiLogic
{
@Autowired
ApiUserInfoService
apiUserInfoService
;
@Autowired
private
ImgProcService
imgProcService
;
@Override
@OpenApi
(
"获取Token"
)
public
ApiResp
getApiToken
(
ApiForm
form
)
{
String
appId
=
form
.
getString
(
"appId"
);
String
appSecret
=
form
.
getString
(
"appSecret"
);
AssertUtils
.
hasText
(
appId
,
"缺少参数appId"
);
AssertUtils
.
hasText
(
appSecret
,
"缺少参数secret"
);
return
ApiUtils
.
toApiResp
(
form
,
apiUserInfoService
.
getApiToken
(
appId
,
appSecret
));
}
@Override
@OpenApi
(
"检测图片信息"
)
public
ApiResp
detection
(
ApiForm
form
)
{
ImageReq
req
=
form
.
toBean
(
ImageReq
.
class
);
AssertUtils
.
hasText
(
req
.
getFileContent
(),
"缺少文件内容"
);
AssertUtils
.
hasText
(
req
.
getFileName
(),
"缺少文件名"
);
return
ApiUtils
.
toApiResp
(
form
,
imgProcService
.
detection
(
req
));
}
//
// @ApiMethod(name = "图片纠偏", filterRequestField = "fileContent")
// @Override
// public ApiResp deskew(ApiForm form) {
// DetectionVo vo = form.toBean(DetectionVo.class);
// AssertUtils.hasText(vo.getFileContent(), "缺少文件内容");
// AssertUtils.hasText(vo.getFilename(), "缺少文件名");
// return ApiUtils.toApiResp(form, imgProcService.apiService(vo, "imageCorrection"));
// }
//
// @ApiMethod(name = "去黑边", filterRequestField = "fileContent")
// @Override
// public ApiResp removeBlack(ApiForm form) {
// DetectionVo vo = form.toBean(DetectionVo.class);
// AssertUtils.hasText(vo.getFileContent(), "缺少文件内容");
// AssertUtils.hasText(vo.getFilename(), "缺少文件名");
// return ApiUtils.toApiResp(form, imgProcService.apiService(vo, "removeBlack"));
// }
//
// @ApiMethod(name = "图片灰度化", filterRequestField = "fileContent")
// @Override
// public ApiResp gray(ApiForm form) {
// DetectionVo vo = form.toBean(DetectionVo.class);
// AssertUtils.hasText(vo.getFileContent(), "缺少文件内容");
// AssertUtils.hasText(vo.getFilename(), "缺少文件名");
// return ApiUtils.toApiResp(form, imgProcService.apiService(vo, "gray"));
// }
//
// @ApiMethod(name = "图片边缘检测", filterRequestField = "fileContent")
// @Override
// public ApiResp canny(ApiForm form) {
// DetectionVo vo = form.toBean(DetectionVo.class);
// AssertUtils.hasText(vo.getFileContent(), "缺少文件内容");
// AssertUtils.hasText(vo.getFilename(), "缺少文件名");
// return ApiUtils.toApiResp(form, imgProcService.apiService(vo, "gray"));
// }
//
// @ApiMethod(name = "图片弯曲矫正", filterRequestField = "fileContent")
// @Override
// public ApiResp correct(ApiForm form) {
// DetectionVo vo = form.toBean(DetectionVo.class);
// AssertUtils.hasText(vo.getFileContent(), "缺少文件内容");
// AssertUtils.hasText(vo.getFilename(), "缺少文件名");
// return ApiUtils.toApiResp(form, imgProcService.apiService(vo, "correct"));
// }
//
// @ApiMethod(name = "图片优化", filterRequestField = "fileContent")
// @Override
// public ApiResp imageOptimization(ApiForm form) {
// DetectionVo vo = form.toBean(DetectionVo.class);
// AssertUtils.hasText(vo.getFileContent(), "缺少文件内容");
// AssertUtils.hasText(vo.getFilename(), "缺少文件名");
// return ApiUtils.toApiResp(form, imgProcService.imageOptimization(vo, "imageOptimization"));
// }
}
interface-server/src/main/java/com/zq/im/modules/api/service/impl/ApiV2Logic.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
api
.
service
.
impl
;
import
com.zq.im.modules.api.service.IApiLogic
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Component
;
/**
* API实现类
*
* @author wilmiam
* @since 2022-10-31 17:16
*/
@Slf4j
@Component
public
class
ApiV2Logic
extends
ApiV1Logic
implements
IApiLogic
{
}
interface-server/src/main/java/com/zq/im/modules/api/service/impl/BaseApiLogic.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
api
.
service
.
impl
;
import
com.zq.im.modules.api.form.ApiForm
;
import
com.zq.im.modules.api.form.ApiResp
;
import
com.zq.im.modules.api.service.IApiLogic
;
import
com.zq.im.modules.api.utils.ApiUtils
;
/**
* API基础类
* <p>
* 2016年11月15日 下午9:48:27
*
* @author wilmiam
*/
public
abstract
class
BaseApiLogic
implements
IApiLogic
{
@Override
public
ApiResp
signValid
(
ApiForm
form
)
{
return
ApiUtils
.
success
(
form
);
}
}
interface-server/src/main/java/com/zq/im/modules/api/utils/ApiUtils.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
api
.
utils
;
import
cn.hutool.core.codec.Base64
;
import
cn.hutool.core.util.StrUtil
;
import
cn.hutool.crypto.SecureUtil
;
import
com.zq.im.constant.ApiCodeEnum
;
import
com.zq.im.modules.api.form.ApiForm
;
import
com.zq.im.modules.api.form.ApiResp
;
import
com.zq.im.modules.api.service.IApiLogic
;
import
com.zq.im.modules.api.service.impl.ApiV1Logic
;
import
com.zq.im.modules.api.service.impl.ApiV2Logic
;
import
com.zq.im.modules.system.vo.ResultVo
;
import
org.springframework.stereotype.Component
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* @author wilmiam
* @since 2021-07-22 10:18
*/
@Component
public
class
ApiUtils
{
private
static
final
Map
<
String
,
IApiLogic
>
MAP
=
new
HashMap
<>();
public
ApiUtils
(
ApiV1Logic
apiV1Logic
,
ApiV2Logic
apiV2Logic
)
{
addApi
(
"v1"
,
apiV1Logic
);
addApi
(
"v2"
,
apiV2Logic
);
}
public
static
void
addApi
(
String
version
,
IApiLogic
apiLogic
)
{
MAP
.
put
(
version
,
apiLogic
);
}
public
static
IApiLogic
getApiLogic
(
ApiForm
form
)
{
return
MAP
.
get
(
form
.
getVersion
());
}
/**
* 获取成功响应
*/
public
static
ApiResp
success
(
ApiForm
form
)
{
return
new
ApiResp
(
form
,
ApiCodeEnum
.
SUCCESS
);
}
/**
* 获取失败的响应
*/
public
static
ApiResp
fail
(
ApiForm
form
,
String
errMsg
)
{
ApiResp
apiResp
=
new
ApiResp
(
form
,
ApiCodeEnum
.
BUSINESS_ERROR
);
apiResp
.
setMsg
(
errMsg
);
return
apiResp
;
}
public
static
ApiResp
of
(
ApiForm
form
,
ApiCodeEnum
apiCodeEnum
)
{
return
new
ApiResp
(
form
,
apiCodeEnum
);
}
public
static
ApiResp
toApiResp
(
ApiForm
form
,
ResultVo
resultVo
)
{
ApiResp
apiResp
=
new
ApiResp
(
form
);
if
(
resultVo
.
isSuccess
())
{
apiResp
.
setData
(
resultVo
.
getData
()
==
null
?
""
:
resultVo
.
getData
());
}
else
{
return
apiResp
.
setCode
(
String
.
valueOf
(
resultVo
.
getErrCode
())).
setMsg
(
resultVo
.
getErrMsg
());
}
return
apiResp
;
}
public
static
ApiResp
toApiResp
(
ApiForm
form
,
Object
data
)
{
ApiResp
apiResp
=
new
ApiResp
(
form
);
apiResp
.
setData
(
data
);
return
apiResp
;
}
/**
* 解码
*/
public
static
String
decode
(
String
params
,
String
encryptType
)
{
if
(
StrUtil
.
isBlank
(
params
))
{
return
""
;
}
// params = EncryptUtils.urlDecode(params, "UTF-8");
if
(
"RSA"
.
equals
(
encryptType
))
{
params
=
EncryptUtils
.
rsaDecodeByPrivateKey
(
params
,
RsaUtils
.
privateKey
);
}
else
{
params
=
Base64
.
decodeStr
(
params
);
}
return
params
;
}
/**
* 编码
* <p>
* 2017年3月15日 下午1:49:09
*
* @param params
* @return
*/
public
static
String
encode
(
String
params
,
String
encryptType
)
{
if
(
StrUtil
.
isBlank
(
params
))
{
return
""
;
}
if
(
"RSA"
.
equals
(
encryptType
))
{
params
=
EncryptUtils
.
rsaDecodeByPrivateKey
(
params
,
RsaUtils
.
publicKey
);
}
else
{
params
=
EncryptUtils
.
base64Decode
(
params
);
}
params
=
EncryptUtils
.
urlEncode
(
params
,
"UTF-8"
);
return
params
;
}
/**
* 获取验证sign
* <p>
* 2017年3月15日 下午3:14:27
*
* @param content
* @return
*/
public
static
String
getSign
(
String
content
)
{
return
SecureUtil
.
md5
(
content
);
}
}
interface-server/src/main/java/com/zq/im/modules/api/utils/EncryptUtils.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
api
.
utils
;
import
cn.hutool.core.util.StrUtil
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.web.server.ServerErrorException
;
import
java.io.UnsupportedEncodingException
;
import
java.net.URLEncoder
;
import
java.security.MessageDigest
;
import
java.security.NoSuchAlgorithmException
;
import
java.util.Base64
;
/**
* 加密工具类
*
* @author wilmiam
* @since 2021-07-09 17:55
*/
public
class
EncryptUtils
{
private
static
final
Logger
log
=
LoggerFactory
.
getLogger
(
EncryptUtils
.
class
);
/**
* 字符编码
*/
private
static
final
String
CHARSET_NAME
=
"UTF-8"
;
/**
* 用来将字节转换成 16 进制表示的字符
*/
private
static
final
char
[]
HEX_DIGITS
=
{
'0'
,
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'6'
,
'7'
,
'8'
,
'9'
,
'a'
,
'b'
,
'c'
,
'd'
,
'e'
,
'f'
};
private
static
final
int
HEX_RADIUS
=
16
;
/**
* MD5 加密字符串
*/
public
static
String
md5Encrypt
(
final
String
sourceStr
)
{
return
md5Encrypt
(
sourceStr
,
CHARSET_NAME
);
}
/**
* MD5加密字符串
*/
public
static
String
md5Encrypt
(
final
String
sourceStr
,
String
coding
)
{
if
(
StrUtil
.
isBlank
(
sourceStr
))
{
return
null
;
}
byte
[]
sourceByte
;
try
{
sourceByte
=
sourceStr
.
getBytes
(
coding
);
}
catch
(
UnsupportedEncodingException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
sourceByte
=
sourceStr
.
getBytes
();
}
MessageDigest
md
;
try
{
md
=
MessageDigest
.
getInstance
(
"MD5"
);
md
.
update
(
sourceByte
);
// MD5 的计算结果是一个 128 位的长整数,用字节表示就是 16 个字节
final
byte
[]
tmp
=
md
.
digest
();
// 每个字节用 16 进制表示的话,使用两个字符,所以表示成 16 进制需要 32 个字符
// 16 << 1 相当于 16*2
final
char
[]
str
=
new
char
[
16
<<
1
];
// 表示转换结果中对应的字符位置
int
k
=
0
;
// 从第一个字节开始,对 MD5 的每一个字节转换成 16 进制字符的转换
for
(
int
i
=
0
;
i
<
HEX_RADIUS
;
i
++)
{
// 取第 i 个字节
final
byte
byte0
=
tmp
[
i
];
// 取字节中高 4 位的数字转换, >>> 为逻辑右移,将符号位一起右移
str
[
k
++]
=
HEX_DIGITS
[
byte0
>>>
4
&
0xf
];
// 取字节中低 4 位的数字转换
str
[
k
++]
=
HEX_DIGITS
[
byte0
&
0xf
];
}
// 换后的结果转换为字符串
return
new
String
(
str
);
}
catch
(
final
NoSuchAlgorithmException
e
)
{
log
.
error
(
">> MD5加密错误"
,
e
);
}
return
null
;
}
/**
* 私钥解密(注意:encodedData是base64加密后的才行)
*/
public
static
String
rsaDecodeByPrivateKey
(
String
encodedData
,
String
privateKey
)
{
try
{
byte
[]
decodedData
=
RsaUtils
.
decryptByPrivateKey
(
Base64
.
getDecoder
().
decode
(
encodedData
),
privateKey
);
return
new
String
(
decodedData
,
CHARSET_NAME
);
}
catch
(
Exception
e
)
{
log
.
error
(
"rsaDecodeByPrivateKey error"
,
e
);
return
null
;
}
}
/**
* 使用BASE64进行解密
*
* @param base64Str base64字符串
* @return 解密字符串
*/
public
static
String
base64Decode
(
final
String
base64Str
)
{
byte
[]
decode
=
Base64
.
getDecoder
().
decode
(
base64Str
);
try
{
return
new
String
(
decode
,
CHARSET_NAME
);
}
catch
(
UnsupportedEncodingException
e
)
{
log
.
error
(
"base64 decode error"
,
e
);
throw
new
ServerErrorException
(
"编码失败"
);
}
}
/**
* 对字符串进行URL编码
*
* @param sourceStr 需要编码的字符串
* @param enc 编码格式
* @return
*/
public
static
String
urlEncode
(
String
sourceStr
,
String
enc
)
{
try
{
return
URLEncoder
.
encode
(
sourceStr
,
enc
);
}
catch
(
UnsupportedEncodingException
e
)
{
log
.
error
(
"urlEncode error"
,
e
);
return
null
;
}
}
}
interface-server/src/main/java/com/zq/im/modules/api/utils/ReflectionUtils.java
0 → 100644
View file @
627e5035
/**
* Copyright 2015-2025 .
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
zq
.
im
.
modules
.
api
.
utils
;
import
lombok.extern.slf4j.Slf4j
;
import
java.lang.reflect.Field
;
import
java.lang.reflect.InvocationTargetException
;
import
java.lang.reflect.Method
;
/**
* 方法类
*
* @author syh
*/
@Slf4j
public
class
ReflectionUtils
{
/**
* 循环向上转型, 获取对象的 DeclaredMethod
*
* @param object : 子类对象
* @param methodName : 父类中的方法名
* @param parameterTypes : 父类中的方法参数类型
* @return 父类中的方法对象
*/
private
static
Method
getDeclaredMethod
(
Object
object
,
String
methodName
,
Class
<?>...
parameterTypes
)
{
Method
method
;
Class
<?>
clazz
=
object
.
getClass
();
while
(
clazz
!=
Object
.
class
)
{
try
{
method
=
clazz
.
getDeclaredMethod
(
methodName
,
parameterTypes
);
return
method
;
}
catch
(
Exception
e
)
{
// 未获取到就往上找
clazz
=
clazz
.
getSuperclass
();
}
}
return
null
;
}
/**
* 直接调用对象方法, 而忽略修饰符(private, protected, default)
*
* @param object : 子类对象
* @param methodName : 父类中的方法名
* @param parameterTypes : 父类中的方法参数类型
* @param parameters : 父类中的方法参数
* @return 父类中方法的执行结果
*/
public
static
Object
invokeMethod
(
Object
object
,
String
methodName
,
Class
<?>[]
parameterTypes
,
Object
[]
parameters
)
throws
InvocationTargetException
,
IllegalAccessException
{
// 根据 对象、方法名和对应的方法参数 通过反射 调用上面的方法获取 Method 对象
Method
method
=
getDeclaredMethod
(
object
,
methodName
,
parameterTypes
);
if
(
method
==
null
)
{
log
.
warn
(
object
.
getClass
()
+
"未获取到"
+
methodName
+
"方法!"
);
return
null
;
}
// 抑制Java对方法进行检查,主要是针对私有方法而言
method
.
setAccessible
(
true
);
// 调用object 的 method 所代表的方法,其方法的参数是 parameters
return
method
.
invoke
(
object
,
parameters
);
}
/**
* 循环向上转型, 获取对象的 DeclaredField
*
* @param object : 子类对象
* @param fieldName : 父类中的属性名
* @return 父类中的属性对象
*/
private
static
Field
getDeclaredField
(
Object
object
,
String
fieldName
)
{
Field
field
;
Class
<?>
clazz
=
object
.
getClass
();
while
(
clazz
!=
Object
.
class
)
{
try
{
field
=
clazz
.
getDeclaredField
(
fieldName
);
return
field
;
}
catch
(
Exception
e
)
{
// 未获取到就往上找
clazz
=
clazz
.
getSuperclass
();
}
}
return
null
;
}
/**
* 直接设置对象属性值, 忽略 private/protected 修饰符, 也不经过 setter
*
* @param object : 子类对象
* @param fieldName : 父类中的属性名
* @param value : 将要设置的值
*/
public
static
void
setFieldValue
(
Object
object
,
String
fieldName
,
Object
value
)
{
// 根据 对象和属性名通过反射 调用上面的方法获取 Field对象
Field
field
=
getDeclaredField
(
object
,
fieldName
);
if
(
field
==
null
)
{
System
.
err
.
println
(
object
.
getClass
()
+
"未获取到"
+
fieldName
+
"属性!"
);
return
;
}
// 抑制Java对其的检查
field
.
setAccessible
(
true
);
try
{
// 将 object 中 field 所代表的值 设置为 value
field
.
set
(
object
,
value
);
}
catch
(
IllegalArgumentException
|
IllegalAccessException
e
)
{
e
.
printStackTrace
();
}
}
/**
* 直接读取对象的属性值, 忽略 private/protected 修饰符, 也不经过 getter
*
* @param object : 子类对象
* @param fieldName : 父类中的属性名
* @return : 父类中的属性值
*/
public
static
Object
getFieldValue
(
Object
object
,
String
fieldName
)
{
// 根据 对象和属性名通过反射 调用上面的方法获取 Field对象
Field
field
=
getDeclaredField
(
object
,
fieldName
);
if
(
field
==
null
)
{
System
.
err
.
println
(
object
.
getClass
()
+
"未获取到"
+
fieldName
+
"属性!"
);
return
null
;
}
// 抑制Java对其的检查
field
.
setAccessible
(
true
);
try
{
// 获取 object 中 field 所代表的属性值
return
field
.
get
(
object
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
return
null
;
}
}
interface-server/src/main/java/com/zq/im/modules/api/utils/RsaUtils.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
api
.
utils
;
import
javax.crypto.Cipher
;
import
java.io.ByteArrayOutputStream
;
import
java.io.IOException
;
import
java.security.*
;
import
java.security.interfaces.RSAPrivateKey
;
import
java.security.interfaces.RSAPublicKey
;
import
java.security.spec.PKCS8EncodedKeySpec
;
import
java.security.spec.X509EncodedKeySpec
;
import
java.util.Base64
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* @author wilmiam
* @since 2021-07-09 17:56
*/
public
class
RsaUtils
{
/**
* 获取公钥的key
*/
public
static
final
String
PUBLIC_KEY
=
"RSAPublicKey"
;
/**
* 获取私钥的key
*/
public
static
final
String
PRIVATE_KEY
=
"RSAPrivateKey"
;
/**
* 加密算法RSA
*/
private
static
final
String
KEY_ALGORITHM
=
"RSA"
;
/**
* 签名算法
*/
private
static
final
String
SIGNATURE_ALGORITHM
=
"MD5withRSA"
;
/**
* RSA最大加密明文大小
*/
private
static
final
int
MAX_ENCRYPT_BLOCK
=
117
;
/**
* RSA最大解密密文大小
*/
private
static
final
int
MAX_DECRYPT_BLOCK
=
128
;
public
static
String
privateKey
=
"MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMTaoTuj4LU9WAMeaVWcpwgyMcdvAA3JRDcG0+pWG086c+WPdSggNNZaVw3szCKOTnWvNc6SoqjpjpbQpC57uag67VzKWLmsZoF6SXjCARyRaEkfK2VRHTfkVpyd8FF16gebVhhyjbkkja9JVEekwqOGzfmnfSKfx5LwvcSxdiSrAgMBAAECgYBZgGHQQPk4zhRHDrurnhbfhhrV5yTqH7kxH5yYLeAqzJPHKsuEm+gKEXcFMMW7bGJF5YycSFVGYTJgZapQLBbDlrZdM8SjxsNyrCKI3v3LNQDsqs5x751HfFVvTme7wroN/uJszUaQJPagEUckMkHvpv7XWoL3Wbz7oy94T3ENoQJBAPAhj2yo9jRZv5JRlYy5BFwqYpxSWqGjzr2k2YiGqB9/y/pDpDx3q42FaBcOlOOeh/My+iVNLcezqgj+U0yx79ECQQDR3Oz9ckCm2q7AMCLFmp9cs4dws6DLim35awOvLIXtm/Z1tRNyuLqb6g2VM4O/QiTu64F3+ljKiOWHAcgxqUe7AkEArTuYy4vs6gFhCb6fg8Cp24+cSifDSF7zM67sW+jA+tBoJ+iKYDD46wS1/gQ/9yGT9Cfve998ylfbr9dB4s9vMQJAOH/uHd3gogtF+N/8vI6AUQjUcfcqVyIRsZCqEUM/W1Ud6VqyvbQWKVu+BGk2EwvPvbMRzCdOOFja0pocN6KHeQJAQPwlDo1IHJI5F60CvfIG8dIwtGexMnd4NNHQ4KH0peK9jUCPkkpW0No5ZEtKNgfdPk23erfyx5cGqocvnoUpoQ=="
;
public
static
String
publicKey
=
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDE2qE7o+C1PVgDHmlVnKcIMjHHbwANyUQ3BtPqVhtPOnPlj3UoIDTWWlcN7Mwijk51rzXOkqKo6Y6W0KQue7moOu1cyli5rGaBekl4wgEckWhJHytlUR035FacnfBRdeoHm1YYco25JI2vSVRHpMKjhs35p30in8eS8L3EsXYkqwIDAQAB"
;
/**
* 生成密钥对(公钥和私钥)
*
* @return
* @throws Exception
*/
public
static
Map
<
String
,
Key
>
genKeyPair
()
throws
Exception
{
KeyPairGenerator
keyPairGen
=
KeyPairGenerator
.
getInstance
(
KEY_ALGORITHM
);
keyPairGen
.
initialize
(
1024
);
KeyPair
keyPair
=
keyPairGen
.
generateKeyPair
();
RSAPublicKey
publicKey
=
(
RSAPublicKey
)
keyPair
.
getPublic
();
RSAPrivateKey
privateKey
=
(
RSAPrivateKey
)
keyPair
.
getPrivate
();
Map
<
String
,
Key
>
keyMap
=
new
HashMap
<>(
4
);
keyMap
.
put
(
PUBLIC_KEY
,
publicKey
);
keyMap
.
put
(
PRIVATE_KEY
,
privateKey
);
return
keyMap
;
}
/**
* 用私钥对信息生成数字签名
*
* @param data 已加密数据
* @param privateKey 私钥(BASE64编码)
* @return
* @throws Exception
*/
public
static
String
sign
(
byte
[]
data
,
String
privateKey
)
throws
Exception
{
byte
[]
keyBytes
=
Base64
.
getDecoder
().
decode
(
privateKey
);
PKCS8EncodedKeySpec
pkcs8KeySpec
=
new
PKCS8EncodedKeySpec
(
keyBytes
);
KeyFactory
keyFactory
=
KeyFactory
.
getInstance
(
KEY_ALGORITHM
);
PrivateKey
privateK
=
keyFactory
.
generatePrivate
(
pkcs8KeySpec
);
Signature
signature
=
Signature
.
getInstance
(
SIGNATURE_ALGORITHM
);
signature
.
initSign
(
privateK
);
signature
.
update
(
data
);
return
Base64
.
getEncoder
().
encodeToString
(
signature
.
sign
());
}
/**
* 校验数字签名
*
* @param data 已加密数据
* @param publicKey 公钥(BASE64编码)
* @param sign 数字签名
* @return
* @throws Exception
*/
public
static
boolean
verify
(
byte
[]
data
,
String
publicKey
,
String
sign
)
throws
Exception
{
byte
[]
keyBytes
=
Base64
.
getDecoder
().
decode
(
publicKey
);
X509EncodedKeySpec
keySpec
=
new
X509EncodedKeySpec
(
keyBytes
);
KeyFactory
keyFactory
=
KeyFactory
.
getInstance
(
KEY_ALGORITHM
);
PublicKey
publicK
=
keyFactory
.
generatePublic
(
keySpec
);
Signature
signature
=
Signature
.
getInstance
(
SIGNATURE_ALGORITHM
);
signature
.
initVerify
(
publicK
);
signature
.
update
(
data
);
return
signature
.
verify
(
Base64
.
getDecoder
().
decode
(
sign
));
}
/**
* <p>
* 公钥解密
* </p>
*
* @param encryptedData 已加密数据
* @param publicKey 公钥(BASE64编码)
* @return
* @throws Exception
*/
public
static
byte
[]
decryptByPublicKey
(
byte
[]
encryptedData
,
String
publicKey
)
throws
Exception
{
return
byteTransfer
(
getCipherByRsaPublicKey
(
Cipher
.
DECRYPT_MODE
,
publicKey
),
encryptedData
,
MAX_ENCRYPT_BLOCK
);
}
/**
* <p>
* 公钥加密
* </p>
*
* @param data 源数据
* @param publicKey 公钥(BASE64编码)
* @return
* @throws Exception
*/
public
static
byte
[]
encryptByPublicKey
(
byte
[]
data
,
String
publicKey
)
throws
Exception
{
return
byteTransfer
(
getCipherByRsaPublicKey
(
Cipher
.
ENCRYPT_MODE
,
publicKey
),
data
,
MAX_ENCRYPT_BLOCK
);
}
private
static
Cipher
getCipherByRsaPublicKey
(
int
mode
,
String
publicKey
)
throws
GeneralSecurityException
{
byte
[]
keyBytes
=
Base64
.
getDecoder
().
decode
(
publicKey
);
X509EncodedKeySpec
x509KeySpec
=
new
X509EncodedKeySpec
(
keyBytes
);
KeyFactory
keyFactory
=
KeyFactory
.
getInstance
(
KEY_ALGORITHM
);
Key
publicK
=
keyFactory
.
generatePublic
(
x509KeySpec
);
// 对数据加密
Cipher
cipher
=
Cipher
.
getInstance
(
keyFactory
.
getAlgorithm
());
cipher
.
init
(
Cipher
.
ENCRYPT_MODE
,
publicK
);
return
cipher
;
}
/**
* <P>
* 私钥解密
* </p>
*
* @param encryptedData 已加密数据
* @param privateKey 私钥(BASE64编码)
* @return
* @throws Exception
*/
public
static
byte
[]
decryptByPrivateKey
(
byte
[]
encryptedData
,
String
privateKey
)
throws
Exception
{
return
byteTransfer
(
getCipherByRsaPrivateKey
(
Cipher
.
DECRYPT_MODE
,
privateKey
),
encryptedData
,
MAX_DECRYPT_BLOCK
);
}
/**
* 私钥加密
*
* @param data 源数据
* @param privateKey 私钥(BASE64编码)
* @return
* @throws Exception
*/
public
static
byte
[]
encryptByPrivateKey
(
byte
[]
data
,
String
privateKey
)
throws
Exception
{
return
byteTransfer
(
getCipherByRsaPrivateKey
(
Cipher
.
ENCRYPT_MODE
,
privateKey
),
data
,
MAX_ENCRYPT_BLOCK
);
}
private
static
Cipher
getCipherByRsaPrivateKey
(
int
mode
,
String
key
)
throws
GeneralSecurityException
{
byte
[]
keyBytes
=
Base64
.
getDecoder
().
decode
(
key
);
PKCS8EncodedKeySpec
pkcs8KeySpec
=
new
PKCS8EncodedKeySpec
(
keyBytes
);
KeyFactory
keyFactory
=
KeyFactory
.
getInstance
(
KEY_ALGORITHM
);
Key
privateK
=
keyFactory
.
generatePrivate
(
pkcs8KeySpec
);
Cipher
cipher
=
Cipher
.
getInstance
(
keyFactory
.
getAlgorithm
());
cipher
.
init
(
mode
,
privateK
);
return
cipher
;
}
/**
* <p>
* 获取私钥
* </p>
*
* @param keyMap 密钥对
* @return
*/
public
static
String
getPrivateKey
(
Map
<
String
,
Key
>
keyMap
)
{
Key
key
=
keyMap
.
get
(
PRIVATE_KEY
);
return
Base64
.
getEncoder
().
encodeToString
(
key
.
getEncoded
());
}
/**
* 获取公钥
*
* @param keyMap 密钥对
* @return
*/
public
static
String
getPublicKey
(
Map
<
String
,
Key
>
keyMap
)
{
Key
key
=
keyMap
.
get
(
PUBLIC_KEY
);
return
Base64
.
getEncoder
().
encodeToString
(
key
.
getEncoded
());
}
/**
* 根据cipher的模式, 对数据进行分段加密/解密
*
* @param cipher
* @param data
* @return
* @throws GeneralSecurityException,IOException
*/
private
static
byte
[]
byteTransfer
(
Cipher
cipher
,
byte
[]
data
,
int
maxBlock
)
throws
GeneralSecurityException
,
IOException
{
int
inputLen
=
data
.
length
;
ByteArrayOutputStream
out
=
new
ByteArrayOutputStream
();
int
offSet
=
0
;
byte
[]
cache
;
int
i
=
0
;
// 根据cipher的模式, 对数据分段加密/解密
while
(
inputLen
-
offSet
>
0
)
{
if
(
inputLen
-
offSet
>
maxBlock
)
{
cache
=
cipher
.
doFinal
(
data
,
offSet
,
maxBlock
);
}
else
{
cache
=
cipher
.
doFinal
(
data
,
offSet
,
inputLen
-
offSet
);
}
out
.
write
(
cache
,
0
,
cache
.
length
);
i
++;
offSet
=
i
*
maxBlock
;
}
byte
[]
encryptedData
=
out
.
toByteArray
();
out
.
close
();
return
encryptedData
;
}
}
interface-server/src/main/java/com/zq/im/modules/api/vo/MethodVo.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
api
.
vo
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.util.Objects
;
/**
* @author wilmiam
* @since 2022/1/27 12:30
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public
class
MethodVo
{
private
String
name
;
private
String
service
;
private
String
value
;
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
{
return
true
;
}
if
(
o
==
null
||
getClass
()
!=
o
.
getClass
())
{
return
false
;
}
MethodVo
methodVo
=
(
MethodVo
)
o
;
return
Objects
.
equals
(
value
,
methodVo
.
value
);
}
@Override
public
int
hashCode
()
{
return
Objects
.
hash
(
value
);
}
}
interface-server/src/main/java/com/zq/im/modules/im/controller/ImgProcController.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
im
.
controller
;
import
com.zq.im.modules.im.req.ImageReq
;
import
com.zq.im.modules.im.service.ImgProcService
;
import
com.zq.im.modules.system.vo.ResultVo
;
import
com.zq.im.utils.AssertUtils
;
import
io.swagger.annotations.Api
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RequestBody
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
/**
* <p>
* 图片处理相关接口
* </p>
*
* @author chenhao
* @since 2022/10/27 17:55
*/
@Slf4j
@RestController
@RequestMapping
(
"/interface/api/imgproc"
)
@RequiredArgsConstructor
@Api
(
tags
=
"图片处理相关接口"
)
public
class
ImgProcController
{
private
final
ImgProcService
service
;
@PostMapping
(
value
=
"/detection"
)
public
ResultVo
<?>
detection
(
@RequestBody
ImageReq
req
)
{
AssertUtils
.
hasText
(
req
.
getFileContent
(),
"缺少文件内容"
);
AssertUtils
.
hasText
(
req
.
getFileName
(),
"缺少文件名"
);
return
ResultVo
.
success
(
service
.
detection
(
req
));
}
}
interface-server/src/main/java/com/zq/im/modules/im/feign/ImgprocFeign.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
im
.
feign
;
import
com.zq.im.modules.im.req.ImageReq
;
import
com.zq.im.modules.im.vo.DetectionResVo
;
import
com.zq.im.modules.system.vo.ResultVo
;
import
org.springframework.cloud.openfeign.FeignClient
;
import
org.springframework.web.bind.annotation.PostMapping
;
/**
* @author chenhao
* @since 2022/4/24 10:26
*/
@FeignClient
(
name
=
"IMGPROC-SERVER"
,
path
=
"/imgproc/v1"
)
public
interface
ImgprocFeign
{
/**
* 图片质量检测接口
*/
@PostMapping
(
value
=
"/detection"
)
ResultVo
<
DetectionResVo
>
detection
(
ImageReq
req
);
}
interface-server/src/main/java/com/zq/im/modules/im/req/ImageReq.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
im
.
req
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
/**
* <p>
* 图片请求类
* </p>
*
* @author chenhao
* @since 2023/11/9
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
ImageReq
{
/**
* 图片名称
*/
String
fileName
;
/**
* 图片的Base64字符串
*/
String
fileContent
;
}
interface-server/src/main/java/com/zq/im/modules/im/service/ImgProcService.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
im
.
service
;
import
com.zq.im.modules.im.feign.ImgprocFeign
;
import
com.zq.im.modules.im.req.ImageReq
;
import
com.zq.im.modules.im.vo.DetectionResVo
;
import
com.zq.im.modules.system.vo.ResultVo
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
/**
* <p>
* 图片处理Service
* </p>
*
* @author chenhao
* @since 2022/10/27 17:56
*/
@Slf4j
@Service
@RequiredArgsConstructor
public
class
ImgProcService
{
@Autowired
ImgprocFeign
feign
;
public
ResultVo
<?>
detection
(
ImageReq
req
)
{
ResultVo
<
DetectionResVo
>
resultVo
=
feign
.
detection
(
req
);
if
(!
resultVo
.
isSuccess
())
{
return
ResultVo
.
fail
(
resultVo
.
getErrMsg
());
}
return
resultVo
;
}
}
interface-server/src/main/java/com/zq/im/modules/im/vo/DetectionResVo.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
im
.
vo
;
import
io.swagger.annotations.ApiModelProperty
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
/**
* <p>
*
* </p>
*
* @author yww
* @since 2023/4/21
*/
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public
class
DetectionResVo
{
@ApiModelProperty
(
"文件名称"
)
private
String
fileName
;
@ApiModelProperty
(
"图片大小"
)
private
Double
size
;
@ApiModelProperty
(
"水平分辨率"
)
private
Integer
widthResolution
;
@ApiModelProperty
(
"垂直分辨率"
)
private
Integer
heightResolution
;
@ApiModelProperty
(
"DPI"
)
private
Integer
dpi
;
@ApiModelProperty
(
"图片清晰度"
)
private
Double
clarity
;
@ApiModelProperty
(
"图片弯曲置信度"
)
private
Double
bend
;
@ApiModelProperty
(
"图片亮度值"
)
private
Integer
brightness
;
@ApiModelProperty
(
"图片偏离角度"
)
private
Integer
deskewAngel
;
@ApiModelProperty
(
"图片黑边数量"
)
private
Integer
black
;
}
interface-server/src/main/java/com/zq/im/modules/system/dao/ApiUserInfoDao.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
system
.
dao
;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
import
com.zq.im.modules.system.entity.ApiUserInfo
;
import
org.springframework.stereotype.Repository
;
/**
* 第三方接口调用用户信息(ApiUserInfo)表数据库访问层
*
* @author makejava
* @since 2021-12-09 17:20:44
*/
@Repository
public
interface
ApiUserInfoDao
extends
BaseMapper
<
ApiUserInfo
>
{
}
interface-server/src/main/java/com/zq/im/modules/system/dao/OpenApiLogDao.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
system
.
dao
;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
import
com.zq.im.modules.system.entity.OpenApiLog
;
import
org.springframework.stereotype.Repository
;
/**
* 开放接口日志Dao层
*
* @author chenhao
*/
@Repository
public
interface
OpenApiLogDao
extends
BaseMapper
<
OpenApiLog
>
{
}
interface-server/src/main/java/com/zq/im/modules/system/entity/ApiUserInfo.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
system
.
entity
;
import
com.baomidou.mybatisplus.annotation.IdType
;
import
com.baomidou.mybatisplus.annotation.TableId
;
import
com.baomidou.mybatisplus.annotation.TableName
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.util.Date
;
/**
* 第三方接口调用用户信息(ApiUserInfo)实体类
*
* @author makejava
* @since 2021-12-09 17:20:44
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@TableName
(
value
=
"api_user_info"
)
public
class
ApiUserInfo
{
/**
* 主键
*/
@TableId
(
type
=
IdType
.
ASSIGN_UUID
)
private
String
id
;
/**
* APP_ID
*/
private
String
appId
;
/**
* APP_SECRET
*/
private
String
appSecret
;
/**
* 申请人
*/
private
String
applyer
;
/**
* 状态
*/
private
Integer
state
;
/**
* 创建时间
*/
private
Date
createTime
;
/**
* 更新时间
*/
private
Date
updateTime
;
}
interface-server/src/main/java/com/zq/im/modules/system/entity/OpenApiLog.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
system
.
entity
;
import
com.baomidou.mybatisplus.annotation.IdType
;
import
com.baomidou.mybatisplus.annotation.TableId
;
import
com.baomidou.mybatisplus.annotation.TableName
;
import
io.swagger.annotations.ApiModelProperty
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
/**
*
* 开放接口日志实体类
*
* @author chenhao
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@TableName
(
value
=
"open_api_log"
)
public
class
OpenApiLog
{
/**
* ID
*/
@TableId
(
type
=
IdType
.
AUTO
)
@ApiModelProperty
(
"ID"
)
private
String
id
;
/**
* APPID
*/
private
String
appId
;
/**
* 申请人名称
*/
private
String
applyer
;
/**
* 调用方法
*/
private
String
method
;
/**
* IP
*/
private
String
serverIp
;
/**
* 版本号
*/
private
String
version
;
/**
* 接口描述
*/
private
String
description
;
/**
* 报错描述
*/
private
String
errMsg
;
/**
* 日志级别
*/
private
String
logType
;
/**
* IP
*/
private
String
clientIp
;
/**
* 耗时-毫秒
*/
private
Long
timeCost
;
/**
* 创建时间
*/
private
String
createTime
;
}
interface-server/src/main/java/com/zq/im/modules/system/service/ApiUserInfoService.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
system
.
service
;
import
cn.hutool.core.date.DateUtil
;
import
cn.hutool.core.util.IdUtil
;
import
cn.hutool.json.JSONUtil
;
import
com.baomidou.mybatisplus.core.toolkit.Wrappers
;
import
com.zq.im.modules.system.dao.ApiUserInfoDao
;
import
com.zq.im.modules.system.entity.ApiUserInfo
;
import
com.zq.im.utils.AssertUtils
;
import
com.zq.im.utils.RedisUtil
;
import
com.zq.im.utils.TokenUtil
;
import
com.zq.im.utils.UuidUtils
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
import
javax.annotation.Resource
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.concurrent.TimeUnit
;
/**
* @author chenhao
*/
@Slf4j
@Service
public
class
ApiUserInfoService
{
@Autowired
ApiUserInfoDao
apiUserInfoDao
;
@Resource
RedisUtil
redisUtil
;
public
static
void
main
(
String
[]
args
)
{
// 创建用户
ApiUserInfo
apiUserInfo
=
new
ApiUserInfo
();
apiUserInfo
.
setId
(
UuidUtils
.
uuidNoDash
());
apiUserInfo
.
setAppId
(
UuidUtils
.
uuidNoDash
());
apiUserInfo
.
setAppSecret
(
UuidUtils
.
uuidNoDash
());
apiUserInfo
.
setApplyer
(
"测试用户"
);
apiUserInfo
.
setState
(
1
);
System
.
out
.
println
(
DateUtil
.
now
());
System
.
out
.
println
(
JSONUtil
.
toJsonStr
(
apiUserInfo
));
}
public
Map
<
String
,
Object
>
getApiToken
(
String
appId
,
String
appSecret
)
{
ApiUserInfo
apiAppInfo
=
apiUserInfoDao
.
selectOne
(
Wrappers
.
lambdaQuery
(
ApiUserInfo
.
builder
().
appId
(
appId
).
appSecret
(
appSecret
).
build
())
);
AssertUtils
.
notNull
(
apiAppInfo
,
"账号或密码错误"
);
AssertUtils
.
isTrue
(
apiAppInfo
.
getState
()
==
1
,
"账号未激活"
);
String
sessionKey
=
IdUtil
.
simpleUUID
();
String
apiToken
=
TokenUtil
.
createToken
(
apiAppInfo
.
getAppId
(),
sessionKey
,
apiAppInfo
.
getApplyer
());
log
.
debug
(
">> [session-key]:{}"
,
sessionKey
);
redisUtil
.
setStr
(
TokenUtil
.
getApiTokenKey
(
apiAppInfo
.
getAppId
()),
apiToken
,
120L
);
Map
<
String
,
Object
>
data
=
new
HashMap
<>();
data
.
put
(
"userId"
,
apiAppInfo
.
getId
());
data
.
put
(
"username"
,
apiAppInfo
.
getApplyer
());
data
.
put
(
"key"
,
sessionKey
);
data
.
put
(
"expireTime"
,
TimeUnit
.
MINUTES
.
toSeconds
(
TokenUtil
.
API_TOKEN_EXPIRE_MINUTES
));
data
.
put
(
"unit"
,
"秒"
);
return
data
;
}
}
interface-server/src/main/java/com/zq/im/modules/system/vo/ResultVo.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
modules
.
system
.
vo
;
import
com.fasterxml.jackson.annotation.JsonIgnoreProperties
;
import
com.fasterxml.jackson.annotation.JsonInclude
;
import
io.swagger.annotations.ApiModel
;
import
io.swagger.annotations.ApiModelProperty
;
import
java.io.Serializable
;
/**
* 统一的接口响应信息
*
* @author wilmiam
* @since 2021-07-09 17:45
*/
@ApiModel
(
"API响应消息"
)
@JsonInclude
(
JsonInclude
.
Include
.
NON_NULL
)
@JsonIgnoreProperties
(
ignoreUnknown
=
true
)
public
class
ResultVo
<
T
>
implements
Serializable
{
@ApiModelProperty
(
value
=
"成功标记"
,
example
=
"true"
)
private
boolean
success
;
@ApiModelProperty
(
"错误码"
)
@JsonInclude
(
JsonInclude
.
Include
.
NON_DEFAULT
)
private
int
errCode
;
@ApiModelProperty
(
"错误信息"
)
private
String
errMsg
;
@ApiModelProperty
(
"响应的数据"
)
private
T
data
;
public
static
ResultVo
success
()
{
return
success
(
null
);
}
public
static
<
E
>
ResultVo
<
E
>
success
(
E
data
)
{
ResultVo
<
E
>
result
=
new
ResultVo
<>();
result
.
setSuccess
(
true
);
result
.
setData
(
data
);
return
result
;
}
public
static
ResultVo
fail
(
String
errMsg
)
{
return
fail
(
500
,
errMsg
);
}
public
static
ResultVo
fail
(
int
errCode
,
String
errMsg
)
{
ResultVo
result
=
new
ResultVo
<>();
result
.
setSuccess
(
false
);
result
.
setErrCode
(
errCode
);
result
.
setErrMsg
(
errMsg
);
return
result
;
}
public
boolean
isSuccess
()
{
return
success
;
}
public
void
setSuccess
(
boolean
success
)
{
this
.
success
=
success
;
}
public
int
getErrCode
()
{
return
errCode
;
}
public
void
setErrCode
(
int
errCode
)
{
this
.
errCode
=
errCode
;
}
public
String
getErrMsg
()
{
return
errMsg
;
}
public
void
setErrMsg
(
String
errMsg
)
{
this
.
errMsg
=
errMsg
;
}
public
T
getData
()
{
return
data
;
}
public
void
setData
(
T
data
)
{
this
.
data
=
data
;
}
}
interface-server/src/main/java/com/zq/im/utils/AssertUtils.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
utils
;
import
cn.hutool.core.util.StrUtil
;
import
com.zq.im.exception.BusinessException
;
import
java.util.Arrays
;
import
java.util.Collection
;
import
java.util.Map
;
/**
* 断言验证帮助类
*
* @author wilmiam
* @since 2018-04-03
*/
@SuppressWarnings
(
"all"
)
public
final
class
AssertUtils
{
private
static
final
String
[]
IMG_EXTS
=
{
"png"
,
"jpg"
,
"jpeg"
};
/**
* Don't let anyone instantiate this class
*/
private
AssertUtils
()
{
}
/**
* 判断给定的文件名后缀是否为图片
*
* @param ext 文件名后缀, 不带点
* @param errMsg 错误信息
*/
public
static
void
isImgExt
(
String
ext
,
String
errMsg
)
{
isImgExt
(
ext
,
400
,
errMsg
);
}
/**
* 判断给定的文件名后缀是否为图片
*
* @param ext 文件名后缀, 不带点
* @param errCode 断言失败的错误代码
* @param errMsg 错误信息
*/
public
static
void
isImgExt
(
String
ext
,
int
errCode
,
String
errMsg
)
{
if
(
StrUtil
.
isBlank
(
ext
)
||
Arrays
.
stream
(
IMG_EXTS
).
noneMatch
(
img
->
img
.
equalsIgnoreCase
(
ext
)))
{
throw
new
BusinessException
(
errCode
,
errMsg
);
}
}
/**
* UnifiedExceptionHandler
* 判断一个布尔表达式, 若表达式为{@code true}则抛出指定错误信息的{@code BusinessException}.
*
* @param expression 布尔表达式
* @param message 断言失败时的错误信息
* @throws BusinessException
*/
public
static
void
notTrue
(
boolean
expression
,
String
message
)
throws
BusinessException
{
notTrue
(
expression
,
400
,
message
);
}
/**
* 判断一个布尔表达式, 若表达式为{@code true}则抛出指定错误信息的{@code BusinessException}.
*
* @param expression 布尔表达式
* @param errCode 断言失败时的错误代码
* @param message 断言失败时的错误信息
* @throws BusinessException
*/
public
static
void
notTrue
(
boolean
expression
,
int
errCode
,
String
message
)
throws
BusinessException
{
if
(
expression
)
{
throw
new
BusinessException
(
errCode
,
message
);
}
}
/**
* 判断一个布尔表达式, 若表达式为{@code false}则抛出指定错误信息的{@code BusinessException}.
*
* @param expression 布尔表达式
* @param message 断言失败时的错误信息
* @throws BusinessException
*/
public
static
void
isTrue
(
boolean
expression
,
String
message
)
throws
BusinessException
{
isTrue
(
expression
,
400
,
message
);
}
/**
* 判断一个布尔表达式, 若表达式为{@code false}则抛出指定错误信息的{@code BusinessException}.
*
* @param expression 布尔表达式
* @param errCode 断言失败时的错误代码
* @param message 断言失败时的错误信息
* @throws BusinessException
*/
public
static
void
isTrue
(
boolean
expression
,
int
errCode
,
String
message
)
throws
BusinessException
{
if
(!
expression
)
{
throw
new
BusinessException
(
errCode
,
message
);
}
}
/**
* 如果对象为{@code null}, 则抛出异常
*
* @param object 要判断的对象
* @throws BusinessException
*/
public
static
void
notNull
(
Object
object
)
throws
BusinessException
{
notNull
(
object
,
"不能处理空对象"
);
}
/**
* 如果对象为{@code null}, 则抛出异常
*
* @param object 要判断的对象
* @param message 断言失败时的错误信息
* @throws BusinessException
*/
public
static
void
notNull
(
Object
object
,
String
message
)
throws
BusinessException
{
notNull
(
object
,
400
,
message
);
}
/**
* 如果对象为{@code null}, 则抛出异常
*
* @param object 要判断的对象
* @param errCode 断言失败时的错误代码
* @param errMsg 断言失败时的错误信息
* @throws BusinessException
*/
public
static
void
notNull
(
Object
object
,
int
errCode
,
String
errMsg
)
throws
BusinessException
{
if
(
object
==
null
)
{
throw
new
BusinessException
(
errCode
,
errMsg
);
}
}
/**
* 如果字符串为{@code null}、空字符串或仅包含空白字符, 则抛出异常
*
* @param text 要进行检查的字符串
* @throws BusinessException
*/
public
static
void
hasText
(
String
text
)
throws
BusinessException
{
hasText
(
text
,
400
,
"参数不能为空字符串"
);
}
/**
* 如果字符串为{@code null}、空字符串或仅包含空白字符, 则抛出异常
*
* @param text 要进行检查的字符串
* @param message 断言失败时的错误信息
* @throws BusinessException
*/
public
static
void
hasText
(
String
text
,
String
message
)
throws
BusinessException
{
hasText
(
text
,
400
,
message
);
}
/**
* 如果字符串为{@code null}、空字符串或仅包含空白字符, 则抛出异常
*
* @param text 要进行检查的字符串
* @param errCode 断言失败时的错误代码
* @param errMsg 错误信息
* @throws BusinessException
*/
public
static
void
hasText
(
String
text
,
int
errCode
,
String
errMsg
)
throws
BusinessException
{
if
(
StrUtil
.
isBlank
(
text
))
{
throw
new
BusinessException
(
errCode
,
errMsg
);
}
}
/**
* 如果数组为{@code null}或长度为0, 则抛出异常
*
* @param array 要进行检查的数组
* @param message 断言失败时的错误信息
* @param <T> 数组的数据类型
* @throws BusinessException
*/
public
static
<
T
>
void
notEmpty
(
T
[]
array
,
String
message
)
throws
BusinessException
{
notEmpty
(
array
,
400
,
message
);
}
/**
* 如果数组为{@code null}或长度为0, 则抛出异常
*
* @param array 要进行检查的数组
* @param errCode 断言失败时的错误代码
* @param errMsg 错误信息
* @param <T> 数组的数据类型
* @throws BusinessException
*/
public
static
<
T
>
void
notEmpty
(
T
[]
array
,
int
errCode
,
String
errMsg
)
throws
BusinessException
{
if
(
array
==
null
||
array
.
length
==
0
)
{
throw
new
BusinessException
(
errCode
,
errMsg
);
}
}
/**
* 如果数组里包含有{@code null}的元素, 则抛出异常. 注意: 若数组本身为{@code null}则不会进行处理, 直接返回
*
* @param array 要进行检查的数组
* @param message 断言失败时的错误信息
* @param <T> 数组的数据类型
* @throws BusinessException
*/
public
static
<
T
>
void
noNullElements
(
T
[]
array
,
String
message
)
throws
BusinessException
{
noNullElements
(
array
,
400
,
message
);
}
/**
* 如果数组里包含有{@code null}的元素, 则抛出异常. 注意: 若数组本身为{@code null}则不会进行处理, 直接返回
*
* @param array 要进行检查的数组
* @param errCode 断言失败时的错误代码
* @param errMsg 错误信息
* @param <T> 数组的数据类型
* @throws BusinessException
*/
public
static
<
T
>
void
noNullElements
(
T
[]
array
,
int
errCode
,
String
errMsg
)
throws
BusinessException
{
if
(
array
!=
null
)
{
for
(
T
element
:
array
)
{
if
(
element
==
null
)
{
throw
new
BusinessException
(
errCode
,
errMsg
);
}
}
}
}
/**
* 如果集合为{@code null},或者不包含任何元素,则抛出异常
*
* @param collection 要进行检查的集合
* @param message 断言失败时的错误信息
* @throws BusinessException
*/
public
static
void
notEmpty
(
Collection
<?>
collection
,
String
message
)
throws
BusinessException
{
notEmpty
(
collection
,
400
,
message
);
}
/**
* 如果集合为{@code null},或者不包含任何元素,则抛出异常
*
* @param collection 要进行检查的集合
* @param errCode 断言失败时的错误代码
* @param errMsg 错误信息
* @throws BusinessException
*/
public
static
void
notEmpty
(
Collection
<?>
collection
,
int
errCode
,
String
errMsg
)
throws
BusinessException
{
if
(
collection
==
null
||
collection
.
isEmpty
())
{
throw
new
BusinessException
(
errCode
,
errMsg
);
}
}
/**
* 如果键值对为{@code null},或者不包含任何键值,则抛出异常
*
* @param map 要进行检查的键值对
* @param message 断言失败时的错误信息
* @throws BusinessException
*/
public
static
void
notEmpty
(
Map
<?,
?>
map
,
String
message
)
throws
BusinessException
{
notEmpty
(
map
,
400
,
message
);
}
/**
* 如果键值对为{@code null},或者不包含任何键值,则抛出异常
*
* @param map 要进行检查的键值对
* @param errCode 断言失败时的错误代码
* @param errMsg 错误信息
* @throws BusinessException
*/
public
static
void
notEmpty
(
Map
<?,
?>
map
,
int
errCode
,
String
errMsg
)
throws
BusinessException
{
if
(
map
==
null
||
map
.
isEmpty
())
{
throw
new
BusinessException
(
errCode
,
errMsg
);
}
}
}
interface-server/src/main/java/com/zq/im/utils/IpUtil.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
utils
;
import
cn.hutool.core.util.CharUtil
;
import
cn.hutool.core.util.StrUtil
;
import
cn.hutool.http.useragent.UserAgent
;
import
cn.hutool.http.useragent.UserAgentUtil
;
import
org.springframework.web.context.request.RequestContextHolder
;
import
org.springframework.web.context.request.ServletRequestAttributes
;
import
javax.servlet.http.HttpServletRequest
;
import
java.util.Objects
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
/**
* <p>
* IP相关工具类
* </p>
*
* @author chenhao
* @since 2022/10/12 20:57
*/
public
class
IpUtil
{
public
static
long
getLongIpAddr
(
HttpServletRequest
request
)
{
String
ip
=
getIpAddr
(
request
);
return
ipv4ToLong
(
ip
);
}
/**
* 获取客户端IP
*
* @return IP
*/
public
static
String
getIpAddr
()
{
return
getIpAddr
(
getRequest
());
}
/**
* 获取客户端IP
*
* @param request 请求
* @return IP
*/
public
static
String
getIpAddr
(
HttpServletRequest
request
)
{
if
(
request
==
null
)
{
return
"unknown"
;
}
// 判断x-forwarded-for是否有IP
String
ip
=
request
.
getHeader
(
"x-forwarded-for"
);
if
(
isNotUnknown
(
ip
))
{
ip
=
request
.
getHeader
(
"Proxy-Client-IP"
);
}
// 判断Proxy-Client-IP是否有IP
if
(
isNotUnknown
(
ip
))
{
ip
=
request
.
getHeader
(
"X-Forwarded-For"
);
}
// 判断X-Forwarded-For是否有IP
if
(
isNotUnknown
(
ip
))
{
ip
=
request
.
getHeader
(
"WL-Proxy-Client-IP"
);
}
// 判断WL-Proxy-Client-IP是否有IP
if
(
isNotUnknown
(
ip
))
{
ip
=
request
.
getHeader
(
"X-Real-IP"
);
}
// 判断X-Real-IP是否有IP
if
(
isNotUnknown
(
ip
))
{
ip
=
request
.
getRemoteAddr
();
}
// 若是IP最后为0:0:0:0:0:0:0:1,就是本地回环地址,否则第一个非unknown的IP地址就是真实地址
return
"0:0:0:0:0:0:0:1"
.
equals
(
ip
)
?
"127.0.0.1"
:
getMultistageReverseProxyIp
(
ip
);
}
/**
* 从多级反向代理中获得第一个非unknown IP地址
*
* @param ip 获得的IP地址
* @return 第一个非unknown IP地址
*/
@SuppressWarnings
(
"all"
)
private
static
String
getMultistageReverseProxyIp
(
String
ip
)
{
// 多级反向代理检测
if
(
ip
!=
null
&&
ip
.
indexOf
(
","
)
>
0
)
{
final
String
[]
ips
=
ip
.
trim
().
split
(
","
);
for
(
String
subIp
:
ips
)
{
if
(
isNotUnknown
(
subIp
))
{
ip
=
subIp
;
break
;
}
}
}
return
ip
;
}
/**
* 检测给定字符串是否为未知,多用于检测HTTP请求相关
*
* @param checkString 被检测的字符串
* @return 是否未知
*/
private
static
boolean
isNotUnknown
(
String
checkString
)
{
return
StrUtil
.
isNotBlank
(
checkString
)
&&
StrUtil
.
isNotEmpty
(
checkString
)
&&
!
"unknown"
.
equalsIgnoreCase
(
checkString
);
}
/**
* 获取UserAgent信息对象
*
* @param request 请求
* @return UserAgent
*/
public
static
UserAgent
getBrowser
(
HttpServletRequest
request
)
{
return
UserAgentUtil
.
parse
(
request
.
getHeader
(
"User-Agent"
));
}
/**
* 获取当前请求
*
* @return 当前请求
*/
private
static
HttpServletRequest
getRequest
()
{
return
((
ServletRequestAttributes
)
Objects
.
requireNonNull
(
RequestContextHolder
.
getRequestAttributes
())).
getRequest
();
}
/**
* 将ipv4地址转换为long类型
* 等同于MySQL的inet_aton方法
*
* @param ipStr ipv4地址
* @return long类型的ipv地址
*/
public
static
long
ipv4ToLong
(
String
ipStr
)
{
String
regex
=
"^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)$"
;
Pattern
pattern
=
Pattern
.
compile
(
regex
);
Matcher
matcher
=
pattern
.
matcher
(
ipStr
);
if
(
matcher
.
matches
())
{
long
addr
=
0
;
for
(
int
i
=
1
;
i
<=
4
;
i
++)
{
addr
|=
Long
.
parseLong
(
matcher
.
group
(
i
))
<<
8
*
(
4
-
i
);
}
return
addr
;
}
else
{
throw
new
RuntimeException
(
"ipv4地址格式出错!"
);
}
}
/**
* 将long类型的ip转为ipv4字符串
* 等同于MySQL的inet_ntoa方法
*
* @param longIp long类型IP
* @return IPV4字符串
*/
public
static
String
longToIpv4
(
long
longIp
)
{
StringBuilder
sb
=
new
StringBuilder
();
// 直接右移24位
sb
.
append
(
longIp
>>
24
&
0xFF
);
sb
.
append
(
CharUtil
.
DOT
);
// 将高8位置0,然后右移16位
sb
.
append
(
longIp
>>
16
&
0xFF
);
sb
.
append
(
CharUtil
.
DOT
);
sb
.
append
(
longIp
>>
8
&
0xFF
);
sb
.
append
(
CharUtil
.
DOT
);
sb
.
append
(
longIp
&
0xFF
);
return
sb
.
toString
();
}
}
interface-server/src/main/java/com/zq/im/utils/RedisUtil.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
utils
;
import
com.alibaba.fastjson2.JSON
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.data.redis.connection.RedisConnection
;
import
org.springframework.data.redis.connection.RedisConnectionFactory
;
import
org.springframework.data.redis.core.*
;
import
org.springframework.stereotype.Component
;
import
java.util.*
;
import
java.util.concurrent.TimeUnit
;
/**
* <p>
* Redis的工具类
* </p>
*
* @ClassName RedisUtil
* @Author yww
* @Date 2022/10/15 10:40
*/
@Slf4j
@Component
@SuppressWarnings
(
"all"
)
public
class
RedisUtil
{
private
final
StringRedisTemplate
stringRedisTemplate
;
private
final
RedisTemplate
<
String
,
Object
>
redisTemplate
;
@Autowired
public
RedisUtil
(
StringRedisTemplate
stringRedisTemplate
,
RedisTemplate
<
String
,
Object
>
redisTemplate
)
{
this
.
stringRedisTemplate
=
stringRedisTemplate
;
this
.
redisTemplate
=
redisTemplate
;
}
/**
* 普通缓存
*
* @param key 键
*/
public
void
setStr
(
String
key
,
String
value
)
{
stringRedisTemplate
.
opsForValue
().
set
(
key
,
value
);
}
/**
* 普通缓存
*
* @param key 键
*/
public
void
setStr
(
String
key
,
String
value
,
long
time
)
{
stringRedisTemplate
.
opsForValue
().
set
(
key
,
value
,
time
,
TimeUnit
.
MINUTES
);
}
/**
* 普通缓存
*
* @param key 键
*/
public
void
setStr
(
String
key
,
String
value
,
long
time
,
TimeUnit
timeUnit
)
{
stringRedisTemplate
.
opsForValue
().
set
(
key
,
value
,
time
,
timeUnit
);
}
/**
* 普通缓存获取
*
* @param key 键
* @return 值
*/
public
String
getStr
(
String
key
)
{
return
key
==
null
?
null
:
stringRedisTemplate
.
opsForValue
().
get
(
key
);
}
/**
* 普通缓存获取
*
* @param key 键
* @return 值
*/
public
<
T
>
T
getStr
(
String
key
,
Class
<
T
>
clazz
)
{
return
key
==
null
?
null
:
JSON
.
parseObject
(
stringRedisTemplate
.
opsForValue
().
get
(
key
),
clazz
);
}
/**
* 普通缓存删除
*
* @param key 键
*/
public
void
deleteStr
(
String
key
)
{
stringRedisTemplate
.
delete
(
key
);
}
/**
* Object缓存
*
* @param key 键
*/
public
void
setObj
(
String
key
,
Object
value
)
{
redisTemplate
.
opsForValue
().
set
(
key
,
value
);
}
/**
* Object缓存
*
* @param key 键
*/
public
void
setObj
(
String
key
,
Object
value
,
long
time
)
{
redisTemplate
.
opsForValue
().
set
(
key
,
value
,
time
,
TimeUnit
.
MINUTES
);
}
/**
* Object缓存
*
* @param key 键
*/
public
void
setObj
(
String
key
,
Object
value
,
long
time
,
TimeUnit
timeUnit
)
{
redisTemplate
.
opsForValue
().
set
(
key
,
value
,
time
,
timeUnit
);
}
/**
* Object缓存获取
*
* @param key 键
* @return 值
*/
public
Object
getObj
(
String
key
)
{
return
key
==
null
?
null
:
redisTemplate
.
opsForValue
().
get
(
key
);
}
/**
* Object缓存获取
*
* @param key 键
* @return 值
*/
public
<
T
>
T
getObj
(
String
key
,
Class
<
T
>
clazz
)
{
return
key
==
null
?
null
:
(
T
)
redisTemplate
.
opsForValue
().
get
(
key
);
}
/**
* Object缓存删除
*
* @param key 键
*/
public
void
deleteObj
(
String
key
)
{
redisTemplate
.
delete
(
key
);
}
/**
* 查找匹配key
*
* @param pattern key
* @return /
*/
public
List
<
String
>
scan
(
String
pattern
)
{
ScanOptions
options
=
ScanOptions
.
scanOptions
().
match
(
pattern
).
build
();
RedisConnectionFactory
factory
=
redisTemplate
.
getConnectionFactory
();
RedisConnection
rc
=
Objects
.
requireNonNull
(
factory
).
getConnection
();
Cursor
<
byte
[]>
cursor
=
rc
.
scan
(
options
);
List
<
String
>
result
=
new
ArrayList
<>();
while
(
cursor
.
hasNext
())
{
result
.
add
(
new
String
(
cursor
.
next
()));
}
try
{
RedisConnectionUtils
.
releaseConnection
(
rc
,
factory
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
return
result
;
}
/**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒)
*/
public
boolean
expire
(
String
key
,
long
time
)
{
try
{
if
(
time
>
0
)
{
redisTemplate
.
expire
(
key
,
time
,
TimeUnit
.
SECONDS
);
}
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
false
;
}
return
true
;
}
/**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒)
* @param timeUnit 单位
*/
public
boolean
expire
(
String
key
,
long
time
,
TimeUnit
timeUnit
)
{
try
{
if
(
time
>
0
)
{
redisTemplate
.
expire
(
key
,
time
,
timeUnit
);
}
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
false
;
}
return
true
;
}
/**
* 根据 key 获取过期时间
*
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public
long
getExpire
(
String
key
)
{
return
redisTemplate
.
getExpire
(
key
,
TimeUnit
.
SECONDS
);
}
/**
* 分页查询 key
*
* @param patternKey key
* @param page 页码
* @param size 每页数目
* @return /
*/
public
List
<
String
>
findKeysForPage
(
String
patternKey
,
int
page
,
int
size
)
{
ScanOptions
options
=
ScanOptions
.
scanOptions
().
match
(
patternKey
).
build
();
RedisConnectionFactory
factory
=
redisTemplate
.
getConnectionFactory
();
RedisConnection
rc
=
Objects
.
requireNonNull
(
factory
).
getConnection
();
Cursor
<
byte
[]>
cursor
=
rc
.
scan
(
options
);
List
<
String
>
result
=
new
ArrayList
<>(
size
);
int
tmpIndex
=
0
;
int
fromIndex
=
page
*
size
;
int
toIndex
=
page
*
size
+
size
;
while
(
cursor
.
hasNext
())
{
if
(
tmpIndex
>=
fromIndex
&&
tmpIndex
<
toIndex
)
{
result
.
add
(
new
String
(
cursor
.
next
()));
tmpIndex
++;
continue
;
}
// 获取到满足条件的数据后,就可以退出了
if
(
tmpIndex
>=
toIndex
)
{
break
;
}
tmpIndex
++;
cursor
.
next
();
}
try
{
RedisConnectionUtils
.
releaseConnection
(
rc
,
factory
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
return
result
;
}
/**
* 判断key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public
boolean
hasKey
(
String
key
)
{
try
{
return
redisTemplate
.
hasKey
(
key
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
false
;
}
}
/**
* 删除缓存
*
* @param keys 可以传一个值 或多个
*/
public
void
del
(
String
...
keys
)
{
if
(
keys
!=
null
&&
keys
.
length
>
0
)
{
if
(
keys
.
length
==
1
)
{
boolean
result
=
redisTemplate
.
delete
(
keys
[
0
]);
log
.
debug
(
"--------------------------------------------"
);
log
.
debug
(
"删除缓存:{},结果:{}"
,
keys
[
0
],
result
);
log
.
debug
(
"--------------------------------------------"
);
}
else
{
Set
<
String
>
keySet
=
new
HashSet
<>();
for
(
String
key
:
keys
)
{
keySet
.
addAll
(
redisTemplate
.
keys
(
key
));
}
long
count
=
redisTemplate
.
delete
(
keySet
);
log
.
debug
(
"--------------------------------------------"
);
log
.
debug
(
"成功删除缓存:{}"
,
keySet
);
log
.
debug
(
"缓存删除数量:{}个"
,
count
);
log
.
debug
(
"--------------------------------------------"
);
}
}
}
// ============================String=============================
/**
* 普通缓存获取
*
* @param key 键
* @return 值
*/
public
Object
get
(
String
key
)
{
return
key
==
null
?
null
:
redisTemplate
.
opsForValue
().
get
(
key
);
}
/**
* 批量获取
*/
public
List
<
Object
>
multiGet
(
List
<
String
>
keys
)
{
return
redisTemplate
.
opsForValue
().
multiGet
(
keys
);
}
/**
* 普通缓存放入
*
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public
boolean
set
(
String
key
,
Object
value
)
{
try
{
redisTemplate
.
opsForValue
().
set
(
key
,
value
);
return
true
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
false
;
}
}
/**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public
boolean
set
(
String
key
,
Object
value
,
long
time
)
{
try
{
if
(
time
>
0
)
{
redisTemplate
.
opsForValue
().
set
(
key
,
value
,
time
,
TimeUnit
.
SECONDS
);
}
else
{
set
(
key
,
value
);
}
return
true
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
false
;
}
}
/**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值
* @param time 时间
* @param timeUnit 类型
* @return true成功 false 失败
*/
public
boolean
set
(
String
key
,
Object
value
,
long
time
,
TimeUnit
timeUnit
)
{
try
{
if
(
time
>
0
)
{
redisTemplate
.
opsForValue
().
set
(
key
,
value
,
time
,
timeUnit
);
}
else
{
set
(
key
,
value
);
}
return
true
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
false
;
}
}
// ================================Map=================================
/**
* HashGet
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return 值
*/
public
Object
hget
(
String
key
,
String
item
)
{
return
redisTemplate
.
opsForHash
().
get
(
key
,
item
);
}
/**
* 获取hashKey对应的所有键值
*
* @param key 键
* @return 对应的多个键值
*/
public
Map
<
Object
,
Object
>
hmget
(
String
key
)
{
return
redisTemplate
.
opsForHash
().
entries
(
key
);
}
/**
* HashSet
*
* @param key 键
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public
boolean
hmset
(
String
key
,
Map
<
String
,
Object
>
map
)
{
try
{
redisTemplate
.
opsForHash
().
putAll
(
key
,
map
);
return
true
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
false
;
}
}
/**
* HashSet 并设置时间
*
* @param key 键
* @param map 对应多个键值
* @param time 时间(秒)
* @return true成功 false失败
*/
public
boolean
hmset
(
String
key
,
Map
<
String
,
Object
>
map
,
long
time
)
{
try
{
redisTemplate
.
opsForHash
().
putAll
(
key
,
map
);
if
(
time
>
0
)
{
expire
(
key
,
time
);
}
return
true
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
false
;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @return true 成功 false失败
*/
public
boolean
hset
(
String
key
,
String
item
,
Object
value
)
{
try
{
redisTemplate
.
opsForHash
().
put
(
key
,
item
,
value
);
return
true
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
false
;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public
boolean
hset
(
String
key
,
String
item
,
Object
value
,
long
time
)
{
try
{
redisTemplate
.
opsForHash
().
put
(
key
,
item
,
value
);
if
(
time
>
0
)
{
expire
(
key
,
time
);
}
return
true
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
false
;
}
}
/**
* 删除hash表中的值
*
* @param key 键 不能为null
* @param item 项 可以使多个 不能为null
*/
public
void
hdel
(
String
key
,
Object
...
item
)
{
redisTemplate
.
opsForHash
().
delete
(
key
,
item
);
}
/**
* 判断hash表中是否有该项的值
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return true 存在 false不存在
*/
public
boolean
hHasKey
(
String
key
,
String
item
)
{
return
redisTemplate
.
opsForHash
().
hasKey
(
key
,
item
);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
*
* @param key 键
* @param item 项
* @param by 要增加几(大于0)
*/
public
double
hincr
(
String
key
,
String
item
,
double
by
)
{
return
redisTemplate
.
opsForHash
().
increment
(
key
,
item
,
by
);
}
/**
* hash递减
*
* @param key 键
* @param item 项
* @param by 要减少记(小于0)
*/
public
double
hdecr
(
String
key
,
String
item
,
double
by
)
{
return
redisTemplate
.
opsForHash
().
increment
(
key
,
item
,
-
by
);
}
// ============================set=============================
/**
* 根据key获取Set中的所有值
*
* @param key 键
*/
public
Set
<
Object
>
sGet
(
String
key
)
{
try
{
return
redisTemplate
.
opsForSet
().
members
(
key
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
null
;
}
}
/**
* 根据value从一个set中查询,是否存在
*
* @param key 键
* @param value 值
* @return true 存在 false不存在
*/
public
boolean
sHasKey
(
String
key
,
Object
value
)
{
try
{
return
redisTemplate
.
opsForSet
().
isMember
(
key
,
value
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
false
;
}
}
/**
* 将数据放入set缓存
*
* @param key 键
* @param values 值 可以是多个
* @return 成功个数
*/
public
long
sSet
(
String
key
,
Object
...
values
)
{
try
{
return
redisTemplate
.
opsForSet
().
add
(
key
,
values
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
0
;
}
}
/**
* 将set数据放入缓存
*
* @param key 键
* @param time 时间(秒)
* @param values 值 可以是多个
* @return 成功个数
*/
public
long
sSetAndTime
(
String
key
,
long
time
,
Object
...
values
)
{
try
{
Long
count
=
redisTemplate
.
opsForSet
().
add
(
key
,
values
);
if
(
time
>
0
)
{
expire
(
key
,
time
);
}
return
count
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
0
;
}
}
/**
* 获取set缓存的长度
*
* @param key 键
*/
public
long
sGetSetSize
(
String
key
)
{
try
{
return
redisTemplate
.
opsForSet
().
size
(
key
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
0
;
}
}
/**
* 移除值为value的
*
* @param key 键
* @param values 值 可以是多个
* @return 移除的个数
*/
public
long
setRemove
(
String
key
,
Object
...
values
)
{
try
{
Long
count
=
redisTemplate
.
opsForSet
().
remove
(
key
,
values
);
return
count
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
0
;
}
}
// ===============================list=================================
/**
* 获取list缓存的内容
*
* @param key 键
* @param start 开始
* @param end 结束 0 到 -1代表所有值
*/
public
List
<
Object
>
lGet
(
String
key
,
long
start
,
long
end
)
{
try
{
return
redisTemplate
.
opsForList
().
range
(
key
,
start
,
end
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
null
;
}
}
/**
* 获取list缓存的长度
*
* @param key 键
*/
public
long
lGetListSize
(
String
key
)
{
try
{
return
redisTemplate
.
opsForList
().
size
(
key
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
0
;
}
}
/**
* 通过索引 获取list中的值
*
* @param key 键
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
*/
public
Object
lGetIndex
(
String
key
,
long
index
)
{
try
{
return
redisTemplate
.
opsForList
().
index
(
key
,
index
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
null
;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
*/
public
boolean
lSet
(
String
key
,
Object
value
)
{
try
{
redisTemplate
.
opsForList
().
rightPush
(
key
,
value
);
return
true
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
false
;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
*/
public
boolean
lSet
(
String
key
,
Object
value
,
long
time
)
{
try
{
redisTemplate
.
opsForList
().
rightPush
(
key
,
value
);
if
(
time
>
0
)
{
expire
(
key
,
time
);
}
return
true
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
false
;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
*/
public
boolean
lSet
(
String
key
,
List
<
Object
>
value
)
{
try
{
redisTemplate
.
opsForList
().
rightPushAll
(
key
,
value
);
return
true
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
false
;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
*/
public
boolean
lSet
(
String
key
,
List
<
Object
>
value
,
long
time
)
{
try
{
redisTemplate
.
opsForList
().
rightPushAll
(
key
,
value
);
if
(
time
>
0
)
{
expire
(
key
,
time
);
}
return
true
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
false
;
}
}
/**
* 根据索引修改list中的某条数据
*
* @param key 键
* @param index 索引
* @param value 值
* @return /
*/
public
boolean
lUpdateIndex
(
String
key
,
long
index
,
Object
value
)
{
try
{
redisTemplate
.
opsForList
().
set
(
key
,
index
,
value
);
return
true
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
false
;
}
}
/**
* 移除N个值为value
*
* @param key 键
* @param count 移除多少个
* @param value 值
* @return 移除的个数
*/
public
long
lRemove
(
String
key
,
long
count
,
Object
value
)
{
try
{
return
redisTemplate
.
opsForList
().
remove
(
key
,
count
,
value
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
0
;
}
}
/**
* @param prefix 前缀
* @param ids id
*/
public
void
delByKeys
(
String
prefix
,
Set
<
Long
>
ids
)
{
Set
<
String
>
keys
=
new
HashSet
<>();
for
(
Long
id
:
ids
)
{
keys
.
addAll
(
redisTemplate
.
keys
(
String
.
valueOf
(
new
StringBuffer
(
prefix
).
append
(
id
))));
}
long
count
=
redisTemplate
.
delete
(
keys
);
// 此处提示可自行删除
log
.
debug
(
"--------------------------------------------"
);
log
.
debug
(
"成功删除缓存:{}"
,
keys
);
log
.
debug
(
"缓存删除数量:{}个"
,
count
);
log
.
debug
(
"--------------------------------------------"
);
}
}
interface-server/src/main/java/com/zq/im/utils/ThreadContextUtil.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
utils
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* <p>
* 基于ThreadLocal的线程相关上下文帮助类, 用于在同一线程下传递变量.
* </p>
*
* @author zq
* @since 2023/11/8
*/
public
class
ThreadContextUtil
{
private
static
ThreadLocal
<
Map
<
String
,
Object
>>
threadLocalMap
=
ThreadLocal
.
withInitial
(
HashMap:
:
new
);
/**
* 根据指定的key获取当前线程相关的变量值
*
* @param key 变量的key
* @param <T> 变量值的具体类型
* @return 若无此key对应的变量值, 则返回{@code null}
* @throws ClassCastException 若接收此返回值的变量类型与上下文保存的值的实际类型不匹配, 则抛出异常
*/
@SuppressWarnings
(
"unchecked"
)
public
static
<
T
>
T
get
(
String
key
)
{
return
(
T
)
threadLocalMap
.
get
().
get
(
key
);
}
/**
* 根据指定的key获取当前线程相关的变量值, 若为{@code null}则返回指定的默认值
*
* @param key 变量的key
* @param defaultValue 默认值
* @param <T> 变量值的具体类型
* @return 若无此key对应的变量值, 则返回defaultValue
* @throws ClassCastException 若接收此返回值的变量类型与上下文保存的值的实际类型不匹配, 则抛出异常
*/
public
static
<
T
>
T
get
(
String
key
,
T
defaultValue
)
{
T
value
=
get
(
key
);
return
value
==
null
?
defaultValue
:
value
;
}
/**
* 设置线程相关上下文的变量值
*
* @param key 变量的key
* @param value 变量值
*/
public
static
void
set
(
String
key
,
Object
value
)
{
threadLocalMap
.
get
().
put
(
key
,
value
);
}
/**
* 删除指定key的变量
*
* @param key 变量的key
*/
public
static
void
remove
(
String
key
)
{
threadLocalMap
.
get
().
remove
(
key
);
}
/**
* 清除当前线程相关的上下文
*/
public
static
void
close
()
{
threadLocalMap
.
remove
();
}
/**
* Don't let anyone instantiate this class
*/
private
void
ThreadContext
()
{
}
}
interface-server/src/main/java/com/zq/im/utils/TokenUtil.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
utils
;
import
cn.hutool.core.date.DateUtil
;
import
cn.hutool.core.util.IdUtil
;
import
com.auth0.jwt.JWT
;
import
com.auth0.jwt.algorithms.Algorithm
;
import
com.auth0.jwt.interfaces.DecodedJWT
;
import
com.auth0.jwt.interfaces.JWTVerifier
;
import
com.zq.im.constant.TokenConstant
;
import
java.util.Date
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* <p>
* Token工具类
* 1. Header,记录令牌类型和签名算法
* 2. payload,携带用户信息
* (1) iss(issuer), 签发者
* (2) sub(subject), 面向的主体
* (3) aud(audience), 接收方
* (4) nbf(notBefore), 开始生效生效时间戳
* (5) exp(expiresAt), 过期时间戳
* (6) iat(issuedAt ), 签发时间
* (7) jti(jwtId), 唯一标识
* 3. signature, 签名,防止Token被篡改
* </p>
*
* @author chenhao
* @since 2022/10/15 14:31
*/
public
class
TokenUtil
{
public
static
final
String
APPID
=
"appId"
;
public
static
final
String
SESSIONKEY
=
"sessionKey"
;
public
static
final
String
APPLYER
=
"applyer"
;
/**
* 过期时长
*/
public
static
final
long
API_TOKEN_EXPIRE_MINUTES
=
120L
;
/**
* 线程变量的键值
*/
private
static
final
String
APP_TOKEN_CONTEXT_KEY
=
"app-token"
;
/**
* 生成Token
* 当前使用HMAC512的加密算法
*
* @return Token
*/
public
static
String
createToken
(
String
appId
,
String
sessionKey
,
String
applyer
)
{
// 设置Token头部(不设置也会默认有这两个值)
Map
<
String
,
Object
>
header
=
new
HashMap
<
String
,
Object
>(
2
)
{
private
static
final
long
serialVersionUID
=
1L
;
{
put
(
"alg"
,
TokenConstant
.
TOKEN_ALG
);
put
(
"typ"
,
TokenConstant
.
TOKEN_TYP
);
}
};
// 设置负载
Map
<
String
,
Object
>
payload
=
new
HashMap
<
String
,
Object
>(
1
)
{
private
static
final
long
serialVersionUID
=
1L
;
{
put
(
APPID
,
appId
);
put
(
SESSIONKEY
,
sessionKey
);
put
(
APPLYER
,
applyer
);
}
};
// 过期时间三小时
long
now
=
DateUtil
.
current
();
long
exp
=
now
+
1000
*
API_TOKEN_EXPIRE_MINUTES
*
60
;
return
JWT
.
create
()
// 设置header
.
withHeader
(
header
)
// 设置payload
.
withIssuer
(
TokenConstant
.
TOKEN_ISSUER
)
.
withSubject
(
TokenConstant
.
TOKEN_SUBJECT
)
.
withAudience
(
TokenConstant
.
TOKEN_AUDIENCE
)
.
withNotBefore
(
new
Date
(
now
))
.
withExpiresAt
(
new
Date
(
exp
))
.
withIssuedAt
(
new
Date
(
now
))
.
withJWTId
(
IdUtil
.
fastSimpleUUID
())
.
withPayload
(
payload
)
// 签名
.
sign
(
Algorithm
.
HMAC512
(
TokenConstant
.
TOKEN_SECRET
));
}
/**
* 解析Token
* 当前使用HMAC512的加密算法
*
* @param token Token
*/
public
static
DecodedJWT
parse
(
String
token
)
{
JWTVerifier
jwtVerifier
=
JWT
.
require
(
Algorithm
.
HMAC512
(
TokenConstant
.
TOKEN_SECRET
)).
build
();
return
jwtVerifier
.
verify
(
token
);
}
/**
* 获取APPID
*
* @param decoded 解析后的Token
* @return appId
*/
public
static
String
getAppid
(
DecodedJWT
decoded
)
{
return
decoded
.
getClaim
(
APPID
).
asString
();
}
/**
* 获取SessionKey
*
* @param decoded 解析后的Token
* @return sessionKey
*/
public
static
String
getSessionkey
(
DecodedJWT
decoded
)
{
return
decoded
.
getClaim
(
SESSIONKEY
).
asString
();
}
/**
* 获取Applyer
*
* @param decoded 解析后的Token
* @return applyer
*/
public
static
String
getApplyer
(
DecodedJWT
decoded
)
{
return
decoded
.
getClaim
(
APPLYER
).
asString
();
}
public
static
String
getApiTokenKey
(
String
tokenKey
)
{
return
TokenConstant
.
TOKEN_PREFIX
+
tokenKey
;
}
public
static
DecodedJWT
getUserContext
()
{
return
ThreadContextUtil
.
get
(
APP_TOKEN_CONTEXT_KEY
);
}
public
static
void
setUserContext
(
DecodedJWT
decodedJWT
)
{
if
(
decodedJWT
!=
null
)
{
ThreadContextUtil
.
set
(
APP_TOKEN_CONTEXT_KEY
,
decodedJWT
);
}
}
public
static
void
main
(
String
[]
args
)
{
// String token = createToken("ec3f54b398e64fbeb9ed00bb0144a91b",
// "4c0d6c2a99e541c8a1affc3c8d8dcddb");
String
token
=
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhcGkiLCJhdWQiOiJhcGkiLCJuYmYiOjE2OTk0OTc1MTIsInNlc3Npb25LZXkiOiI5MjhkMmM0YjE2NTY0YTY3OTkwZjY4ZmE2ZmExZmIxNSIsImlzcyI6IkhXVEoiLCJleHAiOjE2OTk1MDQ3MTIsInVzZXJOYW1lIjoiZWMzZjU0YjM5OGU2NGZiZWI5ZWQwMGJiMDE0NGE5MWIiLCJpYXQiOjE2OTk0OTc1MTIsImp0aSI6ImNmYTBhNzNmYmM0NTRlYmE4NzNlNmY3ODA3ZDE1Y2QyIn0.0ZoVFzZWFYmUEwbymR7M75hbt6RMDlpyWlh9NzmXgwATaPZGsGCFSou5RvjQWa2vKFOOdUV065pXX3uyWJ3c0Q"
;
DecodedJWT
decodedJWT
=
parse
(
token
);
setUserContext
(
decodedJWT
);
DecodedJWT
jwt
=
getUserContext
();
System
.
out
.
println
(
jwt
.
getToken
());
System
.
out
.
println
(
getSessionkey
(
decodedJWT
));
}
}
interface-server/src/main/java/com/zq/im/utils/UuidUtils.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
utils
;
import
java.util.UUID
;
/**
* Utility class that handles the uuid stuff.
*
* @author wilmiam
* @since 2021-07-09 18:05
*/
public
class
UuidUtils
{
/**
* Don't let anyone instantiate this class
*/
private
UuidUtils
()
{
}
/**
* 返回一个随机的带有分隔符"-"的36位UUID字符串
*/
public
static
String
uuid
()
{
return
UUID
.
randomUUID
().
toString
();
}
/**
* 返回一个随机的没有分隔符"-"的32位UUID字符串
*/
public
static
String
uuidNoDash
()
{
return
uuid
().
replaceAll
(
"-"
,
""
);
}
}
interface-server/src/main/java/com/zq/im/utils/V1Demo.java
0 → 100644
View file @
627e5035
package
com
.
zq
.
im
.
utils
;
import
cn.hutool.core.codec.Base64
;
import
cn.hutool.core.convert.Convert
;
import
cn.hutool.core.date.DatePattern
;
import
cn.hutool.core.date.DateUtil
;
import
cn.hutool.core.io.FileUtil
;
import
cn.hutool.core.net.url.UrlQuery
;
import
cn.hutool.core.util.ArrayUtil
;
import
cn.hutool.core.util.IdUtil
;
import
cn.hutool.core.util.URLUtil
;
import
cn.hutool.crypto.SecureUtil
;
import
cn.hutool.http.HttpRequest
;
import
cn.hutool.http.HttpResponse
;
import
cn.hutool.json.JSONObject
;
import
cn.hutool.json.JSONUtil
;
import
com.zq.im.modules.im.vo.DetectionResVo
;
import
lombok.Data
;
import
java.io.File
;
import
java.io.InputStream
;
import
java.util.Date
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.TreeMap
;
/**
* 使用的请求工具为hutool
* <dependency>
* <groupId>cn.hutool</groupId>
* <artifactId>hutool-all</artifactId>
* <version>${hutool.version}</version>
* </dependency>
*
* @author wilmiam
* @since 2021/12/13 9:21
*/
public
class
V1Demo
{
private
static
final
Map
<
String
,
ApiInfo
>
API_INFO_MAP
=
new
HashMap
<>();
private
static
final
String
APP_ID
=
"ec3f54b398e64fbeb9ed00bb0144a91b"
;
private
static
final
String
APP_SECRET
=
"4c0d6c2a99e541c8a1affc3c8d8dcddb"
;
private
static
final
String
URL
=
"http://127.0.0.1:9900/api/v1/action"
;
public
static
ApiInfo
getApiInfo
()
{
ApiInfo
apiInfo
=
API_INFO_MAP
.
get
(
APP_ID
);
if
(
apiInfo
!=
null
&&
(
apiInfo
.
getDueTime
().
getTime
()
-
3000
)
>
System
.
currentTimeMillis
())
{
return
apiInfo
;
}
Map
<
String
,
Object
>
bizContentMap
=
new
HashMap
<>();
bizContentMap
.
put
(
"appId"
,
APP_ID
);
bizContentMap
.
put
(
"appSecret"
,
APP_SECRET
);
String
apiNo
=
IdUtil
.
simpleUUID
();
String
timestamp
=
DateUtil
.
format
(
DateUtil
.
date
(),
DatePattern
.
PURE_DATETIME_PATTERN
);
//JSON字符串
String
bizContent
=
JSONUtil
.
toJsonStr
(
bizContentMap
);
Map
<
String
,
Object
>
params
=
new
HashMap
<>(
6
);
params
.
put
(
"appId"
,
APP_ID
);
params
.
put
(
"apiNo"
,
apiNo
);
params
.
put
(
"method"
,
"getApiToken"
);
params
.
put
(
"timestamp"
,
timestamp
);
params
.
put
(
"bizContent"
,
URLUtil
.
encode
(
Base64
.
encode
(
bizContent
)));
HttpRequest
request
=
HttpRequest
.
post
(
URL
)
.
contentType
(
"application/x-www-form-urlencoded"
)
.
form
(
params
);
System
.
out
.
println
(
"请求报文 => "
+
UrlQuery
.
of
(
params
));
HttpResponse
execute
=
request
.
execute
();
String
body
=
execute
.
body
();
System
.
out
.
println
(
"响应报文 => "
+
body
);
int
status
=
execute
.
getStatus
();
if
(
status
==
200
)
{
JSONObject
obj
=
JSONUtil
.
parseObj
(
body
);
Integer
code
=
obj
.
getInt
(
"code"
);
if
(
code
==
200
)
{
JSONObject
data
=
obj
.
getJSONObject
(
"data"
);
apiInfo
=
data
.
toBean
(
ApiInfo
.
class
);
apiInfo
.
setDueTime
(
new
Date
(
System
.
currentTimeMillis
()
+
(
data
.
getInt
(
"expireTime"
)
*
1000
)));
API_INFO_MAP
.
put
(
APP_ID
,
apiInfo
);
}
}
return
apiInfo
;
}
public
static
Object
doPost
(
String
method
,
Map
<
String
,
Object
>
bizContentMap
,
String
sessionKey
)
{
return
doPost
(
method
,
bizContentMap
,
sessionKey
,
null
,
null
);
}
public
static
Object
doPost
(
String
method
,
Map
<
String
,
Object
>
bizContentMap
,
String
sessionKey
,
File
file
,
File
[]
fileList
)
{
String
apiNo
=
IdUtil
.
simpleUUID
();
String
timestamp
=
DateUtil
.
format
(
DateUtil
.
date
(),
DatePattern
.
PURE_DATETIME_PATTERN
);
//JSON字符串
String
bizContent
=
bizContentMap
==
null
?
""
:
JSONUtil
.
toJsonStr
(
bizContentMap
);
Map
<
String
,
Object
>
params
=
new
HashMap
<>(
6
);
params
.
put
(
"appId"
,
APP_ID
);
params
.
put
(
"apiNo"
,
apiNo
);
params
.
put
(
"method"
,
method
);
params
.
put
(
"timestamp"
,
timestamp
);
params
.
put
(
"bizContent"
,
URLUtil
.
encode
(
Base64
.
encode
(
bizContent
)));
params
.
put
(
"sign"
,
getSign
(
bizContent
,
method
,
timestamp
,
apiNo
,
sessionKey
,
file
,
fileList
));
params
.
put
(
"file"
,
file
);
params
.
put
(
"fileList"
,
fileList
);
// POST的Content-Type默认是application/x-www-form-urlencoded,有文件则是multipart/form-data
HttpRequest
request
=
HttpRequest
.
post
(
URL
)
.
form
(
params
);
System
.
out
.
println
(
"请求报文 => "
+
UrlQuery
.
of
(
params
));
HttpResponse
execute
=
request
.
execute
();
String
body
=
execute
.
body
();
System
.
out
.
println
(
"响应报文 => "
+
body
);
// 失败 => {"apiNo":"09c1ad82ec0f4b2d80cae0cfb1d7059b","code":"103","msg":"调用方法异常","timestamp":1638176339560,"data":null,"success":false}
// 成功 => {"apiNo":"bc070a7c31ac4b8eb1180b2d82a2096b","code":"200","msg":"成功","timestamp":1638176552353,"data":{"userId":"123","username":"admin@gxfy.com"},"success":true}
int
status
=
execute
.
getStatus
();
if
(
status
==
200
)
{
JSONObject
obj
=
JSONUtil
.
parseObj
(
body
);
Integer
code
=
obj
.
getInt
(
"code"
);
if
(
code
==
200
)
{
return
obj
.
get
(
"data"
);
}
}
return
null
;
}
/**
* 下载文件
*
* @param method
* @param bizContentMap
* @param sessionKey
* @return
*/
public
static
InputStream
download
(
String
method
,
Map
<
String
,
Object
>
bizContentMap
,
String
sessionKey
)
{
String
apiNo
=
IdUtil
.
simpleUUID
();
String
timestamp
=
DateUtil
.
format
(
DateUtil
.
date
(),
DatePattern
.
PURE_DATETIME_PATTERN
);
//JSON字符串
String
bizContent
=
bizContentMap
==
null
?
""
:
JSONUtil
.
toJsonStr
(
bizContentMap
);
Map
<
String
,
Object
>
params
=
new
HashMap
<>(
6
);
params
.
put
(
"appId"
,
APP_ID
);
params
.
put
(
"apiNo"
,
apiNo
);
params
.
put
(
"method"
,
method
);
params
.
put
(
"timestamp"
,
timestamp
);
params
.
put
(
"bizContent"
,
URLUtil
.
encode
(
Base64
.
encode
(
bizContent
)));
params
.
put
(
"sign"
,
getSign
(
bizContent
,
method
,
timestamp
,
apiNo
,
sessionKey
,
null
,
null
));
// POST的Content-Type默认是application/x-www-form-urlencoded,有文件则是multipart/form-data
HttpRequest
request
=
HttpRequest
.
post
(
URL
)
.
form
(
params
);
System
.
out
.
println
(
"请求报文 => "
+
UrlQuery
.
of
(
params
));
HttpResponse
execute
=
request
.
execute
();
if
(!
execute
.
isOk
())
{
String
body
=
execute
.
body
();
System
.
out
.
println
(
"响应报文 => "
+
body
);
return
null
;
}
return
execute
.
bodyStream
();
}
/**
* 获取签名
*
* @param bizContent
* @param method
* @param timestamp
* @param apiNo
* @param sessionKey
* @return
*/
public
static
String
getSign
(
String
bizContent
,
String
method
,
String
timestamp
,
String
apiNo
,
String
sessionKey
,
File
file
,
File
[]
fileList
)
{
// 参与签名的参数排序
TreeMap
<
String
,
String
>
signTreeMap
=
new
TreeMap
<>();
signTreeMap
.
put
(
"apiNo"
,
apiNo
);
signTreeMap
.
put
(
"timestamp"
,
timestamp
);
signTreeMap
.
put
(
"method"
,
method
);
signTreeMap
.
put
(
"bizContent"
,
bizContent
);
if
(
file
!=
null
)
{
signTreeMap
.
put
(
"fileMd5"
,
SecureUtil
.
md5
(
file
));
}
if
(
ArrayUtil
.
isNotEmpty
(
fileList
))
{
StringBuilder
md5
=
new
StringBuilder
();
for
(
File
f
:
fileList
)
{
md5
.
append
(
SecureUtil
.
md5
(
f
));
}
signTreeMap
.
put
(
"fileMd5"
,
md5
.
toString
());
}
// 拼接签名参数
StringBuilder
src
=
new
StringBuilder
();
for
(
Map
.
Entry
<
String
,
String
>
entry
:
signTreeMap
.
entrySet
())
{
src
.
append
(
entry
.
getKey
()).
append
(
"="
).
append
(
entry
.
getValue
()).
append
(
"&"
);
}
src
.
append
(
"key="
).
append
(
sessionKey
);
return
SecureUtil
.
md5
(
src
.
toString
());
}
public
static
void
main
(
String
[]
args
)
{
// 这两个值可以存起来,不需每次都获取
ApiInfo
apiInfo
=
getApiInfo
();
String
sessionKey
=
apiInfo
.
getKey
();
System
.
out
.
println
(
sessionKey
);
// String sessionKey = "860a013f4e7344bca5869b361a186648";
Map
<
String
,
Object
>
params
=
new
HashMap
<>(
2
);
params
.
put
(
"filename"
,
"6.png"
);
params
.
put
(
"fileContent"
,
Base64
.
encode
(
FileUtil
.
file
(
"C:\\Users\\11419\\Desktop\\test\\bend1.jpg"
)));
Object
o
=
doPost
(
"detection"
,
params
,
sessionKey
);
DetectionResVo
convert
=
Convert
.
convert
(
DetectionResVo
.
class
,
o
);
System
.
out
.
println
(
JSONUtil
.
toJsonStr
(
convert
));
}
@Data
public
static
class
ApiInfo
{
private
String
userId
;
private
String
username
;
private
String
key
;
private
String
expireTime
;
private
String
unit
;
private
Date
dueTime
;
}
}
interface-server/src/main/resources/application.yml
0 → 100644
View file @
627e5035
server
:
port
:
9900
tomcat
:
max-http-form-post-size
:
-1
#配置数据源
spring
:
application
:
name
:
INTERFACE-SERVER
servlet
:
#上传文件限制
multipart
:
#单个文件大小
max-file-size
:
20MB
#设置总上传的数据大小
max-request-size
:
100MB
mvc
:
hiddenmethod
:
filter
:
enabled
:
true
#启用Servlet的Filter过滤器,需要的地方HttpServletRequestFilter
jackson
:
date-format
:
yyyy-MM-dd HH:mm:ss
time-zone
:
GMT+8
redis
:
#数据库索引
database
:
7
host
:
${redis.url}
port
:
${redis.port}
password
:
${redis.password}
lettuce
:
pool
:
min-idle
:
10
max-active
:
50
max-idle
:
16
max-wait
:
5000
time-between-eviction-runs
:
1s
datasource
:
druid
:
db-type
:
com.alibaba.druid.pool.DruidDataSource
driver-class-name
:
${db.cloud.driver-class-name}
username
:
${db.cloud.username}
password
:
${db.cloud.password}
url
:
${db.cloud.url.cloud}
initial-size
:
3
# 初始化时建立物理连接的个数
min-idle
:
5
# 最小连接池数量
max-active
:
200
# 最大连接池数量
max-wait
:
5000
# 获取连接时最大等待时间,单位毫秒
time-between-eviction-runs-millis
:
60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
min-evictable-idle-time-millis
:
100000
# 连接保持空闲而不被驱逐的最小时间
max-evictable-idle-time-millis
:
300000
# 连接保持空闲而不被驱逐的最大时间
test-while-idle
:
true
test-on-borrow
:
false
test-on-return
:
false
validation-query
:
select 1
webStatFilter
:
enabled
:
true
#安全配置
stat-view-servlet
:
enabled
:
true
url-pattern
:
/druid/*
reset-enable
:
false
login-username
:
admin
login-password
:
GXfy2021
filter
:
stat
:
enabled
:
true
log-slow-sql
:
true
slow-sql-millis
:
1000
merge-sql
:
true
wall
:
config
:
multi-statement-allow
:
true
# mybatis plus 配置
mybatis-plus
:
global-config
:
db-config
:
select-strategy
:
not_empty
update-strategy
:
not_empty
interface-server/src/main/resources/bootstrap.yml
0 → 100644
View file @
627e5035
spring
:
profiles
:
active
:
@
profiles.active@
cloud
:
config
:
name
:
config
profile
:
${spring.profiles.active}
discovery
:
enabled
:
true
service-id
:
CONFIG-SERVER
username
:
admin
password
:
GXfy2022
eureka
:
instance
:
prefer-ip-address
:
true
lease-renewal-interval-in-seconds
:
2
#向服务端发送心跳间隔
lease-expiration-duration-in-seconds
:
6
#告诉服务端多少秒没收到心跳将我踢出掉
instance-id
:
${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
client
:
registry-fetch-interval-seconds
:
2
#从服务端注册表中获取注册信息的时间间隔
serviceUrl
:
defaultZone
:
@
register.url@
feign
:
client
:
config
:
default
:
connect-timeout
:
2000
#连接超时时间
read-timeout
:
10000
#读超时时间
ribbon
:
# ribbon服务列表刷新间隔(单位ms)
ServerListRefreshInterval
:
2000
interface-server/src/main/resources/logback-spring.xml
0 → 100644
View file @
627e5035
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--<include resource="org/springframework/boot/logging/logback/base.xml"/>-->
<include
resource=
"org/springframework/boot/logging/logback/defaults.xml"
/>
<include
resource=
"org/springframework/boot/logging/logback/console-appender.xml"
/>
<property
name=
"default_log_path"
value=
"logs"
/>
<property
name=
"default_log_file"
value=
"interface"
/>
<!--主要日志文件名-->
<property
name=
"LOG_PATH"
value=
"${LOG_PATH:-${default_log_path}}"
/>
<property
name=
"LOG_FILE"
value=
"${LOG_FILE:-${default_log_file}}"
/>
<!-- the name of the application's logging context -->
<!-- by default each JMXConfigurator instance will be registered under the same name in the same JVM -->
<!-- we need to set the contextName for different apps, so that the jmxconfigurator won't collide -->
<contextName>
user
</contextName>
<jmxConfigurator/>
<!--主要日志配置 开始-->
<appender
name=
"SIZED_ROLLING_FILE"
class=
"ch.qos.logback.core.rolling.RollingFileAppender"
>
<encoder>
<pattern>
%d %-5p [%t] %logger : %m%n
</pattern>
<charset>
UTF-8
</charset>
</encoder>
<file>
${LOG_FILE}.log
</file>
<rollingPolicy
class=
"ch.qos.logback.core.rolling.TimeBasedRollingPolicy"
>
<fileNamePattern>
${LOG_PATH}/${LOG_FILE}.%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class=
"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"
>
<maxFileSize>
50MB
</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!-- 日志文档保留天数 -->
<maxHistory>
15
</maxHistory>
</rollingPolicy>
</appender>
<!-- 异步输出 -->
<appender
name=
"main-logger-appender"
class=
"ch.qos.logback.classic.AsyncAppender"
>
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>
0
</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>
512
</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref
ref=
"SIZED_ROLLING_FILE"
/>
</appender>
<!--主要日志配置 结束-->
<!--DEBUG日志配置 开始-->
<appender
name=
"DEBUG_FILE"
class=
"ch.qos.logback.core.rolling.RollingFileAppender"
>
<encoder>
<pattern>
%d %-5p [%t] %logger : %m%n
</pattern>
<charset>
UTF-8
</charset>
</encoder>
<file>
debug.log
</file>
<rollingPolicy
class=
"ch.qos.logback.core.rolling.TimeBasedRollingPolicy"
>
<fileNamePattern>
${LOG_PATH}/debug.%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class=
"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"
>
<maxFileSize>
50MB
</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!-- 日志文档保留天数 -->
<maxHistory>
15
</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录ERROR级别的 -->
<filter
class=
"ch.qos.logback.classic.filter.LevelFilter"
>
<level>
DEBUG
</level>
<onMatch>
ACCEPT
</onMatch>
<onMismatch>
DENY
</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender
name=
"debug-appender"
class=
"ch.qos.logback.classic.AsyncAppender"
>
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>
0
</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>
512
</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref
ref=
"DEBUG_FILE"
/>
</appender>
<!--DEBUG日志配置 结束-->
<!--INFO日志配置 开始-->
<appender
name=
"INFO_FILE"
class=
"ch.qos.logback.core.rolling.RollingFileAppender"
>
<encoder>
<pattern>
%d %-5p [%t] %logger : %m%n
</pattern>
<charset>
UTF-8
</charset>
</encoder>
<file>
info.log
</file>
<rollingPolicy
class=
"ch.qos.logback.core.rolling.TimeBasedRollingPolicy"
>
<fileNamePattern>
${LOG_PATH}/info.%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class=
"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"
>
<maxFileSize>
50MB
</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!-- 日志文档保留天数 -->
<maxHistory>
15
</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录ERROR级别的 -->
<filter
class=
"ch.qos.logback.classic.filter.LevelFilter"
>
<level>
INFO
</level>
<onMatch>
ACCEPT
</onMatch>
<onMismatch>
DENY
</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender
name=
"info-appender"
class=
"ch.qos.logback.classic.AsyncAppender"
>
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>
0
</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>
512
</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref
ref=
"INFO_FILE"
/>
</appender>
<!--INFO日志配置 结束-->
<!--WARN日志配置 开始-->
<appender
name=
"WARN_FILE"
class=
"ch.qos.logback.core.rolling.RollingFileAppender"
>
<encoder>
<pattern>
%d %-5p [%t] %logger : %m%n
</pattern>
<charset>
UTF-8
</charset>
</encoder>
<file>
warn.log
</file>
<rollingPolicy
class=
"ch.qos.logback.core.rolling.TimeBasedRollingPolicy"
>
<fileNamePattern>
${LOG_PATH}/warn.%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class=
"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"
>
<maxFileSize>
50MB
</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!-- 日志文档保留天数 -->
<maxHistory>
15
</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录ERROR级别的 -->
<filter
class=
"ch.qos.logback.classic.filter.LevelFilter"
>
<level>
WARN
</level>
<onMatch>
ACCEPT
</onMatch>
<onMismatch>
DENY
</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender
name=
"warn-appender"
class=
"ch.qos.logback.classic.AsyncAppender"
>
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>
0
</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>
512
</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref
ref=
"WARN_FILE"
/>
</appender>
<!--WARN日志配置 结束-->
<!--ERROR错误日志配置 开始-->
<appender
name=
"ERROR_FILE"
class=
"ch.qos.logback.core.rolling.RollingFileAppender"
>
<!-- 正在记录的日志文件的路径及文件名 -->
<file>
error.log
</file>
<!--日志文件输出格式-->
<encoder>
<pattern>
%d %-5p [%t] %logger : %m%n
</pattern>
<charset>
UTF-8
</charset>
<!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy
class=
"ch.qos.logback.core.rolling.TimeBasedRollingPolicy"
>
<fileNamePattern>
${LOG_PATH}/error.%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class=
"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"
>
<maxFileSize>
50MB
</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>
15
</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录ERROR级别的 -->
<filter
class=
"ch.qos.logback.classic.filter.LevelFilter"
>
<level>
ERROR
</level>
<onMatch>
ACCEPT
</onMatch>
<onMismatch>
DENY
</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender
name=
"error-appender"
class=
"ch.qos.logback.classic.AsyncAppender"
>
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>
0
</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>
512
</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref
ref=
"ERROR_FILE"
/>
</appender>
<!--ERROR错误日志配置 结束-->
<logger
name=
"com.zq.im"
level=
"DEBUG"
/>
<logger
name=
"com.zq.im.dao"
level=
"INFO"
/>
<root
level=
"INFO"
>
<appender-ref
ref=
"CONSOLE"
/>
<appender-ref
ref=
"main-logger-appender"
/>
<appender-ref
ref=
"debug-appender"
/>
<appender-ref
ref=
"info-appender"
/>
<appender-ref
ref=
"warn-appender"
/>
<appender-ref
ref=
"error-appender"
/>
</root>
</configuration>
pom.xml
View file @
627e5035
...
@@ -41,6 +41,7 @@
...
@@ -41,6 +41,7 @@
<module>
admin-server
</module>
<module>
admin-server
</module>
<module>
logging-server
</module>
<module>
logging-server
</module>
<module>
imgproc-server
</module>
<module>
imgproc-server
</module>
<module>
interface-server
</module>
</modules>
</modules>
<dependencies>
<dependencies>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment