SpringMVC-第一天
第1章 SpringMVC 的基本概念
1.1关于三层架构和 MVC
1.1.1 三层架构
我们的开发架构一般都是基于两种形式,一种是 C/S 架构,也就是客户端/服务器,另一种是 B/S 架构,也就是浏览器服务器。在 JavaEE 开发中,几乎全都是基于 B/S 架构的开发。那么在 B/S 架构中,系统标准的三层架构包括:表现层、业务层、持久层。三层架构在我们的实际开发中使用的非常多,所以我们课程中的案例也都是基于三层架构设计的。
三层架构中,每一层各司其职,接下来我们就说说每层都负责哪些方面:
表现层:
也就是我们常说的web层。它负责接收客户端请求,向客户端响应结果,通常客户端使用http协议请求web 层, web 需要接收 http 请求,完成 http 响应。
- 表现层包括展示层和控制层:控制层负责接收请求,展示层负责结果的展示。
- 表现层依赖业务层,接收到客户端请求一般会调用业务层进行业务处理,并将处理结果响应给客户端。
- 表现层的设计一般都使用 MVC 模型。(MVC 是表现层的设计模型,和其他层没有关系)
业务层:
也就是我们常说的 service 层。它负责业务逻辑处理,和我们开发项目的需求息息相关。 web 层依赖业务层,但是业务层不依赖 web 层。业务层在业务处理时可能会依赖持久层,如果要对数据持久化需要保证事务一致性。(也就是我们说的,事务应该放到业务层来控制)
持久层:
也就是我们是常说的 dao 层。负责数据持久化,包括数据层即数据库和数据访问层,数据库是对数据进行持久化的载体,数据访问层是业务层和持久层交互的接口,业务层需要通过数据访问层将数据持久化到数据库中。通俗的讲,持久层就是和数据库交互,对数据库表进行曾删改查的。
1.1.2 MVC 模型
MVC 全名是 Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是一种用于设计创建 Web 应用程序表现层的模式。 MVC 中每个部分各司其职:
Model(模型):
通常指的就是我们的数据模型。作用一般情况下用于封装数据。
View(视图):
- 通常指的就是我们的 jsp 或者 html。作用一般就是展示数据的。
- 通常视图是依据模型数据创建的。
Controller(控制器) :
是应用程序中处理用户交互的部分。 作用一般就是处理程序逻辑的。它相对于前两个不是很好理解,这里举个例子:
例如:
我们要保存一个用户的信息,该用户信息中包含了姓名,性别,年龄等等。
这时候表单输入要求年龄必须是 1~100 之间的整数。姓名和性别不能为空。并且把数据填充
到模型之中。
此时除了 js 的校验之外,服务器端也应该有数据准确性的校验,那么校验就是控制器的该做
的。
当校验失败后,由控制器负责把错误页面展示给使用者。
如果校验成功,也是控制器负责把数据填充到模型,并且调用业务层实现完整的业务需求。
1.2SpringMVC 概述
1.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 编程风格的请求。
1.2.2 SpringMVC 在三层架构的位置
1.2.3 SpringMVC 的优势
-
清晰的角色划分:
- 前端控制器(DispatcherServlet)
- 请求到处理器映射(HandlerMapping)
- 处理器适配器(HandlerAdapter)
- 视图解析器(ViewResolver)
- 处理器或页面控制器(Controller)
- 验证器( Validator)
- 命令对象(Command 请求参数绑定到的对象就叫命令对象)
- 表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)。
-
分工明确,而且扩展点相当灵活,可以很容易扩展,虽然几乎不需要。
-
由于命令对象就是一个 POJO,无需继承框架特定 API,可以使用命令对象直接作为业务对象。
-
和 Spring 其他框架无缝集成,是其它 Web 框架所不具备的。
-
可适配,通过 HandlerAdapter 可以支持任意的类作为处理器。
-
可定制性, HandlerMapping、 ViewResolver 等能够非常简单的定制。
-
功能强大的数据验证、格式化、绑定机制。
-
利用 Spring 提供的 Mock 对象能够非常简单的进行 Web 层单元测试。
-
本地化、主题的解析的支持,使我们更容易进行国际化和主题的切换。
-
强大的 JSP 标签库,使 JSP 编写更容易。
………………还有比如RESTful风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配置支持等等。
1.2.4 SpringMVC 和 Struts2 的优略分析
共同点:
- 它们都是表现层框架,都是基于 MVC 模型编写的。
- 它们的底层都离不开原始 ServletAPI。
- 它们处理请求的机制都是一个核心控制器。
区别:
-
Spring MVC 的入口是 Servlet, 而 Struts2 是 Filter
-
Spring MVC 是基于方法设计的,而 Struts2 是基于类,Struts2 每次执行都会创建一个动作类。所以 Spring MVC 会稍微比 Struts2 快些。
-
Spring MVC 使用更加简洁,同时还支持 JSR303,处理 ajax 的请求更方便
(JSR303 是一套 JavaBean 参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们 JavaBean 的属性上面,就可以在需要校验的时候进行校验了。)
- Struts2 的 OGNL 表达式使页面的开发效率相比 Spring MVC 更高些,但执行效率并没有比 JSTL 提升,尤其是 struts2 的表单标签,远没有 html 执行效率高。
第2章 SpringMVC 的入门
2.1SpringMVC 的入门案例
入门案例的需求
1.需要搭建开发环境
2.编写入门的程序
2.1.1 前期准备
新建一个文件夹用来存放我们整个教程的所有的练习代码。我这里文件夹为SpringMVC,使用IDEA打开这个文件夹(这样做的目的是后面我会把本教程中创建的项目都以Module的形式创建在这个文件中,便于以后的复习)。
然后创建一个Module,选择新建Module,创建一个Maven的web项目。
填写项目名GroupId和ArtifactId
选择Maven(我这里使用我自己安装的Maven,各位同学如果使用IDEA默认的Maven的话这里就不用修改了)。添加archetypeCatalog和internal键值对可以加快项目的创建。然后点击Finish。
然后项目的结构如下,这里我们可以看出这个项目的结构不完整。下面我们自己添加java文件夹和resources文件夹并设置Sources Root和Resources Root。
下面我们来修改poim.xml文件导入项目的依赖。
<?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>cn.itcast</groupId>
<artifactId>springmvc_day01_01_start</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>springmvc_day01_01_start Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<!--版本锁定-->
<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.2.8.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--导入spring的依赖-->
<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>
<!--导入servlet依赖-->
<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.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>springmvc_day01_01_start</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
2.1.2 创建一个页面控制器
先创建一个包cn.itcast.controller,然后在该包中创建一个Controller。
package cn.itcast.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 控制器类
*/
@Controller//Spring里注解
public class HelloController {
@RequestMapping(path = "/hello")
public String sayHello() {
System.out.println("Hello SpringMVC");
// 返回success.jsp页面
return "success";
}
}
2.1.3 创建 spring mvc 的配置文件
在resources文件下创建 springmvc.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--开启注解的扫描-->
<context:component-scan base-package="cn.itcast"/>
<!--视图解析器,完成页面的跳转的功能-->
<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>
2.1.4 配置核心控制器-一个 Servlet
在WEB-INF下修改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 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" id="WebApp_ID" version="2.5">
<display-name>Archetype Created Web Application</display-name>
<!-- 配置 spring mvc 的核心控制器 -->
<servlet>
<servlet-name>dispatchServlet</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>dispatchServlet</servlet-name>
<!--设置其适用于任何路径的请求-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
2.1.5 创建jsp文件的文件夹pages
先创建一个存放jsp文件的文件夹pages,然后在其中创建一个success.jsp的文件。success文件如下
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>入门成功</h3>
</body>
</html>
2.1.6 修改index.jsp文件
因为创建项目时自带的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>
最终的项目结构如下
至此SpringMVC的入门完成。配置好tomcat服务器后测试运行程序。
点击入门程序就会跳转到success.jsp页面
项目的大致流程如下
2.2入门案例中涉及的组件
2.2.1 DispatcherServlet:前端控制器
用户请求到达前端控制器,它就相当于 mvc 模式中的 c, dispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求, dispatcherServlet 的存在降低了组件之间的耦合性。
2.2.2 HandlerMapping:处理器映射器
HandlerMapping 负责根据用户请求找到 Handler 即处理器, SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
2.2.3 Handler:处理器
它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由Handler 对具体的用户请求进行处理。
2.2.4 HandlAdapter:处理器适配器
通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
2.2.6 View:视图
SpringMVC 框架提供了很多的 View 视图类型的支持,包括: jstlView、 freemarkerView、 pdfView等。我们最常用的视图就是 jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
2.2.7 <mvc:annotation-driven>说明
在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。使 用 <mvc:annotation-driven> 自 动 加 载 RequestMappingHandlerMapping ( 处 理 映 射 器 ) 和RequestMappingHandlerAdapter ( 处 理 适 配 器 ), 可 用 在 SpringMVC.xml 配 置 文 件 中 使 用<mvc:annotation-driven>替代注解处理器和适配器的配置。它就相当于在 xml 中配置了:
<!-- 上面的标签相当于 如下配置-->
<!-- Begin -->
<!-- HandlerMapping -->
<!-- 这里的 bean 没有配置id就使用默认的id -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerM
apping"></bean>
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!-- HandlerAdapter -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerA
dapter"></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.ExceptionHandlerExcept
ionResolver"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolv
er"></bean>
<bean class="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver"
></bean>
<!-- End -->
注意:
一般开发中,我们都需要写上此标签(虽然从入门案例中看,我们不写也行,随着课程的深入,该标签还有具体的使用场景)。
明确:
我们只需要编写处理具体业务的控制器以及视图。
2.3 RequestMapping 注解
2.3.1 使用说明
// 源码:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
}
作用:
用于建立请求 URL 和处理请求方法之间的对应关系。
出现位置:
-
类上:
请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。 写的话需要以/开头。它出现的目的是为了使我们的 URL 可以按照模块化管理:
例如:
账户模块:
/account/add
/account/update
/account/delete
…
订单模块:
/order/add
/order/update
/order/delete
红色的部分就是把 RequsetMappding 写在类上,使我们的 URL 更加精细。 -
方法上:
请求 URL 的第二级访问目录。
属性:
value:用于指定请求的 URL。 它和 path 属性的作用是一样的。
method:用于指定请求的方式。
params:用于指定限制请求参数的条件。 它支持简单的表达式。 要求请求参数的 key 和 value 必须和配置的一模一样。
例如:
params = {“accountName”},表示请求参数必须有 accountName
params = {“moeny!100”},表示请求参数中 money 不能是 100。
headers:用于指定限制请求消息头的条件。
注意:
以上四个属性只要出现 2 个或以上时,他们的关系是与的关系。
第3章 请求参数的绑定
3.1 请求参数的绑定说明
- 绑定机制
- 表单提交的数据都是k=v格式的 username=haha&password=123
- SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的
- 要求:提交表单的name和参数的名称是相同的
- 支持的数据类型
- 基本数据类型和字符串类型
- 实体类型(JavaBean)
- 集合数据类型(List、map集合等)
3.2 基本数据类型和字符串类型
- 提交表单的name和参数的名称是相同的
- 区分大小写
3.3 实体类型(JavaBean)
-
提交表单的name和JavaBean中的属性名称需要一致
-
如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:对象.属性 例如:
address.name具体如下:
一个Account类作为请求参数
package cn.itcast.domain; import java.io.Serializable; public class Account implements Serializable { private String username; private String password; private Double money; private User user; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Double getMoney() { return money; } public void setMoney(Double money) { this.money = money; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } @Override public String toString() { return "Account{" + "username='" + username + '\'' + ", password='" + password + '\'' + ", money=" + money + ", user=" + user + '}'; } }
还有一个User类
package cn.itcast.domain; import java.io.Serializable; public class User implements Serializable { private String name; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
增加一个Controller方法 saveAccount
package cn.itcast.controller; import cn.itcast.domain.Account; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; /** * 请求参数的绑定 */ @Controller @RequestMapping("/param") public class ParamController { /** * 请求参数的绑定入门 * @return */ @RequestMapping("/testParam") public String testParam(String username, String password) { System.out.println("testParam 执行了..."); System.out.println("你的用户名:" + username); System.out.println("你的密码:" + password); return "success"; } /** * 把数据封装到一个Javabean类中 * @return */ @RequestMapping("/saveAccount") public String saveAccount(Account account) { System.out.println("saveAccount 执行了..."); System.out.println(account); return "success"; } }
那么对应的param.jsp如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>请求参数绑定</title> </head> <body> <%--请求参数的绑定--%> <a href="param/testParam?username=呵呵&password=123456">请求参数的绑定 测试</a> <%--表单的请求--%> <form action="param/saveAccount" method="post"> 姓名:<input type="text" name="username" placeholder="用户名"/><br/> 密码:<input type="text" name="password" placeholder="密码"/><br/> 金额:<input type="text" name="money" placeholder="金额"/><br/> 用户的姓名:<input type="text" name="user.name" placeholder="用户的姓名"/><br/> 用户的年龄:<input type="text" name="user.age" placeholder="用户的年龄"/><br/> <input type="submit" name="submit" value="提交"/> </form> </body> </html>
3.4 给集合属性数据封装
-
JSP页面编写方式:list[0].属性 map[‘key‘].属性
如下:
修改Account类
package cn.itcast.domain; import java.io.Serializable; import java.util.List; import java.util.Map; public class Account implements Serializable { private String username; private String password; private Double money; //private User user; private List<User> list; private Map<String, User> map; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Double getMoney() { return money; } public void setMoney(Double money) { this.money = money; } // public User getUser() { // return user; // } // // public void setUser(User user) { // this.user = user; // } public List<User> getList() { return list; } public void setList(List<User> list) { this.list = list; } public Map<String, User> getMap() { return map; } public void setMap(Map<String, User> map) { this.map = map; } @Override public String toString() { return "Account{" + "username='" + username + '\'' + ", password='" + password + '\'' + ", money=" + money + ", list=" + list + ", map=" + map + '}'; } }
修改对应的param.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>请求参数绑定</title> </head> <body> <%--请求参数的绑定--%> <a href="param/testParam?username=呵呵&password=123456">请求参数的绑定 测试</a> <%--把数据封装到Account类中--%> <%--<form action="param/saveAccount" method="post"> 姓名:<input type="text" name="username" placeholder="用户名"/><br/> 密码:<input type="text" name="password" placeholder="密码"/><br/> 金额:<input type="text" name="money" placeholder="金额"/><br/> 用户的姓名:<input type="text" name="user.name" placeholder="用户的姓名"/><br/> 用户的年龄:<input type="text" name="user.age" placeholder="用户的年龄"/><br/> <input type="submit" name="submit" value="提交"/> </form>--%> <%--把数据封装到Account类中,类中存在List,Map等集合--%> <form action="param/saveAccount" method="post"> 姓名:<input type="text" name="username" placeholder="用户名"/><br/> 密码:<input type="text" name="password" placeholder="密码"/><br/> 金额:<input type="text" name="money" placeholder="金额"/><br/> <%--封装到List中--%> 用户的姓名:<input type="text" name="list[0].name"/><br/> 用户的年龄:<input type="text" name="user[0].age"/><br/> <%--封装到Map中--%> 用户的姓名:<input type="text" name="map['one'].name"/><br/> 用户的年龄:<input type="text" name="map['one'].age"/><br/> <input type="submit" name="submit" value="提交"/> </form> </body> </html>
3.5 请求参数中文乱码的解决
- 在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>
3.6 自定义类型转换器
-
表单提交的任何数据类型全部都是字符串类型,但是后台定义Integer类型,数据也可以封装上,说明Spring框架内部会默认进行数据类型转换。
-
如果想自定义数据类型转换,可以实现Converter的接口
- 自定义类型转换器
package cn.itcast.utils; import org.springframework.core.convert.converter.Converter; import org.springframework.util.StringUtils; import java.text.SimpleDateFormat; import java.util.Date; /** * 把字符串转成日期类型 */ public class StringToDateConverter implements Converter<String, Date> { /** * @param source 传入的字符串 * @return 返回日期 */ @Override public Date convert(String source) { if (StringUtils.isEmpty(source)) { throw new RuntimeException("请传入正确的日期格式"); } SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try { return df.parse(source); } catch (Exception e) { throw new RuntimeException("请传入正确的日期格式"); } } }
- 注册自定义类型转换器,在springmvc.xml配置文件中编写配置
<!--配置自定义类型转换器--> <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <!--converters属性是一个Set集合--> <property name="converters"> <set> <bean class="cn.itcast.utils.StringToDateConverter"/> </set> </property> </bean> <!--annotation-driven开启SpringMVC框架注解的支持--> <!--conversion-service使配置的自定义类型转换器生效--> <mvc:annotation-driven conversion-service="conversionService"/>
- 自定义类型转换器
3.7 在控制器中使用原生的ServletAPI对象
只需要在控制器的方法中定义HttpServletRequest和HttpServletResponse对象作为参数即可
/**
* 在控制器中使用原生的ServletAPI对象
*/
@RequestMapping("/testServlet")
public String testServlet(HttpServletRequest request, HttpServletResponse response) {
System.out.println(request);
HttpSession session = request.getSession();
System.out.println(session);
ServletContext context = session.getServletContext();
System.out.println(context);
System.out.println(response);
System.out.println("在控制器中使用原生的ServletAPI对象");
return "success";
}
第4章 常用注解
4.1 RequestParam注解
-
作用:把请求中的指定名称的参数传递给控制器中的形参赋值
-
属性:
- value:请求参数中的名称
- required:请求参数中是否必须提供此参数,默认值是true,必须提供
-
代码如下
/** * 常用注解 */ @Controller @RequestMapping("/anno") public class AnnoController { @RequestMapping("/testRequestParam") public String testRequestParam(@RequestParam(value = "name", required = true) String username) { System.out.println(username); System.out.println("testRequestParam 执行了..."); return "success"; } }
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>常用的注解</title> </head> <body> <%--常用注解--%> <a href="anno/testRequestParam?name=哈哈">RequestParam 注解</a> </body> </html>
4.2 RequestBody注解
-
作用:用于获取请求体内容。直接使用得到是 key=value&key=value…结构的数据。get 请求方式不适用。
-
属性
- required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值为 false,get 请求得到是 null
-
代码如下
/** * 常用注解 */ @Controller @RequestMapping("/anno") public class AnnoController { ... @RequestMapping(path = "/testRequestBody", method = RequestMethod.POST) public String testRequestBody(@RequestBody String user) { System.out.println(user); System.out.println("testRequestBody 执行了..."); return "success"; } }
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>常用的注解</title> </head> <body> <%--testRequestBody 注解--%> <form action="anno/testRequestBody" method="post"> 用户的姓名:<input type="text" name="name"/><br/> 用户的年龄:<input type="text" name="age"/><br/> 用户的生日:<input type="text" name="date"/><br/> <input type="submit" name="submit" value="提交"/> </form> </body> </html>
4.3 PathVaribale
-
作用:
用于绑定 url 中的占位符。 例如:请求 url 中 /delete/{id}, 这个{id}就是 url 占位符。url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。
-
属性:
value: 用于指定 url 中占位符名称。
required:是否必须提供占位符。 -
代码如下
/** * 常用注解 */ @Controller @RequestMapping("/anno") public class AnnoController { ... @RequestMapping(path = "/testPathVariable/{sid}") public String testPathVariable(@PathVariable(value = "sid") String id) { System.out.println(id); System.out.println("testPathVariable 执行了..."); return "success"; } }
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>常用的注解</title> </head> <body> <a href="anno/testPathVariable/10">PathVariable 注解</a> </body> </html>
补充:有时候我们的这个url路径的占位符里含有“.”逗点等一些特殊的符号,这时spring MVC框架就不能很好的识别,例如
@RequestMapping(path = "/testPathVariable/{sid}")
如果sid为a.b,例如url为/testPathVariable/a.b这时spring MVC 就会识别成/testPathVariable/a而不是/testPathVariable/a.b为里解决这种问题,我们可以把RequestMappIng的path这样写:@RequestMapping(path = "/testPathVariable/{sid:.+}")
表示解析url时忽略后面的"."
4.4 RequestHeader
-
作用:
获取指定请求头的值
-
属性:
value: 请求头的名称
-
代码如下
/** * 获取请求头信息 */ @RequestMapping(path = "/testRequestHeader") public String testRequestHeader(@RequestHeader(value = "Accept") String header) { System.out.println(header); System.out.println("testRequestHeader 执行了..."); return "success"; }
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>常用的注解</title> </head> <body> <a href="anno/testRequestHeader">RequestHeader 注解</a><br/> </body> </html>
4.5 CookieValue
-
作用:
获取指定请求头的值
-
属性:
value:cookie的名称
-
代码如下
/** * 获取Cookie的值 */ @RequestMapping(path = "/testCookieValue") public String testCookieValue(@CookieValue(value = "JSESSIONID") String cookieValue) { System.out.println(cookieValue); System.out.println("testCookieValue 执行了..."); return "success"; }
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>常用的注解</title> </head> <body> <a href="anno/testCookieValue">CookieValue 注解</a><br/> </body> </html>
4.6 ModelAttribut
-
作用:
- 出现在方法上:表示当前方法会在控制器方法执行前先执行。
- 出现在参数上:获取指定的数据给参数赋值。
-
应用场景
- 当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据。
-
代码如下
/**
* ModelAttribute 注解 表示当前方法会在其他的控制器的方法执行之前,先执行
* 它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法
*/
@ModelAttribute
public User sowUserMethod(String uname) {
// public User sowUser(User user) // 方法名也可以这样写
System.out.println("showUser 执行了...");
// 通过用户名查询数据库(我们者流模拟一下,就是new一个user)
User user = new User();
user.setName(uname);
// 因为前端jsp传来的参数中有age参数,所以我们在这里的修改会被覆盖掉
user.setAge(20);
user.setDate(new Date());
System.out.println(user);
return user;
}
@ModelAttribute
public void sowUser(String uname, Map<String, User> map) {
// public User sowUser(User user) // 方法名也可以这样写
System.out.println("showUser 执行了...");
// 通过用户名查询数据库(我们者流模拟一下,就是new一个user)
User user = new User();
user.setName(uname);
// 因为前端jsp传来的参数中有age参数,所以我们在这里的修改会被覆盖掉
user.setAge(20);
user.setDate(new Date());
map.put("abc", user);
}
/**
* ModelAttribute 注解测试,
* 因为 ModelAttribute 注解修饰的方法先执行,所以这个控制器方法的参数是
* sowUser 方法的返回值,但是只有参数为null的参数才会被真正的修改。
* 通过 ModelAttribute 修饰参数来获取指定的参数值
*/
@RequestMapping(path = "/testModelAttribute")
public String testModelAttribute(@ModelAttribute("abc") User user) {
System.out.println("testModelAttribute 执行了...");
System.out.println(user);
return "success";
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>常用的注解</title>
</head>
<body>
<form action="anno/testModelAttribute" method="post">
用户的姓名:<input type="text" name="name"/><br/>
用户的年龄:<input type="text" name="age"/><br/>
<input type="submit" name="submit" value="提交"/>
</form>
</body>
</html>
4.7 SessionAttributes
-
作用:
用于多次执行控制器方法间的参数共享
-
属性:
value:指定存入属性的名称
-
代码如下
package cn.itcast.controller;
import cn.itcast.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.support.SessionStatus;
import java.util.Date;
import java.util.Map;
/**
* 常用注解
*/
@Controller
@RequestMapping("/anno")
@SessionAttributes(value = {"msg"})// 这样也会把我们在方法testSessionAttributes中存放在request域中的数据也存在session域中
public class AnnoController {
/**
* SessionAttributes 注解
* 使用参数 Model 在request域中存放数据 供前端jsp页面使用
*/
@RequestMapping(path = "/testSessionAttributes")
public String testSessionAttributes(Model model) {
System.out.println("testSessionAttributes 执行了...");
// 底层会存储到request域对象中
model.addAttribute("msg", "你好");
return "success";
}
/**
* 获取值
*/
@RequestMapping(path = "/getSessionAttributes")
public String getSessionAttributes(ModelMap model) {
System.out.println("getSessionAttributes 执行了...");
String msg = (String) model.get("msg");
System.out.println(msg);
return "success";
}
/**
* 清除值
*/
@RequestMapping(path = "/delSessionAttributes")
public String delSessionAttributes(SessionStatus status) {
System.out.println("delSessionAttributes 执行了...");
status.setComplete();// 表示Session使用完成,会自动删除里面的数据
return "success";
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>常用的注解</title>
</head>
<body>
<%--向request域中存放数据--%>
<a href="anno/testSessionAttributes">SessionAttributes 注解</a><br/>
<%--从request域中取数据--%>
<a href="anno/getSessionAttributes">getSessionAttributes 注解</a><br/>
<%--清除request域中的数据--%>
<a href="anno/delSessionAttributes">delSessionAttributes 注解</a><br/>
</body>
</html>
补充 REST 风格 URL
什么是 rest:
REST(英文: Representational State Transfer,简称 REST)描述了一个架构样式的网络系统,比如 web 应用程序。它首次出现在 2000 年 Roy Fielding 的博士论文中,他是 HTTP 规范的主要编写者之一。在目前主流的三种 Web 服务交互方案中,REST 相比于 SOAP(Simple Object Access protocol,简单对象访问协议)以及 XML-RPC 更加简单明了,无论是对 URL 的处理还是对 Payload 的编码, REST 都倾向于用更加简单轻量的方法设计和实现。值得注意的是 REST 并没有一个明确的标准,而更像是一种设计的风格。
它本身并没有什么实用性,其核心价值在于如何设计出符合 REST 风格的网络接口。
restful 的优点
它结构清晰、符合标准、易于理解、 扩展方便,所以正得到越来越多网站的采用。
restful 的特性
资源(Resources):网络上的一个实体,或者说是网络上的一个具体信息。
它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个 URI(统一资源定位符)指向它,每种资源对应一个特定的 URI 。要获取这个资源,访问它的 URI 就可以,因此 URI 即为每一个资源的独一无二的识别符。
表现层(Representation): 把资源具体呈现出来的形式,叫做它的表现层(Representation)。
比如,文本可以用 txt 格式表现,也可以用 HTML 格式、 XML 格式、 JSON 格式表现,甚至可以采用二进制格式。
状态转化(State Transfer) : 每 发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP 协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段, 让服务器端发生“ 状态转化” (State Transfer)。而这种转化是建立在表现层之上的,所以就是 “ 表现层状态转化” 。具体说,就是 HTTP 协议里面,四个表示操作方式的动词: GET 、 POST 、 PUT、DELETE。它们分别对应四种基本操作: GET 用来获取资源, POST 用来新建资源,PUT 用来更新资源, DELETE 用来删除资源。
restful 的示例:
/account/1 | HTTP GET : | 得到 id = 1 的 account |
---|---|---|
/account/1 | HTTP DELETE: | 删除 id = 1 的 account |
/account/1 | HTTP PUT: | 更新 id = 1 的 account |
补充基于 HiddentHttpMethodFilter 的示例
-
作用:
由于浏览器 form 表单只支持 GET 与 POST 请求,而 DELETE、 PUT 等 method 并不支持, Spring3.0 添 加了一个过滤器,可以将浏览器请求改为指定的请求方式,发送给我们的控制器方法,使得支持 GET、 POST、 PUT与 DELETE 请求。
-
使用方法:
第一步:在 web.xml 中配置该过滤器。
第二步:请求方式必须使用 post 请求。
参考
https://www.bilibili.com/video/BV1mE411X7yp