springMVC是一个MVC的开源框架,springMVC就至关因而Struts2加上sring的整合,那么springMVC和spring是什么样的关系呢?在百度百科上有一个很好的解释:springMVC是spring的一个后续产品,其实就是spring在原有基础上,又提供了web应用的MVC模块,能够简单的把springMVC理解为是spring的一个模块(相似AOP,IOC这样的模块),网络上常常会说springMVC和spring无缝集成,其实springMVC就是spring的一个子模块,因此根本不须要同spring进行整合。html
工做原理图:前端
能够看到这里分为大体11个步骤,这11个步骤的任务是这样的:java
一、用户发送请求至前端控制器DispatcherServlet。web
二、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。spring
三、 处理器映射器找到具体的处理器(能够根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(若是有则生成)一并返回给DispatcherServlet。apache
四、DispatcherServlet调用HandlerAdapter处理器适配器。后端
五、 HandlerAdapter通过适配调用具体的处理器(Controller,也叫后端控制器)。api
六、Controller执行完成返回ModelAndView。网络
七、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。架构
八、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
九、 ViewReslover解析后返回具体View,这个view不是完整的,仅仅是一个页面(视图)名字,且没有后缀名。
十、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
十一、 DispatcherServlet响应用户。
图中能够看到,DispatcherServlet(前端控制器)占据了很大的一部分,事实也是这样,springMVC中,DispatcherServlet是他的核心。
接下来再看一下springMVC组件及其核心步骤的说明:
黄色字体和绿色字体是对组件做用的说明,其中黄色字体说明的组件是框架提供,绿色字体说明的部分是要由工程师实现,红色字体是核心架构的具体流程步骤
看完了原理,再来经过注释的方式,写一个Hello World,熟悉一下过程。
maven须要的相关依赖,springMVC须要的spring-webmvc,日志相关的slf4j-log4j12,JSP相关的jstl、servlet-api、jsp-api。
由于DispatcherServlet自己就是一个Servlet,因此要在web.xml配置:
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
复制代码
前端控制器要协调各个组件干活,因此就要依赖于配置文件,SpringMVC要读取的配置文件是要是本身手动建立,怎么建立?配置文件应该怎么命名?先来到DispatcherServlet的源代码中:
能够看到DispatcherServlet继承了FrameworkServlet,FrameworkServlet是Spring web框架的基本servlet。为集成提供了基于javabean的总体解决方案中的Spring应用程序上下文。FrameworkServlet注释中有这样一段描述:
大体意思就是,默认的SpringMVC配置文件名字是“servlet-name”-servlet.xml, 而这个“servlet-name”就是在web.xml中配置的的名字,这里就是springmvc,固然你也能够起其余名字。而后读取的默认位置是在/WEB-INF/“servlet-name”-servlet.xml,因此这里要在WEB-INF下面建立的是名叫springmvc-servlet.xml的配置文件,由于他和Spring都是一个体系内的,因此能够直接建立spring的配置文件模板:
如今有了配置文件,那么改在配置文件中配置什么东西?能够回到SpringMVC工做流程图看到,在springMVC配置文件中起码要配置,映射器HandlerMapping、适配器HandelAdapter、处理器Handel(Controller)、视图解析器ViewResolver。View的渲染不是SpringMVC来完成,因此这里不须要配置。
先来配置HandlerMapping,找到HandlerMapping,他是一个接口,因此要配置的是HandlerMapping的实现类,找到HandlerMapping源码,查看他的继承树:
不看已通过时的(这里Spring基于4.3的一个版本),咱们要经过请求中的url和HandlerMapping找处处理器,因此使用BeanNameUrlHandlerMapping,类名中的BeanName也就是要找的处理器,在注释中也有说明,若是url是/foo ,对应的处理器名字也是/foo,假设咱们等等要访问的url是localhost:8080/hello.do,那么后面咱们再写 处理器中的代码的名字也是hello.do.
而后再springmvc-servler.xml中配置映射器:
<!--HandelMapping-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
复制代码
映射器处理完后,返回执行链,DispatcherServlet去调用处理器,处理器实现自己就就是多元化的,要根据处理器的具体实现,经过适配器(处理器包装后)调用处理器,咱们先找到HandlerAdapter,看看这个接口的继承树:
有一个适配器SimpleControllerHandlerAdapter,可以帮咱们调用处理器(也能够叫Controller)中的方法,
那么他是怎么调用处理器方法?
他是经过判断你的处理器是否属于Controller的类型,是则返回true。那么Controller又是什么呢?查看源代码发现Controller是一个接口,也就意味着,咱们写处理器部分的代码要实现这一个接口。
这个接口中就一个方法,也就是处理器方法,这个方法等同与Servlet中的doGet/doPost方法。
咱们调用处理器方法的前提是实现Controller接口,在交给适配器,适配器判断完以后,处理器(handler)在调用Controller接口中的处理器方法,因此最终调用处理器方法返回ModelAndView的是适配器的handler方法:
接下来咱们要作的事就是在springmvc-servlet.xml配置这个SimpleControllerHandlerAdapter:
<!--SimpleControllerHandlerAdapter-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
复制代码
配置好适配器,按照流程图接下来搞配置处理器,前面说提处处理器部分是咱们本身来实现的。
咱们在项目中建立一个一个包com.ljm.springmvc.controller,而后在包中建立处理器HelloController。这里不叫包名类名不叫Handler而叫controller,至于为何,多是由于他要实现一个接口,这接口叫Controller。而后重写Controller中的方法:
package com.ljm.springmvc.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
return null;
}
}
复制代码
由于咱们本身建立了处理器和Spring没啥关系,要想有有点什么关系,就要把它配置到springmvc-servlet.xml中,处理器有不少个,那么就要给他配上id或者name,这里给他配置name,前面在配置映射器时提到,这个名字是咱们要访问的url因此,不能随便配:
<!--处理器,注意/不能丢-->
<bean name="/hello.do" class="com.ljm.springmvc.controller.HelloController" />
复制代码
建立配置好处理器后,就要开始实现处理器中的业务,该调用哪一个service层就调用哪一个service,而后把结果响应到客户端,这里响应回去的是一个ModelAndView,这里不实现service和dao层,写一个死数据,无论三七二十一,先建立一个ModelAndView对象用于返回,
这里能够看到modelAndView有一些add方法:addObject(),根据参数能够联想到request的get/set Attribute方法,先设置一对key/value;但这时候只设置了数据,没有告诉他往哪一个页面返回,因此这里还有一个操做,叫设置视图名称,使用的是modelAndView的setViewName方法,但这里参数仅仅是设置要返回到的视图名称(逻辑视图),且不带后缀名,这里咱们要返回到index.jsp,因此参数是index;因此处理器的代码实现已经完成了:
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg","spring MVC : Hello World!");
modelAndView.setViewName("index");
return modelAndView;
}
}
复制代码
视图解析器:ViewResolver是框架提供的,因此直接配置到springmvc-servlet.xml就行。
ViewResolver也是个接口,查看继承树,
其中有一个InternalResourceViewResolver,根据注释咱们能够看到咱们要用的就是他InternalResourceViewResolver继承了UrlBasedViewResolver,根据UrlBasedViewResolver注释的提示,咱们能够看到视图解析器正确的配置姿式:
咱们这里的配置就应该是:
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
<!--配置路径:返回页面在webapp下,因此配置/-->
<property name="prefix" value="/" />
<!--配置后缀名-->
<property name="suffix" value=".jsp" />
<!--viewname已经在处理器配置过了-->
</bean>
复制代码
<html>
<body>
<h2>${msg}</h2>
</body>
</html>
复制代码
添加log4j.properties 到resources
log4j.rootLogger=DEBUG,A1
log4j.logger.org.apache=DEBUG
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n
复制代码