spring mvc的数据转换和格式化

前面介绍了spring mvc的各个组件,spring mvc通过注解便可以让控制器得到丰富的参数类型,那么它是如何做到的呢,其实它是spring mvc的消息转换机制完成的。

       处理器在http请求到达控制器之前能够对http的各类消息进行处理。首先当一个请求到达DispatcherServlet的时候,需要找到对应的HandlerMapping,然后根据HandlerMapping去找到对应的HandlerAdapter执行处理器。处理器在要调用的控制器之前,需要先获取http发送过来的信息,然后将其转变为控制器的各种不同类型的参数,这就是各类注解能够得到丰富类型参数的原因。它首先用http的消息转换器(HttpMessageConverter)对消息转换,但这是一个比较原始的转换,它是String类型和文件类型比较简易的转换,它还需要进一步转换才能转换为POJO或者其它丰富的参数类型。为了拥有这样的能力,Spring 4提供了转换器和格式化器,这样通过注解的信息和参数的类型,它就能够把http发送过来的各种消息转换成为控制器所需要的各类参数了。

       当处理器完成了这些参数的转换,它就会进行验证(数据校验),下一步就是调用开发者提供的控制器了,将之前转换成功的参数传递进去,进而完成控制器的逻辑,返回结果后,处理器如果可以找到对应处理结果类型的HttpMessageConverter的实现类,它就会调用对应的HttpMessageConverter的实现方法对控制器返回的结果进行http转换,这一步不是必须的,可以转换的前提是能够找到对应的转换器。

        接下来就是关于视图解析和视图解析器的流程了。有时候要自定义一些特殊的转换规则,比如和第三方合作,第三方可能提供的并不是一个良好的json格式,而是一些特殊的规则,这时候就需要使用自定义的消息转换规则,把消息转为对应的java类型,从而简化开发。

对于spring mvc,在xml配置了<mvc:annotation-driven>,或者java配置的注解上加入@EnableEebMvc的时候,spring IoC容器会自定义生成一个关于转换器和格式化器的类实例-----FormattingConversionServiceFactoryBean,这样就可以从spring IoC容器中获取这个对象了,它是一个工厂,通过它可以获得DefaultFormattingConversionService类对象,它实现了转换器与格式化器的注册机(即ConverterRegistry与FormatterRegistry),我们可以通过它注册转换器与格式化器,SpringMvc默认已经注册了一些常用的转换器与处理器。

一对一转换器(Converter)


      Converter是一对一的转换器,先看看Converter的源码:

import org.springframework.lang.Nullable;  
/** 
 * 转换接口 
 * @param <S>源类型 
 * @param <T>目标类型 
 */  
@FunctionalInterface  
public interface Converter<S, T> {  
    @Nullable  
    T convert(S source);  
}  

        spring mvc所提供的功能,能够满足一般的要求,但是有时候我们需要自定义实现转换器,此时只需要实现Converter接口,然后注册给转换服务类(FormattingConversionServiceFactoryBean类,实际是注册到DefaultFormattingConversionService类中)。

         jsp页面提交的privileges类型为String[]

<%@ page language="java" contentType="text/html; charset=UTF-8"  
    pageEncoding="UTF-8"%>  
<!DOCTYPE html>  
<html>  
<head>  
<meta charset="UTF-8">  
<title>Insert title here</title>  
</head>  
<body>  
    <form action="${pageContext.request.contextPath }/control/role/save" method="post">  
        <label>角色名称:</label><input type="text" name="name" required="required"/><br/>  
        <input type="checkbox" name="privileges" value="departmentsave"/>部门添加  
        <input type="checkbox" name="privileges" value="departmentremove"/>部门删除  
        <input type="checkbox" name="privileges" value="departmentedit"/>部门编辑  
        input type="checkbox" name="privileges" value="departmentlist"/>部门查看  
        <br/>  
        <input type="checkbox" name="privileges" value="rolesave"/>角色添加  
        <input type="checkbox" name="privileges" value="roleremove"/>角色删除  
        <input type="checkbox" name="privileges" value="roleedit"/>角色编辑  
        <input type="checkbox" name="privileges" value="rolelist"/>角色查看  
        <br/>  
        <input type="submit"/>  
    </form>  
</body>  
</html>  

    相关 POJO类:

package edu.uestc.avatar.pojo;  
  
import java.util.HashSet;  
import java.util.Set;  
  
