【java】SpringMVC总结(很全)

文章目录

文档

官方文档
W3Cschool文档
C语言中文网 springMVC
本文章参考文档C语言中文网 springMVC

SSM思维导图图解

在这里插入图片描述

MVC设计模式简介

MVC 是 Model、View 和 Controller 的缩写,分别代表 Web 应用程序中的 3 种职责。

  • 模型:用于存储数据以及处理用户请求的业务逻辑。
  • 视图:向控制器提交数据,显示模型中的数据。
  • 控制器:根据视图提出的请求判断将请求和数据交给哪个模型处理,将处理后的有关结果交给哪个视图更新显示。

基于 Servlet 的 MVC 模式的具体实现如下。

  • 模型:一个或多个 JavaBean 对象,用于存储数据(实体模型,由 JavaBean 类创建)和处理业务逻辑(业务模型,由一般的 Java 类创建)。
  • 视图:一个或多个 JSP 页面,向控制器提交数据和为模型提供数据显示,JSP 页面主要使用 HTML 标记和 JavaBean 标记来显示数据。
  • 控制器:一个或多个 Servlet 对象,根据视图提交的请求进行控制,即将请求转发给处理业务逻辑的 JavaBean,并将处理结果存放到实体模型 JavaBean 中,输出给视图显示。

基于 Servlet 的 MVC 模式的流程如图 1 所示。

在这里插入图片描述

Spring MVC处理用户请求的完整流程

Spring MVC 工作流程

Spring MVC 框架主要由 DispatcherServlet、处理器映射、控制器、视图解析器、视图组成,其工作原理如图 1 所示。
在这里插入图片描述

从图 1 可总结出 Spring MVC 的工作流程如下:

  1. 客户端请求提交到 DispatcherServlet。
  2. 由 DispatcherServlet 控制器寻找一个或多个 HandlerMapping,找到处理请求的 Controller。
  3. DispatcherServlet 将请求提交到 Controller。
  4. Controller 调用业务逻辑处理后返回 ModelAndView。
  5. DispatcherServlet 寻找一个或多个 ViewResolver 视图解析器,找到 ModelAndView 指定的视图。
  6. 视图负责将结果显示到客户端。

Spring MVC接口

在图 1 中包含 4 个 Spring MVC 接口,即 DispatcherServletHandlerMappingControllerViewResolver

Spring MVC 所有的请求都经过 DispatcherServlet 来统一分发,在 DispatcherServlet 将请求分发给 Controller 之前需要借助 Spring MVC 提供的 HandlerMapping 定位到具体的 Controller。

HandlerMapping 接口负责完成客户请求到 Controller 映射。

Controller 接口将处理用户请求,这和 Java Servlet 扮演的角色是一致的。一旦 Controller 处理完用户请求,将返回 ModelAndView 对象给 DispatcherServlet 前端控制器,ModelAndView 中包含了模型(Model)和视图(View)。

从宏观角度考虑,DispatcherServlet 是整个 Web 应用的控制器;从微观考虑,Controller 是单个 Http 请求处理过程中的控制器,而 ModelAndView 是 Http 请求过程中返回的模型(Model)和视图(View)。

ViewResolver 接口(视图解析器)在 Web 应用中负责查找 View 对象,从而将相应结果渲染给客户。

第一个Spring MVC应用(Spring MVC框架搭建教程)、

代码实例

1)创建 Web 应用并引入 JAR 包

2)在 web.xml 文件中部署 DispatcherServlet

3)创建 Web 应用首页

4)创建 Controller 类

5)创建 Spring MVC 配置文件并配置 Controller 映射信息

6)应用的其他页面

7)发布并运行 Spring MVC 应用

Spring MVC视图解析器

Spring 视图解析器是 Spring MVC 中的重要组成部分,用户可以在配置文件中定义 Spring MVC 的一个视图解析器(ViewResolver),示例代码如下:

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" ><!--前缀--><property name="prefix" value="/WEB-INF/jsp/"/><!--后缀--><property name="suffix" value=".jsp"/></bean>

上述视图解析器配置了前缀和后缀两个属性,因此《第一个Spring MVC应用》教程中的 RegisterController 和 LoginController 控制器类的视图路径仅需提供 register 和 login,视图解析器将会自动添加前缀和后缀。

单从字面意思来看,我们可以把 InternalResourceViewResolver 解释为内部资源视图解析器,这就是 InternalResourceViewResolver 的一个特性。

InternalResourceViewResolver 会把返回的视图名称都解析为 InternalResourceView 对象,InternalResourceView 会把 Controller 处理器方法返回的模型属性都存放到对应的 request 属性中,然后通过 RequestDispatcher 在服务器端把请求 forword 重定向到目标 URL。

比如在 InternalResourceViewResolver 中定义了 prefix=/WEB-INF/suffix=.jsp,然后请求的 Controller 处理器方法返回的视图名称为login,那么这个时候InternalResourceViewResolver 就会把 login 解析为一个InternalResourceView对象,先把返回的模型属性都存放到对应的 HttpServletRequest 属性中,然后利用 RequestDispatcher 在服务器端把请求 forword 到 /WEB-INF/test.jsp

这就是 InternalResourceViewResolver 一个非常重要的特性,我们都知道存放在 /WEB-INF/ 下面的内容是不能直接通过 request 请求的方式请求到的,为了安全性考虑,我们通常会把 jsp 文件放在 WEB-INF 目录下,而InternalResourceView 在服务器端跳转的方式可以很好的解决这个问题

Spring MVC中@Controller和@RequestMapping注解详解

使用基于注解的控制器具有以下两个优点

  • 在基于注解的控制器类中可以编写多个处理方法,进而可以处理多个请求(动作),这就允许将相关的操作编写在同一个控制器类中,从而减少控制器类的数量,方便以后的维护。
  • 基于注解的控制器不需要在配置文件中部署映射,仅需要使用 RequestMapping注释类型注解一个方法进行请求处理。

Controller 注解类型

代码实现

RequestMapping 注解类型

