0%

简述

在拼接字符串的过程中有时需要拼接分隔符, 如果你只会用 + 或者 StringBuilder/ StringBuffer 拼接字符串?那你就 OUT 了,建议使用 Java 8 中的这款字符串拼接神器:StringJoiner,你值得拥有。

代码片断

原来的字符串拼接代码

1
2
3
4
5
6
7
8
String logStr="\n---------------------------------------------------------------------" +
"\n请求ip:" + clientIp + ":" + clientPort +
"\n请求url:"+clientUrl+
"\n请求方式:"+requestMethod+
"\n执行时长:" + stopwatch.elapsed(TimeUnit.MILLISECONDS) + "ms" +
"\n入参:" + (args == null ? "[]" : Arrays.toString(args)) +
"\n出参:" + (result == null ? "[]" : objectMapper.writeValueAsString(result))+
"\n----------------------------------------------------------------------";

使用 StringJoiner 之后

1
2
3
4
5
6
7
8
9
10
11
StringJoiner stringJoiner = new StringJoiner("\n");
stringJoiner.add("");
stringJoiner.add("---------------------------------------------------------------------");
stringJoiner.add("请求ip:" + clientIp + ":" + clientPort);
stringJoiner.add("请求url:"+clientUrl);
stringJoiner.add("请求方式:"+requestMethod);
stringJoiner.add("执行时长:"+stopwatch.elapsed(TimeUnit.MILLISECONDS) + "ms");
stringJoiner.add("入参:" + (args == null ? "[]" : Arrays.toString(args)));
stringJoiner.add("出参:" + (result == null ? "[]" : objectMapper.writeValueAsString(result)));
stringJoiner.add("----------------------------------------------------------------------");
String logStr=stringJoiner.toString();

不需要自己处理分隔符了,是不是轻闲了不少?

进一步研究源码就会发现,其实际上是对 StringBuilder 做了进一步的封装

stringJoiner-01


微信端的朋友也可关注我的公众号

qrcode-12cm

背景说明

如果你的工程中使用maven, 你是否亲自处理过jar包冲突?

jar包冲突一般是间接依赖引起的,举个例子,假如你在项目中使用了2个jar包,分别是A和B, 现在A依赖C, B也依赖C, 但是A依赖的C的版本是1.0, B依赖的C的版本是2.0。

这时候你的项目中的C就会有2个不同的版本,这时maven会依据自己的原则,来决定使用哪个版本的jar包, 而另一个无用的的jar包则未被使用,这就是所谓的依赖冲突。

在大多数情况下,依赖冲突并不会对系统造成什么异常,但是在某些情况下,有可能会出现找不到类的异常, 因此理解冲突导致的原因并且快速定位到冲突源,是每个程序员的必修课。

这里列出一些常见的由于jar包冲突导致的异常

  • 程序抛出java.lang.ClassNotFoundException异常
  • 程序抛出java.lang.NoSuchMethodError异常
  • 程序抛出java.lang.NoClassDefFoundError异常
  • 程序抛出java.lang.LinkageError异常等

这些是能够直观呈现的,当然还有隐性的异常,比如程序执行结果与预期不符等。

原理介绍

上面介绍了什么是jar包冲突以及jar包冲突有可能产生的错误, 本节讲一些maven jar包管理原则,了解这些背景知识会帮助我们解决jar包冲突。

依赖传递

当在maven项目中引入A依赖,A依赖通常又会引入B的jar包,B可能还会引入C的jar包。这样,当你在pom.xml文件中添加了A依赖,maven会自动帮你把所有相关的依赖都添加进来. 这就叫做依赖传递. transitive dependencies

maven引入依赖传递机制,一方面大大简化和方便了依赖声明,另一方面,大部分情况下我们只需要关心项目的直接依赖是什么,而不用考虑这些间接依赖。但有时候,当依赖传递造成问题的时候,我们就需要清楚地知道该传递性依赖是从哪条依赖路径引入的。

依赖调解

上一节讲了maven的依赖传递, 其是jar包冲突产生的原因, 而当maven中出现依赖冲突时,其又是如何解决的呢? 这就涉及到依赖调解,maven中有2条处理依赖的原则

  1. 第一原则:最短路径优先原则
  2. 第二原则:最先声明优先原则

