我正在尝试创建一个简单的Spring项目,餐厅可以在共享数据库中添加菜单项,用户可以使用html表单根据一系列标准搜索菜肴,尤其是饮食要求
表格示例:
Restaurant Name: Chez Hans
Gluten Free: (X)
Egg Free: (X)
Vegan: ()
示例SQL命令
Select all FROM "dishes" Dish WHERE restaurant_name = "Chez Hans" AND egg_free = TRUE AND
gluten_Free = TRUE;
然后,符合他们标准的菜肴列表将返回给用户。
表单中的任何字段都可以留空,不勾选框(例如,“素食主义者”并不意味着条件应设置为“假”,而是不包括在查询中)。因此,处理该问题的最佳方法似乎是使用JpaSpecificationExecutor创建动态SQL查询(类似于下面问题答案中的实现)
使用spring数据jpa和spring mvc筛选数据库行
基于我的研究和先前的知识,我创建了一个解决方案。然而,当我实现我的解决方案时,不会返回任何菜肴——即使数据库中有符合搜索条件的菜肴。没有产生任何错误,只是一张空白表,所以我不确定哪里出了问题。
我已经研究了无数关于JpaSpeficationExecators/动态查询的文章/视频,但是这个理论的某些部分我仍然不确定。这就是我收集的关于JpaSpeficationExecators/动态查询的信息(但是我可能错了)
>
元模型不需要创建动态查询而是验证数据库查询语句的正确性
要使用元模型类创建查询,需要包装类(在我的例子中-DishSearch)
下面的几行是将元模型Singular属性类强制转换回原始类值。
路径dname=root.get(Dish_. dname); Path vegan=root.get(Dish_. vegan);
我对Spring还很陌生,仍然觉得它很难。任何帮助或建议都将不胜感激!
请看下面我的课程:
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()]));
}
}
请看我的搜索课:
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;
}
请查看我的SearchController类:
@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";
}
}
请看我的课程:
@Repository
public interface DishRepository extends JpaRepository<Dish, Long>, JpaSpecificationExecutor<Dish>{
@Transactional
@Modifying
List<Dish> findAll(Specification<Dish> spec);
}
请看我的搜索盘。html模板:
<!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>
请看我的节目单。html模板:
<!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>
----------------------------更新------------------------------
除了下面提供的答案外,在碟子规格类别I中更改了
if(criteria.getDname()!=null) {
predicates.add(cb.equal(dname, criteria.getDname()));
}
到
if(criteria.getDname()!="") {
predicates.add(cb.equal(dname, criteria.getDname()));
}
搜索工作现在很顺利!
我认为问题是您没有在用于呈现页面的show_dish_L
中添加结果,因此UI中没有填充任何内容。您的用户界面期望数据在listDishSearch
中,并且该变量中没有任何内容。
更新您的代码到:
@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";
}
一切都应该很好。
从dish存储库
中删除方法findAll
。它已经由接口JpaSpecificationExecutor
提供。
问题内容: 我正在寻找一种使用Spring Data JPA动态构建查询的解决方案。我有一个GameController,它有一个RESTful服务终结点/ games,它带有4个可选参数:体裁,平台,年份,标题。可能不传递任何API,而是传递所有4种,以及之间的每种组合。如果未传递任何参数,则默认为null。我需要在存储库中使用一种方法来构建适当的查询,并且理想情况下还允许Spring Data
我的webapp中有一个过滤器,允许按车辆类型、品牌、燃油、州和城市进行搜索,但所有这些过滤器都是可选的。 如何使用存储库实现这一点。 控制器类 服务类 我还没有实现任何东西,因为我不知道如何实现这个过滤器。 车辆等级 车型和品牌是另一张桌子上的...我是葡萄牙人我把密码翻译成了英文... 当它发生时,我需要做什么?
问题内容: 我正在与后端的Mongodb一起开发nodejs / express应用程序。在我的一个API调用中,根据是否存在特定的querystring参数,我想使用$ gt或$ lt向Mongodb发出查询。 在某些情况下,我们想要的所有内容都比使用$ lt少,但在其他情况下,我们希望所有的内容都比使用$ lt大。我们如何做到这一点而不重复查询? 这是一个示例查询: 有没有一种方法可以动态创建
我们希望按属性名对查询结果进行排序。此属性名称可能不同。根据这一需求,哪一个是用spring SDN来完成它的最佳解决方案? 我找到的唯一解决方案是使用OGM并动态创建查询。 有什么建议吗?也许是Spring SDN的增强?
Spring官方JPA规范文档 我对非常陌生,所以任何指导都很有价值。