《Spring 3.0就這麼簡單》——1.6 展現層
本節書摘來自異步社區《Spring 3.0就這麼簡單》一書中的第1章,第1.6節,作者: 陳雄華 , 林開雄著,更多章節內容可以訪問雲棲社區“異步社區”公眾號查看
1.6 展現層
業務層和持久層的開發任務已經完成,該是為程序提供界麵的時候了。Struts MVC框架由於搶盡天時地利,成為當下最流行的展現層框架。但也有很多人認為Spring MVC相比較於Struts更簡單、更強大、更優雅。此外,由於Spring MVC出自於Spring之手,因此和Spring容器沒有任何不兼容性,顯得天衣無縫。
Spring 1.5新增了基於注解的MVC,而且Spring 3.1還提供了REST風格的MVC,Spring MVC已經變得輕便、強大、易用。我們將會在本書的第8章中學習Spring MVC的詳細內容。
1.6.1 配置Spring MVC框架
首先需要對web.xml文件進行配置,以便Web容器啟動時能夠自動啟動Spring容器,如代碼清單1-13所示。
代碼清單1-13 自動啟動Spring容器的配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="1.5"
xmlns="https://java.sun.com/xml/ns/javaee"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://java.sun.com/xml/ns/javaee
https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!--①從類路徑下加載Spring配置文件,classpath關鍵字特指在類路徑下加載_-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:applicationContext.xml
</param-value>
</context-param>
_<!--②負責啟動Spring容器的監聽器,它將引用①處的上下文參數獲得Spring配置文件地址-->_
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
…
</web-app>
首先,通過Web容器上下文參數指定Spring配置文件的地址,如①所示。多個配置文件可用逗號或空格分隔,建議采用逗號分隔的方式。在②處指定Spring所提供的ContextLoaderListener的Web容器監聽器,該監聽器在Web容器啟動時自動運行,它會根據contextConfigLocation Web容器參數獲取Spring配置文件,並啟動Spring容器。注意需要將log4J.propertis日誌配置文件放置在類路徑下,以便日誌引擎自動生效。
接下來,需要配置Spring MVC相關的信息,Spring MVC像Struts一樣,也通過一個Servlet截獲URL請求,然後再進行相關的處理,如代碼清單1-14所示。
代碼清單1-14 Spring MVC地址映射
…
<!-- Spring MVC的主控Servlet -->
<servlet> ①
<servlet-name>viewspace</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<!-- Spring MVC處理的URL -->
<servlet-mapping>②
<servlet-name>viewspace</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
在①處聲明了一個Servlet,Spring MVC也擁有一個Spring配置文件(稍後會涉及),該配置文件的文件名和此處定義的Servlet名有一個契約:即采用-servlet.xml的形式。在這裏,因為Servlet名為viewspace,所以在/WEB-INF目錄下必須提供一個viewspace- servlet.xml的Spring MVC配置文件,但這個配置文件無須通過web.xml的contextConfigLocation上下文參數進行聲明,因為Spring MVC的Servlet會自動將viewspace -servlet.xml和Spring其他的配置文件進行拚裝。
在②處對這個Servlet的URL路徑映射進行定義,在這裏讓所有以.html為後綴的URL都能被viewspace Servlet截獲,進而轉由Spring MVC框架進行處理。我們知道,在Struts框架中,一般將URL後綴配置為*.do,在Webwork中一般配置為*.action,其實,框架本身和URL模式沒有任何關係,用戶大可使用喜歡的任何後綴。使用.html後綴,一方麵,用戶不能通過URL直接知道開發者采用了何種服務端技術;另一方麵,.html是靜態網頁的後綴,可以騙過搜索引擎,增加被收錄的概率,所以推薦采用這種後綴。對於那些真正的無須任何動態處理的靜態網頁,則可以使用.htm後綴加以區分,以避免被框架截獲。
請求被Spring MVC截獲後,首先根據請求的URL查找到目標的處理控製器,並將請求參數封裝成一個“命令”對象一起傳給控製器處理,控製器調用Spring容器中的業務Bean完成業務處理工作並返回結果視圖。
1.6.2 處理登錄請求
POJO控製器類
首先要編寫的是LoginController,它負責處理登錄請求,完成登錄業務,並根據登錄成功與否轉向歡迎頁麵或失敗頁麵,如代碼清單1-15所示。
代碼清單1-15 LoginController.java
package com.smart.web;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.smart.domain.User;
import com.smart.service.UserService;
@Controller①
@RequestMapping(value = "/admin"
public class LoginController{
@Autowired
private UserService userService;
@RequestMapping(value = "/login.html")②
public String loginPage(){
return "login";
}
@RequestMapping(value = "/loginCheck.html")③
public ModelAndView loginCheck(HttpServletRequest request,LoginCommand loginCommand){
boolean isValidUser =
userService.hasMatchUser(loginCommand.getUserName(),
loginCommand.getPassword());
if (!isValidUser) {
return new ModelAndView("login", "error", "用戶名或密碼錯誤。");
} else {
User user = userService.findUserByUserName(loginCommand
.getUserName());
user.setLastIp(request.getRemoteAddr());
user.setLastVisit(new Date());
userService.loginSuccess(user);
request.getSession().setAttribute("user", user);
return new ModelAndView("main");
}
}
}
在①處通過Spring MVC的@Controller注解可以將任何一個POJO的類標注為Spring MVC的控製器,處理HTTP的請求。當然標注了@Controller的類首先會是一個Bean,所以可以使用@Autowired進行Bean的注入。
一個控製器可以擁有多個對應不同HTTP請求路徑的處理方法,通過@RequestMapping指定方法如何映射請求路徑,如②和③所示。
請求的參數會根據參數名稱默認契約自動綁定到響應方法的入參中,在③處的loginCheck(HttpServletRequest request,LoginCommand loginCommand)方法中,請求參數會按名稱匹配綁定到loginCommand的入參中。
請求響應方法可以返回一個ModelAndView,或直接返回一個字符串,Spring MVC會解析之並轉向目標響應頁麵。
ModelAndView對象既包括了視圖信息又包括了視圖渲染所需的模型數據信息,在這裏用戶僅需要了解它代表一個視圖就可以了,在後麵的內容中,讀者將了解到Spring MVC如何根據這個對象轉向真正的頁麵。
前麵使用到的LoginCommand對象是一個POJO,它沒有繼承於特定的父類或實現特定的接口。LoginCommand類僅包括用戶/密碼這兩個屬性(和請求的用戶/密碼參數名稱一樣),如代碼清單1-16所示。
代碼清單1-16 LoginCommand
package com.smart.web;
public class LoginCommand {
private String userName;
private String password;
//省略get/setter方法
}
Spring MVC配置文件
編寫好LoginCommand後,需要在viewspace-servlet.xml中聲明該控製器,掃描Web路徑,指定Spring MVC的視圖解析器,如代碼清單1-17所示。
代碼清單1-17 viewspace-servlet.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:p="https://www.springframework. org/schema/p"
xmlns:context="https://www.springframework.org/schema/context"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans-3.1.xsd
https://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context-3.1.xsd">
<!--①掃描web包,應用Spring的注解 -->
<context:component-scan base-package="com.smart.web"/>
<!--②配置視圖解析器,將ModelAndView及字符串解析為具體的頁麵 -->
<bean
p:viewClass="org.springframework.web.servlet.view.JstlView"
p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp" />
</beans>
ModelAndView的解析配置
在代碼清單1-15 的③處,控製器根據登錄處理結果分別返回 ModelAndView ("login", "error", "用戶名或密碼錯誤。")和ModelAndView("main")。ModelAndView的第一個參數代表視圖的邏輯名,第二個和第三個參數分別為數據模型名稱和數據模型對象,數據模型對象將以數據模型名稱為參數名放置到request的屬性中。
Spring MVC如何將視圖邏輯名解析為具體的視圖頁麵呢?解決的思路也和上麵的方法類似,需要在viewspace-servlet.xml中提供一個定義解析規則的Bean,如代碼清單1-18所示。
代碼清單1-18 viewspace-servlet.xml視圖解析規則
…
<!--通過prefix指定在視圖名前所添加的前綴,通過suffix指定在視圖名後添加的後綴-->
<bean
p:viewClass="org.springframework.web.servlet.view.JstlView"
p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp" />
Spring MVC為視圖名到具體視圖的映射提供了許多可供選擇的方法。在這裏,使用了InternalResourceViewResolver,它通過為視圖邏輯名添加前後綴的方式進行解析。如視圖邏輯名“login”將解析為/WEB-INF/jsp/login.jsp;視圖邏輯名“main”將解析為/WEB-INF/jsp/main.jsp。
1.6.3 JSP視圖頁麵
景區網站登錄模塊共包括兩個JSP頁麵,分別是登錄頁麵login.jsp和管理主頁麵main.jsp,下麵將完成這兩個頁麵的開發工作。
登錄頁麵login.jsp
登錄頁麵login.jsp的代碼如代碼清單1-19所示。
代碼清單1-19 login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="https://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>景區網站登錄</title>
</head>
<body>
<c:if test="${!empty error}"> ①
<font color="red"><c:out value="${error}" /></font>
</c:if>
<form action="<c:url value="/ loginCheck.html "/>" method= "post">②
用戶名:
<input type="text" name="userName">
<br>
密 碼:
<input type="password" name="password">
<br>
<input type="submit" value="登錄" />
<input type="reset" value="重置" />
</form>
</body>
</html>
login.jsp頁麵既作為登錄頁麵又作為登錄失敗後的響應頁麵。因此在 ①處使用JSTL標簽對登錄錯誤返回的信息進行處理。JSTL標簽中引用了error變量,這個變量正是LoginController中返回的ModelAndView("login", "error", "用戶名或密碼錯誤。") 對象所聲明的error參數。
login.jsp的登錄表單提交到/loginController.html,如②所示。的JSTL標簽會在URL前自動加上應用程序部署根目錄,假設應用部署在網站的viewspace目錄下,標簽將輸出/viewspace/loginController.html。通過標簽很好地解決了開發和應用部署目錄不一致的問題。
由於 login.jsp 放置在 WEB-INF/jsp 目錄下,無法直接通過 URL 進行調用,它由LoginController 控製類中標注了@RequestMapping(value = "/login.html")的loginPage()進行轉發,見代碼清單1-15。
景區管理主頁麵main.jsp
登錄成功的歡迎頁麵很簡單,僅使用JSTL標簽顯示一條歡迎信息即可,如代碼清單1-20所示。
代碼清單1-20 main.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="https://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>景區後台管理主頁麵</title>
</head>
<body>
${user.userName},歡迎您進入景區後台管理! ①
</body>
</html>
①處訪問Session域中的user對象,顯示用戶名和積分信息。這樣,就完成了實例所有的開發任務。
最後更新:2017-05-31 14:31:33