最短路径优先原则

主要根据依赖的路径长短来决定引入哪个依赖(两个冲突的依赖)

示例:

maven-helper-27267

项目中同时引入了A和B两个依赖,它们都间接引入了Z依赖,但由于B的依赖链路比较短,因此最终生效的是Z(20.0)版本。这就是最短路径优先原则。

此时如果Z的21.0版本和20.0版本区别较大,那么就会发生jar包冲突的表现

最先声明优先原则

如果两个依赖的路径一样,最短路径优先原则是无法进行判断的,此时需要使用最先声明优先原则,也就是说,谁的声明在前则优先选择谁。

示例:

maven-helper-20082

A和B最终都依赖Z,此时A的声明(pom中引入的顺序)优先于B,则针对冲突的Z会优先引入Z(21.0)。

如果Z(21.0)向下兼容Z(20.0),则不会出现Jar包冲突问题。但如果将B声明放前面,则有可能会发生Jar包冲突

工程问题总结

上面说的都是原理,可能大家更关心的是如下2个问题

  1. 我的项目中到底有没有依赖冲突?
  2. 冲突是从哪里引入的?

解决思路

方法1 maven-dependency-plugin 插件

maven-dependency-plugin插件可以打印依赖树,如果加上-Dverbose参数可以查看更详细的日志,当然也包括冲突的jar包

1
mvn dependency:tree -Dverbose

但是很少有人告诉你该插件从3.0开始不再支持 -Dverbose 参数,所以即使加上该参数其也不会输出冲突的jar包,如果使用该参数会看到如下的日志

1
Verbose not supported since maven-dependency-plugin 3.0

所以正确的命令是指定一个支持-Dverbose参数的版本,例如2.10版本

1
mvn org.apache.maven.plugins:maven-dependency-plugin:2.10:tree -Dverbose > tree.txt

方法2 IDEA 插件 Maven Helper

在这里向大家推荐IDEA 解决Maven依赖冲突的高能神器 Maven Helper。

maven-helper-7082

当你安装完该插件后,打开pom.xml 会看到一个 Dependency Analyzer 的标签页

maven-helper-7069

其有三大功能,而且还提供搜索功能方便使用

  1. Conflicts(查看冲突):可以很方便的看出哪些jar包冲突,其冲突是从哪些jar包引入的, 最终用的是哪个版本
  2. All Dependencies as List(列表形式查看所有依赖)
  3. All Dependencies as Tree(树形式查看所有依赖)

实践案例

案例1 log4j漏洞爆发后快速定位log4j-2.X的引入源头

2021年12月7日 log4j爆发了史诗级漏洞,log4j这个再平常不过的jar包,如今却变成了洪水猛兽,只要工程中有log4j-2.X相关版本的jar包,都要立即清除,当时需要确认工程中是否引入了log4j-2.X版本, 我们确实没有在工程中显式引入log4j-2.X,但是最终的lib中确实有log4j-2.X相关的jar包。

maven-helper-26949

我们希望能快速定位到是哪个依赖间接引入了log4j-2.X, 当时就借助了Maven Helper插件,很快定位到问题。

如下可以看到是mybatis-spring-boot-starter这个依赖间接引入了log4j-2.X 相关的jar包

maven-helper-24139

案例2: 引入 EasyExcel 引发 asm依赖冲突

项目中有excel导出功能,所以引入了EasyExcel, 当时希望将导出excel的功能封装到一个jar包里,但是在使用的过程中有报错,后来定位到问题与依赖冲突有关系。

当时就借助Maven Helper插件, 可以看到spring-boot-starter-test 依赖asm 5.0.3, blue-web中通过easyexcel依赖asm 7.1, 而最终使用的asm的版本是通过spring-boot-starter-test 引入的, 定位到冲突的产生的根源后,我们很快解决了问题。

maven-helper-30182

结语

理解冲突导致的原因并且快速定位到冲突源,是每个程序员的必修课,希望通过该文档的讲解能帮助到大家。


微信端的朋友也可关注我的公众号

小马向前走

qrcode-12cm

引言

接口调试是每个软件开发从业者必不可少的一项技能,一个项目的完成,可能接口调试的时间比真正开发写代码的时间还要多,几乎是每个开发者的日常工作项。之前写的几篇文章都是从HOW的角度讲如何使用 REST Client 插件, 没有从为什么的角度去讲, 今天将从WHY的角度讲为什么使用该插件。

