AfterFilter/BefterFilter
BeforeFilter 序列化时在最前添加内容,AfterFilter 序列化时在最后添加内容。BeforeFilter和AfterFilter的用法类似,这里就不单独举例了,该用例中,我们主要处理的是在实际开发中常遇到的将枚举值转换为中文返回前端,当然这里不是直接转换,而是增加一个返回字段专门存放中文字段值。
具体如下
实体类:
package com.jy.demo.model;
import com.jy.demo.ann.TextDisplay;
import com.jy.demo.provider.AreaValueProvider;
import java.math.BigDecimal;
public class Apple{
private Integer id;
private String name;
private BigDecimal money;
private Integer num;
@TextDisplay(AreaValueProvider.class)
private String area;//产地
public Apple(Integer id, String name, BigDecimal money, Integer num) {
this.id = id;
this.name = name;
this.money = money;
this.num = num;
}
public Apple(Integer id, String name, BigDecimal money, Integer num, String area) {
this.id = id;
this.name = name;
this.money = money;
this.num = num;
this.area = area;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public BigDecimal getMoney() {
return money;
}
public void setMoney(BigDecimal money) {
this.money = money;
}
public Integer getNum() {
return num;
}
public void setNum(Integer num) {
this.num = num;
}
public String getArea() {
return area;
}
public void setArea(String area) {
this.area = area;
}
@Override
public String toString() {
return "Apple{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
", num=" + num +
", area='" + area + '\'' +
'}';
}
}
这里产地就是需要我们转换的字段。
编写对应的枚举类:
package com.jy.demo.areaEnum;
/**
* @Date 2022/3/8 17:29
* @Version 1.0
*/
public enum Area {
CD("028", "成都"),
BJ("010", "北京");
private String name;
private String code;
Area(String code, String name) {
this.code = code;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
/**
* 根据code获取城市名称
* @param code
* @return
*/
public static String getNameByCode(String code){
for (Area area:Area.values()
) {
if (area.code.equals(code))
return area.name;
}
return null;
}
}
在枚举类中添加了一个通过code获取name的静态方法,这个是后续需要用到的。
同时在实体类的产地字段上,我们可以看到这里我们添加了一个自定义的注解,这里的目的就是为了,我们在序列化的时候能识别出我们专门需要处理的字段,同时标识出具体处理的转换类。
package com.jy.demo.ann;
import com.jy.demo.provider.ValueProvider;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* @Date 2022/3/8 17:37
* 自定义注解类,作用于实体类字段上
* 在运行时生效
*/
@Target({FIELD})
@Retention(RUNTIME)
@Documented
public @interface TextDisplay {
/**
* 转换的provider,用于中文转换
*/
Class<? extends ValueProvider> value();
}
package com.jy.demo.provider;
/**
* @Date 2022/3/8 17:40
* @Version 1.0
*/
public interface ValueProvider {
/**
*
* @param val 对应的就是该字段的值
* @return
*/
String getDisplayText(Object val);
}
package com.jy.demo.provider;
import com.jy.demo.areaEnum.Area;
/**
* @Date 2022/3/8 17:46
* @Version 1.0
*/
public class AreaValueProvider implements ValueProvider{
@Override
public String getDisplayText(Object val) {
/**
* 根据值返回枚举类中的中文名称
*/
return Area.getNameByCode((String)val);
}
}
以上都是前期准备,真正处理的代码如下:
package com.jy.demo.SerializeFilter;
import com.alibaba.fastjson.serializer.AfterFilter;
import com.jy.demo.ann.TextDisplay;
import com.jy.demo.provider.ValueProvider;
import org.apache.commons.lang3.StringUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Arrays;
/**
* @Date 2022/3/8 17:20
* BeforeFilter 序列化时在最前添加内容
* AfterFilter 序列化时在最后添加内容
*/
public class JyAfterFilter extends AfterFilter{
/**
* 表示这个包下面的类才有效
*/
private static final String NEED_SCAN_PACKAGE = "com.jy.demo.model";
private static final String DISPLAY_SUFFIX = "Text";
@Override
public void writeAfter(Object object) {
/**
* BeforeFilter和AfterFilter的用法类似,这里就不单独举例了
* 该用例中,我们主要处理的是在实际开发中常遇到的将枚举值转换为中文返回前端
* 当然这里不是直接转换,而是增加一个返回字段专门存放中文字段值
*/
String packageName = object.getClass().getPackageName();//该方法是获取包名,可以利用该方法的结果来缩小范围
if (!packageName.startsWith(NEED_SCAN_PACKAGE)) {
return;
}
//获取所有的字段
Field[] fields = object.getClass().getDeclaredFields();
System.out.println(Arrays.toString(fields));
//遍历字段
try {
for (Field f : fields
) {
//获取字段上的自定义注解
Annotation annotation = f.getAnnotation(TextDisplay.class);
if (annotation == null) {
continue;
}
//如果不为空,则说明该字段上添加了TextDisplay注解,说明需要进行转换
Class<? extends ValueProvider> providerClass = ((TextDisplay) annotation).value();
//获取转换对象
//这里因为是个人demo所以就试用的是反射机制创建的对象,在接入spring环境后最好使用spring相应的功能获取对象比如,
// 实现接口ApplicationContextAware 注入ApplicationContext,利用getBean方法获取对象
//1是因为反射浪费性能2是因为反射破坏了对象的单例模式
ValueProvider valueProvider = providerClass.newInstance();
System.out.println(valueProvider);
f.setAccessible(true);
String o = (String) f.get(object);
String displayText = valueProvider.getDisplayText(o);
if (StringUtils.isNoneBlank(displayText)) {
//构造一个新的key value
super.writeKeyValue(f.getName() + DISPLAY_SUFFIX, displayText);
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
测试类:
package com.jy.demo.test;
import com.alibaba.fastjson.JSON;
import com.jy.demo.SerializeFilter.JyAfterFilter;
import com.jy.demo.model.Apple;
import java.math.BigDecimal;
/**
* @Date 2022/3/9 14:20
* @Version 1.0
*/
public class Demo8 {
public static void main(String[] args) {
JyAfterFilter jyAfterFilter = new JyAfterFilter();
Apple apple = new Apple(1,"lili",new BigDecimal("11"),1,"028");
String jsonString = JSON.toJSONString(apple, jyAfterFilter);
System.out.println(jsonString);
}
}
运行结果:
从运行结果可以看出,这里增加了一个原本没有的字段及对应的中文值,这就是我们在序列化时后置处理器处理的结果。当然这里只是demo所以是这样写的,在实际项目中,我们的查询返回前端结果都是需要JSON格式的,所以我们只需把前面的写好,在查询方法上加@ResponseBody注解,或@Restcontroller就行了。
以上是个人对这个处理器的一些简单用例,欢迎大家一起讨论!!!