SpringMVC学习
SpringMVC的基本概念
关于三层架构和MVC
三层架构
- 表现层:WEB层,用来和客户端进行数据交互的。表现层一般会采用MVC的设计模型
- 业务层:处理公司具体的业务逻辑的
- 持久层:用来操作数据库的
MVC模型
- MVC全名是Model View Controller 模型视图控制器,每个部分各司其职。
- Model:数据模型,JavaBean的类,用来进行数据封装。
- View:指JSP、HTML用来展示数据给用户
- Controller:用来接收用户的请求,整个流程的控制器。用来进行数据校验等。
SpringMVC概述
SpringMVC是什么
- SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,属于 Spring FrameWork 的后续产品,已经融合在 Spring Web Flow 里面。Spring 框架提供了构建 Web 应用程序的全功 能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用 Spring 进行 WEB 开发时,可以选择使用 Spring 的 Spring MVC 框架或集成其他 MVC 开发框架,如 Struts1(现在一般不用),Struts2 等。
- SpringMVC 已经成为目前最主流的 MVC 框架之一,并且随着 Spring3.0 的发布,全面超越 Struts2,成 为最优秀的 MVC 框架。
- 它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持 RESTful 编程风格的请求。
SpringMVC在三层架构中的位置
SpringMVC的优势
- 清晰的角色划分:
- 前端控制器(DispatcherServlet)
- 请求到处理器映射(HandlerMapping)
- 处理器适配器(HandlerAdapter)
- 视图解析器(ViewResolver)
- 处理器或页面控制器(Controller)
- 验证器( Validator)
- 命令对象(Command 请求参数绑定到的对象就叫命令对象)
- 表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象
- 分工明确,而且扩展点相当灵活,可以很容易扩展,虽然几乎不需要。
- 由于命令对象就是一个 POJO,无需继承框架特定 API,可以使用命令对象直接作为业务对象。
- 和 Spring 其他框架无缝集成,是其它 Web 框架所不具备的。
- 可适配,通过 HandlerAdapter 可以支持任意的类作为处理器。
- 可定制性,HandlerMapping、ViewResolver 等能够非常简单的定制。
- 功能强大的数据验证、格式化、绑定机制。
- 利用 Spring 提供的 Mock 对象能够非常简单的进行 Web 层单元测试。
- 本地化、主题的解析的支持,使我们更容易进行国际化和主题的切换。
- 强大的 JSP 标签库,使 JSP 编写更容易。 ………………还有比如RESTful风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配 置支持等等。
SpringMVC和Structs2的优劣分析
- 共同点:
- 它们都是表现层框架,都是基于 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 执行效率高。
SpringMVC的入门
入门案例
-
配置核心控制器-一个Servlet
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <!--配置前端控制器--> <servlet> <servlet-name>dispatcherServlet</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> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
-
创建spring mvc的配置文件
<?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"> <!--开启注解扫描--> <context:component-scan base-package="com.seafy"></context:component-scan> <!--视图解析器对象--> <bean id ="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/"/> <property name="suffix" value=".jsp"/> </bean> <!--开启SpringMVC框架注解支持--> <mvc:annotation-driven conversion-service="conversionService"/> </beans>
-
编写控制器并使用注解配置
package com.seafy.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; //控制器类 @Controller @RequestMapping(path = "/user") public class HelloController { /** * 入门案例 * @return */ @RequestMapping(path = "/hello") public String sayHello(){ System.out.println("hello!"); return "success"; } /** * RequestMapping注解 * @return */ @RequestMapping(path = "/testRequestMapping") public String testRequestMapping(){ System.out.println("测试RequestMapping注解。。。"); return "success"; } }
入门案例的分析
入门案例的执行过程分析
- 入门案例的执行流程
- 当启动Tomcat服务器的时候,因为配置了load-on-startup标签,所以会创建DispatcherServlet对象, 就会加载springmvc.xml配置文件
- 开启了注解扫描,那么HelloController对象就会被创建
- 从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解 找到执行的具体方法
- 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件
- Tomcat服务器渲染页面,做出响应
- SpringMVC官方提供图形
- 入门案例中的组件分析
- 前端控制器(DispatcherServlet)
- 用户请求到达前端控制器,它就相当于 mvc 模式中的 c,dispatcherServlet 是整个流程控制的中心,由 它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。
- 处理器映射器(HandlerMapping)
- HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的 映射方式,例如:配置文件方式,实现接口方式,注解方式等。
- 处理器(Handler)
- 它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由 Handler 对具体的用户请求进行处理。
- 处理器适配器(HandlAdapter)
- 通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理 器进行执行
- 视图解析器(View Resolver)
- View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名 即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。
- 视图(View)
- SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView 等。我们最常用的视图就是 jsp。
- 一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
- 前端控制器(DispatcherServlet)
RequestMapping注解
使用说明
- 作用: 用于建立请求 URL 和处理请求方法之间的对应关系。
- 出现位置:
- 类上: 请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头。 它出现的目的是为了使我们的 URL 可以按照模块化管理
- 方法上: 请求 URL 的第二级访问目录。
- 属性:
- path 指定请求路径的url
- value:用于指定请求的 URL。它和 path 属性的作用是一样的。
- method:用于指定请求的方式。
- params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和 配置的一模一样
- headers 发送的请求中必须包含的请求头
使用示例
/**
* RequestMapping注解
* @return
*/
@RequestMapping(path = "/testRequestMapping")
public String testRequestMapping(){
System.out.println("测试RequestMapping注解。。。");
return "success";
}
请求参数的绑定
绑定说明
绑定的机制
- 表单提交的数据都是k=v格式的 username=haha&password=123
- SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的
- 要求:提交表单的name和参数的名称是相同的
支持的数据类型
- 基本数据类型和字符串类型
- 实体类型(JavaBean)
- 集合数据类型(List、map集合等)
基本类型和String类型作为参数
- 提交表单的name和参数的名称是相同的
- 区分大小写
请求参数乱码问题解决
-
在web.xml中配置Spring提供的过滤器类
<!--配置解决中文乱码的过滤器--> <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> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
特殊情况
自定义类型转换器
-
表单提交的任何数据类型全部都是字符串类型,但是后台定义Integer类型,数据也可以封装上,说明 Spring框架内部会默认进行数据类型转换。
-
如果想自定义数据类型转换,可以实现Converter的接口
-
自定义类型转换器
package com.seafy.utils; import com.sun.xml.internal.ws.policy.privateutil.RuntimePolicyUtilsException; import org.springframework.core.convert.converter.Converter; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; /** * 把字符串转换日期 */ public class StringToDateConventer implements Converter<String, Date> { /** * @param source 传入进来字符串 * @return */ @Override public Date convert(String source) { //判断 if (source == null){ throw new RuntimeException("请您传入数据"); } DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); //把字符串转化日期 try { return df.parse(source); } catch (Exception e) { throw new RuntimeException("数据类型转化出现错误"); } } }
-
注册自定义类型转换器,在springmvc.xml配置文件中编写配置
<!--配置自定义类型转换器--> <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="com.seafy.utils.StringToDateConventer"></bean> </set> </property> </bean>
-
常用注解
RequestParam注解
-
作用:把请求中的指定名称的参数传递给控制器中的形参赋值
-
属性
-
value:请求参数中的名称
-
required:请求参数中是否必须提供此参数,默认值是true,必须提供
-
代码:
/** * 接收请求 * @return */ @RequestMapping(path="/hello") public String sayHello(@RequestParam(value="username",required=false)String name) { System.out.println("aaaa"); System.out.println(name); return "success"; }
RequestBody注解
-
作用:用于获取请求体的内容(注意:get方法不可以)
-
属性
- required:是否必须有请求体,默认值是true
-
代码:
/** * 接收请求 * @return */ @RequestMapping(path="/hello") public String sayHello(@RequestBody String body) { System.out.println("aaaa"); System.out.println(body); return "success"; }
PathVarable注解
-
作用:拥有绑定url中的占位符的。例如:url中有/delete/{id},{id}就是占位符
-
属性
-
value:指定url中的占位符名称
-
Restful风格的URL
-
请求路径一样,可以根据不同的请求方式去执行后台的不同方法
-
restful风格的URL优点
- 结构清晰
- 符合标准
- 易于理解
- 扩展方便
-
代码:
/** * 接收请求 * @return */ @RequestMapping(path="/hello/{id}") public String sayHello(@PathVariable(value="id") String id) { System.out.println(id); return "success"; }
RequestHeader注解
-
作用:获取指定请求头的值
-
属性
- value:请求头的名称
-
代码:
@RequestMapping(path="/hello") public String sayHello(@RequestHeader(value="Accept") String header) { System.out.println(header); return "success"; }
CookieValue注解
-
作用:用于获取指定cookie的名称的值
-
属性
- value:cookie的名称
-
代码:
@RequestMapping(path="/hello") public String sayHello(@CookieValue(value="JSESSIONID") String cookieValue) { System.out.println(cookieValue); return "success"; }
ModelAttribute注解
-
作用
- 出现在方法上:表示当前方法会在控制器方法执行前线执行。
- 出现在参数上:获取指定的数据给参数赋值。
-
应用场景
- 当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据。
-
代码:
-
修饰的方法有返回值
/** * 作用在方法,先执行 * @param name * @return */ @ModelAttribute public User showUser(String name) { System.out.println("showUser执行了..."); // 模拟从数据库中查询对象 User user = new User(); user.setName("哈哈"); user.setPassword("123"); user.setMoney(100d); return user; } /** * 修改用户的方法 * @param cookieValue * @return */ @RequestMapping(path="/updateUser") public String updateUser(User user) { System.out.println(user); return "success"; }
-
修饰的方法没有返回值
/** * 作用在方法,先执行 * @param name * @return */ @ModelAttribute public void showUser(String name,Map<String, User> map) { System.out.println("showUser执行了..."); // 模拟从数据库中查询对象 User user = new User(); user.setName("哈哈"); user.setPassword("123"); user.setMoney(100d); } /** * 修改用户的方法 * @param cookieValue * @return */ @RequestMapping(path="/updateUser") public String updateUser(@ModelAttribute(value="abc") User user) { System.out.println(user); return "success"; }
-
SessionAttributes注解
-
作用:用于多次执行控制器方法间的参数共享
-
属性
- value:指定存入属性的名称
-
代码:
@Controller @RequestMapping(path = "/user") @SessionAttributes(value = {"username","password","age"},types = {String.class,Integer.class}) //把数据存入到session域对象中 public class HelloController{ /** * 向session中存入值 * @param model * @return */ @RequestMapping(path = "/save") public String save(Model model){ System.out.println("向session域中保存数据"); model.addAttribute("username", "root"); model.addAttribute("password", "123"); model.addAttribute("age", 20); return "success"; } /** * * 从session中获取值 * * @return * */ @RequestMapping(path="/find") public String find(ModelMap modelMap) { String username = (String) modelMap.get("username"); String password = (String) modelMap.get("password"); Integer age = (Integer) modelMap.get("age"); System.out.println(username + " : "+password +" : "+age); return "success"; } /** * * 清除值 * * @return * */ @RequestMapping(path="/delete") public String delete(SessionStatus status) { status.setComplete(); return "success"; } }
课程总结
- SpringMVC的概述
- 入门
- 创建工程,导入坐标
- 在web.xml中配置前端控制器(启动服务器,加载springmvc.xml配置文件)
- 编写springmvc.xml配置文件
- 编写index.jsp的页面,发送请求
- 编写Controller类,编写方法(@RequestMapping(path="/hello")),处理请求
- 编写配置文件(开启注解扫描),配置视图解析器
- 执行的流程
- @RequestMapping注解
- path
- value
- method
- …
- 参数绑定
- 参数绑定必须会
- 解决中文乱码,配置过滤器
- 自定义数据类型转换器