SpringMVC入门

SpringMVC框架概述

1)一种轻量级的、基于MVC的Web层应用框架。偏前端而不是基于业务逻辑层。Spring框架的一个后续产品。
2)Spring 为展现层提供的基于 MVC 设计理念的优秀的 Web 框架,是目前最主流的 MVC 框架之一
3)Spring MVC 通过一套 MVC 注解,让 POJO 成为处理请求的控制器,而无须实现任何接口

  1. SpringMVC处理请求过程及RequestMapping映射请求注解的说明

(1) SpringMVC处理请求过程:

<a href="${pageContext.request.contextPath }/QingQiu">HELLO SPRINGMVC</a>

当点击HELLO SPRINGMVC超链接,向服务器发送/QingQiu这个请求,首先到web.xml中查找映射,如果在web.xml中配置如下:

<!-- 将url-pattern标签的值设置为 / -->
		<url-pattern>/</url-pattern>

其中url-pattern标签的值设置为/的话,/代表的意思就是处理除JSP页面以外其他所有的请求,意味着:除jsp页面外所有请求都交由前端控制器DispatcherServlet处理,而jsp页面的请求还是由Tomcat服务器来处理。

接着,前端控制器DispatcherServlet进行分析判断,去寻找控制器来处理刚才提交的非JSP页面请求QingQiu

/*
处理请求的方法及其类
*/
@Controller	// 标识当前类是一个控制器(处理器)
public class HelloWorldController {
	
	@RequestMapping("/QingQiu")
	public String helloWorld() {
		System.out.println("Hello SpringMVC!");
		return "success";
	}
	
}

首先前端控制器会检索有标记有@Controller的类,在标记有@Controller的类中寻找映射有请求字样的方法@RequestMapping("/QingQiu")。注:@Controller标记的类在服务器中,搜索的时候直接在服务器中检索,所以/QingQiu这个地址是由服务器来解析的
然后方法的返回值交由SpringMVC配置文件中视图解析器解析为一个真实的物理视图,拼接的地址为:前缀 + 控制器中处理请求的方法的返回值 + 后缀,然后自动进行请求的转发

如下为SpringMVC配置文件中视图解析器配置的代码片段:

	<!-- 设置视图解析器 -->
	<!-- 视图解析器 拼接:
		前缀 + 控制器中处理请求的方法的返回值 + 后缀
		然后进行自动的转发
	 -->
	<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<!-- 配置前缀 -->
		<property name="prefix" value="/WEB-INF/pages/"></property>
		<!-- 配置后缀 -->
		<property name="suffix" value=".jsp"></property>
	</bean>

因此,SpringMVC处理请求简单过程可以描述为:

客户端发送请求 ----> 然后核心控制器(DispatcherServlet)进行拦截,拦截之后到业务控制器(@Controller)中去寻找映射(@RequestMapping(value="")),找到对应的映射方法后,该映射方法处理请求,返回一个返回值("success"),然后视图解析器进行 前缀 + 返回值 + 后缀的拼接,然后自动进行请求的转发。

(2) 对于@ResquestMapping映射请求注解的说明

1)SpringMVC使用@RequestMapping注解为控制器指定可以处理哪些 URL 请求
2)作用:DispatcherServlet 截获请求后,就通过控制器上 @RequestMapping 提供的映射信息确定请求所对应的处理方法。

1. @RequestMapping 可标注的位置:

可以标注在之前,方法前面,比如:

/*
处理请求的方法及其类
*/
@RequestMapping("/Lei")
@Controller	// 标识当前类是一个控制器(处理器)
public class HelloWorldController {
	
	@RequestMapping("/QingQiu")
	public String helloWorld() {
		System.out.println("Hello SpringMVC!");
		return "success";
	}
	
}

那么这个方法就可以处理浏览器发送的/Lei/QingQiu请求。

2. @RequestMapping 的属性

