JFinal 如何优雅的处理复杂的条件查询

绝望的八皮 发布于 2012/08/04 13:50
阅读 10K+
收藏 39

比如我现在有一个50个字段的表。

我会对其中20个字段做条件做组合条件查询。

之前我用的框架是把所有的查询,分页,排序信息都通过一个pageInfo对象传给后台。

后台有一个方法调用参数是这个pageInfo,然后就能得到符合条件的分页数据。这样的处理后台代码会相当简洁优雅。

我想请问在jfinal中怎么能做到这样优雅的复杂条件查询?

加载中
10
JFinal
JFinal

    目前在网校网项目中是这样做的,代码很少,很简洁:

1:创建一个拦截器继承自 PrototypeInterceptor,名叫 Condition

2:这个拦截器中包含了所有条询时需要用到的条件,并且可以处理默认值

3:在 Condition 创建 buildSql 方法,可以针对所有属性的状态生成条询的 sql

4:在需要这个 Condition 的 action 之上应用此拦截器

    以下是目前项目中的部分代码,代码功能对应于这类链接:http://www.wangxiaowang.com/class/list/1-34-0-0

public class Condition extends PrototypeInterceptor {
  
  private static String[] order = {"compose_id desc, sort_index asc", "compose_id asc, sort_index asc", "final_price asc, sort_index desc", "study_time asc, sort_index desc"};
  private Integer pageNum;
  private Integer subject_id;
  private Integer klass_id;
  private Integer area;
  private Integer klass_type_id;
  private Integer school_id;
  private Integer price;
  private Integer is_ensure;
  private Integer sort_type;
  private String hot_keyword;
  private Integer pageSize;
  private Integer listTab;
  private Integer displayCondition;
  
  private KlassController c;
  
  /**
   * 对Condition的属性进行赋值初始化
   */
  private void init(ActionInvocation ai) {
    c = (KlassController)ai.getController();
    pageNum = c.getParaToInt(0 , 1); //1:默认PageNum为1
    subject_id = c.getParaToInt(1, 0); //0:默认所有学科
    klass_id = c.getParaToInt(2, 0); //0:默认没有此Id
    area = c.getParaToInt(3, 0);   //0:默认,没有地区 1:各省公务员 2:事业单位 3:政法干警 4:各直辖市公务员
    klass_type_id = c.getParaToInt(4, 0); //0:班型不限
    school_id = c.getParaToInt(5, 0); //0:所有学校
    price = c.getParaToInt(6, 0); //0:价格不限
    is_ensure = c.getParaToInt(7, Klass.IS_ENSURE_ALL);
    sort_type = c.getParaToInt(8, 0); //0:默认按套餐排序
    pageSize = c.getParaToInt(9, 10); //默认每页显示10条数据
    listTab = c.getParaToInt(10,  0); //默认是课程列表; 0:课程列表; 1:网校列表
    displayCondition = klass_type_id != 0 ? 1 : 0;
  }
  
  public void doIntercept(ActionInvocation ai) {
    init(ai);
    c.cond = this;
    ai.invoke();
  }

  /**
   * 生成KlassController.list()的查询条件
   */
  public void buildSql(StringBuilder sql, List<Object> paras) {
    sql.append("from klass where 1 = 1");
    if (klass_type_id != null && klass_type_id != 0) {
      sql.append(" and klass_type_id = ?");
      paras.add(klass_type_id);
    }
    if (school_id != null && school_id != 0) {
      sql.append(" and school_id = ?");
      paras.add(school_id);
    }
    if (price != null && price != 0) {
      if (price == 1)
        sql.append(" and price between 0 and 99");
      if (price == 2) 
        sql.append(" and price between 100 and 499");
      if (price == 3)
        sql.append(" and price between 500 and 999");
      if (price == 4)
        sql.append(" and price >= 1000");
    }
    if (is_ensure != null && is_ensure != Klass.IS_ENSURE_ALL) {
      sql.append(" and is_ensure = ?");
      paras.add(is_ensure);
    }
    sql.append(" order by ").append(order[sort_type]);
  }
  
  public int getPageNum() {
    return pageNum;
  }
  
  public int getPageSize() {
    return pageSize;
  }
}

     以下代码是在 KlassController.list() 方法中使用该 Contition

public class KlassController extends Controller {
  
  public Condition cond;
  
  @Before({Condition.class, KlassListSeoInter.class})
  public void list() {
    StringBuilder sql = new StringBuilder();
    List<Object> paras = new ArrayList<Object>();
    cond.buildSql(sql, paras);
    Page<Klass> klassPage = Klass.dao.paginate(cond.getPageNum(), cond.getPageSize(), "select * ", sql.toString(), paras.toArray());
    setAttr("klassPage", klassPage);
    render("list.html");
  }
// other method ......
}

    以上方法只需传入 StringBuilder 与 List 对象给 Condition 就可以生成 sql 和其条件了,有一个关键点:为了节省时空,普通拦截器全局共享的,所以当需要使用线程安全拦截器时,可以继承PrototypeInterceptor 达到目的。

    以上代码实现了类似京东商城按条件筛选的功能,请看过来: http://www.360buy.com/products/670-671-672.html

JFinal
JFinal
这个方案还可以更完善一下,即去掉 Controller 中的 private Condition cond 属性,而改用在 Condition中调用 controller.setAttr("cond", cond) 传递给action,这样将Controller 与 Condition解耦了,Condtion 可以完全重用于各种Controller 之中,仅与 action 有一定的耦合 :)
0
JFinal
JFinal
    刚刚谁顶了这个贴子? 如果这个贴子不值得顶,那么就别顶,别为难 OSC 工作人员,谢谢合作 :)
EugeneQiu
EugeneQiu
很有参考价值。
0
车开源
车开源

终于俺也遇到这种需求了~

请问这个办法是否还有升级版?谢谢

绝望的八皮
绝望的八皮
就根据需求自己做查询条件的简单封装吧.我有尝试过通用的conditionIntercepter,但是如果有多表关联也复杂了.再设计下去也就和hibernate差不多了..,
0
写下带不走的风
写下带不走的风
还是用map手动塞查询条件吧。。。
0
yak
yak
可以用map用来配置查询条件吗?
0
故宫导览小程序
故宫导览小程序

jfinal 3.0 没有了 

ActionInvocation
返回顶部
顶部