Post Object with List of Object containing multipart files - java

I'm trying to send a post request from Thymeleaf to my controller. The page dynamically creates new input fields when a button is pressed and the page can have multiple of these fields.
function addNewRow(){
let row = document.createElement("tr");
let data = document.createElement("td");
let floorData = document.createElement("td");
let imageData = document.createElement("td");
let floorInput = document.createElement("input");
let imageInput = document.createElement("input");
row.setAttribute("id","newAdditions");
floorInput.setAttribute("id","floorNumber");
floorInput.setAttribute("type", "text");
floorInput.setAttribute("placeHolder", "Floor Number");
floorInput.setAttribute("class", "form-control floorNumber");
floorData.setAttribute("id", "floorNumberData")
floorData.appendChild(floorInput);
imageInput.setAttribute("type","file");
imageInput.setAttribute("accept","image/*");
imageInput.setAttribute("id","imageData");
imageInput.setAttribute("class","imageData");
imageData.appendChild(imageInput);
row.appendChild(data);
row.appendChild(floorData);
row.appendChild(imageData);
document.getElementById("tableBody").appendChild(row);
}
Now when the submit button is pressed, the images (imageData) is passed into a List along with the floorNumber
function submitImages(){
let allItems = document.querySelectorAll('[id=newAdditions]');
for(let i = 0; i < allItems.length; i++){
let floor = allItems[i].getElementsByClassName('floorNumber');
let image = allItems[i].getElementsByClassName('imageData');
floor[0].setAttribute("name", "images[" + i +"].floorNumber");
image[0].setAttribute("name", "images[" + i +"].floorImage");
}
$('#floorForm').submit();
}
My #ModelAttribute/Dto class is as below
public class UploadFormDto{
private List<UploadData> images;
private Long id;
getters & setters
}
UploadFormDto contains
public class UploadData{
private MultipartFile floorImage;
private String floorNumber;
getters & setters
}
And my controller method is as below
#PostMapping(value = "/edit")
#Transactional
public String handleEditHotelRooms(#ModelAttribute("editForm") UploadFormDto editForm,
#PathVariable("hotelId") Hotel hotel,
BindingResult result, RedirectAttributes redirectAttributes) throws WebActionException {}
ISSUE: When the form is sent through, the list of objects populate the floorNumber correctly but the file is never sent through. What am i doing wrong or missing?
My thymeleaf page does not have the enctype='multipart/form-data' because if I add it, the controller complains that the "Current request is not a multipart request"

So i finally managed to fix this, the issue was not in the js or the DTO. The issue was on the Thymeleaf page itself, i had "ajax-form=true" in the form attribute of the page. Once that was removed, I was able to submit the form correctly and get all the images to the controller.

Related

SpringBoot - How do I create a request which can be based on user input and is then picked up by a controller method?

I have managed to send a parameterised request based on the URL entered by the user, however I am not sure how to get the 2nd controller to properly receive the route for the URL field of the Project class object. How do I do this? I don't even know what to search.
//ProjectController
//Creating Project Object
Project project = new Project();
System.out.println("userID: " + userID);
//Getting values using webuser userid (Parameter that passed by model attribute)
WebUser webUser = webUserRepo.findUserById(Long.parseLong(userID));
//Setting values to project object to save
project.setUserID(webUser);
project.setDescription(description);
project.setTargets(targets);
project.setUrl(url);
// Getting date
Date date = new Date();
project.setPublishedOn(date);
//Save Project Object and get that saved Object for system.print
Project savedProject = projectRepo.save(project);
//Print saved Object
System.out.println("saved Project Object : "+ savedProject.toString());
//Set user id in model attribute for return page
model.addAttribute("userID", userID);
model.addAttribute("url", url);
return "/project-dashboard/" + savedProject.getUrl();
//Dashboard Controller:
#GetMapping("project/{url}")
public String serveProject(#PathVariable("url") String url, #RequestParam Long userID, Model model){
System.out.println("OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO ADKLLDAL " + userID);
Project project = projectRepo.getById(userID);
System.out.println(project.toString());
model.addAttribute(project);
return "project";
}
Thanks for any help!

Spring MVC annotation #ModelAttribute

