文章目录
一、引言
因为经常需要对一个对象中的字段进行一些固定的处理处理,每次都要对每个字段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 接口,可以方便地扩展新的功能。文中还展示了各个功能的实现代码和使用案例,并给出了相应的执行结果示例。这个工具类能够简化对象字段的处理过程,提高开发效率和代码的可维护性。