• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Mock.java: 相信大部分前端开发人员都知道Mock.js,前端用来拦截Ajax并生成假数据进行 ...

原作者: [db:作者] 来自: 网络 收藏 邀请

Mock.java使用说明手册

简介

这是一个仿照Mock.js语法的Java语言使用的假数据生成工具框架。部分方法与类介绍详细可查看JavaDoc文档(推荐先下载下来再看):JavaDoc文档

码云生成的在线javaDoc文档:在线文档

如果存在BUG或者有什么意见、建议,可以通过 issue 进行反馈。

github: github

gitee : 码云地址

此框架中不仅仅只可以作为假数据获取用,还有一些比较实用的工具类可以拿来单独使用。

*工具类介绍:工具类介绍

当前版本:maven

最低JDK版本:JDK8

※ 版本更新内容与预期更新计划详见于文档末尾 : 更新公告

WIKI

文档将会开始转移至WIKI处,转移完成后,此处README中的说明性文档将不再更新并择日删除,替换为简单的介绍与demo示例。

wiki文档:github wiki or gitee wiki

注意

未来2.x版本将会使用与1.x版本不同的包路径。如果迭代版本请注意包路径的修改。仅为修改包路径,其余内容不变。如果有2.x的话


友情链接

项目名称项目介绍项目地址
Mock.JDBC基于Mock.java与JDBC向数据库插入假数据(暂时停工)https://github.com/ForteScarlet/Mock.JDBC

使用方法

Maven

在maven项目下,从pom.xml中导入以下地址:

最新版本以maven仓库中的地址为准。仓库地址:https://mvnrepository.com/artifact/io.gitee.ForteScarlet/mock.java

<dependency>    <groupId>io.gitee.ForteScarlet</groupId>    <artifactId>mock.java</artifactId>    <version>${version}</version></dependency>

Gradle

compile group: 'io.gitee.ForteScarlet', name: 'mock.java', version: '${version}'

Jar

使用jar包导入的时候,记得同时把作为依赖的commons-beanutils.commons-beanutils:1.9.3中的jar包也导入进去。我上传了这些依赖在 dependencies文件夹 中。

使用

相信使用过Mock.js的各位大佬应该知道,在使用Mock.js的时候是用的JSON格式的参数。但是,Java可是没法直接识别JSON的啊!所以,我们采用最接近JSON格式的方式:Map集合

简单来说,就是将一个类的字段根据Mock.js那样的key-value的键值对转化为一个Map<String, Object>对象就好了!我习惯将这种Map对象称为 字段映射表

而且作为Java语言,数据类型是必须要多加考虑的问题。我在获取值的时候已经尽可能的增加了容错率,但是还是需要您注意数据类型的问题,请尽可能不要犯下将一个字符串赋值给整数这类难以防范的错误..

或许感觉上比JSON格式的使用要麻烦一些,但是这也是没有办法的事情嘛!假如您有更好的代替方式,希望您能告诉我 :)

设置字段映射的方式:

1·创建对象字段与随机值语法的映射关系(Map<String , Object> 类型的键值对)

创建的这个Map,Key值代表了映射的字段名,value值代表了映射语法由于这毕竟与弱引用类型语言不同,所以在设置映射的时候请务必注意字段的数据类型。

Map<String, Object> map = new HashMap<>();

2·添加字段映射

字段映射中,value值所用到的 @函数 可以从 JavaDoc文档 中查阅 MockUtil 类中的方法,MockUtil中的全部方法均可作为 @函数 出现在value值中。

再次提醒,请务必注意对应好字段的字段类型

map.put("age","@age");map.put("list|2-3","@title");map.put("user","@name");  ......

key值中,有三种写法:

仅有字段映射、字段映射与整数部分区间参数、字段映射、整数部分区间参数与小数部分区间参数。

例如如下这么两个字段映射:

map.put("money1|10-40.2-4" , 0);map.put("money2|10-40.2" , 0);

其中,字段名与区间参数之间的分割符为 | 符号,左边为字段名,右半边为区间参数。

