Spring / roo定制查找器

时间:2011-10-20 15:32:21

标签: java spring spring-mvc spring-roo

我想创建一个自定义查找程序(作为Web开发资深人员,但在Java,Spring和AND Roo中是一个完整的第一个计时器)。

下面的第一个方法来自我的“资产”视图控制器类。这是您第一次点击资产管理页面时发生的事情 - 它返回一个视图和一批当前活动的资产。它工作正常:

@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注入攻击,但它很酷(几乎)不必了解所提供的数据,它只是从它所在的字段汇集查询。给出。它确实需要知道它正在做哪些字段 - 哪些字段是“喜欢”而不是“等于”,如何处理定义范围的“min”和“max”字段等等。但这并不是那么糟糕。

3 个答案:

答案 0 :(得分:2)

好吧,走老式路...... 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
}

答案 1 :(得分:2)

我发表了评论,但我更愿意在答案中解释我的方法:

我认为最好创建一个自定义查找程序,如下面的Raloh所说(使用Roo生成的代码)使用POJO作为参数而不是WebRequest,以便不与MVC有依赖关系。

尝试创建一个POJO,AssetFilter,例如,包含您要在finder中使用的属性。

public static TypedQuery<Asset> findAssetsByFilter(AssetFilter filter) {
    If (filter.getManufacturer()!=null) where.append(" AND ...")
}

Controller将使用Request创建POJO过滤器,您可以在任何地方使用此finder,甚至可以为其创建集成测试。

答案 2 :(得分:0)

Spring roo可以为您生成查找器:

型:

finder list --class ~.domain.MyClass   
finder add --finderName findMyClassByWhatEver

finder list将列出具有一个属性的所有finder,您可以使用可选参数设置属性数