学习SpringMVC

1. MVC概念

1.1 M-V-C

MVC 全名是 Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,
SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,属于 Spring 
FrameWork 的后续产品,已经融合在 Spring Web Flow 里面。Spring 框架提供了构建 Web 应用程序的全功
能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用 Spring 进行 WEB 开发时,可以选择使用 Spring
的 Spring MVC 框架或集成其他 MVC 开发框架,如 Struts1(现在一般不用),Struts2 等。
是一种用于设计创建 Web 应用程序表现层的模式。MVC 中每个部分各司其职:

Model(模型)

通常指的就是我们的数据模型。作用一般情况下用于封装数据。

View(视图):

通常指的就是我们的 jsp 或者 html。作用一般就是展示数据的。
通常视图是依据模型数据创建的。

Controller(控制器):

是应用程序中处理用户交互的部分。作用一般就是处理程序逻辑的。

例子:
我们要保存一个用户的信息,该用户信息中包含了姓名,性别,年龄等等。
这时候表单输入要求年龄必须是 1~100 之间的整数。姓名和性别不能为空。并且把数据填充
到模型之中。
此时除了 js 的校验之外,服务器端也应该有数据准确性的校验,那么校验就是控制器的该做
的。
当校验失败后,由控制器负责把错误页面展示给使用者。
如果校验成功,也是控制器负责把数据填充到模型,并且调用业务层实现完整的业务需求。

在这里插入图片描述

执行流程
在这里插入图片描述
在这里插入图片描述

1.2 优势

1、清晰的角色划分:
	前端控制器(DispatcherServlet)
	请求到处理器映射(HandlerMapping)
	处理器适配器(HandlerAdapter)
	视图解析器(ViewResolver)
	处理器或页面控制器(Controller)
	验证器( Validator)
	命令对象(Command 请求参数绑定到的对象就叫命令对象)
	表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)。
2、分工明确,而且扩展点相当灵活,可以很容易扩展,虽然几乎不需要。 
3、由于命令对象就是一个 POJO,无需继承框架特定 API,可以使用命令对象直接作为业务对象。
4、和 Spring 其他框架无缝集成,是其它 Web 框架所不具备的。 
5、可适配,通过 HandlerAdapter 可以支持任意的类作为处理器。 
6、可定制性,HandlerMapping、ViewResolver 等能够非常简单的定制。 
7、功能强大的数据验证、格式化、绑定机制。
8、利用 Spring 提供的 Mock 对象能够非常简单的进行 Web 层单元测试。 
9、本地化、主题的解析的支持,使我们更容易进行国际化和主题的切换。
10、强大的 JSP 标签库,使 JSP 编写更容易。
…还有比如RESTful风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配置支持等等。

1.3对比Struts2

共同点:

它们都是表现层框架,都是基于 MVC 模型编写的。
它们的底层都离不开原始 ServletAPI。
它们处理请求的机制都是一个核心控制器。

区别:

Spring MVC 的入口是 Servlet, 而 Struts2 是 Filter 
Spring MVC 是基于方法设计的而 Struts2 是基于类
Struts2 每次执行都会创建一个动作类。所以 Spring MVC 会稍微比 Struts2 快些。
Spring MVC 使用更加简洁,同时还支持 JSR303, 处理 ajax 的请求更方便

(JSR303 是一套 JavaBean 参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注
解加在我们 JavaBean 的属性上面,就可以在需要校验的时候进行校验了。)
Struts2 的 OGNL 表达式使页面的开发效率相比 Spring MVC 更高些,但执行效率并没有比 JSTL 提升,
尤其是 struts2 的表单标签,远没有 html 执行效率高。

2.入门配置

在这里插入图片描述

2.1 web.xml配置核心控制器(Servlet)

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<!-- 配置 spring mvc 的核心控制器 --> 
<servlet> 
	<servlet-name>SpringMVCDispatcherServlet</servlet-name> 
	<servlet-class>=org.springframework.web.servlet.DispatcherServlet=</servlet-class>
	<!-- 配置初始化参数,用于读取 SpringMVC 的配置文件 --> 
	<init-param> 
		<param-name>contextConfigLocation</param-name> 
		<param-value>classpath:SpringMVC.xml</param-value>
	</init-param>
	<!-- 配置 servlet 的对象的创建时间点:应用加载时创建。
	取值只能是非 0 正整数,表示启动顺序 --> 
	<load-on-startup>1</load-on-startup>
