Бои SpringBoot: элегантное использование параметров перечисления

Spring Boot задняя часть
Бои SpringBoot: элегантное использование параметров перечисления

«Это 25-й день моего участия в ноябрьском испытании обновлений. Ознакомьтесь с подробностями события:Вызов последнего обновления 2021 г."

Эта статья была«Реальный бой весеннего ботинка»Коллекция столбцов.

Привет, я смотрю на гору.

В процессе разработки интерфейса неизбежно появляются параметры, представляющие типы, такие как 0 для неизвестного, 1 для мужчины и 2 для женщины. Обычно есть два способа сделать это: один представлен числами, а другой реализуется с помощью перечислений.

Использование цифрового представления заключается в согласовании значения каждого цифрового представления в форме контракта.Когда интерфейс получает параметры, он оценивает тип в соответствии с соглашением, а стоимость обслуживания интерфейса относительно высока.

В системе Spring использование представления перечисления заключается в использовании механизма преобразования Spring, который может сопоставлять числа или строки с серийным номером или именем перечисления, а затем преобразовывать входные данные внешнего интерфейса в тип перечисления.

В сценариях, где сцена несложная, перечисление может легко выполнить эту работу.

Итак, быстро внедряйте логику и готовьтесь к тестированию. В настоящее время требования изменились. Нельзя выбрать неизвестный пол. Можно выбрать только мужчину или женщину, и нет значения 0. Таким образом, поскольку значение начинается с 1, а порядковый номер перечисления начинается с 0, возникнет конфликт.

Есть также некоторые не слишком много сценариев, то есть внешний интерфейс не ожидает, что типы будут числами, и может ожидать, что они будут представлены некоторыми значимыми строками. Однако, согласно спецификации внешнего интерфейса, его имя должно быть написано в нижнем или верблюжьем регистре. Но во внутренней спецификации перечисления должны быть написаны с заглавной буквы, что является конфликтом.

Независимо от того, разумен спрос или нет, мы должны сохранять дух исследования технологий.

Подтвердить потребности

Сначала подтвердите потребности. Ждем определения класса перечисления в качестве параметра.При обращении к интерфейсу это может быть идентификатор типа int.Значение идентификатора не ограничено количеством перечислений или тип String,код,значение кода не ограничено. к перечисляемому Имени. Другими словами, это перечисление имеет идентификатор и код, определяемые свободно, пока передается интерфейс, он может быть автоматически преобразован в тип перечисления.

В таком случае давайте стандартизируем значения id и code. Для расширения определите три интерфейса: IdBaseEnum, CodeBaseEnum и IdCodeBaseEnum.

public interface IdBaseEnum {
    Integer getId();
}

public interface CodeBaseEnum {
    String getCode();
}

public interface IdCodeBaseEnum extends IdBaseEnum, CodeBaseEnum {
}

Теперь пришло время определить нашего главного героя.

определить перечисление

Впереди определены три интерфейса: отдельный идентификатор, отдельный код и один с идентификатором и кодом. Таким образом, мы можем определить три перечисления, соответствующие трем интерфейсам. Все три метода похожи, поэтому в тексте они не повторяются. Если вам интересно, вы можете обратить внимание на паблик «Дом в горах» и ответить на него, чтобы получить исходный код.

Мы определяем гендерное перечисление с двумя свойствами: id и code.

public enum GenderIdCodeEnum implements IdCodeBaseEnum {
    MALE(1, "male"),
    FEMALE(2, "female");

    private final Integer id;
    private final String code;

    GenderIdCodeEnum(Integer id, String code) {
        this.id = id;
        this.code = code;
    }

    @Override
    public String getCode() {
        return code;
    }

    @Override
    public Integer getId() {
        return id;
    }
}

Следует отметить, что идентификатор и код не могут повторяться.

  1. id и id, code и code не могут повторяться. Например, MAIL определяет id как 1, а FAMLE не может определять id как 1.
  2. Идентификатор и код не могут повторяться. Например, MALE определяет идентификатор как 1001, а FEMALE определяет код как 1001.

