知識庫 / Spring / Spring Boot RSS 訂閱

Spring Boot 與 JavaServer Pages (JSP)

Spring Boot
HongKong
4
12:33 PM · Dec 06 ,2025

1. 概述

當構建 Web 應用程序時,JavaServer Pages (JSP) 是一種我們可以用作 HTML 頁面的模板機制的選項。

另一方面,Spring Boot 是一個流行的框架,我們可以用它來啓動我們的 Web 應用程序。

在本教程中,我們將學習如何使用 JSP 與 Spring Boot 結合來構建 Web 應用程序。

首先,我們將看到如何設置應用程序以在不同的部署場景中工作。然後,我們將研究 JSP 的一些常見用法。最後,我們將探索在打包應用程序時我們有的一些選項。

這裏做一個簡短的説明:JSP 本身以及與 Spring Boot 結合使用時都有侷限性。因此,我們應該考慮 Thymeleaf 或 FreeMarker 作為 JSP 的更好替代方案。

2. Maven 依賴

讓我們看看哪些依賴項可以支持 Spring Boot 與 JSP 的結合使用。

我們還會注意在將應用程序作為獨立應用程序運行和在 Web 容器中運行之間存在的細微差別。

2.1. 作為獨立應用程序運行

首先,請包含 spring-boot-starter-web 依賴項。

該依賴項提供了所有核心要求,用於使用 Spring Boot 運行 Web 應用程序,並附帶默認的嵌入式 Tomcat Servlet 容器:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>3.2.2</version>
</dependency>

請查閲我們的文章《Spring Boot 中嵌入式 Servlet 容器的比較》以獲取更多有關如何配置非 Tomcat 的嵌入式 Servlet 容器的信息。

請特別注意,Undertow 在作為嵌入式 Servlet 容器時不支持 JSP。

接下來,我們需要包含 tomcat-embed-jasper 依賴項,以便我們的應用程序可以編譯和渲染 JSP 頁面:

<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <version>10.1.18</version>
</dependency>

雖然上述兩個依賴項可以手動提供,但通常最好讓 Spring Boot 管理這些依賴項的版本,我們只需管理 Spring Boot 的版本。

可以通過使用 Spring Boot 父 POM,如我們在文章《Spring Boot 教程 – 構建一個簡單的應用程序》中所展示的,或者通過使用依賴管理,如我們在文章《Spring Boot 依賴管理與自定義父 POM》中所展示的,來進行版本管理。

最後,我們需要包含 JSTL 庫,該庫將提供我們 JSP 頁面所需的 JSTL 標籤支持:

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>

2.2. 在 Tomcat Web 容器中運行

我們需要在 Tomcat Web 容器中運行時,仍然需要上述依賴項。

但是,為了避免我們應用程序提供的依賴項與 Tomcat 運行時提供的依賴項衝突,我們需要使用 provided 作用域設置兩個依賴項:

<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <version>10.1.18</version>
    <scope>provided</scope>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <version>3.2.2</version>
    <scope>provided</scope>
</dependency>

需要注意的是,我們必須明確定義 spring-boot-starter-tomcat 並將其標記為 provided 範圍。這是因為該依賴項已經在 spring-boot-starter-web 中作為傳遞依賴項提供。

3. JSP 視圖解析配置

按照約定,我們將 JSP 文件放置在 ${project.basedir}/main/webapp/WEB-INF/jsp/  目錄下。

我們需要告知 Spring 如何查找這些 JSP 文件,通過在 application.properties 文件中配置兩個屬性來實現:

spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp

編譯完成後,Maven 會確保生成的 WAR 文件會將上述 jsp 目錄放置在 WEB-INF 目錄下,然後由我們的應用程序提供服務。

4. 啓動我們的應用程序

我們的主應用程序類將受到我們是否計劃作為獨立應用程序或在Web容器中運行的影響。

當作為獨立應用程序運行時,我們的應用程序類將是一個帶有@SpringBootApplication註解和main方法的簡單類:

@SpringBootApplication(scanBasePackages = "com.baeldung.boot.jsp")
public class SpringBootJspApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootJspApplication.class);
    }
}

但是,如果需要將其部署在Web容器中,則需要擴展 SpringBootServletInitializer

這會將應用程序的 ServletFilterServletContextInitializer 綁定到運行時服務器,這對於應用程序的運行是必要的。

@SpringBootApplication(scanBasePackages = "com.baeldung.boot.jsp")
public class SpringBootJspApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(SpringBootJspApplication.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(SpringBootJspApplication.class);
    }
}

