Spring Boot 视图层与模板引擎

19.1 学习目标与重点提示

学习目标:掌握Spring Boot视图层与模板引擎的核心概念与使用方法,包括Spring Boot视图层的基本方法、Spring Boot与Thymeleaf的集成、Spring Boot与Freemarker的集成、Spring Boot与Velocity的集成、Spring Boot的静态资源管理、Spring Boot的实际应用场景,学会在实际开发中处理视图层问题。

重点:Spring Boot视图层的基本方法Spring Boot与Thymeleaf的集成Spring Boot与Freemarker的集成Spring Boot与Velocity的集成Spring Boot的静态资源管理Spring Boot的实际应用场景

19.2 Spring Boot视图层概述

Spring Boot视图层是指使用Spring Boot进行Web应用开发的方法。

19.2.1 视图层的定义

定义 :视图层是指使用Spring Boot进行Web应用开发的方法。
作用

  • 实现Web页面的渲染。
  • 实现数据的展示。
  • 实现用户交互。

✅ 结论:视图层是指使用Spring Boot进行Web应用开发的方法,作用是实现Web页面的渲染、数据的展示、用户交互。

19.2.2 视图层的常用组件

定义 :视图层的常用组件是指Spring Boot提供的视图层组件。
组件

  • Thymeleaf:用于Thymeleaf模板。
  • Freemarker:用于Freemarker模板。
  • Velocity:用于Velocity模板。

✅ 结论:视图层的常用组件包括Thymeleaf、Freemarker、Velocity。

19.3 Spring Boot与Thymeleaf的集成

Spring Boot与Thymeleaf的集成是最常用的视图层方法之一。

19.3.1 集成Thymeleaf的步骤

定义 :集成Thymeleaf的步骤是指使用Spring Boot与Thymeleaf集成的方法。
步骤

  1. 在pom.xml文件中添加Thymeleaf依赖。
  2. 在application.properties或application.yml文件中配置Thymeleaf。
  3. 创建实体类。
  4. 创建Repository接口。
  5. 创建控制器类。
  6. 创建Thymeleaf模板文件。
  7. 测试应用。

示例

pom.xml文件中的Thymeleaf依赖:

xml 复制代码
<dependencies>
    <!-- Web依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- Thymeleaf依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    
    <!-- Data JPA依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    
    <!-- H2数据库依赖 -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
    
    <!-- 测试依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

AI写代码xml
123456789101112131415161718192021222324252627282930313233

application.properties文件中的Thymeleaf配置:

ini 复制代码
# 服务器端口
server.port=8080

# 数据库连接信息
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password

# JPA配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

# H2数据库控制台
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console

# Thymeleaf配置
spring.thymeleaf.cache=false
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html

AI写代码properties
123456789101112131415161718192021

实体类:

typescript 复制代码
import javax.persistence.*;

@Entity
@Table(name = "product")
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String productId;
    private String productName;
    private double price;
    private int sales;
    
    public Product() {
    }
    
    public Product(String productId, String productName, double price, int sales) {
        this.productId = productId;
        this.productName = productName;
        this.price = price;
        this.sales = sales;
    }
    
    // Getter和Setter方法
    public Long getId() {
        return id;
    }
    
    public void setId(Long id) {
        this.id = id;
    }
    
    public String getProductId() {
        return productId;
    }
    
    public void setProductId(String productId) {
        this.productId = productId;
    }
    
    public String getProductName() {
        return productName;
    }
    
    public void setProductName(String productName) {
        this.productName = productName;
    }
    
    public double getPrice() {
        return price;
    }
    
    public void setPrice(double price) {
        this.price = price;
    }
    
    public int getSales() {
        return sales;
    }
    
    public void setSales(int sales) {
        this.sales = sales;
    }
    
    @Override
    public String toString() {
        return "Product{" +
                "id=" + id +
                ", productId='" + productId + ''' +
                ", productName='" + productName + ''' +
                ", price=" + price +
                ", sales=" + sales +
                '}';
    }
}

AI写代码java
运行
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475

Repository接口:

java 复制代码
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
    List<Product> findBySalesGreaterThan(int sales);
}

AI写代码java
运行
123456789

控制器类:

kotlin 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@Controller
@RequestMapping("/products")
public class ProductController {
    @Autowired
    private ProductRepository productRepository;
    
    @GetMapping("/")
    public String getAllProducts(Model model) {
        List<Product> products = productRepository.findAll();
        model.addAttribute("products", products);
        return "products";
    }
    
    @PostMapping("/")
    public String addProduct(@ModelAttribute Product product) {
        productRepository.save(product);
        return "redirect:/products/";
    }
    
    @GetMapping("/top-selling")
    public String getTopSellingProducts(@RequestParam int topN, Model model) {
        List<Product> products = productRepository.findBySalesGreaterThan(0);
        products.sort((p1, p2) -> p2.getSales() - p1.getSales());
        if (products.size() > topN) {
            products = products.subList(0, topN);
        }
        model.addAttribute("products", products);
        return "products";
    }
}

AI写代码java
运行
12345678910111213141516171819202122232425262728293031323334353637

Thymeleaf模板文件(src/main/resources/templates/products.html):

xml 复制代码
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>产品列表</title>
    <style>
        table {
            border-collapse: collapse;
            width: 100%;
        }
        th, td {
            border: 1px solid #ddd;
            padding: 8px;
            text-align: left;
        }
        th {
            background-color: #f2f2f2;
        }
        .add-product {
            margin-bottom: 20px;
        }
    </style>
</head>
<body>
    <h1>产品列表</h1>
    
    <div class="add-product">
        <form th:action="@{/products/}" method="post" th:object="${product}">
            <label>产品ID:</label>
            <input type="text" th:field="*{productId}" required>
            <br>
            <label>产品名称:</label>
            <input type="text" th:field="*{productName}" required>
            <br>
            <label>价格:</label>
            <input type="number" th:field="*{price}" step="0.01" required>
            <br>
            <label>销量:</label>
            <input type="number" th:field="*{sales}" required>
            <br>
            <button type="submit">添加产品</button>
        </form>
    </div>
    
    <div>
        <form th:action="@{/products/top-selling}" method="get">
            <label>销量TOP:</label>
            <input type="number" name="topN" value="3" min="1" required>
            <button type="submit">查询</button>
        </form>
    </div>
    
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>产品ID</th>
                <th>产品名称</th>
                <th>价格</th>
                <th>销量</th>
            </tr>
        </thead>
        <tbody>
            <tr th:each="product : ${products}">
                <td th:text="${product.id}"></td>
                <td th:text="${product.productId}"></td>
                <td th:text="${product.productName}"></td>
                <td th:text="${#numbers.formatDecimal(product.price, 0, 'COMMA', 2, 'POINT')}"></td>
                <td th:text="${product.sales}"></td>
            </tr>
        </tbody>
    </table>
</body>
</html>

AI写代码html
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374

测试类:

typescript 复制代码
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;

import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ProductApplicationTests {
    @LocalServerPort
    private int port;
    
    @Autowired
    private TestRestTemplate restTemplate;
    
    @Test
    void contextLoads() {
    }
    
    @Test
    void testHomePage() {
        String response = restTemplate.getForObject("http://localhost:" + port + "/products/", String.class);
        assertThat(response).contains("产品列表");
    }
}

AI写代码java
运行
1234567891011121314151617181920212223242526

✅ 结论:集成Thymeleaf的步骤包括添加Thymeleaf依赖、配置Thymeleaf、创建实体类、创建Repository接口、创建控制器类、创建Thymeleaf模板文件、测试应用。

19.4 Spring Boot与Freemarker的集成

Spring Boot与Freemarker的集成是常用的视图层方法之一。

19.4.1 集成Freemarker的步骤

