java生成假数据工具类-基于Faker1.0.2

背景

回想平时我们测试,需要数据就在数据库一顿猛操作也没达到所谓的乱数假文,但是Faker很好的为我们解决了这个问题,伪造的数据接近真实数据。但是我们也不能每次都去一个一个数据的生成,这样会叠加代码量,工作量也增加了,于是写了一个工具类,将faker相关的方法以及方法需要的参数和参数类型存入了数据库中,前端只要配置好相对应的数据就能生成伪造数据
githup地址

技术点

泛型+反射

Faker

基本用法
用法为:Faker.**.**
Faker faker = Faker.instance(Locale.CHINA);//.instance(Locale.CHINA)指定为中文
//默认英语,如下:
//Faker faker = new Faker();
//生成数据(生成随机电话号码)
//faker.phoneNumber().phoneNumber();
System.err.println("生成的随机电话号码为:"+faker.phoneNumber().phoneNumber());

Faker支持多种语言,80+个基础方法,约500种假数据类型(常用的有320种左右,记不清楚了,写入数据库就知道了),详情请看githup地址

控制台输出结果
生成的随机电话号码为:11132037344
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS

maven 依赖

<dependency>
  <groupId>com.github.javafaker</groupId>
  <artifactId>javafaker</artifactId>
  <version>1.0.2</version>
</dependency>

数据库表结构

数据库字段以及字段类型由于是测试,可根据实际需求修改。

utilFaker,主要用于存入Faker一级二级方法(faker.phoneNumber().cellPhone())一级为phoneNumber()二级为cellPhone()
在这里插入图片描述
util_faker_parameterinfo主要是存入最终方法的参数以及参数类型
如faker.number().randomDouble(int maxNumberOfDecimals, int min, int max)三个int类型的参数,参数主要是设置默认参数
在这里插入图片描述

JAVA实现

MockItem参数类(包含调用的方法,参数以及输出时参数对应的key)
@Data
public class MockItem{

    /**
     * @ 名称对应的faker一级方法.二级方法(number.randomDigit)
     */
    private  String methodNames;

    /**
     * @ 生成数据调用方法对应的参数,前段传入的参数
     */
    public List<MockItemParamters> inParameters;

    /**
     * @ 返回数据时的key
     */
    private  String key;

}
MockItemParamters(调用方法时传入的参数以及参数类型)
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MockItemParamters {
    /**
     * @ 名称对应Params参数
     */
    private Object Params;
    /**
     * @ 名称对应Params参数类型
     */
    Class<?> clazz;

}
最终实现的工具类GenerateData
public class GenerateData{

    /**
    * TODO
        * @param: faker
        * @param: mockItem 生成数据是调用的方法,方法需要的参数及类型以及输出数据时的key
        * @param: number 生成假数据的条数
        * @param: clazz 需要输出的实体
    */
    public static <T> List<T> generatList(Faker faker, List<MockItem> mockItem, int number, Class<T> clazz) throws Exception {
        List<T> listResult = new ArrayList<>();
        for(int i = 0; i < number; i++){
            listResult.add(i,generateEntity(faker,mockItem,clazz));
        }
        return listResult;
    }
   
    public static List<Map<String, Object>> generatListMap(Faker faker,List<MockItem> mockItem,int number){
        List<Map<String, Object>> listResult = new ArrayList<>();
        for(int i=0;i<number;i++){
            listResult.add(i,generateMap(faker,mockItem));
        }
        return listResult;
    }

    /**
     * TODO
     * @Description: 一次生成一条Map假数据
     * @return: listResultdata
     */
    public static Map<String, Object> generateMap(Faker faker,List<MockItem> mockItem){
        Map<String,Object> listResultdata = new HashMap<>();
        try {
            for (MockItem m : mockItem) {
                listResultdata.put(m.getKey(),generateSingleData(faker,m));
            }
        }
        catch (Exception e){
            throw new RuntimeException("Data generation failed", e);
        }
        return listResultdata;
    }

    /**
     * TODO
     * @Description: 一次生成一条数据,核心在于利用BeanUtils.setProperty反射机制
     * @return: T
     */
    public static <T> T generateEntity(Faker faker,List<MockItem> mockItem, Class<T> clazz){
        try {
            T result = clazz.newInstance();
            for (MockItem mock : mockItem) {
                Object value = generateSingleData(faker, mock);
                BeanUtils.setProperty(result, mock.getKey(), value);
            }
            return result;
        }
        catch (Exception e){
           throw new RuntimeException("Data generation failed", e);
        }
    }

