Image management using Spring & Cloudinary.
Cloudinary is your one stop shop for every image related task. It is a software–as-a-service (SaaS) solution hosted in the cloud. Cloudinary manages your web application’s resources in the cloud. The resources are delivered from high-performance servers through Content Delivery Networks.
Cloudinary is an end-to-end image management solution for your website and mobile apps. Cloudinary covers everything from image uploads, storage, manipulations, optimizations to delivery. You can easily upload images to the cloud, automatically perform smart image manipulations without installing any complex software. All your images are then seamlessly delivered through a fast CDN, optimized and using industry best practices. Cloudinary offers comprehensive APIs and administration capabilities and is easy to integrate with new and existing web and mobile applications.
Cloudinary provides many features which include Image upload, Image Transformation, Image storage and many more. Click here to see their all features.
Further we will see a sample demonstration to image upload and transformation using Spring MVC and Cloudinary.
Technologies used in this examples are :
1. JDK 8
2. Maven 3.3.9
3. Spring
4. Tomcat
5. Cloudinary Account – Before starting this example make sure you have the Cloudinary account to get the following details –
a. Cloudinary cloud name
b. Cloudiinary API key
c. Cloudinary API Seceret
This example has been implemented using Eclipse IDE and Maven. Run the following command to create the Maven based project in your workspace through command prompt.
mvn archetype:generate -DgroupId={project-packaging} -DartifactId={project-name} -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
For example –
mvn archetype:generate -DgroupId=com.c2s.upload -DartifactId=SpringCloudinaryDemo -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
It will create the project in your workspace.
Import the project as existing maven project in your eclipse IDE and add the following folder in the maven based project –
1). Add below dependencies in your pom.xml and build the project to add these dependencies in the project.
Command – mvn clean install
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.c2s.upload</groupId> <artifactId>SpringCloudinaryDemo</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>SpringCloudinaryDemo Maven Webapp</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <!-- Spring framework --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> <version>2.5.6</version> </dependency> <!-- Spring MVC framework --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>2.5.6</version> </dependency> <!-- Apache Commons Upload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.2.2</version> </dependency> <!-- Apache Commons Upload --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> </dependency> <!-- JSTL --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.1.2</version> </dependency> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>com.cloudinary</groupId> <artifactId>cloudinary-http43</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>com.cloudinary</groupId> <artifactId>cloudinary-core</artifactId> <version>1.2.2</version> </dependency> </dependencies> <build> <finalName>SpringCloudinaryDemo</finalName> </build> </project> |
2). Add below servlet mapping configuration into web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name>Spring Web MVC Application</display-name> <servlet> <servlet-name>mvc-dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>mvc-dispatcher</servlet-name> <url-pattern>*.htm</url-pattern> </servlet-mapping> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <error-page> <error-code>404</error-code> <location>/WEB-INF/pages/404.jsp</location> </error-page> <error-page> <exception-type>java.lang.Exception</exception-type> <location>/WEB-INF/pages/404.jsp</location> </error-page> </web-app> |
3). Spring Configuration –
Register “CommonsMultipartResolver” to tell Spring to use commons-upload library to handle the file upload form. The rest is just normal bean declaration.
File – mvc-dispatcher-servler.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/> <bean class="com.c2s.upload.controller.FileUploadController"> <property name="formView" value="FileUploadForm" /> <property name="successView" value="FileUploadSuccess" /> <!-- Map a validator --> <property name="validator"> <bean class="com.c2s.upload.validator.FileUploadValidator" /> </property> </bean> <!-- Register the Customer.properties --> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basename" value="message" /> </bean> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" > <property name="prefix"> <value>/WEB-INF/pages/</value> </property> <property name="suffix"> <value>.jsp</value> </property> </bean> </beans> |
4). File Upload Controller – Extends the SimpleFormController and handle the file upload form like a normal form.
File : FileUploadController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
package com.c2s.upload.controller; import java.io.File; import java.io.IOException; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.validation.BindException; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.SimpleFormController; import com.c2s.upload.model.FileUpload; import com.cloudinary.Cloudinary; import com.cloudinary.Transformation; import com.cloudinary.utils.ObjectUtils; public class FileUploadController extends SimpleFormController{ // Cloudinary cloud_name, API_Key and API_Secret private static final String CLOUDINARY_CLOUD_NAME = "XXXXXXXX"; private static final String CLOUDINARY_API_KEY = "XXXXXXXXXXXXXXX"; private static final String CLOUDINARY_API_SECRET = "XXXXXXXXXXXXXXXXXXXXX"; public FileUploadController(){ setCommandClass(FileUpload.class); setCommandName("fileUploadForm"); } @Override protected ModelAndView onSubmit(HttpServletRequest request,HttpServletResponse response, Object command, BindException errors) throws Exception { Cloudinary cloudinary = getCloudinaryClient(); FileUpload file = (FileUpload)command; MultipartFile multipartFile = file.getFile(); String fileName=""; Map<String, Object> cloudinaryURL = null; if(multipartFile!=null){ fileName = multipartFile.getOriginalFilename(); cloudinaryURL = uploadToCloudinary(cloudinary,multipartFile); } System.out.println("Clodinary URL: "+(String)cloudinaryURL.get("public_id")); // apply Transformation on the uploaded image and get the url from Cloudinary cloud String url = cloudinary.url().format("jpg").transformation(new Transformation().width(450).height(200).crop("fit").radius("max") .effect("sepia")).generate("mm_images/profile/"+multipartFile.getOriginalFilename().split("\\.", 3)[0]); System.out.println("Transformation URL: "+url); return new ModelAndView("FileUploadSuccess","url",url); } private static Cloudinary getCloudinaryClient() { return new Cloudinary(ObjectUtils.asMap( "cloud_name", CLOUDINARY_CLOUD_NAME, "api_key", CLOUDINARY_API_KEY, "api_secret", CLOUDINARY_API_SECRET, "secure", true)); } public static Map<String, Object> uploadToCloudinary(Cloudinary cloudinary,MultipartFile sourceFile)throws IOException { Map<String, Object> cloudinaryUrl = null; Map params = ObjectUtils.asMap("public_id", "mm_images/profile/"+sourceFile.getOriginalFilename().split("\\.", 3)[0]); // Convert multipart file type image to File type because Cloudinary doesn't accept multipart file type. File convFile = multipartToFile(sourceFile); try { @SuppressWarnings("unchecked") Map<String, Object> result = (Map<String, Object>)cloudinary.uploader().upload(convFile,params); cloudinaryUrl = result; } catch (IOException e) { System.out.println("Could not upload file to Cloundinary from MultipartFile " + sourceFile.getOriginalFilename()+ e.toString()); throw e; } return cloudinaryUrl; } private static File multipartToFile(MultipartFile image) throws IllegalStateException, IOException { File convFile = new File( image.getOriginalFilename()); image.transferTo(convFile); return convFile; } } |
5). FileUpload.java class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
package com.c2s.upload.model; import org.springframework.web.multipart.MultipartFile; public class FileUpload{ MultipartFile file; public MultipartFile getFile() { return file; } public void setFile(MultipartFile file) { this.file = file; } } |
6). FileUploadValidator.java class to validate the image upload –
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
package com.c2s.upload.validator; import org.springframework.validation.Errors; import org.springframework.validation.Validator; import com.c2s.upload.model.FileUpload; public class FileUploadValidator implements Validator{ @Override public boolean supports(Class clazz) { //just validate the FileUpload instances return FileUpload.class.isAssignableFrom(clazz); } @Override public void validate(Object target, Errors errors) { FileUpload file = (FileUpload)target; if(file.getFile().getSize()==0){ errors.rejectValue("file", "required.fileUpload"); } } } |
7). View Page –
The Spring’s form tag didn’t comes with any file upload tag (that’s weird). So, you have to declared the pure HTML file tag >input type=”file” /> manually. Furthermore, in the Spring’s form, define the form encoding attribute enctype=”multipart/form-data”, so that the browser will know how to handle the multipart file. In last, wrap some Spring’s form error tag to display the error message.
File: FileUploadForm.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <html> <head> <style> .error { color: #ff0000; } .errorblock{ color: #000; background-color: #ffEEEE; border: 3px solid #ff0000; padding:8px; margin:16px; } </style> </head> <body> <h2>Spring MVC image upload example using Cloudinary</h2> <form:form method="POST" commandName="fileUploadForm" enctype="multipart/form-data"> <form:errors path="*" cssClass="errorblock" element="div"/> Please select a file to upload : <input type="file" name="file" /> <input type="submit" value="upload" /> <span><form:errors path="file" cssClass="error" /></span> </form:form> </body> </html> |
8). If the file is uploaded successfully, display the uploaded file name.
File: FileUploadSuccess.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <body> <h2>Spring MVC image upload example using Cloudinary</h2> Status : <strong>Uploaded Successful. </strong><br/><br/> Transformed Image: <a href='${url}' target="_blank" style="color:blue">Click here</a><br/><br/> <img alt="TransformedImage" src='${url}' /> </body> </html> |
9). Demo –
URL: http://localhost:8080/SpringCloudinaryDemo/fileupload.htm
Render a file upload component.
Display the error message if user didn’t select a file to upload while clicking on the upload button.
Upload the image File from your computer/laptop
If file upload successful, display the transformed image file.
Also we can login to Cloudinary account to verify the uploaded image file –
If you want to explore more about Cloudinary and its integration with other platform, please go through following resources –
1). Architecture & Concepts –
http://cloudinary.com/documentation/architecture_and_concepts
2). Cloudinary Image Management –
http://cloudinary.com/documentation/upload_images
3). Cloudinary Image API –
http://cloudinary.com/documentation/image_upload_api_reference
4). Cloudinary Video Management –
http://cloudinary.com/documentation/video_management
5). Cloudinary Integration –
http://cloudinary.com/documentation/java_integration
6). Cloudinary Github –
Download the attached zip project.
springcloudinarydemo
Stay tuned for more updates!