`
yimeng528
  • 浏览: 188764 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

基于Spring MVC的Web应用开发(5) - Redirect

阅读更多

本文介绍Spring MVC中的重定向(Redirect),先回顾一下在JSP中,实现页面跳转的几种方式:

  1. RequestDispatcher.forward():是在服务端起作用,当使用forward()时,Servlet引擎传递http请求从当前的servlet或者jsp到另外一个servlet,jsp或者普通的html文件,即你的表单(form)提交至a.jsp,在a.jsp中用到了forward()重定向到b.jsp,此时form提交的所有信息在b.jsp都可以获得,参数自动传递,但forward()无法重定向至有frame的jsp文件,可以重定向到有frame的html文件,同时forward()无法带参数传递,比如servlet?name=**,但可以在程序内通过response.setAttribute("name",name)来将参数传至下一个页面。另外,重定向后浏览器地址栏的URL不变,且通常在servlet中使用,不在jsp中使用。
  2. response.sendRedirect():时在用户的浏览器端工作,sendRedirect()可以带参数传递,比如servlet?name=**传至下一个页面,同时它可以重定向至不同的主机,sendRedirect()可以重定向有frame的jsp文件。重定向后在浏览器地址栏上会出现重定向页面的URL。另外,由于response是jsp页面中的隐含对象,故在jsp页面中可以用response.sendRedirect()直接实现重定位。我们在讲第三点之前,先比较一下头两点,比较:(1) Dispatcher.forward()是容器中的控制权的转向,在客户端浏览器地址栏中不会显示出转向后的地址;(2) response.sendRedirect()则是完全的跳转,浏览器将会得到跳转的地址,并重新发送请求链接可,这样,从浏览器的地址栏中可以看到跳转后的链接地址。前者更加高效,再跑题一点,在有些情况下,比如,需要跳转到到一个其它服务器上的资源,则必须使用HttpServletResponse.sendRequest()方法。
  3. <jsp:forward page=""/>:这个jsp标签的底层部分是由RequestDispatcher来实现的,因此它带有RequestDispatcher.forward()方法的所有特性。要注意,它不能改变浏览器地址,刷新的话会导致重复提交。

在Spring MVC中 ,跳转其实和Controller中的return方法紧密联系在一起,编写一个新的Controller,叫RedirectController:

Java代码 复制代码 收藏代码
  1. package org.springframework.samples.mvc.redirect;
  2. import org.joda.time.LocalDate;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.core.convert.ConversionService;
  5. import org.springframework.stereotype.Controller;
  6. import org.springframework.web.bind.annotation.PathVariable;
  7. import org.springframework.web.bind.annotation.RequestMapping;
  8. import org.springframework.web.bind.annotation.RequestMethod;
  9. import org.springframework.web.bind.annotation.RequestParam;
  10. import org.springframework.web.servlet.mvc.support.RedirectAttributes;
  11. import org.springframework.web.util.UriComponents;
  12. import org.springframework.web.util.UriComponentsBuilder;
  13. @Controller
  14. @RequestMapping("/redirect")
  15. publicclass RedirectController {
  16. privatefinal ConversionService conversionService;
  17. @Autowired
  18. public RedirectController(ConversionService conversionService) {
  19. this.conversionService = conversionService;
  20. }
  21. @RequestMapping(value="/uriTemplate", method=RequestMethod.GET)
  22. public String uriTemplate(RedirectAttributes redirectAttrs) {
  23. redirectAttrs.addAttribute("account", "a123"); // Used as URI template variable
  24. redirectAttrs.addAttribute("date", new LocalDate(2011, 12, 31)); // Appended as a query parameter
  25. return"redirect:/redirect/{account}";
  26. }
  27. @RequestMapping(value="/uriComponentsBuilder", method=RequestMethod.GET)
  28. public String uriComponentsBuilder() {
  29. String date = this.conversionService.convert(new LocalDate(2011, 12, 31), String.class);
  30. UriComponents redirectUri = UriComponentsBuilder.fromPath("/redirect/{account}").queryParam("date", date)
  31. .build().expand("a123").encode();
  32. return"redirect:" + redirectUri.toUriString();
  33. }
  34. @RequestMapping(value="/{account}", method=RequestMethod.GET)
  35. public String show(@PathVariable String account, @RequestParam(required=false) LocalDate date) {
  36. return"redirect/redirectResults";
  37. }
  38. }
package org.springframework.samples.mvc.redirect;

import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

@Controller
@RequestMapping("/redirect")
public class RedirectController {
	
	private final ConversionService conversionService;

	@Autowired
	public RedirectController(ConversionService conversionService) {
		this.conversionService = conversionService;
	}

	@RequestMapping(value="/uriTemplate", method=RequestMethod.GET)
	public String uriTemplate(RedirectAttributes redirectAttrs) {
		redirectAttrs.addAttribute("account", "a123");  // Used as URI template variable
		redirectAttrs.addAttribute("date", new LocalDate(2011, 12, 31));  // Appended as a query parameter
		return "redirect:/redirect/{account}";
	}

	@RequestMapping(value="/uriComponentsBuilder", method=RequestMethod.GET)
	public String uriComponentsBuilder() {
		String date = this.conversionService.convert(new LocalDate(2011, 12, 31), String.class);
		UriComponents redirectUri = UriComponentsBuilder.fromPath("/redirect/{account}").queryParam("date", date)
				.build().expand("a123").encode();
		return "redirect:" + redirectUri.toUriString();
	}

	@RequestMapping(value="/{account}", method=RequestMethod.GET)
	public String show(@PathVariable String account, @RequestParam(required=false) LocalDate date) {
		return "redirect/redirectResults";
	}

}

先看看show这个方法:

Java代码 复制代码 收藏代码
  1. @RequestMapping(value="/{account}", method=RequestMethod.GET)
  2. public String show(@PathVariable String account, @RequestParam(required=false) LocalDate date) {
  3. return"redirect/redirectResults";
  4. }
	@RequestMapping(value="/{account}", method=RequestMethod.GET)
	public String show(@PathVariable String account, @RequestParam(required=false) LocalDate date) {
		return "redirect/redirectResults";
	}

注解好像有点多,简单解释一下每个注解代表什么含义,具体详细用法等后面讲到Spring MVC的Convert部分再展开。在@RequestMapping注解中有个/{account}的url模式,在方法中也有一个参数叫accout,它带有@PathVariable注解,即当访问http://localhost:8080/web/redirect/1时,account变量会自动获取到1这个值(当然不限数字,只要是字符串即可),从PathVariable也可以猜到它是解析url路径的变量。再看@RequestParam注解,它是解析请求的参数的,如访问http://localhost:8080/web/redirect/1?date=2012/03/26时,show方法中的date参数会自动得到2012/03/26这个值并将其转换成LocalDate类。

最后看return,show方法返回String,并且没有加上@ResponseBody,返回的View就是该字符串对应的View名字,我们已经有一个默认的ViewResolver,因此这个@RequestMapping最终将返回到

webapp/WEB-INF/views/redirect/redirectResults.jsp:

Html代码 复制代码 收藏代码
  1. <%@ taglib uri="http://java.sun.com/jsp/jstl/core"prefix="c" %>
  2. <%@ taglib uri="http://www.springframework.org/tags"prefix="spring" %>
  3. <%@ page session="false" %>
  4. <html>
  5. <head>
  6. <title>Redirect Results</title>
  7. <linkhref="<c:url value="/resources/form.css" />" rel="stylesheet"type="text/css"/>
  8. </head>
  9. <body>
  10. <divclass="success">
  11. <h3>Path variable 'account': ${account}</h3>
  12. <h3>Query param 'date': ${param.date}</h3>
  13. </div>
  14. </body>
  15. </html>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
<%@ page session="false" %>
<html>
<head>
	<title>Redirect Results</title>
	<link href="<c:url value="/resources/form.css" />" rel="stylesheet"  type="text/css" />		
</head>
<body>
<div class="success">
	<h3>Path variable 'account': ${account}</h3>
	<h3>Query param 'date': ${param.date}</h3>
</div>
</body>
</html>

此jsp取得response中的account值(类似response.setAttribute(name,value)中设置的值),和url参数传过来的变量date(注意${param.date}中的param是jsp标准中定义的8个隐含对象(是8个吧?))并显示在页面。

下面马上看到的RedirectController中另外两个方法将会展示如何跳转到上面的show方法的URL,先看:

Java代码 复制代码 收藏代码
  1. @RequestMapping(value="/uriTemplate", method=RequestMethod.GET)
  2. public String uriTemplate(RedirectAttributes redirectAttrs) {
  3. redirectAttrs.addAttribute("account", "a123"); // Used as URI template variable
  4. redirectAttrs.addAttribute("date", new LocalDate(2011, 12, 31)); // Appended as a query parameter
  5. return"redirect:/redirect/{account}";
  6. }
	@RequestMapping(value="/uriTemplate", method=RequestMethod.GET)
	public String uriTemplate(RedirectAttributes redirectAttrs) {
		redirectAttrs.addAttribute("account", "a123");  // Used as URI template variable
		redirectAttrs.addAttribute("date", new LocalDate(2011, 12, 31));  // Appended as a query parameter
		return "redirect:/redirect/{account}";
	}

出现了一个新类RedirectAttributes,方法中给它添加了两个属性,添加的属性可以在跳转后的页面中获取到。最后该方法返回"redirect:/redirect/{account}",一般理解的跳转肯定是跳转到某个url,SpringMVC中也不例外,

它将跳转到http://localhost:8080/web/redirect/{account},而此URL最终将返回到一个JSP页面上。

看看浏览器效果,在浏览器访问 http://localhost:8080/web/redirect/uriTemplate,短暂的等待后,浏览器的地址栏将变成:

Html代码 复制代码 收藏代码
  1. http://localhost:8080/web/redirect/a123?date=12%2F31%2F11
http://localhost:8080/web/redirect/a123?date=12%2F31%2F11

提个问题,date=12%2F31%2F11是怎么回事?

看下一个方法:

Java代码 复制代码 收藏代码
  1. @RequestMapping(value="/uriComponentsBuilder", method=RequestMethod.GET)
  2. public String uriComponentsBuilder() {
  3. String date = this.conversionService.convert(new LocalDate(2011, 12, 31), String.class);
  4. UriComponents redirectUri = UriComponentsBuilder.fromPath("/redirect/{account}").queryParam("date", date)
  5. .build().expand("a123").encode();
  6. return"redirect:" + redirectUri.toUriString();
  7. }
	@RequestMapping(value="/uriComponentsBuilder", method=RequestMethod.GET)
	public String uriComponentsBuilder() {
		String date = this.conversionService.convert(new LocalDate(2011, 12, 31), String.class);
		UriComponents redirectUri = UriComponentsBuilder.fromPath("/redirect/{account}").queryParam("date", date)
				.build().expand("a123").encode();
		return "redirect:" + redirectUri.toUriString();
	}

该方法只是前一个方法的变种。

访问http://localhost:8080/web/redirect/uriComponentsBuilder

短暂的等待后(应该非常短暂以至于你感觉不到),浏览器地址栏变成:

Html代码 复制代码 收藏代码
  1. http://localhost:8080/web/redirect/a123?date=12/31/11
http://localhost:8080/web/redirect/a123?date=12/31/11

效果一模一样(其实还是有点不一样,因为这个没有出现怪异的"%2F"了),打印redirectUri出来看看:

Java代码 复制代码 收藏代码
  1. /redirect/a123?date=12/31/11
/redirect/a123?date=12/31/11

那么最终return语句就是

 

Java代码 复制代码 收藏代码
  1. return"redirect:/redirect/a123?date=12/31/11";
return "redirect:/redirect/a123?date=12/31/11";

UriComponents是一个工具类,帮助我们生成URL,比如在本例中,通过UriComponentsBuilder这个类,

有url为"/redirect/{account}",传递的参数为date,并且进行转码(encode),

结果返回的的URL就是"/redirect/a123?date=12/31/11"。(可以试着不加encode()方法看看效果)

这个结果也说明Spring MVC中的redirect可以带参数。

 

[本附录可不看,翻译也很渣]

附录Spring Reference Documentation中16.5.3 Redirection to views翻译

 

16.5.3 重定向(redirect)到视图(view)

前文提及,controller(控制器)返回一个view(视图)名,view resolver(视图解析器)解析这个特定的view。对于view technologies(视图技术?),象JSP(JSP由servlet或者JSP引擎解析),Spring MVC中的内部解决方案是将InternalResourceViewResolver和InternalResourceView组合起来使用,这种组合采用一个内部定向(forward)或者通过Servlet自身API提供的RequestDispatcher.forward(..)方法或者RequestDispatcher.include()方法。对于其它的view technologies,如Velocity,XSLT,等等,view本身就将内容直接写到response的输出流里了。

有时我们想要在view渲染前就将HTTP重定向回客户端,这是有可能的,比如,当使用POST方式提交数据到一个Controller时,response实际上是另外一个controller的委托(比如一个成功的form表单提交)。在这种情况下,一个正常的内部定向意味着其它controller将也会看到相同的POST数据,如果将它和其它期望的数据弄混了,这就是一个潜在的问题了。在显示结果之前进行重定向的另一个原因就是排除用户多次提交表单数据的可能性。在这种场景下,浏览器会先发送一个初始POST;然后接受一个response来重定向到一个不同的URL;最后浏览器的地址栏会体现在重定向response中的GET方式的URL。因此,从浏览器的角度看,当前页显示的不是POST而是GET的结果。最后一个影响就是用户不能通过“意外地”点击了刷新,从而重复POST提交了相同的数据。刷新会到一个GET的结果页面,而不是重复以POST方式提交数据。(说实话,这一段我没怎么看懂 =;=)

16.5.3.1 RedirectView

对controller来说,作为controller的response的结果来重定向的一个方式就是创建并返回一个Spring的RedirectView的实例。在这种情况下,DispatcherServlet不使用通用的view解决机制。这是由于依然重定向的view已经有了,DispatcherServlet只要简单得让这个view工作即可。

RedirectView通过HttpServletResponse.sendRedirect()实现,它作为一个HTTP重定向返回给客户端浏览器。默认所有得model attribute会以URI模板变量得形式暴露在重定向的URL里。保留的attribute中那些primitive types或者collections/arrays的primitive types会自动地以查询参数的形式添加上。

如果一个model实例是为重定向特殊准备的,以查询参数添加primitive type attributes就是我们想要的结果。然而,在加上了注解的controller中,model可能包含额外的作为渲染目的的(rendering purposes)attribute(比如:drop-down field values)。为了避免这样的attribute出现在URL里,一个带有注解的controller可以声明一个RedirectAttributes类型的参数,并使用它指定明确的attribute来让RedirectView获取到。如果controller方法重定向了,RedirectAttributes的内容就可以使用了,否则使用的是model的内容。

注意来自当前请求的URI模板变量,在重定向到一个URL时,是自动可获得的,不需要额外添加,也不需要通过Model或者RedirectAttributes来添加,举个例子:

Java代码 复制代码 收藏代码
  1. @RequestMapping(value = "/files/{path}", method = RequestMethod.POST)
  2. public String upload(...) {
  3. // ...
  4. return"redirect:files/{path}";
  5. }
@RequestMapping(value = "/files/{path}", method = RequestMethod.POST)
public String upload(...) {
    // ...
    return "redirect:files/{path}";
}

如果你使用RedirectView,这个view是被controller自身创建的,推荐你配置重定向URL,让其注入到controller,从而it is not baked into the controller,而是在上下文中带着view名配置的。下一节我们继续讨论。

16.5.3.2 redirect:前缀

因为controller本身可以创建RedirectView,所以我们使用RedirectView可以工作得很好,不可避免的一个事实是controller得知道这个Redirect,这让事情紧紧得耦合在一起了,controller不应该知道response是如何处理的,通常它应该只关心注入进来的view名。

这个特殊的redirect:前缀可以达到这个目的,如果一个view名以前缀名redirect:方式返回,UrlBasedViewrResolver(以及它的子类)会识别出来这是一个特殊的indication,这个indication 是一个redirect需要的。剩下的view名将会作为重定向的URL来处理。

如果controller返回的是RedirectView,实际的效果是一样的,但现在controller自身可以操作逻辑意义上的view名,一个逻辑意义上的view名,如redirect:/myapp/some/resources会重定向关联到当前Servlet上下文,同时这样的redirect:http://myhost.com/some/arbitrary/path的view名会重定向到一个绝对路径的URL上。

16.5.3.3 forward:前缀

也可以给view名使用一个特殊的forward:前缀,它会被UrlBasedViewResolver及其子类解析。它给view名创建一个InternalResourceView(实际使用RequestDispatcher.forward()),剩下的view名就是一个URL,然而,这个前缀对于InternalResourceViewResolver和InternalResourceView(比如JSP)是不可用的。但是这个前缀在你使用其它view technology时还是可以提供一些帮助的。但是仍然要强制forward到一个能被Servlet/JSP引擎处理的资源。(注意你也可以将多个view解析器串起来,替代)。(说实话,这段没怎么明白 译者)

16.5.4 ContentNegotiatingViewResolver (跟我们讲的关联不大,略去 译者)

分享到:
评论

相关推荐

    Spring MVC 文件上传下载 后端 - Java.zip

    在Java Web开发中,Spring MVC框架是一个非常流行的用于构建企业级应用的模型-视图-控制器(MVC)架构。这个压缩包“Spring MVC 文件上传下载 后端 - Java.zip”很可能包含了关于如何在Spring MVC中实现文件上传和...

    Spring4 In Action-5.2.2-Spring Web应用程序-简单的控制器实现跳转

    在本主题中,我们将深入探讨Spring框架的Web应用程序开发,特别是如何通过简单的控制器来实现页面间的跳转。《Spring4 In Action》是Spring框架的经典学习资料,第五版的2.2章节聚焦于Spring MVC,它是Spring框架...

    spring mvc教程

    - **定义**:Spring MVC 是一种基于 Java 的轻量级 Web 框架,它实现了 MVC(Model-View-Controller)设计模式。该框架通过将 Web 层进行职责解耦,帮助开发者简化 Web 应用程序的开发过程。 - **工作原理**:...

    基于注解的Spring mvc增删改DEMO

    总结,基于注解的Spring MVC简化了Web应用的开发,通过注解可以快速地定义路由、数据绑定、事务管理等功能。这种面向切面编程(AOP)的方式使得代码更加简洁,易于维护。通过阅读提供的博客链接...

    spring 登录web应用

    Spring MVC是Spring框架的一部分,它为Web开发提供了一个模型-视图-控制器(MVC)架构。在MVC模式中,模型负责业务逻辑,视图负责呈现数据,而控制器处理用户请求并协调模型和视图。 **二、创建Spring Boot项目** ...

    spring学习: spring mvc在redirect请求中传递数据

    标题中的“spring学习:spring mvc在redirect请求中传递数据”揭示了本次讨论的核心主题,即如何在Spring MVC框架中处理重定向(redirect)请求时传递数据。这涉及到Spring MVC的请求转发和重定向概念,以及如何在...

    spring mvc 快速入门深入分析

    Spring MVC 是 Spring Framework 的一个重要模块,主要用于构建 Web 应用程序。它遵循 MVC(Model-View-Controller)设计模式,将应用程序的不同关注点进行分离,使得代码更易于维护和扩展。 **特点**: 1. **简洁...

    spring mvc 注解 增删改 实例

    Spring MVC 是一个强大的Java web开发框架,用于构建高效、可维护和模块化的Web应用程序。它在MVC(Model-View-Controller)设计模式的基础上提供了一种结构化的方法来组织应用程序的逻辑。在这个实例中,我们将重点...

    spring mvc 文档

    Spring是一款开源框架,主要用于Web应用开发,其官方网站为http://www.springframework.org。该框架包含多个组件,如Web开发组件、数据库开发组件等。本文将重点介绍Spring中的Web开发组件。 **假设**:本文假定...

    Spring-Boot-application.properties

    spring.mvc.view.prefix=/WEB-INF/views/ spring.mvc.view.suffix=.jsp ``` #### 四、消息国际化配置 ##### 10. spring.messages.basename - **作用**:定义消息资源文件的基本名称。 - **默认值**:`messages`...

    第三课:spring mvc 原理深度解析1

    Spring MVC 是一个强大的 web 框架,它简化了基于模型-视图-控制器(MVC)架构的应用程序开发。本课程将深入讲解 Spring MVC 的核心原理和组件,特别是 HandlerAdapter 的作用。 首先,让我们回顾 MVC 应用场景。在...

    Spring3_MVC_基础实践之路

    在Spring MVC 3的基础实践中,配置是至关重要的第一...以上是Spring MVC 3的基础实践,通过这些配置和机制,可以构建出功能丰富的Web应用。在实际开发中,可能还需要根据具体需求调整和扩展配置,以实现更复杂的功能。

    Spring MVC常用注解

    Spring MVC 是一个基于 Java 的轻量级 Web 开发框架,它是 Spring 框架的一部分,主要用于构建 MVC(Model-View-Controller)模式的 Web 应用程序。在 Spring MVC 中,注解扮演着非常重要的角色,它们使得代码更加...

    Spring MVC--2.@RequestMapping 映射请求

    在实际开发中,通常会结合使用`@RequestMapping`和其他注解,如`@ControllerAdvice`(全局异常处理)、`@ResponseBody`(将方法返回值直接转换为HTTP响应体)等,构建出功能丰富的Spring MVC应用程序。 通过理解并...

    spring mvc step by step

    本文档详细介绍了如何使用Spring Framework MVC框架逐步构建一个完整的Web应用程序。文档版本为2.5,由Thomas Risberg、Rick Evans和Portia Tung共同编著,版权归属2004-2008年。 #### 基本应用及环境搭建 ##### ...

    Spring MVC文件上传下载

    Spring MVC 是一个强大的Java web开发框架,用于构建可维护、模块化且松散耦合的Web应用程序。在Spring MVC中,文件的上传和下载是常见的功能需求,这涉及到客户端与服务器之间的数据传输。本篇文章将深入探讨Spring...

    Spring MVC面试题(2022最新版)

    在Web开发中,MVC模式将应用程序分为三个主要部分:模型(Model)、视图(View)和控制器(Controller)。 - **模型(Model)**:负责处理应用程序数据逻辑,通常与数据源交互,例如数据库。 - **视图(View)**:...

    spring mvc 自學筆記

    ### Spring MVC 数据跳转 在 Spring MVC 中,数据跳转主要指的是控制器(Controller)处理完请求后,将数据转发到视图(View)进行...通过上述知识点的学习,可以帮助开发者更好地理解和运用 Spring MVC 进行项目开发。

    Spring 3.0 mvc 简单跳转 实例 源码

    基于Spring 3.0 MVC的Web应用通常有以下结构: - `WEB-INF`:存放配置文件(如`servlet-context.xml`)、JSP页面(`views`目录)等。 - `src/main/java`:存放Java源代码,包括Controller、Service、DAO等层的...

Global site tag (gtag.js) - Google Analytics