public class Role {  
    private Integer id;  
    private String name;  
        //角色所拥有的权限  
    private Set<Privilege> privileges = new HashSet<Privilege>();  
    //***********************setter and getter **************//  
}  
  
package com.wise.tiger.pojo;  
  
public class Privilege {  
    private Integer id;  
    private String name;  
      
    public Privilege() {}  
      
    public Privilege(String name) {  
        this.name = name;  
    }  
    //***********************setter and getter **************//  
}  

    Controller:

package edu.uestc.avatar.web.controller;  
  
import org.springframework.stereotype.Controller;  
import org.springframework.web.bind.annotation.RequestMapping;  
  
import com.wise.tiger.pojo.Role;  
  
@Controller  
@RequestMapping("control/role")  
public class RoleManageController {  
    @RequestMapping("/save")  
    public String saveRole(Role role) {  
        role.getPrivileges().forEach(pri->System.out.println(pri.getName()));  
        return "role_list";  
    }  
      
    @RequestMapping("/saveUI")  
    public String saveUI() {  
        return "role_add";  
    }  
}  

自定义一对一类型转换器

package edu.uestc.avatar.converter;  
//*****************import****************//  
/** 
 * @Description:将http请求中的字符串数组转为pojo属性的Set<Privilege>  
 * @author: <a href="mailto:1020zhaodan@163.com">Adan</a>  
 * @date: 2019年5月31日  上午11:29:25 
 * @version:1.0-snapshot 
 */  
public class StringArray2SetRoleConverter  implements Converter<String[], Set<Privilege>>{  
    @Override  
    public Set<Privilege> convert(String[] source) {  
        if(source == null) return null;  
        var ret = new HashSet<Privilege>();  
        for(var privilegeName : source) {  
            ret.add(new Privilege(privilegeName));  
        }  
        return ret;  
    }  
}  

      注册转换器:在xml配置了<mvc:annotation-driven>,或者java配置的注解上加入@EnableEebMvc的时候,spring IoC容器会自定义生成一个关于转换器和格式化器的类实例-----FormattingConversionServiceFactoryBean,通过它可以生成一个ConversionService接口,实际为DefaultFormattingConversionService对象。

  • xml方式
    <!--首先在mvc:annotation-driven元素上指定转换服务类,然后通过配置其属性加载对应的转换器 -->  
    <mvc:annotation-driven conversion-service="conversionService"/>  
    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">  
        <property name="converters">  
           <set>  
              <bean class="com.wise.tiger.web.converter.StringArray2SetRoleConverter"/>  
           </set>  
        </property>  
    </bean> 
  •  java配置
@Configuration  
@ComponentScan(basePackages = "com.wise.tiger.web")  
@EnableWebMvc  
public class WebConfig implements WebMvcConfigurer {  
    @Override  
    public void addFormatters(FormatterRegistry registry) {  
        registry.addConverter(new StringArray2SetRoleConverter());  
    }  
      
} 

数组和集合转换器GenericConverter


      上面的转换器是一种一对一的转换,它只能从一种类型转换成另一种类型,不能进行一对多转换,为了克服这个问题,Spring core还加入了另外一个转换器GenericConverter。

使用格式化器


      有些数据需要格式化,比如日期、金额等,为了支持这些场景,Spring Context提供了相关的Formatter。它需要实现一个接口Formatter,而Formatter又扩展了两个接口Printer和Parser

       通过print方法能将结果按照一定的格式输出字符串,通过parse方法能够将满足一定格式的字符串转换为对象,它的内部实际是委托给Converter机制去实现的,需要自定义的场景不多(了解用法即可),这里介绍两个注解

  • @DateTimeFormat:进行日期格式的转换
  • @NumberFormat:进行数字的格式转换
@Controller  
@RequestMapping("/convert")  
public class ConvertController{  
    @RequestMapping("/format")  
    public String format(@DateTimeFormat(ios=ISO.DATE)Date date,  
                         @NumberFormat(pattern="#,###.##")Double amount){  
        ..........  
    }  
} 

参数可以是一个POJO,而不单单是一个日期或者数字,只是要给POJO加入对应注解:

public class FormatPojo{  
    @DateTimeFormat(iso = ISO.DATE)  
    private LocalDate date1;  
    @NumberFormat(pattern = "##,###.00")  
    private BigDecimal amount;  
}     
@RequestMapping("/format")  
public String format(FormatPojo bean){        
    ..........     
}  

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值