SpringMVC-HMday01–01-基本概念-入门-请求参数的绑定
1.三层架构和MVC
1.1 三层架构
- 我们的开发架构一般都是基于两种形式,一种是 C/S 架构,也就是客户端/服务器,另一种是 B/S 架构,也就是浏览器服务器。在 JavaEE 开发中,几乎全都是基于 B/S 架构的开发。在 B/S 架构中,系统标准的三层架构,包括:表现层、业务层、持久层。三层架构在我们的实际开发中使用的非常多,所以我们课程中的案例也都是基于三层架构设计的。
- 三层架构中,每一层各司其职,接下来我们就说说每层都负责哪些方面:
-
表现层:
也就是我们常说的web层。它负责接收客户端请求,向客户端响应结果,通常客户端使用http协议请求web 层,web 需要接收 http 请求,完成 http 响应。- 表现层包括展示层和控制层:控制层负责接收请求,展示层负责结果的展示。
- 表现层依赖业务层,接收到客户端请求一般会调用业务层进行业务处理,并将处理结果响应给客户端。
- 表现层的设计一般都使用 MVC 模型。(MVC 是表现层的设计模型,和其他层没有关系)
-
业务层:
也就是我们常说的 service 层。它负责业务逻辑处理,和我们开发项目的需求息息相关。web 层依赖业务层,但是业务层不依赖 web 层。- 业务层在业务处理时可能会依赖持久层,如果要对数据持久化需要保证事务一致性。(也就是我们说的,事务应该放到业务层来控制)
-
持久层:
也就是我们是常说的 dao 层。负责数据持久化,包括数据层即数据库和数据访问层,数据库是对数据进行持久化的载体,数据访问层是业务层和持久层交互的接口,业务层需要通过数据访问层将数据持久化到数据库中。通俗的讲,持久层就是和数据库交互,对数据库表进行曾删改查的。
-
1.2 MVC模型
- MVC 全名是 Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是一种用于设计创建 Web 应用程序表现层的模式。MVC 中每个部分各司其职:
- Model(模型):
通常指的就是我们的数据模型。作用一般情况下用于封装数据。 - View(视图):
通常指的就是我们的 jsp 或者 html。作用一般就是展示数据的。
通常视图是依据模型数据创建的。 - Controller(控制器):
是应用程序中处理用户交互的部分。作用一般就是处理程序逻辑的。它相对于前两个不是很好理解,这里举个例子:- 例如:
我们要保存一个用户的信息,该用户信息中包含了姓名,性别,年龄等等。
这时候表单输入要求年龄必须是 1~100 之间的整数。姓名和性别不能为空。并且把数据填充到模型之中。
此时除了 js 的校验之外,服务器端也应该有数据准确性的校验,那么校验就是控制器的该做的。
当校验失败后,由控制器负责把错误页面展示给使用者。
如果校验成功,也是控制器负责把数据填充到模型,并且调用业务层实现完整的业务需求。
- 例如:
- Model(模型):
2 SpringMVC概述
2.1 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 编程风格的请求。
2.2 SpringMVC 在三层架构的位置
2.3 SpringMVC 的优势
- 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 编写更容易。
- 11、如RESTful风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配置支持等等。
3.SpringMVC的入门
3.1 创建maven-web项目
- 第一步:File–>New–>Priject
- 第二步:选择maven–>选择jdk1.8–>勾选Create from archetype–>选择maven-webapp
- 第三步: 项目名称 工作空间
- 第四步:添加 Properties–>archetypeCatalog
- 解决maven网络下载缓慢问题,将archetype-catalog文件放在maven仓库根目录下
- name : archetypeCatalog
- value : internal
- 第五步:修改项目目录
- main目录添加java和resources文件
- 第六步:删除index.jsp 重新创建index.jsp
- 第七步 :在WEB-INF目录下创建–>pages目录—>创建–>success.jsp
- 第八步:编写web.xml文件
<!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>
<!--全局初始化参数:加载springmvc的配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvcConfig.xml</param-value>
</init-param>
<!--启动服务器时间。就创建DispatcherServlet类的实例对象
如果不配置,就是在DispatcherServlet类接收到请求之后才会创建其类的实例对象
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- 第九步:java目录下创建包—> com.zzy.controller
3.2 导入依赖
- 第一步:删除pom文件中的junit包,同时将编译版本改为1.8
- 第二步:添加依赖
<properties>
<!--Spring版本锁定-->
<spring.version>5.0.2.RELEASE</spring.version>
</properties>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
</dependency>
3.3 编写核心配置文件springmvcConfig.xml
- 第一步:在resources–>创建springmvcConfig,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">
<!--开始注解扫描-->
<context:component-scan base-package="com.zzy"/>
<!--配置驶入解析器-->
<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/>
</beans>
3.4 编写代码
- 第一步 :创建HelloController
package com.zzy.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
@RequestMapping("/hello")
public String helloController(){
System.out.println("输出正常");
return "success";
}
}
- 第二步:编写index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>入门案例</h3>
<a href="/hello">入门程序</a>
</body>
</html>
- 第三步:编写success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>入门成功了</h3>
</body>
</html>
- 第四步:配置tomcat服务器
- 第五步:启动服务器
服务启动成功,自动跳转
- 第六步:测试项目
地址栏输入:localhost:8080/hello
页面输出
查看控制台输出
3.5 入门流程说明
- 入门案例的执行流程
-
- 当启动Tomcat服务器的时候,因为配置了load-on-startup标签,所以会创建DispatcherServlet对象,就会加载springmvc.xml配置文件
-
- 开启了注解扫描,那么HelloController对象就会被创建
-
- 从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解
找到执行的具体方法
- 从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解
-
- 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件
-
- Tomcat服务器渲染页面,做出响应
4.springMVC的工作流程
4.1 执行流程
- 1、 用户发送请求至前端控制器DispatcherServlet。
- 2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。
- 3、 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
- 4、 DispatcherServlet调用HandlerAdapter处理器适配器。
- 5、 HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
- 6、 Controller执行完成返回ModelAndView。
- 7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
- 8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器。-
- 9、 ViewReslover解析后返回具体View。
- 10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
- 11、 DispatcherServlet响应用户。
4.2 组件介绍
- 1 前端控制器DispatcherServlet(不需要工程师开发),由框架提供
- 作用:接收请求,响应结果,相当于转发器,中央处理器。
- 有了dispatcherServlet减少了其它组件之间的耦合度。用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性
- 2 处理器映射器HandlerMapping(不需要工程师开发),由框架提供
- 作用:根据请求的url查找Handler
- HandlerMapping负责根据用户请求找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
- 3 处理器适配器HandlerAdapter
- 作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler
- 通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
-
4、处理器Handler(需要工程师开发–也就是Controller)
- 注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler
- Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。由于Handler涉及到具体的用户业务请求,所以一般情况需要工程师根据业务需求开发Handler。
-
5、视图解析器View resolver(不需要工程师开发),由框架提供
- 作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)
- View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。
-
6、视图View(需要工程师开发jsp…)
- View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf…)
5.RequestMapping注解说明
5.1 RequestMapping注解的作用是建立请求URL和处理方法之间的对应关系**
5.2 RequestMapping可以作用在方法和类上
- 1、作用在类上:表示第一级的访问目录
- 2、作用在方法上:表示第二季的访问目录
- 3、细节:请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以 / 开头,它出现的目的是为了使我们的 URL 可以按照模块化管理
- 账户模块:
/account
/add
/account
/update
/account
/delete
…
订单模块:
/order
/add
/order
/update
/order
/delete - 红色的部分就是把 RequsetMappding 写在类上,使我们的 URL 更加精细
- 账户模块:
- 4、细节:${pageContext.request.contextPath}也可以省略不写,但是路径上不能写/
5.3 RequestMapping的属性
- 1、path:指定请求路径的url
- 2、value:value属性和path属性是一样的
- 3、method:指定该方法的请求方式
- 4、params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和配置的一模一样,
- 5、headers:发送的请求中必须包含的请求头
5.请求参数的绑定
5.1 请求参数的绑定说明
5.1.1 绑定机制
- 1 、表单提交的数据都是k=v格式,比如username=张三&password =123
- 2 、springMVC的参数绑定过程就是把表单提交的请求参数表,作为控制器中的方法的参数进行绑定
- 3 、要求:提交表单的name和参数的名称是相同的
5.1.2 支持的数据类型
- 1、基本数据类型和字符串类型
- 2、字体类型(javaBean)
- 3、集合数据类型(List map集合等)
5.2 基本数据类型和字符串类型
- 1、提交表单的name和参数的名称是相同的
- 2、区分大小写
param.jsp
<%--简单的请求参数绑定--%>
<a href="param/testParam?username=tom&password=123">请求参数绑定</a>
5.3 实体类型(JavaBean)—dept.jsp
- 1、提交表单的name和JavaBean中的属性名称要一致
acount.jsp
<%--表单提交实体类JavaBean
name属性和实体类的属性名称要对应一致
--%>
<form action="param/saveAcount" method="post">
用户名:<input type="text" name="username">
密码:<input type="text" name="password">
金额:<input type="text" name="money">
提交:<input type="submit" value="提交">
</form>
- 2、如果一个JavaBean中包含其他的引用类型,那么表单的name属性要编写成:对象.属性
dept.jsp
<%--单提交实体类JavaBean,对象嵌套对象--%>
<form action="param/saveDept" method="post"/>
部门名称:<input type="text" name="dname"/><br/>
部门编号:<input type="text" name="did"/><br/>
部门地址:<input type="text" name="daddress"/><br/>
用户姓名:<input type="text" name="user.uname"/><br/>
用户年龄:<input type="text" name="user.age"/><br/>
提交:<input type="submit" value="提交"/><br/>
</form>
5.4 配置解决中文乱码(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>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
5.5 给集合属性数据封装
- 1、JSP页面编写方式:list[0].属性
company.jsp
<%--单提交实体类JavaBean,包含list和map属性--%>
<form action="/param/saveCollection" method="post">
公司名称:<input type="text" name="name"><br/>
公司地址:<input type="text" name="add"><br/>
公司市值:<input type="text" name="money"><br/>
用户姓名:<input type="text" name="list[0].uname"/><br/>
用户年龄:<input type="text" name="list[0].age"/><br/>
用户姓名:<input type="text" name="map['one'].uname"/><br/>
用户年龄:<input type="text" name="map['one'].age"/><br/>
提交:<input type="submit" value="提交"/><br/>
</form>
5.6 自定义类型转换器
- 1、表单提交的任何数据类型都是字符串类型,但是后台定义integer类型,数据也可以封装上,说明spring框架内部会默认进行数据类型转换
- 2、 如果想自定义数据尅性转换,需要实现controller接口
5.6.1 编写自定义类型转换器工具类
package com.zzy.utils;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 将表单提交的字符串转换成后台可以接收的日期类型
*/
public class StringToDateComverter implements Converter<String,Date>{
/**
*
* @param source 表示传递进来的字符串
* @return
*/
@Override
public Date convert(String source) {
//判断
if (source == null) {
throw new RuntimeException("请您传入数据");
}
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
//把字符串转换为日期
try {
return simpleDateFormat.parse(source);
} catch (ParseException e) {
throw new RuntimeException("数据类型转换出现错误");
}
}
}
5.6.2 在springmvc.xml中配置自定义转换器
<!--配置自定义类型转换器-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.zzy.utils.StringToDateComverter"/>
</set>
</property>
</bean>
<!--开启springmvc注解支持-->
<mvc:annotation-driven conversion-service="conversionService"/>
5.6.3 编写emp.jsp
<%--自定义类型转换器--%>
<form action="/param/saveEmp" method="post">
员工姓名:<input type="text" name="ename"/><br/>
员工编号:<input type="text" name="eid"/><br/>
员工生日:<input type="text" name="date"/><br/>
提交:<input type="submit" value="提交">
</form>
5.6.4 编写controller
/**
* 自定义类型转换器
* @param emp
* @return
* http://localhost:8088/emp.jsp
* http://localhost:8088/param/saveEmp
*/
@RequestMapping("/saveEmp")
public String saveCompany(Emp emp){
System.out.println("执行了");
System.out.println(emp);
return "success";
}
5.6.5 运行访问输出结果
- 1、运行服务器
- 2、浏览器访问: http://localhost:8088/emp.jsp
- 3、输入表单内容,日期格式yyyy-MM-dd
- 4、查看控制台输出
- 5、正常格式/异常格式
正常格式:yyyy/MM/dd
异常格式:yyyy-MM-dd (会报如下错误,需要做自定义转换)
5.7 测试Servlet原生的API
` 1、编写servlet.jsp文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--测试servlet的原生的API--%>
<a href="param/testServletAPI">测试servlet的原生的API</a>
</body>
</html>
- 2、编写原生代码
/**
* 测试Servlet原生的API
* @return
*/
@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request,
HttpServletResponse response,
HttpSession session){
System.out.println("执行了");
//输出request对象
System.out.println(request);
//输出session对象
System.out.println(session);
//获取输出session1对象
HttpSession session1 = request.getSession();
System.out.println(session1);
//比较对象 true
System.out.println(session==session1);
//获取输出最大作用域ServletContext
ServletContext servletContext = session.getServletContext();
System.out.println(servletContext);
//输出response对象
System.out.println(response);
return "success";
}
- 3、输出结果
- Servlet的四大作用域
- applicationContext > session > request > pageContext
- 可以通过小范围的作用域get到大范围的作用域