Vaadin com JQuery FileUpload

Eu gostaria de criarFileUploader comVaadin . Mas preciso obter mais recursosUpload Vaadin normal.

bonito e fácil de gerenciar (mas opcional)rápido e nunca falhou durante o uploadincluir barra de progressomostrar pré-visualizaçãosuporte a upload de arquivos múltiplosupload de tamanho de arquivo e restrição de tipoarraste e solteredimensionável imagem do lado do cliente(é a principal característica para mim porque todos os meus arquivos enviados eram imagens)

Existe um addonMultiFileUpload. Sim, é perfeito para a maioria dos meus requisitos, mas não pararedimensionamento de imagem no tamanho do cliente. Então eu decidi usarJQuery FileUpload porque é suporte paraRedimensionamento de imagem do lado do cliente.

Eu usei vaadinJanela para carregar imagem. Mas eu tive um problema ao criar minha janela, muito difícil criar cada elemento HTML respectivamente (pode ser que eu tenho menos exp) Então eu useiCustomLayout com HTML para fácil criar e editar o design da minha janela de upload de imagens.

Abaixo está o meu arquivo HTML de layout personalizado. (dois scripts eram modelos para visualização de imagem)

<script id="template-upload" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
<tr class="template-upload">
    <td width="100px" align="center">
        <span class="preview"></span>
    </td>
    <td width="400px" align="center">
        <p class="name">{%=file.name%}</p>
        {% if (!o.files.error) { %}
            <div class="progress progress-success progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><div class="bar" style="width:0%;"></div></div>
        {% } %}
        {% if (file.error) { %}
            <div><span class="label label-important">Error</span> {%=file.error%}</div>
        {% } %}
    </td>
    <td width="100px" align="center">
        {% if (!i) { %}
            <button style="display: none;" class="start" type="button">
                <span>Start</span>
            </button>
            <div class="v-button v-widget cancel" type = "button">
                <span class="v-button-wrap" style="color: red;">
                    <span class="v-button-caption">Cancel</span>
                </span>
            </div>
        {% } %}
        <br>
        {%=o.formatFileSize(file.size)%}
    </td>
</tr>
{% } %}
</script>
<!-- The template to display files available for download -->
<script id="template-download" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
<tr class="template-download">
    <td width="100px" align="center">
        <span class="preview">
            {% if (file.path) { %}
                <img src="../{%=file.path%}" width="100px">
            {% } %}
        </span>
    </td>
    <td width="400px" align="center">
        <p class="name">
            {%=file.name%}
        </p>
        {% if (file.error) { %}
            <div><span class="label label-important">Error</span> {%=file.error%}</div>
        {% } %}
    </td>
    <td width="100px" align="center">
        <span class="size">{%=o.formatFileSize(file.size)%}</span>
    </td>
</tr>
{% } %}
</script>
<table cellpadding="5" style="width: 100%;">
<colgroup>
<col>
</colgroup>
<tbody>
    <tr>
        <td width="90px">
            <div style="text-align: right; width: 120px;">UploadPhoto :</div>
        </td>
        <td>
            <div id="pnlProgress" aria-valuenow="0" aria-valuemax="100" aria-valuemin="0" style="display: none;" class="progress progressall progress-success progress-striped active">
                <div style="width: 0%;" class="allbar" id="pnlProgressBar">&nbsp;</div>
            </div>
        </td>
    </tr>
    <tr>
        <td colspan="3">
            <div id="imageForm" style="width: 600px;">
                <form id="fileupload">
                    <div style="margin-bottom: 10px; border: 1px solid #DDD; width: 600px; height: 300px; overflow: scroll">
                        <table cellspacing="0" cellpadding="5">
                            <tbody class="files"></tbody>
                        </table>
                    </div>
                    <div style="margin-bottom: 10px;" class="fileupload-buttonbar">
                        <div class="v-button v-widget btnPlus">
                            <span class="v-button-caption">Add Files</span> 
                            <input type="file" multiple="" name="files[]">
                        </div>
                        <div class="v-button v-widget start" type = "submit">
                            <span class="v-button-wrap">
                                <span class="v-button-caption">StartUpload</span>
                            </span>
                        </div>
                        <div class="v-button v-widget cancel" type = "reset">
                            <span class="v-button-wrap">
                                <span class="v-button-caption">Cancel All</span>
                            </span>
                        </div>
                    </div>
                    <div style="border: 1px solid #999; width: 600px; height: 100px;" id="dropZone">
                        <div class="carPhotoDropMsg">
                            Draft &amp; Drop Photos<br>(jpg, jpeg, png, gif only)
                        </div>
                    </div>
                </form>
            </div>
        </td>
    </tr>
</tbody>

Abaixo está a janela ImageUpload

