SpringMVC 笔记

SpringMVC笔记

Ant风格访问

Spring MVC 支持 Ant 风格(Ant-style path matching)主要体现在 URL 路径匹配模式上。这种模式是 Spring Web 框架用来进行 URL 模式匹配的一种方式,借用了 Apache Ant(一个流行的 Java 构建工具)中的路径匹配规则。Ant 风格的路径匹配使得 URL 路径映射更加灵活和方便。

  • * 匹配单一路径层级中的任意字符。
  • ** 匹配任意多个路径层级。
  • ? 匹配单个字符。

1. Ant 风格路径匹配规则

Ant 风格的路径匹配规则中有几个特殊字符,分别是 ***?,它们具有不同的匹配意义:

(1) *(匹配零个或多个字符)
  • * 可以匹配路径中的任何部分,但只能匹配单一层级中的路径。

  • 举个例子,/foo/* 可以匹配 /foo/bar/foo/abc,但不能匹配 /foo/bar/baz

  • 示例:

    • /foo/* 匹配 /foo/bar
    • /foo/*/bar 匹配 /foo/abc/bar
(2) **(匹配零个或多个目录)
  • ** 可以匹配多个目录层级,它比 * 更加强大,能够跨越多个层级。

  • 示例:

    • /foo/**/bar 匹配 /foo/bar/foo/abc/bar/foo/abc/def/bar 等。
    • /foo/**/bar/**/baz 匹配 /foo/abc/bar/xyz/baz
(3) ?(匹配单个字符)
  • ? 用于匹配单个字符,不是零个或多个字符。它通常用于精确匹配某些路径中的单个字符。

  • 示例:

    • /foo/a?c 可以匹配 /foo/abc,但不能匹配 /foo/abcc

2. Ant 风格的路径匹配应用

Spring MVC 采用了这种路径匹配方式,使得映射 URL 路径时更加灵活。例如,使用 @RequestMapping 注解来定义控制器方法时,可以利用 Ant 风格的路径匹配规则。

示例 1:@RequestMapping 使用 Ant 风格
typescript 复制代码
@Controller
public class MyController {
​
    @RequestMapping("/foo/*")  // 匹配路径 /foo/bar 或 /foo/abc
    public String handleFoo() {
        return "foo";
    }
​
    @RequestMapping("/foo/**") // 匹配路径 /foo/bar 或 /foo/abc/xyz
    public String handleFooRecursive() {
        return "fooRecursive";
    }
​
    @RequestMapping("/foo/a?c") // 匹配路径 /foo/abc,但不匹配 /foo/abcc
    public String handleSpecificPattern() {
        return "specificPattern";
    }
}

在这个例子中:

  • /foo/* 只会匹配 /foo/bar/foo/abc 等简单路径。
  • /foo/** 会匹配 /foo/bar/foo/abc/xyz 等多层次路径。
  • /foo/a?c 会匹配 /foo/abc,但不会匹配 /foo/abcc
示例 2:@RequestMapping 配合请求方法

Spring MVC 还支持在映射中结合请求方法(如 GETPOST)来实现更细粒度的路径匹配:

kotlin 复制代码
@Controller
@RequestMapping("/foo")
public class FooController {
​
    @RequestMapping(value = "/bar/*", method = RequestMethod.GET)  // GET 请求
    public String handleBar() {
        return "barGET";
    }
​
    @RequestMapping(value = "/bar/**", method = RequestMethod.POST) // POST 请求
    public String handleBarPost() {
        return "barPOST";
    }
}

在这个例子中:

  • /foo/bar/* 仅在处理 GET 请求时匹配。
  • /foo/bar/** 仅在处理 POST 请求时匹配。

3. Ant 风格路径与通配符的结合使用

在实际开发中,Spring MVC 支持 Ant 风格路径的同时,还可以与路径变量、正则表达式等功能结合使用。

示例 1:路径变量 + Ant 风格
less 复制代码
@RequestMapping("/user/{id}/**") // 匹配多层路径,id 为路径变量
public String handleUser(@PathVariable("id") String userId) {
    return "User ID: " + userId;
}
  • 这个路径匹配 /user/123/abc/xyz,其中 id 会捕获为 123
示例 2:正则表达式 + Ant 风格
less 复制代码
@RequestMapping("/product/{id:\d+}/**") // 正则匹配数字 id
public String handleProduct(@PathVariable("id") String productId) {
    return "Product ID: " + productId;
}
  • 这里的路径 /product/{id:\d+}/** 只会匹配数字形式的 id,比如 /product/123/abc/xyz

4. 优先级和匹配规则

在使用 Ant 风格路径匹配时,路径匹配的优先级有一定的规则。具体来说,/** 会匹配任何路径,所以它的优先级通常较低,避免与其他精确匹配的路径冲突。

示例:优先级比较
less 复制代码
@Controller
@RequestMapping("/foo")
public class FooController {
​
    @RequestMapping("/foo/{id}") // 精确匹配路径 /foo/{id}
    public String handleFoo(@PathVariable String id) {
        return "foo:" + id;
    }
​
    @RequestMapping("/foo/**") // 匹配所有以 /foo/ 开头的路径
    public String handleFooCatchAll() {
        return "catchAll";
    }
}

在这个例子中,如果访问 /foo/bar,它会首先匹配 /foo/{id},因为它更精确。

访问控制

请求地址时返回对应的网页文件

  • @RestController用于返回对象格式的内容,在后面会使用ModelAndView可以返回网页文件
  • @Controller用于返回网页文件

环境要求

xml 复制代码
  <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <!-- thymeleaf -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <!-- devtools -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <!-- lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.36</version>
    </dependency>

错误页面设置

在这个路径下可以配置错误码要访问的页面,也就是可以自定义页面内容

使用@Controller

返回需要访问的HTML内容页面,最后返回的字符串就是页面,这个页面位于templates目录下

typescript 复制代码
@RequestMapping("/use")
@Controller
public class UseController {
​
    // 带参数访问
    @RequestMapping(value = "hello", method = RequestMethod.GET, params = {"name"})
    public String hello() {
        return "hello";
    }
​
    @GetMapping("jumpPage")
    public String jumpPage() {
        return "jumpPage";
    }
​
    @GetMapping("index")
    public String quick() {
        return "user";
    }
​
    // 跳转的页面
    @GetMapping("toJump")
    public String toJump() {
        return "redirect:jumpPage";
    }
}

如果在使用@Controller需要返回JSON内容,需要在控制器方法上加上@ResponseBody

less 复制代码
@GetMapping("getJson")
@ResponseBody
public List<String> getJson() {
    ArrayList<String> list = new ArrayList<>();
    list.add("a");
    list.add("b");
    list.add("c");
​
    return list;
}
将视图和模型拆开
typescript 复制代码
// 将视图和模型拆开
@GetMapping("page/test3")
public String test3(Model model) {
    model.addAttribute("test3", "测试3");
    return "page/test3";
}

使用@RestController

使用方式1

如果使用@RestController那么返回的就是JSON对象,但是这时候要想返回网页文件,需要使用ModelAndView

less 复制代码
@RequestMapping("userRest")
@RestController
public class UseRestController {
​
    @GetMapping("page/test")
    public ModelAndView test() {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("page/test");
        modelAndView.addObject("message", "这是消息内容");
        return modelAndView;
    }
}

我们引入了thymeleaf所以有以下内容<h4 th:text="'消息:'+ ${message}"></h4>

xml 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>使用RestController返回页面信息</title>
</head>
<body>
<h3>使用RestController返回页面信息</h3>
<h4 th:text="'消息:'+ ${message}"></h4>
</body>
</html>

其中modelAndView.addObject("message", "这是消息内容");是可选的

使用方式2

在控制器方法上使用ModelAndView

kotlin 复制代码
@GetMapping("page/test2")
public ModelAndView test2(ModelAndView modelAndView) {
    modelAndView.addObject("hello", "你好");
    modelAndView.setViewName("page/test2");
    return modelAndView;
}

向session共享数据

在 Spring MVC 中,Session 是用于存储用户会话期间的数据的一种机制。每个用户访问的应用程序都将拥有一个唯一的会话。通过 HttpSession,可以在用户的会话中存储一些数据,直到用户关闭浏览器或会话过期。

Spring MVC 提供了多种方式来与 HttpSession 进行交互,下面详细介绍如何通过 HttpSession 向 Session 共享数据。

1. 通过 HttpSession 操作 Session 数据

在 Spring MVC 控制器中,您可以通过 HttpSession 对象来存储和读取会话数据。

示例:将数据添加到 Session
typescript 复制代码
@Controller
public class SessionController {

    @RequestMapping("/setSessionData")
    public String setSessionData(HttpSession session) {
        // 将数据存储到 Session 中
        session.setAttribute("username", "JohnDoe");
        session.setAttribute("age", 30);
        return "sessionSet";  // 返回视图名
    }

    @RequestMapping("/getSessionData")
    public String getSessionData(HttpSession session, Model model) {
        // 从 Session 中获取数据
        String username = (String) session.getAttribute("username");
        Integer age = (Integer) session.getAttribute("age");
        model.addAttribute("username", username);
        model.addAttribute("age", age);
        return "sessionData";  // 返回视图名
    }
}

URL 请求:

  • GET /setSessionData 会将数据 "username": "JohnDoe""age": 30 存储到 Session 中。
  • GET /getSessionData 会从 Session 中获取并显示存储的值。

2. 使用 @SessionAttributes 注解

@SessionAttributes 注解用于将控制器中的某些模型属性放入 Session 中。这种方式比直接操作 HttpSession 更为方便和简洁,特别是当需要共享多个模型属性时。

示例:使用 @SessionAttributes
less 复制代码
@Controller
@SessionAttributes("user")
public class UserController {

    // 在模型中添加用户对象
    @RequestMapping("/setUser")
    public String setUser(Model model) {
        User user = new User("John", 30);
        model.addAttribute("user", user);
        return "userSet";
    }

    // 从 Session 中获取用户对象
    @RequestMapping("/getUser")
    public String getUser(@ModelAttribute("user") User user, Model model) {
        model.addAttribute("user", user);
        return "userDetails";
    }
}

URL 请求:

  • GET /setUser 会将 user 对象放入 Session 中。
  • GET /getUser 会从 Session 中获取 user 对象。

@SessionAttributes 注解不仅可以放入 Session 中,还可以与 @ModelAttribute 注解结合使用,确保模型数据保持在 Session 中。

3. 使用 @ModelAttribute 注解

@ModelAttribute 注解允许将数据放入模型中,并且在方法调用前通过 Model 传递给视图。如果和 @SessionAttributes 一起使用,它可以将属性直接添加到 HttpSession

示例:使用 @ModelAttribute@SessionAttributes
less 复制代码
@Controller
@SessionAttributes("cart")
public class CartController {

    // 在模型中创建并存储购物车
    @ModelAttribute("cart")
    public Cart createCart() {
        return new Cart();  // 创建一个空的购物车对象
    }

    // 添加商品到购物车
    @RequestMapping("/addToCart")
    public String addToCart(@ModelAttribute("cart") Cart cart, @RequestParam("item") String item) {
        cart.addItem(item);  // 将商品添加到购物车
        return "cartUpdated";
    }

    // 显示购物车内容
    @RequestMapping("/viewCart")
    public String viewCart(@ModelAttribute("cart") Cart cart, Model model) {
        model.addAttribute("cart", cart);
        return "viewCart";
    }
}

URL 请求:

  • GET /addToCart?item=Apple 会将 Apple 添加到 cart 中。
  • GET /viewCart 会显示购物车中的内容。

4. 通过 @RequestParam@PathVariable 获取 Session 数据

如果在请求中需要通过路径变量或请求参数传递数据并存储到 Session 中,可以结合 @RequestParam@PathVariable 来实现。

示例:使用 @RequestParam 存储 Session 数据
typescript 复制代码
@Controller
public class SessionController {

    @RequestMapping("/setSession/{username}")
    public String setSessionData(@PathVariable("username") String username, HttpSession session) {
        session.setAttribute("username", username);
        return "sessionSet";
    }

    @RequestMapping("/getSession")
    public String getSessionData(HttpSession session, Model model) {
        String username = (String) session.getAttribute("username");
        model.addAttribute("username", username);
        return "sessionData";
    }
}

URL 请求:

  • GET /setSession/JohnDoe 会将 "username": "JohnDoe" 存储到 Session 中。
  • GET /getSession 会从 Session 中获取并显示 username

5. 删除 Session 数据

如果希望在某个操作后清除 Session 中的某些数据,可以使用 HttpSession 提供的 removeAttribute 方法。

示例:删除 Session 数据
kotlin 复制代码
@Controller
public class SessionController {

    @RequestMapping("/removeSessionData")
    public String removeSessionData(HttpSession session) {
        session.removeAttribute("username");  // 删除指定的属性
        return "sessionRemoved";
    }
}

URL 请求:

  • GET /removeSessionData 会从 Session 中删除 "username" 属性。

6. Session 过期与清理

默认情况下,Spring MVC 的 HttpSession 会话会在用户关闭浏览器后过期,或者会话超时(默认30分钟)。可以在 web.xml 或应用的配置类中设置会话超时:

示例:设置 Session 超时
xml 复制代码
<session-config>
    <session-timeout>30</session-timeout> <!-- 设置会话超时为30分钟 -->
</session-config>

7. 通过 Spring 配置 Session

通过 Spring 配置文件或 Java 配置类,还可以控制 Session 的相关行为(如会话过期时间、session 的持久化等)。

示例:Java 配置类
less 复制代码
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new SessionInterceptor()).addPathPatterns("/**");
    }
}

SessionInterceptor 可以用于监控和管理 Session 数据。

8. 总结

在 Spring MVC 中,向 Session 共享数据主要有以下几种方式:

  • HttpSession :通过 HttpSession 对象存储和读取 Session 数据。
  • @SessionAttributes :通过 @SessionAttributes 注解将模型属性添加到 Session 中。
  • @ModelAttribute :结合 @SessionAttributes 使用,将模型数据持久化到 Session 中。
  • @RequestParam@PathVariable:将请求参数或路径变量存储到 Session 中。
  • Session 过期与清理:可以通过配置控制会话超时,或手动清除 Session 数据。

Spring MVC 提供的 Session 管理机制非常灵活,能够满足各种需求。

向application域共享数据

在 Spring MVC 中,Application 域(也称为 ServletContext )是一个全局范围,用于在整个应用程序中共享数据。不同于 Session 域和 Request 域,Application 域中的数据对整个 Web 应用的所有用户都是可见的,因此适合存储全局共享的配置信息、常量、初始化数据等。

在 Spring MVC 中,我们可以通过 ServletContext 来向 Application 域共享数据,通常使用 setAttributegetAttribute 方法来进行操作。

1. 通过 ServletContext 共享数据

ServletContext 是与整个 Web 应用程序相关联的对象,它允许你在多个请求和多个会话之间共享数据。在 Spring MVC 中,可以通过以下两种方式来访问 ServletContext

  • 直接使用 HttpServletRequest.getSession().getServletContext() 获取 ServletContext
  • 使用 @Autowired 注解注入 ServletContext 对象。
示例 1:通过 ServletContext 共享数据
1.1 通过 HttpServletRequest 获取 ServletContext
typescript 复制代码
@Controller
public class ApplicationController {

    @RequestMapping("/setApplicationData")
    public String setApplicationData(HttpServletRequest request) {
        // 获取 ServletContext
        ServletContext servletContext = request.getServletContext();
        // 向 Application 域存储数据
        servletContext.setAttribute("appName", "SpringMVCApp");
        servletContext.setAttribute("version", "1.0.0");
        return "applicationDataSet";
    }

    @RequestMapping("/getApplicationData")
    public String getApplicationData(HttpServletRequest request, Model model) {
        // 获取 ServletContext
        ServletContext servletContext = request.getServletContext();
        // 从 Application 域获取数据
        String appName = (String) servletContext.getAttribute("appName");
        String version = (String) servletContext.getAttribute("version");
        
        model.addAttribute("appName", appName);
        model.addAttribute("version", version);
        return "applicationData";
    }
}

URL 请求:

  • GET /setApplicationData 会向 Application 域中存储 "appName": "SpringMVCApp""version": "1.0.0"
  • GET /getApplicationData 会从 Application 域中读取数据,并返回给视图。
1.2 通过 @Autowired 注入 ServletContext
typescript 复制代码
@Controller
public class ApplicationController {

    @Autowired
    private ServletContext servletContext;

    @RequestMapping("/setApplicationData")
    public String setApplicationData() {
        // 向 Application 域存储数据
        servletContext.setAttribute("appName", "SpringMVCApp");
        servletContext.setAttribute("version", "1.0.0");
        return "applicationDataSet";
    }

    @RequestMapping("/getApplicationData")
    public String getApplicationData(Model model) {
        // 从 Application 域获取数据
        String appName = (String) servletContext.getAttribute("appName");
        String version = (String) servletContext.getAttribute("version");

        model.addAttribute("appName", appName);
        model.addAttribute("version", version);
        return "applicationData";
    }
}

在这个例子中,@Autowired 注解会自动将 ServletContext 注入到控制器中。

2. 应用场景

将数据放到 Application 域中通常用于存储以下类型的数据:

  • 应用级别的数据:例如应用名称、版本号、初始化配置等,这些数据是全局共享的。
  • 常量和初始化信息 :如果有一些需要在多个请求中共享的常量或初始化信息,可以将它们放到 Application 域中。
  • 数据库连接池或常用资源 :对于一些全局共享的资源(如数据库连接池),可以在 Application 域中进行配置并在不同的请求中共享。

3. 注意事项

  • 全局共享 :与 SessionRequest 域不同,Application 域中的数据对所有用户和请求都可见。因此,要特别小心在 Application 域中存储敏感数据,避免泄漏用户个人信息等。
  • 生命周期Application 域中的数据在整个应用程序生命周期内有效,直到应用服务器重新启动。因此,放入 Application 域的数据一般是全局的、不会频繁变化的。
  • 线程安全Application 域的数据是共享的,因此在并发访问时要考虑线程安全问题。如果有多个线程访问同一数据,可能需要进行同步。

4. 清理 Application 域中的数据

如果不再需要某个共享数据,可以使用 removeAttribute 方法从 Application 域中移除该数据。

示例:删除 Application 域中的数据
kotlin 复制代码
@Controller
public class ApplicationController {

    @RequestMapping("/removeApplicationData")
    public String removeApplicationData(HttpServletRequest request) {
        // 获取 ServletContext
        ServletContext servletContext = request.getServletContext();
        // 从 Application 域移除数据
        servletContext.removeAttribute("appName");
        servletContext.removeAttribute("version");
        return "applicationDataRemoved";
    }
}

URL 请求:

  • GET /removeApplicationData 会从 Application 域中移除 appNameversion 属性。

5. 使用 @ApplicationScope(Spring 方式)

如果使用 Spring 框架进行开发,也可以使用 Spring 提供的 @ApplicationScope 注解来定义在整个应用范围内共享的 Bean。这种方法通常用于 Spring 组件,而不是直接操作 ServletContext

示例:使用 @ApplicationScope
typescript 复制代码
@Component
@Scope("application")
public class AppConfig {
    private String appName = "SpringMVCApp";

    public String getAppName() {
        return appName;
    }
}

在这种情况下,Spring 管理的 Bean 会在应用级别共享,类似于 ServletContext 中存储的数据。

6. 总结

  • Application 域(即 ServletContext)用于在整个应用程序范围内共享数据,适合存储全局共享的信息、配置和常量。
  • 通过 HttpServletRequest.getServletContext()@Autowired 注解可以访问 ServletContext 并向 Application 域中共享数据。
  • 数据存储在 Application 域中可以在整个应用程序生命周期内有效,适用于共享全局性的、无需频繁更新的数据。
  • 应谨慎存储敏感数据,并注意线程安全和数据的生命周期。

通过合理地使用 Application 域,你可以实现全局共享的数据管理,并且不需要担心会话或请求的生命周期问题。

重定向和转发使用

在 Spring MVC 中,重定向(Redirect)转发(Forward) 是两种常见的请求处理方式,它们分别用于不同的场景。Spring 提供了灵活的 API 来实现这两种请求方式。

1. 转发(Forward)

转发是指服务器将请求转发到另一个资源(如 JSP 页面或另一个控制器方法),并且请求和响应都不会发生改变。即,URL 不会发生变化,客户端仍然看到原始的 URL。

转发的实现

在 Spring MVC 中,可以通过以下两种方式实现转发:

  • 使用 RequestDispatcher.forward() 方法。
  • 使用 ModelAndView 中的 "forward:" 前缀来指定转发的路径。
示例 1:使用 RequestDispatcher 转发
java 复制代码
@Controller
public class ForwardController {

    @RequestMapping("/forwardExample")
    public void forward(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 使用 Servlet 的 RequestDispatcher 进行转发
        request.getRequestDispatcher("/forwardedPage").forward(request, response);
    }

    @RequestMapping("/forwardedPage")
    public String forwardedPage() {
        return "forwardedPage";  // 返回视图
    }
}
示例 2:使用 ModelAndView 转发
typescript 复制代码
@Controller
public class ForwardController {

    @RequestMapping("/forwardExample")
    public ModelAndView forwardExample() {
        // 使用 ModelAndView 进行转发
        return new ModelAndView("forward:/forwardedPage");
    }

    @RequestMapping("/forwardedPage")
    public String forwardedPage() {
        return "forwardedPage";  // 返回视图
    }
}

解释:

  • forward:/forwardedPage 表示将请求转发到 /forwardedPage,且客户端的 URL 不会发生变化。
  • 在转发的过程中,控制器方法返回的视图会直接被渲染。
转发的特点
  • URL 不改变:用户的浏览器地址栏不会发生变化,仍然显示原始的请求路径。
  • 共享同一个请求 :请求数据(如请求参数)会被转发到目标资源,可以通过 request 对象共享。
  • 适用于内部请求:转发是服务端内部的操作,适用于控制器之间的跳转或者从控制器到视图的跳转。

2. 重定向(Redirect)

重定向是指服务器告诉客户端(浏览器)重新发起一个新的请求。重定向会导致浏览器地址栏的 URL 更新为新的地址,因此会导致一次新的 HTTP 请求。

重定向的实现

在 Spring MVC 中,重定向可以通过以下几种方式实现:

  • 使用 redirect: 前缀返回视图。
  • 使用 HttpServletResponse.sendRedirect() 方法。
示例 1:使用 redirect: 前缀
typescript 复制代码
@Controller
public class RedirectController {

    @RequestMapping("/redirectExample")
    public String redirectExample() {
        // 使用 redirect: 前缀进行重定向
        return "redirect:/redirectedPage";
    }

    @RequestMapping("/redirectedPage")
    public String redirectedPage() {
        return "redirectedPage";  // 返回视图
    }
}
示例 2:使用 HttpServletResponse.sendRedirect()
java 复制代码
@Controller
public class RedirectController {

    @RequestMapping("/redirectExample")
    public void redirectExample(HttpServletResponse response) throws IOException {
        // 使用 HttpServletResponse.sendRedirect() 进行重定向
        response.sendRedirect("/redirectedPage");
    }

    @RequestMapping("/redirectedPage")
    public String redirectedPage() {
        return "redirectedPage";  // 返回视图
    }
}

解释:

  • redirect:/redirectedPage 会发出一个 HTTP 302 重定向响应,浏览器会发起一次新的请求到 /redirectedPage,并更新地址栏的 URL。
  • 使用 HttpServletResponse.sendRedirect() 方法也会发送重定向响应,同样会导致浏览器重新发起新的请求。
重定向的特点
  • URL 改变:浏览器的地址栏会更新为重定向的目标 URL。
  • 不同的请求:重定向会产生一次新的 HTTP 请求,原请求的参数不会自动携带到新请求中,除非在重定向 URL 中显式传递。
  • 适用于跨请求跳转:重定向适合用于不同请求之间的跳转,特别是当需要在多个请求中传递数据时。

3. 重定向与转发的区别

特性 重定向(Redirect) 转发(Forward)
URL 变化 浏览器地址栏会更新为新的 URL 浏览器地址栏不会改变,仍然是原始请求 URL
请求次数 会产生两次请求:第一次请求重定向,第二次是新的目标请求 只会产生一次请求(内部请求)
数据传递 重定向后,数据不能自动传递到新请求中,除非通过 URL 参数传递 可以直接传递请求数据,如请求参数和请求属性
适用场景 当需要跨请求或跨控制器传递数据时,或者需要跳转到外部 URL 当请求处理完成后,内部跳转到另一个视图或资源时
性能 因为需要进行两次请求,所以相比转发略有性能开销 因为只需要一次请求,性能开销较小

4. 常见使用场景

(1) 重定向的使用场景
  • 表单提交后的重定向 :表单数据提交后,为了防止表单重复提交(用户刷新页面时),常常会使用重定向到另一个页面,这种方法叫做 Post/Redirect/Get (PRG) 模式。

    例如,用户提交了一个订单数据后,页面显示 "订单已提交",并重定向到订单查看页面。

    typescript 复制代码
    @RequestMapping("/submitOrder")
    public String submitOrder(Order order) {
        orderService.save(order);
        // 提交订单后重定向到订单详情页
        return "redirect:/orderDetails?orderId=" + order.getId();
    }
  • 外部 URL 重定向:在用户登录后重定向到外部系统或第三方网站。

    typescript 复制代码
    @RequestMapping("/redirectToExternalSite")
    public String redirectToExternal() {
        // 重定向到外部 URL
        return "redirect:http://www.example.com";
    }
(2) 转发的使用场景
  • 内部资源的转发:当需要在同一应用程序内部跳转时(如从控制器到视图),或者从一个控制器跳转到另一个控制器时,可以使用转发。

    例如,在处理用户请求后,将其转发到 JSP 页面进行显示:

    typescript 复制代码
    @RequestMapping("/showUser")
    public String showUserDetails(Model model) {
        User user = userService.getUser();
        model.addAttribute("user", user);
        return "forward:/userDetails.jsp";  // 内部转发到 userDetails.jsp 页面
    }
  • 从一个控制器跳转到另一个控制器:在处理完业务逻辑后,可能需要跳转到另一个控制器来处理某些逻辑。

    typescript 复制代码
    @RequestMapping("/processOrder")
    public String processOrder(Order order) {
        orderService.process(order);
        return "forward:/orderConfirmation";  // 内部跳转到订单确认页面
    }

5. 总结

  • 重定向(Redirect) :客户端浏览器会发起一次新的请求,地址栏 URL 会发生变化,适用于需要跨请求跳转或外部跳转的场景。
  • 转发(Forward) :请求在服务器内部被转发,地址栏 URL 不变,适用于同一请求的内部跳转。

通过合理使用转发和重定向,你可以灵活地控制请求流转和用户体验。

Thymeleaf快速入门

Thymeleaf 是一种现代化的 Java 模板引擎,广泛用于生成 HTML、XML、JavaScript 等内容。它有许多内置的指令和功能,用于渲染动态内容、条件渲染、循环、处理表达式等。以下是 Thymeleaf 中常见的指令和属性的详细介绍:

1. th:text

用于替换元素的文本内容。

bash 复制代码
<span th:text="${message}"></span>
  • ${message} 的值会替换 span 元素的文本。

如果需要格式化日期,需要注意,使用temporals进行操作

kotlin 复制代码
<td class="text-success" th:text="${#temporals.format(bill.transactionDate,'yyyy-MM-dd HH:mm:ss')}"></td>

2. th:utext

用于替换元素的文本内容,并允许处理 HTML 标签(不会转义 HTML)。

bash 复制代码
<span th:utext="${htmlContent}"></span>
  • ${htmlContent} 的内容直接插入,并解析其中的 HTML。

3. th:value

设置表单元素的 value 属性,通常用于输入框或选择框。

bash 复制代码
<input type="text" th:value="${user.name}" />
  • ${user.name} 的值赋给该输入框的 value 属性。

4. th:each

用于循环遍历集合或数组。

less 复制代码
<ul>
    <li th:each="person : ${people}">
        <span th:text="${person.name}"></span>
    </li>
</ul>
  • 遍历 people 集合,输出每个 person.name

5. th:if

用于条件渲染,只有满足条件时才渲染元素。

less 复制代码
<div th:if="${user.isAdmin}">
    <p>Welcome, admin!</p>
</div>
  • 如果 user.isAdmintrue,渲染该 div

6. th:unless

th:if 相反,只有条件为 false 时才渲染元素。

less 复制代码
<div th:unless="${user.isAdmin}">
    <p>You are not an admin!</p>
</div>
  • 如果 user.isAdminfalse,渲染该 div

7. th:attr

用于设置元素的多个属性。

bash 复制代码
<img th:attr="src=${imageUrl}" th:attr="alt=${imageDescription}" />
  • 设置 img 元素的 srcalt 属性。

8. th:src / th:href

用于动态设置 srchref 属性。

ini 复制代码
<img th:src="@{${imageUrl}}" alt="Image">
<a th:href="@{${linkUrl}}">Click Here</a>
  • th:src 用于设置图片的 src 属性,th:href 用于设置链接的 href 属性。

9. th:class

动态设置 class 属性,支持条件表达式。

bash 复制代码
<div th:class="${isActive} ? 'active' : 'inactive'">...</div>
  • 如果 isActivetrue,设置 class="active",否则为 inactive

10. th:classappend / th:classprepend

分别在现有的 class 属性上追加或前置新类。

ini 复制代码
<div th:classappend="'newClass'">...</div>
<div th:classprepend="'prefixClass'">...</div>
  • th:classappend 会将新的类追加到现有类的后面。
  • th:classprepend 会将新的类添加到现有类的前面。

11. th:id

设置元素的 id 属性。

bash 复制代码
<input type="text" th:id="${elementId}" />
  • 设置 input 元素的 id${elementId} 的值。

12. th:action

设置表单的 action 属性。

xml 复制代码
<form th:action="@{/submitForm}" method="post">
    <!-- form fields -->
</form>
  • 设置表单的 action/submitForm

13. th:style

设置元素的 style 属性。

bash 复制代码
<div th:style="'color: ' + ${color}"></div>
  • 动态设置 style 属性,${color} 的值会成为 color 样式的值。

14. th:fragment

定义一个可重用的片段,通常在模板中调用。

less 复制代码
<div th:fragment="userFragment">
    <p>Welcome, <span th:text="${user.name}"></span></p>
</div>
  • 定义一个 userFragment 片段,可以在其他模板中引用。

15. th:replace

替换当前元素,并将一个片段或其他模板插入其中。

css 复制代码
<div th:replace="~{userFragment}"></div>
  • th:replace 会将 userFragment 片段的内容插入到当前 div 中。

16. th:include

将另一个模板的内容插入当前模板中,但不会替换当前元素。

css 复制代码
<div th:include="~{userFragment}"></div>
  • 插入 userFragment 的内容,但保留当前 div 元素。

17. th:with

局部变量声明,用于在模板中定义临时变量。

bash 复制代码
<div th:with="total=${cart.totalPrice}">
    <p th:text="'Total price: ' + ${total}"></p>
</div>
  • th:with 用于在当前元素的上下文中定义变量,类似于局部变量。

18. th:block

在模板中定义一个不会渲染任何 HTML 标签的块元素。用于组合多个元素。

bash 复制代码
<th:block th:each="person : ${people}">
    <p th:text="${person.name}"></p>
</th:block>
  • th:block 不会渲染任何标签,但可以用来包装多个元素进行条件判断或循环。

19. th:switch / th:case

类似于 Java 中的 switch 语句,用于条件选择。

bash 复制代码
<div th:switch="${status}">
    <span th:case="'active'">Active</span>
    <span th:case="'inactive'">Inactive</span>
    <span th:case="*">Unknown</span>
</div>
  • 根据 ${status} 的值,渲染对应的 span 元素。

20. th:object

用来为表单元素绑定一个对象。

ini 复制代码
<form th:action="@{/submit}" th:object="${user}">
    <input type="text" th:field="*{name}" />
    <input type="text" th:field="*{email}" />
    <button type="submit">Submit</button>
</form>
  • th:object 绑定整个表单到 user 对象。
  • th:field 用于绑定每个表单字段到对象的属性。

21. th:href / th:src

用于动态设置 URL 值。

ini 复制代码
<a th:href="@{/users/{id}(id=${user.id})}">Profile</a>
<img th:src="@{/images/{imageName}(imageName=${image.name})}" />
  • 动态生成 URL,支持路径变量的替换。

22. th:placeholder

设置表单输入框的 placeholder 属性。

bash 复制代码
<input type="text" th:placeholder="${placeholderText}" />
  • 设置 inputplaceholder${placeholderText} 的值。

总结

Thymeleaf 提供了许多强大的指令来处理模板中的动态内容、条件渲染、迭代和属性绑定。常见的指令包括:

  • th:textth:utext:用于设置文本内容。
  • th:each:用于循环遍历。
  • th:ifth:unless:用于条件判断。
  • th:attrth:idth:class:用于设置 HTML 属性。
  • th:replaceth:include:用于片段包含。
  • th:switchth:case:用于类似 switch 的条件语句。
相关推荐
光而不耀@lgy13 分钟前
C++初登门槛
linux·开发语言·网络·c++·后端
方圆想当图灵32 分钟前
由 Mybatis 源码畅谈软件设计(七):SQL “染色” 拦截器实战
后端·mybatis·代码规范
毅航1 小时前
MyBatis 事务管理:一文掌握Mybatis事务管理核心逻辑
java·后端·mybatis
我的golang之路果然有问题1 小时前
速成GO访问sql,个人笔记
经验分享·笔记·后端·sql·golang·go·database
柏油1 小时前
MySql InnoDB 事务实现之 undo log 日志
数据库·后端·mysql
写bug写bug3 小时前
Java Streams 中的7个常见错误
java·后端
Luck小吕3 小时前
两天两夜!这个 GB28181 的坑让我差点卸载 VSCode
后端·网络协议
M1A13 小时前
全栈开发必备:Windows安装VS Code全流程
前端·后端·全栈
蜗牛快跑1233 小时前
github 源码阅读神器 deepwiki,自动生成源码架构图和知识库
前端·后端
嘻嘻嘻嘻嘻嘻ys4 小时前
《Vue 3.4响应式超级工厂:Script Setup工程化实战与性能跃迁》
前端·后端