Показать процент выполнения ч: загрузка входного файла
Я нашел этот очень хороший пример загрузки файла с использованием JSF 2.2. Можно ли добавить индикатор выполнения с процентом загрузки файла или общим количеством загруженных байтов?
<script type="text/javascript">
function progressBar(data) {
if (data.status === "begin") {
document.getElementById("uploadMsgId").innerHTML="";
document.getElementById("progressBarId").setAttribute("src", "./resources/progress_bar.gif");
}
if (data.status === "complete") {
document.getElementById("progressBarId").removeAttribute("src");
}
}
</script>
<h:messages id="uploadMsgId" globalOnly="true" showDetail="false" showSummary="true" style="color:red"/>
<h:form id="uploadFormId" enctype="multipart/form-data">
<h:inputFile id="fileToUpload" required="true" requiredMessage="No file selected ..." value="#{uploadBean.file}"/>
<h:message showDetail="false" showSummary="true" for="fileToUpload" style="color:red"/>
<h:commandButton value="Upload" action="#{uploadBean.upload()}">
<f:ajax execute="fileToUpload" onevent="progressBar" render=":uploadMsgId @form"/>
</h:commandButton>
</h:form>
<div>
<img id="progressBarId" width="250px;" height="23"/>
</div>
Боб:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.context.RequestScoped;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Named;
import javax.servlet.http.Part;
@Named
@RequestScoped
public class UploadBean {
private static final Logger logger = Logger.getLogger(UploadBean.class.getName());
private Part file;
public Part getFile() {
return file;
}
public void setFile(Part file) {
this.file = file;
}
public void upload() {
if (file != null) {
logger.info("File Details:");
logger.log(Level.INFO, "File name:{0}", file.getName());
logger.log(Level.INFO, "Content type:{0}", file.getContentType());
logger.log(Level.INFO, "Submitted file name:{0}", file.getSubmittedFileName());
logger.log(Level.INFO, "File size:{0}", file.getSize());
try (InputStream inputStream = file.getInputStream(); FileOutputStream outputStream = new FileOutputStream("C:" + File.separator + "jsf_files_test_for_delete" + File.separator +file.getSubmittedFileName())) {
int bytesRead = 0;
final byte[] chunck = new byte[1024];
while ((bytesRead = inputStream.read(chunck)) != -1) {
outputStream.write(chunck, 0, bytesRead);
}
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Upload successfully ended!"));
} catch (IOException e) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Upload failed!"));
}
}
}
}
Возможно ли это без дополнительного кода JavaScript? Только с JSF?
1 ответ
Я обнаружил, что плагин Malsup Form для jQuery довольно прост и имеет хорошую документацию и демонстрационный код (поэтому довольно легко использовать для Ajaxify индикатор выполнения), если вы готовы идти по пути jQuery (Javascript). (Конечно, существуют и другие плагины, такие как плагин для загрузки файлов BlueImp, который имеет гораздо больше возможностей, но может быть не так прост в использовании.)
Для решения "только для JSF" BalusC рекомендует использовать библиотеку компонентов JSF, такую как Primefaces - что, вероятно, является лучшим вариантом - рекомендуется прочитать его комментарии и ссылки, которые он предоставляет, которые объясняют причины предпочтения одной технологии перед другой.
=== Добавлен пример ===
Вот очень простой пример с использованием плагина Malsup Form и jQuery, который демонстрирует индикатор выполнения. (Он также обрабатывает другие поля в форме, если вы этого хотите, но читайте о плюсах и минусах разных enctype
Настройки в <form>
элемент.) Обратите внимание, что <div>
с индикатором выполнения и текстовой меткой, показывающей процент выполнения, и другой <div>
показ некоторого текста по завершении процесса - любой из этих элементов может быть опущен или настроен иным образом. Эти <div>
Стили оформляются с помощью CSS и обновляются различными обработчиками событий в Javascript. В бэк-компоненте Java не выполняется никакой работы.
Замечания:
Я надеюсь, что это очевидно, но файлы *.js сохраняются в каталоге <my-eclipse-project>/WebContent/resources/js/
для <h:outputScript>
теги для правильной работы.
1. Представление XHTML, включая CSS и Javascript
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Demo File upload with progress</title>
<style>
.progress {
position: relative;
width: 400px;
border: 1px solid #ddd;
padding: 1px;
border-radius: 3px;
}
.bar {
background-color: #B4F5B4;
width: 0%;
height: 20px;
border-radius: 3px;
}
.percent {
position: absolute;
display: inline-block;
top: 3px;
left: 48%;
}
</style>
<h:outputScript target="head" library="js" name="jquery.js" />
<h:outputScript target="head" library="js" name="jquery.form.js" /><!-- http://jquery.malsup.com/form/ -->
<h:outputScript target="body">
//<![CDATA[
jQuery(document).ready(function() {
var bar = jQuery('.bar');
var percent = jQuery('.percent');
var status = jQuery('#status');
jQuery('#formid').ajaxForm({
beforeSend: function() {
status.empty();
var percentVal = '0%';
bar.width(percentVal)
percent.html(percentVal);
},
uploadProgress: function(event, position, total, percentComplete) {
var percentVal = percentComplete + '%';
bar.width(percentVal)
percent.html(percentVal);
},
success: function() {
var percentVal = '100%';
bar.width(percentVal)
percent.html(percentVal);
},
complete: function(xhr) {
status.html(xhr.statusText);
}
});
});
//]]>
</h:outputScript>
</h:head>
<h:body>
<h:form id="formid" enctype="multipart/form-data" method="post">
<h1>Demo File upload with progress</h1>
<h:messages globalOnly="true" tooltip="true" />
<h:inputFile id="fileupload" name="fileupload" value="#{uploadBean.file}" />
<div class="progress">
<div class="bar"></div>
<div class="percent">0%</div>
</div>
<div id="status"></div>
<br />
<h:inputText value="#{uploadBean.field}"></h:inputText>
<br />
<h:commandButton id="submit" action="#{uploadBean.submit}" value="Submit" />
</h:form>
</h:body>
</html>
2. Задняя часть бобов
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.servlet.http.Part;
@ManagedBean
@ViewScoped
public class UploadBean implements Serializable {
private static final long serialVersionUID = 1L;
private String field;
private Part file;
/** Constructor */
public UploadBean() {}
/** Action handler */
public String submit() {
// the file is already uploaded at this point
// TODO whatever you need to do with the file and other form values
return ""; // ... or another view
}
// TODO getters and setters for fields
}