FieldHandChain 重新定义对象字段处理方式

一、引言

因为经常需要对一个对象中的字段进行一些固定的处理处理,每次都要对每个字段get、set作相应的操作比较麻烦(主要是懒),所以我写了一个我利用反射技术,结合责任链模式+策略模式写了一个FieldHandChain 的工具类。目前这个工具类支持过滤字段中的表情符号、清除不可被修改的字段的值、替换字段中不可见的字符、替换字段中的特殊字符、给字段设置默认值、去除字符串字段的前后空格等功能,并且可以通过继承FieldHand 接口来扩展新的功能。

二、工具类说明

工具类的主体主要是FieldHand 接口FieldHandChain 类。

1、FieldHand 接口

FieldHand 是一个定义了处理字段操作的接口。

方法:

  • void hand(Field field, Object obj) throws IllegalAccessException:用于处理指定的字段和对象。
  • default Boolean isString(Field field):判断字段的类型是否为字符串类型。

代码如下:

import java.lang.reflect.Field;

/**
 * @author fhey
 * @date 2022-02-02 21:38:00
 * @description: TODO
 */
public interface FieldHand {
    void hand(Field field, Object obj) throws IllegalAccessException;

    default Boolean isString(Field field){
        return String.class.equals(field.getType());
    }
}

2、FieldHandChain

用于管理一系列的 FieldHand 实现类,并对给定对象的字段进行处理。

方法:

  • add(FieldHand hand):添加一个 FieldHand 实现类到处理链中。

  • hand(Object obj):对给定对象的所有声明字段,依次使用添加的 FieldHand 进行处理。

代码如下:

import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * @author fhey
 * @date 2022-02-02 21:41:13
 * @description: TODO
 */
@Slf4j
public class FieldHandChain {
    private List<FieldHand> hands = new ArrayList<>();

    public FieldHandChain add(FieldHand hand){
        hands.add(hand);
        return this;
    }

    public void hand(Object obj){
        for(Field field : obj.getClass().getDeclaredFields()){
            for (FieldHand hand : hands){
                try{
                    hand.hand(field, obj);
                } catch (IllegalAccessException e) {
                    log.error("FieldHandChain hand is error:{}", e);
                }
            }
        }
    }
}

使用案例:

void testClearUnmodifiable(){
      User user = new User("1","ming",20);
      FieldHandChain fieldHandChain = new FieldHandChain();
      fieldHandChain.add(new TrimString()).add(new ClearUnmodifiable());
      System.out.println(user);
}

执行结果:


三、实现的功能

首先我们先新建一个测试的对象

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    @Unmodifiable
    private String id;
    private String name;
    private Integer age;
}

1、ClearUnmodifiable

实现了 FieldHand 接口,用于清除被 @Unmodifiable 注解的字段的值。

@Unmodifiable 注解

public @interface Unmodifiable {}

实现代码如下:

import com.fhey.common.annotation.Unmodifiable;
import com.fhey.common.filedHand.base.FieldHand;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

/**
 * @author fhey
 * @date 2022-02-02 21:51:35
 * @description: TODO
 */
public class ClearUnmodifiable implements FieldHand {
    @Override
    public void hand(Field field, Object obj) throws IllegalAccessException {
        Annotation annotation = field.getAnnotation(Unmodifiable.class);
        if (null != annotation){
            field.set(obj, null);
        }
    }
}

使用案例:

public class ClearUnmodifiableTest {
    public static void main(String[] args) {
        User user = new User("1", "ming", 20);
        FieldHandChain fieldHandChain = new FieldHandChain();
        fieldHandChain.add(new ClearUnmodifiable());
        fieldHandChain.hand(user);
        System.out.println(user);
    }
}

执行结果:

User(id=null, name=ming, age=20)

可以看到带@unmodifiableField 的id字段的值被设置为 null了。

2、EmojiFilter

实现了 FieldHand 接口,用于过滤字段中的表情符号。

实现代码如下:

import com.fhey.common.filedHand.base.FieldHand;
import com.fhey.common.utils.EmojiUtils;
import java.lang.reflect.Field;

/**
 * @author fhey
 * @date 2022-02-02 21:56:14
 * @description: TODO
 */
public class EmojiFilter implements FieldHand {
    @Override
    public void hand(Field field, Object obj) throws IllegalAccessException {
        if(isString(field)){
            Object value = field.get(obj);
            if (null != value){
                field.set(obj, EmojiUtils.filterEmoji(value.toString()));
            }
        }
    }
}

EmojiUtils类:

/**
 * @author fhey
 * @date 2022-02-02 22:18:37
 * @description: TODO
 */
