In my scenario, i'm developing nested select on a JSP, binded to a bean:
Bean
public class WizardPanelp1Bean {
private Integer id;
private Stringofpanels stringofpanels;
private Paneltype paneltype;
private Integer number;
private String paneltypestring;
//and getters/setters... [Omitted]
Now i have the Paneltype object, another simple bean
Paneltype
private Integer id;
private double peakpower;
private double weight;
private String name;
private double dimension;
private double conversion;
private Set functions = new HashSet(0);
private Set sensors = new HashSet(0);
private Set panels = new HashSet(0);
//[Getters/setters omitted as usual]
So, i prepare the view, with a bean named wb
a simple arraylist of panels
public class PanelsBean {
private ArrayList<WizardPanelp1Bean> panels =new ArrayList<WizardPanelp1Bean>();
and finally i go to the jsp (please note this is in a )
<tbody>
<c:forEach items="${wb.panels}" varStatus="loop" var="item">
<tr>
<td>${item.id}</td>
<td>
<form:select path="panels[${loop.index}].paneltype" >
<c:forEach var="type" items="${types}">
<c:choose>
<c:when test="${item.paneltype.id==type.id}">
<form:option selected="selected" value="${type.id}" label="${type.name}" />
</c:when>
<c:otherwise>
<form:option value="${type.id}" label="${type.name}" />
</c:otherwise>
</c:choose>
</c:forEach>
</form:select>
</td>
<td><form:input style="width:180px" path="panels[${loop.index}].number" /></td>
<td>
<div>
<form:input style="visibility: hidden ; width:0px" path="panels[${loop.index}].id" disabled="disabled" />
<a href="javascript:remove(${item.id},${stringofpanels.id})" class="wb.panels.remove" >Rimuovi</a>
</div>
</td>
</tr>
</c:forEach>
</tbody>
every time i get a null reference to paneltype. I obviously used a #InitBinder on the controller:
Initbinder
#InitBinder
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
binder.registerCustomEditor(Paneltype.class, "paneltype", new PropertyEditorSupport() {
#Override
public void setAsText(String text) {
int i=0;
PaneltypeDAO pDAO=new PaneltypeDAO();
setValue(pDAO.findById(Integer.parseInt(text)));
}
});
}
but the code never reach this. It's like the jsp is sure that the value is null.
Suggestions? Thanks
I think your problem persists when you try to submit this form and not getting the binded values in the model.
Try to initialize your list using LazyList. Please replace your panels declaration in PanelsBean class as below.
private List<WizardPanelp1Bean> panels = LazyList.decorate(new ArrayList<WizardPanelp1Bean>(),FactoryUtils.instantiateFactory(WizardPanelp1Bean.class));
Hope this helps you. Cheers.
Related
I 'm a beginer with spring framework. I insert an image to postgresql database and i want to display it.
the model class is:
#Data
#Entity
#Table(name="Item")
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
private byte[] imageTo_display;
private Long price;
#ManyToOne
private Cart cart;
}
I think the problem is at image tag but i don't know how to solve it .
and the html is:
<th:block th:each="item:${listItems}">
<tr>
<td>[[${item.id}]]</td>
<td>[[${item.name}]]</td>
<td>[[${item.price}]]</td>
<td> <img class="s-ava-alone-img" width="150" height="150" th:src="#{${item.imageTo_display}}"></td>
</tr>
<td>
<a class="h4 mr-3" th:href="#{'/users/edit/'+${item.id}}">Edit</a>
<a class="h4 mr-3" th:href="#{'/users/delete/' +${item.id}}">Delete</a>
</td>
</th:block>
The way you should do this is:
Create a controller that just returns the byte[] array of the image:
#GetMapping(value = "/image/{id}")
public void view(HttpServletResponse response, #PathVariable(name="id") int id) throws Exception {
response.setHeader("content-type", "image/jpg");
Item item = ...; // Get the item based on id;
OutputStream o = response.getOutputStream();
o.write(item.imageTo_display);
o.close();
}
Link to your image on the page:
<th:block th:each="item: ${listItems}">
<tr>
<td th:text="${item.id}" />
<td th:text="${item.name}" />
<td th:text="${item.price}" />
<td><img class="s-ava-alone-img" width="150" height="150" th:src="#{/image/{id}(id=${item.id})}"></td>
</tr>
<td>
<a class="h4 mr-3" th:href="#{/users/edit/{id}(id=${item.id})}">Edit</a>
<a class="h4 mr-3" th:href="#{/users/delete/{id}(id=${item.id})}">Delete</a>
</td>
</th:block>
I am trying to create a simple Spring project where restaurants can add menu items to shared database and users can use a html form to search the dishes based on a range of criteria- especially dietary requirements
Form example:
Restaurant Name: Chez Hans
Gluten Free: (X)
Egg Free: (X)
Vegan: ()
Example SQL command
Select all FROM "dishes" Dish WHERE restaurant_name = "Chez Hans" AND egg_free = TRUE AND
gluten_Free = TRUE;
A list of dishes that fit their criteria would then be returned to the user.
Any field in the form can be left blank, and not checking a box for example, "vegan" does not mean that criteria should be set as 'false', but rather not included within the query.
Because of this it seemed the best way to handle the issue was using JpaSpecificationExecutor to create dynamic SQL queries (similar to the implementation in the answer to the problem below)
Filtering database rows with spring-data-jpa and spring-mvc
I have created a solution based on my research and prior knowledge. However, when I implement my solution, no dishes are returned- even though there are dishes in the database that fit the search criteria. No errors are being produced, but simply a blank table, so I am not sure where I am going wrong.
I have researched countless articles/videos regarding JpaSpecificationExecutor/dynamic queries but there are parts of the that theory I am still unsure about. This is what I gather about JpaSpecificationExecutor/dynamic queries (but I may be wrong)
The meta model is not need to create dynamic queries but to verify the correctness of database query statements
To create queries using meta-model classes a wrapper class is required (In my example- DishSearch)
The following lines are to cast metamodel SingularAttribute class back to the original class value.
Path dname = root.get(Dish_.dname);
Path vegan= root.get(Dish_.vegan);
I am quite new to Spring and still finding it pretty difficult. Any help or advice would be very much appreciated!
Please see below my DishSpecification class:
package com.bron.demoJPA.specification;
public class DishSpecification implements Specification<Dish> {
private final DishSearch criteria;
public DishSpecification(DishSearch ds) {
criteria =ds;
}
#Override
public Predicate toPredicate(Root<Dish> root, CriteriaQuery<?> query,
CriteriaBuilder cb) {
Path<String> dname = root.get(Dish_.dname);
Path<Boolean> vegan= root.get(Dish_.vegan);
Path<Boolean> eggFree= root.get(Dish_.eggFree);
Path<Boolean> glutenFree= root.get(Dish_.glutenFree);
final List<Predicate> predicates = new ArrayList<Predicate>();
if(criteria.getDname()!=null) {
predicates.add(cb.equal(dname, criteria.getDname()));
}
if(criteria.isVegan()!=false) {
predicates.add(cb.equal(vegan, criteria.isVegan()));
}
if(criteria.isEggFree()!=false) {
predicates.add(cb.equal(eggFree, criteria.isEggFree()));
}
if(criteria.isGlutenFree()!=false) {
predicates.add(cb.equal(glutenFree, criteria.isGlutenFree()));
}
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
}
}
Please see my DishSearch Class:
package com.bron.demoJPA.specification;
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Setter
public class DishSearch {
private Long dishId;
private String dname;
private String description;
private double price;
private boolean vegan;
private boolean glutenFree;
private boolean eggFree;
private AppUser app;
}
Please see my SearchController Class:
#Controller
public class SearchController {
#Autowired
DishRepository drep;
#GetMapping("/showSearchForm")
public String showNewDishForm(Model model) {
// Create model attribute to bind form data
DishSearch dishSearch = new DishSearch();
model.addAttribute("dishSearch", dishSearch);
return "search_Dish";
}
#PostMapping("/showDishList")
public String saveUser(#ModelAttribute("dishSearch")DishSearch dishSearch) {
Specification<Dish> spec = new DishSpecification(dishSearch);
drep.findAll(spec);
return "show_dish_List";
}
}
Please see my DishRepository Class:
#Repository
public interface DishRepository extends JpaRepository<Dish, Long>, JpaSpecificationExecutor<Dish>{
#Transactional
#Modifying
List<Dish> findAll(Specification<Dish> spec);
}
Please see my search_Dish.html Thymeleaf Template:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Dish Management System</title>
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<br>
<div class="col-sm-10 offset-sm-1 text-center">
<div class="container">
<h2> Manage Dishes </h2>
<hr>
</div>
<form action="#" th:action="#{/showDishList}" th:object="${dishSearch}" method="POST">
<div class="col-sm-10 offset-sm-1 text-center">
<input type="text" th:field="*{dname}"
placeholder="Dish Name" class="form-control mb-4 col-10">
</div>
<div class="form-check form-check-inline">
<label class=" form-check-label" for="inlineCheckbox1 ">Vegan?</label>
<input type="checkbox" th:field="*{vegan}" />
<label class="form-check-label" for="inlineCheckbox1">Gluten Free?</label>
<input type="checkbox" th:field="*{glutenFree}" />
<label class="form-check-label" for="inlineCheckbox1">Egg Free?</label>
<input type="checkbox" th:field="*{EggFree}" />
</div>
<br>
<br>
<br>
<br>
<button type="submit" class="btn btn-info col-4"> Search Database</button>
</form>
</div>
<hr>
</body>
</html>
Please see my show_dish_List.html Thymeleaf Template:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Search Results</title>
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
</head>
<body>
<br>
<div class="col-sm-10 offset-sm-1 text-center">
<h1>Dish List</h1>
</div>
<table border="1" class="table table-striped table-responsive-md">
<thead>
<tr>
<th>Dish Name</th>
<th>Dish description</th>
<th>Dish Price</th>
<th>Restaurant</th>
</tr>
</thead>
<tbody>
<tr th:each="dishSearch : ${listDishSearch}">
<td th:text="${dishSearch.dname}"></td>
<td th:text="${dishSearch.description}"></td>
<td th:text="${dishSearch.price}"></td>
</tr>
</tbody>
</table>
<div class="col-sm-10 offset-sm-1 text-center">
<a th:href="#{/showNewDishForm}"
class="btn btn-primary btn-sm mb-3"> Search Again</a>
</div>
----------------------------Update------------------------------
In addition to the answer provided below, in the Dish Specification Class I changed
if(criteria.getDname()!=null) {
predicates.add(cb.equal(dname, criteria.getDname()));
}
to
if(criteria.getDname()!="") {
predicates.add(cb.equal(dname, criteria.getDname()));
}
and the search is working fine now!
I believe the issue is that you are not adding the result in the Model which is being used to render the page show_dish_List.html, therefore nothing is being populated in the UI. Your UI is expecting the data to be in listDishSearch and there is nothing in that variable.
Update your code to:
#PostMapping("/showDishList")
public String saveUser(#ModelAttribute("dishSearch") DishSearch dishSearch, Model model) {
Specification<Dish> spec = new DishSpecification(dishSearch);
model.addAttribute("listDishSearch", drep.findAll(spec));
return "show_dish_List";
}
and everything should be working fine.
Remove the method findAll from your DishRepository repository. It is already being provided by the interface JpaSpecificationExecutor.
I'm getting this exception while trying to update a row in my database. I performed a lot of research in Google all I find is that I should add #modelAttribute which is already done.
I also found that I need to add bindind result after #ModelAttribute but this also didn't work so I removed it. I'm using JPA for persistence to manipulate my data, spring boot and thymeleaf for my views.
These are my Controllers one for updating and rendering views
#GetMapping("/edit/{id}")
public ModelAndView UpdateList(#PathVariable(name="id") String id) {
ModelAndView mav = new ModelAndView("updateList");
com.pfe.ClientRest.model.Files files = fileServ.get(id);
mav.addObject("Files", files);
return mav ;
}
#PostMapping("/Save")
public String saveRepport(#ModelAttribute("Files") com.pfe.ClientRest.model.Files dbfile) {
fileServ.save(dbfile);
return "/redirect:/ListFile";
}
this is my entity class I have getter setters and constructors
#Table( name="Files")
#Entity
public class Files {
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Id
private String id;
private String FileName;
private String Verif;
public String getId() {
return id;
}
this is my template.
<div class="container">
<h1> Modifier les informations du Rapports</h1>
<form action="#" th:action="#{/Save}" th:objects="${Files}"
method="post" >
<input type="text" th:field=*{id} readonly="readonly"/>
<input type="text" th:field="*{fileName}" placeholder="Nom du Fichier"
class="form-control mb-4
col-4">
<input type="text" th:field="*{verif}" placeholder="Accepted/Rejected"
class="form-control mb-4
col-4">
<button type="submit" class="btn btn-info col-2"> Mettre à jour</button>
</form>
</div>
The field names in the html page and entity class does not match. These are case sensitive. So the correct one should be
private String fileName;
private String verif;
Today I am stuck with the spring-form with the POST method which doesn't give posted item to the Controller which I wanted. Here is my code.
Controller.java
#Controller
#RequestMapping("/cart")
public class CartController extends CommonController
{
#RequestMapping(value = "/add", method = RequestMethod.POST)
public ModelAndView addCart(#ModelAttribute("productList") Item item, BindingResult result,Model model){
System.out.println(item.getId()); /// <-- doesn't gives me the ID
return new ModelAndView("cart");
}
}
ProductList.jsp
/// Loop through the products of search itemlist and generates the forms with the correct items
<c:forEach var="item" items="${productList.items}" varStatus="status">
${item.name}
<div class="addCart">
<c:url value="/cart/add.html" var="addURL" />
<form:form method="POST" action="${addURL}" modelAttribute="productList">
<form:hidden path="items[${status.index}].id"/>
<input type="submit" class="addCartBtn" value="Add to cart" />
</form:form>
</div>
BackingBean.java
public class SearchForm implements Serializable
{
private Collection<Item> items;
private String term;
// getters and setters
}
The ${productList} is the backingbean which loops through all items.
I don't really know what the problem is why it isn't giving me the correct data it passed through the POST.
Many thanks.
Covert your spring:hidden tag to normal html hidden tag:
<form:hidden path="items[${status.index}].id"/>
to
<input type="hidden" name="id" value="${item.id}"/>
I have create a Spring form like this:
index.jsp
Order
Order.jsp
<form:form action="createOrder" method="Post" modelAttribute="order">
<table>
<tr>
<th>
Order ID:
</th>
<td>
<form:input path="order.orderId"/>
</td>
</tr>
<tr>
<th>
Product Name:
</th>
<td>
<form:input path="order.productName"/>
</td>
</tr>
<tr>
<td>
<input type="submit" value="Submit"/>
</td>
</tr>
</table>
</form:form>
Order.java:
public class Order {
private String orderId;
private String productName;
/**
*
*/
public Order() {
}
public Order(String orderId, String productName) {
super();
this.orderId = orderId;
this.productName = productName;
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
}
OrderController.java:
#Controller
public class OrderController {
private static final Logger logger = Logger.getLogger(LoginController.class.getName());
/**
*
*/
public OrderController() {
super();
}
#RequestMapping(value = "/createOrder", method=RequestMethod.POST)
public String createOrder(#ModelAttribute("order")Order order, BindingResult result) {
logger.log(Level.INFO, "Order ID: " + order.getOrderId());
logger.log(Level.INFO, "Product Name: " + order.getProductName());
// Implementation validator
// Data Binding the form properties to Order field
if (result.hasErrors()) {
logger.log(Level.INFO, "Error in Binding Result");
}
return "/order";
}
}
I get the Neither BindingResult nor plain target object for bean name order available. Is it i need to create a bean name order using GET and pass to the web first before POST back to server.
Please help.
Thanks.
The problem is in your JSP page.
You have used the field names wrongly in the path attribute of the input tag.
it should be like this.
<form:input path="orderId"/>
Hope this helps you.
Cheers.
Based on reference, your path attribute inside the input tag should not include the model attribute name order; e.g.:
<form:input path="orderId" />