定义 :集成Freemarker的步骤是指使用Spring Boot与Freemarker集成的方法。
步骤

  1. 在pom.xml文件中添加Freemarker依赖。
  2. 在application.properties或application.yml文件中配置Freemarker。
  3. 创建实体类。
  4. 创建Repository接口。
  5. 创建控制器类。
  6. 创建Freemarker模板文件。
  7. 测试应用。

示例

pom.xml文件中的Freemarker依赖:

xml 复制代码
<dependencies>
    <!-- Web依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- Freemarker依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-freemarker</artifactId>
    </dependency>
    
    <!-- Data JPA依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    
    <!-- H2数据库依赖 -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
    
    <!-- 测试依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

AI写代码xml
123456789101112131415161718192021222324252627282930313233

application.properties文件中的Freemarker配置:

ini 复制代码
# 服务器端口
server.port=8080

# 数据库连接信息
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password

# JPA配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

# H2数据库控制台
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console

# Freemarker配置
spring.freemarker.cache=false
spring.freemarker.prefix=classpath:/templates/
spring.freemarker.suffix=.ftl

AI写代码properties
123456789101112131415161718192021

实体类、Repository接口、控制器类与集成Thymeleaf的示例相同。

Freemarker模板文件(src/main/resources/templates/products.ftl):

xml 复制代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>产品列表</title>
    <style>
        table {
            border-collapse: collapse;
            width: 100%;
        }
        th, td {
            border: 1px solid #ddd;
            padding: 8px;
            text-align: left;
        }
        th {
            background-color: #f2f2f2;
        }
        .add-product {
            margin-bottom: 20px;
        }
    </style>
</head>
<body>
    <h1>产品列表</h1>
    
    <div class="add-product">
        <form action="/products/" method="post">
            <label>产品ID:</label>
            <input type="text" name="productId" required>
            <br>
            <label>产品名称:</label>
            <input type="text" name="productName" required>
            <br>
            <label>价格:</label>
            <input type="number" name="price" step="0.01" required>
            <br>
            <label>销量:</label>
            <input type="number" name="sales" required>
            <br>
            <button type="submit">添加产品</button>
        </form>
    </div>
    
    <div>
        <form action="/products/top-selling" method="get">
            <label>销量TOP:</label>
            <input type="number" name="topN" value="3" min="1" required>
            <button type="submit">查询</button>
        </form>
    </div>
    
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>产品ID</th>
                <th>产品名称</th>
                <th>价格</th>
                <th>销量</th>
            </tr>
        </thead>
        <tbody>
            <#list products as product>
                <tr>
                    <td>${product.id}</td>
                    <td>${product.productId}</td>
                    <td>${product.productName}</td>
                    <td>${product.price?string(",###.00")}</td>
                    <td>${product.sales}</td>
                </tr>
            </#list>
        </tbody>
    </table>
</body>
</html>

AI写代码ftl
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576

测试类:

typescript 复制代码
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;

import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ProductApplicationTests {
    @LocalServerPort
    private int port;
    
    @Autowired
    private TestRestTemplate restTemplate;
    
    @Test
    void contextLoads() {
    }
    
    @Test
    void testHomePage() {
        String response = restTemplate.getForObject("http://localhost:" + port + "/products/", String.class);
        assertThat(response).contains("产品列表");
    }
}

AI写代码java
运行
1234567891011121314151617181920212223242526

✅ 结论:集成Freemarker的步骤包括添加Freemarker依赖、配置Freemarker、创建实体类、创建Repository接口、创建控制器类、创建Freemarker模板文件、测试应用。

19.5 Spring Boot与Velocity的集成

Spring Boot与Velocity的集成是常用的视图层方法之一。

19.5.1 集成Velocity的步骤

定义 :集成Velocity的步骤是指使用Spring Boot与Velocity集成的方法。
步骤

  1. 在pom.xml文件中添加Velocity依赖。
  2. 在application.properties或application.yml文件中配置Velocity。
  3. 创建实体类。
  4. 创建Repository接口。
  5. 创建控制器类。
  6. 创建Velocity模板文件。
  7. 测试应用。

