前言

  • 关于URI参考这里。
  • springboot 2.1.1.RELEASE

UriComponentsBuilder

  • UriComponentsBuilder 是UriBuilder的实现。针对Servlet,还派生出来ServletUriComponentsBuilder。
  • 使用过UriComponentsBuilder 的都知道,很好用

快速来个示例

String url = UriComponentsBuilder.fromUriString("http://mydomain/api/getToken").queryParam("appid", "123").queryParam("appsecret", "secret123").build().encode().toString();
System.out.println(url);
  • 这段代码可以得到:http://mydomain/api/getToken?appid=123&appsecret=secret123
  • 这段代码实际做了几件事:
    1. 实例化 UriComponentsBuilder 。UriComponentsBuilder.fromUriString("http://mydomain/api/getToken")
    2. 设置 UriComponentsBuilder 实例。.queryParam("appid", "123").queryParam("appsecret", "secret123")
    3. 创建 UriComponents 实例。.build()
    4. 设置 UriComponents 实例。.encode()
    5. UriComponents 实例转成字符串。.toString()

实例化 UriComponentsBuilder 的方法

UriComponentsBuilder 提供的实例化 UriComponentsBuilder 的方法

public static UriComponentsBuilder newInstance();
public static UriComponentsBuilder fromPath(String path);
public static UriComponentsBuilder fromUri(URI uri);
public static UriComponentsBuilder fromUriString(String uri);
public static UriComponentsBuilder fromHttpUrl(String httpUrl);
public static UriComponentsBuilder fromHttpRequest(HttpRequest request);
public static UriComponentsBuilder fromOriginHeader(String origin);

ServletUriComponentsBuilder 提供的实例化 UriComponentsBuilder 的方法

public static ServletUriComponentsBuilder fromContextPath(HttpServletRequest);
public static ServletUriComponentsBuilder fromServletMapping(HttpServletRequest);
public static ServletUriComponentsBuilder fromRequest(HttpServletRequest);
public static ServletUriComponentsBuilder fromCurrentContextPath();
public static ServletUriComponentsBuilder fromCurrentServletMapping();
public static ServletUriComponentsBuilder fromCurrentRequest();

设置 UriComponentsBuilder 实例

赋值
.queryParam("appid", "123")
重复赋值
.queryParam("appid", "123")
.queryParam("appid", "234")
  • appid 会变为[“123”, “234”]
替换
.queryParam("appid", "123")
.replaceQueryParam("appid", "234")
  • appid 变为234
路径
.path("a")
.path("b")
.path("c")
  • xxx/a/b/c
替换路径
.path("a")
.path("b")
.path("c")
.replacePath("d")
  • xxx/d
更多

略。

关于urlencode

前面示例中.build() 中得到的是 UriComponents 派生类(HierarchicalUriComponents)的实例。

HierarchicalUriComponents 类的实例在.encode()时,使用HierarchicalUriComponents.encodeUriComponent() 方法进行 url 编码。其编码方式与java.net.URLEncoder的实现不同。

总结一下(代码参考测试代码1):

代码 结果 特征 遵循协议
URLEncoder.encode(“1 + 2 = 3”, “utf-8”); 1+%2B+2+%3D+3 空格转义成+;+转义成%2B W3C标准规定
HierarchicalUriComponents.encodeUriComponent(“1 + 2 = 3”, “utf-8”,Type.QUERY_PARAM); 1%20+%202%20%3D%203 空格转义成%20;+不变 RFC 3986

用哪个对呢?都对!!!但,要看提供服务的应用支持哪个。我的建议是,都试试,哪个能用用哪个。

如何让 URLEncoder 支持 空格转义成%20;+不变呢?

参考这里:https://blog.csdn.net/qq_43566496/article/details/84935364

如何让 HierarchicalUriComponents 支持 空格转义成+;+转义成%2B呢?

方法1
String url = UriComponentsBuilder.fromUriString("http://mydomain/api/getToken").queryParam("appid", "123").queryParam("appsecret", "secret123").queryParam("q", URLEncoder.encode("1 + 2 = 3")).build(true).encode().toString();
System.out.println(url);
  • .build(true) 告诉 UriComponents 我已经做过uri编码了,你就不要再做uri编码了。