5. 運行一個簡單的網頁

JSP 頁面依賴於 JavaServer Pages 標準標記庫 (JSTL) 以提供常見的模板功能,例如分支、迭代和格式化,並且它還提供了一組預定義的函數。

讓我們創建一個簡單的網頁,顯示我們應用程序中保存的書籍列表。

假設我們有一個 BookService,它可以幫助我們查找所有 Book 對象:

public class Book {
    private String isbn;
    private String name;
    private String author;

    //getters, setters, constructors and toString
}

public interface BookService {
    Collection<Book> getBooks();
    Book addBook(Book book);
}

我們可以編寫一個 Spring MVC 控制器,將其暴露為網頁:

@Controller
@RequestMapping("/book")
public class BookController {

    private final BookService bookService;

    public BookController(BookService bookService) {
        this.bookService = bookService;
    }

    @GetMapping("/viewBooks")
    public String viewBooks(Model model) {
        model.addAttribute("books", bookService.getBooks());
        return "view-books";
    }
}

請注意,BookController 將返回一個名為 view-books 的視圖模板。根據我們在 application.properties 中的先前配置,Spring MVC 將在 /WEB-INF/jsp/ 目錄下查找 view-books.jsp

我們需要在該位置創建該文件:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
    <head>
        <title>View Books</title>
        <link href="<c:url value="/css/common.css"/>" rel="stylesheet" type="text/css">
    </head>
    <body>
        <table>
            <thead>
                <tr>
                    <th>ISBN</th>
                    <th>Name</th>
                    <th>Author</th>
                </tr>
            </thead>
            <tbody>
                <c:forEach items="${books}" var="book">
                    <tr>
                        <td>${book.isbn}</td>
                        <td>${book.name}</td>
                        <td>${book.author}</td>
                    </tr>
                </c:forEach>
            </tbody>
        </table>
    </body>
</html>

上述示例展示瞭如何使用 JSTL 的 標籤來鏈接外部資源,例如 JavaScript 和 CSS。 我們通常會將這些文件放置在 目錄下。

此外,我們還可以看到 JSTL 的 標籤可以用於迭代由我們的 提供的 模型屬性。

6. 處理表單提交

現在我們來看如何使用 JSP 處理表單提交。

我們的 <em >BookController</em> 將需要提供 MVC 端點,用於向用户提供添加書籍的表單,並處理表單提交:

public class BookController {

    //already existing code

    @GetMapping("/addBook")
    public String addBookView(Model model) {
        model.addAttribute("book", new Book());
        return "add-book";
    }

    @PostMapping("/addBook")
    public RedirectView addBook(@ModelAttribute("book") Book book, RedirectAttributes redirectAttributes) {
        final RedirectView redirectView = new RedirectView("/book/addBook", true);
        Book savedBook = bookService.addBook(book);
        redirectAttributes.addFlashAttribute("savedBook", savedBook);
        redirectAttributes.addFlashAttribute("addBookSuccess", true);
        return redirectView;
    } 
}

我們將會創建以下 add-book.jsp 文件(請務必將其放置在正確的目錄下):

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Add Book</title>
    </head>
    <body>
        <c:if test="${addBookSuccess}">
            <div>Successfully added Book with ISBN: ${savedBook.isbn}</div>
        </c:if>
    
        <c:url var="add_book_url" value="/book/addBook"/>
        <form:form action="${add_book_url}" method="post" modelAttribute="book">
            <form:label path="isbn">ISBN: </form:label> <form:input type="text" path="isbn"/>
            <form:label path="name">Book Name: </form:label> <form:input type="text" path="name"/>
            <form:label path="author">Author Name: </form:label> <form:input path="author"/>
            <input type="submit" value="submit"/>
        </form:form>
    </body>
</html>

我們使用 modelAttribute 參數,該參數由 <form:form> 標籤提供,將其與 book 屬性綁定,該屬性是在 addBookView() 方法中 BookController 中添加的,從而在提交表單時填充表單。

由於使用該標籤,我們需要分別定義表單的 action URL,因為我們不能在標籤內放置標籤。我們還使用 path 屬性,該屬性位於 <form:input> 標籤中,將其與 Book 對象中的每個輸入字段綁定。

請參閲我們的文章“Spring MVC 表單入門”以獲取有關如何處理表單提交的更多詳細信息。

7. 處理錯誤