    /**
    * TODO
        * @Description: 调用Faker方法一次生成一个数据
        * @return: (T)
    */
    public static Object generateSingleData(Faker faker,MockItem mockItem) throws Exception{
        String[] methods = mockItem.getMethodNames().split("\\.");
        if(methods.length != 2) {
            throw new RuntimeException("methodNames is not invaild");
        }
        Object firstMethod = faker.getClass().getMethod(methods[0]).invoke(faker);//获取到faker第一个方法的调用句柄
        Class<?> firstMethodClass = firstMethod.getClass();
        if(mockItem.getInParameters() != null) {
            Class<?>[] clazz = typeConversion(mockItem.getInParameters());
            Object[] paramets = parameterConversion(mockItem.getInParameters());
            //getMethod的第二个参数parameterTypes是按声明顺序标识该方法形参类型。
            return firstMethodClass.getMethod(methods[1], clazz).invoke(firstMethod, paramets);
        }
        return firstMethodClass.getMethod(methods[1]).invoke(firstMethod);
    }

    /**
     * TODO
     * @Description: 根据调用者提供的数据类型进行相对应的转换(类型转换)主要用在getMethod的第二个参数parameterTypes需要声明方法形参类型
     * @param: mockItemParamters 参数类包含参数及参数类型
     * @return: Class<?>[]
     */
    public static Class<?>[] typeConversion(List<MockItemParamters> mockItemParamters){
        Class<?>[] clazz = new Class<?>[mockItemParamters.size()];
        //遍历获取形参类型以及转换参数
        int i = 0;
        for(MockItemParamters m : mockItemParamters){
            if(int.class == m.getClazz() || Integer.class == m.getClazz()){
                clazz[i] = int.class;
            }else if(boolean.class == m.getClazz() || Double.class == m.getClazz()){
                clazz[i] = boolean.class;
            }else if(long.class == m.getClazz() || Long.class == m.getClazz()){
                clazz[i] = long.class;
            }else if(byte.class == m.getClazz() || Byte.class == m.getClazz()){
                clazz[i] = byte.class;
            }else if(float.class == m.getClazz() || Float.class == m.getClazz()){
                clazz[i] = float.class;
            }else if(double.class == m.getClazz() || Double.class == m.getClazz()){
                clazz[i] = double.class;
            }else if(short.class == m.getClazz() || Short.class == m.getClazz()){
                clazz[i] = short.class;
            }else{
                clazz[i] = String.class;
            }
            i++;
        }
        return clazz;
    }

    /**
     * TODO
     * @Description: 根据调用者提供的数据类型进行相对应的转换(参数类型转换)
     * @param: mockItemParamters参数类包含参数及参数类型
     * @return: Class<?>[]
     */
    public static Object[] parameterConversion(List<MockItemParamters> mockItemParamters){
        Object[] paramets = new Object[mockItemParamters.size()];
        //遍历获取形参类型以及转换参数
        int i = 0;
        for(MockItemParamters m : mockItemParamters){
            if(int.class == m.getClazz() || Integer.class == m.getClazz()){
                //int a = ConvertUtils.convert(m.getParams(),int.class,true);
                paramets[i] = (Integer.parseInt(m.getParams().toString()));
            }else if(boolean.class == m.getClazz() || Double.class == m.getClazz()){
                paramets[i] = (Boolean.parseBoolean(m.getParams().toString()));
            }else if(long.class == m.getClazz() || Long.class == m.getClazz()){
                paramets[i] = (Long.parseLong(m.getParams().toString()));
            }else if(byte.class == m.getClazz() || Byte.class == m.getClazz()){
                paramets[i] = (Byte.parseByte(m.getParams().toString()));
            }else if(float.class == m.getClazz() || Float.class == m.getClazz()){
                paramets[i] = (Float.parseFloat(m.getParams().toString()));
            }else if(double.class == m.getClazz() || Double.class == m.getClazz()){
                paramets[i] = (Double.parseDouble(m.getParams().toString()));
            }else if(short.class == m.getClazz() || Short.class == m.getClazz()){
                paramets[i] = (Short.parseShort(m.getParams().toString()));
            }else{
                paramets[i] = (m.getParams().toString());
            }
            i++;
        }
        return paramets;
    }

    public static void main(String[] args) throws Exception {
        Faker faker = Faker.instance(Locale.CHINA);
        List<MockItem> mockItemList = new ArrayList<>();
        //参数
        List<MockItemParamters> mockItemParamters = new ArrayList<>();
        MockItemParamters MockItemParamters = new MockItemParamters();
        MockItemParamters.setParams(2);
        MockItemParamters.setClazz(int.class);
        MockItemParamters MockItemParamters1 = new MockItemParamters();
        MockItemParamters1.setParams(2);
        MockItemParamters1.setClazz(int.class);
        MockItemParamters MockItemParamters2 = new MockItemParamters();
        MockItemParamters2.setParams(99);
        MockItemParamters2.setClazz(int.class);
        mockItemParamters.add(MockItemParamters);
        mockItemParamters.add(MockItemParamters1);
        mockItemParamters.add(MockItemParamters2);
        MockItem mockItem = new MockItem();
        mockItem.setMethodNames("name.fullName");
        mockItem.setKey("name");
        MockItem mockItem1 = new MockItem();
        mockItem1.setMethodNames("number.randomDouble");
        mockItem1.setInParameters(mockItemParamters);
        mockItem1.setKey("value");
        mockItemList.add(mockItem);
        mockItemList.add(mockItem1);
        //输入的参数
        System.out.println("输入的参数~~~~~~~~~~~~~~~~~"+mockItemList);
        //根据实体类生成
        List<***> **=  generatList(faker,mockItemList,10, 	***.class);
        System.out.println("根据实体映射输出的list结果~~~~~~~~~~~~~~~~~"+**);
        //生成map类型
        List<Map<String,Object>>  listMap =  generatListMap(faker, mockItemList, 10);
        System.out.println("输出的listMap结果~~~~~~~~~~~~~~~~~"+listMap );
    }
}

