springMVC ----HELLO word
1.配置开发环境,导入springmvc依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
</dependency>
</dependencies>
2.准备一个Controller,即一个处理浏览器请求的接口
public class MyController implements Controller{
/**
*这是一个请求处理接口
*@param rep 这是前端发来的请求
*@param resp 这是服务端给前端的响应
*@return 返回值是一个ModelAandView,Model相当于是我们数据的模型,View是我们的视图
*@throws Exception
*/
public ModelAndViewhandleRequest(HttpServeletRequest req,HttpServletResponse resp)throws Exception {
ModelAndView mv = new ModelAndView("hello");
mv.addObject("name","wangze");
return mv;
}
3.创建视图
这里使用jsp 作为视图,在webapp目录下,创建名为 hello的jsp文件
%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>hello ${name}!</h1>
</body>
</html>
4.在resources目录下,创建一个名为spring-servlet.xml的springmvc配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.javaboy.helloworld.MyController" name="/hello"/>
<!--这个是处理器映射器,这种方式,请求地址其实就是一个 Bean 的名字,然后根据这个 bean 的名字查找对应的处理器-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" id="handlerMapping">
<property name="beanName" value="/hello"/>
</bean>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" id="handlerAdapter"/>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="viewResolver">
<property name="prefix" value="/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
5.加载springmvc的配置文件
在web项目启动时,加载springmvc配置文件,这个配置是在web.xml中完成的。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
注:
所有请求都将自动拦截下来,拦截下来后,请求交给 DispatcherServlet 去处理,在加载 DispatcherServlet 时,还需要指定配置文件路径。这里有一个默认的规则,如果配置文件放在 webapp/WEB-INF/ 目录下,并且配置文件的名字等于 DispatcherServlet 的名字+ -servlet(即这里的配置文件路径是 webapp/WEB-INF/springmvc-servlet.xml),如果是这样的话,可以不用添加 init-param 参数,即不用手动配置 springmvc 的配置文件,框架会自动加载。
6.配置并启动项目
7.浏览器输入http://localhost:8080/hello 就可以看到界面
hello wangze!
SpringMVC工作流程
springMVC中的组件
-
DispatcherServlet: 前端控制器
用户请求到达前端控制器,它就相当于mvc模式中的C,DispatcherServlet是整个流程控制的中心,相当于是springmvc的大脑,由它调用其他组件处理用户的请求,Dispatcher的存在降低了组件之间的耦合性。
-
HandlerMapping:处理器映射器
HanderMapping 负责根据用户请求找到Handler(处理器)也就是我们常说的Controller,Springmvc提供了不同映射器实现的不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等,在实际开发中,我们常用的方式是注解方式。
-
Handler :处理器
Handler 是继 DispatherServlet前端控制器的后端控制器,在dispatherServlet的控制下Handler对具体的用户请求进行处理。由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。(这里的handler就是指的我们的Controller)
-
HandlAdapter: 处理器适配器
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过拓展适配器可以对更多类型的处理器进行执行。
-
ViewResolver: 视图解析器
ViewResolver 负责将处理结果生成View视图,ViewResolver 首先根据逻辑视图名解析成物理视图名(具体的页面地址),在生成View图像,最后对View进行渲染将处理结果通过页面展示给用户。springMVC框架提供了很多的View视图类型,包括:jstView,freemarkerView,pdfView等。一般情况下需要通过页面标签或页面模板技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
DispatcherServlet
DispatcherServlet的作用
DispatcherServlet 是前端控制器设计模式的实现,提供 Spring Web MVC 的集中访问点,而且负责职责的分派,而且与 Spring IoC 容器无缝集成,从而可以获得 Spring 的所有好处。DispatcherServlet 主要用作职责调度工作,本身主要用于控制流程,主要职责如下:
1.文件上传解析,如果请求类型是 multipart 将通过 MultipartResolver 进行文件上传解析;
2.通过 HandlerMapping,将请求映射到处理器(返回一个 HandlerExecutionChain,它包括一个处理器、多个 HandlerInterceptor 拦截器);
3.通过 HandlerAdapter 支持多种类型的处理器(HandlerExecutionChain 中的处理器);
4.通过 ViewResolver 解析逻辑视图名到具体视图实现;
5.本地化解析;
6.渲染具体的视图等;
7.如果执行过程中遇到异常将交给 HandlerExceptionResolver 来解析
DispatcherServlet 配置详解
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name> <!--contextConfigLocation:表示 SpringMVC 配置文件的路径-->
<param-value>classpath:spring-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup> <!-- load-on-startup:表示启动容器时初始化该 Servlet;-->
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern> <!-- url-pattern:表示哪些请求交给 Spring Web MVC 处理, “/” 是用来定义默认 servlet 映射的。也可以如 *.html 表示拦截所有以 html 为扩展名的请求 -->
</servlet-mapping>
其他参数配置:
参数 | 描述 |
---|---|
contextClass | 实现WebApplicationContext接口的类,当前的servlet用它来创建上下文。如果这个参数没有指定, 默认使用XmlWebApplicationContext。 |
contextConfigLocation | 传给上下文实例(由contextClass指定)的字符串,用来指定上下文的位置。这个字符串可以被分成多个字符串(使用逗号作为分隔符) 来支持多个上下文(在多上下文的情况下,如果同一个bean被定义两次,后面一个优先)。 |
namespace | WebApplicationContext命名空间。默认值是[server-name]-servlet。 |
Spring配置
之前的案例中,只有springMVC,没有spring,Web程序也是可以运行的。但是在实际开发中,spring和springMVC是分开配置的,所以我们对上面的项目继续进行完善,添加Spring相关配置。
-
首先,项目添加一个service包,提供一个helloService类:
@Service public class HelloService { public String hello(String name){ return "hello"+name; } }
-
现在,假设我需要将helloservice注入到spring容器中并使用它,这个是属于spring层的bean,所以我们一般将除了controller之外的所有bean 注册到spring容器中,而将controller注册到springMVC容器中,现在,在resources目录下添加applicationContext.xml作为spring的配置:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="org.javaboy" use-default-filters="true"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> </beans>
-
在web.xml文件中加载
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!--首先通过 context-param 指定 Spring 配置文件的位置,这个配置文件也有一些默认规则,它的配置文件名默认就叫 applicationContext.xml ,并且,如果你将这个配置文件放在 WEB-INF 目录下,那么这里就可以不用指定配置文件位置了,只需要指定监听器就可以了。这段配置是 Spring 集成 Web 环境的通用配置;一般用于加载除 Web 层的 Bean(如DAO、Service 等),以便于与其他任何Web框架集成。 contextConfigLocation:表示用于加载 Bean 的配置文件; contextClass:表示用于加载 Bean 的 ApplicationContext 实现类,默认 WebApplicationContext。-->
-
配置完后,还需要修改mycontroller,在mycontroller中注入helloservice
@org.springframework.stereotype.Controller("/hello") public class MyController implements Controller { @Autowired HelloService helloService; /** * 这就是一个请求处理接口 * @param req 这就是前端发送来的请求 * @param resp 这就是服务端给前端的响应 * @return 返回值是一个 ModelAndView,Model 相当于是我们的数据模型,View 是我们的视图 * @throws Exception */ public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) throws Exception { System.out.println(helloService.hello("javaboy")); ModelAndView mv = new ModelAndView("hello"); mv.addObject("name", "javaboy"); return mv; } }
-
注意:
为了在 SpringMVC 容器中能够扫描到 MyController ,这里给 MyController 添加了 @Controller 注解,同时,由于我们目前采用的 HandlerMapping 是 BeanNameUrlHandlerMapping(意味着请求地址就是处理器 Bean 的名字),所以,还需要手动指定 MyController 的名字。 最后,修改 SpringMVC 的配置文件,将 Bean 配置为扫描形式:
<context:component-scan base-package="org.javaboy.helloworld" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!--这个是处理器映射器,这种方式,请求地址其实就是一个 Bean 的名字,然后根据这个 bean 的名字查找对应的处理器--> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" id="handlerMapping"> <property name="beanName" value="/hello"/> </bean> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" id="handlerAdapter"/> <!--视图解析器--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="viewResolver"> <property name="prefix" value="/jsp/"/> <property name="suffix" value=".jsp"/> </bean>
配置完成后,再次启动项目,Spring 容器也将会被创建。访问 /hello 接口,HelloService 中的 hello 方法就会自动被调用。
两个容器
当 Spring 和 SpringMVC 同时出现,我们的项目中将存在两个容器,一个是 Spring 容器,另一个是 SpringMVC 容器,Spring 容器通过 ContextLoaderListener 来加载,SpringMVC 容器则通过 DispatcherServlet 来加载,这两个容器不一样:
ContextLoaderListener 初始化的上下文加载的 Bean 是对于整个应用程序共享的,不管是使用什么表现层技术,一般如 DAO 层、Service 层 Bean;
DispatcherServlet 初始化的上下文加载的 Bean 是只对 Spring Web MVC 有效的 Bean,如 Controller、HandlerMapping、HandlerAdapter 等等,该初始化上下文应该只加载 Web相关组件。
为什么不在 Spring 容器中扫描所有 Bean?
这个是不可能的。因为请求达到服务端后,找 DispatcherServlet 去处理,只会去 SpringMVC 容器中找,这就意味着 Controller 必须在 SpringMVC 容器中扫描。
2.为什么不在 SpringMVC 容器中扫描所有 Bean?
这个是可以的,可以在 SpringMVC 容器中扫描所有 Bean。不写在一起,有两个方面的原因:
为了方便配置文件的管理
在 Spring+SpringMVC+Hibernate 组合中,实际上也不支持这种写法