关于mvc:从MVC到DDD该如何下手重构

作者:付政委 博客:bugstack.cn 积淀、分享、成长,让本人和别人都能有所播种!大家好,我是技术UP主小傅哥。MVC解说了,DDD解说了。接下来这个章节,咱们讲讲从MVC到DDD的重构! MVC 旧工程腐化重大,迭代老本太高。DDD 新工程全副重构,步子扯的太大。 这是现阶段在工程体系化治理中,咱们所面临的最大问题;既想使用 DDD 的思维循序渐进重构现有工程,又想不毁坏原有的工程体系结构以放弃新需要的承接效率。 通过实际得悉,DDD 架构能解决,现阶段 MVC 贫血构造中所遇到的泛滥问题。 家喻户晓,MVC 分层构造是一种贫血模型设计,它将”状态“和”行为“拆散到不同的包构造中进行开发应用。domain 里写 po、vo、enum 对象,service 里写性能逻辑实现。也正因为 MVC 构造没有太多的束缚,让后期的交付速度十分快。但随着系统工程的长期迭代,贫血对象开始被泛滥 serivice 穿插应用,而 service 服务也是互相调用。这样短少一个上下文关系的开发方式,让长期迭代的 MVC 工程逐渐腐化到重大腐化。 MVC 工程的腐化基本,就在于对象、服务、组件的穿插凌乱应用。工夫越长,腐化的越重大。 在 MVC 的分层构造就像家里所有人的衣服放一个大衣柜、所有人的裤子放一个大库柜。衣服裤子(对象),很少的时候很节俭空间,因为你的裤子他人可能也拿去穿,复用一下开发速度很快。但工夫一长,就越来越乱了。 一条裤子被加肥加大,所有人都穿。 而 DDD 架构的模型分层,则是以人为视角,一个人就是一个畛域,一个畛域内包含他所需的衣服、裤子、袜子、鞋子。尽管刚开始有点节约空间,但随着软件的长周期倒退,后续的保护老本就会升高。 那么,接下来咱们就着重看以下,从 MVC 到 DDD 的轻量化重构应该怎么做。 文章前面,含有 MVC 到 DDD 重构编码实际解说。此文也是 MVC、DDD 的架构编码领导教训阐明。一、能学到啥本文是偏实战可落地的 DDD 常识分享,也是从 MVC 到 DDD 的可落地计划解说。在本文中会介绍 DDD 架构下的分层构造、调用全景图以及十分重要的 MVC 到 DDD 应该如何映射和编码。所以如下这一系列内容都是你能取得的常识; DDD 畛域驱动设计,对应的分层构造解说。涵盖调用关系、依赖关系、对象转换以及各层的性能划分。—— 简略且清晰。DDD 调用全景图,以一张全方位的构造关系调用视图,开展 DDD 的血脉流转关系。有了这一张视图,你会更加分明的晓得 DDD 的调用链路构造和各个代码都要写到那一层。MVC 映射 DDD 后的调整计划,在尽可能低的老本下,让 MVC 构造具备 DDD 畛域驱动设计的实现思维。这样的调整,能够在肯定水平上,阻止旧工程的腐化水平,进步编码品质。同时也为后续从 MVC 到 DDD 的迁徙,做好根底。MVC、DDD 是工程设计骨架,设计准则、设计模式是工程实现血肉。所以设计模式也是本文要展现的重点内容。一整套实战开源课程;解说在 DDD 架构中,各项技术栈;Dubbo、MQ、Redis、Zookeeper - 配置核心等的分层应用。—— 否则你可能都不晓得一个 MQ 音讯发送要放在哪里。有了 DDD 分层架构,这些货色会被归类的特地清晰。此外,除了这些碎片化的常识学习,还有利用级实战我的项目锤炼;Lottery DDD 架构设计、ChatGPT 新DDD架构设计、API网关 会话设计 - 学习架构能力和编程思维,以及高端的编码技巧。 ...

September 26, 2023 · 3 min · jiezi

关于mvc:ChatGPT如何做投资

最新钻研预测,ChatGPT无奈预感将来,但对于那些心愿预测股票价格走向的投资者而言,这一语言模型可能具备价值。 美国佛罗里达大学(University of Florida)金融学传授亚历桑德罗·洛佩兹-里拉(Alejandro Lopez-Lira)认为,大型语言模型可能预测股价涨跌。 他在近期一篇未经同行评审的论文中示意,在应用ChatGPT来剖析新闻头条对一只股票是利好还是利空后,他发现ChatGPT预测次日股票回报方向的能力远好于传统模型。 试验是如何进行的? 在这项试验中,洛佩兹-里拉及其合作伙伴应用了一家数据供应商提供的对于纽交所、纳斯达克和一家小盘股交易所上市股票的5万多条新闻。这些新闻开始于2022年10月,是在ChatGPT训练数据的截止日期之后。这意味着,ChatGPT在其自身训练中没有看到或应用过这些新闻。 而后,他们将新闻标题输出ChatGPT 3.5中,并附上指令:“忘掉之前的所有批示。假设你是一位有荐股教训的金融专家。在第一行中,如果是好消息,答复‘是’;如果是坏消息,答复‘否’;如果不确定,答复‘未知’。而后在下一行中用简短的句子来论述。” 他们应用这种情绪剖析来计算一个“ChatGPT分数”,并剖析这些分数是否能够预测该公司第二天的股票市场体现。 钻研人员发现,这些得分与他们剖析的公司第二天的股票体现之间存在统计学上显著的正相干。得分较高的公司往往比得分较低的公司取得更好的回报。 该钻研还发现,ChatGPT优于其余“传统的情绪分析方法”,这些办法也应用头条新闻和社交媒体的数据来预测股票走势。不过,钻研人员也抵赖,他们在这项钻研中并没有测试每一种办法。 在论文的一个案例中,一家公司就诉讼达成和解并领取罚款,这条新闻在传统数据分析上被认为是负面,但ChatGPT正确地推断出这实际上是个好消息。 “简而言之,咱们的钻研证实了ChatGPT在预测股市回报方面的价值。”钻研人员写道。“咱们的钻研结果表明,将高级语言模型纳入投资决策过程能够产生更精确的预测,并进步量化交易策略的体现。” 我对chatgpt的投资倡议持开发举荐态度我之前也应用ChatGPT做过股票的剖析,包含行业特点,投资实践,价值投资,F10等等,的确还是很有价值的,最次要的是“你能够随时向他发问,他能够随时解答你的纳闷”,这一点是我深深依赖chatgpt的起因,截取几张测试图片。 让我喜爱的一个答复 最近A股长得多的根本都盖住了,虽说ChatGPT还是基于之前的数据,然而我坚信它是个价值投资的bot, 可能捕捉到各行业龙头,并且剖析的如此全面和主观,的确是投资的得力助手。 分享下应用的chatgpt工具 : https://www.chatgpt-future.com.cn/ 感激浏览! 本文由博客群发一文多发等经营工具平台 OpenWrite 公布

April 14, 2023 · 1 min · jiezi

关于mvc:关于三层架构和-MVC

1、三层架构 咱们的开发架构个别都是基于两种模式,一种是 C/S 架构,也就是客户端/服务器,另一种是 B/S 架构,也就 是浏览器服务器。在 JavaEE 开发中,简直全都是基于 B/S 架构的开发。那么在 B/S 架构中,零碎规范的三层架构 包含:体现层、业务层、长久层。三层架构在咱们的理论开发中应用得十分多,所以咱们课程中的案例也都是基于 三层架构设计的。 三层架构中,每一层各司其职,接下来咱们就说说每层都负责哪些方面: 体现层: 也就是咱们常说的 web 层。它负责接管客户端申请,向客户端响应后果,通常客户端应用 http 协定申请 web 层,web 须要接管 http 申请,实现 http 响应。 体现层包含展现层和管制层:管制层负责接管申请,展现层负责后果的展现。 体现层依赖业务层,接管到客户端申请个别会调用业务层进行业务解决,并将处理结果响应给客户端。 体现层的设计个别都应用 MVC 模型。(MVC 是体现层的设计模型,和其余层没有关系) 业务层: 也就是咱们常说的 service 层。它负责业务逻辑解决,和咱们开发我的项目的需要非亲非故。web 层依赖业 务层,然而业务层不依赖 web 层。 业务层在业务解决时可能会依赖长久层,如果要对数据长久化须要保障事务一致性。(也就是咱们说的, 事务应该放到业务层来管制) 长久层: 也就是咱们是常说的 dao 层。负责数据长久化,包含数据层即数据库和数据拜访层,数据库是对数据进 行长久化的载体,数据拜访层是业务层和长久层交互的接口,业务层须要通过数据拜访层将数据长久化到数据库中。艰深地讲,长久层就是和数据库交互,对数据库表进行增删改查的。 2、MVC 模型 MVC 全名是 Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写, 是一种用于设计创立 Web 应用程序体现层的模式。MVC 中每个局部各司其职: Model(模型): 通常指的就是咱们的数据模型。作用个别状况下用于封装数据。 View(视图): 通常指的就是咱们的 jsp 或者 html。作用个别就是展现数据的。 通常视图是根据模型数据创立的。 ...

February 28, 2022 · 1 min · jiezi

关于mvc:EDA-事件驱动架构与-EventBridge-二三事

简介: 事件驱动型架构 (EDA) 方兴未艾,作为一种 Serverless 化的利用概念对云原生架构具备着深远影响。当咱们探讨到一个具体架构时,首当其冲的是它的倒退是否具备技术先进性。这里从咱们相熟的 MVC 架构,SOA 架构谈起,聊一聊对于音讯事件畛域的历史与发展趋势。 作者|肯梦 当下比拟胜利的企业未然意识到,要想最大限度晋升经营效率和客户体验,务必将业务和技术两方面的动作紧密结合起来。经营事件或业务局势的变动是时下泛滥企业关注的焦点,这些变动可能为企业领导者带来切实有用的信息,而架构设计的宗旨恰好是从客户联系人、交易、经营等方面的信息中获取洞见,两者相辅相成。传统技术从来对企业从事件中获取洞见的速度有着诸多限度,比方用于记录、收集和解决此类事件的批处理 ETL(提取、转换、加载)。 事件驱动型架构 (EDA) 方兴未艾,作为一种 Serverless 化的利用概念对云原生架构具备着深远影响。当咱们探讨到一个具体架构时,首当其冲的是它的倒退是否具备技术先进性。这里从咱们相熟的 MVC 架构,SOA 架构谈起,聊一聊对于音讯事件畛域的历史与发展趋势。 音讯事件畛域的发展趋势 早在 2018 年,Gartner 评估报告将 Event-Driven Model 列为 10 大策略技术趋势之一,事件驱动架构(EDA)将成为将来微服务的支流,并做出以下断言: 到 2022 年,事件告诉的软件模型将成为超过 60% 的新型数字化商业的解决方案; 到 2022 年,超过 50% 的商业组织将参加到事件驱动的数字化商业服务的生态系统当中; George Santayana 在《 The Life of Reason》曾提到, Those who fail to learn History are doomed to repeat it.(不懂历史的人注定会吃一堑;长一智)。咱们以史为鉴,来看看为什么会架构会演进到事件驱动。 架构自身没有优劣之分,它自身就是一组技术决策,决定后续我的项目的所有性能开发(框架,编码标准,文档,流程….),这里聊聊为什么会引入某些框架,这个框架解决了软件开发中的什么问题。 单体架构:在单节点服务中,单体利用的所有模块都封装在单个过程运行,通信通过雷同堆栈调用实现。这种模式下非常容易导致构造和关系不明确,难以对系统进行更改和重构。就像一个不通明的,粘稠的,软弱的,生硬的 Big Ball of Mud!分层架构:在经典的分层架构中,层以相当审慎的形式应用。即一个层只能晓得它下方层的数据。在随后的理论利用中,更多的形式是一个层能够拜访它上面的任何层。分层架构解决了单体架构的的逻辑拆散问题,每一层都能够被等效替换,层辨别也更加标准化,同时一个层能够被几个不同/更高级别的层应用。当然,层也有比拟显著的毛病,层不能封装掉所有,比方增加到UI的某个字段,可能也须要增加到DB,而且额定多余的层会重大侵害零碎性能。MVC 架构:MVC 架构产生的起因其实很简略,随着业务零碎的复杂性减少,之前所谓“全栈工程师”曾经不实用大部分场景。为了升高前端和后盾的集成复杂性,故而开始推广 MVC 架构。其中,Model 代表业务逻辑,View 代表视图层比方前端UI的某个小组件,Controller 提供 View 和 Model 的协调比方将用户某项操作转为业务逻辑等。这里还有很多扩大架构,譬如 Model-View-Presenter ,Model-View-Presenter-ViewModel,Resource-Method-Representation,Action-Domain-Responder 。EBI 架构:即 Entity,Boundary(接口),Interactor(管制)。EBI架构将零碎边界视为残缺连贯,而不仅仅是视图,控制器或接口。EBI 的实体代表持有数据并完结相干行为的理论实体,很相似阿里云的 POP API。EBI 次要还是后端概念,他是与 MVC 相辅相成的。洋葱架构:洋葱架构是一种低耦合,高内聚的架构模型。所有的应用程序围绕独立的对象模型构建,内层定义接口外层实现接口,耦合方向向核心内聚,所有代码都能够独立与基础设施进行编译和运行。SOA 架构:SOA 是 Service Orientated Architure 的缩写,即面向服务架构。示意每一个性能都是通过一个独立的服务来提供,服务定义了明确的可调用接口,服务之间的编排调用实现一个残缺的业务。其实这个架构也是目前架构中最成熟的,日常应用最多的架构模式。什么是 EDA 架构咱们聊完之前全副的架构趋势后,再回过头看看什么是 EDA 架构。 ...

October 15, 2021 · 2 min · jiezi

关于spring:SpringBoot工程中Spring-MVC模块的应用

