文章目录
- 1. SpringMVC基本概念
- 1.1 三层架构
- 1.2 MVC架构
- 1.3 什么是SpringMVC
- 1.4 SpringMVC的优势
- 2. SpringMVC 的入门
- 2.1 入门程序
- 2.2 SpringMVC执行原理刨析
- 2.3 SpringMVC的核心执行流程
- 2.4 SpringMVC的组件
- 3. RequestMapping注解
- 4.请求参数绑定
- 4.1 参数绑定
- 4.2 请求参数乱码问题
- 4.2.1 POST请求方式解决乱码问题
- 4.2.2 GET请求方式解决乱码问题
- 4.3 自定义类型转换器
- 4.4 使用ServletAPI传递参数
- 5. SpringMVC常用注解
1. SpringMVC基本概念
1.1 三层架构
我们的开发架构一般都是基于两种形式,一种是C/S架构,也就是客户端/服务器,另一种是B/S架构,也就是浏览器服务器。在JavaEE开发中,几乎全都是基于B/S架构的开发。那么在B/S架构中,系统标准的三层架构包括:表现层、业务层、持久层。三层架构在我们的实际开发中使用的非常多。
三层架构中,每一层各司其职,接下来我们就说说每层都负责哪些方面:
-
表现层
也就是我们常说的web层。它负责接收客户端请求,向客户端响应结果,通常客户端使用http协议请求web层,web需要接收http请求,完成http响应。- 表现层包括展示层和控制层: 控制层负责接收请求,展示层负责结果的展示。
- 表现层依赖业务层,接收到客户端请求一般会调用业务层进行业务处理,并将处理结果响应给客户端。
- 表现层的设计一般都使用MVC模型。(MVC 是表现层的设计模型,和其他层没有关系)
-
业务层
也就是我们常说的service层。它负责业务逻辑处理,和我们开发项目的需求息息相关。- web层依赖业务层,但是业务层不依赖web层。
- 业务层在业务处理时可能会依赖持久层,如果要对数据持久化需要保证事务一致性。( 也就是我们说的,事务应该放到业务层来控制)
-
数据访问层(DAL,dao)
也就是我们是常说的 dao层。负责数据持久化,包括数据层即数据库和数据访问层,数据库是对数据进行持久化的载体,数据访问层是业务层和持久层交互的接口,业务层需要通过数据访问层将数据持久化到数据库中。通俗的讲,持久层就是和数据库交互,对数据库表进行增、删、改、查的。
1.2 MVC架构
MVC全名是Model view Controller, 是模型(model) — 视图(view) — 控制器(controller) 的缩写,是一种用于设计创建Web应用程序表现层的模式。MVC中每个部分各司其职:
-
模型(model)
- 通常指的就是我们的数据模型。作用一般情况下用于封装数据。
-
视图(view)
- 通常指的就是我们的jsp或者html。作用一般就是展示数据的。
- 通常视图是依据模型数据创建的。
-
控制器(controller)
- 是应用程序中处理用户交互的部分。作用一-般就是处理程序逻辑的。
-
例如:
- 我们要保存一个用户的信息,该用户信息中包含了姓名,性别,年龄等等。
- 这时候表单输入要求年龄必须是 1~100 之间的整数。姓名和性别不能为空。并且把数据填充到模型之中。
- 此时除了 js 的校验之外,服务器端也应该有数据准确性的校验,那么校验就是控制器的该做的。
- 当校验失败后,由控制器负责把错误页面展示给使用者。
- 如果校验成功,也是控制器负责把数据填充到模型,并且调用业务层实现完整的业务需求。
-
综上所述,我们可以用一幅图来描述MVC三层架构:
1.3 什么是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 在三层架构的位置:
1.4 SpringMVC的优势
- 清晰的角色划分:
- 前端控制器(DispatcherServlet)
- 请求到处理器映射(HandlerMapping)
- 处理器适配器(HandlerAdapter)
- 视图解析器(ViewResolver)
- 处理器或页面控制器(Controller/Handler)
- 验证器( Validator)
- 命令对象(Command 请求参数绑定到的对象就叫命令对象)
- 表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)。
- 分工明确,而且扩展点相当灵活,可以很容易扩展,虽然几乎不需要。
- 由于命令对象就是一个 POJO,无需继承框架特定 API,可以使用命令对象直接作为业务对象。
- 和 Spring 其他框架无缝集成,是其它 Web 框架所不具备的。
- 可适配,通过 HandlerAdapter 可以支持任意的类作为处理器。
- 可定制性,HandlerMapping、ViewResolver 等能够非常简单的定制。
- 功能强大的数据验证、格式化、绑定机制。
- 利用 Spring 提供的 Mock 对象能够非常简单的进行 Web 层单元测试。
- 本地化、主题的解析的支持,使我们更容易进行国际化和主题的切换。
- 强大的 JSP 标签库,使 JSP 编写更容易。
- 还有比如RESTful风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配置支持等等
2. SpringMVC 的入门
2.1 入门程序
(1)入门案例
- 需求: 用户发送一个请求,跳转到一个jsp页面。
- web.xml中配置核心控制器
<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>
- 配置springmvc.xml
<!-- 配置创建 spring 容器要扫描的包 -->
<context:component-scan base-package="com.qf"></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>
<!--开启springmvc注解支持-->
<mvc:annotation-driven></mvc:annotation-driven>
- 在/WEB-INF/pages/下编写success.jsp页面
<body>
<h2>欢迎你。SpringMVC</h2>
</body>
- 编写controller
@Controller
public class HelloController {
@RequestMapping("/hello")
public String sayHello(){
System.out.println("hello,springmvc");
return "success";
}
}
- 启动项目,测试
(2)入门程序处理流程分析
- 具体详情见 —— 2.3 Springmvc的核心执行流程
2.2 SpringMVC执行原理刨析
(1)疑问?
- tomacat容器只能存放servlet,外部通过url如何访问到Spring容器中组件?
- Spring容器如何初始化?
(2)分析解决?
- SpringMVC提供了一个Servlet ——
DispatcherServlet(核心控制器)
,在核心控制器内部提供了一个属性contextConfigLocation
,它可以用来加载Spring配置文件
- 在web.xml中可以通过
load-on-startup
来设置servlet的加载时机(在访问时加载,还是在tomcat容器初始化时加载),因此,当servlet加载时,通过配置contextConfigLocation
则Spring容器也会加载(配置实例bean组件也会初始化创建)
(3)配置
- 问: 在使用SpringMVC框架对web层进行配置时,有些需要配置到web.xml,有些需要配置到Spring核心配置文件,应该如何取舍配置?
- 答: 在配置相关SpringMVC组件时,需要抓住核心思想:
- 与tomcat容器相关需要配置到web.xml (核心控制器(本质是一个servlet),过滤器)
- 与tomcat容器无关的,但又需要使用的,则配置到Spring的核心配置文件中 (视图解析器,spring组件拦截路径、类型转换器)
2.3 SpringMVC的核心执行流程
(1)Springmvc的核心执行流程
(2)具体步骤
- 第一步:发起请求到前端控制器(DispatcherServlet)
- 第二步:前端控制器请求HandlerMapping查找 Handler (可以根据xml配置、注解进行查找)
- 第三步:处理器映射器HandlerMapping向前端控制器返回Handler,HandlerMapping会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象,多个HandlerInterceptor拦截器对象),通过这种策略模式,很容易添加新的映射策略
- 第四步:前端控制器调用处理器适配器去执行Handler
- 第五步:处理器适配器HandlerAdapter将会根据适配的结果去执行Handler
- 第六步:Handler执行完成给适配器返回ModelAndView
- 第七步:处理器适配器向前端控制器返回ModelAndView (ModelAndView是springmvc框架的一个底层对象,包括 Model和view)
- 第八步:前端控制器请求视图解析器去进行视图解析 (根据逻辑视图名解析成真正的视图(jsp)),通过这种策略很容易更换其他视图技术,只需要更改视图解析器即可
- 第九步:视图解析器向前端控制器返回View
- 第十步:前端控制器进行视图渲染 (视图渲染将模型数据(在ModelAndView对象中)填充到request域)
- 第十一步:前端控制器向用户响应结果
2.4 SpringMVC的组件
- DispatcherServlet 前端控制器(核心控制器)
用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。
- HandlerMapping 处理器映射器
HandlerMapping负责根据用户请求找到 Handler 即处理器(controller),SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。 - Handler 处理器
它就是我们开发中要编写的具体业务控制器(controller)。由DispatcherServlet 把用户请求转发到 Handler。由Handler对具体的用户请求进行处理。 - HandlAdapter 处理器适配器
通过 HandlerAdapter 对Handler (处理器) 进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。 - View Resolver 视图解析器
View Resolver负责将处理结果生成View 视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成 View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。
- View视图
- SpringMVC框架提供了很多View视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是jsp。
- 一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
- <mvc: annotation-driven>说明
在SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。 使用自动加载RequestMappingHandlerMapping(处理映射器)和 RequestMappingHandlerAdapter(处理适配器) , 可用在SpringMVC.xml配置文件中使用替代注解处理器和适配器的配置 (开启springmvc注解支持)。注意: 一般开发中,我们都需要写上此标签。
3. RequestMapping注解
(1)接口
- url ==>> 接口(接口必须包含以下要素)
- 具体的路径
- 请求方式:GET、POST、DELETE、PUT
- 请求参数
- 相应数据格式
(2)@RequestMapping
-
作用:
- 用于建立请求URL和处理请求方法之间的对应关系。
-
出现位置:
- 类上 : 请求URL的第一级访问目录
- 方法上: 请求URL的第二级访问目录
- 示例:/account/findOne
-
属性:
- value: 用于指定请求的URL。它和path属性的作用是一样的。
- method: 用于指定请求的方式。
- params: 用于指定限制请求参数的条件。 它支持简单的表达式。要求请求参数的key和value必须和配置的一模一样。
- 例如:
params = {“accountName”},表示请求参数必须有accountName
params = {“moeny!=100”},表示请求参数中money不能是 100。
- 例如:
- 注意: 以上四个属性只要出现2个或以上时,他们的关系是与的关系。
4.请求参数绑定
4.1 参数绑定
- 绑定机制:
用户请求参数都是基于key=value的。SpringMVC绑定请求参数的过程是通过把请求提交的参数,作为控制器中的方法参数进行绑定的。 - SpringMVC 绑定请求参数是自动实现的,但是要想使用,必须遵循使用要求
(1)基本参数类型绑定
- 数据类型: 包括基本类型和 String 类型
- 要求: 要求请求参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写)
(2)POJO类型参数绑定
- 数据类型: 包括实体类,以及关联的实体类
- 要求: 要求表单中参数名称和 POJO 类的属性名称保持一致。并且控制器方法的参数类型是 POJO 类型。
- 类中有关联的实体类:
- 表单参数类型:
实体属性名.关联实体属性名
- 表单参数类型:
(3)集合类型参数绑定
- 数据类型: 包括 List 结构和 Map 结构的集合(包括数组)
- 要求:
如果是集合类型,有两种方式:- 第一种:
要求集合类型的请求参数必须在 POJO 中。在表单中请求参数名称要和 POJO 中集合属性名称相同。
给 List 集合中的元素赋值,使用下标。
给 Map 集合中的元素赋值,使用键值对。 - 第二种:
接收的请求参数是 json 格式数据。需要借助一个注解实现。
- 第一种:
4.2 请求参数乱码问题
4.2.1 POST请求方式解决乱码问题
(1)在 web.xml 里面设置编码过滤器
<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)在 Springmvc.xml 里面设置
- web应用里面有静态资源,比如js css image等。我们不能够把静态资源也过滤了,否则会造成静态资源不能正常加载的问题。所以在配置编码过滤器的时候。我们需要设置静态资源不过滤。
<!-- location 表示路径,mapping 表示文件,**表示该目录下的文件以及子目录的文件 -->
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/images/" mapping="/images/**"/>
<mvc:resources location="/scripts/" mapping="/javascript/**"/>
4.2.2 GET请求方式解决乱码问题
- tomcat对GET和POST请求处理方式是不同的,GET请求的编码问题,要改tomcat的 server.xml 配置文件,如下:
- 如果遇到 ajax 请求仍然乱码,请把:
useBodyEncodingForURI="true"改为 URIEncoding=“UTF-8” 即可。
4.3 自定义类型转换器
(1)场景
- 若前端传递日期类型字符串参数,后端使用Date日期类型参数进行接收,会出现异常
- 原因: 我们前台传递的是字符串类型的参数,但是后台使用的是Date类型接收的。我们期望springmvc可以帮我们做数据类型的自动转换,显然没有做。所以我们需要自己自定义类型转换器。
(2)自定义类型转换器
- 第一步:定义一个类,实现Converter接口,该接口有两个泛型
public class StringToDateConverter implements Converter<String, Date> {
@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("输入日期有误");
}
}
}
- 第二步:在 springmvc.xml配置文件中配置类型转换器。
<!-- 配置类型转换器工厂 -->
<bean id="converterService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<!-- 给工厂注入一个新的类型转换器 -->
<property name="converters">
<array>
<!-- 配置自定义类型转换器 -->
<bean id="dateConverter " class="com.qf.convert.StringToDateConverter"></bean>
</array>
</property>
</bean>
<!--开启springmvc注解支持-->
<mvc:annotation-driven conversion-service="converterService"></mvc:annotation-driven>
- 第三步:在annotation-driven标签中引用配置的类型转换服务。
- 在annotation-driven标签中引用配置的类型转换服务后,SpringMVC遇到需要转换类型的操作时,会自动去类型转换器中查找有无相应的转换器,进而进行类型的自动转换
<!--开启springmvc注解支持-->
<mvc:annotation-driven conversion-service="converterService"></mvc:annotation-driven>
(3)@DateTimeFormat注解
- 作用范围:
- 作用:
- 可将请求携带日期字符串的参数转化为相应的日期格式类型
- 可在方法形参前添加注解进行格式转换
- 可在pojo属性上添加此注解(可以对应转换封装)
- 参数:
- pattern: 指定转换成日期的格式
- pattern: 指定转换成日期的格式
4.4 使用ServletAPI传递参数
SpringMVC还支持使用原始ServletAPI对象作为控制器方法的参数。支持原始ServletAPI对象有:
- HttpServletRequest
- HttpServletResponse
- HttpSession
我们可以把上述对象,直接写在控制的方法参数中使用。
- 示例:
- 请求:
- 使用:
- 请求:
5. SpringMVC常用注解
(1)@RequestParam
- 作用:
- 作用在形参前
- 把请求中指定名称的参数给控制器中的形参赋值。
- 属性:
- value:请求参数中的名称。
- required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。
- 注意事项
- 当请求传递的参数名称和方法的形参名称不一致时,需要加@RequestParam(“传递参数名称”)
- @RequestParam必须指定参数名称,否则会出现400错误
- 如果方法形参定义多个参数,用@RequestParm来修饰,请求参数必须有指定的参数,否则会出现400错误
(2)@RequestBody
- 作用:
- 作用在形参前
- 用于获取请求体内容。直接使用此注解,得到是 key=value&key=value…结构的数据。
- 结合json依赖转换,使用此注解:@RequestBody:会自动的将前台传递的json格式的数据转换成pojo对象。此时接收对象可以为pojo类型
- get请求方式不适用。
- 属性:
- required: 是否必须有请求体。默认值是:true。当取值为true时,get请求方式会报错。如果取值为false,get 请求得到是 null。
- 注意事项:
- 直接使用注解后,控制器中接收此请求的参数必须为 字符串类型
(3)@PathVariable
- 作用:
- 用于绑定url中的占位符。例如:请求url中/delete/{id},这个{id}就是url占位符。
- url支持占位符是spring3.0之后加入的。是springmvc支持rest风格URL的一个重要标志。
- 属性:
- value: 用于指定url中占位符名称。
- required: 是否必须提供占位符。
- REST风格URL
- Restful风格就是请求url统一,根据不同的请求方式,请求不同的后台方法。
- GET: 获取资源
- POST:新建资源
- PUT: 更新资源
- DELETE: 删除资源
- 如果需要携带参数,在url上使用/{}占位符。
- 示例:
- Restful风格就是请求url统一,根据不同的请求方式,请求不同的后台方法。
(4)@RequestHeader
- 作用:
用于获取请求消息头。 - 属性:
- value:提供消息头名称
- required:是否必须有此消息头
- 注:
在实际开发中一般不怎么用。
(5)@CookieValue
- 作用:
用于把指定cookie名称的值传入控制器方法参数。 - 属性:
- value:指定cookie的名称。
- required:是否必须有此cookie。
(6)@ModelAttribute
- 作用:
该注解是 SpringMVC4.3 版本以后新加入的。它可以用于修饰方法和参数。- 出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法。
- 出现在参数上,获取指定的数据给参数赋值。
- 属性:
- value:用于获取数据的 key。key 可以是 POJO 的属性名称,也可以是 map 结构的 key。
- 应用场景:
- 当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。
- 例如:
- 我们在编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许被修改的。在提交表单数据是肯定没有此字段的内容,一旦更新会把该字段内容置为 null,此时就可以使用此注解解决问题。
(7)@SessionAttribute
- 作用:
用于多次执行控制器方法间的参数共享。 - 属性:
- value: 用于指定存入的属性名称
- type: 用于指定存入的数据类型。