我在互联网上找不到任何帮助,所以我在这里问。我想用Java类创建一个Google卡。因此,我要创建的JSON是:

{
   "thread":{
      "name":"some url here"
   },
   "cards":[
      {
         "sections":[
            {
               "widgets":[
                  {
                     "textParagraph":{
                        "text":"bla bla"
                     }
                  },
                  {
                     "buttons":[
                        {
                           "textButton":{
                              "text":"reminder in 10",
                              "onClick":{
                                 "openLink":{
                                    "url":"some Method"
                                 }
                              }
                           }
                        }
                     ]
                  }
               ]
            }
         ]
      }
   ]
}


我尝试了几件事。我什至发现了一个生成POJO的站点,但我听不懂。我的尝试是这样的:

 Cards cards = new Cards();
 Sections sections = new Sections();
 Widgets widgets = new Widgets();
 TextParagraph textParagraph = new TextParagraph();
 Text text = new Text();
 Buttons button = new Buttons();
 TextButton textButton = new TextButton();
 OnClick onClick = new OnClick();
 OpenLink openLink = new OpenLink();
 NoNameClass haha = new NoNameClass();
 ThreadX threadx = new ThreadX();

 threadx.name = "spaces/" + reminder.getSpaceId() + "/threads/" + reminder.getThreadId();
 text.text = "<" + reminder.getSenderDisplayName() + "> " + reminder.getWhat();
 openLink.url = "https://media0.giphy.com/media/QNnKbtl03OGsM/giphy.gif?cid=3640f6095c5851de3064736a2ef2345a";
 onClick.openLink = openLink;
 textButton.onClick = onClick;
 textButton.text = "se 10";
 haha.textButton = textButton;
 textParagraph.textParagraph = text;
 button.buttons = Lists.newArrayList(haha);
 widgets.widgets = Lists.newArrayList(textParagraph, button);
 sections.sections = Lists.newArrayList(widgets);
 cards.thread = threadx;
 cards.cards = Lists.newArrayList(sections);


并发送该请求,我创建了一个JsonHttpContent

private String send(GenericUrl url, Cards message, String httpMethod) {
    HttpContent content = new JsonHttpContent(new JacksonFactory(),message);

    HttpRequest request;
    try {
        if (httpMethod.equals("POST")) {
            request = requestFactory.buildPostRequest(url, content);
        } else {
            request = requestFactory.buildGetRequest(url);
        }
    } catch (Exception e) {
        logger.error("Error creating request using url: {}", url, e);
        return null;
    }

    String response = "";
    try {
        HttpResponse httpResponse = request.execute();
        response = httpResponse.parseAsString();
    } catch (IOException e) {
        logger.error("Error creating request using url: {}", url, e);
    }

    return response;
}


但这根本不起作用,我将JsonIgnoreProperties设为true
但我得到那个错误

{
   "error":{
      "code":400,
      "message":"Message cannot be empty. Discarding empty create message request in spaces/AAAADvB8eGY.",
      "errors":[
         {
            "message":"Message cannot be empty. Discarding empty create message request in spaces/AAAADvB8eGY.",
            "domain":"global",
            "reason":"badRequest"
         }
      ],
      "status":"INVALID_ARGUMENT"
   }
}


我已经设置了很多参数,但是什么也没读,所以我需要帮助。

最佳答案

Google API通常不容易构建结构化数据模型。上
Card Formatting Messages页面上,我们可以看到许多用于不同类型卡的不同JSON有效负载。在Github上,我们可以找到Hangouts Chat code samples项目,该项目引入了CardResponseBuilder类,该类提供了一些构建器方法来构建不同种类的卡。我认为,这是一种很好的方法。如果可以,您可以尝试使用此类。它依赖于javax.json库。使用此类并知道JacksonMap序列化为JSON ObjectList序列化为JSON Array,我们可以创建非常相似的类:

class CardResponseBuilder {

    private interface Builder {
        Object get();
    }

    private ObjectBuilder createObjectBuilder() {
        return new ObjectBuilder();
    }

    private static class ObjectBuilder implements Builder {
        Map<String, Object> map = new HashMap<>(5);

        ObjectBuilder add(String key, Object value) {
            map.put(key, value);
            return this;
        }

        ObjectBuilder add(String key, Builder builder) {
            return add(key, builder.get());
        }

        @Override
        public Map<String, Object> get() {
            return map;
        }
    }

    private ArrayBuilder createArrayBuilder() {
        return new ArrayBuilder();
    }

    private static class ArrayBuilder implements Builder {
        List<Object> list = new ArrayList<>(4);

