SpringMVC: Set pathvariable using form data - java

So I'm a little unclear on how to properly use #PathVariable in the context I'm trying to here. Let me explain.
I have a JSP page with a table. The table contains all the records in a table in my database. That all works fine.
At the bottom of the table, there are buttons. Add, Edit, Delete. They are all using separate forms because I want to have separate URL paths/ HTTP Methods for each.
To accomplish this, I'm using JQuery so that when I hit submit on the form, it retrieves the ID value of the currently selected record. All of that works perfectly, and is not what I'm asking about.
Here is the form where the submit action is taking place:
<form:form id="editForm" action="./${courseId}.html" path="courseId" method="get">
<input type="hidden" id="editCourseId" name="courseId"/>
<input class="btn btn-lg btn-default btn-shadow" type="submit"
value="Edit"/>
</form:form>
So, what I want is for this form to call a URL with courseId as the #PathVariable value. The value of courseId is contained in the hidden input field with the name courseId. Again, that input field's value is set by JQuery code, and I've already tested that and it seems to be working perfectly.
What I want is to use courseId as the #PathVariable, and have it work in the following controller method:
#RequestMapping (value="/{courseId}", method=RequestMethod.GET)
public String editCourse(Model model,
#PathVariable ("courseId") String courseId){
System.out.println("CourseID: " + courseId);
return "course-form";
}
Obviously that method is still in the early stages, just trying to get confirmation that it works.
So, what do I have to do to make this happen? Again, I want to pass the value of courseId in the URL, as a RESTful style URL command, using it as a #PathVariable. How do I do this?
Thanks so much.

You can get a very clear explanation here
#RequestMapping (path="/{courseId}", method=RequestMethod.GET)
public String editCourse(Model model,
#PathVariable String courseId){
System.out.println("CourseID: " + courseId);
return "course-form";
}

Related

How can I get the values ​of 1-20 checkboxes from the controller?

How can I get the values ​​of 1-20 checkboxes from the controller?
<div>
<ul>
<li th:each="poi : ${poiList}">
<label th:for="${poi.modelName}" th:text="${poi.modelName}">modelName</label>
<input type="checkbox" th:id="${poi.modelName}"
th:name="${poi.modelName}" th:checked="false"/>
</li>
</ul>
</div>
As above, there are 20 checkboxes in the form tag.
When the send button is pressed, only the checked poi among poi1~poi20 is sent as poi6=on&poi15=on.
How should I get the value from the controller at this time?
#PostMapping("/add")
public String save(
#RequestParam String poi1,
#RequestParam String poi2
...){
// modelName=%EB%8F%84%EB%A9%B41&poi6=on&poi15=on
if( poi == null)
...
}
I wonder if there is a better way than this way.
In case you use multiple parameters in url.
You can inject HttpServerletRequest instead of specifying full parameters.
#PostMapping("/add")
public String save(HttpServletRequest req)
}
With getParameterNames or getParameterMap method, it can help you to iterate the list of parameters. getParameter method can help to retrieve the value of specific param name.
Please refer to spec:
https://docs.oracle.com/javaee/6/api/javax/servlet/ServletRequest.html#getParameterNames()
The second way, use DTO in your method, spring will auto bind its properties.
#PostMapping("/add")
public String save(YourObject obj)
}
Make sure the attribute name in YourObject match with parameter name, spring will use getter/setter to apply the value.
You can refer at:
Spring MVC: Complex object as GET #RequestParam

Best way to edit an object with Thymeleaf and Spring MVC

