“This is the second day of my participation in the First Challenge 2022, for more details: First Challenge 2022”.

The introduction

Hello, this is Anyin.

In our daily development work, we will certainly encounter similar status, type and other fields need to be returned to the front end in Chinese form. For example, in the database, gender is stored as man and woman, while in the front interface display requirements are displayed as male and female.

There are several ways to implement these requirements

  1. Escape in the business code or get method, that is, in the business code through judgment and then converted to the corresponding Chinese or in the returned entity class in the get method judgment return corresponding Chinese
  2. All the dictionary values are stored in the database, and the Chinese meaning is queried through the database Left Join. When returned, a Chinese field is added
  3. Serialization transforms when Spring MVC returns, but the corresponding annotation metadata information needs to be added to the returned entity class
  4. The front end pulls all dictionary types and their corresponding values and processes them during page rendering, exposing all dictionary data in the front end cache

Of the above four methods, the third method is more suitable because it handles all dictionary values in a uniform manner, shields business code from impact, and provides some guarantee of security.

Train of thought

Before we implement the code, let’s go through some ideas.

  1. We do a little bit of work when Spring MVC serializes the entity class
  2. Return the corresponding dictionary information as an object with the same field name, for example:statusField, entity class is oneStringType that returns to the front end as an object:Status: {code: "enable", text: "enable"}
  3. Specify dictionary values of a certain type through custom annotations
  4. through@JsonSerializeThe annotation specifies a custom serializer

implementation

With that in mind, we can see a using attribute on the @jsonserialize annotation, which specifies a Class

So, we can define our own serializer that inherits from the JsonSerializer class.

@Slf4j
public class StringAsDictSerializer extends JsonSerializer<String>{

    public StringAsDictSerializer(a){}

    @SneakyThrows
    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider provider) throws IOException {}}Copy the code

The value argument to the serialize method is the code value we need to convert to a dictionary object. However, we still lack one other information. Is this code a dictionary of the type sex or status?

Therefore, the class also implements the ContextualSerializer interface, retrieving the corresponding annotation from the BeanProperty property.

The complete code for the StringAsDictSerializer class is as follows:

@Slf4j
public class StringAsDictSerializer extends JsonSerializer<String> implements ContextualSerializer {
    // Dictionary custom annotations for the current field
    private DictAnnotation annotation;

    public StringAsDictSerializer(DictAnnotation annotation) {
        this.annotation = annotation;
    }

    public StringAsDictSerializer(a){}

    @SneakyThrows
    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        if(annotation == null){
            log.error("dict annotation not found");
            return;
        }
        Class<? extends Enum> typeClazz = annotation.type();
        // Convert to the base enumeration class
        BaseEnum type = Arrays.stream(typeClazz.getEnumConstants()).map(t -> (BaseEnum) t)
                .filter(t -> Objects.equals(t.getCode(), value))
                .findAny().orElse(null);
        if(type == null){
            log.error("annotation type not found");
            return;
        }
        // Convert to object and return
        Dict dict = new Dict();
        dict.setCode(type.getCode());
        dict.setText(type.getText());
        gen.writeObject(dict);
    }

    @Override
    publicJsonSerializer<? > createContextual(SerializerProvider prov, BeanProperty property)throws JsonMappingException {
        // Get the annotation information for the current field
        DictAnnotation annotation = Optional.ofNullable(property).map(item -> item.getAnnotation(DictAnnotation.class)).orElse(null);
        return newStringAsDictSerializer(annotation); }}Copy the code

Then add a custom annotation

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface DictAnnotation {
    Class<? extends Enum> type();
}
Copy the code

The type field of this custom annotation represents the type of the dictionary. Normally, database dictionary fields will have a corresponding enumeration class in the code.

Finally, we define the dictionary objects we need to return to the front end

@Data
public class Dict {
    private String code;
    private String text;
}
Copy the code

test

Next, let’s test our code. In the entity class returned by controller, we add the corresponding annotation configuration as follows:

@Data
public static class TestDTO{
    @JsonSerialize(using = StringAsDictSerializer.class)
    @DictAnnotation(type = SexEnum.class)
    private String sex;

    @JsonSerialize(using = StringAsDictSerializer.class)
    @DictAnnotation(type = StatusEnum.class)
    private String status;
}
Copy the code

Use postman to return the result:

The last

Above, we implemented the front end dictionary echo for dictionary enumeration values, did you learn to waste?

Anyin Cloud