1. 程式人生 > 其它 >第2章 Spring MVC基礎:4、表單標籤庫與資料繫結

第2章 Spring MVC基礎:4、表單標籤庫與資料繫結

技術標籤:javaspringhtml

學習目標:

表單標籤庫與資料繫結


學習大綱:

一、表單標籤庫
二、資料繫結


學習內容:

資料繫結是將使用者引數輸入值繫結到領域模型的一種特性。在Spring MVC的Controller和View引數資料傳遞中,所有的HTTP請求的型別均為字串。如果模型需要繫結的型別為double或int,則需要手動進行型別轉換。而有了資料繫結後,就無需再手動將HTTP請求中的Spring型別轉化為模型需要的型別。資料繫結的另一個好處是,當輸入驗證失敗時,會重新生成一個HTML表單,無須重新填寫輸入欄位。在Spring MVC中,為了方便、高效的使用資料繫結,還需要學習表單標籤庫。

“資料繫結”是前端框架技術中的一個概念,比如微信小程式開發中的資料繫結、vue.js中的雙向資料繫結。

我們知道前端框架的意義是讓前端開發更方便、更高效,那麼資料繫結肯定也是為這個目的服務的。

資料繫結是為了實現一種“動態”的效果,後臺的資料更新了,前端頁面也自動更新;前端頁面上的資料更新了,後臺的資料也自動更新。

一、表單標籤庫

表單標籤庫中包含了可以用在JSP頁面中渲染HTML元素的標籤。JSP頁面使用Spring表單標籤庫時,必須在JSP頁面開頭處宣告taglib指令,指令程式碼如下:

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"
%>

表單標籤庫中有forminputpasswordhiddentextareacheckboxcheckboxesradiobuttonradiobuttonsselectoptionoptionserrors

1.表單標籤
表單標籤,語法格式如下:

<form:form modelAttribute="xxx" method="post" action="xxx">
	……
</form:form>

除了具有HTML表單元素屬性外,表單標籤還有具有acceptCharset、commandName、cssClass、cssStyle、htmlEscape和modelAttribute

等屬性。

最常用的是modelAttribute屬性:用來暴露form backing object的模型屬性名稱。預設為command。

其中,commandNamemodelAttribute屬性功能基本一致,屬性值繫結一個JavaBean物件。

2.input標籤

input標籤,語法格式如下:

 <form:input path="xxx"/>

該標籤除了cssClass、cssStyle、htmlEscape屬性外,還有一個最重要的屬性pathpath屬性將文字框輸入值繫結到form backing object的一個屬性。

3.password標籤
password標籤,語法格式如下:

<form:password path="xxx"/>

該標籤與input標籤用法完全一致,不再贅述。

4.hidden標籤
hidden標籤,語法格式如下:

<form:hidden path="xxx"/>

該標籤與input標籤用法基本一致,只不過它不可顯示,不支援cssClass和cssStyle屬性。

5.textarea標籤
textarea基本上就是一個支援多行輸入的input元素,語法格式如下:

<form:textarea path="xxx"/>

該標籤與input標籤用法完全一致,不再贅述。

6.checkbox標籤
checkbox標籤,語法格式如下:

<form:checkbox path="xxx" value="xxx"/>

多個path相同的checkbox標籤,它們是一個選項組,允許多選。選項值繫結到一個數組屬性。示例程式碼如下:

<form:checkbox path="friends" value="張三"/>張三
<form:checkbox path="friends" value="李四"/>李四
<form:checkbox path="friends" value="王五"/>王五

上述示例程式碼中的複選框的值繫結到一個字串陣列屬性friends(String[ ] friends)。

7.checkboxes標籤
checkboxes標籤渲染多個複選框,是一個選項組,等價於多個path相同的checkbox標籤。它有3個非常重要的屬性:items、itemLabel和itemValue
items:用於生成input元素的Collection、Map或Array。
itemLabel:items屬性中指定的集合物件的屬性,為每個input元素提供label。
itemValue:items屬性中指定的集合物件的屬性,為每個input元素提供value。
checkboxes標籤語法格式如下:

 <form:checkboxes items="xxx"  path="xxx"/>

示例程式碼如下:

 <form:checkboxes items="${hobbys}"  path="hobby"/>

上述程式碼是將model屬性hobbys的內容(集合元素)渲染為複選框。