示例

pom.xml文件中的Velocity依赖:

xml 复制代码
<dependencies>
    <!-- Web依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- Velocity依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-velocity</artifactId>
        <version>1.5.22.RELEASE</version>
    </dependency>
    
    <!-- Data JPA依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    
    <!-- H2数据库依赖 -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
    
    <!-- 测试依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

AI写代码xml
12345678910111213141516171819202122232425262728293031323334

application.properties文件中的Velocity配置:

ini 复制代码
# 服务器端口
server.port=8080

# 数据库连接信息
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password

# JPA配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

# H2数据库控制台
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console

# Velocity配置
spring.velocity.cache=false
spring.velocity.prefix=classpath:/templates/
spring.velocity.suffix=.vm

AI写代码properties
123456789101112131415161718192021

实体类、Repository接口、控制器类与集成Thymeleaf的示例相同。

Velocity模板文件(src/main/resources/templates/products.vm):

xml 复制代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>产品列表</title>
    <style>
        table {
            border-collapse: collapse;
            width: 100%;
        }
        th, td {
            border: 1px solid #ddd;
            padding: 8px;
            text-align: left;
        }
        th {
            background-color: #f2f2f2;
        }
        .add-product {
            margin-bottom: 20px;
        }
    </style>
</head>
<body>
    <h1>产品列表</h1>
    
    <div class="add-product">
        <form action="/products/" method="post">
            <label>产品ID:</label>
            <input type="text" name="productId" required>
            <br>
            <label>产品名称:</label>
            <input type="text" name="productName" required>
            <br>
            <label>价格:</label>
            <input type="number" name="price" step="0.01" required>
            <br>
            <label>销量:</label>
            <input type="number" name="sales" required>
            <br>
            <button type="submit">添加产品</button>
        </form>
    </div>
    
    <div>
        <form action="/products/top-selling" method="get">
            <label>销量TOP:</label>
            <input type="number" name="topN" value="3" min="1" required>
            <button type="submit">查询</button>
        </form>
    </div>
    
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>产品ID</th>
                <th>产品名称</th>
                <th>价格</th>
                <th>销量</th>
            </tr>
        </thead>
        <tbody>
            #foreach ($product in $products)
                <tr>
                    <td>$product.id</td>
                    <td>$product.productId</td>
                    <td>$product.productName</td>
                    <td>$product.price.format("###,###.00")</td>
                    <td>$product.sales</td>
                </tr>
            #end
        </tbody>
    </table>
</body>
</html>

AI写代码vm
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576

测试类:

typescript 复制代码
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;

import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ProductApplicationTests {
    @LocalServerPort
    private int port;
    
    @Autowired
    private TestRestTemplate restTemplate;
    
    @Test
    void contextLoads() {
    }
    
    @Test
    void testHomePage() {
        String response = restTemplate.getForObject("http://localhost:" + port + "/products/", String.class);
        assertThat(response).contains("产品列表");
    }
}

AI写代码java
运行
1234567891011121314151617181920212223242526

✅ 结论:集成Velocity的步骤包括添加Velocity依赖、配置Velocity、创建实体类、创建Repository接口、创建控制器类、创建Velocity模板文件、测试应用。

19.6 Spring Boot的静态资源管理

Spring Boot的静态资源管理是视图层的重要组件。

19.6.1 静态资源管理的定义

定义 :静态资源管理是指使用Spring Boot管理静态资源的方法。
作用

  • 管理Web应用的静态资源,如CSS、JavaScript、图片等。
  • 提高开发效率。
  • 提供统一的编程模型。

常用静态资源目录

  • src/main/resources/static:用于存放静态资源。
  • src/main/resources/public:用于存放静态资源。
  • src/main/resources/resources:用于存放静态资源。
  • src/main/resources/templates:用于存放模板文件。