@RequestMapping中共有6个属性,分别为:value(),method(),params(),headers(),consumers(),produces()。

1. value属性

其中,value 属性用来设置要映射的请求地址,它的底层类型是一个String类型的数组,那么如果这样写:

@RequestMapping({"/QingQiu1","/QingQiu2"}
public String test(){
	
	return "test";

}

那么这意味着这个方法可以处理/QingQiu1/QingQiu2这两个请求。当然了,如果只映射一个请求地址,那么大括号可以省略不写,而且如果@RequestMapping中只有value属性的话,那么value属性名可以不写。

2. method属性

method属性用来设置要映射的请求方式(get或post等),如果没有指定该属性,那么处理请求时,只考虑请求地址,不考虑请求方式,即:没有指定method属性值时,get和post请求都可以处理。

2.处理请求数据

请求处理方法签名:
1)Spring MVC 通过分析处理方法的签名,将HTTP请求信息绑定到处理方法的相应入参中。
2)Spring MVC 对控制器处理方法签名的限制是很宽松的,几乎可以按喜欢的任何方式对方法进行签名。
如何才能将浏览器端传入的请求参数传入我们的方法中呢?
SpringMVC中有3种可以处理请求数据的方式,分别是 @RequestParam注解、使用POJO作为参数使用Servlet原生API作为参数。下面来分别进行介绍。

1. 使用@RequestParam注解

@RequestParam 的属性

@RequestParam中共有3个属性,分别为:value,required,defaultValue。

其中value为请求参数的参数名,该注解添加在需要获取的参数的前面,同样地,如果注解@RequestParam中只有一个value属性时,value=可以省略,具体代码如下:
浏览器发送请求代码片段:

<a href="${pageContext.request.contextPath }/requestparam?username=admin&age=19">测试requestparam属性</a><br>

java处理请求的方法代码:

@RequestMapping("/requestparam")
	public String test3(@RequestParam("username") String user,Integer age) {
		System.out.println(user);
		System.out.println(age);
		return SUCCESS;
	}

但是,如果在处理请求的方法的入参处,参数前面如果加上了注解@RequestParam,那么浏览器必须在请求时候设有请求参数。如果想要在浏览器端不设置也不报错的话,可以通过更改注解@RequestParam中另一个属性required,将其值设为false即可,其默认值为true。如:@RequestParam(value="username",required=false)

如果我们将处理请求的方法中的java代码的入参age类型改为int,代码如下:

@RequestMapping("/requestparam")
	public String test3(@RequestParam("username") String user,@RequestParam(value="age",required=false) int age) {
		System.out.println(user);
		System.out.println(age);
		return SUCCESS;
	}

这个时候,如果浏览器未传入age参数的话,那么就会报错,这时候为避免报错,就需要@RequestParam中的第3个属性:defaultValue。
defaultValue属性:设置一个默认值,如果没传该请求参数就使用该值。
那么上述方法可以改为:

@RequestMapping("/requestparam")
	public String test3(@RequestParam("username") String user,@RequestParam(value="age",required=false,defaultValue="0") int age) {
		System.out.println(user);
		System.out.println(age);
		return SUCCESS;
	}

2. 使用POJO作为参数

通过上述的方法可以指定到具体的请求参数的传入情况,那么问题来了,如果参数众多的话,比如一个form表单中有很多填写的input的请求,每一个请求都是一个参数,如果要是一个参数一个参数设置的话,可能得吐血,这个时候怎么操作呢?对的,我们可以通过传入包含有请求参数的对象来完成请求参数的传递。这就是所谓的使用POJO作为参数传递。

那么何为POJO?
POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBeans。