方法2
String url = UriComponentsBuilder.fromUriString("http://mydomain/api/getToken").queryParam("appid", "123").queryParam("appsecret", "secret123").queryParam("q", URLEncoder.encode("1 + 2 = 3")).build().toString();
System.out.println(url);
  • 去掉.encode()UriComponents 就不要再做uri编码了。

spring 提供的支持 RFC 2396、RFC 3986 的类: UriUtils

https://docs.spring.io/spring-framework/docs/3.0.x/javadoc-api/org/springframework/web/util/UriUtils.html

测试代码1

import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;import org.springframework.util.Assert;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;public class Test {public static void main(String[] args) throws UnsupportedEncodingException {System.out.println(URLEncoder.encode("1 + 2 = 3", "utf-8"));System.out.println(encodeUriComponent("1 + 2 = 3", Charset.forName("utf-8"), Type.QUERY_PARAM));}/*HierarchicalUriComponents.encodeUriComponent() 方法的高仿实现*/static String encodeUriComponent(String source, Charset charset, Type type) {if (!StringUtils.hasLength(source)) {return source;}Assert.notNull(charset, "Charset must not be null");Assert.notNull(type, "Type must not be null");byte[] bytes = source.getBytes(charset);boolean original = true;for (byte b : bytes) {if (!type.isAllowed(b)) {original = false;break;}}if (original) {return source;}ByteArrayOutputStream baos = new ByteArrayOutputStream(bytes.length);for (byte b : bytes) {if (type.isAllowed(b)) {baos.write(b);}else {baos.write('%');char hex1 = Character.toUpperCase(Character.forDigit((b >> 4) & 0xF, 16));char hex2 = Character.toUpperCase(Character.forDigit(b & 0xF, 16));baos.write(hex1);baos.write(hex2);}}return StreamUtils.copyToString(baos, charset);}enum Type {QUERY {@Overridepublic boolean isAllowed(int c) {return isPchar(c) || '/' == c || '?' == c;}},QUERY_PARAM {@Overridepublic boolean isAllowed(int c) {if ('=' == c || '&' == c) {return false;}else {return isPchar(c) || '/' == c || '?' == c;}}};/*** Indicates whether the given character is allowed in this URI component.* @return {@code true} if the character is allowed; {@code false} otherwise*/public abstract boolean isAllowed(int c);/*** Indicates whether the given character is in the {@code ALPHA} set.* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>*/protected boolean isAlpha(int c) {return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z');}/*** Indicates whether the given character is in the {@code DIGIT} set.* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>*/protected boolean isDigit(int c) {return (c >= '0' && c <= '9');}/*** Indicates whether the given character is in the {@code sub-delims} set.* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>*/protected boolean isSubDelimiter(int c) {return ('!' == c || '$' == c || '&' == c || '\'' == c || '(' == c || ')' == c || '*' == c || '+' == c ||',' == c || ';' == c || '=' == c);}/*** Indicates whether the given character is in the {@code unreserved} set.* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>*/protected boolean isUnreserved(int c) {return (isAlpha(c) || isDigit(c) || '-' == c || '.' == c || '_' == c || '~' == c);}/*** Indicates whether the given character is in the {@code pchar} set.* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>*/protected boolean isPchar(int c) {return (isUnreserved(c) || isSubDelimiter(c) || ':' == c || '@' == c);}}
}
String url = UriComponentsBuilder.fromUriString("http://api.fanyi.baidu.com/api/trans/vip/translate").queryParam("appid", appid).queryParam("q", encode(query)).queryParam("from", from).queryParam("to", to).queryParam("salt", salt).queryParam("sign", sign).build(true).encode().toString();

参考

https://www.cnblogs.com/zhengxl5566/p/10783422.html
https://www.cnblogs.com/zhengxl5566/p/13492602.html
https://www.cnblogs.com/siqi/p/10070926.html

UriComponentsBuilder 拼接URL、解析URL相关推荐

  1. Python3 URL格式化url解析url提取参数

    我们一般见到的url地址都是字符串形式,例如: http://api.bilibili.com/x/web-interface/view?aid=44699780 请求协议: http 请求域名:ap ...

  2. yy神曲url解析php_使用PHP来简单的创建一个RPC服务

    RPC全称为Remote Procedure Call,翻译过来为"远程过程调用".主要应用于不同的系统之间的远程通信和相互调用. 比如有两个系统,一个是PHP写的,一个是JAVA ...

  3. python3 url解析 urllib.parse.urlparse 库简介

    urllib.parse - 将URL解析为组件 urllib.parse定义了一个标准接口,用于在组件中解析统一资源定位符(URL)字符串(寻址方案,网络位置,路径等),将组件组合回URL字符串,并 ...

  4. url参数拼接 php,PHP解析url并得到url参数方法总结

    PHP 中解析 url 并得到 url 参数 这里介绍两种对url操作的方法: 1.拿到一个完整url后,如何解析该url得到里面的参数. /** * 解析url中参数信息,返回参数数组 */ fun ...

  5. python爬虫基础扫盲之urllib.pase解析URL

    在笨方法"学习python笔记之urlopen,中提了urllib主要是提供打开网页,解析url等功能用于网络爬虫,其lib主要包含四个部分,其中urllib.parse主要是负责url的解 ...

  6. js常用方法,JS实用方法,jq获得文件后缀,解析window。location,解析URL参数

    jq获取文件后缀的方法 var file = "测试文档1111111111.docx"; // 文件 var fileName = file.replace(/.*(\/|\\) ...

  7. window对象(一) 计时器 定位导航 url解析 浏览历史 对话框 消息推送

    window对象 计时器 一个jQuery作者的写的关于定时器解释,记的顺手订阅一下.John Resig,jQuery之父 https://johnresig.com/blog/how-javasc ...

  8. python url解析path_Django(CBV解析、模板层)

    https://www.zhihu.com/video/1249450287595159552 每日测验 """ 今日考题 1.反向解析的本质是什么,无名和有名反向解析如 ...

  9. python url解析_Python中实现URL的解析

    在Python中的urlparse模块主要是用于解析url中的参数  对url按照一定格式进行 拆分或拼接 1.urlparse.urlparse 将url分为6个部分,返回一个包含6个字符串项目的元 ...

  10. Go 学习笔记(50)— Go 标准库之 net/url(查询转义、查询参数增/删/改/查、解析URL)

    1. URL 概述 import "net/url" url 包解析 URL 并实现了查询的转码.URL 提供了一种定位因特网上任意资源的手段,但这些资源是可以通过各种不同的方案( ...

最新文章

  1. 2.13 向量化 Logistic 回归-深度学习-Stanford吴恩达教授
  2. db2 springboot 整合_springboot的yml配置文件通过db2的方式整合mysql代码示例
  3. jQuery导航切换功能
  4. mysql如何植入到oracle_MySQL产品的生命周期
  5. Linux下共享内存的查看和释放
  6. dbv mysql_MariaDB与MySQL对比 --- 对分布式事务的支持
  7. microsoft fix it_it狂人【14季全】
  8. 如果你对web前端学习感到迷茫的话请看完本文
  9. 中文语音识别数据集总结
  10. 【工具】我的键盘(机械键盘)快捷键设置
  11. BZOJ 4399 魔法少女LJJ(线段树合并)
  12. 【背包问题】基于matlab禁忌搜索算法求解背包问题【含Matlab源码 373期】
  13. 2021年最佳知识库软件指南
  14. Linux服务器下搭建SFTP服务
  15. 【龙讯module小课堂】“光”怪陆离:PWmat计算光学性质(二)
  16. 都市鸿蒙珠认主,都市之我能穿越洪荒
  17. Spark广播变量与累加器
  18. python 数据结构常用操作
  19. 复制文件或文件夹时出错(无法复制***:没有足够的可用磁盘空间
  20. 大整理!程序员最爱的12个免费Python课程

热门文章

  1. 联想确认再次裁员 称调整主要分布在海外
  2. 征服数据科学面试的10个小技巧(附资源)
  3. Hyper-V下的Linux虚拟机网卡丢失问题原因及解决办法
  4. MySQL查询in操作 查询结果按in集合顺序显示(转)
  5. Win7安装VC++6.0已知的兼容性问题的解决方法
  6. Dynamips 简介
  7. 工作日志之个人统计篇
  8. Windows程序闪退Windows日志捕获Kernelbase模块错误
  9. 获取webbrowser中元素的屏幕坐标
  10. NopCommerce开源项目中很基础但是很实用的C# Helper方法