SpringMVC

1.HiddenHttpMethodFilter、HttpPutFormContentFilter

HiddenHttpMethodFilter

可以把 POST 请求转为 DELETE 或 POST 请求 可以把 POST 请求转为 DELETE 或 PUT请求

①web.xml配置

<!--  配置 org.springframework.web.filter.HiddenHttpMethodFilter: 可以把 POST 请求转为 DELETE 或 POST 请求  -->
    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

② 页面处使用方式

<form action="springmvc/testRest/1" method="post">
    <!-- 设置请求方式 -->
    <input type="hidden" name="_method" value="PUT/DELETE">
    <input type="submit" value="TestRest PUT/DELETE"/>
</form>

HttpPutFormContentFilter

在Spring3.0中获取put表单的参数,即使用HttpPutFormContentFilter过滤器

①web.xml配置

<filter>  
    <filter-name>httpPutFormcontentFilter</filter-name>  
    <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>  
</filter>  
<filter-mapping>  
    <filter-name>httpPutFormContentFilter</filter-name>  
    <url-pattern>/*</url-pattern>  
</filter-mapping> 

注: 该过滤器只能接受enctype值为application/x-www-form-urlencoded的表单,也就是说,在使用该过滤器时,form表单的代码必须如下:

<form action="" method="put" enctype="application/x-www-form-urlencoded">  
...
</form>  

2.使用 Servlet API 作为入参

MVC 的 Handler 方法可以接受哪些 ServletAPI 类型的参数

  • HttpServletRequest
  • HttpServletResponse
  • HttpSession
  • java.security.Principal
  • Locale
  • InputStream
  • OutputStream - Reader
  • Writer

3.@RequestParam, @RequestBody

@RequestParam

A) 常用来处理简单类型的绑定,通过Request.getParameter() 获取的String可直接转换为简单类型的情况( String–> 简单类型的转换操作由ConversionService配置的转换器来完成);因为使用request.getParameter()方式获取参数,所以可以处理get 方式中queryString的值,也可以处理post方式中 body data的值;

B)用来处理Content-Type: 为 application/x-www-form-urlencoded编码的内容,提交方式GET、POST;

C) 该注解有两个属性: value、required; value用来指定要传入值的id名称,required用来指示参数是否必须绑定;

示例代码:

@Controller  
@RequestMapping("/pets")  
@SessionAttributes("pet")  
public class EditPetForm {  

    @RequestMapping(method = RequestMethod.GET)  
    public String setupForm(@RequestParam("petId") int petId, ModelMap model) {  
        Pet pet = this.clinic.loadPet(petId);  
        model.addAttribute("pet", pet);  
        return "petForm";  
    }  

application/x-www-form-urlencoded方式是Jquery的Ajax请求默认方式,这种方式的好处就是浏览器都支持,在请求发送过程中会对数据进行序列化处理,以键值对形式?key1=value1&key2=value2的方式发送到服务器,如果用Jquery,它内部已经进行了处理,如果自己写原生的Ajax请求,就需要自己对数据进行序列化。
application/json,随着json规范的越来越流行,并且浏览器支持程度原来越好,许多开发人员易application/json作为请求content-type,告诉服务器请求的主题内容是json格式的字符串,服务器端会对json字符串进行解析,这种方式的好处就是前端人员不需要关心数据结构的复杂度,只要是标准的json格式就能提交成功,application/json数据格式越来越得到开发人员的青睐。

@RequestBody

该注解常用来处理Content-Type: 不是application/x-www-form-urlencoded编码的内容,例如application/json, pplication/xml等;

它是通过使用HandlerAdapter 配置的HttpMessageConverters来解析post data body,然后绑定到相应的bean上的。

因为配置有FormHttpMessageConverter,所以也可以用来处理 application/x-www-form-urlencoded的内容,处理完的结果放在一个MultiValueMap<String, String>里,这种情况在某些特殊需求下使用,详情查看ormHttpMessageConverter api;

示例代码:

@RequestMapping(value = "/something", method = RequestMethod.PUT)  
public void handle(@RequestBody String body, Writer writer) throws IOException {  
  writer.write(body);  
}  

4.@SessionAttributes、@SessionAttribute

@SessionAttributes

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

注意: 该注解只能放在类的上面. 而不能修饰放方法.

@SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中
@SessionAttributes(types=User.class) 会将隐含模型中所有类型为 User.class 的属性添加到会话中。
@SessionAttributes(value={“user1”, “user2”})
@SessionAttributes(types={User.class, Dept.class})
@SessionAttributes(value={“user1”, “user2”},types={Dept.class})

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

避免@SessionAttributes引发的异常

//该方法会往隐含模型中添加一个名为xxx的模型属性
@ModelAttribute("XXX")
public XXX getXXX(){
    XXX xxx = new XXX();
    return xxx;
}

@SessionAttribute

如果你需要访问预先存在的、以全局方式管理的会话属性的话,比如在控制器之外(比如通过过滤器)可能或不可能存在在一个方法参数上使用注解@SessionAttribute:

 /**
     * 在处理请求 /helloWorld/jump 的时候,会在会话中添加一个 sessionStr 属性。
     * <p/>
     * 这里可以通过@SessionAttribute 获取到
     */
    @RequestMapping("/sesAttr")
    public String handleSessionAttr(@SessionAttribute(value = "sessionStr") String sessionStr, Model model)
    {
        System.out.println("--> sessionStr : " + sessionStr);
        model.addAttribute("sth", sessionStr);
        return "/examples/targets/test1";
    }

