Si vous utilisez l'ID qui est automatiquement numéroté dans la base de données comme pour l'ID affiché à l'écran, l'utilisateur devinera diverses choses. (Cela s'appelle le nombre d'utilisateurs)
Pour un champ aussi spécial, je pense qu'il est courant de préparer un objet de valeur dédié et d'écrire le processus de conversion d'identifiant en interne. Cependant, lorsque le type de demande ou de modèle de réponse ne peut pas être modifié en raison de circonstances complexes, j'ai cherché à savoir s'il pouvait être géré avec des annotations.
L'environnement de travail est Java9
,SpringBoot (2.0.0.RELEASE)
. (Je n'ai rien fait de spécial, donc je pense que les autres versions sont bien)
Les exigences pour ce temps sont les suivantes.
Sur la base des exigences ci-dessus, je voudrais faire les spécifications comme suit.
--Annotation est ʻObfusquer`
Cette classe est obscurcie. (Où quitter le serveur)
Héritez et implémentez StdSerializer
.
S'il est «nul», il se terminera tel quel. (Parce que NotNull etc. doit être exprimé par d'autres annotations)
ObfuscateSerializer.java
public class ObfuscateSerializer extends StdSerializer<Long> {
private static final long serialVersionUID = -6910413385029615313L;
protected ObfuscateSerializer() {
super(Long.class);
}
@Override
public void serialize(Long value, JsonGenerator gen, SerializerProvider provider) throws IOException {
//Logique d'obfuscation
if (value == null) {
return;
}
gen.writeNumber(value + 1);
}
}
C'est une classe qui simplifie. (Où entrer dans le serveur)
Comme le sérialiseur, il utilise StdDeserializer
.
ObfuscateDeserializer.java
public class ObfuscateDeserializer extends StdDeserializer<Long> {
private static final long serialVersionUID = 4303388430635458159L;
protected ObfuscateDeserializer() {
super(Long.class);
}
@Override
public Long deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
//Logique simplifiée
return Long.parseLong(p.getValueAsString()) - 1;
}
}
{
"timestamp": 1521424385168,
"status": 400,
"error": "Bad Request",
"message": "JSON parse error: For input string: \"hoge\"; nested exception is com.fasterxml.jackson.databind.JsonMappingException: For input string: \"hoge\" (through reference chain: com.example.Hoge[\"value\"])",
"path": "/api/sample/obfuscate"
}
Puisqu'il s'agit d'une annotation de marqueur, elle n'a aucune propriété. La cible est définie uniquement sur ʻElementType.FIELD` dans les spécifications.
Obfuscate.java
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD })
public @interface Obfuscate {
}
C'est une classe qui associe l'annotation définie au sérialiseur / désérialiseur.
Héritez et implémentez JacksonAnnotationIntrospector
.
Cette classe est appelée pour chaque élément lorsque Jackson dans Spring Boot convertit json en classe spécifiée et que la classe, le champ ou la méthode cible est annoté.
Cette fois, nous rendrons le sérialiseur et le désérialiseur uniques, donc nous remplacerons les paramètres findSerializer
et findDeserializer
.
MyAnnotationInterceptor.java
public class MyAnnotationInterceptor extends JacksonAnnotationIntrospector {
private static final long serialVersionUID = -7722925738908936096L;
@Override
public Object findSerializer(Annotated a) {
if (a.hasAnnotation(Obfuscate.class)) {
return ObfuscateSerializer.class;
}
return super.findSerializer(a);
}
@Override
public Object findDeserializer(Annotated a) {
if (a.hasAnnotation(Obfuscate.class)) {
return ObfuscateDeserializer.class;
}
return super.findDeserializer(a);
}
}
Enregistrez l'intercepteur d'annotations ci-dessus avec Spring Boot.
JacksonConfig.java
@Configuration
public class JacksonConfig {
@Bean
public Jackson2ObjectMapperBuilder jacksonBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.annotationIntrospector(new MyAnnotationInterceptor());
return builder;
}
}
Maintenant que vous êtes prêt, vous pouvez ajouter @ Obfuscate
aux champs du modèle de demande ou de réponse et ils seront convertis automatiquement.
ObfuscateRequest.java
@lombok.Value
public class ObfuscateRequest {
@Obfuscate
Long id;
}
Cette fois, j'ai défini une annotation pour obscurcir et simplifier le champ. Je pense qu'il y a des situations où il est utile s'il a déjà été publié et qu'il est difficile de changer de classe, ou si vous réutilisez le modèle et ne pouvez pas le changer. De plus, dans le cas des objets de valeur, il y a quelques inconvénients (bien que cela puisse être évité) tels que l'approfondissement de la hiérarchie lors de l'utilisation de json, donc j'ai pensé que c'était un bon choix.
https://qiita.com/nijuya_o/items/0f512792c4db27913c7a https://qiita.com/k_ui/items/b6e1763d023da96ea46f
Recommended Posts