1. 程式人生 > >springBoot中自定義引數型別轉換

springBoot中自定義引數型別轉換

一、緣起

       由於工作中的專案需要與第三方進行聯調,在對方呼叫我方的介面中請求接受Content-Type 為application/x-www-form-urlencoded,但是針對該請求方式的springBoot中無法封裝複雜型別的引數 例如一個VO物件中含有1、Date型別或者2、List物件

本片博文針對其中的兩個問題進行解決。

二、解決方式

  1、構造VO物件

  Order物件

/**
 * author  xieqx
 * date   2018/9/7
 * 訂單資訊
 */
public class Order {

    /**
     * 訂單id
     */
    private Long orderId;

    /**
     * 訂單編號
     */
    private String orderNo;

    /**
     * 預定時間 預設情況下的日期型別也無法進行封裝 需要新增自定義的預定時間
     */
    private Date bookingTime;

    /**
     * 訂單詳情列表,controller封裝的order物件中如果沒有自定義的型別轉換,預設情況下無法正確的封裝
     */
    private List<OrderDetail> orderDetailList;


...省略seter getter方法

OrderDetail物件

/**
 * @author  xieqx
 * date   2018/9/7
 * 訂單詳情 
 * 使用了lombok框架 簡化了bean的建立
 */
@AllArgsConstructor
@Getter
@Setter
public class OrderDetail {

    private Long productId;

    private String productName;

    /**
     * 日期型別
     */
    private Date  buyTime;
}

     2、編寫自定義的型別轉換器

         2.1 String型別轉換為Date型別

          繼承Spring提供的org.springframework.core.convert.converter.Converter物件,重寫其中的convert()方法 其中是自己的轉換邏輯。

/**
 * author  xieqx
 * date   2018/9/4
 * 將String 轉換為Date集合
 */
public class StringToDateConverter implements Converter<String, Date> {
    @Nullable
    @Override
    public Date convert(String json) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        try {
            return simpleDateFormat.parse(json);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;

    }
}

2.2 String型別轉換為List集合型別

   與2.1轉換Date型別相似 這裡使用了jackson框架進行轉換

/**
 * author  xieqx
 * date   2018/9/4
 * 將String 轉換為list集合
 */
public class StringToListConverter  implements Converter<String, List<OrderDetail>> {

    @Override
    public List<OrderDetail> convert(String json) {
        List<OrderDetail> priceDetails = JsonUtil.str2List(json,OrderDetail.class);
        return  priceDetails;
    }

}

2.3 轉換類完成後,還需要將其交由Spring的容器進行處理,這裡提供了兩種方式 

   1、繼承WebMvcConfigurationSupport類並將該物件建立進行新增

@Configuration
public class ApplicationConfig extends WebMvcConfigurationSupport {
    /**
     * 新增靜態資原始檔
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/img").addResourceLocations("/img/");
        registry.addResourceHandler("/static/css").addResourceLocations("/css/");
        registry.addResourceHandler("/static/js").addResourceLocations("/js/");
        registry.addResourceHandler("/static/swf").addResourceLocations("/swf/");
        registry.addResourceHandler("/static/media").addResourceLocations("/media/");
    }

    /**
     * 新增自定義的Converters和Formatters.
     */
    @Override
    protected void addFormatters(FormatterRegistry registry) {
        //新增字串轉換list的自定義轉換器
        registry.addConverter(new StringToListConverter());
        //新增字串轉換Date的自定義轉換器
        registry.addConverter(new StringToDateConverter());
    }

}

  使用該方式會破壞SpringBoot預設載入靜態檔案的預設配置,需要重新進行新增. 切記

  2、第二種方式 

@Configuration
public class SpringDataConvert {

    @Autowired
    private RequestMappingHandlerAdapter requestMappingHandlerAdapter;