实际上有很多接口测试工具 如postman, swagger, 他们的使用体验都非常好,那为什么我们会选择REST Client 插件呢?

其除了能满足基本的接口测试功能外, 最大的好处就在于分享, 因为接口文件是纯文本,我们可以把HTTP文件放到GitLab上, 这样既便于管理也便于分享。 所有开发者或者使用项目的人都能复用这个HTTP文件,也极大的方便管理所有REST API, 满足自己的同时也方便了他人。

结语

当你跳出个人的视角,从团队的角度出发, 拉通各个环节之间的壁垒, 提升协作的效率 , 也许比单纯的局部优化要好。


微信端的朋友也可关注我的公众号

小马向前走

qrcode-12cm

引言

REST Client 是一个 VSCode 插件,使我们可以直接在 VSCode 中直接发送http请求,目前我用它来代替 postman 做一些简单接口测试。

REST Client allows you to send HTTP request and view the response in Visual Studio Code directly

restClient-1

说起测试接口,大家一定会想起 postman ,那在引入 REST Client 插件之前,需要解答一个问题,难道 postman 不香么,为什么还要引入新工具? 实际上 postman 很香,只是对于一些入参简单的请求,用 postman 感觉太重了,而且如果接口数量很多,导致打开很多标签。

一直以来我也在寻找更好的方案,一个不用切换窗口的方案 – 终于在使用 VSCode 一段时间后,我找到了 REST Client 插件,初看 REST Client 插件的时候,会觉得他十分简陋,但是在使用一段时间后会发现在 REST Client 插件中已经有完成接口测试所需的大部分功能。

我总结了3点使用REST Client插件的好处

  1. 便于分享,因为是纯文本,联调时可以做为一个成果物,发给前端开发同事做为测试列表,这是我使用它的主要原因
  2. 不用切换标签,通过###分隔符,同一个HTTP文件里可以包含多个HTTP请求, 不像Postman,不同的HTTP请求需要放在不同的tab里
  3. 可以更直接的接触到http的相关知识,因为不论请求还是返回都是文本,这样可以更直接的感受到http请求的细节

相关资料

github

https://github.com/Huachao/vscode-restclient

关于安装

直接在插件商店中搜索 REST Client 安装即可

restClient-13246

简单使用

本节列出几个示例,指引大家快速入门

示例1 get请求示例

这里演示如何发送一个get请求,从该示例中你会掌握基本的用法

1
2
3
4
@IP=127.0.0.1:8083

### get 请求示例
GET http://{{IP}}/helloJson/testParam?name=hello

当一个文件的后缀名是.http 或者 .rest时,VSCode 会自动识别成接口文件

在VSCode中 用三个#号 ### 表示一个接口的开始,其下方会有一个 Send Request的按钮,当点击该按钮时会发送请求,之后会在窗口右边显示请求返回的内容

restClient-26417

示例2 post请求示例

这里演示如何发送一个post请求

1
2
3
4
5
6
7
8
9
10
@IP=127.0.0.1:8083

### post 请求示例
POST {{IP}}/authorize/register
Content-Type: application/json

{
"name": "小天",
"username": "sky"
}

注意data 与请求头之间有空行

高阶使用

其实REST Client还有很多的功能,有需求的同学可以慢慢挖掘,笔者列出了一些比较有用的高阶技巧。

示例1 变量的使用

1
2
3
4
@IP=127.0.0.1:8083

### get 请求示例
GET http://{{IP}}/pgp/helloJson/testParam?name=hello

实际上细心的你可能已经发现,在前面的简单示例中IP并没有写死,而是使用了一个变量,这样做的好处是可以快速切换环境。

当然这里的变量可以不光是变量,还可以是环境变量,其在使用方式上没有差别。

示例2 Get请求参数写成多行

1
2
3
4
### get 请求 参数写到多行示例
GET https://example.com/comments
?page=2
&pageSize=10

如果参数有很多,写在一行上不方便阅读和修改,则可以像这里一样分行写,一行一个。

示例3 添加头信息

