Вот рекурсивная функция для установки innerHTML элемента, который я использую на нашем сервере объявлений:
// o: container to set the innerHTML
// html: html text to set.
// clear: if true, the container is cleared first (children removed)
function setHTML(o, html, clear) {
if (clear) o.innerHTML = "";
// Generate a parseable object with the html:
var dv = document.createElement("div");
dv.innerHTML = html;
// Handle edge case where innerHTML contains no tags, just text:
if (dv.children.length===0){ o.innerHTML = html; return; }
for (var i = 0; i < dv.children.length; i++) {
var c = dv.children[i];
// n: new node with the same type as c
var n = document.createElement(c.nodeName);
// copy all attributes from c to n
for (var j = 0; j < c.attributes.length; j++)
n.setAttribute(c.attributes[j].nodeName, c.attributes[j].nodeValue);
// If current node is a leaf, just copy the appropriate property (text or innerHTML)
if (c.children.length == 0)
{
switch (c.nodeName)
{
case "SCRIPT":
if (c.text) n.text = c.text;
break;
default:
if (c.innerHTML) n.innerHTML = c.innerHTML;
break;
}
}
// If current node has sub nodes, call itself recursively:
else setHTML(n, c.innerHTML, false);
o.appendChild(n);
}
}
Вы можете увидеть демо здесь .
Ответ - нет.
Причина проста: это о параметрах, которые вы можете получить в методе. Они должны быть связаны с запросом. Правильно? Таким образом, они должны быть либо заголовками, либо файлами cookie или параметрами запроса, либо параметрами матрицы, или параметрами пути, или объектом запроса. (Просто, чтобы рассказать полную историю, есть дополнительные типы параметров, называемые контекстом).
Теперь, когда вы получаете объект JSON в своем запросе, вы получаете его в теле запроса. Сколько тел может иметь запрос? Один и единственный. Таким образом, вы можете получить только один объект JSON.
Если мы посмотрим, что пытается сделать OP, он пытается опубликовать два (возможно, несвязанных) объекта JSON. Прежде всего, любое решение попробовать и отправить одну часть в качестве тела, а одна часть как другой параметр IMO - это ужасные решения. Данные POST должны поступать в тело. Неправильно делать что-то только потому, что оно работает. Некоторые работы могут нарушать основные принципы REST.
Я вижу несколько решений
Другой вариант - просто использовать application/x-www-form-urlencoded
. Фактически мы можем иметь значения JSON. Для примера
curl -v http://localhost:8080/api/model \
-d 'one={"modelOne":"helloone"}' \
-d 'two={"modelTwo":"hellotwo"}'
public class ModelOne {
public String modelOne;
}
public class ModelTwo {
public String modelTwo;
}
@Path("model")
public class ModelResource {
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public String post(@FormParam("one") ModelOne modelOne,
@FormParam("two") ModelTwo modelTwo) {
return modelOne.modelOne + ":" + modelTwo.modelTwo;
}
}
Единственное, что нам нужно, чтобы заставить это работать, - это ParamConverterProvider
, чтобы заставить это работать. Ниже приведена версия, которая была реализована Михалом Гаджосом из команды Джерси (здесь была найдена ).
@Provider
public class JacksonJsonParamConverterProvider implements ParamConverterProvider {
@Context
private Providers providers;
@Override
public <T> ParamConverter<T> getConverter(final Class<T> rawType,
final Type genericType,
final Annotation[] annotations) {
// Check whether we can convert the given type with Jackson.
final MessageBodyReader<T> mbr = providers.getMessageBodyReader(rawType,
genericType, annotations, MediaType.APPLICATION_JSON_TYPE);
if (mbr == null
|| !mbr.isReadable(rawType, genericType, annotations, MediaType.APPLICATION_JSON_TYPE)) {
return null;
}
// Obtain custom ObjectMapper for special handling.
final ContextResolver<ObjectMapper> contextResolver = providers
.getContextResolver(ObjectMapper.class, MediaType.APPLICATION_JSON_TYPE);
final ObjectMapper mapper = contextResolver != null ?
contextResolver.getContext(rawType) : new ObjectMapper();
// Create ParamConverter.
return new ParamConverter<T>() {
@Override
public T fromString(final String value) {
try {
return mapper.reader(rawType).readValue(value);
} catch (IOException e) {
throw new ProcessingException(e);
}
}
@Override
public String toString(final T value) {
try {
return mapper.writer().writeValueAsString(value);
} catch (JsonProcessingException e) {
throw new ProcessingException(e);
}
}
};
}
}
Если вы не просматриваете ресурсы и поставщиков, просто зарегистрируйте этого поставщика, и приведенный выше пример должен работать.
Одно из решений, о котором никто не упомянул, заключается в использовании multipart . Это позволяет нам отправлять произвольные части в запрос. Поскольку каждый запрос может иметь только один объект, многопроцессор - это работа вокруг, поскольку он позволяет иметь разные части (с их собственными типами контента) как часть тела сущности.
Вот пример использования Джерси (см. официальный doc здесь )
Зависимость
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>${jersey-2.x.version}</version>
</dependency>
Зарегистрируйте класс MultipartFeature
import javax.ws.rs.ApplicationPath;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
@ApplicationPath("/api")
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
packages("stackoverflow.jersey");
register(MultiPartFeature.class);
}
}
Resource
g32]import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.media.multipart.FormDataParam;
@Path("foobar")
public class MultipartResource {
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response postFooBar(@FormDataParam("foo") Foo foo,
@FormDataParam("bar") Bar bar) {
String response = foo.foo + "; " + bar.bar;
return Response.ok(response).build();
}
public static class Foo {
public String foo;
}
public static class Bar {
public String bar;
}
}
Теперь сложная часть с некоторыми клиентами заключается в том, что не существует способа установить Content-Type
каждой части тела, что требуется для работы вышеприведенного. Многостраничный провайдер будет искать устройство чтения сообщений, основанное на типе каждой части. Если он не установлен на application/json
или тип, для Foo
или Bar
будет читатель, это не удастся. Мы будем использовать JSON здесь. Нет никакой дополнительной конфигурации, кроме как иметь доступный читатель. Я буду использовать Джексона. При использовании следующей зависимости никакая другая конфигурация не требуется, так как поставщик будет обнаружен через сканирование классов.
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey-2.x.version}</version>
</dependency>
Теперь тест. Я буду использовать cURL . Вы можете видеть, что я явно установил Content-Type
для каждой части с type
. -F
означает разную часть. (См. Очень низкую позицию для представления о том, как выглядит тело запроса.)
blockquote>
curl -v -X POST \ -H "Content-Type:multipart/form-data" \ -F "bar={\"bar\":\"BarBar\"};type=application/json" \ -F "foo={\"foo\":\"FooFoo\"};type=application/json" \ http://localhost:8080/api/foobar
Результат:FooFoo; BarBar
Результат как мы и ожидали. Если вы посмотрите на метод ресурса, все, что мы делаем, это вернуть эту строку
foo.foo + "; " + bar.bar
, собранную из двух объектов JSON.Вы можете увидеть некоторые примеры, используя несколько разных клиентов JAX-RS, в ссылках ниже , Вы также увидите пример на стороне сервера из этих различных реализаций JAX-RS. В каждой ссылке должно быть где-то в нем ссылка на официальную документацию для этой реализации
Там есть другие реализации JAX-RS, но вам нужно будет найти документацию для него самостоятельно. Вышеупомянутые три являются единственными, с которыми у меня есть опыт.
Что касается клиентов Javascript, то большинство примеров, которые я вижу (например, , некоторые из этих включают установку
Content-Type
на undefined / false (используяFormData
), позволяя обозревателю обработать его, но это не сработает для нас, так как браузер не будет устанавливатьContent-Type
для каждой части. И тип по умолчанию -text/plain
.Я уверен, что есть библиотеки, которые позволяют устанавливать тип для каждой части, но просто чтобы показать вам, как это можно сделать вручную, я отправлю пример (получил небольшую помощь от здесь . Я буду использовать Angular, но ворчание работы по созданию тела объекта будет простым старым Javascript.
<!DOCTYPE html> <html ng-app="multipartApp"> <head> <script src="js/libs/angular.js/angular.js"></script> <script> angular.module("multipartApp", []) .controller("defaultCtrl", function($scope, $http) { $scope.sendData = function() { var foo = JSON.stringify({foo: "FooFoo"}); var bar = JSON.stringify({bar: "BarBar"}); var boundary = Math.random().toString().substr(2); var header = "multipart/form-data; charset=utf-8; boundary=" + boundary; $http({ url: "/api/foobar", headers: { "Content-Type": header }, data: createRequest(foo, bar, boundary), method: "POST" }).then(function(response) { $scope.result = response.data; }); }; function createRequest(foo, bar, boundary) { var multipart = ""; multipart += "--" + boundary + "\r\nContent-Disposition: form-data; name=foo" + "\r\nContent-type: application/json" + "\r\n\r\n" + foo + "\r\n"; multipart += "--" + boundary + "\r\nContent-Disposition: form-data; name=bar" + "\r\nContent-type: application/json" + "\r\n\r\n" + bar + "\r\n"; multipart += "--" + boundary + "--\r\n"; return multipart; } }); </script> </head> <body> <div ng-controller="defaultCtrl"> <button ng-click="sendData()">Send</button> <p>{{result}}</p> </div> </body> </html>
Интересной частью является функция
createRequest
. где мы построим multipart, установивContent-Type
каждой части вapplication/json
и объединив стробированные объектыfoo
иbar
к каждой части. Если вы не знакомы с многостраничным см. здесь для получения дополнительной информации . Другая интересная часть - это заголовок. t доmultipart/form-data
.Ниже приведен результат. В Angular я использовал результат, чтобы показать в HTML, с
$scope.result = response.data
. Кнопка, которую вы видите, просто должна была сделать запрос. Вы также увидите данные запроса в firebug[/g15]
3. Просто заверните их в один родительский объект
Этот параметр должен быть понятным, как это уже упоминалось другими.
Я также столкнулся с этой проблемой. Возможно, это поможет.
@POST
@Path("/{par}")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Object centralService(@PathParam("par") String operation, Object requestEntity) throws JSONException {
ObjectMapper objectMapper=new ObjectMapper();
Cars cars = new Cars();
Seller seller = new Seller();
String someThingElse;
HashMap<String, Object> mapper = new HashMap<>(); //Diamond )))
mapper = (HashMap<String, Object>) requestEntity;
cars=objectMapper.convertValue(mapper.get("cars"), Cars.class);
seller=objectMapper.convertValue(mapper.get("seller"), Seller.class);
someThingElse=objectMapper.convertValue(mapper.get("someThingElse"), String.class);
System.out.println("Cars Data "+cars.toString());
System.out.println("Sellers Data "+seller.toString());
System.out.println("SomeThingElse "+someThingElse);
if (operation.equals("search")) {
System.out.println("Searching");
} else if (operation.equals("insertNewData")) {
System.out.println("Inserting New Data");
} else if (operation.equals("buyCar")) {
System.out.println("Buying new Car");
}
JSONObject json=new JSONObject();
json.put("result","Works Fine!!!");
return json.toString();
}
*******CARS POJO********@XmlRootElement for Mapping Object to XML or JSON***
@XmlRootElement
public class Cars {
private int id;
private String brand;
private String model;
private String body_type;
private String fuel;
private String engine_volume;
private String horsepower;
private String transmission;
private String drive;
private String status;
private String mileage;
private String price;
private String description;
private String picture;
private String fk_seller_oid;
} // Setters and Getters Omitted
*******SELLER POJO********@XmlRootElement for Mapping Object to XML or JSON***
@XmlRootElement
public class Seller {
private int id;
private String name;
private String surname;
private String phone;
private String email;
private String country;
private String city;
private String paste_date;
}//Setters and Getters omitted too
*********************FRONT END Looks Like This******************
$(function(){
$('#post').on('click',function(){
console.log('Begins');
$.ajax({
type:'POST',
url: '/ENGINE/cars/test',
contentType: "application/json; charset=utf-8",
dataType: "json",
data:complexObject(),
success: function(data){
console.log('Sended and returned'+JSON.stringify(data));
},
error: function(err){
console.log('Error');
console.log("AJAX error in request: " + JSON.stringify(err, null, 2));
}
}); //-- END of Ajax
console.log('Ends POST');
console.log(formToJSON());
}); // -- END of click function POST
function complexObject(){
return JSON.stringify({
"cars":{"id":"1234","brand":"Mercedes","model":"S class","body_type":"Sedan","fuel":"Benzoline","engine_volume":"6.5",
"horsepower":"1600","transmission":"Automat","drive":"Full PLag","status":"new","mileage":"7.00","price":"15000",
"description":"new car and very nice car","picture":"mercedes.jpg","fk_seller_oid":"1234444"},
"seller":{ "id":"234","name":"Djonotan","surname":"Klinton","phone":"+994707702747","email":"email@gmail.com", "country":"Azeribaijan","city":"Baku","paste_date":"20150327"},
"someThingElse":"String type of element"
});
} //-- END of Complex Object
});// -- END of JQuery - Ajax
Вы не можете поместить два отдельных объекта в один вызов POST, как объясняется Tarlog.
В любом случае вы могли бы создать третий контейнерный объект, который содержит первые два объекта и передать тот, который находится внутри вызова POS .
Следующий подход обычно применяется в таких случаях:
TransferObject {
ObjectOne objectOne;
ObjectTwo objectTwo;
//getters/setters
}
@POST
@Path("test")
@Consumes(MediaType.APPLICATION_JSON)
public void test(TransferObject object){
// object.getObejctOne()....
}
Это можно сделать, если объявленный метод POST принимает массив объектов. Пример, подобный этому
T[] create(@RequestBody T[] objects) {
for( T object : objects ) {
service.create(object);
}
}
Вы не можете использовать свой метод, как это, как указано в Tarlog.
Однако вы можете сделать это:
@POST
@Path("test")
@Consumes(MediaType.APPLICATION_JSON)
public void test(List<ObjectOne> objects)
или это:
@POST
@Path("test")
@Consumes(MediaType.APPLICATION_JSON)
public void test(BeanWithObjectOneAndObjectTwo containerObject)
Кроме того, вы всегда можете комбинировать свой метод с параметрами GET:
@POST
@Path("test")
@Consumes(MediaType.APPLICATION_JSON)
public void test(List<ObjectOne> objects, @QueryParam("objectTwoId") long objectTwoId)
List<Object> objects is not working
здесь я отправляю свою проблему link
– JustStartedProgramming
19 March 2018 в 16:36