package com.imyeyu.network; import com.imyeyu.utils.Encoder; import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder; import org.apache.hc.client5.http.fluent.Form; import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.HttpEntity; import org.apache.hc.core5.http.NameValuePair; import java.io.File; import java.io.InputStream; import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.function.BiConsumer; /** * 请求参数列表。 *

* 该实现允许同名 key 重复出现,适用于 query 参数和表单参数场景。 * * @author 夜雨 * @since 2025-06-26 15:41 */ public class ArgMap { private final List> entries = new ArrayList<>(); /** * 追加一个参数。 * * @param key 参数名 * @param value 参数值 * @return 当前对象 */ public ArgMap put(K key, V value) { entries.add(new AbstractMap.SimpleImmutableEntry<>(key, value)); return this; } /** * 按插入顺序遍历全部参数。 * * @param consumer 处理逻辑 */ public void forEach(BiConsumer consumer) { entries.forEach(entry -> consumer.accept(entry.getKey(), entry.getValue())); } /** * 返回参数数量。 * * @return 参数数量 */ public int size() { return entries.size(); } /** * 判断参数列表是否为空。 * * @return 是否为空 */ public boolean isEmpty() { return entries.isEmpty(); } /** * 清空全部参数。 */ public void clear() { entries.clear(); } /** * 返回只读参数视图。 * * @return 参数条目列表 */ public List> entries() { return Collections.unmodifiableList(entries); } /** * 转换为 multipart 实体。 * * @return multipart 请求体 */ public HttpEntity toEntity() { MultipartEntityBuilder builder = MultipartEntityBuilder.create(); forEach((k, v) -> { String key = k.toString(); switch (v) { case File file -> builder.addBinaryBody(key, file); case byte[] bytes -> builder.addBinaryBody(key, bytes); case InputStream stream -> builder.addBinaryBody(key, stream, ContentType.APPLICATION_OCTET_STREAM, key); default -> builder.addTextBody(key, v.toString()); } }); return builder.build(); } /** * 转换为表单参数列表。 * * @return 表单参数列表 */ public List toNameValuePair() { Form form = Form.form(); forEach((k, v) -> form.add(k.toString(), v.toString())); return form.build(); } /** * 转换为 query string。 * * @return query string */ public String toURL() { if (isEmpty()) { return ""; } StringBuilder sb = new StringBuilder(); forEach((k, v) -> sb.append(k.toString()).append('=').append(Encoder.urlArg(v.toString())).append('&')); sb.deleteCharAt(sb.length() - 1); return sb.toString(); } /** * 将参数拼接到指定 URL。 * * @param url 原始 URL * @return 拼接后的 URL */ public String toURL(String url) { if (isEmpty()) { return url; } StringBuilder sb = new StringBuilder(url); if (url.contains("?")) { if (!url.endsWith("?") && !url.endsWith("&")) { sb.append('&'); } sb.append(toURL()); return sb.toString(); } return url + "?" + toURL(); } /** * 使用一组参数创建对象。 * * @param key 参数名 * @param value 参数值 * @param key 类型 * @param value 类型 * @return 参数对象 */ public static ArgMap of(K key, V value) { return new ArgMap().put(key, value); } /** * 使用两组参数创建对象。 * * @param key1 参数名 1 * @param value1 参数值 1 * @param key2 参数名 2 * @param value2 参数值 2 * @param key 类型 * @param value 类型 * @return 参数对象 */ public static ArgMap of(K key1, V value1, K key2, V value2) { return new ArgMap().put(key1, value1).put(key2, value2); } /** * 使用三组参数创建对象。 * * @param key1 参数名 1 * @param value1 参数值 1 * @param key2 参数名 2 * @param value2 参数值 2 * @param key3 参数名 3 * @param value3 参数值 3 * @param key 类型 * @param value 类型 * @return 参数对象 */ public static ArgMap of(K key1, V value1, K key2, V value2, K key3, V value3) { return new ArgMap().put(key1, value1).put(key2, value2).put(key3, value3); } }