背景剖析当我的项目做的越来越来大时,我的项目中业务就会变得越来越简单,如果咱们只应用一个对象去解决所有的业务,这个对象的复杂度就会更高并且难以保护,生存中和理论我的项目中对相似问题的解决计划往往"分而治之"的思维.来升高业务复杂度,进步其可维护性.那当初的问题的是如何分,依照什么规定去分,这就须要有肯定的设计,于是MVC设计思维诞生. MVC 是什么?1)分层设计思维2)一种套路或设计模式3)是Model,View,Controller单词的缩写3.1)Model (业务逻辑对象)3.2)Controller(管制逻辑对象)3.3)View(显示逻辑对象) Spring 框架中Web模块中的MVC设计Spring中的Web模块基于MVC设计思维做了落地实现,其外围组件有: 1)DispatcherServlet (Spring MVC中外围控制器-Controller)2)RequestMapping (封装的申请映射->url到具体handler及办法之间的映射)3)Handler(申请处理器->负责解决Controller获取申请->能够将其了解为model)4)ModelAndView (封装了业务数据和视图信息的对象)5)ViewResolver (负责模板视图解析的对象->View) SpringBoot工程中Web MVC 疾速入门实现1)创立我的项目module2)增加我的项目依赖(spring web,thymeleaf)3) 我的项目构造剖析(static,templates)4) 我的项目启动剖析(启动运行启动类,检测服务是否启动ok)5) 批改我的项目端口,重新启动剖析6)别离在static和templates目录中创立html页面而后进行拜访测试6.1)在static目录下间接创立index.html,启动服务后间接浏览器拜访测试,测试ok.6.2)在templates目录下创立default.html,启动服务后间接浏览器拜访测试,404异样6.3)在我的项目中定义TemplateController以及相干办法,在办法外部返回字符串default(能够将这个字符串了解为view的名字),而后启动服务,基于办法上定义的申请url映射(@RequestMapping("/doTemplateUI"))拜访办法,检测测试输入。 templates目录存储什么文件(html模板文件)templates目录的html页面能够在浏览器间接拜访吗?不能够static目录下个别能够放什么资源?(html/css/js/images)templates目录和static目录下寄存的html文件有什么不同吗?static目录下的html能够间接在浏览器拜访但不能被spring中视图解析器进行解析templates目录的html页面不能够在浏览器间接拜访但能够被spring的视图解析器进行解析,从而为html赋予更多的能力(例如thymeleaf表达式,分支语句,循环语句,...)thymeleaf是什么?(是一个以html作为模板的模板引擎,此引擎为html元素增加额定属性并进行解析,而后对其进行赋能。springboot工程中对thymeleaf做了默认的反对与配置) Bug?1)404异样(web申请资源不存在)2)TemplateInputException (template may not exists) 5.SpringBoot工程中Web MVC利用配置进阶 1)SpringBoot工程中thymeleaf模板引擎的前后缀配置2)SpringBoot工程中页面主动刷新配置(批改页面内容后,不重启服务既可看到更新内容) 1)ModelAndView是什么? (Spring MVC模块中默认提供一个封装响应数据的对象)2)ModelAndView个别利用在什么场景呢?(响应数据既蕴含view又蕴含model)3)你是如何了解JSON的?(就是一种反对跨端需要的轻量级数据格式而已)4)SpringBoot工程中默认是如何将pojo,map等相似对象转换为json格局字符串的?(借助jackson)5)@ReponseBody注解的作用是什么?(形容Handler中的办法,用于通知底层应该如何对办法的返回值进行解决,例如此注解形容的办法,其返回值必定不是view,同时通知底层办法返回值的转换后果最终要写到响应体,而后传输到客户端)6)@RestController注解的作用的是什么?(形容Handler类型,用于定义此类是一个Controller申请解决对象,同时类中所有办法都默认增加@ResponseBody注解)

March 13, 2021 · 1 min · jiezi

关于mvc:SpringMVC执行流程还不清楚

