资讯专栏INFORMATION COLUMN

SpringMVC学习笔记

roundstones / 1108人阅读

摘要:是目前最流行的一种互联网软件架构。协议,是一个无状态协议,即所有的状态都保存在服务器端。而这种转化是建立在表现层之上的,所以就是表现层状态转化。具体说,就是协议里面,四个表示操作方式的动词。

一、SpringMVC概述

Spring为展现层提供的基于MVC设计理念的优秀的Web框架,是目前最主流的MVC框架之一

Spring3.0之后全面超越Struts2,成为最优秀的MVC框架

SpringMVC通过一套MVC注解,让POJO成为处理请求的控制器,而无须实现任何接口

支持REST风格的URL请求

采用了松散耦合可挺拔组件结构,比其他MVC框架更具扩展性和灵活性

二、HelloWorld

步骤:

maven依赖



    4.0.0

    com.meituan.spring
    mvc
    1.0-SNAPSHOT

    
        
            org.springframework
            spring-web
            4.3.14.RELEASE
        

        
            org.springframework
            spring-core
            4.3.14.RELEASE
        

        
            org.springframework
            spring-context
            4.3.14.RELEASE
        

        
            org.springframework
            spring-webmvc
            4.3.14.RELEASE
        

    

    
        
            
            
                org.apache.maven.plugins
                maven-compiler-plugin
                3.5.1
                
                    1.8
                    1.8
                    UTF-8
                
            
            
                org.apache.maven.plugins
                maven-war-plugin
            
        
    

在Module Settings->Project Settings->Artifacts->output layout中,找到WEB-INF目录,确认在其下存在lib目录,不存在则创建,将library files添加进去

web.xml



    
        contextConfigLocation
        /WEB-INF/applicationContext.xml
    
    
        org.springframework.web.context.ContextLoaderListener
    
    
        dispatcher
        org.springframework.web.servlet.DispatcherServlet
        1
    
    
        dispatcher
        /
    

dispatcher-servlet.xml

可以通过contextConfigLocation来指定SpringMVC配置文件的位置

使用默认规则:/WEB-INF/-servlet.xml




    

    

    
        
        
    

注意:前后缀一定不要出错

Controller类

   import org.springframework.stereotype.Controller;
   import org.springframework.web.bind.annotation.RequestMapping;
   import org.springframework.web.bind.annotation.ResponseBody;

   @Controller
   public class HelloWorld {
   
       @RequestMapping("/helloworld")
       public String hello() {
           System.out.println("hello world, hello springmvc !");
           return "success";
       }
   }

index.jsp文件

 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 
  
    $Title$
  
  
    hello world!
  
 

视图jsp文件

 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 
  
    $Title$
  
  
    

success page!

配置好Tomcat

值得注意的是,在deployment->Deploy at the server startup中添加artifact

启动Tomcat即可

三、使用@RequestMapping映射请求

源码

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping
3.1 使用@RequestMapping映射请求

可以用来修饰方法,还可以用来修饰类

类定义处:提供初步的请求映射信息,相对于WEB应用的根目录

方法处:提供进一步的细分映射信息,相对于类定义处的URL,若类定义处未标@RequestMapping,则方法处标记的URL相对于WEB应用的根目录

DispatcherServlet截获请求后,就通过控制器上@RequestMapping提供的映射信息确定请求所对应的处理方法

3.2 映射请求参数、请求方法或请求头

@RequestMapping除了可以使用请求URL映射请求外,还可以使用请求方法、请求参数及请求头映射请求

@RequestMapping的value、method、params及heads分别表示请求URL、请求方法、请求参数及请求头的映射条件,它们之间是与的关系,联合使用多个条件可让请求映射更加精确化

params和headers支持简单的表达式

param1:表示请求必须包含名为param1的请求参数

!param1:表示请求不能包含名为param1的请求参数

param1!=value1表示请求包含名为param1的请求参数,但其值不能为value1

{"param1=value1", "param2"}:请求必须包含名为param1和param2的两个请求参数,且param1参数的值必须为value1

Ant风格资源地址支持3种匹配符:

?:匹配文件名中的一个字符

* :匹配文件名中的任意字符

**:匹配多层路径

3.3 支持Ant风格(了解即可)