i have some question about Spring MVC annotation #ModelAttribute.
In first method named as "addProduct" i create Model model and after call model.addAttribute i can use "product" name in jsp file,for example product.getProductPrice.
But in second method named same as first,i added parameter
" #ModelAttribute("product") Product product ",but why??
If i will delete this annotation, my program works as same as before,please explain me)
Thank you very much,sorry for my English,i am from Ukraine)
#RequestMapping("/admin/productInventory/addProduct")
public String addProduct(Model model) {
Product product = new Product();
// add default for radio button!
product.setProductCategory("Mobile Phone");
product.setProductCondition("New");
product.setProductStatus("active");
model.addAttribute("product", product);
return "addProduct";
}
#RequestMapping(value = "/admin/productInventory/addProduct", method = RequestMethod.POST)
public String addProduct(#ModelAttribute("product") Product product, HttpServletRequest request) {
productDao.addProduct(product);
MultipartFile productImage = product.getProductImage();
String rootDirectory = request.getSession().getServletContext().getRealPath("/");
System.out.println(rootDirectory);
// product id as the file name
// !!!! TODO
// path = Paths.get(rootDirectory + "/WEB-INF/resources/image/" +
// product.getProductId() + ".png");
path = Paths.get("F:\\Spring\\eMusicStore\\src\\main\\webapp\\WEB-INF\\resources\\images\\"
+ product.getProductId() + ".png");
if (productImage != null && !productImage.isEmpty()) {
try {
productImage.transferTo(new File(path.toString()));
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Product image saving failed", e);
}
}
return "redirect:/admin/productInventory";
}
Purpose #ModelAttribute is bind param/properties from request a model object,
say #ModelAttribute("person") Person person in your method, it will bind properties from object such name, age to Person and construct a object out of it. It does not pass anything to your view, it job finishes once the request submitted. Not carried down to the view of that action.
In contrast, when you have Model model you are explicitly constructing an object with property added to its attribute. It will be carried down to your view unlike what #ModelAttribute does above

the map of the model always returns an empty object

Good evening, I have a Spring MVC project on an e-commerce site.
concerning cart management, when I add a product to the cart by clicking the "Ajouter au panier", it adds good, but the problem if I add another product, I show that the second product .
I made "println" and I noticed that "model.asMap (). get (" panier ")" always returns null. what is the problem please?
Here are some screen prints on the console, controller and index.jsp
Controller
#RequestMapping(value = "/ajouterAuPanier")
public String ajouterAuPanier(#RequestParam Long idArticle, #RequestParam int quantite, Model model) {
System.out.println("111111111111111111111111111111111111111111111");
Panier panier = null;
if (model.asMap().get("panier") == null) {
System.out.println("222222222222222222222222222222222222222222222");
panier = new Panier();
System.out.println("333333333333333333333333333333333333333333333");
model.addAttribute("panier", panier);
System.out.println("9999999999999999999999999999999" + panier.getItems().size());
} else System.out.println("555555555555555555555555555555555555555555555");
panier = (Panier) model.asMap().get("panier");
panier.addArticle(metier.getArticle(idArticle), quantite);
model.addAttribute("categories", metier.listCategories());
model.addAttribute("articles", metier.listArticles());
return "index";
}

Java playFramework2: how to put value to form field before post

I have entity for reporting. I wonna know who filled up report. I would like to put id of user from session to form class.
I've tried already methods like: bind, fill; but no working solution found.
Ofcorse I mean form class: play.data.Form.form
How can I achive this?
Please help.
Here is my approach (when I wrote this Post):
static Form<Registry> modelForm = form(Registry.class);
Registry registry = new Registry();
registry.creationUser = User.getCurrentUser();
registry.test="tt";
modelForm.fill(registry);
modelForm.bind(data, allowedFields)
My submit method
#Transactional
public static Result submit() {
modelForm = modelForm.bindFromRequest();
if (modelForm.hasErrors()) {
return badRequest(views.html.Registry.form.render(modelForm));
} else {
modelForm.get();
}
registry.creationUser = User.getCurrentUser();
modelForm.fill(registry);
if (modelForm.hasErrors()) {
Logger.debug(modelForm.toString());
return badRequest(views.html.Registry.form.render(modelForm));
} else {
modelForm.get().toDataBase();
toLog("success", "Succefully added new Report");
flash("success", "Pomyślnie dodano.");
return redirect(routes.Index.index());
}
}
Let's say you have a Report model like:
public Date date;
public User user;
public String message;
You need to create and fill an object first (without saving to DB!) and then fill the form with it, like:
Report report = new Report(); // constructors params are welcome here
report.user = loggedUser;
report.date = new Date();
Form<Report> reportForm = Form.form(Report.class).fill(report);
// OR
Form<Report> reportForm = Form.form(Report.class);
reportForm = reportForm().fill(report);
// NOT
Form<Report> reportForm = Form.form(Report.class);
reportForm().fill(report); // Wrong!
return ok(reportCreatingView.render(reportForm));
Edit: You don't need to fill User data at first step, as actually you can add it after binding, you have too much lines in your submit() action, keep it simple :)
public static Result submit() {
User user = User.getCurrentUser();
if (user == null) return unauthorized("You must log in");
modelForm = modelForm.bindFromRequest();
if (modelForm.hasErrors()) {
return badRequest(views.html.Registry.form.render(modelForm));
}
// At this point you have a logged User obj which is not null,
// you have modelForm without errors (checked previously)
// so you need to only add the user to form and save it.
Registry registry = modelForm.get();
registry.creationUser = user;
registry.save();
flash("success", "Twój log został zapisany w bazie.");
return redirect(routes.Index.index());
}

