首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Spring MVC 實戰總結(四):表單標簽庫深度解析、視圖解析器鏈與 FreeMarker 多視圖整合、CRUD 綜合示例

     編輯:Java 綜合教學

一、Spring 表單標簽庫

自 Spring 2.0 起提供 spring-form.tld,生成 HTML 4.01/XHTML 1.0 兼容標簽,實現雙向數據綁定。引入方式:

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

核心屬性

  • path:綁定屬性路徑(最關鍵),對應 modelAttribute.getXxx()。
  • cssClass / cssStyle:樣式類 / 行內樣式。
  • htmlEscape:是否 HTML 轉義,默認 true。
  • cssErrorClass:驗證錯誤時覆蓋 cssClass。

1. form + input 綁定對象

<!-- Controller -->
model.addAttribute("product", new Product("Meizu note1", 999));
return "bar/action11";

<!-- JSP -->
<form:form modelAttribute="product">
    <form:input path="name" cssClass="textCss" htmlEscape="false"/>
    <form:input path="price"/>
</form:form>

渲染後:

<form id="product" action="..." method="post">
    <input id="name" name="name" class="textCss" type="text" value="Meizu note1<hr/>"/>
    <input id="price" name="price" type="text" value="999.0"/>
</form>

htmlEscape="false" 允許原樣輸出 HTML 標簽(慎用 XSS 風險)。

2. checkbox 三種綁定模式

綁定類型選中條件示例
Boolean值為 truepath="isMarried"
數組/集合值在集合中path="hobbies" value="讀書" 多個同 path 不同 value
其他類型值等於綁定值path="education" value="本科"

渲染會自動生成隱藏域 _propertyName 確保未勾選也能提交值。

3. radiobutton 單選組

<form:radiobutton path="education" value="專科"/>專科
<form:radiobutton path="education" value="本科"/>本科
<form:radiobutton path="education" value="研究生"/>研究生

同 path 不同 value,自動按綁定值選中。

4. password 密碼框

<form:password path="pwd" showPassword="true"/>  <!-- 顯示明文 -->
<form:password path="pwd" showPassword="false"/> <!-- 默認掩碼 -->

5. select / option / options 下拉框

<!-- 單選 -->
<form:select path="education" items="${productTypes}" itemLabel="name" itemValue="id"/>

<!-- 多選 -->
<form:select path="education" multiple="true" size="3" items="${productTypes}" itemLabel="name" itemValue="id"/>

<!-- 手動 option + options 混用實現「請選擇」 -->
<form:select path="education">
    <form:option value="">--請選擇--</form:option>
    <form:options items="${productTypes}" itemLabel="name" itemValue="id"/>
</form:select>

6. textarea、errors、hidden

<form:textarea path="desc" rows="3" cols="20"/>
<form:errors path="desc"/>  <!-- 顯示驗證錯誤,生成 <span> -->
<form:hidden path="id"/>   <!-- 隱藏域,保持狀態 -->

7. radiobuttons / checkboxes 批量生成

<form:radiobuttons path="education" items="${productTypes}" itemLabel="name" itemValue="id" delimiter="," element="a"/>
<form:checkboxes path="hobbies" items="${productTypes}" itemLabel="name" itemValue="id" delimiter="-"/>

delimiter 分隔符,element 包裹標簽(默認 span)。

二、視圖解析器

核心接口

  • ViewResolver:邏輯視圖名 → 真實 View 對象映射。
  • View:渲染模型數據到響應。

常用解析器體系

鏈式視圖解析器

配置多個解析器,通過 order 控制優先級(值越小越優先)。InternalResourceViewResolver 必須放最後(總能解析成功,返回非空 View)。

<!-- FreeMarker 優先 order=1 -->
<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
    <property name="order" value="1"/>
    <property name="suffix" value=".html"/>
    <property name="prefix" value=""/>
    <property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView"/>
    <property name="exposeSpringMacroHelpers" value="true"/>
    <property name="requestContextAttribute" value="rc"/>
</bean>

<!-- JSP 兜底 order=2 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="order" value="2"/>
    <property name="prefix" value="/WEB-INF/views/"/>
    <property name="suffix" value=".jsp"/>
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
</bean>

三、FreeMarker 多視圖整合實戰

1. 依賴

<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.23</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>4.3.0.RELEASE</version>
</dependency>

2. 配置 FreeMarkerConfigurer

<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
    <property name="templateLoaderPath" value="/WEB-INF/htmlviews"/>
    <property name="freemarkerSettings">
        <props>
            <prop key="template_update_delay">5</prop>
            <prop key="defaultEncoding">UTF-8</prop>
            <prop key="classic_compatible">true</prop>
            <prop key="locale">zh_CN</prop>
            <prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop>
            <prop key="number_format">0.######</prop>
        </props>
    </property>
</bean>

3. Controller 雙視圖演示

