Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
ai-chat-agent
Project
Project
Details
Activity
Releases
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
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
李超鹏
ai-chat-agent
Commits
be52c207
Commit
be52c207
authored
Dec 07, 2023
by
李超鹏
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
登录,登录白名单
parent
260bde3d
Changes
33
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
1103 additions
and
229 deletions
+1103
-229
pom.xml
pom.xml
+197
-174
AuthInfo.java
src/main/java/cc/shenjiying/ai/common/dto/AuthInfo.java
+17
-0
R.java
src/main/java/cc/shenjiying/ai/common/dto/R.java
+115
-0
QuestionerHolder.java
src/main/java/cc/shenjiying/ai/config/QuestionerHolder.java
+6
-3
AnnotateFilter.java
.../java/cc/shenjiying/ai/config/filters/AnnotateFilter.java
+0
-28
LoggingFilter.java
...n/java/cc/shenjiying/ai/config/filters/LoggingFilter.java
+0
-2
QuestionerFilter.java
...ava/cc/shenjiying/ai/config/filters/QuestionerFilter.java
+9
-13
TokenFilter.java
...ain/java/cc/shenjiying/ai/config/filters/TokenFilter.java
+79
-0
TestWriterInterceptor.java
...njiying/ai/config/interceptors/TestWriterInterceptor.java
+0
-2
QuestionerLoginDTO.java
src/main/java/cc/shenjiying/ai/dto/QuestionerLoginDTO.java
+10
-0
QuestionerService.java
...main/java/cc/shenjiying/ai/manager/QuestionerService.java
+76
-0
SmsCodeService.java
src/main/java/cc/shenjiying/ai/manager/SmsCodeService.java
+54
-0
Questioner.java
...n/java/cc/shenjiying/ai/repository/entity/Questioner.java
+6
-0
QuestionerWhiteList.java
.../shenjiying/ai/repository/entity/QuestionerWhiteList.java
+25
-0
SmsSendLog.java
...n/java/cc/shenjiying/ai/repository/entity/SmsSendLog.java
+37
-0
QuestionerWhiteListMapper.java
...iying/ai/repository/mapper/QuestionerWhiteListMapper.java
+9
-0
SmsSendLogMapper.java
.../cc/shenjiying/ai/repository/mapper/SmsSendLogMapper.java
+10
-0
KnowLedgeResource.java
...ain/java/cc/shenjiying/ai/resource/KnowLedgeResource.java
+9
-5
QuestionerResource.java
...in/java/cc/shenjiying/ai/resource/QuestionerResource.java
+41
-0
RandomUtil.java
src/main/java/cc/shenjiying/ai/util/RandomUtil.java
+17
-0
TokenUtil.java
src/main/java/cc/shenjiying/ai/util/TokenUtil.java
+68
-0
RedisCache.java
src/main/java/cc/shenjiying/redis/RedisCache.java
+33
-0
MobileCodeKey.java
src/main/java/cc/shenjiying/redis/key/MobileCodeKey.java
+10
-0
RedisCacheKey.java
src/main/java/cc/shenjiying/redis/key/RedisCacheKey.java
+23
-0
AliSmsSender.java
src/main/java/cc/shenjiying/sms/AliSmsSender.java
+49
-0
TencentSmsSender.java
src/main/java/cc/shenjiying/sms/TencentSmsSender.java
+98
-0
SmsSendResult.java
src/main/java/cc/shenjiying/sms/dto/SmsSendResult.java
+18
-0
SmsSendParam.java
src/main/java/cc/shenjiying/sms/param/SmsSendParam.java
+24
-0
application-prod.properties
src/main/resources/application-prod.properties
+4
-1
application-stage.properties
src/main/resources/application-stage.properties
+2
-0
application.properties
src/main/resources/application.properties
+20
-1
jwt_private.pem
src/main/resources/key/jwt_private.pem
+28
-0
jwt_public.pem
src/main/resources/key/jwt_public.pem
+9
-0
No files found.
pom.xml
View file @
be52c207
This diff is collapsed.
Click to expand it.
src/main/java/cc/shenjiying/ai/common/dto/AuthInfo.java
0 → 100644
View file @
be52c207
package
cc
.
shenjiying
.
ai
.
common
.
dto
;
import
lombok.Data
;
import
lombok.experimental.Accessors
;
@Data
@Accessors
(
chain
=
true
)
public
class
AuthInfo
{
private
String
token
;
private
String
nickname
;
private
Long
id
;
private
String
account
;
private
String
mobile
;
private
String
channel
;
private
String
channelUserId
;
}
src/main/java/cc/shenjiying/ai/common/dto/R.java
0 → 100644
View file @
be52c207
package
cc
.
shenjiying
.
ai
.
common
.
dto
;
import
java.util.HashMap
;
import
java.util.Map
;
public
class
R
<
T
>
{
public
static
final
String
DEF_ERROR_MESSAGE
=
"系统繁忙,请稍候再试"
;
public
static
final
String
VALID_ERROR_MESSAGE
=
"参数异常"
;
public
static
final
int
SUCCESS_CODE
=
0
;
public
static
final
int
FAIL_CODE
=
-
1
;
private
int
code
;
private
T
data
;
private
String
msg
=
"ok"
;
private
Map
<
Object
,
Object
>
extra
;
private
R
()
{
}
public
R
(
int
code
,
T
data
)
{
this
.
code
=
code
;
this
.
data
=
data
;
}
public
R
(
int
code
,
T
data
,
String
msg
)
{
this
.
code
=
code
;
this
.
data
=
data
;
this
.
msg
=
msg
;
}
public
static
<
E
>
R
<
E
>
result
(
int
code
,
E
data
,
String
msg
)
{
return
new
R
<>(
code
,
data
,
msg
);
}
public
static
<
E
>
R
<
E
>
success
(
E
data
)
{
return
new
R
<>(
SUCCESS_CODE
,
data
);
}
public
static
R
<
Boolean
>
success
()
{
return
new
R
<>(
SUCCESS_CODE
,
true
);
}
public
static
<
E
>
R
<
E
>
success
(
E
data
,
String
msg
)
{
return
new
R
<>(
SUCCESS_CODE
,
data
,
msg
);
}
public
static
<
E
>
R
<
E
>
fail
(
int
code
,
String
msg
)
{
return
new
R
<>(
code
,
null
,
(
msg
==
null
||
msg
.
isEmpty
())
?
DEF_ERROR_MESSAGE
:
msg
);
}
public
static
<
E
>
R
<
E
>
fail
(
String
msg
)
{
return
fail
(
FAIL_CODE
,
msg
);
}
public
static
<
E
>
R
<
E
>
fail
(
String
msg
,
Object
...
args
)
{
String
message
=
(
msg
==
null
||
msg
.
isEmpty
())
?
DEF_ERROR_MESSAGE
:
msg
;
return
new
R
<>(
FAIL_CODE
,
null
,
String
.
format
(
message
,
args
));
}
public
static
<
E
>
R
<
E
>
fail
(
Throwable
throwable
)
{
String
msg
=
throwable
!=
null
?
throwable
.
getMessage
()
:
DEF_ERROR_MESSAGE
;
return
fail
(
FAIL_CODE
,
msg
);
}
public
static
<
E
>
R
<
E
>
validFail
()
{
return
new
R
<>(
FAIL_CODE
,
null
,
VALID_ERROR_MESSAGE
);
}
public
R
<
T
>
put
(
String
key
,
Object
value
)
{
if
(
this
.
extra
==
null
)
{
this
.
extra
=
new
HashMap
<>(
16
);
}
this
.
extra
.
put
(
key
,
value
);
return
this
;
}
public
R
<
T
>
putAll
(
Map
<
Object
,
Object
>
extra
)
{
if
(
this
.
extra
==
null
)
{
this
.
extra
=
new
HashMap
<>(
16
);
}
this
.
extra
.
putAll
(
extra
);
return
this
;
}
/**
* 逻辑处理是否成功
*
* @return 是否成功
*/
public
Boolean
getIsSuccess
()
{
return
this
.
code
==
SUCCESS_CODE
||
this
.
code
==
200
;
}
public
int
getCode
()
{
return
code
;
}
public
T
getData
()
{
return
data
;
}
public
String
getMsg
()
{
return
msg
;
}
public
Map
<
Object
,
Object
>
getExtra
()
{
return
extra
;
}
}
src/main/java/cc/shenjiying/ai/config/QuestionerHolder.java
View file @
be52c207
package
cc
.
shenjiying
.
ai
.
config
;
package
cc
.
shenjiying
.
ai
.
config
;
import
cc.shenjiying.ai.common.dto.AuthInfo
;
import
cc.shenjiying.ai.repository.entity.Questioner
;
import
cc.shenjiying.ai.repository.entity.Questioner
;
import
io.smallrye.common.vertx.ContextLocals
;
import
io.smallrye.common.vertx.ContextLocals
;
...
@@ -13,11 +14,13 @@ public class QuestionerHolder {
...
@@ -13,11 +14,13 @@ public class QuestionerHolder {
public
static
final
String
FROM_CHANNEL_KEY
=
"channel"
;
public
static
final
String
FROM_CHANNEL_KEY
=
"channel"
;
public
static
final
String
TOKEN_KEY
=
"token"
;
public
static
Long
getId
()
{
public
static
Long
getId
()
{
return
QuestionerHolder
.
get
(
QUESTIONER_KEY
).
map
(
Questioner
:
:
getId
).
orElse
(
0L
);
return
QuestionerHolder
.
get
(
QUESTIONER_KEY
).
map
(
AuthInfo
:
:
getId
).
orElse
(
0L
);
}
}
public
static
Optional
<
Questioner
>
get
(
String
key
)
{
public
static
Optional
<
AuthInfo
>
get
(
String
key
)
{
return
ContextLocals
.
get
(
key
);
return
ContextLocals
.
get
(
key
);
}
}
...
@@ -27,7 +30,7 @@ public class QuestionerHolder {
...
@@ -27,7 +30,7 @@ public class QuestionerHolder {
ContextLocals
.
put
(
FROM_CHANNEL_KEY
,
channel
);
ContextLocals
.
put
(
FROM_CHANNEL_KEY
,
channel
);
}
}
public
static
void
putQuestioner
(
Questioner
questioner
)
{
public
static
void
putQuestioner
(
AuthInfo
questioner
)
{
if
(
Objects
.
isNull
(
questioner
))
if
(
Objects
.
isNull
(
questioner
))
return
;
return
;
ContextLocals
.
put
(
QUESTIONER_KEY
,
questioner
);
ContextLocals
.
put
(
QUESTIONER_KEY
,
questioner
);
...
...
src/main/java/cc/shenjiying/ai/config/filters/AnnotateFilter.java
deleted
100644 → 0
View file @
260bde3d
package
cc
.
shenjiying
.
ai
.
config
.
filters
;
import
io.quarkus.logging.Log
;
import
jakarta.ws.rs.container.ContainerRequestContext
;
import
org.jboss.resteasy.reactive.RestResponse
;
import
java.util.Optional
;
// Response/RestResponse Uni<Response/Response> Optional
// 返回 null or empty 代表继续执行链,其他则返回给客户端
public
class
AnnotateFilter
{
// @ServerRequestFilter(priority = 2000)
public
void
test
(
ContainerRequestContext
context
)
{
if
(
null
==
context
.
getHeaderString
(
"token"
))
{
Log
.
info
(
"not has token"
);
}
}
// @ServerRequestFilter
public
Optional
<
RestResponse
<
Void
>>
getFilter
(
ContainerRequestContext
ctx
)
{
// only allow GET methods for now
// if(ctx.getMethod().equals(HttpMethod.GET)) {
// return Optional.of(RestResponse.status(Response.Status.METHOD_NOT_ALLOWED));
// }
return
Optional
.
empty
();
}
}
src/main/java/cc/shenjiying/ai/config/filters/LoggingFilter.java
View file @
be52c207
package
cc
.
shenjiying
.
ai
.
config
.
filters
;
package
cc
.
shenjiying
.
ai
.
config
.
filters
;
import
cc.shenjiying.ai.util.IpUtils
;
import
cc.shenjiying.ai.util.IpUtils
;
import
io.smallrye.common.vertx.ContextLocals
;
import
io.vertx.core.http.HttpServerRequest
;
import
io.vertx.core.http.HttpServerRequest
;
import
io.vertx.mutiny.core.Vertx
;
import
jakarta.ws.rs.container.ContainerRequestContext
;
import
jakarta.ws.rs.container.ContainerRequestContext
;
import
jakarta.ws.rs.container.ContainerRequestFilter
;
import
jakarta.ws.rs.container.ContainerRequestFilter
;
import
jakarta.ws.rs.container.ContainerResponseContext
;
import
jakarta.ws.rs.container.ContainerResponseContext
;
...
...
src/main/java/cc/shenjiying/ai/config/filters/QuestionerFilter.java
View file @
be52c207
package
cc
.
shenjiying
.
ai
.
config
.
filters
;
package
cc
.
shenjiying
.
ai
.
config
.
filters
;
import
cc.shenjiying.ai.config.QuestionerHolder
;
import
cc.shenjiying.ai.config.QuestionerHolder
;
import
cc.shenjiying.ai.repository.entity.Question
;
import
cc.shenjiying.ai.repository.entity.Questioner
;
import
cc.shenjiying.ai.repository.entity.Questioner
;
import
cc.shenjiying.ai.repository.mapper.QuestionMapper
;
import
cc.shenjiying.ai.manager.QuestionerService
;
import
cc.shenjiying.ai.repository.mapper.QuestionerMapper
;
import
cc.shenjiying.ai.repository.service.QuestionerService
;
import
cc.shenjiying.ai.util.IpUtils
;
import
cc.shenjiying.ai.util.IpUtils
;
import
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
;
import
cc.shenjiying.ai.util.TokenUtil
;
import
com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
;
import
io.quarkus.runtime.util.StringUtil
;
import
io.quarkus.runtime.util.StringUtil
;
import
io.vertx.core.http.HttpServerRequest
;
import
io.vertx.core.http.HttpServerRequest
;
import
jakarta.inject.Inject
;
import
jakarta.inject.Inject
;
...
@@ -22,20 +18,16 @@ import jakarta.ws.rs.ext.Provider;
...
@@ -22,20 +18,16 @@ import jakarta.ws.rs.ext.Provider;
import
org.slf4j.Logger
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.slf4j.LoggerFactory
;
import
java.sql.Wrapper
;
import
java.util.Objects
;
import
java.util.Objects
;
import
static
cc
.
shenjiying
.
ai
.
config
.
QuestionerHolder
.
FROM_CHANNEL_KEY
;
import
static
cc
.
shenjiying
.
ai
.
config
.
QuestionerHolder
.
FROM_CHANNEL_KEY
;
import
static
cc
.
shenjiying
.
ai
.
config
.
QuestionerHolder
.
QUESTIONER
_KEY
;
import
static
cc
.
shenjiying
.
ai
.
config
.
QuestionerHolder
.
TOKEN
_KEY
;
/**
/**
* 日志拦截器
* 日志拦截器
*/
*/
@Provider
//
@Provider
public
class
QuestionerFilter
implements
ContainerRequestFilter
,
ContainerResponseFilter
{
public
class
QuestionerFilter
implements
ContainerRequestFilter
,
ContainerResponseFilter
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
QuestionerFilter
.
class
);
@Context
UriInfo
uriInfo
;
@Context
@Context
HttpServerRequest
request
;
HttpServerRequest
request
;
@Inject
@Inject
...
@@ -46,6 +38,10 @@ public class QuestionerFilter implements ContainerRequestFilter, ContainerRespon
...
@@ -46,6 +38,10 @@ public class QuestionerFilter implements ContainerRequestFilter, ContainerRespon
String
ipAddr
=
IpUtils
.
getIpAddr
(
request
);
String
ipAddr
=
IpUtils
.
getIpAddr
(
request
);
String
channel
=
requestContext
.
getHeaderString
(
FROM_CHANNEL_KEY
);
String
channel
=
requestContext
.
getHeaderString
(
FROM_CHANNEL_KEY
);
channel
=
StringUtil
.
isNullOrEmpty
(
channel
)
?
"qs"
:
""
;
channel
=
StringUtil
.
isNullOrEmpty
(
channel
)
?
"qs"
:
""
;
String
token
=
requestContext
.
getHeaderString
(
TOKEN_KEY
);
if
(
StringUtil
.
isNullOrEmpty
(
token
)){
}
Questioner
questioner
=
questionerService
.
getByChannel
(
channel
,
ipAddr
);
Questioner
questioner
=
questionerService
.
getByChannel
(
channel
,
ipAddr
);
if
(
Objects
.
isNull
(
questioner
))
{
if
(
Objects
.
isNull
(
questioner
))
{
try
{
try
{
...
@@ -54,7 +50,7 @@ public class QuestionerFilter implements ContainerRequestFilter, ContainerRespon
...
@@ -54,7 +50,7 @@ public class QuestionerFilter implements ContainerRequestFilter, ContainerRespon
questioner
=
questionerService
.
getByChannel
(
channel
,
ipAddr
);
questioner
=
questionerService
.
getByChannel
(
channel
,
ipAddr
);
}
}
}
}
QuestionerHolder
.
putQuestioner
(
questioner
);
//
QuestionerHolder.putQuestioner(questioner);
QuestionerHolder
.
putChannel
(
channel
);
QuestionerHolder
.
putChannel
(
channel
);
}
}
...
...
src/main/java/cc/shenjiying/ai/config/filters/TokenFilter.java
0 → 100644
View file @
be52c207
package
cc
.
shenjiying
.
ai
.
config
.
filters
;
import
cc.shenjiying.ai.common.dto.AuthInfo
;
import
cc.shenjiying.ai.common.dto.R
;
import
cc.shenjiying.ai.config.QuestionerHolder
;
import
cc.shenjiying.ai.manager.QuestionerService
;
import
cc.shenjiying.ai.repository.entity.Questioner
;
import
cc.shenjiying.ai.util.IpUtils
;
import
cc.shenjiying.ai.util.TokenUtil
;
import
com.fasterxml.jackson.core.JsonProcessingException
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
io.quarkus.logging.Log
;
import
io.quarkus.runtime.util.StringUtil
;
import
io.smallrye.jwt.auth.principal.JWTParser
;
import
io.vertx.core.http.HttpServerRequest
;
import
jakarta.enterprise.context.ApplicationScoped
;
import
jakarta.inject.Inject
;
import
jakarta.ws.rs.container.ContainerRequestContext
;
import
jakarta.ws.rs.core.Context
;
import
jakarta.ws.rs.core.Request
;
import
jakarta.ws.rs.core.Response
;
import
org.jboss.resteasy.reactive.RestResponse
;
import
org.jboss.resteasy.reactive.server.ServerRequestFilter
;
import
org.jboss.resteasy.reactive.server.ServerResponseFilter
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.Objects
;
import
java.util.Optional
;
import
static
cc
.
shenjiying
.
ai
.
config
.
QuestionerHolder
.
FROM_CHANNEL_KEY
;
import
static
cc
.
shenjiying
.
ai
.
config
.
QuestionerHolder
.
TOKEN_KEY
;
// Response/RestResponse Uni<Response/Response> Optional
// 返回 null or empty 代表继续执行链,其他则返回给客户端
@ApplicationScoped
public
class
TokenFilter
{
@Inject
JWTParser
jwtParser
;
@Inject
ObjectMapper
objectMapper
;
private
List
<
String
>
ignoreUrl
=
Arrays
.
asList
(
"/questioner/login"
,
"/questioner/login/code"
);
private
boolean
isIgnore
(
String
url
)
{
return
ignoreUrl
.
contains
(
url
);
}
@ServerRequestFilter
(
priority
=
2000
)
public
RestResponse
<
String
>
request
(
ContainerRequestContext
context
,
@Context
HttpServerRequest
request
)
throws
JsonProcessingException
{
String
channel
=
context
.
getHeaderString
(
FROM_CHANNEL_KEY
);
channel
=
StringUtil
.
isNullOrEmpty
(
channel
)
?
"qs"
:
""
;
String
token
=
context
.
getHeaderString
(
TOKEN_KEY
);
if
(!
isIgnore
(
context
.
getUriInfo
().
getPath
())
&&
StringUtil
.
isNullOrEmpty
(
token
))
{
return
RestResponse
.
status
(
Response
.
Status
.
FORBIDDEN
,
objectMapper
.
writeValueAsString
(
R
.
fail
(
"您需要登录后才能进行此操作"
)));
}
AuthInfo
parse
=
TokenUtil
.
parse
(
jwtParser
,
token
);
QuestionerHolder
.
putQuestioner
(
parse
);
QuestionerHolder
.
putChannel
(
channel
);
return
null
;
}
@ServerResponseFilter
(
priority
=
2000
)
public
void
response
()
{
QuestionerHolder
.
remove
();
}
//// @ServerRequestFilter
// public Optional<RestResponse<Void>> getFilter(ContainerRequestContext ctx) {
// // only allow GET methods for now
//// if(ctx.getMethod().equals(HttpMethod.GET)) {
//// return Optional.of(RestResponse.status(Response.Status.METHOD_NOT_ALLOWED));
//// }
// return Optional.empty();
// }
}
src/main/java/cc/shenjiying/ai/config/interceptors/TestWriterInterceptor.java
View file @
be52c207
...
@@ -10,9 +10,7 @@ import jakarta.ws.rs.ext.*;
...
@@ -10,9 +10,7 @@ import jakarta.ws.rs.ext.*;
import
java.io.IOException
;
import
java.io.IOException
;
//@Provider
@Priority
(
Interceptor
.
Priority
.
APPLICATION
+
1
)
@Priority
(
Interceptor
.
Priority
.
APPLICATION
+
1
)
//@ConstrainedTo(RuntimeType.SERVER)
public
class
TestWriterInterceptor
implements
WriterInterceptor
,
ReaderInterceptor
{
public
class
TestWriterInterceptor
implements
WriterInterceptor
,
ReaderInterceptor
{
@Inject
@Inject
...
...
src/main/java/cc/shenjiying/ai/dto/QuestionerLoginDTO.java
0 → 100644
View file @
be52c207
package
cc
.
shenjiying
.
ai
.
dto
;
import
lombok.Data
;
@Data
public
class
QuestionerLoginDTO
{
private
String
account
;
private
String
password
;
}
src/main/java/cc/shenjiying/ai/
repository/service
/QuestionerService.java
→
src/main/java/cc/shenjiying/ai/
manager
/QuestionerService.java
View file @
be52c207
package
cc
.
shenjiying
.
ai
.
repository
.
service
;
package
cc
.
shenjiying
.
ai
.
manager
;
import
cc.shenjiying.ai.common.dto.AuthInfo
;
import
cc.shenjiying.ai.common.dto.R
;
import
cc.shenjiying.ai.repository.entity.Questioner
;
import
cc.shenjiying.ai.repository.entity.Questioner
;
import
cc.shenjiying.ai.repository.entity.QuestionerWhiteList
;
import
cc.shenjiying.ai.repository.mapper.QuestionerMapper
;
import
cc.shenjiying.ai.repository.mapper.QuestionerMapper
;
import
cc.shenjiying.ai.repository.mapper.QuestionerWhiteListMapper
;
import
cc.shenjiying.ai.util.TokenUtil
;
import
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
;
import
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
;
import
io.quarkus.runtime.util.StringUtil
;
import
jakarta.enterprise.context.ApplicationScoped
;
import
jakarta.enterprise.context.ApplicationScoped
;
import
jakarta.inject.Inject
;
import
jakarta.inject.Inject
;
import
jakarta.inject.Singleton
;
import
jakarta.inject.Singleton
;
import
org.jboss.resteasy.reactive.RestQuery
;
import
java.util.Objects
;
import
java.util.Objects
;
...
@@ -15,6 +22,12 @@ public class QuestionerService {
...
@@ -15,6 +22,12 @@ public class QuestionerService {
@Inject
@Inject
QuestionerMapper
questionerMapper
;
QuestionerMapper
questionerMapper
;
@Inject
SmsCodeService
smsCodeService
;
@Inject
QuestionerWhiteListMapper
questionerWhiteListMapper
;
public
Questioner
getQuestioner
(
Long
userId
)
{
public
Questioner
getQuestioner
(
Long
userId
)
{
return
questionerMapper
.
selectById
(
userId
);
return
questionerMapper
.
selectById
(
userId
);
}
}
...
@@ -31,4 +44,33 @@ public class QuestionerService {
...
@@ -31,4 +44,33 @@ public class QuestionerService {
}
}
return
questionerMapper
.
insert
(
questioner
);
return
questionerMapper
.
insert
(
questioner
);
}
}
public
R
<
Boolean
>
getLoginCode
(
@RestQuery
String
mobile
)
{
if
(
StringUtil
.
isNullOrEmpty
(
mobile
))
{
return
R
.
validFail
();
}
Long
count
=
questionerWhiteListMapper
.
selectCount
(
new
LambdaQueryWrapper
<
QuestionerWhiteList
>().
eq
(
QuestionerWhiteList:
:
getAccount
,
mobile
));
if
(
count
>
0
)
{
smsCodeService
.
send
(
mobile
);
return
R
.
success
(
Boolean
.
TRUE
);
}
return
R
.
fail
(
"尊敬的用户,感谢您对我们的产品感兴趣。但请注意,目前该产品仍处于内测阶段,仅对特定用户开放"
);
}
public
R
<
String
>
getLoginToken
(
String
mobile
,
String
code
)
{
if
(
StringUtil
.
isNullOrEmpty
(
mobile
)
||
StringUtil
.
isNullOrEmpty
(
code
))
{
return
R
.
validFail
();
}
if
(
smsCodeService
.
check
(
mobile
,
code
))
{
Questioner
questioner
=
questionerMapper
.
selectOne
(
new
LambdaQueryWrapper
<
Questioner
>().
eq
(
Questioner:
:
getAccount
,
mobile
).
last
(
"limit 1"
));
if
(
Objects
.
isNull
(
questioner
))
{
return
R
.
fail
(
"用户名或密码错误,请重新输入"
);
}
String
token
=
TokenUtil
.
create
(
new
AuthInfo
().
setId
(
questioner
.
getId
()).
setAccount
(
questioner
.
getAccount
())
.
setMobile
(
questioner
.
getMobile
()).
setChannel
(
questioner
.
getChannel
()).
setChannelUserId
(
questioner
.
getChannelUserId
()));
return
R
.
success
(
token
);
}
return
R
.
fail
(
"验证码错误或已过期,请重新获取验证码后再试"
);
}
}
}
src/main/java/cc/shenjiying/ai/manager/SmsCodeService.java
0 → 100644
View file @
be52c207
package
cc
.
shenjiying
.
ai
.
manager
;
import
cc.shenjiying.ai.repository.entity.SmsSendLog
;
import
cc.shenjiying.ai.repository.mapper.SmsSendLogMapper
;
import
cc.shenjiying.ai.util.RandomUtil
;
import
cc.shenjiying.redis.RedisCache
;
import
cc.shenjiying.redis.key.MobileCodeKey
;
import
cc.shenjiying.sms.AliSmsSender
;
import
cc.shenjiying.sms.TencentSmsSender
;
import
cc.shenjiying.sms.dto.SmsSendResult
;
import
cc.shenjiying.sms.param.SmsSendParam
;
import
io.quarkus.runtime.util.StringUtil
;
import
jakarta.enterprise.context.ApplicationScoped
;
import
jakarta.inject.Inject
;
import
lombok.extern.slf4j.Slf4j
;
import
java.util.Map
;
/**
* 验证码服务
*/
@Slf4j
@ApplicationScoped
public
class
SmsCodeService
{
@Inject
AliSmsSender
smsSender
;
@Inject
RedisCache
redisCache
;
@Inject
SmsSendLogMapper
logMapper
;
public
void
send
(
String
mobile
)
{
String
code
=
RandomUtil
.
generateNumber
(
4
);
redisCache
.
setValue
(
new
MobileCodeKey
().
key
(
mobile
),
code
,
5
*
60
);
SmsSendResult
sendResult
=
smsSender
.
send
(
SmsSendParam
.
of
(
mobile
,
"扳手快查"
,
"SMS_130170012"
,
Map
.
of
(
"code"
,
code
)));
logMapper
.
insert
(
new
SmsSendLog
().
setProviderType
(
sendResult
.
getProviderType
())
.
setMobile
(
sendResult
.
getMobile
()).
setParams
(
sendResult
.
getParams
())
.
setResult
(
sendResult
.
isResult
()).
setMessage
(
sendResult
.
getMessage
()));
}
public
boolean
check
(
String
mobile
,
String
code
)
{
if
(
StringUtil
.
isNullOrEmpty
(
mobile
)
||
StringUtil
.
isNullOrEmpty
(
code
))
{
return
false
;
}
String
value
=
redisCache
.
getValue
(
new
MobileCodeKey
().
key
(
mobile
));
return
code
.
equals
(
value
);
}
}
src/main/java/cc/shenjiying/ai/repository/entity/Questioner.java
View file @
be52c207
...
@@ -17,6 +17,12 @@ public class Questioner {
...
@@ -17,6 +17,12 @@ public class Questioner {
@TableId
(
type
=
IdType
.
AUTO
)
@TableId
(
type
=
IdType
.
AUTO
)
private
Long
id
;
private
Long
id
;
@TableField
(
value
=
"account"
)
private
String
account
;
@TableField
(
value
=
"mobile"
)
private
String
mobile
;
@TableField
(
value
=
"channel"
)
@TableField
(
value
=
"channel"
)
private
String
channel
;
private
String
channel
;
...
...
src/main/java/cc/shenjiying/ai/repository/entity/QuestionerWhiteList.java
0 → 100644
View file @
be52c207
package
cc
.
shenjiying
.
ai
.
repository
.
entity
;
import
com.baomidou.mybatisplus.annotation.IdType
;
import
com.baomidou.mybatisplus.annotation.TableField
;
import
com.baomidou.mybatisplus.annotation.TableId
;
import
com.baomidou.mybatisplus.annotation.TableName
;
import
lombok.Data
;
import
lombok.experimental.Accessors
;
import
java.time.LocalDateTime
;
@Data
@TableName
(
"questioner_white_list"
)
@Accessors
(
chain
=
true
)
public
class
QuestionerWhiteList
{
@TableId
(
type
=
IdType
.
AUTO
)
private
Long
id
;
@TableField
(
value
=
"account"
)
private
String
account
;
@TableField
(
"create_time"
)
private
LocalDateTime
createTime
;
}
src/main/java/cc/shenjiying/ai/repository/entity/SmsSendLog.java
0 → 100644
View file @
be52c207
package
cc
.
shenjiying
.
ai
.
repository
.
entity
;
import
com.baomidou.mybatisplus.annotation.IdType
;
import
com.baomidou.mybatisplus.annotation.TableField
;
import
com.baomidou.mybatisplus.annotation.TableId
;
import
com.baomidou.mybatisplus.annotation.TableName
;
import
lombok.Data
;
import
lombok.experimental.Accessors
;
import
java.time.LocalDateTime
;
@Data
@TableName
(
"sms_send_log"
)
@Accessors
(
chain
=
true
)
public
class
SmsSendLog
{
@TableId
(
type
=
IdType
.
AUTO
)
private
Long
id
;
@TableField
(
value
=
"provider_type"
)
private
String
providerType
;
@TableField
(
value
=
"mobile"
)
private
String
mobile
;
@TableField
(
value
=
"params"
)
private
String
params
;
@TableField
(
"result"
)
private
boolean
result
;
@TableField
(
"message"
)
private
String
message
;
@TableField
(
"create_time"
)
private
LocalDateTime
createTime
;
}
src/main/java/cc/shenjiying/ai/repository/mapper/QuestionerWhiteListMapper.java
0 → 100644
View file @
be52c207
package
cc
.
shenjiying
.
ai
.
repository
.
mapper
;
import
cc.shenjiying.ai.repository.entity.QuestionerWhiteList
;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
import
org.apache.ibatis.annotations.Mapper
;
@Mapper
public
interface
QuestionerWhiteListMapper
extends
BaseMapper
<
QuestionerWhiteList
>
{
}
src/main/java/cc/shenjiying/ai/repository/mapper/SmsSendLogMapper.java
0 → 100644
View file @
be52c207
package
cc
.
shenjiying
.
ai
.
repository
.
mapper
;
import
cc.shenjiying.ai.repository.entity.Question
;
import
cc.shenjiying.ai.repository.entity.SmsSendLog
;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
import
org.apache.ibatis.annotations.Mapper
;
@Mapper
public
interface
SmsSendLogMapper
extends
BaseMapper
<
SmsSendLog
>
{
}
src/main/java/cc/shenjiying/ai/resource/KnowLedgeResource.java
View file @
be52c207
package
cc
.
shenjiying
.
ai
.
resource
;
package
cc
.
shenjiying
.
ai
.
resource
;
import
cc.shenjiying.ai.config.QuestionerHolder
;
import
cc.shenjiying.ai.dto.ChatAIResponse
;
import
cc.shenjiying.ai.dto.ChatAIResponse
;
import
cc.shenjiying.ai.dto.FeedbackSaveDTO
;
import
cc.shenjiying.ai.dto.FeedbackSaveDTO
;
import
cc.shenjiying.ai.service.KnowledgeService
;
import
cc.shenjiying.ai.service.KnowledgeService
;
...
@@ -10,10 +11,8 @@ import jakarta.inject.Inject;
...
@@ -10,10 +11,8 @@ import jakarta.inject.Inject;
import
jakarta.ws.rs.*
;
import
jakarta.ws.rs.*
;
import
jakarta.ws.rs.core.MediaType
;
import
jakarta.ws.rs.core.MediaType
;
import
org.eclipse.microprofile.openapi.annotations.Operation
;
import
org.eclipse.microprofile.openapi.annotations.Operation
;
import
org.eclipse.microprofile.openapi.annotations.headers.Header
;
import
org.eclipse.microprofile.openapi.annotations.parameters.Parameter
;
import
org.eclipse.microprofile.openapi.annotations.media.Schema
;
import
org.eclipse.microprofile.openapi.annotations.tags.Tag
;
import
org.eclipse.microprofile.openapi.annotations.tags.Tag
;
import
org.jboss.logging.annotations.Producer
;
import
org.jboss.resteasy.reactive.RestPath
;
import
org.jboss.resteasy.reactive.RestPath
;
import
org.jboss.resteasy.reactive.RestStreamElementType
;
import
org.jboss.resteasy.reactive.RestStreamElementType
;
...
@@ -23,9 +22,14 @@ public class KnowLedgeResource {
...
@@ -23,9 +22,14 @@ public class KnowLedgeResource {
@Inject
@Inject
KnowledgeService
knowledgeService
;
KnowledgeService
knowledgeService
;
@HeaderParam
(
QuestionerHolder
.
TOKEN_KEY
)
@Parameter
(
name
=
QuestionerHolder
.
TOKEN_KEY
,
description
=
"登录返回的token"
)
String
myHeaderId
;
@GET
@GET
@Path
(
"/stream"
)
@Path
(
"/stream"
)
@Operation
(
summary
=
"流式请求"
)
@Operation
(
summary
=
"流式请求"
)
@Parameter
(
name
=
QuestionerHolder
.
TOKEN_KEY
,
description
=
"登录返回的token"
)
@Produces
(
MediaType
.
SERVER_SENT_EVENTS
)
@Produces
(
MediaType
.
SERVER_SENT_EVENTS
)
@RestStreamElementType
(
MediaType
.
APPLICATION_JSON
)
@RestStreamElementType
(
MediaType
.
APPLICATION_JSON
)
@RateLimited
(
bucket
=
"chat"
)
@RateLimited
(
bucket
=
"chat"
)
...
@@ -54,8 +58,8 @@ public class KnowLedgeResource {
...
@@ -54,8 +58,8 @@ public class KnowLedgeResource {
@Operation
(
summary
=
"反馈"
)
@Operation
(
summary
=
"反馈"
)
@Consumes
(
MediaType
.
APPLICATION_JSON
)
@Consumes
(
MediaType
.
APPLICATION_JSON
)
@Produces
(
MediaType
.
APPLICATION_JSON
)
@Produces
(
MediaType
.
APPLICATION_JSON
)
public
Mult
i
<
Long
>
feedback
(
FeedbackSaveDTO
feedback
)
{
public
Un
i
<
Long
>
feedback
(
FeedbackSaveDTO
feedback
)
{
return
Mult
i
.
createFrom
().
item
(()
->
knowledgeService
.
newFeedback
(
feedback
));
return
Un
i
.
createFrom
().
item
(()
->
knowledgeService
.
newFeedback
(
feedback
));
}
}
}
}
src/main/java/cc/shenjiying/ai/resource/QuestionerResource.java
0 → 100644
View file @
be52c207
package
cc
.
shenjiying
.
ai
.
resource
;
import
cc.shenjiying.ai.common.dto.R
;
import
cc.shenjiying.ai.dto.QuestionerLoginDTO
;
import
cc.shenjiying.ai.manager.QuestionerService
;
import
jakarta.inject.Inject
;
import
jakarta.ws.rs.*
;
import
jakarta.ws.rs.core.MediaType
;
import
org.eclipse.microprofile.jwt.JsonWebToken
;
import
org.eclipse.microprofile.openapi.annotations.Operation
;
import
org.eclipse.microprofile.openapi.annotations.tags.Tag
;
import
org.jboss.resteasy.reactive.RestQuery
;
@Path
(
"/questioner"
)
@Tag
(
name
=
"用户"
)
public
class
QuestionerResource
{
@Inject
QuestionerService
questionerService
;
@Inject
JsonWebToken
jwt
;
@GET
@Path
(
"/login/code"
)
@Operation
(
summary
=
"发送验证码"
)
public
R
<
Boolean
>
getLoginCode
(
@RestQuery
String
mobile
)
{
return
questionerService
.
getLoginCode
(
mobile
);
}
@POST
@Path
(
"/login"
)
@Operation
(
summary
=
"手机号登录"
)
@Produces
(
MediaType
.
APPLICATION_JSON
)
@Consumes
(
MediaType
.
APPLICATION_JSON
)
public
R
<
String
>
login
(
QuestionerLoginDTO
loginDTO
)
{
return
questionerService
.
getLoginToken
(
loginDTO
.
getAccount
(),
loginDTO
.
getPassword
());
}
}
src/main/java/cc/shenjiying/ai/util/RandomUtil.java
0 → 100644
View file @
be52c207
package
cc
.
shenjiying
.
ai
.
util
;
import
java.security.SecureRandom
;
public
class
RandomUtil
{
private
static
SecureRandom
random
=
new
SecureRandom
();
public
static
String
generateNumber
(
int
count
)
{
StringBuilder
sb
=
new
StringBuilder
();
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
sb
.
append
(
random
.
nextInt
(
10
));
}
return
sb
.
toString
();
}
}
src/main/java/cc/shenjiying/ai/util/TokenUtil.java
0 → 100644
View file @
be52c207
package
cc
.
shenjiying
.
ai
.
util
;
import
cc.shenjiying.ai.common.dto.AuthInfo
;
import
io.quarkus.runtime.util.StringUtil
;
import
io.smallrye.jwt.auth.principal.DefaultJWTParser
;
import
io.smallrye.jwt.auth.principal.JWTAuthContextInfo
;
import
io.smallrye.jwt.auth.principal.JWTParser
;
import
io.smallrye.jwt.auth.principal.ParseException
;
import
io.smallrye.jwt.build.Jwt
;
import
io.smallrye.jwt.build.impl.JwtBuildUtils
;
import
io.smallrye.jwt.util.KeyUtils
;
import
io.smallrye.jwt.util.ResourceUtils
;
import
org.eclipse.microprofile.config.ConfigProvider
;
import
org.eclipse.microprofile.jwt.Claims
;
import
org.eclipse.microprofile.jwt.JsonWebToken
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.security.GeneralSecurityException
;
import
java.util.Arrays
;
import
java.util.HashSet
;
import
java.util.Optional
;
public
class
TokenUtil
{
private
static
final
String
USER_ID
=
"userId"
;
private
static
final
String
ACCOUNT
=
"account"
;
private
static
final
String
NICKNAME
=
"nickName"
;
private
static
final
String
MOBILE
=
"mobile"
;
private
static
final
String
CHANNEL
=
"channel"
;
private
static
final
String
CHANNEL_USER_ID
=
"channelUserId"
;
public
static
String
create
(
AuthInfo
info
)
{
return
Jwt
.
claim
(
USER_ID
,
info
.
getId
())
.
claim
(
ACCOUNT
,
info
.
getAccount
())
// .claim(NICKNAME, info.getNickname())
.
claim
(
MOBILE
,
info
.
getMobile
())
.
claim
(
CHANNEL
,
info
.
getChannel
())
.
claim
(
CHANNEL_USER_ID
,
info
.
getChannelUserId
())
.
sign
();
}
public
static
AuthInfo
parse
(
JWTParser
jwtParser
,
String
token
)
{
if
(
StringUtil
.
isNullOrEmpty
(
token
))
{
return
null
;
}
try
{
String
keyLocation
=
ConfigProvider
.
getConfig
().
getOptionalValue
(
JwtBuildUtils
.
ENC_KEY_LOCATION_PROPERTY
,
String
.
class
).
orElse
(
""
);
String
issuedBy
=
ConfigProvider
.
getConfig
().
getOptionalValue
(
JwtBuildUtils
.
NEW_TOKEN_ISSUER_PROPERTY
,
String
.
class
).
orElse
(
""
);
JWTAuthContextInfo
authContextInfo
=
new
JWTAuthContextInfo
(
keyLocation
,
issuedBy
);
authContextInfo
.
setRequireNamedPrincipal
(
false
);
JsonWebToken
webToken
=
jwtParser
.
parse
(
token
,
authContextInfo
);
AuthInfo
authInfo
=
new
AuthInfo
();
authInfo
.
setId
(
Long
.
valueOf
(
webToken
.
getClaim
(
USER_ID
).
toString
()))
.
setAccount
(
webToken
.
getClaim
(
ACCOUNT
))
.
setNickname
(
webToken
.
getClaim
(
NICKNAME
))
.
setMobile
(
webToken
.
getClaim
(
MOBILE
))
.
setChannel
(
webToken
.
getClaim
(
CHANNEL
))
.
setChannelUserId
(
webToken
.
getClaim
(
CHANNEL_USER_ID
));
return
authInfo
;
}
catch
(
ParseException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
}
src/main/java/cc/shenjiying/redis/RedisCache.java
0 → 100644
View file @
be52c207
package
cc
.
shenjiying
.
redis
;
import
cc.shenjiying.redis.key.RedisCacheKey
;
import
io.quarkus.redis.datasource.RedisDataSource
;
import
io.quarkus.redis.datasource.value.ValueCommands
;
import
jakarta.enterprise.context.ApplicationScoped
;
@ApplicationScoped
public
class
RedisCache
{
ValueCommands
<
String
,
String
>
valueCommands
;
public
RedisCache
(
RedisDataSource
ds
)
{
valueCommands
=
ds
.
value
(
String
.
class
);
}
public
<
T
>
void
setValue
(
RedisCacheKey
key
,
String
value
,
long
time
)
{
valueCommands
.
setex
(
key
.
getKey
(),
time
,
value
);
}
public
void
setNxValue
(
RedisCacheKey
key
,
String
value
)
{
valueCommands
.
setnx
(
key
.
getKey
(),
value
);
}
public
String
getValue
(
RedisCacheKey
key
)
{
return
valueCommands
.
get
(
key
.
getKey
());
}
public
String
delete
(
RedisCacheKey
key
)
{
return
valueCommands
.
getdel
(
key
.
getKey
());
}
}
src/main/java/cc/shenjiying/redis/key/MobileCodeKey.java
0 → 100644
View file @
be52c207
package
cc
.
shenjiying
.
redis
.
key
;
public
class
MobileCodeKey
extends
RedisCacheKey
{
@Override
public
String
biz
()
{
return
"mobile_code"
;
}
}
src/main/java/cc/shenjiying/redis/key/RedisCacheKey.java
0 → 100644
View file @
be52c207
package
cc
.
shenjiying
.
redis
.
key
;
import
cc.shenjiying.redis.RedisCache
;
public
abstract
class
RedisCacheKey
{
private
String
key
;
String
project
()
{
return
"ai_agent"
;
}
public
abstract
String
biz
();
public
RedisCacheKey
key
(
String
key
)
{
this
.
key
=
key
;
return
this
;
}
public
String
getKey
()
{
return
project
()
+
":"
+
biz
()
+
":"
+
this
.
key
;
}
}
src/main/java/cc/shenjiying/sms/AliSmsSender.java
0 → 100644
View file @
be52c207
package
cc
.
shenjiying
.
sms
;
import
cc.shenjiying.sms.dto.SmsSendResult
;
import
cc.shenjiying.sms.param.SmsSendParam
;
import
com.aliyun.dysmsapi20170525.Client
;
import
com.aliyun.dysmsapi20170525.models.SendSmsRequest
;
import
com.aliyun.dysmsapi20170525.models.SendSmsResponse
;
import
com.aliyun.teaopenapi.models.Config
;
import
com.aliyun.teautil.models.RuntimeOptions
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
jakarta.enterprise.context.ApplicationScoped
;
import
jakarta.inject.Inject
;
@ApplicationScoped
public
class
AliSmsSender
{
private
static
final
String
DOMAIN
=
"dysmsapi.aliyuncs.com"
;
private
final
String
appId
=
"LTAIAXZdcDQgzEt9"
;
private
final
String
secret
=
"nlKCSemDT7fejXwdny9ebXBvd2qaS1"
;
@Inject
ObjectMapper
objectMapper
;
public
SmsSendResult
send
(
SmsSendParam
param
)
{
SmsSendResult
.
SmsSendResultBuilder
resultBuilder
=
SmsSendResult
.
builder
().
providerType
(
"ALI"
).
mobile
(
param
.
getMobile
());
try
{
Config
config
=
new
Config
().
setAccessKeyId
(
appId
).
setAccessKeySecret
(
secret
);
config
.
endpoint
=
DOMAIN
;
Client
client
=
new
Client
(
config
);
String
sendParam
=
objectMapper
.
writeValueAsString
(
param
.
getParams
());
SendSmsRequest
sendSmsRequest
=
new
SendSmsRequest
();
//必填:待发送手机号
sendSmsRequest
.
setPhoneNumbers
(
param
.
getMobile
());
sendSmsRequest
.
setSignName
(
param
.
getSignName
());
sendSmsRequest
.
setTemplateCode
(
param
.
getTempleCode
());
sendSmsRequest
.
setTemplateParam
(
sendParam
);
// sendSmsRequest.setOutId(String.valueOf(smsDO.getTaskId()));
SendSmsResponse
response
=
client
.
sendSmsWithOptions
(
sendSmsRequest
,
new
RuntimeOptions
());
return
resultBuilder
.
params
(
sendParam
).
result
(
"OK"
.
equals
(
response
.
body
.
code
)).
message
(
response
.
body
.
message
).
build
();
}
catch
(
Exception
_error
)
{
return
resultBuilder
.
result
(
false
).
message
(
_error
.
getMessage
()).
build
();
}
}
}
\ No newline at end of file
src/main/java/cc/shenjiying/sms/TencentSmsSender.java
0 → 100644
View file @
be52c207
package
cc
.
shenjiying
.
sms
;
import
cc.shenjiying.sms.dto.SmsSendResult
;
import
cc.shenjiying.sms.param.SmsSendParam
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.github.qcloudsms.SmsSingleSender
;
import
com.github.qcloudsms.SmsSingleSenderResult
;
import
jakarta.enterprise.context.ApplicationScoped
;
import
jakarta.inject.Inject
;
import
lombok.extern.slf4j.Slf4j
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.Objects
;
@Slf4j
//@ApplicationScoped
public
class
TencentSmsSender
{
private
static
final
Map
<
String
,
String
>
ERROR_CODE_MAP
=
new
HashMap
<>(
50
);
static
{
ERROR_CODE_MAP
.
put
(
"1001"
,
"sig 校验失败"
);
ERROR_CODE_MAP
.
put
(
"1002"
,
"短信/语音内容中含有敏感词"
);
ERROR_CODE_MAP
.
put
(
"1003"
,
"请求包体没有 sig 字段或 sig 为空"
);
ERROR_CODE_MAP
.
put
(
"1004"
,
"请求包解析失败,通常情况下是由于没有遵守 API 接口说明规范导致的"
);
ERROR_CODE_MAP
.
put
(
"1006"
,
"请求没有权限"
);
ERROR_CODE_MAP
.
put
(
"1007"
,
"其他错误"
);
ERROR_CODE_MAP
.
put
(
"1008"
,
"请求下发短信/语音超时"
);
ERROR_CODE_MAP
.
put
(
"1009"
,
"请求 IP 不在白名单中"
);
ERROR_CODE_MAP
.
put
(
"1011"
,
"不存在该 REST API 接口"
);
ERROR_CODE_MAP
.
put
(
"1012"
,
"签名格式错误或者签名未审批"
);
ERROR_CODE_MAP
.
put
(
"1013"
,
"下发短信/语音命中了频率限制策略"
);
ERROR_CODE_MAP
.
put
(
"1014"
,
"模版未审批或请求的内容与审核通过的模版内容不匹配"
);
ERROR_CODE_MAP
.
put
(
"1015"
,
"手机号在阻止列表库中,通常是用户退订或者命中运营商阻止列表导致的"
);
ERROR_CODE_MAP
.
put
(
"1016"
,
"手机号格式错误"
);
ERROR_CODE_MAP
.
put
(
"1017"
,
"请求的短信内容太长"
);
ERROR_CODE_MAP
.
put
(
"1018"
,
"语音验证码格式错误"
);
ERROR_CODE_MAP
.
put
(
"1019"
,
"sdk appId 不存在"
);
ERROR_CODE_MAP
.
put
(
"1020"
,
"sdk appId 已禁用"
);
ERROR_CODE_MAP
.
put
(
"1021"
,
"请求发起时间不正常,通常是由于您的服务器时间与腾讯云服务器时间差异超过10分钟导致的"
);
ERROR_CODE_MAP
.
put
(
"1022"
,
"业务短信日下发条数超过设定的上限"
);
ERROR_CODE_MAP
.
put
(
"1023"
,
"单个手机号30秒内下发短信条数超过设定的上限"
);
ERROR_CODE_MAP
.
put
(
"1024"
,
"单个手机号1小时内下发短信条数超过设定的上限"
);
ERROR_CODE_MAP
.
put
(
"1025"
,
"单个手机号日下发短信条数超过设定的上限"
);
ERROR_CODE_MAP
.
put
(
"1026"
,
"单个手机号下发相同内容超过设定的上限"
);
ERROR_CODE_MAP
.
put
(
"1029"
,
"营销短信发送时间限制"
);
ERROR_CODE_MAP
.
put
(
"1030"
,
"不支持该请求"
);
ERROR_CODE_MAP
.
put
(
"1031"
,
"套餐包余量不足"
);
ERROR_CODE_MAP
.
put
(
"1032"
,
"个人用户没有发营销短信的权限"
);
ERROR_CODE_MAP
.
put
(
"1033"
,
"欠费被停止服务"
);
ERROR_CODE_MAP
.
put
(
"1034"
,
"群发请求里既有国内手机号也有国际手机号"
);
ERROR_CODE_MAP
.
put
(
"1036"
,
"单个模板变量字符数超过12个"
);
ERROR_CODE_MAP
.
put
(
"1045"
,
"不支持该地区短信下发"
);
ERROR_CODE_MAP
.
put
(
"1046"
,
"调用群发 API 接口单次提交的手机号个数超过200个"
);
ERROR_CODE_MAP
.
put
(
"1047"
,
"国际短信日下发条数被限制"
);
ERROR_CODE_MAP
.
put
(
"60008"
,
"处理请求超时"
);
}
private
final
int
appId
=
1400623773
;
private
final
String
secret
=
"3e566d11db636382dd498c6a01aced03"
;
@Inject
ObjectMapper
objectMapper
;
public
TencentSmsSender
()
{
}
public
SmsSendResult
send
(
SmsSendParam
param
)
{
SmsSendResult
.
SmsSendResultBuilder
resultBuilder
=
SmsSendResult
.
builder
().
providerType
(
"TENCENT"
).
mobile
(
param
.
getMobile
());
try
{
resultBuilder
.
params
(
objectMapper
.
writeValueAsString
(
param
.
getParams
()));
}
catch
(
Exception
e
)
{
log
.
warn
(
"序列化错误"
,
e
);
}
try
{
//初始化单发
SmsSingleSender
singleSender
=
new
SmsSingleSender
(
appId
,
secret
);
Map
<
String
,
String
>
sendParam
=
param
.
getParams
();
ArrayList
<
String
>
paramList
=
new
ArrayList
<>();
if
(
Objects
.
nonNull
(
sendParam
))
{
for
(
Map
.
Entry
<
String
,
String
>
val
:
sendParam
.
entrySet
())
{
paramList
.
add
(
val
.
getValue
());
}
}
SmsSingleSenderResult
singleSenderResult
=
singleSender
.
sendWithParam
(
"86"
,
param
.
getMobile
(),
Integer
.
parseInt
(
param
.
getTempleCode
()),
paramList
,
param
.
getSignName
(),
""
,
""
);
return
resultBuilder
.
result
(
0
==
singleSenderResult
.
result
).
build
();
}
catch
(
Exception
e
)
{
return
resultBuilder
.
result
(
false
).
message
(
e
.
getMessage
()).
build
();
}
}
}
src/main/java/cc/shenjiying/sms/dto/SmsSendResult.java
0 → 100644
View file @
be52c207
package
cc
.
shenjiying
.
sms
.
dto
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.experimental.Accessors
;
@Data
@Builder
@Accessors
(
chain
=
true
)
public
class
SmsSendResult
{
private
String
providerType
;
private
String
mobile
;
private
String
params
;
private
boolean
result
;
private
String
message
;
}
src/main/java/cc/shenjiying/sms/param/SmsSendParam.java
0 → 100644
View file @
be52c207
package
cc
.
shenjiying
.
sms
.
param
;
import
lombok.Data
;
import
java.util.Map
;
@Data
public
class
SmsSendParam
{
private
String
mobile
;
private
String
templeCode
;
private
String
signName
;
private
Map
<
String
,
String
>
params
;
public
static
SmsSendParam
of
(
String
mobile
,
String
signName
,
String
templeCode
,
Map
<
String
,
String
>
sendParam
)
{
SmsSendParam
param
=
new
SmsSendParam
();
param
.
mobile
=
mobile
;
param
.
signName
=
signName
;
param
.
templeCode
=
templeCode
;
param
.
params
=
sendParam
;
return
param
;
}
}
src/main/resources/application-prod.properties
View file @
be52c207
...
@@ -8,9 +8,12 @@ quarkus.datasource.jdbc.url=jdbc:mysql://172.16.16.3:3306/ai_chat
...
@@ -8,9 +8,12 @@ quarkus.datasource.jdbc.url=jdbc:mysql://172.16.16.3:3306/ai_chat
quarkus.mybatis.map-underscore-to-camel-case
=
true
quarkus.mybatis.map-underscore-to-camel-case
=
true
quarkus.log.file.enable
=
true
quarkus.log.file.enable
=
true
quarkus.log.file.level
=
WAR
E
quarkus.log.file.level
=
WAR
N
quarkus.log.file.path
=
/weixiuhui/logStore/ai-chat/application.log
quarkus.log.file.path
=
/weixiuhui/logStore/ai-chat/application.log
quarkus.log.file.format
=
%d{yyyy-MM-dd HH:mm:ss} %-5p [%c] (%t) %s%e%n
quarkus.log.file.format
=
%d{yyyy-MM-dd HH:mm:ss} %-5p [%c] (%t) %s%e%n
quarkus.log.file.async
=
true
quarkus.log.file.async
=
true
quarkus.redis.hosts
=
redis://172.16.16.21:6379/
#quarkus.redis.password=crs-duci75tn:Weixiuhui2014!
src/main/resources/application-stage.properties
View file @
be52c207
...
@@ -15,3 +15,5 @@ quarkus.log.file.path=/weixiuhui/logStore/ai-chat/application.log
...
@@ -15,3 +15,5 @@ quarkus.log.file.path=/weixiuhui/logStore/ai-chat/application.log
quarkus.log.file.format
=
%d{yyyy-MM-dd HH:mm:ss} %-5p [%c] (%t) %s%e%n
quarkus.log.file.format
=
%d{yyyy-MM-dd HH:mm:ss} %-5p [%c] (%t) %s%e%n
quarkus.log.file.async
=
true
quarkus.log.file.async
=
true
quarkus.redis.hosts
=
redis://127.0.0.1:6379/
#
quarkus.redis.password
=
\ No newline at end of file
src/main/resources/application.properties
View file @
be52c207
...
@@ -49,7 +49,8 @@ quarkus.mybatis.map-underscore-to-camel-case=true
...
@@ -49,7 +49,8 @@ quarkus.mybatis.map-underscore-to-camel-case=true
#quarkus.mybatis.environment=development
#quarkus.mybatis.environment=development
#quarkus.mybatis.mapper-locations=mapper
#quarkus.mybatis.mapper-locations=mapper
#Redis\u914D\u7F6E
#Redis\u914D\u7F6E
quarkus.redis.hosts
=
redis://192.168.1.24:3306/
quarkus.redis.hosts
=
redis://192.168.1.24:6379/
#quarkus.redis.password=
#Reids\u96C6\u7FA4\u6A21\u5F0F
#Reids\u96C6\u7FA4\u6A21\u5F0F
#quarkus.redis.hosts=redis://localhost:7000,redis://localhost:7001,redis://localhost:7002
#quarkus.redis.hosts=redis://localhost:7000,redis://localhost:7001,redis://localhost:7002
#quarkus.redis.client-type=cluster
#quarkus.redis.client-type=cluster
...
@@ -61,3 +62,21 @@ quarkus.rate-limiter.buckets.chat.limits[0].period: 1S
...
@@ -61,3 +62,21 @@ quarkus.rate-limiter.buckets.chat.limits[0].period: 1S
quarkus.rate-limiter.buckets.chat.limits[1]
.permitted-uses
:
700
quarkus.rate-limiter.buckets.chat.limits[1]
.permitted-uses
:
700
quarkus.rate-limiter.buckets.chat.limits[1]
.period
:
5M
quarkus.rate-limiter.buckets.chat.limits[1]
.period
:
5M
#jwt
#\u53D1\u884C\u8005\u3001\u53D7\u4F17
smallrye.jwt.new-token.issuer
=
ai.kaying.cc
#smallrye.jwt.new-token.audience=
smallrye.jwt.claims.sub
=
ai
smallrye.jwt.require.named-principal
=
false
# \u8FC7\u671F\u65F6\u95F4 7\u5929
smallrye.jwt.new-token.lifespan
=
604800
#\u7B7E\u540D\u7B97\u6CD5
#smallrye.jwt.new-token.signature-algorithm=PS256
#smallrye.jwt.new-token.key-encryption-algorithm=RSA-OAEP-256
#smallrye.jwt.new-token.content-encryption-algorithm=A256CBC-HS512
#\u7B7E\u540D\u79C1\u94A5\u516C\u94A5
smallrye.jwt.sign.key.location
=
key/jwt_private.pem
smallrye.jwt.encrypt.key.location
=
key/jwt_public.pem
#smallrye.jwt.decrypt.key.location=key/jwt_private.pem
src/main/resources/key/jwt_private.pem
0 → 100644
View file @
be52c207
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCuNQEMVqODpEfj
srUUR4bTYFtaWcWutS279TZI2SGUEaVY2j8OCh8SGkB38u4faNuAL09b6utASQxt
YFi42+s9kfUu+x+BEgluQU7m25qNIWscvM/k0QzNfrToD0ncc6/4EYQuEzfYpic+
UDGrlkswLfWP0Nw7L4uQ4yNpGQGjU8p4u1wL7GIR1mfbOZ6HRHd/rIMW6Jd65Nmm
kgO70YvInS/8XREsw40T3rDMdRbQo9WsaxocZ8DqFVXSLSym+v/kwZuHCR+6C7KE
O599Fd2vwNf+yH9nD9hOgPv+kbbZBZazVUl3jPQvIg99Dhf7snoDhgKB76yIJ9Wh
pJmTrew9AgMBAAECggEAAW62vsrtlq6gpE4uMAFm9rdmbBrfePbNB/kihHA71vOO
mDYlnTA9hJDjsjjOQ9x0XzYqx5cDogH+KkR7DK+xdc5zJWFz2l3AGk1K+hn/LnIc
AKuXmApiBqr09apYHj1AF3ppZSMyUXbYTSpfcvynsWwHU2Xq+BYFgBNmEXF4f0cB
iSiuFN/n7HS27h9zGwSCysZfffR+CW6+lejqEWQDZeEMZPi5TEyBliwBcFXo4DY9
Ak+maAzNSsuW4oDi3BDQx7IDlLsVX1NRtYxUQbuP3/UgnBd2HfaK6Gupr4f7QEQv
8/Pon63y6Hixn7KFoIn0LN53QSkfKZtWAOnx9hNgEQKBgQDVfiBoJ6UZ7y5I/dln
j69ldsPjOYhc2qVZ6fqmWFk4t4VlZ2DWICSRr8W8dG+jgeH6rkwSdPBe+j6IVALL
6ZP9OsSW+KUbX9THd/HWDQ/mWkMfSoWTQcobbihpNDa9n7hlbFhKm2NOpD94QH/l
twqzbErCpm2qqn83EBwW4pRp6QKBgQDQ5HX5qUjBVi47QSTqgD53ObZJKAMsE+35
Ia4hPvK/hb28ao4tjB7GbyttsoqNPBTV1rZShU6OcxoT/g+CECqcYeE9NRmHaYPP
mymfy2mULvbTP/wjGKfM2vHFevGqS/PT9cY8AOV761FTQyMD7DYvwRAm57pJ6oh0
RCA0A9WnNQKBgQCmodsJcGgc5eJqdjfJ7QwpVZlvMOiOENoeY9GPJEX/Tr5/d0DN
4CiqzVa40OiR5j5LOt+FSGCUwR0tquTD43vumn/2lfvIcfPR/Hx1ZZyTXsAlHDVF
yoPFBSXldyuCtbdm8jm3gbDxIKGpai5pTYS8pjlz1BKkso64m4pREmhkgQKBgHcU
xew9BKyyZEiDKnhEA1gUHkY1+Rj3g4GyIYHyUI+9vhva4pI0fpbAaRFv5mv9BCOi
8uy38cBi/UrIWi7a6G+dnLk3vAXlsK541ZGyc811uF9U6ndXZtDxP0JEg9+AzM7Y
HNm36RprW0EL1Lo3vewbMwn6r8fTW1ZsP69nQDTBAoGBALlhyGCm2V1LXAUP4kPG
jmhtaXWUTiSx6+ZAOujjz2KOPK82BbyKS65laar+3+TrRZTsZMeOIo36MxgdmeKw
Wd22qn2bYOW30+yJZybgNOXPmFEMIPdONJixIItR2iGHN8OO6Nxk1owxJHM83O8v
F39rjadAJVFgdHmuM/U5FTGr
-----END PRIVATE KEY-----
src/main/resources/key/jwt_public.pem
0 → 100644
View file @
be52c207
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArjUBDFajg6RH47K1FEeG
02BbWlnFrrUtu/U2SNkhlBGlWNo/DgofEhpAd/LuH2jbgC9PW+rrQEkMbWBYuNvr
PZH1LvsfgRIJbkFO5tuajSFrHLzP5NEMzX606A9J3HOv+BGELhM32KYnPlAxq5ZL
MC31j9DcOy+LkOMjaRkBo1PKeLtcC+xiEdZn2zmeh0R3f6yDFuiXeuTZppIDu9GL
yJ0v/F0RLMONE96wzHUW0KPVrGsaHGfA6hVV0i0spvr/5MGbhwkfuguyhDuffRXd
r8DX/sh/Zw/YToD7/pG22QWWs1VJd4z0LyIPfQ4X+7J6A4YCge+siCfVoaSZk63s
PQIDAQAB
-----END PUBLIC KEY-----
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