pass complex data from angularjs controller to Spring MVC controller - java

I have a form with following sections ( following example is for understanding purpose)
GeneralInformation - it 's an object with Cityname (String) and population(int)
Location Information: It's an object with locationCode (int) and Nearest HospitalName(String)
Companies: It's an object with company details. There is list of companies dynamically added
with Company as object. Basically List
Hospitals: it's like List
// generalInfo - populated from form
//locationInfo - populated from form
//companiesArr[] // this is dynamicallypopulated (each row each object) companies array
// hospitalsArr[] // // this is dynamicallypopulated (each row each object) Hospitals array
//Angular code starts..
controller('addGeneralController', function($scope, close,Service) {
$scope.companiesArr = [];
$scope.comapnyName='';
$scope.companyType='';
$scope.hospitalsArr = [];
$scope.hospitalName='';
$scope.locationCode='';
$scope.generalInfo = {};
$scope.locationInfo = {};
$scope.companies = {};
$scope.hospitals = {};
$scope.dataInfo = {};//this is to carry entire objects and arrays
//Following method calls after populating data from form and submit.
//companiesArr,hospitalsArr are populated from front end and passing as submission parameters
$scope.saveGeneral = functio(generalInfo,locationInfo,companiesArr,hospitalsArr){
$scope.companies = companiesArr;
$scope.hospitals = hospitalsArr;
//Create an empty array
//$scope.dataInfo = [];
$scope.dataInfo.push({'generalInfo' : generalInfo, 'locationInfo' : locationInfo,'companies' : $scope.companies,'hospitals' : $scope.hospitals});
$http.post("/addGeneralData",$scope.dataInfo);
});
//Angular code ends..
It's not reaching to the following Spring MVC method:
#RequestMapping(value = "/addGeneralData", method = RequestMethod.POST)
public #ResponseBody String addGeneralData(#RequestBody List<Data> dataInfo){
// not reaching here.With simple parametrs it's reaching here, so no other mapping issue apart from this complex data
// Data - is an object with generalInfo as object,locationInfo as object, //companies List ,hospitals List as it's attributes.
Data data = dataInfo.get(0);
GeneralInfo generalInfo = data.getgeneralInfo();
LocationInfo locationInfo = data.getLocationInfo();
List<Company> companies = data.getCompanies();
List<Hospital> hospitals = data.getHospitals();
}
Basically I want to know how can I transfer this complex data from angular controller to Spring MVC controller?

Please share the request sent from the browser to comment more
It certainly looks like you are sending DataInfo Object but receiving
List dataInfo in your controller. there is a mismatch.
Change the Signature of the handler method
to public #ResponseBody String addGeneralData(#RequestBody DataInfo dataInfo)

Thanks for your response.It's worked when I changed to array instead of list. I have changed all lists inside the Data objects also to array. In addition to that make sure that all data passing from input is as per the type mentioned in the concrete object. For example any data mentioned as int , make sure it's passing int only. If it is complex form and before input validation we are integrating front end with backend, make sure all data we passed exactly as the type mentioned in the mapping object.Is it good practice to use array as parameter in MVC controller?

Do you have any exception ?
It is very likely that you get Serialization Exception due to List interface passed as parameter to controller. Spring just can not initialize new instance of List. Try to use array instead of List. For example
#RequestMapping(value = "/addGeneralData", method = RequestMethod.POST)
public #ResponseBody String addGeneralData(#RequestBody Data[] dataInfo){
Data data = dataInfo[0];
GeneralInfo generalInfo = data.getgeneralInfo();
LocationInfo locationInfo = data.getLocationInfo();
Company[] companies = data.getCompanies();
Hospital[] hospitals = data.getHospitals();
}
Be sure that you use concrete implementations, not interfaces in your Data object.
Hope it helps

Related

Passing json object to an endpoint developed with spring

