总结
直接返回模板页面
和请求转发
这两种方式都不会改变浏览器地址栏中的url,仅仅是改变浏览器页面展示的内容,但是重定向
会改变浏览器地址栏中的url- 请求转发和重定向的发起方是不一样的,请求转发是服务器代替浏览器发起请求,这种请求只能发往当前微服务;而重定向是服务器命令浏览器直接向服务器发送请求,所以这是浏览器发送的请求,那么这种请求可以发往任意服务器;根据以上分析可知,在浏览器中输入地址然后回车,请求转发方式只需要浏览器发送一次请求,而重定向方式需要浏览器发送两次请求,我们所说的请求转发和重定向属于仅进行一次的情况;
- 请求转发和重定向想要在模板页面中展示数据的方式是不一样的,请求转发的话使用
Model
将数据放在请求域中,那么我们就可以模板页面中取出请求域中的数据进行展示了;而重定向需要使用RedirectAttributes
来将数据放在请求域中,注意使用的不是Model
,我们在重定向中不用Model,如果我们注册信息输错了,那页面中是会显示错误信息的,但是当我们刷新页面的时候,那就是直接向http://auth.gulimall.com/reg.html
发送请求,这就会导致请求域中的错误信息对象消失,毕竟这个错误信息对象是我们当时发送注册请求http://cart.gulimall.com/register
才得到的,而我们直接发送http://auth.gulimall.com/reg.html
,那请求域中肯定不会有错误信息对象了,不过你可以通过参数传递来完成错误信息对象的传递,不过本次就不采用了,错误信息只要展示一次就好,即使用户刷新页面之后错误信息不见了,它也不会怀疑什么;另外重定向中可以使用RedirectAttributes
的addFlashAttribute()
模拟session往请求域中放数据,也可以使用RedirectAttributes
的addAttribute()
将里面的请求参数放在重定向地址后面,例如以下代码就相当于让浏览器发送http://cart.gulimall.com/success.html?skuId=XXX
请求,代码如下:
@GetMapping("/addToCart")
public String addToCart(@RequestParam Long skuId, @RequestParam Integer num, RedirectAttributes attributes) {
cartService.addToCart(skuId, num);
attributes.addAttribute("skuId", skuId);
// 避免用户多次添加商品,所以使用重定向的方法来改变浏览器地址栏的url
return "redirect:http://cart.gulimall.com/success.html";
}
- 代码写法注意:return中的
forward:
和redirect:
中的冒号后面没有空格,直接就是url地址,如果多1个空格的话,那么返回的地址就是错误的
以下三种详细解释的情景
本次注册网页是reg.html
,然后使用form表单提交注册请求(url:http://auth.gulimall.com/register
),然后登录网页是login.html
;
如果注册成功,将会在浏览器上展示login.html
登录页面;
如果注册失败,将回到reg.html
注册页面,并且展示错误信息;
1、直接返回模板页面
比如我使用的是thymeleaf模板,代码如下:
@Controller
public class RegisterController {
@PostMapping("/register")
public String register(UserRegisterVo userRegisterVo, Model model) {
……………………………………
if(注册成功){
// 注册成功,会到登录页
return "login";
} else {
// 注册失败,会到注册页
model.addAttribute("errorData", errorData);
return "reg";
}
}
}
首先说一下浏览器地址栏url问题,无论注册成功还是失败,浏览器地址栏的url都是http://auth.gulimall.com/register
,所以这种方式不会改变浏览器地址栏的url,只不过浏览器网页中展示页面内容是reg.html
h或者login.html
,因此这就直接pass了这种做法,毕竟谁也不想注册成功之后刷新网页就再次发起注册请求了
然后说一下错误信息展示问题,使用这种做法可以正确显示错误信息,Model是可以使用的
2、使用forward请求转发
比如我使用的是thymeleaf模板,代码如下:
// 可以使用Model进行数据传输
@Controller
public class RegisterController {
@PostMapping("/register")
public String register(UserRegisterVo userRegisterVo, Model model) {
……………………………………
if(注册成功){
// 注册成功,会到登录页
return "forward:http://auth.gulimall.com/login.html";
} else {
// 注册失败,会到注册页
model.addAttribute("errorData", errorData);
return "forward:http://auth.gulimall.com/reg.html";
}
}
}
对于/reg.html
和/login.html
请求我使用的是视图映射方式来接受请求并返回结果,具体如下:
@Configuration
public class GulimallWebConfig implements WebMvcConfigurer {
/**
* 视图映射
* @param registry
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
/**
* @GetMapping("/login.html")
* public String loginPage() {
* return "login";
* }
* 下面的这种做法,可以代替上面的空方法,这样配置更简单一点,访问的的时候需要使用GET请求方式
*/
registry.addViewController("/login.html").setViewName("login");
registry.addViewController("/reg.html").setViewName("reg");
}
}
首先说一下浏览器地址栏url问题,无论注册成功还是失败,浏览器地址栏的url都是http://auth.gulimall.com/register
,所以这种方式不会改变浏览器地址栏的url,只不过浏览器网页中展示页面内容是reg.html
h或者login.html
,因此这就直接pass了这种做法,毕竟谁也不想注册成功之后刷新网页就再次发起注册请求了;
其次我们请求http://auth.gulimall.com/register
的时候使用POST
请求方式,而请求/reg.html
和/login.html
页面都需要使用GET
请求方式,因此使用请求转发的时候还会沿用之前的请求方法,那就会出现请求方式不对应的错误,所以直接pass了这种做法;
最后说一下错误信息展示问题,使用这种做法可以正确显示错误信息,Model是可以使用的
3、使用redirect重定向
比如我使用的是thymeleaf模板,代码如下:
@Controller
public class RegisterController {
@PostMapping("/register")
public String register(UserRegisterVo userRegisterVo, RedirectAttributes attributes) {
……………………………………
if(注册成功){
// 注册成功,会到登录页
return "redirect:http://auth.gulimall.com/login.html";
} else {
// 注册失败,会到注册页,注意使用的是addFlashAttribute()方法
attributes.addFlashAttribute("errorData", errorData);
return "redirect:http://auth.gulimall.com/reg.html";
}
}
}
对于/reg.html
和/login.html
请求我使用的是视图映射方式来接受请求并返回结果,具体如下:
@Configuration
public class GulimallWebConfig implements WebMvcConfigurer {
/**
* 视图映射
* @param registry
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
/**
* @GetMapping("/login.html")
* public String loginPage() {
* return "login";
* }
* 下面的这种做法,可以代替上面的空方法,这样配置更简单一点,访问的的时候需要使用GET请求方式
*/
registry.addViewController("/login.html").setViewName("login");
registry.addViewController("/reg.html").setViewName("reg");
}
}
首先说一下请求方式问题,当我们使用return "redirect:http://auth.gulimall.com/XXX.html"
进行重定向的时候依然会采用GET请求,毕竟浏览器地址栏发起的请求只能是GET请求,因此请求方式一致,不存在问题
然后说一下错误信息展示问题,假设注册失败,可以通过RedirectAttributes 把错误信息带过去,但是刷新页面之后错误信息就会消失,毕竟我们刷新页面会导致请求域中的错误信息对象消失,虽然只会展示一次错误信息,那也够了,可以选择使用这种方式
上面代码中我们使用的是attributes.addFlashAttribute("errorData", errorData)
,也就是使用addFlashAttribute()
方法,该方法可以模拟session往请求域中放置数据,然后我们在模板页面中可以像从session中取出数据一样使用;另外还可以使用addAttribute()
方法,该方法相当于把参数放在了重定向地址后面,我们在总结中的第3条
也使用例子进行了说明