SpringMVC快速入門

1、概述

SpringMVC屬於Spring Framework的後續產品,已經融合到Spring Web Flow中。SpringMVC基於Model2而實現,利用處理器分離了模型對象、視圖、控制,達到了鬆散耦合的效果,提升了系統的可重用性、可維護性以及可擴展性。其功能與Struts相似,只是實現原理和方式上有所不一樣。css

優勢:html

  • 使用簡單,學習成本低
  • 功能強大,很容易寫出性能優秀的程序
  • 十分靈活,而且可與Spring無縫銜接

2、框架

SpringMVC框架主要由DispatcherServlet、HandlerMapping、Controller、ViewResolver四個接口組成。前端

一、前端控制器DispatcherServlet

是整個SpringMVC的核心。從名稱來看,它是一個Servlet,負責統一分發全部請求。web

  • 攔截符合特定格式的URL請求
  • 初始化DispatcherServlet上下文對應的WebApplicationContext,並與業務層、持久化層創建聯繫
  • 初始化SpringMVC的各個組件,並裝配到DispatcherServlet中

在web.xml文件中進行配置,負責接收HTTP請求、組織協調SpringMVC的各個組成部分。spring

<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>

若是不指定<param-value>的值,則默認配置文件爲/WEB-INF/<servlet-name>-servlet.xml。<load-on-startup>是啓動順序,一般讓Servlet跟隨Servlet容器一塊兒啓動。<url-pattern>定義要攔截的URL請求。安全