区间参数中,整数部分与小数部分用 . 符号分割,左半边为整数部分区间参数,右半边为小数部分区间参数。

  • 仅有字段映射

    任务分配器首先会根据参数(value)的类型分配字段解析器,然后再根据字段类型进行取值。

    参数类型有一下几种情况:

    • 字符串类型:如果存在一个或多个@函数,解析@函数并取值,(如果有多个@函数则会尝试对@函数的取值进行加法计算);如果不存在@函数或@函数不存在于MockUtil中的方法列表则将其会视为普通字符串。
    • 整数(Integer)、浮点数(Double)类型:如果参数为Integer或Double类型,则字段值获取器会直接将此值作为默认值赋给字段。
    • 数组或集合:如果参数是数组或集合类型,字段值获取器会从其中随机获取一个值赋予字段。
    • Map集合:如果参数是Map集合类型,则会对字段的类型进行判断,如果:
      • 字段为Map类型,则直接将此Map作为字段值赋予字段,不做处理。
      • 字段为List类型,则字段值获取器会将将此Map集合封装至List集合中并返回。
      • 字段为其他任意类型,则任务分配器会将此Map视为此字段类型的字段映射集合进行解析并获取一个实例对象为字段赋值。(※注:此字段映射同样会被Mock的映射集合记录下来。即嵌套的字段映射不需要单独再进行set了。)
    • 其他任意类型:如果参数不是上面的任何类型,则字段值获取器会将此参数原样赋值,不做处理。
    //假设以下字段映射的是User类Map<String, Object> map = new HashMap<>();map.put("age1" , "@age");map.put("age2" , 15);map.put("age3" , new Integer(){1,2,3,4});map.put("name1" , "@name");map.put("name2" , "@title(2)");map.put("name3" , "这是一个名字");//下面三个email字段的参数,如果是中文,必须放在单引号或双引号中才会生效,英文不受限制map.put("email1" , "@email('这是中文')");map.put("email2" , "@email('this is english')");map.put("email3" , "@email(this is english)");//下面的friend字段的字段类型是一个Friend类,friendMap是对friend字段的映射,也就是嵌套映射//此friendMap的映射无需单独进行记录map.put("friend" , friendMap);//记录映射Mock.set(User.class, map);//User类的映射被直接记录,可以获取MockObject<User> userMockObject = Mock.get(User.class);//Friend类的映射以嵌套的形式被记录过了,可以直接获取MockObject<Friend> friendMockObject = Mock.get(Friend.class);
  • 字段映射与仅整数部分的区间参数

    参数类型有一下几种情况:

    • 字符串类型:如果存在一个或多个@函数,解析@函数并取值,(如果有多个@函数则会尝试对@函数的取值进行加法计算);在存在@函数的情况下,区间参数将被忽略。

      ※ 从v1.4.2与v1.4.3之后,当字段类型为Object类型(常见于创建Map类型对象)则会根据区间函数创建范围内大小的List集合。(详细见v1.4.2与v1.4.3更新日志)

      如果不存在@函数或@函数不存在于MockUtil中的方法列表则将其会视为普通字符串,然后根据整数参数区间获取一个随机数值并对此字符串进行重复输出。

    • 整数(Integer)、浮点数(Double)类型:如果参数为Integer或Double类型,则字段值获取器将区间参数作为方法参数,根据字段的类型使用随机函数获取对应的随机值。

      例如:

      //age为一个Integer类型的字段,等同于使用了@integer(2,4)函数map.put("age|2-4" , 0);//money为一个Double类型,等同于使用了@doubles(2,4)函数map.put("money|2-4" , 0);

      则age将会被赋予一个2-4之间的随机整数(Integer),money将会被赋予一个2-4之间最大小数位数为0的浮点数(Double)。

    • 数组或集合:如果参数是数组或集合类型,任务分配器会判断字段的类型分配字段值获取器:

      • 字段类型为整数或浮点数,则区间参数将会被忽略,直接从参数中获取一个随机元素并赋值。

        如下所示三种情况的取值是完全相同的:

        //age为一个Integer类型的字段map.put("age|2-4" , new Integer[]{1,2,3});map.put("age|2" , new Integer[]{1,2,3});map.put("age" , new Integer[]{1,2,3});
      • 字段类型为数组或集合的时候,会根据区间参数获取一个随机数量,并从传入的参数中获取此数量的随机元素。

    • Map集合:如果参数是Map集合类型,则任务分配器会对字段的类型进行判断,如果:

      • 字段为Map类型,则直接将此Map作为字段值赋予字段且忽略区间参数,不做处理。

      • 字段为List类型,则字段值获取器会将将此Map集合封装至List集合并根据区间参数重复一个随即数量并返回。

      • 字段为List<? extends Object> 类型,即一个任意泛型的List类型的时候,任务分配器会将此Map视为此泛型类型的字段映射集合进行解析,再根据区间参数获取指定范围内数量的实例对象,并封装为List类型为字段赋值。(※注:上文提到过,内嵌字段映射同样会被记录。)

      • 字段为其他任意类型,则任务分配器会将此Map视为此字段类型的字段映射集合进行解析并获取一个实例对象为字段赋值,忽略区间参数。(※注:上文提到过,内嵌字段映射同样会被记录。)

        ※ 在v1.4.3版本之后,存在整数区间的Map映射机制存在改动(主要为结果对象为Map类型的时候)详见v1.4.3版本日志。

    • 其他任意类型

    • 如果字段是list类型或数组类型,则会根区间参数重复输出并为字段赋值。

      • 如果字段类型为其他未知类型,则会忽略区间参数并使用参数值作为默认值赋值。
   map.put("list|2-6" , "@title");   map.put("age|10-40" , 2);

3·获取假字段封装对象

通过Mock的get方法获取一个已经添加过映射记录的数据

  • 首先使用set方法记录类的字段映射

    //映射表尽可能是Sting,Object类型的Map<String, Object> map = new HashMap<>();//添加一个映射map.put("age|10-40" , 2);//记录类的映射//1、使用javaBean封装Mock.set(User.class , map);//2、或者直接使用Map类型,不再需要javaBean的class对象,但是需要指定一个映射名Mock.set("userMap", map);
    • 然后使用get方法得到假对象封装类
//已经记录过User类的映射,获取封装类//1、如果是使用的javaBean记录的,使用javaBean获取MockObject<User> mockObject = Mock.get(User.class);//2、或者你之前是使用map记录的,使用记录时保存的映射名获取//注:MockMapObject 对象实现了MockObject接口MockMapObject mockMapObject = Mock.get("userMap");
  • 根据MockObject中提供的API来获取你所需要的结果:
// 获取一个结果,并使用Optional类进行封装。Optional<T> get();
// 获取一个结果T getOne();
// 获取指定数量的多个结果,返回List集合List<T> getList(int num);
// 获取指定数量的多个结果,并根据给定规则进行转化,返回List集合List<R> getList(int num , Function<T, R> mapper);
// 获取指定数量的多个结果,返回Set集合Set<T> getSet(int num);
// 获取指定数量的多个结果,并根据给定规则进行转化,返回Set集合Set<R> getSet(int num , Function<T, R> mapper);
```java

// 获取指定数量的多个结果,并根据给定规则转化为Map集合Map<K,V> getMap(int num , Function<T,K> keyMapper, Function<T,V> valueMapper);```


※ 自1.3版本之后,我优化了MockObject接口内部结构,并增加了大量parallel方法与collect方法,您现在可以在1.3版本中更加灵活的对数据进行转化,或者根据数据量的需求自行决定是否需要使用并行线程进行对象创建。

自定义@函数

有时候,我提供的MockUtil中的方法可能无法满足您的需求,那么这时候,就需要一个可以对@函数进行扩展、加强的窗口。在v1.1版本中,我添加了这个功能。(这个功能测数量很少,可能会存在很多bug)

1· 获取自定义@函数加载器

//获取@函数加载器MethodLoader methodLoader = Mock.mockMethodLoader();

函数加载器支持链式加载,也支持一次性加载

链式:

LoadResults loadResults = methodLoader				//添加指定类中的指定方法名的方法                .append(Demo1.class, "testMethod")    			//添加指定类中的多个指定方法名的方法                .appendByNames(Demo2.class, new String[]{"method1" , "method2"})    			//添加指定类中的多个符合指定正则回则的方法                .appendByRegex(Demo3.class, "[a-zA-Z]+")    			//还有很多...敬请查阅API文档                .load();

使用链式加载的时候,请务必记住在结尾使用load()进行加载,否则方法集将无法被加载,而是一直留存在等待区。

