MVC3|学习笔记

简介: 快速学习MVC3

开发者学堂课程【高校精品课-上海交通大学 -互联网应用开发技术MVC3】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:https://developer.aliyun.com/learning/course/76/detail/15768


MVC3


内容介绍:

一、后端工程

二、 Annotated Controllers

三、关于跨域

四、 Spring 定义


一、后端工程

现在来解释为什么会有这些层。

image.png

Entity 层是从数据库里面实例化出来的那些实体,对应的就是数据库的那些表。在 Entity  层的上面有一个 Repository 层,在这个里也可以写一个方法,用 Query {HQL}  即Query 和 {HQL} 的语句去定义一些你自定义的增删改查的方法。这里已经定义好一些现成的,比如说 found By ID,上课给过一个表里面有定义好的东西,这一层是从关系型数据库生成的。 Entity 和 Repository 这两层是靠ORM 映射工具得到的。

数据访问对象为什么会出现,因为在很多地方, Repository 就是 Dao 数据访问对象。 因为 user 的一部分来自于 Mycircle ,一部分来自于 MangoDB 。

有一个 user 的 Repository 处理如何从 Mycircle 里拿相关的信息,另外一个user 的 Repository 是在处理如何从 MangDB 返回信息。但是不管怎么样都需要两个 Repository 从两个不同的 Repository 中继承。在 DAO 这一层去把对一个完整的 user 的处理变成对两个 Repository 的访问。也就是说当数据来自于两个不同的地方的时候,可以在上面加一层,再加一层就要做一个接口和实现分离。Service 层就直接再调 DAO 里的东西用来针对接口编程,至于这个接口的实现是在另外一个类里。

它的好处就是既可以用 spring 写,也可以用 stress 写。无论写一个,在上面的Service 层是对接口来编程,所以上面这些代码都不需要修改。Service 层在完成一个面向业务的一个逻辑。

例如:购买书籍需要下订单,而下订单就涉及到找到用户以及用户购物车里的书。
它找到购物车后读取购物车里的书,然后就产生一个订单并发布下下订单这个 Service 就会涉及到多个数据的操作,包括 user ,order ,book,购物车 等。所以 Service 是在实现业务逻辑层,它面向的是用户的需求,它会被Controller 调用,所以它也有接口和实现,要做接口和实现的分离。Controller 层是面向最前端发过来的请求。它的作用就是接受到一个 URL 请求之后,去调后面的 Service 并让它们进行处理。本身不把业务逻辑封装到 controller 里, controller 只是做请求转发。所以它不含业务逻辑,它更像是含一个业务的流程,就是来了Control转给别的去处理。不管怎么转,可以通过这个转发逻辑的变化去改变业务流程的执行顺序,但是具体的还是由 Service 在后面来实现。也就是说,如果 Service 有 A B C  三个,前端来了个 URL 。某一个 URL 被一个 Controller 去处理,那它可以说发 A ;它过了一段时间觉得业务流程要发生变化,它要先发给 B ,然后再发给 A 。

由此可知, A 和 B 本身不做修改,只是在 Controller 内进行修改,所以它像是在控制流程,关键的是在面向前端的请求。在系统里肯定有一些叫横切的东西,就是无论是服务,还是 DAO ,还是一些其他的 Controller 。

可能会有一些都需要用到的东西,就把这些东西都抽取出来变成一个工具类,放到 Utils 包里。不一定是都要用到,但是它相对功能独立,别的某一个类用的也是一样。反正是要用于代码复用的,就会有 message 的相关的东西,也有关于绘画相关的东西,在最上面还有一个 constant  就是类似于配置的一些东西以及一些常量的东西就放在这里。 以上就是整个后端工程的样子,那前端的是放在页面里的是不用说的,因为最终用的是 react 。那么后端就是这样的架构,所以后端的架构体现了两个特点。第一个是分层,就一定是分层来处理的,因为所有代码都很臃肿,如果全部都写到 Controller 里。

从功能角度来看,也许实现了无论是浏览书籍还是下订单之前,可能确实实现了。

但是从代码维护的角度来说,这样做非常不好。第二个特点就是在做接口和实现的时候需要去分离,接口和实现分离的作用是代码全部针对接口编程就是代码里出现的全部都是接口。比如说, Service 被 Control 调用 Service 里出现的只是 Book service  接口,并没有 Bookserviceimpl  这一类的身影。对于接口编程,接口和实现应分离开。这样如果实现发生变化,对于使用这个接口代码是不需要做修改的。接口和实现分离的另外一个好处就是,这个实现不仅可以去做修改,还可以做替换。意思就是,如果 A 实现不太好就可以换一个 B 实现。

