前言
本节我们要学习的就是如何接收页面的参数、如何传递参数到页面以及页面跳转的问题,如果说之前学习过Servlet就会发现SpringMVC的参数传递实现会简单的多,就好比自己烧火做饭和去外面吃豪华自助做对比的赶脚
那么我们就开始本节的内容吧~
SpringMVC的参数传递
大家还记得在Servelt中的参数传递吗?我们通过request.getParameter()的方式获取来自页面的值,但是这种方式在SpringMVC中行的通吗?我们之前在控制器中写的方法都是自定义的,该怎么获取到request对象呢?
我们这边还是借用一个登录的案例来展示如何获取页面上的参数以及将参数传递到页面上去
在此之前呢,我们来解决一个之前遗留下来的"问题"。
之前在Contoller中我想获取UserService对象不是这么获取吗?
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserService userService = context.getBean(UserService.class)
en…这种方式实在是太low了,但是想演示出效果来确实也没办法,那么我们这里提前拓展一个小知识,关于Spring的监听器的配置
在配置监听器之前,我们直接在Controller中对UserService对象加上自动装配注解@Autowired是没有效果的,
原因是我们的数据源的配置,包括UserService的扫描操作都是在applicationContext.xml中的,那么但是controller层的扫描是在springmvc.xml中的,因此如何把两个文件关联起来是个问题
还记得我们之前在web.xml中对DispatcherServlet的配置吗?
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 注入核心配置文件的地址 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:springmvc.xml</param-value>
</init-param>
<!-- 服务器加载时就创建对象 -->
<load-on-startup>1</load-on-startup>
</servlet>
DispatcherServlet是在tomcat一启动的时候加载web.xml就生成的,那么我们想想,applicationContext这个Spring的巨型容器对象,是不是也应该在服务器启动的时候就生成的?
因此,我们在listener中对applicationContext进行配置,目的就是为了让它在服务器启动的时候就加载进来
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
大家按照上面形式配置就可以了,记得一定一定要在各自的文件(如application-service.xml和springmvc.xml)中对当前的MVC层的类(如service和controller)进行扫描(使用context:component-scan标签)!否则也会执行失败!
基本数据类型参数绑定
那做了这么多的铺垫工作,就回归到我们的正题啦,先看栗子,先来个复古的登录页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>LoginInterface</title>
</head>
<body>
<h2 align="left" >Login</h2>
<hr>
<form action="login.action">
User Name:<input type="text" name="userName"/><br>
Password: <input type="password" name="password"/><br>
<input type="submit" value="Submit"/>
</form>
</body>
</html>
接下来就是我们Controller层的代码
package com.marco.servlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.marco.domain.User;
import com.marco.service.UserService;
@Controller
public class LoginController{
@Autowired
UserService userService;
@RequestMapping("login")
public ModelAndView login(String userName, String password) throws Exception {
User user = userService.login(userName, password);
ModelAndView modelAndView = new ModelAndView();
if(user!= null) {
modelAndView.setViewName("/update.jsp");
modelAndView.addObject("user", user);
modelAndView.setStatus(HttpStatus.OK);
return modelAndView;
}
return modelAndView;
}
}
看了上面的代码有没有觉得很简单?一看就懂,唯一需要我们注意一点就是表单里面name属性值必须和Controller里面的形式参数名保持一致。
那有的朋友会说,我就是不想保持一致!那怎么搞?我的userName就想写成"我是马云",你能取到值么?
好,看我的骚操作
我这边在Controller中打印页面上传过来的userName,看看测试结果
完全没有问题!@RequestParam()注解可以解决表单的name属性值和形式参数名不一致的问题,但是如果不是特立独行,但是保持一致的比较好哦
数组集合参数绑定
接下来把页面上的内容换一下,看看我们能不能用数组接收数据
<form action="hobby.action">
用户爱好: <input type="checkbox" name="hobby" value="LOL"/> 撸啊撸
<input type="checkbox" name="hobby" value="HOK"/> 王者农药
<input type="checkbox" name="hobby" value="DNF"/> 地下城
<input type="submit" value="Submit"/>
</form>
@RequestMapping("hobby")
public String hobby(String[] hobby) throws Exception {
System.out.println("###@##########################");
System.out.println(Arrays.toString(hobby));
return "main.jsp";
}
我这边全选checkbox,测试结果如下,没得问题吧~
那么我们试试能不能用集合来接收呢?我这里以List为栗子
@RequestMapping("hobby")
public String hobby(List<String> hobby) throws Exception {
System.out.println("###@##########################");
System.out.println(hobby);
return "main.jsp";
}
出现异常了?异常显示的是不能不能实例化instantiate,因为List是一个接口?
其实当我们把List换成ArrayList之后,程序并不会报错,但是获取不到外部的值,因此我们得出结论我们只能使用数组来接收View层传过来的值,而不能使用集合
对象参数绑定
这个方式就比较牛掰了,还是以登录为案例,请看下面的代码,直接使用User能接受的到不?
@RequestMapping("login")
public ModelAndView login(User user) throws Exception {
System.out.println("###@##########################");
System.out.println(user);
User currentUser = userService.login(user.getUserName(), user.getPassword());
ModelAndView modelAndView = new ModelAndView();
if(user!= null) {
modelAndView.setViewName("/update.jsp");
modelAndView.addObject("user", currentUser);
modelAndView.setStatus(HttpStatus.OK);
}
return modelAndView;
}
答案是肯定的,这个机制真的非常好用有没有?比方说我们要修改一个用户的信息,我们一般调用Service层的方法传入的参数就是user对象,那么这样的话,根本就不需要再将页面上的参数组装成user对象之后传过去了~
SpringMVC的跳转方式
在Servlet和struts里面有两种跳转方法
- 请求转发 【项目内部,一次请求一次响应】
- 请求重定向【可以转发到外部的项目,两次请求两次响应】
那前几次案例中大家都发现了,我们的跳转方式都是请求内部转发的方式,这个是SpringMVC默认的转发方式,那么如果我想使用重定向的跳转方式该怎么写呢?
还记得我们上面使用SpringMVC的内部转发时,是这么写的
@RequestMapping("login")
public ModelAndView login(String userName, String password) throws Exception {
User user = userService.login(userName, password);
ModelAndView modelAndView = new ModelAndView();
if(user!= null) {
modelAndView.setViewName("/update.jsp");
modelAndView.addObject("user", user);
modelAndView.setStatus(HttpStatus.OK);
return modelAndView;
}
return modelAndView;
}
如果要改成请求转发,那么只需要将modelAndView中的setViewName的信息稍微修改成下面这样就可以了
modelAndView.setViewName("redirect:../update.jsp");
或者直接通过构造器的方式
return new ModelAndView("redirect:../update.jsp");
springmvc视图解析器的配置
这里我们补充一个小知识点,就是关于springmvc视图解析器的配置
为什么需要配置这个呢?因为我们实际开发中,.jsp
文件是不会直接放在WebRoot下面的,而是会专门建一个文件夹来存放,比方说我们的view文件夹(之前的销售合同项目中也是这么存放的),但是这样就会存在一个问题,就是我们无法通过xxx.jsp直接访问到这个jsp页面,那么一般情况下,我们会使用/WEB-INF/view/list.jsp的方式来访问。
但是每次都这么写很麻烦,因此配置好InternalResourceViewResolver视图解析器之后,只要是被DispatcherServlet放行之后的内部.jsp页面的跳转就变得非常简单了!
<!-- 配置前视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 注入前后缀 -->
<property name="prefix" value="/WEB-INF/view/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
比方说之前跳转页面的路径是/WEB-INF/view/login.jsp
,那么加了视图解析器之后,我们只需要写login
就可以了,是不是很方便呢?
其实查看源码也不难发现,我们的视图解析器在内部对你请求的地址加以"装饰",随后再返回给我们的DispatcherServlet处理。