SpringMVC的入门
- SpringMVC的入门案例
- 开发准备
第一步:创建web工程
项目名:springmvc_day01_quickStart
指定:
Key:archetypeCatalog
Value:internal
解决web项目使用idea创建工程后,加载过慢的问题。
第二步:导入jar包
<!-- 版本锁定 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.0.2.RELEASE</spring.version>
</properties>
<dependencies>
<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>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
第三步:配置web.xml
在web.xml配置文件中核心控制器DispatcherServlet
<!-- SpringMVC的核心控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置Servlet的初始化参数,读取springmvc的配置文件,创建spring容器 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!-- 配置servlet启动时加载对象 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
第四步:配置编写springmvc.xml的配置文件
在resources下创建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">
<!-- 1:配置spring创建容器时要扫描的包,可以使用@Controller注解 -->
<context:component-scan base-package="com.itheima"></context:component-scan>
<!-- 2:配置视图解析器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 3:配置spring开启注解mvc的支持,自动开启处理器映射器和处理器适配器 -->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
第五步:创建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>
第六步:创建包com.itheima.controller,创建类HelloController.java
/**
* 控制器
*/
@Controller
public class HelloController {
// 请求参数
@RequestMapping(path = "/hello")
public String sayHello(){
System.out.println("Hello SpringMVC!!");
return "success";// 请求参数
}
}
第七步:在WEB-INF下创建pages的文件夹,创建success.jsp
<body>
<h1>访问成功</h1>
</body>
启动tomcat测试:
【配置tomcat服务器】
【配置tomcat服务器】
入门案例的执行过程分析
1:入门案例的执行流程
(1)当启动Tomcat服务器的时候,因为配置了load-on-startup标签,所以会创建DispatcherServlet对象,就会加载springmvc.xml配置文件
(2)开启了注解扫描,由于配置了@Controller,那么HelloController对象就会被创建
(3)从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解找到执行的具体方法
(4)根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称success的JSP文件
(5)Tomcat服务器渲染页面,做出响应
2:入门案例执行流程
3:SpringMVC官方提供图形
4:入门案例中的组件分析
前端控制器(DispatcherServlet)
用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。
处理器映射器(HandlerMapping)
HandlerMapping负责根据用户请求找到Handler即处理器,SpringMVC提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
返回执行链,包含两部分内容:
- 处理器对象:Handler
- HandlerInterceptor(拦截器)的集合
处理器适配器(HandlAdapter)
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
前端控制器通过HandlerAdapter(处理器适配器)对Handler进行适配包装
不同的适配器,查找不同的Handler,(即不同请求查找所对应Controller中处理的方法)
处理器(Handler)
它就是我们开发中要编写的具体业务控制器。由DispatcherServlet把用户请求转发到Handler。由Handler对具体的用户请求进行处理。
视图解析器(View Resolver)
View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。
视图(View)
SpringMVC框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是jsp。
一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
<mvc:annotation-driven>说明
在SpringMVC的各个组件中,处理器映射器、处理器适配器、视图解析器称为SpringMVC的三大组件。
使用<mvc:annotation-driven>自动加载RequestMappingHandlerMapping(处理映射器)和RequestMappingHandlerAdapter(处理适配器),可用在SpringMVC.xml配置文件中使用<mvc:annotation-driven>替代注解处理器和适配器的配置。
它就相当于在xml中配置了:
<!-- 上面的标签相当于 如下配置-->
<!-- Begin -->
<!-- HandlerMapping -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!-- HandlerAdapter -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"></bean>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<!-- HadnlerExceptionResolvers -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver"></bean>
<bean class="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver"></bean>
<!-- End -->
查看:spring-webmvc的jar包中 的AnnotationDriverBeanDefinitionParser.java的类。
注意:
一般开发中,我们都需要在springmvc.xml写上<mvc:annotation-driven>,因为它会帮助我们处理注解的一些默认配置。
RequestMapping注解
2.4.1 使用说明
源码:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
String name() default "";
@AliasFor("path")
String[] value() default {};
@AliasFor("value")
String[] path() default {};
RequestMethod[] method() default {};
String[] params() default {};
String[] headers() default {};
String[] consumes() default {};
String[] produces() default {};
}
作用:
用于建立请求URL和处理请求方法之间的对应关系
出现位置:
当该注解标注在类上:
请求URL的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头。
它出现的目的是为了使我们的URL可以按照模块化管理:
例如:
账户模块:
/account/add
/account/update
/account/delete
...
订单模块:
/order/add
/order/update
/order/delete
...
红色的部分就是把RequsetMappding写在类上,使我们的URL更加精细。
修改HelloController.java
@Controller
@RequestMapping(path = "/user")
public class HelloController {
// 请求参数
@RequestMapping(path = "/hello")
public String sayHello(){
System.out.println("Hello SpringMVC!!");
return "success";// 响应结果
}
// 请求参数
@RequestMapping(path = "/testRequestMapping")
public String testRequestMapping(){
System.out.println("Hello SpringMVC!!,测试testRequestMapping方法");
return "success";// 响应结果
}
}
访问:http://localhost:8080/springmvc_day01_quickStart/user/testRequestMapping
类上:
请求URL的第一级访问目录。
方法上:
请求URL的第二级访问目录。
属性:
value:用于指定请求的URL。它和path属性的作用是一样的。
method:用于指定请求的方式。
params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的key和value必须和配置的一模一样。
例如:
params = {"accountName"},表示请求参数必须有accountName
params = {"accountName=zhangsan"},表示请求参数中accountName的值必须是zhangsan。
params = {"accountName!zhangsan"},表示请求参数中accountName的值不能是zhangsan。
headers:用于指定限制请求消息头的条件。
注意:
以上四个属性只要出现2个或以上时,他们的关系是与的关系。
// 请求参数
@RequestMapping(path = "/testRequestMapping",method = {RequestMethod.GET},params = {"username=haha"},headers = "accept")
public String testRequestMapping(){
System.out.println("Hello SpringMVC!!,测试testRequestMapping方法");
return "success";// 响应结果
}
http://localhost:8080/springmvc_day01_quickStart/user/testRequestMapping?username=haha
要求:
1:必须是Get请求
2:必须有username=haha的参数
3:请求头必须包含accept的属性
请求参数的绑定(重点)
- 请求参数的绑定说明
(1)绑定机制
【1】表单提交的数据都是k=v格式的 username=haha&password=123
【2】SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的
【3】要求:提交表单的name和参数的名称是相同的
(2)支持的数据类型
【1】基本数据类型和字符串类型
【2】实体类型(JavaBean)
【3】集合数据类型(List、map集合等)
基本数据类型和字符串类型
(1)提交表单的name和参数的名称是相同的
(2)区分大小写
案例:
第一步:创建param.jsp
<body>
<h3>传递参数</h3>
<a href="param/testParam?username=张三&age=18">入门案例</a>
</body>
第二步:创建ParamController.java
@Controller
@RequestMapping(path = "/param")
public class ParamController {
// 请求参数
@RequestMapping(path = "/testParam")
public String testParam(String username,Integer age){
System.out.println("params测试:username:"+username+" age:"+age);
return "success";// 响应结果
}
}
实体类型(JavaBean)
(1)提交表单的name和JavaBean中的属性名称需要一致
(2)如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:对象.属性 例如:address.name
案例:
第一步:创建 com.itheima.domain,创建类User.java
public class User {
private String username;
private Integer age;
}
测试:
在Controller中定义
@RequestMapping(value = "/testParam")
public String testParam(User user){
System.out.println("欢迎执行ParamController中的testParam方法!user:"+user);
return "success";// 执行视图解析器 /WEB-INF/page/success.jsp
}
访问:
第二步:创建Account.java
指定账号对应的用户
public class Account {
private String name;
private String password;
private Double money;
private User user;
}
第三步:param.jsp
<form action="param/saveAccount" method="post">
账号:<input type="text" name="name"/><br>
密码:<input type="text" name="password"/><br>
金额:<input type="text" name="money"/><br>
用户姓名:<input type="text" name="user.username"/><br>
用户年龄:<input type="text" name="user.age"/><br>
<input type="submit" value="提交"/>
</form>
第四步:ParamController.java
@RequestMapping(path = "/saveAccount")
public String testParam(Account account){
System.out.println(account);
return "success";// 响应结果
}
请求参数中文乱码的解决
<!-- 配置过滤器,解决中文乱码的问题 -->
<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>
给集合属性数据封装(了解)
(1)JSP页面编写方式:list[0].属性
(2)JSP页面编写方式:map[‘one’].属性
第一步:param.jsp
<form action="param/saveAccount" method="post">
账号:<input type="text" name="name"/><br>
密码:<input type="text" name="password"/><br>
金额:<input type="text" name="money"/><br>
用户姓名:<input type="text" name="user.username"/><br>
用户年龄:<input type="text" name="user.age"/><br>
用户姓名(list):<input type="text" name="list[0].username"/><br>
用户年龄(list):<input type="text" name="list[0].age"/><br>
用户姓名(list):<input type="text" name="list[1].username"/><br>
用户年龄(list):<input type="text" name="list[1].age"/><br>
用户姓名(map):<input type="text" name="map['one'].username"/><br>
用户年龄(map):<input type="text" name="map['one'].age"/><br>
用户姓名(map):<input type="text" name="map['two'].username"/><br>
用户年龄(map):<input type="text" name="map['two'].age"/><br>
<input type="submit" value="提交"/>
</form>
第二步:在Account.java中添加:
private List<User> list;
private Map<String,User> map;
第三步:测试
自定义类型转换器(了解)
(1)表单提交的任何数据类型全部都是字符串类型,但是后台定义Integer类型,数据也可以封装上,说明SpringMVC框架内部会默认进行数据类型转换。
(2)如果想自定义数据类型转换,可以实现Converter的接口
第一步:在User.java中添加:
public class User {
private String username;
private Integer age;
private Date birthday;
}
第二步:param.jsp
<form action="param/saveUser" method="post">
姓名:<input type="text" name="username"/><br>
年龄:<input type="text" name="age"/><br>
生日:<input type="text" name="birthday"/><br>
<input type="submit" value="提交"/>
</form>
第三步:ParamController.java
@RequestMapping(path = "/saveUser")
public String saveUser(User user){
System.out.println(user);
return "success";// 响应结果
}
测试发现
默认支持的日期格式是:2010/11/12,如果输入2010-11-12呢?则会报错,怎么办呢?
【1】自定义类型转换器
package com.itheima.utils;
import org.springframework.core.convert.converter.Converter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 把字符串转换成日期的转换器
*/
public class StringToDateConverter implements Converter<String, Date> {
/**
* 进行类型转换的方法
*/
public Date convert(String source) {
// 判断
if(source == null) {
throw new RuntimeException("参数不能为空");
}
try {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
// 解析字符串
Date date = df.parse(source);
return date;
} catch (Exception e) {
throw new RuntimeException("类型转换错误");
}
}
}
【2】注册自定义类型转换器,在springmvc.xml配置文件中编写配置
<!-- 注册自定义类型转换器 -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.itheima.utils.StringToDateConverter"></bean>
</set>
</property>
</bean>
<!-- 配置spring开启注解mvc的支持 -->
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
再次访问:没有问题。
在控制器中使用原生的ServletAPI对象
只需要在控制器的方法参数定义HttpServletRequest和HttpServletResponse对象
第一步:param.jsp
<br>
<a href="param/testServlet">测试ServletAPI</a>
第二步:paramController.java
@RequestMapping(path = "/testServlet")
public String testServlet(HttpServletRequest request, HttpServletResponse response){
System.out.println("request:"+request);
System.out.println("session:"+request.getSession());
System.out.println("application:"+request.getSession().getServletContext());
System.out.println("response:"+response);
return "success";// 响应结果
}
测试: