使用Spring MVC搭建WEB應用框架-完整案例
============
1.簡介
首先Spring MVC是基於三個層面來開發的,那三個層面呢?
M(model) - 模型層,控制器完成邏輯處理後,通常會產生一些資訊,而這些資訊需要返回給使用者並在瀏覽器上顯示的,我們把這些資訊稱為模型;
V(view) - 檢視層,我們使用JSP作為檢視層,通過檢視能使這些模型資料渲染輸出,並通過這個輸出響應的對你傳遞給客戶端;
C(controller) - 控制層,從使用者提交請求開始,這些請求都會通過一個前端控制器Servlet,然後經過前端控制器Servlet的解析,再將使用者請求指定到某一個特定的控制器,即控制層。
三個層的關係:使用者提交請求,經前端控制器Servlet解析,再指定控制器,當控制器處理邏輯資訊後,返回模型資料,然後再經指定的檢視把模型資料渲染輸出,終於呈現給客戶端,即使用者。
2.引入spring mvc jar包
因為我之前的文章介紹過Maven的使用(專案是用Maven搭建的),我們這裡就使用Maven的依賴來關聯下載spring的jar包吧。
首先,搜尋需要的,如圖:
下面還有一大堆相關的列表,找到我們需要的或者你可以輸入命名搜尋會更快
點選進去,選擇版本
點選進去,把依賴複製出來到你的pom.xml中,即可
pom.xml配置:
<project> ... <!-- 定義屬性,供${propertieName}訪問 --> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>4.1.3.RELEASE</spring.version> </properties> <!-- 依賴關聯 --> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> </dependencies> ... </project>
完之後,執行pom.xml update
看,相關聯的jar都會下載到本地倉庫,這就是使用Maven的好處!
3.配置一個前端控制器Servlet
Spring MVC中,所有的請求的必經之路為一個前端控制器Servlet,即DispatcherServlet,它是Spring MVC的核心。
DispatcherServlet必須在Web應用程式的web.xml檔案中進行配置,配置如下:
<?xml version="1.0" encoding="UTF-8"?> <web-app...> ... <!-- spring mvc 前端控制器 --> <servlet> <servlet-name>wwo</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:conf/wwo-servlet.xml </param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>wwo</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> ... </web-app>
DispatcherServlet的目的既是為了根據一個XML檔案來載入其配置到Spring應用上下文中,xml檔案的命名方式是預設通過<servlet-name>來指定的XML的檔名,即我們常見的${<servlet-name>}-servlet.xml,如上述例子xml檔案命名為:wwo-servlet.xml(預設路徑位於應用程式的WEB-INF目錄下)。通常我們spring的配置檔案可以分成多個XML檔案,一個用於服務層,一個用於持久層還有一個用於資料來源配置。那怎麼辦呢?
spring 為我提供了一個ContextLoaderListener,它是一個Servlet監聽器,我們只需將ContextLoaderListener配置於web.xml檔案裡即可,配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app ...>
...
<!-- spring監聽器 -->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
...
</web-app>
但,一般這樣配置監聽器的話,它會預設去載入/WEB-INF/applicationContext.xml這個spring配置檔案。
如果我們要指定spring配置檔案的名字或載入多個spring xml配置檔案的話,我們需要這樣配置:
<?xml version="1.0" encoding="UTF-8"?>
<web-app ...>
...
<!-- spring監聽器 -->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- 指定監聽器載入指定的spring xml配置檔案 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<!-- 分別對應的是資料來源、服務層、持久層、安全 -->
<param-value>
classpath:conf/dataSource-context.xml
classpath:conf/service-context.xml
classpath:conf/persistence-context.xml
/WEB-INF/wwo-security.xml
</param-value>
</context-param>
...
</web-app>
好了,這樣spring的xml配置檔案就分得很清楚了!
但是,這裡有個問題,就是所有的請求都經過這個監聽器,包括對靜態資源的請求,問題就在這。如果是靜態資源,怎麼辦呢?
顯示我們還要對所謂的靜態資源進行處理,spring為我們提供了<mvc:resources>元素可以處理這個問題,service-context.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:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- 對靜態資源的處理 -->
<mvc:resources
location="/JScript/**"
mapping="/JScript/" />
</beans>
這樣就對URL包含/JScript/的請求,即對應位於/JScript/下的所以資源來進行特別處理!
4.配置註解驅動的Spring MVC
好了,不多說!現在spring已經大部分能使用註釋來代替從前要在配置檔案裡所做的事,接下來我們大部分會使用註釋方式來完成。
a.定義控制器
DispatcherServlet需要諮詢一個或多個處理器來明確地將請求分發給那個控制器。Spring提供了許多處理器對映實現,那我們只需要DefaultAnnotationHandlerMapping來實現即可。
DefaultAnnotationHandlerMapping:將請求對映給使用@requestMapping註解的控制器和控制器方法。
首先要作用註解,你必需把註解的類及方法等載入到上下文應用中,即spring容器,才能使用!
我們需要在配置檔案中加上以下配置,即可實現註解功能:
<beans>
...
<!-- 掃描指定包下的註解 --></span>
<context:component-scan base-package="com.blog">
<!-- 配置元件過濾器 -->
<!-- 指定掃描的包 -->
<context:include-filter type="annotation" expression="com.blog.controller"/>
<!-- 指定不需要掃描的包 -->
<context:exclude-filter type="annotation" expression="com.blog.dao"/>
</context:component-scan>
...
</beans>
注:上面只是為了舉例說明
下面配置基本也夠用了,如果不是特別要求:
<beans>
...
<!-- 掃描指定包下的註解 -->
<context:component-scan base-package="com.blog"/>
...
</beans>
說明:
預設情況下,<context:component-scan>查詢使用構造型註解所標註的類,這些特殊的註解如下:
@Component -- 通用的構造型註解,標識該類為Spring元件;
@Controller -- 標識將該類定義為Spring MVC controller;
@Repository -- 標識將該類定義為資料倉庫;
@Service -- 標識將該類定義為服務;
使用@component標註的任意自定義註解。
一般為好區分某類屬於控制、資料庫訪問和業務層,會分別使用對應的註解@Controller、@Repository和@Service,而儘量少用@Component,@Component是通用的!
接下來我們可以宣告一個登入到主頁面(或首頁)的控制器:
先把 spring mvc切換到3.x版本的jar吧,之前用的是4.x以上的。
這是因為4.x的註解可能與3.x有點差別,而本例子注重的是3.x版本的開發。
切換配置:
<project>
...
<!-- 定義屬性,供${propertieName}訪問 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>3.2.13.RELEASE</spring.version>
</properties>
...
</project>
b.渲染檢視
--通過上述的控制器去呼叫對應的業務層後,然後要將處理的結果告知使用者時,我們需要對檢視進行渲染,從而顯示在客戶端上即可!
wwo-servlet.xml檔案中配置的程式碼如下:
<!--
原理:邏輯檢視名通過新增字首字尾來確定要檢視路徑
解析檢視,因jsp檢視使用了jstl標籤,
所以需要通過設定viewClass屬於來將InternalResourceViewResolver替換為JstlView -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
上面是我常用渲染檢視的配置方法,但我們接下講的是通過Apache Tiles佈局管理器來渲染!
Apache Tiles:對於一般的web應用程式,InternalResourceViewResolver檢視基本夠用了。但對於一些複雜的web應用,就應該使用Apache Tiles佈局管理器了,好處是它可以使一些通用的元素(或頁面)被頁面所共享,從而達到元素的重用。
wwo-servlet.xml檔案中配置的程式碼如下:
<!--
Apache Tiles 代替 JstlView
要是希望一些通用的元素被頁面共享,則可以使用Apache Tiles佈局管理器。
通過Spring MVC配置解析Tiles的佈局檢視!
建立檢視解析器:TilesViewResolver;
載入Tiles的定義:TilesConfigurer;
由TilesConfigurer載入tiles定義,並使用TilesViewResolver解析檢視。
views.xml為tiles的定義檔案,它們都分散在/WEB-INF/views/目錄下;
/WEB-INF/views/**/views.xml:**,查詢/WEB-INF/views/目錄下的所以views.xml檔案
-->
<bean class="org.springframework.web.servlet.view.tiles2.TilesViewResolver"/>
<bean class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/main-tiles/main-tiles.xml</value>
</list>
</property>
</bean>
我們再來看看/WEB-INF/main-tiles/main-titles.xml檔案的配置:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN"
"http://tiles.apache.org/dtds/tiles-config_2_1.dtd">
<tiles-definitions>
<!--
定義通用的佈局
-->
<definition name="template" template="/blog/main/main_template.jsp">
<put-attribute name="top" value="/blog/main/title.jsp"/>
</definition>
<!--
定義main的tiles
-->
<definition name="main" extends="template">
<put-attribute name="content" value="/blog/main/main.jsp"/>
</definition>
</tiles-definitions>
注:這裡definition標籤的屬性name是對應控制層,return返回的邏輯檢視名。
再下來,看在main_template.jsp中怎麼來配置使用,來達到重用的目的的。
也就是說,main_template.jsp可以由若干個.jsp頁面組成!
main_template.jsp檔案:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="t" uri="http://tiles.apache.org/tags-tiles" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<style type="text/css">
body{
background-color: rgb(95, 2, 2);
}
</style>
</head>
<body>
<t:insertAttribute name="top"/>
<t:insertAttribute name="content"/>
</body>
</html>
好了,我們可以看到要使用tags-tiles的標籤庫來達到目的!
效果:
main_template.jsp顯示的頁面:
title.jsp顯示的頁面:
main.jsp顯示的頁面:
好了,到此Spring MVC構架完成!