Это связано с тем, что Spring обрабатывает все входные параметры как типы String при преобразовании параметров. Хотя мы определяем разные типы идентификатора и кода, при сопоставлении все они сопоставляются в соответствии со строками. Если одно и то же значение существует, возникает неоднозначность.

Преобразователи и ConverterFactory

Далее согласно спецификации определим Converter и ConverterFactory. Это порты расширения, которые оставляет нам Spring, и их можно определить в соответствии со спецификацией.

Класс преобразователя:

public class IdCodeToEnumConverter<T extends IdCodeBaseEnum> implements Converter<String, T> {
    private final Map<String, T> idEnumMap = Maps.newHashMap();
    private final Map<String, T> codeEnumMap = Maps.newHashMap();

    public IdCodeToEnumConverter(Class<T> enumType) {
        Arrays.stream(enumType.getEnumConstants())
                .forEach(x -> {
                    idEnumMap.put(x.getId().toString(), x);
                    codeEnumMap.put(x.getCode(), x);
                });
    }

    @Override
    public T convert(String source) {
        return Optional.of(source)
                .map(codeEnumMap::get)
                .orElseGet(() -> Optional.of(source)
                        .map(idEnumMap::get)
                        .orElseThrow(() -> new CodeBaseException(ErrorResponseEnum.PARAMS_ENUM_NOT_MATCH)));
    }
}

Класс ConverterFactory:

public class IdCodeToEnumConverterFactory implements ConverterFactory<String, IdCodeBaseEnum> {
    @SuppressWarnings("rawtypes")
    private static final Map<Class, Converter> CONVERTERS = Maps.newHashMap();

    @Override
    public <T extends IdCodeBaseEnum> Converter<String, T> getConverter(Class<T> targetType) {
        //noinspection unchecked
        Converter<String, T> converter = CONVERTERS.get(targetType);
        if (converter == null) {
            converter = new IdCodeToEnumConverter<>(targetType);
            CONVERTERS.put(targetType, converter);
        }
        return converter;
    }
}

Эти два являются ядром преобразования.Мы можем реализовать автоматическое преобразование типов перечисления, собрав их в преобразователь типов Spring.

загрузить конфигурацию

Зарегистрируйте наши определенные Converter и ConverterFactory с помощью преобразователя типов Spring.

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverterFactory(new IdCodeToEnumConverterFactory());
        registry.addConverterFactory(new CodeToEnumConverterFactory());
        registry.addConverterFactory(new IdToEnumConverterFactory());
    }
}

На этом основные определения закончены.

контрольная работа

Напишите Controller в качестве тестовой записи:

@RestController
@RequestMapping("echo")
public class EchoController {
    @GetMapping("gender-id-code")
    public String genderIdCode(@RequestParam("gender") GenderIdCodeEnum gender) {
        return gender.name();
    }
}

Подготовьте тестовый пример для тестирования:

@SpringBootTest(classes = SpringEnumParamApplication.class)
@AutoConfigureMockMvc
class EchoControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @ParameterizedTest
    @ValueSource(strings = {"MALE", "male", "1"})
    void genderIdCode(String gender) throws Exception {
        final String result = mockMvc.perform(
                MockMvcRequestBuilders.get("/echo/gender-id-code")
                        .param("gender", gender)
        )
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print())
                .andReturn()
                .getResponse()
                .getContentAsString();

        Assertions.assertEquals("MALE", result);
    }
}

Вывод в конце статьи

Реализовать параметры перечисления несложно, если оно реализовано в соответствии со спецификацией расширения Spring. Важно обратить внимание на уникальный идентификатор и код в классе enum.

Эта статья приложения, в следующей статье будет говорить о принципе. И логика преобразования enum для запросов в виде http body. Ответьте на «весну» на официальном аккаунте «Глядя на хижину горы», чтобы получить исходный код. Три формы перечисления полностью определены в исходном коде.

Рекомендуемое чтение


Привет, я смотрю на гору. Плавайте в мире кода, играйте и наслаждайтесь жизнью. Если статья была вам полезна, ставьте лайк, добавляйте в закладки и подписывайтесь. Приглашаем обратить внимание на паблик-аккаунт «Глядя на горную хижину» и открыть для себя другой мир.