        ArrayBuilder add(Builder builder) {
            list.add(builder.get());
            return this;
        }

        @Override
        public List<Object> get() {
            return list;
        }
    }

    public static final String UPDATE_MESSAGE = "UPDATE_MESSAGE";
    public static final String NEW_MESSAGE = "NEW_MESSAGE";

    private ObjectBuilder headerNode;
    private ObjectBuilder responseNode;
    private ArrayBuilder widgetsArray;
    private ArrayBuilder cardsArray;

    /**
     * Default public constructor.
     */
    public CardResponseBuilder() {
        this.responseNode = createObjectBuilder();
        this.cardsArray = createArrayBuilder();
        this.widgetsArray = createArrayBuilder();
    }

    /**
     * Creates a new CardResponseBuilder object for responding to an interactive card click.
     *
     * @param updateType the update type, either UPDATE_MESSAGE or NEW_MESSAGE.
     */
    public CardResponseBuilder(String updateType) {
        this();
        responseNode.add("actionResponse",
                createObjectBuilder().add("type", updateType));
    }

    /**
     * Adds a header to the card response.
     *
     * @param title    the header title
     * @param subtitle the header subtitle
     * @param imageUrl the header image
     * @return this CardResponseBuilder
     */
    public CardResponseBuilder header(String title, String subtitle, String imageUrl) {
        this.headerNode = createObjectBuilder()
                .add("header", createObjectBuilder()
                        .add("title", title)
                        .add("subtitle", subtitle)
                        .add("imageUrl", imageUrl)
                        .add("imageStyle", "IMAGE"));
        return this;
    }

    /**
     * Adds a TextParagraph widget to the card response.
     *
     * @param message the message in the text paragraph
     * @return this CardResponseBuilder
     */
    public CardResponseBuilder textParagraph(String message) {
        this.widgetsArray.add(
                createObjectBuilder()
                        .add("textParagraph",
                                createObjectBuilder().add("text", message)));
        return this;
    }

    /**
     * Adds a KeyValue widget to the card response.
     * <p>
     * For a list of icons that can be used, see:
     * https://developers.google.com/hangouts/chat/reference/message-formats/cards#builtinicons
     *
     * @param key         the key or top label
     * @param value       the value or content
     * @param bottomLabel the content below the key/value pair
     * @param iconName    a specific icon
     * @return this CardResponseBuilder
     */
    public CardResponseBuilder keyValue(String key, String value,
                                        String bottomLabel, String iconName) {
        this.widgetsArray.add(createObjectBuilder()
                .add("keyValue", createObjectBuilder()
                        .add("topLabel", key)
                        .add("content", value)
                        .add("bottomLabel", bottomLabel)
                        .add("icon", iconName)));
        return this;
    }

    /**
     * Adds an Image widget to the card response.
     *
     * @param imageUrl    the URL of the image to display
     * @param redirectUrl the URL to open when the image is clicked.
     * @return this CardResponseBuilder
     */
    public CardResponseBuilder image(String imageUrl, String redirectUrl) {
        this.widgetsArray.add(createObjectBuilder()
                .add("image", createObjectBuilder()
                        .add("imageUrl", imageUrl)
                        .add("onClick", createObjectBuilder()
                                .add("openLink", createObjectBuilder()
                                        .add("url", redirectUrl)))));
        return this;
    }

    /**
     * Adds a Text Button widget to the card response.
     * <p>
     * When clicked, the button opens a link in the user's browser.
     *
     * @param text        the text on the button
     * @param redirectUrl the link to open
     * @return this CardResponseBuilder
     */
    public CardResponseBuilder textButton(String text, String redirectUrl) {
        this.widgetsArray.add(createObjectBuilder()
                .add("buttons", createArrayBuilder()
                        .add(createObjectBuilder()
                                .add("textButton", createObjectBuilder()
                                        .add("text", text)
                                        .add("onClick", createObjectBuilder()
                                                .add("openLink", createObjectBuilder()
                                                        .add("url", redirectUrl)))))));
        return this;
    }

    /**
     * Adds an Image Button widget to the card response.
     * <p>
     * When clicked, the button opens a link in the user's browser.
     *
     * @param iconName    the icon to display
     * @param redirectUrl the link to open
     * @return this CardResponseBuilder
     */
    public CardResponseBuilder imageButton(String iconName, String redirectUrl) {
        this.widgetsArray.add(createObjectBuilder()
                .add("buttons", createArrayBuilder()
                        .add(createObjectBuilder()
                                .add("imageButton", createObjectBuilder()
                                        .add("icon", iconName)
                                        .add("onClick", createObjectBuilder()
                                                .add("openLink", createObjectBuilder()
                                                        .add("url", redirectUrl)))))));
        return this;
    }

