我目前在Vaadin页面上有一个画布来绘制边界框,在其中将它们作为对象保存到包含其宽度,高度,坐标等的数组中。我还有一个Vertx后端,可以执行GET和POST来自我的MariaDB数据库(使用JDBC)的请求,该请求应该包含Vaadin前端的所有边界框对象(但目前仅包含示例创建的对象)。我想知道如何使用Unirest在Vaadin前端上正确编写POST请求,以便可以使用“保存”按钮将对象从Vaadin传递到Vertx,因为我当前在UserService.java中的当前代码是“什么也没做。
Vaadin UserService.java:
package com.vaadin.starter.beveragebuddy.service;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import com.vaadin.starter.beveragebuddy.ui.components.BoundingBox;
import com.vaadin.starter.beveragebuddy.ui.components.Canvas;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import static com.helger.commons.mock.CommonsAssert.assertEquals;
//import static com.sun.xml.internal.ws.spi.db.BindingContextFactory.LOGGER;
public class UserService {
public JSONArray bbJsonArray;
public JSONObject bbJsonObject;
public static ArrayList<BoundingBox> bb = Canvas.getArrayBoxes();
public static String createAnnotations(String boxname) throws UnirestException {
Map<String, String> headers = new HashMap<>();
try {
HttpResponse<JsonNode> jsonResponse = Unirest.post("http://localhost:9080/api/annotations")
.header("accept", "application/json")
.field("boxname", bb.get(0).boxname)
.asJson();
JSONObject output = jsonResponse.getBody().getObject();
String status = output.getString("status");
System.out.println(jsonResponse.getBody());
return status;
} catch (UnirestException e) {
return "error";
}
}
}
Vaadin BoundingBox.java:
package com.vaadin.starter.beveragebuddy.ui.components;
import org.json.JSONObject;
public class BoundingBox {
public double xcoordi = 0;
public double ycoordi = 0;
public double boxWidth = 0;
public double boxHeight = 0;
public double endX = 0;
public double endY = 0;
public String picID;
public String boxname;
public String boxcategory;
public String boxcolour;
public BoundingBox(String picID, String boxname, String boxcategory, String boxcolour, double xcoordi, double ycoordi, double boxWidth, double boxHeight, double endX, double endY) {
this.picID = picID;
this.boxname = boxname;
this.boxcategory = boxcategory;
this.boxcolour = boxcolour;
this.xcoordi = xcoordi;
this.ycoordi = ycoordi;
this.boxWidth = boxWidth;
this.boxHeight = boxHeight;
this.endX = endX;
this.endY = endY;
}
public String getPicID() {
return picID;
}
public void setPicID(String picID) {
this.picID = picID;
}
public String getBoxName() {
return boxname;
}
public void setName(String boxname) {
this.boxname = boxname;
}
public String getBoxcategory() {
return boxcategory;
}
public void setBoxcategory(String boxcategory) {
this.boxcategory = boxcategory;
}
public String getBoxcolour() {
return boxcolour;
}
public void setBoxcolour(String boxcolour) {
this.boxcolour = boxcolour;
}
public double getXcoordi() {
return xcoordi;
}
public void setXcoordi(double xcoordi) {
this.xcoordi = xcoordi;
}
public double getYcoordi() {
return ycoordi;
}
public void setYcoordi(double ycoordi) {
this.ycoordi = ycoordi;
}
public double getWidth() {
return boxWidth;
}
public void setWidth(double endX, double xcoordi) {
boxWidth = endX - xcoordi;
}
public double getHeight() {
return boxHeight;
}
public void setHeight(double endY, double ycoordi) {
boxHeight = endY - ycoordi;
}
public double getEndX() { // Bottom-right X coordinate of box
return endX;
}
public void setEndX(double endX) {
this.endX = endX;
}
public double getEndY() { // // Bottom-right Y coordinate of box
return endY;
}
public void setEndY(double endY) {
this.endY = endY;
}
public JSONObject toJSON() {
JSONObject bbJsonObject = new JSONObject();
bbJsonObject.put("boxname", boxname);
bbJsonObject.put("boxcategory", boxcategory);
bbJsonObject.put("boxcolour", boxcolour);
bbJsonObject.put("xcoordi", xcoordi);
bbJsonObject.put("ycoordi", ycoordi);
bbJsonObject.put("boxwidth", boxWidth);
bbJsonObject.put("boxheight", boxHeight);
return bbJsonObject;
}
@Override
public String toString() {
return "{" +
"Name=" + boxname +
", Class=" + boxcategory +
", Colour=" + boxcolour +
", X=" + xcoordi +
", Y=" + ycoordi +
", Width=" + boxWidth +
", Height=" + boxHeight +
'}';
}
}
Vertx MainVerticle.java:
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.Json;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.jdbc.JDBCClient;
import io.vertx.ext.sql.ResultSet;
import io.vertx.ext.sql.SQLClient;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.StaticHandler;
import io.vertx.ext.jdbc.JDBCClient;
import io.vertx.ext.sql.SQLConnection;
import io.vertx.ext.sql.UpdateResult;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.handler.StaticHandler;
import io.vertx.starter.components.BoundingBox;
import io.vertx.starter.components.Picture;
import java.sql.Statement;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MainVerticle extends AbstractVerticle {
private JDBCClient jdbc;
private static final Logger LOGGER = LoggerFactory.getLogger(MainVerticle.class);
private Future fut;
private String SQL_GET_ANNOTATION = "SELECT * FROM boundingboxes";
private String SQL_ADD_ANNOTATION = "INSERT INTO boundingboxes (picID, boxname, boxcategory, boxcolour, xcoordi, ycoordi, boxWidth, boxHeight, endX, endY) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
private int nextCount = 0;
private Map<Integer, Picture> pictures = new LinkedHashMap<>();
private Map<Integer, BoundingBox> annotations = new LinkedHashMap<>();
@Override
public void start(Future<Void> fut) {
createBBData();
startHttpServer();
dbConnection();
// Router router = Router.router(vertx);
}
public Future<Void> dbConnection(){
// Create a JDBC client
jdbc = JDBCClient.createShared(vertx, new JsonObject()
.put("url", "jdbc:mariadb://localhost:3306/annotationdb")
.put("driver_name", "org.mariadb.jdbc.Driver")
.put("max_pool_size", 5)
.put("user", "root"));
jdbc.getConnection(ar -> {
if (ar.failed()) {
LOGGER.error("Could not open a database connection", ar.cause());
fut.fail(ar.cause()); // If SQL Connection could not be obtained, then method future is completed to fail.
} else {
SQLConnection connection = ar.result(); // else ... SQL connection is established with successful AsyncResult (Use this connection to perform a SQL query)
connection.query(SQL_GET_ANNOTATION, get -> {
connection.close();
if (get.failed()) { // If SQL Query fails ...
LOGGER.error("Database operation error", get.cause()); // ...
fut.fail(get.cause());
} else {
LOGGER.info("Connection Established");
// fut.complete(); // Complete method future object with a success
System.out.print("Succeed");
ResultSet rs = get.result();
if (rs.getNumRows() > 0) {
System.out.println(rs.getResults().toString());
nextCount++;
}
}
});
}
});
return fut;
}
public Future<Void> startHttpServer(){
Future<Void> future = Future.future();
HttpServer server = vertx.createHttpServer();
Router router = Router.router(vertx);
router.route("/").handler(routingContext -> {
HttpServerResponse response = routingContext.response();
response
.putHeader("content-type", "text/html")
.end("<h1>Hello from my first Vert.x 3 application</h1>");
});
// Serve static resources from the /assets directory
router.route("/assets/*").handler(StaticHandler.create("assets"));
router.route("/api/annotations*").handler(BodyHandler.create());
router.get("/api/annotations").handler(this::getAll);
// router.get("/api/annotations/:bbID").handler(this::getOne);
router.post("/api/annotations").handler(this::addOne);
router.put("/api/annotations/:bbID").handler(this::updateOne);
router.delete("/api/annotations/:bbID").handler(this::deleteOne);
vertx
.createHttpServer()
.requestHandler(router::accept)
.listen(
// Retrieve the port from the configuration,
// default to 8080.
config().getInteger("http.port", 9080)
);
return future;
}
private void createBBData() {
BoundingBox annotation1 = new BoundingBox("P1", "sign1", "signs", "Magenta", 340.0, 110.0, 100.0, 200.0, 500.0, 400.0);
annotations.put(annotation1.getBbID(), annotation1);
BoundingBox annotation2 = new BoundingBox("P2", "woman1", "people", "Red", 300.0, 150.0, 200.0, 400.0, 600.0, 350.0);
annotations.put(annotation2.getBbID(), annotation2);
}
private void getAll(RoutingContext routingContext) {
jdbc.getConnection(ar -> {
SQLConnection connection = ar.result();
connection.query("SELECT * FROM boundingboxes", result -> {
System.out.println("[GetALL] NUMBER = " + result.result().getNumRows());
LOGGER.info("LOGGER INFO TEST!!");
LOGGER.error("LOGGER ERROR TEST!!");
// System.out.println("[GetALL] CONTENTS = " + result.result().getResults().get(0).encodePrettily());
List<BoundingBox> annotation = result.result().getRows().stream().map(BoundingBox::new).collect(Collectors.toList());
routingContext.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(Json.encodePrettily(annotation));
connection.close();
});
});
}
private void addOne(RoutingContext routingContext) { // OK
jdbc.getConnection(ar -> {
System.out.println("CONNECTION INSERT OK");
final BoundingBox annotation = Json.decodeValue(routingContext.getBodyAsString(),
BoundingBox.class);
System.out.println(annotation.getEndX());
SQLConnection connection = ar.result();
// annotations.put(annotation.getBbID(), annotation);
insert(annotation, connection, (r) ->
routingContext.response()
.setStatusCode(201)
.putHeader("content-type", "application/json; charset=utf-8")
.end(Json.encodePrettily(r.result())));
connection.close();
});
}
private void updateOne(RoutingContext routingContext) {
final String bbID = routingContext.request().getParam("bbID");
JsonObject json = routingContext.getBodyAsJson();
if (bbID == null || json == null) {
routingContext.response().setStatusCode(400).end();
} else {
jdbc.getConnection(ar ->
update(bbID, json, ar.result(), (annotation) -> {
if (annotation.failed()) {
routingContext.response().setStatusCode(404).end();
} else {
routingContext.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(Json.encodePrettily(annotation.result()));
}
ar.result().close();
})
);
}
}
private void select(String bbID, SQLConnection connection, Handler<AsyncResult<BoundingBox>> resultHandler) {
System.out.println("[TEST] SELECT ONE REQUEST !!!");
connection.queryWithParams("SELECT * FROM boundingboxes", new JsonArray().add(bbID), ar -> {
if (ar.failed()) {
resultHandler.handle(Future.failedFuture("Annotation not found"));
} else {
if (ar.result().getNumRows() >= 1) {
System.out.println(ar.result().getResults().get(0).encodePrettily());
System.out.println(ar.result().getRows().get(0).fieldNames());
System.out.println(ar.result().getRows().get(0).encodePrettily());
resultHandler.handle(Future.succeededFuture(new BoundingBox(ar.result().getRows().get(0))));
} else {
System.out.println("Annotation is not found!");
resultHandler.handle(Future.failedFuture("Annotation not found"));
}
}
});
}
private void insert(BoundingBox annotation, SQLConnection connection, Handler<AsyncResult<BoundingBox>> next) { // OK
String sql = "INSERT INTO boundingboxes (picID, boxname, boxcategory, boxcolour, xcoordi, ycoordi, boxWidth, boxHeight, endX, endY) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
JsonArray annotationJson = new JsonArray().add(annotation.getPicID()).add(annotation.getBoxName()).add(annotation.getBoxcategory()).add(annotation.getBoxcolour()).add(annotation.getXcoordi()).add(annotation.getYcoordi()).add(annotation.getWidth()).add(annotation.getHeight()).add(annotation.getEndX()).add(annotation.getEndX());
// System.out.println(annotationJson);
connection.updateWithParams(sql, annotationJson,
(ar) -> {
if (ar.failed()) {
next.handle(Future.failedFuture(ar.cause()));
connection.close();
return;
}
UpdateResult result = ar.result();
BoundingBox bb = new BoundingBox(result.getKeys().getInteger(0), annotation.getPicID(), annotation.getBoxName(), annotation.getBoxcategory(), annotation.getBoxcolour(), annotation.getXcoordi(), annotation.getYcoordi(), annotation.getWidth(), annotation.getHeight(), annotation.getEndX(), annotation.getEndY());
System.out.println(bb);
next.handle(Future.succeededFuture(bb));
});
}
private void update(String bbID, JsonObject content, SQLConnection connection,
Handler<AsyncResult<BoundingBox>> resultHandler) {
String sql = "UPDATE boundingboxes SET picID=?, boxname=?, boxcategory=?, boxcolour=?, xcoordi=?, ycoordi=?, boxWidth=?, boxHeight=?, endX=?, endY=? WHERE bbID=?";
connection.updateWithParams(sql,
new JsonArray().add(content.getString("picID")).add(content.getString("boxname")).add(content.getString("boxcategory")).add(content.getString("boxcolour")).add(content.getDouble("xcoordi")).add(content.getDouble("ycoordi")).add(content.getDouble("boxWidth")).add(content.getDouble("boxHeight")).add(content.getDouble("endX")).add(content.getDouble("endY")).add(bbID),
update -> {
if (update.failed()) {
resultHandler.handle(Future.failedFuture("Cannot update the annotation"));
return;
}
if (update.result().getUpdated() == 0) {
resultHandler.handle(Future.failedFuture("Annotation not found"));
return;
}
resultHandler.handle(
Future.succeededFuture(new BoundingBox(Integer.valueOf(bbID),
content.getString("picID"), content.getString("boxname"), content.getString("boxcategory"), content.getString("boxcolour"), content.getDouble("xcoordi"), content.getDouble("ycoordi"), content.getDouble("boxWidth"), content.getDouble("boxHeight"), content.getDouble("endX"), content.getDouble("endY"))));
});
}
}
Vertx index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>List of Annotations</title>
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container" role="main">
<div class="jumbotron">
<h1>List of Annotations</h1>
<p>Just an example of simple CRUD application developed using Vert.x and Vertx Web.</p>
</div>
<div class="page-header">
<h1>Annotations</h1>
<button class="pull-right btn btn-primary annotation-add" data-action="add" data-toggle="modal"
data-target="#annotationModal">
<span class="glyphicon glyphicon-plus"></span> Add a new annotation
</button>
<div class="row">
<div class="col-md-12">
<table class="table table-striped">
<thead>
<tr>
<th>bbID</th>
<th>picID</th>
<th>Box Name</th>
<th>Box Category</th>
<th>Box Colour</th>
<th>X-Coordi</th>
<th>Y-Coordi</th>
<th>Box Width</th>
<th>Box Height</th>
<th>End X</th>
<th>End Y</th>
<th></th>
</tr>
</thead>
<tbody id="content">
<!-- filled using Ajax -->
</tbody>
</table>
</div>
</div>
</div>
</div>
<script>
$(function () {
load();
initModal();
});
function create(picID, boxname, boxcategory, boxcolour, xcoordi, ycoordi, boxWidth, boxHeight, endX, endY) {
$.post("/api/annotations", JSON.stringify({picID: picID, boxname: boxname, boxcategory: boxcategory, boxcolour: boxcolour, xcoordi: xcoordi, ycoordi: ycoordi, boxWidth: boxWidth, boxHeight: boxHeight, endX: endX, endY: endY}), function () {
load();
}, "json");
}
function remove(bbID) {
$.ajax({
method: "DELETE",
url: "/api/annotations/" + bbID
}).done(function () {
load();
});
}
function update(bbID, picID, boxname, boxcategory, boxcolour, xcoordi, ycoordi, boxWidth, boxHeight, endX, endY) {
$.ajax({
method: "PUT",
url: "/api/annotations/" + bbID,
data: JSON.stringify({picID: picID, boxname: boxname, boxcategory: boxcategory, boxcolour: boxcolour, xcoordi: xcoordi, ycoordi: ycoordi, boxWidth: boxWidth, boxHeight: boxHeight, endX: endX, endY: endY})
}).done(function () {
load();
});
}
function load() {
$("#content").children().remove();
$.getJSON("/api/annotations", function (data) {
$.each(data, function (key, val) {
$("<tr><td>" + val.bbID + "</td><td>" + val.picID + "</td><td>" + val.boxname + "</td><td>" + val.boxcategory + "</td><td>" + val.boxcolour + "</td><td>" + val.xcoordi + "</td><td>" + val.ycoordi + "</td><td>" + val.boxWidth + "</td><td>" + val.boxHeight + "</td><td>" + val.endX + "</td><td>" + val.endY + "</td>" +
"<td>" +
"<button data-action='edit' class='btn btn-primary btn-sm annotation-edit' " +
"data-toggle='modal' " +
"data-target='#annotationModal' " +
"data-bbID='" + val.bbID + "' " +
"data-boxname='" + val.boxname + "' " +
"data-boxcategory='" + val.boxcategory + "' " +
"data-boxcolour='" + val.boxcolour + "'>" +
<!--"data-xcoordi='" + val.xcoordi + "'>" +-->
<!--"data-ycoordi='" + val.ycoordi + "'>" +-->
<!--"data-boxWidth='" + val.boxWidth + "'>" +-->
<!--"data-boxHeight='" + val.boxHeight + "'>" +-->
<!--"data-endX='" + val.endX + "'>" +-->
<!--"data-endY='" + val.endY + "'>" +-->
"<span class='glyphicon glyphicon-pencil'></span>" +
"</button>" +
" " +
"<button class='btn btn-danger btn-sm annotation-delete' data-bbID='" + val.bbID + "'>" +
" <span class='glyphicon glyphicon-minus'></span>" +
"</button>" +
"</td>" +
"</tr>").appendTo("#content");
});
initCallbacks();
});
}
function initCallbacks() {
$(".annotation-delete").unbind().click(function() {
var bbID = $(this).data("bbID");
remove(bbID);
});
}
function initModal() {
$("#annotationModal").on('show.bs.modal', function (event) {
var button = $(event.relatedTarget);
var action = button.data('action');
var bbID = button.data('bbID');
var annotationAction = $("#annotationAction");
annotationAction.unbind();
var modal = $(this);
if (action === "add") {
modal.find('.modal-title').text("Add an annotation");
modal.find('#annotation-picID').val("");
modal.find('#annotation-boxname').val("");
modal.find('#annotation-boxcategory').val("");
modal.find('#annotation-boxcolour').val("");
modal.find('#annotation-xcoordi').val("");
modal.find('#annotation-ycoordi').val("");
modal.find('#annotation-boxWidth').val("");
modal.find('#annotation-boxHeight').val("");
modal.find('#annotation-endX').val("");
modal.find('#annotation-endY').val("");
annotationAction.click(function () {
create($("#annotation-picID").val(), $("#annotation-boxname").val(), $("#annotation-boxcategory").val(), $("#annotation-boxcolour").val(), $("#annotation-xcoordi").val(), $("#annotation-ycoordi").val(), $("#annotation-boxWidth").val(), $("#annotation-boxHeight").val(), $("#annotation-endX").val(), $("#annotation-endY").val());
$('#annotationModal').modal('toggle');
});
} else {
modal.find('.modal-title').text("Edit an annotation");
modal.find('#annotation-picID').val(button.data("picID"));
modal.find('#annotation-boxname').val(button.data("boxname"));
modal.find('#annotation-boxcategory').val(button.data("boxcategory"));
modal.find('#annotation-boxcolour').val(button.data("boxcolour"));
modal.find('#annotation-xcoordi').val(button.data("xcoordi"));
modal.find('#annotation-ycoordi').val(button.data("ycoordi"));
modal.find('#annotation-boxWidth').val(button.data("boxWidth"));
modal.find('#annotation-boxHeight').val(button.data("boxHeight"));
modal.find('#annotation-endX').val(button.data("endX"));
modal.find('#annotation-endY').val(button.data("endY"));
annotationAction.click(function () {
update(id, $("#annotation-picID").val(), $("#annotation-boxname").val(), $("#annotation-boxcategory").val(), $("#annotation-boxcolour").val(), $("#annotation-xcoordi").val(), $("#annotation-ycoordi").val(), $("#annotation-boxWidth").val(), $("#annotation-boxHeight").val(), $("#annotation-endX").val(), $("#annotation-endY").val());
$('#annotationModal').modal('toggle');
});
}
})
}
</script>
<div class="modal fade" id="annotationModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span>×</span></button>
<h4 class="modal-title" id="annotationModalTitle">Add an annotation</h4>
</div>
<div class="modal-body">
<form>
<div class="form-group">
<label for="annotation-picID" class="control-label">Pic ID:</label>
<input type="text" class="form-control" id="annotation-picID">
</div>
<div class="form-group">
<label for="annotation-boxname" class="control-label">Box Name:</label>
<input type="text" class="form-control" id="annotation-boxname">
</div>
<div class="form-group">
<label for="annotation-boxcategory" class="control-label">Box Category:</label>
<input type="text" class="form-control" id="annotation-boxcategory">
</div>
<div class="form-group">
<label for="annotation-boxcolour" class="control-label">Box Colour:</label>
<input type="text" class="form-control" id="annotation-boxcolour">
</div>
<div class="form-group">
<label for="annotation-xcoordi" class="control-label">X-Coordi:</label>
<input type="text" class="form-control" id="annotation-xcoordi">
</div>
<div class="form-group">
<label for="annotation-ycoordi" class="control-label">Y-Coordi:</label>
<input type="text" class="form-control" id="annotation-ycoordi">
</div>
<div class="form-group">
<label for="annotation-boxWidth" class="control-label">Box Width:</label>
<input type="text" class="form-control" id="annotation-boxWidth">
</div>
<div class="form-group">
<label for="annotation-boxHeight" class="control-label">Box Height:</label>
<input type="text" class="form-control" id="annotation-boxHeight">
</div>
<div class="form-group">
<label for="annotation-endX" class="control-label">End X:</label>
<input type="text" class="form-control" id="annotation-endX">
</div>
<div class="form-group">
<label for="annotation-endY" class="control-label">End Y:</label>
<input type="text" class="form-control" id="annotation-endY">
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" id="annotationAction" class="btn btn-primary">Save</button>
</div>
</div>
</div>
</div>
</body>
</html>
感谢您的帮助,谢谢!
答案 0 :(得分:0)
您不仅需要发送边界框的名称,还需要发送整个对象以及所有有关坐标和其他信息的信息,因此所有相关数据都可以存储在DB中。仅发送和存储名称将无济于事。
通常使用json完成。如果需要,可以自行构建json,但是使用ObjectMapper将BoundingBox转换为json并返回则方便得多,特别是如果除了BoundingBoxes之外还需要发送其他对象时。
这是一篇有关在Java中使用unirest的精彩文章,示例如下:https://www.baeldung.com/unirest。