Vaadin с JQuery FileUpload

Я хотел бы создатьFileUploader сVaadin , Но мне нужно, чтобы получить больше возможностейнормальный ваадин Загрузить.

красивый и простой в управлении (но не обязательно)быстро и никогда не подводил при загрузкевключить индикаторпредварительный просмотрподдержка загрузки нескольких файловразмер загружаемого файла и ограничение типаперетащитьизменение размера изображения на стороне клиента(для меня это главная особенность, потому что все мои загруженные файлы были изображениями)

Там есть аддонMultiFileUpload, Да, это идеально подходит для большинства моих требований, но не дляизменение размера изображения клиента, Поэтому я решил использоватьJQuery FileUpload потому что это поддержкаИзменение размера изображения на стороне клиента.

Я использовал ваадинОкно для загрузки изображения. Но у меня возникла проблема при создании моего окна, очень сложно создать каждый элемент HTML соответственно (может быть у меня меньше опыта). Так что я использовалCustomLayout с HTML для легкого создания и редактирования дизайна моего окна загрузки изображений.

Ниже мой HTML-файл пользовательского макета. (два скрипта были шаблонами для предпросмотра изображения)

<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>

Ниже для окна 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);
}
}

И ниже мой файл upload.js для инициализации моего загрузчика изображений

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;
    }
});
}

И вам нужны дополнительные файлы javascripts для загрузки изображений, и я импортировал их в своем классе пользовательского интерфейса, как показано ниже

@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 {
..............
}

Пожалуйста, обратите внимание на порядок файлов JS!

Ниже мой пользовательский файл CSS для окна загрузки изображений (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;
}

Мне нужно управление на стороне сервера для сохранения изображения. Вам нужны две банкиапач-синфазный И.О. а такжеапач-синфазного FileUpload, Ниже для хранилища Maven этих двух банок.

    <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>

Наконец, ниже приведены коды для управления на стороне сервера.

@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();
}
}

Я знаю, что мои коды могут иметь риски и некоторые слабые места. Все предложения приветствуются. Но я считаю, что есть кое-что полезное для новичка (Я тоже новичок). Извините за слишком длинный и плохой формат.

Последнее, что моя проблема ....

Почему предпросмотр изображения (после загрузки не до загрузки) автоматически включатьURL вместо пути к файлу? Я получил изображение не найдена ошибка

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

На самом деле этот путь изображения должен бытьdata/photo/20140723/23/111_235918346.jpg, Я понятия не имею, почему префикс URLhttp://localhost:8080/myproject/VAADIN/themes/myTheme/ был автоматически включен (может быть из-за моего пути к файлу CustomLayout HTML) Пути к файлам были получены из ответа HTTP (с JSON). Я думаю, что это из-за VAADIN, потому что он работает на моем проекте GWT, или, может быть, я ошибаюсь. Какие-либо предложения ? Спасибо за чтение моего вопроса.

Ответы на вопрос(1)

Ваш ответ на вопрос