返回介绍

5.3 数据绑定范例

发布于 2025-04-22 20:09:59 字数 13609 浏览 0 评论 0 收藏

在表单标签库中利用标签进行数据绑定的例子,参见 tags-demo 应用程序。这个范例围绕 domain 类 Book 进行。这个类中有几个属性,包括一个类型为 Category 的 category 属性。Category 有 id 和 name 两个属性。

这个应用程序允许列出书目、添加新书,以及编辑书目。

5.3.1 目录结构

图 5.1 中展示了 tags-demo 的目录结构。

图片 1

图 5.1 tags-demo 的目录结构

5.3.2 Domain 类

Book 类和 Category 类是这个应用程序中的 domain 类,它们分别如清单 5.1 和清单 5.2 所示。

清单 5.1 Book 类

package domain;
import java.math.BigDecimal;
import java.io.Serializable;

public class Book implements Serializable {

  private static final long serialVersionUID = 1L;
  private long id;
  private String isbn;
  private String title;
  private Category category;
  private String author;

  public Book() {
  }

  public Book(long id, String isbn, String title,
      Category category, String author, BigDecimal price) {
    this.id = id;
    this.isbn = isbn;
    this.title = title;
    this.category = category;
    this.author = author;
    this.price = price;
  }

  // get and set methods not shown

}

清单 5.2 Category 类

package domain;

import java.io.Serializable;

public class Category implements Serializable {
  private static final long serialVersionUID = 1L;
  private int id;
  private String name;

  public Category() {
  }

  public Category(int id, String name) {
    this.id = id;
    this.name = name;
  }

  // get and set methods not shown
}

5.3.3 Controller 类

下面的范例为 Book 提供了一个控制器:BookController 类。它允许用户创建新书目、更新书的详细信息,并在系统中列出所有书目。清单 5.3 中展示了 BookController 类。

清单 5.3 BookController 类

package controller;
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.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import domain.Book;
import domain.Category;
import service.BookService;

@Controller
public class BookController {

  @Autowired
  private BookService bookService;

  private static final Log logger =
      LogFactory.getLog(BookController.class);

  @RequestMapping(value = "/input-book ")
  public String inputBook(Model model) {
    List<Category> categories = bookService.getAllCategories();
    model.addAttribute("categories", categories);
    model.addAttribute("book", new Book());
    return "BookAddForm";
  }
  @RequestMapping(value = "/edit-book/{id}")
  public String editBook(Model model, @PathVariable long id) {
    List<Category> categories = bookService.getAllCategories();
    model.addAttribute("categories", categories);
    Book book = bookService.get(id);
    model.addAttribute("book", book);
    return "BookEditForm";
  }
  @RequestMapping(value = "/save-book")
  public String saveBook(@ModelAttribute Book book) {
    Category category =
        bookService.getCategory(book.getCategory().getId());
    book.setCategory(category);
    bookService.save(book);
    return "redirect:/list-book";
  }

  @RequestMapping(value = "/update-book")
  public String updateBook(@ModelAttribute Book book) {
    Category category =
         bookService.getCategory(book.getCategory().getId());
    book.setCategory(category);
    bookService.update(book);
    return "redirect:/list-book";
  }

  @RequestMapping(value = "/list-book")
  public String listBooks(Model model) {
    logger.info("listBooks");
    List<Book> books = bookService.getAllBooks();
    model.addAttribute("books", books);
    return "BookList";
  }
}

BookController 依赖 BookService 进行一些后台处理。@Autowired 注解用于给 Book Controller 注入一个 BookService 实现。

@Autowired
private BookService bookService;

5.3.4 Service 类

清单 5.4 和清单 5.5 分别展示了 BookService 接口和 BookServiceImpl 类。顾名思义,BookServiceImpl 就是实现 BookService。

清单 5.4 BookService 接口

package service;
import java.util.List;
import domain.Book;
import domain.Category;

