Browse Source

数据库字段长文本存储

陈长荣 1 week ago
parent
commit
8e1b50a2db

+ 5 - 0
jfcloud-gene-biz/src/main/java/com/github/jfcloud/gene/file/service/FileInfoService.java

@@ -47,4 +47,9 @@ public interface FileInfoService extends IService<FileInfo> {
      * @return
      */
     FileDetail getFileSize(String url);
+
+    /**
+     * 获取文件流
+     */
+    InputStream getStreamByUrl(String url);
 }

+ 22 - 7
jfcloud-gene-biz/src/main/java/com/github/jfcloud/gene/file/service/impl/FileInfoServiceImpl.java

@@ -1,12 +1,14 @@
 package com.github.jfcloud.gene.file.service.impl;
 
 import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.io.IoUtil;
 import cn.hutool.core.io.unit.DataSizeUtil;
 import cn.hutool.core.lang.Assert;
 import cn.hutool.core.util.ReflectUtil;
 import cn.hutool.crypto.digest.DigestUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.amazonaws.services.s3.AmazonS3;
+import com.amazonaws.services.s3.model.S3Object;
 import com.amazonaws.services.s3.model.S3ObjectSummary;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -53,20 +55,17 @@ public class FileInfoServiceImpl extends ServiceImpl<FileInfoMapper, FileInfo> i
     public FileVo uploadFileWithFileName(InputStream fileInputStream, String fileName) {
         Assert.notNull(fileInputStream, "FileInputStream can not be null");
 
-        FileVo vo = new FileVo();
-        vo.setName(fileName);
+        String bucketName = ossProperties.getBucketName();
+        FileVo vo = new FileVo(bucketName, fileName);
 
         try {
-            String bucketName = ossProperties.getBucketName();
             fileTemplate.removeObject(bucketName, fileName);
             fileTemplate.putObject(bucketName, fileName, fileInputStream);
-
-            vo.setUrl(String.format("/admin/sys-file/%s/%s", bucketName, fileName));
+            return vo;
         } catch (Exception e) {
             log.error("上传失败", e);
-            Assert.isTrue(false, "附件生成上传失败");
+            throw new RuntimeException("附件生成上传失败");
         }
-        return vo;
     }
 
     @Override
@@ -124,4 +123,20 @@ public class FileInfoServiceImpl extends ServiceImpl<FileInfoMapper, FileInfo> i
         }
         return fileDetail;
     }
+
+    public InputStream getStreamByUrl(String url) {
+        url = url.replace("/admin/sys-file/", "");
+        String bucketName = url.substring(0, url.indexOf("/"));
+        String fileName = url.substring(url.indexOf("/") + 1);
+
+        //s3Object会自动关闭,所以需要复制流
+        try (S3Object s3Object = fileTemplate.getObject(bucketName, fileName);
+             ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+            IoUtil.copy(s3Object.getObjectContent(), out);
+            return new ByteArrayInputStream(out.toByteArray());
+        } catch (Exception e) {
+            log.error("文件读取异常: {}", e.getLocalizedMessage());
+        }
+        return null;
+    }
 }

+ 12 - 2
jfcloud-gene-biz/src/main/java/com/github/jfcloud/gene/file/vo/FileVo.java

@@ -1,14 +1,12 @@
 package com.github.jfcloud.gene.file.vo;
 
 import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
 @Data
 @Schema(description = "附件")
 @NoArgsConstructor
