Как присоединиться к элементам списка с помощью", "используя потоки с" в качестве префикса и суффикса тоже

у меня есть инструкция insert, как показано ниже

private final COLUMNS = "NAME,TYPE,STATUS,CATEGORY";

String values = list
    .stream()
    .collect(Collectors.joining(","));

String insertStatement = String.format("INSERT INTO ifc.documents (%s) VALUES (%s) ",COLUMNS,values); 

Я могу легко помещать столбцы без кавычек, но для значений мой SQL терпит неудачу и жалуется на отсутствующие кавычки для кода выше.

Итак, я попытался

 String values = list.stream()
.collect(Collectors.joining("','"));

но он терпит неудачу и с этим.Поэтому я сделал обходной путь и добавил еще один оператор с префиксом и суффиксом одной цитаты, и он начал работать.

 values = "'"+values+"'";

чтобы быть более конкретным, если я говорю "отдых", "тест" и "лучший" в списке

тогда ожидаемый результат

'rest','test','best'

кто-нибудь знает лучшее решение для этого?

4 ответов


Вы можете использовать Collectors.joining(CharSequence delimiter,CharSequence prefix,CharSequence suffix) и здесь для API.

String values = list.stream().collect(Collectors.joining("','", "'", "'"));

можно использовать перегрузка Collectors.joining который принимает параметры префикса и суффикса.

 String values = list.stream()
    .collect(Collectors.joining("','", "'", "'"));

это правильно разместит одинарные кавычки вокруг всех ваших значений, предполагая, что все ваши значения являются строками, которым нужны одинарные кавычки для синтаксиса.

но, как и в случае со всеми проблемами, связанными с построением запроса путем объединения значений, он оставляет ваш уязвимым для SQL-инъекции. Более надежное и универсальное решение предполагает использование PreparedStatement. Заполнители значений:? символы, и вы можете использовать различные setXyz методы для безопасной установки значений. Он защищает от SQL-инъекций и позволяет использовать любые типы данных, а не только строковые типы.


не создавайте часть "значения", используя конкатенацию строк, поскольку это открывает возможность для атак SQL-инъекций.

Я бы использовал подготовленное заявление здесь. Вы все еще можете построить свой запрос следующим образом:

List<String> columns = Arrays.asList("column1", "column2", "column3");
String columnsFragment = columns.stream().collect(Collectors.joining(","));
String placeholdersFragment = columns.stream().filter(s -> "?").collect(Collectors.joining(","))
String insertStatement = String.format("INSERT INTO ifc.documents (%s) VALUES (%s) ", columnsFragment, placeholdersFragment);

и затем использовать insertStatement С PreparedStatement:

PreparedStatement st = connection.prepareStatement(insertStatement);
for (int i = 0; i < values.size(); i++) {
    // +1 because prepared statement parameters indices are 1-based
    st.setString(i + 1, values.get(i));
}
st.executeUpdate();

в этом случае результирующий запрос будет выглядеть как

INSERT INTO ifc.documents (column1, column2, column3) VALUES (?, ?, ?)

другое использование решения строку.присоединяйтесь метод, как это

String result = "'"+String.join("','", list)+"'";

 Function<List<String>,String> function = list2->"'".concat(String.join("','",list2)).concat("'");
 System.out.println(function.apply(list));

или использовать сокращение как это

String result =   "'"+list.stream().reduce((s, p) -> s + "','" + p).get()+"'";