public interface BookService {
  List<Category> getAllCategories();
  Category getCategory(int id);
  List<Book> getAllBooks();
  Book save(Book book);
  Book update(Book book);
  Book get(long id);
  long getNextId();
}

清单 5.5 BookServiceImpl 类

package service;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Service;
import domain.Book;
import domain.Category;

@Service
public class BookServiceImpl implements BookService {

  /*
   * this implementation is not thread-safe
   */
  private List<Category> categories;
  private List<Book> books;

  public BookServiceImpl() {
    categories = new ArrayList<Category>();
    Category category1 = new Category(1, "Computer");
    Category category2 = new Category(2, "Travel");
    Category category3 = new Category(3, "Health");
    categories.add(category1);
    categories.add(category2);
    categories.add(category3);

    books = new ArrayList<Book>();
    books.add(new Book(1L, "9781771970273",
        "Servlet & JSP: A Tutorial (2nd Edition)",
        category1, "Budi Kurniawan", new BigDecimal("54.99"));
    books.add(new Book(2L, "9781771970297",
        "C#: A Beginner's Tutorial (2nd Edition) ",
        category1, "Jayden Ky", new BigDecimal("39.99")));
  }

  @Override
  public List<Category> getAllCategories() {
    return categories;
  }

  @Override
  public Category getCategory(int id) {
    for (Category category : categories) {
      if (id == category.getId()) {
        return category;
      }
    }
    return null;
  }

  @Override
  public List<Book> getAllBooks() {
    return books;
  }

  @Override
  public Book save(Book book) {
    book.setId(getNextId());
    books.add(book);
    return book;
  }

  @Override
  public Book get(long id) {
    for (Book book : books) {
      if (id == book.getId()) {
        return book;
      }
    }
    return null;
  }

  @Override
  public Book update(Book book) {
    int bookCount = books.size();
    for (int i = 0; i < bookCount; i++) {
      Book savedBook = books.get(i);
      if (savedBook.getId() == book.getId()) {
        books.set(i, book);
        return book;
      }
    }
    return book;
  }

  @Override
  public long getNextId() {
    // needs to be locked
    long id = 0L;
    for (Book book : books) {
      long bookId = book.getId();
      if (bookId > id) {
        id = bookId;
      }
    }
    return id + 1;
  }
}

BookServiceImpl 类中包含了一个 Book 对象的 List 和一个 Category 对象的 List。这两个 List 都是在实例化类时生成的。这个类中还包含了获取所有书目、获取单个书目,以及添加和更新书目的方法。

5.3.5 配置文件

清单 5.6 展示了 tags-demo 中的 Spring MVC 配置文件。

清单 5.6 Spring MVC 配置文件

< ?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:p="http://www.springframework.org/schema/p"
  xmlns:mvc="http://www.springframework.org/schema/mvc"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.
    xsd">

  < context:component-scan base-package="controller"/>
  < context:component-scan base-package="service"/>