攔截規則:併發

  • *.xxx,指定要攔截的特定類型,最簡單實用的方式,而且不會攔截靜態文件
  • /,使用REST風格進行攔截,可是會致使靜態文件被攔截不能正常顯示
  • /*,不能像Struts那樣使用,會致使不能訪問jsp

若是使用/進行攔截,而且但願正常訪問靜態文件,能夠在DispatcherServlet以前,使用DefaultServlet先攔截特定類型的請求(如:*.js、*.css等)。mvc

二、處理器映射HandlerMapping

負責完成請求到控制器的映射。在servlet的配置文件中,進行uri與控制器的映射。同時,還能夠對控制器進行攔截。app

SpringMVC默認的處理器映射,直接將uri與實現類進行綁定,書寫方便,可是耦合性高。框架

<bean id="defaultHandlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean name="/hello.html" class="com.demo.ssm.HelloController"></bean>

使用SimpleUrlHandlerMapping,將uri與類的id進行綁定,彼此的耦合性低,更加靈活。

<bean id="simpleUrlHandlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
  <property name="urlMap">
    <map>
      <entry key="/hello.html" value-ref="hello"></entry>
    </map>
  </property>
</bean>
<bean id="hello" class="com.demo.ssm.controller.HelloController"></bean>

對控制器進行攔截,首先聲明攔截器:

<bean id="myInterceptor" class="com.demo.ssm.interceptor.MyInterceptor"></bean>

而後利用SimpleUrlHandlerMapping,映射攔截器與控制器:

<property name="interceptors">
  <list>
    <ref bean="myInterceptor" />
  </list>
</property>

三、控制器Controller

負責處理用戶請求,完成以後返回ModelAndView對象給前端控制器。由於須要考慮併發,因此必須保證線程安全而且可重用。

SpringMVC中的Controller與Struts中的Action基本相同。經過實現Controller接口或繼承父類的方式編寫控制器。

實現Controller接口:

public class HelloController implements Controller {
  // 至關於servlet的doGet和doPost方法
  public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response) throws Exception {
    // 接收數據
    // 調用服務層
    return new ModelAndView("success","username","sean");
  }
}

繼承AbstractController類,該類與接口相似,須要重寫裏邊的方法。

繼承MultiActionController類,能夠實現多個方法,處理多個請求。

public class MultiController extends MultiActionController {
  // 自定義處理請求的方法
  public ModelAndView insert(HttpServletRequest request,HttpServletResponse response) throws Exception {
    return new ModelAndView("insertSuccess");
  }
  public ModelAndView update(HttpServletRequest request,HttpServletResponse response) throws Exception {
    return new ModelAndView("updateSuccess");
  }
}

相應的配置文件:

<bean id="multi" class="com.demo.ssm.controller.MultiController"></bean>

<bean id="simpleUrlHandlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
  <property name="urlMap">
    <map>
      <!-- 使用通配符進行模糊匹配 -->
      <entry key="/multi-*.html" value-ref="multi"></entry>
    </map>
  </property>
</bean>

<bean id="multiActionController" class="org.springframework.web.servlet.mvc.multiaction.MultiActionController">
  <property name="methodNameResolver" ref="methodNameResolver"></property>
  <property name="delegate">
    <ref bean="multi" />
  </property>
</bean>

<bean id="methodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
  <property name="mappings">
    <props>
      <prop key="/multi-insert.html">insert</prop>
      <prop key="/multi-update.html">update</prop>
    </props>
  </property>
</bean>

繼承AbstractCommandController類,用於獲取頁面的參數,將參數封裝到指定的對象模型中。

public class CommandController extends AbstractCommandController {
  public CommandController() {
    // User是用於接收請求參數的數據模型類
    this.setCommandClass(User.class);
  }

  protected ModelAndView handle(HttpServletRequest request,HttpServletResponse response,
    Object command, BindException errors) throws Exception {
    // command參數是指定的數據模型對象
    User user = (User)command;
    return new ModelAndView("command");
  }
}

四、視圖解析器ViewResolver

負責對ModelAndView對象的解析,並查找對應的View對象。SpringMVC框架默認經過轉發進行頁面跳轉,若是想經過重定向的方式進行跳轉,有如下幾種實現方式。

在控制器中,返回一個RedirectView對象,由對象來指定重定向的URL:

View view = new RedirectView("/index.jsp");
return new ModelAndView(view);

經過配置文件設置,在控制器返回對象的方法中只須要設置一個與bean id一致的字符串便可:

<bean id="viewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver"></bean>
<bean id="index" class="org.springframework.web.servlet.view.RedirectView">
  <property name="url" value="/index.jsp"></property>
</bean>

return new ModelAndView("index");

直接跳轉:

return "redirect:/index.jsp";

若是一個配置文件中出現多個視圖解析器,能夠經過設置order屬性來設定優先級。值越低,優先級越高。

3、工做原理

  1. 將客戶端請求提交給DispatcherServlet
  2. 根據<servlet-name>servlet.xml的配置,查找HandlerMapping
  3. 經過HandlerMapping找處處理請求的具體Controller
  4. Controller調用業務邏輯處理
  5. 處理完成以後,返回ModelAndView對象給DispatcherServlet
  6. 經過ViewResolver找到負責顯示的具體View
  7. 由View將結果渲染到客戶端

4、經常使用註解

  • @Controller:聲明Action組件,負責註冊bean到Spring上下文
  • @RequestMapping:用於爲控制器指定能夠處理的url請求
  • @RequestParam:用於指定參數的name屬性
  • @RequestBody:用於讀取Request請求的body部分數據
  • @ResponseBody:用於將控制器方法返回的對象寫入到Response對象的body數據區
  • @PathVariable:用於指定url做爲參數
  • @Resource用於注入,( 由j2ee提供 ) 默認按名稱裝配
  • @Autowired用於注入,(由spring提供) 默認按類型裝配
  • @ExceptionHandler:用於異常處理的方法
  • @ControllerAdvice:用於使控制器成爲全局的異常處理類
  • @ModelAttribute:用於優先調用被註解的方法,或註解參數中的隱藏對象

5、攔截器

Spring提供了HandlerInterceptor接口和HandlerInterceptorAdapter適配器。實現這個接口或繼承此類,就能夠實現本身的攔截器。接口HandlerInterceptor包含三個方法,每一個方法的參數handler,用來指向下一個攔截器。

  • preHandle(),在Action以前執行的預處理,能夠進行編碼、安全控制等處理
  • postHandle(),在生成View以前執行的後處理,調用了Service並返回ModelAndView,但未進行頁面渲染,能夠修改ModelAndView
  • afterCompletion(),最後執行的返回處理,這時已經進行了頁面渲染,能夠進行日誌記錄、釋放資源等處理

在實現了接口以後,就能夠在配置文件中進行攔截器的配置。

攔截全部url:

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

攔截匹配的url:

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

HandlerMapping上的攔截器:

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

注意:若是配置了<mvc:annotation-driven />,會自動註冊DefaultAnnotationHandlerMapping與AnnotationMethodHandlerAdapter這兩個bean。這樣就不能再注入interceptors屬性,也就沒法指定攔截器了。

6、異常處理

能夠在配置文件中設置SimpleMappingExceptionResolver,也能夠實現HandlerExceptionResolver接口,編寫本身的異常處理。經過exceptionMappings屬性的配置,能夠將不一樣的異常映射到不一樣的頁面。經過defaultErrorView屬性的配置,能夠爲全部異常指定一個默認的異常處理頁面。

<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>
</bean>

7、獲取Spring管理的Bean

首先在配置文件中添加:

<bean class="com.xxxx.SpringContextHolder" lazy-init="false" />

而後定義一個Spring上下文持有類:

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class SpringContextHolder implements ApplicationContextAware {
  // 聲明靜態變量, 保證在任何代碼任何地方任什麼時候候可以取得ApplicaitonContext
  private static ApplicationContext applicationContext;

  // 實現ApplicationContextAware接口的context注入函數, 將其存入靜態變量
  public void setApplicationContext(ApplicationContext applicationContext) {
    SpringContextHolder.applicationContext = applicationContext;
  }

  // 取得ApplicationContext
  public static ApplicationContext getApplicationContext() {
    return applicationContext;
  }

  // 從靜態變量ApplicationContext中取得Bean, 自動轉型爲所賦值對象的類型
  @SuppressWarnings("unchecked")
  public static <T> T getBean(String name) {
    return (T) applicationContext.getBean(name);
  }

  @SuppressWarnings("unchecked")
  public static <T> T getBean(Class<T> clazz) {
    return (T) applicationContext.getBeansOfType(clazz);
  }

  // 清除applicationContext靜態變量
  public static void cleanApplicationContext() {
    applicationContext = null;
  }
}

參考文章:

SpringMVC教程

相關文章
相關標籤/搜索