输出结果

输入的参数~~~~~~~~~~~~~~~~~[MockItem(methodNames=name.fullName, inParameters=null, key=name), MockItem(methodNames=number.randomDouble, inParameters=[MockItemParamters(Params=2, clazz=int), MockItemParamters(Params=2, clazz=int), MockItemParamters(Params=99, clazz=int)], key=value)]
根据实体映射输出的10条结果~~~~~~**实体类名称~~~~~~~~~~~[**(name=苏梓晨, value=39.76), **(name=叶昊然, value=47.0), **(name=张笑愚, value=67.61), **(name=黎峻熙, value=77.59), **(name=覃彬, value=14.1), **(name=贺展鹏, value=8.53), **(name=覃致远, value=77.93), **(name=谢煜城, value=35.23), **(name=孙风华, value=29.26), **(name=赖志泽, value=15.06)]
输出的10条Map结果~~~~~~~~~~~~~~~~~[{name=崔天磊, value=78.89}, {name=邱思聪, value=44.28}, {name=陆伟宸, value=57.53}, {name=宋远航, value=19.53}, {name=曾炫明, value=82.85}, {name=周鹏飞, value=82.98}, {name=谭文博, value=78.05}, {name=陈瑾瑜, value=15.98}, {name=史明辉, value=56.29}, {name=尹正豪, value=13.07}]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS

将Faker中的方法以及参数类型输出到数据库中

根据自己框架把 super.save修改为自己的插入数据的方法即可(insert语句)

    public void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Faker faker = Faker.instance( Locale.CHINA);
        Field[] fileds = faker.getClass().getDeclaredFields();
        for( Field f1:fileds ){
            UtilFakerPO utilFakerPO = new UtilFakerPO();
            utilFakerPO.setCreateTime(new Date());
            utilFakerPO.setEhName(f1.getName());
            utilFakerPO.setMthod(f1.getName());
            utilFakerPO.setParentId(0l);
            super.save(utilFakerPO);
            UtilFakerParameterinfoVo details = ConvertUtils.convertIgnoreNull(utilFakerPO, UtilFakerParameterinfoVo.class);
            if(!"fakeValuesService".equals(f1.getName())){
                String name = f1.getName();
                if("randomService".equals(f1.getName())){
                    name = "random";
                }else if("dateAndTime".equals(f1.getName())){
                    name = "date";
                }
                Object object = faker.getClass().getMethod(name).invoke(faker);
                Method[] methods = object.getClass().getDeclaredMethods();
                for (Method method:methods){
                    String methodName = method.getName();
                    UtilFakerPO utilFakerchild = new UtilFakerPO();
                    utilFakerchild.setCreateTime(new Date());
                    utilFakerchild.setEhName(methodName);
                    utilFakerchild.setMthod(name+"."+methodName);
                    utilFakerchild.setParentId(details.getId());
                    super.save(utilFakerchild);
                    UtilFakerParameterinfoVo detailschild = ConvertUtils.convertIgnoreNull(utilFakerchild, UtilFakerParameterinfoVo.class);
                    Class<?>[] parameterTypes = method.getParameterTypes();
                    for (Class<?> clas:parameterTypes){
                        String parameterName = clas.getSimpleName();
                        UtilFakerParameterinfoPO utilFakerParameterinfoPO = new UtilFakerParameterinfoPO();
                        utilFakerParameterinfoPO.setCreateTime(new Date());
                        utilFakerParameterinfoPO.setDataType(parameterName);
                        utilFakerParameterinfoPO.setUtilFakerId(detailschild.getId());
                        super.save(utilFakerParameterinfoPO);
                    }
                }
            }
        }
    };

上面代码中类型转换与参数转换应该有更好的办法,我暂时没有查到,如果大神有更好的方法求指教,写下这篇文章纯属为了学习,记录。同时也希望能给他人提供帮助。

  • 25
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Etc.End

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

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

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

打赏作者

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

抵扣说明:

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

余额充值