  ... < !-- other elements are not shown -->

< /beans>

component-scan bean 使得 app05a.controller 包和 app05a.service 包得以被扫描。

5.3.6 视图

tags-demo 中使用的 3 个 JSP 页面如清单 5.7、清单 5.8 和清单 5.9 所示。BookAddForm.jsp 和 BookEditForm.jsp 页面中使用的是来自表单标签库的标签。

清单 5.7 BookList.jsp 页面

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML>
<html>
<head>
<title>Book List</title>
<style type="text/css">@import url("<c:url value="/css/main.css"/>");
</style>
</head>
<body>

<div id="global">
<h1>Book List</h1>
<a href="<c:url value="/book_input"/>">Add Book</a>
<table>
<tr>
  <th>Category</th>
  <th>Title</th>
  <th>ISBN</th>
  <th>Author</th>
  <th>Price</th>
  <th>&nbsp;</th>
</tr>
<c:forEach items="${books}" var="book">
  <tr>
    <td>${book.category.name}</td>
    <td>${book.title}</td>
    <td>${book.isbn}</td>
    <td>${book.author}</td>
    <td>${book.price}</td>
    <td><a href="book_edit/${book.id}">Edit</a></td>
  </tr>
</c:forEach>
</table>
</div>
</body>
</html>

清单 5.8 BookAddForm.jsp 页面

<%@ taglib prefix="form"
    uri="http://www.springframework.org/tags/form" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML>
<html>
<head>
<title>Add Book Form</title>
<style type="text/css">@import url("<c:url
    value="/css/main.css"/>");</style>
</head>
<body>
<div id="global">

<form:form commandName="book" action="save-book" method="post">
  <fieldset>
    <legend>Add a book</legend>
    <p>
      <label for="category">Category: </label>
       <form:select id="category" path="category.id"
        items="${categories}" itemLabel="name"
        itemValue="id"/>
    </p>
    <p>
      <label for="title">Title: </label>
      <form:input id="title" path="title"/>
    </p>
    <p>
      <label for="author">Author: </label>
      <form:input id="author" path="author"/>
    </p>
    <p>
      <label for="isbn">ISBN: </label>
      <form:input id="isbn" path="isbn"/>
    </p>

    <p id="buttons">
      <input id="reset" type="reset">
      <input id="submit" type="submit"
        value="Add Book">
    </p>
  </fieldset>
</form:form>
</div>
</body>
</html>

清单 5.9 BookEditForm.jsp 页面

< %@ taglib prefix="form"
    uri="http://www.springframework.org/tags/form" %>
< %@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
< !DOCTYPE HTML>
< html>
< head>
< title>Edit Book Form< /title>
< style type="text/css">@import url("< c:url
    value="/css/main.css"/>");< /style>
< /head>
< body>

< div id="global">
< c:url var=”formAction” value=”/update-book” /> < form:form commandName="book" action="${formAction}" method="post"> < fieldset> < legend>Edit a book< /legend> < form:hidden path="id"/> < p> < label for="category">Category: < /label> < form:select id="category" path="category.id" items="$ {categories}" itemLabel="name" itemValue="id"/> < /p> < p> < label for="title">Title: < /label> < form:input id="title" path="title"/> < /p> < p> < label for="author">Author: < /label> < form:input id="author" path="author"/> < /p> < p> < label for="isbn">ISBN: < /label> < form:input id="isbn" path="isbn"/> < /p> < p id="buttons"> < input id="reset" type="reset"> < input id="submit" type="submit" value="Update Book"> < /p> < /fieldset> < /form:form> < /div> < /body> < /html>

注意,在 BookEditForm.jsp 页面中,表单的 action 属性为<c:url />的值:

<c:url var="formAction" value ="/update-book"/>
<form:form commandName="book" action="${formAction}" method="post">

这是因为表单需要定位/update-book 映射,并且给 action 属性一个静态值“update-book”是有问题的。如果图书 ID 作为请求参数发送到编辑图书页面,则页面 URL 将如下所示:

http://domain/context/edit-book?id=1

该表单将正确提交到 http://domain/context/update-book。

但是,如果图书 ID 作为路径变量发送,页面网址将如下所示:

http://domain/context/edit-book/id

并且表单将被提交到:

http://domain/context/edit-book/update-book

因此,您应该使用<c:url/>来确保表单目标始终正确,无论网页网址如何。遗憾的是,表单的 action 属性不能取<c:url/>。因此,您需要创建一个变量 formAction 并从 action 属性引用它。

5.3.7 测试应用

要想测试这个应用程序范例,请打开以下网页:

http://localhost:8080/tags-demo/list-books

图 5.2 展示了第一次启动这个应用程序时显示的书目列表。

单击“Add Book”链接添加书目,或者单击书籍详情右侧的“Edit”链接来编辑书目。

图 5.3 展示了“Add a book”表单。图 5.4 中展示了“Edit a book”表单。

图片 2

图 5.2 书目列表

图片 3

图 5.3 Add a book 表单

图片 4

图 5.4 Edit a book 表单

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。