Cant inject checkbox value into spring bean - java

I am using SpringMVC and tring to read params from form. My bean looks like this :
public class ChannelBean {
private Integer id;
private Integer siteId;
private String name;
private Boolean active;
private Boolean premium;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boolean getActive() {
return active;
}
public void setActive(Boolean active) {
this.active = active;
}
public Boolean getPremium() {
return premium;
}
public void setPremium(Boolean premium) {
this.premium = premium;
}
public Integer getSiteId() {
return siteId;
}
public void setSiteId(Integer siteId) {
this.siteId = siteId;
}
}
And on the front end i have handlebars template :
<script id="editFormTemplate" type="text/x-handlebars-template">
<form id="channelForm" class="form-horizontal" action="/admin/channel/save.action" method="POST">
<input type="hidden" readonly="readonly" name="siteId" value="${selectedSiteId}">
<input type="hidden" readonly="readonly" name="id" value="{{id}}">
<div class="form-group">
<label class="col-sm-2 control-label channelName">Name<span class="required">*</span></label>
<div class="col-sm-10">
<input class="form-control" type="text" name="name" value="{{name}}" />
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Premium</label>
<div class="col-sm-10">
<input type="checkbox" name="premium" {{#if premium}}checked{{/if}} value="{{premium}}">
</div>
</div>
<cms:csrfToken />
<div class="modal-footer">
<button type="submit" class="btn btn-edit btn-primary has-spinner submitEditButton">Ok<span class="spinner"><i class="fa fa-refresh fa-spin"></i></span></button>
<button type="button" class="btn btn-warning" data-dismiss="modal">Cancel</button>
</div>
</form>
</script>
In the controller in Java when i receive Bean, 'name' value is set properly but premium that comes from checkbox is null ?

Since you are using Boolean you need to initialise the value to false when the page loads. So either initialize premium to false on the page load OR
change private Boolean premium in the ChannelBean.java to private boolean premium.

Related

'Required request parameter 'id' for method parameter type Integer is present but converted to null'

I'm creating todo-app with spring-boot.
After adding a task, once I enter a check on checkbox provided next to each todo and then click the done-button, the error occurs.'Required request parameter 'id' for method parameter type Integer is present but converted to null' has occurs.
below is codes.
Todo.java
#Entity
#Data
#Table(name = "todos")
public class Todo {
#Id
#Nullable
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Nullable
#Column(name = "user_id", nullable = false)
private Integer userId;
#NotNull
#NotBlank
#Column(name = "title")
private String title;
#NotNull
#NotBlank
#Column(name = "description")
private String description;
#NotNull
#NotBlank
#Column(name = "due_date")
private String dueDate;
#Column(name = "priority")
private Integer priority;
#NotNull
#Column(name = "is_completed")
private Boolean isCompleted = false;
public Todo() {
}
public Todo(Integer userId, String title, String description, String dueDate, Integer priority, Boolean isCompleted) {
this.userId = userId;
this.title = title;
this.description = description;
this.dueDate = dueDate;
this.priority = priority;
this.isCompleted = isCompleted;
}
}
TodoController.java
#Controller
public class TodoController {
#Autowired
TodoRepository todoRepository;
#Autowired
TodoService todoService;
#GetMapping("/todo/{id}")
public String home(Model model, User user, Todo todo, #PathVariable("id")Integer id) {
Integer userId = user.getId();
if(userId == null) {
return "redirect:/todo/{id}";
}
List<Todo> list = todoRepository.find(userId);
model.addAttribute("list", list);
model.addAttribute("todo", new Todo(user.getId(), todo.getTitle(), todo.getDescription(), todo.getDueDate(), todo.getPriority(), todo.getIsCompleted()));
return "home";
}
#PostMapping("/todo/{id}")
public String createTodo(#Validated Todo todo,BindingResult result, User user) {
if(result.hasErrors()){
return "redirect:/todo/{id}";
}
Todo userTodo = new Todo(user.getId(), todo.getTitle(), todo.getDescription(), todo.getDueDate(), todo.getPriority(), todo.getIsCompleted());
todoService.addTodo(userTodo);
return "redirect:/todo/{id}";
}
#PostMapping("/todo/update/{id}")
public String doneTodo(#RequestParam(name="id")Integer todoId) {
Todo updateTodo = todoService.findById(todoId);
updateTodo.setIsCompleted(true);
todoService.addTodo(updateTodo);
return "redirect:/todo/{id}";
}
#PostMapping("/todo/edit/{id}")
public String editTodo() {
System.out.println("edit");
return "redirect:/todo/{id}";
}
}
TodoService.java
#Service
public class TodoService {
#Autowired
TodoRepository todoRepository;
public List<Todo> searchAll() {
return todoRepository.findAll();
}
public void addTodo(Todo todo) {
todoRepository.save(todo);
}
public Todo findById(Integer id) {
Optional<Todo> updateTodo = todoRepository.findById(id);
return updateTodo.orElseGet(updateTodo::get);
}
}
home.html
<html xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/html">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link th:href="#{/css/home.css}" rel="stylesheet"/>
<title>Todo</title>
</head>
<body>
<h1>Todo</h1>
<div>
<form method="post" th:action="#{/todo/}+${id}" th:object="${todo}">
<p th:errors="*{title}" class="todo-error-message"></p>
<input th:field="*{title}" class="add-input" type="text" placeholder="title">
<input th:field="*{description}" class="add-input" type="text" placeholder="details">
<input th:field="*{dueDate}" class="add-input-third" type="date"><br/>
<div class="add-form">
<span>priority</span>
<input th:field="*{priority}" type="radio" name="priority" value="3" checked>3
<input th:field="*{priority}" type="radio" name="priority" value="2">2
<input th:field="*{priority}" type="radio" name="priority" value="1">1
</div>
<button type="submit" class="add-btn">add</button>
</form>
</div>
<h2>LIST</h2>
<form method="post" th:action="#{/todo/edit/}+${id}" th:each="list:${list}" th:object="${todo}">
<div th:if="${!todo.isCompleted}">
<input type="checkbox" th:id="${todo.id}" th:value="${todo.id}" th:field="*{isCompleted}" form="done-todo">
<input type="hidden" name="userId" th:value="${list.userId}">
<input type="text" name="title" th:value="${list.title}">
<input type="text" name="description" th:value="${list.description}">
<input type="date" name="dueDate" th:value="${list.dueDate}">
<input type="submit" value="update">
</div>
</form>
<form method="post" id="done-todo" th:action="#{/todo/update/}+${id}">
<input type="hidden" name="id" th:value="${todo.id}">
<input type="submit" value="done">
</form>
<div>
<button type="button" class="btn btn-primary p-3" data-toggle="collapse" data-target="#collapseExample" aria-expanded="false" aria-controls="collapseExample">
show done todos
</button>
<div class="collapse" id="collapseExample">
<form class="border p-3" th:action="#{/todo/delete/}+${id}" th:each="todo:${todo}">
<div th:if="${todo.isCompleted}">
<input type="text" name="title" th:value="${todo.title}">
<input type="submit" value="delete">
</div>
</form>
</div>
</div>
<form th:action="#{/logout}" method="post">
<button class="logout-button" type="submit" value="logout">logout</button>
</form>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
</body>
</html>
What I want to do
I aim to change the value of added todo from false to true after entering a check on checkbox provided next to each todo and then click the done-button.
I aim to show todos of which value is true.(true means 'done')
Does anyone know how to fix this?
I couldn't find the way to fix this and I’m so badly stuck at this task.

How to configure the modal to display the retrieved data from a table in springboot?

Customer.java
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String relative;
private String address;
private Long aadhar;
private Long contact;
private String townname;
public Long getAadhar() {
return aadhar;
}
public void setAadhar(Long aadhar) {
this.aadhar = aadhar;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRelative() {
return relative;
}
public void setRelative(String relative) {
this.relative = relative;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Long getContact() {
return contact;
}
public void setContact(Long contact) {
this.contact = contact;
}
public String getTownname() {
return townname;
}
public void setTownname(String townname) {
this.townname = townname;
}
CustomerController.java
#Controller
public class CustomerController {
#Autowired
private CustomerService customerService;
#Autowired
private TownService townService;
#GetMapping("/customer")
public String findAllCustomers(Model model) {
model.addAttribute("customers", customerService.findAllCustomers());
model.addAttribute("towns", townService.findAllTown());
return "customer";
}
#PostMapping("/customer/addnew")
public String addNew(Customer customer) {
customerService.saveCustomer(customer);
return "redirect:/customer";
}
#RequestMapping(value="/customer/findCustomerById/",method = RequestMethod.GET)
#ResponseBody
public Optional<Customer> findCustomerById(Long id) {
return customerService.getCustomerById(id);
}
}
CustomerService.java
#Service
public class CustomerService {
#Autowired private CustomerRepository customerRepository;
public List<Customer> findAllCustomers() {
return customerRepository.findAll();
}
public void saveCustomer(Customer customer) {
customerRepository.save(customer);
}
public Optional<Customer> getCustomerById(Long id) {
return customerRepository.findById(id);
}
}
customer.html
<a th:href="#{/customer/findCustomerById/(id=${customer.id})}"
type="button" class="btn btn-primary "
data-toggle="modal" data-target=".bd-edit-modal-lg">
<span class="material-icons" >edit</span></a>
<form class="row g-3">
<div class="col-md-8">
<label for="customername" class="form-label">Customer ID</label>
<input type="text" class="form-control" id="nameEdit" name="id"
onKeyup="this.value = this.value.toUpperCase()" readonly>
</div>
<div class="col-md-4">
<label for="aadhar" class="form-label">Aadhar No.</label>
<input type="number" min="0" max="999999999999" class="form-control" id="aadhar"
name="aadhar">
</div>
<div class="col-md-8">
<label for="customername" class="form-label">Customer Name</label>
<input type="text" class="form-control" id="nameEdit" name="name"
onKeyup="this.value = this.value.toUpperCase()" required>
</div>
<div class="col-md-6">
<label for="relative" class="form-label">S/O,D/O,C/O</label>
<input type="text"class="form-control" id="relativeEdit" name="relative"
onKeyup="this.value = this.value.toUpperCase()" required>
</div>
<div class="col-md-6">
<label for="contact" class="form-label">Contact No.</label>
<input type="number" minlength="10" max="9999999999" class="form-control"
id="contactEdit" name="contact">
</div>
<div class="col-12">
<label for="inputAddress5" class="form-label">Address</label>
<input type="text"class="form-control" id="addressEdit" name="address"
onKeyup="this.value = this.value.toUpperCase()" placeholder="1234 Main St" required>
</div>
<div class="col-md-4">
<label for="inputTown" class="form-label" id="selecttown">Town/Area</label>
<select class="form-control" id="selecttownEdit" name="townname" required>
<option selected>Choose...</option>
<option th:each="town:${towns}" th:value="${town.townname}"
th:text="${town.townname}">...
</option>
</select>
</div>
<div class="text-center" style="margin-bottom:10px">
<button type="submit" class="btn btn-primary mx-1 my-1">Submit</button>
<button type="reset" class="btn btn-secondary mx-1 my-1">Reset</button>
</div>
</form><!-- End Multi Columns Form -->
I checked my responsebody in postman,works fine.But i am stuck at how to populate this data to the form.anything i tried my html page becames blank
My Json Response Body:
{
"id": 1,
"name": "M",
"relative": "U",
"address": "130",
"aadhar": 8891,
"contact": 90,
"townname": "DAR"
}

Bean property 'categoryName' is not readable or has an invalid getter method

Could anyone take a look of this error and help me? I spent 2 hours to find problem but I didn't find solution.
Listing data works, but problem is when adding jsp with action="saveCategory.
org.springframework.beans.NotReadablePropertyException: Invalid property 'categoryName' of bean class [java.util.ArrayList]: Bean property 'categoryName' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
JSP:
<c:forEach var="tempInvoiceCategory" items="${invoiceCategory}">
<tr>
<td>${tempInvoiceCategory.categoryName}</td>
<td>
<button type="button" class="btn btn-info">Edit</button>
<button type="button" class="btn btn-danger">Delete</button>
</td>
</tr>
</c:forEach>
<form:form class="forms-sample" action="saveCategory" modelAttribute="invoiceCategory" method="POST">
<div class="form-group">
<label>Nazwa Kategorii</label>
<form:input path="categoryName" type="text" class="form-control"/>
</div>
<button type="submit" class="btn btn-primary mr-2">Submit</button>
</form:form>
Entity:
#Entity
#Table(name="T_INVOICE_CATEGORY")
public class InvoiceCategory {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="ID_CATEGORY")
private int id;
#Column(name="CATEGORY_NAME")
private String categoryName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
#Override
public String toString() {
return "InvoiceCategory [id=" + id + ", categoryName=" + categoryName + "]";
}
}
Controller:
#Controller
#RequestMapping("/invoice")
public class InvoiceController {
#Autowired
private InvoiceCategoryService invoiceCategoryService;
#GetMapping("/listCategory")
public String listCategory(Model theModel) {
List<InvoiceCategory> invoiceCategory = invoiceCategoryService.getInvoiceCategory();
theModel.addAttribute("invoiceCategory",invoiceCategory);
return "add-invoice-category";
}
#PostMapping("/saveCategory")
public String saveCustomer(#ModelAttribute("invoiceCategory") InvoiceCategory theInvoiceCategory) {
invoiceCategoryService.saveInvoiceCategory(theInvoiceCategory);
return "redirect:/customer/list";
}
}
I think problem is that model attribute invoiceCategory is List<InvoiceCategory> and in same JSP you try build list of items and form which try access to this item, but it is List<InvoiceCategory>:
<form:form class="forms-sample" action="saveCategory" modelAttribute="invoiceCategory" method="POST">
<div class="form-group">
<label>Nazwa Kategorii</label>
<form:input path="categoryName" type="text" class="form-control"/>
</div>
<button type="submit" class="btn btn-primary mr-2">Submit</button>
</form:form>
Try comment this part and run application again.

Spring Boot Thymeleaf Dropdown List option doesn't display values

It's my first topic at this beautiful site;)
I cant fix this, I am trying to present names of states and products in drop down lists. Intelij is helping me by underlines these fields.
https://ibb.co/wKgV940 (cant add image)
When I am adding th:object to divs or form it doesn't help.
There are racords on my db, and mathod retrieves values properly.
<div class="row justify-content-center">
<div class="form-group col-md-8" >
<label for="firstName" class="col-form-label">Choose State</label>
<select class="form-control" th:field="*{state.id}" id="state">
<options items="${listStates}>"></options>
<option th:each="state : ${states}"
th:value="${state.id}"
th:utext="${state.stateName}"></option>
</select>
</div>
<div class="form-group col-md-8" >
<label for="firstName" class="col-form-label">Choose products</label>
<select class="form-control" th:field="*{product.id}" id="product">
<option th:each="product : ${products}"
th:value="${product.id}"
th:utext="${product.productName}"></option>
</select>
</div>
<div class="form-group col-md-8">
<label for="firstName" class="col-form-label">Start price</label>
<input id="firstName" type="number" value="1" min="0" max="1000" step="1"/>
</div>
<div class="form-group col-md-8">
<label for="firstName" class="col-form-label">Preferred final prize</label>
<input type="text" class="form-control"
id="lastName" placeholder=""/>
</div>
<div class="form-group col-md-8">
<label for="firstName" class="col-form-label">Logistic costs</label>
<input type="text" class="form-control"
id="email" placeholder=""/>
</div>
<div class="col-md-6">
<input type="submit" class="btn btn-primary" value=" Calculate ">
</div>
</div>
</form>
public class CalculateController {
#Autowired
private StateRepository stateService;
#Autowired
private ProductRepository productService;
#RequestMapping(value = { "/calculateForm" }, method = RequestMethod.GET)
public String selectState(Model model) {
List<Product> product = new ArrayList<>();
List<State> state = new ArrayList<>();
model.addAttribute("product", product);
model.addAttribute("state", state);
List<Product> products = productService.findAll();
List<State> states = stateService.findAll();
model.addAttribute("states", states);
model.addAttribute("products", products);
return "calculateForm";
}
}
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String productName;
private String category;
private Double wholePrice;
public Product() {
}
public Product(String productName, String category, Double wholePrice) {
this.productName = productName;
this.category = category;
this.wholePrice = wholePrice;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public Double getWholePrice() {
return wholePrice;
}
public void setWholePrice(Double wholePrice) {
this.wholePrice = wholePrice;
}
}
I have replaced this:
List<Product> product = new ArrayList<>();
List<State> state = new ArrayList<>();
model.addAttribute("product", product);
model.addAttribute("state", state);
by this:
Product product = new Product();
State state = new State();
model.addAttribute("product", product);
model.addAttribute("state", state);```
now it works. Thank you.

Spring MVC forms - model with reference to object

I created a form, that has 2 fields (product name and price) and dropdown list of category objects (product's categories).
I have no idea how to make this work, when I have got a of Category objects to be set in Product object.
Product:
public class Product {
private String name;
private Category category;
private int price;
public Product() {
}
public Product(String name, Category category, int price) {
this.name = name;
this.category = category;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
Product controller:
#ModelAttribute("categoryList")
public List<Category> categoryList() {
return categoryService.getCategories();
}
#RequestMapping("/products/add")
public ModelAndView addProductForm() {
ModelAndView mv = new ModelAndView("addProduct");
mv.addObject("product", new Product());
return mv;
}
#RequestMapping(value = "/products/add/process", method = RequestMethod.POST)
public ModelAndView addProduct(#ModelAttribute("product") Product product) {
ModelAndView mv = new ModelAndView("products");
System.out.println("added " + product.getName() + " " + product.getPrice());
return mv;
}
The form:
<form class="form-horizontal" action="#"
th:action="#{/products/add/process}" th:object="${product}"
method="post">
<fieldset>
<!-- Form Name -->
<legend>Add product</legend>
<!-- Text input-->
<div class="form-group">
<label class="col-md-4 control-label" for="textinput">Product
name</label>
<div class="col-md-4">
<input id="textinput" name="textinput" placeholder="Product name"
class="form-control input-md" required="" type="text"
th:field="*{name}"></input>
</div>
</div>
<!-- Select Basic -->
<div class="form-group">
<label class="col-md-4 control-label" for="selectbasic">Category</label>
<div class="col-md-4">
<select th:field="*{category}">
<option th:each="cat : ${categoryList}" th:value="${cat.getId()}"
th:text="${cat.getName()}"></option>
</select>
</div>
</div>
<!-- Text input-->
<div class="form-group">
<label class="col-md-4 control-label" for="textinput">Price</label>
<div class="col-md-4">
<input id="textinput" name="textinput" placeholder=""
class="form-control input-md" required="" type="text"
th:field="*{price}"></input>
</div>
</div>
<!-- Button -->
<div class="form-group">
<label class="col-md-4 control-label" for="singlebutton"></label>
<div class="col-md-4">
<button id="singlebutton" name="singlebutton"
class="btn btn-success">Add product</button>
</div>
</div>
</fieldset>
</form>
Additional Info from comments
When I submit it (see addProduct method - it's a form handler) I get: java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [com.example.shop.Category] for property 'category': no matching editors or conversion strategy found]. I simply can't convert String coming from dropdown to an object
Problem is that Spring doesn't have a built-in conversion ability from String to Category. It knows it needs a Category to use the setCategory(Category category) method of Product, but has no way of converting the String it gets from your posted drop down into one. Thus, you need to be a dear and help Spring some by telling it how to do the conversion and define a converter, see Spring docs for more info.
Easiest option is to use Converter SPI:
package com.example.shop.converter;
final class StringToCategoryConverter implements Converter<String, Category> {
public Category convert(String source) {
Category category;
// Put your conversion logic here
return category;
}
}
In your case, I'd guess you'll want to use: CategoryService.getCategory(int id) or a similar method.
Then you need to configure Spring to actually use your converter, here's an XML example of how to do that:
<mvc:annotation-driven conversion-service="conversionService" />
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="com.example.shop.converter.StringToCategoryConverter" />
</list>
</property>
</bean>

Categories

Resources