Passing a boolean value from UI to rest controller - java

I have an application with front end on Angular and backend using Spring/Java.
The functionality is like show employee details and there is a checkbox in the UI. Following should be the behavior
when checkbox is checked, show all employees for a given department
when the checkbox is unchcecked, exclude some employees based on some criteria (this logic is done on backend)
For this, I have a get request and I added an additional parameter of type boolean to the "get" request.
This is how the code is for the UI component
get(include:boolean, dept:string):Observable<EmployeeList>{
let params = new HttpParams();
params=params.set('dept',dept);
params=params.set('include',String(include));
}
Please note that I am using casting to String for include param since I am not finding a way to pass the boolean value from UI using HttpParams.
On the backend the controller is like this
#GetMapping(value="/employee")
public EmployeeList list(#RequestParam String dept, String include) {
boolean flag = Boolean.parseBoolean(include);
.............
}
So I am trying to avoid the following
1. params=params.set('include',String(include));
2. boolean flag = Boolean.parseBoolean(include);
Is there a way? For post and put request,we use form which works fine with booleans.

Turns out the Spring automatically takes care of converting to intended data type so fixed the problem by
#GetMapping(value="/employee")
public EmployeeList list(#RequestParam String dept,#RequestParam boolean include) {
.............
}

Related

Saving data over multiple pages with java web-application

I was looking for a way to store information so I can use a specific variabele multiple times.
If the user gives his/her name, I want to be able to set the name at the top of each page.
I already tried to use this in my controller.
public String login(Model model, HttpServletRequest request) {
gebruikersnaam = request.getParameter("gebruikersnaam");
gebruikerRepository.gebruikersnaamOpslaan();
gebruikerRepository.getGebruiker(gebruikersnaam);
return "/index";
}
Thank you in advanced
Jonas
Assuming gebruikerRepository is the pojo class, you need to use a setter method like gebruikerRepository.setGebruiker(gebruikersnaam) to set the name into variable gebruiker.
Use gebruikerRepository.getGebruiker() to retrieve the variable.

How to receive dynamically generated input value in spring as bean

In my project i dynamically generate the text box in table like below
project Name Date1 Date2 Date3 Date4 Date5 Activity
java Development Addnew
C++ Development Addnew
i display tables for one week.if user clicks addnew i generate the dynamic text box below the row where user clicked addnew button.
My problem is how to get all the textbox value in my spring controller as bean class.Because i am not sure abut how many text boxes are come in page load and submit.
Any Idea will be greatly appreciated!!!
There aren't enough specifics in your question for a specific answer. However the general approach I would recommend.
If you have a framework like Backbone or Angular, investigate use of its collection facilities.
Write JavaScript that builds JSON array from all your textfields
Define a POJO in Java that mirrors each entry in your array.
Ensure you're using Jackson - this maps JSON to Java objects for you before your controller is called
Define an method in your controller that takes a list of POJO, e.g. create(List values) with a URL like /times/{ employeeId} using PUT
For reading out of the database, add method in your controller that returns a list of POJO, e.g. List values get(long employeeId) with a URL like /times/{ employeeId} using GET
Alternatively if you need the form to be 'live', i.e. 'Add new' causes row in database instantly use a REST interface with a create, update and DELETE using POST, PUT and DELETE respectively
I assume you'll need to update the list later, so I'd recommend a structure with an ID which can be used for CREATE and UPDATE operations, not just a plain list of Strings, this will also allow more fields later.
public void Foo {
private String project;
private String name;
private long id;
// getters + setters
}
JSON for a create
[{"project":"java","name":"Development",id:0}, {"project":"C++","name":"Development",id:0}]
JSON for a later update, i.e. with IDs round-tripped
[{"project":"java","name":"Development",id:100}, {"project":"C++","name":"Development",id:101}]
Go with the traditional getParameter() method. I assume your text box will have unique names while generated using jquery.
In the controller,
List<String> requestParameterNames = Collections.list((Enumeration<String>) request.getParameterNames());
for (String parameterName : requestParameterNames) {
String attributeName = parameterName;
String attributeValue = request.getParameter(parameterName);
// will have the text box values
}

