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;
    }
    }
  • 相关阅读:
    mysql 1449 : The user specified as a definer ('root'@'%') does not exist 解决方法
    java中使用正则表达式
    Timer与ScheduledThreadPoolExecutor的比较
    Java同步块
    java中的浅拷贝与深拷贝
    java的关闭钩子(Shutdown Hook)
    JVM系列三:JVM参数设置、分析
    java虚拟机参数设置
    UTF-8编码规则(转)
    过滤3个字节以上的utf-8字符
  • 原文地址:https://www.cnblogs.com/fswhq/p/9783959.html
Copyright © 2011-2022 走看看