    /**
     * Adds an interactive Text Button widget to the card response.
     * <p>
     * When clicked, the button sends a new request to the bot, passing along the custom actionName
     * and parameter values. The actionName and parameter values are defined by the developer when the
     * widget is first declared (as shown below).
     *
     * @param text                   the text to display
     * @param actionName             the custom action name
     * @param customActionParameters the custom key value pairs
     * @return this CardResponseBuilder
     */
    public CardResponseBuilder interactiveTextButton(String text, String actionName,
                                                     Map<String, String> customActionParameters) {

        // Define the custom action name and parameters for the interactive button.
        ObjectBuilder actionNode = createObjectBuilder()
                .add("actionMethodName", actionName);

        if (customActionParameters != null && customActionParameters.size() > 0) {
            addCustomActionParameters(actionNode, customActionParameters);
        }

        this.widgetsArray.add(createObjectBuilder()
                .add("buttons", createArrayBuilder()
                        .add(createObjectBuilder()
                                .add("textButton", createObjectBuilder()
                                        .add("text", text)
                                        .add("onClick", createObjectBuilder()
                                                .add("action", actionNode))))));
        return this;
    }

    /**
     * Adds an interactive Image Button widget to the card response.
     * <p>
     * When clicked, the button sends a new request to the bot, passing along the custom actionName
     * and parameter values. The actionName and parameter values are defined by the developer when the
     * widget is first declared (as shown below).
     *
     * @param iconName               the pre-defined icon to display.
     * @param actionName             the custom action name
     * @param customActionParameters the custom key value pairs
     * @return this CardResponseBuilder
     */
    public CardResponseBuilder interactiveImageButton(String iconName, String actionName,
                                                      Map<String, String> customActionParameters) {

        // Define the custom action name and parameters for the interactive button.
        ObjectBuilder actionNode = createObjectBuilder()
                .add("actionMethodName", actionName);

        if (customActionParameters != null && customActionParameters.size() > 0) {
            addCustomActionParameters(actionNode, customActionParameters);
        }

        this.widgetsArray.add(createObjectBuilder()
                .add("buttons", createArrayBuilder()
                        .add(createObjectBuilder()
                                .add("imageButton", createObjectBuilder()
                                        .add("icon", iconName)
                                        .add("onClick", createObjectBuilder()
                                                .add("action", actionNode))))));
        return this;
    }

    /**
     * Builds the card response and returns a JSON object node.
     *
     * @return card response as JSON-formatted string
     */
    public Object build() {

        // If you want your header to appear before all other cards,
        // you must add it to the `cards` array as the first / 0th item.
        if (this.headerNode != null) {
            this.cardsArray.add(this.headerNode);
        }

        return responseNode.add("cards", this.cardsArray
                .add(createObjectBuilder()
                        .add("sections", createArrayBuilder()
                                .add(createObjectBuilder()
                                        .add("widgets", this.widgetsArray)))))
                .get();
    }

    /**
     * Applies sets of custom parameters to the parameter field of an action.
     *
     * @param actionNode             the JSON action node
     * @param customActionParameters the parameters to apply to the custom action
     */
    private void addCustomActionParameters(ObjectBuilder actionNode,
                                           Map<String, String> customActionParameters) {
        ArrayBuilder parametersArray = createArrayBuilder();

        customActionParameters.forEach((k, v) -> {
            parametersArray.add(createObjectBuilder()
                    .add("key", k)
                    .add("value", v));
        });

        actionNode.add("parameters", parametersArray);
    }
}


我只是将JsonObjectBuilder替换为基于ObjectBuilderMap,将JsonArrayBuilder替换为基于ArrayBuilderList。以下是该构建器的简单用法:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(SerializationFeature.INDENT_OUTPUT);

        Object response = new CardResponseBuilder()
                .textParagraph("bla bla")
                .textButton("reminder in 10", "some Method")
                .build();
        System.out.println(mapper.writeValueAsString(response));
    }
}


上面的代码打印:

{
  "cards" : [ {
    "sections" : [ {
      "widgets" : [ {
        "textParagraph" : {
          "text" : "bla bla"
        }
      }, {
        "buttons" : [ {
          "textButton" : {
            "onClick" : {
              "openLink" : {
                "url" : "some Method"
              }
            },
            "text" : "reminder in 10"
          }
        } ]
      } ]
    } ]
  } ]
}


我没有添加用于处理thread属性的方法,因为我没有在文档中找到它,但是您应该可以自己进行操作。

09-12 16:40