-@AllArgsConstructor
 public class FileVo {
 
     @Schema(description = "附件名称")
@@ -16,4 +14,16 @@ public class FileVo {
 
     @Schema(description = "附件链接")
     private String url;
+
+    @Schema(description = "附件存储桶名称")
+    private String bucketName;
+
+    private String bucketUrl;
+
+    public FileVo(String bucketName, String fileName) {
+        this.bucketName = bucketName;
+        this.name = fileName;
+        this.url = String.format("/admin/sys-file/%s/%s", bucketName, fileName);
+        this.bucketUrl = String.format("/%s/%s", bucketName, fileName);
+    }
 }

+ 99 - 0
jfcloud-gene-biz/src/main/java/com/github/jfcloud/gene/handler/LongTextHandler.java

@@ -0,0 +1,99 @@
+package com.github.jfcloud.gene.handler;
+
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.digest.DigestUtil;
+import com.github.jfcloud.common.core.util.SpringContextHolder;
+import com.github.jfcloud.gene.file.service.FileInfoService;
+import com.github.jfcloud.gene.file.vo.FileVo;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.type.JdbcType;
+import org.apache.ibatis.type.StringTypeHandler;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * 自定义长文本类型处理器,将长文本存储在minIO上
+ */
+@Slf4j
+public class LongTextHandler extends StringTypeHandler {
+
+    /**
+     * 长文本字段前缀
+     */
+    public static final String LONG_TEXT_FIELD_PREFIX = "@SampleLongText@";
+    public static final String FILE_PREFIX = "SampleLongText_Md5_";
+    /**
+     * 长文本字段最大长度,过短的文本没必要使用minIO
+     */
+    public static final int MAX_TEXT_LENGTH = 200;
+
+    @Override
+    public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
+        ps.setString(i, saveLongText(parameter));
+    }
+
+    @Override
+    public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
+        String textKey = super.getNullableResult(rs, columnName);
+        return getLongText(textKey);
+    }
+
+    @Override
+    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
+        String textKey = super.getNullableResult(rs, columnIndex);
+        return getLongText(textKey);
+    }
+
+    @Override
+    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
+        String textKey = super.getNullableResult(cs, columnIndex);
+        return getLongText(textKey);
+    }
+
+    /**
+     * 保存长文本
+     *
+     * @param text 长文本字符串
+     * @return 长文本key
+     */
+    private String saveLongText(String text) {
+        if (StrUtil.isBlank(text) || text.length() <= MAX_TEXT_LENGTH) {
+            return text;
+        }
+
+        try (ByteArrayInputStream bytesArrayInputStream = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8))) {
+
+            FileInfoService fileService = SpringContextHolder.getBean(FileInfoService.class);
+            FileVo fileVo = fileService.uploadFileWithFileName(bytesArrayInputStream,
+                    FILE_PREFIX + DigestUtil.md5Hex(text) + ".txt");
+            return LONG_TEXT_FIELD_PREFIX + fileVo.getBucketUrl();
+        } catch (IOException e) {
+            log.error("保存长文本失败", e);
+        }
+        return "";
+    }
+
+    /**
+     * 获取长文本
+     *
+     * @param textKey 长文本key
+     * @return 长文本字符串
+     */
+    public String getLongText(String textKey) {
+        if (StrUtil.isBlank(textKey) || !textKey.startsWith(LONG_TEXT_FIELD_PREFIX)) {
+            return textKey;
+        }
+
+        FileInfoService fileService = SpringContextHolder.getBean(FileInfoService.class);
+        InputStream inputStream = fileService.getStreamByUrl(textKey.substring(LONG_TEXT_FIELD_PREFIX.length() + 1));
+        return IoUtil.read(inputStream, StandardCharsets.UTF_8);
+    }
+}

+ 3 - 0
jfcloud-gene-biz/src/main/java/com/github/jfcloud/gene/sample/entity/InspectionCommission.java

@@ -1,8 +1,10 @@
 package com.github.jfcloud.gene.sample.entity;
 
 import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.github.jfcloud.gene.handler.LongTextHandler;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
@@ -52,5 +54,6 @@ public class InspectionCommission extends Model {
     private LocalDate submitDate;
 
     @Schema(description = "扩展字段")
+    @TableField(typeHandler = LongTextHandler.class)
     private String ext;
 }

+ 5 - 0
jfcloud-gene-biz/src/main/java/com/github/jfcloud/gene/sample/entity/SampleAnimal.java

@@ -1,6 +1,8 @@
 package com.github.jfcloud.gene.sample.entity;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.github.jfcloud.gene.common.entity.BaseEntity;
+import com.github.jfcloud.gene.handler.LongTextHandler;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
@@ -41,12 +43,15 @@ public class SampleAnimal extends BaseEntity {
     private String piOffice;
 
     @Schema(description = "前期实验结果补充说明")
+    @TableField(value = "preliminary_notes", typeHandler = LongTextHandler.class)
     private String preliminaryNotes;
 
     @Schema(description = "检测指标及样本数")
+    @TableField(value = "detection_parameters", typeHandler = LongTextHandler.class)
     private String detectionParameters;
 
     @Schema(description = "特殊检测指标及样本数")
+    @TableField(value = "special_detection_parameters", typeHandler = LongTextHandler.class)
     private String specialDetectionParameters;
 
     @Schema(description = "送检样本总数量")