1)使用 POJO 对象绑定请求参数值
2)Spring MVC 会按请求参数名和 POJO 属性名进行自动匹配,自动为该对象填充属性值。支持级联属性。如:dept.deptId、dept.address.tel 等。如:
表单代码片段:

	<form action="${pageContext.request.contextPath }/testPOJO" method="post">
		员工编号:<input type="text" name="id"><br>
		员工姓名:<input type="text" name="lastName"><br>
		员工邮箱:<input type="text" name="email"><br>
		员工部门id:<input type="text" name="dept.id"><br>
		员工部门名称:<input type="text" name="dept.name"><br>
		<input type="submit">
	</form>

使用POJO做为入参的处理请求的方法的java代码如下:

	@RequestMapping("/testPOJO")
	public String test4(Employee emp) {
		System.out.println(emp);
		return SUCCESS;
	}

要注意的是,Spring会帮我们造好对象,就不用我们自己创建了,那么它是如何对表单中的数据和对象属性之间进行匹配而创建的对象呢?这里,它通过表单中设置的name的名称,然后去匹配对应的set方法来为新创建的对象的属性赋值,所以,表单中的name的名称一定要写成实体对象的属性名,不然Spring匹配不到对应的set方法,从而出现空值。
当然了,它也支持给级联属性赋值,即实体类中的一个属性是另一个类,它可以实体类这个属性的属性赋值,具体如上面代码段中,通过属性.属性的方式进行表示。

3. 使用Servlet原生API作为参数

在SpringMVC控制器方法里面,可以直接传的原生ServletAPI参数有如下9种:
MVC 的 Handler 方法可以接受哪些 ServletAPI 类型的参数
1) ★HttpServletRequest
2) ★HttpServletResponse
3) ★HttpSession
4) java.security.Principal
5) Locale
6) InputStream
7) OutputStream
8) Reader
9) Write

其中,通过前3个可以得到后6个。

例如表单提交代码片段:

	<form action="${pageContext.request.contextPath }/testServletAPI" method="post">
		用户名:<input type="text" name="adminname"><br>
		密码:<input type="text" name="userpswd"><br>
		<input type="submit">
	</form>

通过原生的ServletAPI参数处理的控制器方法的java代码如下:

	@RequestMapping("/testServletAPI")
	public String test5(HttpServletRequest request, HttpServletResponse response) {
		String username = request.getParameter("adminname");
		String password = request.getParameter("userpswd");
		System.out.println(username);
		System.out.println(password);
		return SUCCESS;
	}

通过测试,后台可以拿到前端通过表单发送的请求参数。

SpringMVC处理响应数据

SpringMVC处理响应数据共有两种方式,分别为ModelAndViewMap及Model,其中:
1)ModelAndView: 处理方法返回值类型为 ModelAndView 时, 方法体即可通过该对象添加模型数据
2)Map 及 Model: 入参为 org.springframework.ui.Model、
org.springframework.ui.ModelMap 或 java.uti.Map 时,处理方法返回时,Map 中的数据会自动添加到模型中。
下面对两种情况分别进行介绍。

处理响应数据方式1之 ModelAndView(方法的返回值设置为ModelAndView)

该途径是通过将处理请求的方法的返回值类型设置为ModelAndView,其1)既包含视图信息,也包含模型
数据信息。那么如何向ModelAndView中添加视图信息和模型数据信息呢?通过下面方法分别可以完成对模型数据的添加和视图的设置。
添加模型数据:

MoelAndView addObject(String attributeName, Object attributeValue)
ModelAndView addAllObject(Map<String, ?> modelMap)

设置视图:

void setView(View view)
void setViewName(String viewName)

通过设置ModelAndView为返回值类型的处理请求的方法大致可以分为5步:
1.创建ModelAndView对象
2.通过controler调用Service然后调用Dao连接数据库,查询到数据
3.将拿到的员工数据放到ModelAndView对象中
4.设置视图名,处理完请求后,跳转到该页面
5.返回ModelAndView对象

网页的查询页面的代码片段:

	<a href="${pageContext.request.contextPath }/testModelAndView">查询员工信息</a><br>

具体java代码实现为:

@RequestMapping("/testModelAndView")
	public ModelAndView test6() {
		//1.创建ModelAndView对象
		ModelAndView mv = new ModelAndView();
		//2.通过controler调用Service然后调用Dao连接数据库,查询到数据
		//这里假设拿到了从数据库中查询到的数据
		Employee employee = new Employee(9527, "孙悟空", "xitianqujing@xiyou.com", new Department(1001, "散打部"));
		//3.将拿到的员工数据放到ModelAndView对象中
		mv.addObject("emp", employee);
		//4.设置视图名,处理完请求后,跳转到该页面
		mv.setViewName(SUCCESS);
		//5.返回ModelAndView对象
		return mv;
		
	}

跳转成功页面的代码片段:

<body>
	<h1>这是一个跳转成功页面</h1><br>
	
	<h2>员工信息为:${requestScope.emp }</h2><br>
</body>

可以从网页中看到已经拿到了后台响应的数据,那么问题来了,ModelAndView对象将数据放在了哪个域呢?我们可以用session域测试一下,当然测试结果是session域中没有拿到后台的响应数据,因此ModelAndView对象是将响应数据放到了request域中。测试代码片段如下:

<body>
	<h1>这是一个跳转成功页面</h1><br>
	
	<h2>员工信息为:${requestScope.emp }</h2><br>
	<h2>session员工信息为:${sessionScope.emp }</h2>
</body>

对应的返回的结果是:

员工信息为:Employee [id=9527, lastName=孙悟空, email=xitianqujing@xiyou.com, dept=Department [id=1001, name=散打部]]

session员工信息为:

可以看到返回的session员工信息为空,并未取到,佐证了后台确实将响应数据放到了request域中。通过查看源码,确实是通过request放置的信息。

处理响应数据方式2之Map 、Model(方法的返回值仍为String,入参中传入MAP、Model或ModelMap)

1)Spring MVC 在内部使用了一个 org.springframework.ui.Model 接口存储模型数据
具体使用步骤
2)Spring MVC 在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器。
3)如果方法的入参为 Map 或 Model 类型,Spring MVC 会将隐含模型的引用传递给这些入参。
4)在方法体内,开发者可以通过这个入参对象访问到模型中的所有数据,也可以向模型中添加新的属性数据

特点:不管是将方法的返回值设置为ModelAndView,还是在方法入参中传入MapMAP、Model或ModelMap,SpringMVC都会转换为ModelAndView对象。*

处理方法的java代码:

@RequestMapping("/testMap")
	public String test7(Map<String, Object> map) {
		// 1.通过controler调用Service然后调用Dao连接数据库,查询到数据
		// 这里假设拿到了从数据库中查询到的数据
		Employee employee = new Employee(6666, "猪八戒", "jingtanshizhe@xiyou.com", new Department(1002, "后厨部"));
		// 2.将拿到的员工数据添加到map中
		map.put("emp", employee);
		return SUCCESS;
	}

相应的跳转页面代码片段:

<body>
	<h1>这是一个跳转成功页面</h1><br>
	
	<h2>后厨员工信息为:${requestScope.emp }</h2><br>
</body>

可以看到前端确实得到了后台响应的数据。同样的,这个数据默认也是在request域中的。那么,如何将响应的数据放在session域中呢?这时可以在传参的时候,同时传入HttpSession类型的对象作为参数,代码片段如下:
处理方法的java代码:

	@RequestMapping("/testMapSession")
	public String test8(Map<String, Object> map,HttpSession session) {
		// 1.通过controler调用Service然后调用Dao连接数据库,查询到数据
		// 这里假设拿到了从数据库中查询到的数据
		Employee employee = new Employee(7777, "沙僧", "juanliandajiang@xiyou.com", new Department(1003, "卷帘部"));
		//2.将员工数据放到session域中
		session.setAttribute("emp",employee);
		// 3.将拿到的员工数据添加到map中
		map.put("emp", employee);
		return SUCCESS;
	}