示例

创建静态资源文件(src/main/resources/static/css/style.css):

css 复制代码
body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 0;
}

h1 {
    color: #333;
    margin: 20px 0;
}

table {
    border-collapse: collapse;
    width: 100%;
}

th, td {
    border: 1px solid #ddd;
    padding: 8px;
    text-align: left;
}

th {
    background-color: #f2f2f2;
}

.add-product {
    margin-bottom: 20px;
}

AI写代码css
1234567891011121314151617181920212223242526272829

在Thymeleaf模板文件中引用静态资源:

xml 复制代码
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>产品列表</title>
    <link rel="stylesheet" th:href="@{/css/style.css}">
</head>
<body>
    <h1>产品列表</h1>
    
    <div class="add-product">
        <form th:action="@{/products/}" method="post" th:object="${product}">
            <label>产品ID:</label>
            <input type="text" th:field="*{productId}" required>
            <br>
            <label>产品名称:</label>
            <input type="text" th:field="*{productName}" required>
            <br>
            <label>价格:</label>
            <input type="number" th:field="*{price}" step="0.01" required>
            <br>
            <label>销量:</label>
            <input type="number" th:field="*{sales}" required>
            <br>
            <button type="submit">添加产品</button>
        </form>
    </div>
    
    <div>
        <form th:action="@{/products/top-selling}" method="get">
            <label>销量TOP:</label>
            <input type="number" name="topN" value="3" min="1" required>
            <button type="submit">查询</button>
        </form>
    </div>
    
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>产品ID</th>
                <th>产品名称</th>
                <th>价格</th>
                <th>销量</th>
            </tr>
        </thead>
        <tbody>
            <tr th:each="product : ${products}">
                <td th:text="${product.id}"></td>
                <td th:text="${product.productId}"></td>
                <td th:text="${product.productName}"></td>
                <td th:text="${#numbers.formatDecimal(product.price, 0, 'COMMA', 2, 'POINT')}"></td>
                <td th:text="${product.sales}"></td>
            </tr>
        </tbody>
    </table>
</body>
</html>

AI写代码html
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758

✅ 结论:静态资源管理是指使用Spring Boot管理静态资源的方法,常用静态资源目录包括src/main/resources/static、src/main/resources/public、src/main/resources/resources、src/main/resources/templates。

19.7 Spring Boot的实际应用场景

在实际开发中,Spring Boot视图层与模板引擎的应用场景非常广泛,如:

  • 实现商品的展示与购买。
  • 实现订单的管理。
  • 实现用户的管理。
  • 实现博客的发布与管理。

示例

arduino 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.persistence.*;
import java.util.List;

// 产品类
@Entity
@Table(name = "product")
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String productId;
    private String productName;
    private double price;
    private int sales;
    
    public Product() {
    }
    
    public Product(String productId, String productName, double price, int sales) {
        this.productId = productId;
        this.productName = productName;
        this.price = price;
        this.sales = sales;
    }
    
    // Getter和Setter方法
    public Long getId() {
        return id;
    }
    
    public void setId(Long id) {
        this.id = id;
    }
    
    public String getProductId() {
        return productId;
    }
    
    public void setProductId(String productId) {
        this.productId = productId;
    }
    
    public String getProductName() {
        return productName;
    }
    
    public void setProductName(String productName) {
        this.productName = productName;
    }
    
    public double getPrice() {
        return price;
    }
    
    public void setPrice(double price) {
        this.price = price;
    }
    
    public int getSales() {
        return sales;
    }
    
    public void setSales(int sales) {
        this.sales = sales;
    }
    
    @Override
    public String toString() {
        return "Product{" +
                "id=" + id +
                ", productId='" + productId + ''' +
                ", productName='" + productName + ''' +
                ", price=" + price +
                ", sales=" + sales +
                '}';
    }
}

// 产品Repository
@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
    List<Product> findBySalesGreaterThan(int sales);
}

