基于ollama,langchain,springboot从零搭建知识库四【设计通用rag系统】
需求:
1:可以自定义管理大模型,可自行选择ollama,openai,千问等大模型
2:自定义向量数据库,支持pgvector,elasticsearch,milvus(这三个目前比较常用,且支持过滤元数据)
3:自定义管理知识库,知识库中可以支持创建文档,文档切片,修改切片,向量搜索等功能
4:系统可以根据不同的知识库检索用户需要的内容
表设计:
用户表:
CREATE TABLE `rag_user` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL COMMENT '用户名 ',
`password` varchar(255) NOT NULL COMMENT '用户密码',
`phone` varchar(15) NOT NULL COMMENT '用户手机号',
`cover` varchar(255) NOT NULL COMMENT '用户头像',
`status` tinyint NOT NULL COMMENT '用户状态0:不可用 1:可用',
`ctime` datetime DEFAULT NULL,
`utime` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`delete_flag` tinyint DEFAULT NULL,
`cby` tinyint DEFAULT NULL,
`uby` tinyint DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
模型表:
CREATE TABLE `rag_model` (
`id` bigint NOT NULL AUTO_INCREMENT,
`code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '唯一键(用于唯一确定bean)',
`model_name` varchar(255) NOT NULL COMMENT '模型名',
`type` varchar(10) NOT NULL COMMENT '类型(MODEL:模型 EMBEDDING:向量)',
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '名称',
`supplier` varchar(10) NOT NULL COMMENT '模型厂商 OLLAMA:ollama QWEN:千问 OPENAI:openAi',
`response_length` int DEFAULT NULL COMMENT '响应结果长度',
`temperature` double DEFAULT NULL COMMENT '温度',
`top` double DEFAULT NULL COMMENT '匹配数',
`api_key` varchar(255) DEFAULT NULL COMMENT '模型的key(ollama不需要)',
`secret_key` varchar(255) DEFAULT NULL COMMENT '模型secret',
`url` varchar(255) DEFAULT NULL COMMENT '模型url',
`dimensions` int DEFAULT NULL COMMENT '向量模型维度数',
`ctime` datetime DEFAULT NULL,
`utime` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`delete_flag` tinyint DEFAULT NULL COMMENT '是否删除 0:否 1:是',
`cby` bigint DEFAULT NULL COMMENT '创建人',
`uby` bigint DEFAULT NULL COMMENT '创建人',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
向量库表:
CREATE TABLE `rag_embedding_store` (
`id` bigint NOT NULL AUTO_INCREMENT,
`code` varchar(255) NOT NULL COMMENT '用于唯一确定bean',
`name` varchar(255) NOT NULL COMMENT '向量数据库名称',
`supplier` varchar(10) NOT NULL COMMENT '向量数据库类型(PG:pgvector , MILVUS:Milvus ES:Elasticsearch)',
`port` int NOT NULL COMMENT '端口号',
`host` varchar(255) NOT NULL COMMENT '数据库ip',
`user_name` varchar(255) NOT NULL COMMENT '用户名',
`password` varchar(255) NOT NULL COMMENT '密码',
`database` varchar(255) NOT NULL COMMENT '数据库名',
`table_name` varchar(255) NOT NULL COMMENT '表名',
`dimensions` int DEFAULT NULL COMMENT '向量维度',
`ctime` datetime DEFAULT NULL,
`utime` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`delete_flag` tinyint DEFAULT NULL,
`cby` bigint DEFAULT NULL,
`uby` bigint DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
知识库表:
CREATE TABLE `rag_knowledge` (
`id` bigint NOT NULL AUTO_INCREMENT,
`code` varchar(255) NOT NULL,
`embedding_store_id` bigint NOT NULL COMMENT '向量数据库id',
`embedding_model_id` bigint NOT NULL COMMENT '向量模型id',
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '知识库名称',
`descr` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '知识库描述',
`ctime` datetime DEFAULT NULL,
`utime` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP,
`delete_flag` tinyint NOT NULL,
`cby` bigint DEFAULT NULL,
`uby` bigint DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
文档表:
CREATE TABLE `rag_doc` (
`id` bigint NOT NULL AUTO_INCREMENT,
`code` varchar(255) NOT NULL,
`knowledge_id` bigint NOT NULL COMMENT '知识库id',
`name` varchar(255) NOT NULL COMMENT '文档名称',
`path` varchar(255) NOT NULL COMMENT '文档路径',
`url` varchar(255) NOT NULL COMMENT '文档url',
`source` tinyint NOT NULL COMMENT '0:本地上传 1:网页',
`size` int NOT NULL COMMENT '文档大小',
`slice_num` int DEFAULT NULL COMMENT '切片数',
`slice_status` tinyint DEFAULT NULL COMMENT '切片状态(0:未处理 , 1:已处理)',
`ctime` datetime DEFAULT NULL,
`utime` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`delete_flag` tinyint DEFAULT NULL,
`cby` tinyint DEFAULT NULL,
`uby` tinyint DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
会话表:
CREATE TABLE `rag_message` (
`id` bigint NOT NULL AUTO_INCREMENT,
`user_id` bigint NOT NULL,
`chat_id` bigint NOT NULL COMMENT '聊天id(每个会话一个id)',
`user_name` varchar(255) NOT NULL COMMENT '用户名',
`message` varchar(1000) DEFAULT NULL COMMENT '会话内容',
`knowledge_id` bigint DEFAULT NULL COMMENT '知识库id',
`model_id` bigint DEFAULT NULL COMMENT '模型id',
`tokens` int DEFAULT NULL COMMENT '消耗的token数',
`promote_tokens` int DEFAULT NULL COMMENT '请求token数',
`ctime` datetime DEFAULT NULL,
`utime` datetime DEFAULT NULL,
`delete_flag` tinyint DEFAULT NULL,
`cby` tinyint DEFAULT NULL,
`uby` tinyint DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
基础框架搭建:
pom依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>studyLlm</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>studyLlm</name>
<description>studyLlm</description>
<url/>
<properties>
<java.version>17</java.version>
<langchain4j.version>0.35.0</langchain4j.version>
<mybatis.plus.version>3.4.3</mybatis.plus.version>
<mysql.connector.version>8.0.17</mysql.connector.version>
<mapstruct.version>1.2.0.Final</mapstruct.version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- langchain4j -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-core</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-dashscope</artifactId>
<version>${langchain4j.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-redis</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-pgvector</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-embedding-store-filter-parser-sql</artifactId>
<version>${langchain4j.version}</version>
<exclusions>
<exclusion>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-document-parser-apache-tika</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-pgvector</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-ollama</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-reactor</artifactId>
<version>0.35.0</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>
<!-- end langchain4j -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<!--mybatis-plus 3.3.1.tmp-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis.plus.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-typehandlers-jsr310</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>3.8.7</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.connector.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
统一返回格式设置:
ResultEnum枚举
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 返回code枚举
* @author wang
*
*/
@Getter
@AllArgsConstructor
public enum ResultEnum {
// 成功
SUCCESS(200, "SUCCESS"),
// crud异常,4开头
BAD_REQUEST(400, "BAD_REQUEST"),
UN_AUTH(401, "UN_AUTH"),
// crud异常,5开头
// 默认错误
ERROR(500, "ERROR"),
DB_CONNECT_ERROR(501, "DB_CONNECT_ERROR")
;
private Integer code;
private String desc;
}
统一返回格式Result
import com.example.studyllm.enums.ResultEnum;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.io.Serializable;
/**
* 统一返回格式
* @author wang
* @param <T>
*/
@Slf4j
@Data
@JsonInclude(JsonInclude.Include.ALWAYS)
public final class Result<T> implements Serializable {
private static final long serialVersionUID = -5816713866887895850L;
/**
* 错误码
*/
/**
* 错误信息
*/
private String msg = null;
private Integer code = ResultEnum.ERROR.getCode();
private boolean success;
/**
* 返回结果实体
*/
private T data = null;
public Result() {
}
public Result(int code, String msg, T data, boolean success) {
this.code = code;
this.msg = msg;
this.data = data;
this.success = success;
}
public static <T> Result<T> error(String msg) {
log.debug("返回默认错误:, msg={}", msg);
return new Result<>(ResultEnum.ERROR.getCode(), msg, null,false);
}
public static <T> Result<T> error(){
return error(ResultEnum.ERROR.getDesc());
}
public static <T> Result<T> error(String msg , int code){
log.debug("返回默认错误:, msg={}", msg);
return new Result<>(code, msg, null,false);
}
public static Result<String> error(ResultEnum resultEnum) {
log.debug("返回错误:code={}, msg={}", resultEnum.getCode(), resultEnum.getDesc());
return new Result<>(resultEnum.getCode(), resultEnum.getDesc(), resultEnum.getDesc(),false);
}
public static <T> Result<T> error(ResultEnum resultEnum, String msg) {
log.debug("返回错误:code={}, msg={}", resultEnum.getCode(), msg);
return new Result<T>(resultEnum.getCode(), msg, null,false);
}
public static <T> Result<T> errorForData(ResultEnum resultEnum, T data) {
log.debug("返回错误:code={}, msg={}, data={}", resultEnum.getCode(), resultEnum.getDesc(), data);
return new Result<>(resultEnum.getCode(), resultEnum.getDesc(), data,false);
}
public static <T> Result<T> success(T data) {
return new Result<>(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getDesc(), data,true);
}
public static <T> Result<T> success(){
return new Result<>(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getDesc(),null,true);
}
}
统一异常:
业务异常类定义:
import com.example.studyllm.enums.ResultEnum;
import java.text.MessageFormat;
public class BusinessException extends RuntimeException {
private static final long serialVersionUID = 1L;
private Integer code;
private ResultEnum enumType;
public BusinessException(String msg) {
super(msg);
this.code = 500;
}
public BusinessException(Integer code , String msg){
super(msg);
this.code = code;
}
public BusinessException(ResultEnum baseEnumType) {
super(baseEnumType.getDesc());
this.code = baseEnumType.getCode();
this.enumType = baseEnumType;
}
public BusinessException(String msg, Object... arguments) {
super(MessageFormat.format(msg, arguments));
this.code = 500;
}
public BusinessException(ResultEnum baseEnumType, Object... arguments) {
super(MessageFormat.format(baseEnumType.getDesc(), arguments));
this.code = baseEnumType.getCode();
this.enumType = baseEnumType;
}
public ResultEnum getEnumType() {
return enumType;
}
public void setEnumType(ResultEnum enumType) {
this.enumType = enumType;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
}
统一异常处理类
import cn.hutool.core.util.StrUtil;
import com.example.studyllm.enums.ResultEnum;
import com.example.studyllm.vo.base.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.nio.file.AccessDeniedException;
import java.sql.SQLTransientConnectionException;
import java.util.List;
/**
* @author wk
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@Value("${spring.profiles.active:dev}")
private String active ;
/**
* 校验错误拦截处理
*
* @param exception 错误信息集合
* @return 错误信息
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.OK)
public Result<String> validationBodyException(MethodArgumentNotValidException exception) {
BindingResult result = exception.getBindingResult();
String message = "";
if (result.hasErrors()) {
List<ObjectError> errors = result.getAllErrors();
if (errors != null) {
errors.forEach(p -> {
FieldError fieldError = (FieldError) p;
log.error("Data check failure : object{" + fieldError.getObjectName() + "},field{" + fieldError.getField() +
"},errorMessage{" + fieldError.getDefaultMessage() + "}");
});
if (errors.size() > 0) {
FieldError fieldError = (FieldError) errors.get(0);
message = fieldError.getDefaultMessage();
}
}
}
return Result.error("".equals(message) ? "请填写正确信息" : message);
}
/**
* 业务错误拦截
* @param exception
* @return
*/
@ExceptionHandler(AccessDeniedException.class)
@ResponseStatus(HttpStatus.OK)
public Result<String> accessDeniedException(AccessDeniedException exception){
log.error("无权限访问:", exception);
return Result.error(ResultEnum.UN_AUTH);
}
/**
* 业务错误拦截
* @param exception
* @return
*/
@ExceptionHandler(BusinessException.class)
@ResponseStatus(HttpStatus.OK)
public Result<String> businessException(BusinessException exception){
if(exception.getEnumType()!=null){
return Result.error(exception.getEnumType().getDesc());
}
log.error("捕获业务异常:", exception);
if(StrUtil.isNotEmpty(exception.getMessage())){
return Result.error(exception.getMessage());
}
return Result.error();
}
/**
* IllegalArgumentException错误拦截
* @param exception
* @return
*/
@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(HttpStatus.OK)
public Result<String> illegalArgumentException(IllegalArgumentException exception){
log.error("捕获业务异常:", exception);
return Result.error(exception.getMessage());
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.OK)
public Result<String> exception(Exception exception){
log.error("globalException:", exception);
if(active.equals("dev")){
return Result.error();
}
return Result.error(exception.getMessage());
}
/**
* 拦截捕获 @RequestBody required=true 绑定请求参数异常
*
*/
@ExceptionHandler(value = HttpMessageNotReadableException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Result<String> validExceptionHandler(HttpMessageNotReadableException ex) {
log.error("", ex);
return Result.error(ResultEnum.BAD_REQUEST,ResultEnum.BAD_REQUEST.getDesc());
}
/**
* 拦截捕获 @RequestBody required=true 绑定请求参数异常
*
*/
@ExceptionHandler(value = BindException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Result<String> validExceptionHandler(BindException ex) {
log.error("", ex);
return Result.error(ResultEnum.BAD_REQUEST,ResultEnum.BAD_REQUEST.getDesc());
}
@ExceptionHandler(value = SQLTransientConnectionException.class)
@ResponseStatus(HttpStatus.OK)
public Result<String> cannotGetJdbcConnectionExceptionHandle(SQLTransientConnectionException ex){
log.error("", ex);
return Result.error(ResultEnum.DB_CONNECT_ERROR);
}
}
mybatis-plus配置:
自动填充设置(用户还没做,先写死返回1)
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.example.studyllm.constants.CommonConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.util.ClassUtils;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
/**
* MybatisPlus 自动填充配置
*
* @author L.cm
*/
@Slf4j
public class MybatisPlusMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.debug("mybatis plus start insert fill ....");
LocalDateTime now = LocalDateTime.now();
// 审计字段自动填充
fillValIfNullByName("ctime", now, metaObject, false);
fillValIfNullByName("utime", now, metaObject, false);
fillValIfNullByName("cby", getUserId(), metaObject, false);
fillValIfNullByName("uby", getUserId(), metaObject, false);
// 删除标记自动填充
fillValIfNullByName("deleteFlag", CommonConstant.UN_DELETE_FLAG, metaObject, false);
}
@Override
public void updateFill(MetaObject metaObject) {
log.debug("mybatis plus start update fill ....");
fillValIfNullByName("utime", LocalDateTime.now(), metaObject, false);
fillValIfNullByName("uby", getUserId(), metaObject, false);
}
/**
* 填充值,先判断是否有手动设置,优先手动设置的值,例如:job必须手动设置
* @param fieldName 属性名
* @param fieldVal 属性值
* @param metaObject MetaObject
* @param isCover 是否覆盖原有值,避免更新操作手动入参
*/
private static void fillValIfNullByName(String fieldName, Object fieldVal, MetaObject metaObject, boolean isCover) {
// 0. 如果填充值为空
if (fieldVal == null) {
return;
}
// 1. 没有 get 方法
if (!metaObject.hasSetter(fieldName)) {
return;
}
// 2. 如果用户有手动设置的值
Object userSetValue = metaObject.getValue(fieldName);
String setValueStr = StrUtil.str(userSetValue, Charset.defaultCharset());
if (StrUtil.isNotBlank(setValueStr) && !isCover) {
return;
}
// 3. field 类型相同时设置
Class<?> getterType = metaObject.getGetterType(fieldName);
if (ClassUtils.isAssignableValue(getterType, fieldVal)) {
metaObject.setValue(fieldName, fieldVal);
}
}
/**
* 获取 spring security 当前的用户名
* @return 当前用户名
*/
private Long getUserId() {
return 1L;
}
}
mybatis配置类
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.example.studyllm.constants.CommonConstant;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author kw
* @Description 集成mybatisplus,注意扫包这里规定好
*
*/
@Configuration
@Slf4j
public class MybatisPlusConfig implements ApplicationContextAware {
private ApplicationContext applicationContext ;
private final static Long MAX_LIMIT = Long.MAX_VALUE ;
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer scannerConfigurer = new MapperScannerConfigurer();
scannerConfigurer.setBasePackage("com.example.studyllm.mapper");
return scannerConfigurer;
}
@Bean
public GlobalConfig globalConfig() {
GlobalConfig globalConfig = new GlobalConfig();
GlobalConfig.DbConfig dbConfig = new GlobalConfig.DbConfig();
dbConfig.setLogicDeleteField("delFlag")
.setLogicDeleteValue(String.valueOf(CommonConstant.DELETED_FLAG))
.setLogicNotDeleteValue(String.valueOf(CommonConstant.UN_DELETE_FLAG));
globalConfig.setDbConfig(dbConfig);
return globalConfig;
}
/**
* 审计字段自动填充
* @return {@link MetaObjectHandler}
*/
@Bean
public MybatisPlusMetaObjectHandler mybatisPlusMetaObjectHandler() {
return new MybatisPlusMetaObjectHandler();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext ;
}
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
paginationInnerInterceptor.setMaxLimit(MAX_LIMIT);
//分页插件
interceptor.addInnerInterceptor(paginationInnerInterceptor);
return interceptor;
}
}
yml配置
server:
tomcat:
uri-encoding: utf-8
port: 8888
spring:
application:
name: studyllm
main:
allow-bean-definition-overriding: true
datasource:
driver-class-name: com.p6spy.engine.spy.P6SpyDriver
url: jdbc:p6spy:mysql://${MYSQL_URL:127.0.0.1:3306}/studyllm?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=Asia/Shanghai&autoReconnect=true&failOverReadOnly=false&rewriteBatchedStatements=true
username: ${MYSQL_USER_NAME:root}
password: ${MYSQL_PASSWORD:root}
type: com.zaxxer.hikari.HikariDataSource
hikari:
register-mbeans: true
# 最小连接
minimum-idle: 5
# 最大连接
maximum-pool-size: 10
# 自动提交
auto-commit: true
# 最大空闲时间
idle-timeout: 30000
# 连接池名称
pool-name: DatebookHikariCP
# 最大生命周期
max-lifetime: 900000
# 连接超时时间
connection-timeout: 30000
好了,简单的开发框架搭好了,写不动了。。。