5.@ModelAttribute

  1. 有 @ModelAttribute 标记的方法, 会在每个目标方法执行之前被 SpringMVC 调用!
  2. @ModelAttribute 注解也可以来修饰目标方法 POJO 类型的入参, 其 value 属性值有如下的作用:

    1). SpringMVC 会使用 value 属性值在 implicitModel 中查找对应的对象, 若存在则会直接传入到目标方法的入参中.
    2). SpringMVC 会一 value 为 key, POJO 类型的对象为 value, 存入到 request 中.

@ModelAttribute(value = "user")
public User getUser(@RequestParam("id") Integer id){
    if(id!=null) {
        System.out.println("id = " + id);
        User user = new User(1, "tom", "123", "tom@qq.com", "SHENZHEN");
        System.out.println("模拟从数据库根据id获取的user:" + user);
        return user;
    }
    return null;
}
@RequestMapping("/testModelAttribute")
public void update(User user){
    System.out.println("更新user:" + user);
}

6.自定义视图解析器

springmvc配置文件

<!-- 配置视图  BeanNameViewResolver 解析器: 使用视图的名字来解析视图 -->
    <!-- 通过 order 属性来定义视图解析器的优先级, order 值越小优先级越高 -->
    <bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
        <property name="order" value="100"></property>
    </bean>

自定义视图解析器

@Component
public class HelloView implements View{

    @Override
    public String getContentType() {
        return "text/html";
    }

    @Override
    public void render(Map<String, ?> model, HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        response.getWriter().print("hello view, time: " + new Date());
    }

}

controller渲染时 return “XXX”;返回自定义视图 解析器的bean的name

7.静态资源

<mvc:default-servlet-handler/>

  • 若将 DispatcherServlet 请求映射配置为 /,则 Spring MVC 将捕获WEB 容器的所有请求,包括静态资源的请求, SpringMVC 会将他们当成一个普通请求处理,因找不到对应处理器将导致错误。
  • 可以在 SpringMVC 的配置文件中配置 <mvc:default-servlet-handler/> 的方式解决静态资源的问题:

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

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

<mvc:resources />

<!--将链接中/p的静态的访问路径映射为URL,常用于加载html、js、css、图片、视频等静态资源-->
    <mvc:resources mapping="/js/**" location="classpath:/pageSource/js/"/>
    <mvc:resources mapping="/img/**" location="classpath:/pageSource/img/"/>
    <mvc:resources mapping="/css/**" location="classpath:/pageSource/css/"/>

8.数据绑定流程

  • Spring MVC 主框架将 ServletRequest 对象及目标方法的入参实例传递给 WebDataBinderFactory 实例,以创建 DataBinder 实例对象
  • DataBinder 调用装配在 Spring MVC 上下文中的ConversionService 组件进行数据类型转换、数据格式化工作。将 Servlet 中的请求信息填充到入参对象中
  • 调用 Validator 组件对已经绑定了请求消息的入参对象进行数据合法性校验,并最终生成数据绑定结果BindingData 对象
  • Spring MVC 抽取 BindingResult 中的入参对象和校验错误对象,将它们赋给处理方法的响应入参

@InitBinder

  • 由 @InitBinder 标识的方法,可以对 WebDataBinder 对象进行初始化。WebDataBinder 是 DataBinder 的子类,用
    于完成由表单字段到 JavaBean 属性的绑定
  • @InitBinder方法不能有返回值,它必须声明为void。
  • @InitBinder方法的参数通常是是 WebDataBinder