在基于注解的控制器类中可以为每个请求编写对应的处理方法。那么如何将请求与处理方法一一对应呢?
需要使用 org.springframework.web.bind.annotation.RequestMapping 注解类型将请求与处理方法一一对应。

1)方法级别注解

2)类级别注解

编写请求处理方法

在控制类中每个请求处理方法可以有多个不同类型的参数,以及一个多种类型的返回结果。

1)请求处理方法中常出现的参数类型

如果需要在请求处理方法中使用 Servlet API 类型,那么可以将这些类型作为请求处理方法的参数类型。

除了 Servlet API 参数类型以外,还有输入输出流、表单实体类、注解类型、与 Spring 框架相关的类型等,这些类型在后续章节中使用时再详细介绍。

其中特别重要的类型是 org.springframework.ui.Model 类型,该类型是一个包含 Map 的 Spring 框架类型。在每次调用请求处理方法时 Spring MVC 都将创建 org.springframework.ui.Model 对象。

2)请求处理方法常见的返回类型

最常见的返回类型就是代表逻辑视图名称的 String 类型,例如前面教程中的请求处理方法。除了 String 类型以外,还有 ModelAndView、Model、View 以及其他任意的 Java 类型。

Spring MVC获取参数的几种常见方式

Controller 接收请求参数的方式有很多种,有的适合 get 请求方式,有的适合 post 请求方式,有的两者都适合。

通过实体 Bean 接收请求参数

通过一个实体 Bean 来接收请求参数,适用于 get 和 post 提交请求方式。需要注意的是,Bean 的属性名称必须与请求参数名称相同。

通过处理方法的形参接收请求参数

通过处理方法的形参接收请求参数也就是直接把表单参数写在控制器类相应方法的形参中,即形参名称与请求参数名称完全相同。该接收参数方式适用于 get 和 post 提交请求方式。

通过 HttpServletRequest 接收请求参数

通过 HttpServletRequest 接收请求参数适用于 get 和 post 提交请求方式,可以将“通过实体 Bean 接收请求参数”部分中控制器类 UserController 中 register 方法的代码修改.

通过 @PathVariable 接收 URL 中的请求参数

通过 @PathVariable 获取 URL 中的参数.

通过 @RequestParam 接收请求参数

通过 @RequestParam接收请求参数适用于getpost提交请求方式

通过 @RequestParam 接收请求参数与“通过处理方法的形参接收请求参数”部分的区别如下:当请求参数与接收参数名不一致时,“通过处理方法的形参接收请求参数”不会报 404 错误,而“通过 @RequestParam 接收请求参数”会报 404 错误。

通过 @ModelAttribute 接收请求参数

当 @ModelAttribute 注解放在处理方法的形参上时,用于将多个请求参数封装到一个实体对象,从而简化数据绑定流程,而且自动暴露为模型数据,在视图页面展示时使用。

而“通过实体 Bean 接收请求参数”中只是将多个请求参数封装到一个实体对象,并不能暴露为模型数据(需要使用 model.addAttribute 语句才能暴露为模型数据,数据绑定与模型数据展示后面教程中会讲解)

过 @ModelAttribute 注解接收请求参数适用于 getpost 提交请求方式.

Spring MVC的转发与重定向

重定向是将用户从当前处理请求定向到另一个视图(例如 JSP)或处理请求,以前的请求(request)中存放的信息全部失效,并进入一个新的 request 作用域;转发是将用户对当前处理的请求转发给另一个视图或处理请求,以前的 request 中存放的信息不会失效。

转发是服务器行为,重定向是客户端行为。

1)转发过程

客户浏览器发送 http 请求,Web 服务器接受此请求,调用内部的一个方法在容器内部完成请求处理和转发动作,将目标资源发送给客户;在这里转发的路径必须是同一个 Web 容器下的 URL,其不能转向到其他的 Web 路径上,中间传递的是自己的容器内的 request。

在客户浏览器的地址栏中显示的仍然是其第一次访问的路径,也就是说客户是感觉不到服务器做了转发的。转发行为是浏览器只做了一次访问请求。

2)重定向过程

客户浏览器发送 http 请求,Web 服务器接受后发送 302 状态码响应及对应新的 location 给客户浏览器,客户浏览器发现是 302 响应,则自动再发送一个新的 http 请求,请求 URL 是新的 location 地址,服务器根据此请求寻找资源并发送给客户。

在这里 location 可以重定向到任意 URL,既然是浏览器重新发出了请求,那么就没有什么 request 传递的概念了。在客户浏览器的地址栏中显示的是其重定向的路径,客户可以观察到地址的变化。重定向行为是浏览器做了至少两次的访问请求。

package controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/index")
public class IndexController {
@RequestMapping("/login")
public String login() {
//转发到一个请求方法(同一个控制器类可以省略/index/)
return"forward:/index/isLogin";
}
@RequestMapping("/isLogin")
public String isLogin() {
//重定向到一个请求方法
return"redirect:/index/isRegister";
}
@RequestMapping("/isRegister")
public String isRegister() {
//转发到一个视图
return "register";
}
}

在 Spring MVC 框架中,不管是重定向或转发,都需要符合视图解析器的配置,如果直接转发到一个不需要 DispatcherServlet 的资源,例如:

return "forward:/html/my.html";

则需要使用 mvc:resources 配置:

<mvc:resources location="/html/" mapping="/html/**" />

Spring MVC应用@Autowired和@Service进行依赖注入

Spring MVC 框架本身就是一个非常优秀的 MVC 框架,它具有依赖注入的优点,可以通过 org.springframework.beans.factory. annotation.Autowired 注解类型将依赖注入到一个属性(成员变量)或方法

在 Spring MVC 中,为了能被作为依赖注入,类必须使用 org.springframework.stereotype.Service 注解类型注明为 @Service(一个服务)。另外,还需要在配置文件中使用 <context:component-scan base-package=“基本包”/> 元素来扫描依赖基本包。

Spring MVC中@ModelAttribute注解的使用

通过 org.springframework.web.bind.annotation.ModelAttribute 注解类型可经常实现以下两个功能:

1)绑定请求参数到实体对象(表单的命令对象)

@RequestMapping("/register")
public String register(@ModelAttribute("user") UserForm user) {
if ("zhangsan".equals(uname) && "123456".equals(upass)) {
logger.info("成功");
return "login";
} else {
logger.info("失败");
return "register";
}

在上述代码中“@ModelAttribute(“user”)UserForm user”语句的功能有两个:

  • 将请求参数的输入封装到 user 对象中。
  • 创建 UserForm 实例。

以“user”为键值存储在 Model 对象中,和“model.addAttribute(“user”,user)”语句的功能一样。
如果没有指定键值,即“@ModelAttribute UserForm user”,那么在创建 UserForm 实例时以“userForm”为键值存储在 Model 对象中,和“model.addAtttribute(“userForm”, user)”语句的功能一样。

2)注解一个非请求处理方法

被 @ModelAttribute 注解的方法将在每次调用该控制器类的请求处理方法前被调用。这种特性可以用来控制登录权限,当然控制登录权限的方法有很多,例如拦截器、过滤器等。

Spring MVC类型转换的意义

代码演示为何需要SpringMVC中的类型转换器

Spring MVC Converter(类型转换器)详解

Spring MVC 框架的Converter<S,T>是一个可以将一种数据类型转换成另一种数据类型的接口,这里 S 表示源类型,T 表示目标类型。开发者在实际应用中使用框架内置的类型转换器基本上就够了,但有时需要编写具有特定功能的类型转换器。

内置的类型转换器

在 Spring MVC 框架中,对于常用的数据类型,开发者无须创建自己的类型转换器,因为 Spring MVC 框架有许多内置的类型转换器用于完成常用的类型转换。Spring MVC 框架提供的内置类型转换包括以下几种类型。

1)标量转换器

名称作用
StringToBooleanConverterString 到 boolean 类型转换
ObjectToStringConverterObject 到 String 转换,调用 toString 方法转换
StringToNumberConverterFactoryString 到数字转换(例如 Integer、Long 等)
NumberToNumberConverterFactory数字子类型(基本类型)到数字类型(包装类型)转换
StringToCharacterConverterString 到 Character 转换,取字符串中的第一个字符
NumberToCharacterConverter数字子类型到 Character 转换
CharacterToNumberFactoryCharacter 到数字子类型转换
StringToEnumConverterFactoryString 到枚举类型转换,通过 Enum.valueOf 将字符串转换为需要的枚举类型
EnumToStringConverter枚举类型到 String 转换,返回枚举对象的 name 值
StringToLocaleConverterString 到 java.util.Locale 转换
PropertiesToStringConverterjava.util.Properties 到 String 转换,默认通过 ISO-8859-1 解码
StringToPropertiesConverterString 到 java.util.Properties 转换,默认使用 ISO-8859-1 编码

2)集合、数组相关转换器

名称作用
ArrayToCollectionConverter任意数组到任意集合(List、Set)转换
CollectionToArrayConverter任意集合到任意数组转换
ArrayToArrayConverter任意数组到任意数组转换
CollectionToCollectionConverter集合之间的类型转换
MapToMapConverterMap之间的类型转换
ArrayToStringConverter任意数组到 String 转换
StringToArrayConverter字符串到数组的转换,默认通过“,”分割,且去除字符串两边的空格(trim)
ArrayToObjectConverter任意数组到 Object 的转换,如果目标类型和源类型兼容,直接返回源对象;否则返回数组的第一个元素并进行类型转换
ObjectToArrayConverterObject 到单元素数组转换
CollectionToStringConverter任意集合(List、Set)到 String 转换
StringToCollectionConverterString 到集合(List、Set)转换,默认通过“,”分割,且去除字符串两边的空格(trim)
CollectionToObjectConverter任意集合到任意 Object 的转换,如果目标类型和源类型兼容,直接返回源对象;否则返回集合的第一个元素并进行类型转换
ObjectToCollectionConverterObject 到单元素集合的类型转换

类型转换是在视图与控制器相互传递数据时发生的。Spring MVC 框架对于基本类型(例如 int、long、float、double、boolean 以及 char 等)已经做好了基本类型转换。

Spring MVC Formatter(数据格式化)详解

Spring MVC 框架的 Formatter 与 Converter<S,T> 一样,也是一个可以将一种数据类型转换成另一种数据类型的接口。
不同的是,Formatter 的源数据类型必须是 String 类型,而 Converter<S,T> 的源数据类型是任意数据类型

在 Web 应用中由 HTTP 发送的请求数据到控制器中都是以 String 类型获取,因此在 Web 应用中选择 Formatter 比选择 Converter<S,T> 更加合理

内置的格式化转换器

Spring MVC 提供了几个内置的格式化转换器,具体如下。

  • mberFormatter:实现 Number 与 String 之间的解析与格式化。
  • CurrencyFormatter:实现 Number 与 String 之间的解析与格式化(带货币符号)。
  • PercentFormatter:实现 Number 与 String 之间的解析与格式化(带百分数符号)。
  • DateFormatter:实现 Date 与 String 之间的解析与格式化。

自定义格式化转换器

自定义格式化转换器就是编写一个实现 org.springframework.format.Formatter 接口的 Java 类。该接口声明如下:

public interface Formatter<T>

这里的 T 表示由字符串转换的目标数据类型。该接口有 parse 和 print 两个接口方法,自定义格式化转换器类必须覆盖它们。

public T parse(String s,java.util.Locale locale)public String print(T object,java.util.Locale locale)

parse 方法的功能是利用指定的 Locale 将一个 String 类型转换成目标类型,print 方法与之相反,用于返回目标对象的字符串表示。

Spring MVC的表单标签库详解

表单标签库中包含了可以用在 JSP 页面中渲染 HTML 元素的标签。在 JSP 页面使用 Spring 表单标签库时,必须在 JSP 页面开头处声明 taglib 指令,指令代码如下:

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>

在表单标签库中有 form、input、password、hidden、textarea、checkbox、checkboxes、radiobuttton、radiobuttons、select、option、options、errors 等标签。