非链式:

methodLoader.add(Demo1.class, "testMethod");

通过以上代码可以发现,加载完成后都会有一个 LoadResults 类作为返回值,这个类是在方法加载后的一个加载报告封装类,通过LoadResults 可以获取到刚刚加载的方法谁成功了,谁失败了,失败了的方法为什么失败等信息:

 		Map<Boolean, Set<Method>> map = loadResults.loadResults();//加载的方法集根据成功与否分组Set<Method> successMethods = loadResults.loadSuccessResults();//加载成功的方法集Map<Method, Exception> whyFailMap = loadResults.whyFail();//加载失败的方法以及抛出的异常int successNum = loadResults.successNums();//成功的个数int failNum = loadResults.failNums();//失败的个数

假若加载成功后,则此方法便可以直接在映射中直接用@开头作为使用@函数使用了~

注解形式映射

1.4版本之后我提供了两个可以使用在字段上的注解:@MockValue@MockArray

@MockValue

使用在类的字段上,参数:

    /**     * 映射值,如果为空则视为无效     */    String value();	/* --- 1.6.0后增加 --- */    /**     * 区间参数,如果有值,则代表了字段之前的区间参数。默认没有值     * 例如当字段{@code age} 的注解参数为 {@code param = "10-20"} 的时候, 相当于字段值为 {@code "age|10-20"}。参数中的那个竖线不需要写。写了也会被去除的。     * @since  1.6.0     */    String param() default "";    /**     * 参数value的最终类型,在转化的时候会使用beanutils中的工具类     {@link org.apache.commons.beanutils.ConvertUtils}进行类型转化, 默认为String类型。     * @return     */    Class<?> valueType() default String.class;

也就是说,假设这个字段叫做:field_A,则映射结果大致相当于:

// 其中,${value()} 的最终结果值为通过ConvertUtils进行转化的结果。// 其中,[|${param()}]的存在与否取决于param()里有没有值xxxMap.put("${field_A}[|${param()}]", (${valueType()}) ${value()})

用来指定此字段的映射值。例如:

public class User {        // 相当于 ("name", "@cname")    @MockValue("@name")    private String name;        // 相当于 ("age|20-40", 0)    @MockValue(value = "0", param = "20-40", valueType = Integer.class)    private Integer age;   // 省略 getter & setter    }

@MockArray

使用在类的字段上,参数:

	/**     * 数组参数, 必填参数     */    String[] value();    /**     * 类型转化器实现类,需要存在无参构造     * 默认转化为字符串,即默认不变     */    Class<? extends ArrayMapper> mapper() default ArrayMapperType.ToString.class;	/* --- 1.6.0后增加 --- */    /**     * 区间参数,如果有值,则代表了字段之前的区间参数。默认没有值     * 例如当字段{@code age} 的注解参数为 {@code param = "10-20"} 的时候, 相当于字段值为     {@code "age|10-20"}。参数中的那个竖线不需要写。写了也会被去除的。     * @since  1.6.0     */    String param() default "";

其中,mapper()参数可选,其类型为ArrayMapper接口的的实现类,用于指定将字符串数组,也就是value()中的值进行转化的规则。此参数默认为不进行转化,即转化为字符串类型。

ArrayMapper接口中的抽象方法:

	/**     * 给你一个数组长度,返回一个数组实例的function,用于数组的实例化获取     * @return 数组实例获取函数,例如:Integer[]::new; 或者 size -> new Integer[size];     */    IntFunction<T[]> getArrayParseFunction();	/**	 * 将字符串转化为指定类型	 */	T apply(String t);

在对ArrayMapper接口进行实现的时候,请务必保留下无参构造用于对其进行实例化。

对于一些比较常见的类型转化,我提供了几个已经实现好的实现类。这些实现类以内部类的形式存在于ArrayMapperType接口中。

  • ArrayMapperType.ToString.class

    转化为字符串类型,即不进行转化

  • ArrayMapperType.ToInt.class

    转化为Integer类型

  • ArrayMapperType.ToLong.class

    转化为Long类型

  • ArrayMapperType.ToDouble.class