Spring controller pre-process #ModelAttribute request parameters

In my Spring 4 driven portlet I have a data-object which contains a date-field. In the JSP-view I have two separate fields for it, date (dd/mm/yyyy) and time (hh/mm). The action handler in my controller receives the form-data by using the #ModelAttribute-annotation:
#ActionMapping(params = "action=update")
public void onUpdate(#Valid #ModelAttribute("myObject") MyObject myObject,
BindingResult bindingResult, ActionResponse response, SessionStatus status)
{
if (!bindingResult.hasErrors())
myObjectService.save(myObject);
else
// provide 'myObject' in the view which displays validation errors
}
I need to merge date and time before the form-data is validated an onUpdate() receives myObject, since in MyObject there is only one java.util.Calendar-field for the whole date available.
Idea 1 to work around this need
Now I thought, I could also split the date into two separate fields in MyObject and provide a getter which merges the values on demand:
#Column(name = "begin")
public Calendar getBegin()
{
// return calendar object built from this.beginDate and this.beginTime
}
but I think this is not a good idea for several reasons (see this question: Hibernate Annotations - Which is better, field or property access?)
I want the model-object to be a mirror of the database-record and hence it should be validated before getting assigned.
Idea 2
Another approch would be, to create or modify the calendar-object in myObject on demand, when setting the date or time:
#Column(name = "begin")
#Temporal(TemporalType.TIMESTAMP)
private Calendar begin;
public void setBeginDate(String value)
{
// assign a new calendar object to "begin", if "begin" is null
// set only day, month and year components on this calendar object
}
public void setBeginTime(String value)
{
// see "setBeginDate", do the same with hours and minutes
}
The problem here is, that a new calendar-object is created if only one of the fields "date" or "time" is valid. The field in the view is filled with the current date or current time (depending on which value was correct)
I can even solve this problem, by adding another private isValidDate-flag to the model. But I think this is an unclean solution.
Conclusion
I think there is a big difference between myObject for the controller and myObject as an actual model-object. myObject should be a model-object, as soon as being validated and "mapped".
So here my questions:
Do you think that the last point reveals using #ModelAttribute as a bad idea generally?
Or is there a way mapping and validating form-data BEFORE the MyObject-instance is created?
If not, how would you recommend to solve the problem?
EDIT : #initBinder is OK the other way around (1 field -> N attributes)
I don't know if the framework can do what you want (N fields -> 1 attribute) out of the box without getting into the binding plumbing.
Here are two simple solutions to get around the issue :
Do it the old "Struts" way and create a MyObjectForm object that you will use exclusively in your view, and then transform it in your controller to MyObject.
You can still use your #Valid at the service layer MyObjectService which is technically sound.
If MyObject does not contain dozens of attributes, Forget about #ModelAttribute + Controller layer validation and just use #RequestParam for each field. Service layer validation is still in play.
You can certainly hack something that will allow you to "bind" your form data to your object manually using Spring MVC's internal facilities, but in the end it will be something like my 2nd point, with much more confusing plumbing.

Struts2 type conversion of a flattened JSON object in a query string