名称作用
form渲染表单元素
input渲染 元素
password渲染 元素
hidden渲染 元素
textarea渲染 textarea 元素
checkbox渲染一个 元素
checkboxes渲染多个 元素
radiobutton渲染一个 元素
radiobuttons渲染多个 元素
select渲染一个选择元素
option渲染一个选项元素
options渲染多个选项元素
errors在 span 元素中渲染字段错误

表单标签

<form:form modelAttribute="xxx" method="post" action="xxx">    ...</form:form>

表单标签除了具有 HTML 表单元素属性以外,还具有 acceptCharsetcommandNamecssClasscssStylehtmlEscapemodelAttribute 等属性。

acceptCharset:定义服务器接受的字符编码列表。
commandName:暴露表单对象的模型属性名称,默认为command。cssClass:定义应用到 form 元素的 CSS 类。
cssStyle:定义应用到 form 元素的 CSS 样式。
htmlEscape:true 或 false,表示是否进行 HTML 转义。modelAttribute:暴露 form backing object 的模型属性名称,默认为 command。

其中,commandNamemodelAttribute 属性的功能基本一致,属性值绑定一个 JavaBean 对象。

各种标签实例

Spring MVC数据绑定和表单标签的应用(附带实例)

代码实例

Spring MVC JSON数据交互(附带实例)

Spring MVC 在数据绑定的过程中需要对传递数据的格式和类型进行转换,它既可以转换 String 等类型的数据,也可以转换 JSON 等其他类型的数据。本节将针对 Spring MVC 中 JSON 类型的数据交互进行讲解。

JSON 数据转换

为实现浏览器与控制器类之间的 JSON 数据交互,Spring MVC 提供了 MappingJackson2HttpMessageConverter 实现类默认处理 JSON 格式请求响应。该实现类利用 Jackson 开源包读写 JSON 数据,将 Java 对象转换为 JSON 对象和 XML 文档,同时也可以将 JSON 对象和 XML 文档转换为 Java 对象。

在使用注解开发时需要用到两个重要的 JSON 格式转换注解,分别是 @RequestBody@ResponseBody

  • @RequestBody:用于将请求体中的数据绑定到方法的形参中,该注解应用在方法的形参上。
    -@ResponseBody:用于直接返回 return 对象,该注解应用在方法上。

@RequestBody的使用

静态资源加载

Spring MVC拦截器(Interceptor)的配置及使用

在开发一个网站时可能有这样的需求:某些页面只希望几个特定的用户浏览。对于这样的访问权限控制,应该如何实现呢?拦截器就可以实现上述需求。在 Struts 2 框架中,拦截器是其重要的组成部分,Spring MVC 框架也提供了拦截器功能。

Spring MVC 的拦截器(Interceptor)与 Java Servlet 的过滤器(Filter)类似,它主要用于拦截用户的请求并做相应的处理,通常应用在权限验证、记录请求信息的日志、判断用户是否登录等功能上。

拦截器的定义

在 Spring MVC 框架中定义一个拦截器需要对拦截器进行定义和配置,定义一个拦截器可以通过两种方式:
一种是通过实现 HandlerInterceptor接口或继承HandlerInterceptor 接口的实现类来定义;另一种是通过实现 WebRequestInterceptor接口或继承 WebRequestInterceptor 接口的实现类来定义。

  • preHandle 方法:该方法在控制器的处理请求方法前执行,其返回值表示是否中断后续操作,返回 true 表示继续向下执行,返回 false 表示中断后续操作。
  • postHandle 方法:该方法在控制器的处理请求方法调用之后、解析视图之前执行,可以通过此方法对请求域中的模型和视图做进一步的修改。
  • afterCompletion 方法:该方法在控制器的处理请求方法执行完成后执行,即视图渲染结束后执行,可以通过此方法实现一些资源清理、记录日志信息等工作。

拦截器的配置

<!-- 配置拦截器 -->
<mvc:interceptors>
<!-- 配置一个全局拦截器,拦截所有请求 -->
<bean class="interceptor.TestInterceptor" />
<mvc:interceptor>

<!-- 配置拦截器作用的路径 -->
<mvc:mapping path="/**" />

<!-- 配置不需要拦截作用的路径 -->
<mvc:exclude-mapping path="" />

<!-- 定义<mvc:interceptor>元素中,表示匹配指定路径的请求才进行拦截 -->
<bean class="interceptor.Interceptor1" />
</mvc:interceptor>

<mvc:interceptor>
<!-- 配置拦截器作用的路径 -->
<mvc:mapping path="/gotoTest" />
<!-- 定义在<mvc: interceptor>元素中,表示匹配指定路径的请求才进行拦截 -->
<bean class="interceptor.Interceptor2" />
</mvc:interceptor>

</mvc:interceptors>

