SpringMVC的Controller中常用的三种返回值类型

SpringMVC 通过注解实现的 Controller 常用的返回值类型主要有三种:返回字符串,返回 ModelAndView,返回 void。

先看一下项目的目录结构:
SpringMVC的Controller中常用的三种返回值类型_第1张图片

再看一下 springmvc.xml配置文件的内容:


<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
    	http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
    	http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
    	http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
    	http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">
	
	
	<context:component-scan base-package="com.lyu.qjl.interview.controller" />

	 
	<mvc:annotation-driven />
	
	
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		
		<property name="prefix" value="/">property>
		
		<property name="suffix" value=".jsp">property>
	bean>
	
beans>

返回字符串

应用场景1:直接返回视图名称,例如跳转到某个功能主页。

下面的 Controller 是用来处理用户页面的请求,gotoUserEdit 方法是用来处理跳转到用户编辑页面的请求。

package com.lyu.qjl.interview.controller;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.lyu.qjl.interview.entity.User;
import com.lyu.qjl.interview.vo.UserVO;

/**
 * 类名称:处理用户请求的handler
 * 全限定性类名: com.lyu.qjl.interview.controller.UserController
 * @author 曲健磊
 * @date 2018年5月21日下午7:24:07
 * @version V1.0
 */
@Controller
public class UserController{
	
	/**
	 * 跳转到编辑用户页面
	 * @return
	 */
	@RequestMapping("/gotoUserEdit")
	public String gotoUserEdit() {
		return "userEdit";
	}
	
}

这个 gotoUserEdit 方法匹配 /gotoUserEdit 请求。返回值为一个 userEdit字符串,表示的是一个视图名,但是由于我们在 springmvc.xml 中已经配置了视图名的前缀和后缀,所以前端控制器实际上获得的视图名为 prefix配置的值+ returnStr(方法返回值)+ suffix配置的值,即 /userEdit.jsp,所以页面最终会跳转到网站根目录下的 userEdit.jsp。

**Question:**我想访问某个页面我直接去输入这个页面的地址 /userEdit.jsp 不就可以了吗,为什么还要先去请求 SpringMVC,再由它返回?

**Answer:**对于 WebContent 这一层目录下面的页面,用户如果知道某个 jsp 页面可以直接访问。但是,通常情况下为了保证页面的安全,我们一般的做法是在 WebContent 这一层目录下只留一个引导页面(index.jsp)作为跳转,把网站相关的页面放入 WEB-INF文件夹下保护起来。因为放在 WEB-INF文件夹下的页面没有办法通过地址栏直接访问,只能通过后台的跳转来间接的访问,所以就需要请求 SpingMVC 来返回相应的页面。

实际应用中的 web 页面的目录结构:
SpringMVC的Controller中常用的三种返回值类型_第2张图片

注:login.jsp, main.jsp, userEdit.jsp, userList.jsp, userMain.jsp 都是放在 WEB-INF 这层目录下的,只有 index.jsp 是放在 WebContext 这一层下的。

测试:直接访问 WEB-INF 文件夹下的 login.jsp 页面的结果如下:
SpringMVC的Controller中常用的三种返回值类型_第3张图片

这样我们就没有办法直接从地址栏去访问 WEB-INF 下的 login.jsp 页面了,只能通过 SpringMVC 来进行页面的跳转了。

这里还需要注意一点:由于页面已经放到了 WEB-INF 目录下,所以 springmvc.xml 配置文件中的视图解析器中的前缀也要对应的有所改动:


<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
    	http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
    	http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
    	http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
    	http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">
	...
	
	
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		
		<property name="prefix" value="/WEB-INF/">property>
		
		<property name="suffix" value=".jsp">property>
	bean>
	
beans>

扩展:

大家注意到那个放在 WebContent 那一层目录下的 index.jsp 页面了吗?它在实际应用中有什么作用呢?

它一般配置为项目的欢迎页面,即 web.xml 中的 welcome-file。当我们在地址栏输入 localhost:8080/interview 的时候,首先就会访问该页面,然后由该页面向后台发请求,通过后台的 Controller 跳转到被 WEB-INF 文件夹保护起来的登录页面 login.jsp,最后,展现在我们面前的就是一个登录页面。
SpringMVC的Controller中常用的三种返回值类型_第4张图片
index.jsp 中的内容如下:

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%
// 转发一个 "/login" 请求给后台的 Controller,由 Controller 返回 WEB-INF 目录下的 login.jsp 页面
request.getRequestDispatcher("/login").forward(request, response);
%>

应用场景2:在登录成功的时候重定向到主页面,登录失败的时候转发回登录页面

String 类型的返回值除了返回一个可以被视图解析器解析的视图名以外,还可以返回 含有 redirect 或 forward 标签的字符串,如下:

package com.lyu.qjl.interview.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * 类名称:用于处理登录请求的处理器
 * 全限定性类名: com.lyu.qjl.interview.controller.LoginController
 * @author 曲健磊
 * @date 2018年5月21日下午7:02:03
 * @version V1.0
 */
@Controller
public class LoginController{
	