8.radiobutton標籤
radiobutton標籤,語法格式如下:

<form:radiobutton path="xxx" value="xxx"/>

多個path相同的radiobutton標籤,它們是一個選項組,只允許單選。

9.radiobuttons標籤
radiobuttons標籤渲染多個radio,是一個選項組,等價於多個path相同的radiobutton標籤。radiobuttons標籤,語法格式如下:

  <form:radiobuttons path="xxx" items="xxx"/>

該標籤的itemLabel和itemValue屬性與checkboxes標籤的itemLabel和itemValue屬性完全一樣,但只允許單選。

10.select標籤
select標籤的選項可能來自其屬性items指定的集合,或者來自一個巢狀的option標籤或options標籤。語法格式如下:

  <`form:select path="xxx" items="xxx" />`

  <form:select path="xxx" items="xxx" >
	 <option value="xxx">xxx</option>
    </ form:select>

 <form:select path="xxx">
       <form:options items="xxx"/>
    </form:select>

該標籤的itemLabel和itemValue屬性與checkboxes標籤的itemLabelitemValue屬性完全一樣。

11.options標籤
options標籤生成一個select標籤的選項列表。因此,需要與select標籤一同使用,具體用法參見select標籤。

12.errors標籤
errors標籤渲染一個或者多個span元素,每個span元素包含一個錯誤訊息。它可以用於顯示一個特定的錯誤訊息,也可以顯示所有錯誤訊息。語法如下:

<form:errors path="*"/>

  <form:errors path="xxx"/>

其中,“*”表示顯示所有錯誤訊息;“xxx”表示顯示由“xxx”指定的特定錯誤訊息。

二、資料繫結

為了讓讀者進一步學習資料繫結和表單標籤,本節給出了一個應用例項ch2_4。ch2_4應用中實現了User類屬性和JSP頁面中表單引數的繫結,同時在JSP頁面中分別展示了input、textarea、checkbox、checkboxs、select等標籤。

【例2-4】資料繫結和表單標籤。
具體實現步驟如下:
1、建立應用並匯入相關的JAR包
在ch2_4應用中需要使用JSTL,因此不僅需要將Spring MVC相關jar包複製到應用的WEB-INF/lib目錄下還需要從Tomcat的webapps\examples\WEB-INF\lib目錄下將JSTL相關jar包複製到應用的WEB-INF/lib目錄下。
在這裡插入圖片描述
在這裡插入圖片描述

2、建立Web和Spring MVC配置類
在ch2_4應用的src目錄下建立名為config的包,並在該包中建立Web配置類WebConfig和Spring MVC配置類SpringMVCConfig
為了避免中文亂碼問題,需要在Web配置類WebConfig中註冊編碼過濾器,同時JSP頁面編碼設定為UTF-8,form表單的提交方式為post。

WebConfig的程式碼如下:

package config;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.DispatcherServlet;
public class WebConfig implements WebApplicationInitializer{
	@Override
	public void onStartup(ServletContext arg0) throws ServletException {
		AnnotationConfigWebApplicationContext ctx 
		= new AnnotationConfigWebApplicationContext();
		ctx.register(SpringMVCConfig.class);//註冊Spring MVC的Java配置類SpringMVCConfig
		ctx.setServletContext(arg0);//和當前ServletContext關聯
		/**
		 * 註冊Spring MVC的DispatcherServlet
		 */
		javax.servlet.ServletRegistration.Dynamic servlet =
				arg0.addServlet("dispatcher", new DispatcherServlet(ctx));
		servlet.addMapping("/");
		servlet.setLoadOnStartup(1);
		/**
		 * 註冊字元編碼過濾器
		 */
		javax.servlet.FilterRegistration.Dynamic filter =
				arg0.addFilter("characterEncodingFilter", CharacterEncodingFilter.class);
		filter.setInitParameter("encoding", "UTF-8");
		filter.addMappingForUrlPatterns(null, false, "/*");
	}
}

SpringMVCConfig的程式碼如下:

