1

Tapestry5とHibernateを使用しています。URLから生成された動的制限を使用する基準クエリを作成しようとしています。私のURLコンテキストは、キーと値のペアのように設計されています。

www.mywebsite.com/make/ford/model/focus/year/2009

次のようにパラメータをデコードします

private Map<String, String> queryParameters;
private List<Vehicle> vehicles;

    void onActivate(EventContext context) {
            //Count is 6 - make/ford/model/focus/year/2009
            int count = context.getCount();

            if (count > 0) {
                int i;
                for (i = 0; (i + 1) < count; i += 2) {
                    String name = context.get(String.class, i);
                    String value = context.get(String.class, i + 1);

                    example "make"
                    System.out.println("name " + name);

                    example "ford"
                    System.out.println("value " + value);

                    this.queryParameters.put(name, value);
                }
            }  

            this.vehicles = this.session.createCriteria(Vehicle.class)
...add dynamic restrictions. 
        }

誰かが私のクエリに制限のリストを動的に追加する方法を理解するのを手伝ってくれることを望んでいました。これが行われたと確信しているので、誰かが投稿を知っているなら、それも役に立ちます。ありがとう

4

4 に答える 4

2

他の回答が言ったとおりですが、ここではさらに詳しく説明します。あなたの質問の核心は本当に「制限を追加する方法を教えてください」だと思います。それはとにかく私の解釈です。

各制限を独自のフィールドにデコードする必要があります。

各フィールドのJavaエンティティプロパティ名を知っている必要があります。

次に、これら2つのマップを作成します。キーは既知の静的Javaエンティティプロパティ名であり、値はURLでデコードされたデータです(おそらく型変換を使用)。

private Map<String, Object> queryParameters;
private List<Vehicle> vehicles;

void onActivate(EventContext context) {
        //Count is 6 - make/ford/model/focus/year/2009
        int count = context.getCount();

        queryParameters = new HashMap<String,Object>();
        if (count > 0) {
            int i;
            for (i = 0; (i + 1) < count; i += 2) {
                String name = context.get(String.class, i);
                String value = context.get(String.class, i + 1);

                Object sqlValue = value;
                if("foobar".equals(name)) {
                    // sometime you don't want a String type for SQL compasition
                    //  so convert it
                    sqlValue = UtilityClass.doTypeConversionForFoobar(value);
                } else if("search".equals(name) ||
                          "model".equals(name) ||
                          "year".equals(name)) {
                    // no-op this is valid 'name'
                } else if("make".equals(name)) {
                    // this is a suggestion depends on your project conf
                    name = "vehicleMake.name";
                } else {
                    continue;  // ignore values we did not expect
                }
                // FIXME: You should validate all 'name' values 
                // to be valid and/or convert to Java property names here

                System.out.println("name " + name);
                System.out.println("value " + value);

                this.queryParameters.put(name, sqlValue);
            }
        }  

        Criteria crit = this.session.createCriteria(Vehicle.class)
        for(Map.Entry<String,Object> e : this.queryParameters.entrySet()) {
            String n = e.getKey();
            Object v = e.getValue();
            // Sometimes you don't want a direct compare 'Restructions.eq()'
            if("search".equals(n))
                crit.add(Restrictions.like(n, "%" + v + "%"));
            else  // Most of the time you do
                crit.add(Restrictions.eq(n, v));
        }

        this.vehicles = crit.list();  // run query
    }

https://docs.jboss.org/hibernate/orm/3.5/reference/en/html/querycriteria.htmlも参照してください

上記の場合、「名前」と「n」の部分は既知の適切なリストに対して100%検証される必要があるため、SQLインジェクションのリスクはありません。「value」と「v」は、SQL位置プレースホルダー「?」を使用するのと同じように正しくエスケープされます。

E&OE

于 2012-09-24T02:14:32.910 に答える
1

パラメータMapをループして、各ペアに制限を追加するとします。

注意しないと、これによりSQLインジェクション攻撃が発生する可能性があることに注意してください。これを防ぐ最も簡単な方法は、基準に追加する前に、既知の車両プロパティに対してキーをチェックすることです。

于 2012-09-24T01:49:03.710 に答える
1

それらがクエリ パラメーターである場合は、パス パラメーターではなくクエリ パラメーターとして扱う必要があります。URL は次のようになります。

www.mywebsite.com/vehicles?make=ford&model=focus&year=2009

コードは次のようになります。

public class Vehicles {

@ActivationRequestParameter
private String make;

@ActivationRequestParameter
private String model;

@ActivationRequestParameter
private String year;

@Inject
private Session session;

@OnEvent(EventConstants.ACTIVATE)
void activate() {
    Criteria criteria = session.createCriteria(Vehicle.class);

    if (make != null) criteria.add(Restrictions.eq("make", make));
    if (model != null) criteria.add(Restrictions.eq("model", model));
    if (year != null) criteria.add(Restrictions.eq("year", year));

    vehicles = criteria.list();
}

}

Grid コンポーネントを使用して車両を表示すると仮定すると、「アクティブ化」イベント ハンドラでクエリを作成する代わりに、HibernateGridDataSource を使用することを強くお勧めします。

public class Vehicles {

    @ActivationRequestParameter
    private String make;

    @ActivationRequestParameter
    private String model;

    @ActivationRequestParameter
    private String year;

    @Inject
    private Session session;

    @OnEvent(EventConstants.ACTIVATE)
    void activate() {
    }

    public GridDataSource getVehicles() {
        return new HibernateGridDataSource(session, Vehicles.class) {
            @Override
            protected void applyAdditionalConstraints(Criteria criteria) {
                if (make != null) criteria.add(Restrictions.eq("make", make));
                if (model != null) criteria.add(Restrictions.eq("model", model));
                if (year != null) criteria.add(Restrictions.eq("year", year));
            }
        };
    }
}
于 2012-09-25T21:01:15.687 に答える
1

Another option would be to create an example query by building an object from the name/value pairs:

Vehicle vehicle = new Vehicle();
int count = context.getCount();
int i;
for (i = 0; (i + 1) < count; i += 2) {
  String name = context.get(String.class, i);
  String value = context.get(String.class, i + 1);
  // This will call the setter for the name, passing the value
  // So if name is 'make' and value is 'ford', it will call vehicle.setMake('ford')
  BeantUtils.setProperty(vehicle, name, value);
}

// This is using a Hibernate example query:
vehicles = session.createCriteria(Vehicle.class).add(Example.create(vehicle)).list();

See BeanUtils.setProperty and Example Queries for more info.

That assumes you are allowing only one value per property and that the query parameters map to the property names correctly. There may also be conversion issues to think about but I think setProperty handles the common ones.

于 2012-09-24T02:47:05.653 に答える