跳转到的页面的代码片段:

<body>
	<h1>这是一个跳转成功页面</h1><br>
	
	<h2>员工信息为(通过request域取得):${requestScope.emp }</h2><br>
	<h2>员工信息为通过session域取得):${sessionScope.emp }</h2><br>
	
</body>

可以通过跳转页面看到request和session域中都能得到该值,页面如下:

这是一个跳转成功页面

员工信息为(通过request域取得):Employee [id=7777, lastName=沙僧, email=juanliandajiang@xiyou.com, dept=Department [id=1003, name=卷帘部]]

员工信息为通过session域取得):Employee [id=7777, lastName=沙僧, email=juanliandajiang@xiyou.com, dept=Department [id=1003, name=卷帘部]]

关于地址的重定向问题

前文介绍的处理请求的方法的最后都是通过返回值为String类型的字符串("success")来经过配置的视图解析器进行前缀+success+后缀进行拼接,然后自动转发到该页面,我们同样可以通过指定的方式让其进行相应的转发或者重定向操作。关于控制器的转发和重定向的问题有以下几点说明:
**1)一般情况下,控制器方法返回字符串类型的值会被当成逻辑视图名处理

2)如果返回的字符串中带 forward: 或 *redirect: *前缀时,SpringMVC 会对他们进行特殊处理:将forward:redirect: 当成指示符,其后的字符串作为 URL 来处理
比如:
①如果返回值内容是redirect:success.jsp,那么将会完成一个到 success.jsp 的重定向的操作

②如果返回值内容是forward:success.jsp,那么将会完成一个到 success.jsp 的转发操作**

示例代码如下:
转发:

	@RequestMapping("/testForward")
	public String test9() {
		
		System.out.println("已进行转发处理");
		return "forward:/forwardPage.jsp";
	}

重定向:

	@RequestMapping("/testRedirect")
	public String test10() {
		System.out.println("已重定向到新的页面");
		return "redirect:/redirectPage.jsp";
	}

@ResponseBody注解

这个注解可以标注于类上和方法上,
如果添加到方法上,它的作用是,将添加了该注解的方法的返回值直接响应到浏览器,
如果添加到类上,当前类中所有的方法的返回值将直接响应到浏览器,但是需要在SpringMVC的配置文件中配置
<mvc:annotation-driven />标签。

处理静态资源

在最后补充一个响应Ajax请求的方法,道理一样,不过引入Ajax的之后需要配置一下配置文件。需要1springmvc的配置文件中加入如下两个配置:

<mvc:default-servlet-handler/>
<mvc:annotation-driven/>

具体配置片段如下:

	<!-- 配置处理静态资源 -->
	<mvc:default-servlet-handler/>
	<!-- 配置处理静态资源之后,必须配置以下标签 -->
	<mvc:annotation-driven></mvc:annotation-driven>

因为默认情况下,静态资源(Html、CSS、Js)都交由defaultServlet处理,而动态的则交由Controller去处理。所以这个时候如果使用Ajax发送请求的话,需要配置一下处理静态资源的标签。代码片段如下:

<button id="btID">发送Ajax请求,接收Controller响应过来的字符串</button>

Ajax:

<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.7.2.js"></script>
<script type="text/javascript">
	$(function(){
		//给按钮绑定单击事件
		$("#btID").click(function(){
			//声明请求地址
			var url = "${pageContext.request.contextPath}/testAjax";
			//发送Ajax请求接收Controller响应过来的字符串
			$.post(url,function(res){
				alert(res);
			});
		});
		
	});
	
</script>

java处理方法代码如下:

	@ResponseBody
	@RequestMapping("/testAjax")
	public String test11() {
		System.out.println("响应Ajax请求");
		return "Hello?";
	}

从浏览器端可以看到响应的字符串"Hello?"弹窗。

原文地址:https://www.cnblogs.com/zhqin/p/11732874.html