这种情况只会出现在String类型的数据中,我是最近偶然才发现这个问题的,由于数据库的数据我是从别处粘贴过来直接放到数据库的,比如【密码】这个字段,它的值是经过MD5加密得到的字符串,我在复制的时候不小心带了一个空格。
这个微小的瑕疵仍是没被我发现,于是在我登录的时候,输入正确的账号密码却出现了提示密码错误。
于是我把数据库查询到的密码和页面输入的进行加密的密码都输出
这不完全一样吗!
真的是一样的吗?
这个空格,就是罪恶的源头!那么问题来了,我们该如何去除这个空格?这条数据就通过Mapper接口将查询结果映射给PO类的,我们可以在PO类中动手脚,比如在每个String类型的 setter 方法中添加 trim() 方法。
public String getPassWord() {
return PassWord;
}
public void setPassWord(String passWord) {
PassWord = passWord.trim();//使用trim()方法去除空格
}
可能会有同学觉得这种方法太麻烦了,要修改每个String类型的字段。有没有那种一键去空格的功能呢,方便简单又快捷的那种。这个我也不知道,我也懒得用上面那种方法一个一个的去改,于是我使用了万能的反射:将接收数据的PO类丢到反射中,提取出所有String类型的字段,再执行它的getter方法获取到属性值,对其进行去空格操作后赋值给setter方法。
public class TrimDataUtil {
public static <T>T getTrim(T obj){
Field[] fields = obj.getClass().getDeclaredFields();//获取到PO中所有的属性
for (int i = 0; i < fields.length; i++) {
boolean flag=true;//设置一个标识
Method m = null;//用于存放getter方法
String name = fields[i].getName();//获取字段名
String gets ="get"+name;//getter方法名称
String sets ="set"+name;//setter方法名称
传入一个PO对象obj,返回的也是该PO类型的对象。首先通过obj.getClass()加载类,获取到PO中所有的属性,进行循环。然后得到字段名称,并分别声明getter和setter方法名,用来作对比。
Method[] methods = obj.getClass().getMethods();//获取PO中所有方法
for (int j = 0; j < methods.length; j++) {
try {
Class<?> type = obj.getClass().getDeclaredField(name).getType();//获取类型
if(String.valueOf(type).contains("String")){//筛选String类型的字段
if(m!=null){
if(flag){
flag=false;//如果获取到getter方法之后就从头开始查找setter方法,设置flag防止重复执行
j=0;
}
接下来得到PO中所有的方法,并与之前声明的getter和setter方法进行比较,得到与字段名相对应的方法。在获取setter方法之前我们要先得到getter,因为setter方法的值需要通过getter方法来得到。
if(methods[j].getName().toLowerCase().equals(gets.toLowerCase())){
String value = (String) methods[j].invoke(obj);//执行getter方法
m.invoke(obj, value.trim());//将值赋值给setter方法
continue;//任务完成,跳出循环
}
}else{
if(methods[j].getName().toLowerCase().equals(sets.toLowerCase())){
m=methods[j];//获取到getter方法,并存放起来。
}
}
}
得到getter方法,并存放在之前声明的Method对象中,当Method不为空就说明已经得到getter方法了,那么就将循环重置,从头开始寻找对应的setter方法,设置flag是为了防止方法重复执行。
当setter方法也获取到之后,执行getter方法,将得到的值进行去空格处理,再作为参数赋值给setter方法。
所有数据处理完成后,返回该PO对象。
}
return obj;
}
给一份完整的代码吧
package com.mobile.util;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TrimDataUtil {
public static <T>T getTrim(T obj){
Field[] fields = obj.getClass().getDeclaredFields();//获取到PO中所有的属性
for (int i = 0; i < fields.length; i++) {
boolean flag=true;//设置一个标识
Method m = null;//用于存放getter方法
String name = fields[i].getName();//获取字段名
String gets ="get"+name;//getter方法名称
String sets ="set"+name;//setter方法名称
Method[] methods = obj.getClass().getMethods();//获取PO中所有方法
for (int j = 0; j < methods.length; j++) {
try {
Class<?> type = obj.getClass().getDeclaredField(name).getType();//获取类型
if(String.valueOf(type).contains("String")){//筛选String类型的字段
if(m!=null){
if(flag){
flag=false;//如果获取到getter方法之后就从头开始查找setter方法,设置flag防止重复执行
j=0;
}
if(methods[j].getName().toLowerCase().equals(gets.toLowerCase())){
String value = (String) methods[j].invoke(obj);//执行getter方法
m.invoke(obj, value.trim());//将值赋值给setter方法
continue;//任务完成,跳出循环
}
}else{
if(methods[j].getName().toLowerCase().equals(sets.toLowerCase())){
m=methods[j];//获取到getter方法,并存放起来。
}
}
}
} catch (NoSuchFieldException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (SecurityException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return obj;
}
}
最后在查询结果处调用该方法,可以看到空格已经被处理了。
由于在数据处理的时候进行了多重循环,执行这个方法处理数据肯定会降低代码的执行效率,所以这个方法大家可以借鉴一下,再进行改进,我相信你们肯定能写出更好更快的方法。