在使用第三方 API 的时候,总是会需要在 url 后面拼接一些请求参数,也就是 ? 符号后面的一串键值对。
看一个具体的例子,比如说要使用高德地图的 api,需要拼接一些参数,比如说出发地 orgin,目的地 destination 的经纬度等参数,在代码中最直接的拼接方法如下:
```java String url = "https://restapi.amap.com/v3/direction/driving" StringBuilder sb = new StringBuilder(); sb.append("?").append("orgin").append("=").append(depLongitude).append(",").append(depLatitude) .append("destination").append("=")..append(destLongitude).append(",").append(destLatitude);
// 下面省略一堆参数拼接...
```
如果使用 StringBuilder 傻瓜式拼接就会导致代码写得非常臃肿,而且如果以后有新的条件那么拼接的代码就会更多,非常不优雅,非常丑陋。所以,需要一个优化的办法。
下面介绍使用 Stream API 来优化参数拼接:
使用一个 Map 来存放查询的参数,使用 @Value 注解来获取编写在 yml 文件中的值,然后让 Map 调用 entrySet 方法之后再转为 Stream。这其中的每一项就是 entry,然后把 entry 通过 map 方法转为 k=v 的形式,这一步完成之后 Stream 中的元素就是一堆字符串集合,最终使用 joining 方法传入参数 &
符号将它们拼接到一起,就得到了查询的参数。
最后一步,就是把原始的第三方 api 和查询参数拼接,中间用 ?
符号分隔。
```java @Service public class MapService {
// https://restapi.amap.com/v3/config/district?keywords=%E5%8D%97%E4%BA%AC&subdistrict=2
@Value("${system.map.path-api}")
private String districtUrl;
@Value("${system.map.key}")
private String userKey;
@Autowired
private RestTemplate restTemplate;
public DirectionResponse direction(String depLongitude, String depLatitude, String destLongitude,
String destLatitude) {
Map<String, String> conditions = new HashMap<String, String>() {
{
put("origin", depLongitude + "," + depLatitude);
put("destination", destLongitude + "," + destLatitude);
put("key", userKey);
}};
String s = conditions.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(joining("&"));
String url = mapUrl + "?" + s;
log.info("调用的接口地址: {}", url);
// 调用高德接口
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
log.info("高德地图路径规划返回信息: {}", response.getBody());
// 解析接口
return parseDirectionEntity(response.getBody());
}
} ```
为了方便以后调用,可以封装一个工具类:
```java /** * URL工具类 */ public class UrlUtil {
/**
* 根据条件拼装url
* @param api 基准的api地址
* @param conditions 存放查询条件的map
* @return 最终的api地址
*/
public static String createQueryParameters(String api, Map<String, String> conditions) {
String params = conditions.entrySet()
.stream()
.map(e -> e.getKey() + "=" + e.getValue())
.collect(Collectors.joining("&"));
return api + "?" + params;
}
} ``` 这样就不用写一堆 StringBuilder 的拼接代码了,非常丑陋。高手和菜鸟区别就在这里。