【发布时间】:2011-10-20 15:32:20
【问题描述】:
我想创建一个自定义查找器(我是一名 Web 开发老手,但完全是 Java、Spring 和 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”请求接受资产搜索表单的提交,其中包含资产对象的几个关键属性的字段。
(现在我正在我的视图控制器中编写那个查找器,我知道最终我想把它推到模型类中。现在我只是为了方便起见在这里工作。另外,我知道我不必给出对象的完全限定名称,我刚刚将我的控制器命名为与它正在与之交谈的模型相同的名称,所以在我解决这个问题之前,我正在解决它。)
我从我生成的一些 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 注入攻击,但它(几乎)不需要知道任何有关提供给它的数据的信息,它只会从它所在的字段中组装一个查询,这很酷给定的。它确实需要知道它在处理哪些字段——哪些字段是“like”与“equals”,如何处理定义范围的“min”和“max”字段等。但这还不错。
【问题讨论】:
-
我认为最好使用 POJO 作为参数而不是 WebRequest,如下所述(使用 Roo 生成的代码)创建自定义查找器,以免与 MVC 有依赖关系。跨度>
标签: java spring spring-mvc spring-roo