V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dssxzuxc
V2EX  ›  Java

附件系统应该怎么设计比较好?

  •  
  •   dssxzuxc ·
    jianxingxuejian · 2021-12-15 12:46:17 +08:00 · 4332 次点击
    这是一个创建于 1080 天前的主题,其中的信息可能已经有所发展或是发生改变。
    假如我有 20 张以上的业务表,每张表需要一个或多个附件字段,比如 xxx 信息表,有一个证明材料字段,有个验收材料字段,都是可以上传多个附件的。那我该怎么设计附件系统比较好?
    我的初步设想是,首先一个附件主表 file,一个附件从表 file_detail,一对多,从表存文件的路径和具体信息,每个业务表的附件字段存 file_id,这样就能关联起来。但是开发的时候又犯难了,上传的时候,我这么设计文件上传又没办法关联到业务表(上传和表单提交是分开的)。我想到文件上传之后,我把 file_id 返回给前端,前端提交表单再一起提交上来。但是这样又有新的问题,如果用户想要分次上传,比如两张图片,他先上传了 1 张,然后再传另 1 张,就会返回两个 file_id 过来。
    我看了公司之前有个项目也涉及到附件,他是这么做的,附件表每多一个业务表就加一个字段,20 张业务表就是 20 个 idxxx 、idxxx 这样的字段,上传的时候把自己的主键存到对应字段,不过这样没办法业务表多附件字段,除非 idxxx 字段加后缀接着细分,而且数据库一堆 null 有点蛋疼。
    各位有什么好的建议吗?
    32 条回复    2021-12-16 14:07:57 +08:00
    thinkershare
        1
    thinkershare  
       2021-12-15 13:28:23 +08:00   ❤️ 1
    这个问题不是很容易解决吗? 文件上传只做上传, 不要做任何逻辑就好了, 逻辑交给业务接口处理, 文件只返回临时存储的地址, 后面的文件上的业务由业务接口处理
    Ayanokouji
        2
    Ayanokouji  
       2021-12-15 13:38:11 +08:00
    minio
    eason1874
        3
    eason1874  
       2021-12-15 13:39:27 +08:00
    用户要填表,进入表单,你就初始化表单,就是往数据库插入一条空信息,返回业务 form_id 给前端(要检查有没有历史空表单,有应该直接返回或者删除后再创建,防止用户每次进入都创建一个空表单)

    用户填表时,单独上传文件,你连着表单名、字段名一起上传,成功写入文件后就把 file_id 关联到 form_id ,返回状态时也返回字段名,根据字段名填充 file_id 到表单,提交时再验证一下
    dssxzuxc
        4
    dssxzuxc  
    OP
       2021-12-15 16:09:51 +08:00
    @eason1874 这样能实现,但是流程一下子复杂了好多
    aliveyang
        5
    aliveyang  
       2021-12-15 16:37:18 +08:00
    业务表中为什么要有附件字段?不是一对多么
    xuelu520
        6
    xuelu520  
       2021-12-15 16:41:22 +08:00   ❤️ 1
    首先你想复杂了。
    1 、附件上传是独立的,存附件表信息,返回附件表的 id 。
    2 、可以弄个通用关联表
    例如:
    业务类型 业务类型 ID 附件类型 附件 ID
    A 业务 1 A1 file_id
    B 业务 2 B1 file_id

    这样就不用动到业务表那边去
    gengchun
        7
    gengchun  
       2021-12-15 16:47:38 +08:00
    @Ayanokouji OP 也没有提他用的是 S3 ,也没有提对象存储,也没有提自己做的是分布式应用。这是怎么联想到的?
    nekoneko
        8
    nekoneko  
       2021-12-15 17:22:12 +08:00
    字段给个数组类型不行吗?
    Mac
        9
    Mac  
       2021-12-15 17:34:10 +08:00
    是表设计还是存储设计?

    表就是简单的关联子表呗,分类完全可以用字段来替代,只记录上传后的文件名和上传者 ID ,文件直接放到存储目录下。

    存储设计我现在是用 /UPLOAD/上传人 /业务号 /随机文件名.xxx 来做存储的
    cp19890714
        10
    cp19890714  
       2021-12-15 17:37:07 +08:00
    ## 一张表即可

    `id`
    `batch_no`
    `file_name`
    `file_type`
    `file_size`
    `url`
    `business_type`
    `expire_at`
    `active_flag`
    `del_flag`


    ## interface

    //打开新的 BatchNo, 返回 batchNo
    openBatchNo

    //添加文件到 BatchNo, 返回所有文件的执行结果
    upload(String batchNo, List<File> files));

    //可多次 commit. 每次 commit,激活本次提交的 file,其他 file 失活
    commitBatchNo(String batchNo, List<String> fileIds)

    get(String batchNo);

    delete(String batchNO)


    ## 说明
    * 1 个 batchNo 可以添加多个 file
    * file 可以无限次的追加到已有的 BatchNo 中.
    * 通过 active_flag 实现事务,只有 commit 后,file 才有效. 无效的 file 会被定时删除.
    * 业务表使用 batchNo 关联
    zoharSoul
        11
    zoharSoul  
       2021-12-15 19:16:16 +08:00   ❤️ 1
    业务表直接存附件(文件)地址不完事了.
    弄个附件表干啥?
    fpure
        12
    fpure  
       2021-12-15 19:38:44 +08:00
    建议直接存成一个 json 到数据库里
    Huelse
        13
    Huelse  
       2021-12-15 19:59:24 +08:00
    我觉得怎么设计都是家常便饭,像提交表单一样,重要的是文件放在那里,建议一开始就做好独立存储的准备
    815979670
        14
    815979670  
       2021-12-15 20:06:08 +08:00
    一个附件表即可,附件表存储 附件 id ,附件路径,附件的业务表,关联业务 id 信息。
    第一步,图片上次成功,写入附件路径,得到附件 id ,返回给客户端。
    第二步,业务执行保存操作,根据附件 id 附件业务表明和业务 id 写回附件表。

    第一步实现了通用上传附件,第二部实现了附件的信息补全。

    最后做一个定时任务,当附件表的附件上传超过一定时间(如 24 小时),但是没有回写 业务 id 的就是脏数据(上传了福附件但是没有保存的),定时清除数据和对应文件。
    janus77
        15
    janus77  
       2021-12-15 20:31:30 +08:00
    附件只需要一张表,file 表就不要了,业务表就包含了 file 的功能。
    为什么业务表和附件表不能一对多?
    hingbong
        16
    hingbong  
       2021-12-15 21:16:37 +08:00 via Android
    MySQL blob 直接存😏
    Valid
        17
    Valid  
       2021-12-15 22:12:08 +08:00
    minio 直接用 s3 的 sdk
    dssxzuxc
        18
    dssxzuxc  
    OP
       2021-12-16 00:14:14 +08:00
    @nekoneko 那样展示整页的表单数据就有点麻烦了,每行的多个数组分别做一次查询?还是一次性把所有的数组合并然后查出所有的附件,然后再多次遍历放到各自的业务列表里去?
    857681664
        19
    857681664  
       2021-12-16 09:12:52 +08:00 via Android
    把附件信息以 json 数组的形式存进附件表,同时用 id 和 type 字段与相对应的业务表进行关联
    nekoneko
        20
    nekoneko  
       2021-12-16 10:34:04 +08:00
    @zoharSoul #11 附件删除了怎么办
    nekoneko
        21
    nekoneko  
       2021-12-16 10:35:49 +08:00
    @dssxzuxc #18 对呀
    nekoneko
        22
    nekoneko  
       2021-12-16 10:36:59 +08:00
    @zoharSoul #11 附件可能有上传者,上传时间等等信息,也就没了
    zoharSoul
        23
    zoharSoul  
       2021-12-16 10:37:42 +08:00
    @nekoneko #22 全追加到业务表上就行
    zoharSoul
        24
    zoharSoul  
       2021-12-16 10:38:10 +08:00
    @nekoneko #20 删除了就把业务表上的附件相关字段清掉啊
    nekoneko
        25
    nekoneko  
       2021-12-16 10:52:41 +08:00
    @zoharSoul #24 业务表只存了个地址,是要字符串匹配着清吗
    #23 那意思就是业务表存 json 呗
    nekoneko
        26
    nekoneko  
       2021-12-16 10:55:15 +08:00
    @zoharSoul #24 你可能看漏了,楼主说了每张表有多个附件字段,每个字段可以有多个附件,我感觉你理解成每个字段只有一个附件了
    zoharSoul
        27
    zoharSoul  
       2021-12-16 11:12:02 +08:00
    @nekoneko #26 嗯, 我的意思就是业务表存 json
    2i2Re2PLMaDnghL
        28
    2i2Re2PLMaDnghL  
       2021-12-16 11:31:50 +08:00
    『关系型数据库里的数组需要转置一下存成多条记录』
    (这是 RDBMS 还没几个数组类型的时候说的)

    一对多就是把关系倒转,是附件表里带业务表的 ID 。
    neptuno
        29
    neptuno  
       2021-12-16 11:44:28 +08:00 via iPhone
    上传文件是单独的功能,表单跟附件表可以一对多
    dssxzuxc
        30
    dssxzuxc  
    OP
       2021-12-16 12:40:46 +08:00
    @815979670 这个可行,附件表里加上业务 id 、业务表名、业务字段名 3 个字段,不过插入字段名只能用硬编码,查询 sql 也是用硬编码拼接,而这个字段名对于业务 entity 是多余的,因为业务表不存附件表信息,那这个字段名我只能放 vo 类里面,感觉后期维护容易写出 bug
    815979670
        31
    815979670  
       2021-12-16 13:42:42 +08:00
    @dssxzuxc 如果业务表不存附件信息的话,附件表必须存业务表名+业务 id 啊,不然怎么确定这个附件是属于那个业务表的?
    至于硬编码问题,如果你们对查询接口做了同意封装,应该可以通过传参 或者取表名的方式解决。
    unco020511
        32
    unco020511  
       2021-12-16 14:07:57 +08:00
    文件上传做成与业务无关的服务,后期管理和切换都方便.业务这边直接存文件 url 就行,有个表来关联 file 和业务 id,你想怎么对应都可以
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2558 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 01:31 · PVG 09:31 · LAX 17:31 · JFK 20:31
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.