---
url: "https://pay.weixin.qq.com/doc/v3/merchant/4012533439-java.md"
title: "查询投诉单协商历史-请求示例-java"
doc_id: 4012533439
example_lang: "java"
---

## Java


需配合微信支付工具库 WXPayUtility 使用，请参考 [Java](https://pay.weixin.qq.com/doc/v3/merchant/4014931831.md)

```
package com.java.demo;

import com.java.utils.WXPayUtility; // 引用微信支付工具库，参考：https://pay.weixin.qq.com/doc/v3/merchant/4014931831

import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 查询投诉单协商历史
 */
public class QueryNegotiationHistoryV2 {
  private static String HOST = "https://api.mch.weixin.qq.com";
  private static String METHOD = "GET";
  private static String PATH = "/v3/merchant-service/complaints-v2/{complaint_id}/negotiation-historys";

  public static void main(String[] args) {
    // TODO: 请准备商户开发必要参数，参考：https://pay.weixin.qq.com/doc/v3/merchant/4013070756
    QueryNegotiationHistoryV2 client = new QueryNegotiationHistoryV2(
      "19xxxxxxxx",                    // 商户号，是由微信支付系统生成并分配给每个商户的唯一标识符，商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/merchant/4013070756
      "1DDE55AD98Exxxxxxxxxx",         // 商户API证书序列号，如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013053053
      "/path/to/apiclient_key.pem",     // 商户API证书私钥文件路径，本地文件路径
      "PUB_KEY_ID_xxxxxxxxxxxxx",      // 微信支付公钥ID，如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013038816
      "/path/to/wxp_pub.pem"           // 微信支付公钥文件路径，本地文件路径
    );

    QueryNegotiationHistoryV2Request request = new QueryNegotiationHistoryV2Request();
    request.complaintId = "200201820200101080076610000";
    request.limit = 50L;
    request.offset = 10L;
    try {
      QueryNegotiationHistoryV2Response response = client.run(request);
        // TODO: 请求成功，继续业务逻辑
        System.out.println(response);
    } catch (WXPayUtility.ApiException e) {
        // TODO: 请求失败，根据状态码执行不同的逻辑
        e.printStackTrace();
    }
  }

  public QueryNegotiationHistoryV2Response run(QueryNegotiationHistoryV2Request request) {
    String uri = PATH;
    uri = uri.replace("{complaint_id}", WXPayUtility.urlEncode(request.complaintId));
    Map<String, Object> args = new HashMap<>();
    args.put("limit", request.limit);
    args.put("offset", request.offset);
    String queryString = WXPayUtility.urlEncode(args);
    if (!queryString.isEmpty()) {
        uri = uri + "?" + queryString;
    }

    Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
    reqBuilder.addHeader("Accept", "application/json");
    reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
    reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, null));
    reqBuilder.method(METHOD, null);
    Request httpRequest = reqBuilder.build();

    // 发送HTTP请求
    OkHttpClient client = new OkHttpClient.Builder().build();
    try (Response httpResponse = client.newCall(httpRequest).execute()) {
      String respBody = WXPayUtility.extractBody(httpResponse);
      if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
        // 2XX 成功，验证应答签名
        WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
            httpResponse.headers(), respBody);

        // 从HTTP应答报文构建返回数据
        return WXPayUtility.fromJson(respBody, QueryNegotiationHistoryV2Response.class);
      } else {
        throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
      }
    } catch (IOException e) {
      throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
    }
  }

  private final String mchid;
  private final String certificateSerialNo;
  private final PrivateKey privateKey;
  private final String wechatPayPublicKeyId;
  private final PublicKey wechatPayPublicKey;

  public QueryNegotiationHistoryV2(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
    this.mchid = mchid;
    this.certificateSerialNo = certificateSerialNo;
    this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
    this.wechatPayPublicKeyId = wechatPayPublicKeyId;
    this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
  }

  public static class QueryNegotiationHistoryV2Request {
    @SerializedName("complaint_id")
    @Expose(serialize = false)
    public String complaintId;

    @SerializedName("limit")
    @Expose(serialize = false)
    public Long limit;

    @SerializedName("offset")
    @Expose(serialize = false)
    public Long offset;
  }

  public static class QueryNegotiationHistoryV2Response {
    @SerializedName("data")
    public List<ComplaintNegotiationHistoryWithLogId> data;

    @SerializedName("limit")
    public Long limit;

    @SerializedName("offset")
    public Long offset;

    @SerializedName("total_count")
    public Long totalCount;
  }

  public static class ComplaintNegotiationHistoryWithLogId {
    @SerializedName("log_id")
    public String logId;

    @SerializedName("operator")
    public String operator;

    @SerializedName("operate_time")
    public String operateTime;

    @SerializedName("operate_type")
    public ComplaintNegotiationOperateType operateType;

    @SerializedName("operate_details")
    public String operateDetails;

    @SerializedName("image_list")
    public List<String> imageList;

    @SerializedName("complaint_media_list")
    public ComplaintMedia complaintMediaList;

    @SerializedName("user_appy_platform_service_reason")
    public String userAppyPlatformServiceReason;

    @SerializedName("user_appy_platform_service_reason_description")
    public String userAppyPlatformServiceReasonDescription;

    @SerializedName("normal_message")
    public NormalMessage normalMessage;

    @SerializedName("click_message")
    public ClickMessage clickMessage;
  }

  public enum ComplaintNegotiationOperateType {
    @SerializedName("USER_CREATE_COMPLAINT")
    USER_CREATE_COMPLAINT,
    @SerializedName("USER_CONTINUE_COMPLAINT")
    USER_CONTINUE_COMPLAINT,
    @SerializedName("USER_RESPONSE")
    USER_RESPONSE,
    @SerializedName("PLATFORM_RESPONSE")
    PLATFORM_RESPONSE,
    @SerializedName("MERCHANT_RESPONSE")
    MERCHANT_RESPONSE,
    @SerializedName("MERCHANT_CONFIRM_COMPLETE")
    MERCHANT_CONFIRM_COMPLETE,
    @SerializedName("USER_CREATE_COMPLAINT_SYSTEM_MESSAGE")
    USER_CREATE_COMPLAINT_SYSTEM_MESSAGE,
    @SerializedName("COMPLAINT_FULL_REFUNDED_SYSTEM_MESSAGE")
    COMPLAINT_FULL_REFUNDED_SYSTEM_MESSAGE,
    @SerializedName("USER_CONTINUE_COMPLAINT_SYSTEM_MESSAGE")
    USER_CONTINUE_COMPLAINT_SYSTEM_MESSAGE,
    @SerializedName("USER_REVOKE_COMPLAINT")
    USER_REVOKE_COMPLAINT,
    @SerializedName("USER_COMFIRM_COMPLAINT")
    USER_COMFIRM_COMPLAINT,
    @SerializedName("PLATFORM_HELP_APPLICATION")
    PLATFORM_HELP_APPLICATION,
    @SerializedName("USER_APPLY_PLATFORM_HELP")
    USER_APPLY_PLATFORM_HELP,
    @SerializedName("MERCHANT_APPROVE_REFUND")
    MERCHANT_APPROVE_REFUND,
    @SerializedName("MERCHANT_REFUSE_RERUND")
    MERCHANT_REFUSE_RERUND,
    @SerializedName("USER_SUBMIT_SATISFACTION")
    USER_SUBMIT_SATISFACTION,
    @SerializedName("SERVICE_ORDER_CANCEL")
    SERVICE_ORDER_CANCEL,
    @SerializedName("SERVICE_ORDER_COMPLETE")
    SERVICE_ORDER_COMPLETE,
    @SerializedName("COMPLAINT_PARTIAL_REFUNDED_SYSTEM_MESSAGE")
    COMPLAINT_PARTIAL_REFUNDED_SYSTEM_MESSAGE,
    @SerializedName("COMPLAINT_REFUND_RECEIVED_SYSTEM_MESSAGE")
    COMPLAINT_REFUND_RECEIVED_SYSTEM_MESSAGE,
    @SerializedName("COMPLAINT_ENTRUSTED_REFUND_SYSTEM_MESSAGE")
    COMPLAINT_ENTRUSTED_REFUND_SYSTEM_MESSAGE,
    @SerializedName("USER_APPLY_PLATFORM_SERVICE")
    USER_APPLY_PLATFORM_SERVICE,
    @SerializedName("USER_CANCEL_PLATFORM_SERVICE")
    USER_CANCEL_PLATFORM_SERVICE,
    @SerializedName("PLATFORM_SERVICE_FINISHED")
    PLATFORM_SERVICE_FINISHED,
    @SerializedName("USER_CLICK_RESPONSE")
    USER_CLICK_RESPONSE
  }

  public static class ComplaintMedia {
    @SerializedName("media_type")
    public ComplaintMediaType mediaType;

    @SerializedName("media_url")
    public List<String> mediaUrl = new ArrayList<String>();
  }

  public static class NormalMessage {
    @SerializedName("blocks")
    public List<Block> blocks;

    @SerializedName("sender_identity")
    public SenderIdentity senderIdentity;

    @SerializedName("custom_data")
    public String customData;
  }

  public static class ClickMessage {
    @SerializedName("message_content")
    public String messageContent;

    @SerializedName("action_id")
    public String actionId;

    @SerializedName("clicked_log_id")
    public String clickedLogId;
  }

  public enum ComplaintMediaType {
    @SerializedName("USER_COMPLAINT_IMAGE")
    USER_COMPLAINT_IMAGE,
    @SerializedName("OPERATION_IMAGE")
    OPERATION_IMAGE
  }

  public static class Block {
    @SerializedName("type")
    public BlockType type;

    @SerializedName("text")
    public Text text;

    @SerializedName("image")
    public Image image;

    @SerializedName("link")
    public Link link;

    @SerializedName("faq_list")
    public FaqList faqList;

    @SerializedName("button")
    public Button button;

    @SerializedName("button_group")
    public ButtonGroup buttonGroup;
  }

  public enum SenderIdentity {
    @SerializedName("UNKNOWN")
    UNKNOWN,
    @SerializedName("MANUAL")
    MANUAL,
    @SerializedName("MACHINE")
    MACHINE
  }

  public enum BlockType {
    @SerializedName("TEXT")
    TEXT,
    @SerializedName("IMAGE")
    IMAGE,
    @SerializedName("LINK")
    LINK,
    @SerializedName("FAQ_LIST")
    FAQ_LIST,
    @SerializedName("BUTTON")
    BUTTON,
    @SerializedName("BUTTON_GROUP")
    BUTTON_GROUP
  }

  public static class Text {
    @SerializedName("text")
    public String text;

    @SerializedName("color")
    public TextColor color;

    @SerializedName("is_bold")
    public Boolean isBold;
  }

  public static class Image {
    @SerializedName("media_id")
    public String mediaId;

    @SerializedName("image_style_type")
    public ImageStyleType imageStyleType;
  }

  public static class Link {
    @SerializedName("text")
    public String text;

    @SerializedName("action")
    public ClickAction action;

    @SerializedName("invalid_info")
    public InvalidInfo invalidInfo;
  }

  public static class FaqList {
    @SerializedName("faqs")
    public List<FaqListItem> faqs;
  }

  public static class Button {
    @SerializedName("text")
    public String text;

    @SerializedName("action")
    public ClickAction action;

    @SerializedName("invalid_info")
    public InvalidInfo invalidInfo;
  }

  public static class ButtonGroup {
    @SerializedName("buttons")
    public List<InnerButton> buttons;

    @SerializedName("button_layout")
    public ButtonLayout buttonLayout;

    @SerializedName("invalid_info")
    public InvalidInfo invalidInfo;
  }

  public enum TextColor {
    @SerializedName("DEFAULT")
    DEFAULT,
    @SerializedName("SECONDARY")
    SECONDARY
  }

  public enum ImageStyleType {
    @SerializedName("IMAGE_STYLE_TYPE_NARROW")
    IMAGE_STYLE_TYPE_NARROW,
    @SerializedName("IMAGE_STYLE_TYPE_WIDE")
    IMAGE_STYLE_TYPE_WIDE
  }

  public static class ClickAction {
    @SerializedName("action_type")
    public ActionType actionType;

    @SerializedName("jump_url")
    public String jumpUrl;

    @SerializedName("mini_program_jump_info")
    public MiniProgramJump miniProgramJumpInfo;

    @SerializedName("message_info")
    public MessageInfo messageInfo;

    @SerializedName("action_id")
    public String actionId;
  }

  public static class InvalidInfo {
    @SerializedName("expired_time")
    public String expiredTime;

    @SerializedName("multi_clickable")
    public Boolean multiClickable;
  }

  public static class FaqListItem {
    @SerializedName("faq_id")
    public String faqId;

    @SerializedName("faq_title")
    public String faqTitle;

    @SerializedName("action")
    public ClickAction action;
  }

  public static class InnerButton {
    @SerializedName("text")
    public String text;

    @SerializedName("action")
    public ClickAction action;
  }

  public enum ButtonLayout {
    @SerializedName("LAYOUT_UNKNOWN")
    LAYOUT_UNKNOWN,
    @SerializedName("LAYOUT_HORIZONTAL")
    LAYOUT_HORIZONTAL,
    @SerializedName("LAYOUT_VERTICAL")
    LAYOUT_VERTICAL
  }

  public enum ActionType {
    @SerializedName("ACTION_TYPE_SEND_MESSAGE")
    ACTION_TYPE_SEND_MESSAGE,
    @SerializedName("ACTION_TYPE_JUMP_URL")
    ACTION_TYPE_JUMP_URL,
    @SerializedName("ACTION_TYPE_JUMP_MINI_PROGRAM")
    ACTION_TYPE_JUMP_MINI_PROGRAM
  }

  public static class MiniProgramJump {
    @SerializedName("appid")
    public String appid;

    @SerializedName("path")
    public String path;
  }

  public static class MessageInfo {
    @SerializedName("content")
    public String content;

    @SerializedName("custom_data")
    public String customData;
  }

}

```