数据格式化

  • FormattingConversionServiceFactroyBean 内部已经注册了 :
    NumberFormatAnnotationFormatterFactroy:支持对数字类型的属性 使用 @NumberFormat 注解
    JodaDateTimeFormatAnnotationFormatterFactroy:支持对日期类型的属性 使用 @DateTimeFormat 注解
  • 装配了 FormattingConversionServiceFactroyBean 后,就可以在 Spring MVC 入参绑定及模型数据输出时使用注解驱动
    了。<mvc:annotation-driven/> 默认创建的ConversionService 实例即为FormattingConversionServiceFactroyBean

@DateTimeFormat

@DateTimeFormat 注解可对java.util.Date、java.util.Calendar、java.long.Long 时间类型进行标注:
– pattern 属性:类型为字符串。指定解析/格式化字段数据的模式,如:”yyyy-MM-dd hh:mm:ss”
– iso 属性:类型为 DateTimeFormat.ISO。指定解析/格式化字段数据的ISO模式,包括四种:ISO.NONE(不使用) – 默
认、ISO.DATE(yyyy-MM-dd) 、ISO.TIME(hh:mm:ss.SSSZ)、ISO.DATE_TIME(yyyy-MM-dd hh:mm:ss.SSSZ)
– style 属性:字符串类型。通过样式指定日期时间的格式,由两位字符组成,第一位表示日期的格式,第二位表示时间的格式:S:短日期/时间格式、M:中日期/时间格式、L:长日期/时间格式、F:完整日期/时间格式、-:忽略日期或时间格式

@NumberFormat

@NumberFormat 可对类似数字类型的属性进行标注,它拥有两个互斥的属性:
– style:类型为 NumberFormat.Style。用于指定样式类型,包括三种:Style.NUMBER(正常数字类型)、
Style.CURRENCY(货币类型)、 Style.PERCENT(百分数类型)
– pattern:类型为 String,自定义样式,如patter=”#,###”;

@DateTimeFormat(pattern="yyyy/MM/dd")
private Date birthday;

@NumberFormat(pattern="#,###.##")

数据校验

JSR 303中含有的注解

@Null   被注释的元素必须为 null  
@NotNull    被注释的元素必须不为 null  
@AssertTrue     被注释的元素必须为 true  
@AssertFalse    被注释的元素必须为 false  
@Min(value)     被注释的元素必须是一个数字,其值必须大于等于指定的最小值  
@Max(value)     被注释的元素必须是一个数字,其值必须小于等于指定的最大值  
@DecimalMin(value)  被注释的元素必须是一个数字,其值必须大于等于指定的最小值  
@DecimalMax(value)  被注释的元素必须是一个数字,其值必须小于等于指定的最大值  
@Size(max=, min=)   被注释的元素的大小必须在指定的范围内  
@Digits (integer, fraction)     被注释的元素必须是一个数字,其值必须在可接受的范围内  
@Past   被注释的元素必须是一个过去的日期  
@Future     被注释的元素必须是一个将来的日期  
@Pattern(regex=,flag=)  被注释的元素必须符合指定的正则表达式  
------------------------------  
Hibernate Validator 附加的注解
@NotBlank(message =)   验证字符串非null,且长度必须大于0  
@Email  被注释的元素必须是电子邮箱地址  
@Length(min=,max=)  被注释的字符串的大小必须在指定的范围内  
@NotEmpty   被注释的字符串的必须非空  
@Range(min=,max=,message=)  被注释的元素必须在合适的范围内  

Spring 本身并没有提供JSR 303 的实现,所有必须将JSR 303的实现者的jar 包(HIbernate Validator jar包)导入到项目中

<!--JSR 303的实现者的jar 包(HIbernate Validator jar包)-->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>5.3.4.Final</version>
    </dependency>

在表单/命令对象类的属性中标注校验注解,处理方法对应的入参前添加 @Valid,
这个保存校验结果的入参必须是 BindingResult 或Errors

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


提示消息的国际化

