zoukankan      html  css  js  c++  java
  • springboot mybatis自定义枚举enum转换

    原文链接:https://blog.csdn.net/u014527058/article/details/62883573

    一、概述

    在利用Spring进行Web后台开发时,经常会遇到枚举类型的绑定问题。一般情况下,如果Spring接收到的参数值为字符串类型,Spring会根据枚举的值与传入的字符串进行对应。假设有如下枚举

    清单1:枚举定义

    public enum Gender {
    MALE, FEMALE;
    }

    那么,只要客户端在发送请求时,将参数的值设为MALE或FEMALE即可。请求类似如下形式:
    http://localhost:8080/handle/enum?gender=MALE

    但是,假如客户端传来的参数值不是枚举值对应的字符串,而是诸如整数值之类的值,Spring就没法做自动对应了。这种情况下该如何处理呢?

    二、枚举与接口定义

    好了,从现在开始,我们将使用如下枚举进行参数绑定。

    清单2:需要进行转换的枚举定义

    package org.fhp.springbootdemo.entity;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public enum Gender implements BaseEnum {
    MALE(1), FEMALE(2);
    
    private int value;
    private static Map<Integer, Gender> valueMap = new HashMap<>();
    
    static {
    for(Gender gender : Gender.values()) {
    valueMap.put(gender.value, gender);
    }
    }
    
    Gender(int value) {
    this.value = value;
    }
    
    @Override
    public int getValue() {
    return value;
    }
    
    public static Gender getByValue(int value) {
    Gender result = valueMap.get(value);
    if(result == null) {
    throw new IllegalArgumentException("No element matches " + value);
    }
    return result;
    }
    }

    在这里,我们令所有的枚举都实现BaseEnum接口,以便转换时使用。BaseEnum接口定义如下:
    清单3:枚举所需的实现接口

    package org.fhp.springbootdemo.entity;
    
    public interface BaseEnum {
    int getValue();
    }

    三、Converter接口

    好在Spring为我们提供了一个类型自动转换接口Converter<S, T>,可以实现从一个Object转为另一个Object的功能。除了Converter接口之外,实现ConverterFactory接口和GenericConverter接口也可以实现我们自己的类型转换逻辑。

    我们先来看一下Converter接口的定义:

    清单4:Converter接口定义

    public interface Converter<S, T> { 
    
    T convert(S source); 
    
    }

    我们可以看到这个接口是使用了泛型的,第一个类型表示原类型,第二个类型表示目标类型,然后里面定义了一个convert方法,将原类型对象作为参数传入进行转换之后返回目标类型对象。当我们需要建立自己的converter的时候就可以实现该接口。
    下面给出一个字符串转换为Gender枚举的converter实现。需要注意的是,在Spring MVC和Spring Boot中,由于从客户端接收到的请求都被视为String类型,所以只能用String转枚举的converter。

    清单5:String转Gender的Converter实现

    package org.fhp.springbootdemo.converter;
    
    
    import org.springframework.core.convert.converter.Converter;
    
    
    public class StringToGenderConverter implements Converter<String, Gender> {
    
        @Override
        public Gender convert(String source) {
            return Gender.getByValue(Integer.parseInt(source));
        }
    }

    四、ConverterFactory接口

    ConverterFactory的出现可以让我们统一管理一些相关联的Converter。顾名思义,ConverterFactory就是产生Converter的一个工厂,确实ConverterFactory就是用来产生Converter的。我们先来看一下ConverterFactory接口的定义:

    清单6:ConverterFactory的接口定义

    public interface ConverterFactory<S, R> { 
    
    <T extends R> Converter<S, T> getConverter(Class<T> targetType); 
    
    }

    我们可以看到ConverterFactory接口里面就定义了一个产生Converter的getConverter方法,参数是目标类型的class。我们可以看到ConverterFactory中一共用到了三个泛型,S、R、T,其中S表示原类型,R表示目标类型,T是类型R的一个子类。
    可以看出,ConverterFactory相比ConvertFactory的好处在于,ConverterFactory可以将原类型转换成一组实现了相同接口类型的对象,而Converter则只能转换成一种类型。这样做的坏处在于,假如我们又定义了其他枚举,那么对于每一个枚举,我们都需要实现一个对应的Converter,十分的不方便。而有了ConverterFactory之后,事情就变得简单了不少。现在可以定义一个String到所有实现了BaseEnum的枚举的ConverterFactory,然后根据目标类型生成对应的Converter来进行转换操作。如清单7所示。有了ConverterFactory,就可以取代清单5中的Converter了。

    清单7:ConverterFactory转换

    package org.fhp.springbootdemo.converter;
    
    import org.fhp.springbootdemo.entity.BaseEnum;
    import org.springframework.core.convert.converter.Converter;
    import org.springframework.core.convert.converter.ConverterFactory;
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.WeakHashMap;
    
    public class UniversalEnumConverterFactory implements ConverterFactory<String, BaseEnum> {
    
    private static final Map<Class, Converter> converterMap = new WeakHashMap<>();
    
    @Override
    public <T extends BaseEnum> Converter<String, T> getConverter(Class<T> targetType) {
    Converter result = converterMap.get(targetType);
    if(result == null) {
    result = new IntegerStrToEnum<T>(targetType);
    converterMap.put(targetType, result);
    }
    return result;
    }
    
    class IntegerStrToEnum<T extends BaseEnum> implements Converter<String, T> {
    private final Class<T> enumType;
    private Map<String, T> enumMap = new HashMap<>();
    
    public IntegerStrToEnum(Class<T> enumType) {
    this.enumType = enumType;
    T[] enums = enumType.getEnumConstants();
    for(T e : enums) {
    enumMap.put(e.getValue() + "", e);
    }
    }
    
    
    @Override
    public T convert(String source) {
    T result = enumMap.get(source);
    if(result == null) {
    throw new IllegalArgumentException("No element matches " + source);
    }
    return result;
    }
    }
    }

    五、集成至Spring Boot

    在Spring Boot中,可以通过覆盖addFormatter方法来实现对Converter和ConverterFactory的绑定。

    清单8:在配置中绑定ConverterFactory

    package org.fhp.springbootdemo;
    
    import org.fhp.springbootdemo.converter.UniversalEnumConverterFactory;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.format.FormatterRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    
    @Configuration
    public class MyWebAppConfigurer extends WebMvcConfigurerAdapter {
    
    @Override
    public void addFormatters(FormatterRegistry registry) {
    registry.addConverterFactory(new UniversalEnumConverterFactory());
    }
    }

    当然,也可以通过registry.addConverter()方法来绑定Converter。
    在Controller中,采用如下方式来进行接收,和平常接收参数是一样的用法。

    清单9:在Controller中的用法

    package org.fhp.springbootdemo.controller;
    
    import org.fhp.springbootdemo.entity.Gender;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.HashMap;
    import java.util.Map;
    
    @RestController
    public class HandleEnumController {
    
    @RequestMapping("/handle/enum")
    public Object handleEnum(@RequestParam("gender") Gender gender) {
    Map<String, Object> dataMap = new HashMap<>();
    dataMap.put("data", gender.name());
    return dataMap;
    }
    }
  • 相关阅读:
    Leetcode 811. Subdomain Visit Count
    Leetcode 70. Climbing Stairs
    Leetcode 509. Fibonacci Number
    Leetcode 771. Jewels and Stones
    Leetcode 217. Contains Duplicate
    MYSQL安装第三步报错
    .net 开发WEB程序
    JDK版本问题
    打开ECLIPSE 报failed to load the jni shared library
    ANSI_NULLS SQL语句
  • 原文地址:https://www.cnblogs.com/fswhq/p/9783959.html
Copyright © 2011-2022 走看看