总的来说,接口是最稳定的,实现是最不稳定的。越多的实现越不稳定,越少的实现越稳定,代码应该依赖于一个稳定的东西。如果想要实现稳定就要用到依赖注入。


二、 Annotated Controllers

1. Spring MVC

Spring 基于注解的这种编程模型里,它提供了两个 @Annotation 可以来标注在监听 URL 请求时的相关配置。

一个叫@Controller,另一个叫 @RestController 。在 Controller 里,要对一些方法去说明它们在监听什么的是方法,就是 HTTP 发过来请求的什么方法,是 get 还是 post ;且它监听的是 URL 。因为是用  @Annotation  在进行映射,所以方法名可以随便写。它可以叫 grating ,也可以叫 handle 。

在对 handle 进行处理的时候,会给一个 model ,这里面也可以带其他参数,比如 request ,parameter 等来表示请求。也就是说,这个 model 是以处理完后要组装结果的地方。

当在里面放入相关内容时, model 就相当于在 map 里放入一个界和值即 map<key,vcl> 。在里面放一个属性,属性是 message ,而 “Hello World﹗” 就是它的值。然后让它返回,实际上就是要跳到另外一个页面上去。

image.png


2. Declaration

在做这种 controller 的声明的时候,可以有两种方法。就是写的 controller 如何在应用后调用到方法,即 Springboot 启动后会扫描到相关的信息,于是对着 URL 发的请求就会被相应的方法处理。一种是 spring boot 自动扫描;另一种就是专门写一个叫做 WebConfig 的类,把要描述的所有的内容全部写里面,然后在前面用一个 Configuration来描述,这就是这个应用里面所有的配置信息。

看有关跨域的例子就可以将信息写入相关的类里。用 @ComponentScan 去描述,这个配置文件会作用于 “org.example.web” 里所有的类,所以 spring boot  在加载时就能够扫描到。如果不用 Annotation 的方式,那就用xmlns来描述。这就是 application.context. 文件,它的作用是一样就是做一个扫描。为什么叫做 @component 扫描?在spring的世界里,它认为写的东西都是一个一个的 @component ,比如刚才写的 @controller 就是一个 @component 。所谓的扫描,就在扫描了整个工程包里所有的 @Component 、@ Annotation 标注过的进行记录,就知道这是由 spring 监管的。

其中 controller 和 rest control

都属于 @component 的一个子类,所以它们的信息会被扫描到。所以spring加载之后, @Controller 和 @GetMapping 会被扫描到,
Spring 就会知道 URL 的请求可以被其内部的方法处理。

image.png


3. ResquestMapping

这里的 controller 可以写的有很多,比如get 、post 、put 、delete 、patch 。但 Patch 是前面要达到所有的在一起,一般不会去写。

要注意的是 @RestController 和 @Controller 的差异。@RestController 中的 getPerson 在监听请求,如果这个请求前面有 @RequertMapping 就说明这个请求监听的是 /persons/1 ,括号里的表示的是个变量。

因为 @PathVariable Long id 是在路径里,这个方法被调用的时候有一个参数而这个参数就是路径里的变量即 id 。这是说明怎么映射的,那这个 Rest 就是要求返回一个 person ,而之前要求写的都是在返回一个字符串,这个字符串表示要跳到哪一个页面的 URL 。返回一个 person 就是 @RestController 的含义,就是 @RestController会把一个 java 对象转成一个 json  字符返回到 client 端。

而在例子里返回一个 book ,原因是 rest 实际上是将 person 转成了 json 对象返回到前端。

所以 React 拿到结果的时候就已经转成了一个 json。而 @postMapping 就是对 post 这个方法进行处理,而 post 的状态就是被创建还要求返回的结果是创建成功的,这就是一个映射。很多情况下 @Controller 都是 rest 因为这样可以省掉一些过程。

image.png

刚才的这个路径里有一对大括号,大括号里的东西就表示的是通配符,表示的是个变量。{owner Id} 和{pet Id} 分别就是两个在路径里出现的变量,就分别赋给了{owner Id} 和{pet Id} 对应的位置。实际上不是说它的名字一样,而是说它们对应的这个顺序一样。为了不引起歧义,所以可以把这个名字写成一样的。这样就可以映射过来,映射后就可以在代码里读到 {owner Id} 和{pet Id} 的值。如果这个control里面,包含很多个方法。它们的方法,响应的路径的前一部分都是一样,只是后面有差异,就可以用这种方式进行映射。