I'm working on a website in which users can add and edit things (it's not relevant describing what these things are in particular).
I'm implementing it using Thymeleaf for the frontend, Spring MVC for the backend and JPA for the database logic. Now I'm trying to implement the edit logic but I don't know which is the best way to do it.
What I'm thinking is: display to the user all the input fields (on a HTML page) that he is allowed to edit, already filled in with the current values. He can edit then whatever fields he wants and finally press the edit button to persist the changes.
Once I get the new object in the backend, I retrieve the old version from the database in order to check which field the user changed. For every field that got changed I update the old version and only when I've finished I call the JPA method save and I persist the new version of that object.
Is there a better way to do it?
It would be perfect if the object I put inside the model in order to display all its field to the user inside the HTML page, could mantain all the information of the old object and not just the ones the user can change. Let me explain better what I'm trying to say with an example:
Let's say the object we are trying to edit its called Person and has these attributes:
id
name
surname
money
nickname
sex
But the user can edit only the following attributes:
money
nickname
sex
so the controller which handler the get request of the page would look like this:
#GetMapping("person/{personId}/edit")
public String getEditPersonPage(#PathVariable Integer personId, Model model) {
Person person = personService.getById(personId); //person has all the attributes filled in
model.addAttribute("person", person);
and the controller which handler the put request looks like this:
#PutMapping("person/{personId}/edit")
public String editPerson(#ModelAttribute Person person, #PathVariable Integer personId){
personService.editPerson(person); //person has only the three fields filled in and all the other attributes as NULL
return "redirect:/person/" + personId;
}
the HTML page:
<form th:object="${person}" th:method="PUT">
<fieldset>
<p th:text="*{id}"></p>
<p th:text="*{name}"></p>
<p th:text="*{surname}"></p>
<input type="number" th:field="*{money}" th:value="*{money}" />
<input type="text" th:field="*{nickname}" th:value="*{nickname}" />
<input type="text" th:field="*{sex}" th:value="*{sex}" />
<input type="submit" value="Edit" />
</fieldset>
</form>
When I insert the object person inside the model to render the HTML page the object has all the attributes. Indeed I can decide which of its attributes display inside the HTML page (in this case only three: money, nickname and sex). But when the user press the submit button (edit), I receive only the fields displayed inside the HTML page (money, nickname, sex). So what I have to do is: I have to take these three fields, check if they are changed and if so, update the old version.
It would be perfect if when the user press the submit button, all the fields of person (and not just those three he is allowed to update) could be retrieved by the controller. In that case I could skip the check phase and persist directly the new version inside the database (with the old values unchanged and not set to NULL).
Any thoughts?
You can use readonly attributes for the ones that are not going to be edited.
I think is the best way in order to keep all the values visible in the form to give all the info to the user that is editing. All the values will be submitted and serialized with your object, but the form just allows to edit the three of them that you need.
A readonly element is just not editable, but gets sent when the according form submits. A disabled element isn't editable and isn't sent on submit.

Prevent Form Action From Changing URL After File Upload

I have a simple form in my Spring MVC project that handles a file upload.
form.jsp
<form method="POST" enctype="multipart/form-data" action="/upload" id="form">
<input id="file" type="file" name="file"><br />
<input type="submit" value="Upload">
<input type="reset" value="Reset">
</form>
Because of the form's action however, I am redirected to localhost:8080/myApp/upload rather than localhost:8080/myApp/form as specified in my #Controller
#RequestMapping(method = RequestMethod.POST, value = "${context}/upload", headers = "content-type=multipart/*")
public String uploadFile(#RequestParam("file") MultipartFile file, Model model) {
//do some upload stuff
model.addAttribute("uploadSuccess", "Upload Successful.");
return "/form";
}
Is it possible to prevent only the form action's redirection, but still retain the value ${context}/upload so that my Controller method gets called? I need my page to land back on myApp/form because this particualr url makes a call to a separate Controller method that retrieves some data
Note that I don't wish to rename my jsp file to 'upload.jsp' and I don't want to make an AJAX Post (Thanks for nothing IE9). Any thoughts mates?
Found the answer for my exact case on 17.5.3 Redirecting to views from Spring's Docs
It is sometimes desirable to issue an HTTP redirect back to the
client, before the view is rendered. This is desirable, for example,
when one controller has been called with POST data, and the response
is actually a delegation to another controller (for example on a
successful form submission). In this case, a normal internal forward
will mean that the other controller will also see the same POST data,
which is potentially problematic if it can confuse it with other
expected data.
This can be done with the following:
return "redirect:/form";
A nice benefit to the redirect is that it prevents the user from accidentally re-POSTing the same data by performing a refresh. The refresh forces a GET of the result page, not a resend of the initial POST data.
UPDATE:
The default redirect:/view will append your model attributes to your URL as query params. This may be undesirable in some cases as it could expose sensitive information to the user. Utilize RedirectAttributes addFlashAttribute(String attributeName, Object attributeValue) method to in order to store Flash Attributes that will be used to store attributes when redirected from one URL to another (Success/Failure messages, etc.)

Separately managing obiects from lists in spring 3 mvc + jsp web application

After thinking a lot, this is the best question title I could find. Not that representative, I'm sorry :-(.
By the way let me explain the problem.
I have to implement an administration panel. It displays a table where every line contains a user with his roles and account status. You can see the idea sketched in the following image
now, my problem is about managing the backing model object:
I have to pass a list of users to populate the administration panel but
I have to bind each user to a model object and
I have to submit each user separately.
I found many tips for managing the table as a whole so that a single button submits all the users at the same time, but what I want to do is populating the table with a list and managing every list record (the user) separately.
I thought to manage each line with javascript to keep trace of the modified values and to use them to build a uri like http://authority/app/user_management/{user_id}/{is_locked}/{is_admin}/.../. The uri will be triggered by the corresponding submit button, but I prefer to avoid this approach.
Moreover, to populate the table with the correct checkbox value it is necessary to have a binding enstablished.
Any advice?
Thanks!
I think you can use separate form for each row with a User object as a Model. You will have simple 'updateUser' handler with User object in input parameters list.
As I remember it could be a User you are iterating through in your foreach, but I need to check it with the real example..) At least you can use simple form and pass 'id', 'isLocked', etc. as request parameters.
<!-- Inside foreach loop -->
<form action="/updateUser" method="POST">
<input type="hidden" name="id" value="${user.id}"/>
<tr>
<td><input type="checkbox" name="isAdmin" value="Is Admin" checked="${user.isAdmin}"/></td>
<td><input type="submit" value="Submit"/></td>
</tr>
</form>
And something similar on server side:
#RequestMapping(value = "/updateUser", method = RequestMethod.POST)
#ResponseBody
public ResponseDTO updateUser(#RequestParam String id, #RequstParam boolean isAdmin) {
// your update logic
}

