I am working with a spring boot project and I am trying to create a route in the controller that works with a dynamic number of parameters. The route looks like this:
#RequestMapping(value = "/addItem", method = RequestMethod.POST)
public String addItem(ModelMap model, #RequestParam Map<String,String> allRequestParams) {
String stringId = allRequestParams.get("id");
System.out.println(stringId);
long id = Long.valueOf(stringId);
System.out.println(id);
...
}
I need to convert the id parameter to a Long and I have tried to do this with Long.valueOf(stringId) and Long.parseLong(stringId) but when I call the route with the parameter id as 1, I get this error:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NumberFormatException: For input string: "1
"] with root cause
java.lang.NumberFormatException: For input string: "1
I call the route from a form like this:
<form method="POST" action="addItem">
<div class="form-group">
<table id="details" class="table table-responsive">
<tr id="type">
<th class="text-left select-title">Type* :</th>
<td>
<select name="id" id="input" class="form-control form-control-sm inv-select" required>
<option value="" disabled selected>Selected...</option>
<%# include file = "common/dropdown.jsp" %>
</select>
</td>
</tr>
<tr id="component1">
<th class="text-left select-title">Type of Component * :</th>
<td>
<select id="select" name="component1" class="form-control form-control-sm inv-select" required>
<option value="" disabled selected>Selected...</option>
<%# include file = "common/dropdown.jsp" %>
</select>
</td>
<th class="text-left quant-title">Quantity * :</th>
<td class="quantity-field">
<input name="quantity1" type="number" step="any" placeholder="Quantity" class="quantity-input" required>
</td>
</tr>
<tr class="table-row">
<td>
<button onclick="addComponent()" id="add-component" class="btn btn-md btn-outline-success"> + Add Component</button><br>
</td>
<td>
<button onclick="removeComponent()" id="rem-component" class="btn btn-md btn-outline-danger"> - Remove Component</button><br>
</td>
</tr>
<tr>
<th>
<input type="submit" name="submit" id="submit">
</th>
</tr>
</table>
</div>
</form>
The print statements in the controller route are there for debugging and only the first print statement prints. How can I correctly convert the string to a long?
You said the string is "1\r\n".
However, Long.valueOf() only works strings that only consist of numbers.
In order to fix this, use trim():
Long.valueOf(stringId.trim());
I would recommend you to use Long#parseLong instead of Long#valueOf as it returns long instead of Long. That gets rid of useless object creation.
#RequestMapping(value = "/addItem", method = RequestMethod.POST)
public String addItem(ModelMap model, #RequestParam Map<String,String> allRequestParams) {
String stringId = allRequestParams.get("id");
System.out.println(stringId);
long id = Long.parseLong(stringId.trim());
System.out.println(id);
...
}
Related
I'm having an issue where I have a form that will save all updates to a formula. This loads fine and everything works except for when trying to delete an ingredient within a list that is in the updateFormula object.
When I pass my two #RequestParameters in to delete a specific ingredient, I recieve the error:
Required request parameter 'formulaId' for method parameter type String is not present
This has stumped me as the formulaId parameter is for the first #GetMapping method updateFormula, which retrieves the formula information that can be updated. I have tried adding the formulaId as a model object, and pass that into the deleteIngredientInFormula method, but that did not work either.
#GetMapping to get all formula details to display
#GetMapping("/update-formula")
public String updateFormula(#RequestParam("formulaId") String id, Model model) {
//unwraps the optional formula object if present, then adds to the model.
formulaService.getFormulaById(id).ifPresent(f -> model.addAttribute("updatedFormula",f));
return "Update-Formula-Form";
}
#GetMapping to select a specific ingredient in the list to delete
#GetMapping("delete-ingredient")
public String deleteIngredientInFormula(#RequestParam("ingredientId") String inId,
#RequestParam("formId") String formId) {
formulaService.deleteIngredientInFormula(formId, inId);
return "redirect:/update-formula";
}
Thymeleaf Page: Update-Formula-Form
<div class="container">
<h2>Formula Update Form</h2>
<form action="#" th:action="#{/save-updated-formula}" method="post" th:object="${updatedFormula}">
<input type="text" th:readonly="true" th:field="*{formulaId}">
<input type="text" th:field="*{formulaName}">
<input type="text" th:field="*{dosageForm}">
<input type="text" th:readonly="true" th:field="*{unitWeight}">
<input type="text" th:field="*{servingSize}">
<!--FORMULA INGREDIENTS (SELECT ACTION) -->
<div class="container table-responsive">
<table class="table table-striped">
<thead class="table-light">
<tr>
<td>Ingredient ID</td>
<td>Ingredient Name</td>
<td>Type</td>
<td>Potency</td>
<td>Manufacturer</td>
<td>Label Claim (mg)</td>
<td>Delete Ingredient</td>
</tr>
</thead>
<tbody>
<tr th:each="ingredient, holder : *{ingredients}">
<td><input th:readonly="true" th:field="*{ingredients[__${holder.index}__].ingredientId}"></td>
<td><input th:readonly="true" th:field="*{ingredients[__${holder.index}__].ingredientName}"></td>
<td><input th:readonly="true" th:field="*{ingredients[__${holder.index}__].type}"></td>
<td><input th:field="*{ingredients[__${holder.index}__].potency}"></td>
<td><input th:readonly="true" th:field="*{ingredients[__${holder.index}__].manufacturer}"></td>
<td><input th:field="*{ingredients[__${holder.index}__].labelClaim}"></td>
<td>
<a th:href="#{/delete-ingredient(ingredientId=${ingredient.getIngredientId()}, formId=${updatedFormula.getFormulaId()})}"
class="btn btn-info btn-sm">Delete</a>
</td>
</tr>
</tbody>
</table>
</div>
<button type="submit" class="btn btn-info col-2">Save Formula Details</button>
</form>
</div>
When you call the #GetMapping("delete-ingredient") endpoint you are then redirecting to update-formula which requires formulaId. That is why you are getting the error. You are basically redirecting to update-formula without any additional data. You need to add that as follows:
#GetMapping("delete-ingredient")
public String deleteIngredientInFormula(#RequestParam("ingredientId") String inId,
#RequestParam("formId") String formId) {
formulaService.deleteIngredientInFormula(formId, inId);
return "redirect:/update-formula?formulaId=" + formId;
}
Additionally, you might want to use the same parameter names for the same thing. You have #RequestParam("formulaId") String id and #RequestParam("formId") String formId which if I understood this correctly are one and the same thing formulaId.
Finally, you definitely shouldn't use a GET to delete data. That is why the DELETE HTTP method exists.
Need some advice how should I retrieve a list of exhibits.
In my html template below, I only put one record of exhibit. If i were to put additional rows/records of exhibit, how do i go about mapping them to the controller.
HTML Template
<h3>Exhibit Details</h3>
<div class="table-responsive">
<table id="exhibitTable"
class="table table-bordered table-hover table-striped">
<thead>
<tr>
<th>Exhibit Type</th>
<th>Description</th>
<th>Marking</th>
<th>Remarks</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="form-group col-md-3">
<div class="cols-sm-10">
<select class="form-control selectpicker cols-md-3"
th:value="${exhibit.exhibitType}" id="exhibitType"
name="exhibitType" roleId="exhibitType">
<option value="">Select Type</option>
<option>Desktop</option>
<option>Laptop</option>
<option>Mobile Device</option>
<option>Portable Storage</option>
<option>Server</option>
<option>Video System</option>
<option>Save As</option>
<option>Others</option>
</select>
</div>
</div>
</td>
<td>
<div class="form-group col-md-3">
<input type="text" name="exhibitDescription"
id="exhibitDescription"
th:value="${exhibit.exhibitDescription}" />
</div>
</td>
<td>
<div class="form-group col-md-3">
<input type="text" name="exhibitMarking" id="exhibitMarking"
th:value="${exhibit.exhibitMarking}" />
</div>
</td>
<td><div class="form-group col-md-3">
<input type="text" name="exhibitRemarks" id="exhibitRemarks"
th:value="${exhibit.exhibitRemarks}" />
</div></td>
</tr>
</tbody>
</table>
</div>
Controller
#RequestMapping(value = "/register", method = RequestMethod.POST)
public String registerIncidentPost(#ModelAttribute("incident") Incident incident,
#ModelAttribute("exhibit") Exhibit exhibit, Principal principal) throws Exception {
long year = Calendar.getInstance().get(Calendar.YEAR);
incident.setIncidentYear(year + "");
Long refNo = incidentService.findMaxRefNoCurrentYear(year + "");
if (refNo == null)
refNo = (long) 1;
else
refNo += 1;
incident.setIncidentRefNo(refNo);
incident.setIncidentStatus(Incident.INCIDENT_REGISTERED);
incident.setIncidentOpeningTimestamp(new Date());
User user = userService.findByUsername(principal.getName());
incident.setIncidentCreatedBy(user);
incidentService.createIncident(incident);
exhibitService.createExhibit(exhibit);
return "redirect:/incident";
}
I've attempted to add the following to my template
<tr data-th-each="exhibit:${exhibitList}">
and the following to my controller
#ModelAttribute("exhibitList") ArrayList<Exhibit> exhibitList
but did not work.
Thanks in advance.
I can only assume this is vb.net since you didn't specify. You need to pass in the complete dataset to the page. Each item in the dataset will be one pre-loaded instance of the model. Then you can do a for each loop on the page itself and generate the html dynamically. Hope this helps.
I am trying to pass the information from a thymeleaf list and trying to add it to database.
I am getting data from the tmdb and it will be changing so i display the information obtain to the endpoint "/LatestMovies" this information is not saved in the db and ether should it be. so i am trying to add a save button for the custumer to add the movie listed.(its simple it just haves movieid and moviename)
Showing the movies listed i have no problem and it works fine but where i get error is when i add a hidden form. The current code i have is this:
<div class="container">
<table class="table table-hover">
<tr>
<th>Id</th>
<th>Name</th>
</tr>
<tr th:each="LatestMovies : ${latestMovies}">
<td th:text="${LatestMovies.id}"></td>
<td th:text="${LatestMovies.movieName}"></td>
<td>
<form action="#" th:action="#{/LatestMovies}" th:object="${addMovies}" method="post">
<p><input type="hidden" th:field="*{id}" th:attr="value = ${LatestMovies.id}" /></p>
<p><input type="hidden" th:field="*{movieName}" th:attr="value = ${LatestMovies.movieName}" /></p>
<p><input type="submit" value="Submit" /></p>
</form>
</td>
</tr>
</table>
#Controller
public class LatestMoviesController {
#Autowired
private LatestMoviesDao listOfMovies;
#Autowired
private savedMoviesDao movieRepo;
#GetMapping("/LatestMovies")
public String prueba(Model model) {
TmdbMovies movies = new TmdbApi("22914f477aaa3e7f86c6f5434df8d1eb").getMovies();
ResultsPage<MovieDb> movie = movies.getPopularMovies("en", 1);
for(int i=0; i <= 19; i++){
int movieId = movie.getResults().get(i).getId();
String movieName = movie.getResults().get(i).toString();
listOfMovies.save(new LatestMovies(movieId, movieName));
}
model.addAttribute("latestMovies", listOfMovies.findAll());
return "index";
}
#PostMapping("/LatestMovies")
public String save(#ModelAttribute("addMovies") Model model, SavedMovies addMovies) {
movieRepo.save(addMovies);
return "index";
}
}
Thx in advance
First, let's change your form. You don't need to add a new object to it, since you are already iterating through a list of them. That way, you will also avoid having to add the value for each field manually using th:attr. What we are gonna do, is send the required params separately and then build our movie object with them.
<div class="container">
<table class="table table-hover">
<tr>
<th>Id</th>
<th>Name</th>
</tr>
<tr th:each="LatestMovies : ${latestMovies}">
<td th:text="${LatestMovies.id}"></td>
<td th:text="${LatestMovies.movieName}"></td>
<td>
<form th:action="#{/LatestMovies}" method="post">
<p><input type="hidden" th:value="${LatestMovies.id}" name="id"/></p>
<p><input type="hidden" th:value="${LatestMovies.movieName}" name="name"/></p>
<p><input type="submit" value="Submit"/></p>
</form>
</td>
</tr>
</table>
</div>
Now, on your controller, do the following modifications.
#PostMapping("/LatestMovies")
public String save(#RequestParam("id") Integer id, #RequesParam("name") String name) {
SavedMovies movie = new SavedMovies();
movie.setId(id);
movie.setName(name);
movieRepo.save(movie);
return "index";
}
These changes should do the trick.
i have a thymeleaf form that can validate data from the database through spring controller, the data validation works fine, but when i want to validate with different data after validation it give me an Error 400, there's no error in the stack trace, so i don't know how how to fix this, maybe because of my bad logic, because i'm newbie at this..
here's the form
<form th:name="memberRkiForm" id="memberRkiForm" th:action="#{/}" th:object="${formResult}"
method="POST">
<div>
<table id="form">
<tr>
<td colspan="7" height="40"><img class="formlogo"
th:src="#{/resources/img/docicon.png}">
<h3 class="formHeader"><b><u>REGISTER MANUAL</u></b></h3></td>
</tr>
<tr>
<td>
<label>Provider Name </label>
</td>
<td><label>:</label></td>
<td>
<input type="text" th:value="${providerId}" name="providerId" style="width:275px;"
readonly="readonly" hidden="hidden"> </input>
<input type="text" th:value="${providerName}" name="providerName" style="width:275px;"
readonly="readonly"> </input>
</td>
<td class="sep"></td>
</tr>
<tr>
<td>
<label>Member Card Number* </label>
</td>
<td><label>:</label></td>
<td>
<input type="text" name="cardNumber" th:field="*{cardNumber}"
onkeypress="return isNumberKey(event)"
style="width:190px; display: inline;"> </input>
<input id="checkCardNum" class="default-button" type="submit" style="display: inline;"
value="Validasi">
</td>
<td width="500">
<div class="error" style="display:inline;color:red;">
<p id="cardNumError" style="margin-left:15px;" th:text="${cardNumError}"></p>
</div>
</td>
<td class="sep"></td>
</tr>
<tr>
<td>
<label>Member Name </label>
</td>
<td><label>:</label></td>
<td>
<input type="text" th:value="${memberName}" name="memberName" style="width:275px;"
readonly="readonly"> </input>
</td>
<td class="sep"></td>
</tr>
<tr>
<td>
<label>Date Of Birth </label>
</td>
<td><label>:</label></td>
<td>
<input type="text" th:value="${birthday}" name="birthday" style="width:275px;"
readonly="readonly"> </input>
</td>
<td class="sep"></td>
</tr>
<tr>
<td><label>Client Name </label></td>
<td><label>:</label></td>
<td>
<input type="text" th:value="${clientName}" name="clientName" style="width:275px;"
readonly="readonly"> </input>
</td>
<td class="sep"></td>
</tr>
<tr>
<td>
<label>Admission Date </label>
</td>
<td><label>:</label></td>
<td>
<input id="datepicker" type="text"
style="margin-top:4px;width:230px;display:inline-block;"/>
<span class="calendarbox"><img th:src="#{/resources/img/calendar.png}" height="25"
width="35"></span>
</td>
<td class="sep"></td>
</tr>
<tr>
<td><label>Claim Service* </label></td>
<td><label>:</label></td>
<td>
<input type="text" th:value="${selectServiceIsEnabled}" name="selectServiceIsEnabled"
style="width:275px;" readonly="readonly" hidden="hidden"> </input>
<select id="selectservice" th:field="*{caseCategoryList}" class="selectcss"
style="width:275px;margin-left: 5px;" disabled="disabled">
<option th:each="case : ${caseCategoryList}" th:value="${case.caseCategoryId}"
th:text="${case.caseCategoryName + ' - ' + case.caseCategoryCode}"></option>
</select>
</td>
<td width="500">
<span class="error" style="display: inline;color:red;"><p id="select_error"></p></span>
</td>
<td class="sep"></td>
</tr>
<tr colspan="7" class="jumper"></tr>
<tr>
<td>
<input id="addMember" class="remodal-confirm" type="submit" name="action"
value="Register"/>
<input class="remodal-cancel" type="reset" value="Clear"/>
</td>
</tr>
</table>
</div>
</form>
when validate button is clicked, the form action goes to a spring controller that check the card number to the database (checkCardNum), then if the data validation return true, the form will be automatically filled by the data that related to the card number, after the form's filled with the data, i want to check validation with another card number (different from the first validated card number), but it give me an error 400.
here's my controller
#PreAuthorize("hasAuthority('"+ACLConstant.MENU_REGISTRATIONMEMBERRKI+"')")
#RequestMapping(value="/member-rki-form",method={RequestMethod.GET , RequestMethod.POST} )
public String memberrkiform(Model model, HttpServletRequest request, #ModelAttribute("formResult") MemberRkiForm formResult){
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
UserAuth userAuth = (UserAuth)auth.getPrincipal();
String[] cols = {"username", "deletedStatus"};
Object[] values = {userAuth.getUserName(), 0};
Users user = userService.findUserByColsAndValues(cols, values);
int userid = user.getUserId();
Users currentUser = userService.findUserByPK(userid);
Provider provider = currentUser.getProvider();
model.addAttribute("providerId", provider.getProviderId());
model.addAttribute("providerName", currentUser.getFirstName());
model.addAttribute("cardNumber", formResult.getcardNumber());
model.addAttribute("cardNumError", formResult.getErrorMsg());
model.addAttribute("memberName", formResult.getMemberName());
model.addAttribute("birthday", formResult.getBirthday());
model.addAttribute("clientName", formResult.getClientName());
model.addAttribute("caseCategoryList", formResult.getCaseCategoryList());
model.addAttribute("selectServiceIsEnabled", formResult.getSelectServiceIsEnabled());
return "memberrki/member-rki-form";
}
#RequestMapping(value="/checkCardNum",method={RequestMethod.GET , RequestMethod.POST})
public String checkCardNum(#ModelAttribute("formResult") MemberRkiForm formResult, Model model, HttpServletRequest request, RedirectAttributes redirectFormData){
String errorMsg = "";
String cardNumber = formResult.getcardNumber();
if(cardNumber==null || cardNumber==""){
errorMsg="Card Number Data Is Required";
}
else{
String[] cols = {"currentCardNumber", "deletedStatus" , "subscriptionStatus"};
Object[] values = {formResult.getcardNumber(), 0 , 1};
Member member = memberService.findMemberByColsAndValues(cols, values);
if(member==null){
errorMsg="Member Not Found";
}
else{
Member validatedMember = memberService.findMemberByPK(member.getMemberId());
Client validatedMemberClient = validatedMember.getClient();
formResult.setMemberName(validatedMember.getFirstName());
formResult.setBirthday(validatedMember.getBirthday().toString());
formResult.setClientName(validatedMemberClient.getClientName());
MemberProductSearchParams memberProductParams = new MemberProductSearchParams();
memberProductParams.setMember(validatedMember);
memberProductParams.setDeletedStatus(0);
memberProductParams.setSubscriptionStatus(1);
Page<MemberProduct> memberProductPage = memberService.findMemberProductListing(memberProductParams, null);
List<MemberProduct> memberProductLists = memberProductPage.getContent();
if(memberProductPage==null || memberProductLists==null){
/*System.out.println("NO PRODUCT FOUND");*/
errorMsg="NO PRODUCT AVAILABLE";
}
else{
List<Product> productList = new ArrayList<Product>();
List<CaseCategory> caseCategoryList = new ArrayList<CaseCategory>();
for(int i=0; i<memberProductLists.size(); i++){
String[] productCols = {"productId", "deletedStatus"};
Object[] productValues = {memberProductLists.get(i).getProduct().getProductId(), 0};
Product products = productService.findProductByColsAndValues(productCols, productValues);
productList.add(products);
String[] caseCategoryCols = {"caseCategoryId", "deletedStatus"};
Object[] caseCategoryValues = {productList.get(i).getCaseCategory().getCaseCategoryId(), 0};
CaseCategory caseCategories = caseCategoryService.findCaseCategoryByColsAndValues(caseCategoryCols, caseCategoryValues);
caseCategoryList.add(caseCategories);
}
formResult.setCaseCategoryList(caseCategoryList);
}
formResult.setSelectServiceIsEnabled("true");
}
}
formResult.setErrorMsg(errorMsg);
formResult.setcardNumber(cardNumber);
redirectFormData.addFlashAttribute("formResult", formResult);
formResult = new MemberRkiForm();
return "redirect:/memberrki/member-rki-form";
}
}
maybe someone here can help me to solve the problem,
Thx in advance.. (sorry for my bad english)
I have the following form in my Thymleaf page:
<div class="panel-body">
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Issue Date</th>
<th>Payment Schedule</th>
<th>Total</th>
<th>Status</th>
<th>Start Date</th>
<th>End Date</th>
<th>Send Invoice</th>
</tr>
</thead>
<tbody>
<tr class="table-row" th:each="p : ${POList}">
<td th:text="${p.issueDate}"></td>
<td th:text="${p.paymentSchedule}"></td>
<td th:text="${p.total}"></td>
<td th:text="${p.status}"></td>
<td th:text="${p.rentalPeriod.startDate}"></td>
<td th:text="${p.rentalPeriod.endDate}"></td>
<td>
<form style='float:left; padding:5px; height:0px' th:object="${po}" th:method="post" th:action="#{'/dashboard/makeAndSendInvoice(email=${po.Email})'}">
<button class="btn btn-default btn-xs" type="submit">Send Invoice</button>
</form>
</td>
</tr>
</tbody>
</table>
</div>
I have tried to send the value of po.Email to the method.
I thought the th:action="#{'/dashboard/makeAndSendInvoice(email=${po.Email})'}"
will make a link like dashboard/makeAndSendInvoice/{Email}
So i tried to get it in the method like this:
#RequestMapping(method=POST, path="makeAndSendInvoice")
public String makeAndSendInvoice(#PathVariable("email") String email){
System.out.println("Invoice is sent to..................."+email);
return "Invoice";
}
but it seems to me it does not work, since it does not recognize my method.
So how can recieve the po.Email in my method
Change th:action to:
th:action="#{/dashboard/makeAndSendInvoice/{email}(email=${po.Email})}"
and add the PathVariable in the RequestMapping value like:
#RequestMapping(method=POST, path="/dashboard/makeAndSendInvoice/{email:.+}")
public String makeAndSendInvoice(#PathVariable("email") String email) {
From Thymeleaf - Link URLs:
Variable templates are also allowed in URL paths, like
#{/order/{orderId}/details(orderId=${orderId})}
<!-- Will produce '/gtvg/order/details?orderId=3' (plus rewriting) -->
view
<!-- Will produce '/gtvg/order/3/details' (plus rewriting) -->
view
From Spring - URI Template Patterns:
In Spring MVC you can use the #PathVariable annotation on a method
argument to bind it to the value of a URI template variable:
#RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(#PathVariable String ownerId, Model model) {
Owner owner = ownerService.findOwner(ownerId);
model.addAttribute("owner", owner);
return "displayOwner";
}