1
2
3
### 测试 不拦截 请求头中加标记
GET http://{{IP}}/pgp/helloJson/testMap
XX-NOT-INTERCEPT:true

如果需要添加自定义的头信息可以这样添加。

示例4 添加cookie

1
2
3
### 测试 cookie
GET http://{{IP}}/pgp/helloJson/testCookie
Cookie: eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiIxNjI2MTA1NjAwIiwic3ViIjoic2t5Iiwib2ZmaWNpYWxBY2NvdW50cyI6IuWwj-mprOWQkeWJjei1sCIsImlhdCI6MTYyNjE3MTcwMywiZXhwIjoxNjI2MTcyMjAzfQ.PTzL-lw6NQb2qhQg_-q2DWmMOe-1IcpEWcKyLv2rQfQhnrJiIEnVEd0s4FKxre5qVkyfc9b40u31dvJS-ejYUg

这里演示在请求中如何添加cookie, 实际上cookie也是头的一部分,和添加头没什么区别。

示例5 代码生成

代码生成也是REST Client里一个很方便的功能,可以方便的将HTTP请求生成代码片段或者curl命令。

Generate Code Snippet

你可以方便地通过 Generate Code Snippet 命令来把HTTP请求生成出不同编程语言的代码:JavaScript, Python, C, C#, Java, PHP, Go, Ruby, Swift等等主流语言。

restClient-21529

Copy Request As cURL

也可以通过Copy Request As cURL功能将HTTP请求生成 curl 命令,这个方法在运维排错时特别有用,在运维时有可能网络不通,需要登录到内网机器执行curl命令测试接口是否正常,但也许你对curl命令不熟悉, 不能很快写出命令,则可以借助REST Client 直接生成curl命令。

restClient-128

选中接口文本–> 右键 Copy Request As cURL

restClient-25289

如下是生成的curl命令

1
2
3
4
5
curl --request POST \
--url 'http://127.0.0.1:8083/blue/sql/queryListByKeyWithParam?key=00_0005' \
--header 'content-type: application/json' \
--header 'user-agent: vscode-restclient' \
--data '{"dataType":"default","code":["001","002"]}'

总结

本节演示了REST Client的一些用法,希望大家把 VSCode 转化为一个 REST 接口测试的利器。


微信端的朋友也可关注我的公众号

小马向前走

qrcode-12cm

问题的引出

RestTemplate 是spring提供的访问rest接口的类,RestTemplate提供了多种便捷访问http服务的方法,使得调用rest接口更容易,记得在以前的代码中发送http请求我们还使用 HttpClient 或者 OkHttp 但其有如下的问题

  1. 代码复杂
  2. 需要操心资源回收等细节问题
  3. 每个项目组都有自己的一套http工具类,重复造轮子

现在我基本上用RestTemplate代替了以前自己写的工具类。

本文不讲RestTemplate的普遍使用方法,而是讲在非springboot工程中如何使用RestTemplate

那为什么会有这样的场景呢?举个例子:我们要开发一个jar包提供给其他人,并集成到别人的工程中使用,该jar包封装对某短信接口的请求细节,别人只需要引入我们的jar包然后调用相关类即可,不用关心具体的http请求细节,因为我们提供的是一个很小的jar包,而不是一个完整的工程,所以再去用springboot那套就不合适了。

大部分情况下我们的工程都是基于springboot或者spring系的,使用RestTemplate很简单,直接自动注入即可。

那在脱离了spring系的工程中我们还能开心的使用RestTemplate么?

在非springboot工程中使用RestTemplate

步骤 pom.xml 中添加依赖

1
2
3
4
5
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>

步骤 代码中使用

1
2
3
4
5
RestTemplate restTemplate=new RestTemplate();
HttpHeaders headers=new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
HttpEntity requestEntity=new HttpEntity<>(bean,headers);
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST,requestEntity,String.class);

以前spring帮我们初始化RestTemplate,现在我们需要自己new 对象了,其它使用方式没有区别。

关于初始化RestTemplate的说明

1
2
3
RestTemplate restTemplate = new RestTemplate();
RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
RestTemplate restTemplate = new RestTemplate(new OkHttp3ClientHttpRequestFactory());

