閱讀419 返回首頁    go 阿裏雲 go 技術社區[雲棲]


《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

  上一篇:go  《單頁Web應用:JavaScript從前端到後端》——導讀
  下一篇:go  《Spring 3.0就這麼簡單》——1.5 業務層