Search code examples
ajaxspring-mvcfile-uploadtinymce

How to upload images in Spring MVC from TinyMCE editor


I am making a content management system for ecommerce and have a blocks which would be displayed in different parts of the pages. This blocks can contain html and images, so I use <textarea> with TinyMCE to manage blocks content.

I didn't found complete solution anywhere - only separate questions about TinyMCE or loading images controllers, so I want to share my experience with you - complete JavaScript for TinyMCE initialization and back end controller, that saves images.

JavaScript is taken from this theme answers(I used steve.hanson answer), but I changed it a bit to fit my controller and moved image button methods inside setup function.


Solution

  • Important thing- 'files' is the name of multipart form variable in ajax and controller, and request url is : '${pageContext.request.contextPath}/a/images'

    JavaScript initialization of TinyMCE and ajax request to process images:

    <script src="https://cloud.tinymce.com/stable/tinymce.min.js"></script> 
    <script>
    tinymce.init({      
          selector: 'textarea',  // change this value according to your HTML
          auto_focus: 'element1',
          toolbar: 'undo redo | imageupload',
          setup: function(editor) {
    
                  // create input and insert in the DOM
                  var inp = $('<input id="tinymce-uploader" type="file" name="pic" accept="image/*" style="display:none">');
                  $(editor.getElement()).parent().append(inp);
    
                  // add the image upload button to the editor toolbar
                  editor.addButton('imageupload', {
                    text: 'Add image',  
                    icon: 'image',
                    onclick: function(e) { // when toolbar button is clicked, open file select modal
                      inp.trigger('click');
                    }
                  });
    
                  // when a file is selected, upload it to the server
                  inp.on("change", function(e){
                    uploadFile($(this), editor);
                  });
    
    
                function uploadFile(inp, editor) {
                  var input = inp.get(0);
                  var data = new FormData();
                  data.append('files', input.files[0]);
    
                  $.ajax({
                    url: '${pageContext.request.contextPath}/a/images',
                    type: 'POST',
                    data: data,
                    enctype: 'multipart/form-data',
                    dataType : 'json',
                    processData: false, // Don't process the files
                    contentType: false, // Set content type to false as jQuery will tell the server its a query string request
                    success: function(data, textStatus, jqXHR) {
                      editor.insertContent('<img class="content-img" src="${pageContext.request.contextPath}' + data.location + '" data-mce-src="${pageContext.request.contextPath}' + data.location + '" />');
                    },
                    error: function(jqXHR, textStatus, errorThrown) {
                      if(jqXHR.responseText) {
                        errors = JSON.parse(jqXHR.responseText).errors
                        alert('Error uploading image: ' + errors.join(", ") + '. Make sure the file is an image and has extension jpg/jpeg/png.');
                      }
                    }
                  });
                }
          }
        });
    
    
    </script>
    

    Here is my controller for Spring MVC and method to save files:

    @RequestMapping(value = "/a/images", method = RequestMethod.POST)
    @ResponseBody
    public String handleTinyMCEUpload(@RequestParam("files") MultipartFile files[]) {
        System.out.println("uploading______________________________________MultipartFile " + files.length);
        String filePath = "/resources/uploads/tinyMCE/" + files[0].getOriginalFilename();
        String result = uploadFilesFromTinyMCE("tinyMCE", files, false);
        System.out.println(result);
        return "{\"location\":\"" + filePath + "\"}";
    
    }
    
    private String uploadFilesFromTinyMCE(String prefix, MultipartFile files[], boolean isMain) {
        System.out.println("uploading______________________________________" + prefix);
        try {
            String folder = context.getRealPath("/") + "/resources/uploads/" + prefix;
            StringBuffer result = new StringBuffer();
            byte[] bytes = null;
            result.append("Uploading of File(s) ");
    
            for (int i = 0; i < files.length; i++) {
                if (!files[i].isEmpty()) {
    
                    try {
                        boolean created = false;
    
                        try {
                            File theDir = new File(folder);
                            theDir.mkdir();
                            created = true;
                        } catch (SecurityException se) {
                            se.printStackTrace();
                        }
                        if (created) {
                            System.out.println("DIR created");
                        }
                        String path = "";
                        path = folder + files[i].getOriginalFilename();
                        File destination = new File(path);
                        System.out.println("--> " + destination);
                        files[i].transferTo(destination);
                        result.append(files[i].getOriginalFilename() + " Succsess. ");
                    } catch (Exception e) {
                        throw new RuntimeException("Product Image saving failed", e);
                    }
    
                } else
                    result.append(files[i].getOriginalFilename() + " Failed. ");
    
            }
    
            return result.toString();
    
        } catch (Exception e) {
            return "Error Occured while uploading files." + " => " + e.getMessage();
        }
    }