Я хочу создать собственный поисковик (будучи ветераном веб-разработки, но новичком в 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;
}
Итак, теперь я хочу, чтобы запрос «POST» на этот URL-адрес принимал отправку формы поиска активов, которая содержит поля для нескольких ключевых свойств объекта «Актив».
(Сейчас я кодирую этот искатель в моем контроллере представления, и я знаю, что в конечном итоге я захочу передать его в класс модели. Пока я просто работаю здесь для удобства. Кроме того, я знаю, что не не нужно указывать полное имя объекта, я по-новому назвал свой контроллер тем же именем, что и модель, с которой он общается, поэтому, пока я не разберусь с этим, я работаю над этим.)
Я позаимствовал некоторый код из некоторых сгенерированных мной искателей 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-инъекцией, но здорово, что ему (почти) не нужно ничего знать о передаваемых ему данных, что он просто соберет запрос из полей, которые ему были предоставлены. Ему нужно знать, с какими полями он что делает — какие поля являются «подобными», а какие — «равными», как обрабатывать «минимальные» и «максимальные» поля, определяющие диапазон, и т. д. Но это не так уж плохо.