• 每个属性在数据绑定和数据校验发生错误时,都会生成一 个对应的 FieldError 对象。
• 当一个属性校验失败后,校验框架会为该属性生成 4 个消 息代码,这些代码以校验注解类名为前缀,结合
modleAttribute、属性名及属性类型名生成多个对应的消 息代码:例如 User 类中的 password 属性标准了一个
@Pattern 注 解,当该属性值不满足 @Pattern 所定义的规则时, 就会产生以下 4 个错误代码:
– Pattern.user.password
– Pattern.password
– Pattern.java.lang.String
– Pattern
• 当使用 Spring MVC 标签显示错误消息时, Spring MVC 会查看 WEB 上下文是否装配了对应的国际化消息,如果没有,则显示默认 的错误消息,否则使用国际化消息。
• 若数据类型转换或数据格式转换时发生错误,或该有的参 数不存在,或调用处理方法时发生错误,都会在隐含模型
中创建错误消息。其错误代码前缀说明如下:
– required:必要的参数不存在。如 @RequiredParam(“param1”)标注了一个入参,但是该参数不存在
– typeMismatch:在数据绑定时,发生数据类型不匹配的问题
– methodInvocation:Spring MVC 在调用处理方法时发生了错误

超链接切换 Locale

<!-- 配置国际化资源文件 -->
    <bean id="messageSource"
          class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basename" value="i18n"></property>
    </bean>

    <!--可以通过超链接切换 Locale, 而不再依赖于浏览器的语言设置情况
    配置 LocalResolver 和 LocaleChangeInterceptor-->
    <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver" >
    </bean>

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

9.关于 mvc:annotation-driven

  1. <mvc:annotation-driven /> 会自动注册RequestMappingHandlerMapping、RequestMappingHandlerAdapter 与ExceptionHandlerExceptionResolver 三个bean。
  2. 还将提供以下支持:
    支持使用 ConversionService 实例对表单参数进行类型转换
    支持使用 @NumberFormat annotation、@DateTimeFormat注解完成数据类型的格式化
    支持使用 @Valid 注解对 JavaBean 实例进行 JSR 303 验证
    支持使用 @RequestBody 和 @ResponseBody 注解

10.异常处理

ExceptionHandlerExceptionResolver

  • 主要处理 Handler 中用 @ExceptionHandler 注解定义的方法。
  • @ExceptionHandler 注解定义的方法优先级问题:例如发生的是NullPointerException,但是声明的异常有
    RuntimeException 和 Exception,此候会根据异常的最近继承关系找到继承深度最浅的那个 @ExceptionHandler
    注解方法,即标记了 RuntimeException 的方法
  • ExceptionHandlerMethodResolver 内部若找不到@ExceptionHandler 注解的话,会找@ControllerAdvice 中的@ExceptionHandler 注解方法

ResponseStatusExceptionResolver
• 在异常及异常父类中找到 @ResponseStatus 注解,然后使用这个注解的属性进行处理。
• 定义一个 @ResponseStatus 注解修饰的异常类:

@ResponseStatus(HttpStatus.UNAUTHORIZED)
public class UnauthorizedException extend RuntimeException{}

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

DefaultHandlerExceptionResolver
• 对一些特殊的异常进行处理,比如
NoSuchRequestHandlingMethodException、HttpRequestMethodNotSupportedException、
HttpMediaTypeNotSupportedException、HttpMediaTypeNotAcceptableException等,
请参考 DefaultHandlerExceptionResolver.doResolveException()源码。

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

<!-- 配置使用 SimpleMappingExceptionResolver 来映射异常 -->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <!-- 页面显示异常信息 ${exceptionAttribute.value} 默认为${exception} -->
        <!--<property name="exceptionAttribute" value="ex"></property>-->
        <property name="exceptionMappings">
            <props>
                <prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
            </props>
        </property>
    </bean>

11.SpringMVC工作流程

这里写图片描述
这里写图片描述

Spring工作流程

  1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获;
  2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;
    HandlerExecutionChain mappedHandler = null;
    mappedHandler = getHandler(processedRequest);
  3. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(…)方法)
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

  4. 执行拦截器 applyPreHandle 方法
    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    return;
    }

  5. 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller) ,并返回一个ModelAndView对象。

    // Actually invoke the handler.
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

    在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
    • HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
    • 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
    • 数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
    • 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
  6. 执行拦截器 applyPostHandle方法
    mappedHandler.applyPostHandle(processedRequest, response, mv);
  7. 根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet , ViewResolver 结合Model和View,来渲染视图
  8. 执行拦截器triggerAfterCompletion方法
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

render(mv, request, response);

if (mappedHandler != null) {
    mappedHandler.triggerAfterCompletion(request, response, null);
}

最后将渲染结果返回给客户端。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值