// 产品控制器
@Controller
@RequestMapping("/products")
public class ProductController {
    @Autowired
    private ProductRepository productRepository;
    
    @GetMapping("/")
    public String getAllProducts(Model model) {
        List<Product> products = productRepository.findAll();
        model.addAttribute("products", products);
        model.addAttribute("product", new Product());
        return "products";
    }
    
    @PostMapping("/")
    public String addProduct(@ModelAttribute Product product) {
        productRepository.save(product);
        return "redirect:/products/";
    }
    
    @GetMapping("/top-selling")
    public String getTopSellingProducts(@RequestParam int topN, Model model) {
        List<Product> products = productRepository.findBySalesGreaterThan(0);
        products.sort((p1, p2) -> p2.getSales() - p1.getSales());
        if (products.size() > topN) {
            products = products.subList(0, topN);
        }
        model.addAttribute("products", products);
        model.addAttribute("product", new Product());
        return "products";
    }
}

// 应用启动类
@SpringBootApplication
public class ProductApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProductApplication.class, args);
    }
    
    @Autowired
    private ProductRepository productRepository;
    
    public void run(String... args) {
        // 初始化数据
        productRepository.save(new Product("P001", "手机", 1000.0, 100));
        productRepository.save(new Product("P002", "电脑", 5000.0, 50));
        productRepository.save(new Product("P003", "电视", 3000.0, 80));
        productRepository.save(new Product("P004", "手表", 500.0, 200));
        productRepository.save(new Product("P005", "耳机", 300.0, 150));
    }
}

// 测试类
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ProductApplicationTests {
    @LocalServerPort
    private int port;
    
    @Autowired
    private TestRestTemplate restTemplate;
    
    @Test
    void contextLoads() {
    }
    
    @Test
    void testHomePage() {
        String response = restTemplate.getForObject("http://localhost:" + port + "/products/", String.class);
        assertThat(response).contains("产品列表");
    }
}

AI写代码java
运行
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166

✅ 结论:在实际开发中,Spring Boot视图层与模板引擎的应用场景非常广泛,需要根据实际问题选择合适的模板引擎。

总结

本章我们学习了Spring Boot视图层与模板引擎,包括Spring Boot视图层的基本方法、Spring Boot与Thymeleaf的集成、Spring Boot与Freemarker的集成、Spring Boot与Velocity的集成、Spring Boot的静态资源管理、Spring Boot的实际应用场景,学会了在实际开发中处理视图层问题。其中,Spring Boot视图层的基本方法、Spring Boot与Thymeleaf的集成、Spring Boot与Freemarker的集成、Spring Boot与Velocity的集成、Spring Boot的静态资源管理、Spring Boot的实际应用场景是本章的重点内容。从下一章开始,我们将学习Spring Boot的其他组件、微服务等内容。

相关推荐
飘尘1 小时前
前端转型全栈(Java后端)的快速上手指引
前端·后端·全栈
浏览器工程师2 小时前
AI Agent 接浏览器任务,先别让它一路点到底
前端·后端
行者全栈架构师2 小时前
Maven dependency:tree 的 8 个高级用法
java·后端
Chenyiax2 小时前
从一次请求看懂 OkHttp:架构、调度与连接管理
后端
爱勇宝3 小时前
深扒 Anthropic 1680 位工程师简历:应届生几乎没机会,AI 公司最缺的不是博士
前端·后端·程序员
AskHarries3 小时前
工具失败时怎么办:重试、回滚、人工确认和风险提示
后端·程序员
苏三说技术5 小时前
Claude Code从失控到起飞,只用了这些技巧
后端
长栎6 小时前
写 for 循环写了十年,你却从没用过迭代器模式最狠的那一面
后端
LiaCode6 小时前
Redis 在生产项目的使用
前端·后端
用户559822481226 小时前
Docker Compose Down 导致容器数据误删——ext4 日志恢复全记录
后端