UriComponentsBuilder 拼接URL、解析URL
前言
- 關于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
- 這段代碼實際做了幾件事:
- 實例化 UriComponentsBuilder 。UriComponentsBuilder.fromUriString("http://mydomain/api/getToken")
- 設置 UriComponentsBuilder 實例。.queryParam("appid", "123").queryParam("appsecret", "secret123")
- 創建 UriComponents 實例。.build()
- 設置 UriComponents 實例。.encode()
- 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的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: real解码器是什么?
- 下一篇: Spring @Value 设置默认值