我想创建一个自定义查找器(既是Web开发专家,又是Java,Spring和AND Roo的完整初学者)。
下面的第一个方法来自我的“ Asset”视图控制器类。这是您第一次访问资产管理页面时发生的事情-它返回一个视图和一批当前活动的资产。它工作正常:
@RequestMapping("/assets")
public ModelAndView listAssets() {
ModelAndView mav = new ModelAndView();
mav.setViewName("admin/asset");
Collection<com.myapp.model.Asset> assets = com.myapp.model.Asset.findAllAssets() ;
mav.addObject("assets", assets);
return mav;
}
因此,现在我想对该URL发出“ POST”请求,以接受资产搜索表单的提交,该表单包含Asset对象的几个关键属性的字段。
(现在我正在用我的视图控制器编码该查找器,我知道最终我希望将其下推到模型类。为了方便起见,现在我只在这里工作。另外,我知道我不不必提供对象的完全限定名称,我刚刚将控制器命名为与其正在使用的模型相同的名称,因此在我进行排序之前,我一直在努力解决它。)
我从生成的一些Roo查找器中借了一些代码,最后得到了:
@RequestMapping(value = "/assets", method = RequestMethod.POST)
public ModelAndView searchAssets(
@RequestParam("category") String category,
@RequestParam("year") String year,
@RequestParam("manufacturer") String manufacturer,
@RequestParam("drive_type") String driveType,
@RequestParam("subcategory") String subcategory,
@RequestParam("serial") String serial,
@RequestParam("listing_type") String listingType,
@RequestParam("hours") String hours,
@RequestParam("model") String model,
@RequestParam("mileage") String mileage ) {
ModelAndView mav = new ModelAndView();
mav.setViewName("admin/asset");
EntityManager em = com.myapp.model.Asset.entityManager();
TypedQuery<Asset> q = em.createQuery("SELECT o FROM Asset AS o ", Asset.class);
Collection<Asset> assets = q.getResultList();
mav.addObject("assets", assets);
return mav;
}
所以问题是:
1)有没有一种方法可以获取我的参数集合,而不是将其烘焙到方法签名中?因为我有点讨厌。
2)有没有办法遍历我的参数并以此方式生成查询字符串的WHERE子句?我不想对这里给出的领域了解太多,而且我需要能够处理的是,我大部分都不会拥有所有这些领域。因此,如果可以的话,我宁愿只迭代地构建查询,而不是声明性地构建查询。
您将如何在此处构建select语句?
编辑(解决方案):
@ madth3在这里为我指明了正确的方向。这就是我最终的结果,我为此感到非常自豪:
public static TypedQuery<Asset> findAssetsByWebRequest( WebRequest request) {
ArrayList<String> wheres = new ArrayList<String>();
Iterator<String> i = request.getParameterNames();
while (i.hasNext()) {
String fieldname = i.next();
String value = request.getParameter(fieldname);
if (value.length() == 0) {
continue;
}
if (fieldname.equals("manufacturer") || fieldname.equals("model") ) {
value = value.replace('*', '%');
if (value.charAt(0) != '%') {
value = "%" + value;
}
if (value.charAt(value.length() - 1) != '%') {
value = value + "%";
}
wheres.add(" o." + fieldname + " LIKE '" + value + "'");
}
else if (fieldname.contains("min")) {
fieldname = fieldname.replace("min", "").toLowerCase();
wheres.add(" o." + fieldname + " >= '" + value + "' ");
}
else if (fieldname.contains("max")) {
fieldname = fieldname.replace("max", "").toLowerCase();
wheres.add(" o." + fieldname + " <= '" + value + "' ");
}
else {
wheres.add(" o." + fieldname + " = '" + value + "' ");
}
}
String query = "SELECT o FROM Asset AS o ";
if (wheres.size() > 0) {
query += " WHERE ";
for (String clause: wheres) {
query += clause + " AND ";
}
query += " 1 = 1 ";
}
EntityManager em = Asset.entityManager();
TypedQuery<Asset> q = em.createQuery(query, Asset.class);
return q;
}
显然,需要对它进行参数化以避免SQL注入攻击,但是很酷的是,它(几乎)不必了解有关给定数据的任何信息,它只会从给定的字段中组装一个查询。它确实需要知道它正在处理哪些字段-哪些字段是“喜欢”还是“等于”,如何处理定义范围的“最小”和“最大”字段,等等。但这还不错。
最佳答案
好吧,走老式的路...
Java中的Servlets标准定义了对象Request,其中存在带有参数的Map(哈希,字典),因此您可以通过以下方式访问它们:
public ModelAndView searchAssets(HttpRequest request) {
StringBuilder builder = new StringBuilder();
for (String param : request.getParameterNames()) {
value = request.getParameter(param);
builder.append(param);
builder.append("="); // or LIKE
builder.append("\'" + value "\'");
builder.append(" AND ");
}
// deleting the last " AND "
builder.delete(builder.length-5, builder.length);
// In the entity create a method that executes a query with the string
// If the parameter names are column names then you'd have to use a nativeQuery
// You'd have to look it up in JPA
List<Asset> list = Asset.search(builder.toString());
// put the list in the ModelAndView
}