</servlet> 
<servlet-mapping> 
	<servlet-name>SpringMVCDispatcherServlet</servlet-name> 
	<url-pattern>/</url-pattern>
</servlet-mapping>

2.2 创建 springmvc.xml -配视图解析器

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:mvc="http://www.springframework.org/schema/mvc"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd
 http://www.springframework.org/schema/mvc
 http://www.springframework.org/schema/mvc/spring-mvc.xsd
 http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context.xsd">

 <!-- 配置创建 spring 容器要扫描的包 -->
	 <context:component-scan base-package="com.itheima"></context:component-scan>
	 
	 <!-- 配置视图解析器 -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/pages/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>
</beans>

< mvc:annotation-driven >

在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。使 用 < mvc:annotation-driven > 自动加载 RequestMappingHandlerMapping (处理映射器) 和
RequestMappingHandlerAdapter ( 处 理 适 配 器 ) , 可 用 在 SpringMVC.xml 配 置 文 件 中 使 用< mvc:annotation-driven >替代注解处理器和适配器的配置。

2.3 控制器controlor.java

@Controller("helloController")
public class HelloController {

	@RequestMapping("/hello")
	public String sayHello() {
		System.out.println("HelloController 的 sayHello 方法执行了。。。。");
		return "success"; 
	} 
}

@RequestMapping–method属性

用如下method属性,提交表单时也要设为post,当使用 get 请求时,提示错误信息是 405,信息是方法不支持 get 方式请求

@RequestMapping(value="/saveAccount",method=RequestMethod.POST)

@RequestMapping–params 属性

@RequestMapping(value="/removeAccount",params= {"accountName","money>100"})

用第二个参数可以访问,第一个会报400Bad Request

<!-- 请求参数的示例 --> 
<a href="account/removeAccount?accountName=aaa&money>100">删除账户,金额 100</a> 
<a href="account/removeAccount?accountName=aaa&money>150">删除账户,金额 150</a>

SpringMVC 的请求响应流程在这里插入图片描述

2.4请求参数乱码问题

get方式已解决,针对post 请求方式:
在 web.xml 中配置一个过滤器

<!-- 配置 springMVC 编码过滤器 --> 
<filter> 
	<filter-name>CharacterEncodingFilter</filter-name> 
	<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
	<!-- 设置过滤器中的属性值 --> 
	<init-param> 
		<param-name>encoding</param-name> 
	 	<param-value>UTF-8</param-value> 
	</init-param> 
	<!-- 启动过滤器 --> 
	<init-param> 
		<param-name>forceEncoding</param-name> 
		 <param-value>true</param-value> 
	</init-param> 
</filter> 
<!-- 过滤所有请求 --> 
<filter-mapping> 
	<filter-name>CharacterEncodingFilter</filter-name> 
	<url-pattern>/*</url-pattern> 
</filter-mapping>

2.5控制方法的参数问题

2.5.1自定义类型转换器

场景: 参数为日期,是String类型的

<a href="account/deleteAccount?date=2021-01-01">根据日期删除账户</a>

问题:以下情况不会报错:String date,但是将String改成Date就400错误了

@RequestMapping("/deleteAccount")
public String deleteAccount(String date) {
	System.out.println("删除了账户。。。。"+date);
	return "success"; 
}

解决:3步
1.定义一个类,实现 Converter 接口,该接口有两个泛型(String,Date)

public class StringToDateConverter implements Converter<String, Date> {
	/**
	* 用于把 String 类型转成日期类型
	*/
	@Override
	public Date convert(String source) {
		DateFormat format = null;
		try {
			if(StringUtils.isEmpty(source)) {
				throw new NullPointerException("请输入要转换的日期");
			}
			format = new SimpleDateFormat("yyyy-MM-dd");
			Date date = format.parse(source);
			return date;
		} catch (Exception e) {
			throw new RuntimeException("输入日期有误");
		} 
	}
}

