Simple restful JSON POST with java as server and jquery as client - java

Before I ask my question I have to say that I have read more than 20 questions and articles about this problem and none of them could solve it.
My problem is I have a restful server in java like this:
#RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
#ResponseBody
public void downloadByCode(#RequestBody final String stringRequest, final HttpServletResponse response)
{
try
{
final ObjectMapper objectMapper = new ObjectMapper();
final JsonNode jsonRequest = objectMapper.readValue(stringRequest, JsonNode.class);
// ...
// some processings here to create the result
// ....
final ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(result);
// Flush the result
outputStream.flush();
}
catch (final Exception exception)
{
LOG.debug("Exception Thrown [downloadByCode]", exception);
}
}
And I have tried different ways to send a json to this server with jquery (but all of them create errors):
$.ajax({
url:"/downloadByCode",
type:"POST",
data: JSON.stringify({"name":"value"}) });
415 "errors message" : "Content type 'application/x-www-form
urlencoded;charset=UTF-8' not supported", "type" :
"HttpMediaTypeNotSupportedError"
So I tried to fix it by adding contentType:
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });
400 "errors message" : "Could not instantiate JAXBContext for class
[class java.lang.String]: null; nested exception is
javax.xml.bind.JAXBException\n - with linked
exception:\n[java.lang.NullPointerException", "type"
:"HttpMessageConversionError"
I tried to send json object directly instead of JSON.stringify and it gives the same 400 error.
I tried to add different consumes to the #requestMapping but still no luck.
I tried to define my own class instead of JsonNode but it does not change anything.
Any ideas?

Please try to create new class :
public class InputData{
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}
Then
public void downloadByCode(#RequestBody InputData stringRequest, final HttpServletResponse response)
And
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });

try #RequestBody final Map<String, String> stringRequest
also you will need consumes = "application/json" on the #RequestMapping because you have that in your AJAX call
You will get 400 if spring doesn't like the format in which you send your ajax - I've had so much trouble with this in the past and it seems better to just ignore header types and content types unless necessary

You might try sending your response back as a ResponseEntity instead of using the HttpServletResponse directly. My hunch is that second argument, the HttpServletRequest argument, is what is causing the problem. I've never used that. I've always send my response back using the spring mvc api.

With Jersey api you can try just:
#POST
public void downloadByCode(String stringRequest)
and I think you'll find the body of your post in stringRequest.

You can take request body as string with usage of org.springframework.http.HttpEntity<String> as request type, here is example with your code as base:
#RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
#ResponseBody
public void downloadByCode(final HttpEntity<String> request, final HttpServletResponse response)
{
try
{
final ObjectMapper objectMapper = new ObjectMapper();
final JsonNode jsonRequest = objectMapper.readValue(request.getBody(), JsonNode.class);
// ...
// some processings here to create the result
// ....
final ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(result);
// Flush the result
outputStream.flush();
}
catch (final Exception exception)
{
LOG.debug("Exception Thrown [downloadByCode]", exception);
}
}
But maybe it will be better to use also String as return type, if you are planning to return result as string value, like this:
#RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
#ResponseBody
public String downloadByCode(HttpEntity<String> request) {
String requestBody = request.getBody();
String result;
// ...
// some processings here to create the result text
// ....
return result;
}
I made simple application using Spring Boot with usage of proposed solutions using HttpEntity and also additional example of usage POJO, to run application you need to have Maven and JDK >= 1.7.
#clonning repository with sample
git clone git#github.com:mind-blowing/samples.git
#change current folder to sample application root
cd samples/spring-boot/rest-handler-for-plain-text
#running application using maven spring-boot plugin
mvn spring-boot:run
After application will be started you can open http://localhost:8080 and you will see html page with simple usage of JQuery to send POST requests, text of request and response will visible on html page, in controller I added two handlers, first with usage of HttpEntity and second with usage of POJO.
Controller: SampleRestController.java
HTML page: index.html
Project: https://github.com/mind-blowing/samples/tree/master/spring-boot/rest-handler-for-plain-text

First of all If you are using maven you should add dependency for jackson
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.1</version>
</dependency>
or you can download the jar and put it in our project class path (you can use other mapper as well)
then you should create a model or DTO class where you can map your json
public class Data{
private String name;
pubilc Data(){}
//getter and setter
}
THEN you controller
#RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
#ResponseBody
public Data downloadByCode(#RequestBody final Data data, final HttpServletResponse response)
{
//your code
return data;
}
AJAX CALL
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });
(Optional)You can override behavior by telling object mapper not to fail on missing properties by defining the bean as follows:
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false));
return converter;
}
http://websystique.com/springmvc/spring-mvc-requestbody-responsebody-example/