public final class ImageUploadDialog extends CustomComponent {
private Window window;

public void show() {
    UI.getCurrent().addWindow(window);
 // 123 is seq for save in database or other use
    Page.getCurrent().getJavaScript().execute("initImageuploader(123)");
}

public ImageUploadDialog() {
    CustomLayout layout = new CustomLayout("imageUploadLayout");
    window = new Window("Uploading Photos");
    window.center();
    window.setWidth("615px");
    window.setModal(true);
    window.setResizable(false);
    window.setClosable(true);
    window.setContent(layout);
}
}

Abaixo, está o meu arquivo upload.js para inicializar o meu carregador de imagens

function initImageuploader(seq) {
$('#fileupload').fileupload({
    url : 'photo/upload.html?s=' + seq,
    sequentialUploads : true,
    disableImageResize : false,
    imageMaxWidth : 1024,
    imageMaxHeight : 1024,
    previewCrop : true,
    dropZone : $("#dropZone"),
    acceptFileTypes : /(\.|\/)(gif|jpe?g|png)$/i,
    progress : function(e, data) {
        if (data.context) {
            var progress = data.loaded / data.total * 100;
            progress = Math.floor(progress);
            $('.progress').attr('aria-valuenow', progress);
            $('.progress').css('display', 'block');
            $('.bar').css('width', progress + '%');
        }
    },
    progressall : function(e, data) {
        var progress = data.loaded / data.total * 100;
        progress = Math.floor(progress);
        $('.progressall').attr('aria-valuenow', progress);
        $('.progressall').css('display', 'block');
        $('.allbar').css('width', progress + '%');
        if (progress > 20) {
            $('.allbar').text(progress + '% Completed');
        }
    },
    stop: function (e) {
        return;
    }
});
}

E você precisa de arquivos javascripts adicionais para o upload de imagens e eu os importei na minha classe de interface do usuário, como abaixo

@JavaScript({ "vaadin://themes/myproject/js/load-image.min.js",
    "vaadin://themes/myproject/js/tmpl.min.js",
    "vaadin://themes/myproject/js/jquery/jquery-1.10.1.min.js",
    "vaadin://themes/myproject/js/jquery/vendor/jquery.ui.widget.js",
    "vaadin://themes/myproject/js/jquery/jquery.iframe-transport.js",
    "vaadin://themes/myproject/js/jquery/jquery.fileupload.js",
    "vaadin://themes/myproject/js/jquery/jquery.fileupload-ui.js",
    "vaadin://themes/myproject/js/jquery/jquery.fileupload-process.js",
    "vaadin://themes/myproject/js/jquery/jquery.fileupload-image.js",
    "vaadin://themes/myproject/js/jquery/jquery.fileupload-validate.js",
    "vaadin://themes/myproject/js/canvas-to-blob.min.js",
    "vaadin://themes/myproject/js/upload.js" })
@StyleSheet({ "vaadin://themes/myproject/css/jquery-ui-1.10.3.custom.min.css",
    "vaadin://themes/myproject/css/imageUpload.css" })
public class EntryPoint extends UI {
..............
}

Observe para a ordem dos arquivos JS!

Abaixo está o meu arquivo CSS personalizado para a janela de upload de imagens (imageUpload.css)