MVC总结1. 概述还是之前的三个套路 1.1 是什么?Spring提供一套视图层的解决框架,他基于Servlet实现,能够通过XML或者注解进行咱们须要的配置。 他提供了拦截器,文件上传,CORS等服务。 1.2 为什么用?原生Servlet在大型项目中须要进过多重封装,来防止代码冗余,其次因为不同接口须要的参数不同,咱们须要本人在Servlet层 封装咱们须要的参数,这对于开发者来说是一种反复且干燥的工作,于是呈现了视图层框架,为咱们进行参数封装等性能。让开发者的注意力全副放在逻辑架构中,不须要思考参数封装等问题。 1.3 怎么用再聊怎么用之前,咱们须要理解一下MVC的工作原理。 他基于一个DispatcherServlet类实现对各种申请的转发,即前端的所有申请都会来到这个Servlet中,而后这个类进行参数封装和申请转发,执行具体的逻辑。(第二章咱们细聊) 1.3.1 XML依据下面的原理,咱们须要一个DispatcherServlet来为咱们提供根底的Servlet服务,咱们能够通过servlet标准的web.xml文件,对该类进行初始化。并且申明该类解决所有的申请,而后通过这个类实现申请转发。另外,咱们还须要一个配置文件,用来配置咱们须要的相干的mvc信息。上面来看一个残缺的web.xml配置 <web-app> <servlet> <servlet-name>dispatchServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatchServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping></web-app>1.3.2 注解注解形式也是当初支流,SpringBoot基于JavaConfig实现了主动配置 实现形式: 在Servlet3.0的时候定义了一个标准SPI标准。 SPI ,全称为 Service Provider Interface,是一种服务发现机制。它通过在ClassPath门路下的META-INF/services文件夹查找文件,主动加载文件里所定义的类。也就是在服务启动的时候会Servlet会主动加载该文件定义的类 咱们看一眼这个文件里的内容。他外部定义了SpringServletContainerInitializer容器初始化类,也就是说在Servlet启动的时候会主动初始化这个类,这个类也是注解实现的要害。 这个类中存在一个onStartup办法,这个也是当容器初始化的时候调用的办法,这个办法有两参数 Set<Class<?>> webAppInitializerClasses他代表了以后咱们的Spring容器中存在的web初始化类。咱们本人能够通过实现WebApplicationInitializer类来自定义Servlet初始化的时候执行的办法。ServletContext servletContex代表了Servlet上下文对象org.springframework.web.SpringServletContainerInitializer@HandlesTypes(WebApplicationInitializer.class)public class SpringServletContainerInitializer implements ServletContainerInitializer { @Override public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException { //启动逻辑 }}具体看一下注解配置形式: public class MyWebApplicationInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletCxt) { // Load Spring web application configuration AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext(); //一个配置类,@Configuration ac.register(AppConfig.class); //spring的那个refresh办法 ac.refresh(); // Create and register the DispatcherServlet DispatcherServlet servlet = new DispatcherServlet(ac); ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet); registration.setLoadOnStartup(1); registration.addMapping("/app/*"); }}通过实现WebApplicationInitializer接口,来作为MVC的配置类,在加载SpringServletContainerInitializer的时候加载这个类。 ...

November 17, 2020 · 2 min · jiezi

关于mvc:MVC分层设计思想

典型的MVC分层设计,咱们能够参考阿里巴巴开发手册中给出分层设计模型,如图所示:其中,在上图中的箭头示意一种间接依赖关系,凋谢接口层能够依赖于 Web 层,也能够间接依赖于 Service 层,其它依此类推(具体每层要实现的逻辑可自行查阅阿里巴巴开发手册)。 零碎分层设计是一种设计思维,是让每层对象都有一个独立职责,再让多层对象协同(耦合)实现一个残缺的性能。这样做能够更好进步零碎可扩展性,但同时也会减少零碎整体运维的难度。

November 11, 2020 · 1 min · jiezi

关于mvc:编码风格Mvc模式下SSM环境代码分层管理

本文源码:GitHub·点这里 || GitEE·点这里 一、分层策略MVC模式与代码分层策略,MVC全名是ModelViewController即模型-视图-控制器,作为一种软件设计榜样,用一种业务逻辑、数据、界面显示拆散的办法组织代码,将业务逻辑汇集到一个部件外面,在改良和个性化定制界面及用户交互的同时,不须要从新编写业务逻辑,这是一种开发模式,但并不是理论开发中代码的分层模式,通常SSM框架的后端代码分层如下: controller管制层:定义服务端接口,入参出参,和一些入参校验;service业务服务层:组装业务逻辑,业务校验,构建管制层须要的参数模型;dao数据交互层:提供服务层须要的数据查询方法,解决数据交互条件相干的逻辑;mapper长久层:基于mybatis框架须要的原生反对,目前很罕用的长久层组件;二、管制层1、Rest接口格调 基于资源拜访和解决的逻辑,应用不同格调的注解。例如资源新增,更新,查问,删除。 /** * 新增 */@PostMapping("/insert")public Integer insert (@RequestBody BaseInfo baseInfo){ return baseInfoService.insert(baseInfo);}/** * 更新 */@PutMapping("/update/{id}")public String update(@PathVariable(value = "id") Integer id, @RequestBody BaseInfo baseInfo) { if (id<1){ return "error"; } baseInfo.setId(id); return "update="+baseInfoService.update(baseInfo);}/** * 主键查问 */@GetMapping("/detail/{id}")public InfoModel detail(@PathVariable(value = "id") Integer id) { return baseInfoService.detail(id) ;}/** * 主键删除 */@DeleteMapping("/delete/{id}")public String delete(@PathVariable(value = "id") Integer id) { baseInfoService.delete(id) ; return "SUS" ;}2、接口复用度 ...

November 9, 2020 · 2 min · jiezi

关于mvc:基于MVC的RESTFul风格API实战

基于MVC的RESTful格调的实现1.RESTful格调论述REST服务是一种ROA(Resource-Oriented Architecture,面向资源的架构)利用。次要特点是办法信息存在于HTTP协定的办法中(GET,POST,PUT,DELETE),作用域存在于URL中。例如,在一个获取设施资源列表的GET申请中,办法信息是GET,作用域信息是URI种蕴含的对设施资源的过滤、分页和排序等条件==良好的REST API不须要任何文档== 1.1REST格调资源门路REST格调的资源门路设计是面向资源的,==资源的名称==应该是精确形容该资源的==名词==。 资源门路概览:sheme://host:port/path?queryString例:http://localhost:8080/bywlstudio/users/user?username=xiuer 1.2HTTP办法GET用于==读取==、==检索==、==查问==、==过滤==资源PSOT用于==创立==一个资源 PUT用于==批改==、==更新==资源、==创立客户端保护主键信息的资源== DELETE用于==删除==资源 资源地址和HTTP办法联合在一起就能够实现对资源的残缺定位 1.3RESTful格调API设计上文讲述了通过HTTP办法和资源门路对服务器的一个资源进行定位的过程 接下来看一个REST格调API的设计 性能形容增加/创立POST/usersPUT/users{id}1删除DELETE/users/{id}批改/更新PUT/users/{id}查问全副GET/users主键查问GET/users/{id}GET/users?id=26分页作用域查问GET/users?start=0&size=10GET/users?07,2019-07,2020能够看到通过这个RESTAPI都是通过对==同一个资源==的操作,所不同的就是通过不同的==HTTP办法==来实现对资源不同的解决。 2.MVC对REST的反对1.1次要通过注解来实现@Controller声名一个解决申请的控制器@RequestMapping申请映射地址,它存在几个子注解对于实现REST格调来说更加具备==语义性== @GETMapping ==GET申请==@PUTMapping ==PUT申请==@POSTMapping ==POST申请==@DELETEMapping ==DELETE申请==@ResponseBody 将响应内容转换为JSON格局@RequestBody 申请内容转换为JSON格局@PathVariable("id")用于绑定一个参数@RESTController 等同于@Controller+@ResponseBody在类上写了这个注解,标识这个类的所有办法只==返回数据==,而不进行==视图跳转==1.2返回HTTP状态码REST格调API一个最显明的特点通过返回对应的HTTPStatus来判断客户端的操作是否实现 ==上面是spring中对于Http状态码形容的枚举类,本文列举了常见的状态码==(读者若对此感兴趣能够查看HttpStatus源码) public enum HttpStatus{ OK(200, "OK"),//用于服务器有实体响应 CREATED(201, "Created"),//创立了新实体,响应该实体 NO_CONTENT(204, "No Content"),//服务器失常响应,但无实体响应 BAD_REQUEST(400, "Bad Request"),//客户端申请语法错误 NOT_FOUND(404, "Not Found"),//指标资源不存在 INTERNAL_SERVER_ERROR(500, "Internal Server Error"),//服务器外部谬误 NOT_IMPLEMENTED(501, "Not Implemented"),//服务器不反对以后申请}Spring返回状态码是通过@ResponseStatus注解或者ResponseEntity<?>类实现的。 ==@ResponseStatus形式== @GetMapping(path = "/user/{id}" , produces = "application/json;charset=utf-8")@ResponseStatus(HttpStatus.OK)public User findUserById(@PathVariable("id")Integer id){ User user = userService.findUserById(id); return user ;}==ResponseEntity<?>==形式 @GetMapping(produces = "application/json;charset=utf-8")public ResponseEntity<List<User>> findAll(){ List<User> users = userService.findAll(); return new ResponseEntity<List<User>>(users , HttpStatus.OK);}1.3因为MVC默认不反对PUT和DELETE办法,所以须要手动开启在tomcat服务器的web.xml文件中开启一下配置 ...

November 6, 2020 · 2 min · jiezi

关于mvc:MVCMVP和MVVM

前言在web1.0时代,并没有前端的概念,要写就就后端一起写了。前后端的代码杂糅到一起,比方php开发前后端,随后衍生出MVC开发模式和框架。web1.0时代起初的MVC指标数据、视图、以及业务逻辑管制分层;这样就能够把代码切割成性能独立的模块。 长处应用了这种分层架构,实则清晰,代码易保护。 实现了肯定水平的前后端的拆散,然而还不是很清晰 起初的MVC仅限于服务端(后端),在服务器端渲染。前端只实现了后端开发中的view层(只是写模板文件,依照模版语法去写动静内容);Model层提供数据查问。View层通过模板引擎来进行解析。解析成真正的HTML内容,浏览器去渲染毛病前端页面开发效率不高前端之前都是以动态页面呈现的;很少的js交互;将代码交给后端程序员,后端在用模板语法对它进行动态化的革新,效率不高。前后端指摘不清晰个别都是一个程序员,前后端一起抓,要会的也很多,前端的兼容性,后端的语法等等。web2.0时代谷歌的Gmai的呈现,ajax技术开始风靡寰球,从而前后端的职责更加清晰了。前端能够通过Ajax与后端进行数据交互。 前端: 应用HTML、CSS、 Javascript(在Js中来撰写Ajax的申请),前端通过Ajax申请来获取数据,前端在进行交互和渲染。后端:只须要把数据的根本构造返回给前端。通过Ajax与后端服务器进行数据交互;前端只须要开发页面内容,数据由后端提供;ajax能够使页面实现局部刷新,缩小服务端负载和流量耗费。这是才有了专职的前端来法工程师,同时前端的各种类库就缓缓倒退起来,比方早前的JQuery 长处流量耗费变小了,部分刷新;用户体验晋升 毛病开发模式承载了更简单的业务需要,一旦利用规模增大,还是会导致难以保护,因为Html、Css、 JS还是杂糅在一起。从而咱们须要设计模式和框架。前端的MVC才会随之而来 MVCMVC框架分为,前端MVC和后端MVC;前端的MVC与后端的类似,模仿这后端的架构;都具备View、Controller和ModelModel: 模型负责保留利用数据,与后盾数据进行同步Controller:控制器负责业务逻辑,依据用户行为对Model数据进行批改View: 负责视图的展现,将model中的数据可视化进去 来个模型瞅瞅~~真够难画的,一图弄了10分钟。也没有多难看,应该是我不太用这个软件的问题,如果有错,那肯定是我的错。哈哈哈哈哈 视图会通过事件去告诉控制器,控制器去改模型,模型在尝试用某种方法告诉视图去更新。实践上可行,然而往往在理论开发中,并不会这样操作。因为开发过程并不灵便。比方: 一个小的事件操作,都必须通过这样的一个流程,那么开发就不便捷。在理论中场景中,可能是另一种模式,这样的:来~~~画图,算了用网上找的把。这个模式看上去是不便一些,backbone.js框架就是这种模式;View能够操作Model,Model扭转也能够View;从而控制器层就显得很薄弱,可有可无;(控制器外面就变成了简略的数据坚监听和调用)毛病: 谬误很难定位,数据凌乱 `因为MVC框架呈现的缺点,从而有了MVVM框架。最早是AngularJS 用的MVVM框架模式。MVP模式前端开发并不常见,然而在安卓原生开发中,开发者还是会思考到它。` MVPMVP和MVC很靠近,方才看到了,可能会呈现凌乱的状况,MVP就 做了一个中间人,Presenter: 负责View和Model之间的数据流动,如果数据和视图非要交互就必须要通过中间人。 Presenter负责和Model进行双向交互,还有和View进行双向交互。 如果业务简单一点,Presenter的体积增大、臃肿,就很难保护;MVVMMVVM能够分解成(Model-View-ViewModel);ViewModel能够了解为在Presenter根底上的进阶。ViewModel,次要是胶水层,核心思想是简化1.数据发生变化,如何晓得变动, 通过数据响应式的机制,用某种机制晓得这个数据的变动,主动的去响应数据的变动,主动去做更新;外部晓得了数据的变动,不须要用户来操作。更新,以前做Dom操作,用JQ;数据变了要做Dom操作来更新(代码多,效率不高);所以有虚构Dom的形式去做更新,依据精准的diff算法来做比对;达到高效的后果。`通过响应式和虚构Dom来做到数据驱动。如果数据变,间接视图更新;开发人员只须要批改数据,不必操作Dom;不须要操心其余事件。` 视图层如何扭转数据层?和之前一样,还是做数据监听,模版引擎会有事件处理的语法,通过这些语法,轻易的写出这些事件监听的形式 长处ViewModel 通过实现一套数据响应式机制主动响应Model中数据变动ViewModel 也有一套更新策略主动将数据转化为视图更新通过事件监听响应View中用户交互批改Model中数据从而使开发者专一于业务逻辑,兼顾开发效率和可维护性 总结三个框架,反映了web前端倒退的过程,职责都是: 代码分层职责(前后端)划分解决维护性问题解决 Model和View的耦合问题MVC 早起专一利用在后端;前端早起的利用BackBone.js. 长处:分层清晰(刚开始,算是比之前清晰了)毛病: 数据流凌乱,灵活性带来的维护性问题MVP 模式是由MVC的进化模式,Persenter作为中间层负责MV通信,解决了两者耦合关系,然而中间层过于臃肿会导致保护问题 MVVM模式在前端畛域目前更宽泛。不仅解决了MV的耦合问题,解决了保护两者映射关系的大量繁冗代码和Dom操作代码;进步了开发效率。

September 14, 2020 · 1 min · jiezi

MVC模式实现数据库的增删改查

什么是MVC模式MVC模式中M代表模型、V代表视图、C代表控制器。Model(模型)表示应用程序核心(比如数据库记录列表)。View(视图)显示数据(数据库记录)。Controller(控制器)处理输入(写入数据库记录)。 数据库设计表名:student、使用的为mysql数据库 M层package cn.jdbc.domain;public class student {//学号private String sno;//姓名private String sname;//年龄private int sage;public String getSno() { return sno;}public void setSno(String sno) { this.sno = sno;}public String getSname() { return sname;}public void setSname(String sname) { this.sname = sname;}public int getSage() { return sage;}public void setSage(int sage) { this.sage = sage;}}V层jsp页面 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>学生数据</title></head><body> <table border="1" border="1" cellpadding="0" cellspacing="0" width="100%"> <thead> <tr> <th>学号</th> <th>姓名</th> <th>年龄</th> </tr> </thead> <tbody> <c:forEach items="${list}" var="i"> <tr > <td>${i.sno}</td> <td>${i.sname}</td> <td>${i.sage}</td> </tr> </c:forEach> </tbody> </table> <form action="/sy3/display" method="post"> <label>查询的学号</label> <input type="text" name="search_no" value=""> <input type="submit" value="查询"> <a href="http://localhost:9999/sy3/display">返回</a><br> </form> <h5>添加数据</h5> <form action="/sy3/display" method="post"> <label>学号</label> <input type="text" name="add_sno" value=""> <label>姓名</label> <input type="text" name="add_sname" value=""> <label>年龄</label> <input type="text" name="add_sage" value=""> <input type="submit" value="添加"> </form> <h5>修改数据</h5> <form action="/sy3/display" method="post"> <label>学号</label> <input type="text" name="cg_sno" value=""> <label>姓名</label> <input type="text" name="cg_sname" value=""> <label>年龄</label> <input type="text" name="cg_sage" value=""> <input type="submit" value="修改"> </form> <h5>删除数据</h5> <form action="/sy3/display" method="post"> <label>删除数据学生的学号</label> <input type="text" name="del_sno" value=""> <input type="submit" value="删除"> </form></body></html> ...

June 22, 2020 · 5 min · jiezi

Spring-Boot-2X四Spring-Boot-自定义-Web-MVC-配置

0.准备Spring Boot 不仅提供了相当简单使用的自动配置功能,而且开放了非常自由灵活的配置类。Spring MVC 为我们提供了 WebMvcConfigurationSupport 类和一个注解 @EnableWebMvc 以帮助我们减少配置 Bean 的声明。本文简单说明如何自定义 Web MVC 配置。首先需要使用 @Configuration 将 WebMvcConfig 类标注为 Spring 配置类,示例代码如下: @Configurationpublic class WebMvcConfig extends WebMvcConfigurationSupport { //通过重写配置方法覆盖}并在启动类上添加 @EnableWebMvc,代码如下: @SpringBootApplication@MapperScan("cn.zwqh.springboot.dao")@EnableWebMvc //启用 Spring MVC 配置public class SpringBootSsmThymeleafApplication { public static void main(String[] args) { SpringApplication.run(SpringBootSsmThymeleafApplication.class, args); }}1.静态资源配置Spring Boot 中默认的静态资源配置,是把类路径下的/static、/public、/resources 和 /METAINF/resources 目录或者 ServletContext 的根目录中的静态文件直接映射为 /**。它使用来自 Spring MVC 的ResourceHttpRequestHandler,以便您可以通过添加自己的WebMvcConfigurer并覆盖addResourceHandlers方法来修改该行为。示例代码如下: @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/statics/**").addResourceLocations("classpath:/statics/");//静态资源路径 css,js,img等 registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/templates/");//视图 registry.addResourceHandler("/mapper/**").addResourceLocations("classpath:/mapper/");//mapper.xml super.addResourceHandlers(registry); } 2.拦截器配置通过重写 addInterceptors() 方法,使用 InterceptorRegistry 注册类来添加拦截器 HandlerInterceptor。示例代码如下: ...

November 5, 2019 · 2 min · jiezi

iijs-一个基于nodejskoa2构建的简单轻量级MVC框架

iijsA simple and lightweight MVC framework built on nodejs+koa2 项目介绍一个基于nodejs+koa2构建的简单轻量级MVC框架,最低依赖仅仅koa和koa-router 官网:js.i-i.me 源码:github 码云 QQ:331406669 使用安装 npm i iijs应用结构├── app //应用目录 (非必需,可更改)│ ├── Controller //控制器目录 (非必需,可更改)│ │ └── index.js //控制器│ ├── view //模板目录 (非必需,可更改)│ │ └── index //index控制器模板目录 (非必需,可更改)│ │ └── index.htm //模板│ ├── model //模型目录 (非必需,可更改)│ ├── logic //逻辑目录 (非必需,可更改)│ └── **** //其他目录 (非必需,可更改)├── app2 //应用2目录 (非必需,可更改)├── common //公共应用目录 (非必需,可更改)├── config //配置目录 (非必需,不可更改)│ ├── app.js //APP配置 (非必需,不可更改)│ ├── route.js //路由配置 (非必需,不可更改)│ └── **** //其他配置 (非必需,可更改)├── public //静态访问目录 (非必需,可更改)│ └── static //css image文件目录 (非必需,可更改)├── node_modules //nodejs模块目录├── server.js //应用入口文件 (必需,可更改)└── package.json //npm package.json应用入口// server.jsconst {app} = require('iijs');app.listen(3000, '127.0.0.1', function(err){ if(!err) console.log('http server is ready on 3000');});Hello world !// app/controller/index.jsclass Index { constructor(ctx, next) { this.ctx = ctx; this.next = next; } async hello() { this.ctx.body = `hello iijs, hello world !`; }}module.exports = Index;访问URL:http://localhost/app/index/hello ...

September 8, 2019 · 2 min · jiezi

从零开始实现mvc框架

造个轮子— 从socket到mvc框架1. 缘起为什么要造这个轮子?现在Java领域的mvc框架层出不穷,springmvc,struts2,jfinal;容器方面有tomcat,jetty,undertow。为什么要造这个不成熟的东西出来?我想起我在大二刚接触java web是学的struts2,一大堆xml配置让我看到吐,感觉这掩盖了网络编程的本来面目,为什么不从底层的socket写起,解析http协议,封装请求和响应,我觉得这样更能理解本质。于是我造了第一个轮子作为这个想法的验证MineServer, 这个轮子现在放在github上,但这只是一个玩具项目,我想造的是一个完整的轮子,于是我开了这个坑Boomvc。 2. 我想要什么?我想要一个类似spring boot这种开发体验的web框架,可以用一行代码开启一个http server,没有xml配置,使用注解和简单的properties配置文件,最简的依赖,可以不用遵守servlet规范的web mvc框架。框架要包括3个部分:底层的http server和上层的mvc框架,以及ioc容器。http server可以自己从socket实现,也可以使用netty这样的网络框架实现。 3. 实现目前框架已经基本实现完成,还有很多bug,但是完成了自己的想法,我感到很开心。目前框架实现了一下的功能。 轻量级MVC框架,不依赖任何web容器可以直接运行jar包启动一个web服务支持cookie支持session使用jdk原生的nio api实现http serverRestful风格路由支持模板引擎支持JSON输出可以像spring boot 那样一行代码启动 :) public static void main(String[] args) { Boom.me().start(Main.class, args);}写一个controller @RestPathpublic class TestController { @GetRoute("/") public String hello(){ return "hello world"; }}同时还有过滤器和拦截器 public interface Filter { void init(FilterConfig config); void doFilter(HttpRequest request, HttpResponse response, FilterChain chain) throws Exception; void destroy();}public interface Interceptor { boolean preHandle(HttpRequest request, HttpResponse response); void postHandle(HttpRequest request, HttpResponse response, ModelAndView modelAndView); void afterCompletion(HttpRequest request, HttpResponse response, Exception e);}然后像spring boot那样注册,写一个配置类继承WebMvcConfigurerAdapter ...

August 21, 2019 · 1 min · jiezi

用纯-JavaScript-撸一个-MVC-程序

作者:Tania翻译:疯狂的技术宅 原文:https://www.taniarascia.com/j... 未经允许严禁转载 我想用 model-view-controller 架构模式在纯 JavaScript 中写一个简单的程序,于是我这样做了。希望它可以帮你理解 MVC,因为当你刚开始接触它时,它是一个难以理解的概念。 我做了这个todo应用程序,这是一个简单小巧的浏览器应用,允许你对待办事项进行CRUD(创建,读取,更新和删除)操作。它只包含 index.html、style.css和script.js 三个文件,非常简单,无需任何依赖和框架。 先决条件基本的 JavaScript 和 HTML 知识熟悉最新的 JavaScript 语法目标用纯 JavaScript 在浏览器中创建一个 todo 应用程序,并熟悉MVC(和 OOP——面向对象编程)的概念。 查看程序的演示查看程序的源代码注意:由于此程序使用了最新的 JavaScript 功能(ES2017),因此在某些浏览器(如 Safari)上无法用 Babel 编译为向后兼容的 JavaScript 语法。什么是 MVC?MVC 是一种非常受欢迎组织代码的模式。 Model(模型) - 管理程序的数据View(视图) - 模型的直观表示Controller(控制器) - 链接用户和系统模型是数据。在这个 todo 程序中,这将是实际的待办事项,以及将添加、编辑或删除它们的方法。 视图是数据的显示方式。在这个程序中,是 DOM 和 CSS 中呈现的 HTML。 控制器用来连接模型和视图。它需要用户输入,例如单击或键入,并处理用户交互的回调。 模型永远不会触及视图。视图永远不会触及模型。控制器用来连接它们。 我想提一下,为一个简单的 todo 程序做 MVC 实际上是一大堆样板。如果这是你想要创建的程序并且创建了整个系统,那真的会让事情变得过于复杂。关键是要尝试在较小的层面上理解它。初始设置这将是一个完全用 JavaScript 写的程序,这意味着一切都将通过 JavaScript 处理,HTML 将只包含根元素。 index.html <!DOCTYPE html><html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Todo App</title> <link rel="stylesheet" href="style.css" /> </head> <body> <div id="root"></div> <script src="script.js"></script> </body></html>我写了一小部分 CSS 只是为了让它看起来可以接受,你可以找到这个文件并保存到 style.css 。我不打算再写CSS了,因为它不是本文的重点。 ...

August 8, 2019 · 6 min · jiezi

springboot结合全局异常处理之登录注册验证

在学校做一个校企合作项目,注册登录这一块需要对注册登录进行输入合法的服务器端验证,因为是前后端分离开发,所以要求返回JSON数据。方法有很多,这觉得用全局异常处理比较容易上手 全局异常处理首先来创建一个sprIngboot的web项目或模块,目录结构如下 实体类User.java @Datapublic class User { private String userName; private String passwold;}实体类UserResult.java 把数据封装到这里返回到客户端 @Data@NoArgsConstructor@AllArgsConstructorpublic class UserResult { private int code; private String msg;}接下来自定义异常,都继承自ExceptionUserNullException.java 当用户名为空抛出这个异常 public class UserNullException extends Exception{ public UserNullException() { super("用户名不能为空"); }}PasswoldNullException.java 当密码为空抛出这个异常 public class PasswoldNullException extends Exception { public PasswoldNullException() { super("密码不能为空"); }}UserNamePasswordNullException.java 当用户名和密码都为空抛出这个异常 public class UserNamePasswordNullException extends Exception { public UserNamePasswordNullException() { super("请输入用户名和密码"); }}UserNameValidationException.jva 当输入不符合要求的用户名时抛出此异常 public class UserNameValidationException extends Exception{ public UserNameValidationException() { super("请输入6到16位的数字或字母组合"); }}UserNamePasswordNullException.java 当输入的密码不符合要求时抛出这个异常 ...

May 11, 2019 · 2 min · jiezi

ThinkGo:一个轻量级的 Go 语言 MVC 框架

ThinkGo 是一个轻量级的 Go 语言 MVC 框架,目前支持路由、中间件、控制器、请求、响应、Session、视图、日志、缓存、ORM等 web 框架应该具备的基本功能,ThinkGo致力于让代码简洁且富于表达力,帮助开发者快速构建一个 Web 应用。特性简洁的路由,支持参数注入强大的路由中间件,支持前置/后置中间件Session支持,支持cookie、redis及自定义存储强大的日志服务,支持多通道存储,遵循RFC 5424规范。缓存,支持memory、redis及自定义缓存驱动简洁的ORM,能使用原生 SQL、流畅的查询构造器安装go get github.com/thinkoner/thinkgo快速开始package mainimport ( “github.com/thinkoner/thinkgo” “fmt” “github.com/thinkoner/thinkgo/router” “github.com/thinkoner/thinkgo/context”)func main() { app := thinkgo.BootStrap() app.RegisterRoute(func(route *router.Route) { route.Get("/", func(req *context.Request) *context.Response { return thinkgo.Text(“Hello ThinkGo !”) }) route.Get("/ping", func(req *context.Request) *context.Response { return thinkgo.Json(map[string]string{ “message”: “pong”, }) }) // Dependency injection route.Get("/user/{name}", func(req *context.Request, name string) *context.Response { return thinkgo.Text(fmt.Sprintf(“Hello %s !”, name)) }) }) // listen and serve on 0.0.0.0:9011 app.Run()}协议ThinkGo 采用 Apache 2.0 开源协议发布。项目地址GitHub: https://github.com/thinkoner/...Gitee: https://gitee.com/thinkgo/thi…联系作者https://github.com/thinkoner/… ...

February 12, 2019 · 1 min · jiezi

编程--基本概念

1.面向过程(PROCEDURE ORIENTED)1).具体化,流程化2).性能高3).算法+数据结构2.面向对象(OBJECT ORIENTED)(OO)1).模型化2).易维护,易复用,易扩展3.面向对象编程(OOP)1).继承 允许在现存的组件基础上创建子类组件,这统一并增强了多态性和封装性 A).重载(以统一的方法处理不同数据类型) 一个类的多态性表现 B).重写(方法重写) 父子类多态性体现2).封装(信息封装) 确保组件不会以不可预期的方式改变其它组件的内部状态3).多态 组件的引用和类集会涉及到其它不同类型的组件,而且引用组件所产生的结果得依据实际调用的类型4.面向切面编程(ASPECT ORIENTED PAROGRAMMING)(AOP)1).切面 项目模块中某些业务逻辑(业务需要一定共性)2).解耦,提高程序可重用性,提高开发效率5.三层架构、MVC、MVP、MVVM1).三层架构–界面层(User Interface Layer-Business Logic Layer-Data access Layer 界面–业务逻辑–数据访问) A).界面层(UIL) 与用户交互 B).业务逻辑层(BLL) 实现业务逻辑。业务逻辑具体包含:验证、计算、业务规则等 C).数据访问层(DAL) 与数据库打交道。主要实现对数据的增、删、改、查 2).MVC(Model-View-Controller 模型–视图–控制器) A).Model(模型) 业务逻辑、业务模型、业务操作、数据模型。定义了数据修改和操作的业务规则 B).View (视图) UI组件。接收Controller数据,降Model转化成UI C).Controller(控制器) 处理流入请求 D).特点 View和Model分离(1978 Trygve Reenskaug) E).流程 View⇒Controller⇒Model⇔View 3).MVP(Model-View-Presenter MVC改良模式(View与Model完全解耦)) A).Model(模型) 业务逻辑、业务模型、业务操作、数据模型。定义了数据修改和操作的业务规则 B).View (视图) UI组件。接收Controller数据,降Model转化成UI C).Presenter(控制器) 处理View背后所有UI事件(一个Presenter只映射一个view) D).特点 View和Presenter双向交互(IBM的子公司Taligent提出) E).流程 View⇔Presenter⇔Model 4).MVVM(Model-View-View Model MVP中把P层削弱为VM层,部分简单的逻辑职责分给了View层) A).Model(模型) 业务逻辑、业务模型、业务操作、数据模型。定义了数据修改和操作的业务规则 B).View (视图) UI组件。接收Controller数据,降Model转化成UI C).View Model(控制器) 负责暴漏方法,命令,其他属性来操作View的状态,触发View自己的事件 D).特点 View和View Model双向数据绑定关系 E).流程 View⇒View Model⇔Model ...