实际上RestTemplate自己并不实现具体的http操作,其只是对已有类库进行了封装,而其具体实现仍然依赖底层的类库

  1. 上面第一种初始化方法 其使用JDK自带的 HttpURLConnection
  2. 第二种初始化方法 使用的是 HttpClient 库
  3. 第三种初始化方法 使用的是 OkHttp 库

所以如果对具体使用的类库有要求的话,应该在初始化时指定具体的工厂类,当然还需要添加相关的依赖

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>

<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.11.0</version>
</dependency>

微信端的朋友也可关注我的公众号

小马向前走

qrcode-12cm

本文推荐一些java中好用的工具类

  1. 如统计执行时长的 Guava下的 Stopwatch 类
  2. Bean 与 Map 相互转换的 Apache的BeanUtils

计时相关

项目中经常有记录某一操作花费多长时间的需求,如下是最开始的代码,是不是很熟悉?

1
2
3
4
5
6
long start = System.currentTimeMillis();
//do something
Thread.sleep(2020);

long end = System.currentTimeMillis();
System.out.println("运行时间:"+(end - start)+ "ms");

这种方式确实简单,但是这种方式也有不灵活的地方

  1. 默认情况下我们只能取ms为单位,如果需要分钟,则需要自己换算单位。
  2. 不能支持更复杂的计时需求,如中途暂停计时,当代码执行到某一步再继续计时。

下面介绍一个关于计时的工具类 Guava下的 Stopwatch

引入依赖

1
2
3
4
5
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.5-jre</version>
</dependency>

Stopwatch代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Test
public void stopwatch1() throws InterruptedException {
//创建stopwatch并开始计时
Stopwatch stopwatch=Stopwatch.createStarted();


Thread.sleep(2020);
System.out.println(stopwatch.elapsed(TimeUnit.MILLISECONDS));


//暂停计时
stopwatch.stop();
Thread.sleep(1000);


//再次开始计时
stopwatch.start();
Thread.sleep(2020);
stopwatch.stop();


//统计运行时长
System.out.println(stopwatch.elapsed(TimeUnit.MILLISECONDS));
}

可以看到除了满足基本的计时需求外,其使用更灵活,更简单。

  1. 不需要自己再去计算时长

  2. 可以中途暂停计时

下面总结下常用的操作

1
2
3
4
5
6
7
8
9
10
11
12
//创建计时器,但是不立即运行 需要主动调用 stopwatch.start()方法开始计时
Stopwatch stopwatch=Stopwatch.createUnstarted();
stopwatch.start();

//创建stopwatch并开始计时
Stopwatch stopwatch=Stopwatch.createStarted();

//暂停计时
stopwatch.stop();

//统计运行时长
stopwatch.elapsed(TimeUnit.MILLISECONDS)

Bean 与 Map 互转

日常开发中经常有将Bean转成Map,或者将Map转成Bean的需求,这里阐述下具体的实现.

目前Map 与 Bean互转有如下几种方式

  1. 方式一: 通过Jackson 先将Bean转成json,再将json转成Map
  2. 方式二: 使用Spring的BeanMap类
  3. 方式三: 使用Apache的BeanUtils

我目前使用方式三. 原因如下

  1. 方式一 效率不行
  2. 方式二 需要依赖spring,在有些非spring系工程中不方便使用

使用Apache的BeanUtils

引入依赖

1
2
3
4
5
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>

bean 转 map

1
2
3
4
5
6
7
8
9
10
11
12
/**
* bean 转 map
* */
public static Map beanToMap(Object bean){
Map<String,String> map=Maps.newHashMap();
try {
map=BeanUtils.describe(bean);
} catch (Exception e) {
e.printStackTrace();
}
return map;
}

map 转 bean

1
2
3
4
5
6
7
8
9
10
11
/**
* map 转 bean
* */
public static Object mapToBean(Map map,Object bean){
try {
BeanUtils.populate(bean,map);
} catch (Exception e) {
e.printStackTrace();
}
return bean;
}

微信端的朋友也可关注我的公众号

小马向前走

qrcode-12cm

背景

有时需要定义一些模板,然后用实际值替换占位符. 这里介绍一个jar包 ST4.

还是以生成验证码短信的例子为背景.

如下是我定义的模板,需要传入用户名和验证码.

1
2
你好 <name> , 你的验证码是 <captcha>
验证码5分钟有效,尽快使用

最终生成的文本如下

