1 入门程序
2 SpringMVC运行流程
3 注解
4 请求参数绑定
5 请求参数中文乱码的解决
6 自定义类型转换器
SpringMVC
WEB层框架,MVC框架
表现层:WEB层,用来和客户端进行交互的。表现层一般会采用MVC的设计模型
基于 HTTP请求响应的方式。
在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。
2、运行流程
入门程序,环境搭建
1、新建 maven 工程,打包方式 war
2、pom.xml 导入依赖坐标
<!-- 版本锁定 -->
<properties>
<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>
3、webapp---WEB-INF--web.xml 中配置前端控制器 DispatcherServlet
<servlet>
<servlet-name>自己命名(springmvc)</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!--springmvc 配置文件所在的路径-->
<param-value>classpath*:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>自己命名(springmvc)</servlet-name>
<url-parttern>/</url-parttern>
</servlet-mapping>
3、在resources里编写 springmvc 的核心配置文件: 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">
<!-- 配置spring创建容器时要扫描的包 -->
<context:component-scan base-package="com.itheima"></context:component-scan>
<!-- 配置视图解析器 -->
<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>
<!-- 配置spring开启注解mvc的支持-->
<mvc:annotation-driven/>
</beans>
配置包扫描器、视图解析器、<mvc:annotation-driven/>
配置了这句话就相当于 自动加载 RequestMappingHandlerMapping
(处理映射器)和RequestMappingHandlerAdapter
(处理适配器 )
<!-- 配置spring开启注解mvc的支持-->
<mvc:annotation-driven/>
4、编写 Controller (在类上 加 @Controller)
编写 Handler 接收请求,给出响应
@Controller 类上
@RequestMapping 方法上,也可以在类上
@RequestMapping(value="请求的url",method=RequestMethod.请求方式)
public String sayHello(){
return "success";//逻辑视图名
}
5、编写JSP页面
6、测试 tomcat 部署项目
SpringMVC运行流程
springMVC执行流程:
首先浏览器端发送一个request请求发送到前端控制器DispatcherServlet
,前端控制器了解这个请求应该由谁来处理,通过处理器映射器HandlerMapping
最终找到Controller,Controller了解这个业务的细节逻辑,就会调用业务逻辑产生业务数据,并将这个业务数据返回给前端控制器,此时前端控制将这些业务数据通过处理器适配器HandlerAdapter
返还给业务视图,由业务视图呈现页面,再将这些页面返还给前端控制器,前端控制器再把这些页面通过视图解析器ViewResolver
返回给浏览器端。
DispatcherServlet
:前端控制器
用户请求第一步到达前端控制器,相当于mvc模式中的c,它是整个流程控制的中心,由它调用其他组件完成用户的请求,它的存在降低了程序之间的耦合。
HandlerMapping
:处理器映射器
HandlerMapping负责根据用户的请求找到处理器Handler
(就是编写的具体业务处理请求的方法) ,springmvc提供了不同的映射方式 比如配置文件方式、实现接口方式、注解方式等。它返回的是一个执行链。
HandlerAdapter
:处理器适配器
适配能够处理请求的 适配器(现在用的是注解,所以使用 RequestMappingHandlerAdapter)去执行 Handler。
ModelAndView
:视图解析器
这个对象是 springmvc 提供的,负责将处理结果生成View视图,View Resolver 首先根据逻辑视图名解析成物理视图名 即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。
**View
:视图 **
无论返回是 String、还是 void、还是 ModelAndView ,Springmvc 最终都会把它封装成一个ModelAndView 对象。
InternalResourceViewResolver:视图解析器可以把 逻辑视图(字符串)变成物理视图(JSP)。可以对逻辑视图进行路径拼接 因为视图有很多种:JSP、HTML、PDF、World、Excel
注解
@RequestMapping
RequestMapping 用于简历请求URL和处理请求方法之间的对应关系。 可以标记在类和方法上,如果类和方法上都标记有该注解,则访问时需要 /类注解url/方法注解url。
注意:该注解必不可少,其 value 值不能重复
举例:
@Controller
@RequestMapping("/user")
public class UserController{
@RequestMapping("/save")
public String save(){
return null;
}
}
如上:映射请求的 URL 为 /user/save
属性:
value:用于指定请求的 URL。它和 path 属性的作用是一样的。
method:用于指定请求的方式。
params:底层字符串,用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的条件必须满足在params上字符串的条件。
headers 发送的请求中必须包含的请求头。
@RequestParam
说人话:修饰当前方法的参数
把请求中指定的名称参数给控制器中的形参赋值。
属性:
value:参数名称
requried:指定该参数是否必须
defaultValue:指定默认值
代码:
jsp 中的代码:
<!-- requestParams 注解的使用 -->
<a href="springmvc/useRequestParam?name=test">requestParam 注解</a>
控制器中的代码:
/**
* requestParams 注解的使用
*/
@RequestMapping("/useRequestParam")
public String useRequestParam(@RequestParam("name")String username,
@RequestParam(value="age",required=false)Integer age){
System.out.println(username+","+age);
return "success";
}
RequestBody
作用: 用于获取请求体内容。直接使用得到是 key=value&key=value...结构的数据。 get 请求方式不适用。
属性:
required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值 为 false,get 请求得到是 null。
代码:
post 请求 jsp代码:
<!-- request body 注解 -->
<form action="springmvc/useRequestBody" method="post">
用户名称:<input type="text" name="username" ><br/>
用户密码:<input type="password" name="password" ><br/>
用户年龄:<input type="text" name="age" ><br/>
<input type="submit" value=" 保存 ">
</form>
get 请求 jsp代码:
<a href="springmvc/useRequestBody?body=test">requestBody 注解 get 请求</a>
控制器代码:
//RequestBody 注解
@RequestMapping("/useRequestBody")
public String useRequestBody(@RequestBody(required=false) String body){
System.out.println(body);
return "success";
}
PathVariable
作用: 用于绑定 url 中的占位符。例如:请求 url 中 /delete/{id},这个{id}就是 url 占位符。 url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。它就是可以取到id里的值。
属性: value:用于指定 url 中占位符名称。 required:是否必须提供占位符。
代码:
jsp 代码:
<!-- PathVariable 注解 -->
<a href="springmvc/usePathVariable/100">pathVariable 注解</a>
控制器代码: /**
* PathVariable 注解
*/
@RequestMapping("/usePathVariable/{id}")
public String usePathVariable(@PathVariable("id") Integer id){
System.out.println(id);
return "success";
}
restFule风格:例如同一个类当中会有增删改查的方法,传统的方式路径会是:localhost:8080/路径/所执行方法。而restfule风格则是:localhost:8080/路径。至于执行哪个方法则是又方法访问方式所决定 比如查询用get、新增用post、更新用put等,到时候用的时候通过获取请求方式来判断到底执行路径下的哪个方法。
查询的方式有根据ID查询和查询全部,如果是这样,单独通过请求方式就无法判断执行的是哪个方法了,所以这时候会在根据id查询的方法路径后面放一个{id},这样就能区分了。
HiddenHttpMethodFilter(不重要)
作用:由于浏览器的form表单只支持GET和post请求,而DELETE/PUT等method不支持, 所以spring3.0添加了过滤器HiddenHttpMethodFilter
,它可以将浏览器请求改为指定的请求方式。
修改方法:
1 在web.xml 中配置 过滤器 HiddenHttpMethodFilter。
2 请求发过货四必须用psot请求。
3 按照提供的method请求参数,该参数的值就是我们需要请求的方式。
tomcat8 不兼容 put 跟 delete 请求,需要更换成 tomcat7
在 restful 中,请求与方式相对应
GET:查询
POST:新增
PUT:更新
DELETE:删除
jsp 中示例代码:
<!-- 保存 -->
<form action="springmvc/testRestPOST" method="post">
用户名称:<input type="text" name="username"><br/>
<!-- <input type="hidden" name="_method" value="POST"> -->
<input type="submit" value=" 保存 ">
</form>
<hr/>
<!-- 更新 -->
<form action="springmvc/testRestPUT/1" method="post">
用户名称:<input type="text" name="username"><br/>
<input type="hidden" name="_method" value="PUT">
<input type="submit" value=" 更新 ">
</form>
<hr/>
<!-- 删除 -->
<form action="springmvc/testRestDELETE/1" method="post">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value=" 删除 ">
</form>
<hr/>
<!-- 查询一个 -->
<form action="springmvc/testRestGET/1" method="post">
<input type="hidden" name="_method" value="GET">
<input type="submit" value=" 查询 ">
</form>
控制器中示例代码:
/**
* post 请求:保存 .
*/
@RequestMapping(value="/testRestPOST",method=RequestMethod.POST)
public String testRestfulURLPOST(User user){
System.out.println("rest post"+user);
return "success";
}
/**
* put 请求:更新
*/
@RequestMapping(value="/testRestPUT/{id}",method=RequestMethod.PUT)
public String testRestfulURLPUT(@PathVariable("id")Integer id,User user){
System.out.println("rest put "+id+","+user);
return "success";
}
/**
* post 请求:删除
*/ @RequestMapping(value="/testRestDELETE/{id}",method=RequestMethod.DELETE)
public String testRestfulURLDELETE(@PathVariable("id")Integer id){
System.out.println("rest delete "+id);
return "success";
}
/**
* post 请求:查询
*/
@RequestMapping(value="/testRestGET/{id}",method=RequestMethod.GET)
public String testRestfulURLGET(@PathVariable("id")Integer id){
System.out.println("rest get "+id);
return "success";
}
RequestHeader
作用: 用于获取请求消息头。
属性: value:提供消息头名称
required:是否必须有此消息头
注: 在实际开发中一般不怎么用。
CookieValue
作用: 用于把指定 cookie 名称的值传入控制器方法参数。
属性: value:指定 cookie 的名称。
required:是否必须有此 cookie。
注: 在实际开发中一般不怎么用。
ModelAttribute
作用:出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可 以修饰有具体返回值的方法。 出现在参数上,获取指定的数据给参数赋值。
属性: value:用于获取数据的 key。key 可以是 POJO 的属性名称,也可以是 map 结构的 key。
应用场景: 当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。
我们在编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许被修改的。在提交表单数据是肯定没有此字段的内容,一旦更新会把该字段内容置为 null,此时就可以使用此注解解决问题。
基于 POJO 属性的基本使用:
jps 代码:
<!-- ModelAttribute 注解的基本使用 -->
<a href="springmvc/testModelAttribute?username=test">测试 modelattribute</a>
控制器代码:
/**
* 被 ModelAttribute 修饰的方法
*/
@ModelAttribute
public void showModel(User user) {
System.out.println("执行了 showModel 方法"+user.getUsername());
}
/**
* 接收请求的方法
*/
@RequestMapping("/testModelAttribute")
public String testModelAttribute(User user) {
System.out.println("执行了控制器的方法"+user.getUsername());
return "success";
}
SessionAttribute
作用: 用于多次执行控制器方法间的参数共享。
属性: value:用于指定存入的属性名称
type:用于指定存入的数据类型
jsp 中的代码:
<!-- SessionAttribute 注解的使用 -->
<a href="springmvc/testPut">存入 SessionAttribute</a> <hr/>
<a href="springmvc/testGet">取出 SessionAttribute</a> <hr/>
<a href="springmvc/testClean">清除 SessionAttribute</a>
控制器中的代码:
/**
* SessionAttribute 注解的使用
*/
@Controller("sessionAttributeController")
@RequestMapping("/springmvc")
@SessionAttributes(value ={"username","password"},types={Integer.class})
public class SessionAttributeController {
/**
* 把数据存入 SessionAttribute
* Model 是 spring 提供的一个接口,该接口有一个实现类 ExtendedModelMap
* 该类继承了 ModelMap,而 ModelMap 就是 LinkedHashMap 子类
*/
@RequestMapping("/testPut")
public String testPut(Model model){
model.addAttribute("username", "泰斯特");
model.addAttribute("password","123456");
model.addAttribute("age", 31);
//跳转之前将数据保存到 username、password 和 age 中,因为注解
// @SessionAttribute 中有 这几个参数
return "success";
}
@RequestMapping("/testGet")
public String testGet(ModelMap model){
System.out.println(model.get("username")+";"+model.get("password")+";"+model.get("a ge"));
return "success";
}
@RequestMapping("/testClean")
public String complete(SessionStatus sessionStatus){
sessionStatus.setComplete();
return "success";
}
}
请求参数绑定
请求参数的绑定说明:
1 绑定机制:表单提交的数据都是k=v格式的 username=haha&password=123
2 SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的。
3 要求:提交表单的name和参数的名称是相同的 。
支持的数据类型:
1 基本数据类型和字符串类型
2 实体类型(JavaBean)
3 集合数据类型(List、map集合等)
基本数据类型和字符串类型
1 提交表单的name和参数的名称是相同的
2 区分大小写
实体类型(JavaBean)
1 提交表单的name和JavaBean中的属性名称需要一致
2 如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:对象.属性 例如: address.name
给集合属性数据封装
JSP页面编写方式:list[0].属性 。
支持的数据类型:
基本类型参数: 包括基本类型和 String 类型
POJO 类型参数: 包括实体类,以及关联的实体类
数组和集合类型参数: 包括 List 结构和 Map 结构的集合(包括数组)
SpringMVC 绑定请求参数是自动实现的,但是要想使用,必须遵循使用要求。
基本类型和 String 类型作为参数 :
jsp 代码:
<!-- 基本类型示例 -->
<a href="account/findAccount?accountId=10&accountName=zhangsan">查询账户</a>
控制器代码:
/**
* 查询账户
* @return
*/
@RequestMapping("/findAccount")
public String findAccount(Integer accountId,String accountName) {
System.out.println("查询了账户。。。。"+accountId+","+accountName);
return "success";
}
POJO 类型作为参数
实体类代码:
/**
* 账户信息
*/
public class Account implements Serializable {
private Integer id;
private String name;
private Float money;
private Address address;
//此处省略getters and setters
}
/**
* 地址的实体类
*/
public class Address implements Serializable {
private String provinceName;
private String cityName;
//此处省略getters and setters
}
jsp 代码:
<!-- pojo 类型演示 -->
<form action="account/saveAccount" method="post">
账户名称:<input type="text" name="name" ><br/>
账户金额:<input type="text" name="money" ><br/>
账户省份:<input type="text" name="address.provinceName" ><br/>
账户城市:<input type="text" name="address.cityName" ><br/>
<input type="submit" value=" 保存 "> </form>
控制器代码:
/**
* 保存账户
*/
@RequestMapping("/saveAccount")
public String saveAccount(Account account) {
System.out.println("保存了账户。。。。"+account);
return "success";
}
POJO 类中包含集合类型参数
实体类代码:
/**
* 用户实体类
*/
public class User implements Serializable {
private String username;
private String password;
private Integer age;
private List<Account> accounts;
private Map<String,Account> accountMap;
//此处省略getters and setters
@Override
public String toString() {
return "User [username=" + username + ", password=" + password + ", age=" + age + ",\n accounts=" + accounts
+ ",\n accountMap=" + accountMap + "]";
}
}
jsp 代码:
<!-- POJO 类包含集合类型演示 -->
<form action="account/updateAccount" method="post">
用户名称:<input type="text" name="username" ><br/>
用户密码:<input type="password" name="password" ><br/>
用户年龄:<input type="text" name="age" ><br/>
账户 1 名称:<input type="text" name="accounts[0].name" ><br/>
账户 1 金额:<input type="text" name="accounts[0].money" ><br/>
账户 2 名称:<input type="text" name="accounts[1].name" ><br/>
账户 2 金额:<input type="text" name="accounts[1].money" ><br/>
账户 3 名称:<input type="text" name="accountMap['one'].name" ><br/>
账户 3 金额:<input type="text" name="accountMap['one'].money" ><br/>
账户 4 名称:<input type="text" name="accountMap['two'].name" ><br/>
账户 4 金额:<input type="text" name="accountMap['two'].money" ><br/>
<input type="submit" value=" 保存 "> </form>
控制器代码:
/**
* 更新账户
*/
@RequestMapping("/updateAccount")
public String updateAccount(User user) {
System.out.println("更新了账户。。。。"+user);
return "success";
}
请求参数中文乱码的解决
- 在web.xml中配置Spring提供的过滤器类
<!-- 配置过滤器,解决中文乱码的问题 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filterclass>
<!-- 指定字符集 -->
<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 cn.itcast.utils;
import java.text.DateFormat; import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.core.convert.converter.Converter;
/**
* 把字符串转换成日期的转换器
*/
public class StringToDateConverter implements Converter<String, Date>{
/**
* 进行类型转换的方法
* String:传进来的字符串
*/
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("类型转换错误");
}
}
}
注册自定义类型转换器,在springmvc.xml配置文件中编写配置
<!-- 注册自定义类型转换器 -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="cn.itcast.utils.StringToDateConverter"/>
</set>
</property>
</bean>
<!-- 开启Spring对MVC注解的支持 -->
<mvc:annotation-driven conversion-service="conversionService"/>
在控制器中使用原生的ServletAPI对象
只需要在控制器的方法参数定义HttpServletRequest和HttpServletResponse对象