SpringMVC - 响应

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

1. 返回字符串

Controller方法返回字符串可以指定逻辑视图的名称,根据视图解析器为物理视图的地址

1.1 使用场景1 跳转到某个功能主页

通常的使用是在当前查找数据存储到Model中,也就是存储到Request域中,然后在跳转到的页面中取出使用

@Controller 
@RequestMapping("/user") 
public class UserController {        
	/**     
 	 * 请求参数的绑定     
 	*/    
	@RequestMapping(value="/initUpdate")    
	public String initUpdate(Model model) {        
		// 模拟从数据库中查询的数据        
		User user = new User();        
		user.setUsername("张三");        
		user.setPassword("123");        
		user.setMoney(100d);        
		user.setBirthday(new Date());        
		model.addAttribute("user", user);        
		return "update";    
	}    
}
 
    <h3>修改用户</h3>    
    ${ requestScope }    
    <form action="user/update" method="post">        
    	姓名:<input type="text" name="username" value="${ user.username }"><br>        
    	密码:<input type="text" name="password" value="${ user.password }"><br>        
    	金额:<input type="text" name="money" value="${ user.money }"><br>        
    	<input type="submit" value="提交">
    </form>

注意我们在 springmvc.xml 中已经配置了视图名的前缀和后缀,所以前端控制器实际上获得的视图名为 prefix配置的值+ returnStr(方法返回值)+ suffix配置的值,即/WEB-INF/update.jsp,所以页面最终会跳转到网站根目录下的 update.jsp

<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<!-- 配置视图名的默认前缀 -->
	<property name="prefix" value="/WEB-INF/"></property>
	<!-- 配置视图名的默认后缀 -->
	<property name="suffix" value=".jsp"></property>
</bean>

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

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

1.2 使用场景2 转发和重定向

String 类型的返回值除了返回一个可以被视图解析器解析的视图名以外,还可以返回 含有 redirect 或 forward 标签的字符串,我们使用它在登录成功的时候重定向到主页面,登录失败的时候转发回登录页面

@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

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

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

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

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

2. 返回值是void

  • 如果控制器的方法返回值编写成void,默认会跳转到页面名为当前请求的value的页面,如果默认查找的JSP页面没有找到,执行程序报404的异常
@RequestMapping(value="/initUpdate") ---> initUpdate
  • 可以使用请求转发或者重定向跳转到指定的页面
public void test(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	// 转发到指定页面
	request.getRequestDispatcher("xxx").forward(request, response);
	// 或者重定向到指定页面
	response.sendRedirect("/xxx");
}

请求转发和重定向的路径的写法

  • 请求转发:是一次请求,不用再编写项目的路径,但是不再执行视图解析器
  • 重定向:两次请求

3. ModelAndView

ModelAndView对象是Spring提供的一个对象,可以用来调整具体的JSP视图,可以携带数据,也是存在request域中

@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;
	}
}

4. Model和ModelAndView

Model、ModelMap和ModelAndView的使用详解
控制器Controller执行业务逻辑,用于产生模型数据Model,而视图View用于渲染模型数据。
使用Model和ModelAndView这两个类在spring的视图解析时作用以及区别。

这两者之间有着很大的区别,具体就表现在Model只是用来传输数据的,并不会进行业务的寻址。ModelAndView 却是可以进行业务寻址的,就是设置对应的要请求的静态文件,这里的静态文件指的是类似jsp的文件。

其次,两者还有一个最大的区别,那就是Model是每一次请求可以自动创建,但是ModelAndView 是需要我们自己去new的。

Model:
Model是包含四个addAttribute 和一个 merAttribute方法的接口,其实现类为ExtendedModelMap,继承了ModelMap类
在这里插入图片描述
ModelMap:
实现了Map接口,包含Map方法。视图层通过request找到ModelMap中的数据

Model 和 ModelMap 的实例都是spirng mvc框架来自动创建并作为控制器方法参数传入,用户无需自己创建

而且需要return 返回指定的页面路径

public String toProvinceView(Model model, HttpSession session,) {
 	model.addAttribute("colModel", colModel);
	model.addAttribute("colNames", colNames);
	model.addAttribute("buttonName", buttonName);
	return "statistic/StatisticChart";
}

ModelAndView:
是包含ModelMap 和视图对象的容器。正如名字暗示的一样既包含模型也包含视图,而ModelMap只是包含模型的信息

Model是每一次请求可以自动创建,但是ModelAndView 是需要我们自己去new的

public class CarListController implements Controller {
 
	public ModelAndView handleRequest(HttpServletRequest arg0,
			HttpServletResponse arg1) throws Exception {
 
		CarManager carManager = new CarManager();
 
		ModelAndView modelAndView = new ModelAndView("carList");
		modelAndView.addObject("carList", carManager.getCarList());
 
		return modelAndView;
	}
}
发布了167 篇原创文章 · 获赞 3 · 访问量 5411

猜你喜欢

转载自blog.csdn.net/weixin_43907800/article/details/104856715