Ответ 1
Как загрузить несколько файлов с помощью JSF 2.2
Вы действительно можете добиться этого с помощью другой функции JSF 2.2: атрибуты passsthrough. Установите атрибут multiple
в качестве атрибута прокси (поддержка браузера в настоящее время довольно широкий).
<html ... xmlns:a="http://xmlns.jcp.org/jsf/passthrough">
...
<h:inputFile ... a:multiple="true" />
Однако сам компонент <h:inputFile>
не поддерживает захват нескольких Part
из запроса и установку его как свойства массива или Collection
bean. Он только установил бы последнюю часть, соответствующую имени поля ввода. В принципе, для поддержки нескольких частей необходимо создать настраиваемый рендерер (и вы должны немедленно воспользоваться возможностью просто поддержать атрибут multiple
сразу, не прибегая к атрибутам пересылки).
Для того, чтобы создать "обходной путь" без создания всего средства визуализации, вы могли бы вручную захватить все части с помощью HttpServletRequest
с помощью небольшого метода полезности:
public static Collection<Part> getAllParts(Part part) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
return request.getParts().stream().filter(p -> part.getName().equals(p.getName())).collect(Collectors.toList());
}
Итак, приведенная ниже конструкция должна работать с вышеуказанным методом утилиты:
<h:inputFile value="#{bean.part}" a:multiple="true" />
<h:commandButton ... action="#{bean.submit}" />
private Part file;
public void submit() throws ServletException, IOException {
for (Part part : getAllParts(file)) {
String fileName = part.getSubmittedFileName();
InputStream fileContent = part.getInputStream();
// ...
// Do your thing with it.
// E.g. https://stackoverflow.com/q/14211843/157882
}
}
public Part getFile() {
return null; // Important!
}
public void setFile(Part file) {
this.file = file;
}
Заметьте, что геттер может для безопасности и ясности лучше всегда возвращать null
. Фактически, весь метод геттера должен был быть ненужным, но это то, чем оно является.
В более современных браузерах вы можете даже выбрать целые папки. Для этого требуется только еще новый атрибут directory
. Это поддерживается, поскольку Firefox 46 (уже с 42, но должен быть явно включен примерно в: config). Webkit-браузеры (Chrome 11+, Safari 4+ и Edge) поддерживают это через собственный атрибут webkitdirectory
. Поэтому, если вы укажете оба атрибута, вы в целом безопасны.
<h:inputFile ... a:multiple="true" a:directory="true" a:webkitdirectory="true" />
Заметьте, что это не отправляет физические папки, а только файлы, содержащиеся в этих папках.
Обновить: если вы используете служебную библиотеку JSF OmniFaces, начиная с версии 2.5 <o:inputFile>
, который должен сделать несколько и выбор каталога менее утомительным.
<o:inputFile value="#{bean.files}" multiple="true" />
<o:inputFile value="#{bean.files}" directory="true" />
Значение может быть привязано к a List<Part>
.
private List<Part> files; // +getter+setter