2.在 spring 配置文件中配置类型转换器
spring 配置类型转换器的机制是,将自定义的转换器注册到类型转换服务中去。

<!-- 配置类型转换器工厂 --> 
<bean id="converterService" class="org.springframework.context.support.ConversionServiceFactoryBean">
	 <!-- 给工厂注入一个新的类型转换器 -->
	 <property name="converters">
	 <array>
		 <!-- 配置自定义类型转换器 -->
		 <bean class="com.itheima.web.converter.StringToDateConverter"></bean>
	 </array>
	 </property>
</bean>

3.在 annotation-driven 标签中引用配置的类型转换服务

<!-- 引用自定义类型转换器 --> 
<mvc:annotation-driven conversion-service="converterService"></mvc:annotation-driven>

2.5.2使用 ServletAPI 对象作为方法参数

SpringMVC 还支持使用原始 ServletAPI 对象作为控制器方法的参数。支持原始 ServletAPI 对象有:

HttpServletRequest 
HttpServletResponse
HttpSession
java.security.Principal
Locale
InputStream 
OutputStream 
Reader 
Writer

我们可以把上述对象,直接写在控制的方法参数中使用。比如:

@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request,
							 HttpServletResponse response,
							 HttpSession session) {
	System.out.println(request);
	System.out.println(response);
	System.out.println(session);
	return "success"; 
}

3.控制方法的常用注解

3.1 RequestParam

==作用==:
	把请求中指定名称的参数给控制器中的形参赋值。
==属性==:
	value:请求参数中的名称。
	required:请求参数中是否必须提供此参数。默认值:true表示必须提供,如果不提供将报错。

案例,参数只有一个name,不提供 age参数

<a href="springmvc/useRequestParam?name=test">requestParam 注解</a>

由于required=false所以age也可不提供,照样执行成功

@RequestMapping("/useRequestParam")
public String useRequestParam(@RequestParam("name")String username,
							  @RequestParam(value="age",required=false)Integer age){
	System.out.println(username+","+age);
	return "success"; 
}

3.2 RequestBody

作用:
用于获取请求体内容。直接使用得到是 key=value&key=value...结构的数据。get 请求方式不适用。
属性:
required:是否必须有请求体。默认值是:true。
当取值为 true 时,get 请求方式会报错。如果取值为 false,get 请求得到是 null。

测试提交代码

post 请求 jsp 代码:
<form action="springmvc/useRequestBody" method="post">
	用户名称:<input type="text" name="username" ><br/>
	用户密码:<input type="password" name="password" ><br/>
	用户年龄:<input type="text" name="age" ><br/>
	<input type="submit" value="保存">
</form>

get 请求 jsp 代码:
<a href="springmvc/useRequestBody?body=test">requestBody 注解 get 请求</a>
@RequestMapping("/useRequestBody")
public String useRequestBody(@RequestBody(required=false) String body){
	System.out.println(body);
	return "success"; 
}

post结果
在这里插入图片描述
get结果
在这里插入图片描述

3.3 PathVaribale

作用:
用于绑定 url 中的占位符。例如:请求 url 中 /delete/{id},这个{id}就是 url 占位符。
url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。
属性:
value:用于指定 url 中占位符名称。
required:是否必须提供占位符。
<a href="springmvc/usePathVariable/100">pathVariable 注解</a>

成功输出 100

@RequestMapping("/usePathVariable/{id}")
public String usePathVariable(@PathVariable("id") Integer id){
	System.out.println(id);
	return "success"; 
}

3.4 RequestHeader

一般不用

3.5 CookieValue

作用:
用于把指定 cookie 名称的值传入控制器方法参数。
属性:
value:指定 cookie 的名称。
required:是否必须有此 cookie。
<a href="springmvc/useCookieValue">绑定 cookie 的值</a>
@RequestMapping("/useCookieValue")
public String useCookieValue(@CookieValue(value="JSESSIONID",required=false) 
												String cookieValue){
	System.out.println(cookieValue);
	return "success"; 
}

结果:(不太懂???)
在这里插入图片描述

3.6 ModelAttribute

作用:
	该注解是 SpringMVC4.3 版本以后新加入的。它可以用于修饰方法和参数。
	出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,
	也可以修饰有具体返回值的方法。
	出现在参数上,获取指定的数据给参数赋值。