I have an endpoint I created using spring.io. My GetMapping declaration can be seen below
#ApiOperation(
value = "Returns a pageable list of CustomerInvoiceProducts for an array of CustomerInvoices.",
notes = "Must be authenticated.")
#EmptyNotFound
#GetMapping({
"customers/{customerId}/getProductsForInvoices/{invoiceIds}"
})
public Page<CustomerInvoiceProduct> getProductsForInvoices(
#PathVariable(required = false) Long customerId,
#PathVariable String[] invoiceIds,
Pageable pageInfo) {
//Do something fun here
for (string i: invoiceIds){
//invoiceIds is always empty
}
}
Here is how I am calling the url from postman and passing the data.
http://localhost:8030/api/v1/customers/4499/getProductsForInvoices/invoiceIds/
{
"invoiceIds": [
"123456",
"234566",
"343939"
]
}
My string array for invoiceIds is always empty in the for loop Nothing gets passed to the array. What am I doing wrong?
The mapping you are using is this:
customers/{customerId}/getProductsForInvoices/{invoiceIds}
Both customerId and invoiceIds are Path variables here.
http://localhost:8030/api/v1/customers/4499/getProductsForInvoices/invoiceIds/
The call you are making contains customerId but no invoiceIds. Either you can pass the list in place of invoiceIds as String and read it as a String and then create a List by breaking up the List - which will be a bad practice.
Other way is to change your path variable - invoiceId to RequestBody.
Generally, Path Variables are used for single id or say navigating through some structured data. When you want to deal in a group of ids, the recommended practice would be to pass them as RequestBody in a Post method call rather than a Get method call.
Sample code snippet for REST API (post calls):
Here, say you are trying to pass Employee object to the POST call, the REST API will look like something below
#PostMapping("/employees")
Employee newEmployee(#RequestBody Employee newEmployee) {
//.. perform some operation on newEmployee
}
This link will give you a better understanding of using RequestBody and PathVariables -
https://javarevisited.blogspot.com/2017/10/differences-between-requestparam-and-pathvariable-annotations-spring-mvc.html
https://spring.io/guides/tutorials/rest/

Creating a endpoint to return a list of objects from a database using Spring

I have a database and I want to use a endpoint to get the data. But I want to filter the data so that only certain values are returned. What I want is to call the endpoint and then get the data that I wanted out of it. I have made two methods one for calling all the data and another for calling only 1 record in the database. they both working good, but I want to now get multiple records from the database. This is what I have so far:
//This get every record
#RequestMapping(
value = API_PREFIX_1_0 + ENDPOINT_coupon + "/getCoupon",
method = RequestMethod.GET)
public Collection<Coupon> couponGetAll()
{
return couponService.getAll();
}
//this get only one record based on the ID of the table
#RequestMapping(
value = API_PREFIX_1_0 + ENDPOINT_coupon + "/{id}",
method = RequestMethod.GET)
public Coupon couponGetById(#PathVariable(value = "id") final long id) {
return couponService.getById(id);
}
What I want to do is use an array or a list of id to get the data from the server.
Thank you for any help with this
The spring CrudRepository already provides a method to find items by a set of ids:
Iterable<T> findAll(Iterable<ID> ids)
this method should be triggered by your service if you are using a CrudRepository in your persistence layer.
Then you could add a request parameter to your couponGetAll() method where to get the ids and send it to your service.
#RequestMapping( value = API_PREFIX_1_0 + ENDPOINT_coupon + "/listOfCoupons", method = RequestMethod.GET)
public Iterable<Coupon> couponGetMine(#RequestParam(name="ids")String ids) {
Iterable<Long> longIds = convertToLong(ids);
return couponService.getAll(ids);
}
The client side url to call would look something like this:
.../listOfCoupons?ids=2,4,7,3
In the endpoint you extract the numbers out of the string. Maybe there is a nicer solution but this is what is in my mind in this short time.
Convert the id string e.g.:
public Iterable<Long> convertToLong(final String ids){
String[] idArray = ids.split(",");
List<Long> idsAsLong = new ArrayList<>();
for (int i = 0; i < idArray.length; i++) {
idsAsLong.add(Long.parseLong(idArray[i]));
}
return idsAsLong;
}

JPA dont want to fetch OneToMany Object (One Level deep)

I am using Spring Data Rest. It works great except that I have a REST call that I need to just return the top object and not have the OneToMany object returned.
How do I do this?
For example:
So I have a Rest interface with "/States" and "StatesWithHotels". There is a OneToMany from the State JPA object to the Hotel JPA object. The "/States" should just return just the States and the "StatesWithHotels" should return State object with the corresponding Hotel objects. The "StatesWithHotels" works perfect in which it returns States and Hotels. But the "States" I just need to return just States, but it is returning both.
So this is what I came up with.
The top level object iterated through and set the secondary object to null
for example:
#RequestMapping(value = "/getStates", method = RequestMethod.GET,
headers = { "Accept=application/xml" }, produces = "application/xml")
public #ResponseBody StateList getStates() {
List<StateList> tmpStateList = countryRepo.findByStates();
for(State tmpState : tmpStateList ){
tmpState.setHotels(null);
}
StateList tmpResult = new StateList(tmpStateList );
return tmpResult;
You need to set the fetch mode for that collection to lazy. This will make sure that the collection isn't retrieved until it's accessed.
#OneToMany(fetch=FetchType.LAZY)
If you want it not to be serialised when it's returned, you might also need to annotate it with
#JsonIgnore

