在spring MVC 中,每個請求到DispatcherServlet後根據需求,將會分配到相對應的控制器controller去處理,因此controller在 spring MVC中的作用是非常重要的。本文先介紹兩類controller。
一、頁面直接跳轉
當我們請求一個頁面時,由於文件都隱藏在了文件下,無法直接訪問,因此需要有一個控制器來實現簡單的頁面跳轉,跳轉到對應的頁面。這類控制器不需要對請求做太多的處理地,只需實現頁面跳轉即可。這時,我們可以不需要自己去設計自己的controller,而是直接配置現有的controller類。與頁面直接跳轉的現有controller主要有以下兩個:
1、ParameterizableViewController
我們在“/WEB-INF/jsp/”目錄下創建了一個welcome.html文檔,爲了實現在瀏覽器中輸入welcome.test就直接跳轉到welcome.html,spring-servlet.xml文件配置主要如下:
不需要自己寫控制器,而是直接調用現有的ParameterizableViewController類來實現。只需要指定對應的視圖名就可以。然後就能根據視圖解析器去查找需要跳轉的頁面,視圖解析器設置如下:
<!-- 視圖解析器 -->
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property>
<!-- 前綴 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 後綴 -->
<property name="suffix" value=".html" />
</bean>
2、UrlFilenameViewController
這個控制器相對於ParameterizableViewController更爲簡潔,可以不用指明視圖名,而直接通過請求的url去查找文件,直接以請求 的URL來確定視圖名,然後直接跳轉過去。例如請求的url是“welcome.test”,那麼從中提取出視圖名爲“welcome”,而不需要另外指定視圖名。這種方法適用於請求的url跟視圖名一致。
這兩種方法都是直接配置現有的controller類來實現頁面的直接跳轉,區別在於ParameterizableViewController類可以根據需要指定視圖名,較爲靈活,而UrlFilenameViewController類只能跳轉到跟url對應的視圖名,而不能自行指定視圖名。
welcome.html文檔如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>welcome page</title>
</head>
<body>
<h1>this is the welcome page</h1>
</body>
</html>
啓動服務器後,在外部瀏覽器中輸入:http://localhost:8080/springMVC/welcome.test,即可正常跳轉到welcome.htm頁面。
二、封裝表單參數的控制器
一般我們在進行表單登記或者註冊時,會要求填較多的信息,這些信息如果按照之前介紹的繼承Controller來實現參數的注入,當表單參數較多時,代碼就會顯得冗餘。因此我們希望controller能實現數據的自動封裝。這裏,我將介紹兩種方法來實現表單參數的自動封裝。
1、AbstractCommandController
首先需要注意的一個問題是由於AbstractCommandController在spring 3之後就不建議使用了,因此在一些比較新的spring MVC框架中並不包含這個類,這裏本着學習的態度,還是瞭解一下。所以在導入jar包是需要注意版本問題。通過查看各版本的jar包,注意到3.2.2這個版本中包含有AbstractCommandController,讀者們可以到 http://repo.spring.io/libs-release-local/org/springframework/spring/3.2.2.RELEASE/ 中下載。在測試中,我導入的jar包如下:
接下來使配置文件,首先配置info.java
和infoController.java
文檔
infoController.java
文檔
package test.springMVC;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractCommandController;
@SuppressWarnings("deprecation")
public class infoController extends AbstractCommandController {
@Override
protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException exception)
throws Exception {
info inf = (info)command;
System.out.println(inf);
return new ModelAndView("addsucc");
}
}
info.java
文檔
package test.springMVC;
public class info {
private String name;
private int num;
private String phone;
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String toString() {
return name + ";" + num + ";" + phone;
}
}
spring-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: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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd">
<!-- 設置映射方式 -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="addInfo.html">addInfoController</prop>
<prop key="add.test">addSuccController</prop>
</props>
</property>
</bean>
<bean id="addInfoController" class="org.springframework.web.servlet.mvc.UrlFilenameViewController">
</bean>
<bean id="addSuccController" class="test.springMVC.infoController">
<property name="commandClass" value="test.springMVC.info"></property>
</bean>
<!-- scan the package and the sub package -->
<context:component-scan base-package="test.SpringMVC" />
<!-- don't handle the static resource -->
<mvc:default-servlet-handler />
<!-- if you use annotation you must configure following setting -->
<mvc:annotation-driven />
<!-- 視圖解析器 -->
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property>
<!-- 前綴 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 後綴 -->
<property name="suffix" value=".html" />
</bean>
</beans>
視圖文檔 addInfo.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>添加信息</title>
</head>
<body>
<form action="add.test" method="post">
name : <input type="text" name="name" /><br />
number : <input type="text" name="num" /><br />
phone:<input type="text" name="phone" /><br />
<input type="submit" value="提交" />
</form>
</body>
</html>
啓動服務器後,在外部瀏覽器中輸入http://localhost:8080/springMVC/addInfo.html,跳轉到addInfo.html
的頁面
填入信息後點提交,提交成功後會跳轉到成功頁面
另外查看eclipse控制能打印出所填信息
當輸入的表單參數爲“int”和“String”類型,並且輸入格式正確的話,是能正確顯示的,但是如果我們在視圖addInfo.html
文檔中加入一個日期格式,就會報“空指針異常”的錯誤。這是因爲當表單提交參數時,會有一個數據綁定DateBind的過程,根據“name”的值把參數註冊到對象中。當輸入的爲“int”和“String”類型時,通過屬性編輯器能將其轉成正確的數據類型,但是缺少Date類型的屬性編輯器,因此要將Date類型正確的註冊到對象中,在數據綁定中手動註冊一個Date類型屬性編輯器。
infoController.java
文檔
package test.springMVC;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.validation.BindException;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractCommandController;
@SuppressWarnings("deprecation")
public class infoController extends AbstractCommandController {
@Override
protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException exception)
throws Exception {
info inf = (info)command;
System.out.println(inf);
return new ModelAndView("addsucc");
}
@Override
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
// TODO Auto-generated method stub
binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
}
}
info.java
文檔
package test.springMVC;
import java.text.SimpleDateFormat;
import java.util.Date;
public class info {
private String name;
private int num;
private String phone;
private Date schoolDate;
public Date getSchoolDate() {
return schoolDate;
}
public void setSchoolDate(Date schoolDate) {
this.schoolDate = schoolDate;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String toString() {
return name + ";" + num + ";" + phone + ";" + new SimpleDateFormat("yyyy-mm-dd").format(schoolDate);
}
}
對應的 addInfo.html
也增加一個日期選擇框
date : <input type="date" name="schoolDate" />
這樣運行之後,控制檯就能打印出正確的表單提交的參數
2、SimpleFormController
SimpleFormController也是用自動封裝表單參數。SimpleFormController有如下一些特點:
1、表單提交方式必須採用“post”方法;
2、相對於AbstractCommandController信息登記和封裝成功需要兩個控制器來處理,SimpleFormController只需要一個控制器就行,兩次請求的地址都是同一個,根據提交方式不同來區分轉到的頁面,因此在控制器中需要設置formView
和successView
屬性。第一個網址中提交是使用的“GET”方式,因此轉到formView
對應的頁面,第二次表單提交時採用的“post”方式,因此轉到successView
對應的頁面。
spring-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: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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd">
<!-- 設置映射方式 -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="addInfo.html">addInfoController</prop>
</props>
</property>
</bean>
<bean id="addInfoController" class="test.springMVC.infoFormController">
<property name="commandClass" value="test.springMVC.info"></property>
<property name="formView" value="addInfo"></property>
<property name="successView" value="addsucc"></property>
</bean>
<!-- 視圖解析器 -->
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property>
<!-- 前綴 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 後綴 -->
<property name="suffix" value=".jsp" />
</bean>
</beans>
infoFormController.java
package test.springMVC;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
public class infoFormController extends SimpleFormController {
@Override
protected Map referenceData(HttpServletRequest request) throws Exception {
Map<String, Object> model = new HashMap<String, Object>();
model.put("groupList", new String[]{"group1", "group2"});
return model;
}
@Override
protected ModelAndView onSubmit(Object command) throws Exception {
info inf = (info)command;
System.out.println(inf);
return new ModelAndView("addsucc");
}
@Override
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
// TODO Auto-generated method stub
binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
}
}
addInfo.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!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=ISO-8859-1">
<title>信息添加</title>
</head>
<body>
<form action="" method="post"> <!-- 必須指定爲post -->
name : <input type="text" name="name" /><br />
number : <input type="text" name="num" /><br />
phone:<input type="text" name="phone" /><br />
group:<select name="group">
<c:forEach items="${groupList}" var="group">
<option value="${group}">${group}</option>
</c:forEach>
</select>
date : <input type="date" name="schoolDate" />
<input type="submit" value="提交" />
</form>
</body>
</html>
info.java
package test.springMVC;
import java.text.SimpleDateFormat;
import java.util.Date;
public class info {
private String name;
private int num;
private String phone;
private String group;
private Date schoolDate;
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public Date getSchoolDate() {
return schoolDate;
}
public void setSchoolDate(Date schoolDate) {
this.schoolDate = schoolDate;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String toString() {
return name + ";" + num + ";" + phone + ";" + group + ";" + new SimpleDateFormat("yyyy-mm-dd").format(schoolDate);
}
}
針對上面給出的代碼,對SimpleFormController實現表單數據自動封裝的過程總結如下:
- 瀏覽器中輸入url:“http://localhost:8080/springMVC/addInfo.html”,通過查找
spring-servlet.xml
文檔,由於是get請求,因此轉到formView
對應的addInfo.jsp
頁面。 addInfo.html
頁面中的<select>
標籤中的數據來自infoFormController
中的“referenceData”方法,因此轉到addInfo.html
頁面之前先獲取“referenceData”中的數據,然後在addInfo.html
頁面頁面中顯示出來。- 填寫信息之後,提交表單,提交的url還是 “http://localhost:8080/springMVC/addInfo.html”。由於表單的提交方式爲“post”,因此調用controller中的“onSubmit”方法。
- 數據封裝成功後,轉到
successView
對應的addsucc.jsp
頁面。