当前位置: 首页 > article >正文

基于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

好了,简单的开发框架搭好了,写不动了。。。


http://www.kler.cn/a/516758.html

相关文章:

  • Scade 表达式 - 使用索引的迭代器
  • C#AWS signatureV4对接Amazon接口
  • 【C语言】预处理详解
  • .Net Core微服务入门全纪录(四)——Ocelot-API网关(上)
  • SecureUtil.aes数据加密工具类
  • Java操作Excel导入导出——POI、Hutool、EasyExcel
  • 掌握Spring事务隔离级别,提升并发处理能力
  • element-plus 的table section如何实现单选
  • 亚博microros小车-原生ubuntu支持系列:6-整体检测
  • Android SystemUI——快捷面板的创建(十四)
  • 禁止 iOS 系统浏览器双指放大页面
  • blender 安装笔记 linux 2025
  • 56.命令绑定 C#例子 WPF例子
  • (DM)达梦数据库基本操作(持续更新)
  • Springboot使用war启动的配置
  • 知识图谱结合大模型用于聊天分析
  • excel批量提取批注
  • c# 打印字符串
  • 迅为RK3568开发板篇OpenHarmony实操HDF驱动控制LED-添加内核编译
  • C语言常用知识结构深入学习
  • vue项目的创建
  • GPU算力平台|在GPU算力平台部署MedicalGPT医疗大模型的应用教程
  • MyBatis最佳实践:MyBatis 框架的缓存
  • 3、搭建企业知识库:从需求分析到方案设计
  • 配电网的自动化和智能化水平介绍
  • Python中使用Ollama API