Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Administrator
magic-api
Commits
02897568
Commit
02897568
authored
Dec 18, 2023
by
liang.tang
Browse files
magic-api
parents
Pipeline
#222
failed with stages
in 0 seconds
Changes
320
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
2093 additions
and
0 deletions
+2093
-0
magic-api/src/main/java/org/ssssssss/magicapi/core/servlet/MagicHttpSession.java
.../org/ssssssss/magicapi/core/servlet/MagicHttpSession.java
+10
-0
magic-api/src/main/java/org/ssssssss/magicapi/core/servlet/MagicRequestContextHolder.java
...ssss/magicapi/core/servlet/MagicRequestContextHolder.java
+23
-0
magic-api/src/main/java/org/ssssssss/magicapi/core/web/MagicController.java
.../java/org/ssssssss/magicapi/core/web/MagicController.java
+99
-0
magic-api/src/main/java/org/ssssssss/magicapi/core/web/MagicControllerRegister.java
...g/ssssssss/magicapi/core/web/MagicControllerRegister.java
+9
-0
magic-api/src/main/java/org/ssssssss/magicapi/core/web/MagicExceptionHandler.java
...org/ssssssss/magicapi/core/web/MagicExceptionHandler.java
+43
-0
magic-api/src/main/java/org/ssssssss/magicapi/core/web/MagicResourceController.java
...g/ssssssss/magicapi/core/web/MagicResourceController.java
+185
-0
magic-api/src/main/java/org/ssssssss/magicapi/core/web/MagicWorkbenchController.java
.../ssssssss/magicapi/core/web/MagicWorkbenchController.java
+334
-0
magic-api/src/main/java/org/ssssssss/magicapi/core/web/RequestHandler.java
...n/java/org/ssssssss/magicapi/core/web/RequestHandler.java
+483
-0
magic-api/src/main/java/org/ssssssss/magicapi/datasource/model/DataSourceInfo.java
...rg/ssssssss/magicapi/datasource/model/DataSourceInfo.java
+119
-0
magic-api/src/main/java/org/ssssssss/magicapi/datasource/model/MagicDynamicDataSource.java
...sss/magicapi/datasource/model/MagicDynamicDataSource.java
+242
-0
magic-api/src/main/java/org/ssssssss/magicapi/datasource/service/DataSourceEncryptProvider.java
...agicapi/datasource/service/DataSourceEncryptProvider.java
+23
-0
magic-api/src/main/java/org/ssssssss/magicapi/datasource/service/DataSourceInfoMagicResourceStorage.java
...atasource/service/DataSourceInfoMagicResourceStorage.java
+78
-0
magic-api/src/main/java/org/ssssssss/magicapi/datasource/service/DataSourceMagicDynamicRegistry.java
...pi/datasource/service/DataSourceMagicDynamicRegistry.java
+123
-0
magic-api/src/main/java/org/ssssssss/magicapi/datasource/web/MagicDataSourceController.java
...ss/magicapi/datasource/web/MagicDataSourceController.java
+32
-0
magic-api/src/main/java/org/ssssssss/magicapi/function/model/FunctionInfo.java
...va/org/ssssssss/magicapi/function/model/FunctionInfo.java
+107
-0
magic-api/src/main/java/org/ssssssss/magicapi/function/service/FunctionInfoMagicResourceStorage.java
...pi/function/service/FunctionInfoMagicResourceStorage.java
+27
-0
magic-api/src/main/java/org/ssssssss/magicapi/function/service/FunctionMagicDynamicRegistry.java
...gicapi/function/service/FunctionMagicDynamicRegistry.java
+74
-0
magic-api/src/main/java/org/ssssssss/magicapi/jsr223/JSR223LanguageProvider.java
.../org/ssssssss/magicapi/jsr223/JSR223LanguageProvider.java
+41
-0
magic-api/src/main/java/org/ssssssss/magicapi/jsr223/LanguageProvider.java
...n/java/org/ssssssss/magicapi/jsr223/LanguageProvider.java
+30
-0
magic-api/src/main/java/org/ssssssss/magicapi/modules/DynamicModule.java
...ain/java/org/ssssssss/magicapi/modules/DynamicModule.java
+11
-0
No files found.
magic-api/src/main/java/org/ssssssss/magicapi/core/servlet/MagicHttpSession.java
0 → 100644
View file @
02897568
package
org.ssssssss.magicapi.core.servlet
;
public
interface
MagicHttpSession
{
Object
getAttribute
(
String
key
);
void
setAttribute
(
String
key
,
Object
value
);
<
T
>
T
getSession
();
}
magic-api/src/main/java/org/ssssssss/magicapi/core/servlet/MagicRequestContextHolder.java
0 → 100644
View file @
02897568
package
org.ssssssss.magicapi.core.servlet
;
import
org.springframework.web.context.request.RequestAttributes
;
import
org.springframework.web.context.request.RequestContextHolder
;
import
org.springframework.web.context.request.ServletRequestAttributes
;
import
java.util.function.Function
;
public
interface
MagicRequestContextHolder
{
default
<
R
>
R
convert
(
Function
<
ServletRequestAttributes
,
R
>
function
){
RequestAttributes
requestAttributes
=
RequestContextHolder
.
getRequestAttributes
();
if
(
requestAttributes
instanceof
ServletRequestAttributes
)
{
ServletRequestAttributes
servletRequestAttributes
=
((
ServletRequestAttributes
)
requestAttributes
);
return
function
.
apply
(
servletRequestAttributes
);
}
return
null
;
}
MagicHttpServletRequest
getRequest
();
MagicHttpServletResponse
getResponse
();
}
magic-api/src/main/java/org/ssssssss/magicapi/core/web/MagicController.java
0 → 100644
View file @
02897568
package
org.ssssssss.magicapi.core.web
;
import
org.springframework.web.bind.annotation.ExceptionHandler
;
import
org.springframework.web.bind.annotation.ResponseBody
;
import
org.ssssssss.magicapi.backup.service.MagicBackupService
;
import
org.ssssssss.magicapi.core.annotation.Valid
;
import
org.ssssssss.magicapi.core.config.Constants
;
import
org.ssssssss.magicapi.core.config.JsonCodeConstants
;
import
org.ssssssss.magicapi.core.config.MagicConfiguration
;
import
org.ssssssss.magicapi.core.context.MagicUser
;
import
org.ssssssss.magicapi.core.exception.InvalidArgumentException
;
import
org.ssssssss.magicapi.core.exception.MagicLoginException
;
import
org.ssssssss.magicapi.core.interceptor.Authorization
;
import
org.ssssssss.magicapi.core.model.Group
;
import
org.ssssssss.magicapi.core.model.JsonBean
;
import
org.ssssssss.magicapi.core.model.MagicEntity
;
import
org.ssssssss.magicapi.core.service.MagicAPIService
;
import
org.ssssssss.magicapi.core.service.MagicResourceService
;
import
org.ssssssss.magicapi.core.servlet.MagicHttpServletRequest
;
import
java.util.List
;
import
java.util.Objects
;
import
java.util.stream.Collectors
;
/**
* Controller 基类
*
* @author mxd
*/
public
class
MagicController
implements
JsonCodeConstants
{
final
MagicAPIService
magicAPIService
;
final
MagicBackupService
magicBackupService
;
protected
MagicConfiguration
configuration
;
public
MagicController
(
MagicConfiguration
configuration
)
{
this
.
configuration
=
configuration
;
this
.
magicAPIService
=
configuration
.
getMagicAPIService
();
this
.
magicBackupService
=
configuration
.
getMagicBackupService
();
}
public
void
doValid
(
MagicHttpServletRequest
request
,
Valid
valid
)
{
if
(
valid
!=
null
)
{
if
(!
valid
.
readonly
()
&&
configuration
.
getWorkspace
().
readonly
())
{
throw
new
InvalidArgumentException
(
IS_READ_ONLY
);
}
if
(
valid
.
authorization
()
!=
Authorization
.
NONE
&&
!
allowVisit
(
request
,
valid
.
authorization
()))
{
throw
new
InvalidArgumentException
(
PERMISSION_INVALID
);
}
}
}
/**
* 判断是否有权限访问按钮
*/
boolean
allowVisit
(
MagicHttpServletRequest
request
,
Authorization
authorization
)
{
if
(
authorization
==
null
)
{
return
true
;
}
MagicUser
magicUser
=
(
MagicUser
)
request
.
getAttribute
(
Constants
.
ATTRIBUTE_MAGIC_USER
);
return
configuration
.
getAuthorizationInterceptor
().
allowVisit
(
magicUser
,
request
,
authorization
);
}
boolean
allowVisit
(
MagicHttpServletRequest
request
,
Authorization
authorization
,
MagicEntity
entity
)
{
if
(
authorization
==
null
)
{
return
true
;
}
MagicUser
magicUser
=
(
MagicUser
)
request
.
getAttribute
(
Constants
.
ATTRIBUTE_MAGIC_USER
);
return
configuration
.
getAuthorizationInterceptor
().
allowVisit
(
magicUser
,
request
,
authorization
,
entity
);
}
boolean
allowVisit
(
MagicHttpServletRequest
request
,
Authorization
authorization
,
Group
group
)
{
if
(
authorization
==
null
)
{
return
true
;
}
MagicUser
magicUser
=
(
MagicUser
)
request
.
getAttribute
(
Constants
.
ATTRIBUTE_MAGIC_USER
);
return
configuration
.
getAuthorizationInterceptor
().
allowVisit
(
magicUser
,
request
,
authorization
,
group
);
}
List
<
MagicEntity
>
entities
(
MagicHttpServletRequest
request
,
Authorization
authorization
)
{
MagicResourceService
service
=
configuration
.
getMagicResourceService
();
return
service
.
tree
()
.
values
()
.
stream
()
.
flatMap
(
it
->
it
.
flat
().
stream
())
.
filter
(
it
->
!
Constants
.
ROOT_ID
.
equals
(
it
.
getId
()))
.
filter
(
it
->
allowVisit
(
request
,
authorization
,
it
))
.
flatMap
(
it
->
service
.
listFiles
(
it
.
getId
()).
stream
())
.
filter
(
it
->
allowVisit
(
request
,
authorization
,
it
))
.
filter
(
it
->
Objects
.
nonNull
(
it
.
getScript
()))
.
collect
(
Collectors
.
toList
());
}
@ExceptionHandler
(
MagicLoginException
.
class
)
@ResponseBody
public
JsonBean
<
Void
>
invalidLogin
(
MagicLoginException
exception
)
{
return
new
JsonBean
<>(
401
,
exception
.
getMessage
());
}
}
magic-api/src/main/java/org/ssssssss/magicapi/core/web/MagicControllerRegister.java
0 → 100644
View file @
02897568
package
org.ssssssss.magicapi.core.web
;
import
org.ssssssss.magicapi.core.config.MagicConfiguration
;
import
org.ssssssss.magicapi.utils.Mapping
;
public
interface
MagicControllerRegister
{
void
register
(
Mapping
mapping
,
MagicConfiguration
configuration
);
}
magic-api/src/main/java/org/ssssssss/magicapi/core/web/MagicExceptionHandler.java
0 → 100644
View file @
02897568
package
org.ssssssss.magicapi.core.web
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.web.bind.annotation.ExceptionHandler
;
import
org.springframework.web.bind.annotation.ResponseBody
;
import
org.ssssssss.magicapi.core.exception.InvalidArgumentException
;
import
org.ssssssss.magicapi.core.model.JsonBean
;
/**
* magic-api接口异常处理器
*
* @author mxd
*/
public
interface
MagicExceptionHandler
{
Logger
logger
=
LoggerFactory
.
getLogger
(
MagicExceptionHandler
.
class
);
/**
* magic-api中的接口异常处理
*
* @param e 异常对象
* @return 返回json对象
*/
@ExceptionHandler
(
Exception
.
class
)
@ResponseBody
default
Object
exceptionHandler
(
Exception
e
)
{
logger
.
error
(
"magic-api调用接口出错"
,
e
);
return
new
JsonBean
<>(-
1
,
e
.
getMessage
());
}
/**
* magic-api中的接口异常处理
*
* @param e 异常对象
* @return 返回json对象
*/
@ExceptionHandler
(
InvalidArgumentException
.
class
)
@ResponseBody
default
Object
exceptionHandler
(
InvalidArgumentException
e
)
{
return
new
JsonBean
<>(
e
.
getCode
(),
e
.
getMessage
());
}
}
magic-api/src/main/java/org/ssssssss/magicapi/core/web/MagicResourceController.java
0 → 100644
View file @
02897568
package
org.ssssssss.magicapi.core.web
;
import
org.springframework.web.bind.annotation.*
;
import
org.ssssssss.magicapi.core.config.Constants
;
import
org.ssssssss.magicapi.core.config.MagicConfiguration
;
import
org.ssssssss.magicapi.core.exception.InvalidArgumentException
;
import
org.ssssssss.magicapi.core.interceptor.Authorization
;
import
org.ssssssss.magicapi.core.model.*
;
import
org.ssssssss.magicapi.core.resource.FileResource
;
import
org.ssssssss.magicapi.core.resource.Resource
;
import
org.ssssssss.magicapi.core.service.MagicDynamicRegistry
;
import
org.ssssssss.magicapi.core.service.MagicResourceService
;
import
org.ssssssss.magicapi.core.servlet.MagicHttpServletRequest
;
import
org.ssssssss.magicapi.utils.IoUtils
;
import
java.io.IOException
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Objects
;
import
java.util.function.Function
;
public
class
MagicResourceController
extends
MagicController
implements
MagicExceptionHandler
{
private
final
MagicResourceService
service
;
public
MagicResourceController
(
MagicConfiguration
configuration
)
{
super
(
configuration
);
this
.
service
=
MagicConfiguration
.
getMagicResourceService
();
}
@PostMapping
(
"/resource/folder/save"
)
@ResponseBody
public
JsonBean
<
String
>
saveFolder
(
@RequestBody
Group
group
,
MagicHttpServletRequest
request
)
{
isTrue
(
allowVisit
(
request
,
Authorization
.
SAVE
,
group
),
PERMISSION_INVALID
);
Resource
resource
=
service
.
getResource
();
if
(
resource
instanceof
FileResource
){
isTrue
(
resource
.
exists
(),
FILE_PATH_NOT_EXISTS
);
}
if
(
service
.
saveGroup
(
group
))
{
return
new
JsonBean
<>(
group
.
getId
());
}
return
new
JsonBean
<>((
String
)
null
);
}
@PostMapping
(
"/resource/folder/copy"
)
@ResponseBody
public
JsonBean
<
String
>
saveFolder
(
String
src
,
String
target
,
MagicHttpServletRequest
request
)
{
Group
srcGroup
=
service
.
getGroup
(
src
);
notNull
(
srcGroup
,
GROUP_NOT_FOUND
);
isTrue
(
allowVisit
(
request
,
Authorization
.
VIEW
,
srcGroup
),
PERMISSION_INVALID
);
Group
targetGroup
=
srcGroup
.
copy
();
targetGroup
.
setId
(
null
);
targetGroup
.
setParentId
(
target
);
targetGroup
.
setType
(
srcGroup
.
getType
());
isTrue
(
allowVisit
(
request
,
Authorization
.
SAVE
,
targetGroup
),
PERMISSION_INVALID
);
return
new
JsonBean
<>(
service
.
copyGroup
(
src
,
target
));
}
@PostMapping
(
"/resource/delete"
)
@ResponseBody
public
JsonBean
<
Boolean
>
delete
(
String
id
,
MagicHttpServletRequest
request
)
{
Group
group
=
service
.
getGroup
(
id
);
if
(
group
==
null
){
MagicEntity
entity
=
service
.
file
(
id
);
notNull
(
entity
,
FILE_NOT_FOUND
);
isTrue
(
allowVisit
(
request
,
Authorization
.
DELETE
,
entity
),
PERMISSION_INVALID
);
}
else
{
isTrue
(
allowVisit
(
request
,
Authorization
.
DELETE
,
group
),
PERMISSION_INVALID
);
}
return
new
JsonBean
<>(
service
.
delete
(
id
));
}
@PostMapping
(
"/resource/file/{folder}/save"
)
@ResponseBody
public
JsonBean
<
String
>
saveFile
(
@PathVariable
(
"folder"
)
String
folder
,
String
auto
,
MagicHttpServletRequest
request
)
throws
IOException
{
byte
[]
bytes
=
IoUtils
.
bytes
(
request
.
getInputStream
());
MagicEntity
entity
=
configuration
.
getMagicDynamicRegistries
().
stream
()
.
map
(
MagicDynamicRegistry:
:
getMagicResourceStorage
)
.
filter
(
it
->
Objects
.
equals
(
it
.
folder
(),
folder
))
.
findFirst
()
.
orElseThrow
(()
->
new
InvalidArgumentException
(
GROUP_NOT_FOUND
))
.
read
(
bytes
);
isTrue
(
allowVisit
(
request
,
Authorization
.
SAVE
,
entity
),
PERMISSION_INVALID
);
// 自动保存的代码,和旧版代码对比,如果一致,则不保存,直接返回。
if
(
entity
.
getId
()
!=
null
&&
"1"
.
equals
(
auto
)){
MagicEntity
oldInfo
=
service
.
file
(
entity
.
getId
());
if
(
oldInfo
!=
null
&&
Objects
.
equals
(
oldInfo
,
entity
)){
return
new
JsonBean
<>(
entity
.
getId
());
}
}
if
(
MagicConfiguration
.
getMagicResourceService
().
saveFile
(
entity
))
{
return
new
JsonBean
<>(
entity
.
getId
());
}
return
new
JsonBean
<>(
null
);
}
@GetMapping
(
"/resource/file/{id}"
)
@ResponseBody
public
JsonBean
<
MagicEntity
>
detail
(
@PathVariable
(
"id"
)
String
id
,
MagicHttpServletRequest
request
)
{
MagicEntity
entity
=
MagicConfiguration
.
getMagicResourceService
().
file
(
id
);
isTrue
(
allowVisit
(
request
,
Authorization
.
VIEW
,
entity
),
PERMISSION_INVALID
);
return
new
JsonBean
<>(
MagicConfiguration
.
getMagicResourceService
().
file
(
id
));
}
@PostMapping
(
"/resource/move"
)
@ResponseBody
public
JsonBean
<
Boolean
>
move
(
String
src
,
String
groupId
,
MagicHttpServletRequest
request
)
{
Group
group
=
service
.
getGroup
(
src
);
if
(
group
==
null
){
MagicEntity
entity
=
service
.
file
(
src
);
notNull
(
entity
,
FILE_NOT_FOUND
);
entity
=
entity
.
copy
();
entity
.
setGroupId
(
groupId
);
isTrue
(
allowVisit
(
request
,
Authorization
.
SAVE
,
entity
),
PERMISSION_INVALID
);
}
else
{
group
=
group
.
copy
();
group
.
setParentId
(
groupId
);
isTrue
(
allowVisit
(
request
,
Authorization
.
DELETE
,
group
),
PERMISSION_INVALID
);
}
return
new
JsonBean
<>(
service
.
move
(
src
,
groupId
));
}
@PostMapping
(
"/resource/lock"
)
@ResponseBody
public
JsonBean
<
Boolean
>
lock
(
String
id
,
MagicHttpServletRequest
request
)
{
MagicEntity
entity
=
service
.
file
(
id
);
notNull
(
entity
,
FILE_NOT_FOUND
);
isTrue
(
allowVisit
(
request
,
Authorization
.
LOCK
,
entity
),
PERMISSION_INVALID
);
return
new
JsonBean
<>(
service
.
lock
(
id
));
}
@PostMapping
(
"/resource/unlock"
)
@ResponseBody
public
JsonBean
<
Boolean
>
unlock
(
String
id
,
MagicHttpServletRequest
request
)
{
MagicEntity
entity
=
service
.
file
(
id
);
notNull
(
entity
,
FILE_NOT_FOUND
);
isTrue
(
allowVisit
(
request
,
Authorization
.
UNLOCK
,
entity
),
PERMISSION_INVALID
);
return
new
JsonBean
<>(
service
.
unlock
(
id
));
}
@GetMapping
(
"/resource"
)
@ResponseBody
public
JsonBean
<
Map
<
String
,
TreeNode
<
Attributes
<
Object
>>>>
resources
(
MagicHttpServletRequest
request
)
{
Map
<
String
,
TreeNode
<
Group
>>
tree
=
service
.
tree
();
Map
<
String
,
TreeNode
<
Attributes
<
Object
>>>
result
=
new
HashMap
<>();
tree
.
forEach
((
key
,
value
)
->
{
TreeNode
<
Attributes
<
Object
>>
node
=
process
(
value
,
request
);
List
<
TreeNode
<
Attributes
<
Object
>>>
groups
=
node
.
getChildren
();
if
(
groups
.
size
()
>
0
){
List
<
TreeNode
<
Attributes
<
Object
>>>
nodes
=
groups
.
get
(
0
).
getChildren
();
configuration
.
getMagicDynamicRegistries
().
stream
()
.
filter
(
it
->
it
.
getMagicResourceStorage
().
folder
().
equals
(
key
))
.
findFirst
()
.
map
(
MagicDynamicRegistry:
:
defaultMappings
)
.
ifPresent
(
mappings
->
{
for
(
MagicEntity
mapping
:
mappings
)
{
nodes
.
add
(
new
TreeNode
<>(
mapping
));
}
});
}
result
.
put
(
key
,
node
);
});
return
new
JsonBean
<>(
result
);
}
private
TreeNode
<
Attributes
<
Object
>>
process
(
TreeNode
<
Group
>
groupNode
,
MagicHttpServletRequest
request
)
{
TreeNode
<
Attributes
<
Object
>>
value
=
new
TreeNode
<>();
value
.
setNode
(
groupNode
.
getNode
());
groupNode
.
getChildren
().
stream
()
.
filter
(
it
->
allowVisit
(
request
,
Authorization
.
VIEW
,
it
.
getNode
()))
.
map
(
it
->
process
(
it
,
request
))
.
forEach
(
value:
:
addChild
);
if
(!
Constants
.
ROOT_ID
.
equals
(
groupNode
.
getNode
().
getId
()))
{
service
.
listFiles
(
groupNode
.
getNode
().
getId
())
.
stream
()
.
filter
(
it
->
allowVisit
(
request
,
Authorization
.
VIEW
,
it
))
.
map
(
MagicEntity:
:
simple
)
.
map
((
Function
<
MagicEntity
,
TreeNode
<
Attributes
<
Object
>>>)
TreeNode:
:
new
)
.
forEach
(
value:
:
addChild
);
}
return
value
;
}
}
magic-api/src/main/java/org/ssssssss/magicapi/core/web/MagicWorkbenchController.java
0 → 100644
View file @
02897568
package
org.ssssssss.magicapi.core.web
;
import
org.apache.commons.lang3.StringUtils
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.core.io.ClassPathResource
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.MediaType
;
import
org.springframework.util.ResourceUtils
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.multipart.MultipartFile
;
import
org.ssssssss.magicapi.core.annotation.Valid
;
import
org.ssssssss.magicapi.core.config.Constants
;
import
org.ssssssss.magicapi.core.config.MagicAPIProperties
;
import
org.ssssssss.magicapi.core.config.MagicConfiguration
;
import
org.ssssssss.magicapi.core.context.MagicUser
;
import
org.ssssssss.magicapi.core.exception.MagicLoginException
;
import
org.ssssssss.magicapi.core.interceptor.Authorization
;
import
org.ssssssss.magicapi.core.model.*
;
import
org.ssssssss.magicapi.core.service.MagicAPIService
;
import
org.ssssssss.magicapi.core.servlet.MagicHttpServletRequest
;
import
org.ssssssss.magicapi.core.servlet.MagicHttpServletResponse
;
import
org.ssssssss.magicapi.modules.db.SQLModule
;
import
org.ssssssss.magicapi.utils.ClassScanner
;
import
org.ssssssss.magicapi.utils.IoUtils
;
import
org.ssssssss.magicapi.utils.SignUtils
;
import
org.ssssssss.magicapi.utils.WebUtils
;
import
org.ssssssss.script.MagicResourceLoader
;
import
org.ssssssss.script.MagicScriptEngine
;
import
org.ssssssss.script.ScriptClass
;
import
org.ssssssss.script.parsing.Span
;
import
org.ssssssss.script.parsing.Tokenizer
;
import
java.io.*
;
import
java.net.URLEncoder
;
import
java.nio.file.Files
;
import
java.nio.file.Paths
;
import
java.util.*
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
import
java.util.stream.Collectors
;
import
java.util.stream.Stream
;
public
class
MagicWorkbenchController
extends
MagicController
implements
MagicExceptionHandler
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
MagicWorkbenchController
.
class
);
private
static
final
Pattern
SINGLE_LINE_COMMENT_TODO
=
Pattern
.
compile
(
"((TODO)|(todo)|(fixme)|(FIXME))[ \t]+[^\n]+"
);
private
static
final
Pattern
MULTI_LINE_COMMENT_TODO
=
Pattern
.
compile
(
"((TODO)|(todo)|(fixme)|(FIXME))[ \t]+[^\n(?!*/)]+"
);
private
final
String
secretKey
;
private
final
List
<
Plugin
>
plugins
;
private
final
MagicAPIProperties
properties
;
private
String
allClassTxt
;
public
MagicWorkbenchController
(
MagicConfiguration
configuration
,
MagicAPIProperties
properties
,
List
<
Plugin
>
plugins
)
{
super
(
configuration
);
this
.
properties
=
properties
;
this
.
plugins
=
plugins
;
this
.
secretKey
=
properties
.
getSecretKey
();
// 给前端添加代码提示
MagicScriptEngine
.
addScriptClass
(
SQLModule
.
class
);
MagicScriptEngine
.
addScriptClass
(
MagicAPIService
.
class
);
}
@GetMapping
({
""
,
"/"
})
@Valid
(
requireLogin
=
false
)
public
String
redirectIndex
(
MagicHttpServletRequest
request
)
{
if
(
request
.
getRequestURI
().
endsWith
(
"/"
))
{
return
"redirect:./index.html"
;
}
return
"redirect:"
+
properties
.
getWeb
()
+
"/index.html"
;
}
@GetMapping
(
"/config.json"
)
@Valid
(
requireLogin
=
false
)
@ResponseBody
public
MagicAPIProperties
readConfig
()
{
return
properties
;
}
@GetMapping
(
value
=
"/classes.txt"
,
produces
=
"text/plain"
)
@ResponseBody
@Valid
(
requireLogin
=
false
)
private
String
readClass
()
{
if
(
allClassTxt
==
null
)
{
try
{
allClassTxt
=
ClassScanner
.
compress
(
ClassScanner
.
scan
());
}
catch
(
Throwable
t
)
{
logger
.
warn
(
"扫描Class失败"
,
t
);
allClassTxt
=
""
;
}
}
return
allClassTxt
;
}
/**
* 获取所有class
*/
@PostMapping
(
"/classes"
)
@ResponseBody
@Valid
(
requireLogin
=
false
)
public
JsonBean
<
Map
<
String
,
Object
>>
classes
()
{
Map
<
String
,
ScriptClass
>
classMap
=
MagicScriptEngine
.
getScriptClassMap
();
classMap
.
putAll
(
MagicResourceLoader
.
getModules
());
Map
<
String
,
Object
>
values
=
new
HashMap
<>();
values
.
put
(
"classes"
,
classMap
);
values
.
put
(
"extensions"
,
MagicScriptEngine
.
getExtensionScriptClass
());
values
.
put
(
"functions"
,
MagicScriptEngine
.
getFunctions
());
return
new
JsonBean
<>(
values
);
}
/**
* 获取单个class
*
* @param className 类名
*/
@PostMapping
(
"/class"
)
@ResponseBody
public
JsonBean
<
Set
<
ScriptClass
>>
clazz
(
String
className
)
{
if
(
StringUtils
.
isBlank
(
className
))
{
return
new
JsonBean
<>(
Collections
.
emptySet
());
}
return
new
JsonBean
<>(
MagicScriptEngine
.
getScriptClass
(
className
));
}
/**
* 登录
*/
@PostMapping
(
"/login"
)
@ResponseBody
@Valid
(
requireLogin
=
false
)
public
JsonBean
<
Boolean
>
login
(
String
username
,
String
password
,
MagicHttpServletRequest
request
,
MagicHttpServletResponse
response
)
throws
MagicLoginException
{
if
(
configuration
.
getAuthorizationInterceptor
().
requireLogin
())
{
if
(
StringUtils
.
isBlank
(
username
)
&&
StringUtils
.
isBlank
(
password
))
{
try
{
configuration
.
getAuthorizationInterceptor
().
getUserByToken
(
request
.
getHeader
(
Constants
.
MAGIC_TOKEN_HEADER
));
}
catch
(
MagicLoginException
ignored
)
{
return
new
JsonBean
<>(
false
);
}
}
else
{
MagicUser
user
=
configuration
.
getAuthorizationInterceptor
().
login
(
username
,
password
);
response
.
setHeader
(
Constants
.
MAGIC_TOKEN_HEADER
,
user
.
getToken
());
response
.
setHeader
(
HttpHeaders
.
ACCESS_CONTROL_EXPOSE_HEADERS
,
Constants
.
MAGIC_TOKEN_HEADER
);
}
}
return
new
JsonBean
<>(
true
);
}
@PostMapping
(
"/user"
)
@ResponseBody
public
JsonBean
<
MagicUser
>
user
(
MagicHttpServletRequest
request
)
{
if
(
configuration
.
getAuthorizationInterceptor
().
requireLogin
())
{
try
{
return
new
JsonBean
<>(
configuration
.
getAuthorizationInterceptor
().
getUserByToken
(
request
.
getHeader
(
Constants
.
MAGIC_TOKEN_HEADER
)));
}
catch
(
MagicLoginException
ignored
)
{
}
}
return
new
JsonBean
<>(
MagicUser
.
guest
());
}
@PostMapping
(
"/logout"
)
@ResponseBody
@Valid
(
requireLogin
=
false
)
public
JsonBean
<
Void
>
logout
(
MagicHttpServletRequest
request
)
{
configuration
.
getAuthorizationInterceptor
().
logout
(
request
.
getHeader
(
Constants
.
MAGIC_TOKEN_HEADER
));
return
new
JsonBean
<>();
}
@GetMapping
(
"/plugins"
)
@Valid
(
requireLogin
=
false
)
@ResponseBody
public
JsonBean
<
List
<
Plugin
>>
plugins
()
{
return
new
JsonBean
<>(
plugins
);
}
@RequestMapping
(
"/options"
)
@ResponseBody
@Valid
(
requireLogin
=
false
)
public
JsonBean
<
List
<
List
<
String
>>>
options
()
{
return
new
JsonBean
<>(
Stream
.
of
(
Options
.
values
()).
map
(
item
->
Arrays
.
asList
(
item
.
getValue
(),
item
.
getName
(),
item
.
getDefaultValue
())).
collect
(
Collectors
.
toList
()));
}
@GetMapping
(
"/reload"
)
@ResponseBody
public
JsonBean
<
Boolean
>
reload
(
MagicHttpServletRequest
request
)
{
isTrue
(
allowVisit
(
request
,
Authorization
.
RELOAD
),
PERMISSION_INVALID
);
MagicConfiguration
.
getMagicResourceService
().
refresh
();
return
new
JsonBean
<>(
true
);
}
@GetMapping
(
"/search"
)
@ResponseBody
public
JsonBean
<
List
<
Map
<
String
,
Object
>>>
search
(
String
keyword
,
MagicHttpServletRequest
request
)
{
if
(
StringUtils
.
isBlank
(
keyword
))
{
return
new
JsonBean
<>(
Collections
.
emptyList
());
}
return
new
JsonBean
<>(
entities
(
request
,
Authorization
.
VIEW
)
.
stream
()
.
filter
(
it
->
it
.
getScript
().
contains
(
keyword
))
.
map
(
it
->
{
String
script
=
it
.
getScript
();
int
index
=
script
.
indexOf
(
keyword
);
int
endIndex
=
script
.
indexOf
(
"\n"
,
index
+
keyword
.
length
());
index
=
script
.
lastIndexOf
(
"\n"
,
index
)
+
1
;
Span
span
=
new
Span
(
script
,
index
,
endIndex
==
-
1
?
script
.
length
()
:
endIndex
);
return
new
HashMap
<
String
,
Object
>()
{
{
put
(
"id"
,
it
.
getId
());
put
(
"text"
,
span
.
getText
().
trim
());
put
(
"line"
,
span
.
getLine
().
getLineNumber
());
}
};
}).
collect
(
Collectors
.
toList
()));
}
@GetMapping
(
"/todo"
)
@ResponseBody
@Valid
public
JsonBean
<
List
<
Map
<
String
,
Object
>>>
todo
(
MagicHttpServletRequest
request
)
{
List
<
MagicEntity
>
entities
=
entities
(
request
,
Authorization
.
VIEW
);
List
<
Map
<
String
,
Object
>>
result
=
new
ArrayList
<>(
entities
.
size
());
for
(
MagicEntity
entity
:
entities
)
{
try
{
List
<
Span
>
comments
=
Tokenizer
.
tokenize
(
entity
.
getScript
(),
true
).
comments
();
for
(
Span
comment
:
comments
)
{
String
text
=
comment
.
getText
();
Pattern
pattern
=
text
.
startsWith
(
"//"
)
?
SINGLE_LINE_COMMENT_TODO
:
MULTI_LINE_COMMENT_TODO
;
Matcher
matcher
=
pattern
.
matcher
(
text
);
while
(
matcher
.
find
())
{
result
.
add
(
new
HashMap
<
String
,
Object
>()
{
{
put
(
"id"
,
entity
.
getId
());
put
(
"text"
,
matcher
.
group
(
0
).
trim
());
put
(
"line"
,
comment
.
getLine
().
getLineNumber
());
}
});
}
}
}
catch
(
Exception
ignored
)
{
}
}
return
new
JsonBean
<>(
result
);
}
@RequestMapping
(
value
=
"/config-js"
)
@Valid
(
requireLogin
=
false
)
public
void
configJs
(
MagicHttpServletResponse
response
)
throws
IOException
{
response
.
setContentType
(
"application/javascript"
);
response
.
setCharacterEncoding
(
"UTF-8"
);
byte
[]
bytes
=
"var MAGIC_EDITOR_CONFIG = {}"
.
getBytes
();
if
(
configuration
.
getEditorConfig
()
!=
null
)
{
try
{
String
path
=
configuration
.
getEditorConfig
();
if
(
path
.
startsWith
(
ResourceUtils
.
CLASSPATH_URL_PREFIX
))
{
path
=
path
.
substring
(
ResourceUtils
.
CLASSPATH_URL_PREFIX
.
length
());
bytes
=
IoUtils
.
bytes
(
new
ClassPathResource
(
path
).
getInputStream
());
}
File
file
=
ResourceUtils
.
getFile
(
configuration
.
getEditorConfig
());
bytes
=
Files
.
readAllBytes
(
Paths
.
get
(
file
.
toURI
()));
}
catch
(
IOException
e
)
{
logger
.
warn
(
"读取编辑器配置文件{}失败"
,
configuration
.
getEditorConfig
());
}
}
try
(
OutputStream
stream
=
response
.
getOutputStream
())
{
stream
.
write
(
bytes
);
stream
.
flush
();
}
}
@RequestMapping
(
"/download"
)
@Valid
(
authorization
=
Authorization
.
DOWNLOAD
)
public
void
download
(
String
groupId
,
@RequestBody
(
required
=
false
)
List
<
SelectedResource
>
resources
,
MagicHttpServletRequest
request
,
MagicHttpServletResponse
response
)
throws
IOException
{
isTrue
(
allowVisit
(
request
,
Authorization
.
DOWNLOAD
),
PERMISSION_INVALID
);
response
.
setContentType
(
MediaType
.
APPLICATION_OCTET_STREAM_VALUE
);
ByteArrayOutputStream
os
=
new
ByteArrayOutputStream
();
magicAPIService
.
download
(
groupId
,
resources
,
os
);
String
filename
=
"magic-api-all.zip"
;
if
(
StringUtils
.
isBlank
(
groupId
))
{
filename
=
"magic-api-group.zip"
;
}
response
.
setHeader
(
HttpHeaders
.
CONTENT_DISPOSITION
,
"attachment; filename="
+
URLEncoder
.
encode
(
filename
,
"UTF-8"
));
try
(
OutputStream
stream
=
response
.
getOutputStream
())
{
stream
.
write
(
os
.
toByteArray
());
stream
.
flush
();
}
}
@RequestMapping
(
"/upload"
)
@Valid
(
readonly
=
false
,
authorization
=
Authorization
.
UPLOAD
)
@ResponseBody
public
JsonBean
<
Boolean
>
upload
(
MultipartFile
file
,
String
mode
,
MagicHttpServletRequest
request
)
throws
IOException
{
notNull
(
file
,
FILE_IS_REQUIRED
);
isTrue
(
allowVisit
(
request
,
Authorization
.
UPLOAD
),
PERMISSION_INVALID
);
if
(
configuration
.
getMagicBackupService
()
!=
null
)
{
configuration
.
getMagicBackupService
().
doBackupAll
(
"上传前,系统自动全量备份"
,
WebUtils
.
currentUserName
());
}
return
new
JsonBean
<>(
magicAPIService
.
upload
(
file
.
getInputStream
(),
mode
));
}
@RequestMapping
(
"/push"
)
@ResponseBody
@Valid
(
authorization
=
Authorization
.
PUSH
)
public
JsonBean
<?>
push
(
@RequestHeader
(
"magic-push-target"
)
String
target
,
@RequestHeader
(
"magic-push-secret-key"
)
String
secretKey
,
@RequestHeader
(
"magic-push-mode"
)
String
mode
,
@RequestBody
List
<
SelectedResource
>
resources
,
MagicHttpServletRequest
request
)
{
isTrue
(
allowVisit
(
request
,
Authorization
.
PUSH
),
PERMISSION_INVALID
);
return
magicAPIService
.
push
(
target
,
secretKey
,
mode
,
resources
);
}
@ResponseBody
@Valid
(
requireLogin
=
false
)
public
JsonBean
<
Void
>
receivePush
(
MultipartFile
file
,
String
mode
,
Long
timestamp
,
String
sign
)
throws
IOException
{
notNull
(
timestamp
,
SIGN_IS_INVALID
);
notBlank
(
mode
,
SIGN_IS_INVALID
);
notBlank
(
sign
,
SIGN_IS_INVALID
);
notNull
(
file
,
SIGN_IS_INVALID
);
byte
[]
bytes
=
IoUtils
.
bytes
(
file
.
getInputStream
());
isTrue
(
sign
.
equals
(
SignUtils
.
sign
(
timestamp
,
secretKey
,
mode
,
bytes
)),
SIGN_IS_INVALID
);
if
(
configuration
.
getMagicBackupService
()
!=
null
)
{
configuration
.
getMagicBackupService
().
doBackupAll
(
"推送前,系统自动全量备份"
,
WebUtils
.
currentUserName
());
}
magicAPIService
.
upload
(
new
ByteArrayInputStream
(
bytes
),
mode
);
return
new
JsonBean
<>();
}
}
magic-api/src/main/java/org/ssssssss/magicapi/core/web/RequestHandler.java
0 → 100644
View file @
02897568
package
org.ssssssss.magicapi.core.web
;
import
org.apache.commons.lang3.StringUtils
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.http.MediaType
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.http.converter.HttpMessageConverter
;
import
org.springframework.http.converter.HttpMessageNotReadableException
;
import
org.springframework.util.CollectionUtils
;
import
org.springframework.util.LinkedCaseInsensitiveMap
;
import
org.springframework.web.bind.annotation.PathVariable
;
import
org.springframework.web.bind.annotation.RequestHeader
;
import
org.springframework.web.bind.annotation.RequestParam
;
import
org.springframework.web.bind.annotation.ResponseBody
;
import
org.ssssssss.magicapi.core.annotation.Valid
;
import
org.ssssssss.magicapi.core.config.Constants
;
import
org.ssssssss.magicapi.core.config.MagicConfiguration
;
import
org.ssssssss.magicapi.core.config.WebSocketSessionManager
;
import
org.ssssssss.magicapi.core.context.CookieContext
;
import
org.ssssssss.magicapi.core.context.RequestContext
;
import
org.ssssssss.magicapi.core.context.RequestEntity
;
import
org.ssssssss.magicapi.core.context.SessionContext
;
import
org.ssssssss.magicapi.core.exception.ValidateException
;
import
org.ssssssss.magicapi.core.interceptor.RequestInterceptor
;
import
org.ssssssss.magicapi.core.interceptor.ResultProvider
;
import
org.ssssssss.magicapi.core.logging.MagicLoggerContext
;
import
org.ssssssss.magicapi.core.model.*
;
import
org.ssssssss.magicapi.core.service.impl.RequestMagicDynamicRegistry
;
import
org.ssssssss.magicapi.core.servlet.MagicHttpServletRequest
;
import
org.ssssssss.magicapi.core.servlet.MagicHttpServletResponse
;
import
org.ssssssss.magicapi.modules.servlet.ResponseModule
;
import
org.ssssssss.magicapi.utils.PatternUtils
;
import
org.ssssssss.magicapi.utils.ScriptManager
;
import
org.ssssssss.script.MagicScriptContext
;
import
org.ssssssss.script.MagicScriptDebugContext
;
import
org.ssssssss.script.exception.MagicScriptAssertException
;
import
org.ssssssss.script.exception.MagicScriptException
;
import
org.ssssssss.script.functions.ObjectConvertExtension
;
import
org.ssssssss.script.parsing.Span
;
import
org.ssssssss.script.parsing.ast.literal.BooleanLiteral
;
import
org.ssssssss.script.reflection.JavaInvoker
;
import
java.io.IOException
;
import
java.lang.reflect.Method
;
import
java.math.BigDecimal
;
import
java.util.*
;
import
java.util.stream.Collectors
;
import
static
org
.
springframework
.
http
.
HttpHeaders
.*;
import
static
org
.
ssssssss
.
magicapi
.
core
.
config
.
Constants
.*;
import
static
org
.
ssssssss
.
magicapi
.
core
.
config
.
MessageType
.
EXCEPTION
;
/**
* 请求入口处理
*
* @author mxd
*/
public
class
RequestHandler
extends
MagicController
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
RequestHandler
.
class
);
private
static
final
Map
<
String
,
Object
>
EMPTY_MAP
=
new
HashMap
<>();
private
static
final
List
<
String
>
DEFAULT_ALLOW_READ_RESPONSE_HEADERS
=
Arrays
.
asList
(
ACCESS_CONTROL_ALLOW_CREDENTIALS
,
ACCESS_CONTROL_ALLOW_HEADERS
,
ACCESS_CONTROL_ALLOW_METHODS
,
ACCESS_CONTROL_ALLOW_METHODS
,
CONTENT_TYPE
,
DATE
,
SERVER
,
SET_COOKIE
,
CONNECTION
,
CONTENT_LENGTH
,
CONTENT_ENCODING
,
TRANSFER_ENCODING
,
VARY
);
private
final
ResultProvider
resultProvider
;
private
final
RequestMagicDynamicRegistry
requestMagicDynamicRegistry
;
public
RequestHandler
(
MagicConfiguration
configuration
,
RequestMagicDynamicRegistry
requestMagicDynamicRegistry
)
{
super
(
configuration
);
this
.
requestMagicDynamicRegistry
=
requestMagicDynamicRegistry
;
this
.
resultProvider
=
configuration
.
getResultProvider
();
}
/**
* 测试入口、实际请求入口
*
* @param request HttpServletRequest
* @param response HttpServletResponse
* @param pathVariables 路径变量
* @param parameters 表单参数&URL参数
* @return 返回请求结果
* @throws Throwable 处理失败抛出的异常
*/
@ResponseBody
@Valid
(
requireLogin
=
false
)
public
Object
invoke
(
MagicHttpServletRequest
request
,
MagicHttpServletResponse
response
,
@PathVariable
(
required
=
false
)
Map
<
String
,
Object
>
pathVariables
,
@RequestHeader
(
required
=
false
)
Map
<
String
,
Object
>
defaultHeaders
,
@RequestParam
(
required
=
false
)
Map
<
String
,
Object
>
parameters
)
throws
Throwable
{
String
clientId
=
null
;
Map
<
String
,
Object
>
headers
=
new
LinkedCaseInsensitiveMap
<>();
headers
.
putAll
(
defaultHeaders
);
boolean
requestedFromTest
=
configuration
.
isEnableWeb
()
&&
(
clientId
=
request
.
getHeader
(
HEADER_REQUEST_CLIENT_ID
))
!=
null
&&
request
.
getHeader
(
HEADER_REQUEST_SCRIPT_ID
)
!=
null
;
RequestEntity
requestEntity
=
RequestEntity
.
create
()
.
info
(
requestMagicDynamicRegistry
.
getApiInfoFromRequest
(
request
))
.
request
(
request
)
.
response
(
response
)
.
requestedFromTest
(
requestedFromTest
)
// 兼容 spring boot 3.0
.
pathVariables
(
new
HashMap
<>(
pathVariables
))
.
parameters
(
parameters
);
ApiInfo
info
=
requestEntity
.
getApiInfo
();
if
(
info
==
null
)
{
logger
.
error
(
"{}找不到对应接口"
,
request
.
getRequestURI
());
return
afterCompletion
(
requestEntity
,
buildResult
(
requestEntity
,
API_NOT_FOUND
,
"接口不存在"
));
}
requestEntity
.
setHeaders
(
headers
);
List
<
Path
>
paths
=
new
ArrayList
<>(
info
.
getPaths
());
MagicConfiguration
.
getMagicResourceService
().
getGroupsByFileId
(
info
.
getId
())
.
stream
()
.
flatMap
(
it
->
it
.
getPaths
().
stream
())
.
filter
(
it
->
!
paths
.
contains
(
it
))
.
forEach
(
paths:
:
add
);
Object
bodyValue
=
readRequestBody
(
requestEntity
.
getRequest
());
requestEntity
.
setRequestBody
(
bodyValue
);
String
scriptName
=
MagicConfiguration
.
getMagicResourceService
().
getScriptName
(
info
);
MagicScriptContext
context
=
createMagicScriptContext
(
scriptName
,
requestEntity
);
requestEntity
.
setMagicScriptContext
(
context
);
try
{
boolean
disabledUnknownParameter
=
CONST_STRING_TRUE
.
equalsIgnoreCase
(
info
.
getOptionValue
(
Options
.
DISABLED_UNKNOWN_PARAMETER
));
// 验证参数
doValidate
(
scriptName
,
"参数"
,
info
.
getParameters
(),
parameters
,
PARAMETER_INVALID
,
disabledUnknownParameter
);
Object
wrap
=
requestEntity
.
getApiInfo
().
getOptionValue
(
Options
.
WRAP_REQUEST_PARAMETERS
.
getValue
());
if
(
wrap
!=
null
&&
StringUtils
.
isNotBlank
(
wrap
.
toString
()))
{
context
.
set
(
wrap
.
toString
(),
requestEntity
.
getParameters
());
}
String
defaultDataSourceValue
=
requestEntity
.
getApiInfo
().
getOptionValue
(
Options
.
DEFAULT_DATA_SOURCE
.
getValue
());
if
(
defaultDataSourceValue
!=
null
)
{
context
.
set
(
Options
.
DEFAULT_DATA_SOURCE
.
getValue
(),
defaultDataSourceValue
);
}
context
.
putMapIntoContext
(
requestEntity
.
getParameters
());
// 验证 path
doValidate
(
scriptName
,
"path"
,
paths
,
requestEntity
.
getPathVariables
(),
PATH_VARIABLE_INVALID
,
disabledUnknownParameter
);
context
.
putMapIntoContext
(
requestEntity
.
getPathVariables
());
// 设置 cookie 变量
context
.
set
(
VAR_NAME_COOKIE
,
new
CookieContext
(
requestEntity
.
getRequest
()));
// 验证 header
doValidate
(
scriptName
,
"header"
,
info
.
getHeaders
(),
headers
,
HEADER_INVALID
,
disabledUnknownParameter
);
// 设置 header 变量
context
.
set
(
VAR_NAME_HEADER
,
headers
);
// 设置 session 变量
context
.
set
(
VAR_NAME_SESSION
,
new
SessionContext
(
requestEntity
.
getRequest
().
getSession
()));
// 设置 path 变量
context
.
set
(
VAR_NAME_PATH_VARIABLE
,
requestEntity
.
getPathVariables
());
// 设置 body 变量
if
(
bodyValue
!=
null
)
{
context
.
set
(
VAR_NAME_REQUEST_BODY
,
bodyValue
);
}
BaseDefinition
requestBody
=
info
.
getRequestBodyDefinition
();
if
(
requestBody
!=
null
&&
!
CONST_STRING_TRUE
.
equalsIgnoreCase
(
info
.
getOptionValue
(
Options
.
DISABLED_VALIDATE_REQUEST_BODY
))
&&
!
CollectionUtils
.
isEmpty
(
requestBody
.
getChildren
()))
{
requestBody
.
setName
(
StringUtils
.
defaultIfBlank
(
requestBody
.
getName
(),
"root"
));
doValidate
(
scriptName
,
VAR_NAME_REQUEST_BODY
,
Collections
.
singletonList
(
requestBody
),
new
HashMap
<
String
,
Object
>()
{{
put
(
requestBody
.
getName
(),
bodyValue
);
}},
BODY_INVALID
,
disabledUnknownParameter
);
}
}
catch
(
ValidateException
e
)
{
return
afterCompletion
(
requestEntity
,
resultProvider
.
buildResult
(
requestEntity
,
RESPONSE_CODE_INVALID
,
e
.
getMessage
()));
}
catch
(
Throwable
root
)
{
return
processException
(
requestEntity
,
root
);
}
RequestContext
.
setRequestEntity
(
requestEntity
);
Object
value
;
// 执行前置拦截器
if
((
value
=
doPreHandle
(
requestEntity
))
!=
null
)
{
return
afterCompletion
(
requestEntity
,
value
);
}
if
(
requestedFromTest
)
{
DebugRequest
debugRequest
=
requestEntity
.
getDebugRequest
();
String
sessionAndScriptId
=
debugRequest
.
getRequestedClientId
()
+
debugRequest
.
getRequestedScriptId
();
try
{
if
(
context
instanceof
MagicScriptDebugContext
)
{
WebSocketSessionManager
.
addMagicScriptContext
(
sessionAndScriptId
,
(
MagicScriptDebugContext
)
context
);
}
MagicLoggerContext
.
SESSION
.
set
(
clientId
);
return
invokeRequest
(
requestEntity
);
}
finally
{
MagicLoggerContext
.
remove
();
WebSocketSessionManager
.
removeMagicScriptContext
(
sessionAndScriptId
);
}
}
else
{
return
invokeRequest
(
requestEntity
);
}
}
private
Object
buildResult
(
RequestEntity
requestEntity
,
JsonCode
code
,
Object
data
)
{
return
resultProvider
.
buildResult
(
requestEntity
,
code
.
getCode
(),
code
.
getMessage
(),
data
);
}
private
void
removeUnknownKey
(
Map
<
String
,
Object
>
src
,
List
<?
extends
BaseDefinition
>
definitions
)
{
if
(!
src
.
isEmpty
())
{
Map
<
String
,
Object
>
newMap
=
new
HashMap
<>(
definitions
.
size
());
for
(
BaseDefinition
definition
:
definitions
)
{
newMap
.
put
(
definition
.
getName
(),
src
.
get
(
definition
.
getName
()));
}
src
.
clear
();
src
.
putAll
(
newMap
);
}
}
private
boolean
doValidateBody
(
String
comment
,
BaseDefinition
parameter
,
Map
<
String
,
Object
>
parameters
,
JsonCode
jsonCode
,
Class
<?>
target
)
{
if
(!
parameter
.
isRequired
()
&&
parameters
.
isEmpty
())
{
return
true
;
}
if
(
parameter
.
isRequired
()
&&
!
BooleanLiteral
.
isTrue
(
parameters
.
get
(
parameter
.
getName
())))
{
throw
new
ValidateException
(
jsonCode
,
StringUtils
.
defaultIfBlank
(
parameter
.
getError
(),
String
.
format
(
"%s[%s]为必填项"
,
comment
,
parameter
.
getName
())));
}
Object
value
=
parameters
.
get
(
parameter
.
getName
());
if
(
value
!=
null
&&
!
target
.
isAssignableFrom
(
value
.
getClass
()))
{
throw
new
ValidateException
(
jsonCode
,
StringUtils
.
defaultIfBlank
(
parameter
.
getError
(),
String
.
format
(
"%s[%s]数据类型错误"
,
comment
,
parameter
.
getName
())));
}
return
false
;
}
private
Map
<
String
,
Object
>
doValidate
(
String
scriptName
,
String
comment
,
List
<?
extends
BaseDefinition
>
validateParameters
,
Map
<
String
,
Object
>
parameters
,
JsonCode
jsonCode
,
boolean
disabledUnknownParameter
)
{
parameters
=
parameters
!=
null
?
parameters
:
EMPTY_MAP
;
if
(
CollectionUtils
.
isEmpty
(
validateParameters
))
{
return
parameters
;
}
if
(
disabledUnknownParameter
)
{
removeUnknownKey
(
parameters
,
validateParameters
);
}
for
(
BaseDefinition
parameter
:
validateParameters
)
{
if
(
parameter
.
getDataType
()
==
DataType
.
Any
)
{
continue
;
}
// 针对requestBody多层级的情况
if
(
DataType
.
Object
==
parameter
.
getDataType
())
{
if
(
doValidateBody
(
comment
,
parameter
,
parameters
,
jsonCode
,
Map
.
class
))
{
continue
;
}
doValidate
(
scriptName
,
VAR_NAME_REQUEST_BODY
,
parameter
.
getChildren
(),
(
Map
)
parameters
.
get
(
parameter
.
getName
()),
jsonCode
,
disabledUnknownParameter
);
}
else
if
(
DataType
.
Array
==
parameter
.
getDataType
())
{
if
(
doValidateBody
(
comment
,
parameter
,
parameters
,
jsonCode
,
List
.
class
))
{
continue
;
}
List
<
Object
>
list
=
(
List
)
parameters
.
get
(
parameter
.
getName
());
if
(
list
!=
null
)
{
List
<
Map
<
String
,
Object
>>
newList
=
list
.
stream
().
map
(
it
->
doValidate
(
scriptName
,
VAR_NAME_REQUEST_BODY
,
parameter
.
getChildren
(),
new
HashMap
<
String
,
Object
>()
{{
put
(
Constants
.
EMPTY
,
it
);
}},
jsonCode
,
disabledUnknownParameter
)).
collect
(
Collectors
.
toList
());
for
(
int
i
=
0
,
size
=
newList
.
size
();
i
<
size
;
i
++)
{
list
.
set
(
i
,
newList
.
get
(
i
).
get
(
Constants
.
EMPTY
));
}
}
}
else
if
(
StringUtils
.
isNotBlank
(
parameter
.
getName
())
||
parameters
.
containsKey
(
parameter
.
getName
()))
{
boolean
isFile
=
parameter
.
getDataType
()
==
DataType
.
MultipartFile
||
parameter
.
getDataType
()
==
DataType
.
MultipartFiles
;
String
requestValue
=
StringUtils
.
defaultIfBlank
(
Objects
.
toString
(
parameters
.
get
(
parameter
.
getName
()),
Constants
.
EMPTY
),
Objects
.
toString
(
parameter
.
getDefaultValue
(),
Constants
.
EMPTY
));
if
(
StringUtils
.
isBlank
(
requestValue
)
&&
!
isFile
)
{
if
(!
parameter
.
isRequired
())
{
continue
;
}
throw
new
ValidateException
(
jsonCode
,
StringUtils
.
defaultIfBlank
(
parameter
.
getError
(),
String
.
format
(
"%s[%s]为必填项"
,
comment
,
parameter
.
getName
())));
}
try
{
Object
value
=
convertValue
(
parameter
.
getDataType
(),
parameter
.
getName
(),
requestValue
);
if
(
isFile
&&
parameter
.
isRequired
())
{
if
(
value
==
null
||
(
parameter
.
getDataType
()
==
DataType
.
MultipartFiles
&&
((
List
<?>)
value
).
isEmpty
()))
{
throw
new
ValidateException
(
jsonCode
,
StringUtils
.
defaultIfBlank
(
parameter
.
getError
(),
String
.
format
(
"%s[%s]为必填项"
,
comment
,
parameter
.
getName
())));
}
}
// 正则验证
if
(
VALIDATE_TYPE_PATTERN
.
equals
(
parameter
.
getValidateType
()))
{
String
expression
=
parameter
.
getExpression
();
if
(
StringUtils
.
isNotBlank
(
expression
)
&&
!
PatternUtils
.
match
(
Objects
.
toString
(
value
,
Constants
.
EMPTY
),
expression
))
{
throw
new
ValidateException
(
jsonCode
,
StringUtils
.
defaultIfBlank
(
parameter
.
getError
(),
String
.
format
(
"%s[%s]不满足正则表达式"
,
comment
,
parameter
.
getName
())));
}
}
parameters
.
put
(
parameter
.
getName
(),
value
);
}
catch
(
ValidateException
ve
)
{
throw
ve
;
}
catch
(
Exception
e
)
{
throw
new
ValidateException
(
jsonCode
,
StringUtils
.
defaultIfBlank
(
parameter
.
getError
(),
String
.
format
(
"%s[%s]不合法"
,
comment
,
parameter
.
getName
())));
}
}
}
// 取出表达式验证的参数
List
<
BaseDefinition
>
validates
=
validateParameters
.
stream
().
filter
(
it
->
VALIDATE_TYPE_EXPRESSION
.
equals
(
it
.
getValidateType
())
&&
StringUtils
.
isNotBlank
(
it
.
getExpression
())).
collect
(
Collectors
.
toList
());
for
(
BaseDefinition
parameter
:
validates
)
{
MagicScriptContext
context
=
new
MagicScriptContext
();
// 将其他参数也放置脚本中,以实现“依赖”的情况
context
.
putMapIntoContext
(
parameters
);
Object
value
=
parameters
.
get
(
parameter
.
getName
());
if
(
value
!=
null
)
{
context
.
setScriptName
(
scriptName
);
// 设置自身变量
context
.
set
(
EXPRESSION_DEFAULT_VAR_NAME
,
value
);
if
(!
BooleanLiteral
.
isTrue
(
ScriptManager
.
executeExpression
(
parameter
.
getExpression
(),
context
)))
{
throw
new
ValidateException
(
jsonCode
,
StringUtils
.
defaultIfBlank
(
parameter
.
getError
(),
String
.
format
(
"%s[%s]不满足表达式"
,
comment
,
parameter
.
getName
())));
}
}
}
return
parameters
;
}
/**
* 转换参数类型
*/
private
Object
convertValue
(
DataType
dataType
,
String
name
,
String
value
)
{
if
(
dataType
==
null
)
{
return
value
;
}
try
{
if
(
dataType
.
isNumber
())
{
BigDecimal
decimal
=
ObjectConvertExtension
.
asDecimal
(
value
,
null
);
if
(
decimal
==
null
)
{
throw
new
IllegalArgumentException
();
}
return
dataType
.
getInvoker
().
invoke0
(
decimal
,
null
,
EMPTY_OBJECT_ARRAY
);
}
else
{
JavaInvoker
<
Method
>
invoker
=
dataType
.
getInvoker
();
if
(
invoker
!=
null
)
{
List
<
Object
>
params
=
new
ArrayList
<>();
if
(
dataType
.
isNeedName
())
{
params
.
add
(
name
);
}
if
(
dataType
.
isNeedValue
())
{
params
.
add
(
value
);
}
return
invoker
.
invoke0
(
null
,
null
,
params
.
toArray
());
}
}
return
value
;
}
catch
(
Throwable
throwable
)
{
throw
new
IllegalArgumentException
(
throwable
);
}
}
private
Object
invokeRequest
(
RequestEntity
requestEntity
)
throws
Throwable
{
try
{
MagicScriptContext
context
=
requestEntity
.
getMagicScriptContext
();
Object
result
=
ScriptManager
.
executeScript
(
requestEntity
.
getApiInfo
().
getScript
(),
context
);
Object
value
=
result
;
// 执行后置拦截器
if
((
value
=
doPostHandle
(
requestEntity
,
value
))
!=
null
)
{
return
afterCompletion
(
requestEntity
,
value
);
}
// 对返回结果包装处理
return
afterCompletion
(
requestEntity
,
response
(
requestEntity
,
result
));
}
catch
(
Throwable
root
)
{
return
processException
(
requestEntity
,
root
);
}
finally
{
RequestContext
.
remove
();
}
}
private
Object
processException
(
RequestEntity
requestEntity
,
Throwable
root
)
throws
Throwable
{
MagicScriptException
se
=
null
;
Throwable
parent
=
root
;
do
{
if
(
parent
instanceof
MagicScriptAssertException
)
{
MagicScriptAssertException
sae
=
(
MagicScriptAssertException
)
parent
;
return
afterCompletion
(
requestEntity
,
resultProvider
.
buildResult
(
requestEntity
,
sae
.
getCode
(),
sae
.
getMessage
()),
root
);
}
if
(
parent
instanceof
MagicScriptException
)
{
se
=
(
MagicScriptException
)
parent
;
}
}
while
((
parent
=
parent
.
getCause
())
!=
null
);
if
(
se
!=
null
&&
requestEntity
.
isRequestedFromTest
())
{
Span
.
Line
line
=
se
.
getLine
();
WebSocketSessionManager
.
sendByClientId
(
requestEntity
.
getDebugRequest
().
getRequestedClientId
(),
EXCEPTION
,
Arrays
.
asList
(
requestEntity
.
getDebugRequest
().
getRequestedScriptId
(),
se
.
getSimpleMessage
(),
line
==
null
?
null
:
Arrays
.
asList
(
line
.
getLineNumber
(),
line
.
getEndLineNumber
(),
line
.
getStartCol
(),
line
.
getEndCol
())
));
}
if
(
configuration
.
isThrowException
())
{
afterCompletion
(
requestEntity
,
null
,
root
);
throw
root
;
}
logger
.
error
(
"接口{}请求出错"
,
requestEntity
.
getRequest
().
getRequestURI
(),
root
);
return
afterCompletion
(
requestEntity
,
resultProvider
.
buildException
(
requestEntity
,
root
),
root
);
}
/**
* 读取RequestBody
*/
private
Object
readRequestBody
(
MagicHttpServletRequest
request
)
throws
IOException
{
if
(
configuration
.
getHttpMessageConverters
()
!=
null
&&
request
.
getContentType
()
!=
null
)
{
MediaType
mediaType
=
MediaType
.
valueOf
(
request
.
getContentType
());
Class
clazz
=
Object
.
class
;
try
{
for
(
HttpMessageConverter
<?>
converter
:
configuration
.
getHttpMessageConverters
())
{
if
(
converter
.
canRead
(
clazz
,
mediaType
))
{
return
converter
.
read
(
clazz
,
request
.
getHttpInputMessage
());
}
}
}
catch
(
HttpMessageNotReadableException
ignored
)
{
return
null
;
}
}
return
null
;
}
/**
* 构建 MagicScriptContext
*/
private
MagicScriptContext
createMagicScriptContext
(
String
scriptName
,
RequestEntity
requestEntity
)
{
DebugRequest
debugRequest
=
requestEntity
.
getDebugRequest
();
List
<
Integer
>
breakpoints
=
debugRequest
.
getRequestedBreakpoints
();
// 构建脚本上下文
MagicScriptContext
context
;
// TODO 安全校验
if
(
requestEntity
.
isRequestedFromDebug
()
&&
breakpoints
.
size
()
>
0
)
{
context
=
debugRequest
.
createMagicScriptContext
(
configuration
.
getDebugTimeout
());
}
else
{
context
=
new
MagicScriptContext
();
}
context
.
setScriptName
(
scriptName
);
return
context
;
}
/**
* 包装返回结果
*/
private
Object
response
(
RequestEntity
requestEntity
,
Object
value
)
{
if
(
value
instanceof
ResponseEntity
)
{
return
value
;
}
else
if
(
value
instanceof
ResponseModule
.
NullValue
)
{
return
null
;
}
return
resultProvider
.
buildResult
(
requestEntity
,
value
);
}
/**
* 执行后置拦截器
*/
private
Object
doPostHandle
(
RequestEntity
requestEntity
,
Object
value
)
throws
Exception
{
for
(
RequestInterceptor
requestInterceptor
:
configuration
.
getRequestInterceptors
())
{
Object
target
=
requestInterceptor
.
postHandle
(
requestEntity
,
value
);
if
(
target
!=
null
)
{
return
afterCompletion
(
requestEntity
,
target
);
}
}
return
null
;
}
private
Object
afterCompletion
(
RequestEntity
requestEntity
,
Object
returnValue
)
{
return
afterCompletion
(
requestEntity
,
returnValue
,
null
);
}
private
Object
afterCompletion
(
RequestEntity
requestEntity
,
Object
returnValue
,
Throwable
throwable
)
{
for
(
RequestInterceptor
requestInterceptor
:
configuration
.
getRequestInterceptors
())
{
try
{
requestInterceptor
.
afterCompletion
(
requestEntity
,
returnValue
,
throwable
);
}
catch
(
Exception
e
)
{
logger
.
warn
(
"执行afterCompletion出现出错"
,
e
);
}
}
Set
<
String
>
exposeHeaders
=
new
HashSet
<>(
16
);
if
(
returnValue
instanceof
ResponseEntity
)
{
exposeHeaders
.
addAll
(((
ResponseEntity
<?>)
returnValue
).
getHeaders
().
keySet
());
}
if
(
requestEntity
.
isRequestedFromTest
())
{
MagicHttpServletResponse
response
=
requestEntity
.
getResponse
();
exposeHeaders
.
addAll
(
response
.
getHeaderNames
());
exposeHeaders
.
addAll
(
DEFAULT_ALLOW_READ_RESPONSE_HEADERS
);
}
if
(!
exposeHeaders
.
isEmpty
())
{
requestEntity
.
getResponse
().
setHeader
(
ACCESS_CONTROL_EXPOSE_HEADERS
,
String
.
join
(
","
,
exposeHeaders
));
}
return
returnValue
;
}
/**
* 执行前置拦截器
*/
private
Object
doPreHandle
(
RequestEntity
requestEntity
)
throws
Exception
{
for
(
RequestInterceptor
requestInterceptor
:
configuration
.
getRequestInterceptors
())
{
Object
value
=
requestInterceptor
.
preHandle
(
requestEntity
);
if
(
value
!=
null
)
{
return
value
;
}
}
return
null
;
}
}
magic-api/src/main/java/org/ssssssss/magicapi/datasource/model/DataSourceInfo.java
0 → 100644
View file @
02897568
package
org.ssssssss.magicapi.datasource.model
;
import
org.ssssssss.magicapi.core.model.MagicEntity
;
public
class
DataSourceInfo
extends
MagicEntity
{
/**
* URL
*/
private
String
url
;
/**
* 用户名
*/
private
String
username
;
/**
* 密码
*/
private
String
password
;
/**
* 数据源key
*/
private
String
key
;
/**
* 最多返回条数
*/
private
int
maxRows
=
-
1
;
/**
* 驱动类
*/
private
String
driverClassName
;
/**
* 连接池类型
*/
private
String
type
;
public
String
getUrl
()
{
return
url
;
}
public
void
setUrl
(
String
url
)
{
this
.
url
=
url
;
}
public
String
getUsername
()
{
return
username
;
}
public
void
setUsername
(
String
username
)
{
this
.
username
=
username
;
}
public
String
getPassword
()
{
return
password
;
}
public
void
setPassword
(
String
password
)
{
this
.
password
=
password
;
}
public
String
getKey
()
{
return
key
;
}
public
void
setKey
(
String
key
)
{
this
.
key
=
key
;
}
public
int
getMaxRows
()
{
return
maxRows
;
}
public
void
setMaxRows
(
int
maxRows
)
{
this
.
maxRows
=
maxRows
;
}
public
String
getDriverClassName
()
{
return
driverClassName
;
}
public
void
setDriverClassName
(
String
driverClassName
)
{
this
.
driverClassName
=
driverClassName
;
}
public
String
getType
()
{
return
type
;
}
public
void
setType
(
String
type
)
{
this
.
type
=
type
;
}
@Override
public
MagicEntity
simple
()
{
DataSourceInfo
dataSourceInfo
=
new
DataSourceInfo
();
super
.
simple
(
dataSourceInfo
);
dataSourceInfo
.
setKey
(
this
.
key
);
return
dataSourceInfo
;
}
@Override
public
MagicEntity
copy
()
{
DataSourceInfo
dataSourceInfo
=
new
DataSourceInfo
();
super
.
copyTo
(
dataSourceInfo
);
dataSourceInfo
.
setUsername
(
this
.
username
);
dataSourceInfo
.
setPassword
(
this
.
password
);
dataSourceInfo
.
setUrl
(
this
.
url
);
dataSourceInfo
.
setDriverClassName
(
this
.
driverClassName
);
dataSourceInfo
.
setType
(
this
.
type
);
dataSourceInfo
.
setMaxRows
(
this
.
maxRows
);
dataSourceInfo
.
setKey
(
this
.
key
);
return
dataSourceInfo
;
}
}
magic-api/src/main/java/org/ssssssss/magicapi/datasource/model/MagicDynamicDataSource.java
0 → 100644
View file @
02897568
package
org.ssssssss.magicapi.datasource.model
;
import
org.apache.commons.lang3.StringUtils
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.jdbc.core.JdbcTemplate
;
import
org.springframework.jdbc.datasource.DataSourceTransactionManager
;
import
org.springframework.jdbc.datasource.DataSourceUtils
;
import
org.ssssssss.magicapi.modules.db.dialect.DialectAdapter
;
import
org.ssssssss.magicapi.core.exception.MagicAPIException
;
import
org.ssssssss.magicapi.modules.db.dialect.Dialect
;
import
org.ssssssss.magicapi.utils.Assert
;
import
org.ssssssss.magicapi.utils.IoUtils
;
import
javax.sql.DataSource
;
import
java.sql.Connection
;
import
java.util.*
;
/**
* 动态数据源对象
*
* @author mxd
*/
public
class
MagicDynamicDataSource
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
MagicDynamicDataSource
.
class
);
private
final
Map
<
String
,
MagicDynamicDataSource
.
DataSourceNode
>
dataSourceMap
=
new
HashMap
<>();
/**
* 注册默认数据源
*/
public
void
put
(
DataSource
dataSource
)
{
put
(
null
,
dataSource
);
}
/**
* 注册数据源(可以运行时注册)
*
* @param dataSourceKey 数据源Key
*/
public
void
put
(
String
dataSourceKey
,
DataSource
dataSource
)
{
put
(
dataSourceKey
,
dataSource
,
-
1
);
}
/**
* 注册数据源(可以运行时注册)
*
* @param dataSourceKey 数据源Key
* @param maxRows 最大返回行数
*/
public
void
put
(
String
dataSourceKey
,
DataSource
dataSource
,
int
maxRows
)
{
put
(
null
,
dataSourceKey
,
dataSourceKey
,
dataSource
,
maxRows
);
}
/**
* 注册数据源(可以运行时注册)
*
* @param id 数据源ID
* @param dataSourceKey 数据源Key
* @param datasourceName 数据源名称
*/
public
void
put
(
String
id
,
String
dataSourceKey
,
String
datasourceName
,
DataSource
dataSource
,
int
maxRows
)
{
if
(
dataSourceKey
==
null
)
{
dataSourceKey
=
""
;
}
logger
.
info
(
"注册数据源:{}"
,
StringUtils
.
isNotBlank
(
dataSourceKey
)
?
dataSourceKey
:
"default"
);
DataSourceNode
node
=
this
.
dataSourceMap
.
put
(
dataSourceKey
,
new
DataSourceNode
(
dataSource
,
dataSourceKey
,
datasourceName
,
id
,
maxRows
));
if
(
node
!=
null
)
{
node
.
close
();
}
if
(
id
!=
null
)
{
String
finalDataSourceKey
=
dataSourceKey
;
this
.
dataSourceMap
.
entrySet
().
stream
()
.
filter
(
it
->
id
.
equals
(
it
.
getValue
().
getId
())
&&
!
finalDataSourceKey
.
equals
(
it
.
getValue
().
getKey
()))
.
findFirst
()
.
ifPresent
(
it
->
{
logger
.
info
(
"移除旧数据源:{}"
,
it
.
getValue
().
getKey
());
this
.
dataSourceMap
.
remove
(
it
.
getValue
().
getKey
()).
close
();
});
}
}
/**
* 获取全部数据源
*/
public
List
<
String
>
datasources
()
{
return
new
ArrayList
<>(
this
.
dataSourceMap
.
keySet
());
}
public
boolean
isEmpty
()
{
return
this
.
dataSourceMap
.
isEmpty
();
}
/**
* 获取全部数据源
*/
public
Collection
<
DataSourceNode
>
datasourceNodes
()
{
return
this
.
dataSourceMap
.
values
();
}
/**
* 删除数据源
*
* @param datasourceKey 数据源Key
*/
public
boolean
delete
(
String
datasourceKey
)
{
boolean
result
=
false
;
// 检查参数是否合法
if
(
datasourceKey
!=
null
&&
!
datasourceKey
.
isEmpty
())
{
DataSourceNode
node
=
this
.
dataSourceMap
.
remove
(
datasourceKey
);
result
=
node
!=
null
;
if
(
result
)
{
node
.
close
();
}
}
logger
.
info
(
"删除数据源:{}:{}"
,
datasourceKey
,
result
?
"成功"
:
"失败"
);
return
result
;
}
/**
* 获取默认数据源
*/
public
MagicDynamicDataSource
.
DataSourceNode
getDataSource
()
{
return
getDataSource
(
null
);
}
/**
* 获取数据源
*
* @param datasourceKey 数据源Key
*/
public
MagicDynamicDataSource
.
DataSourceNode
getDataSource
(
String
datasourceKey
)
{
if
(
datasourceKey
==
null
)
{
datasourceKey
=
""
;
}
MagicDynamicDataSource
.
DataSourceNode
dataSourceNode
=
dataSourceMap
.
get
(
datasourceKey
);
Assert
.
isNotNull
(
dataSourceNode
,
String
.
format
(
"找不到数据源%s"
,
datasourceKey
));
return
dataSourceNode
;
}
/**
* 设置默认数据源
*/
public
void
setDefault
(
DataSource
dataSource
)
{
put
(
dataSource
);
}
/**
* 设置默认数据源
*
* @param maxRows 最大返回行数
*/
public
void
setDefault
(
DataSource
dataSource
,
int
maxRows
)
{
put
(
null
,
null
,
null
,
dataSource
,
maxRows
);
}
public
void
add
(
String
dataSourceKey
,
DataSource
dataSource
)
{
put
(
dataSourceKey
,
dataSource
);
}
public
void
add
(
String
dataSourceKey
,
DataSource
dataSource
,
int
maxRows
)
{
put
(
null
,
dataSourceKey
,
dataSourceKey
,
dataSource
,
maxRows
);
}
public
static
class
DataSourceNode
{
private
final
String
id
;
private
final
String
key
;
private
final
String
name
;
/**
* 事务管理器
*/
private
final
DataSourceTransactionManager
dataSourceTransactionManager
;
private
final
JdbcTemplate
jdbcTemplate
;
private
final
DataSource
dataSource
;
private
Dialect
dialect
;
DataSourceNode
(
DataSource
dataSource
,
String
key
,
String
name
,
String
id
,
int
maxRows
)
{
this
.
dataSource
=
dataSource
;
this
.
key
=
key
;
this
.
name
=
name
;
this
.
id
=
id
;
this
.
dataSourceTransactionManager
=
new
DataSourceTransactionManager
(
this
.
dataSource
);
this
.
jdbcTemplate
=
new
JdbcTemplate
(
dataSource
);
this
.
jdbcTemplate
.
setMaxRows
(
maxRows
);
}
public
String
getId
()
{
return
id
;
}
public
String
getName
()
{
return
name
;
}
public
String
getKey
()
{
return
key
;
}
public
JdbcTemplate
getJdbcTemplate
()
{
return
this
.
jdbcTemplate
;
}
public
DataSourceTransactionManager
getDataSourceTransactionManager
()
{
return
dataSourceTransactionManager
;
}
public
Dialect
getDialect
(
DialectAdapter
dialectAdapter
)
{
if
(
this
.
dialect
==
null
)
{
Connection
connection
=
null
;
try
{
connection
=
this
.
dataSource
.
getConnection
();
this
.
dialect
=
dialectAdapter
.
getDialectFromConnection
(
connection
);
if
(
this
.
dialect
==
null
)
{
throw
new
MagicAPIException
(
"自动获取数据库方言失败"
);
}
}
catch
(
Exception
e
)
{
throw
new
MagicAPIException
(
"自动获取数据库方言失败"
,
e
);
}
finally
{
DataSourceUtils
.
releaseConnection
(
connection
,
this
.
dataSource
);
}
}
return
dialect
;
}
public
DataSource
getDataSource
()
{
return
dataSource
;
}
public
void
close
()
{
IoUtils
.
closeDataSource
(
this
.
dataSource
);
}
}
}
magic-api/src/main/java/org/ssssssss/magicapi/datasource/service/DataSourceEncryptProvider.java
0 → 100644
View file @
02897568
package
org.ssssssss.magicapi.datasource.service
;
import
org.ssssssss.magicapi.datasource.model.DataSourceInfo
;
/**
* 数据源加解密
*
* @since 1.7.0
*/
public
interface
DataSourceEncryptProvider
{
/**
* 加密
* @param dataSourceInfo 数据源信息
*/
void
encrypt
(
DataSourceInfo
dataSourceInfo
);
/**
* 解密
* @param dataSourceInfo 数据源信息
*/
void
decrypt
(
DataSourceInfo
dataSourceInfo
);
}
magic-api/src/main/java/org/ssssssss/magicapi/datasource/service/DataSourceInfoMagicResourceStorage.java
0 → 100644
View file @
02897568
package
org.ssssssss.magicapi.datasource.service
;
import
org.ssssssss.magicapi.datasource.model.DataSourceInfo
;
import
org.ssssssss.magicapi.core.config.JsonCodeConstants
;
import
org.ssssssss.magicapi.core.model.MagicEntity
;
import
org.ssssssss.magicapi.core.service.MagicResourceService
;
import
org.ssssssss.magicapi.core.service.MagicResourceStorage
;
import
org.ssssssss.magicapi.utils.IoUtils
;
import
org.ssssssss.magicapi.utils.JsonUtils
;
import
java.util.Objects
;
public
class
DataSourceInfoMagicResourceStorage
implements
MagicResourceStorage
<
DataSourceInfo
>,
JsonCodeConstants
{
private
MagicResourceService
magicResourceService
;
@Override
public
String
folder
()
{
return
"datasource"
;
}
@Override
public
String
suffix
()
{
return
".json"
;
}
@Override
public
Class
<
DataSourceInfo
>
magicClass
()
{
return
DataSourceInfo
.
class
;
}
@Override
public
boolean
requirePath
()
{
return
false
;
}
@Override
public
boolean
requiredScript
()
{
return
false
;
}
@Override
public
boolean
allowRoot
()
{
return
true
;
}
@Override
public
String
buildMappingKey
(
DataSourceInfo
info
)
{
return
String
.
format
(
"%s-%s"
,
info
.
getKey
(),
info
.
getUpdateTime
());
}
@Override
public
void
validate
(
DataSourceInfo
entity
)
{
notBlank
(
entity
.
getUrl
(),
DS_URL_REQUIRED
);
notBlank
(
entity
.
getKey
(),
DS_KEY_REQUIRED
);
isTrue
(
IoUtils
.
validateFileName
(
entity
.
getKey
()),
DATASOURCE_KEY_INVALID
);
boolean
noneMatchKey
=
magicResourceService
.
listFiles
(
"datasource:0"
).
stream
()
.
map
(
it
->
(
DataSourceInfo
)
it
)
.
filter
(
it
->
!
it
.
getId
().
equals
(
entity
.
getId
()))
.
noneMatch
(
it
->
Objects
.
equals
(
it
.
getKey
(),
entity
.
getKey
()));
isTrue
(
noneMatchKey
,
DS_KEY_CONFLICT
);
}
@Override
public
void
setMagicResourceService
(
MagicResourceService
magicResourceService
)
{
this
.
magicResourceService
=
magicResourceService
;
}
@Override
public
DataSourceInfo
read
(
byte
[]
bytes
)
{
return
JsonUtils
.
readValue
(
bytes
,
DataSourceInfo
.
class
);
}
@Override
public
byte
[]
write
(
MagicEntity
entity
)
{
return
JsonUtils
.
toJsonBytes
(
entity
);
}
}
magic-api/src/main/java/org/ssssssss/magicapi/datasource/service/DataSourceMagicDynamicRegistry.java
0 → 100644
View file @
02897568
package
org.ssssssss.magicapi.datasource.service
;
import
org.apache.commons.lang3.StringUtils
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.BeanUtils
;
import
org.springframework.boot.context.properties.bind.Bindable
;
import
org.springframework.boot.context.properties.bind.Binder
;
import
org.springframework.boot.context.properties.source.ConfigurationPropertyName
;
import
org.springframework.boot.context.properties.source.ConfigurationPropertyNameAliases
;
import
org.springframework.boot.context.properties.source.ConfigurationPropertySource
;
import
org.springframework.boot.context.properties.source.MapConfigurationPropertySource
;
import
org.springframework.boot.jdbc.DatabaseDriver
;
import
org.springframework.context.event.EventListener
;
import
org.springframework.util.ClassUtils
;
import
org.ssssssss.magicapi.core.config.Constants
;
import
org.ssssssss.magicapi.datasource.model.MagicDynamicDataSource
;
import
org.ssssssss.magicapi.core.event.FileEvent
;
import
org.ssssssss.magicapi.datasource.model.DataSourceInfo
;
import
org.ssssssss.magicapi.core.service.AbstractMagicDynamicRegistry
;
import
org.ssssssss.magicapi.core.service.MagicResourceStorage
;
import
javax.sql.DataSource
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.stream.Collectors
;
public
class
DataSourceMagicDynamicRegistry
extends
AbstractMagicDynamicRegistry
<
DataSourceInfo
>
{
private
final
MagicDynamicDataSource
magicDynamicDataSource
;
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
DataSourceMagicDynamicRegistry
.
class
);
private
static
final
ClassLoader
CLASSLOADER
=
DataSourceMagicDynamicRegistry
.
class
.
getClassLoader
();
// copy from DataSourceBuilder
private
static
final
String
[]
DATA_SOURCE_TYPE_NAMES
=
new
String
[]{
"com.zaxxer.hikari.HikariDataSource"
,
"org.apache.tomcat.jdbc.pool.DataSource"
,
"org.apache.commons.dbcp2.BasicDataSource"
};
public
DataSourceMagicDynamicRegistry
(
MagicResourceStorage
<
DataSourceInfo
>
magicResourceStorage
,
MagicDynamicDataSource
magicDynamicDataSource
)
{
super
(
magicResourceStorage
);
this
.
magicDynamicDataSource
=
magicDynamicDataSource
;
}
@EventListener
(
condition
=
"#event.type == 'datasource'"
)
public
void
onFileEvent
(
FileEvent
event
)
{
try
{
processEvent
(
event
);
}
catch
(
Exception
e
)
{
logger
.
error
(
"注册数据源失败"
,
e
);
}
}
@Override
protected
boolean
register
(
MappingNode
<
DataSourceInfo
>
mappingNode
)
{
DataSourceInfo
info
=
mappingNode
.
getEntity
();
Map
<
String
,
Object
>
properties
=
new
HashMap
<>(
info
.
getProperties
());
if
(
Constants
.
ES_DRIVER
.
equals
(
info
.
getDriverClassName
())){
properties
.
put
(
"defaultReadOnly"
,
true
);
}
properties
.
put
(
"url"
,
info
.
getUrl
());
properties
.
put
(
"username"
,
info
.
getUsername
());
properties
.
put
(
"password"
,
info
.
getPassword
());
if
(
StringUtils
.
isBlank
(
info
.
getDriverClassName
()))
{
String
driverClass
=
DatabaseDriver
.
fromJdbcUrl
(
info
.
getUrl
()).
getDriverClassName
();
properties
.
put
(
"driverClassName"
,
driverClass
);
}
else
{
properties
.
put
(
"driverClassName"
,
info
.
getDriverClassName
());
}
DataSource
datasource
=
createDataSource
(
getDataSourceType
(
info
.
getType
()),
properties
);
magicDynamicDataSource
.
put
(
info
.
getId
(),
info
.
getKey
(),
info
.
getName
(),
datasource
,
info
.
getMaxRows
());
return
true
;
}
@Override
protected
void
unregister
(
MappingNode
<
DataSourceInfo
>
mappingNode
)
{
magicDynamicDataSource
.
delete
(
mappingNode
.
getMappingKey
());
}
// copy from DataSourceBuilder
private
DataSource
createDataSource
(
Class
<?
extends
DataSource
>
dataSourceType
,
Map
<
String
,
Object
>
properties
)
{
DataSource
dataSource
=
BeanUtils
.
instantiateClass
(
dataSourceType
);
ConfigurationPropertySource
source
=
new
MapConfigurationPropertySource
(
properties
);
ConfigurationPropertyNameAliases
aliases
=
new
ConfigurationPropertyNameAliases
();
aliases
.
addAliases
(
"url"
,
"jdbc-url"
);
aliases
.
addAliases
(
"username"
,
"user"
);
Binder
binder
=
new
Binder
(
source
.
withAliases
(
aliases
));
binder
.
bind
(
ConfigurationPropertyName
.
EMPTY
,
Bindable
.
ofInstance
(
dataSource
));
return
dataSource
;
}
@SuppressWarnings
(
"unchecked"
)
private
Class
<?
extends
DataSource
>
getDataSourceType
(
String
datasourceType
)
{
if
(
StringUtils
.
isNotBlank
(
datasourceType
))
{
try
{
return
(
Class
<?
extends
DataSource
>)
ClassUtils
.
forName
(
datasourceType
,
CLASSLOADER
);
}
catch
(
Exception
ignored
)
{
}
}
for
(
String
name
:
DATA_SOURCE_TYPE_NAMES
)
{
try
{
return
(
Class
<?
extends
DataSource
>)
ClassUtils
.
forName
(
name
,
CLASSLOADER
);
}
catch
(
Exception
ignored
)
{
// ignored
}
}
return
null
;
}
@Override
public
List
<
DataSourceInfo
>
defaultMappings
()
{
return
magicDynamicDataSource
.
datasourceNodes
().
stream
().
filter
(
it
->
it
.
getId
()
==
null
).
map
(
it
->
{
DataSourceInfo
dataSourceInfo
=
new
DataSourceInfo
();
dataSourceInfo
.
setName
(
StringUtils
.
defaultIfBlank
(
it
.
getName
(),
StringUtils
.
defaultIfBlank
(
it
.
getKey
(),
"默认数据源"
)));
dataSourceInfo
.
setKey
(
it
.
getKey
());
return
dataSourceInfo
;
}).
collect
(
Collectors
.
toList
());
}
}
magic-api/src/main/java/org/ssssssss/magicapi/datasource/web/MagicDataSourceController.java
0 → 100644
View file @
02897568
package
org.ssssssss.magicapi.datasource.web
;
import
org.springframework.web.bind.annotation.RequestBody
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.ResponseBody
;
import
org.ssssssss.magicapi.core.web.MagicExceptionHandler
;
import
org.ssssssss.magicapi.core.config.MagicConfiguration
;
import
org.ssssssss.magicapi.datasource.model.DataSourceInfo
;
import
org.ssssssss.magicapi.core.model.JsonBean
;
import
org.ssssssss.magicapi.core.web.MagicController
;
import
org.ssssssss.magicapi.utils.JdbcUtils
;
import
java.sql.Connection
;
public
class
MagicDataSourceController
extends
MagicController
implements
MagicExceptionHandler
{
public
MagicDataSourceController
(
MagicConfiguration
configuration
)
{
super
(
configuration
);
}
@RequestMapping
(
"/datasource/jdbc/test"
)
@ResponseBody
public
JsonBean
<
String
>
test
(
@RequestBody
DataSourceInfo
properties
)
{
try
{
Connection
connection
=
JdbcUtils
.
getConnection
(
properties
.
getDriverClassName
(),
properties
.
getUrl
(),
properties
.
getUsername
(),
properties
.
getPassword
());
JdbcUtils
.
close
(
connection
);
}
catch
(
Exception
e
)
{
return
new
JsonBean
<>(
e
.
getMessage
());
}
return
new
JsonBean
<>(
"ok"
);
}
}
magic-api/src/main/java/org/ssssssss/magicapi/function/model/FunctionInfo.java
0 → 100644
View file @
02897568
package
org.ssssssss.magicapi.function.model
;
import
com.fasterxml.jackson.core.type.TypeReference
;
import
org.ssssssss.magicapi.core.model.MagicEntity
;
import
org.ssssssss.magicapi.core.model.Parameter
;
import
org.ssssssss.magicapi.core.model.PathMagicEntity
;
import
org.ssssssss.magicapi.utils.JsonUtils
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.Objects
;
public
class
FunctionInfo
extends
PathMagicEntity
{
private
String
description
;
private
String
returnType
;
private
String
mappingPath
;
private
List
<
Parameter
>
parameters
=
Collections
.
emptyList
();
public
String
getDescription
()
{
return
description
;
}
public
void
setDescription
(
String
description
)
{
this
.
description
=
description
;
}
public
void
setParameter
(
String
parameter
)
{
try
{
this
.
parameters
=
JsonUtils
.
readValue
(
Objects
.
toString
(
parameter
,
"[]"
),
new
TypeReference
<
List
<
Parameter
>>()
{
});
}
catch
(
Throwable
ignored
)
{
}
}
public
String
getPath
()
{
return
path
;
}
public
void
setPath
(
String
path
)
{
this
.
path
=
path
;
}
public
String
getMappingPath
()
{
return
mappingPath
;
}
public
void
setMappingPath
(
String
mappingPath
)
{
this
.
mappingPath
=
mappingPath
;
}
public
String
getReturnType
()
{
return
returnType
;
}
public
void
setReturnType
(
String
returnType
)
{
this
.
returnType
=
returnType
;
}
public
List
<
Parameter
>
getParameters
()
{
return
parameters
;
}
public
void
setParameters
(
List
<
Parameter
>
parameters
)
{
this
.
parameters
=
parameters
;
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
return
true
;
if
(
o
==
null
||
getClass
()
!=
o
.
getClass
())
return
false
;
FunctionInfo
functionInfo
=
(
FunctionInfo
)
o
;
return
Objects
.
equals
(
id
,
functionInfo
.
id
)
&&
Objects
.
equals
(
path
,
functionInfo
.
path
)
&&
Objects
.
equals
(
script
,
functionInfo
.
script
)
&&
Objects
.
equals
(
name
,
functionInfo
.
name
)
&&
Objects
.
equals
(
groupId
,
functionInfo
.
groupId
)
&&
Objects
.
equals
(
description
,
functionInfo
.
description
)
&&
Objects
.
equals
(
parameters
,
functionInfo
.
parameters
)
&&
Objects
.
equals
(
returnType
,
functionInfo
.
returnType
);
}
public
FunctionInfo
copy
()
{
FunctionInfo
info
=
new
FunctionInfo
();
super
.
copyTo
(
info
);
info
.
setDescription
(
this
.
description
);
info
.
setParameters
(
this
.
parameters
);
info
.
setMappingPath
(
this
.
mappingPath
);
info
.
setReturnType
(
this
.
returnType
);
return
info
;
}
@Override
public
MagicEntity
simple
()
{
FunctionInfo
info
=
new
FunctionInfo
();
super
.
simple
(
info
);
return
info
;
}
@Override
public
int
hashCode
()
{
return
Objects
.
hash
(
id
,
path
,
script
,
name
,
groupId
,
parameters
,
description
,
returnType
);
}
}
magic-api/src/main/java/org/ssssssss/magicapi/function/service/FunctionInfoMagicResourceStorage.java
0 → 100644
View file @
02897568
package
org.ssssssss.magicapi.function.service
;
import
org.ssssssss.magicapi.function.model.FunctionInfo
;
import
org.ssssssss.magicapi.core.service.AbstractPathMagicResourceStorage
;
public
class
FunctionInfoMagicResourceStorage
extends
AbstractPathMagicResourceStorage
<
FunctionInfo
>
{
@Override
public
String
folder
()
{
return
"function"
;
}
@Override
public
Class
<
FunctionInfo
>
magicClass
()
{
return
FunctionInfo
.
class
;
}
@Override
public
String
buildMappingKey
(
FunctionInfo
info
)
{
return
buildMappingKey
(
info
,
magicResourceService
.
getGroupPath
(
info
.
getGroupId
()));
}
@Override
public
void
validate
(
FunctionInfo
entity
)
{
notBlank
(
entity
.
getPath
(),
FUNCTION_PATH_REQUIRED
);
}
}
magic-api/src/main/java/org/ssssssss/magicapi/function/service/FunctionMagicDynamicRegistry.java
0 → 100644
View file @
02897568
package
org.ssssssss.magicapi.function.service
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.context.event.EventListener
;
import
org.ssssssss.magicapi.core.config.MagicConfiguration
;
import
org.ssssssss.magicapi.core.event.FileEvent
;
import
org.ssssssss.magicapi.core.event.GroupEvent
;
import
org.ssssssss.magicapi.function.model.FunctionInfo
;
import
org.ssssssss.magicapi.core.model.Parameter
;
import
org.ssssssss.magicapi.core.service.MagicResourceStorage
;
import
org.ssssssss.magicapi.utils.ScriptManager
;
import
org.ssssssss.magicapi.core.service.AbstractMagicDynamicRegistry
;
import
org.ssssssss.script.MagicResourceLoader
;
import
org.ssssssss.script.MagicScriptContext
;
import
org.ssssssss.script.exception.MagicExitException
;
import
org.ssssssss.script.runtime.ExitValue
;
import
java.util.List
;
import
java.util.function.Function
;
public
class
FunctionMagicDynamicRegistry
extends
AbstractMagicDynamicRegistry
<
FunctionInfo
>
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
FunctionMagicDynamicRegistry
.
class
);
public
FunctionMagicDynamicRegistry
(
MagicResourceStorage
<
FunctionInfo
>
magicResourceStorage
)
{
super
(
magicResourceStorage
);
MagicResourceLoader
.
addFunctionLoader
(
this
::
lookupLambdaFunction
);
}
private
Object
lookupLambdaFunction
(
MagicScriptContext
context
,
String
path
)
{
FunctionInfo
functionInfo
=
getMapping
(
path
);
if
(
functionInfo
!=
null
)
{
String
scriptName
=
MagicConfiguration
.
getMagicResourceService
().
getScriptName
(
functionInfo
);
List
<
Parameter
>
parameters
=
functionInfo
.
getParameters
();
return
(
Function
<
Object
[],
Object
>)
objects
->
{
MagicScriptContext
functionContext
=
new
MagicScriptContext
(
context
.
getRootVariables
());
functionContext
.
setScriptName
(
scriptName
);
if
(
objects
!=
null
)
{
for
(
int
i
=
0
,
len
=
objects
.
length
,
size
=
parameters
.
size
();
i
<
len
&&
i
<
size
;
i
++)
{
functionContext
.
set
(
parameters
.
get
(
i
).
getName
(),
objects
[
i
]);
}
}
Object
value
=
ScriptManager
.
executeScript
(
functionInfo
.
getScript
(),
functionContext
);
if
(
value
instanceof
ExitValue
)
{
throw
new
MagicExitException
((
ExitValue
)
value
);
}
return
value
;
};
}
return
null
;
}
@EventListener
(
condition
=
"#event.type == 'function'"
)
public
void
onFileEvent
(
FileEvent
event
)
{
processEvent
(
event
);
}
@EventListener
(
condition
=
"#event.type == 'function'"
)
public
void
onGroupEvent
(
GroupEvent
event
)
{
processEvent
(
event
);
}
@Override
protected
boolean
register
(
MappingNode
<
FunctionInfo
>
mappingNode
)
{
logger
.
debug
(
"注册函数:{}"
,
mappingNode
.
getMappingKey
());
return
true
;
}
@Override
protected
void
unregister
(
MappingNode
<
FunctionInfo
>
mappingNode
)
{
logger
.
debug
(
"取消注册函数:{}"
,
mappingNode
.
getMappingKey
());
}
}
magic-api/src/main/java/org/ssssssss/magicapi/jsr223/JSR223LanguageProvider.java
0 → 100644
View file @
02897568
package
org.ssssssss.magicapi.jsr223
;
import
org.ssssssss.magicapi.core.exception.MagicAPIException
;
import
org.ssssssss.magicapi.jsr223.LanguageProvider
;
import
javax.script.Compilable
;
import
javax.script.ScriptEngine
;
import
javax.script.ScriptEngineManager
;
import
javax.script.SimpleBindings
;
import
java.util.Map
;
/**
* JSR223规范支持
*
* @author mxd
*/
public
class
JSR223LanguageProvider
implements
LanguageProvider
{
ScriptEngineManager
scriptEngineManager
=
new
ScriptEngineManager
();
@Override
public
boolean
support
(
String
languageName
)
{
return
scriptEngineManager
.
getEngineByName
(
languageName
)
!=
null
;
}
@Override
public
Object
execute
(
String
languageName
,
String
script
,
Map
<
String
,
Object
>
context
)
throws
Exception
{
ScriptEngine
scriptEngine
=
scriptEngineManager
.
getEngineByName
(
languageName
);
if
(
scriptEngine
instanceof
Compilable
)
{
Compilable
compilable
=
(
Compilable
)
scriptEngine
;
try
{
return
compilable
.
compile
(
script
).
eval
(
new
SimpleBindings
(
context
));
}
catch
(
Exception
e
)
{
throw
new
MagicAPIException
(
String
.
format
(
"编译%s出错"
,
languageName
),
e
);
}
}
else
{
return
scriptEngine
.
eval
(
script
,
new
SimpleBindings
(
context
));
}
}
}
magic-api/src/main/java/org/ssssssss/magicapi/jsr223/LanguageProvider.java
0 → 100644
View file @
02897568
package
org.ssssssss.magicapi.jsr223
;
import
java.util.Map
;
/**
* 自定义语言接口
*
* @author mxd
*/
public
interface
LanguageProvider
{
/**
* 是否支持该语言
*
* @param languageName 语言名
* @return 是否支持
*/
boolean
support
(
String
languageName
);
/**
* 执行具体脚本
*
* @param languageName 语言类型
* @param script 脚本内容
* @param context 当前环境中的变量信息
* @return 执行结果
* @throws Exception 执行过程中抛出的异常
*/
Object
execute
(
String
languageName
,
String
script
,
Map
<
String
,
Object
>
context
)
throws
Exception
;
}
magic-api/src/main/java/org/ssssssss/magicapi/modules/DynamicModule.java
0 → 100644
View file @
02897568
package
org.ssssssss.magicapi.modules
;
import
org.ssssssss.script.MagicScriptContext
;
import
java.beans.Transient
;
public
interface
DynamicModule
<
T
>
{
@Transient
T
getDynamicModule
(
MagicScriptContext
context
);
}
Prev
1
…
8
9
10
11
12
13
14
15
16
Next
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