属性:
	value:用于获取数据的 key。key 可以是 POJO 的属性名称,也可以是 map 结构的 key。
应用场景:
	当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。
例如:
	我们在编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许被修改的。在提交表单数
	据是肯定没有此字段的内容,一旦更新会把该字段内容置为 null,此时就可以使用此注解解决问题。

3.6.1 基于 POJO 属性的基本使用:

<a href="springmvc/testModelAttribute?username=test">测试 modelattribute</a>
//被 ModelAttribute 修饰的方法
@ModelAttribute
public void showModel(User user) {
	System.out.println("执行了 showModel 方法"+user.getUsername());
}
// 接收请求的方法
@RequestMapping("/testModelAttribute")
public String testModelAttribute(User user) {
	System.out.println("执行了控制器的方法"+user.getUsername());
	return "success"; 
}

在这里插入图片描述

3.6.2 基于 Map 的应用场景示例 1:ModelAttribute 修饰方法带返回值

注意,没有输入密码

<!-- 修改用户信息 --> 
<form action="springmvc/updateUser" method="post">
	用户名称:<input type="text" name="username" ><br/>
	用户年龄:<input type="text" name="age" ><br/>
	<input type="submit" value="保存">
</form>

调用findUserByName(username)

@ModelAttribute
public User showModel(String username) {
	//模拟去数据库查询
	User abc = findUserByName(username);
	System.out.println("执行了 showModel 方法"+abc);
	return abc; 
}

@RequestMapping("/updateUser")
public String testModelAttribute(User user) {
	System.out.println("控制器中处理请求的方法:修改用户:"+user);
	return "success"; 
}

模拟实现 findUserByName(username)

private User findUserByName(String username) {
	User user = new User();
	user.setUsername(username);
	user.setAge(19);
	user.setPassword("123456");
	return user; 
}

在这里插入图片描述

3.6.3 基于 Map 的应用场景示例 2:ModelAttribute 修饰方法不带返回值

用上一个表单输入
用上一个findUserByName

@ModelAttribute
public void showModel(String username,Map<String,User> map) {
	//模拟去数据库查询
	User user = findUserByName(username);
	System.out.println("执行了 showModel 方法"+user);
	map.put("abc",user);
}

@RequestMapping("/updateUser")
public String testModelAttribute(@ModelAttribute("abc")User user) {
	System.out.println("控制器中处理请求的方法:修改用户:"+user);
	return "success"; 
}

在这里插入图片描述

3.7 SessionAttribute

作用:
	用于多次执行控制器方法间的参数共享。
属性:
	value:用于指定存入的属性名称
	type:用于指定存入的数据类
<a href="springmvc/testPut">存入 SessionAttribute</a> <hr/>
<a href="springmvc/testGet">取出 SessionAttribute</a> <hr/>
<a href="springmvc/testClean">清除 SessionAttribute</a>

@SessionAttributes用在控制器类

@Controller("sessionAttributeController")
@RequestMapping("/springmvc")
@SessionAttributes(value ={"username","password"},types={Integer.class}) 
public class SessionAttributeController {
	/**
	* 把数据存入 SessionAttribute
	* Model 是 spring 提供的一个接口,该接口有一个实现类 ExtendedModelMap
	* 该类继承了 ModelMap,而 ModelMap 就是 LinkedHashMap 子类
	*/
	@RequestMapping("/testPut") 
	public String testPut(Model model){ 
		 model.addAttribute("username", "泰斯特"); 
		 model.addAttribute("password","123456"); 
		 model.addAttribute("age", 31); 
		 //跳转之前将数据保存到 username、password 和 age 中
		 //因为注解@SessionAttribute 中有这几个参数 
		 return "success"; 
	 } 
	 
	 @RequestMapping("/testGet") 
	 public String testGet(ModelMap model){ 
		System.out.println(model.get("username")+";"+model.get("password")+";"+model.get("age")); 
	 	return "success"; 
	 } 
	 
	 @RequestMapping("/testClean") 
	 public String complete(SessionStatus sessionStatus){ 
	 	 sessionStatus.setComplete(); 
		 return "success"; 
	 } 
}

结果
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值