I have the following JSP:
<jsp:useBean id="trackingBean" class="tracking.Tracking" scope="session">
<jsp:setProperty name="trackingBean" property="*" />
</jsp:useBean>
<form action="TrackingController" method="post">
<div id="upper_frequency">
Upper Freq: <input type="text" name="upperFreq"
>
</div>
<div id="lower_frequency">
Lower Freq: <input type="text" name="lowerFreq"
>
</div>
<div id="if_frequency">
IF Freq: <input type="text" name="ifFreq"
>
</div>
<div id="cap_high">
Tuning Cap highest value: <input type="text" name="capHigh"
>
</div>
<div id="cap_low">
Tuning Cap lowest value: <input type="text" name="capLow"
>
</div>
<input type="submit" value="Submit" />
</form>
This should pass on the trackingBean to the sevlet whose doGet, the same as doPost:
doGet..
{
Tracking trackingBean = (Tracking) request.getSession(),getAttribute("tackingBean");
....
}
trackingBrean is not null, but all the values are never set?
The bean is:
package tracking;
public class Tracking {
public Tracking() {
}
private double upperFreq;
private double lowerFreq;
private double ifFreq;
private double capHigh;
private double capLow;
public double getUpperFreq() {
return upperFreq;
}
public void setUpperFreq(double upperFreq) {
this.upperFreq = upperFreq;
}
public double getLowerFreq() {
return lowerFreq;
}
public void setLowerFreq(double lowerFreq) {
this.lowerFreq = lowerFreq;
}
public double getIfFreq() {
return ifFreq;
}
public void setIfFreq(double ifFreq) {
this.ifFreq = ifFreq;
}
public double getCapHigh() {
return capHigh;
}
public void setCapHigh(double capHigh) {
this.capHigh = capHigh;
}
public double getCapLow() {
return capLow;
}
public void setCapLow(double capLow) {
this.capLow = capLow;
}
}
You're requesting "tackingBean" don't you need "trackingBean" ?
Related
I am trying to build a simple select and Option list in thymeleaf, but i keep getting the error
Neither BindingResult nor plain target object for bean name 'BOLForm' available as request attribute
I am pretty sure there is something wrong with my bol.html. But not able to figure out the missing mappings.
Below is my Controller:
#Controller
public class BillOfLadingController {
#Autowired
private DepotList depotList;
#GetMapping("/BillOfLading")
public String getBOLForm(){
return "bol";
}
#PostMapping("/BillOfLading")
public String Login(#ModelAttribute(name="BOLForm") BOLForm bolForm,Model model) {
model.addAttribute("BOLForm", bolForm);
List<DepotDetailEntity> depotDropDown = depotList.getDepots().getDepotDetail();
if(depotDropDown.size() == 0) {
return "login";
}
model.addAttribute("depots", depotDropDown);
return "bol";
}
}
The Form Class
#Component
public class BOLForm {
private String BOL;
private String depotId;
public String getBOL() {
return BOL;
}
public void setBOL(String bOL) {
BOL = bOL;
}
public String getDepotId() {
return depotId;
}
public void setDepotId(String depotId) {
this.depotId = depotId;
}
}
the bol.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>BillOfLading Request Page</title>
</head>
<body>
<h1>BillOfLading Report</h1>
<form th:action="#{/BillOfLading}" th:object="${BOLForm}" method="post">
<label for="bol">BOL No.</label>
<input type="text" id="bol" name="bol">
<br/>
<table>
<tr>
<td>Select DC:</td>
<td>
<select th:field="*{depotId}">
<option value=""> -- </option>
<option th:each="depot : ${depots}"
th:value="${depot.depotId}"
th:utext="${depot.depotName}"/>
</select>
</td>
</tr>
<tr>
<td><input name="submit" type="submit" value="submit" /></td>
</tr>
</table>
</form>
</body>
</html>
When I replace my bol.html as below, it works:
<form th:action="#{/BillOfLading}" th:object="${BOLForm}" method="post">
<label for="bol">BOL No.</label>
<input type="text" id="bol" name="bol">
<br/>
<label for="depotId">DepotID </label>
<input type="text" id="depotId" name="depotId">
<br/>
In the controller, you need to add the BOLForm object as an attribute of the model:
#GetMapping("/BillOfLading")
public String getBOLForm(Model model){
model.addAttribute("BOLForm", new BOLForm());
return "bol";
}
I am trying to validate the input field generated dynamically. below code will give us more input:
code from HTML:
<th:block th:each="word,itera : ${credentialsForm.credentialRequirements}">
<div class="rtr_credential" style="display: inline-block;">
<span th:text="${word.attribute}" ></span>
<input type="hidden" th:name="|credentialRequirements[${itera.index}].attribute|" th:value="${word.attribute}">
</div>
<div class="rtr_credential" style="display: inline-block;">
<input type="text" name="userValue" th:field="*{credentialRequirements[__${itera.index}__].userValue}" class="userValue" maxlength="30"
th:classappend="${#fields.hasErrors('userValue')}? has-error : ''">
</div>
</th:block>
It gives error as userValue is not in credentialsForm and if I include
th:classappend="${#fields.hasErrors('{credentialRequirements[__${itera.index}__].userValue}')}? has-error : ''">
this will throw indexing error.
Java class structure:
public class CredentialRequirementForm {
private List<CredentialRequirements> credentialRequirements;
public List<CredentialRequirements> getCredentialRequirements() {
return credentialRequirements;
}
public void setCredentialRequirements(List<CredentialRequirements> credentialRequirements) {
this.credentialRequirements = credentialRequirements;
}
}
CredentialRequirements.java
public class CredentialRequirements {
private String attribute;
private String carrierDescription;
#NotBlank
#NotNull
private String userValue;
public CredentialRequirements() {
super();
// TODO Auto-generated constructor stub
}
public CredentialRequirements(String attribute, String carrierDescription, String userValue) {
super();
this.attribute = attribute;
this.carrierDescription = carrierDescription;
this.userValue = userValue;
}
public String getAttribute() {
return attribute;
}
public void setAttribute(String attribute) {
this.attribute = attribute;
}
public String getCarrierDescription() {
return carrierDescription;
}
public void setCarrierDescription(String carrierDescription) {
this.carrierDescription = carrierDescription;
}
public String getUserValue() {
return userValue;
}
public void setUserValue(String userValue) {
this.userValue = userValue;
}
#Override
public String toString() {
return "CredentialRequirements [attribute=" + attribute + ", carrierDescription=" + carrierDescription
+ "]";
}
}
How to validate the userValues, it is dynamically generated, some time only 1 attribute and some time 5 attributes. I am also trying the Jquery validate, but confuse how to implement.
Why don't you simply use a th:field attribute to bind HTML fields to your entity fields? Then you can add a div with the error message (if there will be a validation error):
<th:block th:each="word,itera : ${credentialsForm.credentialRequirements}">
<div class="rtr_credential" style="display: inline-block;">
<span th:text="${word.attribute}" ></span>
<input type="hidden" th:field="*{credentialRequirements[__${itera.index}__].attribute}">
</div>
<div th:if="${#fields.hasErrors('credentialRequirements[__${itera.index}__].userValue')}" th:errors="*{credentialRequirements[__${itera.index}__].userValue}">
Error message
</div>
<div class="rtr_credential" style="display: inline-block;">
<input type="text" name="userValue" th:field="*{credentialRequirements[__${itera.index}__].userValue}" class="userValue">
</div>
</th:block>
Thank you everyone for your answer and comments.
I need to deliver the code, so using Jquery and Javascript to validate:
Please find the code below:
submitHandler : function(form) {
let invalid = 0
$( ".userValue" ).removeClass( "has-error" )
$( ".userValue" ).each(function() {
if($( this ).val() == "" ) {
invalid++
$( this ).addClass( "has-error" );
}
});
if(invalid == 0){
//some logic
form.submit();
}
}
I have this input:
Masa: <input type="number" class="form-control form-text" name="masa"/>
<div class="text col-sm-12 error" th:if="${wzrost}" >
<p class="text text-center">
To pole jest wymagane
</p>
</div>
Wzrost: <input type="number" class="form-control form-text " name="wzrost"/>
<div class="text col-sm-12 error" th:if="${wzrost}" >
<p class="text text-center">
To pole jest wymagane
</p>
</div>
And this controller;
String x = String.valueOf(masa);
String y = String.valueOf(wzrost);
if(x==null ){
model.addAttribute("wzrost",true);
return"views/success";
}
if(y==null ){
model.addAttribute("wzrost",true);
return"views/success";
}
When I click form submit button I always get error nullpointerexception.
How do I validate input, so that when it is empty the message pops up
#PostMapping("/cal-bmi")
public String calculateBmiForm(Model model, Integer masa, Integer wzrost) {
String x = String.valueOf(masa);
String y = String.valueOf(wzrost);
if(x==null ){
model.addAttribute("wzrost",true);
return"views/success";
}
if(y==null ){
model.addAttribute("wzrost",true);
return"views/success";
}
}
ANd when i get a valu form masa and wzrost i check from null, i click submit alwas nullpointerexception
<form th:action="#{/cal-bmi}" method="post">
<ul class="gender-options">
<input id="man" type="radio" name="gender" value="male" required />
<label for="man">mężczyzna</label> ⁄
<input id="woman" type="radio" name="gender" value="female"/>
<label for="woman">kobieta</label>
</ul>
Masa: <input type="number" class="form-control form-text" required placeholder="(kg)" name="masa"/>
<!--<div class="text col-sm-12 error" th:if="${wzrost}">-->
<!--<p class="text text-center">-->
<!--To pole jest wymagane-->
<!--</p>-->
<!--</div>-->
Wzrost: <input type="number" class="form-control form-text " required placeholder="(cm)" name="wzrost"/>
<!--<div class="text col-sm-12 error" th:if="${wzrost}">-->
<!--<p class="text text-center">-->
<!--To pole jest wymagane-->
<!--</p>-->
<!--</div>-->
<input type="submit" class="col-lg-10 btn btn-primary" value="Oblicz"/>
</form>
Now i used required but is not good solution
It seems like you want to implement server side validation. For this the best approach is to use validators and its bindingResult. Steps to implement server side validation is
Have for model
public class PersonForm {
private String name;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
Use form model in html
<form action="#" th:action="#{/personForm}" th:object="${personForm}" method="post">
<table>
<tr>
<td><label th:text="#{label.name}+' :'"></label></td>
<td><input type="text" th:field="*{name}" /></td>
<td th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Generic Error</td>
</tr>
<tr>
<td><button type="submit">Submit</button></td>
</tr>
</table>
</form>
Have validator class
#Component
public class PersonFormValidator implements Validator {
#Override
public boolean supports(Class<?> clazz) {
return PersonForm.class.equals(clazz);
}
#Override
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmpty(errors, "name", "field.name.empty");
PersonForm p = (PersonForm) target;
if (p.getName().equalsIgnoreCase("XXX")) {
errors.rejectValue("name", "Name cannot be XXX");
}
}}
Bind validator to controller and let spring do the magic.
#Controller
public class WebController {
#Autowired
PersonFormValidator personFormValidator;
#InitBinder("personForm")
protected void initPersonFormBinder(WebDataBinder binder) {
binder.addValidators(personFormValidator);
}
#PostMapping("/personForm")
public String checkPersonInfo(#Validated PersonForm personForm, BindingResult bindingResult, final RedirectAttributes redirectAttributes) {
if (bindingResult.hasErrors()) {
return "personForm";
}
redirectAttributes.addFlashAttribute("personResult", apiClientService.getPersonResult(personForm));
return "redirect:/spouseForm";
}
}
How to upload files to the #ModelAttribute using Thymeleaf?
I'am doing something that:
upload.html
<form method="POST" action="#" th:action="#{/sending}" th:object="${collage}" enctype="multipart/form-data" >
<input type="file" th:field="*{picture}" />
<input type="file" th:field="*{picture}" />
<input type="submit" value="upload" />
</form>
My controller:
#Controller
public class MainController {
#GetMapping(value = { "/" })
public String index(){
return "upload";
}
#GetMapping("/collage")
public String paintPicture(Model model){
return "collage";
}
#PostMapping("/sending")
public String redirect(#ModelAttribute(value="collage") Collage collage, RedirectAttributes redirectAttr) {
Collections.shuffle(Arrays.asList(collage.getCollage()));
redirectAttr.addFlashAttribute("pictures",collage.getCollage());
return "redirect:/collage";
}
}
Collage.class:
public class Collage {
private MultipartFile[] pictures;
public Collage(){}
public MultipartFile[] getCollage() {
return pictures;
}
public void setCollage(MultipartFile[] pictures) {
this.pictures = pictures;
}
}
I'm getting: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'collage' available as request attribute in the console and a text on "/" page:
One picture is better than 1000 words:
Now code example to upload an array of multipartfiles inside of Entity:
<form action="#" th:action="#{/distribution/save}" class="form-horizontal"
role="form" method="post" th:object="${news}" enctype="multipart/form-data">
<input type="hidden" name="id" value="id" th:field="*{id}"> <div class="form-group has-label"> <label for="inputTitle" th:text="#{news.title}">Título</label>
<input type="text" class="form-control" id="inputTitle" th:placeholder="#{news.title}" th:field="*{title}"></div>
<input type="file" name = "multipartFilesDocument" value="multipartFilesDocument" th:field="*{multipartFilesDocument}" multiple="multiple"/>
<button type="submit" class="btn btn-default"><span th:text="#{common.save}"></span></button>
</div>
</form>
Controller Code:
#PostMapping("/save")
public String saveMultiparthFile(Model model,#ModelAttribute NewsDTO eventDTO){
eventDTO.getId();
return getrDetail(model);
}
Entity code:
public class NewsDTO {
private List<MultipartFile> multipartFilesDocument;
public List<MultipartFile> getMultipartFilesDocument() {
return multipartFilesDocument;
}
public void setMultipartFilesDocument(List<MultipartFile> multipartFilesDocument) {
this.multipartFilesDocument = multipartFilesDocument;
}
}
In this code is really important enctype="multipart/form-data" and name = "multipartFilesDocument" value="multipartFilesDocument" in form
you can apply this changes
1) change #ModelAttibute to #RequestParam
2) use MultipartFile[] as param and only use a single input file html
//name of input html should be collage
#PostMapping("/sending")
public String redirect(#RequestParam("collage") MultipartFile[] files, RedirectAttributes redirectAttr) {
Collections.shuffle(Arrays.asList(files));
redirectAttr.addFlashAttribute("pictures",files);
return "redirect:/collage";
}
and your html page
<form method="POST" th:action="#{/sending}" enctype="multipart/form-data" >
<input type="file" name="collage" multiple="multiple"/>
<input type="submit" value="upload" />
</form>
Following are my POJO, Action, and JSP page.
For single instance of Expense I am getting proper input.
I would like to use ModelDriven to fetch multiple instance of Expense from JSP page.
For that I have created multiple <div class="Expense">...</div>, but I dont know what changes should I made in Action class.
How to achieve this?
Pojo Class:
public class Expense implements java.io.Serializable {
private Long id;
private Client client;
private String param;
private BigDecimal value;
private Date dt;
private Date adddate;
//getter and setter
}
Action Class:
public class ExpenxeAction extends ActionSupport implements ModelDriven<Expense> {
Expense e = new Expense();
ExpenseDAO dao = new ExpenseDAO();
private LoginCheck lc = null;
private List<Expense> expenseList = new ArrayList<Expense>();
public String insertExpense() {
dao.insert(e);
return SUCCESS;
}
#Override
public Expense getModel() {
return e;
}
}
JSP page:
<div class="Expense">
<label>Expense Type</label>
<input type="text" name="param" id="param"/>
<label>Amount</label>
<input type="text" name="value" class="form-control" id="value"/>
<label>Date</label>
<input type="text" name="dt" class="form-control" id="dt"/>
</div>
You should create a getter for expenseList
public List<Expense> getExpenseList() {
return expenseList;
}
in the JSP use indexed property names
<s:iterator value="expenseList" status="stat">
<div class="Expense">
<label>Expense Type</label>
<s:textfield name="expenseList[%{#stat.index}].param" id="param"/>
<label>Amount</label>
<s:textfield name="expenseList[%{#stat.index}].value" class="form-control" id="value"/>
<label>Date</label>
<s:textfield name="expenseList[%{#stat.index}].dt" class="form-control" id="dt"/>
</div>
</s:iterator>
To fetch array list of Expense objects in action class you need to make the following changes to your code.
First you have to change ModelDriven<Expense> to ModelDriven<List<Expense>> and remove Expense e = new Expense();, if you wish. So, finally your action class should look like this.
public class ExpenxeAction extends ActionSupport implements ModelDriven<List<Expense>>, Preparable {
ExpenseDAO dao = new ExpenseDAO();
private LoginCheck lc = null;
private List<Expense> expenseList = new ArrayList<Expense>();
public String insertExpense() {
for (Expense e : expenseList) { //loop to iterate over each elements
dao.insert(e);
}
return SUCCESS;
}
public List<Expense> getExpenseList() {
return expenseList;
}
public void setExpenseList(List<Expense> expenseList) {
this.expenseList = expenseList;
}
#Override
public void prepare() throws Exception {
expenseList = new ArrayList<Expense>();
}
#Override
public List<Expense> getModel() {
return expenseList;
}
}
Now, you have to make changes to your jsp page.
<div class="Expense">
<label>Expense Type</label>
<input type="text" name="model[0].param" id="param"/>
<label>Amount</label>
<input type="text" name="model[0].value" class="form-control" id="value"/>
<label>Date</label>
<input type="text" name="model[0].dt" class="form-control" id="dt"/>
<label>Expense Type</label>
<input type="text" name="model[1].param" id="param"/>
<label>Amount</label>
<input type="text" name="model[1].value" class="form-control" id="value"/>
<label>Date</label>
<input type="text" name="model[1].dt" class="form-control" id="dt"/>
<label>Expense Type</label>
<input type="text" name="model[2].param" id="param"/>
<label>Amount</label>
<input type="text" name="model[2].value" class="form-control" id="value"/>
<label>Date</label>
<input type="text" name="model[2].dt" class="form-control" id="dt"/>
</div>
You will notice that in the jsp code we have mentioned
model[index].<pojo_member_variable_name> instead of specifying of
lstExp[index].<pojo_member_variable_name>
This is because now we want struts2 to set the values directly into these member variables. So we have mentioned model[index].<pojo__member_variable_name> so that struts2 should automatically set the value into the list. Here in the above code we are creating list of 3 Expense Object. If you need to insert more values then just increment the index and set the values and remaining will be done by struts2 for you.