SpringMVC
- SpringMVC基本概念(一)三层架构与mvc
- SpringMVC基本概念(二)SpringMVC介绍
- SpringMVC入门(一)分析
- SpringMVC入门(二)创建项目、添加依赖、配置web.xml
- SpringMVC入门(三)控制器、springMVC.xml
- SpringMVC入门(四)执行流程
- SpringMVC入门(五)涉及组件分析
- @RequestMapping注解使用
- 请求参数绑定(一)简单类型作为参数
- 请求参数绑定(二)pojo类型作为参数
- 请求参数绑定(三)请求参数乱码
- 请求参数绑定(四)@RequestParam实现参数绑定
- 请求参数绑定(五)自定义类型转换器
- 请求参数绑定(六)servletApi对象作为方法参数
- 消息头、消息体相关的注解
SpringMVC基本概念(一)三层架构与mvc
概念
-
什么是三层架构?
描述: 项目的分层
简介: 数据访问层(dao)、业务逻辑层(service)、表现层(web)
-
什么是mvc?
Model 模型(模型的定义【entity】、模型的实现【dao、service】)
View 视图 (html/jsp)
Controller 控制器 (servlet/filter /springmvc/struts)
描述: mvc是一种设计模式。表现层会用到的设计模式。
SpringMVC基本概念(二)SpringMVC介绍
什么是SpringMVC?
-
SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架, 属于 SpringFrameWork 的后续产品,已经融合在 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 在三层架构的位置
优势
- 天生与Spring框架集成,如:(IOC,AOP)
- 支持Restful风格
- 进行更简洁的Web层开发
- 支持灵活的URL到页面控制器的映射
- 非常容易与其他视图技术集成,如:Velocity、FreeMarker等等。
- 因为模型数据不存放在特定的API里,而是放在一个Model里(Map数据结构实现,因此很容易被其他框架使用)
- 非常灵活的数据验证、格式化和数据绑定机制、能使用任何对象进行数据绑定,不必实现特定框架的API
- 更加简单、强大的异常处理
- 对静态资源的支持
- 支持灵活的本地化、主题等解析
SpringMVC入门(一)分析
表现层职责:处理请求响应。
springmvc是表现层的框架。
springmvc是用来处理请求和响应。
实现步骤
- 创建项目:springmvc01。 添加依赖:spring-context、spring-webmvc
- 配置web.xml, 配置SpringMVC提供的:DispatcherServlet。
- 编写控制器类处理请求:HelloController
- 配置springMVC.xml
- 部署项目,启动项目,访问测试
SpringMVC入门(二)创建项目、添加依赖、配置web.xml
步骤
- 创建项目:springmvc01。 添加依赖:spring-context、spring-webmvc
- 配置web.xml, 配置SpringMVC提供的:DispatcherServlet。
实现
-
创建项目:springmvc01。 添加依赖:spring-context、spring-webmvc
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>xxx.xxx</groupId> <artifactId>springmvc01</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <dependencies> <!--spring核心支持包(IOC容器基础包)--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.8.RELEASE</version> </dependency> <!--springmvc支持包--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.8.RELEASE</version> </dependency> </dependencies> </project>
-
配置web.xml, 配置SpringMVC提供的:DispatcherServlet。
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <!-- 配置SpringMVC的前端控制器:DispatcherServlet 1. 如果要用springmvc的功能,必须让请求经过这个servlet 2. 拦截所有.do为后缀的请求 http://localhost:8080/hello 不拦截 http://localhost:8080/hello.do 拦截, 符合DispatcherServlet拦截路径规则 3. 通过init-param 加载类路径下的指定的spring容器配置文件 4. 启动时候创建servlet load-on-startup 配置启动时候创建servlet,值范围是1-6,数字越小越先创建。 --> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springMVC.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> </web-app>
SpringMVC入门(三)控制器、springMVC.xml
步骤
- 编写控制器类处理请求:HelloController
- 配置springMVC.xml
- 部署项目,启动项目,访问测试
实现
-
编写控制器类处理请求:HelloController
/** * SpringMVC中处理请求的控制器类,也可以叫做处理器(Handler) */ @Controller // 创建对象,加入容器;注意:必须使用@Controller注解,才可以处理请求 public class HelloController { /** * 请求地址:http://localhost:8080/hello.do * 后台方法:xxx.xxx.controller.hello.HelloController.hello() * 响应地址:http://localhost:8080/pages/success.jsp * 地址:/pages/success.jsp * 前缀:/pages/ 【springMVC.xml中配置】 * 文件名称:success 控制器方法返回 * 后缀:.jsp 【springMVC.xml中配置】 * @RequestMapping作用: * 1. 根据请求地址,找到处理请求的方法。 * 2. 建立请求地址与处理请求方法的映射关系 */ @RequestMapping("/hello.do") public String hello(){ System.out.println("处理请求!"); // 返回跳转路径页面名称,跳转路径的前缀、后缀在配置文件中配置 return "success"; } }
-
配置springMVC.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--1. 注解扫描--> <context:component-scan base-package="xxx.xxx"/> <!--2. 视图解析器--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--配置跳转路径的前缀--> <property name="prefix" value="/pages/"/> <!--配置跳转路径的后缀--> <property name="suffix" value=".jsp"/> </bean> <!--3. 开启注解驱动(自动创建springmvc的处理器映射器、处理器适配器)--> <mvc:annotation-driven/> </beans>
-
部署项目,启动项目,访问测试
访问:
SpringMVC入门(四)执行流程
流程图
Rational Rose 建模: 时序图
1、Tomcat启动
1.1 加载自身的web.xml
1.2 加载项目的web.xml
1.2.1 创建DispatcherServlet
1.2.2 加载springMVC.xml配置文件,初始化spring的容器
2、请求
2.1 访问地址:http://localhost:8080/hello.do
2.2 DispatcherServlet拦截请求地址
2.3 根据请求的url:/hello.do, 匹配所有的@RequestMappping注解,找到处理请求的方法
2.4 执行方法,处理请求,获取方法返回值(跳转路径的一部分)
3、响应
3.1 视图解析器根据控制器处理请求方法的返回结果,结合视图解析器配置的前缀、后缀,渲染页面(准备)
3.2 由DispatcherServlet处理响应,交给tomcat响应客户端请求。
SpringMVC入门(五)涉及组件分析
三大组件
SpringMVC三大组件:
-
RequestMappingHandlerMapping 处理器映射器
作用:根据请求url地址,找到控制器中处理请求的方法。HelloController.hello()
-
RequestMappingHandlerAdapter 处理器适配器
作用:根据处理器映射器解析的结果,找到处理请求的方法,执行方法。
-
InternalResourceViewResolver 视图解析器
作用:根据处理器适配器执行的结果,交给视图解析器处理准备(渲染)页面。
详解
图1:
图2:
图3:
@RequestMapping注解使用
实现
/**
* @RequestMapping
* 0. 作用:建立请求地址与处理请求方法的映射关系。
* 1. 位置
* 作用于类上, 区分不同的模块,作为路径的一部分
* 作用于方法上,表示方法的访问路径
* 2. 常用的写法:
* @RequestMapping("/list.do") OK
* @RequestMapping("/list") OK 省略后缀 【推荐】
* @RequestMapping("list") OK 省略/
* 3. 注解属性
* value 指定请求的路径
* path 同value,表示请求路径
* method 指定支持的提交方式。如果不指定,支持所有类型的请求(get、post、put、delete..)
* method = RequestMethod.POST
* 指定了请求方式,这里只支持post请求
* 如果通过浏览器直接访问是get请求,报错:405 – Method Not Allowed
* name 指定路径名称,让当前路径更具有可描述性。
* params 指定请求路径必须带这里指定的参数名称以及参数值
* 配置:params = "id=100"
* 访问:http://localhost:8080/person/list.do?id=100 OK
* 访问:http://localhost:8080/person/list.do?id=101 NOK 报错 400 + Bad Request
* 访问:http://localhost:8080/person/list.do?id1=100 NOK 报错 400 + Bad Request
* 4. 常见4XX错误
* 404 路径地址错误
* 405 请求方式服务器不支持
* 400 + Bad Request 封装请求参数错误。 【经常遇到】
*
*/
@Controller
@RequestMapping("/person")
public class RequestMappingController {
/**
* 请求地址:http://localhost:8080/person/list.do
*/
@RequestMapping(
value = "/list",
method = RequestMethod.GET,
name = "人员列表",
params = "id=100"
)
//@RequestMapping("/list") // 最常用
public String list(){
return "success";
}
}
请求参数绑定(一)简单类型作为参数
分析
地址:http://localhost:8080/user?id=100
后台封装请求参数:
public String save(Integer id){ // 方法形参名称与请求参数名称一致,这样就可以封装请求参数。
}
public String save(User user){ //User{int id}
}
演示
@Controller
@RequestMapping("/user")
public class UserController {
/**
* 请求参数绑定(一)简单类型作为参数
*
* 案例1:
* 请求地址:http://localhost:8080/user/list.do?id=100&name=Jacky
* 后台方法:public String list(Integer id,String name){}
* 执行结果:100,Jacky
* 封装数据:
* 请求参数名称,与方法形参名称一致,就可以获取请求数据。
*
* 案例2:
* 后台方法:public String list(Integer id,String name){}
* 请求地址:
* http://localhost:8080/user/list.do?id=100&name=Jacky 结果:100,Jacky
* http://localhost:8080/user/list.do?id=100 结果:100,null
* http://localhost:8080/user/list.do 结果:null,null
*
* 案例3:
* 后台方法:public String list(int id,String name){}
* 请求地址:
* http://localhost:8080/user/list.do?id=100 结果:100,null
* http://localhost:8080/user/list.do 结果:500 报错,因为int不能为NULL
*
* 总结:
* SpringMVC封装请求数据时候,控制器方法参数如果是基本类型,最好用其包装类型。
*/
@RequestMapping("/list")
public String list(Integer id,String name){
System.out.println(id + "," + name);
return "success";
}
}
请求参数绑定(二)pojo类型作为参数
环境
引入lombok支持包
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
实现
实体类的包:entity、beans、javabean、domain、po、pojo
POJO: 简单的Java对象 (Plain Ordinary Java Object)
步骤:
- 定义User对象,封装请求数据
- UserController添加update()方法,参数是User
- 定义Address地址对象,User中添加Address对象属性,如何封装?
- User中添加集合属性,如何封装?
实现:
-
定义User对象,封装请求数据
@Data public class User { private Integer id; private String name; }
-
UserController添加update()方法,参数是User
/** * 请求参数绑定(二)pojo类型作为参数 * 请求地址: http://localhost:8080/user/query.do?id=100&name=Jacky * 后台方法: public String query(User user){} * 小结: * 请求参数名称要与对象属性名称一致,就可以往对象中封装数据。 * * 需求2:User对象中又包含有address对象属性。 * 请求地址: http://localhost:8080/user/query.do?id=100&address.city=gz&address.province=gd */ @RequestMapping("/query") public String query(User user){ System.out.println(user); return "success"; }
-
定义Address地址对象;User中添加Address对象属性,如何封装?
@Data public class Address { private String province; private String city; }
@Data public class User { private Integer id; private String name; // 用户的地址对象 private Address address; }
-
User中添加集合属性,如何封装?
@Data public class User { private Integer id; private String name; // 用户的地址对象 private Address address; // 对象中的集合属性 private List<Address> addresses; private Map<String,Address> map; }
index.jsp <%-- Created by IntelliJ IDEA. User: 61073 Date: 2020/8/9 Time: 11:46 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>测试封装请求数据:封装集合数据</title> </head> <body> <form action="/user/query.do" method="post"> 用户名称:<input type="text" name="name"> <br> 省份:<input type="text" name="address.province"> <br> 城市:<input type="text" name="address.city"> <br><br> 省份list:<input type="text" name="addresses[0].province"> <br> 城市list:<input type="text" name="addresses[0].city"> <br> 省份map:<input type="text" name="map['one'].province"> <br> 城市map:<input type="text" name="map['one'].city"> <br> <br> <input type="submit" value="封装集合数据的测试"> </form> </body> </html>
测试结果:
请求参数绑定(三)请求参数乱码
实现
Spring提供了统一的编码过滤器,解决提交数据中文乱码问题。
在web.xml中配置编码过滤器:CharacterEncodingFilter
<!--配置SpringMVC提供的编码过滤器,解决请求数据中文乱码问题。-->
<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>
SpringMVC封装请求数据,请求数据有中文:
- get提交,默认无问题,前提:tomcat7以上版本。
- post 默认会出现乱码
- 配置CharacterEncodingFilter, 可以解决所有中文数据乱码问题。
请求参数绑定(四)@RequestParam实现参数绑定
@RequestParam
- 应用场景:当请求参数名称与方法形参不一致时候使用
- 建立请求参数与方法形参的映射关系
实现
/**
* 请求参数绑定(四)@RequestParam实现参数绑定
* 请求地址:http://localhost:8080/user/search.do?username=Jack
* @RequestParam
* 1. 当请求参数名称与方法形参名称不一致使用使用;
* 2. 属性
* value 对应请求参数名称
* required 必须要传递该参数,否则报错.
* defaultValue 给参数默认值。
*/
@RequestMapping("/search")
public String search(@RequestParam(value = "username",required = true,defaultValue = "匿名") String uname){
System.out.println("uname = " + uname);
return "success";
}
- @RequestParam与@RequestMapping区别:
- @RequestParam 封装请求参数
- @RequestMapping 指定请求路径
请求参数绑定(五)自定义类型转换器
实现步骤
第一步:测试能否把请求的字符串参数自动转换为Date日期类型
/**
* 请求参数绑定(五)自定义类型转换器
* 请求地址:http://localhost:8080/user/save.do?birth=1998-09-09
* 后台方法:public String save(Date birth){}
* 执行测试:
* 页面:HTTP Status 400 – Bad Request
* 日志: Failed to convert value of type 'java.lang.String' to required type 'java.util.Date';
* 解决?
* 自定义类型转换器,实现String-->Date
* 1、写一个类,实现Converter转换器接口
* 2、springMVC.xml配置转换器工厂
*/
@RequestMapping("/save")
public String save(Date birth){
System.out.println(birth);
return "success";
}
第二步:测试,是否报错
第三步:解决错误,自定义类型转换器
写一个类,实现Converter接口
/**
* 自定义类型转换器,实现String-->Date
*/
@Component // 创建对象,加入容器 (注意:包扫描要扫描到此注解)
public class StringToDateConverter implements Converter<String,Date>{
@Override
public Date convert(String source) {
try {
// 校验 (调用工具类的判断为空的方法)
if (StringUtils.isEmpty(source)){
return null;
}
// 转换
return new SimpleDateFormat("yyyy-MM-dd").parse(source);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
配置springMVC.xml, 配置转换器工厂
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--1. 注解扫描-->
<context:component-scan base-package="xxx.xxx"/>
<!--2. 视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--配置跳转路径的前缀-->
<property name="prefix" value="/pages/"/>
<!--配置跳转路径的后缀-->
<property name="suffix" value=".jsp"/>
</bean>
<!--3. 开启注解驱动(自动创建springmvc的处理器映射器、处理器适配器)-->
<mvc:annotation-driven conversion-service="conversionServiceFactory"/>
<!--4. 配置转换器的工厂-->
<bean id="conversionServiceFactory"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<!--注入自定义的转换器类(引用容器中指定名称的bean)-->
<ref bean="stringToDateConverter"/>
</set>
</property>
</bean>
</beans>
请求参数绑定(六)servletApi对象作为方法参数
第一步:添加依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
第二步:编写控制器类
编写控制器类,servletApi作为方法参数
@Controller
public class ServletApiController {
/**
* ServletApi作为方法参数
* 请求地址:http://localhost:8080/servletApi.do?id=100
*/
@RequestMapping("/servletApi")
public void servletApi(Integer id, HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("SpringMVC封装的请求数据:" + id);
System.out.println("通过request对象获取请求数据:" + request.getParameter("id"));
// 重定向
//response.sendRedirect("http://localhost:8080/pages/success.jsp");
response.sendRedirect("/pages/success.jsp");
}
}
什么情况下需要使用ServletApi?
|-- 举例:文件下载,必须要用到resposne对象,设置下载响应头..
|-- 获取访问者的ip地址。request.getRemoteAddr()
消息头、消息体相关的注解
获取请求信息
获取请求信息:
-
@RequestHeader 获取请求头
-
@CookieValue 获取cookie值
-
@RequestBody 获取请求体(post提交)
示例
@Controller
public class RequestController {
/**
* @RequestHeader 获取请求头的值
*/
@RequestMapping("/requestHeader")
public String requestHeader(@RequestHeader("host") String host){
System.out.println("host = " + host);
return "success";
}
/**
* @CookieValue 获取指定key的cookie的值
*/
@RequestMapping("/CookieValue")
public String cookieValue(@CookieValue("JSESSIONID") String jsessionid){
System.out.println("cookie中JSESSIONID这个key对应的值是:" + jsessionid);
return "success";
}
/**
* @RequestBody 获取请求体
*/
@RequestMapping("/requestBody")
public String requestBody(@RequestBody String requestBody){
// name=jack&age=28
System.out.println(requestBody);
return "success";
}
}