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

Spring 开发,流程冗余

  •  1
     
  •   kachu673 · 2023-07-29 13:06:04 +08:00 · 7517 次点击
    这是一个创建于 485 天前的主题,其中的信息可能已经有所发展或是发生改变。

    使用 SpringBoot 开发项目,少不了要写 Controller 、Service 、Mapper ,虽然 MP 可以一定程度上简化后两者的开发,但必要时候仍要将三个过程全部走完。所以我想请教各位网友:

    1. 其他框架有没有简化这个步骤的?(我不在意代码的耦合,以及各种代码入侵)
    2. 能推荐一些快速开发的框架吗?
    3. 如果可以,我喜欢用 php 来开发(我觉得个人开发者掌握 php 是非常有必要的)
    4. 当然,使用 js 、python 、go 、cpp 的框架我也都可以接受。
    95 条回复    2024-04-30 12:39:24 +08:00
    Goooooos
        1
    Goooooos  
       2023-07-29 13:12:23 +08:00 via Android
    你不要 service 和 mapper 可以不写
    用 jdbctemplate 把逻辑和 sql 都写 controller 不就可以了吗
    leo97
        2
    leo97  
       2023-07-29 13:13:18 +08:00 via Android
    MP 是啥??
    kachu673
        3
    kachu673  
    OP
       2023-07-29 13:17:30 +08:00
    @leo97 MybatisPlus ,常见的单表操作全都包装好了,可以不写 Service 和 Mapper ,直接在 Controller 调包
    echo1937
        4
    echo1937  
       2023-07-29 13:18:51 +08:00
    你直接 Controller + JDBCTemplate 一把梭是完全可以的,
    依赖方面只需要 spring-webmvc + spring-jdbc 。
    kachu673
        5
    kachu673  
    OP
       2023-07-29 13:19:18 +08:00
    @Goooooos 这样也是可以的,但总觉得像个异类。我想找个框架使用的就是这种写法的。或者说我的这个想法有点不正常
    echo1937
        6
    echo1937  
       2023-07-29 13:21:12 +08:00
    然后需要什么自己搞一个工具类,类似 RedisUtils 、xxxxUtils 即可。
    codingadog
        7
    codingadog  
       2023-07-29 13:24:53 +08:00   ❤️ 5
    规范是约束团队开发的,毕竟技术水平残次不齐,规范可以让底线不那么低,增强代码的可维护性。

    个人项目想怎么整就怎么整。例如为什么有人总说 java 一堆 setter getter ?因为那是规范。个人项目直接全都 public 属性都行。
    j1132888093
        8
    j1132888093  
       2023-07-29 13:29:46 +08:00
    SpringBoot 也没要求你必须写 service mapper 啊,直接全部写 controller 里不就完了
    me1onsoda
        9
    me1onsoda  
       2023-07-29 13:32:52 +08:00
    当然可以啊,一个 controller 搞定整个项目都是可以的
    undeflife
        10
    undeflife  
       2023-07-29 13:33:14 +08:00
    jHipster
    ikas
        11
    ikas  
       2023-07-29 13:35:36 +08:00
    route().GET("/hello-world", request -> ServerResponse.ok().body("Hello World"))
    把所有代码都写到这里.多一个类都是多余
    😂
    version
        12
    version  
       2023-07-29 13:40:55 +08:00
    实际上看你用什么数据库...如果 mysql 那种老一套啥都改变不了.
    mongodb 推荐 nodejs 或者 deno 做基本业务够用快速..也不需要定义结构体
    pg 的可以查看下语言库好用不..最好直接能撸 原生的 sql 不要第三方 crud 转一层 DTO.到时候你很多特性和关联坑的很.不好扩展
    啥语言都可以不要 MVC 架构...都可以单例一个数据库连接实例..直接在 controller 下操作数据库
    justonelastdance
        13
    justonelastdance  
       2023-07-29 13:55:36 +08:00
    用的 nodejs 的 express
    zoharSoul
        14
    zoharSoul  
       2023-07-29 14:00:34 +08:00
    你不管用什么, 分层思想是少不了的
    magicfield
        15
    magicfield  
       2023-07-29 14:06:40 +08:00
    java 的各种规范框架本来就更适合团队开发,个人项目直接 controller 堆 shi 山都行。我写个人项目基本是 controller+单层 service ,不分 VOPODTO 不用 mapper 。至于更小的项目用 python+flask 轻量化写着也挺爽的。

    个人项目代码量大了后规范化感觉也还是重要的,否则想改动逻辑各种重复代码、没扩展接口的问题会搞的想死。

    不过 java 的确没啥特别好用的 ORM 啊
    linyuyizhizou
        16
    linyuyizhizou  
       2023-07-29 14:10:44 +08:00
    Rails:?
    teliang
        17
    teliang  
       2023-07-29 14:28:58 +08:00
    在 Spring 开发中,可能会存在一些流程冗余的情况,这可能是由于以下原因造成的:

    过度设计:在设计阶段,可能会为了应对未来的需求考虑过多,导致在实际开发中出现了冗余的流程。

    缺乏经验:缺乏经验的开发人员可能会使用不必要的流程来解决问题,从而导致冗余。

    历史遗留问题:某些代码可能是从早期的版本迁移过来的,而这些代码可能包含了过时的流程或者已经不再需要的流程。

    为了避免流程冗余,可以采取以下措施:

    简化设计:在设计阶段,尽可能避免过度设计,只考虑当前需要解决的问题,不要为未来可能出现的问题预留过多的设计空间。

    增加经验:对于缺乏经验的开发人员,可以通过培训和指导等方式提高他们的水平,使他们能够更加有效地解决问题。

    重构代码:对于历史遗留问题,可以通过重构代码来去除冗余的流程,使代码更加简洁和易于维护。

    自动化流程:对于一些重复性的流程,可以考虑将其自动化,通过工具和脚本来实现,从而减少人工操作的时间和成本。

    总之,避免流程冗余是一个持续不断的过程,需要开发人员不断地学习和改进自己的开发方法和理念。
    neptuno
        18
    neptuno  
       2023-07-29 14:33:25 +08:00 via iPhone
    直接 controller 调用 mapper 就好了呀,变通一下
    L0L
        19
    L0L  
       2023-07-29 15:32:48 +08:00
    Spring 本来是为了简化 J2EE 开发的,结果曾经的屠龙少年也慢慢变成了巨龙了
    bringyou
        20
    bringyou  
       2023-07-29 15:46:35 +08:00
    试试 spring data jpa 吧
    daimubai
        21
    daimubai  
       2023-07-29 16:39:26 +08:00
    自己的项目你想用啥就用啥,在团队中,“冗余”其实也是一种规范
    wellerman
        22
    wellerman  
       2023-07-29 17:22:36 +08:00
    用 MP 就和 PHP 之类的 MVC 框架没什么区别,只要 Controller + Service 就行,Service 就是 Model 。
    配合上代码生成,只要把表设计好,前端后端还有测试全部可以自动生成好。如果只是普通的 CRUD ,改都不用改,就能直接用。
    agagega
        23
    agagega  
       2023-07-29 17:34:57 +08:00 via iPhone
    Try Ruby on Rails
    chocotan
        24
    chocotan  
       2023-07-29 17:52:27 +08:00   ❤️ 2
    自己的项目不需要搞这么复杂,另外我自己是不会选择 mybatis 的,都是 jpa 定义好实体类,第一次运行就自动建好表了,增删改查也都有接口类直接实现就行。
    wxlwsy
        25
    wxlwsy  
       2023-07-29 18:19:57 +08:00
    没人逼你一定要用 coltroller 吧, 一个类一把梭也没有问题!!!
    zed1018
        26
    zed1018  
       2023-07-29 18:39:35 +08:00
    @chocotan JPA +1 ,我看到 xml 就生理不适
    LeegoYih
        27
    LeegoYih  
       2023-07-29 18:40:49 +08:00
    Spring 什么时候要求你这么写了
    chendy
        28
    chendy  
       2023-07-29 19:46:22 +08:00
    不是 springboot 开发项目,是一定规模的项目做好分层有利于维护
    所以如果项目很小,不考虑维护,自己随便玩,爱怎么写怎么写
    GeekSuPro
        29
    GeekSuPro  
       2023-07-29 19:49:41 +08:00
    试试 JFinal 框架?
    BeautifulSoap
        30
    BeautifulSoap  
       2023-07-29 19:58:42 +08:00
    其他语言里像 SpringBoot 这样把框架搞如此复杂的也是少数,基本大部分语言的框架都很简单,直接做 controller 战士就行(不考虑团队的话)

    python 的话有 flask
    go 的话 gin
    php 的话 laravel
    js/ts 的话 nestjs

    都是直接写个 router 然后直接就可以写 controller 了,你高兴的话请求结构都不用定理,直接 map 里取然后直接手拼 map 都行(不在乎维护性的话
    kongkongye
        31
    kongkongye  
       2023-07-29 19:59:02 +08:00 via iPhone
    事实上 copilot 或 openai 是可以根据上下文提示出来这种样板代码的,只是需要一点点提示,要是能做个工具自动提供那一点点提示,那就高效了
    BeautifulSoap
        32
    BeautifulSoap  
       2023-07-29 19:59:41 +08:00
    @BeautifulSoap 打错了,js/ts 上轻量化框架是 express
    volatileSpark
        33
    volatileSpark  
       2023-07-29 20:02:13 +08:00
    Spring 并没有这么要求,仅仅是大家延续了一项共识,即“约定大于配置”,所以做项目的时候,都是 controller+service+dao 分层设计。你自己做的时候,想怎么来都行,把所有服务都写在一个 controller 里面都没关系。
    lululau
        34
    lululau  
       2023-07-29 20:06:35 +08:00
    控制反转 是 人类公敌,Java 的 这套 八股式 框架 是 为 开发 所谓 企业级 应用 准备 的
    lanlanye
        35
    lanlanye  
       2023-07-29 20:09:54 +08:00 via iPhone   ❤️ 1
    需求简单的话,Ruby 的 RoR 或 Py 的 DRF 了解一下
    morebuff
        36
    morebuff  
       2023-07-29 21:11:43 +08:00
    看个人能力吧,没有强制使用任何规范,所有代码写到一个.java 文件都行
    lsls931011
        37
    lsls931011  
       2023-07-29 21:24:15 +08:00
    你们这些问题在我 PHP 眼中都不是事
    ApachW
        38
    ApachW  
       2023-07-29 21:40:19 +08:00
    mybatis-flex 好像有个 apt ,在编译期间生成 mapper ,service ,类似 lombok 注解生成 getter setter
    simenet
        39
    simenet  
       2023-07-29 21:41:36 +08:00
    python ????
    kachu673
        40
    kachu673  
    OP
       2023-07-29 22:17:05 +08:00
    @ApachW 我现在不是想简化 service 和 mapper ,我是想消灭这俩。因为不论怎么简化,遇到困难问题还是要写这俩东西
    EarthChild
        41
    EarthChild  
       2023-07-29 22:43:48 +08:00
    你用 magic-api 连 controller 都可以不要,面向 sql 编程……
    olaloong
        42
    olaloong  
       2023-07-29 22:44:07 +08:00 via Android   ❤️ 2
    @zed1018 jpa 太难用了,自动建的表字段顺序不按属性顺序按字母顺序,还不能改,贼膈应。复杂点的多对多关系都容易搞得一团乱,更别提查询带排序方法名又臭又长。稍微数据复杂点的项目都是一地鸡毛。比 go 的 gorm 差远了。
    反观 mybatis-plus ,建好表后从实体到 service 一键生成,各种操作 lambda query update 一把梭,crud 爽到飞起 -- 真非得写 xml 才能实现的操作,用 jpa 也做不了。
    shyangs
        43
    shyangs  
       2023-07-29 22:59:29 +08:00
    雖然 Java 做得到 ( Controller + JDBCTemplate 一把梭 ).

    但你如果想要的是隨手寫、不考慮維護的話,應該選動態、弱型別的語言,PHP 或 JS.
    NeroKamin
        44
    NeroKamin  
       2023-07-29 22:59:30 +08:00
    为什么一定要写 Service 和 mapper ?你就 controller 一把梭不就行了?这不就消灭了
    EminemW
        45
    EminemW  
       2023-07-29 23:08:16 +08:00
    这跟是不是 Spring 没关系。如果你接手过所有逻辑都写在 Crontroller 的项目,就能理解必要的逻辑分层是有好处的
    suyabgaran
        46
    suyabgaran  
       2023-07-29 23:26:24 +08:00
    @magicfield 😏JOOQ 不错噢
    awolf
        47
    awolf  
       2023-07-29 23:31:09 +08:00
    用什么 java ,启动还麻烦,直接 php
    chihiro2014
        48
    chihiro2014  
       2023-07-29 23:50:41 +08:00
    @olaloong jpa 也可以原生写 sql ,然后使用 projection 。其实很方便
    clf
        49
    clf  
       2023-07-29 23:52:49 +08:00
    直接 serverless 得了。

    这玩意存在是有意义的,统一的对外接口和不同的实现在很多项目里是很有必要的。
    olaloong
        50
    olaloong  
       2023-07-29 23:56:10 +08:00 via Android
    @chihiro2014 可以是可以,但总归是难受,还不如想 mybatis 写在 xml 里。至少 xml 里的 sql 格式是在的,注解里的 sql 换行都得字符串拼接,偶尔需要复制出来调试时很不方便。
    yuanxiaosong
        51
    yuanxiaosong  
       2023-07-30 00:28:55 +08:00   ❤️ 2
    看看我司的分层模型:
    filter -> controller -> application -> service -> manager -> dao

    filter:统一身份认证,公共参数处理,日志等;
    controller:对前端参数验证转换,mq 接收,新旧接口兼容,新旧参数兼容,响应结果按业务裁剪,有些接口 5 年没变过,业务都改了几轮了,调用那些老接口依旧不会报错;
    application:采用 ddd 模型后跨领域调用,mq 发送;
    service:领域内部业务,一般不互相调用,这里写纯粹的业务,最多就是调用 manager 获取数据或者操作数据,经常都是几百行的;
    manager:缓存,领域对象转多个关联表,调用远程服务,切换数据源,比如开始走数据库搜索,后期走 es 搜索,我记得我们最复杂的操作一次要修改接近 50 张表,不在这里的话,service 早疯了;
    dao:mysql ,es ,远程调用都在这一层;
    企业级开发就这么多层,上了微服务后会按照服务拆分,不要搞形式主义,看看每一层你有没有需求,没有需求可以直接砍掉,还有就是这个和 Spring 没啥关系,纯粹是设计的问题,个人开发就可以一层梭哈就行了。
    chihiro2014
        52
    chihiro2014  
       2023-07-30 01:14:15 +08:00
    @olaloong 换个思路啊。mp 固然有优势,但是 xml 格式让人头秃不是。你为什么不考虑尝试使用 freemaker 和 java 去写套 sql 解析模板。毕竟 orm 框架执行到最后都是 sql 。
    james122333
        53
    james122333  
       2023-07-30 01:30:29 +08:00 via Android
    自己写不然就换
    iintothewind
        54
    iintothewind  
       2023-07-30 02:01:52 +08:00
    上 netty, 自己写框架, 要灵活度有灵活度, 要性能有性能, 要编程效率有编程效率,
    前提是你自己玩, 或者你有能力强迫整个团队都陪你这么玩,
    chendy
        55
    chendy  
       2023-07-30 09:14:47 +08:00
    @kachu673 可以消灭,自己的东西 controller 一把梭都没问题,顶多东西复杂了之后改不动骂自己**
    evalcony
        56
    evalcony  
       2023-07-30 09:24:12 +08:00
    个人项目无所谓。
    而规范之所以是规范,是为了多人协作、复杂项目而生的。
    vincent7245
        57
    vincent7245  
       2023-07-30 09:44:25 +08:00
    不在意耦合,你就没必要用 java 了,java 复杂的设计模式就是给大型系统解耦用的
    rOrange
        58
    rOrange  
       2023-07-30 10:11:08 +08:00
    楼上说的 controller 一把梭真的假的😰
    zed1018
        59
    zed1018  
       2023-07-30 10:20:10 +08:00
    @olaloong

    > jpa 太难用了,自动建的表字段顺序不按属性顺序按字母顺序,还不能改,贼膈应。复杂点的多对多关系都容易搞得一团乱,

    建表字段顺序我并不 care 这里我就不讨论了,外键关系我们也从来不在数据库层面做。

    > 更别提查询带排序方法名又臭又长。稍微数据复杂点的项目都是一地鸡毛。比 go 的 gorm 差远了。

    JPA 里面自带一个 Example ,直接把对象丢进去,排序放 pageable 里进去,函数名就 findAll 就完了,不知道哪里又臭又长。我也不知道你要自己取名是有多难,是 @query 不能写吗

    > 真非得写 xml 才能实现的操作,用 jpa 也做不了。

    不懂 jpa 哪里做不了,是没有 querydsl 还是没有 JpaSpecification 。

    你说 mybatis 千好万好,只要他还是要用到 xml 我就恶心
    cs419
        60
    cs419  
       2023-07-30 11:33:02 +08:00
    只要你愿意 实体类也可以省
    都换成 list<map>
    甚至 sql 也让前端传 😂
    olaloong
        61
    olaloong  
       2023-07-30 13:44:24 +08:00 via Android
    @zed1018
    首先,最开始我说的是 mybatis-plus
    不知道你哪来的非得用到 xml 的刻板印象,我这几个 mybatis-plus 项目 crud 飞起也没写一个 xml 。
    已经 jpa example ,这玩意你真觉得好用?你要不要看看 mp 的 lambda query 怎么写的?
    olaloong
        62
    olaloong  
       2023-07-30 13:53:09 +08:00 via Android
    @zed1018 还有就是多对多关系 这个对于 orm 框架还是很重要的吧。比如用户和角色的多对多,但凡中间表需要多点内容,就得从 @ManyToMany 改成双向的 @OneToMany ,难写难看。前阵子像用 jpa 重构个 gorm 的 go 项目时被坑的要死。
    总不能只用 jpa 做单表查询吧?那也太菜了
    janus77
        63
    janus77  
       2023-07-30 15:48:45 +08:00
    就像一楼说的,你不喜欢可以不写,java 的规范就是这样,如果你不想遵守规范,那就不遵守,但是不要试图去找一个不遵守这种规范却又很“合理合法”的框架,来表达自己用 java 的正当性
    LongV2
        64
    LongV2  
       2023-07-30 16:34:09 +08:00
    分层又不是必须遵守的,你想省事,controller 里面把所有流程都写完也可以的。
    haolongsun
        65
    haolongsun  
       2023-07-30 16:34:41 +08:00
    我只能说 django 永远的神,拿来就是一把梭,当你还在写 sql ,苦苦分层的时候我已经写完 crud 下班了,快的一批,没规范和约定,只有业务,一个常见 crud 三行解决。
    haolongsun
        66
    haolongsun  
       2023-07-30 16:38:28 +08:00
    真的要懂设计哲学 过早优化是万恶之源 所以说我不推荐新手刚开始就学设计模式,设计模式都是在优化某个问题,你遇都没遇见过,谈何优化,遇到了再去优化。
    antipro
        67
    antipro  
       2023-07-30 17:36:33 +08:00 via Android
    你可以尝试下 javalin,一个轻量级框架.
    zed1018
        68
    zed1018  
       2023-07-30 21:20:06 +08:00
    @olaloong 1. 我不觉得 onetomany/ manytomany 有多难写难看,2. 不写外键关系不代表不能通过 query+自定义析构函数做多表查询,3. 我觉得你说的都对
    lyxeno
        69
    lyxeno  
       2023-07-31 08:59:51 +08:00
    你全写 Controller 里面也没关系的。但是代码会越堆越多
    miaotaizi
        70
    miaotaizi  
       2023-07-31 09:04:15 +08:00
    PHP 最好的语言, 别不服!
    dif
        71
    dif  
       2023-07-31 10:29:25 +08:00
    和 spring 没毛线关系。不写又不会报错。
    的确有些业务,其实 service 也只是 return 了 dao 的查询结果。甚至 controller 也只是简单的包装了一下 msg,code,data 而已。
    单绝大多数业务还是相对比较复杂的,分层是啰嗦了点,但后期好维护,多写两行代码两三个快捷键的事,这要嫌多,那就放弃 java ,去学别的语言的吧。
    chenzw2
        72
    chenzw2  
       2023-07-31 10:40:04 +08:00
    @Goooooos

    https://codegen.bqrdh.com/ > 用在线工具生成一下,提取自己需要的类,快速解决
    yule111222
        73
    yule111222  
       2023-07-31 11:40:24 +08:00
    这跟你用任何语言和框架都无关,不在意耦合度直接 controller 里面一把嗦就是了
    akyle
        74
    akyle  
       2023-07-31 12:48:27 +08:00
    可能要先该一下自己的不好习惯
    kisnows
        75
    kisnows  
       2023-07-31 13:22:33 +08:00
    想起来前段时间公司搞全栈培训,我们要用 sprintboot 这一套写一个简单的业务需求。
    过程中是真的感受到 java 的繁琐,框架的限定,要是换成 node 下的常见框架,真的是只需要用 1/5 的时间就能完成所有功能。
    lifespy
        76
    lifespy  
       2023-07-31 15:00:31 +08:00
    其实我最喜欢的是 php 里面的那种 new 一个对象,然后可以直接执行 save()方法保存,真的太方便了。
    这种的我好想在 quarkus 里面有个 orm 见过,其他的就没见过了
    iosyyy
        77
    iosyyy  
       2023-07-31 15:12:42 +08:00
    dao 层用 jpa 等 orm 替换 service 大多数情况下都没必要封装好工具类调用就行了 直接 controller 层可以考虑 Google 的 grpc 相比较自己完成 grpc 很多时候都会方便点 不过不建议多用
    burymme11
        78
    burymme11  
       2023-07-31 15:19:30 +08:00
    https://github.com/noear/solon 可以考虑下这个轻量级 java 开发框架。
    yolee599
        79
    yolee599  
       2023-07-31 15:41:01 +08:00
    我一度怀疑 javaer 做项目上来就是 spring 。之前让同事写一个嵌入式量产用的上位机,功能就是通过局域网接受机器发送出来的广播包,然后再根据广播包的 IP 再单播序列号到指定机器,实现序列号烧录,带 GUI 方便工人操作,TCP 通讯。然后做出来了,一看 spring + swing ,后面我自己用 c++ 重写了
    nerkeler
        80
    nerkeler  
       2023-07-31 16:21:59 +08:00
    Controller 和 service 、mapper 包括 entity 不都是个 java 文件,就是名字不一样而已,谁说非要都有,你 service 掉 contorller 也没谁说调不通,controller 引入个 service 难道就不是 “controller 这个实体类( entity)加了一个私有变量 service"?
    kachu673
        81
    kachu673  
    OP
       2023-07-31 19:02:54 +08:00
    @yolee599 是这样的,离开 spring ,他们大多连怎么管理包,怎么编译代码都不会
    bill110100
        82
    bill110100  
       2023-08-10 18:27:47 +08:00
    你个人开发想怎么干怎么干,团队就是要一定的规范,冗余,来规范不同水平的开发人员来达成近似水平的代码,以提高可维护性。
    chaleaochexist
        83
    chaleaochexist  
       213 天前
    @yuanxiaosong #51
    大佬请教一下 调用远程服务到底是在 DAO 层做还是在 manager 层做?
    两层都看到远程服务关键字了.
    chaleaochexist
        84
    chaleaochexist  
       213 天前
    @yuanxiaosong #51

    大佬你好啊, 我想请问:
    controller:mq 接收 是啥意思
    manager:我的个人理解就是面向对象的数据抽象, 可以带业务, 譬如 isSuperUser() {return True}
    dao:这一层是面向数据的抽象, 不带业务, 譬如远程调用的函数名和这个调用的 api 相关和业务无关. 数据库访问也只和数据有关, 譬如 getUserByRole("Super")

    我可以这么理解吗?
    yuanxiaosong
        85
    yuanxiaosong  
       213 天前   ❤️ 1
    @chaleaochexist
    mq 和 controller 平级,我们认为接收 mq 也是一种外部调用方式,可能开始我们写一个 controller 来接收请求,后来解耦了,直接在 mq 中新增一个接收消息就行了,service 不用做任何变更,甚至可以支持一部分请求调用 controller ,另一部分请求发送 mq 消息。

    dao 和 client 是平级,和你理解的差不多,可以简单理解 client 就是一个通过 http 通信的 db 数据库,调用接口获取一条数据和从数据库获取一条数据从上层来看没有区别;

    manager 只要是用来屏蔽数据存储层的实现的,可能我们数据来源有 db/redis/es/client ,比如我获取用户,manager 中先从 redis 中获取,如果 redis 中没有,再从 mysql 中获取,然后再存储到 redis ,最后再返回给 service ;再举个例子,我们一般是一个主表和 n 个关联表,每个表对应一个 dao ,我们比较大的业务对象要产生几十个关联表,会在 manager 中合并成一个 save 方法。service 能够专注于业务逻辑处理。
    chaleaochexist
        86
    chaleaochexist  
       212 天前
    @yuanxiaosong 谢谢大佬, 彻底理解了。
    还剩最后一个问题。
    manager 层方法的命名问题。
    譬如, 你们有没有类似这样的业务, 超级用户查询订单从主数据库读。 普通用户查询订单从 ES 读。
    这样 manager 就要写两个方法。
    query_order_by_superuser
    query_order_by_user
    这样的话 manager 的方法名里面还是体现了一点点业务。
    包括你说的 save 方法, 实际上也是带一点点业务。只不过这种业务是对客户不可见的。
    我可这么理解吗?

    补充, 昨天我担心 V2EX 上你看不见, 还搜索了以下你的 ID, 然后找到了疑似你的邮箱,***.hotmail.com
    给你发了邮件请教问题。 里面有一个红包, 聊表谢意。 (今天中午过期) 感谢大佬!!!
    yuanxiaosong
        87
    yuanxiaosong  
       210 天前   ❤️ 1
    @chaleaochexist 我这个 id 专门用来注册互联网用的,没有任何地方留有邮箱的。

    针对你这种情况,我们一般是这样写:listOrders(OrderQuery query, QueryType queryType),queryType 有两个值,实时查询/非实时查询,分别对应数据库/es ,manager 内部又有两个 私有 方法:listOrdersByDB ,listOrdersByES ,根据用户传入的 queryType 转调两个方法,这样就把业务屏蔽掉了,像你这种在方法命名上带业务,如果后期再来 N 角色,是不是要写 N 个方法?
    chaleaochexist
        88
    chaleaochexist  
       210 天前
    @yuanxiaosong 明白, 大佬能不能最后在举一个 manager save 的例子, 你说的 save 几十张关联表的 manager , 譬如 xxxmanager 中的 xxx 是什么?大概讲下业务逻辑和思路。谢谢!
    yuanxiaosong
        89
    yuanxiaosong  
       209 天前   ❤️ 1
    @chaleaochexist 举个例子,现在我要做一个员工管理功能,员工信息是一个大表单,用户基本信息:姓名,账号……,用户其他信息:任职部门(多个),岗位(多个),紧急联系人(多个),工作经历(多个)……,因为要支持任意关联属性实时搜索,所以一般都是 1 个主表+n 个关联表,大概有 UserDao/UserDeptDao/UserPositionDao/UserContactDao/UserEmployHistoryDao ,每次保存/修改都要调用这么多 dao ,还有就是如果是更新,还需要更新缓存,更新 es ,那么我有一个 UserManager.saveUser(UserDTO user),这个方法再调用 5 个 dao ,修改缓存/es ,上层的 service 方法就简单了,userManager.saveUser(user)即可,service 能够专注于处理业务逻辑,不关心数据存储,manager 关心数据存储,不关心业务逻辑,如果业务小体现不出来,像我们最多的一个主表对了 20 多个关联表,es ,redis ,es 都有,拆分了效果就很明显了。
    chaleaochexist
        90
    chaleaochexist  
       209 天前
    @yuanxiaosong
    那么是否可能存在一个 DepartmentManager 关联 UserDao, DepartmentDao, DepartmentAddressDao.
    我是想表达 一个 Dao 是否可能被多个 Manager 关联?
    yuanxiaosong
        91
    yuanxiaosong  
       209 天前
    @chaleaochexist 理论上一个 dao 不会被两个 manager 调用,这个就要从上层设计来说了,领域驱动设计(DDD)应该有了解吧,我们完整的领域对象应该包括了(属性+业务方法),大概是长这个样子:
    class User {

    }
    yuanxiaosong
        92
    yuanxiaosong  
       209 天前   ❤️ 1
    @chaleaochexist 理论上一个 dao 不会被两个 manager 调用,这个就要从上层设计来说了,领域驱动设计(DDD)应该有了解吧,我们完整的领域对象应该包括了(属性+业务方法),大概是长这个样子:
    class User {
    Long id;
    String name;

    void saveUser(){
    // so something
    userDao.saveUser();
    userDeptDao.saveUserDept();
    }
    }
    后来我们觉得应该职责分离,属性和方法分开,就变成了下面这种:
    class User{
    Long id;
    String name;
    }
    class UserService extends User {
    void saveUser(){
    // so something
    userDao.saveUser();
    userDeptDao.saveUserDept();
    }
    }
    再后来我们觉得方法还可以继续拆,分为业务方法和非业务方法:
    class UserManager extends User {
    void saveUser(){
    userDao.saveUser();
    userDeptDao.saveUserDept();
    }
    }
    class UserService extends UserManager {
    void saveUser(){
    // so something
    userManager.saveUser();
    }
    }
    看出来没有,我们所有的操作其实都围绕着 User 这个模型在工作,如果你有 UserAManager 和 UserBManager ,这两个都调用 UserDao 可以,但是你一个 DeptManager 调用 UserDao ,那就要考虑一下是不是你的模型设计有问题了?
    yuanxiaosong
        93
    yuanxiaosong  
       209 天前   ❤️ 1
    @chaleaochexist 比较有争议的是这种情况,UserDao/DeptDao/UserDeptDao ,UserDao 和 UserDeptDao 肯定是直接被 UserManager 引用,现在有个需求,在部门下有人的情况下,可以直接删除部门,删除部门后,需要将部门下的人员与部门关系解除,很多人就会这样写:
    class DeptManager{
    void deleteDept(id){
    deptDao.deleteById(id);
    userDeptDao.deleteByDeptId(id);
    }
    }
    实际上我们做法是这种;
    class DeptService{
    void deleteDept(id){
    deptManager.deleteById(id);
    userManger.deleteUserDeptByDeptId(id);
    }
    }
    由上层去协调,如果还有业务逻辑掺杂在里面,我们还有更上层的应用层去协调:
    class DeptApplication {
    void deleteDept(id){
    deptService.deleteById(id);
    userService.deleteUserDeptByDeptId(id);
    }
    }
    chaleaochexist
        94
    chaleaochexist  
       209 天前
    @yuanxiaosong
    谢谢, 浪费你这么多时间辛苦打字.

    UserDeptDao 在不考虑 es,缓存和 mq 的情况下, 无非就是一张关联表.
    我叫 UserDept 可以, 叫 DeptUser 其实也没毛病, 没有必要非要站在 User 的角度看问题.
    所以, 在实际项目中,是否这两个 Dao 同时存在?
    如果同时存在,我在 DeptManager 这个层面就可以解决问题.
    如果不同时存在, 这里要如何设计? 还是说无所谓如何设计? User 开头和 Dept 开头其实无所谓, 在 service 层协调一下就可以了? 但是这里会带来一个新问题 -- 就是 Dept 的删除要在 service 里面删, 但是 User 的删除在 manager 删就可以了.
    还是会带来一个分层不清的情况.
    以上是问题 1.

    问题 2, 我一直都搞不清楚, 什么叫业务,什么叫非业务, 目前的理解是, 使用者能看到的算业务, 看不到的算非业务.
    但是实际上上面提到的场景
    ```
    class DeptService{
    void deleteDept(id){
    deptManager.deleteById(id);
    userManger.deleteUserDeptByDeptId(id);
    }
    }
    ```
    这应该算用户看不到的场景, 但确实写到了 service 里面. 有些困惑.

    大佬我付费咨询吧 问题太多了, 浪费了你这么多时间.
    wechat aGh4eHR0eHNoc2hzaA==
    yuanxiaosong
        95
    yuanxiaosong  
       209 天前
    @chaleaochexist
    问题 1:在保证一个 dao 对应一个表(仅限增删改)的前提下,这个确实有很大的争论点,没有一个固定的答案,它可以叫 UserDept ,也可以 DeptUser ,但是在我看来,理论上只有一个存在,除非你底层用双向链表来维护(有两个数据库表),你用 User 打头,那么你潜意识就认为这个关联关系应该由 UserManager 来维护,反之亦然。
    继续问题 1:首先确定,Service 只和 Manager 打交道,类似于事件驱动,Service 会通知每一个 Manager ,我现在要删除一个部门了,真正的执行人是 Manager ,如果关联关系是 DeptManager 维护,那么它会删除 dept 表和 dept_user ,UserManager 说关联关系不是我维护的,我直接 return ,不做任何操作,反之亦然,删除这个工作并不是 service 来完成,真正的删除是在 UserManager 和 DeptManager 中,为什么只调用某个 manager 是我们很明确其他 manager 没有和部门发生关系而已。
    继续问题 1:我们目前使用一个原则来确认代码在那一层:是否抛出业务异常和 Manager 中一个方法只能对应一个动作(增/删/改)

    问题 2:来个简单粗暴的,直接调用 dao 的都在 manager 中,功能权限校验/参数校验/返回结果裁剪都在 controller 中,其他的都扔在 service 中就可以了,不要过多纠结,这个没有统一标准,写的多了自然就有经验了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2939 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 14:59 · PVG 22:59 · LAX 06:59 · JFK 09:59
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.