I would like to implement following functionality: If user write "wrong" PID, alert should show up saying: Do you really save this PID with invalid format? If user say yes, the whole "playerform" (if other fields are correct) will be saved to the database (eventhough that PID would be in incorrect format.)
So how can I achieve this? I would add #Patern(with right regex) and message - this message will be displayed to the user because of the template down below, but how can I add this kind of dialog (yes - save the form with invalid PID, no - do not save it).
Spring boot and thymeleaf are used.
Method in the controller
#PostMapping("/create")
public String createPlayer(#Valid #ModelAttribute("playerForm") PlayerForm playerForm,
BindingResult bindingResult,
Model model,
RedirectAttributes redirectAttributes) {
// Check for errors
if (bindingResult.hasErrors()) {
formViewPreparer.prepare(model, new PlayerFormViewPreparer.ParamObj(true, null));
return "admin/players/create";
}
// Prepare object for service layer
CreatePlayerIn createPlayerIn = CreatePlayerInMapper.fromPlayerForm(playerForm);
// Call service layer
playerService.createPlayer(createPlayerIn);
redirectAttributes.addFlashAttribute("message", "player.toast.created");
return "redirect:/admin/players";
}
Player form class
#Getter
#Setter
public class PlayerForm {
#NotBlank
private String firstName;
#NotBlank
private String lastName;
#NotNull
private GenericState playerState;
#DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate birthDate;
private String PID;
private Long schoolId;
private Long teamId;
private String street;
private String city;
private String zipCode;
private String phoneNumber;
private String email;
private String motherPhoneNumber;
private String motherEmail;
private String fatherPhoneNumber;
private String fatherEmail;
#DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate validityOfMedicalExam;
#NumberFormat(style = NumberFormat.Style.NUMBER)
#Min(0)
private Integer annualFee;
private String annualFeeNote;
#NumberFormat(style = NumberFormat.Style.NUMBER)
#Min(0)
private Integer firstSemiAnnualFee;
private String firstSemiAnnualFeeNote;
#NumberFormat(style = NumberFormat.Style.NUMBER)
#Min(0)
private Integer secondSemiAnnualFee;
private String secondSemiAnnualFeeNote;
create.html template utilizing thymeleaf
<form th:object="${playerForm}"
th:action="#{/admin/players/create}"
novalidate
enctype="multipart/form-data"
method="post">
<div class="form-group col-md-6">
<input type="text" th:field="*{PID}" class="form-control" th:errorclass="is-invalid"
th:placeholder="#{player.input.PID}"/>
<label for="PID" th:text="#{player.input.PID}" class="form-control-placeholder"></label>
<div th:if="${#fields.hasErrors('PID')}" class="invalid-feedback"
th:errors="*{PID}"></div>
</div>
Related
I can't let this exception go:
Failed to convert property value of type java.lang.String to required type com.company.springdemo.entity.Product for property productId; nested exception is java.lang.IllegalStateException: Cannot convert value of type java.lang.String to required type com.company.springdemo.entity.Product for property productId: no matching editors or conversion strategy found
Order Model
#Entity
#Table(name = "orders") // naming the table only order, will throw exception
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "order_id")
private Integer orderId;
#OneToOne(cascade = {CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH})
#JoinColumn(name = "product_id")
private Product productId;
#ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH})
#JoinColumn(name = "client_id")
private Client client;
....
Product Model
#Entity
#Table(name = "product")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "product_id")
private Integer id;
#Column(name = "product_name")
private String productName;
#Column(name = "product_serial")
private String productSerial;
...
Client Model
#Entity
#Table(name = "clients")
public class Client {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#NotEmpty
#Column(name = "first_name")
private String firstName;
#NotEmpty
#Column(name = "last_name")
private String lastName;
#NotEmpty
#Email
#Column(name = "email")
private String email;
#NotEmpty
#Column(name = "location")
private String location;
#OneToMany(mappedBy = "client",cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Order> orders;
Controller, where I save the order with related client and product
#PostMapping("add")
public ModelAndView addOrder( #Validated #ModelAttribute("ords") Order order, BindingResult bindingResult ){
if (bindingResult.hasErrors()) {
System.out.println("Having errors: " + bindingResult.getAllErrors());
Iterable<Product> products = productService.listProducts();
Iterable<Client> clients = clientService.listClients();
System.out.println("Error "+ bindingResult.getAllErrors());
ModelAndView mv = new ModelAndView("orders/add-order");
mv.addObject("products",products);
mv.addObject("clients",clients);
return mv;
}
try {
orderService.saveOrder(order);
} catch (Exception e) {
e.printStackTrace();
}
ModelAndView mv = new ModelAndView("redirect:list");
return mv;
}
Finally, my JSP form View page
<form:form action="add" method="post" modelAttribute="ords">
<label for="productId" >Product Id</label>
<form:select path="productId" >
<c:forEach var="product" items="${products}">
<form:option value="${product.id}">${product.productName}</form:option>
</c:forEach>
</form:select>
<form:errors path="productId"/>
<br>
<label for="client" >Client Id</label>
<form:select path="client" >
<c:forEach var="client" items="${clients}">
<form:option value="${client.id}">${client.id} - ${client.lastName}</form:option>
</c:forEach>
</form:select>
<form:errors path="client"/>
<br>
<input type="submit" value="Place Order">
</form:form>
What am I doing wrong?
You most likely need to build a converter class such as this one :
#Component("facilityConverter")
public class FacilityConverter implements Converter<String, Facility>
{
#Autowired
FacilityService facilityService;
#Override
public Facility convert(String id)
{
return facilityService.findById(Integer.parseInt(id));
}
}
Then, you need to register it by implementing the addFormatters method inside of a configuration class implementing WebMvcConfigurer like so :
#Override
public void addFormatters (FormatterRegistry registry)
{
registry.addConverter((FacilityConverter)ctx.getBean("facilityConverter"));
}
Your entities will then correctly be mapped from a dropdown selection. Also, this might not be part of your issue but you can just build your dropdowns like this :
<form:select name="linkedInterface" path="linkedInterface" id="linkedInterface">
<form:options items="${interfaces}" itemLabel="name" itemValue="id"/>
</form:select>
The productId field is actually a Product object, not an ID (String/int). You need your JSP to use path="productId.id" rather than path="productId".
(Although I'd also suggest you also rename the field product rather than productId.)
<form:select path="product.id">
I think you'll hit the same issue on your <form:select path="client"> too.
So I am binding a form to an object to send to a spring controller,the "chosenAdvertisementsIds" being set with a hidden tag of ${advertisement.id} ends up with blank strings,the correct quantity of strings but empty strings.The tag for advertisement.description prints correctly on the page so the content is in the model correctly.
public class EditScheduleForm {
private String[] chosenAdvertisementsIds;
private String[] chosenAdvertisementsTime;//parralel arrays
private String dates;
//getters setters
}
My html,
<form th:action="#{|/web/editSchedule/${schedule.id}|}"
th:object="${EditScheduleForm}" method="post">
<h1>Advertisement Items</h1>
<div th:each="advertisement : ${chosenAdvertisements}">
<p th:text="${advertisement.description}"></p>
<input type="hidden" th:value="${advertisement.id}" th:field="*{chosenAdvertisementsIds}"/>
<p>Type below what times you want this advertisement to play at(type it like this 10:15/11:15/14:15 )</p>
<input name="text" th:field="*{chosenAdvertisementsTime}" type="text"/>
My controller method
#RequestMapping(value="/web/editSchedule/{scheduleId}",method = RequestMethod.POST)
public String editScheduleFormPost(Model model,
#ModelAttribute EditScheduleForm editScheduleForm,
#PathVariable Long scheduleId,
RedirectAttributes redirectAttributes) {
Advertisement
#Entity
public class Advertisement {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "usergroup_id")
private UserGroup userGroup;
private String description;
#Basic
#Temporal(TemporalType.DATE)
private java.util.Date dateAdded;
//getters setters
}
How I populate the model that the html page is on
#RequestMapping(value="/web/editschedule/{scheduleId}",method = RequestMethod.GET)
public String editOneSchedule(#PathVariable Long scheduleId,
Model model) {
// Get the schedult given by Id
Schedule schedule = scheduleService.findOne(scheduleId);
model.addAttribute("schedule",schedule);
ArrayList<Music> chosenMusics = new ArrayList<>();
for(int i=0;i<schedule.getMusicScheduleItems().size();i++){
chosenMusics.add(schedule.getMusicScheduleItems().get(i).getMusic());
}
model.addAttribute("chosenMusics",chosenMusics);
ArrayList<Advertisement> chosenAdvertisements = new ArrayList<>();
for(int i=0;i<schedule.getAdvertisementScheduleItems().size();i++){
chosenAdvertisements.add(schedule.getAdvertisementScheduleItems().get(i).getAdvertisement());
}
model.addAttribute("chosenAdvertisements",chosenAdvertisements);
model.addAttribute("EditScheduleForm", new EditScheduleForm());
return "editschedule";
}
i have problem with pass object(CarType) in spring input form.
My Car model:
#Entity
#Table(name="CAR")
public class Car implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "CAR_ID", unique=true, nullable=false)
private long id;
#NotEmpty
#Column(name = "REG_NO", nullable=false)
private String regNo;
#NotEmpty
#Column(name = "YEAR", nullable=false, length = 4)
private String year;
#Column(name = "AVAILABLE", nullable=false)
private boolean available = true;
#Column(name = "START_DATE")
private String startDate;
#Column(name = "RETURN_DATE")
private String returnDate;
#OneToOne
#JoinColumn(name="CAR_TYPE_ID")
private CarType carType;
//getters and setters
Car Type model:
#Entity
#Table(name = "CAR_TYPE")
public class CarType {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "CAR_TYPE_ID", unique=true, nullable=false)
private int id;
#NotEmpty
#Column(name = "MARK", nullable=false)
private String mark;
#NotEmpty
#Column(name = "MODEL", nullable=false)
private String model;
//getters and setters
Controllers:
#RequestMapping(value = { "/rent-car-{regNo}" }, method = RequestMethod.GET)
public String rentCar(#PathVariable String regNo, ModelMap model) {
Car car = carService.findCarByRegNo(regNo);
model.addAttribute("car", car);
return "rentcar";
}
#RequestMapping(value = { "/rent-car-{regNo}" }, method = RequestMethod.POST)
public String saveRentCar(#Valid Car car, BindingResult result, ModelMap model) {
carService.updateCar(car);
model.addAttribute("success", "Car " + car.getRegNo() + " rented successfully");
return "registrationsuccess";
}
JSP file
<form:form method="POST" modelAttribute="car" class="form-horizontal">
<form:input type="hidden" path="id" id="id"/>
<form:input type="hidden" path="year" id="year"/>
<form:input type="hidden" path="regNo" id="regNo"/>
<form:input type="hidden" path="available" id="available"/>
<form:input type="hidden" path="carType" id="carType"/>
<form:input type="text" path="startDate" id="startDate"/>
<form:input type="text" path="returnDate" id="returnDate"/>
I have problem with that code
<form:input type="hidden" path="carType" id="carType"/>
how can i pass object CarType to Car form? I always have that same error: column 'CAR_TYPE_ID' cannot be null. It looks like I'm transferring a null CarType to Car. I dont know why?
Someone can help me? In registercar.jsp i used converter (convert regNo to class CarType) and its works.
You need to know how the Car object gets bound in the Controller handler method from http request from the client. Spring MVC maps the the request parameters to contruct the Car object. Hence the CarType is an associated object. You need to provide a minimal clue to Spring MVC to construct that for you.
<form:form method="POST" action="/rent-car${regNo}" modelAttribute="car">
......
<form:input type="hidden" path="carType.id"/>
<form:input type="hidden" path="carType.model"/>
<form:input type="hidden" path="carType.mark"/>
<input type="submit" value="Submit"/>
</form:form>
you will find a complementary example here is this article Spring MVC - Binding Request Parameters and Path Variables to Java Backing Objects
I have a similar issue on my drop down list not showing any values. Like
the solution: dropdown lists with Thymeleaf and SpringBoot No data showing
in dropdown list. If I look in the IE debugger I can see my list for the
dropdown, but the dropdown won't display my list to pick from.
The HTML snippet is here:
<div class="col-lg-3 selectContainer">
<div class="input-group">
<span class="input-group-addon"><i
class="glyphicon glyphicon-list"></i></span>
<select th:field="*{savings_type}" name="savings_type_id"
id="savings_type_id" class="form-control selectpicker">
<option value="">Select Savings Type</option>
<option th:each="dropDownItem : ${leanTypesList}"
th:value="${dropDownItem.lt_id}"
th:text="${dropDownItem.lt_name}">
</option>
</select>
</div>
</div>
Code here:
My Model leanDeatil.java - data populating Savings_Type field
This is value is going too.
#Entity
#Table(name="lean_detail")
public class LeanDetail implements Serializable {
private static final long serialVersionUID = 1L;
#Id
//#Column (name="LEANDETAIL_ID")
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
#Column (name="SAVINGS_TYPE")
private int savings_type;
#Column (name="SAVING_AMOUNT")
private BigDecimal saving_amount;
#Column (name="TITLE")
private String title;
#Column (nullable=true, name="IMPROVEMENT_DESC")
private String improvement_desc;
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "SAVINGS_TYPE", referencedColumnName = "lt_id",
insertable = false, updatable = false)
private LeanTypes leanTypes;
public LeanDetail(){}
public LeanDetail(String title,int savings_type, BigDecimal saving_amount,
String improvement_desc {
super();
this.title = title;
this.savings_type = savings_type;
this.saving_amount = saving_amount;
this.improvement_desc = improvement_desc;
}
getters and setters....
My Model leanTypes.java data coming from
#Entity
#Table(name="lean_types")
public class LeanTypes {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column (name="LT_ID")
private int lt_id;
#Column (name="LT_NAME")
private String lt_name;
#Column (name="LT_DESC")
private String lt_desc;
#Column(nullable=false, name="LT_ACTV")
private boolean lt_actv;
#OneToMany(mappedBy="leanTypes", fetch=FetchType.EAGER)
#Fetch(value = FetchMode.SUBSELECT)
private List<LeanDetail> leanDetail = new ArrayList<LeanDetail>();
public LeanTypes(){}
public LeanTypes(int lt_id, String lt_name, String lt_desc, Boolean lt_actv) {
super();
this.lt_id = lt_id;
this.lt_name = lt_name;
this.lt_desc = lt_desc;
this.lt_actv = lt_actv;
}
getters and setters....
}
From my Controller LeanDetail.java
#GetMapping("/update-leanDetail")
public String updateLeanDetail(#RequestParam int id, HttpServletRequest
request){
request.setAttribute("leanTypesList", leanTypesService.findAll());
request.setAttribute("leanDetail", leanDetailService.findLeanDetail
(id));
request.setAttribute("mode", "MODE_UPDATE");
return "leanDetail";
}
public class Employee implements IEmployee, Serializable {
private static final long serialVersionUID = 3539505455231361934L;
#Column(name="emp_Id", nullable=false)
private Integer emp_Id;
#Id
#GeneratedValue
#Column(name="login_Id", nullable=false)
private String login_Id;
#Column(name="password", nullable=false)
private String password;
#Column(name="first_name", nullable=false)
private String first_name;
#Column(name="last_name", nullable=false)
private String last_name;
#Column(name="email", nullable=false)
private String email;
#Column(name="address", nullable=false)
private String address;
#Column(name="mobile_Number", nullable=false)
private Integer mobile_Number;
#Column(name="create_Date", nullable=false)
private Date create_Date;
#Column(name="modified_Date", nullable=false)
private Date modified_Date;
#Column(name="security_Question")
private String security_Question;
#Column(name="security_Question_Answer")
private String security_Question_Answer;
#Column(name="login_Attempts")
private String login_Attempts;
#OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
#JoinTable(name="employe_role",
joinColumns = {#JoinColumn(name="login_Id")},
inverseJoinColumns = {#JoinColumn(name="role_Id")})
private Collection<Role> role;//need to change name --> Dependent Object Role
---settters and getters
}
Role
#Id
#GeneratedValue
#Column(name="role_Id")
private Integer role_Id;
#Column(name="role_Code", nullable=false)
private String role_Code;
#Column(name="role_Name", nullable=false)
private String role_Name;
#Column(name="discription", nullable=false)
private String discription;
#Column(name="created_Date")
private Date created_Date;
#Column(name="modified_Date")
private Date modified_Date;
JSP form
<form:form name="register-employee" action="/registerEmployee" method="post" commandName="employee">
<c:forEach var="role" varStatus="statusEmpRole" items="${employee.role}">
<form:hidden path="role[${statusEmpRole.index}].role_Name" value="${role.role_Name}" />
<form:checkbox path="role[${statusEmpRole.index}].role_Name" value="${role.role_Name}" itemValue="role.role_Id" />
<c:out value="${role.role_Name}" /><br>
Controller
For displaying the form
#Override
#RequestMapping(value="/employeeregistrationform", method = RequestMethod.GET)
public ModelAndView employeeRegistrationForm(#ModelAttribute("employee") Employee employee, Model map) throws HibernateException, RoleNotFoundException {
IEmployee iEmployee = new Employee();
Collection<Role> collectionRoles= IRoleService.getLookUpRoles();
for (Role role : collectionRoles) {
LOGGER.info("roel {}",role.getRole_Name());
}
iEmployee.setFirst_name("helloooooo");
iEmployee.setRole(collectionRoles);
return new ModelAndView("registerEmploye", "employee", iEmployee);
}
Get the Submitted form Data
#Override
#RequestMapping(value="/registerEmployee",method=RequestMethod.POST)
public ModelAndView registerEmployee(#ModelAttribute("employee")Employee employee, BindingResult result) {
LOGGER.info("Registering Employe {}",employee.getFirst_name());
LOGGER.info("Selected Role Employe {}",employee.getRole());
ModelAndView model = new ModelAndView();
model.setViewName("registerEmploye");
return model;
}
employee.getRole() is getting null
my case is employee having multiple roles. let say admin and Projectmanager. while creating employee admin may select the roles(these are come from database) after submitting the employee registration from i'm getting role object is null.
please help me in this. Am i missing any thing here like property editor or init binder. if so please give me example how to use them.
Thanks
after Google i find the answer
I create Init Binder
#InitBinder
public void bindForm(WebDataBinder binder) {
binder.registerCustomEditor(Collection.class, new RoleEditor(Collection.class,true));
}
And i supply CustomCollectionEditor to that i.e RoleEditor
package com.evoke.tms.util;
import java.util.HashSet;
import java.util.Set;
import org.springframework.beans.propertyeditors.CustomCollectionEditor;
import com.evoke.tms.model.Role;
public class RoleEditor extends CustomCollectionEditor {
private Set<Role> roles;
public RoleEditor(Class collectionType, boolean nullAsEmptyCollection) {
super(collectionType, true);
}
public void setValue( Object object ){
if(object!=null&&object instanceof String)
System.out.println("Object is of type - " + object.getClass().getCanonicalName());
String[] roleIds = (String[])object;
roles=new HashSet<Role>();
if(roleIds!=null && roleIds.length>0)
for( int i=0; i<roleIds.length; i++ ){
try {
int id = Integer.parseInt(roleIds[i]);
Role role = new Role();
role.setRole_Id(id);
roles.add(role);
}catch( NumberFormatException ne ){}
}
}
public Object getValue(){
System.out.println("Roles are - " + roles);
return roles;
}
}
And i'm still confused how it is working
can any one help on this...