在上述示例代码中,<mvc:interceptors> 元素用于配置一组拦截器,其子元素 定义的是全局拦截器,即拦截所有的请求。
<mvc:interceptor> 元素中定义的是指定路径的拦截器,其子元素 <mvc:mapping> 用于配置拦截器作用的路径,该路径在其属性 path 中定义。
如上述示例代码中,path 的属性值“/** ”表示拦截所有路径,“/gotoTest”表示拦截所有以“/gotoTest”结尾的路径。
如果在请求路径中包含不需要拦截的内容,可以通过 <mvc:exclude-mapping> 子元素进行配置。
需要注意的是,<mvc:interceptor> 元素的子元素必须按照 <mvc:mapping…/>、<mvc:exclude-mapping…/>、<bean…/> 的顺序配置。

Spring MVC拦截器的执行流程

单个拦截器的执行流程

在配置文件中如果只定义了一个拦截器,程序将首先执行拦截器类中的 preHandle 方法,如果该方法返回 true,程序将继续执行控制器中处理请求的方法,否则中断执行。如果 preHandle 方法返回 true,并且控制器中处理请求的方法执行后、返回视图前将执行 postHandle 方法,返回视图后才执行 afterCompletion 方法。
代码实现

多个拦截器的执行流程

在 Web 应用中通常需要有多个拦截器同时工作,这时它们的 preHandle 方法将按照配置文件中拦截器的配置顺序执行,而它们的 postHandle 方法和 afterCompletion 方法则按照配置顺序的反序执行。

代码实现

Spring MVC拦截器实现用户登录权限验证案例

代码实例

Spring MVC数据验证简介

用户的输入一般是随意的,为了保证数据的合法性,数据验证是所有 Web 应用必须处理的问题。
在 Spring MVC 框架中有以下两种方法可以验证输入数据:

  • 利用 Spring 自带的验证框架。
  • 利用 JSR 303 实现。

数据验证分为客户端验证和服务器端验证,客户端验证主要是过滤正常用户的误操作,通过 JavaScript 代码完成。服务器端验证是整个应用阻止非法数据的最后防线,通过在应用中编程实现。

客户端验证

在大多数情况下,使用 JavaScript 进行客户端验证的步骤如下:

  • 编写验证函数。
  • 在提交表单的事件中调用验证函数。
  • 根据验证函数来判断是否进行表单提交。

客户端验证可以过滤用户的误操作,是第一道防线,一般使用 JavaScript 代码实现。但仅有客户端验证是不够的,攻击者还可以绕过客户端验证直接进行非法输入,这样可能会引起系统异常,为了确保数据的合法性,防止用户通过非正常手段提交错误信息,必须加上服务器端验证。

服务器端验证

Spring MVC 的 ConverterFormatter在进行类型转换时是将输入数据转换成领域对象的属性值(一种 Java 类型),一旦成功,服务器端验证器就会介入。也就是说,在 Spring MVC 框架中先进行数据类型转换,再进行服务器端验证。

服务器端验证对于系统的安全性、完整性、健壮性起到了至关重要的作用。在 Spring MVC 框架中可以利用 Spring 自带的验证框架验证数据,也可以利用 JSR 303 实现数据验证。

Spring MVC验证器:Validator接口和ValidationUtils类

Validator接口

创建自定义 Spring 验证器需要实现 org.springframework.validation.Validator 接口,该接口有两个接口方法:

boolean supports(Class<?> klass)void validate(Object object,Errors errors)

supports 方法返回 true时,验证器可以处理指定的 Class。validate方法的功能是验证目标对象 object,并将验证错误消息存入 Errors对象。

往 Errors 对象存入错误消息的方法是 rejectrejectValue,这两个方法的部分重载方法如下:

void reject(String errorCode)
void reject(String errorCode,String defaultMessage)
void rejectValue(String filed,String errorCode)
void rejectValue(String filed,String errorCode,String defaultMessage)

在一般情况下只需要给 reject 或 rejectValue 方法一个错误代码,Spring MVC 框架就会在消息属性文件中查找错误代码,获取相应错误消息。具体示例如下:

if(goods.getGprice() > 100 || goods.getGprice() < 0){  
errors.rejectValue("gprice","gprice.invalid");  // gprice.invalid为错误代码
}

ValidationUtils 类

org.springframework.validation.ValidationUtils 是一个工具类,该类中有几个方法可以帮助用户判定值是否为空。

例如:

if(goods.getGname()==null || goods.getGname().isEmpty()) {    errors.rejectValue("gname","goods.gname.required")
}

再如:


if(goods.getGname() == null || goods.getGname().trim().isEmpty()) {    errors.rejectValue("gname","goods.gname.required")
}

上述 if 语句可以编写成:

//gname为goods对象的属性ValidationUtils.rejectIfEmptyOrWhitespace(errors,"gname","goods.gname.required");

Spring MVC验证器应用实例(超详细)

代码实现

Spring MVC JSR-303验证框架之Hibernate-Validator

maven项目中引入Hibernate-Validator

Hibernate-Validator官网

10分钟搞定Hibernate-Validator校验

2.配置属性文件与验证器

如果将验证错误消息放在属性文件中,那么需要在配置文件中配置属性文件,并将属性文件与 Hibernate Validator 关联,具体配置代码如下:

<!-- 配置消息属性文件 -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <!-- 资源文件名 -->
    <property name="basenames">
        <list>
            <value>/WEB-INF/resource/errorMessages</value>
        </list>
    </property>
    <!-- 资源文件编码格式 -->
    <property name="fileEncodings" value="utf-8" />
    <!-- 对资源文件内容缓存的时间,单位为秒 -->
    <property name="cacheSeconds" value="120" />
</bean>
<!-- 注册校验器 -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
    <!-- hibernate 校验器 -->
    <property name="providerClass" value="org.hibernate.validator.HibernateValidator" />
    <!-- 指定校验使用的资源文件,在文件中配置校验错误信息,如果不指定则默认使用 classpath下的 ValidationMessages.properties -->
    <property name="validationMessageSource" ref="messageSource" />
</bean>
<!--开启 Spring的 Valid 功能 -->
<mvc:annotation-driven conversion-service="conversionService" validator="validator" />

标注类型

JSR 303 不需要编写验证器,但需要利用它的标注类型在领域模型的属性上嵌入约束。

1)空检查

  • @Null:验证对象是否为 null。
  • @NotNull:验证对象是否不为 null,无法检查长度为 0 的字符串。
  • @NotBlank:检查约束字符串是不是 null,以及被 trim 后的长度是否大于 0,只针对字符串,且会去掉前后空格。
  • @NotEmpty:检查约束元素是否为 null 或者是 empty。

示例如下:

@NotBlank(message="{goods.gname.required}") //goods.gname.required为属性文件的错误代码private String gname;

2)boolean 检查

  • @AssertTrue:验证 boolean 属性是否为 true。
  • @AssertFalse:验证 boolean 属性是否为 false。

示例如下:

@AssertTrue
private boolean isLogin;

3)长度检查

  • @Size(min=,max=):验证对象(Array、Collection、Map、String)长度是否在给定的范围之内。
  • @Length(min=,max=):验证字符串长度是否在给定的范围之内。

示例如下:

@Length(min=1,max=100)
private String gdescription;

4)日期检查

  • @Past:验证 Date 和 Callendar 对象是否在当前时间之前。
  • @Future:验证 Date 和 Calendar 对象是否在当前时间之后。
  • @Pattern:验证 String 对象是否符合正则表达式的规则。

示例如下:

@Past(message="{gdate.invalid}")private Date gdate;

5)数值检查

名称说明
@Min验证 Number 和 String 对象是否大于指定的值
@Max验证 Number 和 String 对象是否小于指定的值
@DecimalMax被标注的值必须不大于约束中指定的最大值,这个约束的参数是一个通过 BigDecimal 定义的最大值的字符串表示,小数存在精度
@DecimalMin被标注的值必须不小于约束中指定的最小值,这个约束的参数是一个通过 BigDecimal 定义的最小值的字符串表示,小数存在精度
@Digits验证 Number 和 String 的构成是否合法
@Digits(integer=,fraction=)验证字符串是否符合指定格式的数字,integer 指定整数精度,fraction 指定小数精度
@Range(min=,max=)检查数字是否介于 min 和 max 之间
@Valid对关联对象进行校验,如果关联对象是个集合或者数组,那么对其中的元素进行校验,如果是一个 map,则对其中的值部分进行校验
@CreditCardNumber信用卡验证
@Email验证是否为邮件地址,如果为 null,不进行验证,通过验证

示例如下:

@Range(min=10,max=100,message="{gprice.invalid}")private double gprice;

Spring MVC Hibernate-Validator数据验证实例

代码实现

Java国际化概念和使用介绍

程序国际化已成为 Web 应用的基本要求。随着网络的发展,大部分 Web 站点面对的已经不再是本地或者本国的浏览者,而是来自全世界各国、各地区的浏览者,因此国际化成为了 Web 应用不可或缺的一部分。

Java 国际化的思想是将程序中的信息放在资源文件中,程序根据支持的国家及语言环境读取相应的资源文件。资源文件是 key-value对,每个资源文件中的 key 是不变的,但 value 随不同国家/语言变化。

Java 程序的国际化主要通过两个类来完成。

1)java.util.Locale

用于提供本地信息,通常称它为语言环境。不同的语言、不同的国家和地区采用不同的 Locale 对象来表示。

2)java.util.ResourceBundle

该类称为资源包,包含了特定于语言环境的资源对象。当程序需要一个特定于语言环境的资源时(例如字符串资源),程序可以从适合当前用户语言环境的资源包中加载它。采用这种方式可以编写独立于用户语言环境的程序代码,而与特定语言环境相关的信息则通过资源包来提供。

为了实现 Java 程序的国际化,必须事先提供程序所需要的资源文件。资源文件的内容由很多 key-value对组成,其中 key 是程序使用的部分,而 value 是程序界面的显示。

资源文件的命名可以有如下 3 种形式:

  • baseName.properties。
  • baseName_language.properties。
  • baseName_language_country.properties。

baseName 是资源文件的基本名称,由用户自由定义,但是 language 和 country 必须为 Java 所支持的语言和国家/地区代码。

例如:

  • 中国大陆:baseName_zh_CN.properties。
  • 美国:baseName_en_US.properties。

Java 中的资源文件只支持 ISO-8859-1 编码格式字符,直接编写中文会出现乱码。用户可以使用 Java 命令 native2ascii.exe 解决资源文件的中文乱码问题,使用 MyEclipse 编写资源属性文件,在保存资源文件时 MyEclipse 自动执行 native2ascii.exe 命令,因此在 MyEclipse 中资源文件不会出现中文乱码问题。

Java 支持的语言和国家

java.util.Locale类的常用构造方法如下:

public Locale(String language);public Locale(String language, String country)。

其中,language 表示语言,它的取值是由小写的两个字母组成的语言代码。country 表示国家或地区,它的取值是由大写的两个字母组成的国家或地区代码。

实际上,Java 并不能支持所有国家和语言,如果需要获取 Java 所支持的语言和国家,开发者可以通过调用Locale类的 getAvailableLocales方法获取,该方法返回一个 Locale 数组,该数组中包含了 Java 所支持的语言和国家。

下面的 Java 程序简单示范了如何获取 Java 所支持的国家和语言:


import java.util.Locale;

public class Test {
    public static void main(String[] args) {
        // 返回Java所支持的语言和国家的数组
        Locale locales[] = Locale.getAvailableLocales();
        // 遍历数组元素,依次获取所支持的国家和语言
        for (int i = 0; i < locales.length; i++) {
            // 打印出所支持的国家和语言
            System.out.println(locales[i].getDisplayCountry() + "="
                    + locales[i].getCountry() + ""
                    + locales[i].getDisplayLanguage() + "="
                    + locales[i].getLanguage());
        }
    }
}

Java 程序的国际化

假设有如下简单 Java 程序:

public class TestI18N {public static void main(String[] args) {System.out.println("我要向把不同国家的人民问好:您好!");}}

为了让该程序支持国际化,需要将“我要向不同国家的人民问好:您好!”对应不同语言环境的字符串,定义在不同的资源文件中。

在 Web 应用的 src 目录下新建文件 messageResource_zh_CN.propertiesmessageResource_ en_US.properties。然后给资源文件 messageResource_zh_CN.properties添加“hello=我要向不同国家的人民问好:您好!”内容,保存后可看到如图 1 所示的效果。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sYno30G9-1594457289551)(en-resource://database/1210:1)]

图 1 显示的内容看似是很多乱码,实际上是 Unicode 编码文件内容。至此,资源文件 messageResource_zh_CN.properties 创建完成。

最后给资源文件 messageResource_en_US.properties 添加“hello=I want to say hello to all world!”内容。

现在将 TestI18N.java 程序修改成如下形式:

import java.util.Locale;
import java.util.ResourceBundle;

public class TestI18N {
    public static void main(String[] args) {
        // 取得系统默认的国家语言环境
        Locale lc = Locale.getDefault();
        // 根据国家语言环境加载资源文件
        ResourceBundle rb = ResourceBundle.getBundle("messageResource", lc);
        // 打印出从资源文件中取得的信息
        System.out.println(rb.getString("hello"));
    }
}

上面程序中的打印语句打印的内容是从资源文件中读取的信息。如果在中文环境下运行程序,将打印“我要向不同国家的人民问好:您好!”。


如果在“控制面板”中将计算机的语言环境设置成美国,然后再次运行该程序,将打印“I want to say hello to all world!”。需要注意的是,如果程序找不到对应国家/语言的资源文件,系统该怎么办?

假设以简体中文环境为例,先搜索如下文件:

messageResource_zh_CN.properties

如果没有找到国家/语言都匹配的资源文件,再搜索语言匹配文件,即搜索如下文件:

messageResource_zh.properties

如果上面的文件还没有搜索到,则搜索 baseName 匹配的文件,即搜索如下文件:

messageResource.properties

如果上面 3 个文件都找不到,则系统将出现异常。

带占位符的国际化信息

在资源文件中消息文本可以带有参数,例如:

welcome={0},欢迎学习 Spring MVC。

花括号中的数字是一个占位符,可以被动态的数据替换。在消息文本中占位符可以使用 0~9 的数字,也就是说消息文本的参数最多可以有 10 个。例如:

welcome={0},欢迎学习 Spring MVC,今天是星期{1}。

如果要替换消息文本中的占位符,可以使用 java.text.MessageFormat 类,该类提供了一个静态方法 format,用来格式化带参数的文本。format 方法的定义如下:

public static String format(String pattern,Object ...arguments)

替换占位符的示例代码如下:

import java.text.MessageFormat;
import java.util.Locale;
import java.util.ResourceBundle;

public class TestFormat {
    public static void main(String[] args) {
        // 取得系统默认的国家语言环境
        Locale lc = Locale.getDefault();
        // 根据国家语言环境加载资源文件
        ResourceBundle rb = ResourceBundle.getBundle("messageResource", lc);
        // 从资源文件中取得的信息
        String msg = rb.getString("welcome");
        // 替换消息文本中的占位符,消息文本中的数字占位符将按照参数的顺序
        // (从第二个参数开始)被替换,即“我”替换{0}、“5”替换{1}
        String msgFor = MessageFormat.format(msg, "我", "5");
        System.out.println(msgFor);
    }
}

Spring MVC的国际化

Spring MVC 的国际化是建立在 Java 国际化的基础之上的,Spring MVC 框架的底层国际化与 Java 国际化是一致的,作为一个良好的 MVC 框架,Spring MVC 将 Java 国际化的功能进行了封装和简化,开发者使用起来会更加简单、快捷。

国际化和本地化应用程序时需要具备以下两个条件:

  • 将文本信息放到资源属性文件中。
  • 选择和读取正确位置的资源属性文件。

下面讲解第二个条件的实现。

Spring MVC加载资源属性文件

在 Spring MVC 中不能直接使用 ResourceBundle 加载资源属性文件,而是利用 bean(messageSource)告知 Spring MVC 框架要将资源属性文件放到哪里。示例代码如下:

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleM essageSource">
    <property name="basenames">
        <list>
            <value>/WEB-INF/resource/messages</value>
            <value>/WEB-INF/resource/labels</value>
        </list>
    </property>
</bean>

语言区域的选择

在 Spring MVC 中可以使用语言区域解析器 bean 选择语言区域,该 bean 有 3 个常见实现,即 AcceptHeaderLocaleResolverSessionLocaleResolverCookieLocaleResolver

1)AcceptHeaderLocaleResolver

根据浏览器 Http Header 中的 accept-language 域设定(accept-language 域中一般包含了当前操作系统的语言设定,可通过 HttpServletRequest.getLocale 方法获得此域的内容)。

改变 Locale 是不支持的,即不能调用 LocaleResolver接口的 setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale)方法设置 Locale。

2)SessionLocaleResolver

根据用户本次会话过程中的语言设定决定语言区域(例如用户进入首页时选择语言种类,则此次会话周期内统一使用该语言设定)。

3)CookieLocaleResolver

根据 Cookie 判定用户的语言设定(Cookie 中保存着用户前一次的语言设定参数)。

由上述分析可知,SessionLocaleResolver 实现比较方便用户选择喜欢的语言种类,教程中使用该方法进行国际化实现。

下面是使用 SessionLocaleResolver 实现的 bean 定义:

<bean id="localeResolver" class="org.springframework.web.servlet.il8n.SessionLocaleResolver">   
<property name="defaultLocale" value="zh_CN"></property>
</bean>

如果采用基于SessionLocaleResolverCookieLocaleResolver 的国际化实现,必须配置 LocaleChangeInterceptor 拦截器,示例代码如下:

<mvc:interceptors>    
<bean class="org.springframework.web.servlet.il8n.LocaleChangeInterceptor"/>
</mvc:interceptors>

使用 message 标签显示国际化信息

在 Spring MVC 框架中可以使用 Spring 的 message 标签在 JSP 页面中显示国际化消息。在使用 message 标签时需要在 JSP 页面的最前面使用 taglib 指令声明 spring 标签,代码如下:

<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>

message 标签有以下常用属性。

  • code:获得国际化消息的 key。
  • arguments:代表该标签的参数。如果替换消息中的占位符,示例代码为“<spring:message code=“third” arguments=“888,999” />”,third 对应的消息有两个占位符 {0} 和 {1}。
  • argumentSeparator:用来分隔该标签参数的字符,默认为逗号。
  • text:code 属性不存在,或指定的 key 无法获取消息时所显示的默认文本信息。

Spring MVC使用SessionLocaleResolver实现用户自定义切换语言实例

代码实现

Spring MVC统一异常处理的3种方式(附带实例)

在 Spring MVC 应用的开发中,不管是对底层数据库操作,还是业务层或控制层操作,都会不可避免地遇到各种可预知的、不可预知的异常需要处理。

如果每个过程都单独处理异常,那么系统的代码耦合度高,工作量大且不好统一,以后维护的工作量也很大。

如果能将所有类型的异常处理从各层中解耦出来,这样既保证了相关处理过程的功能单一,又实现了异常信息的统一处理和维护。

幸运的是,Spring MVC 框架支持这样的实现。Spring MVC 统一异常处理有以下 3 种方式:

  • 使用 Spring MVC 提供的简单异常处理器 SimpleMappingExceptionResolver。、
  • 实现 Spring 的异常处理接口 HandlerExceptionResolver 自定义自己的异常处理器。
  • 使用 @ExceptionHandler 注解实现异常处理.

代码实现

Spring MVC使用SimpleMappingExceptionResolver类异常处理

代码实例

Spring MVC使用HandlerExceptionResolver接口异常处理

代码实现

Spring MVC使用@ExceptionHandler注解异常处理

代码实现

Spring MVC文件上传

Spring MVC 框架的文件上传是基于 commons-fileupload 组件的文件上传,只不过 Spring MVC 框架在原有文件上传组件上做了进一步封装,简化了文件上传的代码实现,取消了不同上传组件上的编程差异。

commons-fileupload组件

由于 Spring MVC 框架的文件上传是基于 commons-fileupload 组件的文件上传,因此需要将 commons-fileupload 组件相关的 JAR(commons-fileupload-1.3.1.jarcommons-io-2.4.jar)复制到 Spring MVC 应用的 WEB-INF/lib 目录下。下面讲解如何下载相关 JAR 包。

Commons 是 Apache 开放源代码组织中的一个 Java 子项目,该项目包括文件上传、命令行处理、数据库连接池、XML 配置文件处理等模块。fileupload 就是其中用来处理基于表单的文件上传的子项目,commons-fileupload 组件性能优良,并支持任意大小文件的上传。

commons-fileupload 组件可以从“下载地址”下载,本教程采用的版本是 1.2.2。下载它的 Binares 压缩包(commons-fileupload-1.3.1-bin.zip),解压缩后的目录中有两个子目录,分别是 lib 和 site。

在 lib 目录下有一个 JAR 文件——commons-fileupload-1.3.1.jar0,该文件是 commons-fileupload 组件的类库。在 site 目录中是 commons-fileupload 组件的文档,也包括 API 文档。

commons-fileupload 组件依赖于 Apache 的另外一个项目——commons-io,该组件可以从“下载地址”下载,本教程采用的版本是 2.4。下载它的 Binaries 压缩包(commons-io-2.4-bin.zip),解压缩后的目录中有 4 个 JAR 文件,其中有一个 commons-io-2.4.jar 文件,该文件是 commons-io 的类库。

基于表单的文件上传

标签 会在浏览器中显示一个输入框和一个按钮,输入框可供用户填写本地文件的文件名和路径名,按钮可以让浏览器打开一个文件选择框供用户选择文件。

文件上传的表单例子如下:

<form method="post" action="upload" enctype="multipart/form-data">
    <input type="file" name="myfile"/>
</form>

对于基于表单的文件上传,不要忘记使用enctype属性,并将它的值设置为multipart/form-data,同时将表单的提交方式设置为post。为什么要这样呢?下面从 enctype 属性说起。

表单的enctype 属性指定的是表单数据的编码方式,该属性有以下 3 个值。

  • application/x-www-form-urlencoded:这是默认的编码方式,它只处理表单域里的 value 属性值。
  • multipart/form-data:该编码方式以二进制流的方式来处理表单数据,并将文件域指定文件的内容封装到请求参数里。
  • text/plain:该编码方式只有当表单的 action 属性为“mailto:”URL 的形式时才使用,主要适用于直接通过表单发送邮件的方式。

由上面 3 个属性的解释可知,在基于表单上传文件时 enctype 的属性值应为 multipart/form-data。

MultipartFile接口

在 Spring MVC 框架中上传文件时将文件相关信息及操作封装到 MultipartFile 对象中,因此开发者只需要使用 MultipartFile 类型声明模型类的一个属性即可对被上传文件进行操作。该接口具有如下方法。

名称作用
byte[] getBytes()以字节数组的形式返回文件的内容
String getContentType()返回文件的内容类型
InputStream getInputStream()返回一个InputStream,从中读取文件的内容
String getName()返回请求参数的名称
String getOriginalFillename()返回客户端提交的原始文件名称
long getSize()返回文件的大小,单位为字节
boolean isEmpty()判断被上传文件是否为空
void transferTo(File destination)将上传文件保存到目标目录下

在上传文件时需要在配置文件中使用 Spring 的 org.springframework.web.multipart.commons.CommonsMultipartResolver 类配置 MultipartResolver 用于文件上传。

Spring MVC单文件上传(附带实例)

代码实现

Spring MVC多文件上传(附带实例)

[代码实现](http://c.biancheng.net/view/4481.html

Spring MVC文件下载

文件下载的实现方法

实现文件下载有以下两种方法:

  • 通过超链接实现下载。
  • 利用程序编码实现下载。

通过超链接实现下载固然简单,但暴露了下载文件的真实位置,并且只能下载存放在 Web 应用程序所在的目录下的文件。

利用程序编码实现下载可以增加安全访问控制,还可以从任意位置提供下载的数据,可以将文件存放到 Web 应用程序以外的目录中,也可以将文件保存到数据库中。

利用程序实现下载需要设置两个报头:

1)Web 服务器需要告诉浏览器其所输出内容的类型不是普通文本文件或 HTML 文件,而是一个要保存到本地的下载文件,这需要设置 Content-Type 的值为application/x-msdownload

2)Web 服务器希望浏览器不直接处理相应的实体内容,而是由用户选择将相应的实体内容保存到一个文件中,这需要设置 Content-Disposition 报头。

该报头指定了接收程序处理数据内容的方式,在 HTTP 应用中只有 attachment是标准方式,attachment 表示要求用户干预。在 attachment 后面还可以指定 filename 参数,该参数是服务器建议浏览器将实体内容保存到文件中的文件名称。

设置报头的示例如下:

response.setHeader("Content-Type", "application/x-msdownload");
response.setHeader("Content-Disposition", "attachment;filename="+filename);

代码实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值