Spring MVC: Show data in a dialog after making an AJAX call

I am new to Spring and web technology.
I have an table which contains a column with hyperlink. When I click on the hyperlink of a row, I need to display that rows data along with other details in a dialog. My controller method returns a ModelAndView which contains the data I need to show and the display page.
Problems:
How to show the dialog? and
How to pass the data to the dialog?
Table.jsp
<script type="text/javascript">
function showDialog(ref, date) {
$ajax({
type: "POST",
url: "/example/show.htm",
data: {
ref: ref,
date: date
}
success: function(data) {
},
error: function(data) {
}
});
}
</script>
Mapping
#RequestMapping(value = "show.htm", method=RequestMethod.POST)
public ModelAndView show(#RequestParam("ref") String ref, #RequestParam("date") String date,
HttpServletRequest request, HttpServletResponse response) {
ModelAndView modelAndView = new ModelAndView();
try {
SampleDTO SampleDTO = new SampleDTO();
sampleDTO.setDate(sdf.parse(date));
sampleDTO.setRef(ref);
SampleDTO billDto = // server call modelAndView.addObject("showBill", sampleDto);
modelAndView.setViewName("Dialog");
}
return modelAndView;
}
Your code is wrong, you are messing things, if you want to use jQuery and ajax calls then don't use ModelAndView in your Spring controller. Instead of that, use the following and return your bean or dto as a json using Jackson library from Java:
Include this jar in your lib project folder:
http://www.java2s.com/Code/JarDownload/jackson/jackson-all-1.9.9.jar.zip
Java code:
#RequestMapping(value = "businessBill.htm", method = RequestMethod.POST)
#ResponseBody
public String handleBusinessBillDetails(#RequestParam("reference") String billReference, #RequestParam("invoiceDate") String billDate,
HttpServletRequest request, HttpServletResponse response) {
String json = null;
try {
//1. Create 'jackson' object mapper
ObjectMapper objectMapper = new ObjectMapper();
BusinessBillDTO businessBillDTO = new BusinessBillDTO();
businessBillDTO.setBillDate(sdf.parse(billDate));
businessBillDTO.setBillReference(billReference);
BusinessBillDTO billDto = accountStatementBO.getBusinessBillDetails(businessBillDTO);
//2. Convert your 'bean' or 'dto' as 'json' string
json = objectMapper.writeValueAsString(billDto);
} catch (Exception ex) {
LOGGER.error(ex);
}
return json;
}
Then, in Table.jsp put the div used in Dialog.jsp as hidden, this will be your modal dialog in future (note that there are some changes in the span tags also):
<div id="BusinessBill" style="display:none;">
<h2>Bill Details</h2>
<em>Business Ltd</em>
<div class="row">
<span class="spanAsLabel">Account number</span>
<span id="dlg-account-number" class="spanAsLabel"></span>
</div>
<div class="row">
<span class="spanAsLabel">Bill date</span>
<span id="dlg-bill-date" class="spanAsLabel"></span>
</div>
</div>
Now fix your getBusinessBill(..) method like this:
You can also use $.ajax and maybe handle more states like onerror and others but this way is simpler (at least for me, you just need to evaluate if the returned data is null or not and let know the user - if null - that something happened at server side, maybe showing an alert with a generic message) - please read comments.
function getBusinessBill(billReference, billInvoiceDate) {
$.post("/AccountStatement/businessBill.htm", {
reference: billReference,
invoiceDate: billInvoiceDate
}, function (data) {
/* You can implement more validations for 'data', in my case I just used these 'if' conditionals but can vary. */
if(data != null) { //returned 'data' is not 'null'
/* parse 'data' as 'json' object
* will be good to console.log(data) and take a look. */
var obj = $.parseJSON(data);
if(obj != {}) { //check if 'data' is not an empty 'json' object once transformed
//set the 'data' in the dialog
$('#dlg-account-number').text(obj.accountNumber);
$('#dlg-bill-date').text(obj.billDate);
/* open modal dialog, you can simulate it this way (for this case)
* but the correct way is to use 'jquery-ui' dialog or any plugin you prefer.
* At this point you will see the hidden 'div' in a visible way with your 'data'.
*/
$('#BusinessBill').fadeIn();
} else {
//show 'generic' message
alert('No results found.');
}
} else {
//show 'generic' message
alert('An error occurred, try again.');
}
});
}
Finally, if everything is correct, you will see at the same page (Table.jsp) the modal dialog with your data, all made by an ajax call to avoid redirection pages like (Table.jsp to => Dialog.jsp).

Categories