image.png


4.@RequestParam

这个路径来的变量来自于请求,因为发请求的时候请求体里有东西放进去了。通常来说,在一个页面里让用户填了一些东西,这些东西是以一个 Form 的方式发的,那他的内容就在这个请求参数里头。这样过来的信息是 @RequetsParam 而不是 pastvary。

image.png

三、关于跨域

1. 如果用一个 @Restcontrol 对一个地方发出请求的时候,涉及到跨域。跨域就意味着要在前面 @CrossOrigin 这个地方写一下允许跨域。也就是说,当前这个应用如 /Account/1 2……这样的路径,获取时对这个请求可能是 localhost:80,但是 localhost:3000来请求要求要访问这是一个跨域的动作,而加上 @CrossOrigin 的目的就是表示允许被跨域。

跨域在前端只能做的是当前在3000端口可以向80端口移动或者是一个远程的,比如说是202.120.40.80的地方访问重要的是允不允许访问后端的这一动作。跨域可以在整个类前去描述,也就意味着整个 @RestController里面所有的 URL 全都允许跨越。跨域的参数就是允许跨过的 URL 的最大连接时间,请求在进行跨域访问的时超是不允许。

image.png

也可以这样,这是一个极端做法,把所有的配置都写在一个类里并把它定义成是  Configuration 来描述。然后写一个叫做 addCorMappings 跨域映射的方法。

这个方法是 addCorMappings里定义好的,所以再看 @Override 并给它一个具体时间,它的参数就是一个跨越注册表或者是配置表。需要这个配置表里添加进去相应的跨域信息,就是对于当前的应用的什么位置,发请求是允许跨域的,跨越是允许谁在跨越,而跨越快的方法不能是 get和 post ,只能是 put 和 delete ,然后在这个请求头里又允许它是什么。

具体还是要去看跨越本身,它支持哪些参数。最应该关心的是当前应用对谁允许跨越访问。来自不同域的请求所允许的以及允许来自哪个域的访问就可以跨域了。因为现在前后端隔离,所以跨域是一定要解决的问题。Fetch 既不属于 react 也不属于 vew ,而是一个独立的 API ,在两个了里面都可以用。Axros  在 vew 中更加方便。Axros 和 Fetch 可以不跟框架绑定,本身只是说是跨域的数据访问,甚至不是专门去做跨域的,只是因为用这种方式访问所以会被同源检查而涉及到跨域的动作,而跨域本身是靠后台允许才可以,跨域是靠 URL 来的,这是用一个配置文件来描述跨域的配置。

image.png

2. 也可以在代码里写一个内置的跨越过滤器,就是 Spring内置的跨域过滤器来处理。就是先创建一个空的跨域的对象,然后在里面设置相应的东西,然后就会允许跨域对谁进行访问,允许的配置在哪里。

用 source 源对跨域过滤器进行控制,在 spring 里面直接就有跨域但是要告诉它怎样跨域过滤器,于是就通过 source 对象告诉它允许哪个域做什么样的跨域动作,然后 spring 的 Filter 就会来接管所有的请求再进行过滤。如果有跨域访问但是不满足跨域的条件就无法跨域。

image.png


四、 Spring 定义

@Conponent , @Reository , @Service 和 @Controller都spring定义的。

image.png 

Annotation 不是  Java 定义的而是  Java 允许这种机制。而后面三种其实是前面那一个的特例,按照 @Annontation的实践角度上来说,这三种本质上也是component。

举个例子,在 @Controller 中可以看见 controller ,在  @Service 里有 service ,在 @Reository 里有 repository 。这些 Annotation 都是 @Conponent 的子,这些东西是 Spring 在加载的时,工程目录里头的扫描的时候,它就在扫这些东西。凡是被他们标注过的类,就是那些 Controller 也包括副类,凡是被标注过了的,就是带着 Annotation ,全部要被spring托管,这是他的基本含义。它托管以后就会去做一些,比如什么时候创建这样的一个对象去做它的生命周期的管理和做他一些相应的参数配置。就像刚才那个,一个 URL 被 @Controller 拦截以后靠它去处理,Spring 扫描这些信息之后,就是要知道这些操作的逻辑。他们的区别只是为了让你的代码分层显得更合理,在19号层出现的就用 @Repository,在 @Service 层出现的就用 @Service ,在前台控制出现就用 @Controller;本质上它们没什么区别,都是 @Component。之所以区别就是希望代码分好层后,可以一眼代码分别是什么层。