EDIT: Changed question title and content. Upon reading the JSON plugin guide I realize the plugin might be expecting a JSON string instead of this query map, in which case I normally go with GSON instead. I guess the question becomes: how can Struts2 handle type conversion of a query string like this: sort[0][field]=status&sort[0][dir]=asc
I am using Kendo UI grid to interface with my Struts2 backend. The AJAX request being sent to the server follows the following format (GET query string):
take=5&skip=0&page=1&pageSize=5&sort%5B0%5D%5Bfield%5D=status&sort%5B0%5D%5Bdir%5D=asc
or (non-escaped):
take=5&skip=0&page=1&pageSize=5&sort[0][field]=status&sort[0][dir]=asc
Basically, Kendo UI grid is sending a flattened JSON object to the server. So I create a sort model object like so to take the input:
public class SortModel {
private String field;
private String dir;
}
and include this in my Struts2 action as a variable to be populated:
private SortModel[] sort;
However, this never gets populated by Struts2 when the AJAX request comes in. I also tried to add the JSON interceptor, but I think I misunderstood its deserialization process, as explained in the edit.
Anyway, has anyone managed to Struts2 type conversion working using the above query string or similar: sort[0][field]=status&sort[0][dir]=asc?
sort[0][field]=status&sort[0][dir]=asc
The above is not proper JSON, strings should be quoted. With that done the following will work.
In which case a field (or json parameter) in the form name[i]['s'] which has a value of String and where i is an integer and s is any string would be backed by:
private List<Map<String, String>> name = new ArrayList<Map<String, String>>();
//getter AND setter required
PS: With Struts2 you can index into lists of lists of lists... without issue.
Okay.
It turns out that vanilla Struts2 doesn't accept query strings in the format obj[idx][property] (feel free to correct me on this). I was expecting it to convert the query string to an array of that specific object.
What Struts2 does accept is the format obj[idx].property which it will correctly convert to private Object[] obj.
So I guess the possible solutions to this would be:
JSON.stringify(jsonObj) before passing it to the query string, a la &jsonData=[{property:'value'}] - which in this case, I can't do since Kendo UI grid doesn't seem to have an interceptor-like event to let me change the query parameters. Or,
Implement a custom type converter that handles this particular format. Or,
Intercept the AJAX request before it is being sent to the server and re-format the query string, using jQuery.ajaxSend e.g.
$(body).ajaxSend(function(event, req, settings){
console.log(settings.url); //contains the url string to replace
settings.url = settings.url.replace(some_regex, 'correct format');
});

How to pass #RequestParam and #ModelAttribute in one form

I would like to mix #RequestParam and #ModelAttribute in one spring form and controller.
Things that I do in my controller are as follows:
#RequestMapping("/user/edit/{userId}")
public ModelAndView editUser(#PathVariable String userId,
#ModelAttribute User user, BindingResult bindingResult,
#RequestParam Set<String> groups) {
if(bindingResults.hasErrors() {
//return back to form and correct errors
} else {
//save data and get out of form
}
}
There are simple User bean (id, firstName, lastName, etc) but without "groups" property.
There is also simple Group bean (id, name, description) but without any connection with User.
So on the logical level User and Group are totally separeted.
In my form, when editing User, there is a html SELECT element that contains ids of all groups. You can select multiple ids together with filling User data and send it to controller.
Until now, everything works pretty well. I get #ModelAttibute User properly filled. I also get #RequestParam Set[String] groups filled with selected ids (Strings).
Now I would like to do something more. I need to write something that instead of #RequestParam Set[String] groups will give me #RequestParam Set[Group] groups. Of course I can convert it directly in my controller method editUser(...) but it's not a nice solution. So I decided to write a custom #InitBinder method that will do it for me nicely and smoothly.
And tere the problem comes.
I wrote the initBinder as follows:
[...]
webDataBinder.registerCustomEditor(Set.class, "groups", new CustomCollectionEditor(Set.class) {
#Override
protected Object convertElement(Object element) {
if (element instanceof GroupName) {
return element;
}
if (element instanceof String) {
Group group = userCatalog.loadGroup((String) element);
return group.getGroupName();
}
return null;
}
});
[...]
The problem is that there is absolutely no way to call this method. I put inside that some "debugging" System.out.println(...) but it doesn't print anything.
My question is: how to write a correct InitBinder that will be invoked in response to Strings array from html OPTION element and convert it to my Set of Users.
I changed some brackets to this [ and ] because it wasn't displayed.
Thank you for help.
meanwhile I came across on this topic: Custom property editors do not work for request parameters in Spring MVC?
and I think this is a key to the solution. In fact, as javadocs says, "field" argument is necessary only when using ModelAttibute (or form backing object which is the same...), but not for RequestParam. So is there any solution to use InitBinder together with RequestParam? Or I need to write a direct method in controller that converts ids to Set of Group objects?
Try registering your custom editor just against the Set.class type and leaving out the field name to see if that works.
webDataBinder.registerCustomEditor(Set.class, new CustomCol...
I have a suspicion that the field parameter denotes the property name of a ModelAttribute and not the request parameter name.
Alternatively, you could use a wrapper view model and use a second ModelAttribute parameter,
class GroupsViewModel {
private List<Group> groups
...
}

Categories

Resources