大纲:
- 三层架构
- SpringMVC的入门案例
- 入门案例的执行流程以及组件分析
- 请求参数的绑定
请求参数乱码的解决 ;请求参数的类型转换 - 常用的注解
1.三层架构与SpringMVC
1.1三层架构
- 表现层:WEB层,用来和客户端进行数据交互的。表现层一般会采用MVC的设计模型
- 业务层:处理公司具体的业务逻辑的
- 持久层:用来操作数据库的
1.2MVC
- MVC全名是Model View Controller 模型视图控制器,每个部分各司其职。
- Model:数据模型,JavaBean的类,用来进行数据封装。
- View:指JSP、HTML用来展示数据给用户
- Controller:用来接收用户的请求,整个流程的控制器。用来进行数据校验等。
1.3SpringMVC梗概
SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架
SpringMVC在三层架构中的位置 :表现层框架
2.SpringMVC入门案例
2.1IDEA创建SpringMVC
(1) 在IDEA中新建模块或则工程,选择的时候需使用骨架构建:选择webapp
(2) 填写项目的组名称、项目名称、版本号 ,也可以选择父模块
(3) 填写对应的maven信息,为了maven创建的项目骨架构建项目更快,我们可以添加属性:
archetypeCatalog - internal
(4) 创建好项目之后,可能出现项目目录不全,我们需要自己创建目录,补全的目录如下:
(5) 创建好目录后,点击java目录,无法创建.class文件,我们需要进行下列操作:将java目录设置为Sources Root,resources设置为Resources Root,webapp目录需要在项目工程中设置为web。这样才可以在java目录下创建.java文件,resources会作为资源目录,webapp下可以创建jsp、html等前端页面。
(6) 添加依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.20.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.20.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.0.20.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
</dependency>
</dependencies>
(7) 在web.xml文件中创建前端控制器
<!--前端控制器-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--web项目启动后会读取web.xml的内容,就会加载springMVC.xml文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<!--resource目录下的配置文件:springMVC.xml-->
<param-value>classpath:springMVC.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!---所有的请求-->
<url-pattern>/</url-pattern>
</servlet-mapping>
(8) springMVC.xm文件配置,开启包扫描、配置视图解析器、开启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">
<!--读取注解,因为是MVC的文件,所以只读取控制层-->
<context:component-scan base-package="com.Eheart.controller">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--视图解析器,
如果Controller返回的数据类型是String,比如说:success,经过视图解析器会将结果拼接为:/WEB-INF/pages/success.jsp,
此时需要保证存在对应的jsp文件-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--mvc开启对注解的支持-->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
(9) 在java的目录下创建控制层:com.Eheart.controllers.HelloController.java文件
@Controller
@RequestMapping("/hello")
public class HelloController {
///访问接口的路径应该是:http://地址:端口/项目名称/hello/sayhello
@RequestMapping("/sayhello")
public String sayHello(){
System.out.println("Hello .....");
return "success";
}
}
(10) 将web项目部署到tomcat服务器上,部署完成后可以修改对应的路径名(访问接口的时候会用到)和服务名称
(11)前端页面的配置
- 确保webapp目录下存在index.jsp文件,tomcat服务启动的时候会访问该文件,其页面内容如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Index</title>
</head>
<body>
<h5>Index页面</h5>
<!--此处是通过相对路径访问的,前面不需要加 / -->
<a href="hello/sayhello">helloController</a>
</body>
</html>
- 在WEB-INF目录下创建目录pages,在pages下创建success.jsp(当前面定义的控制层返回success的时候会跳到该成功页面)
(12) 启动服务,web服务启动后会跳到index,jsp界面
- 点击helloController,会访问后台的接口helloController,后台打印出:Hello … ,前台跳到success.jsp页面。
当点击helloController超链接,后台打印出:Hello … ,前台跳到success.jsp页面。就可以说明:SpringMVC的入门案例搭建成功了。
2.2 入门案例的执行流程
(1)入门案例执行流程粗略的分析:
- 当启动Tomcat服务器的时候,因为配置了load-on-startup标签,所以会创建DispatcherServlet对象, 就会加载springmvc.xml配置文件
- 开启了注解扫描,那么HelloController对象就会被创建
- 从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMappin注解 找到执行的具体方法
- 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件
- Tomcat服务器渲染页面,做出响应
(2)SpringMVC组件分析入门案例
(3)入门案例时序图
2.3入门案例中的组件分析
- 前端控制器(DispatcherServlet)
控制整个流程的执行
用户请求到达前端控制器,它就相当于 mvc 模式中的 c,dispatcherServlet 是整个流程控制的中心,由 它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。 - 处理器映射器(HandlerMapping)
根据请求获取到对应Controller的方法
HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的 映射方式,例如:配置文件方式,实现接口方式,注解方式等。 - 处理器(Handler)
执行handler的方法
它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由
Handler 对具体的用户请求进行处理。 - 处理器适配器(HandlAdapter)
将任何的Controller的方法适配成Handler
通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理 器进行执行。 - 视图解析器(View Resolver)
根据视图解析器的前缀后缀和controller返回的结果,可以跳转到具体的页面
View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名 即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。 - 视图(View)
SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView
等。我们最常用的视图就是 jsp。
一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开 发具体的页面。
2.4 < mvc:annotation-driven>
在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。
使 用 mvc:annotation-driven 自动加载 RequestMappingHandlerMapping (处理映射器) 和 RequestMappingHandlerAdapter ( 处 理 适 配 器 ) , 可 用 在 SpringMVC.xml 配 置 文 件 中 使 用 mvc:annotation-driven替代注解处理器和适配器的配置。
3.RequestMapping注解
- RequestMapping注解的作用是建立请求URL和处理方法之间的对应关系
- RequestMapping注解可以作用在方法和类上
- 作用在类上:第一级的访问目录
- 作用在方法上:第二级的访问目录
- 细节:路径可以不编写 / 表示应用的根目录开始
- 细节:${ pageContext.request.contextPath }也可以省略不写,但是路径上不能写 /
- RequestMapping的属性
- path 指定请求路径的url
- value value属性和path属性是一样的
- mthod 指定该方法的请求方式 :post、get
- params 指定限制请求参数的条件 :
- headers 发送的请求中必须包含的请求头
@Controller
@RequestMapping("/hello")
public class HelloController {
@RequestMapping("/sayhello")
public String sayHello(){
System.out.println("Hello .....");
return "success";
}
}
<body>
<h5>Index页面</h5>
<!--1.此处是通过相对路径访问的,前面不需要加 / -->
<a href="hello/sayhello">相对路径:helloController</a>
<!--2.此处是通过绝对路径访问的 / -->
<a href="${pageContext.request.contextPath}/hello/sayhello">绝对路径helloController</a>
</body>
4.请求参数的绑定
4.1支持的数据类型
- 基本类型参数:
包括基本类型和 String 类型 - POJO 类型参数:
包括实体类,以及关联的实体类 - 数组和集合类型参数:
包括 List 结构和 Map 结构的集合(包括数组) - ServletAPI作为请求参数
SpringMVC 还支持使用原始 ServletAPI 对象作为控制器方法的参数。支持原始 ServletAPI 对象有:
HttpServletRequest
HttpServletResponse
HttpSession
java.security.Principal
Locale
InputStream
OutputStream
Reader
Writer
我们可以把上述对象,直接写在控制的方法参数中使用。
4.2使用要求
如果是基本类型或者 String 类型:
要求我们的参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写)
如果是 POJO 类型,或者它的关联对象:
- 提交表单的name和JavaBean中的属性名称需要一致
- 如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:对象.属性 例如:
address.name
如果是集合类型,有两种方式:
- 第一种: 要求集合类型的请求参数必须在 POJO 中。在表单中请求参数名称要和 POJO 中集合属性名称相同。 给 List 集合中的元素赋值,使用下标。 给 Map 集合中的元素赋值,使用键值对。 JSP页面编写方式:list[0].属性
- 第二种: 接收的请求参数是 json 格式数据。需要借助一个注解实现。
<!--测试请求参数-->
<a href="testParamController/testStringParam?id=1&username=张三">testStringParam</a>
<form action="testParamController/testPojoParam" method="post">
username: <input type="text" name="username" /><br/>
password: <input type="text" name="password" /><br/>
date: <input type="text" name="date" /><br/>
<input type="submit" value="提交"/>
</form>
@RequestMapping("/testStringParam")
public String testStringParam(Integer id,String username ){
System.out.println("id : " +id);
System.out.println("username : " +username);
return "success";
}
@RequestMapping("/testPojoParam")
public String testPojoParam(User user){
System.out.println(user);
return "success";
}
@RequestMapping("/testParamServlet")
public String testParamServlet(HttpServletRequest request, HttpServletResponse response, HttpSession session){
System.out.println(request );
System.out.println(response );
System.out.println(session );
return "success";
}
4.3请求参数乱码的问题解决:
- post请求方式在web.xml中配置Spring提供的过滤器类
<!--通过过滤器配置编码格式,解决post请求乱码的问题-->
<filter>
<filter-name>encoding</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>encoding</filter-name>
<!--过滤所有的请求,当然有些静态资源是不需要过滤的,我们可以在bean.xml中设置-->
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--在bean.xml文件中,进行配置:静态资源不会过滤-->
<!-- location 表示路径,mapping 表示文件,**表示该目录下的文件以及子目录的文件 -->
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/images/" mapping="/images/**"/>
<mvc:resources location="/scripts/" mapping="/javascript/**"/>
- get请求解决乱码
tomacat 对 GET 和 POST 请求处理方式是不同的,GET 请求的编码问题,要改 tomcat 的 server.xml
配置文件,如下:
<Connector connectionTimeout="20000" port="8080"
protocol="HTTP/1.1" redirectPort="8443"/>
改为:
<Connector connectionTimeout="20000" port="8080"
protocol="HTTP/1.1" redirectPort="8443"
useBodyEncodingForURI="true"/>
如果遇到 ajax 请求仍然乱码,请把:
useBodyEncodingForURI="true"改为 URIEncoding="UTF-8"
即可。
4.4自定义类型转换
<a href="testParamController/testCustomeConvert?date=2022-02-01">自定义类型转换器</a>
@RequestMapping("/testCustomeConvert")
public String testCustomeConvert(@RequestParam(name = "date") Date date){
System.out.println("testCustomeConvert , "+ date );
return "success";
}
当我们控制层接口的参数是Date类型,传递的是String类型的字符串,这样会出现类型转换异常。String类型无法直接转换为Date类型。
Failed to bind request element: org.springframework.web.method.annotation.MethodArgumentTypeMismatchException:
Failed to convert value of type ‘java.lang.String’ to required type ‘java.util.Date’; nested exception is
因为无法直接转换,我们需要。
1. 定义一个自定义类型转换器
public class StringToDateConvert implements Converter<String , Date> {
@Override
public Date convert(String s) {
Date parse = null;
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
try {
parse = simpleDateFormat.parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
return parse;
}
}
- 在bean.xml中定义类型转换器,同时引用配置的类型转换服务
<!--配置自定义类型转换器-->
<bean id="converterService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<array>
<bean class="com.Eheart.util.StringToDateConvert"></bean>
</array>
</property>
</bean>
<!--在 annotation-driven 标签中引用配置的类型转换服务-->
<mvc:annotation-driven conversion-service="converterService"></mvc:annotation-driven>
5.常用注解
5.1 RequestParam
- 作用:
把请求中指定名称的参数给控制器中的形参赋值。 - 属性:
value:请求参数中的名称。
required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。
5.2RequestBody
- 作用:
用于获取请求体内容。直接使用得到是 key=value&key=value…结构的数据。
get 请求方式不适用。 - 属性:
required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值为 false,get 请求得到是 null。
5.3PathVaribale
- 作用:
用于绑定 url 中的占位符。例如:请求 url 中 /delete/{id},这个{id}就是 url 占位符。
url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。 - 属性:
value:用于指定 url 中占位符名称。
required:是否必须提供占位符。
5.4RequestHeader
- 作用:
用于获取请求消息头。 - 属性:
value:提供消息头名称
required:是否必须有此消息头
注:
在实际开发中一般不怎么用。
5.5CookieValue
- 作用:
用于把指定 cookie 名称的值传入控制器方法参数。 - 属性:
value:指定 cookie 的名称。
required:是否必须有此 cookie。
@RequestMapping("/testCookieValue")
public String testCookieValue(@CookieValue(value = "JSESSIONID",required = false) String cookieValue){
System.out.println("testCookieValue , "+ cookieValue );
return "success";
}
5.6ModelAttribute
1.在控制层中被 @ModelAttribute修饰的方法会先于Controller的方法执行。
5.7SessionAttribute
- 作用:
用于多次执行控制器方法间的参数共享。 - 属性:
value:用于指定存入的属性名称
type:用于指定存入的数据类型。
@RequestMapping("/testModel")
@SessionAttributes(value ={"username","password"},types={Integer.class})
@Controller
public class testModel {
/**
* Model 是 spring 提供的一个接口,该接口有一个实现类 ExtendedModelMap
* 该类继承了 ModelMap,而 ModelMap 就是 LinkedHashMap 子类
* @param model
* @return
*/
@RequestMapping("/testPut")
public String testPut(Model model){
model.addAttribute("username","张三");
model.addAttribute("password","123465");
return "success";
}
@RequestMapping("/testGet")
public String testGet(ModelMap modelMap){
System.out.println(modelMap.get("username") + " : " + modelMap.get("password"));
return "success";
}
@RequestMapping("/testClean")
public String complete(SessionStatus sessionStatus){
sessionStatus.setComplete();
return "success";
}
}
<h5>ModelAttribute</h5>
<a href="testModel/testPut">testPut</a><br/>
<a href="testModel/testGet">testGet</a><br/>
<a href="testModel/testClean">testClean</a><br/>