细节上它们是有一些区别的,但是大体上没有什么区别都是 @Component ,都是由 Spring 托管。其实目的就是用不同的代码表示不同的层,但是总体而言,其实只有一个作用,就是告诉 SpringBoot启动了之后所需要扫描的就是这些 Annotation 。就知道这些东西由 SpringBoot 托管,就涉及到了 LOC 的问题。现在来看看要托管什么,代码里有一个 @BookService 的类叫做 bookservice 然后就可以直接调用 {findBookById} 和 {getbooks},为什么这个对象只声明而没有定义却能够被直接调用,为什么没有抛空指针出来;

显然有一个东西去创建了一个对象赋给了 bookService。这些都是由 Spring 做的,Spring 托管后就了解到对象的创建和销毁。实际上是 Spring 扫描到这些东西后,知道这个类需要托管,再看里面写了 @Autwiced,它会自动创建 boolservice 对象赋给 bookservice 。

但是 bookservice 是个接口,接口是不能创建对象的,那就在 bookserviceIlmpl 中寻找,发现实现了 bookservice,而bookserviceIlmpl 又被 Spring 扫描到了,所以就可以创建一个实现类的对象赋给 bookservice 对象,这些全都是 Spring 做的。Spring 看到了 Bookservice 这类,然后看到里面的对象只声明没定义,于是 Spring 就帮它去定义,定义的时候发现这个对象只是个接口,那就去找这个接口的实现类,再从被 Spring 扫描的实现类中去找,找到后 BookserviceImpl 和 bookservice 存在继承关系,如果里面有两个类都实现了 bookservice 的接口,就看二者的名字谁更接近就用谁,然后就可以创建一个实现类的对象赋给 bookserviceImpl 的对象,然后才能调用方法,所有一切的复杂性都由 Spring 做了。

这指针对接口,对接口编程直接调用接口里暴露出来的方法,至于到底用什么实现类在代码里就不需要写死了,这就是接口和实现分离是靠 Spring 框架来实现的。但 Spring 没有那么智能,是靠 Annotation 的基础上去分析出来的。

image.png

这些子类要分的这么细的,是为了支持分层的应用,可以从概念上区分开,如果用了更复杂的工具,处理不同的 Annotation 就有不同的处理逻辑,就给予一个空间去做这件事。

原因就是 Annotation 不是给 Java 用的也不是给编译器用的而是给像 Spring这样的框架用的。

如果想在 Spring 上加一个外挂,就要写一个代码去处理这些  Annotation ,对于 @Reository , @Service 和 @Controller 有不同的处理方式,所以分开是最好的。

从本质上来说,它们都属于 @Component ,都由 Spring 来托管的;从细节来说只是表达的概念不同19层、表示层和服务层。都写成 @Component 也可以,用 @Service 会比较好显得更清楚,显示出代码明确的分层架构。除了 Spring jpa 里的就是@Reository , @Service 和 @Controller 三个。

@Controller 里面最常用的是 @RestController,这样可以保证在后端返回的是一个对象的时候可以比较容易的发送到前端,这种 @Controller 会自动的转成 json 对象发送到前端,而这种  Controller 会自动转化成  JSON  对象发送到前端变成字符串。

在返回的函数直接是一个  json。

实际上在用 @RestController 时候会比较容易,不管返回的是什么都会变成 json ,甚至可能是一个 list 里面放了一组 book ,这样就节省了代码书写麻烦。为什么要讲 MVC 虽然 v 在前端但是必须要知道 c 是怎么写的。在写 c 的时候就是 @Controller 代码里面。本质上都是一种  servlet 的表现。

相关文章
|
4月前
|
Java 容器
mvc02
mvc02
26 0
|
4月前
mvc03
mvc03
19 0
|
10月前
|
前端开发
【MVC】初识
【MVC】初识
41 0
|
前端开发 Java
|
设计模式 前端开发 Java
|
XML JSON 前端开发
MVC 1|学习笔记
快速学习MVC 1
83 0
MVC 1|学习笔记
|
XML 存储 前端开发
MVC1|学习笔记
快速学习MVC1
79 0
MVC1|学习笔记
|
前端开发 Java
|
前端开发 数据处理 开发者