    /**
     * 增加字串轉換為List集合
     */
    @PostConstruct
    public void addConversionConfig() {
        ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) requestMappingHandlerAdapter.getWebBindingInitializer();
        if (initializer.getConversionService() != null) {
            GenericConversionService genericConversionService = (GenericConversionService)initializer.getConversionService();
            //新增字串轉換為list集合的轉換機器
            genericConversionService.addConverter(new StringToListConverter());
            //新增字串轉換為日期型別的字串
            genericConversionService.addConverter(new StringToDateConverter());

        }
    }
}

   2.4 編寫controller進行測試

@Controller
@RequestMapping("/api")
public class DateConvertController {
    private static final Logger logger = LoggerFactory.getLogger(DateConvertController.class);
    /**
     * 
     * @param order 訂單資訊
     * @return  請求方式為application/x-www-form-urlencoded
     */
    @ResponseBody
    @RequestMapping(value = "test",method = RequestMethod.POST,
consumes = "application/x-www-form-urlencoded",produces = "application/json")
    public Object checkInventoryForm(Order order){
        if(order==null){
            throw new RuntimeException("the hotelOrder is null");
        }
        return order;
    }
}

     

3、啟動測試

         3.1、不新增日期型別轉換器的post請求

      提示String無法轉換為Date型別

  3.2  不新增List型別轉換

  提示String無法轉換為List

    3.3、自定義的型別轉換器都註冊上

三、升級

   3.1、 如果我的Order在新增一個Date型別 checkOutTime 格式為yyyy-MM-dd HH:mm:ss(區別於bookingTime yyyy-MM-dd)

如果使用上面的日期型別轉換,需要則無法處理怎可以使用@DateFormat註解來針對每一個日期型別的進行定製化的配置

並取消自定義的日期型別的轉換器

/**
 * author  xieqx
 * date   2018/9/7
 * 訂單資訊
 */
public class Order {

    /**
     * 訂單id
     */
    private Long orderId;

    /**
     * 訂單編號
     */
    private String orderNo;

    /**
     * 預定時間 預設情況下的日期型別也無法進行封裝 需要新增自定義的預定時間
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    //@JsonFormat( timezone = "GMT+8",pattern = "yyyy-MM-dd")
    private Date bookingTime;

    /**
     * 離店時間
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date checkOutTime;

    /**
     * 訂單詳情列表,controller封裝的order物件中如果沒有自定義的型別轉換,預設情況下無法正確的封裝
     */
    private List<OrderDetail> orderDetailList;

  postman的請求結果

3.2、對於若干個相同集合的處理

   新增一個使用者列表List<User>需要重新構造一個類似於StringToListConverter   去轉換User list集合挺麻煩的,我們可以對於StringToListConverter<T>構造成範型,如下程式碼

/**
 * @author  xieqx
 * date   2018/9/4
 * 將String 轉換為list集合 範型的處理
 */
public class StringToListConverter<T>  implements Converter<String, List<T>> {

    @Override
    public List<T> convert(String json) {
        Type type  =  (Class < T > ) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        Class clazz = type.getClass();
        List<T> list = JsonUtil.str2List(json,clazz);
        return  list;
    }

}

需要解析Bean的集合形式只需繼承即可

#解析OrderDetail 集合物件
public class StringToOrderDetailListConverter extends StringToListConverter<OrderDetail> {

}


#解析User 集合物件
public class StringToUserListConverter extends StringToListConverter<User> {

}

在spring中進行註冊

@Configuration
public class SpringDataConvert {

    @Autowired
    private RequestMappingHandlerAdapter requestMappingHandlerAdapter;

    /**
     * 增加字串轉換為List集合
     */
    @PostConstruct
    public void addConversionConfig() {
        ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) requestMappingHandlerAdapter.getWebBindingInitializer();
        if (initializer.getConversionService() != null) {
            GenericConversionService genericConversionService = (GenericConversionService)initializer.getConversionService();
   
   //新增轉換OrderDetail 集合         
   genericConversionService.addConverter(new StringToOrderDetailListConverter());
   //新增轉換User 集合
   genericConversionService.addConverter(new StringToUserListConverter());            

   //新增字串轉換為日期型別的字串
   //genericConversionService.addConverter(new StringToDateConverter());

        }
    }
}

github  原始碼地址:https://github.com/liushangzaibeijing/TypeConvert.git