public class EmojiUtils {
    /**
     * 检测是否有emoji字符
     * @param source 需要判断的字符串
     * @return 一旦含有就抛出
     */
    public static boolean containsEmoji(String source) {
        int len = source.length();
        for (int i = 0; i < len; i++) {
            char codePoint = source.charAt(i);
            if (!notisEmojiCharacter(codePoint)) {
                //判断确认有表情字符
                return true;
            }
        }
        return false;
    }


    /**
     * 非emoji表情字符判断
     * @param codePoint
     * @return
     */
    private static boolean notisEmojiCharacter(char codePoint) {
        return (codePoint == 0x0) ||
                (codePoint == 0x9) ||
                (codePoint == 0xA) ||
                (codePoint == 0xD) ||
                ((codePoint >= 0x20) && (codePoint <= 0xD7FF)) ||
                ((codePoint >= 0xE000) && (codePoint <= 0xFFFD)) ||
                ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF));
    }

    /**
     * 过滤emoji 或者 其他非文字类型的字符
     * @param source  需要过滤的字符串
     * @return
     */
    public static String filterEmoji(String source) {
        if (!containsEmoji(source)) {
            //如果不包含,直接返回
            return source;
        }
        //该buf保存非emoji的字符
        StringBuilder buf = null;
        int len = source.length();
        for (int i = 0; i < len; i++) {
            char codePoint = source.charAt(i);
            if (notisEmojiCharacter(codePoint)) {
                if (buf == null) {
                    buf = new StringBuilder(source.length());
                }
                buf.append(codePoint);
            }
        }

        if (buf == null) {
            //如果没有找到非emoji的字符,则返回无内容的字符串
            return "";
        } else {
            if (buf.length() == len) {
                buf = null;
                return source;
            } else {
                return buf.toString();
            }
        }
    }
}

使用案例:

public class EmojiFilterTest {
    public static void main(String[] args) {
        User user = new User("1", "😀ming😃", 20);
        FieldHandChain fieldHandChain = new FieldHandChain();
        fieldHandChain.add(new EmojiFilter());
        fieldHandChain.hand(user);
        System.out.println(user);
    }
}

执行结果:

User(id=null, name=ming, age=20)

可以看到对象中name字段中的表情符号的字段被过滤。

3、ReplaceNoSeaChar

实现了 FieldHand 接口,用于替换字段中的非标准字符。

实现代码如下:

import com.fhey.common.filedHand.base.FieldHand;
import com.fhey.common.utils.StringEtraUtil;
import java.lang.reflect.Field;

/**
 * @author fhey
 * @date 2022-02-02 22:20:13
 * @description: TODO
 */
public class ReplaceNoSeaChar implements FieldHand {
    @Override
    public void hand(Field field, Object obj) throws IllegalAccessException {
        if(isString(field)){
            Object value = field.get(obj);
            if (null != value){
                field.set(obj, StringEtraUtil.replaceNonSeaChar(value.toString()));
            }
        }
    }
}

replaceNonSeaChar方法:

    public static String replaceNonSeaChar(String source) {
        if (StringUtils.isBlank(source)) {
            return source;
        }

        // 过滤ascii
        char[] contentCharArr = source.toCharArray();
        for (int i = 0; i < contentCharArr.length; i++) {
            if ((contentCharArr[i] > 0x00 && contentCharArr[i] < 0x20)
                    || contentCharArr[i] == 0x7F) {
                contentCharArr[i] = 0x20;
            }
        }
        return (new String(contentCharArr)).trim();
    }

使用案例:

public class ReplaceNoSeaCharTest {
    public static void main(String[] args) {
        User user = new User("1", "    ming   \n", 20);
        FieldHandChain fieldHandChain = new FieldHandChain();
        fieldHandChain.add(new ReplaceNoSeaChar());
        fieldHandChain.hand(user);
        System.out.println(user);
    }
}

执行结果:

User(id=1, name=ming, age=20)

可以看到name字段的值中的的非标准字符被替换。

4、ReplaceSpecialChar

实现了 FieldHand 接口,用于替换字段中的特殊字符。

实现代码如下:

import com.fhey.common.filedHand.base.FieldHand;
import com.fhey.common.utils.StringEtraUtil;
import java.lang.reflect.Field;

/**
 * @author fhey
 * @date 2022-02-02 22:20:13
 * @description: TODO
 */
public class ReplaceSpecialChar implements FieldHand {
    @Override
    public void hand(Field field, Object obj) throws IllegalAccessException {
        if(isString(field)){
            Object value = field.get(obj);
            if (null != value){
                field.set(obj, StringEtraUtil.replaceSpeciaLChar(value.toString()));
            }
        }
    }
}

replaceNonSeaChar方法:

    public static String replaceSpeciaLChar(String source) {
        //可以在中括号内加上任何想要替换的字符
        String regEx = "[\n`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。, 、?]";
        String aa = "";//这里是将特殊字符换为aa字符串,""代表直接去掉
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(source);//这里把想要替换的字符串传进来
        return m.replaceAll(aa).trim(); //将替换后的字符串存在变量newString中
    }

使用案例:

public class ReplaceSpecialCharTest {
    public static void main(String[] args) {
        User user = new User("1", "m@i#n$g", 20);
        FieldHandChain fieldHandChain = new FieldHandChain();
        fieldHandChain.add(new ReplaceSpecialChar());
        fieldHandChain.hand(user);
        System.out.println(user);
    }
}

执行结果:

User(id=1, name=ming, age=20)

可以看到name字段的值中的特殊字符被替换了。

5、SetDefaultValue

实现了 FieldHand 接口,用于为字段设置默认值。

实现代码如下:

import com.fhey.common.annotation.NotSetDefaultValue;
import com.fhey.common.filedHand.base.FieldHand;
import org.apache.commons.lang3.StringUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Date;

/**
 * @author: dongweijie221
 * @create: 2021-03-26 13:41
 * @description:
 */
public class SetDefaultValue implements FieldHand {
    @Override
    public void hand(Field field, Object obj) throws IllegalAccessException {
        Annotation annotation = field.getAnnotation(NotSetDefaultValue.class);
        if(annotation != null){
            return;
        }
        Object value = field.get(obj);
        if (value != null) {
            return;
        }
        if (isString(field)) {
            value = StringUtils.EMPTY;
        } else if (field.getType().equals(byte.class) || field.getType().equals(Byte.class)) {
            value = null;
        } else if (field.getType().equals(boolean.class) || field.getType().equals(Boolean.class)) {
            value = false;
        } else if (field.getType().equals(short.class) || field.getType().equals(Short.class)) {
            value = 0;
        } else if (field.getType().equals(char.class) || field.getType().equals(Character.class)) {
            value = '\0';
        } else if (field.getType().equals(int.class) || field.getType().equals(Integer.class)) {
            value = 0;
        } else if (field.getType().equals(long.class) || field.getType().equals(Long.class)) {
            value = 0L;
        } else if (field.getType().equals(float.class) || field.getType().equals(Float.class)) {
            value = 0;
        } else if (field.getType().equals(double.class) || field.getType().equals(Double.class)) {
            value = 0.0;
        }
        else if (field.getType().equals(Date.class)) {
            value = new Date();
        }
        field.set(obj, value);
    }
}

使用案例:

public class SetDefaultValueTest {
    public static void main(String[] args) {
        User user = new User(null, null, null);
        FieldHandChain fieldHandChain = new FieldHandChain();
        fieldHandChain.add(new SetDefaultValue());
        fieldHandChain.hand(user);
        System.out.println(user);
    }
}

执行结果:

User(id="", name="", age=0)

可以看到id和name的值都被设置了默认值"",age被设置了默认值0。

6、TrimString

实现了 FieldHand 接口,用于去除字符串字段的前后空格。

实现代码如下:

import com.fhey.common.filedHand.base.FieldHand;
import java.lang.reflect.Field;

/**
 * @author fhey
 * @date 2022-02-02 22:35:36
 * @description: TODO
 */
public class TrimString implements FieldHand {
    @Override
    public void hand(Field field, Object obj) throws IllegalAccessException {
        if(isString(field)){
            Object value = field.get(obj);
            if (null != value){
                field.set(obj, value.toString().trim());
            }
        }
    }
}

使用案例:

public class TrimStringTest {
    public static void main(String[] args) {
        User user = new User("1", "   ming   ", 20);
        FieldHandChain fieldHandChain = new FieldHandChain();
        fieldHandChain.add(new TrimString());
        fieldHandChain.hand(user);
        System.out.println(user);
    }
}

执行结果:

User(id=1, name=ming, age=20)

可以看到name字段的值变为前后的空格都被去掉了 。

四、总结

本文介绍了一个利用反射技术结合责任链模式和策略模式编写的 FieldHandChain 工具类,它支持对对象字段进行多种固定处理操作,如清除不可修改字段的值、过滤表情符号、替换非标准字符和特殊字符、设置默认值、去除字符串前后空格等。通过实现 FieldHand 接口,可以方便地扩展新的功能。文中还展示了各个功能的实现代码和使用案例,并给出了相应的执行结果示例。这个工具类能够简化对象字段的处理过程,提高开发效率和代码的可维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知北游z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值