前言:
现在同学们对“java中文转码”大体比较珍视,姐妹们都需要剖析一些“java中文转码”的相关知识。那么小编同时在网上汇集了一些对于“java中文转码””的相关知识,希望兄弟们能喜欢,我们快快来学习一下吧!这一章,我们来说说jackson提供的自定义注解及一些应用吧。
废话不多说,撸起来。
1、自定义注解
在Jackson中使用 @JacksonAnnotationsInside来标注当前定义的注解为jackson注解。我们通过一个简单例子来看下。
1.1 自定义注解
java复制代码/** * @author: jiangjs * @description: * @date: 2023/6/15 10:07 **/@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@JacksonAnnotationsInside@JsonInclude(JsonInclude.Include.NON_NULL)@JsonPropertyOrder({"id","nickName","password","name"})public @interface DataOrderAndFilter {}
上述注解实现了序列化时排列的顺序,以及不显示数值为null的字段。
1.2 创建实体
java复制代码/** * @author: jiangjs * @description: * @date: 2023/6/15 10:11 **/@Data@AllArgsConstructor@DataOrderAndFilterpublic class CustomDataEnter { private Integer id; private String name; private String nickName; private String password;}1.3 测试
java复制代码@Testpublic void useJacksonAnnotationsInside() throws JsonProcessingException { CustomDataEnter dataEnter = new CustomDataEnter(1, "zhangsan", null, "123456"); String json = new ObjectMapper().writeValueAsString(dataEnter); log.info("使用@JacksonAnnotationsInside实现自定义注解序列化json:" + json);}
输出:
上述代码通过简单的例子说明了@JacksonAnnotationsInside可以自定义注解。下面我们来看看在我们日常工作中在哪些地方可以使用。
2、自定义注解应用2.1 实现数据脱敏
结合@JsonSerialize在数据进行序列化时,进行数据的脱敏。
需求:用户信息在返回到前端时,对用户名,身份证号,手机号等进行数据脱敏。
用户名:如果两个字时,只保留姓,后面为*,例如:张三,脱敏后:张*,超过三个字时,则保留前后两个字,中间使用*,例如:张小四,脱敏后:张*四身份证号:前后各保留四位,中间用四个连接,例如:450218199103458901,脱敏后:4501***8901手机号:保留前三位和后四位,中间四位用连接,例如:13456789012,脱敏后:134***9012
根据上述需求,我们先建一个枚举,实现不同类型数据脱敏,也方便后期实现其他字段脱敏时,只要在这个枚举类中加入就行。
2.1.1 创建脱敏枚举
java复制代码/** * @author: jiangjs * @description: 脱敏策略 * @date: 2022/4/15 16:23 **/public enum DesensitizedStrategy { /** * 用户信息脱敏 */ USER_NAME(s -> s.replaceAll("(\S)\S(\S*)", "$1*$2")), /** * 身份证信息脱敏 */ ID_CARD(s -> s.replaceAll("(\d{4})\d{10}(\w{4})", "$1****$2")), /** * 手机号脱敏 */ PHONE(s -> s.replaceAll("(\d{3})\d{4}(\d{4})", "$1****$2")); private final Desensitized desensitized; DesensitizedStrategy(Desensitized desensitized){ this.desensitized = desensitized; } public Desensitized getDesensitize() { return desensitized; }}
定义的脱敏字段中采用了Function函数来实现。
java复制代码/** * @author: jiangjs * @description: 脱敏接口 * @date: 2022/4/15 16:22 **/public interface Desensitized extends Function<String,String> {}2.1.2 创建注解
java复制代码/** * @author: jiangjs * @description: 使用jackson进行数据脱敏 * @date: 2023/6/1 15:50 **/@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)@JacksonAnnotationsInside@JsonSerialize(using = JacksonDataDesensitized.class)public @interface JsonSensitive { DesensitizedStrategy strategy();}
@JsonSerialize:实现数据的序列化,using则是实现序列化的具体类
2.1.3 创建序列化类
java复制代码/** * @author: jiangjs * @description: 通过jackson数据序列化来实现脱敏 * @date: 2023/6/1 15:54 **/@NoArgsConstructor@AllArgsConstructorpublic class JacksonDataDesensitized extends JsonSerializer<String> implements ContextualSerializer { /** * 脱敏数据 */ private DesensitizedStrategy strategy; @Override public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeString(strategy.getDesensitize().apply(value)); } @Override public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException { if (Objects.isNull(property)){ return prov.findNullValueSerializer(null); } //校验当前bean是否为String if (Objects.equals(property.getType().getRawClass(),String.class)){ JsonSensitive sensitive = property.getAnnotation(JsonSensitive.class); if (Objects.isNull(sensitive)){ sensitive = property.getContextAnnotation(JsonSensitive.class); } if (Objects.nonNull(sensitive)){ return new JacksonDataDesensitized(sensitive.strategy()); } } return prov.findValueSerializer(property.getType(), property); }}
创建的序列化类继承了JsonSerializer类,指定了数据的类型,实现了ContextualSerializer上下文序列化来保证JsonSerializer不为空。
JsonGenerator:用来生成Json格式的内容,可以使用JsonFactory来生成一个实例。
2.1.4 使用注解
java复制代码/** * @author: jiangjs * @description: * @date: 2022/4/15 11:33 **/@Data@Accessors(chain = true)@EqualsAndHashCodepublic class UserInfo implements Serializable{ /** * 主键 */ private Integer id; /** * 用户名 */ private String userName; /** * 昵称 */ @JsonSensitive(strategy = DesensitizedStrategy.USER_NAME) private String nickName; /** * 手机号 */ @JsonSensitive(strategy = DesensitizedStrategy.PHONE) private String phone; /** * 身份证号 */ @JsonSensitive(strategy = DesensitizedStrategy.ID_CARD) private String idCard; /** * 创建时间 */ @JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss",timezone = "GTM+8") private Date createTime; private static final long serialVersionUID = 1L;}
在实体中通过注解来指定各字段脱敏的类型。
2.1.4 测试
java复制代码/** * @author: jiangjs * @description: * @date: 2023/6/15 11:31 **/@RestController@RequestMapping("/desensitized")public class DesensitizedController { @GetMapping("/getUserInfo.do") public UserInfo getUserInfo(){ UserInfo userInfo = new UserInfo(); userInfo.setId(1).setUserName("zhangsan").setNickName("张三") .setIdCard("450218199103458901") .setPhone("13456789012"); return userInfo; }}
输出:
从输出结果中,我们可以看到使用注解的字段已经实现数据脱敏。
2.2 通用枚举转换
需求:在实体中有时候会用到枚举,前端往往会传递一个值保存到数据,但是查询返回时往往又是对应的另外的值。因此做一个通用的枚举类型转换,查询数据时进行赋值。
2.2.1 创建注解
java复制代码/** * @author: jiangjs * @description: * @date: 2023/6/15 16:08 **/@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@JacksonAnnotationsInside@JsonSerialize(using = TypeChangeSerialize.class)public @interface TypeChange { //值得替换 导出是{a_id,b_id} 导入反过来,所以只用写一个 String[] replace() default {};}
replace():仿照Easypoi中@Excel注解中的replace。
2.2.1 创建序列化实现类
java复制代码/** * @author: jiangjs * @description: * @date: 2023/6/15 16:21 **/@AllArgsConstructorpublic class TypeChangeSerialize extends JsonSerializer<Object> implements ContextualSerializer { private final String[] annotationValues; @Override public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException { String[] types = this.annotationValues; Map<String, String> typeMap = new ConcurrentHashMap<>(); if (Objects.nonNull(types) && types.length > 0) { for (String type : types) { String[] s = type.split("_"); typeMap.put(s[0],s[1]); } } gen.writeString(typeMap.get(String.valueOf(value))); } @Override public JsonSerializer<?> createContextual(SerializerProvider provider, BeanProperty property) throws JsonMappingException { if (Objects.isNull(property)){ return provider.findNullValueSerializer(null); } //校验当前bean是否为String或Integer if (Objects.equals(property.getType().getRawClass(),String.class) || Objects.equals(property.getType().getRawClass(),Integer.class)){ TypeChange typeChange = property.getAnnotation(TypeChange.class); if (Objects.isNull(typeChange)){ typeChange = property.getContextAnnotation(TypeChange.class); } if (Objects.nonNull(typeChange)){ return new TypeChangeSerialize(typeChange.replace()); } } return provider.findValueSerializer(property.getType(), property); }}
annotationValues:定义接受注解replace的值。
new TypeChangeSerialize(typeChange.replace()):初始化序列化处理类,将获取到的replace()值赋值给annotationValues。
2.2.3 使用注解
java复制代码/** * @author: jiangjs * @description: * @date: 2022/4/15 11:33 **/@Data@Accessors(chain = true)@EqualsAndHashCodepublic class UserInfo implements Serializable{ /** * 主键 */ private Integer id; @TypeChange(replace = {"1_男","2_女"}) private Integer gender; private static final long serialVersionUID = 1L;}
@TypeChange(replace = {"1_男","2_女"}):按照注解的规则,赋值replace。
2.2.4 测试
java复制代码/** * @author: jiangjs * @description: * @date: 2023/6/15 11:31 **/@RestController@RequestMapping("/desensitized")public class DesensitizedController { @GetMapping("/getUserInfo.do") public UserInfo getUserInfo(){ UserInfo userInfo = new UserInfo(); userInfo.setId(1).setGender(1); return userInfo; }}
输出:
从输出结果来看,gender赋值为1,序列化后返回的是对应的中文:男。也就是说,这个实现了我们需求,即字段进行了替换。
上述就是我在工作中使用jackson的一些应用,大家可以举一反三来实现自己的需求,例如:自定义时间格式化等等。
源码:github.com/lovejiashn/…
工欲善其事,必先利其器,小伙伴们撸起来吧。
原文链接:
标签: #java中文转码