Пишу программу на Java + PostgreSQL. Нужно сделать поиск по нескольким полям как на фото:
Поля могут быть пустыми.
Вот код, который сейчас работает на два поля:
for (int i = 0; i < protokols.size(); i++) {
if (protokols.get(i).getNomer().contains(x)) {
if (protokols.get(i).getSotrudnik_Key().contains(y)) {
filterProtokols.add(protokols.get(i));
}
}
}
if (x.equals("")) {
for (int i = 0; i < protokols.size(); i++) {
if (protokols.get(i).getSotrudnik_Key().contains(y)) {
filterProtokols.add(protokols.get(i));
}
}
}
Как это лучше реализовать?
Если все поля строковые, то просто:
String query = "SELECT * FROM some_table";
List<String> paramsList;
Map<String, String> paramsMap = new LinkedHashMap<>();
// Здесь добавляем значения полей формы, если они не равны пустой строке
paramsMap.put("first_parameter", "qwerty");
paramsMap.put("second_parameter", "12345");
paramsList = paramsMap.keySet().stream()
.map(i -> String.format("%s = ?", i))
.collect(Collectors.toList());
if(paramsList.size() > 0)
query += " WHERE " + String.join(" AND ", paramsList);
System.out.println(query);
Можно было бы этим и ограничиться, перебирая не ключи, а пары и вставляя значения параметров вместе с именами в методе map()
. Но тогда не было бы экранирования и можно было бы нарваться на SQL injection. Поэтому добавим к генерации запроса PreparedStatement
:
try {
Class.forName("org.sqlite.JDBC");
try (Connection connection = DriverManager.getConnection("jdbc:sqlite:test.db")) {
try (PreparedStatement stmt = connection.prepareStatement(query)) {
int pn = 1;
for (String value : paramsMap.values()) {
stmt.setString(pn++, value);
}
...
}
}
catch (SQLException e) {
e.printStackTrace();
}
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
Если по какой-то причине фильтровать нужно обязательно на стороне Java, то при условии что все поля в классе Protocol
типа String
, с использованием Java 8 можно сделать так:
Protocol
Тестовый вариант класса Protocol
:
public class Protocol
{
private final String
nomer,
sotrudnik_Key,
street;
public Protocol(String nomer, String sotrudnik_Key, String street)
{
this.nomer = nomer;
this.sotrudnik_Key = sotrudnik_Key;
this.street = street;
}
public String getNomer() { return nomer; }
public String getSotrudnik_Key() { return sotrudnik_Key; }
public String getStreet() { return street; }
@Override
public String toString() { return nomer + " " + sotrudnik_Key + " " + street; }
}
Сама фильтрация:
public static List<Protocol> filter(List<Protocol> allProtocols, Protocol filter,
List<Function<Protocol, String>> comparingFields)
{
return allProtocols.stream()
.filter(protocol -> test(protocol, filter, comparingFields))
.collect(Collectors.toList());
}
private static boolean test(Protocol protocol, Protocol filter,
List<Function<Protocol, String>> comparingFields)
{
return comparingFields.stream()
.allMatch(func -> func.apply(protocol).contains(func.apply(filter)));
}
И пример использования:
Protocol filter = new Protocol("2", "sk", "");
List<Protocol> allProtocols = Arrays.asList(new Protocol("n12", "sk12", "st12"),
new Protocol("n23", "sk23", "st23"), new Protocol("n34", "sk34", "st34"));
List<Function<Protocol, String>> comparingFields = Arrays.asList(Protocol::getNomer,
Protocol::getSotrudnik_Key, Protocol::getStreet);
List<Protocol> filteredProtocols = filter(allProtocols, filter, comparingFields);
System.out.println(filteredProtocols);
Может показаться, что тут слишком много кода для сравнения по всего трём полям, однако не стоит забывать, что, во-первых, из кода исключено дублирование, которого возникло бы при проверке каждого поля "в лоб". А во-вторых, для расширения сравнения с 3 до 9 полей достаточно просто изменить список comparingFields
и обойтись без добавления кучи кода для сравнения по новым 6 полям.
При использовании более старой версии Java подобный подход можно реализовать с помощью рефлексии, сделав comparingFields
в виде списка названий методов.
Рекомендую фильтр на стороне БД: Берешь все поля и передаешь в метод, где формируешь запрос в БД. А там что-то вроде:
String sql = sqlBegin; //Начало запроса "select ... from ... where ...
if (x1.length()>0){ //Поле фильтра первое
sql +=" and ..." //Добавляешь условие.
}
if (x2.length()>0){ //Поле фильтра второе
sql +=" and ..." //Добавляешь условие.
}
//И т.д.
sql += sqlEnd; //Хвост запроса " ... order by ..."
Пример примитивный. Естественно должный быть повешены ограничения на соответствие вводимых данных требованиям и т.п.
Виртуальный выделенный сервер (VDS) становится отличным выбором
Здравствуйте, у меня небольшая проблема возникла, мне необходимо организовать поиск по всем пользователям по базе данных, сохраняю данные...
Помогите разобраться как проверить запрос и найти проблему? У меня есть
Есть bytearray, в котором хранятся байты картинкиЧитал их с помощью OpenCV Imgcodecs