	@RequestMapping("/loginUser")
	public String login(String username, String password, Model model) throws Exception {
		if (username != null && password != null) {
			if ("admin".equals(username) && "123".equals(password)) {
				// 登录成功,重定向到主页面
				return "redirect:/main";
			} else {
				// 向 request 域中设置错误提示信息
				model.addAttribute("loginFlag", "用户名或密码错误");
				// 登录失败,转发到登录页面
				return "forward:/login";
			}
		} else {
			// 只是把模型放到request域里面,并没有真正的安排好
			model.addAttribute("loginFlag", "用户名或密码错误");
			// 登录失败,转发到登录页面
			return "forward:/login";
		}
	}
	
	@RequestMapping("/login")
	// 对外部提供接口的时候需要指定某些参数
	public String login() {
		return "login";
	}
	
	@RequestMapping("/main")
	public String main() {
		return "main";
	}
}

redirect:/main表示这是一个重定向到 /main 的请求, forward:/login表示这是一个转发到 /login 的请求。

注意:如果在返回的字符串前加上了 redirect 或者 forward 标签,就不会走视图解析器,而是直接转发或重定向到指定的路径,所以对于重定向标签后面就不能加 WEB-INF ,因为重定向是客户端重新发送的请求,WEB-INF 目录下的页面仍然访问不到,但是对于转发标签的话后面可以跟 WEB-INF。

以上就是 Controller 的返回值为 String 时的另一种常见用途。

**Question:**为什么登录成功需要重定向到主页面?

**Answer:**因为转发客户端只发送了一次请求,如果登录成功转发到主页面的话,浏览器的地址栏中的 url 保留的是提交表单的请求,此时如果按 F5 刷新,就会造成二次提交表单,增大服务端的压力不说,还影响用户的体验,所以登录成功时要重定向到主页面,这样浏览器的地址栏保留的就是当前主页面的 url,无论怎么刷新都没事。
SpringMVC的Controller中常用的三种返回值类型_第5张图片

**Question:**为什么登录失败需要转发回登录页面?

**Answer:**用户登录失败,我们需要给用户提供相应的提示信息,如:“用户名密码不匹配”。如果重定向到登录页面,用户就没有办法获取到服务端设置在 request 域里面的错误提示信息,因为重定向的本质是客户端发送了两次请求,在第二次请求里面获取不到第一次请求中的数据,所以没有办法给用户相应的提示信息。而转发只发送了一次请求,转发回登录页面的时候可以获取到请求中的数据,所以登录失败时需要转发会登录页面。
SpringMVC的Controller中常用的三种返回值类型_第6张图片

返回ModelAndView

应用场景:其实这种返回值的应用场景比较随意,既可以用来做页面的跳转,也可以在跳转到页面的时候携带一些数据,例如:查询用户列表。

package com.lyu.qjl.interview.controller;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.lyu.qjl.interview.entity.User;
import com.lyu.qjl.interview.vo.UserVO;

/**
 * 类名称:处理用户请求的handler
 * 全限定性类名: com.lyu.qjl.interview.controller.UserController
 * @author 曲健磊
 * @date 2018年5月21日下午7:24:07
 * @version V1.0
 */
@Controller
public class UserController{

	@RequestMapping("/getUserList")
	public ModelAndView getUserList() {
		System.out.println("进入getUseList");
		ModelAndView modelAndView = new ModelAndView();
		
		List<User> userList = new ArrayList<User>();
		User user1 = new User("arry", 18, "男");
		user1.setUserId(1L);
		User user2 = new User("cc", 28, "女");
		user2.setUserId(2L);
		User user3 = new User("dd", 38, "男");
		user3.setUserId(3L);
		userList.add(user1);
		userList.add(user2);
		userList.add(user3);
		
		// 将数据放入modelAndView对象
		modelAndView.addObject("userList", userList);
		
		// 将返回的逻辑视图名称放入modelAndView对象
		modelAndView.setViewName("userList");
		
		return modelAndView;
	}
}

如果想在跳转到某个页面的时候携带一些数据,调用 ModelAndView 对象的 addObject 方法设置一些属性即可,不想带数据也可以不设置,但是必须得设置视图名 setViewName ,要不然它哪知道返回到哪个页面去呢?

返回void

如果是返回 void 会,就必须要在方法的参数中添加 HttpServletRequest 和 HttpServletResponse 来进行页面的跳转,代码如下:

public void test(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	// 转发到指定页面
	request.getRequestDispatcher("xxx").forward(request, response);
	// 或者重定向到指定页面
	response.sendRedirect("/xxx");
}

其实,从本质上来说前面两种方法(String,ModelAndView)就是间接调用的 request 和 response 这个两个对象来进行页面的跳转,以及数据的存储。

稍微的总结一下,这篇文章主要讲了 SpringMVC 的 Controller 的三种返回值类型:String,ModelAndView,void。在讲 String 的时候扩展了一些 redirect 和 forward 标签,提了一下在实际应用中转发和重定向的用处,以及实际项目中需要把页面放入 WEB-INF 目录里保护起来。ModelAndView 可以携带数据也可以不携带数据,以及前两种方法本质上都是在操作 request 和 response 对象。希望文章对大家能有所帮助。

关注我的微信公众号(曲健磊的个人随笔),观看更多精彩内容:
SpringMVC的Controller中常用的三种返回值类型_第7张图片

你可能感兴趣的:(springMVC,controller,返回值类型,【springMVC】,SpringMVC小记)