how to get values in different beans from single JsonNode in play framework controller

I am using play framework for Java. And I have jquery ajax to post my data (String representation of JsonNode). I am writing an action method in my controller class for serving this ajax call.
The problem I am facing is that, the data I am sending with jquery ajax has 10 textfield values. And I have 3 bean classes (viz., MyClass1,MyClass2,MyClass3) that together have all these 10 variables to capture those textfield values. If I had only a single bean(say,MyClass1`) with 10 variables defined in it, I could write something like:
JsonNode json = request().body().asJson();
MyClass1 obj1 = Json.fromJson(json, MyClass1.class);
and easily access values from obj1.
But I have 3 beans and in first bean I've 3 variables, in the second 5 variables, and in the third 2 variables. This creates a problem.
How do i get these 10 textfield values in MyClass1 obj1, MyClass2 obj2, MyClass3 obj3 in proper way and as required. In other words how do i achieve the spliting of JsonNode. Or something similar to get appropriate values in all the 3 beans.
Any help or any clue is really appreciated. Thanks in advance.
What can be done to get these?
Well, the answer to this question is pretty simple. What I did was
I added the following 2 lines in the bean MyClass1:
public MyClass2 m2;
public MyClass3 m3;
and I kept the code in my controller's json method same as it was earlier, i.e.:
JsonNode json = request().body().asJson();
MyClass1 obj1 = Json.fromJson(json, MyClass1.class);
and in jquery I created a complex json var (NOTE: have a look at data1 below):
var data1 = {
"dataField1": dataField1,
"dataField2": dataField2,
"dataField3": dataField3,
"data2": data2,
"data3": data3
}
var data2 = {
"dataField4": dataField4,
"dataField5": dataField5,
"dataField6": dataField6,
"dataField7": dataField7,
"dataField8": dataField8
}
var data3 = {
"dataField9": dataField9,
"dataField10": dataField10
}
and then while making ajax call simply passed data1 as:
$.ajax({
url: '/myUrl/data1',
type: 'POST',
data: JSON.stringify(data1),
contentType: "application/json",
..
..
..
});
Now in the controller's json method, I could access obj1.m2 and obj1.m3and could solve my problem. (No need to think about spliting JsonNode.)

getting the values of array from javascript to java as list

var catids = new Array();
I have a catids array where i store the checked checkbox values like the below one.
cat = $("input[name=catChkBox]:checked").map(function () {
return $(this).data('name');
}).get().join(",");
the cat variable forms something like this 1,2,3..
I want to send this "cat" to a java method and print those values.
I pass the values to java through a dwr call like this
DataHandler.getTasks( categories, {callback:function(data){
}, errorHandler:function(){
},async:false
});
I have configured dwr for pojo. should I configure anything for parameters?
I tried the below code but I didn't get anything.
public List<Facade> getTasks(String myIds){
String[] ids = catids .split(",");
System.out.println("-------size of cat id------------" + myIds.length);
for (int i=0; i<myIds.length;i++)
System.out.println(myIds[i]);
//finally it will return a pojo which i l be receiving it in data of dwr call.
-------size of cat id------------ is 1
myIds[i] prints nothing
I need it as an integer back.
What mistake am I doing ?
I will do it in this way.
JavaScript creates json object like this {"categoryIds": [1,2,3,4,5]}
Java converter convert json to java POJO object using for example Gson or Jackson library.
After convert you can work with java POJO object which have list of categories.
If you use this solution your code will be more clear and you will be able to share more objects between JavaScript and Java using the same clear solution.
Example (pseudo code)
CategorList class
public class CategoryList {
private ArrayList<Category> categoryList;
// getters and setters
}
Converter
public class CategoryListConverter {
public CategoryList convert(String json) {
Gson g = new Gson();
CategoryList cl = g.fromJson(json, CategoryList.class);
return cl;
}
}
I tried the code it workd fine
getTasks("1,2,3");
check what the value of categoriesIds is sent to getTask
Send this as a form parameter from webpage. Then get this from HttpServletRequest request object in java.
request.getParameter('categoryId');

Categories