@RequestMapping 还支持 Ant 风格的 URL :

/user/*/createUser:匹配 /user/aaa/createUser、/user/bbb/createUser 等 URL

/user/**/createUser:匹配 /user/createllser、/user/aaa/bbb/createUser 等 URL

/user/createllser??:匹配 /user/createllseraa、/user/createllserbb 等 URL

3.4 @PathVariable映射URL綁定的占位符

带 占 位 符 的 URL是Spring3.0新增的功能,该功能在SpringMVC向REST目标挺进发展过程中具有里程碑的意义

通过@PathVariable可以将URL中占位符参数绑定到控制器处理方法的入参中:URL中的{xxx丨占位符可以通过 @PathVariable("xxx")綁定到操作方法的入参中。

    @RequestMapping("/delete/{id}")
    public String delete(@PathVariable("id") Integer id) {
        System.out.println(id);
        return "redirect:/user/list.action";
    }
3.5 REST

REST 即Representational State Transfer。 (资源)表现层状态转化。是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便, 所以正得到越来越多网站的采用

资 源 ( Resources):网络上的一个实体,或者说是网络上的一个具体信息。它 可以是一段文本、 一 张图片、一首歌曲、一种服务,总之就是一个具体的存在。 可以用一个URI (统一资源定位符)指向它,每种资源对应一个特定的URU要 获取这个资源,访问它的URI就可以,因此URI即为每一个资源的独一无二的识别符

表现层 ( Representation):把资源具体呈现出来的形式,叫做它的表现层 (Representation) ^比如,文本可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式

状态转化 ( StateTransfer):每发出一个请求,就代表了客户端和服务器的一 次交互过程。HTTP协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转化”( State Transfer)。而这种转化是建立在表现层之上的,所以就是“ 表现层状态转化”。具体说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源,PUT用来更新资源,DELETE用来删除资源。

HiddenHttpMethodFilter: 浏览器 form 表单只支持 GET 与 POST请求,而 DELETE、PUT等method并不支持,Spring3.0添加了一个过滤器,可以将这些请求转换为标准的http方法,使得支持GET、POST、PUT与DELETE请求

web.xml

    
    
        HiddenHttpMethodFilter
        org.springframework.web.filter.HiddenHttpMethodFilter
    
    
    
        HiddenHttpMethodFilter
        /*
    

jsp

添加一个form,增加一个隐藏域name="_method",指明请求的类型,值取PUT或DELETE

    

java

    @RequestMapping("/delete/{id}")
    public String delete(@PathVariable("id") Integer id) {
        userDao.deleteUserById(id);
        return "success";
    }

在Tomcat8以上版本,会出现问题,需要在jsp文件中添加

<%@ page contentType="text/html;charset=UTF-8" language="java"  isErrorPage="true"%>

指定属性isErrorPage="true"

四、映射请求参数 & 请求参数 4.1 请求处理方法签名

Spring MVC通过分析处理方法的签名,将HTTP请求信息绑定到处理方法的相应入参中。

Spring MVC对控制器处理方法签名的限制是很宽松的, 几乎可以按喜欢的任何方式对方法进行签名。

必要时可以对方法及方法入参标注相应的注解(@PathVariable、@RequestParam、 @RequestHeader等)、Spring MVC框架会将HTTP请求的信息绑定到相应的方法入参中,并根据方法的返回值类型做出相应的后续处理。

4.2 使用@RequestParam绑定请求参数值

在处理方法入参处使用@RequestParam可以把请求参数传递给请求方法

value:参数名

required:是否必须。默认为true,表示请求参数中必须包含对应 的参数,若不存在,将抛出异常

defaultValue:请求参数的默认值

4.3 使用@RequestHeader绑定请求报头的属性值(了解即可)

请求头包含了若干个属性,服务器可据此获知客户端的信息,通过@RequestHeader即可将请求头中的属性值绑定到处理方法的入参中

4.4 使用CookieValue绑定请求中的cookie值(了解即可)

@CookieValue可让处理方法入参绑定某个cookie值

4.5 使用POJO对象绑定请求参数值

SpringMVC会按请求参数名和POJO属性名进行自动匹配,自动为该对象填充属性值,支持级联属性

如:dept.deptId、dept.address.tel等

4.6 使用Servlet API作为入参

MVC的handler访求可以接受以下Servlet API类型的参数

HttpServletRequest

HttpServletResponse

HttpSession

java.security.Principal

Locale

InputStream

OutputStream

Reader

Writer

五、处理模式数据

Spring MVC提供了以下几种途径输出模型数据:

ModelAndView:处理方法返回值类型为ModelAndView 时,方法体即可通过该对象添加模型数据

Map及Model: 入参为org.springframework.ui.Model、 org.springframework.ui.ModelMap或 java.util.Map时,处理 方法返回时,Map中的数据会自动添加到模型中。

@SessionAttributes:将模型中的某个属性暂存到 HttpSession中,以便多个请求之间可以共享这个属性

@ModelAttribute:方法入参标注该注解后,入参的对象就会放到数据模型中

5.1 ModelAndView

SpringMVC会把 ModelAndView 里model 中的数据放入到request域对象( requestScope )中

控制器处理方法的返回值如果为ModelAndView,则其既包含视图信息,也包含模型数据信息。

添加模型数据:

MoelAndView addObject(String attributeName, Object attributeValue)

ModelAndView addAIIObject(Map modelMap)

设置视图:

void setView(View view)

void setViewName(String viewName)

5.2 Map及Model

Spring MVC在内部使用了一个 org.springframework.ui.Model 接口存储模型数据

具体步骤

Spring MVC在调用方法前会创建一个隐 含的模型对象作为模型数据的存储容器。

如果方法的入参为Map或Model类型,Spring MVC会将隐含模型的引用传递给这些入参。在方法体内,开发者可以通过这个入参对象访问到模型中的所有数 据,也可以向模型中添加新的属性数据。

5.3 将模型数据存入Session中

若希望在多个请求之间共用某个模型属性数据,则可以在控制器上标注一个 @SessionAttributes,Spring MVC 将在模型中对应的属性暂存到HttpSession中。

@SessionAttributes除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型指定哪些模型属性需要放到session会话中

@SessionAttributes(types=User.class)会将隐含模型中所有类型 为User.class的属添加到会话中。

@SessionAttributes(value={“user1”, “user2”})

@SessionAttributes(types={User.class, Dept.class})

@SessionAttributes(value={“user1”, “user2” } , types={Dept.class})

5.4 @ModelAttribute

在方法定义上使用@ModelAttribute注解: Spring MVC 在调用目标处理方法前,会先逐个调用在方法级上标注了@ModelAttribute 的方法,因此对于一个controller映射多个URL的用法来说,要谨慎使用。

在方法的入参前使用@ModelAttribute注解:

可以从隐含对象中获取隐含的模型数据中获取对象,再将请求参数绑定到对象中,再传入入参

将方法入参对象添加到模型中

@ModelAttribute 注解也可以来修饰目标方法POJO类型的入参,其 value 属性值有如下的作用:

SpringMVC会使用 value 属性值在implicitModel中查找对应的对象,若存在则会直接传入到目标方法的入参中

SpringMVC会以value为key,POJO类型的对象为value,存入到request中

5.4.1 @ModelAttribute运行原理
@ModelAttribute
public void getUser(@RequestParam(value="id", required=false) Integer id, Map map) {
    System.out.println("modelAttribute method");
    
    if (id != null) {
        //模拟从数据库中获取对象
        User user = new User(1, "Tom", "123456", "Tom@meituan.com", 12);
        System.out.println("从数据库中获取一个对象: " + user);
        map.put("user", user);
    }
}

运行流程:

1、 执行@ModelAttribute注解修饰的方法;从数据库中取出对象,把对象放入到Map中,键为user

2、SpringMVC从Map中取出User对象,并把表单的请求参数赋值给该User对象对应的属性

3、SpringMVC把上述对象传入目标方法的参数

注意:在@ModelAttribute修饰的方法中,放入到Map时的键需要和目标方法入参类型的第一个字母小写的字符串一致!

5.4.2 源码分析的流程

调用@ModelAttribute注解修饰的方法,实际上把@ModelAttribute方法中Map中的数据放在了implicitModel中

解析请求处理器的目标参数,实际上该目标参数来自于WebDataBinder对象的target属性,

创建WebDataBinder对象:

确定objectName属性:若传入的attrName属性值为"",则objectName为类名第一个字母小写

注意:attrName,若目标方法的POJO属性使用了@ModelAttribute来修饰,则attrName值即为@ModelAttribute的value属性

确定target的值

在implicitModel中查找attrName对应的属性值。若存在,ok;若不存在,则验证当前handler是否使用了@SessionAttributes进行修饰,若使用了,则尝试从Session中获取attrName所对应的属性值,若session中没有对应的属性值,则抛出异常;若handler没有使用@SessionAttribute进行修饰,或@SessionAttributes中没有使用value值指定的key和attrName相匹配,则通过反射创建POJO对象

SpringMVC把表单的请求参数赋给了WebDataBinder的target对应的属性

SpringMVC会把WebDataBinder的attrName和target赋值给implicitModel

把WebDataBinder的target作为参数传递给目标参数的入参

5.4.3 如何确定目标方法POJO类型的入参

确定一个key

若目标方法的POJO类型的参数没有使用@ModelAttribute作为修饰,则key为POJO类名第一个字母的小写

若使用了@ModelAttribute来修饰,则key为@ModelAttribute注解的value属性值

在implicitModel中查找key对应的对象,若存在,则作为入参传入

若@ModelAttribute标记的方法在Map中保存过,且key和1确定的key一致,则会获取到

若implicitModel中不存在key对应的对象,则检查当前的handler是否使用@SessionAttributes注解修饰,若使用了该注解,且@SessionAttributes注解的value属性值中包含了key,则会从HttpSession中来获取key所对应的value值,若存在则直接传入目标方法的入参中;若不存在则将抛出异常

若handler没有标识@SessionAttributes注解的value值中不包含key,则会通过反射来创建POJO类型的参数,传入为目标方法的参数

SpringMVC会把key和POJO类型的对象保存到implicitModel,进而保存到request中

5.5 @SessionAttributes 注解引发的异常
org.springframework.web.HttpSessionRequiredException: Session attribute "user" required - not found in session

如果在处理类定义处标注了@SessionAttributes(“xxx”), 则尝试从session会话中获取该属性,并将其赋给该入参,然后再用请求消息填充该入参对象。如果在会话中找不到对应的属性,则拋出HttpSessionRequiredException 异常

5.6 视图和视图解析器 5.6.1 视图解析流程分析

请求处理方法执行完成后,最终返回一个ModelAndView 对象。对于那些返回String, View或ModeMap等类型的处理方法,Spring MVC也会在内部将它们装配成一个 ModelAndView对象,它包含了逻辑名和模型对象的视图

SpringMVC借助视图解析器(ViewResolver)得到最终的视图对象(View),最终的视图可以是JSP,也可能是 Excel、JFreeChart等各种表现形式的视图

对于最终究竟采取何种视图对象对模型数据进行渲染,处理器并不关心,处理器工作重点聚焦在生产模型数据的工作上,从而实现MVC的充分解耦

5.6.2 视图

视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给客 户。

为了实现视图模型和具体实现技术的解耦,Spring在org.springframework.web.servlet 包中定义了一个高度抽象的 View接口

视图对象由视图解析器负责实例化。由于视图是无状态的,所以他们 不会有线程安全的问题

常用的视图实现类: 

5.6.3 视图解析器(ViewResolver)

视图解析器的作用是将逻辑视图转为物理视图,所有的视图解析器都必须实现ViewResolver接口。

视图解析器的作用比较单一:将逻辑视图解析为一个具体的视图对象

SpringMVC为逻辑视图名的解析提供了不同的策略,可以在Spring WEB上下文中配置一种或多种解析策略,并指定他们之间的先后顺序。每一种映射策略对应一个具体的视图解析器实现类。

程序员可以选择一种视图解析器或混用多种视图解析器。可以通过order属性指定解析器的优先顺序,order越小优先级越高

SpringMVC会按视图解析器顺序的优先顺序对逻辑视图名进行解析,直到解析成功并返回视图对象,否则抛出ServletException异常。

5.6.4 使用mvc:view-controller不经控制器直接跳转到页面

若希望直接响应通过SpringMVC渲染的页面,可以使用mvc:view-controller标签实现:

       
  
      

那么现在可以直接在某一页面中通过请求路径”success”访问到/WEB-INF/views/success.jsp页面(因为我们上面配置了视图解析器将逻辑视图解析为前缀为/WEB-INF/views/,后缀为.jsp的物理视图)。但是,这种情况下通过控制器就无法映射到请求了,需要再进行如下配置:

   
      
5.6.5 关于重定向

一般情况下,控制器方法返回字符串类型的值会被当成逻辑视图名处理,但如果返回的字符串中带forward:或redirect:前缀时,SpringMVC会对它们进行特殊处理:将forward: 和redirect: 当成指示符,其后的字符串作为URL 来处理。示例如下: 

index.jsp:

Test Redirect

controller:

@Controller
@RequestMapping("/springmvc")
public class SpringMVCTest {

    @RequestMapping("/testRedirect")
    public String testRedirect() {
        System.out.println("testRedirect");
        return "redirect:/index.jsp";
    }
}

即可重定向到index.jsp。也可在redirect:/后添加控制器方法的映射路径,重定向到该目标方法。

六、SpringMVC表单标签&处理静态资源

通过SpringMVC的表单标签可以实现将模型数据 中的属性和HTML表单元素相綁定,以实现表单

数据更便捷编辑和表单值的回显

6.1 表单标签

form:input、 form:passwordN form:hidden、 form:textarea :对应 HTML 表車的 text、password、hidden、 textarea 标签

form:radiobutton :单选框组件标签,当表单bean对应的属性值和value值相等时,单选框破选中

form:radiobuttons :单选框组标签,用于构造多个单选

items :可以是一个 List、String[]或 Map

item Value :指定radio 的value值。可以是集合中bean的一个属性值

itemLabel :指定 radio 的 label 值

delimiter :多个单选框可以通过delimiter指定分隔符

form:checkbox :复选框组件。用于构造单个复选框

form:checkboxs :用于构造多个复选框。使用方式同form:radiobuttons 标签

form:select :用于@造下拉框组件。使用方式同form:radiobuttons 标签

form:option :下拉框选项组件标签。使用方式同 form:radiobuttons 标签

form:errors :显示表单组件或数据校验所对应的错误

6.2 处理静态资源

优雅的REST风格的资源URL不希望带.html或.do等后缀

若将DispatcherServlet请求映射配置为/,则Spring MVC将捕获 WEB容器的所有请求,包括静态资源的请求,SpringMVC会将他 们当成一个普通请求处理,因找不到对应处理器将导致错误。

可以在SpringMVC的配置文件中配置的方式解决静态资源的问题:

将在 SpringMVC 上下文中定义一个DefaultServletHttpRequestHandler,它会对进入DispatcherServlet 的请求进行筛查,如果发现是没有经过映射的请求,就将该请求交由WEB 应用服务器默认的Servlet处理,如果不是静态资源的请求,才由DispatcherServlet 继续处理

一般WEB应用服务器默认的Servlet的名称都是default。若所使用的 WEB服务器的默认Servlet名称不是default,则需要通过default-servlet-name 属性显式指定

七、数据转换 & 数据格式化 & 数据校验 7.1 数据转换 7.1.1 数据綁定流程

Spring MVC主框架将ServletRequest对象及目标方法的入参实例传递给WebDataBinderFactory实例,以创建DataBinder实例对象

DataBinder调用装配在Spring MVC上下文中的
ConversionService组件进行数据类型转换、数据格式化工作。将Servlet中的请求信息填充到入参对象中

调用Validator组件对已经綁定了请求消息的入参对象进行数据合法性校验,并最终生成数据绑定结果BindingData 对象

Spring MVC抽取BindingResult中的入参对象和校验错误对象,将它们赋给处理方法的响应入参

SpringMVC通过反射机制对目标处理方法进行解析,将请求消息绑定到处理方法的入参中。数据绑定的核心部件是DataBinder,运行机制如下:

7.1.2 关于mvc:annotation-driven

会自动注册RequestMappingHandlerMapping、RequestMappingHandlerAdapter 与ExceptionHandlerExceptionResolver 三个bean。

还将提供以下支持:

支持使用ConversionService实例对表单参数进行类型转换

支持使用 @NumberFormat annotation、@DateTimeFormat注解完成数据类型的格式化

支持使用@Valid注解对JavaBean实例进行JSR 303验证

支持使用 @RequestBody和 @ResponseBody 注解

7.1.3 @InitBinder注解

由@lnitBinder标识的方法,可以对WebDataBinder对

象进行初始化。WebDataBinder是DataBinder的子类,用
于完成由表单字段到JavaBean属性的綁定

@lnitBinder方法不能有返回值,它必须声明为void。

@lnitBinder方法的参数通常是是WebDataBinder

7.2 数据格式化

对属性对象的输入/输出进行格式化,从其本质上讲依然属于“类型转换”的范畴。

Spring在格式化模块,定义了一个实现ConversionService接口的FormattingConversionService 实现类,该实现类扩展了 GenericConversionService,因此它既具有类型转换的功能,又具有格式化的功能

FormattingConversionService 拥有一个FormattingConversionServiceFactroyBean 工厂类,后者用于在 Spring上下文中构造前者

FormattingConversionServiceFactroyBean 内部已经注册了:

NumberFormatAnnotationFormatterFactroy :支持对数字类型的属性,使用 @NumberFormat 注解

JodaDateTimeFormatAnnotationFormatterFactroy :支持对日期类型的属性使用@DateTimeFormat注解

装配了 FormattingConversionServiceFactroyBean 后,就可

以在Spring MVC入参绑定及模型数据输出时使用注解驱动
了。 默认创建的ConversionService 实例即为FormattingConversionServiceFactroyBean

7.2.1 日期格式化

@DateTimeFormat 注解可对java.util.Date、java.util.Calendar、java.long.Long 时间类型进行标注:

pattern属性:类型为字符串。指定解析/格式化字段数据的模式,如:”yyyy-MM-dd hh:mm:ss”

iso属性:类型为DateTimeFormat.lSO。指定解析/格式化字段数据的ISO模式,包括四种MSO.NONE (不使用)默认、ISO.DATE(yyyy-MM-dd)、IS〇.TIME(hh:mm:ss.SSSZ)、ISO.DATE_TIME(yyyy-MM-dd hh:mm:ss.SSSZ)

style属性:字符串类型。通过样式指定日期时间的格式,由两位字符组成,第一位表示日期的格式,第二位表示时间的格式:S :短日期/时间格式、M :中日期/时间格式、L :长日期/时间格式、F :完整日期/时间格式、忽略日期或时间格式

7.2.2

@NumberFormat可对类似数字类型的属性进行标注,它拥有两个互斥的属性:

style :类型为NumberFormat.Style。用于指定样式类型,包括三种:Style.NUMBER (正常数字类型)、Style.CURRENCY (货币类型)、Style.PERCENT (百分数类型)

pattern :类型为String,自定义样式,如patter="#,###";

7.3 数据校验 7.3.1 JSR 303

JSR 303是Java为Bean数据合法性校验提供的标准框架,它已经包含在JavaEE 6.0中

JSR 303通过在Bean属性上标注类似于@NotNull、@Max等标准的注解指定校验规则,并通过标准的验证接口对Bean进行验证

7.3.2 SpringMVC数据校验

Spring 4.0拥有自己独立的数据校验框架,同时支持JSR 303标准的校验框架。

Spring在进行数据绑定时,可同时调用校验框架完成数据校验工作。在Spring MVC中,可直接通过注解驱动的方式进行数据校验

Spring 的 LocalValidatorFactroyBean 既实现了 Spring 的Validator 接口,也实现了 JSR 303 的 Validator 接口。只要在Spring容器中定义了一个LocalValidatorFactoryBean,即可将其注入到需要数据校验的Bean中。

Spring本身并没有提供JSR303的实现,所以必须将JSR303的实现者的jar包放到类路径下。

在已经标注了 JSR303 注解的表单/命令对象前标注一个 @Valid , Spring MVC 框架在将请求参数绑定到该入参对象后,就会调用校验框架根据注解声明的校验规则实施校验

Spring MVC 是通过对处理方法签名的规约来保存校验结果的:前一个表单/命令对象的校验结果保存到随后的入参中,这个保存校验结果的入参必须是 BindingResult 或 Errors 类型,这两个类都位于 org.springframework.validation 包中

需校验的Bean对象和其绑定结果对象或错误对象时成对出现的,它们之间不允许声明其他的入参

Errors接口提供了获取错误信息的方法,如getErrorCount()或getFieldErrors(String field)

BindingResult扩展了Errors接口

7.3.3 在目标方法中获取校验结果

在表单/命令对象类的属性中标校验注解,在处理方法对应的入参前添加@Valid,SpringMVC就会实施校验并将校验结果保存在被校验入参对象之后的BindingResult或Errors入参中

7.3.4 在页面上显示错误

Spring MVC 除了会将表单/命令对象的校验结果保存到对 应的 BindingResu|t或 Errors对象中外,还会将所有校验结果保存到“隐含模型”

即使处理方法的签名中没有对应于表单/命合对象的结果入参,校验结果也会保存在“隐含对象”中。

隐含模型中的所有数据最终将通过 Http Servletrequest的属性列表暴露给 JSP 视图对象,因此在 JSP 中可以获取错误信息

在JSP页面上可通过显示错误消息

八、文件上传

Spring MVC为文件上传提供了直接的支持,这种支持是通过即插即用的MultipartResolver实现的。 Spring用 Jakarta Commons FileUpload 技术实现了一个 MultipartResolver 实现类:CommonsMultipartResovler

Spring MVC上下文中默认没有装配MultipartResovler,因此默认情况下不能处理文件的上传工作,如果想使用Spring 的文件上传功能,需现在上下文中配置MultipartResolver

配置MultipartResolver

defaultEncoding:必须和用户 JSP 的 pageEncoding 属性 一致,以便正确解析表单的内容

为了让 CommonsMultipartResovler正确工作,必须先将 Jakarta Commons FileUpload & Jakarta Commons io 的类包添加到类路径下。

九、拦截器

Spring MVC也可以使用拦截器对请求进行拦截处理,用户 可以自定义拦截器来实现特定的功能,自定义的拦截器必须实现 Handlerlnterceptor 接口

preHandle():这个方法在业务处理器处理请求之前被调用,在该 方法中对用户请求request进行处理。如果程序员决定该拦截器对 请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去 进行处理,则返回true ;如果程序员决定不需要再调用其他的组件 去处理请求,则返回false

postHandle():这个方法在业务处理器处理完请求后,但是DispatcherServlet向客户端返回响应前被调用,在该方法中对用户请求request进行处理。

afterCompletion():这个方法在 DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。

拦截器方法执行顺序

拦截器配置

多个拦截器的执行顺序


十、 异常处理

Spring MVC通过 HandlerExceptionResolver 处理程序的异常,包括Handler映射、数据绑定以及目标方法执行时发生的异常

Spring MVC提供的 HandlerExceptionResolver 的实现类

10.1 HandlerExceptionResolver

DispatcherServlet 默认装配的HandlerExceptionResolver

没有使用配置

使用配置

10.2 ExceptionHandlerExceptionResolver

主要处理Handler中用@ExceptionHandler注解定义的方法。

@ExceptionHandler注解定义的方法优先级问题:例如发生的是NullPointerException,但是声明的异常有 RuntimeException和Exception,此时会根据异常的最近继承关系找到继承深度最浅的那个@ExceptionHandler 注解方法,即标记了 RuntimeException的方法

ExceptionHandlerMethodResolver 内部若找不到@ExceptionHandler注解的话,会找 @ControllerAdvice 中的@ExceptionHandler 注解方法

10.3 ResponseStatusExceptionResolver

在异常及异常父类中找到@ResponseStatus注解,然后使用这个注解的属性进行处理。

定义一个@ResponseStatus注解修饰的异常类

若在处理器方法中拋出了上述异常: 若 ExceptionHandlerExceptionResolver 不解析上述异常。由于触发的异常 UnauthorizedException 带有@ResponseStatus 注解。因此会被 ResponseStatusExceptionResolver 解析到。最后响应HttpStatus_UNAUTH〇RIZED代码给客户端。HttpStatus_UNAUTH〇RIZED代表响应码401,无权限。 关于其他的响应码请参考HttpStatus枚举类型源码。

10.4 DefaultHandlerExceptionResolver

对一些特殊的异常进行处理,比如NoSuchRequestHandlingMethodException、 HttpReques tMethodNotSupportedException、 HttpMediaTypeNotSuppo rtedException、 HttpMediaTypeNotAcceptableException 等

10.5 SimpleMappingExceptionResolver

如果希望对所有异常进行统一处理,可以使用SimpleMappingExceptionResolver,它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常

十一、SpringMVC运行流程

十二、在Spring环境下使用SpringMVC

需要进行Spring 整合SpringMVC吗

还是否需要再加入Spring的IOC容器?

是否需要在web.xml文件中配置启动Spring IOC容器的ContextLoaderListener?

需要:通常情况下,类似于数据源、事务、整合其他框架都是放在Spring 的配置文件中(而不是放在SpringMVC的配置文件中),实际上放入Spring配置文件对应的IOC容器中的还有Service和Dao(推荐)

不需要:都放在SpringMVC的配置文件中,也可以分多个Spring的配置文件,然后使用import节点导入其他的配置文件(不推荐)

12.1 Bean的重复创建

若Spring的IOC容器和SpringMVC的IOC容器扫描的包有重合的部分,就会导致有的bean会被创建2次

解决:

使Spring的IOC容器扫描的包和SpringMVC的IOC容器扫描的包没有重合的部分

使用 exclude-filter 和 include-filter 子节点来规定只能扫描的注解

12.2 SpringMVC与Spring容器的关系

多个Spring l〇C容器之间可以设置为父子关系,以实现良好的解耦。

Spring MVC WEB层容器可作为“业务层” Spring 容器的子容器:即WEB层容器可以引用业务层容器的Bean,而业务层容器却访问不到WEB层容器的Bean

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/76552.html

相关文章

  • angularjs+springMvc学习笔记

    摘要:回调说白了,就是把函数当参数传给另一根函数,在另一个函数执行时调用此函数例如,在下面这段代码中,上面定义了两个函数和,下面的方法请求成功执行,失败执行异步异步的原理我看了网上的一些博客和例子,大都以定时任务为例子说明,但具体的原理我还是不太 回调 说白了,就是把函数当参数传给另一根函数,在另一个函数执行时调用此函数例如,在下面这段代码中,上面定义了两个函数success和error,下...

    dreamGong 评论0 收藏0
  • angularjs+springMvc学习笔记

    摘要:回调说白了,就是把函数当参数传给另一根函数,在另一个函数执行时调用此函数例如,在下面这段代码中,上面定义了两个函数和,下面的方法请求成功执行,失败执行异步异步的原理我看了网上的一些博客和例子,大都以定时任务为例子说明,但具体的原理我还是不太 回调 说白了,就是把函数当参数传给另一根函数,在另一个函数执行时调用此函数例如,在下面这段代码中,上面定义了两个函数success和error,下...

    rozbo 评论0 收藏0
  • springMvc学习笔记(2)

    摘要:笔记这周学习安装和配置和,为测试做准备。该软件由创建,并于年首次公开发布。同名公司成立于年,以提供支持。从年月开始,的开发由赞助,而年月至年月期间,其开发由赞助。最后发现是因为中的中的应该为大写将其改为及解决了此问题。 笔记 这周学习安装和配置nginx和redis,为测试做准备。showImg(https://segmentfault.com/img/bVbpdYF?w=660&h=...

    Shonim 评论0 收藏0
  • 设计模式学习笔记:适配器模式

    摘要:二适配器模式概念适配器模式是一种结构型模式,它的思想是将一个接口转化为另一个接口。适配器模式包含四个角色对象定义所需要的方法请求者负责使用对象定义的方法来做具体的处理被适配者以持有方法的角色适配器使用被适配者的方法来满足对象的需要。 一、结构型设计模式 1、概念结构型设计模式描述如何将类或者对象结合在一起形成更为复杂,功能更为强大的结构。 2、分类(1)类结构模型:这种结构模型关心类的...

    CompileYouth 评论0 收藏0
  • SpringMVC入门笔记

    摘要:入门笔记简介是一种基于的实现了设计模式的请求驱动类型的轻量级框架,是系开源项目中的一个,和配合使用。配置在中需要添加使用的和映射规则。入门较快,而掌握起来相对较难。 SpringMVC入门笔记 1. 简介 Spring MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架 ,是Spring系开源项目中的一个,和IoC配合使用。通过策略接口,Spring...

    zhaochunqi 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<