我在互联网上找不到任何帮助,所以我在这里问。我想用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
库。使用此类并知道Jackson
将Map
序列化为JSON Object
和List
序列化为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
替换为基于ObjectBuilder
的Map
,将JsonArrayBuilder
替换为基于ArrayBuilder
的List
。以下是该构建器的简单用法: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
属性的方法,因为我没有在文档中找到它,但是您应该可以自己进行操作。