xuhy
2026-01-27 2d2a8ce78eff4ff88dc146e26f2722d183445823
旺店通接口工具接入
10个文件已添加
1453 ■■■■■ 已修改文件
ruoyi-admin/src/main/java/com/ruoyi/web/controller/yuncang/api/basic/LogisticsQuery.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/yuncang/api/basic/WarehouseQuery.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/yuncang/api/trade/LogisticsSyncAck.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/yuncang/api/trade/LogisticsSyncQuery.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/yuncang/api/trade/TradePush.java 170 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/yuncang/api/trade/TradeQuery.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/yuncang/utils/FileItem.java 146 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/yuncang/utils/StringUtils.java 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/yuncang/utils/WdtClient.java 127 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/yuncang/utils/WebUtils.java 560 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/yuncang/api/basic/LogisticsQuery.java
New file
@@ -0,0 +1,57 @@
package com.ruoyi.web.controller.yuncang.api.basic;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.web.controller.yuncang.utils.WdtClient;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class LogisticsQuery {
    /**
     * 物流查询
     * @param sid     卖家账号,接口请求的公共参数sid
     * @param appkey     接口账号,接口请求的公共参数appkey
     * @param appsecret     接口秘钥,接口请求的参数appsecret ,用于计算签名
     * @param url     接口地址,接口请求的公共参数url
     * @param logistics_no     物流单号
     * @return
     */
    public static JSONObject logisticsQuery(String sid, String appkey, String appsecret,String url, String logistics_no) {
        WdtClient client = new WdtClient(sid, appkey, appsecret, url);
        Map<String, String> params = new HashMap<String, String>();
        params.put("logistics_no", logistics_no);
        try {
            String response = client.execute("logistics.php", params);
            log.info("物流查询结果:{}", response);
            JSONObject jsonObject = JSONObject.parseObject(response);
            if(jsonObject.getInteger("code") == 0){
                return jsonObject;
            }else{
                log.info("物流查询失败");
                throw new ServiceException(jsonObject.getString("message"));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static void main(String[] args) {
        WdtClient client = new WdtClient("", "", "", "");
        Map<String, String> params = new HashMap<String, String>();
        params.put("logistics_no", "11");
        try {
            String response = client.execute("logistics.php", params);
            System.out.println(response);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/yuncang/api/basic/WarehouseQuery.java
New file
@@ -0,0 +1,60 @@
package com.ruoyi.web.controller.yuncang.api.basic;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.web.controller.yuncang.utils.WdtClient;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class WarehouseQuery {
    /**
     * 云仓仓库查询
     * @param sid     卖家账号,接口请求的公共参数sid
     * @param appkey     接口账号,接口请求的公共参数appkey
     * @param appsecret     接口秘钥,接口请求的参数appsecret ,用于计算签名
     * @param url     接口地址,接口请求的公共参数url
     * @return
     */
    public static JSONObject warehouseQuery(String sid, String appkey, String appsecret,String url) {
        WdtClient client = new WdtClient(sid, appkey, appsecret, url);
        //测试环境sid、appkey、密钥请到旺店通开放平台-自助对接-申请测试环境内查看,测试环境url=https://sandbox.wangdian.cn/openapi2/
        //调用正式环境时请将sid、appkey、appsecret切换为实际参数,参数在旺店通开放平台-自助对接-应用管理内应用状态为已上线的应用中查看,调用正式环境注意切换正式环境url=https://api.wangdian.cn/openapi2/
        Map<String, String> params = new HashMap<String, String>();
        params.put("type", "1");
        try {
            String response = client.execute("warehouse_query.php", params);
            log.info("云仓仓库查询结果:{}", response);
            JSONObject jsonObject = JSONObject.parseObject(response);
            if(jsonObject.getInteger("code") == 0){
                return jsonObject;
            }else{
                log.info("云仓仓库查询失败");
                throw new ServiceException(jsonObject.getString("message"));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static void main(String[] args) {
        WdtClient client = new WdtClient("apidevnew2", "hytycw02-test", "c7ae51196", "https://sandbox.wangdian.cn/openapi2/");
        //测试环境sid、appkey、密钥请到旺店通开放平台-自助对接-申请测试环境内查看,测试环境url=https://sandbox.wangdian.cn/openapi2/
        //调用正式环境时请将sid、appkey、appsecret切换为实际参数,参数在旺店通开放平台-自助对接-应用管理内应用状态为已上线的应用中查看,调用正式环境注意切换正式环境url=https://api.wangdian.cn/openapi2/
        Map<String, String> params = new HashMap<String, String>();
        params.put("type", "1");
        try {
            String response = client.execute("warehouse_query.php", params);
            System.err.println(response);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/yuncang/api/trade/LogisticsSyncAck.java
New file
@@ -0,0 +1,71 @@
package com.ruoyi.web.controller.yuncang.api.trade;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.web.controller.yuncang.utils.WdtClient;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
public class LogisticsSyncAck {
    /**
     * 物流erp同步ack
     * @param sid     卖家账号,接口请求的公共参数sid
     * @param appkey     接口账号,接口请求的公共参数appkey
     * @param appsecret 接口秘钥,接口请求的参数appsecret ,用于计算签名
     * @param url     接口地址,接口请求的公共参数url
     * @param logistics_list 同步物流信息Ack列表
     * @return
     */
    public static JSONObject logisticsSyncAck(String sid, String appkey, String appsecret, String url,List<Map<String, Object>> logistics_list) {
        WdtClient client = new WdtClient(sid, appkey, appsecret, url);
        String logistics_list_json = JSON.toJSONString(logistics_list);
        Map<String, String> params = new HashMap<String, String>();
        params.put("logistics_list", logistics_list_json);
        try {
            String response = client.execute("logistics_sync_ack.php", params);
            log.info("物流erp同步ack结果:{}", response);
            JSONObject jsonObject = JSON.parseObject(response);
            if(jsonObject.getInteger("code") == 0){
                return jsonObject;
            }else{
                log.info("物流erp同步ack失败");
                throw new ServiceException(jsonObject.getString("message"));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static void main(String[] args) {
        WdtClient client = new WdtClient("", "", "", "");
        List<Map<String, Object>> logistics_list = new ArrayList<Map<String, Object>>();
        Map<String, Object> logistics_1 = new HashMap<String, Object>();
        logistics_1.put("rec_id", 1);
        logistics_1.put("status", 0);
        logistics_1.put("message", "同步成功");
        logistics_list.add(logistics_1);
        String logistics_list_json = JSON.toJSONString(logistics_list);
        Map<String, String> params = new HashMap<String, String>();
        params.put("logistics_list", logistics_list_json);
        try {
            String response = client.execute("logistics_sync_ack.php", params);
            System.out.println(response);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/yuncang/api/trade/LogisticsSyncQuery.java
New file
@@ -0,0 +1,62 @@
package com.ruoyi.web.controller.yuncang.api.trade;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.web.controller.yuncang.utils.WdtClient;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class LogisticsSyncQuery {
    /**
     * 物流erp查询
     * @param sid     卖家账号,接口请求的公共参数sid
     * @param appkey     接口账号,接口请求的公共参数appkey
     * @param appsecret 接口秘钥,接口请求的参数appsecret ,用于计算签名
     * @param url     接口地址,接口请求的公共参数url
     * @param shop_no     店铺编号
     * @return
     */
    public static JSONObject logisticsSyncQuery(String sid, String appkey, String appsecret, String url,
                                          String shop_no) {
        WdtClient client = new WdtClient(sid, appkey, appsecret, url);
        Map<String, String> params = new HashMap<String, String>();
        params.put("shop_no", shop_no);
//        params.put("is_part_sync_able", "0");
        params.put("limit", "100");
        try {
            String response = client.execute("logistics_sync_query.php", params);
            log.info("物流erp查询结果:{}", response);
            JSONObject jsonObject = JSONObject.parseObject(response);
            if(jsonObject.getInteger("code") == 0){
                return jsonObject;
            }else{
                log.info("物流erp查询失败");
                throw new ServiceException(jsonObject.getString("message"));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static void main(String[] args) {
        WdtClient client = new WdtClient("", "", "", "");
        Map<String, String> params = new HashMap<String, String>();
        params.put("shop_no", "mytest");
        params.put("is_part_sync_able", "0");
        params.put("limit", "100");
        try {
            String response = client.execute("logistics_sync_query.php", params);
            System.out.println(response);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/yuncang/api/trade/TradePush.java
New file
@@ -0,0 +1,170 @@
package com.ruoyi.web.controller.yuncang.api.trade;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.system.model.TErpProcurement;
import com.ruoyi.system.model.TErpProcurementGoods;
import com.ruoyi.web.controller.yuncang.utils.WdtClient;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
public class TradePush {
    /**
     * 推送erp订单
     * @param sid     卖家账号,接口请求的公共参数sid
     * @param appkey     接口账号,接口请求的公共参数appkey
     * @param appsecret 接口秘钥,接口请求的参数appsecret ,用于计算签名
     * @param url     接口地址,接口请求的公共参数url
     * @param erpProcurement 采购单
     * @param erpProcurementGoods 采购单商品
     * @param trade_status 平台订单状态较多且涉及变更,详情介绍单击这里
     * @param clinicName 采购单所属诊所名称
     * @param status 平台子订单状态,子订单状态可以和主订单不一样,比如其中一个子订单退款完成,其状态是80,但主订单仍然是待发货,可选值同trade_status
     * @param refund_status 0:无退款,1:取消退款,2:已申请退款,3:等待退货,4:等待收货,5:退款成功。本字段在售前退款的时候,根据不同的场景填写不同的值,eg:申请退款值为2,取消退款值为1……
     * @param shop_no     代表店铺所有属性的唯一编码,用于店铺区分,ERP内支持自定义(ERP店铺界面设置,查看路径ERP→设置→基本设置→店铺→店铺列表),用于创建指定店铺单据信息,测试环境店铺编号信息同接口账号。ERP内shop_no对应的“店铺平台”必须为“自有/其它”。正式环境店铺创建成功后ERP会自动授权,如果自动授权失败,在ERP店铺界面(路径ERP→设置→基本设置→店铺→店铺列表)选中授权失败的店铺,点击店铺界面提供的店铺授权按钮重新授权。
     */
    public static JSONObject tradePush(String sid, String appkey, String appsecret, String url,
                                 TErpProcurement erpProcurement, List<TErpProcurementGoods> erpProcurementGoods,
                                 Integer trade_status,String clinicName,Integer status,Integer refund_status,String shop_no) {
        WdtClient client = new WdtClient(sid, appkey, appsecret, url);
        //测试环境sid、appkey、密钥请到旺店通开放平台-自助对接-申请测试环境内查看,测试环境url=https://sandbox.wangdian.cn/openapi2/
        //调用正式环境时请将sid、appkey、appsecret切换为实际参数,参数在旺店通开放平台-自助对接-应用管理内应用状态为已上线的应用中查看,调用正式环境注意切换正式环境url=https://api.wangdian.cn/openapi2/
        List<Map<String, Object>> trade_list = new ArrayList<Map<String, Object>>();
        List<Map<String, Object>> order_list = new ArrayList<Map<String, Object>>();
        for (TErpProcurementGoods erpProcurementGood : erpProcurementGoods) {
            Map<String, Object> order_1 = new HashMap<String, Object>();
            order_1.put("oid", erpProcurementGood.getId());
            order_1.put("num", erpProcurementGood.getPurchaseCount());
            order_1.put("price", erpProcurementGood.getPurchasePrice());
            order_1.put("status", status);
            order_1.put("refund_status", refund_status);
            order_1.put("goods_id", "18344");
            order_1.put("spec_id", "18656");
            order_1.put("goods_no", "ghs2");
            order_1.put("spec_no", "ghs201812070212123");
            order_1.put("goods_name", erpProcurementGood.getGoodsName());
            order_1.put("discount", 0);        //子订单折扣
            order_1.put("adjust_amount", 0);    //手工调整,特别注意:正的表示加价,负的表示减价
            order_1.put("share_discount", 0);
            order_list.add(order_1);
        }
        Map<String, Object> trade_1 = new HashMap<String, Object>();
        trade_1.put("tid", erpProcurement.getProcurementCode());
        trade_1.put("trade_status", trade_status);
        trade_1.put("pay_status", "2");
        trade_1.put("delivery_term", 1);
        trade_1.put("trade_time", DateUtils.localDateTimeToDate(erpProcurement.getCreateTime()));
        trade_1.put("pay_time", DateUtils.localDateTimeToDate(erpProcurement.getPayTime()));
        trade_1.put("buyer_nick", clinicName);
        trade_1.put("receiver_name", "123");
        trade_1.put("receiver_province", "河南省");
        trade_1.put("receiver_city", "周口市");
        trade_1.put("receiver_district", "川汇区");
        trade_1.put("receiver_address", "123");
        trade_1.put("receiver_mobile", "26283920011");
//        trade_1.put("logistics_type", 4);
        trade_1.put("post_amount", 0);
        trade_1.put("cod_amount", 0);
        trade_1.put("ext_cod_fee", 0);
        trade_1.put("other_amount", 0);
        trade_1.put("paid", erpProcurement.getPayMoney());
        trade_1.put("order_list", order_list);
        trade_list.add(trade_1);
        String trade_list_json = JSON.toJSONString(trade_list);
        Map<String, String> params = new HashMap<String, String>();
        params.put("shop_no", shop_no);
        params.put("trade_list", trade_list_json);
        try {
            String response = client.execute("trade_push.php", params);
            log.info("推送erp订单结果:{}", response);
            JSONObject jsonObject = JSONObject.parseObject(response);
            if (jsonObject.getIntValue("code") == 0) {
                log.info("推送erp订单成功");
                return jsonObject;
            } else {
                log.info("推送erp订单失败");
                throw new ServiceException(jsonObject.getString("message"));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static void main(String[] args) {
        WdtClient client = new WdtClient("传入sid", "传入appkey", "传入appsecret", "传入url");
        //测试环境sid、appkey、密钥请到旺店通开放平台-自助对接-申请测试环境内查看,测试环境url=https://sandbox.wangdian.cn/openapi2/
        //调用正式环境时请将sid、appkey、appsecret切换为实际参数,参数在旺店通开放平台-自助对接-应用管理内应用状态为已上线的应用中查看,调用正式环境注意切换正式环境url=https://api.wangdian.cn/openapi2/
        List<Map<String, Object>> trade_list = new ArrayList<Map<String, Object>>();
        List<Map<String, Object>> order_list = new ArrayList<Map<String, Object>>();
        Map<String, Object> order_1 = new HashMap<String, Object>();
        order_1.put("oid", "ghsTest121101");
        order_1.put("num", 1);
        order_1.put("price", 12);
        order_1.put("status", 30);
        order_1.put("refund_status", 0);
        order_1.put("goods_id", "18344");
        order_1.put("spec_id", "18656");
        order_1.put("goods_no", "ghs2");
        order_1.put("spec_no", "ghs201812070212123");
        order_1.put("goods_name", "123");
        order_1.put("discount", 0);        //子订单折扣
        order_1.put("adjust_amount", 0);    //手工调整,特别注意:正的表示加价,负的表示减价
        order_1.put("share_discount", 0);
        order_list.add(order_1);
        Map<String, Object> trade_1 = new HashMap<String, Object>();
        trade_1.put("tid", "AT201812110002");
        trade_1.put("trade_status", 20);
        trade_1.put("pay_status", "1");
        trade_1.put("delivery_term", 2);
        trade_1.put("trade_time", "2018-12-11 14:21:00");
        trade_1.put("buyer_nick", "三国杀");
        trade_1.put("receiver_province", "河南省");
        trade_1.put("receiver_city", "周口市");
        trade_1.put("receiver_district", "川汇区");
        trade_1.put("receiver_mobile", "26283920011");
        trade_1.put("receiver_name", "123");
        trade_1.put("receiver_address", "123");
        trade_1.put("logistics_type", 4);
        trade_1.put("post_amount", 12);
        trade_1.put("cod_amount", 2);
        trade_1.put("ext_cod_fee", 0);
        trade_1.put("other_amount", 1);
        trade_1.put("paid", 0);
        trade_1.put("order_list", order_list);
        trade_list.add(trade_1);
        String trade_list_json = JSON.toJSONString(trade_list);
        //System.out.println(purchase_info_json);
        Map<String, String> params = new HashMap<String, String>();
        params.put("shop_no", "ghs2test");
        params.put("trade_list", trade_list_json);
        try {
            String response = client.execute("trade_push.php", params);
            System.out.println(response);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/yuncang/api/trade/TradeQuery.java
New file
@@ -0,0 +1,71 @@
package com.ruoyi.web.controller.yuncang.api.trade;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.web.controller.yuncang.utils.WdtClient;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class TradeQuery {
    /**
     *
     * 订单查询
     * @param sid     卖家账号,接口请求的公共参数sid
     * @param appkey     接口账号,接口请求的公共参数appkey
     * @param appsecret     接口秘钥,接口请求的参数appsecret ,用于计算签名
     * @param url     接口地址,接口请求的公共参数url
     * @param trade_no     订单编号
     * @param start_time     开始时间
     * @param end_time     结束时间 时间跨度不能超过60分钟
     * @return
     */
    public static JSONObject tradeQuery(String sid, String appkey, String appsecret, String url,
                                        String trade_no,String start_time,String end_time) {
        WdtClient client = new WdtClient(sid, appkey, appsecret, url);
        Map<String, String> params = new HashMap<String, String>();
        params.put("start_time", start_time);
        params.put("end_time", end_time);
        params.put("trade_no", trade_no);
//        params.put("page_size", "40");
//        params.put("page_no", "0");
        try {
            String response = client.execute("trade_query.php", params);
            log.info("订单查询结果:{}", response);
            JSONObject jsonObject = JSONObject.parseObject(response);
            if(jsonObject.getInteger("code") == 0){
                return jsonObject;
            }else{
                log.info("订单查询失败");
                throw new RuntimeException(jsonObject.getString("message"));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static void main(String[] args) {
        WdtClient client = new WdtClient("apidevnew2", "hytycw02-test", "c7ae51196", "https://sandbox.wangdian.cn/openapi2/");
        Map<String, String> params = new HashMap<String, String>();
        params.put("start_time", "2025-12-11 12:00:00");
        params.put("end_time", "2025-12-11 13:00:00");
        params.put("page_size", "30");
        params.put("page_no", "0");
        try {
            String response = client.execute("trade_query.php", params);
            System.out.println(response);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/yuncang/utils/FileItem.java
New file
@@ -0,0 +1,146 @@
package com.ruoyi.web.controller.yuncang.utils;
import java.io.*;
/**
 * 文件元数据。
 *
 */
public class FileItem {
    private String fileName;
    private String mimeType;
    private byte[] content;
    private File file;
    /**
     * 基于本地文件的构造器。
     *
     * @param file 本地文件
     */
    public FileItem(File file) {
        this.file = file;
    }
    /**
     * 基于文件绝对路径的构造器。
     *
     * @param filePath 文件绝对路径
     */
    public FileItem(String filePath) {
        this(new File(filePath));
    }
    /**
     * 基于文件名和字节流的构造器。
     *
     * @param fileName 文件名
     * @param content 文件字节流
     */
    public FileItem(String fileName, byte[] content) {
        this.fileName = fileName;
        this.content = content;
    }
    /**
     * 基于文件名、字节流和媒体类型的构造器。
     *
     * @param fileName 文件名
     * @param content 文件字节流
     * @param mimeType 媒体类型
     */
    public FileItem(String fileName, byte[] content, String mimeType) {
        this(fileName, content);
        this.mimeType = mimeType;
    }
    public String getFileName() {
        if (this.fileName == null && this.file != null && this.file.exists()) {
            this.fileName = file.getName();
        }
        return this.fileName;
    }
    public String getMimeType() throws IOException {
        if (this.mimeType == null) {
            this.mimeType = getMimeType(getContent());
        }
        return this.mimeType;
    }
    /**
     * 获取文件的真实后缀名。目前只支持JPG, GIF, PNG, BMP四种图片文件。
     *
     * @param bytes 文件字节流
     * @return JPG, GIF, PNG or null
     */
    public static String getFileSuffix(byte[] bytes) {
        if (bytes == null || bytes.length < 10) {
            return null;
        }
        if (bytes[0] == 'G' && bytes[1] == 'I' && bytes[2] == 'F') {
            return "GIF";
        } else if (bytes[1] == 'P' && bytes[2] == 'N' && bytes[3] == 'G') {
            return "PNG";
        } else if (bytes[6] == 'J' && bytes[7] == 'F' && bytes[8] == 'I' && bytes[9] == 'F') {
            return "JPG";
        } else if (bytes[0] == 'B' && bytes[1] == 'M') {
            return "BMP";
        } else {
            return null;
        }
    }
    /**
     * 获取文件的真实媒体类型。目前只支持JPG, GIF, PNG, BMP四种图片文件。
     *
     * @param bytes 文件字节流
     * @return 媒体类型(MEME-TYPE)
     */
    public static String getMimeType(byte[] bytes) {
        String suffix = getFileSuffix(bytes);
        String mimeType;
        if ("JPG".equals(suffix)) {
            mimeType = "image/jpeg";
        } else if ("GIF".equals(suffix)) {
            mimeType = "image/gif";
        } else if ("PNG".equals(suffix)) {
            mimeType = "image/png";
        } else if ("BMP".equals(suffix)) {
            mimeType = "image/bmp";
        }else {
            mimeType = "application/octet-stream";
        }
        return mimeType;
    }
    public byte[] getContent() throws IOException {
        if (this.content == null && this.file != null && this.file.exists()) {
            InputStream in = null;
            ByteArrayOutputStream out = null;
            try {
                in = new FileInputStream(this.file);
                out = new ByteArrayOutputStream();
                int ch;
                while ((ch = in.read()) != -1) {
                    out.write(ch);
                }
                this.content = out.toByteArray();
            } finally {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            }
        }
        return this.content;
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/yuncang/utils/StringUtils.java
New file
@@ -0,0 +1,129 @@
package com.ruoyi.web.controller.yuncang.utils;
/**
 * 字符串工具类。
 *
 */
public abstract class StringUtils {
    private StringUtils() {}
    /**
     * 检查指定的字符串是否为空。
     * <ul>
     * <li>SysUtils.isEmpty(null) = true</li>
     * <li>SysUtils.isEmpty("") = true</li>
     * <li>SysUtils.isEmpty("   ") = true</li>
     * <li>SysUtils.isEmpty("abc") = false</li>
     * </ul>
     *
     * @param value 待检查的字符串
     * @return true/false
     */
    public static boolean isEmpty(String value) {
        int strLen;
        if (value == null || (strLen = value.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if ((Character.isWhitespace(value.charAt(i)) == false)) {
                return false;
            }
        }
        return true;
    }
    /**
     * 检查对象是否为数字型字符串,包含负数开头的。
     */
    public static boolean isNumeric(Object obj) {
        if (obj == null) {
            return false;
        }
        char[] chars = obj.toString().toCharArray();
        int length = chars.length;
        if(length < 1)
            return false;
        int i = 0;
        if(length > 1 && chars[0] == '-')
            i = 1;
        for (; i < length; i++) {
            if (!Character.isDigit(chars[i])) {
                return false;
            }
        }
        return true;
    }
    /**
     * 检查指定的字符串列表是否不为空。
     */
    public static boolean areNotEmpty(String... values) {
        boolean result = true;
        if (values == null || values.length == 0) {
            result = false;
        } else {
            for (String value : values) {
                result &= !isEmpty(value);
            }
        }
        return result;
    }
    /**
     * 把通用字符编码的字符串转化为汉字编码。
     */
    public static String unicodeToChinese(String unicode) {
        StringBuilder out = new StringBuilder();
        if (!isEmpty(unicode)) {
            for (int i = 0; i < unicode.length(); i++) {
                out.append(unicode.charAt(i));
            }
        }
        return out.toString();
    }
    public static String toUnderlineStyle(String name) {
        StringBuilder newName = new StringBuilder();
        for (int i = 0; i < name.length(); i++) {
            char c = name.charAt(i);
            if (Character.isUpperCase(c)) {
                if (i > 0) {
                    newName.append("_");
                }
                newName.append(Character.toLowerCase(c));
            } else {
                newName.append(c);
            }
        }
        return newName.toString();
    }
    public static String convertString(byte[] data, int offset, int length) {
        if (data == null) {
            return null;
        } else {
            try {
                return new String(data, offset, length, "UTF-8");
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
    public static byte[] convertBytes(String data) {
        if (data == null) {
            return null;
        } else {
            try {
                return data.getBytes("UTF-8");
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/yuncang/utils/WdtClient.java
New file
@@ -0,0 +1,127 @@
package com.ruoyi.web.controller.yuncang.utils;
import com.ruoyi.web.controller.yuncang.utils.WebUtils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Map;
public class WdtClient {
    private String appkey;
    private String appsecret;
    private String sid;
    private String baseUrl;
    private int connectTimeout = 3000;//3秒
    private int readTimeout = 15000;//15秒
    public WdtClient(String sid, String appkey, String appsecret, String baseUrl)
    {
        this.sid = sid;
        this.appkey = appkey;
        this.appsecret = appsecret;
        this.baseUrl = baseUrl;
        if(!this.baseUrl.endsWith("/"))
            this.baseUrl = this.baseUrl+"/";
    }
    public void setTimeout(int connectTimeout, int readTimeout)
    {
        this.connectTimeout = connectTimeout;
        this.readTimeout = readTimeout;
    }
    private static String getStringFromException(Throwable e) {
        String result = "";
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        PrintStream ps = new PrintStream(bos);
        e.printStackTrace(ps);
        try {
            result = bos.toString("UTF-8");
        } catch (IOException ioe) {
        }
        return result;
    }
    private static byte[] encryptMD5(String data) throws IOException {
        byte[] bytes = null;
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            bytes = md.digest(data.getBytes("UTF-8"));
        } catch (GeneralSecurityException gse) {
            String msg = getStringFromException(gse);
            throw new IOException(msg);
        }
        return bytes;
    }
    private static String byte2hex(byte[] bytes) {
        StringBuilder sign = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if (hex.length() == 1) {
                //保证所有的16进制都是两位:00-ff,其中[80~ff]代表[-128,-1]
                sign.append("0");
            }
            sign.append(hex);
        }
        return sign.toString();
    }
    /**
     * 给TOP请求签名。
     *
     * @param params 所有字符型的TOP请求参数
     * @param appsecret 签名密钥
     * @return 签名
     * @throws IOException
     */
    public static String signRequest(Map<String, String> params, String appsecret) throws IOException {
        // 第一步:检查参数是否已经排序
        String[] keys = params.keySet().toArray(new String[0]);
        Arrays.sort(keys);
        // 第二步:把所有参数名和参数值串在一起
        StringBuilder query = new StringBuilder();
        for (String key : keys) {
            if("sign".equals(key))
                continue;
            if(query.length() > 0)
                query.append(';');
            int len = key.length();
            query.append(String.format("%02d", len)).append('-').append(key).append(':');
            String value = params.get(key);
            len = value.length();
            query.append(String.format("%04d", len)).append('-').append(value);
        }
        query.append(appsecret);
        // 第三步:使用MD5加密
        byte[] bytes = encryptMD5(query.toString());
        // 第四步:把二进制转化为大写的十六进制
        return byte2hex(bytes);
    }
    public String execute(String relativeUrl, Map<String, String> params) throws IOException {
        params.put("appkey", this.appkey);
        params.put("sid", this.sid);
        params.put("timestamp", Long.toString(System.currentTimeMillis()/1000));
        params.put("sign", signRequest(params, this.appsecret));
        return WebUtils.doPost(this.baseUrl + relativeUrl, params, "UTF-8", connectTimeout, readTimeout, null);
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/yuncang/utils/WebUtils.java
New file
@@ -0,0 +1,560 @@
package com.ruoyi.web.controller.yuncang.utils;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
//import javax.net.ssl.HostnameVerifier;
//import javax.net.ssl.HttpsURLConnection;
//import javax.net.ssl.SSLContext;
//import javax.net.ssl.SSLSession;
//import javax.net.ssl.TrustManager;
//import javax.net.ssl.X509TrustManager;
/**
 * 网络工具类。
 *
 */
public abstract class WebUtils {
    private static final String DEFAULT_CHARSET = "UTF-8";
    private static final String METHOD_POST = "POST";
    private static final String METHOD_GET = "GET";
    //private static final Certificate verisign; // 根证书
    //private static boolean ignoreSSLCheck; // 忽略SSL检查
//    static {
//        InputStream input = null;
//        try {
//            CertificateFactory cf = CertificateFactory.getInstance("X.509");
//            input = WebUtils.class.getResourceAsStream("/verisign.crt");
//            verisign = cf.generateCertificate(input);
//        } catch (Exception e) {
//            throw new RuntimeException(e);
//        } finally {
//            if (input != null) {
//                try {
//                    input.close();
//                } catch (IOException e) {
//                }
//            }
//        }
//    }
//    public static class VerisignTrustManager implements X509TrustManager {
//        public X509Certificate[] getAcceptedIssuers() {
//            return null;
//        }
//
//        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
//        }
//
//        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
//            Exception exp = null;
//
//            for (X509Certificate cert : chain) {
//                cert.checkValidity(); // 验证证书有效期
//                try {
//                    cert.verify(verisign.getPublicKey());// 验证签名
//                    exp = null;
//                    break;
//                } catch (Exception e) {
//                    exp = e;
//                }
//            }
//
//            if (exp != null) {
//                throw new CertificateException(exp);
//            }
//        }
//    }
//
//    public static class TrustAllTrustManager implements X509TrustManager {
//        public X509Certificate[] getAcceptedIssuers() {
//            return null;
//        }
//
//        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
//        }
//
//        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
//        }
//    }
    private WebUtils() {
    }
//    public static void setIgnoreSSLCheck(boolean ignoreSSLCheck) {
//        WebUtils.ignoreSSLCheck = ignoreSSLCheck;
//    }
    /**
     * 执行HTTP POST请求。
     *
     * @param url 请求地址
     * @param params 请求参数
     * @return 响应字符串
     */
    public static String doPost(String url, Map<String, String> params, int connectTimeout, int readTimeout) throws IOException {
        return doPost(url, params, DEFAULT_CHARSET, connectTimeout, readTimeout);
    }
    /**
     * 执行HTTP POST请求。
     *
     * @param url 请求地址
     * @param params 请求参数
     * @param charset 字符集,如UTF-8, GBK, GB2312
     * @return 响应字符串
     */
    public static String doPost(String url, Map<String, String> params, String charset, int connectTimeout, int readTimeout) throws IOException {
        return doPost(url, params, charset, connectTimeout, readTimeout, null);
    }
    public static String doPost(String url, Map<String, String> params, String charset, int connectTimeout, int readTimeout, Map<String, String> headerMap) throws IOException {
        String ctype = "application/x-www-form-urlencoded;charset=" + charset;
        String query = buildQuery(params, charset);
        byte[] content = {};
        if (query != null) {
            content = query.getBytes(charset);
        }
        return _doPost(url, ctype, content, connectTimeout, readTimeout, headerMap);
    }
    /**
     * 执行HTTP POST请求。
     *
     * @param url 请求地址
     * @param ctype 请求类型
     * @param content 请求字节数组
     * @return 响应字符串
     */
    public static String doPost(String url, String ctype, byte[] content, int connectTimeout, int readTimeout) throws IOException {
        return _doPost(url, ctype, content, connectTimeout, readTimeout, null);
    }
    private static String _doPost(String url, String ctype, byte[] content, int connectTimeout, int readTimeout, Map<String, String> headerMap) throws IOException {
        HttpURLConnection conn = null;
        OutputStream out = null;
        String rsp = null;
        try {
            conn = getConnection(new URL(url), METHOD_POST, ctype, headerMap);
            conn.setConnectTimeout(connectTimeout);
            conn.setReadTimeout(readTimeout);
            out = conn.getOutputStream();
            out.write(content);
            rsp = getResponseAsString(conn);
        } finally {
            if (out != null) {
                out.close();
            }
            if (conn != null) {
                conn.disconnect();
            }
        }
        return rsp;
    }
    /**
     * 执行带文件上传的HTTP POST请求。
     *
     * @param url 请求地址
     * @param fileParams 文件请求参数
     * @return 响应字符串
     */
    public static String doPost(String url, Map<String, String> params, Map<String, FileItem> fileParams, int connectTimeout, int readTimeout) throws IOException {
        if (fileParams == null || fileParams.isEmpty()) {
            return doPost(url, params, DEFAULT_CHARSET, connectTimeout, readTimeout);
        } else {
            return doPost(url, params, fileParams, DEFAULT_CHARSET, connectTimeout, readTimeout);
        }
    }
    public static String doPost(String url, Map<String, String> params, Map<String, FileItem> fileParams, String charset, int connectTimeout, int readTimeout) throws IOException {
        return doPost(url, params, fileParams, charset, connectTimeout, readTimeout, null);
    }
    /**
     * 执行带文件上传的HTTP POST请求。
     *
     * @param url 请求地址
     * @param fileParams 文件请求参数
     * @param charset 字符集,如UTF-8, GBK, GB2312
     * @param headerMap 需要传递的header头,可以为空
     * @return 响应字符串
     */
    public static String doPost(String url, Map<String, String> params, Map<String, FileItem> fileParams, String charset,
            int connectTimeout, int readTimeout, Map<String, String> headerMap) throws IOException {
        if (fileParams == null || fileParams.isEmpty()) {
            return doPost(url, params, charset, connectTimeout, readTimeout, headerMap);
        } else {
            return _doPostWithFile(url, params, fileParams, charset, connectTimeout, readTimeout, headerMap);
        }
    }
    private static String _doPostWithFile(String url, Map<String, String> params, Map<String, FileItem> fileParams,
            String charset, int connectTimeout, int readTimeout, Map<String, String> headerMap) throws IOException {
        String boundary = String.valueOf(System.nanoTime()); // 随机分隔线
        HttpURLConnection conn = null;
        OutputStream out = null;
        String rsp = null;
        try {
            String ctype = "multipart/form-data;charset=" + charset + ";boundary=" + boundary;
            conn = getConnection(new URL(url), METHOD_POST, ctype, headerMap);
            conn.setConnectTimeout(connectTimeout);
            conn.setReadTimeout(readTimeout);
            out = conn.getOutputStream();
            byte[] entryBoundaryBytes = ("\r\n--" + boundary + "\r\n").getBytes(charset);
            // 组装文本请求参数
            Set<Entry<String, String>> textEntrySet = params.entrySet();
            for (Entry<String, String> textEntry : textEntrySet) {
                byte[] textBytes = getTextEntry(textEntry.getKey(), textEntry.getValue(), charset);
                out.write(entryBoundaryBytes);
                out.write(textBytes);
            }
            // 组装文件请求参数
            Set<Entry<String, FileItem>> fileEntrySet = fileParams.entrySet();
            for (Entry<String, FileItem> fileEntry : fileEntrySet) {
                FileItem fileItem = fileEntry.getValue();
                if (fileItem.getContent() == null) {
                    continue;
                }
                byte[] fileBytes = getFileEntry(fileEntry.getKey(), fileItem.getFileName(), fileItem.getMimeType(), charset);
                out.write(entryBoundaryBytes);
                out.write(fileBytes);
                out.write(fileItem.getContent());
            }
            // 添加请求结束标志
            byte[] endBoundaryBytes = ("\r\n--" + boundary + "--\r\n").getBytes(charset);
            out.write(endBoundaryBytes);
            rsp = getResponseAsString(conn);
        } finally {
            if (out != null) {
                out.close();
            }
            if (conn != null) {
                conn.disconnect();
            }
        }
        return rsp;
    }
    private static byte[] getTextEntry(String fieldName, String fieldValue, String charset) throws IOException {
        StringBuilder entry = new StringBuilder();
        entry.append("Content-Disposition:form-data;name=\"");
        entry.append(fieldName);
        entry.append("\"\r\nContent-Type:text/plain\r\n\r\n");
        entry.append(fieldValue);
        return entry.toString().getBytes(charset);
    }
    private static byte[] getFileEntry(String fieldName, String fileName, String mimeType, String charset) throws IOException {
        StringBuilder entry = new StringBuilder();
        entry.append("Content-Disposition:form-data;name=\"");
        entry.append(fieldName);
        entry.append("\";filename=\"");
        entry.append(fileName);
        entry.append("\"\r\nContent-Type:");
        entry.append(mimeType);
        entry.append("\r\n\r\n");
        return entry.toString().getBytes(charset);
    }
    /**
     * 执行HTTP GET请求。
     *
     * @param url 请求地址
     * @param params 请求参数
     * @return 响应字符串
     */
    public static String doGet(String url, Map<String, String> params) throws IOException {
        return doGet(url, params, DEFAULT_CHARSET);
    }
    /**
     * 执行HTTP GET请求。
     *
     * @param url 请求地址
     * @param params 请求参数
     * @param charset 字符集,如UTF-8, GBK, GB2312
     * @return 响应字符串
     */
    public static String doGet(String url, Map<String, String> params, String charset) throws IOException {
        HttpURLConnection conn = null;
        String rsp = null;
        try {
            String ctype = "application/x-www-form-urlencoded;charset=" + charset;
            String query = buildQuery(params, charset);
            conn = getConnection(buildGetUrl(url, query), METHOD_GET, ctype, null);
            rsp = getResponseAsString(conn);
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }
        return rsp;
    }
    private static HttpURLConnection getConnection(URL url, String method, String ctype, Map<String, String> headerMap) throws IOException {
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//        if (conn instanceof HttpsURLConnection) {
//            HttpsURLConnection connHttps = (HttpsURLConnection) conn;
//            if (ignoreSSLCheck) {
//                try {
//                    SSLContext ctx = SSLContext.getInstance("TLS");
//                    ctx.init(null, new TrustManager[] { new TrustAllTrustManager() }, new SecureRandom());
//                    connHttps.setSSLSocketFactory(ctx.getSocketFactory());
//                    connHttps.setHostnameVerifier(new HostnameVerifier() {
//                        public boolean verify(String hostname, SSLSession session) {
//                            return true;
//                        }
//                    });
//                } catch (Exception e) {
//                    throw new IOException(e);
//                }
//            } else {
//                try {
//                    SSLContext ctx = SSLContext.getInstance("TLS");
//                    ctx.init(null, new TrustManager[] { new VerisignTrustManager() }, new SecureRandom());
//                    connHttps.setSSLSocketFactory(ctx.getSocketFactory());
//                } catch (Exception e) {
//                    throw new IOException(e);
//                }
//            }
//            conn = connHttps;
//        }
        conn.setRequestMethod(method);
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setRequestProperty("Accept", "*/*");
        conn.setRequestProperty("User-Agent", "wdt-java-sdk");
        conn.setRequestProperty("Content-Type", ctype);
        if (headerMap != null) {
            for (Entry<String, String> entry : headerMap.entrySet()) {
                conn.setRequestProperty(entry.getKey(), entry.getValue());
            }
        }
        return conn;
    }
    private static URL buildGetUrl(String strUrl, String query) throws IOException {
        URL url = new URL(strUrl);
        if (StringUtils.isEmpty(query)) {
            return url;
        }
        if (StringUtils.isEmpty(url.getQuery())) {
            if (strUrl.endsWith("?")) {
                strUrl = strUrl + query;
            } else {
                strUrl = strUrl + "?" + query;
            }
        } else {
            if (strUrl.endsWith("&")) {
                strUrl = strUrl + query;
            } else {
                strUrl = strUrl + "&" + query;
            }
        }
        return new URL(strUrl);
    }
    public static String buildQuery(Map<String, String> params, String charset) throws IOException {
        if (params == null || params.isEmpty()) {
            return null;
        }
        StringBuilder query = new StringBuilder();
        Set<Entry<String, String>> entries = params.entrySet();
        boolean hasParam = false;
        for (Entry<String, String> entry : entries) {
            String name = entry.getKey();
            String value = entry.getValue();
            // 忽略参数名或参数值为空的参数
            if (StringUtils.areNotEmpty(name, value)) {
                if (hasParam) {
                    query.append("&");
                } else {
                    hasParam = true;
                }
                query.append(name).append("=").append(URLEncoder.encode(value, charset));
            }
        }
        return query.toString();
    }
    protected static String getResponseAsString(HttpURLConnection conn) throws IOException {
        String charset = getResponseCharset(conn.getContentType());
        InputStream es = conn.getErrorStream();
        if (es == null) {
            return getStreamAsString(conn.getInputStream(), charset);
        } else {
            String msg = getStreamAsString(es, charset);
            if (StringUtils.isEmpty(msg)) {
                throw new IOException(conn.getResponseCode() + ":" + conn.getResponseMessage());
            } else {
                throw new IOException(msg);
            }
        }
    }
    private static String getStreamAsString(InputStream stream, String charset) throws IOException {
        try {
            Reader reader = new InputStreamReader(stream, charset);
            StringBuilder response = new StringBuilder();
            final char[] buff = new char[1024];
            int read = 0;
            while ((read = reader.read(buff)) > 0) {
                // 一次读取1024个字符
                response.append(buff, 0, read);
            }
            return response.toString();
        } finally {
            if (stream != null) {
                stream.close();
            }
        }
    }
    private static String getResponseCharset(String ctype) {
        String charset = DEFAULT_CHARSET;
        if (!StringUtils.isEmpty(ctype)) {
            String[] params = ctype.split(";");
            for (String param : params) {
                param = param.trim();
                if (param.startsWith("charset")) {
                    String[] pair = param.split("=", 2);
                    if (pair.length == 2) {
                        if (!StringUtils.isEmpty(pair[1])) {
                            charset = pair[1].trim();
                        }
                    }
                    break;
                }
            }
        }
        return charset;
    }
    /**
     * 使用默认的UTF-8字符集反编码请求参数值。
     *
     * @param value 参数值
     * @return 反编码后的参数值
     */
    public static String decode(String value) {
        return decode(value, DEFAULT_CHARSET);
    }
    /**
     * 使用默认的UTF-8字符集编码请求参数值。
     *
     * @param value 参数值
     * @return 编码后的参数值
     */
    public static String encode(String value) {
        return encode(value, DEFAULT_CHARSET);
    }
    /**
     * 使用指定的字符集反编码请求参数值。
     *
     * @param value 参数值
     * @param charset 字符集
     * @return 反编码后的参数值
     */
    public static String decode(String value, String charset) {
        String result = null;
        if (!StringUtils.isEmpty(value)) {
            try {
                result = URLDecoder.decode(value, charset);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return result;
    }
    /**
     * 使用指定的字符集编码请求参数值。
     *
     * @param value 参数值
     * @param charset 字符集
     * @return 编码后的参数值
     */
    public static String encode(String value, String charset) {
        String result = null;
        if (!StringUtils.isEmpty(value)) {
            try {
                result = URLEncoder.encode(value, charset);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return result;
    }
    public static Map<String, String> getParamsFromUrl(String url) {
        Map<String, String> map = null;
        if (url != null && url.indexOf('?') != -1) {
            map = splitUrlQuery(url.substring(url.indexOf('?') + 1));
        }
        if (map == null) {
            map = new HashMap<String, String>();
        }
        return map;
    }
    /**
     * 从URL中提取所有的参数。
     *
     * @param query URL地址
     * @return 参数映射
     */
    public static Map<String, String> splitUrlQuery(String query) {
        Map<String, String> result = new HashMap<String, String>();
        String[] pairs = query.split("&");
        if (pairs != null && pairs.length > 0) {
            for (String pair : pairs) {
                String[] param = pair.split("=", 2);
                if (param != null && param.length == 2) {
                    result.put(param[0], param[1]);
                }
            }
        }
        return result;
    }
}