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开发者的大模型入门:Spring AI Alibaba组件全攻略(二)
前端·后端
Java水解1 小时前
一文搞懂 Spring Boot 默认数据库连接池 HikariCP
spring boot·后端
重庆穿山甲2 小时前
Java开发者的大模型入门:Spring AI Alibaba组件全攻略(一)
前端·后端
Java编程爱好者2 小时前
小米二面:std::map和std::unordered_map谁更快?别只知道哈希表
后端
重庆穿山甲3 小时前
Java开发者的大模型入门:Spring AI组件全攻略(二)
前端·后端
重庆穿山甲3 小时前
Java开发者的大模型入门:Spring AI组件全攻略(一)
前端·后端
布列瑟农的星空3 小时前
前端都能看懂的rust入门教程(二)——函数和闭包
前端·后端·rust
颜酱4 小时前
二叉树分解问题思路解题模式
javascript·后端·算法
zone77394 小时前
001:LangChain的LCEL语法学习
人工智能·后端·面试