天下事有难易乎?为之,则难者亦易矣;不为,则易者亦难矣。

推荐几个开源类库,效率贼高,学会使用远离996!

itzoo 524次浏览 0个评论

点击“终码一生”,关注,置顶公众号

每日技术干货,第一时间送达!



今天给大家分享几个 Java 的开源类库,亲测非常好用!


有了它们之后,你就可以和很多重复劳动说再见了。但是工具都是一把双刃剑,有利就有弊,自己可以权衡。


 

1

MapStruct



MapStruct是干什么的?


MapStruct是个代码产生器,它能直接根据注解生成 Java 对象对应的转换器。


比如,直接把一个 A 类型的 Java 对象,给转成 B 类型的 Java 对象,只需要在他们之间配置上字段之间的映射关系即可。


为什么在项目里用它?


现在随便一个项目都是多层的,尤其是 Web 项目,经常需要在多层之间做对象模型转换,比如 DTO 转换成 BO。


  • DTO(Data Transfer Object):数据传输对象,Service 向外传输的对象。

  • BO(Business Object):业务对象,由 Service 层输出的封装业务逻辑的对象。


但是这种转换工作就像是小时候,老师罚我们抄写名人名言 100 遍一样,十分枯燥,还容易出错。


像这样:


public class CarMapper {
    CarDto carDoToCarDto(Car car) {
        CarDto carDto = new CarDto();
        carDto.setCarId(car.getCarId());
        carDto.setWheel(car.getWheel());
        carDto.setCarType(car.getCarType());
        carDto.setCarColor(car.getCarColor());
        ......
    }
}


要是 Car 有几十个字段,像 Car 一样的又有几十个类,你可以想一下,这种繁琐程度。


在 MapStruct 之前,我们都是通过 Apache 或者 Spring 的 BeanUtils 工具,去自动做这种事情。


但是这类工具有两个问题:


1.性能比较差


性能差主要是 Apache 的 BeanUtils 这套东西,它每次都要针对字段,做是否可读写的检查,还要根据字段生成对应的 PropertyDescriptor。


这些严重影响了它的性能,所以,在阿里 Java 手册里,也不推荐用它。


Spring 的 BeanUtils,虽然精简了很多 Apache 的 BeanUtils 的读写检查以及对应的属性信息记录,但是它依然是通过反射调用,而且是大量反射调用。这种性能也不能令人满意。


2.运行期做转换,出错就代表损失


BeanUtils 这类工具,有个统一的名称,叫做 Java 对象映射框架。


它们大部分的实现都是在运行期去执行代码,然后在 Java 对象之间去拷贝对应的值。


运行期间做这种事儿,有个最大的问题——整个项目启动运行后,才能发现错误。比如,转换的时候,类型不一致导致报错。


对于此种情况,咱们大家都知道,这事儿就像开业酬宾没搞好,变成了开业仇宾……


如果能写完代码,编译的时候就发现问题,这种损失就可以避免了。


MapStruct 的引入就是为了解决以上这两个问题。


MapStruct 首先是个代码产生器,它是根据注解,去产生一个专门用来转换的工具类,这个工具类,就像我们自己写的 Java 类一样,可以直接被使用,这样就避免了反射。


同时,它产生的转换类也特别简单,就是默认会在两个类型的 Java 对象之间,拷贝同名属性的值。


如果有了配置,属性不同名也可以拷贝。所以它的性能很好。


示例代码如下:


@Mapper
public interface CarMapper {

    CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );

    @Mapping(target = "seatCount", source = "numberOfSeats")
    CarDto carBoToCarDto(Car car);
}


MapStruct由于是个代码产生器,就带来了个巨大的好处,就是这家伙是在编译阶段就会生成对应的类,所以,如果有了类似类型转换不过去的问题,直接就编译报错了,根本等不到运行才发现。这样的话,就不会造成什么损失,这真是件十分 Nice 的事情。


代码库地址:https://github.com/mapstruct/mapstruct


 

2

Retrofit



Retrofit 是干什么的?


Retrofit 就是一套 Http 客户端,可以用来访问第三方的 Http 服务。


比如,咱们代码里想调用一个 Http 协议的 URL,就可以用它来访问这个 URL,获取响应结果。


为什么在项目里用它?


在公司里,我们有些项目有如下的特点:


  • 不是基于 Spring 的项目

  • 需要经常访问大量的第三方 Http 服务

  • 访问 Http 服务的模型通常是异步回调


以前的时候,我们访问 Http 服务,都是直接用的 HttpClient。


可是吧,HttpClient 用起来实在够麻烦的。主要也存在两个问题:


1.请求参数和 URL 拼接实在繁琐


请求参数和 URL 拼接实在是太烦人了。你想想,每调用一个接口,就需要自己去拼接参数,有的 URL,甚至十几二十个参数需要拼接。


拼接这事儿简单、枯燥、重复,还没有技术含量,但是工作量却不小,时间真的算浪费了。


URIBuilder uriBuilder = new URIBuilder(uriBase);
uriBuilder.setParameter("a", "valuea");
uriBuilder.setParameter("b", "valueb");
uriBuilder.setParameter("c", "valuec");
uriBuilder.setParameter("d", "valued");
uriBuilder.setParameter("e", "valuee");
uriBuilder.setParameter("f", "valuef");
uriBuilder.setParameter("g", "valueg");
uriBuilder.setParameter("h", "valueh");
uriBuilder.setParameter("i", "valuei");
...


2.异步回调需要自己搞


异步回调这种模型不好处理,主要就是需要自己去搞线程池,还要对线程池管理,还要考虑出错的重试之类的容错问题,实在麻烦。


所以,我们就需要一套能用法简单,不用我们一直搞拼接参数,自己搞线程管理就能完成对第三方 Http 服务访问的库。


其实我们也想过用 Feign 这套框架的。但是,这套东西和 Spring 绑定的太紧了。如果离开 Spring,它的一些功能就没法简单的通过注解直接使用,必须自己写代码调用。


而且,Feign 要实现异步回调方式使用,尤其在协程方面,还是需要自己开发。


这时候,Retrofit 就跳进了我们的选型里。


Retrofit 的模型里,异步回调模型它支持的很好,我们只需要实现一个 Callable 就够了。


并且最清爽的是,它和 Spring 没什么关系。


Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://xxx.example.com/")
        .build();

public interface BlogService {
    @GET("blog/{id}")
    Call<ResponseBody> getBlog(@Path("id") int id);
}

BlogService service = retrofit.create(BlogService.class);

Call<ResponseBody> call = service.getBlog(2);
// 用法和OkHttp的call如出一辙,
// 回调
call.enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        try {
            System.out.println(response.body().string());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        t.printStackTrace();
    }
});


你看,只需要写上这些代码,我们就不需要操心恼人的 Url 拼接和异步回调的管理问题了。全交给了 Retrofit,着实推荐。


代码库地址:https://github.com/square/retrofit


 

3

Faker



Faker 是干什么的?


Faker 是专门用来产生各种假数据的辅助工具库。


比如,你想产生个和真实数据一样的有姓名、有地址的用户。


为什么在项目里用它?


我们经常需要造数据去测试,但是,如果没有工具辅助,我们自己造数据,存在一些问题。


1.数据是需要格式的


很多关于项目,都需要一些格式上尽量能模仿真实世界的数据。


比如,国内用户的姓名,大部分都是两字、三字的姓名,叫王大,就不能叫 王da 这种。













在Java中,工具类定义了一组公共方法,本文将介绍Java中使用最频繁及最通用的Java工具类。以下工具类、方法按使用流行度排名,下面随动力节点java培训学校小编一起来看看15个超级实用的java开发常用的工具类。

java开发常用的工具类

1、 org.apache.commons.io.IOUtils

介绍

WireMock是用于基于HTTP的API的模拟服务器。 有些人可能会将其视为服务虚拟化工具或模拟服务器。 它使您能够存根所需的API或其他外部依赖项,以加快本地开发速度。 它支持测试真实API无法可靠产生的极端情况和失败模式。 在模拟单元测试和集成测试中的外部依赖关系时,它也很有用。 它与jUnit具有出色的集成。


添加Wiremock依赖性

首先,您将要添加Wiremock依赖项。 您可以下载常规依赖项或包含所有依赖项的胖JAR独立版本。 我们将在此处使用标准依赖项。 将以下依赖项添加到您的build.gradle中


build.gradle


dependencies {

    testCompile(‘com.github.tomakehurst:wiremock:2.1.12’)

}

添加Wiremock单元测试

这是完整的单元测试,可用于测试与Wiremock的集成。 该单元测试使用jUnit4规则启动端口8089上的Wiremock服务器,并在每次测试后将其关闭。 我们使用stubFor方法来定义模拟的终点和响应。 我们使用Spring RestTemplate创建一个到模拟服务器的HTTP请求并捕获结果。


WiremockTests.java


public class WiremockTests {

 

    RestTemplate restTemplate;

    ResponseEntity response;

 

    @Rule

    public WireMockRule wireMockRule = new WireMockRule(wireMockConfig().port(8089).httpsPort(8443));

 

    @Before

    public void setup() throws Exception {

        restTemplate = new RestTemplate();

        response = null;

    }

 

    @Test

    public void givenWireMockAdminEndpoint_whenGetWithoutParams_thenVerifyRequest() {

 

        RestTemplate restTemplate = new RestTemplate();

 

        response = restTemplate.getForEntity(“http://localhost:8089/__admin&#8221;, String.class);

 

        assertThat(“Verify Response Body”, response.getBody().contains(“mappings”));

        assertThat(“Verify Status Code”, response.getStatusCode().equals(HttpStatus.OK));

    }

 

    @Test

    public void givenWireMockEndpoint_whenGetWithoutParams_thenVerifyRequest() {

        stubFor(get(urlEqualTo(“/api/resource/”))

                .willReturn(aResponse()

                        .withStatus(HttpStatus.OK.value())

                        .withHeader(“Content-Type”, TEXT_PLAIN_VALUE)

                        .withBody(“test”)));

 

        response = restTemplate.getForEntity(“http://localhost:8089/api/resource/&#8221;, String.class);

 

        assertThat(“Verify Response Body”, response.getBody().contains(“test”));

        assertThat(“Verify Status Code”, response.getStatusCode().equals(HttpStatus.OK));

 

        verify(getRequestedFor(urlMatching(“/api/resource/.*”)));

    }

}

您可以运行此测试,如果完成,则您已成功将Wiremock集成到应用程序中。


深入到单元测试

这是一些静态导入,您可以在测试中使用这些静态导入来提高可读性和简洁性。


WiremockTests.java


import static com.github.tomakehurst.wiremock.client.WireMock.*;

import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;

import static org.hamcrest.MatcherAssert.assertThat;

import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE;

jUnit4规则


这个jUnit4 @rule将自动管理Wiremock服务器的生命周期以及每个测试用例的启动和关闭Wiremock。 您也可以使用setup()和teardown()方法来实现,但是jUnit4规则更加简洁明了。


WiremockTests.java


@Rule

    public WireMockRule wireMockRule = new WireMockRule(wireMockConfig().port(8089).httpsPort(8443));

残端和响应

此代码使用stubFor()方法(已静态导入)定义端点, / api / resource /和纯文本响应主体“ test”。您也可以使用此方法通过更改Content-返回JSON或XML响应。类型和响应主体


WiremockTests.java


stubFor(get(urlEqualTo(“/api/resource/”))

                .willReturn(aResponse()

                        .withStatus(HttpStatus.OK.value())

                        .withHeader(“Content-Type”, TEXT_PLAIN_VALUE)

                        .withBody(“test”)));

春天RestTemplate

我们使用Spring RestTemplate类对http:// localhost:8089 / api / resource /执行GET HTTP请求,以打到Wiremock服务器的存根端点。 在这种情况下,我们期望一个String.class实体响应,因为那是我们在stubFor()方法中定义的。 如果您配置了POJO对象,则需要定义一个POJO对象以从存根方法捕获JSON响应。 我们在ResponseEntity对象中捕获响应,该对象捕获响应主体,标头和状态代码以及有关请求的其他信息。


WiremockTests.java


response = restTemplate.getForEntity(“http://localhost:8089/api/resource/&#8221;, String.class);

手动启动和停止Wiremock服务器

您可以手动启动和停止Wiremock服务器,而无需使用jUnit4规则来管理生命周期。 当您的应用程序启动时,您可能希望这样做是一种引导方法。


ServiceClass.java


WireMockServer wireMockServer = new WireMockServer(wireMockConfig().port(8089)); //No-args constructor will start on port 8080, no HTTPS

wireMockServer.start();

 

WireMock.reset();

 

wireMockServer.stop();

结论

现在,您的项目中已安装Wiremock

closeQuietly:关闭一个IO流、socket、或者selector且不抛出异常,通常放在finally块

toString:转换IO流、 Uri、 byte[]为String

copy:IO流数据复制,从输入流写到输出流中,最大支持2GB

toByteArray:从输入流、URI获取byte[]

write:把字节. 字符等写入输出流

toInputStream:把字符转换为输入流

readLines:从输入流中读取多行数据,返回List

常用注解

@Mapper 只有在接口加上这个注解, MapStruct 才会去实现该接口

    @Mapper 里有个 componentModel 属性,主要是指定实现类的类型,一般用到两个

    uses:引入class工具类,使用工具类中的类型转换方法

    default:默认,可以通过 Mappers.getMapper(Class) 方式获取实例对象

   

RetrofitUtils

RxJava + Retrofit封装,包含对相同格式请求数据、相同格式返回数据处理,显示Material Design加载dialog,文件上传下载进度展示、全局异常捕捉。


Preview


演示中upload.png为上传图片源文件。


Describe

实现功能:


1、对于相同格式请求数据统一处理;


2、对于相同返回结果进行预处理;


3、显示加载dialog;


4、支持文件带进度上传下载。


主要几个类作用:


1、 RetrofitUtils.java 主要是数据post、get等请求工具类,所有请求调用doHttp()方法。


2、 RetrofitFileUtils.java 主要用于文件下载工具类,包含uploadFile()文件上传、downloadFile()文件下载两个方法。


3、 BaseFileDownload.java 文件下载请求基类,文件下载请求实体类需继承该类实现内部方法。


4、 BaseFileUpload.java 文件上传请求基类,文件上传请求实体类需继承该类实现内部方法。


5、 HttpResultFunc.java 基本数据请求基类,数据请求实体类需继承该类实现内部方法。


6、 RetrofitService.java 主要用于管理请求接口,设置请求地址等。如需修改类名请在调用地方相应进行修改。

spring:在接口的实现类上自动添加注解 @Component,可通过 @Autowired 方式注入

@Mapping:属性映射,若源对象属性与目标对象名字一致,会自动映射对应属性

    source:源属性

    target:目标属性

    dateFormat:String 到 Date 日期之间相互转换,通过 SimpleDateFormat,该值为 SimpleDateFormat              的日期格式

    ignore: 忽略这个字段

    expression:引入Java表达式,获取数据复制给target

@Mappings:配置多个@Mapping

@MappingTarget 用于更新已有对象

@InheritConfiguration 用于继承配置


Spring 注入的方式

// 默认的方式

PersonConverter INSTANCE = Mappers.getMapper(PersonConverter.class);


@Mapper(componentModel=”spring”)


基础用法

一对一转换

1.两个对象属性名相同,类型可能不同:可以直接写转换方法,不用写映射关系


@Mapper

public interface PersonConverter {

//注入spring

    PersonConverter INSTANCE = Mappers.getMapper(PersonConverter.class);


Dto entity2Dto(Entity entity)

}



2.两个对象字段名不同:只需要把属性名不同的字段进行映射,相同的部分不需要处理,如果有不想要映射的属性,可使用ignore


@Mapper(componentModel=”spring”)

public interface PersonConverter {

    //映射方法

    @Mappings({

        @Mapping(source = “birthday”, target = “birth”),

        @Mapping(source = “birthday”, target = “birthDateFormat”, dateFormat = “yyyy-MM-dd HH:mm:ss”),

        @Mapping(target = “birthExpressionFormat”, expression = “java(org.apache.commons.lang3.time.DateFormatUtils.format(person.getBirthday(),”yyyy-MM-dd HH:mm:ss”))”),

        @Mapping(source = “user.age”, target = “age”),

        @Mapping(target = “email”, ignore = true)

    })

    PersonDTO domain2dto(Person person);


    List<PersonDTO> domain2dto(List<Person> people);

}



多对一转换

转换是对应的属性,数据类型相同


@Mapper

public interface ItemConverter {

    ItemConverter INSTANCE = Mappers.getMapper(ItemConverter.class);


    @Mappings({

            @Mapping(source = “sku.id”,target = “skuId”),

            @Mapping(source = “sku.code”,target = “skuCode”),

            @Mapping(source = “sku.price”,target = “skuPrice”),

            @Mapping(source = “item.id”,target = “itemId”),

            @Mapping(source = “item.title”,target = “itemName”)

    })

    SkuDTO domain2dto(Item item, Sku sku);

}



有时候, 我们不是想返回一个新的 Bean 对象, 而是希望更新传入对象的一些属性。这个在实际的时候也会经常使用到


@Mapper

public interface AddressMapper {


    AddressMapper INSTANCE = Mappers.getMapper(AddressMapper.class);


/**

     * Person->DeliveryAddress, 缺失地址信息

     * @param person

     * @return

     */

    DeliveryAddress person2deliveryAddress(Person person);


    /**

     * 更新, 使用 Address 来补全 DeliveryAddress 信息。 注意注解 @MappingTarget

     * @param address

     * @param deliveryAddress

     */

    void updateDeliveryAddressFromAddress(Address address,

                                          @MappingTarget DeliveryAddress deliveryAddress);

}


一些好用的隐式类型转换:everything-String


@Mapper(componentModel=”spring”)

public interface CarMapper {

//从int到String的转换

    @Mapping(source = “price”, numberFormat = “$#.00”)

    CarDto carToCarDto(Car car);


    @IterableMapping(numberFormat = “$#.00”)

    List<String> prices(List<Integer> prices);

}


从BigDecimal到String的转换

@Mapping(source = “power”, numberFormat = “#.##E0”)

    CarDto carToCarDto(Car car);


从日期到字符串的转换

@Mapping(source = “manufacturingDate”, dateFormat = “dd.MM.yyyy”)

    CarDto carToCarDto(Car car);


    @IterableMapping(dateFormat = “dd.MM.yyyy”)

    List<String> stringListToDateList(List<Date> dates);



嵌套bean映射

@Mapper

public interface FishTankMapper {


    @Mapping(target = “fish.kind”, source = “fish.type”)

    @Mapping(target = “fish.name”, ignore = true)

    @Mapping(target = “ornament”, source = “interior.ornament”)

    @Mapping(target = “material.materialType”, source = “material”)

    @Mapping(target = “quality.report.organisation.name”, source = “quality.report.organisationName”)

    FishTankDto map( FishTank source );

}



默认值和常量的引入

分别可以通过@Mapping的defaultValue和constant属性指定,当source对象的属性值为null时,如果有指定defaultValue将注入defaultValue的设定的值。constant属性通用用于给target属性注入常量值。


@Mapper

public interface SourceTargetMapper {


    SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class );


    @Mapping(target = “stringProperty”, source = “stringProp”, defaultValue = “undefined”)

    @Mapping(target = “longProperty”, source = “longProp”, defaultValue = “-1”)

    @Mapping(target = “stringConstant”, constant = “Constant Value”)

    @Mapping(target = “integerConstant”, constant = “14”)

    @Mapping(target = “longWrapperConstant”, constant = “3001”)

    @Mapping(target = “dateConstant”, dateFormat = “dd-MM-yyyy”, constant = “09-01-2014”)

    @Mapping(target = “stringListConstants”, constant = “jack-jill-tom”)

    Target sourceToTarget(Source s);

}



外部转换方法的引入

转换类


@Mapper(componentModel=”spring”,uses = StringListMapper.class)

public interface SourceTargetMapper {

    @Mappings({

            @Mapping(source = “modifyTime”,target = “modifyTime”,qualifiedByName = “LocalDateTime2String)        

    })

    SkuDto entity2Dto(Entity entity);

}



引入的外部方法类


@Component

@Named(”TypeCoversionMapping”)

public class TypeCoversionMapping {

@Named(“String2Double”)

public Double StringentDouble (String value) {

if(StringUtils.isBlank(value)|| value.equals(”“)){

Return 0.0;

}

return new Double(value);

}

}

copyLarge:同copy,支持2GB以上数据的复制

lineIterator:从输入流返回一个迭代器,根据参数要求读取的数据量,全部读取,如果数据不够,则失败

2、 org.apache.commons.io.FileUtils

deleteDirectory:删除文件夹

readFileToString:以字符形式读取文件内容

deleteQueitly:删除文件或文件夹且不会抛出异常

copyFile:复制文件

writeStringToFile:把字符写到目标文件,如果文件不存在,则创建

forceMkdir:强制创建文件夹,如果该文件夹父级目录不存在,则创建父级

write:把字符写到指定文件中

listFiles:列举某个目录下的文件(根据过滤器)

copyDirectory:复制文件夹

forceDelete:强制删除文件

3、org.apache.commons.lang.StringUtils

isBlank:字符串是否为空 (trim后判断)

isEmpty:字符串是否为空 (不trim并判断)

equals:字符串是否相等

join:合并数组为单一字符串,可传分隔符

split:分割字符串

EMPTY:返回空字符串

trimToNull:trim后为空字符串则转换为null

replace:替换字符串

4、org.apache.http.util.EntityUtils

toString:把Entity转换为字符串

consume:确保Entity中的内容全部被消费。可以看到源码里又一次消费了Entity的内容,假如用户没有消费,那调用Entity时候将会把它消费掉

toByteArray:把Entity转换为字节流

consumeQuietly:和consume一样,但不抛异常

getContentCharset:获取内容的编码

5、 org.apache.commons.lang3.StringUtils

isBlank:字符串是否为空 (trim后判断)

isEmpty:字符串是否为空 (不trim并判断)

equals:字符串是否相等

join:合并数组为单一字符串,可传分隔符

split:分割字符串

EMPTY:返回空字符串

replace:替换字符串

capitalize:首字符大写

6、org.apache.commons.io.FilenameUtils

getExtension:返回文件后缀名

getBaseName:返回文件名,不包含后缀名

getName:返回文件全名

concat:按命令行风格组合文件路径(详见方法注释)

removeExtension:删除后缀名

normalize:使路径正常化

wildcardMatch:匹配通配符

seperatorToUnix:路径分隔符改成unix系统格式的,即/

getFullPath:获取文件路径,不包括文件名

isExtension:检查文件后缀名是不是传入参数(List)中的一个

7、 org.springframework.util.StringUtils

hasText:检查字符串中是否包含文本

hasLength:检测字符串是否长度大于0

isEmpty:检测字符串是否为空(若传入为对象,则判断对象是否为null)

commaDelimitedStringToArray:逗号分隔的String转换为数组

collectionToDelimitedString:把集合转为CSV格式字符串

replace 替换字符串

delimitedListToStringArray:相当于split

uncapitalize:首字母小写

collectionToDelimitedCommaString:把集合转为CSV格式字符串

tokenizeToStringArray:和split基本一样,但能自动去掉空白的单词

8、org.apache.commons.lang.ArrayUtils

contains:是否包含某字符串

addAll:添加整个数组

clone:克隆一个数组

isEmpty:是否空数组

add:向数组添加元素

subarray:截取数组

indexOf:查找某个元素的下标

isEquals:比较数组是否相等

toObject:基础类型数据数组转换为对应的Object数组

9、 org.apache.http.client.utils.URLEncodedUtils

format:格式化参数,返回一个HTTP POST或者HTTP PUT可用application/x-www-form-urlencoded字符串

parse:把String或者URI等转换为List

10、 org.apache.commons.codec.digest.DigestUtils

md5Hex:MD5加密,返回32位字符串

sha1Hex:SHA-1加密

sha256Hex:SHA-256加密

sha512Hex:SHA-512加密

md5:MD5加密,返回16位字符串

11、 org.apache.commons.collections.CollectionUtils

isEmpty:是否为空

select:根据条件筛选集合元素

transform:根据指定方法处理集合元素,类似List的map()

filter:过滤元素,雷瑟List的filter()

find:基本和select一样

collect:和transform 差不多一样,但是返回新数组

forAllDo:调用每个元素的指定方法

isEqualCollection:判断两个集合是否一致

12、 org.apache.commons.lang3.ArrayUtils

contains:是否包含某个字符串

addAll:添加整个数组

clone:克隆一个数组

isEmpty:是否空数组

add:向数组添加元素

subarray:截取数组

indexOf:查找某个元素的下标

isEquals:比较数组是否相等

toObject:基础类型数据数组转换为对应的Object数组

13、org.apache.commons.beanutils.PropertyUtils

getProperty:获取对象属性值

setProperty:设置对象属性值

getPropertyDiscriptor:获取属性描述器

isReadable:检查属性是否可访问

copyProperties:复制属性值,从一个对象到另一个对象

getPropertyDiscriptors:获取所有属性描述器

isWriteable:检查属性是否可写

getPropertyType:获取对象属性类型

14、 org.apache.commons.lang3.StringEscapeUtils

unescapeHtml4:转义html

escapeHtml4:反转义html

escapeXml:转义xml

unescapeXml:反转义xml

escapeJava:转义unicode编码

escapeEcmaScript:转义EcmaScript字符

unescapeJava:反转义unicode编码

escapeJson:转义json字符

escapeXml10:转义Xml10

这个现在已经废弃了,建议使用commons-text包里面的方法。

15、 org.apache.commons.beanutils.BeanUtils

copyPeoperties:复制属性值,从一个对象到另一个对象

getProperty:获取对象属性值

setProperty:设置对象属性值

populate:根据Map给属性复制

copyPeoperty:复制单个值,从一个对象到另一个对象

cloneBean:克隆bean实例

1 . Apache相关IOUtils类

closeQuietly:关闭一个IO流、socket、或者selector且不抛出异常,通常放在finally块

toString:转换IO流、 Uri、 byte[]为String

copy:IO流数据复制,从输入流写到输出流中,最大支持2GB

toByteArray:从输入流、URI获取byte[]

write:把字节. 字符等写入输出流

toInputStream:把字符转换为输入流

readLines:从输入流中读取多行数据,返回List<String>

copyLarge:同copy,支持2GB以上数据的复制

lineIterator:从输入流返回一个迭代器,根据参数要求读取的数据量,全部读取,如果数据不够,则失败

2 . Apache相关FileUtils

deleteDirectory:删除文件夹

readFileToString:以字符形式读取文件内容

deleteQueitly:删除文件或文件夹且不会抛出异常

copyFile:复制文件

writeStringToFile:把字符写到目标文件,如果文件不存在,则创建

forceMkdir:强制创建文件夹,如果该文件夹父级目录不存在,则创建父级

write:把字符写到指定文件中

listFiles:列举某个目录下的文件(根据过滤器)

copyDirectory:复制文件夹

forceDelete:强制删除文件

3. Apache相关org.apache.commons.lang.StringUtils

isBlank:字符串是否为空 (trim后判断)

isEmpty:字符串是否为空 (不trim并判断)

equals:字符串是否相等

join:合并数组为单一字符串,可传分隔符

split:分割字符串

EMPTY:返回空字符串

trimToNull:trim后为空字符串则转换为null

replace:替换字符串

4.Apache 相关EntityUtils

toString:把Entity转换为字符串

consume:确保Entity中的内容全部被消费。可以看到源码里又一次消费了Entity的内容,假如用户没有消费,那调用Entity时候将会把它消费掉

toByteArray:把Entity转换为字节流

consumeQuietly:和consume一样,但不抛异常

getContentCharset:获取内容的编码

5 Apache相关org.apache.commons.lang3.StringUtils

isBlank:字符串是否为空 (trim后判断)

isEmpty:字符串是否为空 (不trim并判断)

equals:字符串是否相等

join:合并数组为单一字符串,可传分隔符

split:分割字符串

EMPTY:返回空字符串

replace:替换字符串

capitalize:首字符大写

6. Apache 相关FilenameUtils

  getExtension:返回文件后缀名

getBaseName:返回文件名,不包含后缀名

getName:返回文件全名

concat:按命令行风格组合文件路径(详见方法注释)

removeExtension:删除后缀名

normalize:使路径正常化

wildcardMatch:匹配通配符

seperatorToUnix:路径分隔符改成unix系统格式的,即/

getFullPath:获取文件路径,不包括文件名

isExtension:检查文件后缀名是不是传入参数(List<String>)中的一个

7.Spring相关的org.springframework.util.StringUtils

hasText:检查字符串中是否包含文本

hasLength:检测字符串是否长度大于0

isEmpty:检测字符串是否为空(若传入为对象,则判断对象是否为null)

commaDelimitedStringToArray:逗号分隔的String转换为数组

collectionToDelimitedString:把集合转为CSV格式字符串

replace 替换字符串

delimitedListToStringArray:相当于split

uncapitalize:首字母小写

collectionToDelimitedCommaString:把集合转为CSV格式字符串

tokenizeToStringArray:和split基本一样,但能自动去掉空白的单词

8.Apache相关的 ArrayUtils

contains:是否包含某字符串

addAll:添加整个数组

clone:克隆一个数组

isEmpty:是否空数组

add:向数组添加元素

subarray:截取数组

indexOf:查找某个元素的下标

isEquals:比较数组是否相等

toObject:基础类型数据数组转换为对应的Object数组

9. Apache 相关的CollectionUtils

isEmpty:是否为空

select:根据条件筛选集合元素

transform:根据指定方法处理集合元素,类似List的map()

filter:过滤元素,雷瑟List的filter()

find:基本和select一样

collect:和transform 差不多一样,但是返回新数组

forAllDo:调用每个元素的指定方法

isEqualCollection:判断两个集合是否一致

10 . Apache相关的PropertyUtils

getProperty:获取对象属性值

setProperty:设置对象属性值

getPropertyDiscriptor:获取属性描述器

isReadable:检查属性是否可访问

copyProperties:复制属性值,从一个对象到另一个对象

getPropertyDiscriptors:获取所有属性描述器

isWriteable:检查属性是否可写

getPropertyType:获取对象属性类型

11. Apache相关的StringEscapeUtils

unescapeHtml4:转义html

escapeHtml4:反转义html

escapeXml:转义xml

unescapeXml:反转义xml

escapeJava:转义unicode编码

escapeEcmaScript:转义EcmaScript字符

unescapeJava:反转义unicode编码

escapeJson:转义json字符

escapeXml10:转义Xml10

12.Apache相关的PeopertiesUtils

copyPeoperties:复制属性值,从一个对象到另一个对象

getProperty:获取对象属性值

setProperty:设置对象属性值

populate:根据Map给属性复制

copyPeoperty:复制单个值,从一个对象到另一个对象

cloneBean:克隆bean实例

13. 编码神器 lombok


@Setter 注解在类或字段,注解在类时为所有字段生成setter方法,注解在字段上时只为该字段生成setter方法。

@Getter 使用方法同上,区别在于生成的是getter方法。

@ToString 注解在类,添加toString方法。

@EqualsAndHashCode 注解在类,生成hashCode和equals方法。

@NoArgsConstructor 注解在类,生成无参的构造方法。

@RequiredArgsConstructor 注解在类,为类中需要特殊处理的字段生成构造方法,比如final和被@NonNull注解的字段。

@AllArgsConstructor 注解在类,生成包含类中所有字段的构造方法。

@Data 注解在类,生成setter/getter、equals、canEqual、hashCode、toString方法,如为final属性,则不会为该属性生成setter方法。

@Slf4j 注解在类,生成log变量,严格意义来说是常量。private static final Logger log = LoggerFactory.getLogger(UserController.class);



作者:PrimaryKeyEnoch

链接:https://www.jianshu.com/p/1a9ae5c6584a

来源:简书

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。



又比如,国内的地址是 xx市xx区xx街道xx号 这种的,就不能胡写一个几个没意义的汉字来当地址。


用贴近真实格式的数据,一来可以测出我们对用户的数据解析是否存在问题,二来可以测出数据库内的字段长度是否没问题。


所以,格式对产生出可靠地测试结果,是很重要的。


2.数据的量大


有的测试数据量都是上十万、百万的,这些量级的数据并不是只会产生一次。


甚至几乎每个项目,每个项目的每次测试,可能都会需要新的数据,需要能源源不断地产生出来。


更甚至的是,有时候还想要根据我们的要求,在恰当的时候,产生某种关系的数据,或者以某些特定频率产生。比如,两秒后产生一次数据;比如,产生一批姓王的数据。


以上这三种要求综合起来,要是我们自己造数据,那真是要了命了。


与其自己开发,不如用现成的——Faker 库被我们找到了。


Faker库可以创造三百多种数据,而且还很容易对它进行扩展改造,去产生更多的贴合我们需求的数据。


Faker faker = new Faker();

String name = faker.name().fullName(); // Miss Samanta Schmidt
String firstName = faker.name().firstName(); // Emory
String lastName = faker.name().lastName(); // Barton

String streetAddress = faker.address().streetAddress(); // 60018 Sawayn Brooks Suite 449



几行代码,我们需要的一个用户就有了。


用上 Faker 后,小伙伴们纷纷表示“有更多的时间摸鱼了”。


代码库地址:https://github.com/DiUS/java-faker


 

4

Wiremock



Wiremock 是干什么的?


Wiremock 是一个可以模拟服务的测试框架。


比如,你想测试访问阿里的支付相关接口的代码逻辑,就可以用它来做测试。


为什么在项目里用它?


比如,我们需要调用银行接口去做资金业务,调用微信接口去做微信登录……这些调用第三方服务的测试存在一个问题:


即太过依赖对方的平台。假如对方平台限制了一些 IP,或者限制了访问频率,又或者就是服务出现了维护,都会影响我们自身的功能测试。


为了解决上述问题,在之前,我们需要自己写代码模仿第三方的接口,等我们自己全部测试没问题了,再去和第三方联调。对于这种模拟出来的接口,我们称作挡板。


可是,这种方式是个苦活,没人愿意干。因为每接入一个第三方,可能都需要做挡板。辛苦做个挡板,就是单纯为了测试。如果第三方的接口做了改造,你这边还得跟着改。


大家可以想想,换成你自己,你愿意做这么件事儿吗?


这时候,Wiremock 的价值就体现出来了。有了 Wiremock,挡板这种东西就再也不存在了,直接在单元测试里模拟测试即可,像这样:


WireMock.stubFor(get(urlPathMatching("/aliyun/.*"))
                .willReturn(aResponse()
                        .withStatus(200)
                        .withHeader("Content-Type", APPLICATION_JSON)
                        .withBody(""testing-library": "WireMock"")));

CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet request = new HttpGet(String.format("http://localhost:%s/aliyun/wiremock", port));
HttpResponse httpResponse = httpClient.execute(request);
String stringResponse = convertHttpResponseToString(httpResponse);

verify(getRequestedFor(urlEqualTo(ALIYUN_WIREMOCK_PATH)));
assertEquals(200, httpResponse.getStatusLine().getStatusCode());
assertEquals(APPLICATION_JSON, httpResponse.getFirstHeader("Content-Type").getValue());
assertEquals(""testing-library": "WireMock"", stringResponse);


代码库地址:https://github.com/wiremock/wiremock



5

结语


虽然 Java 有很多遭人诟病的地方,但是 Java 最重要的优点之一,就是它的生态,有其琳琅满目的各种工具类库。


希望大家都“懒”一点,不要埋头去做无效的苦干,不要自己造轮子,你要相信:


你遇到的问题,基本已经有很多人遇到过了,而且已经被牛人给解决了,把轮子都给你造好了。


PS:防止找不到本篇文章,可以收藏点赞,方便翻阅查找哦。


往期推荐



百人被限2天离职?字节跳动承认裁员!

Spring Boot 进行优雅的字段校验,写得太好了!

SpringBoot+Kafka+ELK 完成海量日志收集(超详细)!

扔掉 Postman,一个工具全部搞定,真香!

Java 程序员利器:lombok神工具

不得不说,DataGrip 太吊了!!



ITZOO版权所有丨如未注明 , 均为原创丨转载请注明来自IT乐园 ->推荐几个开源类库,效率贼高,学会使用远离996!
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址