背景

下午三时许,笔者正戴着耳机听着歌开心的敲着bug,忽然听到办公室的吵架声,原来是ios开发和产品小姐姐吵起来了,为了一个车牌号的校验问题。起因是ios传的车牌号没有将字符串的首尾空格去掉,后端直接使用BeanUtils.copyProperties(source,target)接收值存进了数据库,页面直接显示了带空格的车牌号,测试小姐姐就给ios提了一个bug,就这么简单的一件事,两个人吵得不可开交,最后气的产品小姐姐让ios以后不要和她说话,有问题钉钉上打字说。太刚了这两人。

在这儿想说一下,开发人员其实没必要对bug那么敏感,我的意思是bug我们要重视,但是不要看到bug就开始开始心跳加速,热血沸腾,觉得全世界在与你为敌,我们要抱着良好的心态去沟通问题,解决问题,纵然很多时候有些bug确实让人无语,但何必为了一个bug让自己陷入焦躁和愤怒的状态呢,也容易破坏同事之间的关系,你们说是不是?

言归正传,我们来说说这个问题该怎么解决。

一、客户端解决方案

1、题外话

我觉得前后端开发人员真的没必要经常为了某个参数应该谁校验的问题而争执,我觉得这就像院子门和屋门的关系,前端校验就是院子门,后端是真正能进入屋里的门,院子门上锁是第一道防范和心理安慰,虽然知道别人可以绕过院子门翻墙进来,但是上个锁也总比小偷大摇大摆推开院子门直接进来强吧。然后就是后端,不管院子门锁没锁,你的屋门都要加锁的,要不然门户大开,小偷可不会跟你客气。同样的道理,后端不校验,别人就有一百种方法绕过前端校验,直接将请求打入你的数据库。

2、解决方案

如果本文有客户端的小伙伴看到,不要激动,在传字符串类型值给后端的时候,如果没有特殊要求要求你原值传的话,你应该手动trim一下去掉首尾的空格再传值,这应该是前后端的多年来的默契了吧,举手之劳,会减少很多问题的发生。

二、后端解决方案(本文重点)

1、题外话

很多后端人员会说,都9012年了,我们都是使用工具类BeanUtils.copyProperties(source,target)来直接赋值的,谁还手动先trim()再set(),简直就是回到原始时代。我觉得呢,这样说对也不对,我们这一行人员的开发水平真的是层次不齐,每一天你都可能遇到各种奇葩的问题,在必要的时候,后端人员也要主动加锁的意识,因为可能你院子的主人可能不但不锁院子门,甚至打开到最大就出去潇洒了。那么在这种必要的时候,我们要怎样做呢,怎样让BeanUtils.copyProperties(source,target)中的source里的字符串类型在赋值时已经去掉首尾空格了呢?

2、解决方案

下面是我写的一个工具类,利用反射手动给客户端传来的字符串类型的值去掉首尾空格再赋值,话不多说,直接来看代码。

package com.mazhichu.util;

import lombok.Data;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * <p class="detail">
 * 功能: 去掉字符串类型的首尾空格
 * </p>
 *
 * @author Moore
 * @ClassName Bean value trim util.
 * @Version V1.0.
 * @date 2019.11.29 15:53:44
 */
public class BeanValueTrimUtil {
     /**
      * 去掉bean中所有属性为字符串的前后空格
      * @param bean
      * @throws Exception
      */
     public static void beanValueTrim(Object bean) throws Exception {
         if(bean!=null){
             //获取所有的字段包括public,private,protected,private
             Field[] fields = bean.getClass().getDeclaredFields();
             for (int i = 0; i < fields.length; i++) {
                 Field f = fields[i];
                 if (f.getType().getName().equals("java.lang.String")) {
                     String key = f.getName();//获取字段名
                     Object value = getFieldValue(bean, key);

                     if (value == null)
                         continue;

                     setFieldValue(bean, key, value.toString().trim());
                 }
             }
         }
     }

     /**
      * 利用反射通过get方法获取bean中字段fieldName的值
      * @param bean
      * @param fieldName
      * @return
      * @throws Exception
      */
     private static Object getFieldValue(Object bean, String fieldName)
             throws Exception {
         StringBuffer result = new StringBuffer();
         String methodName = result.append("get")
                 .append(fieldName.substring(0, 1).toUpperCase())
                 .append(fieldName.substring(1)).toString();

         Object rObject = null;
         Method method = null;

         @SuppressWarnings("rawtypes")
         Class[] classArr = new Class[0];
         method = bean.getClass().getMethod(methodName, classArr);
         rObject = method.invoke(bean, new Object[0]);

         return rObject;
     }

     /**
      * 利用发射调用bean.set方法将value设置到字段
      * @param bean
      * @param fieldName
      * @param value
      * @throws Exception
      */
     private static void setFieldValue(Object bean, String fieldName, Object value)
             throws Exception {
         StringBuffer result = new StringBuffer();
         String methodName = result.append("set")
                 .append(fieldName.substring(0, 1).toUpperCase())
                 .append(fieldName.substring(1)).toString();

         /**
          * 利用发射调用bean.set方法将value设置到字段
          */
         Class[] classArr = new Class[1];
         classArr[0]="java.lang.String".getClass();
         Method method=bean.getClass().getMethod(methodName,classArr);
         method.invoke(bean,value);
     }

     @Data
     public static class User{
         private String username;
         private String password;
         private int age;
     }

    public static void main(String[] args) throws Exception {
         User user = new User();
         user.setUsername(" hehe ");
         user.setPassword(" ha ha");
         user.setAge(12);
         beanValueTrim(user);
    }
 }

 debug看一下效果

这样,是不是就去掉了字符串类型值的首尾空格了,然后你再BeanUtils.copyProperties(source,target)就没问题了。虽然个人觉得这是多余的操作,但有时候人微言轻的时候,你不得不这样做。

好了,本篇文章就讲到这儿,可能有点鸡肋,但这个世界每一天都有很多鸡肋的事在发生,然后你还不得不去面对,希望给遇到这个问题的人能有所帮助。

文章同步公众号:码之初,每天推送Java技术文章,期待您的关注!

原创不易,转载请注明出处,谢谢!

02-12 06:11