Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
custom-server
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
lizhonghong
custom-server
Commits
17729b0b
Commit
17729b0b
authored
Jul 16, 2026
by
pfh
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
定时任务,文件上传,队列转发功能迁移
parent
da5a00ac
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
1967 additions
and
3 deletions
+1967
-3
custom-server-app/src/main/java/com/jomalls/custom/app/handler/SyntheticServerCallbackHandler.java
+26
-0
custom-server-app/src/main/java/com/jomalls/custom/app/handler/xxljob/CustomXxlJob.java
+19
-0
custom-server-app/src/main/java/com/jomalls/custom/app/handler/xxljob/DemoXxlJob.java
+250
-0
custom-server-app/src/main/java/com/jomalls/custom/app/mq/MqTool.java
+98
-0
custom-server-app/src/main/java/com/jomalls/custom/app/utils/IdUtils.java
+89
-0
custom-server-app/src/main/java/com/jomalls/custom/app/utils/Seq.java
+79
-0
custom-server-app/src/main/java/com/jomalls/custom/app/utils/StrFormatter.java
+74
-0
custom-server-app/src/main/java/com/jomalls/custom/app/utils/StringUtils.java
+611
-0
custom-server-app/src/main/java/com/jomalls/custom/app/utils/UUID.java
+438
-0
custom-server-core/pom.xml
+8
-0
custom-server-core/src/main/java/com/jomalls/custom/enums/MqRoute.java
+28
-0
custom-server-integrate/pom.xml
+6
-0
custom-server-integrate/src/main/java/com/jomalls/custom/integrate/configuration/XxlJobConfig.java
+41
-0
custom-server-starter/src/main/java/com/jomalls/custom/CustomServerApplication.java
+2
-1
custom-server-starter/src/main/resources/application-dev.yml
+28
-0
custom-server-starter/src/main/resources/application-prod.yml
+31
-2
custom-server-starter/src/main/resources/application-test.yml
+29
-0
custom-server-starter/src/main/resources/application.yml
+3
-0
custom-server-webapp/pom.xml
+8
-0
custom-server-webapp/src/main/java/com/jomalls/custom/webapp/controller/rest/SyntheticServerCallbackController.java
+28
-0
custom-server-webapp/src/main/java/com/jomalls/custom/webapp/controller/upload/UploadController.java
+52
-0
pom.xml
+19
-0
No files found.
custom-server-app/src/main/java/com/jomalls/custom/app/handler/SyntheticServerCallbackHandler.java
0 → 100644
View file @
17729b0b
package
com
.
jomalls
.
custom
.
app
.
handler
;
import
com.jomalls.custom.app.mq.MqTool
;
import
com.jomalls.custom.enums.MqRoute
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.stereotype.Component
;
import
java.util.HashMap
;
/**
* 合成服务器回调
*/
@Component
public
class
SyntheticServerCallbackHandler
{
@Value
(
"${jomalls.custom.url}"
)
private
String
customUrl
;
public
void
callback
(
String
queryString
)
{
String
url
=
customUrl
+
"/api/diy/userSave/update?"
+
queryString
;
HashMap
<
String
,
Object
>
params
=
new
HashMap
<>();
params
.
put
(
"url"
,
url
);
MqTool
.
getTool
().
sendMsg
(
MqRoute
.
synthesized_image_server_callback
.
getKey
(),
params
);
}
}
custom-server-app/src/main/java/com/jomalls/custom/app/handler/xxljob/CustomXxlJob.java
0 → 100644
View file @
17729b0b
package
com
.
jomalls
.
custom
.
app
.
handler
.
xxljob
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.stereotype.Component
;
@Component
public
class
CustomXxlJob
{
@Value
(
"${jomalls.job.execute}"
)
private
boolean
executeJob
;
private
static
Logger
logger
=
LoggerFactory
.
getLogger
(
CustomXxlJob
.
class
);
}
custom-server-app/src/main/java/com/jomalls/custom/app/handler/xxljob/DemoXxlJob.java
0 → 100644
View file @
17729b0b
package
com
.
jomalls
.
custom
.
app
.
handler
.
xxljob
;
import
com.xxl.job.core.context.XxlJobHelper
;
import
com.xxl.job.core.handler.annotation.XxlJob
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.stereotype.Component
;
import
java.io.BufferedInputStream
;
import
java.io.BufferedReader
;
import
java.io.DataOutputStream
;
import
java.io.InputStreamReader
;
import
java.net.HttpURLConnection
;
import
java.net.URL
;
import
java.util.Arrays
;
import
java.util.concurrent.TimeUnit
;
/**
*
* 开发步骤:
* 1、任务开发:在Spring Bean实例中,开发Job方法;
* 2、注解配置:为Job方法添加注解 "@XxlJob(value="自定义jobhandler名称", init = "JobHandler初始化方法", destroy = "JobHandler销毁方法")",注解value值对应的是调度中心新建任务的JobHandler属性的值。
* 3、执行日志:需要通过 "XxlJobHelper.log" 打印执行日志;
* 4、任务结果:默认任务结果为 "成功" 状态,不需要主动设置;如有诉求,比如设置任务结果为失败,可以通过 "XxlJobHelper.handleFail/handleSuccess" 自主设置任务结果;
*
*/
@Component
public
class
DemoXxlJob
{
private
static
Logger
logger
=
LoggerFactory
.
getLogger
(
DemoXxlJob
.
class
);
/**
* 1、简单任务示例(Bean模式)
*/
@XxlJob
(
"demoJobHandler"
)
public
void
demoJobHandler
()
throws
Exception
{
XxlJobHelper
.
log
(
"XXL-JOB, Hello World."
);
System
.
out
.
println
(
"XXL-JOB, Hello World."
);
for
(
int
i
=
0
;
i
<
5
;
i
++)
{
XxlJobHelper
.
log
(
"beat at:"
+
i
);
TimeUnit
.
SECONDS
.
sleep
(
2
);
}
// default success
}
/**
* 2、分片广播任务
*/
@XxlJob
(
"shardingJobHandler"
)
public
void
shardingJobHandler
()
throws
Exception
{
// 分片参数
int
shardIndex
=
XxlJobHelper
.
getShardIndex
();
int
shardTotal
=
XxlJobHelper
.
getShardTotal
();
XxlJobHelper
.
log
(
"分片参数:当前分片序号 = {}, 总分片数 = {}"
,
shardIndex
,
shardTotal
);
// 业务逻辑
for
(
int
i
=
0
;
i
<
shardTotal
;
i
++)
{
if
(
i
==
shardIndex
)
{
XxlJobHelper
.
log
(
"第 {} 片, 命中分片开始处理"
,
i
);
}
else
{
XxlJobHelper
.
log
(
"第 {} 片, 忽略"
,
i
);
}
}
}
/**
* 3、命令行任务
*/
@XxlJob
(
"commandJobHandler"
)
public
void
commandJobHandler
()
throws
Exception
{
String
command
=
XxlJobHelper
.
getJobParam
();
int
exitValue
=
-
1
;
BufferedReader
bufferedReader
=
null
;
try
{
// command process
ProcessBuilder
processBuilder
=
new
ProcessBuilder
();
processBuilder
.
command
(
command
);
processBuilder
.
redirectErrorStream
(
true
);
Process
process
=
processBuilder
.
start
();
//Process process = Runtime.getRuntime().exec(command);
BufferedInputStream
bufferedInputStream
=
new
BufferedInputStream
(
process
.
getInputStream
());
bufferedReader
=
new
BufferedReader
(
new
InputStreamReader
(
bufferedInputStream
));
// command log
String
line
;
while
((
line
=
bufferedReader
.
readLine
())
!=
null
)
{
XxlJobHelper
.
log
(
line
);
}
// command exit
process
.
waitFor
();
exitValue
=
process
.
exitValue
();
}
catch
(
Exception
e
)
{
XxlJobHelper
.
log
(
e
);
}
finally
{
if
(
bufferedReader
!=
null
)
{
bufferedReader
.
close
();
}
}
if
(
exitValue
==
0
)
{
// default success
}
else
{
XxlJobHelper
.
handleFail
(
"command exit value("
+
exitValue
+
") is failed"
);
}
}
/**
* 4、跨平台Http任务
* 参数示例:
* "url: http://www.baidu.com\n" +
* "method: get\n" +
* "data: content\n";
*/
@XxlJob
(
"httpJobHandler"
)
public
void
httpJobHandler
()
throws
Exception
{
// param parse
String
param
=
XxlJobHelper
.
getJobParam
();
if
(
param
==
null
||
param
.
trim
().
length
()==
0
)
{
XxlJobHelper
.
log
(
"param["
+
param
+
"] invalid."
);
XxlJobHelper
.
handleFail
();
return
;
}
String
[]
httpParams
=
param
.
split
(
"\n"
);
String
url
=
null
;
String
method
=
null
;
String
data
=
null
;
for
(
String
httpParam:
httpParams
)
{
if
(
httpParam
.
startsWith
(
"url:"
))
{
url
=
httpParam
.
substring
(
httpParam
.
indexOf
(
"url:"
)
+
4
).
trim
();
}
if
(
httpParam
.
startsWith
(
"method:"
))
{
method
=
httpParam
.
substring
(
httpParam
.
indexOf
(
"method:"
)
+
7
).
trim
().
toUpperCase
();
}
if
(
httpParam
.
startsWith
(
"data:"
))
{
data
=
httpParam
.
substring
(
httpParam
.
indexOf
(
"data:"
)
+
5
).
trim
();
}
}
// param valid
if
(
url
==
null
||
url
.
trim
().
length
()==
0
)
{
XxlJobHelper
.
log
(
"url["
+
url
+
"] invalid."
);
XxlJobHelper
.
handleFail
();
return
;
}
if
(
method
==
null
||
!
Arrays
.
asList
(
"GET"
,
"POST"
).
contains
(
method
))
{
XxlJobHelper
.
log
(
"method["
+
method
+
"] invalid."
);
XxlJobHelper
.
handleFail
();
return
;
}
boolean
isPostMethod
=
method
.
equals
(
"POST"
);
// request
HttpURLConnection
connection
=
null
;
BufferedReader
bufferedReader
=
null
;
try
{
// connection
URL
realUrl
=
new
URL
(
url
);
connection
=
(
HttpURLConnection
)
realUrl
.
openConnection
();
// connection setting
connection
.
setRequestMethod
(
method
);
connection
.
setDoOutput
(
isPostMethod
);
connection
.
setDoInput
(
true
);
connection
.
setUseCaches
(
false
);
connection
.
setReadTimeout
(
5
*
1000
);
connection
.
setConnectTimeout
(
3
*
1000
);
connection
.
setRequestProperty
(
"connection"
,
"Keep-Alive"
);
connection
.
setRequestProperty
(
"Content-Type"
,
"application/json;charset=UTF-8"
);
connection
.
setRequestProperty
(
"Accept-Charset"
,
"application/json;charset=UTF-8"
);
// do connection
connection
.
connect
();
// data
if
(
isPostMethod
&&
data
!=
null
&&
data
.
trim
().
length
()>
0
)
{
DataOutputStream
dataOutputStream
=
new
DataOutputStream
(
connection
.
getOutputStream
());
dataOutputStream
.
write
(
data
.
getBytes
(
"UTF-8"
));
dataOutputStream
.
flush
();
dataOutputStream
.
close
();
}
// valid StatusCode
int
statusCode
=
connection
.
getResponseCode
();
if
(
statusCode
!=
200
)
{
throw
new
RuntimeException
(
"Http Request StatusCode("
+
statusCode
+
") Invalid."
);
}
// result
bufferedReader
=
new
BufferedReader
(
new
InputStreamReader
(
connection
.
getInputStream
(),
"UTF-8"
));
StringBuilder
result
=
new
StringBuilder
();
String
line
;
while
((
line
=
bufferedReader
.
readLine
())
!=
null
)
{
result
.
append
(
line
);
}
String
responseMsg
=
result
.
toString
();
XxlJobHelper
.
log
(
responseMsg
);
return
;
}
catch
(
Exception
e
)
{
XxlJobHelper
.
log
(
e
);
XxlJobHelper
.
handleFail
();
return
;
}
finally
{
try
{
if
(
bufferedReader
!=
null
)
{
bufferedReader
.
close
();
}
if
(
connection
!=
null
)
{
connection
.
disconnect
();
}
}
catch
(
Exception
e2
)
{
XxlJobHelper
.
log
(
e2
);
}
}
}
/**
* 5、生命周期任务示例:任务初始化与销毁时,支持自定义相关逻辑;
*/
@XxlJob
(
value
=
"demoJobHandler2"
,
init
=
"init"
,
destroy
=
"destroy"
)
public
void
demoJobHandler2
()
throws
Exception
{
XxlJobHelper
.
log
(
"XXL-JOB, Hello World."
);
}
public
void
init
(){
logger
.
info
(
"init"
);
}
public
void
destroy
(){
logger
.
info
(
"destroy"
);
}
}
custom-server-app/src/main/java/com/jomalls/custom/app/mq/MqTool.java
0 → 100644
View file @
17729b0b
package
com
.
jomalls
.
custom
.
app
.
mq
;
import
com.alibaba.fastjson2.JSONObject
;
import
com.jomalls.custom.app.utils.IdUtils
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.amqp.core.*
;
import
org.springframework.amqp.rabbit.core.RabbitAdmin
;
import
org.springframework.amqp.rabbit.core.RabbitTemplate
;
import
java.util.LinkedHashMap
;
import
java.util.List
;
import
java.util.Map
;
@Slf4j
public
final
class
MqTool
{
public
static
final
String
SUFFIX_DIRECT
=
"_direct"
;
public
static
final
String
SUFFIX_QUEUE
=
"_queue0"
;
public
static
final
String
SUFFIX_ROUTE
=
"_route0"
;
public
static
final
String
SUFFIX_BIND
=
"_bind0"
;
public
static
final
String
NAMESPACE
=
"custom"
;
private
static
MqTool
tool
=
null
;
private
final
RabbitTemplate
rabbitTemplate
;
private
MqTool
(
RabbitTemplate
rabbitTemplate
)
{
this
.
rabbitTemplate
=
rabbitTemplate
;
}
public
static
MqTool
getTool
()
{
return
tool
;
}
public
static
synchronized
Map
<
String
,
Object
>
init
(
RabbitTemplate
rabbitTemplate
,
List
<
String
>
list
)
{
if
(
tool
==
null
){
tool
=
new
MqTool
(
rabbitTemplate
);
}
AmqpAdmin
admin
=
new
RabbitAdmin
(
rabbitTemplate
.
getConnectionFactory
());
Map
<
String
,
Object
>
map
=
new
LinkedHashMap
<>();
for
(
String
key
:
list
)
{
String
exchangeKey
=
key
+
SUFFIX_DIRECT
;
String
queueKey
=
key
+
SUFFIX_QUEUE
;
String
routeKey
=
key
+
SUFFIX_ROUTE
;
String
bindKey
=
key
+
SUFFIX_BIND
;
DirectExchange
exchange
=
new
DirectExchange
(
exchangeKey
,
true
,
false
);
Queue
queue
=
new
Queue
(
queueKey
,
true
);
admin
.
declareExchange
(
exchange
);
admin
.
declareQueue
(
queue
);
Binding
bind
=
BindingBuilder
.
bind
(
queue
).
to
(
exchange
).
with
(
routeKey
);
admin
.
declareBinding
(
bind
);
map
.
put
(
exchangeKey
,
exchange
);
map
.
put
(
queueKey
,
queue
);
map
.
put
(
bindKey
,
bind
);
}
return
map
;
}
public
void
sendMsg
(
String
key
,
Map
<
String
,
Object
>
params
)
{
if
(
params
==
null
){
throw
new
RuntimeException
(
"消息发送失败,发送的消息内容不能为空。"
);
}
if
(
StringUtils
.
isEmpty
(
key
))
{
throw
new
RuntimeException
(
"消息发送失败,不能发送消息到空路由。"
);
}
if
(
params
.
containsKey
(
"namespace"
)){
throw
new
RuntimeException
(
"消息发送失败,namespace为系统关键词,请修改后重试。"
);
}
if
(
params
.
containsKey
(
"msgTime"
)){
throw
new
RuntimeException
(
"消息发送失败,msgTime为系统关键词,请修改后重试。"
);
}
if
(
params
.
containsKey
(
"routeKey"
)){
throw
new
RuntimeException
(
"消息发送失败,routeKey为系统关键词,请修改后重试。"
);
}
if
(!
params
.
containsKey
(
"msgId"
)){
params
.
put
(
"msgId"
,
IdUtils
.
simpleUUID
());
//生成msgId消息唯一标识
}
if
(!
params
.
containsKey
(
"requestId"
)){
params
.
put
(
"requestId"
,
params
.
get
(
"msgId"
));
}
params
.
put
(
"namespace"
,
NAMESPACE
);
params
.
put
(
"msgTime"
,
System
.
currentTimeMillis
());
params
.
put
(
"routeKey"
,
key
);
String
message
=
JSONObject
.
toJSONString
(
params
);
String
exchange
=
key
+
SUFFIX_DIRECT
;
String
route
=
key
+
SUFFIX_ROUTE
;
log
.
info
(
"exchange:{} route:{} message:{} requestId:{}"
,
exchange
,
route
,
message
,
params
.
get
(
"msgId"
));
this
.
rabbitTemplate
.
convertAndSend
(
exchange
,
route
,
message
);
}
}
custom-server-app/src/main/java/com/jomalls/custom/app/utils/IdUtils.java
0 → 100644
View file @
17729b0b
package
com
.
jomalls
.
custom
.
app
.
utils
;
import
org.apache.commons.lang3.StringUtils
;
import
java.util.ArrayList
;
import
java.util.List
;
/**
* ID生成器工具类
*/
public
class
IdUtils
{
/**
* 获取随机UUID
*
* @return 随机UUID
*/
public
static
String
randomUUID
()
{
return
UUID
.
randomUUID
().
toString
();
}
/**
* 简化的UUID,去掉了横线
*
* @return 简化的UUID,去掉了横线
*/
public
static
String
simpleUUID
()
{
return
UUID
.
randomUUID
().
toString
(
true
);
}
/**
* 获取随机UUID,使用性能更好的ThreadLocalRandom生成UUID
*
* @return 随机UUID
*/
public
static
String
fastUUID
()
{
return
UUID
.
fastUUID
().
toString
();
}
/**
* 简化的UUID,去掉了横线,使用性能更好的ThreadLocalRandom生成UUID
*
* @return 简化的UUID,去掉了横线
*/
public
static
String
fastSimpleUUID
()
{
return
UUID
.
fastUUID
().
toString
(
true
);
}
/**
* 将字符串的id分隔,转换成Integer数组
*/
public
static
List
<
Integer
>
idsConvertToIntegerList
(
String
ids
){
List
<
Integer
>
idsList
=
new
ArrayList
<>();
if
(
StringUtils
.
isEmpty
(
ids
)){
return
idsList
;
}
String
[]
arr
=
ids
.
split
(
","
);
for
(
String
s
:
arr
)
{
if
(
StringUtils
.
isNotEmpty
(
s
))
{
idsList
.
add
(
Integer
.
parseInt
(
s
.
trim
()));
}
}
return
idsList
;
}
public
static
List
<
String
>
idsConvertToStringList
(
String
ids
)
{
List
<
String
>
res
=
new
ArrayList
<>();
if
(
StringUtils
.
isEmpty
(
ids
)){
return
res
;
}
for
(
String
s
:
ids
.
split
(
","
))
{
res
.
add
(
s
.
trim
());
}
return
res
;
}
public
static
List
<
Long
>
idsConvertToLongList
(
String
ids
){
List
<
Long
>
idsList
=
new
ArrayList
<>();
if
(
StringUtils
.
isEmpty
(
ids
)){
return
idsList
;
}
String
[]
arr
=
ids
.
split
(
","
);
for
(
String
s
:
arr
)
{
idsList
.
add
(
Long
.
parseLong
(
s
.
trim
()));
}
return
idsList
;
}
}
custom-server-app/src/main/java/com/jomalls/custom/app/utils/Seq.java
0 → 100644
View file @
17729b0b
package
com
.
jomalls
.
custom
.
app
.
utils
;
import
java.util.concurrent.atomic.AtomicInteger
;
/**
* 序列生成类
*/
public
class
Seq
{
// 通用序列类型
public
static
final
String
commSeqType
=
"COMMON"
;
// 上传序列类型
public
static
final
String
uploadSeqType
=
"UPLOAD"
;
// 通用接口序列数
private
static
AtomicInteger
commSeq
=
new
AtomicInteger
(
1
);
// 上传接口序列数
private
static
AtomicInteger
uploadSeq
=
new
AtomicInteger
(
1
);
// 机器标识
private
static
final
String
machineCode
=
"A"
;
/**
* 获取通用序列号
*
* @return 序列值
*/
public
static
String
getId
()
{
return
getId
(
commSeqType
);
}
/**
* 默认16位序列号 yyMMddHHmmss + 一位机器标识 + 3长度循环递增字符串
*
* @return 序列值
*/
public
static
String
getId
(
String
type
)
{
AtomicInteger
atomicInt
=
commSeq
;
if
(
uploadSeqType
.
equals
(
type
))
{
atomicInt
=
uploadSeq
;
}
return
getId
(
atomicInt
,
3
);
}
/**
* 通用接口序列号 yyMMddHHmmss + 一位机器标识 + length长度循环递增字符串
*
* @param atomicInt 序列数
* @param length 数值长度
* @return 序列值
*/
public
static
String
getId
(
AtomicInteger
atomicInt
,
int
length
)
{
String
result
=
DateUtils
.
dateTimeNow
();
result
+=
machineCode
;
result
+=
getSeq
(
atomicInt
,
length
);
return
result
;
}
/**
* 序列循环递增字符串[1, 10 的 (length)幂次方), 用0左补齐length位数
*
* @return 序列值
*/
private
synchronized
static
String
getSeq
(
AtomicInteger
atomicInt
,
int
length
)
{
// 先取值再+1
int
value
=
atomicInt
.
getAndIncrement
();
// 如果更新后值>=10 的 (length)幂次方则重置为1
int
maxSeq
=
(
int
)
Math
.
pow
(
10
,
length
);
if
(
atomicInt
.
get
()
>=
maxSeq
)
{
atomicInt
.
set
(
1
);
}
// 转字符串,用0左补齐
return
StringUtils
.
padl
(
value
,
length
);
}
}
custom-server-app/src/main/java/com/jomalls/custom/app/utils/StrFormatter.java
0 → 100644
View file @
17729b0b
package
com
.
jomalls
.
custom
.
app
.
utils
;
/**
* 字符串格式化
*/
public
class
StrFormatter
{
public
static
final
String
EMPTY_JSON
=
"{}"
;
public
static
final
char
C_BACKSLASH
=
'\\'
;
public
static
final
char
C_DELIM_START
=
'{'
;
public
static
final
char
C_DELIM_END
=
'}'
;
/**
* 格式化字符串<br>
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
* 例:<br>
* 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>
* 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
* 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
*
* @param strPattern 字符串模板
* @param argArray 参数列表
* @return 结果
*/
public
static
String
format
(
final
String
strPattern
,
final
Object
...
argArray
)
{
if
(
StringUtils
.
isEmpty
(
strPattern
)
||
StringUtils
.
isEmpty
(
argArray
))
{
return
strPattern
;
}
final
int
strPatternLength
=
strPattern
.
length
();
// 初始化定义好的长度以获得更好的性能
StringBuilder
sbuf
=
new
StringBuilder
(
strPatternLength
+
50
);
int
handledPosition
=
0
;
int
delimIndex
;
// 占位符所在位置
for
(
int
argIndex
=
0
;
argIndex
<
argArray
.
length
;
argIndex
++)
{
delimIndex
=
strPattern
.
indexOf
(
EMPTY_JSON
,
handledPosition
);
if
(
delimIndex
==
-
1
)
{
if
(
handledPosition
==
0
)
{
return
strPattern
;
}
else
{
// 字符串模板剩余部分不再包含占位符,加入剩余部分后返回结果
sbuf
.
append
(
strPattern
,
handledPosition
,
strPatternLength
);
return
sbuf
.
toString
();
}
}
else
{
if
(
delimIndex
>
0
&&
strPattern
.
charAt
(
delimIndex
-
1
)
==
C_BACKSLASH
)
{
if
(
delimIndex
>
1
&&
strPattern
.
charAt
(
delimIndex
-
2
)
==
C_BACKSLASH
)
{
// 转义符之前还有一个转义符,占位符依旧有效
sbuf
.
append
(
strPattern
,
handledPosition
,
delimIndex
-
1
);
sbuf
.
append
(
Convert
.
utf8Str
(
argArray
[
argIndex
]));
handledPosition
=
delimIndex
+
2
;
}
else
{
// 占位符被转义
argIndex
--;
sbuf
.
append
(
strPattern
,
handledPosition
,
delimIndex
-
1
);
sbuf
.
append
(
C_DELIM_START
);
handledPosition
=
delimIndex
+
1
;
}
}
else
{
// 正常占位符
sbuf
.
append
(
strPattern
,
handledPosition
,
delimIndex
);
sbuf
.
append
(
Convert
.
utf8Str
(
argArray
[
argIndex
]));
handledPosition
=
delimIndex
+
2
;
}
}
}
// 加入最后一个占位符后所有的字符
sbuf
.
append
(
strPattern
,
handledPosition
,
strPattern
.
length
());
return
sbuf
.
toString
();
}
}
custom-server-app/src/main/java/com/jomalls/custom/app/utils/StringUtils.java
0 → 100644
View file @
17729b0b
package
com
.
jomalls
.
custom
.
app
.
utils
;
import
org.springframework.util.AntPathMatcher
;
import
java.util.*
;
/**
* 字符串工具类
*/
public
class
StringUtils
extends
org
.
apache
.
commons
.
lang3
.
StringUtils
{
/**
* 空字符串
*/
private
static
final
String
NULLSTR
=
""
;
/**
* 下划线
*/
private
static
final
char
SEPARATOR
=
'_'
;
/**
* 星号
*/
private
static
final
char
ASTERISK
=
'*'
;
/**
* 获取参数不为空值
*
* @param value defaultValue 要判断的value
* @return value 返回值
*/
public
static
<
T
>
T
nvl
(
T
value
,
T
defaultValue
)
{
return
value
!=
null
?
value
:
defaultValue
;
}
/**
* * 判断一个Collection是否为空, 包含List,Set,Queue
*
* @param coll 要判断的Collection
* @return true:为空 false:非空
*/
public
static
boolean
isEmpty
(
Collection
<?>
coll
)
{
return
isNull
(
coll
)
||
coll
.
isEmpty
();
}
/**
* * 判断一个Collection是否非空,包含List,Set,Queue
*
* @param coll 要判断的Collection
* @return true:非空 false:空
*/
public
static
boolean
isNotEmpty
(
Collection
<?>
coll
)
{
return
!
isEmpty
(
coll
);
}
/**
* * 判断一个对象数组是否为空
*
* @param objects 要判断的对象数组
* * @return true:为空 false:非空
*/
public
static
boolean
isEmpty
(
Object
[]
objects
)
{
return
isNull
(
objects
)
||
(
objects
.
length
==
0
);
}
/**
* * 判断一个对象数组是否非空
*
* @param objects 要判断的对象数组
* @return true:非空 false:空
*/
public
static
boolean
isNotEmpty
(
Object
[]
objects
)
{
return
!
isEmpty
(
objects
);
}
/**
* * 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true:为空 false:非空
*/
public
static
boolean
isEmpty
(
Map
<?,
?>
map
)
{
return
isNull
(
map
)
||
map
.
isEmpty
();
}
/**
* * 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true:非空 false:空
*/
public
static
boolean
isNotEmpty
(
Map
<?,
?>
map
)
{
return
!
isEmpty
(
map
);
}
/**
* * 判断一个字符串是否为空串
*
* @param str String
* @return true:为空 false:非空
*/
public
static
boolean
isEmpty
(
String
str
)
{
return
isNull
(
str
)
||
NULLSTR
.
equals
(
str
.
trim
());
}
/**
* * 判断一个字符串是否为非空串
*
* @param str String
* @return true:非空串 false:空串
*/
public
static
boolean
isNotEmpty
(
String
str
)
{
return
!
isEmpty
(
str
);
}
/**
* * 判断一个对象是否为空
*
* @param object Object
* @return true:为空 false:非空
*/
public
static
boolean
isNull
(
Object
object
)
{
return
object
==
null
;
}
/**
* * 判断一个对象是否非空
*
* @param object Object
* @return true:非空 false:空
*/
public
static
boolean
isNotNull
(
Object
object
)
{
return
!
isNull
(
object
);
}
/**
* * 判断一个对象是否是数组类型(Java基本型别的数组)
*
* @param object 对象
* @return true:是数组 false:不是数组
*/
public
static
boolean
isArray
(
Object
object
)
{
return
isNotNull
(
object
)
&&
object
.
getClass
().
isArray
();
}
/**
* 去空格
*/
public
static
String
trim
(
String
str
)
{
return
(
str
==
null
?
""
:
str
.
trim
());
}
/**
* 替换指定字符串的指定区间内字符为"*"
*
* @param str 字符串
* @param startInclude 开始位置(包含)
* @param endExclude 结束位置(不包含)
* @return 替换后的字符串
*/
public
static
String
hide
(
CharSequence
str
,
int
startInclude
,
int
endExclude
)
{
if
(
isEmpty
(
str
))
{
return
NULLSTR
;
}
final
int
strLength
=
str
.
length
();
if
(
startInclude
>
strLength
)
{
return
NULLSTR
;
}
if
(
endExclude
>
strLength
)
{
endExclude
=
strLength
;
}
if
(
startInclude
>
endExclude
)
{
// 如果起始位置大于结束位置,不替换
return
NULLSTR
;
}
final
char
[]
chars
=
new
char
[
strLength
];
for
(
int
i
=
0
;
i
<
strLength
;
i
++)
{
if
(
i
>=
startInclude
&&
i
<
endExclude
)
{
chars
[
i
]
=
ASTERISK
;
}
else
{
chars
[
i
]
=
str
.
charAt
(
i
);
}
}
return
new
String
(
chars
);
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @return 结果
*/
public
static
String
substring
(
final
String
str
,
int
start
)
{
if
(
str
==
null
)
{
return
NULLSTR
;
}
if
(
start
<
0
)
{
start
=
str
.
length
()
+
start
;
}
if
(
start
<
0
)
{
start
=
0
;
}
if
(
start
>
str
.
length
())
{
return
NULLSTR
;
}
return
str
.
substring
(
start
);
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @param end 结束
* @return 结果
*/
public
static
String
substring
(
final
String
str
,
int
start
,
int
end
)
{
if
(
str
==
null
)
{
return
NULLSTR
;
}
if
(
end
<
0
)
{
end
=
str
.
length
()
+
end
;
}
if
(
start
<
0
)
{
start
=
str
.
length
()
+
start
;
}
if
(
end
>
str
.
length
())
{
end
=
str
.
length
();
}
if
(
start
>
end
)
{
return
NULLSTR
;
}
if
(
start
<
0
)
{
start
=
0
;
}
if
(
end
<
0
)
{
end
=
0
;
}
return
str
.
substring
(
start
,
end
);
}
/**
* 在字符串中查找第一个出现的 `open` 和最后一个出现的 `close` 之间的子字符串
*
* @param str 要截取的字符串
* @param open 起始字符串
* @param close 结束字符串
* @return 截取结果
*/
public
static
String
substringBetweenLast
(
final
String
str
,
final
String
open
,
final
String
close
)
{
if
(
isEmpty
(
str
)
||
isEmpty
(
open
)
||
isEmpty
(
close
))
{
return
NULLSTR
;
}
final
int
start
=
str
.
indexOf
(
open
);
if
(
start
!=
INDEX_NOT_FOUND
)
{
final
int
end
=
str
.
lastIndexOf
(
close
);
if
(
end
!=
INDEX_NOT_FOUND
)
{
return
str
.
substring
(
start
+
open
.
length
(),
end
);
}
}
return
NULLSTR
;
}
/**
* 判断是否为空,并且不是空白字符
*
* @param str 要判断的value
* @return 结果
*/
public
static
boolean
hasText
(
String
str
)
{
return
(
str
!=
null
&&
!
str
.
isEmpty
()
&&
containsText
(
str
));
}
private
static
boolean
containsText
(
CharSequence
str
)
{
int
strLen
=
str
.
length
();
for
(
int
i
=
0
;
i
<
strLen
;
i
++)
{
if
(!
Character
.
isWhitespace
(
str
.
charAt
(
i
)))
{
return
true
;
}
}
return
false
;
}
/**
* 格式化文本, {} 表示占位符<br>
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
* 例:<br>
* 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>
* 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
* 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
*
* @param template 文本模板,被替换的部分用 {} 表示
* @param params 参数值
* @return 格式化后的文本
*/
public
static
String
format
(
String
template
,
Object
...
params
)
{
if
(
isEmpty
(
params
)
||
isEmpty
(
template
))
{
return
template
;
}
return
StrFormatter
.
format
(
template
,
params
);
}
/**
* 是否为http(s)://开头
*
* @param link 链接
* @return 结果
*/
public
static
boolean
ishttp
(
String
link
)
{
return
StringUtils
.
startsWithAny
(
link
,
"http://"
,
"https://"
);
}
/**
* 字符串转set
*
* @param str 字符串
* @param sep 分隔符
* @return set集合
*/
public
static
final
Set
<
String
>
str2Set
(
String
str
,
String
sep
)
{
return
new
HashSet
<
String
>(
str2List
(
str
,
sep
,
true
,
false
));
}
/**
* 字符串转list
*
* @param str 字符串
* @param sep 分隔符
* @return list集合
*/
public
static
final
List
<
String
>
str2List
(
String
str
,
String
sep
)
{
return
str2List
(
str
,
sep
,
true
,
false
);
}
/**
* 字符串转list
*
* @param str 字符串
* @param sep 分隔符
* @param filterBlank 过滤纯空白
* @param trim 去掉首尾空白
* @return list集合
*/
public
static
final
List
<
String
>
str2List
(
String
str
,
String
sep
,
boolean
filterBlank
,
boolean
trim
)
{
List
<
String
>
list
=
new
ArrayList
<
String
>();
if
(
StringUtils
.
isEmpty
(
str
))
{
return
list
;
}
// 过滤空白字符串
if
(
filterBlank
&&
StringUtils
.
isBlank
(
str
))
{
return
list
;
}
String
[]
split
=
str
.
split
(
sep
);
for
(
String
string
:
split
)
{
if
(
filterBlank
&&
StringUtils
.
isBlank
(
string
))
{
continue
;
}
if
(
trim
)
{
string
=
string
.
trim
();
}
list
.
add
(
string
);
}
return
list
;
}
/**
* 判断给定的collection列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value
*
* @param collection 给定的集合
* @param array 给定的数组
* @return boolean 结果
*/
public
static
boolean
containsAny
(
Collection
<
String
>
collection
,
String
...
array
)
{
if
(
isEmpty
(
collection
)
||
isEmpty
(
array
))
{
return
false
;
}
else
{
for
(
String
str
:
array
)
{
if
(
collection
.
contains
(
str
))
{
return
true
;
}
}
return
false
;
}
}
/**
* 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写
*
* @param cs 指定字符串
* @param searchCharSequences 需要检查的字符串数组
* @return 是否包含任意一个字符串
*/
public
static
boolean
containsAnyIgnoreCase
(
CharSequence
cs
,
CharSequence
...
searchCharSequences
)
{
if
(
isEmpty
(
cs
)
||
isEmpty
(
searchCharSequences
))
{
return
false
;
}
for
(
CharSequence
testStr
:
searchCharSequences
)
{
if
(
containsIgnoreCase
(
cs
,
testStr
))
{
return
true
;
}
}
return
false
;
}
/**
* 驼峰转下划线命名
*/
public
static
String
toUnderScoreCase
(
String
str
)
{
if
(
str
==
null
)
{
return
null
;
}
StringBuilder
sb
=
new
StringBuilder
();
// 前置字符是否大写
boolean
preCharIsUpperCase
=
true
;
// 当前字符是否大写
boolean
curreCharIsUpperCase
=
true
;
// 下一字符是否大写
boolean
nexteCharIsUpperCase
=
true
;
for
(
int
i
=
0
;
i
<
str
.
length
();
i
++)
{
char
c
=
str
.
charAt
(
i
);
if
(
i
>
0
)
{
preCharIsUpperCase
=
Character
.
isUpperCase
(
str
.
charAt
(
i
-
1
));
}
else
{
preCharIsUpperCase
=
false
;
}
curreCharIsUpperCase
=
Character
.
isUpperCase
(
c
);
if
(
i
<
(
str
.
length
()
-
1
))
{
nexteCharIsUpperCase
=
Character
.
isUpperCase
(
str
.
charAt
(
i
+
1
));
}
if
(
preCharIsUpperCase
&&
curreCharIsUpperCase
&&
!
nexteCharIsUpperCase
)
{
sb
.
append
(
SEPARATOR
);
}
else
if
((
i
!=
0
&&
!
preCharIsUpperCase
)
&&
curreCharIsUpperCase
)
{
sb
.
append
(
SEPARATOR
);
}
sb
.
append
(
Character
.
toLowerCase
(
c
));
}
return
sb
.
toString
();
}
/**
* 是否包含字符串
*
* @param str 验证字符串
* @param strs 字符串组
* @return 包含返回true
*/
public
static
boolean
inStringIgnoreCase
(
String
str
,
String
...
strs
)
{
if
(
str
!=
null
&&
strs
!=
null
)
{
for
(
String
s
:
strs
)
{
if
(
str
.
equalsIgnoreCase
(
trim
(
s
)))
{
return
true
;
}
}
}
return
false
;
}
/**
* 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld
*
* @param name 转换前的下划线大写方式命名的字符串
* @return 转换后的驼峰式命名的字符串
*/
public
static
String
convertToCamelCase
(
String
name
)
{
StringBuilder
result
=
new
StringBuilder
();
// 快速检查
if
(
name
==
null
||
name
.
isEmpty
())
{
// 没必要转换
return
""
;
}
else
if
(!
name
.
contains
(
"_"
))
{
// 不含下划线,仅将首字母大写
return
name
.
substring
(
0
,
1
).
toUpperCase
()
+
name
.
substring
(
1
);
}
// 用下划线将原始字符串分割
String
[]
camels
=
name
.
split
(
"_"
);
for
(
String
camel
:
camels
)
{
// 跳过原始字符串中开头、结尾的下换线或双重下划线
if
(
camel
.
isEmpty
())
{
continue
;
}
// 首字母大写
result
.
append
(
camel
.
substring
(
0
,
1
).
toUpperCase
());
result
.
append
(
camel
.
substring
(
1
).
toLowerCase
());
}
return
result
.
toString
();
}
/**
* 驼峰式命名法
* 例如:user_name->userName
*/
public
static
String
toCamelCase
(
String
s
)
{
if
(
s
==
null
)
{
return
null
;
}
if
(
s
.
indexOf
(
SEPARATOR
)
==
-
1
)
{
return
s
;
}
s
=
s
.
toLowerCase
();
StringBuilder
sb
=
new
StringBuilder
(
s
.
length
());
boolean
upperCase
=
false
;
for
(
int
i
=
0
;
i
<
s
.
length
();
i
++)
{
char
c
=
s
.
charAt
(
i
);
if
(
c
==
SEPARATOR
)
{
upperCase
=
true
;
}
else
if
(
upperCase
)
{
sb
.
append
(
Character
.
toUpperCase
(
c
));
upperCase
=
false
;
}
else
{
sb
.
append
(
c
);
}
}
return
sb
.
toString
();
}
/**
* 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
*
* @param str 指定字符串
* @param strs 需要检查的字符串数组
* @return 是否匹配
*/
public
static
boolean
matches
(
String
str
,
List
<
String
>
strs
)
{
if
(
isEmpty
(
str
)
||
isEmpty
(
strs
))
{
return
false
;
}
for
(
String
pattern
:
strs
)
{
if
(
isMatch
(
pattern
,
str
))
{
return
true
;
}
}
return
false
;
}
/**
* 判断url是否与规则配置:
* ? 表示单个字符;
* * 表示一层路径内的任意字符串,不可跨层级;
* ** 表示任意层路径;
*
* @param pattern 匹配规则
* @param url 需要匹配的url
* @return
*/
public
static
boolean
isMatch
(
String
pattern
,
String
url
)
{
AntPathMatcher
matcher
=
new
AntPathMatcher
();
return
matcher
.
match
(
pattern
,
url
);
}
@SuppressWarnings
(
"unchecked"
)
public
static
<
T
>
T
cast
(
Object
obj
)
{
return
(
T
)
obj
;
}
/**
* 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。
*
* @param num 数字对象
* @param size 字符串指定长度
* @return 返回数字的字符串格式,该字符串为指定长度。
*/
public
static
final
String
padl
(
final
Number
num
,
final
int
size
)
{
return
padl
(
num
.
toString
(),
size
,
'0'
);
}
/**
* 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。
*
* @param s 原始字符串
* @param size 字符串指定长度
* @param c 用于补齐的字符
* @return 返回指定长度的字符串,由原字符串左补齐或截取得到。
*/
public
static
final
String
padl
(
final
String
s
,
final
int
size
,
final
char
c
)
{
final
StringBuilder
sb
=
new
StringBuilder
(
size
);
if
(
s
!=
null
)
{
final
int
len
=
s
.
length
();
if
(
s
.
length
()
<=
size
)
{
for
(
int
i
=
size
-
len
;
i
>
0
;
i
--)
{
sb
.
append
(
c
);
}
sb
.
append
(
s
);
}
else
{
return
s
.
substring
(
len
-
size
,
len
);
}
}
else
{
for
(
int
i
=
size
;
i
>
0
;
i
--)
{
sb
.
append
(
c
);
}
}
return
sb
.
toString
();
}
}
\ No newline at end of file
custom-server-app/src/main/java/com/jomalls/custom/app/utils/UUID.java
0 → 100644
View file @
17729b0b
package
com
.
jomalls
.
custom
.
app
.
utils
;
import
java.security.MessageDigest
;
import
java.security.NoSuchAlgorithmException
;
import
java.security.SecureRandom
;
import
java.util.Random
;
import
java.util.concurrent.ThreadLocalRandom
;
/**
* 提供通用唯一识别码(universally unique identifier)(UUID)实现
*/
public
final
class
UUID
implements
java
.
io
.
Serializable
,
Comparable
<
UUID
>
{
private
static
final
long
serialVersionUID
=
-
1185015143654744140L
;
/**
* SecureRandom 的单例
*/
private
static
class
Holder
{
static
final
SecureRandom
numberGenerator
=
getSecureRandom
();
}
/**
* 此UUID的最高64有效位
*/
private
final
long
mostSigBits
;
/**
* 此UUID的最低64有效位
*/
private
final
long
leastSigBits
;
/**
* 私有构造
*
* @param data 数据
*/
private
UUID
(
byte
[]
data
)
{
long
msb
=
0
;
long
lsb
=
0
;
assert
data
.
length
==
16
:
"data must be 16 bytes in length"
;
for
(
int
i
=
0
;
i
<
8
;
i
++)
{
msb
=
(
msb
<<
8
)
|
(
data
[
i
]
&
0xff
);
}
for
(
int
i
=
8
;
i
<
16
;
i
++)
{
lsb
=
(
lsb
<<
8
)
|
(
data
[
i
]
&
0xff
);
}
this
.
mostSigBits
=
msb
;
this
.
leastSigBits
=
lsb
;
}
/**
* 使用指定的数据构造新的 UUID。
*
* @param mostSigBits 用于 {@code UUID} 的最高有效 64 位
* @param leastSigBits 用于 {@code UUID} 的最低有效 64 位
*/
public
UUID
(
long
mostSigBits
,
long
leastSigBits
)
{
this
.
mostSigBits
=
mostSigBits
;
this
.
leastSigBits
=
leastSigBits
;
}
/**
* 获取类型 4(伪随机生成的)UUID 的静态工厂。
*
* @return 随机生成的 {@code UUID}
*/
public
static
UUID
fastUUID
()
{
return
randomUUID
(
false
);
}
/**
* 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。
*
* @return 随机生成的 {@code UUID}
*/
public
static
UUID
randomUUID
()
{
return
randomUUID
(
true
);
}
/**
* 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。
*
* @param isSecure 是否使用{@link SecureRandom}如果是可以获得更安全的随机码,否则可以得到更好的性能
* @return 随机生成的 {@code UUID}
*/
public
static
UUID
randomUUID
(
boolean
isSecure
)
{
final
Random
ng
=
isSecure
?
Holder
.
numberGenerator
:
getRandom
();
byte
[]
randomBytes
=
new
byte
[
16
];
ng
.
nextBytes
(
randomBytes
);
randomBytes
[
6
]
&=
0x0f
;
/* clear version */
randomBytes
[
6
]
|=
0x40
;
/* set to version 4 */
randomBytes
[
8
]
&=
0x3f
;
/* clear variant */
randomBytes
[
8
]
|=
0x80
;
/* set to IETF variant */
return
new
UUID
(
randomBytes
);
}
/**
* 根据指定的字节数组获取类型 3(基于名称的)UUID 的静态工厂。
*
* @param name 用于构造 UUID 的字节数组。
* @return 根据指定数组生成的 {@code UUID}
*/
public
static
UUID
nameUUIDFromBytes
(
byte
[]
name
)
{
MessageDigest
md
;
try
{
md
=
MessageDigest
.
getInstance
(
"MD5"
);
}
catch
(
NoSuchAlgorithmException
nsae
)
{
throw
new
InternalError
(
"MD5 not supported"
);
}
byte
[]
md5Bytes
=
md
.
digest
(
name
);
md5Bytes
[
6
]
&=
0x0f
;
/* clear version */
md5Bytes
[
6
]
|=
0x30
;
/* set to version 3 */
md5Bytes
[
8
]
&=
0x3f
;
/* clear variant */
md5Bytes
[
8
]
|=
0x80
;
/* set to IETF variant */
return
new
UUID
(
md5Bytes
);
}
/**
* 根据 {@link #toString()} 方法中描述的字符串标准表示形式创建{@code UUID}。
*
* @param name 指定 {@code UUID} 字符串
* @return 具有指定值的 {@code UUID}
* @throws IllegalArgumentException 如果 name 与 {@link #toString} 中描述的字符串表示形式不符抛出此异常
*/
public
static
UUID
fromString
(
String
name
)
{
String
[]
components
=
name
.
split
(
"-"
);
if
(
components
.
length
!=
5
)
{
throw
new
IllegalArgumentException
(
"Invalid UUID string: "
+
name
);
}
for
(
int
i
=
0
;
i
<
5
;
i
++)
{
components
[
i
]
=
"0x"
+
components
[
i
];
}
long
mostSigBits
=
Long
.
decode
(
components
[
0
]).
longValue
();
mostSigBits
<<=
16
;
mostSigBits
|=
Long
.
decode
(
components
[
1
]).
longValue
();
mostSigBits
<<=
16
;
mostSigBits
|=
Long
.
decode
(
components
[
2
]).
longValue
();
long
leastSigBits
=
Long
.
decode
(
components
[
3
]).
longValue
();
leastSigBits
<<=
48
;
leastSigBits
|=
Long
.
decode
(
components
[
4
]).
longValue
();
return
new
UUID
(
mostSigBits
,
leastSigBits
);
}
/**
* 返回此 UUID 的 128 位值中的最低有效 64 位。
*
* @return 此 UUID 的 128 位值中的最低有效 64 位。
*/
public
long
getLeastSignificantBits
()
{
return
leastSigBits
;
}
/**
* 返回此 UUID 的 128 位值中的最高有效 64 位。
*
* @return 此 UUID 的 128 位值中最高有效 64 位。
*/
public
long
getMostSignificantBits
()
{
return
mostSigBits
;
}
/**
* 与此 {@code UUID} 相关联的版本号. 版本号描述此 {@code UUID} 是如何生成的。
* <p>
* 版本号具有以下含意:
* <ul>
* <li>1 基于时间的 UUID
* <li>2 DCE 安全 UUID
* <li>3 基于名称的 UUID
* <li>4 随机生成的 UUID
* </ul>
*
* @return 此 {@code UUID} 的版本号
*/
public
int
version
()
{
// Version is bits masked by 0x000000000000F000 in MS long
return
(
int
)
((
mostSigBits
>>
12
)
&
0x0f
);
}
/**
* 与此 {@code UUID} 相关联的变体号。变体号描述 {@code UUID} 的布局。
* <p>
* 变体号具有以下含意:
* <ul>
* <li>0 为 NCS 向后兼容保留
* <li>2 <a href="http://www.ietf.org/rfc/rfc4122.txt">IETF RFC 4122</a>(Leach-Salz), 用于此类
* <li>6 保留,微软向后兼容
* <li>7 保留供以后定义使用
* </ul>
*
* @return 此 {@code UUID} 相关联的变体号
*/
public
int
variant
()
{
// This field is composed of a varying number of bits.
// 0 - - Reserved for NCS backward compatibility
// 1 0 - The IETF aka Leach-Salz variant (used by this class)
// 1 1 0 Reserved, Microsoft backward compatibility
// 1 1 1 Reserved for future definition.
return
(
int
)
((
leastSigBits
>>>
(
64
-
(
leastSigBits
>>>
62
)))
&
(
leastSigBits
>>
63
));
}
/**
* 与此 UUID 相关联的时间戳值。
*
* <p>
* 60 位的时间戳值根据此 {@code UUID} 的 time_low、time_mid 和 time_hi 字段构造。<br>
* 所得到的时间戳以 100 毫微秒为单位,从 UTC(通用协调时间) 1582 年 10 月 15 日零时开始。
*
* <p>
* 时间戳值仅在在基于时间的 UUID(其 version 类型为 1)中才有意义。<br>
* 如果此 {@code UUID} 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。
*
* @throws UnsupportedOperationException 如果此 {@code UUID} 不是 version 为 1 的 UUID。
*/
public
long
timestamp
()
throws
UnsupportedOperationException
{
checkTimeBase
();
return
(
mostSigBits
&
0x0FFF
L
)
<<
48
//
|
((
mostSigBits
>>
16
)
&
0x0FFFF
L
)
<<
32
//
|
mostSigBits
>>>
32
;
}
/**
* 与此 UUID 相关联的时钟序列值。
*
* <p>
* 14 位的时钟序列值根据此 UUID 的 clock_seq 字段构造。clock_seq 字段用于保证在基于时间的 UUID 中的时间唯一性。
* <p>
* {@code clockSequence} 值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。 如果此 UUID 不是基于时间的 UUID,则此方法抛出
* UnsupportedOperationException。
*
* @return 此 {@code UUID} 的时钟序列
* @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1
*/
public
int
clockSequence
()
throws
UnsupportedOperationException
{
checkTimeBase
();
return
(
int
)
((
leastSigBits
&
0x3FFF000000000000
L
)
>>>
48
);
}
/**
* 与此 UUID 相关的节点值。
*
* <p>
* 48 位的节点值根据此 UUID 的 node 字段构造。此字段旨在用于保存机器的 IEEE 802 地址,该地址用于生成此 UUID 以保证空间唯一性。
* <p>
* 节点值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。<br>
* 如果此 UUID 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。
*
* @return 此 {@code UUID} 的节点值
* @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1
*/
public
long
node
()
throws
UnsupportedOperationException
{
checkTimeBase
();
return
leastSigBits
&
0x0000FFFFFFFFFFFF
L
;
}
/**
* 返回此{@code UUID} 的字符串表现形式。
*
* <p>
* UUID 的字符串表示形式由此 BNF 描述:
*
* <pre>
* {@code
* UUID = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>
* time_low = 4*<hexOctet>
* time_mid = 2*<hexOctet>
* time_high_and_version = 2*<hexOctet>
* variant_and_sequence = 2*<hexOctet>
* node = 6*<hexOctet>
* hexOctet = <hexDigit><hexDigit>
* hexDigit = [0-9a-fA-F]
* }
* </pre>
*
* </blockquote>
*
* @return 此{@code UUID} 的字符串表现形式
* @see #toString(boolean)
*/
@Override
public
String
toString
()
{
return
toString
(
false
);
}
/**
* 返回此{@code UUID} 的字符串表现形式。
*
* <p>
* UUID 的字符串表示形式由此 BNF 描述:
*
* <pre>
* {@code
* UUID = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>
* time_low = 4*<hexOctet>
* time_mid = 2*<hexOctet>
* time_high_and_version = 2*<hexOctet>
* variant_and_sequence = 2*<hexOctet>
* node = 6*<hexOctet>
* hexOctet = <hexDigit><hexDigit>
* hexDigit = [0-9a-fA-F]
* }
* </pre>
*
* </blockquote>
*
* @param isSimple 是否简单模式,简单模式为不带'-'的UUID字符串
* @return 此{@code UUID} 的字符串表现形式
*/
public
String
toString
(
boolean
isSimple
)
{
final
StringBuilder
builder
=
new
StringBuilder
(
isSimple
?
32
:
36
);
// time_low
builder
.
append
(
digits
(
mostSigBits
>>
32
,
8
));
if
(!
isSimple
)
{
builder
.
append
(
'-'
);
}
// time_mid
builder
.
append
(
digits
(
mostSigBits
>>
16
,
4
));
if
(!
isSimple
)
{
builder
.
append
(
'-'
);
}
// time_high_and_version
builder
.
append
(
digits
(
mostSigBits
,
4
));
if
(!
isSimple
)
{
builder
.
append
(
'-'
);
}
// variant_and_sequence
builder
.
append
(
digits
(
leastSigBits
>>
48
,
4
));
if
(!
isSimple
)
{
builder
.
append
(
'-'
);
}
// node
builder
.
append
(
digits
(
leastSigBits
,
12
));
return
builder
.
toString
();
}
/**
* 返回此 UUID 的哈希码。
*
* @return UUID 的哈希码值。
*/
@Override
public
int
hashCode
()
{
long
hilo
=
mostSigBits
^
leastSigBits
;
return
((
int
)
(
hilo
>>
32
))
^
(
int
)
hilo
;
}
/**
* 将此对象与指定对象比较。
* <p>
* 当且仅当参数不为 {@code null}、而是一个 UUID 对象、具有与此 UUID 相同的 varriant、包含相同的值(每一位均相同)时,结果才为 {@code true}。
*
* @param obj 要与之比较的对象
* @return 如果对象相同,则返回 {@code true};否则返回 {@code false}
*/
@Override
public
boolean
equals
(
Object
obj
)
{
if
((
null
==
obj
)
||
(
obj
.
getClass
()
!=
UUID
.
class
))
{
return
false
;
}
UUID
id
=
(
UUID
)
obj
;
return
(
mostSigBits
==
id
.
mostSigBits
&&
leastSigBits
==
id
.
leastSigBits
);
}
// Comparison Operations
/**
* 将此 UUID 与指定的 UUID 比较。
*
* <p>
* 如果两个 UUID 不同,且第一个 UUID 的最高有效字段大于第二个 UUID 的对应字段,则第一个 UUID 大于第二个 UUID。
*
* @param val 与此 UUID 比较的 UUID
* @return 在此 UUID 小于、等于或大于 val 时,分别返回 -1、0 或 1。
*/
@Override
public
int
compareTo
(
UUID
val
)
{
// The ordering is intentionally set up so that the UUIDs
// can simply be numerically compared as two numbers
return
(
this
.
mostSigBits
<
val
.
mostSigBits
?
-
1
:
//
(
this
.
mostSigBits
>
val
.
mostSigBits
?
1
:
//
(
this
.
leastSigBits
<
val
.
leastSigBits
?
-
1
:
//
(
this
.
leastSigBits
>
val
.
leastSigBits
?
1
:
//
0
))));
}
// -------------------------------------------------------------------------------------------------------------------
// Private method start
/**
* 返回指定数字对应的hex值
*
* @param val 值
* @param digits 位
* @return 值
*/
private
static
String
digits
(
long
val
,
int
digits
)
{
long
hi
=
1L
<<
(
digits
*
4
);
return
Long
.
toHexString
(
hi
|
(
val
&
(
hi
-
1
))).
substring
(
1
);
}
/**
* 检查是否为time-based版本UUID
*/
private
void
checkTimeBase
()
{
if
(
version
()
!=
1
)
{
throw
new
UnsupportedOperationException
(
"Not a time-based UUID"
);
}
}
/**
* 获取{@link SecureRandom},类提供加密的强随机数生成器 (RNG)
*
* @return {@link SecureRandom}
*/
public
static
SecureRandom
getSecureRandom
()
{
try
{
return
SecureRandom
.
getInstance
(
"SHA1PRNG"
);
}
catch
(
NoSuchAlgorithmException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
/**
* 获取随机数生成器对象<br>
* ThreadLocalRandom是JDK 7之后提供并发产生随机数,能够解决多个线程发生的竞争争夺。
*
* @return {@link ThreadLocalRandom}
*/
public
static
ThreadLocalRandom
getRandom
()
{
return
ThreadLocalRandom
.
current
();
}
}
custom-server-core/pom.xml
View file @
17729b0b
...
...
@@ -62,5 +62,13 @@
<groupId>
com.alibaba
</groupId>
<artifactId>
transmittable-thread-local
</artifactId>
</dependency>
<dependency>
<groupId>
org.springframework.amqp
</groupId>
<artifactId>
spring-rabbit
</artifactId>
</dependency>
<dependency>
<groupId>
org.dromara.x-file-storage
</groupId>
<artifactId>
x-file-storage-spring
</artifactId>
</dependency>
</dependencies>
</project>
custom-server-core/src/main/java/com/jomalls/custom/enums/MqRoute.java
0 → 100644
View file @
17729b0b
package
com
.
jomalls
.
custom
.
enums
;
import
lombok.Getter
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.stream.Collectors
;
@Getter
public
enum
MqRoute
{
synthesized_image_server_callback
(
"synthesized_image_server_callback"
,
"com.jomalls.worker.queue.SyntheticServerCallbackQueue"
,
"合成图像服务器回调"
),;
MqRoute
(
String
key
,
String
handleQueue
,
String
remark
)
{
this
.
key
=
key
;
this
.
handleQueue
=
handleQueue
;
this
.
remark
=
remark
;
}
private
final
String
key
;
private
final
String
handleQueue
;
private
final
String
remark
;
public
static
List
<
String
>
geList
()
{
return
Arrays
.
stream
(
MqRoute
.
values
()).
map
(
MqRoute:
:
getKey
).
collect
(
Collectors
.
toList
());
}
}
custom-server-integrate/pom.xml
View file @
17729b0b
...
...
@@ -46,5 +46,11 @@
<artifactId>
resilience4j-spring-boot3
</artifactId>
<version>
2.2.0
</version>
</dependency>
<!-- xxl-job-core -->
<dependency>
<groupId>
com.xuxueli
</groupId>
<artifactId>
xxl-job-core
</artifactId>
<version>
2.4.0
</version>
</dependency>
</dependencies>
</project>
custom-server-integrate/src/main/java/com/jomalls/custom/integrate/configuration/XxlJobConfig.java
0 → 100644
View file @
17729b0b
package
com
.
jomalls
.
custom
.
integrate
.
configuration
;
import
com.xxl.job.core.executor.impl.XxlJobSpringExecutor
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
@Configuration
public
class
XxlJobConfig
{
@Value
(
"${xxl.job.admin.addresses}"
)
private
String
adminAddresses
;
@Value
(
"${xxl.job.accessToken}"
)
private
String
accessToken
;
@Value
(
"${xxl.job.executor.appname}"
)
private
String
appname
;
@Value
(
"${xxl.job.executor.address}"
)
private
String
address
;
@Value
(
"${xxl.job.executor.ip}"
)
private
String
ip
;
@Value
(
"${xxl.job.executor.port}"
)
private
Integer
port
;
@Value
(
"${xxl.job.executor.logpath}"
)
private
String
logpath
;
@Value
(
"${xxl.job.executor.logretentiondays}"
)
private
Integer
logretentiondays
;
@Bean
public
XxlJobSpringExecutor
xxlJobExecutor
()
{
XxlJobSpringExecutor
xxlJobSpringExecutor
=
new
XxlJobSpringExecutor
();
xxlJobSpringExecutor
.
setAdminAddresses
(
adminAddresses
);
xxlJobSpringExecutor
.
setAccessToken
(
accessToken
);
xxlJobSpringExecutor
.
setAppname
(
appname
);
xxlJobSpringExecutor
.
setAddress
(
address
);
xxlJobSpringExecutor
.
setIp
(
ip
);
xxlJobSpringExecutor
.
setPort
(
port
);
xxlJobSpringExecutor
.
setLogPath
(
logpath
);
xxlJobSpringExecutor
.
setLogRetentionDays
(
logretentiondays
);
return
xxlJobSpringExecutor
;
}
}
\ No newline at end of file
custom-server-starter/src/main/java/com/jomalls/custom/CustomServerApplication.java
View file @
17729b0b
package
com
.
jomalls
.
custom
;
import
org.dromara.x.file.storage.spring.EnableFileStorage
;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.boot.autoconfigure.SpringBootApplication
;
import
org.springframework.context.annotation.EnableAspectJAutoProxy
;
import
org.springframework.scheduling.annotation.EnableAsync
;
import
org.springframework.scheduling.annotation.EnableScheduling
;
...
...
@@ -12,6 +12,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
* @author Lizh
* @date 2026-05-26 18:25:27
*/
@EnableFileStorage
@SpringBootApplication
@EnableAsync
@EnableScheduling
...
...
custom-server-starter/src/main/resources/application-dev.yml
View file @
17729b0b
...
...
@@ -17,3 +17,31 @@ token:
header
:
Authorization
# 令牌密钥(兼容旧版本)
secret
:
custom
xxl
:
job
:
admin
:
addresses
:
http://172.16.19.99:8888/xxl-job-admin
accessToken
:
udPDEOHA1Q7rgJSVrTpNFoyXbd79Ynz09CumN9ypYlhvh5eSLZh2DMR5sQ4B5W3P5yKz8mkB77Ynz6KA3L
executor
:
appname
:
xxl-job-executor-custom
# 不同服务使用不同appname
address
:
ip
:
port
:
9060
# 不同执行器使用不同端口
logpath
:
/data/applogs/xxl-job/custom
# 不同服务使用不同日志路径
logretentiondays
:
30
jomalls
:
custom
:
url
:
https://tcustom.jomalls.com
dromara
:
x-file-storage
:
#文件存储配置
default-platform
:
aliyun-oss-1
#默认使用的存储平台
thumbnail-suffix
:
"
.min.jpg"
#缩略图后缀,例如【.min.jpg】【.png】
aliyun-oss
:
-
platform
:
aliyun-oss-1
# 存储平台标识
enable-storage
:
true
# 启用存储
access-key
:
LTAI5t9NpNn2eTVUzvDWhV3W
secret-key
:
jQLgp8mYHuV8rQkBSY4RiZQ8jpJhV4
end-point
:
oss-cn-hangzhou.aliyuncs.com
bucket-name
:
jomalls-psd
domain
:
https://jomalls-psd.oss-cn-hangzhou.aliyuncs.com/
# 访问域名,注意“/”结尾,例如:https://abc.oss-cn-shanghai.aliyuncs.com/
base-path
:
custom/
# 基础路径
custom-server-starter/src/main/resources/application-prod.yml
View file @
17729b0b
...
...
@@ -16,4 +16,33 @@ spring:
token
:
header
:
Authorization
# 令牌密钥(兼容旧版本)
secret
:
custom
\ No newline at end of file
secret
:
custom
xxl
:
job
:
admin
:
addresses
:
http://120.0.0.1:8888/xxl-job-admin
accessToken
:
udPDEOHA1Q7rgJSVrTpNFoyXbd79Ynz09CumN9ypYlhvh5eSLZh2DMR5sQ4B5W3P5yKz8mkB77Ynz6KA3L
executor
:
appname
:
xxl-job-executor-custom
# 不同服务使用不同appname
address
:
ip
:
port
:
9060
# 不同执行器使用不同端口
logpath
:
/data/applogs/xxl-job/custom
# 不同服务使用不同日志路径
logretentiondays
:
30
jomalls
:
custom
:
url
:
https://custom.jomalls.com
dromara
:
x-file-storage
:
#文件存储配置
default-platform
:
aliyun-oss-1
#默认使用的存储平台
thumbnail-suffix
:
"
.min.jpg"
#缩略图后缀,例如【.min.jpg】【.png】
aliyun-oss
:
-
platform
:
aliyun-oss-1
# 存储平台标识
enable-storage
:
true
# 启用存储
access-key
:
LTAI5t9NpNn2eTVUzvDWhV3W
secret-key
:
jQLgp8mYHuV8rQkBSY4RiZQ8jpJhV4
end-point
:
oss-cn-hangzhou.aliyuncs.com
bucket-name
:
jomalls-psd
domain
:
https://jomalls-psd.oss-cn-hangzhou.aliyuncs.com/
# 访问域名,注意“/”结尾,例如:https://abc.oss-cn-shanghai.aliyuncs.com/
base-path
:
custom/
# 基础路径
\ No newline at end of file
custom-server-starter/src/main/resources/application-test.yml
View file @
17729b0b
...
...
@@ -17,3 +17,32 @@ token:
header
:
Authorization
# 令牌密钥(兼容旧版本)
secret
:
custom
xxl
:
job
:
admin
:
addresses
:
http://172.16.19.99:8888/xxl-job-admin
accessToken
:
udPDEOHA1Q7rgJSVrTpNFoyXbd79Ynz09CumN9ypYlhvh5eSLZh2DMR5sQ4B5W3P5yKz8mkB77Ynz6KA3L
executor
:
appname
:
xxl-job-executor-custom
# 不同服务使用不同appname
address
:
ip
:
port
:
9060
# 不同执行器使用不同端口
logpath
:
/data/applogs/xxl-job/custom
# 不同服务使用不同日志路径
logretentiondays
:
30
jomalls
:
custom
:
url
:
https://tcustom.jomalls.com
dromara
:
x-file-storage
:
#文件存储配置
default-platform
:
aliyun-oss-1
#默认使用的存储平台
thumbnail-suffix
:
"
.min.jpg"
#缩略图后缀,例如【.min.jpg】【.png】
aliyun-oss
:
-
platform
:
aliyun-oss-1
# 存储平台标识
enable-storage
:
true
# 启用存储
access-key
:
LTAI5t9NpNn2eTVUzvDWhV3W
secret-key
:
jQLgp8mYHuV8rQkBSY4RiZQ8jpJhV4
end-point
:
oss-cn-hangzhou.aliyuncs.com
bucket-name
:
jomalls-psd
domain
:
https://jomalls-psd.oss-cn-hangzhou.aliyuncs.com/
# 访问域名,注意“/”结尾,例如:https://abc.oss-cn-shanghai.aliyuncs.com/
base-path
:
custom/
# 基础路径
custom-server-starter/src/main/resources/application.yml
View file @
17729b0b
...
...
@@ -138,3 +138,6 @@ management:
base-path
:
/api/v3/actuator
exposure
:
include
:
metrics,health
jomalls
:
job
:
execute
:
true
custom-server-webapp/pom.xml
View file @
17729b0b
...
...
@@ -38,6 +38,14 @@
<artifactId>
lombok
</artifactId>
<scope>
provided
</scope>
</dependency>
<dependency>
<groupId>
org.dromara.x-file-storage
</groupId>
<artifactId>
x-file-storage-spring
</artifactId>
</dependency>
<dependency>
<groupId>
com.aliyun.oss
</groupId>
<artifactId>
aliyun-sdk-oss
</artifactId>
</dependency>
</dependencies>
</project>
custom-server-webapp/src/main/java/com/jomalls/custom/webapp/controller/rest/SyntheticServerCallbackController.java
0 → 100644
View file @
17729b0b
package
com
.
jomalls
.
custom
.
webapp
.
controller
.
rest
;
import
com.jomalls.custom.app.handler.SyntheticServerCallbackHandler
;
import
com.jomalls.custom.utils.R
;
import
jakarta.servlet.http.HttpServletRequest
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
/**
* 合成服务器回调
*/
@RestController
@RequestMapping
(
"api/v2/rest/synthetic-server"
)
public
class
SyntheticServerCallbackController
{
@Autowired
SyntheticServerCallbackHandler
syntheticServerCallbackHandler
;
@GetMapping
(
"/callback"
)
public
R
callback
(
HttpServletRequest
request
)
{
String
queryString
=
request
.
getQueryString
();
syntheticServerCallbackHandler
.
callback
(
queryString
);
return
R
.
ok
();
}
}
custom-server-webapp/src/main/java/com/jomalls/custom/webapp/controller/upload/UploadController.java
0 → 100644
View file @
17729b0b
package
com
.
jomalls
.
custom
.
webapp
.
controller
.
upload
;
import
com.jomalls.custom.utils.R
;
import
org.dromara.x.file.storage.core.FileInfo
;
import
org.dromara.x.file.storage.core.FileStorageService
;
import
org.springframework.beans.factory.annotation.Autowired
;;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.multipart.MultipartFile
;
import
java.time.LocalDateTime
;
import
java.time.format.DateTimeFormatter
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* 上传文件
*/
@RestController
@RequestMapping
(
"api/v2/common"
)
public
class
UploadController
{
@Autowired
private
FileStorageService
fileStorageService
;
private
static
final
String
FILE_DELIMETER
=
","
;
/**
* 通用上传请求(单个)
*/
@PostMapping
(
"/upload"
)
public
R
<
Map
<
String
,
Object
>>
uploadFile
(
MultipartFile
file
){
try
{
String
filePath
=
LocalDateTime
.
now
().
format
(
DateTimeFormatter
.
ofPattern
(
"yy/MM/dd/"
));
FileInfo
fileInfo
=
fileStorageService
.
of
(
file
)
.
setPath
(
filePath
)
.
upload
();
Map
<
String
,
Object
>
map
=
new
HashMap
<>();
map
.
put
(
"url"
,
fileInfo
.
getUrl
());
map
.
put
(
"fileName"
,
fileInfo
.
getUrl
());
map
.
put
(
"newFileName"
,
fileInfo
.
getUrl
());
map
.
put
(
"originalFilename"
,
file
.
getOriginalFilename
());
return
R
.
ok
(
map
);
}
catch
(
Exception
e
)
{
return
R
.
fail
(
e
.
getMessage
());
}
}
}
pom.xml
View file @
17729b0b
...
...
@@ -25,6 +25,9 @@
<transmittable-thread-local.version>
2.14.5
</transmittable-thread-local.version>
<project.build.sourceEncoding>
UTF-8
</project.build.sourceEncoding>
<project.reporting.outputEncoding>
UTF-8
</project.reporting.outputEncoding>
<x-file.version>
2.3.0
</x-file.version>
<aliyun-oss.version>
3.16.1
</aliyun-oss.version>
<spring-boot-starter-amqp.version>
2.5.15
</spring-boot-starter-amqp.version>
</properties>
<dependencies>
<dependency>
...
...
@@ -127,6 +130,22 @@
<artifactId>
transmittable-thread-local
</artifactId>
<version>
${transmittable-thread-local.version}
</version>
</dependency>
<dependency>
<groupId>
org.dromara.x-file-storage
</groupId>
<artifactId>
x-file-storage-spring
</artifactId>
<version>
${x-file.version}
</version>
</dependency>
<!-- RabbitMQ -->
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-amqp
</artifactId>
<version>
${spring-boot-starter-amqp.version}
</version>
</dependency>
<dependency>
<groupId>
com.aliyun.oss
</groupId>
<artifactId>
aliyun-sdk-oss
</artifactId>
<version>
${aliyun-oss.version}
</version>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
...
...
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