让我们追根溯源,从Web的发展讲起吧。
早期,Web开发还比较简单,开发者经常会去操作web服务器,并且他会写一些HTML页面放到服务器指定的文件夹(/www)下。用户使用浏览器输入对应的URL地址,访问到服务器上具体的html文件,服务器将具体的内容返回给浏览器,浏览器将html解析成视图的形式展示出来。浏览器中显示的网页仅是静态的图文组合而已,浏览者可以在网页上阅读信息,但无法进一步地发表意见、查询信息或进行在线购物等商务活动。从这里可以看出开发人员不仅仅要处理业务逻辑和页面展示,还需要完成网络部分的编写。
过了一段时间,人们发现静态网页远远不能满足大家的要求,用户需要跟服务端进行更好地交互。最简单的需求就是用户提交不同的信息,如用户名和密码,能够根据不同的用户返回与之对应的信息。首先是CGI的出现缓解了一点问题,制作一个简单的交互页面,却需要写大量的C代码,再之后微软强势推出ASP搭配IIS服务器,既解决了网络模块的编写问题,又解决了复杂性的问题,并且提供了访问数据库的接口,使得与数据库间的交互容易了很多。貌似解决了好多问题。后期又出现了PHP跟ASP也类似。这时候这两种语言都大行其道,其中最出名的应该是LAMP(Linux、Apache、MySql、PHP),深受中小型企业喜爱。
JAVA作为这个时期最流行的语言,自然要在Web领域分一杯羹,此时Java Server Page(JSP)应运而生,此时的Java Web应用整个都是由JSP页面组成的,JSP页面接收处理客户端请求,对请求处理后直接做响应。用少量的Java Bean与数据库进行交互。也就是说JSP充当了展示和请求处理的工作。
大家想想看这样会带来什么问题?没错,这样子的话,代码的重用性就会很低了,因为控制逻辑跟表现逻辑混杂在一起,Web开发者不仅仅逻辑要写对,而且展示的部分也要调试,这个过程非常地痛苦。确实正是由于这个原因,JSP没多少人用,它的本质跟ASP、PHP没多大区别。
标准做出来了却没有多少人用,他们自然不会善罢甘休,马上就想到了,业务逻辑跟展示逻辑不应该混合在一起,应该将其分开,接下来Java Web正式进入Model 2的时代,由Servlet来接收客户端发送过来的请求,Servlet中只包含控制逻辑和简单的前端处理;控制逻辑部分交给Java Bean来完成,其实这也是很有道理的,毕竟前期Java Bean只用来跟数据库进行简单的交互,交互完之后又传给JSP进一步处理,为啥不让Java Bean直接进行逻辑处理呢。Java Bean完成了复杂的逻辑处理之后,最后将结果给JSP进行展示。这时候分工很明确了,JSP只负责显示逻辑的部分。这就是非常经典的Java Bean+JSP+Servlet(MVC),这也就是著名的MVC设计模式。由于Model 2 引入了MVC模式,实现了组件化的管理,因此也具有了更好地扩展性。
大家觉得这么设计是复杂了还是简单了呢?
毫无疑问,当然是变麻烦了,本来实现一个HelloWorld,你只需要写一个JSP文件,结果现在却要写JSP和Servlet了,前期的开发成本自然是增加了,但是后期的维护成本却降低了不少,Model2就是为了降低系统后期维护的复杂度应运而生的。
可能有些同学还不太清楚,MVC每个部分是干嘛的,这里我啰嗦点我再重复一下,毕竟我们今天的题目是Spring MVC。
Model负责处理业务逻辑并且与数据库进行交互,以及通知视图更新数据;
View负责展示数据;
Controller负责请求处理,并调用Model的方法,然后选择相应的视图进行相应的展示;
整合在一起说,就是在Model2架构中,Servlet作为前端控制器,负责接收客户端发送的请求,在Servlet中只包含控制器逻辑和简单的前端处理;然后,调用后端JavaBean来完成实际的逻辑处理;最后,转发到相应的JSP页面处理显示逻辑。
这种开发套路让Java在Web领域生机勃勃,然后又到了2001年Struts框架诞生,由于其易用性,以及有丰富的标签支持并且能与Spring和Hibernate整合大大提高了开发效率,所以迅速成为了Web开发领域中的霸者。但是由于Struts1的线程安全问题、单元测试困难以及其对Servlet的依赖性太大等原因,后来又出现了Struts2,但是Strust2跟Spring结合存在多种问题,毕竟他们本来就不是一家人嘛,近年来Struts2还存在漏洞问题,所以用的人也越来越少了。此时Spring MVC渐渐走入开发者的视线中,成为了最广泛的Java EE开发框架。
我们回顾历史就回顾到这里吧。知道了Spring MVC的由来,现在我们想想就目前的这种JSP + Servlet + Java Bean这种开发套路有没有什么可以改进的地方。这里可能会有点难理解,不过我们需要大概了解它的设计过程,知其然还得知其所以然,接下来我们尝试一下能不能设计一个架构。
具体图文教程请参考:
MVC模式来实现用JSP页面显示Hello World
一个一个来改进,首先是作为控制器部分的Servlet,它主要是负责接收请求并找到对应的JSP返回给客户端。在上面的代码中,我们看到了我们首先需要在web.xml文件中配置Servlet,访问具体的URL之后tomcat会帮我们跳转到对应的Servlet去,然后在对应的Servlet下的doGet或者是doPost方法中。
Servlet中常常会有这样的语句:
request.getRequestDispatcher(“/hello.jsp”).forward(request, response);
跳转到对应的jsp。首先在web.xml中配置这个其实都是一些重复性的工作,唯一不同的是可能Servlet名字不同,对应不同的URL。所以我们需要弄一个拦截请求的前端控制器,拦截到对应的URL之后再将请求转发到我们自己的控制器,还有就是返回JSP页面的部分,也需要这个前端控制器来帮我们定位到具体的JSP页面。
大家先回想一下我们一般的网站是有登录界面的,登录进去之后才能访问到具体的资源吧?
也就是说浏览器请求相应的资源首先肯定得经过一定的校验,所以这里有一条处理器的执行链,前端控制器还需要帮我们组成这条处理器的执行链。
简单的说,现在前端控制器有几个功能:
1、生成一条处理器的执行链
2、处理请求的映射:将具体的URL映射到具体的Servlet的方法上,当然这个过程是按照前面生成的执行链往下执行的。
3、执行完上面的执行链之后,需要将执行的结果渲染到视图(View)里。
很明显的是,前端控制器的功能太复杂了,我们再根据上面的功能继续细分一下,分出其他部分吧。
生成处理的执行链——交给处理器映射来做(HandlerMapping)
处理请求的映射——我们暂且叫它处理器适配器好了(HandlerAdapter)
这些事情总需要有个指挥官把,指挥官就由前端控制器来担任(Front Controller)
接着,我们再想想我们现在展示的方式是不是多种多样,单纯用JSP已经不能满足我们的要求了,我们所需要的试图不仅仅是JSP,还可以是EXCEL、JSON、XML、PDF等等,所以视图方面我们还需要一个能够解析出具体视图的视图解析器,暂且叫做ViewResolver。来到这里我们现在的Servlet相当于仅仅是处理业务逻辑了,也就是相当于Java Bean了。再整合一下,就变成以下这样子了。
我们自己设计完了MVC之后,接下来我们来对比一下真正的Spring MVC,来向大佬致敬。
(1)接收到客户端发来的一个请求,请求被DispatchServlet截获。
(2)DispatchServlet对请求URL进行解析,得到URI。根据URI调用HandlerMapping获得该Handler配置的所有相关的对象,包括Handler对象及其拦截器,这些对象会封装成Handler的执行链对象。
(3)HandlerMapping将执行链对象返回给DispatchServlet。
(4)(5)DispatchServlet根据获得的Handler选择合适的HandlerAdapter,HandlerAdapter处理这条执行链中的所有Handler对象并执行其相应的方法,如Hello方法。
(6)(7)Handler执行完之后,Handler返回模型和视图给HandlerAdapter。HandlerAdapter再将模型和视图返回给DispatchServlet。
(8)(9)DispatchServlet把对应的视图信息传递给ViewResolver,ViewResolver进行相应的视图渲染。
(10)(11)渲染视图时, 将Model数据传入视图中进行渲染。
(12)最后将渲染后的视图返回给客户端。
大家听了之后可能会觉得这个东西怎么这么复杂,但是实际上Spring MVC帮我们完成了HandlerMapping、HandlerAdapter、ViewResolver ,真正需要我们自己开发的就只有View和Handler的部分。
实际上内部的处理过程还有很多细节,有兴趣的同学可以深入地去了解一下,一定会获益匪浅。
将上面的很多细节屏蔽起来, 从这个图里面我们可以看出,我们写程序需要哪些东西。
1、前端控制器(这个不需要我们具体去写,我们只要知道怎么配置就行了)(前端控制器这里实际上包括了三大组件处理器映射器(HandlerMapping)、处理器适配器(HandlerAdapter)、视图解析器(ViewResolver))
2、Handler部分(这里是我们需要实现的业务逻辑部分)
3、我们先简单一点,用Jsp页面来进行展示。
详细步骤请参考博客:
https://www.java-success.com/spring-mvc-beginner-tutorial-step-step/
https://www.java-success.com/02-spring-mvc-form-submission-tutorial-step-step/
接着我们来讲讲Spring MVC的项目构建过程:
1、由于我们现在都是用Maven来管理项目中的Jar包的,自己复制Jar包到项目的lib文件夹的时代已经过去了。Maven之前不知道大家有没有学过,这里大家先跟着用,因为Maven又是可以讲一节课的东西。
2、编写POM文件,这里主要是要引入Spring和Spring MVC的相关依赖,引入之后,可以看到项目的maven dependencies目录下面就有Spring和Spring MVC相关的Jar包。
3、配置web.xml文件,在SpringMVC中web.xml配置文件需要配置以下四个部分:
(1)Spring的上下文(context):即contextConfigLocation,用来指定SpringMVC的Spring IoC的配置文件在什么位置,这样Spring就会找到这些配置文件去加载它们,这里可以支持正则表达式。(这里如果不配置的话,会在classpath的路径下找application-*.xml作为IoC的配置文件,找不到的话启动就会报错)。
(2)DispatchServlet:实际上就是一个拦截请求的servlet,用来拦截通过浏览器发送的URI请求,拦截给对应处理器(Handler),这里中间还有一些细节,这里就不细说了。
(3)ContextLoaderListener:实现了接口ServletContextListener,配置这个的目的是在web项目初始化之前,先进行SpringIoC容器的初始化,再最后web项目关闭之时,完成Spring IoC容器的资源进行释放。
4、配置三大组件的xml文件
这里是对HandlerMapping、HandlerAdapter、ViewResolver的配置
5、第五步所说的编写控制器、服务和Dao是什么意思呢,其实我们在编写我们自己的控制器的时候又会继续划分成三层,Controller层一般是用来接收请求,并进行一些简单逻辑的处理,Service层进行复杂逻辑的处理,Dao层复杂与数据库进行交互。Controller作为上层会调用Service层的服务,Service层需要用到数据库的话就回去调用对应的Dao来完成数据的读写。最后Service层将结果传给Controller,Controller将结果给到View,视图解析器解析完视图之后,将结果给DispatchServlet,由它将结果返回给客户端。
6、第六步就没有什么疑问吧,这部是编写视图文件,这里主要以JSP为例子,实际上视图文件种类繁多,现在用的比较多的是Thymeleaf、Velocity等。
7、第七步就属于配置应用服务器的操作了。
8、最后配置完之后肯定是要启动应用服务器,应用服务器就会去加载我们自己写出来的应用。然后我们就可以通过浏览器来访问我们自身的应用了。
下面我们就来看编写Controller、Service、Dao这些可能会用到的哪些注解。
首先是Controller,用了@Controller标记的类就是一个Spring MVC Contoller对象,DispatchServlet会扫描使用了此注解的类的方法,并检测该方法是否使用了@RequestMapping注解。
刚提到的RequestMapping,这里也要仔细说明一下,@RequestMapping可以注解在类和方法上的,而@Controller是注解在类上的,我们一般会这么用。
具体使用就像这个图这样:
这个项目的名称是springmvc-demo1,那么我们在浏览器中的uri就应该写成:
/springmvc-demo1/login/hello ——》对应hello方法
/springmvc-demo1/login/login ——》对应login方法
也就是说如果在类中加了RequestMapping,那么所有的方法对应的URI前面都要加上
@Controller
@RequestMapping
• Spring MVC使用此注解为控制器指定可以处理哪些URL请求到控制器的类定义及方法定义处。
• 类定义出:提供初步的请求映射信息。
• 方法定义处:提供进一步的细分映射信息。
• DispatchServlet拦截请求后,就通过控制器上的@RequestMapping提供的映射信息确定请求所对应的处方法
接着看看这两个注解,RequestParam主要是将客户端获取过来的参数赋值到方法中的形参,实际上跟HttpServletRequest.getParameter (“loginname”);作用是类似的。
@ResponseBody 也就是访问以上这个链接的时候,会直接返回abcd给客户端,而不是返回页面。
@RequestParam
@ResponseBody
• 此注解支持将返回值放在response体内,而不是返回一个页面。
@RestController
• 此注解是一个组合注解,组合了@Controller和@ResponseBody。
更多详细内容请参考博客:
http://www.cnblogs.com/lzj0616/p/7542632.html
接着看看这两个注解,PathVariable用于接收请求URI路径,将路径作为参数接收。
@RestController这个是个组合注解,同时具备@Controller @ResponseBody的功能,也就是说当你开发一个和页面交互数据的时候,就会用到这个注解。
大家看这个例子,返回的数据本来是一个User的类,这个类里面有两个属性一个是loginname、一个是password,用了RestController之后直接就转成了Json字符串了,这里还要注意的是因为produces里面定义了类型,而且pom文件里面也要添加json相关的jar包才能支持。
大家了解完刚刚的MVC开发流程之后会不会有以下这几种想法呢,首先我开发个hello-world还得添加n个配置文件,其实最后有用的就是一个helloworld的类。
每次都要配置几个组件,实际上都是重复性劳动,而且部署上linux系统最少最少也要装个Tomcat吧。
这些问题都不严重,需要支持其他的技术的时候才是问题,例如要在工程中支持数据库,得加个数据库的xml文件吧,再支持个redis,又得来个配置文件,这些配置文件里面还要配置一大堆我可能并不关心的属性,还能让我好好写代码吗。那么麻烦我还不如用动态语言呢,用Scala、Node.js什么的都比这个方便多了,各位是不是该考虑转行了呢?
要是真那么严重的话,也就不会开这门课了,下面我要介绍让Spring MVC焕发活力的Spring Boot,它根据“习惯优于配置”的原则,其内部存在大量的配置,此外还内置一个习惯性的配置,让你无须手动进行配置。更方便的是,它直接将应用服务器如Tomcat等直接集成到了项目中,使用Spring Boot你可以不用或者是只需要写很少的配置项。
Spring Boot 有以下这些特性,首先是独立运行的Spring项目,什么意思呢,Spring Boot以Jar包的形式独立运行,运行一个Spring Boot项目只需要使用java –jar xx.jar就可以了。
刚说了它可以把tomcat内嵌到工程里面。无须另外部署容器。Spring Boot会根据在类路径中的jar包、类,为jar包里的类自动配置Bean,这样会极大地减少我们要使用的配置。
Spring 4开始提倡使用Java配置和注解配置相结合,Spring Boot不需要任何xml配置就可以实现Spring 的所有配置。
刚听完Spring Boot的特点,我们赶紧来看下Spring Boot比起Spring MVC到底简化多少吧。
首先我们创建Spring Boot工程需要选择“Spring Starter Project”,选择要使用的Spring Boot版本之后再选择可能会用到的组件。
第二步就可以写我们的业务逻辑部分了,编写Controller、Service、Dao层的Java代码,一般我们Dao层会用MyBatis,Spring Boot也带了JPA来操作数据库。
第三步编写视图文件,Spring Boot用的比较广泛的模板引擎是Thymeleaf,而且Thymeleaf跟语句其实跟HTML类似,它是一个Java类库,是一个xml/html5/xhtml的模板引擎。
最后将Spring Boot 打成Jar包之后,直接部署到服务器上一键运行。
最后值得一提的是,Spring Boot只是帮我们做了一些默认的配置,有时候这些默认的配置常常不能满足我们的要求,例如端口默认是8080,我们可以在application.properties文件中指定我们的端口等其他配置项。例如server.port=8088.
详细图文教程请参考博客:
https://spring.io/guides/gs/spring-boot/