mirror of
https://github.com/ccmjga/zhilu-admin
synced 2026-04-05 11:47:32 +00:00
Compare commits
92 Commits
responsive
...
f0a237fdf3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0a237fdf3 | ||
|
|
13d240342c | ||
|
|
8e20f561a4 | ||
|
|
b759275cf3 | ||
|
|
5f0f0fbd14 | ||
|
|
7088712560 | ||
|
|
2c302315b1 | ||
|
|
87c4706ca7 | ||
|
|
deece30554 | ||
|
|
eecc8bedae | ||
|
|
0a0174c01e | ||
|
|
36d285a61d | ||
|
|
5c685d4f74 | ||
|
|
1bd50f5de2 | ||
|
|
e646bdffa8 | ||
|
|
a767613b58 | ||
|
|
152f0fe07c | ||
|
|
b6ecc929b0 | ||
|
|
3e1d7e6fee | ||
|
|
f9c8e3808b | ||
|
|
56d6a992f8 | ||
|
|
6ec07686a9 | ||
|
|
d4b2343ac9 | ||
|
|
5665ae0fda | ||
|
|
4d70b49e61 | ||
|
|
8ed0b795f3 | ||
|
|
2fb08968ee | ||
|
|
2f7259ca9d | ||
|
|
19090b9c94 | ||
|
|
cbfbd6c5dd | ||
|
|
09f51fa91f | ||
|
|
5494181ae0 | ||
|
|
8d285e1abc | ||
|
|
76b77dbf18 | ||
|
|
8ffa4324d3 | ||
|
|
7442516c07 | ||
|
|
f04ea3a9e8 | ||
|
|
ea86342a0f | ||
|
|
3d48ae9119 | ||
|
|
fa580a5dd4 | ||
|
|
87d288c58e | ||
|
|
772ad547bf | ||
|
|
ca42fbbda9 | ||
|
|
28eed04823 | ||
|
|
5306e24aa2 | ||
|
|
621170b347 | ||
|
|
ea10b156e3 | ||
|
|
7b8ef54e7b | ||
|
|
7e1940e459 | ||
|
|
567223eac3 | ||
|
|
1995985750 | ||
|
|
fe3ebdf931 | ||
|
|
f011086fcf | ||
|
|
d9853ef8d0 | ||
|
|
dc7780e0a8 | ||
|
|
c64f2eb0f6 | ||
|
|
f559e4cde3 | ||
|
|
ab72508408 | ||
|
|
219b4f40a6 | ||
|
|
bb9cd2e529 | ||
|
|
8a8588588f | ||
|
|
ac6c50ff28 | ||
|
|
a00c3e129f | ||
|
|
81b02e68e7 | ||
|
|
79d4ced364 | ||
|
|
a30d63ebdd | ||
|
|
f65349f246 | ||
|
|
2324bcaa13 | ||
|
|
4f35b256e6 | ||
|
|
24f379857a | ||
|
|
17200ec6d1 | ||
|
|
5068e7ff58 | ||
|
|
45c921fa24 | ||
|
|
db02af8677 | ||
|
|
56e92b2cb8 | ||
|
|
39c91a971b | ||
|
|
a1752df1ed | ||
|
|
df3862d496 | ||
|
|
bdf9da7eed | ||
|
|
d4a34e7b52 | ||
|
|
a982942153 | ||
|
|
f53db08c25 | ||
|
|
2210348d3b | ||
|
|
690228cb42 | ||
|
|
d5801b3b50 | ||
|
|
27529ee70c | ||
|
|
50a1bc65ef | ||
|
|
54201aa0f0 | ||
|
|
07e590dc2d | ||
|
|
34e0d3d8e7 | ||
|
|
ad5b20d3c5 | ||
|
|
dba64a38f2 |
23
README.md
23
README.md
@@ -34,21 +34,27 @@
|
|||||||
|
|
||||||
## 🥝 产品社群
|
## 🥝 产品社群
|
||||||
|
|
||||||
**加 QQ 群,获取一键部署脚本(包含数据库 Redis 消息队列等所有中间件!)**
|
**加 QQ 群或微信群立送以下装备,瞬间秒杀全服!!**
|
||||||
|
1. 一键部署脚本(包含数据库 Redis 消息队列等所有中间件!)
|
||||||
|
2. 永久免费的 Https 证书
|
||||||
|
3. 永久免费的分布式对象存储
|
||||||
|
4. 永久免费的 AI 模型
|
||||||
|
5. 永久免费的 Node、Docker、Maven 国内镜像仓库
|
||||||
|
|
||||||
- QQ群:638254979 (获取部署脚本)
|