Spring mvc: controller returns [][], usable in jsp with foreach, but how to bind?

I'm building a spring mvc application.
Now the problem I have is the following.
I have a controller which adds a DayInfo[][] to my ModelMap.
(DayInfo has an id, a title (String) and Text(also String).
Now the problem I have is that I have no problem displaying this DayInfo[][] with <foreach> tags in my jsp.
However I'm outputting the Title property as an input box(type text), and I'd like to be able to update this value (and thus saving it to be a database but that shouldn't be a problem). However I'm having trouble with binding this value to the input box so that it is actually returned to the controller.
If anyone has some advice it would be welcome.
I have never done this with multidimensional arrays but it should be something like this (though I haven't tried it, it's just to give you an idea). In the JSP you should set the name of the input with each index, something like this:
<c:forEach var="row" items="${days}" varStatus="statusRow">
<c:forEach var="day" items="${row}" varStatus="statusCol">
<input type="text" name="days[${statusRow.index}][${statusCol.index}].title" value="${day.title}"/>
</c:forEach>
</c:forEach>
and in the controller you have to prepare days variable so the size of the array is the same as the one you get from the JSP. So you can use #ModelAttribute method to prepare the array (this method will be executed before the #RequestMapping method).
#ModelAttribute("days")
public getDays(){
DayInfo[][] days;
//Here you have to instantiate the days to prepare it so it can be filled
//You can load for example the data from the database
return days;
}
#RequestMapping("/yourURL")
public String getFormData(#ModelAttribute("days")DayInfo[][] days){
//Here in days you should have the data from the form overriding
// the one from the database
}
Hope this helps and sorry if there is any error, though I'm writing withoug trying it.

Categories

Resources