如何搭建合适的Web框架?(web搭建教程)
ccwgpt 2024-11-12 09:48 20 浏览 0 评论
之前在Web开发框架推导一文中我们一步步的搭建了一个开发框架。
在当时的情况下,还算满足需求。但是随着项目的逐渐完善,需求变更的频度逐渐变得比新增需求的频度高,原来框架的弊端越来越明显,所以需要对框架进行升级改进。
我们先来看原来框架的问题,然后基于这些问题,来对框架进行改进。
原框架的问题
- 代码生成问题
- 参数传递问题
- Service层问题
- 测试依赖问题
- Mapper.xml的问题
代码生成问题
在原框架中,我们基于各种约束,编写了一个代码生成组件,通过这个组件,我们可以针对选中的表来生成Controller,Service,Model,Mapper等一系列的类,也就是说,只要建完表,就可以直接生成一套CRUD,直接就可以启动并测试。这在项目初期看起来很美,但是在需求变动时,还是有很多的局限性。
首先,生成的代码逻辑是固化的。如果稍微有些调整,就需要调整生成代码的组件,然后重新打包,上传到jar仓库,项目修改组件版本,再进行代码生成,整个流程过于繁琐。
其次,为了方便代码的生成,其实是做了不少妥协的:
- 为了方便在修改表字段以后,能够重新生成,很多类都抽象了一个基类用于操作Model字段。这些基类不能够手动修改,因为每次生成都会覆盖。这实际导致了类的数量的增多。
- 生成的CRUD固化了,不能手动调整。如果生成的CRUD不满足需求,不能直接在代码上修改。只能拷贝一份进行修改,因为再次生成时会覆盖。这导致了代码的冗余。
- Param和Result委托了Model,这在Model发生改变时,能在编译期就能知道对应字段的调整。但是也引入了不少问题,我们在「参数传递问题」一节单独讨论。
参数传递问题
当初为了便于代码的生成,决定Param和Result都继承Model,这导致了如下的一些问题:
- 使得Param和Result都依赖了Model。但是Param和Result是视图层模型,而Model是持久层模型,两者的进化度并不是一致的。但是现在的继承关系导致了在默认情况下视图层模型的进化需要和持久层同步,当然你也可以手动调整Param和Result,但是这又导致了代码生成的优势没有了。
- Param和Result通过委托的方式来设置字段,也就是说,它们实际是没有字段的,通过getter和setter将值设置到了Model中。这就没法使用lombok来简化getter和setter,使得Param和Result代码行数较多
- 同时,对于swagger来说,有些注解需要基于字段,导致某些功能无法实现(例如:ModelAttribute),只能基于额外手段来处理(例如:需要通过ApiImplicitParams来实现字段文档)。
- CRUD都是基于同一个Param和Result,导致前端的接口会显示很多无用的字段,加大前端理解接口的难度
Service层问题
Service层有如下问题:
- Service层的职责过重,包括了事务处理、参数设置、业务逻辑
- 导致Service中的代码是面条代码,不利于业务逻辑的理解
- 同时事务注解是直接加在类上的,Spring的默认事务机制会导致类似如下代码的逻辑调用不会抛出期望的异常
// PostService public String savePost(Post post) { postRepository.save(post); for(PostDiscuss discuss : post.getDiscuss()) { // 这里是抓不到RuntimeException异常的,会是一个TransactionRollBack的异常 discussService.save(discuss); } } // discussService public String savePost(PostDiscuss discuss) { throw new RuntimeException("保存失败"); }
测试依赖问题
核心的业务逻辑在Service中,测试还是需要依赖于Spring,当项目越来越大时,启动项目的时间越来越长,可能要1分钟甚至更长。这就导致单元测试效率越来越低。
Mapper.xml的问题
在面试的时候,我经常会问下面的一些问题:
- Java里面接口的作用是什么?
- Service、DAO为什么要编写接口,再去实现这个接口?
- 接口和实现在相同的模块下,反正都要重新打包的。多写个接口不是多写了好几行代码吗?
- 和上面类似的问题,Mybatis里面,声称将sql独立到了Mapper.xml文件中,使得可以不需要编译直接修改sql。但Mapper.xml都是和Class放在一起的,改了还是需要重新打包,而且Mybatis是不能动态加载Mapper.xml的,那把sql独立到XML里,到底有什么优势?
对于最后一个问题,我的答案是,对于大部分项目来说,没什么优势!项目易不易于部署、扩展,不在于你使用的框架,而在于你的设计。
就以Mapper.xml来说,Mybatis将sql与代码分离了,但是你在项目里还是将Mapper.xml和代码放在同一个模块下,那这个优势就没有了。既然没有这个优势,我们还有必要单独写Mapper.xml文件吗?我的选择是,那就不写了,直接使用Mybatis提供的注解。
同时为了解决Service层对DAO层(这里也就是对Mybatis)的强依赖,对框架进行了一些改进,解耦Service和DAO层。具体见下面的改进方案。
框架改进方案
为了解决上面这些问题,对框架进行了如下调整:
- 分离Param、Result和Model
- 替换代码生成
- 独立业务逻辑
- Model层优化
分离Param、Result和Model
上面已经提到了Param、Result和Model强耦合会有很多问题,所以这里就将Param、Result和Model分离开。每个都是独立的Bean,这就解决了上面几个问题。但是引入了两个新问题:
- 首先,很明显的,增加了手动编码的量。当一个表修改了字段,需要修改三个类甚至更多的类
- 其次,增加了数据传递之间的代码。即Param传递到Model,需要对字段赋值。如果一个字段一个字段的设值,会增加很多无聊的代码。而使用反射的话会对性能有一些影响
那如何解决这两个问题呢?首先,纯手撸肯定是不可能的。需要提供一些自动化手段。
对于赋值来说,Spring提供了BeanUtils来简化处理,虽然是基于反射来设值的,但是对于现阶段来说,这点性能损耗还是没什么影响的。但是,BeanUtils对于不同类型的属性不能进行拷贝,假设我有一个Domain对象Book,里面有个字段Author,现在我要赋值给BookResult,其中有个字段AuthorResult,此时BeanUtils是无法赋值的。所以我编写了一个基于Gson的工具类来处理,性能测试10000次的属性拷贝BeanUtils需要500多毫秒,基于Gson的工具类只需要300毫秒左右。
对于表字段的生成,如果使用的是IDEA的话,IDE默认提供了一个脚本,可以从表来生成POJO!我们可以使用这个脚本来生成Model,然后将字段拷贝到Param和Result中,来简化字段的编写。我对这个脚本进行了修改,以符合项目需求。主要增加了lombok的支持,新增了类注释和字段注释。
替换代码生成
对于上面代码生成组件的问题,我调整了代码生成的方式。不再基于组件来生成,而是基于IDEA本身的FileTemplate、LiveTemplate以及Scripted Extensions来进行生成。虽然这样的方式,不能够一次性生成多个文件,但是由于生成逻辑基本是一次性的,所以影响不是很大。在初次生成代码时,代码生成组件的效率是高于FileTemplate、LiveTemplate以及Scripted Extensions的组合,但是后期调整的灵活性,明显是FileTemplate、LiveTemplate以及Scripted Extensions的组合要高于代码生成组件的:
- 首先,当文件结构调整时,只需要修改FileTemplate,并将配置文件导出给项目组成员即可。
- 同样的,当LiveTemplate调整时,也只需要修改对应的LiveTemplate,并将配置文件导出给项目组成员即可。
- 其次,想生成哪个文件,只要针对这个文件生成即可
- 第三,通过FileTemplate生成完整的文件后,可以通过LiveTemplate快速的进行模块化的编码
- 最后,FileTemplate可以设置为项目级别,即每个项目可以有独立的FileTemplate
具体的操作流程,在下面演示。
独立业务逻辑
针对Service和测试的问题,将原来的Controller、Service和Model三层,拆分为四层:
- Controller负责前端数据的接收和返回,以及统一异常处理
- Service负责事务以及Domain层逻辑的组装。这里就不会出现事务嵌套问题,也就不会导致抓不到期望的异常的问题
- Domain负责业务逻辑
- Model负责数据持久
这样Service的职责减轻了,同时不再有事务嵌套的问题。
Model层优化
上面提到,框架中最终放弃了Mapper.xml,转而使用Mybatis的注解来实现持久化操作。改用注解,规避了XML代码的编写,但是并没有解决框架对Mybatis的强依赖。所以这里在Domain中新增了Repository接口层,此层用于定义Domain的持久化操作,而Model层中对Repository进行实现,这里的实现就是Mybatis实现。这样做有两个好处:
- 依赖倒置:原来是Domain依赖Model层,而现在是Model层依赖Domain层,这样当我要把Mybatis替换掉时,Domain完全无感知。
- 独立测试:因为现在Domain不依赖于其它任何层,所以可以脱离数据库和容器来进行测试。使得测试的效率不会随着项目的开发而越来越低
框架改进细节
现在已经知道了,如何对框架进行改进,我们现在就开始着手进行改造。其实主要的改造是对代码生成方式的改造,也就是编写FileTemplate、LiveTemplate和ScriptedExtensions。下面对这三个功能进行简单的说明,先说ScriptedExtensions。
Scripted Extensions
先来解释一下,什么是Scripted Extensions。我们都知道,现在的IDE都是插件式的,也就是说,我们可以通过开发商提供的插件开发包来开发插件,扩展现有的IDE功能。但是编写插件需要特定的开发环境,如果是一个很简单的功能,还要费劲去搭开发环境,挺麻烦的。所以IDEA提供了Scripted Extensions,可以理解为一个简化版的插件,就是可以通过脚本来扩展IDE功能。
IDEA提供了Database功能,可以连接数据库进行相关操作。当你连接了数据库,在表上右击时,可以看到Scripted Extensions这个选项,里面有一个功能是可以基于表来生成POJO的groovy脚本。
但是功能比较low:
- 包名是写死的:com.sample
- 没有生成table注释
- 没有基于lombok来简化getter和setter
不过好在,我们能基于这个脚本来自行修改,在刚才的Scripted Extensions菜单里,有个Go to Scripts Directory选项,点击后,可以进入脚本目录。
直接对这个groovy文件Ctrl+c,Ctrl-v,复制一份,重命名一下,基于这个脚本进行修改即可。具体怎么修改,按照自己的需求来,里面主要就是根据表信息对String的拼接而已。
FileTemplate
FileTemplate是IDEA提供的生成文件的模板,你在点击菜单的File->New...以后,出现的各种文件,都是基于FileTemplate来实现的。我们自定义的Controller、Service、Domain等类,都可以通过FileTemplate来简化创建。
具体使用方式为,按下Ctrl-Alt-S呼出设置菜单,点击Editor->File And Code Template,在里面新增Template即可。
几点说明:
- 下面的描述中列出了默认的一些参数以及作用
- 你也可以自定义变量,自定义的变量如果没有赋值,在创建时会有输入框提示输入内容
- 模板是基于Velocity的,所以如果你熟悉 Velocity,那就可以直接上手
- Enable Live Template选项是在FileTemplate激活LiveTemplate变量,不过需要使用#[[]]#包裹。但是对于创建Java,这个功能有bug,并不能定位到需要的位置,所以暂时没使用
创建完成后,就可以在New菜单中看到这个模板了。
LiveTemplate
LiveTemplate实际就是CodeSnippet。创建方式和FileTemplate类似。按下Ctrl-Alt-S呼出设置菜单,点击Editor->Live Template,在里面新增Template即可。
几点说明:
- 这里的变量是使用$包裹
- 每个变量就是一个占位符,在使用tab展开后,可以手动输入值
- 右下角的Edit variables,用于对变量赋值,IDEA提供了一些方法、也可以设置默认值
- 下面的change链接,可以选择LiveTemplate生效的位置,比如只在Java类声明处生效
编码流程
创建了上面的几个模板后,编码流程如下:
- 在表上右击,通过Scripted Extensions来生成Model
- 通过FileTemplate来快速生成Controller、Service、Domain等类
- 通过LiveTemplate来快速编写代码
总结
本文通过对原框架问题的梳理及解决,来对框架进行升级改造,以适应项目的发展和推进。
相关推荐
- 详解DNFSB2毒王的各种改动以及大概的加点框架
-
首先附上改动部分,然后逐项分析第一个,毒攻掌握技能意思是力量智力差距超过15%的话差距会被强行缩小到15%,差距不到15%则无效。举例:2000力量,1650智力,2000*0.85=1700,则智力...
- 通篇干货!纵观 PolarDB-X 并行计算框架
-
作者:玄弟七锋PolarDB-X面向HTAP的混合执行器一文详细说明了PolarDB-X执行器设计的初衷,其初衷一直是致力于为PolarDB-X注入并行计算的能力,兼顾TP和AP场景,逐渐...
- 字节新推理模型逆袭DeepSeek,200B参数战胜671B,豆包史诗级加强
-
梦晨发自凹非寺量子位|公众号QbitAI字节最新深度思考模型,在数学、代码等多项推理任务中超过DeepSeek-R1了?而且参数规模更小。同样是MoE架构,字节新模型Seed-Thinkin...
- 阿里智能化研发起飞!RTP-LLM 实现 Cursor AI 1000 token/s 推理技术揭秘
-
作者|赵骁勇阿里巴巴智能引擎事业部审校|刘侃,KittyRTP-LLM是阿里巴巴大模型预测团队开发的高性能LLM推理加速引擎。它在阿里巴巴集团内广泛应用,支撑着淘宝、天猫、高德、饿...
- 多功能高校校园小程序/校园生活娱乐社交管理小程序/校园系统源码
-
校园系统通常是为学校、学生和教职工提供便捷的数字化管理工具。综合性社交大学校园小程序源码:同城校园小程序-大学校园圈子创业分享,校园趣事,同校跑腿交友综合性论坛。小程序系统基于TP6+Uni-app...
- 婚恋交友系统nuiAPP前端解决上传视频模糊的问题
-
婚恋交友系统-打造您的专属婚恋交友平台系统基于TP6+Uni-app框架开发;客户移动端采用uni-app开发,管理后台TH6开发支持微信公众号端、微信小程序端、H5端、PC端多端账号同步,可快速打包...
- 已节省数百万GPU小时!字节再砍MoE训练成本,核心代码全开源
-
COMET团队投稿量子位|公众号QbitAI字节对MoE模型训练成本再砍一刀,成本可节省40%!刚刚,豆包大模型团队在GitHub上开源了叫做COMET的MoE优化技术。COMET已应用于字节...
- 通用电气完成XA102发动机详细设计审查 将为第六代战斗机提供动力
-
2025年2月19日,美国通用电气航空航天公司(隶属于通用电气公司)宣布,已经完成了“下一代自适应推进系统”(NGAP)计划下提供的XA102自适应变循环发动机的详细设计审查阶段。XA102是通用电气...
- tpxm-19双相钢材质(双相钢f60材质)
-
TPXM-19双相钢是一种特殊的钢材,其独特的化学成分、机械性能以及广泛的应用场景使其在各行业中占有独特的地位。以下是对TPXM-19双相钢的详细介绍。**化学成分**TPXM-19双相钢的主要化学成...
- thinkphp6里怎么给layui数据表格输送数据接口
-
layui官网已经下架了,但是产品还是可以使用。今天一个朋友问我怎么给layui数据表格发送数据接口,当然他是学前端的,后端不怎么懂,自学了tp框架问我怎么调用。其实官方文档上就有相应的数据格式,js...
- 完美可用的全媒体广告精准营销服务平台PHP源码
-
今天测试了一套php开发的企业网站展示平台,还是非常不错的,下面来给大家说一下这套系统。1、系统架构这是一套基于ThinkPHP框架开发的HTML5响应式全媒体广告精准营销服务平台PHP源码。现在基于...
- 一对一源码开发,九大方面完善基础架构
-
以往的直播大多数都是一对多进行直播社交,弊端在于不能满足到每个用户的需求,会降低软件的体验感。伴随着用户需求量的增加,一对一直播源码开始出现。一个完整的一对一直播流程即主播发起直播→观看进入房间观看→...
- Int J Biol Macromol .|交联酶聚集体在分级共价有机骨架上的固定化:用于卤代醇不对称合成的高稳定酶纳米反应器
-
大家好,今天推送的文章发表在InternationalJournalofBiologicalMacromolecules上的“Immobilizationofcross-linkeden...
- 【推荐】一款开源免费的 ChatGPT 聊天管理系统,支持PC、H5等多端
-
如果您对源码&技术感兴趣,请点赞+收藏+转发+关注,大家的支持是我分享最大的动力!!!项目介绍GPTCMS是一款开源且免费(基于GPL-3.0协议开源)的ChatGPT聊天管理系统,它基于先进的GPT...
- 高性能计算(HPC)分布式训练:训练框架、混合精度、计算图优化
-
在深度学习模型愈发庞大的今天,分布式训练、高效计算和资源优化已成为AI开发者的必修课。本文将从数据并行vs模型并行、主流训练框架(如PyTorchDDP、DeepSpeed)、混合精度训练(...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- 详解DNFSB2毒王的各种改动以及大概的加点框架
- 通篇干货!纵观 PolarDB-X 并行计算框架
- 字节新推理模型逆袭DeepSeek,200B参数战胜671B,豆包史诗级加强
- 阿里智能化研发起飞!RTP-LLM 实现 Cursor AI 1000 token/s 推理技术揭秘
- 多功能高校校园小程序/校园生活娱乐社交管理小程序/校园系统源码
- 婚恋交友系统nuiAPP前端解决上传视频模糊的问题
- 已节省数百万GPU小时!字节再砍MoE训练成本,核心代码全开源
- 通用电气完成XA102发动机详细设计审查 将为第六代战斗机提供动力
- tpxm-19双相钢材质(双相钢f60材质)
- thinkphp6里怎么给layui数据表格输送数据接口
- 标签列表
-
- MVC框架 (46)
- spring框架 (46)
- 框架图 (58)
- bootstrap框架 (43)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- jpa框架 (47)
- laravel框架 (46)
- express框架 (43)
- springmvc框架 (49)
- 分布式事务框架 (65)
- scrapy框架 (52)
- java框架spring (43)
- grpc框架 (55)
- orm框架有哪些 (43)
- ppt框架 (48)
- 内联框架 (52)
- winform框架 (46)
- gui框架 (44)
- cad怎么画框架 (58)
- ps怎么画框架 (47)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)
- oracle提交事务 (47)