package config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"controller","service"})
public class SpringMVCConfig implements WebMvcConfigurer {
	/**
	 * 配置檢視解析器
	 */
	@Bean
	public InternalResourceViewResolver getViewResolver() {
		InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
		viewResolver.setPrefix("/WEB-INF/jsp/");
		viewResolver.setSuffix(".jsp");
		return viewResolver;
	}
	/**
	 * 配置靜態資源
	 */
	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/html/**").addResourceLocations("/html/");
		//addResourceHandler指的是對外暴露的訪問路徑
		//addResourceLocations指的是靜態資源存放的位置
	}
}

3、建立View層
View層包含兩個JSP頁面,一個是資訊輸入頁面userAdd.jsp,一個是資訊顯示頁面userList.jsp。在ch2_4應用的WEB-INF/jsp/目錄下,建立這兩個JSP頁面。

在userAdd.jsp頁面中將Map型別的hobbys繫結到checkboxes上,將String[ ]型別的carrers和houseRegisters繫結到select上,實現通過option標籤對select新增選項,同時表單的method方法需指定為post來避免中文亂碼問題。

在userList.jsp頁面中使用JSTL標籤遍歷集合中的使用者資訊。

userAdd.jsp的程式碼如下:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form:form modelAttribute="user"  method="post" action="${pageContext.request.contextPath }/user/save">
    <fieldset>
        <legend>新增一個使用者</legend>
        <p>
            <label>使用者名稱:</label>
            <form:input path="userName"/>
        </p>
        <p>
            <label>愛好:</label>
            <form:checkboxes items="${hobbys}"  path="hobby" />
        </p>
        <p>
            <label>朋友:</label>
            <form:checkbox path="friends" value="張三"/>張三
            <form:checkbox path="friends" value="李四"/>李四
            <form:checkbox path="friends" value="王五"/>王五
            <form:checkbox path="friends" value="趙六"/>趙六
        </p>
        <p>
            <label>職業:</label>
            <form:select path="carrer"> 
                <option/>請選擇職業
                <form:options items="${carrers }"/>
            </form:select>
        </p>
        <p>
            <label>戶籍:</label>
            <form:select path="houseRegister">
                <option/>請選擇戶籍
                <form:options items="${houseRegisters }"/>
            </form:select>
        </p>
        <p>
            <label>個人描述:</label>
            <form:textarea path="remark" rows="5"/>
        </p>
        <p id="buttons">
            <input id="reset" type="reset">
            <input id="submit" type="submit" value="新增">
        </p>
    </fieldset>
</form:form>
</body>
</html>

userList.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>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h1>使用者列表</h1>
    <a href="<c:url value="/user/input"/>">繼續新增</a>
    <table>
        <tr>
            <th>使用者名稱</th>
            <th>興趣愛好</th>
            <th>朋友</th>
            <th>職業</th>
            <th>戶籍</th>
            <th>個人描述</th>
        </tr>
        <!-- JSTL標籤,請參考本書的相關內容 -->
        <c:forEach items="${users}" var="user">
            <tr>
                <td>${user.userName }</td>
                <td>
                	<c:forEach items="${user.hobby }" var="hobby">
                		${hobby }&nbsp;
                	</c:forEach>
                </td>
                <td>
                	<c:forEach items="${user.friends }" var="friend">
                		${friend }&nbsp;
                	</c:forEach>
                </td>
                <td>${user.carrer }</td>
                <td>${user.houseRegister }</td>
                <td>${user.remark }</td>
            </tr>
        </c:forEach>
    </table>
</body>
</html>

4、建立領域模型
在ch2_4應用中實現了User類屬性和JSP頁面中表單引數的繫結,User類包含和表單引數名對應的屬性,以及屬性的set和get方法。在ch2_4應用的src目錄下,建立pojo包,並在該包中建立User類。
User類的程式碼如下:

package pojo;

public class User {
	private String userName;
	private String[] hobby;//興趣愛好
	private String[] friends;//朋友
	private String carrer;
	private String houseRegister;
	private String remark;
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String[] getHobby() {
		return hobby;
	}
	public void setHobby(String[] hobby) {
		this.hobby = hobby;
	}
	public String[] getFriends() {
		return friends;
	}
	public void setFriends(String[] friends) {
		this.friends = friends;
	}
	public String getCarrer() {
		return carrer;
	}
	public void setCarrer(String carrer) {
		this.carrer = carrer;
	}
	public String getHouseRegister() {
		return houseRegister;
	}
	public void setHouseRegister(String houseRegister) {
		this.houseRegister = houseRegister;
	}
	public String getRemark() {
		return remark;
	}
	public void setRemark(String remark) {
		this.remark = remark;
	}
}

5、建立Service層
在ch2_4應用中使用了Service層,在Service層使用靜態集合變數users模擬資料庫儲存使用者資訊,包括新增使用者和查詢使用者兩個功能。在ch2_4應用的src目錄下,建立Service包,並在該包中建立UserService介面和UserServiceImpl實現類。
UserService介面的程式碼如下:

package service;
import java.util.ArrayList;
import pojo.User;
public interface UserService {
	boolean addUser(User u);
	ArrayList<User> getUsers();
}

UserServiceImpl實現類的程式碼如下:

package service;
import java.util.ArrayList;
import org.springframework.stereotype.Service;
import pojo.User;
@Service
public class UserServiceImpl implements UserService{
	//使用靜態集合變數users模擬資料庫
	private static ArrayList<User> users = new ArrayList<User>();
	@Override
	public boolean addUser(User u) {
		if(!"IT民工".equals(u.getCarrer())){//不允許新增IT民工
			users.add(u);
			return true;
		}
		return false;
	}
	@Override
	public ArrayList<User> getUsers() {
		return users;
	}
}

6、建立Controller層
在Controller類的UserController中定義了請求處理方法,包括處理user/input請求的inputUser方法和處理user/save請求的addUser方法,其中在addUser方法中用到了重定向。在UserController類中,通過@Autowired註解在UserController物件中主動注入UserController物件,實現對user物件的新增和查詢操作;通過model的addAttribute方法將User類物件、HashMap型別的hobbys物件、String[ ]型別的carrers物件以及String[ ]型別的houseRegisters物件傳遞給View(userAdd.jsp)。

在ch2_4應用的src目錄下,建立controller包,並在該包中建立UserController控制器類。
UserController類的程式碼如下:

package controller;
import java.util.HashMap;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import pojo.User;
import service.UserService;
@Controller
@RequestMapping("/user")
public class UserController {
	// 得到一個用來記錄日誌的物件,這樣列印資訊的時候能夠標記列印的是那個類的資訊
	private static final Log logger = LogFactory.getLog(UserController.class);
	@Autowired
	private UserService userService;
	@RequestMapping(value = "/input")
	public String inputUser(Model model) {
		HashMap<String, String> hobbys = new HashMap<String, String>();
		hobbys.put("籃球", "籃球");
		hobbys.put("乒乓球", "乒乓球");
		hobbys.put("電玩", "電玩");
		hobbys.put("游泳", "游泳");
	     // 如果model中沒有user屬性,userAdd.jsp會丟擲異常,因為表單標籤無法找到
// modelAttribute屬性指定的form backing object
		model.addAttribute("user", new User());
		model.addAttribute("hobbys", hobbys);
	model.addAttribute("carrers", new String[] { "教師", "學生", "coding搬運工", "IT民工", "其它" });
		model.addAttribute("houseRegisters", new String[] { "北京", "上海", "廣州", "深圳", "其它" });
		return "userAdd";
	}
	@RequestMapping(value = "/save")
	public String addUser(@ModelAttribute User user, Model model) {
		if (userService.addUser(user)) {
			logger.info("成功");
			return "redirect:/user/list";
		} else {
			logger.info("失敗");
			HashMap<String, String> hobbys = new HashMap<String, String>();
			hobbys.put("籃球", "籃球");
			hobbys.put("乒乓球", "乒乓球");
			hobbys.put("電玩", "電玩");
			hobbys.put("游泳", "游泳");
			// 這裡不需要model.addAttribute("user", new
			// User()),因為@ModelAttribute指定form backing object
			model.addAttribute("hobbys", hobbys);
	model.addAttribute("carrers", new String[] { "教師", "學生", "coding搬運工", "IT民工", "其它" });
		model.addAttribute("houseRegisters", new String[] { "北京", "上海", "廣州", "深圳", "其它" });
			return "userAdd";
		}
	}
	@RequestMapping(value = "/list")
	public String listUsers(Model model) {
		List<User> users = userService.getUsers();
		model.addAttribute("users", users);
		return "userList";
	}
}

7、測試應用
通過以下地址訪問應用:
在這裡插入圖片描述
在這裡插入圖片描述

新增成功後,重定向到資訊顯示頁面。

在這裡插入圖片描述


學習時間:

在這裡插入圖片描述


學習產出:

1、 技術筆記 1 遍
2、CSDN 技術部落格 1 篇