|
||||||
|
|
||||||
[](https://qm.qq.com/q/9mvVC57jPO)
|
[](https://qm.qq.com/q/9mvVC57jPO)
|
||||||
|
|
||||||
实在没有 QQ 的可以加微信
|
|
||||||
|
|
||||||
- 微信:Chuck9996
|
- QQ群:638254979(目前人较多)
|
||||||
|
- 微信:Chuck9996(若微信群已过期可以加我 vx)
|
||||||
|
|
||||||
|
|
||||||
## 🍅 相关课程
|
## 🍅 相关课程
|
||||||
|
|
||||||
已上线:
|
已上线:
|
||||||
|
|
||||||
- [《重构方法论与单元测试的艺术》](https://www.bilibili.com/cheese/play/ep1615343)
|
- [《国内首个无幻觉式 AI 编程指南》](https://www.bilibili.com/cheese/play/ep1615343)
|
||||||
|
|
||||||
敬请期待:(加群获取)
|
敬请期待:(加群获取)
|
||||||
|
|
||||||
@@ -70,11 +76,8 @@
|
|||||||
|
|
||||||
用户通过和知路智能体对话,便可完成所有核心业务操作,不再需要再去学习操作复杂的前端页面。使你在任何时间都可享受运筹帷幄,指点江山的人生乐趣!
|
用户通过和知路智能体对话,便可完成所有核心业务操作,不再需要再去学习操作复杂的前端页面。使你在任何时间都可享受运筹帷幄,指点江山的人生乐趣!
|
||||||
|
|
||||||
**企业问答**
|

|
||||||

|

|
||||||
|
|
||||||
**操作业务功能**
|
|
||||||

|
|
||||||
|
|
||||||
**更多功能正在锐意制作中,敬请期待。。。**
|
**更多功能正在锐意制作中,敬请期待。。。**
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 185 KiB |
BIN
assets/action1.png
Normal file
BIN
assets/action1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 298 KiB |
BIN
assets/action2.png
Normal file
BIN
assets/action2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 426 KiB |
BIN
assets/group.png
Normal file
BIN
assets/group.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 530 KiB |
BIN
assets/wechat.png
Normal file
BIN
assets/wechat.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 164 KiB |
@@ -15,3 +15,11 @@ ALLOWED_ORIGINS=http://localhost,https://localhost,http://localhost:8080,http://
|
|||||||
ALLOWED_METHODS=*
|
ALLOWED_METHODS=*
|
||||||
ALLOWED_HEADERS=*
|
ALLOWED_HEADERS=*
|
||||||
ALLOWED_EXPOSE_HEADERS=*
|
ALLOWED_EXPOSE_HEADERS=*
|
||||||
|
# minio
|
||||||
|
MINIO_ENDPOINT=http://host.docker.internal:9000
|
||||||
|
MINIO_EXPOSE_PORT=9000
|
||||||
|
MINIO_WEB_PORT=9001
|
||||||
|
MINIO_STORE=~/docker/store/mjga/minio/data
|
||||||
|
MINIO_ROOT_USER=minio
|
||||||
|
MINIO_ROOT_PASSWORD=minio123
|
||||||
|
MINIO_DEFAULT_BUCKETS=zhilu
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ sourceSets {
|
|||||||
group = "com.zl.mjga"
|
group = "com.zl.mjga"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
description = "make java great again!"
|
description = "make java great again!"
|
||||||
java.sourceCompatibility = JavaVersion.VERSION_17
|
java.sourceCompatibility = JavaVersion.VERSION_21
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
compileOnly {
|
compileOnly {
|
||||||
@@ -53,6 +53,7 @@ dependencies {
|
|||||||
implementation("org.apache.commons:commons-lang3:3.17.0")
|
implementation("org.apache.commons:commons-lang3:3.17.0")
|
||||||
implementation("org.apache.commons:commons-collections4:4.4")
|
implementation("org.apache.commons:commons-collections4:4.4")
|
||||||
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0")
|
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0")
|
||||||
|
implementation("io.minio:minio:8.5.17")
|
||||||
implementation("org.jooq:jooq-meta:$jooqVersion")
|
implementation("org.jooq:jooq-meta:$jooqVersion")
|
||||||
implementation("com.auth0:java-jwt:4.4.0")
|
implementation("com.auth0:java-jwt:4.4.0")
|
||||||
implementation("org.flywaydb:flyway-core:$flywayVersion")
|
implementation("org.flywaydb:flyway-core:$flywayVersion")
|
||||||
@@ -63,6 +64,8 @@ dependencies {
|
|||||||
implementation("dev.langchain4j:langchain4j-open-ai:1.0.0")
|
implementation("dev.langchain4j:langchain4j-open-ai:1.0.0")
|
||||||
implementation("dev.langchain4j:langchain4j-pgvector:1.0.1-beta6")
|
implementation("dev.langchain4j:langchain4j-pgvector:1.0.1-beta6")
|
||||||
implementation("dev.langchain4j:langchain4j-community-zhipu-ai:1.0.1-beta6")
|
implementation("dev.langchain4j:langchain4j-community-zhipu-ai:1.0.1-beta6")
|
||||||
|
implementation("dev.langchain4j:langchain4j-document-parser-apache-tika:1.1.0-beta7")
|
||||||
|
implementation("dev.langchain4j:langchain4j-document-loader-amazon-s3:1.1.0-beta7")
|
||||||
implementation("io.projectreactor:reactor-core:3.7.6")
|
implementation("io.projectreactor:reactor-core:3.7.6")
|
||||||
testImplementation("org.testcontainers:junit-jupiter:$testcontainersVersion")
|
testImplementation("org.testcontainers:junit-jupiter:$testcontainersVersion")
|
||||||
testImplementation("org.testcontainers:postgresql:$testcontainersVersion")
|
testImplementation("org.testcontainers:postgresql:$testcontainersVersion")
|
||||||
@@ -99,14 +102,14 @@ tasks.jacocoTestReport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
jacoco {
|
jacoco {
|
||||||
toolVersion = "0.8.12"
|
toolVersion = "0.8.13"
|
||||||
reportsDirectory.set(layout.buildDirectory.dir("reports/jacoco"))
|
reportsDirectory.set(layout.buildDirectory.dir("reports/jacoco"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pmd {
|
pmd {
|
||||||
sourceSets = listOf(java.sourceSets.findByName("main"))
|
sourceSets = listOf(java.sourceSets.findByName("main"))
|
||||||
isConsoleOutput = true
|
isConsoleOutput = true
|
||||||
toolVersion = "7.9.0"
|
toolVersion = "7.15.0"
|
||||||
rulesMinimumPriority.set(5)
|
rulesMinimumPriority.set(5)
|
||||||
ruleSetFiles = files("pmd-rules.xml")
|
ruleSetFiles = files("pmd-rules.xml")
|
||||||
}
|
}
|
||||||
@@ -122,7 +125,7 @@ spotless {
|
|||||||
}
|
}
|
||||||
|
|
||||||
java {
|
java {
|
||||||
googleJavaFormat("1.25.2").reflowLongStrings()
|
googleJavaFormat("1.28.0").reflowLongStrings()
|
||||||
formatAnnotations()
|
formatAnnotations()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,14 +170,8 @@ jooq {
|
|||||||
}
|
}
|
||||||
forcedTypes {
|
forcedTypes {
|
||||||
forcedType {
|
forcedType {
|
||||||
name = "varchar"
|
isJsonConverter = true
|
||||||
includeExpression = ".*"
|
includeTypes = "(?i:JSON|JSONB)"
|
||||||
includeTypes = "JSONB?"
|
|
||||||
}
|
|
||||||
forcedType {
|
|
||||||
name = "varchar"
|
|
||||||
includeExpression = ".*"
|
|
||||||
includeTypes = "INET"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,11 @@
|
|||||||
</description>
|
</description>
|
||||||
<rule ref="category/java/bestpractices.xml">
|
<rule ref="category/java/bestpractices.xml">
|
||||||
<exclude name="GuardLogStatement"/>
|
<exclude name="GuardLogStatement"/>
|
||||||
|
<exclude name="AvoidReassigningParameters"/>
|
||||||
</rule>
|
</rule>
|
||||||
<rule ref="category/java/errorprone.xml">
|
<rule ref="category/java/errorprone.xml">
|
||||||
<exclude name="AvoidLiteralsInIfCondition"/>
|
<exclude name="AvoidLiteralsInIfCondition"/>
|
||||||
</rule>
|
<exclude name="AvoidDuplicateLiterals"/>
|
||||||
|
|
||||||
</ruleset>
|
</rule>
|
||||||
|
</ruleset>
|
||||||
@@ -2,8 +2,8 @@ rootProject.name = "backend"
|
|||||||
|
|
||||||
pluginManagement {
|
pluginManagement {
|
||||||
repositories {
|
repositories {
|
||||||
maven { url = uri("https://mirrors.cloud.tencent.com/nexus/repository/maven-public/") }
|
// maven { url = uri("https://mirrors.cloud.tencent.com/nexus/repository/maven-public/") }
|
||||||
maven { url = uri("https://mirrors.cloud.tencent.com/nexus/repository/gradle-plugin/") }
|
// maven { url = uri("https://mirrors.cloud.tencent.com/nexus/repository/gradle-plugin/") }
|
||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
@@ -11,8 +11,8 @@ pluginManagement {
|
|||||||
|
|
||||||
dependencyResolutionManagement {
|
dependencyResolutionManagement {
|
||||||
repositories {
|
repositories {
|
||||||
maven { url = uri("https://mirrors.cloud.tencent.com/nexus/repository/maven-public/") }
|
// maven { url = uri("https://mirrors.cloud.tencent.com/nexus/repository/maven-public/") }
|
||||||
maven { url = uri("https://mirrors.cloud.tencent.com/nexus/repository/apache-snapshots/") }
|
// maven { url = uri("https://mirrors.cloud.tencent.com/nexus/repository/apache-snapshots/") }
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ package com.zl.mjga;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
|
||||||
|
@EnableAsync
|
||||||
@SpringBootApplication(scanBasePackages = {"com.zl.mjga", "org.jooq.generated"})
|
@SpringBootApplication(scanBasePackages = {"com.zl.mjga", "org.jooq.generated"})
|
||||||
public class ApplicationService {
|
public class ApplicationService {
|
||||||
|
|
||||||
|
|||||||
45
backend/src/main/java/com/zl/mjga/annotation/SkipAopLog.java
Normal file
45
backend/src/main/java/com/zl/mjga/annotation/SkipAopLog.java
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package com.zl.mjga.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跳过AOP日志记录注解
|
||||||
|
*
|
||||||
|
* <p>在方法上添加此注解,该方法将不会被AOP日志切面拦截和记录。
|
||||||
|
*
|
||||||
|
* <p>使用场景:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>敏感操作方法,不希望记录日志
|
||||||
|
* <li>高频调用方法,避免产生过多日志
|
||||||
|
* <li>内部工具方法,不需要业务日志记录
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>使用示例:
|
||||||
|
*
|
||||||
|
* <pre>{@code
|
||||||
|
* @SkipAopLog
|
||||||
|
* public void sensitiveMethod() {
|
||||||
|
* // 此方法不会被AOP日志记录
|
||||||
|
* }
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* @author AOP Log System
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface SkipAopLog {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跳过日志记录的原因说明(可选)
|
||||||
|
*
|
||||||
|
* @return 跳过原因
|
||||||
|
*/
|
||||||
|
String reason() default "";
|
||||||
|
}
|
||||||
312
backend/src/main/java/com/zl/mjga/aspect/LoggingAspect.java
Normal file
312
backend/src/main/java/com/zl/mjga/aspect/LoggingAspect.java
Normal file
@@ -0,0 +1,312 @@
|
|||||||
|
package com.zl.mjga.aspect;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.zl.mjga.annotation.SkipAopLog;
|
||||||
|
import com.zl.mjga.repository.UserRepository;
|
||||||
|
import com.zl.mjga.service.AopLogService;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.Around;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.reflect.MethodSignature;
|
||||||
|
import org.jooq.generated.mjga.tables.pojos.AopLog;
|
||||||
|
import org.jooq.generated.mjga.tables.pojos.User;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@ConditionalOnProperty(name = "aop.logging.enabled", havingValue = "true", matchIfMissing = true)
|
||||||
|
public class LoggingAspect {
|
||||||
|
|
||||||
|
private final AopLogService aopLogService;
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
|
||||||
|
@Around("execution(* com.zl.mjga.controller..*(..))")
|
||||||
|
public Object logController(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||||
|
AopLog aopLog = new AopLog();
|
||||||
|
setRequestInfo(aopLog);
|
||||||
|
return processWithLogging(joinPoint, aopLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Around("execution(* com.zl.mjga.service..*(..))")
|
||||||
|
// public Object logService(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||||
|
// AopLog aopLog = new AopLog();
|
||||||
|
// return processWithLogging(joinPoint, aopLog);
|
||||||
|
// }
|
||||||
|
|
||||||
|
private Object processWithLogging(ProceedingJoinPoint joinPoint, AopLog aopLog) throws Throwable {
|
||||||
|
if (shouldSkipLogging(joinPoint) || !isUserAuthenticated()) {
|
||||||
|
return joinPoint.proceed();
|
||||||
|
}
|
||||||
|
return logMethodExecution(joinPoint, aopLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldSkipLogging(ProceedingJoinPoint joinPoint) {
|
||||||
|
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||||
|
Method method = signature.getMethod();
|
||||||
|
return method.isAnnotationPresent(SkipAopLog.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isUserAuthenticated() {
|
||||||
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
return authentication != null
|
||||||
|
&& authentication.isAuthenticated()
|
||||||
|
&& !"anonymousUser".equals(authentication.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long getCurrentUserId() {
|
||||||
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
String username = authentication.getName();
|
||||||
|
User user = userRepository.fetchOneByUsername(username);
|
||||||
|
return user.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object logMethodExecution(ProceedingJoinPoint joinPoint, AopLog aopLog) throws Throwable {
|
||||||
|
Instant startTime = Instant.now();
|
||||||
|
String className = joinPoint.getTarget().getClass().getSimpleName();
|
||||||
|
String methodName = joinPoint.getSignature().getName();
|
||||||
|
|
||||||
|
populateBasicLogInfo(aopLog, className, methodName, joinPoint.getArgs());
|
||||||
|
|
||||||
|
Object result = null;
|
||||||
|
Exception executionException = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
result = joinPoint.proceed();
|
||||||
|
aopLog.setReturnValue(serializeReturnValue(result));
|
||||||
|
} catch (Exception e) {
|
||||||
|
executionException = e;
|
||||||
|
aopLog.setErrorMessage(e.getMessage());
|
||||||
|
log.error("Method execution failed: {}.{}", className, methodName, e);
|
||||||
|
} finally {
|
||||||
|
aopLog.setExecutionTime(Duration.between(startTime, Instant.now()).toMillis());
|
||||||
|
aopLog.setSuccess(executionException == null);
|
||||||
|
saveLogSafely(aopLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (executionException != null) {
|
||||||
|
throw executionException;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void populateBasicLogInfo(
|
||||||
|
AopLog aopLog, String className, String methodName, Object[] args) {
|
||||||
|
aopLog.setClassName(className);
|
||||||
|
aopLog.setMethodName(methodName);
|
||||||
|
aopLog.setMethodArgs(serializeArgs(args));
|
||||||
|
aopLog.setUserId(getCurrentUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveLogSafely(AopLog aopLog) {
|
||||||
|
try {
|
||||||
|
aopLogService.saveLogAsync(aopLog);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(
|
||||||
|
"Failed to save AOP log for {}.{}", aopLog.getClassName(), aopLog.getMethodName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setRequestInfo(AopLog aopLog) {
|
||||||
|
ServletRequestAttributes attributes =
|
||||||
|
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||||
|
if (attributes == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpServletRequest request = attributes.getRequest();
|
||||||
|
aopLog.setIpAddress(getClientIpAddress(request));
|
||||||
|
aopLog.setUserAgent(request.getHeader("User-Agent"));
|
||||||
|
aopLog.setCurl(generateCurlCommand(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getClientIpAddress(HttpServletRequest request) {
|
||||||
|
String xForwardedFor = request.getHeader("X-Forwarded-For");
|
||||||
|
if (xForwardedFor != null
|
||||||
|
&& !xForwardedFor.isEmpty()
|
||||||
|
&& !"unknown".equalsIgnoreCase(xForwardedFor)) {
|
||||||
|
return xForwardedFor.split(",")[0].trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
String xRealIp = request.getHeader("X-Real-IP");
|
||||||
|
if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
|
||||||
|
return xRealIp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return request.getRemoteAddr();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String serializeArgs(Object[] args) {
|
||||||
|
if (ArrayUtils.isEmpty(args)) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return serializeObject(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String serializeReturnValue(Object returnValue) {
|
||||||
|
if (returnValue == null) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return serializeObject(returnValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String serializeObject(Object obj) {
|
||||||
|
try {
|
||||||
|
return objectMapper.writeValueAsString(obj);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
log.error("Failed to serialize {} ", obj, e);
|
||||||
|
return e.getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String generateCurlCommand(HttpServletRequest request) {
|
||||||
|
try {
|
||||||
|
StringBuilder curl = new StringBuilder("curl -X ");
|
||||||
|
|
||||||
|
curl.append(request.getMethod());
|
||||||
|
|
||||||
|
String url = getFullRequestUrl(request);
|
||||||
|
curl.append(" '").append(url).append("'");
|
||||||
|
|
||||||
|
appendHeaders(curl, request);
|
||||||
|
|
||||||
|
if (hasRequestBody(request.getMethod())) {
|
||||||
|
appendRequestBody(curl, request);
|
||||||
|
}
|
||||||
|
return curl.toString();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to generate curl command", e);
|
||||||
|
return "curl command generation failed: " + e.getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getFullRequestUrl(HttpServletRequest request) {
|
||||||
|
StringBuilder url = new StringBuilder();
|
||||||
|
|
||||||
|
String scheme = request.getScheme();
|
||||||
|
String serverName = request.getServerName();
|
||||||
|
int serverPort = request.getServerPort();
|
||||||
|
|
||||||
|
if (scheme == null) {
|
||||||
|
scheme = "http";
|
||||||
|
}
|
||||||
|
if (serverName == null) {
|
||||||
|
serverName = "localhost";
|
||||||
|
}
|
||||||
|
|
||||||
|
url.append(scheme).append("://").append(serverName);
|
||||||
|
|
||||||
|
if ((scheme.equals("http") && serverPort != 80)
|
||||||
|
|| (scheme.equals("https") && serverPort != 443)) {
|
||||||
|
url.append(":").append(serverPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
url.append(request.getRequestURI());
|
||||||
|
if (request.getQueryString() != null) {
|
||||||
|
url.append("?").append(request.getQueryString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return url.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendHeaders(StringBuilder curl, HttpServletRequest request) {
|
||||||
|
Enumeration<String> headerNames = request.getHeaderNames();
|
||||||
|
for (String headerName : Collections.list(headerNames)) {
|
||||||
|
if (shouldSkipHeader(headerName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String headerValue = request.getHeader(headerName);
|
||||||
|
curl.append(" -H '").append(headerName).append(": ").append(headerValue).append("'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldSkipHeader(String headerName) {
|
||||||
|
String lowerName = headerName.toLowerCase();
|
||||||
|
return lowerName.equals("host")
|
||||||
|
|| lowerName.equals("content-length")
|
||||||
|
|| lowerName.equals("connection")
|
||||||
|
|| lowerName.startsWith("sec-")
|
||||||
|
|| lowerName.equals("upgrade-insecure-requests");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasRequestBody(String method) {
|
||||||
|
return "POST".equalsIgnoreCase(method)
|
||||||
|
|| "PUT".equalsIgnoreCase(method)
|
||||||
|
|| "PATCH".equalsIgnoreCase(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendRequestBody(StringBuilder curl, HttpServletRequest request) {
|
||||||
|
try {
|
||||||
|
String contentType = request.getContentType();
|
||||||
|
if (StringUtils.contains(contentType, "application/json")) {
|
||||||
|
String body = getRequestBody(request);
|
||||||
|
if (StringUtils.isNotEmpty(body)) {
|
||||||
|
curl.append(" -d '").append(body.replace("'", "\\'")).append("'");
|
||||||
|
}
|
||||||
|
} else if (StringUtils.contains(contentType, "application/x-www-form-urlencoded")) {
|
||||||
|
appendFormData(curl, request);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Failed to append request body to curl command", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getRequestBody(HttpServletRequest request) {
|
||||||
|
try (BufferedReader reader = request.getReader()) {
|
||||||
|
if (reader == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
StringBuilder body = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
body.append(line);
|
||||||
|
}
|
||||||
|
return body.toString();
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Failed to read request body", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendFormData(StringBuilder curl, HttpServletRequest request) {
|
||||||
|
Enumeration<String> paramNames = request.getParameterNames();
|
||||||
|
StringBuilder formData = new StringBuilder();
|
||||||
|
while (paramNames.hasMoreElements()) {
|
||||||
|
String paramName = paramNames.nextElement();
|
||||||
|
String[] paramValues = request.getParameterValues(paramName);
|
||||||
|
for (String paramValue : paramValues) {
|
||||||
|
if (!formData.isEmpty()) {
|
||||||
|
formData.append("&");
|
||||||
|
}
|
||||||
|
formData.append(paramName).append("=").append(paramValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!formData.isEmpty()) {
|
||||||
|
curl.append(" -d '").append(formData).append("'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import com.zl.mjga.service.DepartmentService;
|
|||||||
import dev.langchain4j.agent.tool.P;
|
import dev.langchain4j.agent.tool.P;
|
||||||
import dev.langchain4j.agent.tool.Tool;
|
import dev.langchain4j.agent.tool.Tool;
|
||||||
import dev.langchain4j.model.output.structured.Description;
|
import dev.langchain4j.model.output.structured.Description;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jooq.generated.mjga.tables.pojos.Department;
|
import org.jooq.generated.mjga.tables.pojos.Department;
|
||||||
@@ -21,37 +22,65 @@ public class DepartmentOperatorTool {
|
|||||||
|
|
||||||
@Tool(value = "创建部门")
|
@Tool(value = "创建部门")
|
||||||
void createDepartment(
|
void createDepartment(
|
||||||
@P(value = "部门名称") String departmentName,
|
@P(value = "部门名称") @Size(min = 2, max = 15) String name,
|
||||||
@P(value = "上级部门名称", required = false) String parentDepartmentName) {
|
@P(value = "上级部门名称", required = false) @Size(min = 2, max = 15) String parentName) {
|
||||||
Department exist = departmentRepository.fetchOneByName(departmentName);
|
Department exist = departmentRepository.fetchOneByName(name);
|
||||||
|
Department department = new Department(null, name, null);
|
||||||
if (exist != null) {
|
if (exist != null) {
|
||||||
throw new BusinessException("当前部门已存在");
|
throw new BusinessException("当前部门已存在");
|
||||||
}
|
}
|
||||||
if (StringUtils.isNotEmpty(parentDepartmentName)) {
|
if (StringUtils.isNotEmpty(parentName)) {
|
||||||
Department parent = departmentRepository.fetchOneByName(parentDepartmentName);
|
Department parent = departmentRepository.fetchOneByName(parentName);
|
||||||
if (parent == null) {
|
if (parent == null) {
|
||||||
throw new BusinessException("上级部门不存在");
|
throw new BusinessException("指定的上级部门不存在");
|
||||||
|
} else {
|
||||||
|
department.setParentId(parent.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
departmentService.upsertDepartment(new Department(null, departmentName, null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Tool(value = "更新部门/绑定上级部门/解绑上级部门")
|
|
||||||
void updateDepartment(
|
|
||||||
@P(value = "部门名称") String departmentName,
|
|
||||||
@P(value = "上级部门名称", required = false) String parentDepartmentName) {
|
|
||||||
Department exist = departmentRepository.fetchOneByName(departmentName);
|
|
||||||
if (exist == null) {
|
|
||||||
throw new BusinessException("不存在的部门");
|
|
||||||
}
|
|
||||||
Department department = new Department(null, departmentName, null);
|
|
||||||
if (StringUtils.isNotEmpty(parentDepartmentName)) {
|
|
||||||
Department parent = departmentRepository.fetchOneByName(parentDepartmentName);
|
|
||||||
if (parent == null) {
|
|
||||||
throw new BusinessException("上级部门不存在");
|
|
||||||
}
|
|
||||||
department.setParentId(parent.getId());
|
|
||||||
}
|
|
||||||
departmentService.upsertDepartment(department);
|
departmentService.upsertDepartment(department);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Tool(value = {"更新部门信息"})
|
||||||
|
void updateDepartment(@P(value = "部门名称") String name) {
|
||||||
|
Department exist = departmentRepository.fetchOneByName(name);
|
||||||
|
if (exist == null) {
|
||||||
|
throw new BusinessException("不存在的部门");
|
||||||
|
}
|
||||||
|
exist.setName(name);
|
||||||
|
departmentService.upsertDepartment(exist);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Tool(value = {"给指定部门绑定/分配上级部门"})
|
||||||
|
void bindParentDepartment(
|
||||||
|
@P(value = "部门名称") String name, @P(value = "上级部门名称") String parentName) {
|
||||||
|
Department exist = departmentRepository.fetchOneByName(name);
|
||||||
|
if (exist == null) {
|
||||||
|
throw new BusinessException("不存在的部门");
|
||||||
|
}
|
||||||
|
Department parent = departmentRepository.fetchOneByName(parentName);
|
||||||
|
if (parent == null) {
|
||||||
|
throw new BusinessException("上级部门不存在");
|
||||||
|
}
|
||||||
|
exist.setParentId(parent.getId());
|
||||||
|
departmentService.upsertDepartment(exist);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Tool(value = {"给指定部门解绑/撤销上级部门"})
|
||||||
|
void unbindParentDepartment(@P(value = "部门名称") String name) {
|
||||||
|
Department exist = departmentRepository.fetchOneByName(name);
|
||||||
|
if (exist == null) {
|
||||||
|
throw new BusinessException("不存在的部门");
|
||||||
|
}
|
||||||
|
exist.setParentId(null);
|
||||||
|
departmentService.upsertDepartment(exist);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Tool(value = "删除指定部门")
|
||||||
|
void deleteDepartment(@P(value = "部门名称") String name) {
|
||||||
|
Department exist = departmentRepository.fetchOneByName(name);
|
||||||
|
if (exist == null) {
|
||||||
|
throw new BusinessException("不存在的部门");
|
||||||
|
}
|
||||||
|
departmentRepository.deleteById(exist.getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,12 @@ import com.zl.mjga.repository.PositionRepository;
|
|||||||
import dev.langchain4j.agent.tool.P;
|
import dev.langchain4j.agent.tool.P;
|
||||||
import dev.langchain4j.agent.tool.Tool;
|
import dev.langchain4j.agent.tool.Tool;
|
||||||
import dev.langchain4j.model.output.structured.Description;
|
import dev.langchain4j.model.output.structured.Description;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.jooq.generated.mjga.tables.pojos.Position;
|
import org.jooq.generated.mjga.tables.pojos.Position;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
|
||||||
@Description("和岗位管理有关的操作工具")
|
@Description("和岗位管理有关的操作工具")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Component
|
@Component
|
||||||
@@ -16,17 +18,17 @@ public class PositionOperatorTool {
|
|||||||
private final PositionRepository positionRepository;
|
private final PositionRepository positionRepository;
|
||||||
|
|
||||||
@Tool(value = "创建岗位")
|
@Tool(value = "创建岗位")
|
||||||
void createPosition(@P("岗位名称") String positionName) {
|
void createPosition(@P("岗位名称") @Size(min = 2, max = 15) String name) {
|
||||||
Position position = positionRepository.fetchOneByName(positionName);
|
Position position = positionRepository.fetchOneByName(name);
|
||||||
if (position != null) {
|
if (position != null) {
|
||||||
throw new BusinessException("岗位已存在");
|
throw new BusinessException("岗位已存在");
|
||||||
}
|
}
|
||||||
positionRepository.merge(new Position(null, positionName));
|
positionRepository.merge(new Position(null, name));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "删除岗位")
|
@Tool(value = "删除岗位")
|
||||||
void deletePosition(@P("岗位名称") String positionName) {
|
void deletePosition(@P("岗位名称") String name) {
|
||||||
Position position = positionRepository.fetchOneByName(positionName);
|
Position position = positionRepository.fetchOneByName(name);
|
||||||
if (position == null) {
|
if (position == null) {
|
||||||
throw new BusinessException("岗位不存在");
|
throw new BusinessException("岗位不存在");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
package com.zl.mjga.component;
|
package com.zl.mjga.component;
|
||||||
|
|
||||||
|
import com.zl.mjga.dto.department.DepartmentBindDto;
|
||||||
|
import com.zl.mjga.dto.position.PositionBindDto;
|
||||||
import com.zl.mjga.dto.urp.PermissionUpsertDto;
|
import com.zl.mjga.dto.urp.PermissionUpsertDto;
|
||||||
import com.zl.mjga.dto.urp.RoleUpsertDto;
|
import com.zl.mjga.dto.urp.RoleUpsertDto;
|
||||||
import com.zl.mjga.dto.urp.UserUpsertDto;
|
import com.zl.mjga.dto.urp.UserUpsertDto;
|
||||||
import com.zl.mjga.exception.BusinessException;
|
import com.zl.mjga.exception.BusinessException;
|
||||||
import com.zl.mjga.repository.PermissionRepository;
|
import com.zl.mjga.repository.*;
|
||||||
import com.zl.mjga.repository.RoleRepository;
|
|
||||||
import com.zl.mjga.repository.UserRepository;
|
|
||||||
import com.zl.mjga.service.IdentityAccessService;
|
import com.zl.mjga.service.IdentityAccessService;
|
||||||
import dev.langchain4j.agent.tool.P;
|
import dev.langchain4j.agent.tool.P;
|
||||||
import dev.langchain4j.agent.tool.Tool;
|
import dev.langchain4j.agent.tool.Tool;
|
||||||
import dev.langchain4j.model.output.structured.Description;
|
import dev.langchain4j.model.output.structured.Description;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jooq.generated.mjga.tables.pojos.Permission;
|
import org.jooq.generated.mjga.tables.pojos.*;
|
||||||
import org.jooq.generated.mjga.tables.pojos.Role;
|
|
||||||
import org.jooq.generated.mjga.tables.pojos.User;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Description("和用户管理有关的操作工具")
|
@Description("和用户管理有关的操作工具")
|
||||||
|
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Component
|
@Component
|
||||||
public class UserRolePermissionOperatorTool {
|
public class UserRolePermissionOperatorTool {
|
||||||
@@ -28,14 +28,16 @@ public class UserRolePermissionOperatorTool {
|
|||||||
private final UserRepository userRepository;
|
private final UserRepository userRepository;
|
||||||
private final RoleRepository roleRepository;
|
private final RoleRepository roleRepository;
|
||||||
private final PermissionRepository permissionRepository;
|
private final PermissionRepository permissionRepository;
|
||||||
|
private final DepartmentRepository departmentRepository;
|
||||||
|
private final PositionRepository positionRepository;
|
||||||
|
|
||||||
@Tool(value = "创建用户或注册用户")
|
@Tool(value = {"创建用户", "入职申请", "开通账号"})
|
||||||
void createUser(@P(value = "用户名") String username) {
|
void createUser(@P(value = "用户名") @Size(min = 1, max = 15) String name) {
|
||||||
User user = userRepository.fetchOneByUsername(username);
|
User user = userRepository.fetchOneByUsername(name);
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
throw new BusinessException("用户已存在");
|
throw new BusinessException("用户已存在");
|
||||||
}
|
}
|
||||||
identityAccessService.upsertUser(new UserUpsertDto(null, username, username, true));
|
identityAccessService.upsertUser(new UserUpsertDto(null, name, name, true, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "删除用户")
|
@Tool(value = "删除用户")
|
||||||
@@ -43,34 +45,86 @@ public class UserRolePermissionOperatorTool {
|
|||||||
userRepository.deleteByUsername(username);
|
userRepository.deleteByUsername(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "编辑/更新/更改用户")
|
@Tool(value = {"编辑用户", "更新用户", "更改用户"})
|
||||||
void updateUser(
|
void updateUser(
|
||||||
@P(value = "用户名") String username,
|
@P(value = "用户名") String name,
|
||||||
@P(value = "密码", required = false) String password,
|
@P(value = "密码", required = false) String password,
|
||||||
@P(value = "是否开启", required = false) Boolean enable) {
|
@P(value = "是否开启", required = false) Boolean enable) {
|
||||||
identityAccessService.upsertUser(new UserUpsertDto(null, username, password, enable));
|
identityAccessService.upsertUser(new UserUpsertDto(null, name, password, enable, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "给用户绑定/分配角色")
|
@Tool(value = {"给用户绑定角色", "给用户分配角色"})
|
||||||
void bindRoleToUser(
|
void bindRoleToUser(
|
||||||
@P(value = "用户名") String username, @P(value = "角色名称") List<String> roleNames) {
|
@P(value = "用户名") String username, @P(value = "角色名称") List<String> roleNames) {
|
||||||
User user = userRepository.fetchOneByUsername(username);
|
User user = checkUserExistBy(username);
|
||||||
if (user == null) {
|
|
||||||
throw new BusinessException("指定用户不存在");
|
|
||||||
}
|
|
||||||
List<Long> bindRoleIds = getRoleIdsBy(roleNames);
|
List<Long> bindRoleIds = getRoleIdsBy(roleNames);
|
||||||
identityAccessService.bindRoleToUser(user.getId(), bindRoleIds);
|
identityAccessService.bindRoleToUser(user.getId(), bindRoleIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "给用户解绑/撤销角色")
|
@Tool(value = {"给用户解绑角色", "给用户撤销角色"})
|
||||||
void unbindRoleToUser(
|
void unbindRoleToUser(
|
||||||
@P(value = "用户名") String username, @P(value = "角色名称") List<String> roleNames) {
|
@P(value = "用户名") String username, @P(value = "角色名称") List<String> roleNames) {
|
||||||
|
User user = checkUserExistBy(username);
|
||||||
|
List<Long> bindRoleIds = getRoleIdsBy(roleNames);
|
||||||
|
identityAccessService.unBindRoleToUser(user.getId(), bindRoleIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Tool(value = {"给用户绑定部门", "给用户分配部门"})
|
||||||
|
void bindDepartmentToUser(
|
||||||
|
@P(value = "用户名") String username, @P(value = "部门名称列表") List<String> departmentNames) {
|
||||||
|
User user = checkUserExistBy(username);
|
||||||
|
List<Department> departments =
|
||||||
|
departmentRepository.fetchByName(departmentNames.toArray(String[]::new));
|
||||||
|
if (departments.isEmpty()) {
|
||||||
|
throw new BusinessException("指定部门不存在");
|
||||||
|
}
|
||||||
|
identityAccessService.bindDepartmentBy(
|
||||||
|
new DepartmentBindDto(user.getId(), departments.stream().map(Department::getId).toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Tool(value = {"给用户解绑部门", "给用户撤销部门"})
|
||||||
|
void unbindDepartmentToUser(
|
||||||
|
@P(value = "用户名") String username, @P(value = "部门名称列表") List<String> departmentNames) {
|
||||||
|
User user = checkUserExistBy(username);
|
||||||
|
List<Department> departments =
|
||||||
|
departmentRepository.fetchByName(departmentNames.toArray(String[]::new));
|
||||||
|
if (departments.isEmpty()) {
|
||||||
|
throw new BusinessException("指定部门不存在");
|
||||||
|
}
|
||||||
|
identityAccessService.unBindDepartmentBy(
|
||||||
|
new DepartmentBindDto(user.getId(), departments.stream().map(Department::getId).toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private User checkUserExistBy(String username) {
|
||||||
User user = userRepository.fetchOneByUsername(username);
|
User user = userRepository.fetchOneByUsername(username);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
throw new BusinessException("指定用户不存在");
|
throw new BusinessException("指定用户不存在");
|
||||||
}
|
}
|
||||||
List<Long> bindRoleIds = getRoleIdsBy(roleNames);
|
return user;
|
||||||
identityAccessService.unBindRoleToUser(user.getId(), bindRoleIds);
|
}
|
||||||
|
|
||||||
|
@Tool(value = {"给用户绑定岗位", "给用户分配岗位"})
|
||||||
|
void bindPositionToUser(
|
||||||
|
@P(value = "用户名") String username, @P(value = "岗位名称列表") List<String> positionNames) {
|
||||||
|
User user = checkUserExistBy(username);
|
||||||
|
List<Position> positions = positionRepository.fetchByName(positionNames.toArray(String[]::new));
|
||||||
|
if (positions.isEmpty()) {
|
||||||
|
throw new BusinessException("指定岗位不存在");
|
||||||
|
}
|
||||||
|
identityAccessService.bindPositionBy(
|
||||||
|
new PositionBindDto(user.getId(), positions.stream().map(Position::getId).toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Tool(value = {"给用户解绑岗位", "给用户撤销岗位"})
|
||||||
|
void unbindPositionToUser(
|
||||||
|
@P(value = "用户名") String username, @P(value = "岗位名称列表") List<String> positionNames) {
|
||||||
|
User user = checkUserExistBy(username);
|
||||||
|
List<Position> positions = positionRepository.fetchByName(positionNames.toArray(String[]::new));
|
||||||
|
if (positions.isEmpty()) {
|
||||||
|
throw new BusinessException("指定岗位不存在");
|
||||||
|
}
|
||||||
|
identityAccessService.unBindPositionBy(
|
||||||
|
new PositionBindDto(user.getId(), positions.stream().map(Position::getId).toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Long> getRoleIdsBy(List<String> roleNames) {
|
private List<Long> getRoleIdsBy(List<String> roleNames) {
|
||||||
@@ -81,33 +135,31 @@ public class UserRolePermissionOperatorTool {
|
|||||||
return roles.stream().map(Role::getId).toList();
|
return roles.stream().map(Role::getId).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "创建角色")
|
@Tool(value = {"创建角色", "创建系统角色"})
|
||||||
void createRole(
|
void createRole(
|
||||||
@P(value = "角色名称") String roleName, @P(value = "角色编码", required = false) String roleCode) {
|
@P(value = "角色名称") String name, @P(value = "角色编码", required = false) String code) {
|
||||||
if (StringUtils.isEmpty(roleCode)) {
|
if (StringUtils.isEmpty(code)) {
|
||||||
roleCode = roleName;
|
code = name;
|
||||||
}
|
}
|
||||||
if (identityAccessService.isRoleDuplicate(roleCode, roleName)) {
|
if (identityAccessService.isRoleDuplicate(code, name)) {
|
||||||
throw new BusinessException("角色已存在");
|
throw new BusinessException("角色已存在");
|
||||||
}
|
}
|
||||||
identityAccessService.upsertRole(new RoleUpsertDto(null, roleName, roleCode));
|
identityAccessService.upsertRole(new RoleUpsertDto(null, name, code));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "更新角色")
|
@Tool(value = "更新角色")
|
||||||
void updateRole(@P(value = "角色名称") String roleName, @P(value = "角色编码") String roleCode) {
|
void updateRole(@P(value = "角色名称") String name, @P(value = "角色编码") String code) {
|
||||||
identityAccessService.upsertRole(new RoleUpsertDto(null, roleName, roleCode));
|
identityAccessService.upsertRole(new RoleUpsertDto(null, name, code));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "更新权限")
|
@Tool(value = "更新权限")
|
||||||
void updatePermission(
|
void updatePermission(@P(value = "权限名称") String name, @P(value = "权限编码") String code) {
|
||||||
@P(value = "权限名称") String permissionName, @P(value = "权限编码") String permissionCode) {
|
identityAccessService.upsertPermission(new PermissionUpsertDto(null, name, code));
|
||||||
identityAccessService.upsertPermission(
|
|
||||||
new PermissionUpsertDto(null, permissionName, permissionCode));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "删除角色")
|
@Tool(value = "删除角色")
|
||||||
void deleteRole(@P(value = "角色名称") String roleName) {
|
void deleteRole(@P(value = "角色名称") String name) {
|
||||||
Role role = roleRepository.fetchOneByName(roleName);
|
Role role = roleRepository.fetchOneByName(name);
|
||||||
if (role == null) {
|
if (role == null) {
|
||||||
throw new BusinessException("指定角色不存在");
|
throw new BusinessException("指定角色不存在");
|
||||||
}
|
}
|
||||||
@@ -115,15 +167,15 @@ public class UserRolePermissionOperatorTool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "删除权限")
|
@Tool(value = "删除权限")
|
||||||
void deletePermission(@P(value = "权限名称") String permissionName) {
|
void deletePermission(@P(value = "权限名称") String name) {
|
||||||
Permission permission = permissionRepository.fetchOneByName(permissionName);
|
Permission permission = permissionRepository.fetchOneByName(name);
|
||||||
if (permission == null) {
|
if (permission == null) {
|
||||||
throw new BusinessException("指定权限不存在");
|
throw new BusinessException("指定权限不存在");
|
||||||
}
|
}
|
||||||
permissionRepository.deleteById(permission.getId());
|
permissionRepository.deleteById(permission.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "给角色绑定/分配权限")
|
@Tool(value = {"给角色绑定权限", "给用户分配权限"})
|
||||||
void bindPermissionToRole(
|
void bindPermissionToRole(
|
||||||
@P(value = "角色名称") String roleName, @P(value = "权限名称") List<String> permissionNames) {
|
@P(value = "角色名称") String roleName, @P(value = "权限名称") List<String> permissionNames) {
|
||||||
Role role = roleRepository.fetchOneByName(roleName);
|
Role role = roleRepository.fetchOneByName(roleName);
|
||||||
@@ -139,7 +191,7 @@ public class UserRolePermissionOperatorTool {
|
|||||||
role.getId(), permissions.stream().map(Permission::getId).toList());
|
role.getId(), permissions.stream().map(Permission::getId).toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tool(value = "给角色解绑/撤销权限")
|
@Tool(value = {"给角色解绑权限", "给角色撤销权限"})
|
||||||
void unBindPermissionToRole(
|
void unBindPermissionToRole(
|
||||||
@P(value = "角色名称") String roleName, @P(value = "权限名称") List<String> permissionNames) {
|
@P(value = "角色名称") String roleName, @P(value = "权限名称") List<String> permissionNames) {
|
||||||
Role role = roleRepository.fetchOneByName(roleName);
|
Role role = roleRepository.fetchOneByName(roleName);
|
||||||
@@ -157,15 +209,13 @@ public class UserRolePermissionOperatorTool {
|
|||||||
|
|
||||||
@Tool(value = "创建权限")
|
@Tool(value = "创建权限")
|
||||||
void createPermission(
|
void createPermission(
|
||||||
@P(value = "权限名称") String permissionName,
|
@P(value = "权限名称") String name, @P(value = "权限编码", required = false) String code) {
|
||||||
@P(value = "权限编码", required = false) String permissionCode) {
|
if (StringUtils.isEmpty(code)) {
|
||||||
if (StringUtils.isEmpty(permissionCode)) {
|
code = name;
|
||||||
permissionCode = permissionName;
|
|
||||||
}
|
}
|
||||||
if (identityAccessService.isPermissionDuplicate(permissionName, permissionName)) {
|
if (identityAccessService.isPermissionDuplicate(name, name)) {
|
||||||
throw new BusinessException("权限已存在");
|
throw new BusinessException("权限已存在");
|
||||||
}
|
}
|
||||||
identityAccessService.upsertPermission(
|
identityAccessService.upsertPermission(new PermissionUpsertDto(null, name, code));
|
||||||
new PermissionUpsertDto(null, permissionName, permissionCode));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
35
backend/src/main/java/com/zl/mjga/config/JacksonConfig.java
Normal file
35
backend/src/main/java/com/zl/mjga/config/JacksonConfig.java
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package com.zl.mjga.config;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
|
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||||
|
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
||||||
|
import java.io.IOException;
|
||||||
|
import org.jooq.JSON;
|
||||||
|
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class JacksonConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
|
||||||
|
return builder ->
|
||||||
|
builder
|
||||||
|
.serializationInclusion(JsonInclude.Include.USE_DEFAULTS)
|
||||||
|
.serializers(new JooqJsonSerializer());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class JooqJsonSerializer extends StdSerializer<JSON> {
|
||||||
|
public JooqJsonSerializer() {
|
||||||
|
super(JSON.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serialize(JSON value, JsonGenerator gen, SerializerProvider serializers)
|
||||||
|
throws IOException {
|
||||||
|
gen.writeRawValue(value.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,17 @@
|
|||||||
package com.zl.mjga.config.ai;
|
package com.zl.mjga.config.ai;
|
||||||
|
|
||||||
|
import static dev.langchain4j.store.embedding.filter.MetadataFilterBuilder.metadataKey;
|
||||||
|
|
||||||
import com.zl.mjga.component.PromptConfiguration;
|
import com.zl.mjga.component.PromptConfiguration;
|
||||||
import com.zl.mjga.service.LlmService;
|
import com.zl.mjga.service.LlmService;
|
||||||
import dev.langchain4j.community.model.zhipu.ZhipuAiStreamingChatModel;
|
import dev.langchain4j.community.model.zhipu.ZhipuAiStreamingChatModel;
|
||||||
|
import dev.langchain4j.data.segment.TextSegment;
|
||||||
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
|
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
|
||||||
|
import dev.langchain4j.model.embedding.EmbeddingModel;
|
||||||
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
|
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
|
||||||
|
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
|
||||||
import dev.langchain4j.service.AiServices;
|
import dev.langchain4j.service.AiServices;
|
||||||
|
import dev.langchain4j.store.embedding.EmbeddingStore;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.jooq.generated.mjga.enums.LlmCodeEnum;
|
import org.jooq.generated.mjga.enums.LlmCodeEnum;
|
||||||
import org.jooq.generated.mjga.tables.pojos.AiLlmConfig;
|
import org.jooq.generated.mjga.tables.pojos.AiLlmConfig;
|
||||||
@@ -54,11 +60,26 @@ public class ChatModelInitializer {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@DependsOn("flywayInitializer")
|
@DependsOn("flywayInitializer")
|
||||||
public AiChatAssistant zhiPuChatAssistant(ZhipuAiStreamingChatModel zhipuChatModel) {
|
public AiChatAssistant zhiPuChatAssistant(
|
||||||
|
ZhipuAiStreamingChatModel zhipuChatModel,
|
||||||
|
EmbeddingStore<TextSegment> zhiPuLibraryEmbeddingStore,
|
||||||
|
EmbeddingModel zhipuEmbeddingModel) {
|
||||||
return AiServices.builder(AiChatAssistant.class)
|
return AiServices.builder(AiChatAssistant.class)
|
||||||
.streamingChatModel(zhipuChatModel)
|
.streamingChatModel(zhipuChatModel)
|
||||||
.systemMessageProvider(chatMemoryId -> promptConfiguration.getSystem())
|
.systemMessageProvider(chatMemoryId -> promptConfiguration.getSystem())
|
||||||
.chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(10))
|
.chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(10))
|
||||||
|
.contentRetriever(
|
||||||
|
EmbeddingStoreContentRetriever.builder()
|
||||||
|
.embeddingStore(zhiPuLibraryEmbeddingStore)
|
||||||
|
.embeddingModel(zhipuEmbeddingModel)
|
||||||
|
.minScore(0.75)
|
||||||
|
.maxResults(5)
|
||||||
|
.dynamicFilter(
|
||||||
|
query -> {
|
||||||
|
String libraryId = (String) query.metadata().chatMemoryId();
|
||||||
|
return metadataKey("libraryId").isEqualTo(libraryId);
|
||||||
|
})
|
||||||
|
.build())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
package com.zl.mjga.config.ai;
|
package com.zl.mjga.config.ai;
|
||||||
|
|
||||||
|
import com.zl.mjga.config.minio.MinIoConfig;
|
||||||
import com.zl.mjga.service.LlmService;
|
import com.zl.mjga.service.LlmService;
|
||||||
import dev.langchain4j.community.model.zhipu.ZhipuAiEmbeddingModel;
|
import dev.langchain4j.community.model.zhipu.ZhipuAiEmbeddingModel;
|
||||||
|
import dev.langchain4j.data.document.loader.amazon.s3.AmazonS3DocumentLoader;
|
||||||
|
import dev.langchain4j.data.document.loader.amazon.s3.AwsCredentials;
|
||||||
import dev.langchain4j.data.segment.TextSegment;
|
import dev.langchain4j.data.segment.TextSegment;
|
||||||
import dev.langchain4j.model.embedding.EmbeddingModel;
|
import dev.langchain4j.model.embedding.EmbeddingModel;
|
||||||
import dev.langchain4j.store.embedding.EmbeddingStore;
|
import dev.langchain4j.store.embedding.EmbeddingStore;
|
||||||
@@ -42,7 +45,7 @@ public class EmbeddingInitializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public EmbeddingStore<TextSegment> zhiPuEmbeddingStore(EmbeddingModel zhipuEmbeddingModel) {
|
public EmbeddingStore<TextSegment> zhiPuEmbeddingStore() {
|
||||||
String hostPort = env.getProperty("DATABASE_HOST_PORT");
|
String hostPort = env.getProperty("DATABASE_HOST_PORT");
|
||||||
String host = hostPort.split(":")[0];
|
String host = hostPort.split(":")[0];
|
||||||
return PgVectorEmbeddingStore.builder()
|
return PgVectorEmbeddingStore.builder()
|
||||||
@@ -55,4 +58,28 @@ public class EmbeddingInitializer {
|
|||||||
.dimension(2048)
|
.dimension(2048)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public EmbeddingStore<TextSegment> zhiPuLibraryEmbeddingStore() {
|
||||||
|
String hostPort = env.getProperty("DATABASE_HOST_PORT");
|
||||||
|
String host = hostPort.split(":")[0];
|
||||||
|
return PgVectorEmbeddingStore.builder()
|
||||||
|
.host(host)
|
||||||
|
.port(env.getProperty("DATABASE_EXPOSE_PORT", Integer.class))
|
||||||
|
.database(env.getProperty("DATABASE_DB"))
|
||||||
|
.user(env.getProperty("DATABASE_USER"))
|
||||||
|
.password(env.getProperty("DATABASE_PASSWORD"))
|
||||||
|
.table("mjga.zhipu_library_embedding_store")
|
||||||
|
.dimension(2048)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public AmazonS3DocumentLoader amazonS3DocumentLoader(MinIoConfig minIoConfig) {
|
||||||
|
return AmazonS3DocumentLoader.builder()
|
||||||
|
.endpointUrl(minIoConfig.getEndpoint())
|
||||||
|
.forcePathStyle(true)
|
||||||
|
.awsCredentials(new AwsCredentials(minIoConfig.getAccessKey(), minIoConfig.getSecretKey()))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.zl.mjga.component.PositionOperatorTool;
|
|||||||
import com.zl.mjga.component.UserRolePermissionOperatorTool;
|
import com.zl.mjga.component.UserRolePermissionOperatorTool;
|
||||||
import dev.langchain4j.community.model.zhipu.ZhipuAiStreamingChatModel;
|
import dev.langchain4j.community.model.zhipu.ZhipuAiStreamingChatModel;
|
||||||
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
|
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
|
||||||
|
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
|
||||||
import dev.langchain4j.service.AiServices;
|
import dev.langchain4j.service.AiServices;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@@ -28,4 +29,14 @@ public class ToolsInitializer {
|
|||||||
.tools(userRolePermissionOperatorTool, departmentOperatorTool, positionOperatorTool)
|
.tools(userRolePermissionOperatorTool, departmentOperatorTool, positionOperatorTool)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@DependsOn("flywayInitializer")
|
||||||
|
public SystemToolAssistant deepSeekToolAssistant(OpenAiStreamingChatModel deepSeekChatModel) {
|
||||||
|
return AiServices.builder(SystemToolAssistant.class)
|
||||||
|
.streamingChatModel(deepSeekChatModel)
|
||||||
|
.chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(10))
|
||||||
|
.tools(userRolePermissionOperatorTool, departmentOperatorTool, positionOperatorTool)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.zl.mjga.config.minio;
|
||||||
|
|
||||||
|
import io.minio.MinioClient;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@ConfigurationProperties(prefix = "minio")
|
||||||
|
@Slf4j
|
||||||
|
public class MinIoConfig {
|
||||||
|
private String endpoint;
|
||||||
|
private String accessKey;
|
||||||
|
private String secretKey;
|
||||||
|
private String defaultBucket;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public MinioClient minioClient() {
|
||||||
|
return MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,14 +2,14 @@ package com.zl.mjga.controller;
|
|||||||
|
|
||||||
import com.zl.mjga.dto.PageRequestDto;
|
import com.zl.mjga.dto.PageRequestDto;
|
||||||
import com.zl.mjga.dto.PageResponseDto;
|
import com.zl.mjga.dto.PageResponseDto;
|
||||||
|
import com.zl.mjga.dto.ai.ChatDto;
|
||||||
import com.zl.mjga.dto.ai.LlmQueryDto;
|
import com.zl.mjga.dto.ai.LlmQueryDto;
|
||||||
import com.zl.mjga.dto.ai.LlmVm;
|
import com.zl.mjga.dto.ai.LlmVm;
|
||||||
import com.zl.mjga.exception.BusinessException;
|
import com.zl.mjga.exception.BusinessException;
|
||||||
import com.zl.mjga.repository.DepartmentRepository;
|
import com.zl.mjga.repository.*;
|
||||||
import com.zl.mjga.repository.UserRepository;
|
|
||||||
import com.zl.mjga.service.AiChatService;
|
import com.zl.mjga.service.AiChatService;
|
||||||
import com.zl.mjga.service.EmbeddingService;
|
|
||||||
import com.zl.mjga.service.LlmService;
|
import com.zl.mjga.service.LlmService;
|
||||||
|
import com.zl.mjga.service.RagService;
|
||||||
import dev.langchain4j.service.TokenStream;
|
import dev.langchain4j.service.TokenStream;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
@@ -20,9 +20,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jooq.generated.mjga.enums.LlmCodeEnum;
|
import org.jooq.generated.mjga.enums.LlmCodeEnum;
|
||||||
import org.jooq.generated.mjga.tables.pojos.AiLlmConfig;
|
import org.jooq.generated.mjga.tables.pojos.*;
|
||||||
import org.jooq.generated.mjga.tables.pojos.Department;
|
|
||||||
import org.jooq.generated.mjga.tables.pojos.User;
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
@@ -38,34 +36,46 @@ public class AiController {
|
|||||||
|
|
||||||
private final AiChatService aiChatService;
|
private final AiChatService aiChatService;
|
||||||
private final LlmService llmService;
|
private final LlmService llmService;
|
||||||
private final EmbeddingService embeddingService;
|
private final RagService ragService;
|
||||||
private final UserRepository userRepository;
|
private final UserRepository userRepository;
|
||||||
private final DepartmentRepository departmentRepository;
|
private final DepartmentRepository departmentRepository;
|
||||||
|
private final PositionRepository positionRepository;
|
||||||
|
private final RoleRepository repository;
|
||||||
|
private final PermissionRepository permissionRepository;
|
||||||
|
private final RoleRepository roleRepository;
|
||||||
|
|
||||||
@PostMapping(value = "/action/execute", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
@PostMapping(value = "/action/execute", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||||
public Flux<String> actionExecute(Principal principal, @RequestBody String userMessage) {
|
public Flux<String> actionExecute(Principal principal, @RequestBody String userMessage) {
|
||||||
Sinks.Many<String> sink = Sinks.many().unicast().onBackpressureBuffer();
|
Sinks.Many<String> sink = Sinks.many().unicast().onBackpressureBuffer();
|
||||||
TokenStream chat = aiChatService.actionExecuteWithZhiPu(principal.getName(), userMessage);
|
TokenStream chat = aiChatService.actionPrecedenceExecuteWith(principal.getName(), userMessage);
|
||||||
chat.onPartialResponse(
|
chat.onPartialResponse(
|
||||||
text ->
|
(text) -> {
|
||||||
sink.tryEmitNext(
|
log.debug("ai action partialResponse: {}", text);
|
||||||
StringUtils.isNotEmpty(text) ? text.replace(" ", "␣").replace("\t", "⇥") : ""))
|
sink.tryEmitNext(
|
||||||
|
StringUtils.isNotEmpty(text) ? text.replace(" ", "␣").replace("\t", "⇥") : "");
|
||||||
|
})
|
||||||
.onToolExecuted(
|
.onToolExecuted(
|
||||||
toolExecution -> log.debug("当前请求 {} 成功执行函数调用: {}", userMessage, toolExecution))
|
toolExecution -> log.debug("当前请求 {} 成功执行函数调用: {}", userMessage, toolExecution))
|
||||||
.onCompleteResponse(
|
.onCompleteResponse(
|
||||||
r -> {
|
r -> {
|
||||||
|
log.debug("ai action completeResponse: {}", r);
|
||||||
|
sink.tryEmitComplete();
|
||||||
|
sink.emitComplete(Sinks.EmitFailureHandler.FAIL_FAST);
|
||||||
|
})
|
||||||
|
.onError(
|
||||||
|
(e) -> {
|
||||||
|
sink.tryEmitError(e);
|
||||||
sink.tryEmitComplete();
|
sink.tryEmitComplete();
|
||||||
sink.emitComplete(Sinks.EmitFailureHandler.FAIL_FAST);
|
sink.emitComplete(Sinks.EmitFailureHandler.FAIL_FAST);
|
||||||
})
|
})
|
||||||
.onError(sink::tryEmitError)
|
|
||||||
.start();
|
.start();
|
||||||
return sink.asFlux().timeout(Duration.ofSeconds(120));
|
return sink.asFlux().timeout(Duration.ofSeconds(120));
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
@PostMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||||
public Flux<String> chat(Principal principal, @RequestBody String userMessage) {
|
public Flux<String> chat(Principal principal, @RequestBody ChatDto chatDto) {
|
||||||
Sinks.Many<String> sink = Sinks.many().unicast().onBackpressureBuffer();
|
Sinks.Many<String> sink = Sinks.many().unicast().onBackpressureBuffer();
|
||||||
TokenStream chat = aiChatService.chatPrecedenceLlmWith(principal.getName(), userMessage);
|
TokenStream chat = aiChatService.chat(principal.getName(), chatDto);
|
||||||
chat.onPartialResponse(
|
chat.onPartialResponse(
|
||||||
text ->
|
text ->
|
||||||
sink.tryEmitNext(
|
sink.tryEmitNext(
|
||||||
@@ -100,7 +110,7 @@ public class AiController {
|
|||||||
if (!aiLlmConfig.getEnable()) {
|
if (!aiLlmConfig.getEnable()) {
|
||||||
throw new BusinessException("命令模型未启用,请开启后再试。");
|
throw new BusinessException("命令模型未启用,请开启后再试。");
|
||||||
}
|
}
|
||||||
return embeddingService.searchAction(message);
|
return ragService.searchAction(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
||||||
@@ -116,7 +126,7 @@ public class AiController {
|
|||||||
userRepository.deleteByUsername(username);
|
userRepository.deleteByUsername(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_DEPARTMENT_PERMISSION)")
|
||||||
@DeleteMapping("/action/department")
|
@DeleteMapping("/action/department")
|
||||||
void deleteDepartment(@RequestParam String name) {
|
void deleteDepartment(@RequestParam String name) {
|
||||||
Department department = departmentRepository.fetchOneByName(name);
|
Department department = departmentRepository.fetchOneByName(name);
|
||||||
@@ -125,4 +135,39 @@ public class AiController {
|
|||||||
}
|
}
|
||||||
departmentRepository.deleteByName(name);
|
departmentRepository.deleteByName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_POSITION_PERMISSION)")
|
||||||
|
@DeleteMapping("/action/position")
|
||||||
|
void deletePosition(@RequestParam String name) {
|
||||||
|
Position position = positionRepository.fetchOneByName(name);
|
||||||
|
if (position == null) {
|
||||||
|
throw new BusinessException("该岗位不存在");
|
||||||
|
}
|
||||||
|
positionRepository.deleteById(position.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
||||||
|
@DeleteMapping("/action/role")
|
||||||
|
void deleteRole(@RequestParam String name) {
|
||||||
|
Role role = roleRepository.fetchOneByName(name);
|
||||||
|
if (role == null) {
|
||||||
|
throw new BusinessException("该角色不存在");
|
||||||
|
}
|
||||||
|
roleRepository.deleteById(role.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
||||||
|
@DeleteMapping("/action/permission")
|
||||||
|
void deletePermission(@RequestParam String name) {
|
||||||
|
Permission permission = permissionRepository.fetchOneByName(name);
|
||||||
|
if (permission == null) {
|
||||||
|
throw new BusinessException("该权限不存在");
|
||||||
|
}
|
||||||
|
permissionRepository.deleteById(permission.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/chat/refresh")
|
||||||
|
void createNewConversation(Principal principal) {
|
||||||
|
aiChatService.evictChatMemory(principal.getName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package com.zl.mjga.controller;
|
||||||
|
|
||||||
|
import com.zl.mjga.dto.PageRequestDto;
|
||||||
|
import com.zl.mjga.dto.PageResponseDto;
|
||||||
|
import com.zl.mjga.dto.aoplog.AopLogQueryDto;
|
||||||
|
import com.zl.mjga.dto.aoplog.AopLogRespDto;
|
||||||
|
import com.zl.mjga.repository.AopLogRepository;
|
||||||
|
import com.zl.mjga.service.AopLogService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/aop-log")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
|
@Tag(name = "AOP日志管理", description = "AOP日志查看和管理接口")
|
||||||
|
public class AopLogController {
|
||||||
|
|
||||||
|
private final AopLogService aopLogService;
|
||||||
|
private final AopLogRepository aopLogRepository;
|
||||||
|
|
||||||
|
@GetMapping("/page-query")
|
||||||
|
@ResponseStatus(HttpStatus.OK)
|
||||||
|
@Operation(summary = "分页查询AOP日志", description = "支持多种条件筛选的分页查询")
|
||||||
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).READ_USER_ROLE_PERMISSION)")
|
||||||
|
public PageResponseDto<List<AopLogRespDto>> pageQueryAopLogs(
|
||||||
|
@ModelAttribute @Valid PageRequestDto pageRequestDto,
|
||||||
|
@ModelAttribute AopLogQueryDto queryDto) {
|
||||||
|
return aopLogService.pageQueryAopLogs(pageRequestDto, queryDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
@ResponseStatus(HttpStatus.OK)
|
||||||
|
@Operation(summary = "查询日志详情", description = "根据ID查询单条日志的详细信息")
|
||||||
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).READ_USER_ROLE_PERMISSION)")
|
||||||
|
public AopLogRespDto getAopLogById(@Parameter(description = "日志ID") @PathVariable Long id) {
|
||||||
|
return aopLogService.getAopLogById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/batch")
|
||||||
|
@ResponseStatus(HttpStatus.OK)
|
||||||
|
@Operation(summary = "批量删除日志", description = "根据ID列表批量删除日志")
|
||||||
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
||||||
|
public int deleteAopLogs(@Parameter(description = "日志ID列表") @RequestBody List<Long> ids) {
|
||||||
|
return aopLogRepository.deleteByIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
@ResponseStatus(HttpStatus.OK)
|
||||||
|
@Operation(summary = "删除单条日志", description = "根据ID删除单条日志")
|
||||||
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
||||||
|
public void deleteAopLog(@Parameter(description = "日志ID") @PathVariable Long id) {
|
||||||
|
aopLogRepository.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/before")
|
||||||
|
@ResponseStatus(HttpStatus.OK)
|
||||||
|
@Operation(summary = "删除指定时间前的日志", description = "删除指定时间之前的所有日志")
|
||||||
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
||||||
|
public int deleteLogsBeforeTime(
|
||||||
|
@Parameter(description = "截止时间") @RequestParam OffsetDateTime beforeTime) {
|
||||||
|
return aopLogService.deleteLogsBeforeTime(beforeTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import com.zl.mjga.dto.PageRequestDto;
|
|||||||
import com.zl.mjga.dto.PageResponseDto;
|
import com.zl.mjga.dto.PageResponseDto;
|
||||||
import com.zl.mjga.dto.department.DepartmentQueryDto;
|
import com.zl.mjga.dto.department.DepartmentQueryDto;
|
||||||
import com.zl.mjga.dto.department.DepartmentRespDto;
|
import com.zl.mjga.dto.department.DepartmentRespDto;
|
||||||
|
import com.zl.mjga.dto.department.DepartmentWithParentDto;
|
||||||
import com.zl.mjga.repository.DepartmentRepository;
|
import com.zl.mjga.repository.DepartmentRepository;
|
||||||
import com.zl.mjga.service.DepartmentService;
|
import com.zl.mjga.service.DepartmentService;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -37,6 +38,12 @@ public class DepartmentController {
|
|||||||
return departmentService.queryAvailableParentDepartmentsBy(id);
|
return departmentService.queryAvailableParentDepartmentsBy(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).READ_DEPARTMENT_PERMISSION)")
|
||||||
|
@GetMapping("/query-sub")
|
||||||
|
List<DepartmentWithParentDto> querySubDepartment(@RequestParam(required = false) Long id) {
|
||||||
|
return departmentService.queryDepartmentAndSubsBy(id);
|
||||||
|
}
|
||||||
|
|
||||||
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_DEPARTMENT_PERMISSION)")
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_DEPARTMENT_PERMISSION)")
|
||||||
@DeleteMapping()
|
@DeleteMapping()
|
||||||
void deleteDepartment(@RequestParam Long id) {
|
void deleteDepartment(@RequestParam Long id) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.zl.mjga.controller;
|
package com.zl.mjga.controller;
|
||||||
|
|
||||||
|
import com.zl.mjga.annotation.SkipAopLog;
|
||||||
import com.zl.mjga.dto.PageRequestDto;
|
import com.zl.mjga.dto.PageRequestDto;
|
||||||
import com.zl.mjga.dto.PageResponseDto;
|
import com.zl.mjga.dto.PageResponseDto;
|
||||||
import com.zl.mjga.dto.department.DepartmentBindDto;
|
import com.zl.mjga.dto.department.DepartmentBindDto;
|
||||||
@@ -12,17 +13,19 @@ import com.zl.mjga.repository.PermissionRepository;
|
|||||||
import com.zl.mjga.repository.RoleRepository;
|
import com.zl.mjga.repository.RoleRepository;
|
||||||
import com.zl.mjga.repository.UserRepository;
|
import com.zl.mjga.repository.UserRepository;
|
||||||
import com.zl.mjga.service.IdentityAccessService;
|
import com.zl.mjga.service.IdentityAccessService;
|
||||||
|
import com.zl.mjga.service.UploadService;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.jooq.generated.mjga.tables.pojos.User;
|
import org.jooq.generated.mjga.tables.pojos.User;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.security.authentication.DisabledException;
|
import org.springframework.security.authentication.DisabledException;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/iam")
|
@RequestMapping("/iam")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@@ -32,6 +35,16 @@ public class IdentityAccessController {
|
|||||||
private final UserRepository userRepository;
|
private final UserRepository userRepository;
|
||||||
private final RoleRepository roleRepository;
|
private final RoleRepository roleRepository;
|
||||||
private final PermissionRepository permissionRepository;
|
private final PermissionRepository permissionRepository;
|
||||||
|
private final UploadService uploadService;
|
||||||
|
|
||||||
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
||||||
|
@PostMapping(
|
||||||
|
value = "/avatar/upload",
|
||||||
|
consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
|
||||||
|
produces = MediaType.TEXT_PLAIN_VALUE)
|
||||||
|
public String uploadAvatar(@RequestPart("file") MultipartFile multipartFile) throws Exception {
|
||||||
|
return uploadService.uploadAvatarFile(multipartFile);
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/me")
|
@GetMapping("/me")
|
||||||
UserRolePermissionDto currentUser(Principal principal) {
|
UserRolePermissionDto currentUser(Principal principal) {
|
||||||
@@ -44,6 +57,7 @@ public class IdentityAccessController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/me")
|
@PostMapping("/me")
|
||||||
|
@SkipAopLog
|
||||||
void upsertMe(Principal principal, @RequestBody UserUpsertDto userUpsertDto) {
|
void upsertMe(Principal principal, @RequestBody UserUpsertDto userUpsertDto) {
|
||||||
String name = principal.getName();
|
String name = principal.getName();
|
||||||
User user = userRepository.fetchOneByUsername(name);
|
User user = userRepository.fetchOneByUsername(name);
|
||||||
@@ -53,6 +67,7 @@ public class IdentityAccessController {
|
|||||||
|
|
||||||
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
||||||
@PostMapping("/user")
|
@PostMapping("/user")
|
||||||
|
@SkipAopLog
|
||||||
void upsertUser(@RequestBody @Valid UserUpsertDto userUpsertDto) {
|
void upsertUser(@RequestBody @Valid UserUpsertDto userUpsertDto) {
|
||||||
identityAccessService.upsertUser(userUpsertDto);
|
identityAccessService.upsertUser(userUpsertDto);
|
||||||
}
|
}
|
||||||
@@ -66,9 +81,6 @@ public class IdentityAccessController {
|
|||||||
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
||||||
@DeleteMapping("/user")
|
@DeleteMapping("/user")
|
||||||
void deleteUser(@RequestParam Long userId) {
|
void deleteUser(@RequestParam Long userId) {
|
||||||
if (userId == 1) {
|
|
||||||
throw new BusinessException("演示系统不允许操作管理员角色");
|
|
||||||
}
|
|
||||||
userRepository.deleteById(userId);
|
userRepository.deleteById(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,15 +93,12 @@ public class IdentityAccessController {
|
|||||||
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
||||||
@DeleteMapping("/role")
|
@DeleteMapping("/role")
|
||||||
void deleteRole(@RequestParam Long roleId) {
|
void deleteRole(@RequestParam Long roleId) {
|
||||||
if (roleId == 1) {
|
|
||||||
throw new BusinessException("演示系统不允许删除管理员角色");
|
|
||||||
}
|
|
||||||
roleRepository.deleteById(roleId);
|
roleRepository.deleteById(roleId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
||||||
@GetMapping("/role")
|
@GetMapping("/role")
|
||||||
RoleDto queryRoleWithPermission(@RequestParam Long roleId) {
|
RoleRespDto queryRoleWithPermission(@RequestParam Long roleId) {
|
||||||
return identityAccessService.queryUniqueRoleWithPermission(roleId);
|
return identityAccessService.queryUniqueRoleWithPermission(roleId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,9 +111,6 @@ public class IdentityAccessController {
|
|||||||
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
|
||||||
@DeleteMapping("/permission")
|
@DeleteMapping("/permission")
|
||||||
void deletePermission(@RequestParam Long permissionId) {
|
void deletePermission(@RequestParam Long permissionId) {
|
||||||
if (permissionId < 10) {
|
|
||||||
throw new BusinessException("演示系统不允许删除原有权限");
|
|
||||||
}
|
|
||||||
permissionRepository.deleteById(permissionId);
|
permissionRepository.deleteById(permissionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +125,7 @@ public class IdentityAccessController {
|
|||||||
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).READ_USER_ROLE_PERMISSION)")
|
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).READ_USER_ROLE_PERMISSION)")
|
||||||
@GetMapping("/roles")
|
@GetMapping("/roles")
|
||||||
@ResponseStatus(HttpStatus.OK)
|
@ResponseStatus(HttpStatus.OK)
|
||||||
PageResponseDto<List<RoleDto>> queryRoles(
|
PageResponseDto<List<RoleRespDto>> queryRoles(
|
||||||
@ModelAttribute PageRequestDto pageRequestDto, @ModelAttribute RoleQueryDto roleQueryDto) {
|
@ModelAttribute PageRequestDto pageRequestDto, @ModelAttribute RoleQueryDto roleQueryDto) {
|
||||||
return identityAccessService.pageQueryRole(pageRequestDto, roleQueryDto);
|
return identityAccessService.pageQueryRole(pageRequestDto, roleQueryDto);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package com.zl.mjga.controller;
|
||||||
|
|
||||||
|
import com.zl.mjga.dto.knowledge.DocUpdateDto;
|
||||||
|
import com.zl.mjga.dto.knowledge.LibraryUpsertDto;
|
||||||
|
import com.zl.mjga.repository.LibraryDocRepository;
|
||||||
|
import com.zl.mjga.repository.LibraryDocSegmentRepository;
|
||||||
|
import com.zl.mjga.repository.LibraryRepository;
|
||||||
|
import com.zl.mjga.service.RagService;
|
||||||
|
import com.zl.mjga.service.UploadService;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jooq.generated.mjga.tables.pojos.Library;
|
||||||
|
import org.jooq.generated.mjga.tables.pojos.LibraryDoc;
|
||||||
|
import org.jooq.generated.mjga.tables.pojos.LibraryDocSegment;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/knowledge")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
|
public class LibraryController {
|
||||||
|
|
||||||
|
private final UploadService uploadService;
|
||||||
|
private final RagService ragService;
|
||||||
|
private final LibraryRepository libraryRepository;
|
||||||
|
private final LibraryDocRepository libraryDocRepository;
|
||||||
|
private final LibraryDocSegmentRepository libraryDocSegmentRepository;
|
||||||
|
|
||||||
|
@GetMapping("/libraries")
|
||||||
|
public List<Library> queryLibraries() {
|
||||||
|
return libraryRepository.findAll().stream()
|
||||||
|
.sorted(Comparator.comparing(Library::getId).reversed())
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/docs")
|
||||||
|
public List<LibraryDoc> queryLibraryDocs(@RequestParam Long libraryId) {
|
||||||
|
return libraryDocRepository.fetchByLibId(libraryId).stream()
|
||||||
|
.sorted(Comparator.comparing(LibraryDoc::getId).reversed())
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/segments")
|
||||||
|
public List<LibraryDocSegment> queryLibraryDocSegments(@RequestParam Long libraryDocId) {
|
||||||
|
return libraryDocSegmentRepository.fetchByDocId(libraryDocId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/library")
|
||||||
|
public void upsertLibrary(@RequestBody @Valid LibraryUpsertDto libraryUpsertDto) {
|
||||||
|
Library library = new Library();
|
||||||
|
library.setId(libraryUpsertDto.id());
|
||||||
|
library.setName(libraryUpsertDto.name());
|
||||||
|
library.setDescription(libraryUpsertDto.description());
|
||||||
|
libraryRepository.merge(library);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/library")
|
||||||
|
public void deleteLibrary(@RequestParam Long libraryId) {
|
||||||
|
ragService.deleteLibraryBy(libraryId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/doc")
|
||||||
|
public void deleteLibraryDoc(@RequestParam Long libraryDocId) {
|
||||||
|
ragService.deleteDocBy(libraryDocId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/doc")
|
||||||
|
public void updateLibraryDoc(@RequestBody @Valid DocUpdateDto docUpdateDto) {
|
||||||
|
LibraryDoc exist = libraryDocRepository.fetchOneById(docUpdateDto.id());
|
||||||
|
exist.setEnable(docUpdateDto.enable());
|
||||||
|
libraryDocRepository.merge(exist);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "/doc/upload", produces = MediaType.TEXT_PLAIN_VALUE)
|
||||||
|
public String uploadLibraryDoc(
|
||||||
|
@RequestPart("libraryId") String libraryId, @RequestPart("file") MultipartFile multipartFile)
|
||||||
|
throws Exception {
|
||||||
|
String objectName = uploadService.uploadLibraryDoc(multipartFile);
|
||||||
|
Long libraryDocId =
|
||||||
|
ragService.createLibraryDocBy(
|
||||||
|
Long.valueOf(libraryId), objectName, multipartFile.getOriginalFilename());
|
||||||
|
ragService.embeddingAndCreateDocSegment(Long.valueOf(libraryId), libraryDocId, objectName);
|
||||||
|
return objectName;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.zl.mjga.controller;
|
package com.zl.mjga.controller;
|
||||||
|
|
||||||
|
import com.zl.mjga.annotation.SkipAopLog;
|
||||||
import com.zl.mjga.config.security.Jwt;
|
import com.zl.mjga.config.security.Jwt;
|
||||||
import com.zl.mjga.dto.sign.SignInDto;
|
import com.zl.mjga.dto.sign.SignInDto;
|
||||||
import com.zl.mjga.dto.sign.SignUpDto;
|
import com.zl.mjga.dto.sign.SignUpDto;
|
||||||
@@ -22,6 +23,7 @@ public class SignController {
|
|||||||
|
|
||||||
@ResponseStatus(HttpStatus.OK)
|
@ResponseStatus(HttpStatus.OK)
|
||||||
@PostMapping("/sign-in")
|
@PostMapping("/sign-in")
|
||||||
|
@SkipAopLog
|
||||||
void signIn(
|
void signIn(
|
||||||
HttpServletRequest request,
|
HttpServletRequest request,
|
||||||
HttpServletResponse response,
|
HttpServletResponse response,
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ public class PageRequestDto {
|
|||||||
.sort(SortOrder.valueOf(entry.getValue().getKeyword())))
|
.sort(SortOrder.valueOf(entry.getValue().getKeyword())))
|
||||||
.toList();
|
.toList();
|
||||||
if (sortFields.isEmpty()) {
|
if (sortFields.isEmpty()) {
|
||||||
return List.of(field(name("id")).sort(SortOrder.ASC));
|
return List.of(field(name("id")).sort(SortOrder.DESC));
|
||||||
} else {
|
} else {
|
||||||
return sortFields;
|
return sortFields;
|
||||||
}
|
}
|
||||||
|
|||||||
7
backend/src/main/java/com/zl/mjga/dto/ai/ChatDto.java
Normal file
7
backend/src/main/java/com/zl/mjga/dto/ai/ChatDto.java
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package com.zl.mjga.dto.ai;
|
||||||
|
|
||||||
|
import com.zl.mjga.model.urp.ChatMode;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
public record ChatDto(@NotNull ChatMode mode, Long libraryId, @NotEmpty String message) {}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package com.zl.mjga.dto.aoplog;
|
||||||
|
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/** AOP日志查询DTO */
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AopLogQueryDto {
|
||||||
|
|
||||||
|
/** ID */
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/** 类名 */
|
||||||
|
private String className;
|
||||||
|
|
||||||
|
/** 方法名 */
|
||||||
|
private String methodName;
|
||||||
|
|
||||||
|
/** 是否成功 */
|
||||||
|
private Boolean success;
|
||||||
|
|
||||||
|
/** 用户ID */
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
/** IP地址 */
|
||||||
|
private String ipAddress;
|
||||||
|
|
||||||
|
/** 开始时间 */
|
||||||
|
private OffsetDateTime startTime;
|
||||||
|
|
||||||
|
/** 结束时间 */
|
||||||
|
private OffsetDateTime endTime;
|
||||||
|
|
||||||
|
/** 最小执行时间(毫秒) */
|
||||||
|
private Long minExecutionTime;
|
||||||
|
|
||||||
|
/** 最大执行时间(毫秒) */
|
||||||
|
private Long maxExecutionTime;
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package com.zl.mjga.dto.aoplog;
|
||||||
|
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AopLogRespDto {
|
||||||
|
|
||||||
|
/** 主键ID */
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/** 类名 */
|
||||||
|
private String className;
|
||||||
|
|
||||||
|
/** 方法名 */
|
||||||
|
private String methodName;
|
||||||
|
|
||||||
|
/** 方法参数 */
|
||||||
|
private String methodArgs;
|
||||||
|
|
||||||
|
/** 返回值 */
|
||||||
|
private String returnValue;
|
||||||
|
|
||||||
|
/** 执行时间(毫秒) */
|
||||||
|
private Long executionTime;
|
||||||
|
|
||||||
|
/** 是否成功 */
|
||||||
|
private Boolean success;
|
||||||
|
|
||||||
|
/** 错误信息 */
|
||||||
|
private String errorMessage;
|
||||||
|
|
||||||
|
/** 用户ID */
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
/** 用户名 */
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
/** IP地址 */
|
||||||
|
private String ipAddress;
|
||||||
|
|
||||||
|
/** 用户代理 */
|
||||||
|
private String userAgent;
|
||||||
|
|
||||||
|
/** curl命令 */
|
||||||
|
private String curl;
|
||||||
|
|
||||||
|
/** 创建时间 */
|
||||||
|
private OffsetDateTime createTime;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.zl.mjga.dto.knowledge;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
public record DocUpdateDto(@NotNull Long id, @NotNull Long libId, @NotNull Boolean enable) {}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.zl.mjga.dto.knowledge;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
|
||||||
|
public record LibraryUpsertDto(Long id, @NotEmpty String name, String description) {}
|
||||||
@@ -7,6 +7,7 @@ import lombok.*;
|
|||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
public class PermissionRespDto {
|
public class PermissionRespDto {
|
||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
private String code;
|
private String code;
|
||||||
private String name;
|
private String name;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.zl.mjga.dto.urp;
|
package com.zl.mjga.dto.urp;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
@@ -8,10 +9,18 @@ import lombok.*;
|
|||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
public class RoleDto {
|
public class RoleRespDto {
|
||||||
|
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private String code;
|
private String code;
|
||||||
|
|
||||||
|
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private Boolean isBound;
|
private Boolean isBound;
|
||||||
|
|
||||||
@Builder.Default List<PermissionRespDto> permissions = new LinkedList<>();
|
@Builder.Default List<PermissionRespDto> permissions = new LinkedList<>();
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.zl.mjga.dto.urp;
|
package com.zl.mjga.dto.urp;
|
||||||
|
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@@ -7,4 +8,6 @@ import lombok.*;
|
|||||||
@Data
|
@Data
|
||||||
public class UserQueryDto {
|
public class UserQueryDto {
|
||||||
private String username;
|
private String username;
|
||||||
|
private OffsetDateTime startDate;
|
||||||
|
private OffsetDateTime endDate;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.zl.mjga.dto.urp;
|
package com.zl.mjga.dto.urp;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -13,15 +14,24 @@ import lombok.*;
|
|||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
public class UserRolePermissionDto {
|
public class UserRolePermissionDto {
|
||||||
|
|
||||||
|
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private String username;
|
private String username;
|
||||||
|
|
||||||
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
|
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
private Boolean enable;
|
private String avatar;
|
||||||
@Builder.Default private List<RoleDto> roles = new LinkedList<>();
|
|
||||||
|
|
||||||
|
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private Boolean enable;
|
||||||
|
|
||||||
|
@Builder.Default private List<RoleRespDto> roles = new LinkedList<>();
|
||||||
|
|
||||||
|
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private OffsetDateTime createTime;
|
private OffsetDateTime createTime;
|
||||||
|
|
||||||
public Set<PermissionRespDto> getPermissions() {
|
public Set<PermissionRespDto> getPermissions() {
|
||||||
|
|||||||
@@ -14,4 +14,5 @@ public class UserUpsertDto {
|
|||||||
@NotEmpty private String username;
|
@NotEmpty private String username;
|
||||||
private String password;
|
private String password;
|
||||||
@NotNull private Boolean enable;
|
@NotNull private Boolean enable;
|
||||||
|
private String avatar;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,15 @@ import lombok.Getter;
|
|||||||
@Getter
|
@Getter
|
||||||
public enum Actions {
|
public enum Actions {
|
||||||
CREATE_USER("CREATE_USER", "创建用户"),
|
CREATE_USER("CREATE_USER", "创建用户"),
|
||||||
CREATE_DEPARTMENT("CREATE_DEPARTMENT", "创建部门"),
|
|
||||||
DELETE_USER("DELETE_USER", "删除用户"),
|
DELETE_USER("DELETE_USER", "删除用户"),
|
||||||
DELETE_DEPARTMENT("DELETE_DEPARTMENT", "删除部门");
|
CREATE_DEPARTMENT("CREATE_DEPARTMENT", "创建部门"),
|
||||||
|
DELETE_DEPARTMENT("DELETE_DEPARTMENT", "删除部门"),
|
||||||
|
CREATE_POSITION("CREATE_POSITION", "创建岗位"),
|
||||||
|
DELETE_POSITION("DELETE_POSITION", "删除岗位"),
|
||||||
|
CREATE_ROLE("CREATE_ROLE", "创建角色"),
|
||||||
|
DELETE_ROLE("CREATE_ROLE", "删除角色"),
|
||||||
|
CREATE_PERMISSION("CREATE_PERMISSION", "创建权限"),
|
||||||
|
DELETE_PERMISSION("DELETE_PERMISSION", "删除权限");
|
||||||
public static final String INDEX_KEY = "action";
|
public static final String INDEX_KEY = "action";
|
||||||
private final String code;
|
private final String code;
|
||||||
private final String content;
|
private final String content;
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package com.zl.mjga.model.urp;
|
||||||
|
|
||||||
|
public enum ChatMode {
|
||||||
|
NORMAL,
|
||||||
|
WITH_LIBRARY
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
package com.zl.mjga.repository;
|
||||||
|
|
||||||
|
import static org.jooq.generated.mjga.tables.AopLog.AOP_LOG;
|
||||||
|
import static org.jooq.generated.mjga.tables.User.USER;
|
||||||
|
import static org.jooq.impl.DSL.*;
|
||||||
|
|
||||||
|
import com.zl.mjga.dto.PageRequestDto;
|
||||||
|
import com.zl.mjga.dto.aoplog.AopLogQueryDto;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.jooq.*;
|
||||||
|
import org.jooq.Record;
|
||||||
|
import org.jooq.generated.mjga.tables.daos.AopLogDao;
|
||||||
|
import org.jooq.generated.mjga.tables.pojos.AopLog;
|
||||||
|
import org.jooq.impl.DSL;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
/** AOP日志Repository */
|
||||||
|
@Repository
|
||||||
|
public class AopLogRepository extends AopLogDao {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public AopLogRepository(Configuration configuration) {
|
||||||
|
super(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<Record> pageFetchBy(PageRequestDto pageRequestDto, AopLogQueryDto queryDto) {
|
||||||
|
return selectByWithoutReturnValue(queryDto)
|
||||||
|
.orderBy(pageRequestDto.getSortFields())
|
||||||
|
.limit(pageRequestDto.getSize())
|
||||||
|
.offset(pageRequestDto.getOffset())
|
||||||
|
.fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AopLog> fetchBy(AopLogQueryDto queryDto) {
|
||||||
|
return selectBy(queryDto).fetchInto(AopLog.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SelectConditionStep<Record> selectBy(AopLogQueryDto queryDto) {
|
||||||
|
return ctx()
|
||||||
|
.select(AOP_LOG.asterisk(), USER.USERNAME, DSL.count().over().as("total_count"))
|
||||||
|
.from(AOP_LOG)
|
||||||
|
.leftJoin(USER)
|
||||||
|
.on(AOP_LOG.USER_ID.eq(USER.ID))
|
||||||
|
.where(buildConditions(queryDto));
|
||||||
|
}
|
||||||
|
|
||||||
|
public SelectConditionStep<Record> selectByWithoutReturnValue(AopLogQueryDto queryDto) {
|
||||||
|
return ctx()
|
||||||
|
.select(
|
||||||
|
AOP_LOG.asterisk().except(AOP_LOG.RETURN_VALUE, AOP_LOG.METHOD_ARGS),
|
||||||
|
USER.USERNAME,
|
||||||
|
DSL.count().over().as("total_count"))
|
||||||
|
.from(AOP_LOG)
|
||||||
|
.leftJoin(USER)
|
||||||
|
.on(AOP_LOG.USER_ID.eq(USER.ID))
|
||||||
|
.where(buildConditions(queryDto));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Condition buildConditions(AopLogQueryDto queryDto) {
|
||||||
|
Condition condition = noCondition();
|
||||||
|
|
||||||
|
if (queryDto == null) {
|
||||||
|
return condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID精确查询
|
||||||
|
if (queryDto.getId() != null) {
|
||||||
|
condition = condition.and(AOP_LOG.ID.eq(queryDto.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 类名模糊查询
|
||||||
|
if (StringUtils.isNotBlank(queryDto.getClassName())) {
|
||||||
|
condition = condition.and(AOP_LOG.CLASS_NAME.like("%" + queryDto.getClassName() + "%"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方法名模糊查询
|
||||||
|
if (StringUtils.isNotBlank(queryDto.getMethodName())) {
|
||||||
|
condition = condition.and(AOP_LOG.METHOD_NAME.like("%" + queryDto.getMethodName() + "%"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 成功状态
|
||||||
|
if (queryDto.getSuccess() != null) {
|
||||||
|
condition = condition.and(AOP_LOG.SUCCESS.eq(queryDto.getSuccess()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户ID
|
||||||
|
if (queryDto.getUserId() != null) {
|
||||||
|
condition = condition.and(AOP_LOG.USER_ID.eq(queryDto.getUserId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// IP地址模糊查询
|
||||||
|
if (StringUtils.isNotBlank(queryDto.getIpAddress())) {
|
||||||
|
condition = condition.and(AOP_LOG.IP_ADDRESS.like("%" + queryDto.getIpAddress() + "%"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 时间范围查询
|
||||||
|
if (queryDto.getStartTime() != null) {
|
||||||
|
condition = condition.and(AOP_LOG.CREATE_TIME.ge(queryDto.getStartTime()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queryDto.getEndTime() != null) {
|
||||||
|
condition = condition.and(AOP_LOG.CREATE_TIME.le(queryDto.getEndTime()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行时间范围
|
||||||
|
if (queryDto.getMinExecutionTime() != null) {
|
||||||
|
condition = condition.and(AOP_LOG.EXECUTION_TIME.ge(queryDto.getMinExecutionTime()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queryDto.getMaxExecutionTime() != null) {
|
||||||
|
condition = condition.and(AOP_LOG.EXECUTION_TIME.le(queryDto.getMaxExecutionTime()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int deleteByIds(List<Long> ids) {
|
||||||
|
return ctx().deleteFrom(AOP_LOG).where(AOP_LOG.ID.in(ids)).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int deleteBeforeTime(OffsetDateTime beforeTime) {
|
||||||
|
return ctx().deleteFrom(AOP_LOG).where(AOP_LOG.CREATE_TIME.lt(beforeTime)).execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,7 +37,8 @@ public class DepartmentRepository extends DepartmentDao {
|
|||||||
DEPARTMENT.PARENT_ID,
|
DEPARTMENT.PARENT_ID,
|
||||||
DEPARTMENT.NAME.cast(VARCHAR))
|
DEPARTMENT.NAME.cast(VARCHAR))
|
||||||
.from(DEPARTMENT)
|
.from(DEPARTMENT)
|
||||||
.where(DEPARTMENT.ID.eq(id))
|
.where(id == null ? noCondition() : DEPARTMENT.ID.eq(id))
|
||||||
|
.and(DEPARTMENT.PARENT_ID.isNull())
|
||||||
.unionAll(
|
.unionAll(
|
||||||
select(
|
select(
|
||||||
DEPARTMENT.ID,
|
DEPARTMENT.ID,
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.zl.mjga.repository;
|
||||||
|
|
||||||
|
import org.jooq.Configuration;
|
||||||
|
import org.jooq.generated.mjga.tables.daos.LibraryDocDao;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public class LibraryDocRepository extends LibraryDocDao {
|
||||||
|
@Autowired
|
||||||
|
public LibraryDocRepository(Configuration configuration) {
|
||||||
|
super(configuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.zl.mjga.repository;
|
||||||
|
|
||||||
|
import org.jooq.Configuration;
|
||||||
|
import org.jooq.generated.mjga.tables.daos.LibraryDocSegmentDao;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public class LibraryDocSegmentRepository extends LibraryDocSegmentDao {
|
||||||
|
@Autowired
|
||||||
|
public LibraryDocSegmentRepository(Configuration configuration) {
|
||||||
|
super(configuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.zl.mjga.repository;
|
||||||
|
|
||||||
|
import org.jooq.Configuration;
|
||||||
|
import org.jooq.generated.mjga.tables.daos.LibraryDao;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public class LibraryRepository extends LibraryDao {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public LibraryRepository(Configuration configuration) {
|
||||||
|
super(configuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
package com.zl.mjga.repository;
|
package com.zl.mjga.repository;
|
||||||
|
|
||||||
import static org.jooq.generated.mjga.Tables.*;
|
|
||||||
import static org.jooq.generated.mjga.tables.User.USER;
|
import static org.jooq.generated.mjga.tables.User.USER;
|
||||||
import static org.jooq.impl.DSL.*;
|
import static org.jooq.impl.DSL.*;
|
||||||
|
|
||||||
import com.zl.mjga.dto.PageRequestDto;
|
import com.zl.mjga.dto.PageRequestDto;
|
||||||
import com.zl.mjga.dto.urp.PermissionRespDto;
|
import com.zl.mjga.dto.urp.PermissionRespDto;
|
||||||
import com.zl.mjga.dto.urp.RoleDto;
|
import com.zl.mjga.dto.urp.RoleRespDto;
|
||||||
import com.zl.mjga.dto.urp.UserQueryDto;
|
import com.zl.mjga.dto.urp.UserQueryDto;
|
||||||
import com.zl.mjga.dto.urp.UserRolePermissionDto;
|
import com.zl.mjga.dto.urp.UserRolePermissionDto;
|
||||||
|
import java.util.List;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jooq.*;
|
import org.jooq.*;
|
||||||
import org.jooq.Record;
|
import org.jooq.Record;
|
||||||
@@ -36,6 +36,7 @@ public class UserRepository extends UserDao {
|
|||||||
value(user.getId()).as("id"),
|
value(user.getId()).as("id"),
|
||||||
value(user.getUsername()).as("username"),
|
value(user.getUsername()).as("username"),
|
||||||
value(user.getPassword()).as("password"),
|
value(user.getPassword()).as("password"),
|
||||||
|
value(user.getAvatar()).as("avatar"),
|
||||||
value(user.getEnable()).as("enable"))
|
value(user.getEnable()).as("enable"))
|
||||||
.asTable("newUser"))
|
.asTable("newUser"))
|
||||||
.on(USER.ID.eq(DSL.field(DSL.name("newUser", "id"), Long.class)))
|
.on(USER.ID.eq(DSL.field(DSL.name("newUser", "id"), Long.class)))
|
||||||
@@ -46,16 +47,18 @@ public class UserRepository extends UserDao {
|
|||||||
StringUtils.isNotEmpty(user.getPassword())
|
StringUtils.isNotEmpty(user.getPassword())
|
||||||
? DSL.field(DSL.name("newUser", "password"), String.class)
|
? DSL.field(DSL.name("newUser", "password"), String.class)
|
||||||
: USER.PASSWORD)
|
: USER.PASSWORD)
|
||||||
|
.set(USER.AVATAR, DSL.field(DSL.name("newUser", "avatar"), String.class))
|
||||||
.set(USER.ENABLE, DSL.field(DSL.name("newUser", "enable"), Boolean.class))
|
.set(USER.ENABLE, DSL.field(DSL.name("newUser", "enable"), Boolean.class))
|
||||||
.whenNotMatchedThenInsert(USER.USERNAME, USER.PASSWORD, USER.ENABLE)
|
.whenNotMatchedThenInsert(USER.USERNAME, USER.PASSWORD, USER.AVATAR, USER.ENABLE)
|
||||||
.values(
|
.values(
|
||||||
DSL.field(DSL.name("newUser", "username"), String.class),
|
DSL.field(DSL.name("newUser", "username"), String.class),
|
||||||
DSL.field(DSL.name("newUser", "password"), String.class),
|
DSL.field(DSL.name("newUser", "password"), String.class),
|
||||||
|
DSL.field(DSL.name("newUser", "avatar"), String.class),
|
||||||
DSL.field(DSL.name("newUser", "enable"), Boolean.class))
|
DSL.field(DSL.name("newUser", "enable"), Boolean.class))
|
||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result<Record> pageFetchBy(PageRequestDto pageRequestDto, UserQueryDto userQueryDto) {
|
public SelectConditionStep<Record> selectBy(UserQueryDto userQueryDto) {
|
||||||
return ctx()
|
return ctx()
|
||||||
.select(asterisk(), DSL.count().over().as("total_user"))
|
.select(asterisk(), DSL.count().over().as("total_user"))
|
||||||
.from(USER)
|
.from(USER)
|
||||||
@@ -63,6 +66,22 @@ public class UserRepository extends UserDao {
|
|||||||
userQueryDto.getUsername() != null
|
userQueryDto.getUsername() != null
|
||||||
? USER.USERNAME.like("%" + userQueryDto.getUsername() + "%")
|
? USER.USERNAME.like("%" + userQueryDto.getUsername() + "%")
|
||||||
: noCondition())
|
: noCondition())
|
||||||
|
.and(
|
||||||
|
userQueryDto.getStartDate() != null
|
||||||
|
? USER.CREATE_TIME.ge(userQueryDto.getStartDate())
|
||||||
|
: noCondition())
|
||||||
|
.and(
|
||||||
|
userQueryDto.getEndDate() != null
|
||||||
|
? USER.CREATE_TIME.le(userQueryDto.getEndDate())
|
||||||
|
: noCondition());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<User> fetchBy(UserQueryDto userQueryDto) {
|
||||||
|
return selectBy(userQueryDto).fetchInto(User.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<Record> pageFetchBy(PageRequestDto pageRequestDto, UserQueryDto userQueryDto) {
|
||||||
|
return selectBy(userQueryDto)
|
||||||
.orderBy(pageRequestDto.getSortFields())
|
.orderBy(pageRequestDto.getSortFields())
|
||||||
.limit(pageRequestDto.getSize())
|
.limit(pageRequestDto.getSize())
|
||||||
.offset(pageRequestDto.getOffset())
|
.offset(pageRequestDto.getOffset())
|
||||||
@@ -83,7 +102,7 @@ public class UserRepository extends UserDao {
|
|||||||
r -> r.map((record) -> record.into(PermissionRespDto.class)))
|
r -> r.map((record) -> record.into(PermissionRespDto.class)))
|
||||||
.as("permissions"))
|
.as("permissions"))
|
||||||
.from(USER.role()))
|
.from(USER.role()))
|
||||||
.convertFrom(r -> r.map((record) -> record.into(RoleDto.class)))
|
.convertFrom(r -> r.map((record) -> record.into(RoleRespDto.class)))
|
||||||
.as("roles"))
|
.as("roles"))
|
||||||
.from(USER)
|
.from(USER)
|
||||||
.where(USER.ID.eq(userId))
|
.where(USER.ID.eq(userId))
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.zl.mjga.service;
|
|||||||
|
|
||||||
import com.zl.mjga.config.ai.AiChatAssistant;
|
import com.zl.mjga.config.ai.AiChatAssistant;
|
||||||
import com.zl.mjga.config.ai.SystemToolAssistant;
|
import com.zl.mjga.config.ai.SystemToolAssistant;
|
||||||
|
import com.zl.mjga.dto.ai.ChatDto;
|
||||||
import com.zl.mjga.exception.BusinessException;
|
import com.zl.mjga.exception.BusinessException;
|
||||||
import dev.langchain4j.service.TokenStream;
|
import dev.langchain4j.service.TokenStream;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@@ -19,6 +20,7 @@ public class AiChatService {
|
|||||||
private final AiChatAssistant deepSeekChatAssistant;
|
private final AiChatAssistant deepSeekChatAssistant;
|
||||||
private final AiChatAssistant zhiPuChatAssistant;
|
private final AiChatAssistant zhiPuChatAssistant;
|
||||||
private final SystemToolAssistant zhiPuToolAssistant;
|
private final SystemToolAssistant zhiPuToolAssistant;
|
||||||
|
private final SystemToolAssistant deepSeekToolAssistant;
|
||||||
private final LlmService llmService;
|
private final LlmService llmService;
|
||||||
|
|
||||||
public TokenStream chatWithDeepSeek(String sessionIdentifier, String userMessage) {
|
public TokenStream chatWithDeepSeek(String sessionIdentifier, String userMessage) {
|
||||||
@@ -29,12 +31,29 @@ public class AiChatService {
|
|||||||
return zhiPuChatAssistant.chat(sessionIdentifier, userMessage);
|
return zhiPuChatAssistant.chat(sessionIdentifier, userMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TokenStream actionExecuteWithZhiPu(String sessionIdentifier, String userMessage) {
|
public TokenStream actionPrecedenceExecuteWith(String sessionIdentifier, String userMessage) {
|
||||||
return zhiPuToolAssistant.ask(sessionIdentifier, userMessage);
|
LlmCodeEnum code = getPrecedenceLlmCode();
|
||||||
|
return switch (code) {
|
||||||
|
case ZHI_PU -> zhiPuToolAssistant.ask(sessionIdentifier, userMessage);
|
||||||
|
case DEEP_SEEK -> deepSeekToolAssistant.ask(sessionIdentifier, userMessage);
|
||||||
|
default -> throw new BusinessException(String.format("无效的模型代码 %s", code));
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public TokenStream chatPrecedenceLlmWith(String sessionIdentifier, String userMessage) {
|
public TokenStream chat(String sessionIdentifier, ChatDto chatDto) {
|
||||||
|
return switch (chatDto.mode()) {
|
||||||
|
case NORMAL -> chatWithPrecedenceLlm(sessionIdentifier, chatDto);
|
||||||
|
case WITH_LIBRARY -> chatWithLibrary(chatDto.libraryId(), chatDto);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenStream chatWithLibrary(Long libraryId, ChatDto chatDto) {
|
||||||
|
return zhiPuChatAssistant.chat(String.valueOf(libraryId), chatDto.message());
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenStream chatWithPrecedenceLlm(String sessionIdentifier, ChatDto chatDto) {
|
||||||
LlmCodeEnum code = getPrecedenceLlmCode();
|
LlmCodeEnum code = getPrecedenceLlmCode();
|
||||||
|
String userMessage = chatDto.message();
|
||||||
return switch (code) {
|
return switch (code) {
|
||||||
case ZHI_PU -> zhiPuChatAssistant.chat(sessionIdentifier, userMessage);
|
case ZHI_PU -> zhiPuChatAssistant.chat(sessionIdentifier, userMessage);
|
||||||
case DEEP_SEEK -> deepSeekChatAssistant.chat(sessionIdentifier, userMessage);
|
case DEEP_SEEK -> deepSeekChatAssistant.chat(sessionIdentifier, userMessage);
|
||||||
@@ -47,4 +66,11 @@ public class AiChatService {
|
|||||||
AiLlmConfig aiLlmConfig = precedenceLlmBy.orElseThrow(() -> new BusinessException("没有开启的大模型"));
|
AiLlmConfig aiLlmConfig = precedenceLlmBy.orElseThrow(() -> new BusinessException("没有开启的大模型"));
|
||||||
return aiLlmConfig.getCode();
|
return aiLlmConfig.getCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void evictChatMemory(String sessionIdentifier) {
|
||||||
|
deepSeekChatAssistant.evictChatMemory(sessionIdentifier);
|
||||||
|
zhiPuChatAssistant.evictChatMemory(sessionIdentifier);
|
||||||
|
zhiPuToolAssistant.evictChatMemory(sessionIdentifier);
|
||||||
|
deepSeekToolAssistant.evictChatMemory(sessionIdentifier);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
61
backend/src/main/java/com/zl/mjga/service/AopLogService.java
Normal file
61
backend/src/main/java/com/zl/mjga/service/AopLogService.java
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package com.zl.mjga.service;
|
||||||
|
|
||||||
|
import com.zl.mjga.dto.PageRequestDto;
|
||||||
|
import com.zl.mjga.dto.PageResponseDto;
|
||||||
|
import com.zl.mjga.dto.aoplog.AopLogQueryDto;
|
||||||
|
import com.zl.mjga.dto.aoplog.AopLogRespDto;
|
||||||
|
import com.zl.mjga.repository.AopLogRepository;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jooq.Record;
|
||||||
|
import org.jooq.Result;
|
||||||
|
import org.jooq.SelectConditionStep;
|
||||||
|
import org.jooq.generated.mjga.tables.pojos.AopLog;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AopLogService {
|
||||||
|
|
||||||
|
private final AopLogRepository aopLogRepository;
|
||||||
|
|
||||||
|
@Async
|
||||||
|
public void saveLogAsync(AopLog aopLog) {
|
||||||
|
try {
|
||||||
|
aopLogRepository.insert(aopLog);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to save AOP log asynchronously", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PageResponseDto<List<AopLogRespDto>> pageQueryAopLogs(
|
||||||
|
PageRequestDto pageRequestDto, AopLogQueryDto queryDto) {
|
||||||
|
Result<Record> records = aopLogRepository.pageFetchBy(pageRequestDto, queryDto);
|
||||||
|
|
||||||
|
if (records.isEmpty()) {
|
||||||
|
return PageResponseDto.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<AopLogRespDto> aopLogs = records.map((record -> record.into(AopLogRespDto.class)));
|
||||||
|
Long totalCount = records.get(0).getValue("total_count", Long.class);
|
||||||
|
|
||||||
|
return new PageResponseDto<>(totalCount, aopLogs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AopLogRespDto getAopLogById(Long id) {
|
||||||
|
AopLogQueryDto queryDto = new AopLogQueryDto();
|
||||||
|
queryDto.setId(id);
|
||||||
|
SelectConditionStep<Record> selectStep = aopLogRepository.selectBy(queryDto);
|
||||||
|
return selectStep.fetchOneInto(AopLogRespDto.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public int deleteLogsBeforeTime(OffsetDateTime beforeTime) {
|
||||||
|
return aopLogRepository.deleteBeforeTime(beforeTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
package com.zl.mjga.service;
|
|
||||||
|
|
||||||
import static dev.langchain4j.store.embedding.filter.MetadataFilterBuilder.metadataKey;
|
|
||||||
|
|
||||||
import com.zl.mjga.config.ai.ZhiPuEmbeddingModelConfig;
|
|
||||||
import com.zl.mjga.model.urp.Actions;
|
|
||||||
import dev.langchain4j.data.document.Metadata;
|
|
||||||
import dev.langchain4j.data.embedding.Embedding;
|
|
||||||
import dev.langchain4j.data.segment.TextSegment;
|
|
||||||
import dev.langchain4j.model.embedding.EmbeddingModel;
|
|
||||||
import dev.langchain4j.store.embedding.EmbeddingSearchRequest;
|
|
||||||
import dev.langchain4j.store.embedding.EmbeddingSearchResult;
|
|
||||||
import dev.langchain4j.store.embedding.EmbeddingStore;
|
|
||||||
import dev.langchain4j.store.embedding.filter.Filter;
|
|
||||||
import jakarta.annotation.PostConstruct;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Service
|
|
||||||
public class EmbeddingService {
|
|
||||||
|
|
||||||
private final EmbeddingModel zhipuEmbeddingModel;
|
|
||||||
|
|
||||||
private final EmbeddingStore<TextSegment> zhiPuEmbeddingStore;
|
|
||||||
|
|
||||||
private final ZhiPuEmbeddingModelConfig zhiPuEmbeddingModelConfig;
|
|
||||||
|
|
||||||
public Map<String, String> searchAction(String message) {
|
|
||||||
Map<String, String> result = new HashMap<>();
|
|
||||||
EmbeddingSearchRequest embeddingSearchRequest =
|
|
||||||
EmbeddingSearchRequest.builder()
|
|
||||||
.queryEmbedding(zhipuEmbeddingModel.embed(message).content())
|
|
||||||
.minScore(0.89)
|
|
||||||
.build();
|
|
||||||
EmbeddingSearchResult<TextSegment> embeddingSearchResult =
|
|
||||||
zhiPuEmbeddingStore.search(embeddingSearchRequest);
|
|
||||||
if (!embeddingSearchResult.matches().isEmpty()) {
|
|
||||||
Metadata metadata = embeddingSearchResult.matches().getFirst().embedded().metadata();
|
|
||||||
result.put(Actions.INDEX_KEY, metadata.getString(Actions.INDEX_KEY));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
public void initActionIndex() {
|
|
||||||
if (!zhiPuEmbeddingModelConfig.getEnable()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (Actions action : Actions.values()) {
|
|
||||||
Embedding queryEmbedding = zhipuEmbeddingModel.embed(action.getContent()).content();
|
|
||||||
Filter createUserFilter = metadataKey(Actions.INDEX_KEY).isEqualTo(action.getCode());
|
|
||||||
EmbeddingSearchRequest embeddingSearchRequest =
|
|
||||||
EmbeddingSearchRequest.builder()
|
|
||||||
.queryEmbedding(queryEmbedding)
|
|
||||||
.filter(createUserFilter)
|
|
||||||
.build();
|
|
||||||
EmbeddingSearchResult<TextSegment> embeddingSearchResult =
|
|
||||||
zhiPuEmbeddingStore.search(embeddingSearchRequest);
|
|
||||||
if (embeddingSearchResult.matches().isEmpty()) {
|
|
||||||
TextSegment segment =
|
|
||||||
TextSegment.from(
|
|
||||||
action.getContent(), Metadata.metadata(Actions.INDEX_KEY, action.getCode()));
|
|
||||||
Embedding embedding = zhipuEmbeddingModel.embed(segment).content();
|
|
||||||
zhiPuEmbeddingStore.add(embedding, segment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -80,17 +80,17 @@ public class IdentityAccessService {
|
|||||||
return userRepository.fetchUniqueUserDtoWithNestedRolePermissionBy(userId);
|
return userRepository.fetchUniqueUserDtoWithNestedRolePermissionBy(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PageResponseDto<List<RoleDto>> pageQueryRole(
|
public PageResponseDto<List<RoleRespDto>> pageQueryRole(
|
||||||
PageRequestDto pageRequestDto, RoleQueryDto roleQueryDto) {
|
PageRequestDto pageRequestDto, RoleQueryDto roleQueryDto) {
|
||||||
Result<Record> roleRecords = roleRepository.pageFetchBy(pageRequestDto, roleQueryDto);
|
Result<Record> roleRecords = roleRepository.pageFetchBy(pageRequestDto, roleQueryDto);
|
||||||
if (roleRecords.isEmpty()) {
|
if (roleRecords.isEmpty()) {
|
||||||
return PageResponseDto.empty();
|
return PageResponseDto.empty();
|
||||||
}
|
}
|
||||||
List<RoleDto> roleDtoList =
|
List<RoleRespDto> roleRespDtoList =
|
||||||
roleRecords.stream()
|
roleRecords.stream()
|
||||||
.map(
|
.map(
|
||||||
record -> {
|
record -> {
|
||||||
return RoleDto.builder()
|
return RoleRespDto.builder()
|
||||||
.id(record.getValue("id", Long.class))
|
.id(record.getValue("id", Long.class))
|
||||||
.code(record.getValue("code", String.class))
|
.code(record.getValue("code", String.class))
|
||||||
.name(record.getValue("name", String.class))
|
.name(record.getValue("name", String.class))
|
||||||
@@ -103,17 +103,17 @@ public class IdentityAccessService {
|
|||||||
})
|
})
|
||||||
.toList();
|
.toList();
|
||||||
return new PageResponseDto<>(
|
return new PageResponseDto<>(
|
||||||
roleRecords.get(0).getValue("total_role", Integer.class), roleDtoList);
|
roleRecords.get(0).getValue("total_role", Integer.class), roleRespDtoList);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable RoleDto queryUniqueRoleWithPermission(Long roleId) {
|
public @Nullable RoleRespDto queryUniqueRoleWithPermission(Long roleId) {
|
||||||
Result<Record> roleWithPermissionRecords = roleRepository.fetchUniqueRoleWithPermission(roleId);
|
Result<Record> roleWithPermissionRecords = roleRepository.fetchUniqueRoleWithPermission(roleId);
|
||||||
if (roleWithPermissionRecords.isEmpty()) {
|
if (roleWithPermissionRecords.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
RoleDto roleDto = createRbacDtoRolePart(roleWithPermissionRecords);
|
RoleRespDto roleRespDto = createRbacDtoRolePart(roleWithPermissionRecords);
|
||||||
setCurrentRolePermission(roleDto, roleWithPermissionRecords);
|
setCurrentRolePermission(roleRespDto, roleWithPermissionRecords);
|
||||||
return roleDto;
|
return roleRespDto;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PageResponseDto<List<PermissionRespDto>> pageQueryPermission(
|
public PageResponseDto<List<PermissionRespDto>> pageQueryPermission(
|
||||||
@@ -199,12 +199,12 @@ public class IdentityAccessService {
|
|||||||
.toList());
|
.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setCurrentRolePermission(RoleDto roleDto, List<Record> roleResult) {
|
private void setCurrentRolePermission(RoleRespDto roleRespDto, List<Record> roleResult) {
|
||||||
if (roleResult.get(0).getValue(PERMISSION.ID) != null) {
|
if (roleResult.get(0).getValue(PERMISSION.ID) != null) {
|
||||||
roleResult.forEach(
|
roleResult.forEach(
|
||||||
(record) -> {
|
(record) -> {
|
||||||
PermissionRespDto permissionRespDto = createRbacDtoPermissionPart(record);
|
PermissionRespDto permissionRespDto = createRbacDtoPermissionPart(record);
|
||||||
roleDto.getPermissions().add(permissionRespDto);
|
roleRespDto.getPermissions().add(permissionRespDto);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,12 +217,12 @@ public class IdentityAccessService {
|
|||||||
return permissionRespDto;
|
return permissionRespDto;
|
||||||
}
|
}
|
||||||
|
|
||||||
private RoleDto createRbacDtoRolePart(List<Record> roleResult) {
|
private RoleRespDto createRbacDtoRolePart(List<Record> roleResult) {
|
||||||
RoleDto roleDto = new RoleDto();
|
RoleRespDto roleRespDto = new RoleRespDto();
|
||||||
roleDto.setId(roleResult.get(0).getValue(ROLE.ID));
|
roleRespDto.setId(roleResult.get(0).getValue(ROLE.ID));
|
||||||
roleDto.setCode(roleResult.get(0).getValue(ROLE.CODE));
|
roleRespDto.setCode(roleResult.get(0).getValue(ROLE.CODE));
|
||||||
roleDto.setName(roleResult.get(0).getValue(ROLE.NAME));
|
roleRespDto.setName(roleResult.get(0).getValue(ROLE.NAME));
|
||||||
return roleDto;
|
return roleRespDto;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRoleDuplicate(String roleCode, String name) {
|
public boolean isRoleDuplicate(String roleCode, String name) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user