@Controller @RequestMapping("/foo")
public class FooController {
    @RequestMapping("/jstl")
    public String jstl(Model model) {
        model.addAttribute("message", "Hello JSTL View!");
        return "foo/jstl"; // 解析為 /WEB-INF/views/foo/jstl.jsp
    }
    @RequestMapping("/ftl")
    public String ftl(Model model) {
        model.addAttribute("users", new String[]{"tom","mark","jack"});
        model.addAttribute("message", "Hello FreeMarker View!");
        return "foo/ftl"; // 解析為 /WEB-INF/htmlviews/foo/ftl.html
    }
}

4. 視圖文件

jstl.jsp:${message}

ftl.html:

<p>${message}</p>
<ul>
<#list users as user><li>${user}</li></#list>
</ul>

5. 運行效果

  • /foo/ftl → FreeMarkerViewResolver (order=1) 找到 ftl.html → 渲染成功。
  • /foo/jstl → FreeMarkerViewResolver 找不到 → InternalResourceViewResolver (order=2) 找到 jstl.jsp → 渲染成功。

四、綜合 CRUD 示例:產品管理

技術棧

Spring MVC 4.3 + Maven + MySQL + JSTL + jQuery

核心代碼結構

  • Entity:Product(id、name、price、ProductType)、ProductType
  • Service:ProductService(CRUD、搜索、批量刪除)、ProductTypeService
  • Controller:ProductController(index、add、addSave、edit、editSave、delete、deletes)
  • View:index.jsp(列表+搜索+批刪)、add.jsp、edit.jsp、main.css

關鍵 Controller 片段

@Controller @RequestMapping
public class ProductController {
    @Autowired ProductService productService;
    @Autowired ProductTypeService productTypeService;

    @RequestMapping
    public String index(Model model, String searchKey) {
        model.addAttribute("products", productService.getProductsByName(searchKey));
        model.addAttribute("searchKey", searchKey);
        return "product/index";
    }

    @RequestMapping("/add")
    public String add(Model model) {
        model.addAttribute("product", new Product());
        model.addAttribute("productTypes", productTypeService.getAllProductTypes());
        return "product/add";
    }

    @RequestMapping("/addSave")
    public String addSave(Model model, Product product) {
        try {
            product.setProductType(productTypeService.getProductTypeById(product.getProductType().getId()));
            productService.addProduct(product);
            return "redirect:/";
        } catch (Exception e) {
            model.addAttribute("product", product);
            model.addAttribute("productTypes", productTypeService.getAllProductTypes());
            model.addAttribute("message", e.getMessage());
            return "product/add";
        }
    }
    // edit/editSave/delete/deletes 類似...
}

列表頁核心 JSTL

<form method="get">
    名稱:<input name="searchKey" value="${searchKey}"/>
    <input type="submit" value="搜索"/>
</form>

<form action="deletes" method="post">
    <table class="tab">
        <c:forEach var="p" items="${products}">
            <tr>
                <td><input type="checkbox" name="id" value="${p.id}"/></td>
                <td>${p.id}</td><td>${p.name}</td><td>${p.price}</td><td>${p.productType.name}</td>
                <td>
                    <a href="delete/${p.id}" class="abtn">刪除</a>
                    <a href="edit/${p.id}" class="abtn">編輯</a>
                </td>
            </tr>
        </c:forEach>
    </table>
    <input type="submit" value="刪除選擇項"/>
    <a href="add" class="abtn">添加</a>
</form>

表單頁綁定

<form:form action="addSave" modelAttribute="product">
    <form:input path="name"/>
    <form:select path="productType.id" items="${productTypes}" itemLabel="name" itemValue="id"/>
    <form:input path="price"/>
    <form:hidden path="id"/> <!-- 編輯時保持 ID -->
    <input type="submit" value="保存"/>
</form:form>

五、總結與擴展

  1. 表單標簽:掌握 path 綁定、三種 checkbox 模式、select/options 混用、errors 顯示驗證錯誤。
  2. 視圖解析器鏈:order 控制優先級,InternalResourceViewResolver 兜底,支援 JSP/FreeMarker/Velocity 共存。
  3. CRUD 最佳實踐:PRG 模式、@ModelAttribute 綁定、服務層異常轉換、批量操作數組參數、重定向傳遞提示信息。
  4. 進階方向:RESTful API 設計、@Valid + BindingResult 驗證、異步處理、文件上傳下載、國際化、攔截器權限控制。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
解析器特點適用場景
InternalResourceViewResolverJSP/JSTL,前綴+後綴拼接 URL,最常用傳統 JSP 視圖
FreeMarkerViewResolverFreeMarker 模板,繼承 UrlBasedViewResolver現代模板引擎
VelocityViewResolverVelocity 模板老項目維護
XmlViewResolverXML 文件定義邏輯名→View Bean 映射靜態視圖映射
ContentNegotiatingViewResolver根據 Accept Header 選擇視圖(JSON/HTML/PDF)RESTful 多格式輸出