table.upld-status {
display: none;
}
.fileupload-buttonbar .btnPlus {
float: left;
position: relative;
overflow: hidden;
color: blue;
text-align: center;
margin-right : 10px;
}
.fileupload-buttonbar .btnPlus input {
margin: 0px;
position: absolute;
top: 0px;
right: 0px;
line-height: 30px;
font-size: 23px;
direction: ltr;
opacity: 0;
}
.carPhotoDropMsg {
color: #DDD;
font-size: 20pt;
height: 82%;
padding: 9px;
text-align: center;
}
.progress {
background-color: #F7F7F7;
background-image: linear-gradient(to bottom, #F5F5F5, #F9F9F9);
background-repeat: repeat-x;
border-radius: 4px 4px 4px 4px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1) inset;
height: 17px;
overflow: hidden;
}
.progress-success.progress-striped .bar, .progress-success.progress-striped .allbar, .progress
striped .bar-success {
background-color: #62C462;
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
}
.progress.active .bar, .progress.active .allbar {
animation: 2s linear 0s normal none infinite progress-bar-stripes;
}
.progress-success .bar, .progress-success .allbar, .progress .bar-success {
background-color: #5EB95E;
background-image: linear-gradient(to bottom, #62C462, #57A957);
background-repeat: repeat-x;
}
.progress-striped .bar, .progress-striped .allbar {
background-color: #149BDF;
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
background-size: 40px 40px;
}
.progress .bar, .progress .allbar {
-moz-box-sizing: border-box;
background-color: #0E90D2;
background-image: linear-gradient(to bottom, #149BDF, #0480BE);
background-repeat: repeat-x;
box-shadow: 0 -1px 0 rgba(0, 0, 0, 0.15) inset;
color: #FFFFFF;
float: left;
font-size: 12px;
height: 100%;
text-align: center;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
transition: width 0.4s ease 0s;
width: 0;
}

Preciso de controle do lado do servidor para salvar a imagem. Você precisa de dois frascosapache-common-io eapache-common-fileupload. Abaixo está o repositório maven desses dois jarros.

    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.2.2</version>
    </dependency>

    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.4</version>
    </dependency>

Finalmente, abaixo estão os códigos para controle do servidor.

@WebServlet(value = "/photo/upload.html")
public class UploadServletController extends HttpServlet {
protected final void doPost(final HttpServletRequest request,
        final HttpServletResponse response) throws ServletException, IOException {

    response.setContentType("application/json");
    PrintWriter out = response.getWriter();
    FileItemFactory factory = new DiskFileItemFactory();
    ServletFileUpload upload = new ServletFileUpload(factory);
    List<FileItem> fields = null;
    try {
        fields = upload.parseRequest(request);
    }
    catch (FileUploadException e) {
        throw new RuntimeException("Error Parsing File Item " + e.getMessage(), e);
    }
    if (fields != null) {
        String message = uploadPhoto(request, fields);
        out.write(message);
    }
}
public final synchronized String uploadPhoto(final HttpServletRequest request,
        final List<FileItem> sessionFiles) {

    List<Map<String, Object>> ret = new ArrayList<Map<String, Object>>();
    for (FileItem item : sessionFiles) {
        if (!item.isFormField()) {
            Long seq = Long.parseLong(request.getParameter("s"));
// get from vm arguments (eg:-DstaticDir=/Applications/springsource/workspace/myproject/src/main/webapp)
            String staticDir = System.getProperty("staticDir");

            Date today = new Date();
            SimpleDateFormat fmtYMD = new SimpleDateFormat("/yyyyMMdd/HH");
            SimpleDateFormat fmtHMS = new SimpleDateFormat("HHmmssS");

            String saveDir = "data/photo" + fmtYMD.format(today);
            String format = ".jpg";
            try {
                format = item.getName().substring(item.getName().lastIndexOf("."), item.getName().length())
                        .toLowerCase();
            }
            catch (Exception e) {
                // nothing to do!
            }

            String fileName = seq + "_" + fmtHMS.format(today) + format;
            Map<String, Object> res = new HashMap<String, Object>();
            // Save image in specify location
            String filePath = staticDir + "/" + saveDir;
            saveFile(filePath, fileName, item);

            res.put("seq", seq);
            res.put("path", saveDir + "/" + fileName);
            res.put("ext", format.substring(1));

            res.put("name", item.getName());
            res.put("size", item.getSize());
            ret.add(res);
        }
    }
    Map<String, Object> result = new HashMap<String, Object>();
    result.put("files", ret);
    JSONObject obj = new JSONObject(result);

    return obj.toString();
}
public static String saveFile(final String filePath, final String fileName, final FileItem item) {
    File file = new File(filePath);
    if (!file.exists()) {
        file.mkdirs();
    }
    File imageFile = new File(file, fileName);
    try {
        item.write(imageFile);
    }
    catch (Exception e) {
        e.printStackTrace();
    }
    item.setFieldName(filePath + fileName);
    return item.toString();
}
}

Eu sei que meus códigos podem ter riscos e alguns pontos fracos. Todas as sugestões foram bem-vindas. Mas acredito que há alguns úteis para iniciantes (Eu também sou um novato) Desculpe pelo formato muito longo e ruim.

A última coisa é o meu problema ....

Por que visualizar a imagem (após o upload, não antes do upload) incluem automaticamenteurl em vez de caminho de arquivo? Erro na imagem não encontrada

"NetworkError: 404 Not Found - http://localhost:8080/myproject/VAADIN/themes/myTheme/data/photo/20140723/23/123_235918346.jpg"

Na verdade, esse caminho da imagem deve serdata/photo/20140723/23/111_235918346.jpg. Não faço ideia por que prefixo urlhttp://localhost:8080/myproject/VAADIN/themes/myTheme/ foi incluído automaticamente (pode ser devido ao meu caminho de arquivo HTML CustomLayout)? Os caminhos do arquivo foram obtidos da resposta HTTP (com JSON). Eu acho que é devido ao VAADIN porque funciona no meu projeto GWT ou pode estar errado. Alguma sugestão ? Obrigado por ler minha pergunta.

questionAnswers(1)

yourAnswerToTheQuestion