SpringMVC 知识点整理

来源:互联网 发布:测试网络丢包率软件 编辑:程序博客网 时间:2024/05/14 06:27

图1

图2

先放两张图,是网上找的。下面的文章很多都是其他地方直接copy过来的,尤其是这位仁兄(http://elf8848.iteye.com/blog/875830/),在此感谢,为了加深记忆。

1.DispatcherServlet

使用Spring MVC,配置DispatcherServlet是第一步。
DispatcherServlet是一个Servlet,所以可以配置多个DispatcherServlet。
DispatcherServlet是前置控制器,配置在web.xml文件中的。拦截匹配的请求,Servlet拦截匹配规则要自已定义,把拦截下来的请求,依据某某规则分发到目标Controller(我们写的Action)来处理。

<web-app>      <servlet>          <servlet-name>example</servlet-name>          <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>          <load-on-startup>1</load-on-startup>      </servlet>      <servlet-mapping>          <servlet-name>example</servlet-name>          <url-pattern>*.form</url-pattern>      </servlet-mapping>  </web-app>  

example这个Servlet的名字是example,可以有多个DispatcherServlet,是通过名字来区分的。每一个DispatcherServlet有自己的WebApplicationContext上下文对象。

在DispatcherServlet的初始化过程中,框架会在web应用的 WEB-INF文件夹下寻找名为[servlet-name]-servlet.xml 的配置文件,生成文件中定义的bean。

第二种写法:

<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*:/springMVC.xml</param-value>      </init-param>      <load-on-startup>1</load-on-startup>  </servlet>  <servlet-mapping>      <servlet-name>springMVC</servlet-name>      <url-pattern>/</url-pattern>  </servlet-mapping>  

classpath*:/springMVC.xml 这段写不写有四种方式:
1、不写,使用默认值:/WEB-INF/-servlet.xml
2、/WEB-INF/classes/springMVC.xml
3、classpath*:springMVC-mvc.xml
4、多个值用逗号分隔

Servlet拦截匹配规则可以自已定义,拦截哪种URL合适?

@RequestMapping的用法如下:

当映射为@RequestMapping(“/user/add”)时,为例:

例子一:

@RequestMapping(value="/departments")  public String simplePattern(){    System.out.println("simplePattern method was called");    return "someResult";  }  

当访问//localhost/xxx/departments时,会用到。

例子二:

@RequestMapping(value="/departments")  public String findDepatment(    @RequestParam("departmentId") String departmentId){      System.out.println("Find department with ID: " + departmentId);      return "someResult";  }  

当访问//localhost/xxx/departments?departmentId=00时用到

例子三:

@RequestMapping(value="/departments/{departmentId}")  public String findDepatment(@PathVariable String departmentId){    System.out.println("Find department with ID: " + departmentId);    return "someResult";  }  

当访问//localhost/xxx/departments/23时

例子四:

@Controller  @RequestMapping ( "/test/{variable1}" )  public class MyController {      @RequestMapping ( "/departments/{variable2}" )      public ModelAndView showView( @PathVariable String variable1, @PathVariable ( "variable2" ) int variable2) {         ModelAndView modelAndView = new ModelAndView();         modelAndView.setViewName( "viewName" );         modelAndView.addObject( " 需要放到 model 中的属性名称 " , " 对应的属性值,它是一个对象 " );         return modelAndView;      }  }   

当访问//localhost/xxx/test/33/departments/23时

2.WebApplicationContext上下文

Spring会创建一个WebApplicationContext上下文,称为父上下文(父容器) ,保存在 ServletContext中,key是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE的值。
可以使用Spring提供的工具类取出上下文对象:WebApplicationContextUtils.getWebApplicationContext(ServletContext);

DispatcherServlet是一个Servlet,可以同时配置多个,每个 DispatcherServlet有一个自己的上下文对象(WebApplicationContext),称为子上下文(子容器),子上下文可以访问父上下文中的内容,但父上下文不能访问子上下文中的内容。 它也保存在 ServletContext中,key是”org.springframework.web.servlet.FrameworkServlet.CONTEXT”+Servlet名称。当一个Request对象产生时,会把这个子上下文对象(WebApplicationContext)保存在Request对象中,key是DispatcherServlet.class.getName() + “.CONTEXT”。
可以使用工具类取出上下文对象:RequestContextUtils.getWebApplicationContext(request);

说明 :Spring 并没有限制我们,必须使用父子上下文。我们可以自己决定如何使用。

方案一,传统型:
父上下文容器中保存数据源、服务层、DAO层、事务的Bean。
子上下文容器中保存Mvc相关的Action的Bean.
事务控制在服务层。
由于父上下文容器不能访问子上下文容器中内容,事务的Bean在父上下文容器中,无法访问子上下文容器中内容,就无法对子上下文容器中Action进行AOP(事务)。
当然,做为“传统型”方案,也没有必要这要做。

方案二,激进型:
Java世界的“面向接口编程”的思想是正确的,但在增删改查为主业务的系统里,Dao层接口,Dao层实现类,Service层接口,Service层实现类,Action父类,Action。再加上众多的O(vo\po\bo)和jsp页面。写一个小功能 7、8个类就写出来了。 开发者说我就是想接点私活儿,和PHP,ASP抢抢饭碗,但我又是Java程序员。最好的结果是大项目能做好,小项目能做快。所以“激进型”方案就出现了—–没有接口、没有Service层、还可以没有众多的O(vo\po\bo)。那没有Service层事务控制在哪一层?只好上升的Action层。
本文不想说这是不是正确的思想,我想说的是Spring不会限制你这样做。
由于有了父子上下文,你将无法实现这一目标。解决方案是只使用子上下文容器,不要父上下文容器 。所以数据源、服务层、DAO层、事务的Bean、Action的Bean都放在子上下文容器中。就可以实现了,事务(注解事务)就正常工作了。这样才够激进。
总结:不使用listener监听器来加载spring的配置文件,只使用DispatcherServlet来加载spring的配置,不要父子上下文,只使用一个DispatcherServlet,事情就简单了,什么麻烦事儿也没有了。*

3. 一个典型的servlet.xml结构

<?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:tx="http://www.springframework.org/schema/tx"      xmlns:context="http://www.springframework.org/schema/context"        xmlns:mvc="http://www.springframework.org/schema/mvc"        xsi:schemaLocation="http://www.springframework.org/schema/beans       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd       http://www.springframework.org/schema/tx       http://www.springframework.org/schema/tx/spring-tx-3.0.xsd      http://www.springframework.org/schema/context      http://www.springframework.org/schema/context/spring-context-3.0.xsd      http://www.springframework.org/schema/mvc      http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">      <!-- 自动扫描的包名 包括如下常见注解    @Controller 声明Action组件    @Service    声明Service组件    @Service("myMovieLister")     @Repository 声明Dao组件    @Component   泛指组件, 当不好归类时.     @RequestMapping("/menu")  请求映射    @Resource  用于注入,( j2ee提供的 ) 默认按名称装配,@Resource(name="beanName")     @Autowired 用于注入,(srping提供的) 默认按类型装配     @Transactional( rollbackFor={Exception.class}) 事务管理    @ResponseBody    @Scope("prototype")       设定bean的作用域-->      <context:component-scan base-package="com.app,com.core,JUnit4" ></context:component-scan>      <!-- 默认的注解映射的支持 会自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter 两个bean,是spring MVC为@Controllers分发请求所必须的。并提供了:数据绑定支持,@NumberFormatannotation支持,@DateTimeFormat支持,@Valid支持,读写XML的支持(JAXB),读写JSON的支持(Jackson)。-->      <mvc:annotation-driven />      <!-- 视图解释类 -->      <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">          <property name="prefix" value="/WEB-INF/jsp/"/>          <property name="suffix" value=".jsp"/><!--可为空,方便实现自已的依据扩展名来选择视图解释类的逻辑  -->          <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />      </bean>      <!-- 拦截器,可以有多个拦截器 -->      <mvc:interceptors>          <bean class="com.core.mvc.MyInteceptor" />      </mvc:interceptors>           <!-- 对静态资源文件的访问  方案一 (二选一) -->      <mvc:default-servlet-handler/>      <!-- 对静态资源文件的访问  方案二 (二选一)-->      <mvc:resources mapping="/images/**" location="/images/" cache-period="31556926"/>       <!-- 匹配URL  /images/**  的URL被当做静态资源,由Spring读出到内存中再响应http。-->      <mvc:resources mapping="/js/**" location="/js/" cache-period="31556926"/>      <mvc:resources mapping="/css/**" location="/css/" cache-period="31556926"/>  </beans>   

4. 如何让静态资源请求不被拦截

如果你的DispatcherServlet拦截”/”,为了实现REST风格,拦截了所有的请求,那么同时对.js,.jpg等静态文件的访问也就被拦截了。

方案一:
解决的办法是在web.xml中加入

<servlet-mapping>       <servlet-name>default</servlet-name>      <url-pattern>*.jpg</url-pattern>     </servlet-mapping>    <servlet-mapping>           <servlet-name>default</servlet-name>        <url-pattern>*.js</url-pattern>    </servlet-mapping>    <servlet-mapping>            <servlet-name>default</servlet-name>           <url-pattern>*.css</url-pattern>      </servlet-mapping>    

在dispatchServlet前面,让tomcat自行去先过滤掉。
Tomcat, Jetty, JBoss, and GlassFish 自带的默认Servlet的名字 – “default”
Google App Engine 自带的 默认Servlet的名字 – “_ah_default”
Resin 自带的 默认Servlet的名字 – “resin-file”
WebLogic 自带的 默认Servlet的名字 – “FileServlet”
WebSphere 自带的 默认Servlet的名字 – “SimpleFileServlet”

方案二: 在spring3.0.4以后版本提供了mvc:resources
方案三 ,使用 <mvc:default-servlet-handler/> 会把”/**” url,注册到SimpleUrlHandlerMapping的urlMap中,把对静态资源的访问由HandlerMapping转到org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler处理并返回.
DefaultServletHttpRequestHandler使用就是各个Servlet容器自己的默认Servlet.

方案2的优先级要比方案3来的高,所以一个请求如果是请求静态的资源,是按优先级来的。

OK.看完了servlet.xml,我们来看下Controller这个类

5.Controller如何定义及含义

Controller 负责处理由DispatcherServlet 分发的请求,当一个请求到来时,spring怎么知道该用哪个函数去处理呢?

@Controller  public class MyController {      @RequestMapping ( "/showView" )      public ModelAndView showView() {         ModelAndView modelAndView = new ModelAndView();         modelAndView.setViewName( "viewName" );         modelAndView.addObject( " 需要放到 model 中的属性名称 " , " 对应的属性值,它是一个对象 " );         return modelAndView;      }  }   

如上就是一个典型的Controller定义,spring会扫描加了@Controller前缀的类,并且,如果他的函数中有@RequestMapping字样,则会认为这是个处理类。
那么如何让spring去做这个动作?两个办法,一个是用之前说的context:component-scan标签。
第二种就是显式定义

<bean class="com.host.app.web.controller.MyController"/>

6. Spring中的拦截器
Spring为我们提供了:
org.springframework.web.servlet.HandlerInterceptor接口,
org.springframework.web.servlet.handler.HandlerInterceptorAdapter适配器,
实现这个接口或继承此类,可以非常方便的实现自己的拦截器。

有以下三个方法:

Action之前执行:
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler);

生成视图之前执行
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView);

最后执行,可用于释放资源
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)

分别实现预处理、后处理(调用了Service并返回ModelAndView,但未进行页面渲染)、返回处理(已经渲染了页面)
在preHandle中,可以进行编码、安全控制等处理;
在postHandle中,有机会修改ModelAndView;
在afterCompletion中,可以根据ex是否为null判断是否发生了异常,进行日志记录。
参数中的Object handler是下一个拦截器。

拦截器的定义有几种方式:
第一种,什么都栏,

 <mvc:interceptors>      <bean class="com.app.mvc.MyInteceptor" />  </mvc:interceptors>  

第二种,拦一部分url匹配的

<mvc:interceptors >      <mvc:interceptor>            <mvc:mapping path="/user/*" /> <!-- /user/*  -->            <bean class="com.mvc.MyInteceptor"></bean>        </mvc:interceptor>    </mvc:interceptors>   

第三种,指定我们自己的拦截器,前提是没有事先使用了< mvc:annotation-driven />

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">        <property name="interceptors">            <list>                <bean class="com.mvc.MyInteceptor"></bean>           </list>        </property>       </bean>   

7,异常处理

<!-- 总错误处理-->  <bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">      <property name="defaultErrorView">            <value>/error/error</value>      </property>      <property name="defaultStatusCode">            <value>500</value>      </property>     <property name="warnLogCategory">            <value>org.springframework.web.servlet.handler.SimpleMappingExceptionResolver</value>      </property>     </bean>  

这里主要的类是SimpleMappingExceptionResolver类,和他的父类AbstractHandlerExceptionResolver类。
具体可以配置哪些属性,我是通过查看源码知道的。
你也可以实现HandlerExceptionResolver接口,写一个自己的异常处理程序。spring的扩展性是很好的。

通过SimpleMappingExceptionResolver我们可以将不同的异常映射到不同的jsp页面(通过exceptionMappings属性的配置)。

同时我们也可以为所有的异常指定一个默认的异常提示页面(通过defaultErrorView属性的配置),如果所抛出的异常在exceptionMappings中没有对应的映射,则Spring将用此默认配置显示异常信息。
注意这里配置的异常显示界面均仅包括主文件名,至于文件路径和后缀已经在viewResolver中指定。如/error/error表示/error/error.jsp

8.如何把全局异常记录到日志中

在前的配置中,其中有一个属性warnLogCategory,值是“SimpleMappingExceptionResolver类的全限定名”。我是在SimpleMappingExceptionResolver类父类AbstractHandlerExceptionResolver类中找到这个属性的。查看源码后得知:如果warnLogCategory不为空,spring就会使用apache的org.apache.commons.logging.Log日志工具,记录这个异常,级别是warn。
值:“org.springframework.web.servlet.handler.SimpleMappingExceptionResolver”,是“SimpleMappingExceptionResolver类的全限定名”。这个值不是随便写的。 因为我在log4j的配置文件中还要加入log4j.logger.org.springframework.web.servlet.handler.SimpleMappingExceptionResolver=WARN,保证这个级别是warn的日志一定会被记录,即使log4j的根日志级别是ERROR。

9.转发与重定向

可以通过redirect/forward:url方式转到另一个Action进行连续的处理。可以通过redirect:url 防止表单重复提交 。写法如下:return "forward:/order/add";return "redirect:/index.jsp";

10.处理ajax请求

1、引入下面两个jar包,我用的是1.7.2,好像1.4.2版本以上都可以,下载地址: http://wiki.fasterxml.com/JacksonDownload
jackson-core-asl-1.7.2.jar
jackson-mapper-asl-1.7.2.jar

2、spring的配置文件中要有这一行,才能使用到spring内置支持的json转换。如果你手工把POJO转成json就可以不须要使用spring内置支持的json转换。

3、使用@ResponseBody注解, 表示该方法的返回结果直接写入HTTP response body中

/**  * ajax测试 * http://127.0.0.1/mvc/order/ajax  */  @RequestMapping("/ajax")  @ResponseBody  public Object ajax(HttpServletRequest request){      List<String> list=new ArrayList<String>();      list.add("电视");  nbsp;       list.add("洗衣机");      list.add("冰箱");      list.add("电脑");      list.add("汽车");      list.add("空调");      list.add("自行车");      list.add("饮水机");      list.add("热水器");      return list;  }  

11.可用的ViewResolver实现类(留待补充)

12.ModelAndView详解
ModelAndView, 顾名思义,代表了MVC Web程序中Model与View的对象,不过它只是方便一次返回这两个对象的holder,Model与View两者仍是分离的概念。

最简单的ModelAndView是持有View的名称返回,之后View名称被view resolver,也就是实作org.springframework.web.servlet.View接口的实例解析,例如 InternalResourceView或JstlView等等:
ModelAndView(String viewName)

 如果要返回Model对象,则可以使用Map来收集这些Model对象,然后设定给ModelAndView,使用下面这个版本的ModelAndView:
ModelAndView(String viewName, Map model)

 Map对象中设定好key与value值,之后可以在视图中取出,如果只是要返回一个Model对象,则可以使用下面这个ModelAndView版本:
ModelAndView(String viewName, String modelName, Object modelObject)

 藉由modelName,可以在视图中取出Model并显示。
 ModelAndView类别提供实作View接口的对象来作View的参数:
ModelAndView(View view)
ModelAndView(View view, Map model)
ModelAndView(View view, String modelName, Object modelObject)

0 0
原创粉丝点击