December 26, 2018 · 1 min · jiezi

nest后端开发实战(二)——分层

前言分层是解决软件复杂度很好的方法,它能够降低耦合、增加复用。典型的java后端开发大多分为三层,几乎成了标准模式,但是node社区对于分层的讨论却很少。node后端是否需要分层?如何分层?本文将从个人的角度提供一些思路。是否必要分层?如何分层?个人的结论是:如果想做一个正儿八经的node后台应用,一定需要分层,java的三层架构,同样适用于node。结构如下:dao层dao(data access object),数据访问对象,位于最下层,和数据库打交道。它的基本职责是封装数据的访问细节,为上层提供友好的数据存取接口。一般是各种数据库查询语句,缓存也可以在这层做。无论是nest还是egg,官方demo里都没有明确提到dao层,直接在service层操作数据库了。这对于简单的业务逻辑没问题,如果业务逻辑变得复杂,service层的维护将会变得非常困难。业务一开始一般都很简单,它一定会向着复杂的方向演化,如果从长远考虑,一开始就应该保留dao层。分享两点dao层的建议:1、以实体为中心定义类型描述。后端建模的一大产出是领域实体模型,后续的业务逻辑其实就是对实体模型的增删改查。利用ts对类型的丰富支持,可以先将实体模型的类型描述定义出来,这将极大的方便上层业务逻辑的实现。我一般会将实体相关的类型、常量等都定义到一个文件,命名为xxx.types.ts。定义到一个文件的好处是,编码规范好落实,书写和引用也非常方便,由于没有太多逻辑,即使文件稍微大一点,可读性也不会降低太多。用po和dto来描述实体及其周边。po是持久化对象和数据库的表结构一一对应;dto数据传输对象则很灵活,可以在丰富的场景描述入参或返回值。下面是个user实体的例子:// user.types.ts/** * 用户持久化对象 /export interface UserPo { id: number; name: string; // 姓名 gender: Gender; // 性别 desc: string; // 介绍}/* * 新建用户传输对象 /export interface UserAddDto { name: string; gender?: Gender; desc?: string;}/* * 性别 /export enum Gender { Unknown, Male, Female,}虽然ts提供了强大的类型系统,如果不能总结出一套最佳实践出来,同样会越写越乱。全盘使用不是一个好的选择,因为这样会失去很多的灵活性。我们需要的是在某些必须的场景,坚持使用。2、不推荐orm框架orm的初心很好,它试图完全将对象和数据库映射自动化,让使用者不再关心数据库。过度的封装一定会带来另外一个问题——隐藏复杂度的上升。个人觉得,比起查询语句,隐藏复杂度更可怕。有很多漂亮的orm框架,比如java界曾经非常流行的hibernate,功能非常强大,社区也很火,但实际在生产中使用的人却很少,反倒是一些简单、轻量的被大规模应用了。而且互联网应用,对性能的要求较高,因此对sql的控制也需要更直接和精细。很多互联网公司也不推荐使用外键,因为db往往是瓶颈,关系的维护可以在应用服务器做,所以orm框架对应关系的定义不一定能用得上。node社区有typeorm,sequelizejs等优秀的orm框架,个人其实并不喜欢用。我觉得比较好的是egg mysql插件所使用的ali-rds。它虽然简单,却能满足我大部分的需求。所以我们需要的是一个好用的mysql client,而不是orm。我也造了一个类似的轮子bsql,我希望api的设计更加接近sql的语意。目前第一个版本还比较简单,核心接口已经实现,还在迭代,欢迎关注。下面是user.dao的示例。import { Injectable } from ‘@nestjs/common’;import { BsqlClient } from ‘bsql’;import { UserPo, UserAddDto } from ‘./user.types’;@Injectable()export class UserDao { constructor( private readonly db: BsqlClient, ) { } /* * 添加用户 * @param userAddDto / async addUser(userAddDto: UserAddDto): Promise<number> { const result = await this.db.insertInto(‘user’).values([userAddDto]); return result.insertId; } /* * 查询用户列表 * @param limit * @param offset / async listUsers(limit: number, offset: number): Promise<UserPo[]> { return this.db.select<UserPo>(’’).from(‘user’).limit(limit).offset(offset); } /** * 查询单个用户 * @param id / async getUserById(id: number): Promise<UserPo> { const [user] = await this.db.select<UserPo>(’’).from(‘user’).where({ id }).limit(1); return user; }}从广义的角度看,dao层很像公式“程序=数据结构+算法”中的数据结构。“数据结构”的实现直接关系到上层的“算法”(业务逻辑)。service层service位于dao之上,使用dao提供的接口,也可以调用其它service。service层也比较简单,主要是弄清其职责和边界。1、实现业务逻辑。service负责业务逻辑这点毋庸置疑,核心是如何将业务逻辑抽象成接口及其粒度。service层应该尽量提供功能相对单一的基础方法,更多的场景和变化可以在controller层实现。这样设计有利于service层的复用和稳定。2、处理异常。service应该合理的捕获异常并将其转化成业务异常,因为service层是业务逻辑层,他的调用方更关心业务逻辑进行到哪一步了,而不是一些系统异常。在实现上,可以定义一个business.exception.ts,里面包含常见的业务异常。当遇到业务逻辑执行不下去的问题时,抛出即可,调用方既能根据异常的类型采取行动。// common/business.exception.ts/** * 业务异常 /export class BusinessException { constructor( private readonly code: number, private readonly message: string, private readonly detail?: string, ) { }}/* * 参数异常 /export class ParamException extends BusinessException { constructor(message: string = ‘参数错误’, detail?: string) { super(400, message, detail); }}/* * 权限异常 /export class AuthException extends BusinessException { constructor(message: string = ‘无权访问’, detail?: string) { super(403, message, detail); }}对于业务异常,还需要一个兜底的地方全局捕获,因为不是每个调用方都会捕获并处理异常,兜底之后就可以记录日志(方便排查问题)同时给与一些友好的返回。在nest中统一捕获异常是定义一个全局filter,代码如下:// common/business-exception.filter.tsimport { ExceptionFilter, Catch, ArgumentsHost } from ‘@nestjs/common’;import { BusinessException } from ‘./business.exception’;/* * 业务异常统一处理 */@Catch(BusinessException)export class BusinessExceptionFilter implements ExceptionFilter { catch(exception: BusinessException, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse(); response.json({ code: exception.code, message: exception.message }); console.error(// tslint:disable-line ‘BusinessException code:%s message:%s \n%s’, exception.code, exception.message, exception.detail); }}// main.tsimport { NestFactory } from ‘@nestjs/core’;import { AppModule } from ‘./app.module’;import { BusinessExceptionFilter } from ‘./common/business-exception.filter’;async function bootstrap() { const app = await NestFactory.create(AppModule); // 注册为全局filter app.useGlobalFilters(new BusinessExceptionFilter()); await app.listen(3000);}bootstrap();3、参数校验。dao层设计很简单,几乎不做参数校验,同时dao也一般不会开放给外部直接调用,而是开放service。所以service层应该做好参数校验,起到保护的作用。4、事务控制。dao层可以针对单个的持久化做事物控制,粒度比较小,而基于业务原则的事物处理就应该在service层。nest目前貌似没有在service层提供事务的支持。接下来我准备做个装饰器,在service层提供数据库本地事物的支持。分布式事务比较复杂,有专门的方法,后面有机会再介绍。controller层controller位于最上层,和外部系统打交道。把这层叫做“业务场景层”可能更贴切一点,它的职责是通过service提供的服务,实现某个特定的业务场景,并以http、rpc等方式暴露给外部调用。1、聚合参数前端传参方式有多种:query、body、param。有时搞不清楚到底应该从哪区,很不方便。我一般是自定义一个@Param()装饰器,把这几种参数对象聚合到一个。实现和使用方式如下:// common/param.tsimport { createParamDecorator } from ‘@nestjs/common’;export const Param = createParamDecorator((data, req) => { const param = { …req.query, …req.body, …req.param }; return data ? param[data] : param;});// user/user.controller.tsimport { All, Controller } from ‘@nestjs/common’;import { UserService } from ‘./user.service’;import { UserAddDto } from ‘./user.types’;import { Param } from ‘../common/param’;@Controller(‘api/user’)export class UserController { constructor(private readonly userService: UserService) { } @All(‘add’) async addUser(@Param() user: UserAddDto) { return this.userService.addUser(user); } @All(’list’) async listUsers( @Param(‘pageNo’) pageNo: number = 1, @Param(‘pageSize’) pageSize: number = 20) { return this.userService.listUsers(pageNo, pageSize); }}2、统一返回结构一个api调用,往往都有个固定的结构,比如有状态码和数据。可以将controller的返回包装一层,省去一部分样板代码。下面是用Interceptor的一种实现:// common/result.tsimport { Injectable, NestInterceptor, ExecutionContext } from ‘@nestjs/common’;import { Observable } from ‘rxjs’;import { map } from ‘rxjs/operators’;export interface Response<T> { data: T; code: number; message: string;}@Injectable()export class ResultInterceptor<T> implements NestInterceptor<T, Response<T>> { intercept( context: ExecutionContext, call$: Observable<T>, ): Observable<Response<T>> { return call$.pipe(map(data => ({ code: 200, data, message: ‘success’ }))); }}所有的返回将会包裹在如下的结构中:3、参数校验还是留给service层吧nest提供了一套针对请求参数的校验机制,功能很强大。但使用起来会稍微繁琐一点,实际上也不会有太多复杂的参数校验。个人觉得参数校验可以统一留给service,assert库可能就把这个事情搞定了。小结本文讲的都是一些很小的点,大多是既有的理论。这些东西不想清楚,写代码时就会非常难受。大家可以把这里当做一个规范建议,希望能提供一些参考价值。上一篇:nestjs后端开发实战(一)——依赖注入 ...

November 13, 2018 · 2 min · jiezi