Looking at your errors, it's clear that you have configured 'Jaxb2RootElementHttpMessageConverter' or similar XML converter in your spring configuration. And since you have registerned an XML converter, the #RequestBody and #ResponseBody work based on the registered message converters.
So, to solve your problem, go with a JSON message converter such as 'MappingJacksonHttpMessageConverter'. Once you register a JSON message converter, create a bean class to hold your json data and use it with RequestBody as below:
// It has to meet the json structure you are mapping it with
public class YourInputData {
//properties with getters and setters
}
Update 1:
Since you have defined multiple message converters, Spring tries to use the first one available by default. In order to use specific message converter(in this case Jackson converter), you should specify 'Accept' header from client like below:
$.ajax({
headers: {
"Accept" : "application/json; charset=utf-8",
"Content-Type": "application/json; charset=utf-8"
}
data: "data",
success : function(response) {
...
} })

The final answer is a combination of a number of answers/comments in this question that I am going to summarize them here:
1- You have to make sure you have an appropriate json converter in your spring config such as MappingJacksonHttpMessageConverter (credits to #java Anto)
2- You have to create a POJO class with same structure as your json object (see #Vinh Vo answer)
3- Your POJO class cannot be an inline class unless it is a static class. It means it should have its own java file or it should be static. (credits to #NTyler)
4- Your POJO class can miss parts of your json object if you set it appropriately in your object mapper (see #Aman Tuladhar answer)
5- Your ajax call requires contentType:"application/json", and you should send your data with JSON.stringify
Here is the Final code that is working perfectly:
public static class InputData
{
private String name
public String getName()
{
return name;
}
public void setName(final String name
{
this.name = name;
}
}
#RequestMapping(value = "/downloadByCode", method = RequestMethod.POST)
#ResponseBody
public void downloadByCode(#RequestBody final InputData request, final HttpServletResponse response)
{
try
{
String codes = request.getName();
// ...
// some processings here to create the result
// ....
final ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(result);
// Flush the result
outputStream.flush();
}
catch (final Exception exception)
{
LOG.debug("Exception Thrown [downloadByCode]", exception);
}
}
And it is the jquery Ajax request:
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });

Delete the #ResponseBody on your downloadByCode method

Change your method downloadByCode() return type to String and then return the String
Response body will automatically convert the returned String to JSON and then use the data appropriately

I am not that well versed with java but as much as I know your java code must be something like this.
public class downloadByCode{
#GET
#Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
public Response downloadByCode(#QueryParam("paramater1") final String parameter 1, #Context HttpServletRequest httpRequest) {
If this not helps you can keep you code somewhere and share it.

Related

Spring / Angular 7 POST method requestparameter is null

I would like to send datas (in json form) from frontend to backend using POST, but requestparameter is null.
Angular:
this.http.post('api/example', { mydata: JSON.stringify(data) },
{ "headers": { header: "text/html;charset=UTF-8" } }).subscribe(Response => console.log(Response);
});
JSON.stringify(data) looks like this:
[
["num1","num2","num3","num4","num5", "num6"],
["test6","test2","test1","test5","test4", "test3"]
]
This is just an example, the data will be dynamic, so sometimes I will have more or less columns and rows.
Spring backend:
#RequestMapping(value = "/api/example", method = RequestMethod.POST)
public #ResponseBody void postExample(HttpServletRequest request, HttpServletResponse response)
throws IOException {
HttpSession session = request.getSession();
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
request.setCharacterEncoding("UTF-8");
String mydata = request.getParameter("mydata");
System.out.println(mydata);
...
}
mydata is null, when I print out. I don't know why.
What I tried:
change "text/html" to "application/json" and "application/*" and "text/plain" (and wanted to convert the text to json at backend, but still null parameter)
I would like to use "getParameter" instead of using #RequestBody annotation.
How can I get the json data from frontend and use it in backend?
Edit:
Originally I didn't want to use #RequestBody, but if I want to use it, how can I use it for getting these json arrays?
for using #RequestBody you'll need a Java data structure matching your JSON,
e.g. a nested array
#PostMapping(path="/api/example")
public void postExample(#RequestBody ArrayList<ArrayList<String>> body) {
//....
}
Test case (from question above)
[
["num1","num2","num3","num4","num5", "num6"],
["test6","test2","test1","test5","test4", "test3"]
]
You need to use .getReader(), instead of the .getParameter() method, since you need to retrieve the body of the request not some parameter.

Get request header in spring boot

How do I get the header and body of the current request from an application which called my Springboot application? I need to extract this information. Unfortunately this does not work. I tried to get the current request with this code sample (https://stackoverflow.com/a/26323545/5762515):
public static HttpServletRequest getCurrentHttpRequest(){
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes instanceof ServletRequestAttributes) {
HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
return request;
}
throw new IllegalArgumentException("Request must not be null!");
}
And then I tried to get the body
ContentCachingRequestWrapper requestWrapper = (ContentCachingRequestWrapper) currentRequest;
String requestBody = new String(requestWrapper.getContentAsByteArray());
Can someone tell me what im doing wrong?
Thanks in advance
#RestController
public class SampleController {
#PostMapping("/RestEndpoint")
public ResponseEntity<?> sampleEndpoint(#RequestHeader Map<String, String> headers,#RequestBody Map<String,String> body) {
//Do something with header / body
return null;
}
}
If the application's are communicating through a rest endpoint I believe this would be the simplest solution. In spring you can add RequestHeader and RequestBody annotations to method arguments to have them setup to be used.
Of course you can map RequestBody directly to some POJO instead of using a map but just as an example.
Let me know if this is what you were looking for !
#TryHard, You're using spring boot then following way is more preferable for you,
#RestController
public class SampleController {
#RequestMapping("/get-header-data")
public ResponseEntity<?> sampleEndpoint(HttpServletRequest request) {
// request object comes with various in-built methods use as per your requirement.
request.getHeader("<key>");
}
}
you can get header with your code but need apply some changes.
private String getRequest() throws Exception {
RequestAttributes attribs = RequestContextHolder.getRequestAttributes();
if (attribs != null) {
HttpServletRequest request = ((ServletRequestAttributes) attribs).getRequest();
return request ;
}
throw new IllegalArgumentException("Request must not be null!");
}
after you can extract header info from request. For example if you want get Accept-Encoding
String headerEncoding = getRequest().getHeader("Accept-Encoding");
obliviusly you don't use this approce if not necessary.
If you want exract the body NOT use this solution

Spring gives HTTP Status 400 when receiving a soap request having an xml declaration with special character escape slashes

I am receiving an xml post request from my vendor having a declaration of this format.
<?xml version=\"1.0\" encoding=\"utf-8\"?>
With this type of xml declarion (I am using Spring MVC with JAXB) I am getting the HTTP Status 400 error which states that "The request sent by the client was syntactically incorrect." I tried to post the same request to my site using postman and i get the very same error.
But on changing the xml declarion by removing all the backslashes( see below)
<?xml version="1.0" encoding="utf-8"?>
the error vanishes and i get the correct response with HTTP Status 200, Ok.
My question is how can i intercept this request and modify the xml declaration by removing the forward slashes (My vendor does not comply with modify this from their end).
Below is the sample of my controller
#RequestMapping(method = {RequestMethod.GET,RequestMethod.POST}, value ="/listeningurl", consumes = "application/xml", produces = "application/xml")
public ResponseObject lodgementNotifications(#RequestBody RequesObject reqObject)
{
//do stuffs with reqObject;
// Initialize ResponseObject
return responseObject
}
Thanks for the help.
You can extends the HandlerInterceptorAdapter which is :
Abstract adapter class for the AsyncHandlerInterceptor interface, for
simplified implementation of pre-only/post-only interceptors.
#Component
public class MyHandlerInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// then access your request body (xml content) to update it
// see link bellow for how to retrieve an xml content from the HttpServletRequest
return super.preHandle(request, response, handler);
}
}
After that you override the addInteceptors of WebMvcConfigurerAdapter by creating a custom class that extends from WebMvcConfigurerAdapter :
#Configuration
public class CustomWebMvc extends WebMvcConfigurerAdapter {
#Autowired
MyHandlerInterceptor myHandlerInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myHandlerInterceptor);
super.addInterceptors(registry);
}
}
To know how to retrieve the xml content from your HttpServletRequest read this Get Posted XML from HttpServletRequest Object
Edit
If your goal is simply to retrieve the http body ( xml content ) and then do what ever you want with it inside your controller you can simply inject an InputStream or a Reader in the #RequestMapping handler method (which is your controller method) like so :
#PostMapping(value = "/topics/xml", consumes = "application/xml")
public void getXmlRequest(InputStream data) throws IOException {
String requestBody = IOUtils.toString(data);
// format the xml and do something with it
}
Spring web doc : Handler Methods :
#RequestMapping handler methods have a flexible signature and can choose from a range of supported controller method arguments and return values.
I was able to resolve the issue. I had to receive the xml request in String format, removed the backslashes then unmarshalled it into its corresponding object. Thanks to #Harry Coder for the hints. Here is the solution that worked for me.
#RequestMapping(method = {RequestMethod.GET,RequestMethod.POST}, value ="/listeningurl", consumes = "application/xml", produces = "application/xml")
public ResponseObject lodgementNotifications(#RequestBody String reqObjectXMLStr)
{
//Replace the backslashes from the xml string
String cleanReqObjectXMLStr = reqObjectXMLStr.replaceAll("\\\\", "");
//Unmarshal the string into the corresponding object using JAXB library
RequestObject reqObject = JAXB.unmarshal(new StringReader(cleanReqObjectXMLStr), RequestObject.class);
//do stuffs with reqObject;
// Initialize and set ResponseObject
return responseObject
}

How to pass multiple argument in the REST api [duplicate]

I have a method;
#POST
#Path("test")
#Consumes(MediaType.APPLICATION_JSON)
public void test(ObjectOne objectOne, ObjectTwo objectTwo)
Now I know I can post a single object in json format, just putting it into the body.
But is it possible to do multiple objects? If so, how?
You can not use your method like this as correctly stated by Tarlog.
However, you can do this:
#POST
#Path("test")
#Consumes(MediaType.APPLICATION_JSON)
public void test(List<ObjectOne> objects)
or this:
#POST
#Path("test")
#Consumes(MediaType.APPLICATION_JSON)
public void test(BeanWithObjectOneAndObjectTwo containerObject)
Furthermore, you can always combine your method with GET parameters:
#POST
#Path("test")
#Consumes(MediaType.APPLICATION_JSON)
public void test(List<ObjectOne> objects, #QueryParam("objectTwoId") long objectTwoId)
The answer is no.
The reason is simple: This about the parameters you can receive in a method. They must be related to the request. Right? So they must be either headers or cookies or query parameters or matrix parameters or path parameters or request body. (Just to tell the complete story there is additional types of parameters called context).
Now, when you receive JSON object in your request, you receive it in a request body. How many bodies the request may have? One and only one. So you can receive only one JSON object.
If we look at what the OP is trying to do, he/she is trying to post two (possibly unrelated) JSON objects. First any solution to try and send one part as the body, and one part as some other param, IMO, are horrible solutions. POST data should go in the body. It's not right to do something just because it works. Some work-arounds might be violating basic REST principles.
I see a few solutions
Use application/x-www-form-urlencoded
Use Multipart
Just wrap them in a single parent object
1. Use application/x-www-form-urlencoded
Another option is to just use application/x-www-form-urlencoded. We can actually have JSON values. For examle
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;
}
}
The one thing we need to get this to work is a ParamConverterProvider to get this to work. Below is one that has been implemented by Michal Gadjos of the Jersey Team (found here with explanation).
#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);
}
}
};
}
}
If you aren't scanning for resource and providers, just register this provider, and the above example should work.
2. Use Multipart
One solution that no one has mentioned, is to use multipart. This allows us to send arbitrary parts in a request. Since each request can only have one entity body, multipart is the work around, as it allows to have different parts (with their own content types) as part of the entity body.
Here is an example using Jersey (see official doc here)
Dependency
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>${jersey-2.x.version}</version>
</dependency>
Register the 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 class
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;
}
}
Now the tricky part with some clients is that there isn't a way to set the Content-Type of each body part, which is required for the above to work. The multipart provider will look up message body reader, based on the type of each part. If it's not set to application/json or a type, the Foo or Bar has a reader for, this will fail. We will use JSON here. There's no extra configuration but to have a reader available. I'll use Jackson. With the below dependency, no other configuration should be required, as the provider will be discovered through classpath scanning.
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey-2.x.version}</version>
</dependency>
Now the test. I will be using cURL. You can see I explicitly set the Content-Type for each part with type. The -F signifies to different part. (See very bottom of the post for an idea of how the request body actually looks.)
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
Result: FooFoo; BarBar
The result is exactly as we expected. If you look at the resource method, all we do is return this string foo.foo + "; " + bar.bar, gathered from the two JSON objects.
You can see some examples using some different JAX-RS clients, in the links below. You will also see some server side example also from those different JAX-RS implementations. Each link should have somewhere in it a link to the official documentation for that implementation
Jersey example
Resteasy example
CXF example
There are other JAX-RS implementations out there, but you will need to find the documentation for it yourself. The above three are the only ones I have experience with.
As far as Javascript clients, most of the example I see (e.g. some of these involve setting the Content-Type to undefined/false (using FormData), letting the Browser handle the it. But this will not work for us, as the Browser will not set the Content-Type for each part. And the default type is text/plain.
I'm sure there are libraries out there that allow setting the type for each part, but just to show you how it can be done manually, I'll post an example (got a little help from here. I'll be using Angular, but the grunt work of building the entity body will be plain old 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>
The interesting part is the createRequest function. This is where we build the multipart, setting the Content-Type of each part to application/json, and concatenating the stringified foo and bar objects to each part. If you are unfamiliar multipart format see here for more info. The other interesting part is the header. We set it to multipart/form-data.
Below is the result. In Angular I just used the result to show in the HTML, with $scope.result = response.data. The button you see was just to make the request. You will also see the request data in firebug
3. Just wrap them in a single parent object
This option should be self explanatory, as others have already mentioned.
The next approach is usually applied in this kind of cases:
TransferObject {
ObjectOne objectOne;
ObjectTwo objectTwo;
//getters/setters
}
#POST
#Path("test")
#Consumes(MediaType.APPLICATION_JSON)
public void test(TransferObject object){
// object.getObejctOne()....
}
You can't put two separate objects in one single POST call as explained by Tarlog.
Anyway you could create a third container object that contains the first two objects and pass that one within the POS call.
I have also faced with these problem. Maybe this will help.
#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
It can be done by having the POST method declared to accept array of objects. Example like this
T[] create(#RequestBody T[] objects) {
for( T object : objects ) {
service.create(object);
}
}
Change #Consumes(MediaType.APPLICATION_JSON)
to #Consumes({MediaType.APPLICATION_FORM_URLENCODED})
Then you can putting multiple objects into the body
My solution is written for CXF, it appears to be quite simple.
import org.apache.cxf.jaxrs.ext.multipart.Multipart;
#POST
#Path("paramTest")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public GenericResult paramTest(
#Multipart(value = "myData", type=MediaType.APPLICATION_JSON)
ObjectOne myData,
#Multipart(value = "infoList", type=MediaType.APPLICATION_JSON)
ObjectTwo[] infoList);
The test code for this with io.restassurred:
#Test
public void paramTest()
{
String payload1 = "" +
"{ \"name\": \"someName\", \"branch\": \"testBranch\" }";
String payload2 =
" [ { \"name\": \"cn\", \"status\": \"ts\" }," +
"{ \"name\": \"cn2\", \"status\": \"ts2\" } ] ]";
RestAssured.
given().
contentType("multipart/form-data").
multiPart("myData", payload1, "application/json").
multiPart("infoList", payload2, "application/json").
post(String.format("%s/paramTest", API_PATH)).
then().
statusCode(HttpStatus.SC_OK).
contentType(ContentType.JSON).
body("success", Matchers.equalTo(true));
}

Spring MVC Controller never called from ajax Post

I have the page about.ftl which is invoked when I type localhost:8080/ui/about
and I have put the following block of code inside. Through SendToServlet() function I am trying to send the user info to my controller which is the OAuthController.java
function SendToServlet(){
$.ajax({
url: "localhost:8080/ui/about",
type: "POST",
data: JSON.stringify({ user:jsonObj}),
contentType: 'application/json',
success: function(result) {
alert(done);
},
error: function(xhRequest, ErrorText, thrownError) {
alert(JSON.stringify(jsonObj));
}
});
}
</script>
My Spring MVC Controller class code has the following implementation - all that it does is that it accepts the user's information and then sets up current user:
#Controller
#RequestMapping("/about")
public class OAuthController {
#RequestMapping(method = RequestMethod.POST)
#ResponseBody
public String post( #RequestBody String items, HttpServletRequest request, HttpServletResponse response)
{
String jsonResp = items;//sb.toString();
ArrayList<String> usercredentials = new ArrayList<String>();
usercredentials = parseJson(jsonResp);
UserMethods usermethods = new UserMethods();
usermethods.setCurrentUser (usercredentials);
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
return "{\"success\":\"\"}";
}
public ArrayList<String> parseJson(String json){
}
}
My problem is that the controller is never invoked and actually I never see a Post request to be sent anywhere through Firebug. I've spent several days on it, but still no luck. Do you have any suggestions?
You need to bind value with your function. Your url localhost:8080/ui/about/post is just used to locate the controller but it will not execute any function because you didn't make a call to any function.
To call the function, you have to do like this :
#RequestMapping(method = RequestMethod.POST, value ="/anyValue")
public String anyFunctionName(anyParam){...}
Above function will bind to url localhost:8080/ui/about/anyValue.
Don't you need to call it like this?
url: "localhost:8080/ui/about/post",
but first do this:
#RequestMapping(method = RequestMethod.POST, value = "/post")
How about try to add .html?Application won't add it automatically.

Categories

Resources