    转化为Double类型

例如:

public class User {    @MockArray(value = {"1", "2", "3"}, mapper = ArrayMapperType.ToInt.class)    private int age;   // 省略 getter & setter}

使用

使用也很简单,我在Mock中增加了4个方法,2个set方法 2个reset方法。

	/* --- 1.4版本之后增加 --- */		/**     * 通过注解来获取映射     */    public static <T> void set(Class<T> objClass);	/**     * 通过注解来获取映射, 并提供额外的、难以用注解进行表达的映射参数     */    public static <T> void setWithOther(Class<T> objClass, Map<String, Object> other);		/**     * 通过注解来获取映射     */    public static <T> void reset(Class<T> objClass);	/**     * 通过注解来获取映射, 并提供额外的、难以用注解进行表达的映射参数     */    public static <T> void resetWithOther(Class<T> objClass, Map<String, Object> other);

注意事项

注解优先级

假如你在同一个字段上同时使用了两个注解,则会优先使用@MockValue;

额外映射

可以发现,4个方法中各有一个方法需要提供额外参数,他会在注解映射创建完毕后进行添加,也就是假如额外参数和字段中有冲突的键,则额外参数的值将会覆盖注解映射值。

映射扫描

1.6.0版本后,我更新了映射扫描映射代理功能。感谢提出建议的朋友。Issue#I1CCMT

在您使用注解形式映射的时候,是否有感觉到每个类都需要使用Mock.set(...)进行设置很麻烦?希望能够通过包扫描一键批量set?现在我增加了一个注解:@MockBean,将其标注在您的类上,此时再配合使用Mock.scan(...)方法即可扫描指定的一个或多个包路径中所有标注了@MockBean的javaBean。

对于Mock.scan(...)的方法定义如下:

    /**     * 扫描包路径,加载标记了{@link com.forte.util.mapper.MockBean}注解的类。     *     * @param classLoader nullable, 类加载器, null则默认为当前类加载器     * @param withOther   nullable, 假如扫描的类中存在某些类,你想要为它提供一些额外的参数,此函数用于获取对应class所需要添加的额外参数。可以为null     * @param reset       加载注解映射的时候是否使用reset     * @param packages    emptyable, 要扫描的包路径列表, 为空则直接返回空set     * @return 扫描并加载成功的类     */    public static Set<Class<?>> scan(ClassLoader classLoader, Function<Class<?>, Map<String, Object>> withOther, boolean reset, String... packages) throws Exception;

这么多参数?先别怕,我先简单介绍下这些参数:

  • classLoader:包扫描使用的类加载器。可以为null。
  • withOther:一个Function函数,这个参数接收一个Class参数,返回一个Map<String, Object>结果,即获取一个对应类的额外参数。类似于注解映射中set方法的额外映射。可以为null。
  • reset:即如果扫描到了已经被添加的映射,是否覆盖。
  • packages:需要扫描的包路径列表。

除了这个方法,我还提供了一些重载方法:

    /**     * {@link #scan(ClassLoader, Function, boolean, String...)}的重载方法     * @see #scan(ClassLoader, Function, boolean, String...)     */    public static Set<Class<?>> scan(Function<Class<?>, Map<String, Object>> withOther, boolean reset, String... packages) throws Exception;    /**     * {@link #scan(ClassLoader, Function, boolean, String...)}的重载方法     * @see #scan(ClassLoader, Function, boolean, String...)     */    public static Set<Class<?>> scan(boolean reset, String... packages) throws Exception;    /**     * {@link #scan(ClassLoader, Function, boolean, String...)}的重载方法, reset默认为false     * @see #scan(ClassLoader, Function, boolean, String...)     */    public static Set<Class<?>> scan(String... packages) throws Exception;

使用

所以一般情况下,你可以直接这么使用:

// 扫描两个包Mock.scan("forte.test2.beans", "forte.test1.beans", ...);// 然后直接获取Mock.get(Xxxx.class);// 使用 

映射代理

1.6.0版本后,我更新了映射扫描映射代理功能。感谢提出建议的朋友。Issue#I1CCMT

首先看一下Issue上提出的模拟场景:

// interface public interface ServiceA{    VoA methodA();}// bean, can with @MockBeanpublic class VoA{    @MockValue("@cname")    private String p1;
                      

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap