cn.hutool.core.net.url.UrlPath Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hutool-all Show documentation
Show all versions of hutool-all Show documentation
Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。
package cn.hutool.core.net.url;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.net.RFC3986;
import cn.hutool.core.net.URLDecoder;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import java.nio.charset.Charset;
import java.util.LinkedList;
import java.util.List;
/**
* URL中Path部分的封装
*
* @author looly
* @since 5.3.1
*/
public class UrlPath {
private List segments;
private boolean withEngTag;
/**
* 构建UrlPath
*
* @param pathStr 初始化的路径字符串
* @param charset decode用的编码,null表示不做decode
* @return UrlPath
*/
public static UrlPath of(CharSequence pathStr, Charset charset) {
final UrlPath urlPath = new UrlPath();
urlPath.parse(pathStr, charset);
return urlPath;
}
/**
* 是否path的末尾加 /
*
* @param withEngTag 是否path的末尾加 /
* @return this
*/
public UrlPath setWithEndTag(boolean withEngTag) {
this.withEngTag = withEngTag;
return this;
}
/**
* 获取path的节点列表
*
* @return 节点列表
*/
public List getSegments() {
return ObjectUtil.defaultIfNull(this.segments, ListUtil.empty());
}
/**
* 获得指定节点
*
* @param index 节点位置
* @return 节点,无节点或者越界返回null
*/
public String getSegment(int index) {
if (null == this.segments || index >= this.segments.size()) {
return null;
}
return this.segments.get(index);
}
/**
* 添加到path最后面
*
* @param segment Path节点
* @return this
*/
public UrlPath add(CharSequence segment) {
addInternal(fixPath(segment), false);
return this;
}
/**
* 添加到path最前面
*
* @param segment Path节点
* @return this
*/
public UrlPath addBefore(CharSequence segment) {
addInternal(fixPath(segment), true);
return this;
}
/**
* 解析path
*
* @param path 路径,类似于aaa/bb/ccc或/aaa/bbb/ccc
* @param charset decode编码,null表示不解码
* @return this
*/
public UrlPath parse(CharSequence path, Charset charset) {
if (StrUtil.isNotEmpty(path)) {
// 原URL中以/结尾,则这个规则需保留,issue#I1G44J@Gitee
if(StrUtil.endWith(path, CharUtil.SLASH)){
this.withEngTag = true;
}
path = fixPath(path);
if(StrUtil.isNotEmpty(path)){
final List split = StrUtil.split(path, '/');
for (String seg : split) {
addInternal(URLDecoder.decodeForPath(seg, charset), false);
}
}
}
return this;
}
/**
* 构建path,前面带'/'
*
* path = path-abempty / path-absolute / path-noscheme / path-rootless / path-empty
*
*
* @param charset encode编码,null表示不做encode
* @return 如果没有任何内容,则返回空字符串""
*/
public String build(Charset charset) {
return build(charset, true);
}
/**
* 构建path,前面带'/'
*
* path = path-abempty / path-absolute / path-noscheme / path-rootless / path-empty
*
*
* @param charset encode编码,null表示不做encode
* @param encodePercent 是否编码`%`
* @return 如果没有任何内容,则返回空字符串""
* @since 5.8.0
*/
public String build(Charset charset, boolean encodePercent) {
if (CollUtil.isEmpty(this.segments)) {
// 没有节点的path取决于是否末尾追加/,如果不追加返回空串,否则返回/
return withEngTag ? StrUtil.SLASH : StrUtil.EMPTY;
}
final char[] safeChars = encodePercent ? null : new char[]{'%'};
final StringBuilder builder = new StringBuilder();
for (final String segment : segments) {
if(builder.length() == 0){
// 根据https://www.ietf.org/rfc/rfc3986.html#section-3.3定义
// path的第一部分不允许有":",其余部分允许
// 在此处的Path部分特指host之后的部分,即不包含第一部分
builder.append(CharUtil.SLASH).append(RFC3986.SEGMENT_NZ_NC.encode(segment, charset, safeChars));
} else {
builder.append(CharUtil.SLASH).append(RFC3986.SEGMENT.encode(segment, charset, safeChars));
}
}
if(withEngTag){
if (StrUtil.isEmpty(builder)) {
// 空白追加是保证以/开头
builder.append(CharUtil.SLASH);
}else if (false == StrUtil.endWith(builder, CharUtil.SLASH)) {
// 尾部没有/则追加,否则不追加
builder.append(CharUtil.SLASH);
}
}
return builder.toString();
}
@Override
public String toString() {
return build(null);
}
/**
* 增加节点
*
* @param segment 节点
* @param before 是否在前面添加
*/
private void addInternal(CharSequence segment, boolean before) {
if (this.segments == null) {
this.segments = new LinkedList<>();
}
final String seg = StrUtil.str(segment);
if (before) {
this.segments.add(0, seg);
} else {
this.segments.add(seg);
}
}
/**
* 修正路径,包括去掉前后的/,去掉空白符
*
* @param path 节点或路径path
* @return 修正后的路径
*/
private static String fixPath(CharSequence path) {
Assert.notNull(path, "Path segment must be not null!");
if ("/".contentEquals(path)) {
return StrUtil.EMPTY;
}
String segmentStr = StrUtil.trim(path);
segmentStr = StrUtil.removePrefix(segmentStr, StrUtil.SLASH);
segmentStr = StrUtil.removeSuffix(segmentStr, StrUtil.SLASH);
segmentStr = StrUtil.trim(segmentStr);
return segmentStr;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy