我想创建一个自定义查找器(既是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
}

10-06 10:45