由於使用 Spring Boot 與 JSP 的現有限制,我們無法提供自定義 <em >error.html&nbsp;</em > 以自定義默認的/error  映射。` 相反,我們需要創建自定義錯誤頁面來處理不同的錯誤。

7.1. 靜態錯誤頁面

我們可以提供靜態錯誤頁面,以便為不同的 HTTP 錯誤顯示自定義錯誤頁面。

假設我們需要為應用程序拋出的所有 4xx 錯誤提供一個錯誤頁面。 我們可以簡單地將名為 4xx.html 的文件放在 ${project.basedir}/main/resources/static/error/ 目錄下。

如果我們的應用程序拋出一個 4xx HTTP 錯誤,Spring 將解析此錯誤並返回提供的 4xx.html 頁面。

7.2. 動態錯誤頁面

有多種方法可以處理異常,從而提供定製化的錯誤頁面,並附帶上下文信息。下面我們將通過使用 @ControllerAdvice@ExceptionHandler 註解,查看 Spring MVC 如何提供這項支持。

假設我們的應用程序定義了一個 DuplicateBookException

public class DuplicateBookException extends RuntimeException {
    private final Book book;

    public DuplicateBookException(Book book) {
        this.book = book;
    }

    // getter methods
}

此外,假設我們的 BookServiceImpl 類在嘗試添加兩個具有相同 ISBN 的書籍時,將會拋出上述 DuplicateBookException  異常:

@Service
public class BookServiceImpl implements BookService {

    private final BookRepository bookRepository;

    // constructors, other override methods

    @Override
    public Book addBook(Book book) {
        final Optional<BookData> existingBook = bookRepository.findById(book.getIsbn());
        if (existingBook.isPresent()) {
            throw new DuplicateBookException(book);
        }

        final BookData savedBook = bookRepository.add(convertBook(book));
        return convertBookData(savedBook);
    }

    // conversion logic
}

我們的 LibraryControllerAdvice 類將定義我們想要處理的錯誤,以及我們如何處理每個錯誤:

@ControllerAdvice
public class LibraryControllerAdvice {

    @ExceptionHandler(value = DuplicateBookException.class)
    public ModelAndView duplicateBookException(DuplicateBookException e) {
        final ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("ref", e.getBook().getIsbn());
        modelAndView.addObject("object", e.getBook());
        modelAndView.addObject("message", "Cannot add an already existing book");
        modelAndView.setViewName("error-book");
        return modelAndView;
    }
}

我們需要定義 error-book.jsp 文件,以便解決上述錯誤。請務必將其放置在 ${project.basedir}/main/webapp/WEB-INF/jsp/ 目錄下,因為這不再是靜態 HTML,而是一個 JSP 模板,需要進行編譯。

8. 創建可執行文件

如果我們的應用程序計劃部署在 Web 容器(如 Tomcat)中,選擇就顯而易見,我們將使用 <em >war</em> 包裝來達成此目的。

然而,我們應該意識到,如果使用 JSP 和 Spring Boot 帶有嵌入式 Servlet 容器,我們不能使用 <em >jar</em> 包裝。因此,作為獨立應用程序運行時,我們的唯一選擇是 <em >war</em> 包裝。

我們的 <em >pom.xml</em> 在兩種情況下都需要將 packaging 指令設置為 <em >war</em>

<packaging>war</packaging>

如果我們在管理依賴項時沒有使用 Spring Boot 父POM,則我們需要包含 spring-boot-maven-plugin,以確保生成的 war 文件能夠作為獨立應用程序運行。

現在,我們可以使用嵌入式 Servlet 容器運行我們的獨立應用程序,或者直接將生成的 war 文件放入 Tomcat 中,讓其託管我們的應用程序。

9. 結論

我們已經探討了本教程中的各種主題。以下是關鍵考慮事項的總結:

  • JSP 存在一些固有的侷限性。 考慮使用 Thymeleaf 或 FreeMarker 代替。
  • 在 Web 容器上部署時,請務必標記必要的依賴項為 provided
  • 如果 Undertow 用作嵌入式 Servlet 容器,則不支持 JSP。
  • 如果部署在 Web 容器中,我們的 @SpringBootApplication 註解類應擴展 SpringBootServletInitializer 並提供必要的配置選項。
  • 我們無法使用 JSP 覆蓋默認的 /error 頁面。 相反,我們需要提供自定義錯誤頁面。
  • 如果使用 JSP 與 Spring Boot 結合,則 JAR 包裝不是一個選項。
user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.