1
2
你好 张三 , 你的验证码是 123456
验证码5分钟有效,尽快使用

如果模板越复杂使用ST4越能感觉到优势, 如用于生成源代码、web页面、电子邮件等复杂样式的文本.

github地址

https://github.com/antlr/stringtemplate4

使用示例

pom.xml 引入依赖

1
2
3
4
5
<dependency>
<groupId>org.antlr</groupId>
<artifactId>ST4</artifactId>
<version>4.0.8</version>
</dependency>

一些示例

示例1 简单示例

1
2
3
4
5
6
7
8
9
/*
* 最简单的示例
* */
@Test
public void helloWorld(){
ST hello = new ST("Hello, <name>");
hello.add("name", "World");
System.out.println(hello.render());
}

这个例子算是st4的helloworld版,让你快速感受下.

示例2 STGroupFile的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
/*
* 演示 STGroupFile 的使用
* 可以将多个模板内容放在一个文件中,所以其后缀名叫stg.
* */
@Test
public void testGroupFile(){
STGroup group=new STGroupFile("templates/templates.stg");
ST st=group.getInstanceOf("ShortMessage");
st.add("name","张三");
st.add("captcha","123456");
String result=st.render();
System.out.println(result);
}

如下定义模板文件, 可以看到其定义有点像函数的形式.

resouces/templates/templates.stg

1
2
3
4
5
ShortMessage(name,captcha) ::=
<<
你好 <name> , 你的验证码是 <captcha>
验证码5分钟有效,尽快使用
>>

当模板过于复杂时,以硬编码的方式将模板写在代码中不方便,因此将模板内容写入到文件是一个不错的选择.

示例3 传入参数是对象

1
2
3
4
5
6
7
8
9
10
11
/*
* 如下演示传入的参数是对象 而不是单个的值
* 而且其占位符也不是默认的< 和> 而是$了
* */
@Test
public void testModelObject(){
ST st = new ST("<b>$u.id$</b>: $u.name$", '$', '$');
st.add("u", new User(999, "parrt"));
String result = st.render(); // "<b>999</b>: parrt"
System.out.println(result);
}

这个例子也很经典

  • 一是其传入的参数是一个对象,而不是字符串等基本类型了
  • 二是这里自己指定了占位符

本文推荐一些好用的idea插件,用好这些插件可以省好多时间.

MyBatis Log Plugin

作用: 将mybatis打印到控制台的sql中的?替换成实际参数,替换后的sql可直接复制粘贴到数据库执行

推荐理由: 快速将mybatis打印出的日志拼接成实际的sql,在调试sql时很方便.

MyBatisLogPlugin-1

如下是生成的实际的sql

MyBatisLogPlugin-2

Free Mybatis Plugin

作用:快速在mybatis的mapper接口类和xml间跳转

推荐理由: 从代码中快速跳转到mybatis的xml

FreeMybatisPlugin-1

RestfulToolkit

作用: 其会根据url查找controller

推荐理由: 通过url快速定位到controller, 方便快速定位到代码

快捷键: command+\

image-20201019170120384

彩色括号 Rainbow Bracket

作用: 高亮显示括号配对

推荐理由: 有时代码中的括号直的很多,不好分清楚这行代码到底在哪个括号里,有了彩色括号方便太多了.

RainbowBrackets-1

背景描述

日常开发工作中会遇到替换占位符的需求

例如给用户发验证码短信时需要拼接如下的字符串 “张三 欢迎使用,您的验证码是123456” , 其中用户名和验证码需要动态拼接,其他字符串都是固定的. 则这种情况下可以考虑使用commons-text,比自己实现字符串替换要好.

具体步骤

引入 commons-text 的依赖

1
2
3
4
5
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.9</version>
</dependency>

具体代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void test1(){
/*
* 演示最简单的使用方式
* 这里默认的替换符就是${}
* */
Map<String, Object> params = new HashMap<String, Object>();
params.put("userName", "admin");
params.put("captcha", "123456");
StringSubstitutor stringSubstitutor=new StringSubstitutor(params);
String template = "${userName} 欢迎使用,您的验证码是${captcha}";
String result=stringSubstitutor.replace(template);
System.out.println(result);
}

兜兜转转, 又来到了这里, 欢迎回来