Skip to Content

1. Introduction 

This blog is about the image upload and retrieval approach in SAP cloud platform through Spring based restful services, The image can be profile pics or some some thumbnail, which end users or client need to store in database along with the user information. So, instead of storing in UI application as folder structure or by any other mechanism, using this way we can store the images in the form of binary object in database along with the other information, Which we can retrieve while fetching the other information Like we have requirement that we have products thumbnail needs to upload real time along with the other product information and also customer can upload new thumbnail images, So instead of storing in the UI folder or server, we can upload the same in the database and use it whenever needs to retrieve along with the product details. It will be stored as blob object or clob object form in database.

2. Prerequisite Activities

The prerequisites in two part, the 1st part would be the SAP UI5 app and in the 2nd part backend services along with the database can be covered.

PART-1: UI5 APP

  • Create SAPUI5 app:

The UI5 app explained  here is being used to upload and fetch the image and to explain through UI, how images feature can be used in UI5 by using the FileUploader control.

In any UI5 application includes 5 files namely

  • html
  • js – route to given JS view
  • controller.js – server call for data manipulation
  • view.xml – View logic and SAP UI5 controls
  • xs-app.json – application routing from UI to backend services

As mentioned above the code will be shown below along with the web project snapshots

Index.html

Component.js

Controller.controller.js

View.view.xml

xs-app.json

The above file can be part of one web folder basically in the resource folder and the xs-app.json file be part of the main project which will be used to route the request of server for uploading and retrieving of the images or thumbnails images. You can check the details project structure and files being used in the application in the github account. The apps can be deployed in SAP cloud foundry platform as the mentioned app is being developed and evaluated in SAP cloud foundry account.

PART-2: Java Services & Database

  • Create and build JPA Project: You can refer my previous log series regarding project setup  blog series.
  • Get dependent Library:

In addition to the existing api added in previous blogs pom.xml, following api must be added

 

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

Here we need to use this jar as the file upload is of multipart and for that we need to use this API to upload image as multipart data type.

3. Configuration and Implementation

3.1 Configure persistence.xml in JPA model: Refer to my previous blog series log series for this section.

3.1.1 Configure resource.xml in JPA model: Refer to my previous blog series for this section

4. Adding the spring-servlet.xml file under WEB-INF folder: Refer to my previous blog series for this section.

Along with the above-mentioned content in spring-servlet following code needs to be added in spring-servlet.xml

As shown in the above snapshot that the minimum & maximum upload sizes are defined. Beyond that, will throws an exception.

4.1. Spring-servlet has to be included in web.xml file, code snippet has to added : Refer to my previous blog series for this section.

4.2. Now create class where using JPAEntitymanager establish a connection, basically to connect to database.

@RestController
@RequestMapping("/v1/internal")
public class ImageMgmtService {
final static Logger LOGGER = LoggerFactory.getLogger(ImageMgmtServiceImpl.class);	
	private ImageMgmtServiceImpl imageServiceImpl = new ImageMgmtServiceImpl();
	EntityManagerFactory emf ;
	@InitBinder
	public void initBinder(WebDataBinder dataBinder){		
	dataBinder.setDisallowedFields();
	}	
	@PersistenceUnit
	public void setEntityManagerFactory(EntityManagerFactory emf) {
		this.emf = emf;	}	
	@RequestMapping(value = "/uploadImage", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
	public ResponseEntity<ImageManagementServiceResponse> getuploadImage(@RequestParam("file") MultipartFile file,
	@RequestParam("file-data") String data) throws JSONException {
		JSONObject obj = new JSONObject(data);
		Integer mappingGuid = (Integer) obj.get("mapping_Guid");
		return imageServiceImpl.uploadImage(file, mappingGuid , emf);
	}
	@RequestMapping(value = "/fetchImage/{guid}", method = RequestMethod.GET)
	public ResponseEntity fetchImage(@PathVariable("guid") String mappingGuid )  
	{
		return imageServiceImpl.fetchImage(mappingGuid, emf);}
}

As shown above the image object accepted in the requestParam as multipart data.

public class ImageMgmtServiceImpl {

	final static Logger LOGGER = LoggerFactory.getLogger(ImageMgmtServiceImpl.class);
	HttpStatus statusCode = null;
	EntityManagerFactory emf;
	public ResponseEntity<ImageManagementServiceResponse> uploadImage(MultipartFile file, Integer mappingGUID,
		EntityManagerFactory emf) {
		this.emf = emf;
		return doUploadImage(file, mappingGUID);
	}
	private ResponseEntity<ImageManagementServiceResponse> doUploadImage(MultipartFile file, Integer mappingGuid) {
		EntityManager em = this.emf.createEntityManager();
		HttpHeaders httpHeaders = new HttpHeaders();
		ImageManagementServiceResponse response = null;
		try {
			String EVENT_IDENTFIER = "com.sap.sample::IMAGE_MANAGEMENT.IMAGE_STORE";
			String eventIdentificationCall = "INSERT INTO \"" + EVENT_IDENTFIER + "\" VALUES (?,?,?)";
			em.getTransaction().begin();
			Query query = em.createNativeQuery(eventIdentificationCall);
			query.setParameter(1, mappingGuid);
			query.setParameter(2, file.getContentType());
			query.setParameter(3, file.getBytes());
			int records = query.executeUpdate();
			LOGGER.info("The image has been uploaded" + records);
			em.getTransaction().commit();
			response = new ImageManagementServiceResponse();
			response.setGuid(mappingGuid + "");
			response.setLevel("1");
			response.setSuccess(true);
			return new ResponseEntity<ImageManagementServiceResponse>(response, httpHeaders, HttpStatus.OK);
		} catch (Exception ex) {
			if ((em != null) && (em.isOpen() == true)) {
				em.close();
			}
			response = new ImageManagementServiceResponse();
			response.setGuid(mappingGuid + "");
			response.setLevel("0");
			response.setSuccess(false);
			response.setReasonType(0);
			response.setReasonDescription("Image cannot be uploaded");
			LOGGER.error("tenantName: " + ",Upload image failed : " + ex.getMessage());
			return new ResponseEntity<ImageManagementServiceResponse>(response, httpHeaders, HttpStatus.OK);
		} finally {
			if (em != null) {
				em.close();
			}
		}
	}
	public ResponseEntity fetchImage(String guid, EntityManagerFactory emf) {
		return doFetchImage(guid, emf);
	}
	private ResponseEntity doFetchImage(String guid, EntityManagerFactory emf) {
		EntityManager em = emf.createEntityManager();
		em.getTransaction().begin();
		try {
			String fetchCall = "com.sap.sample::IMAGE_MANAGEMENT.IMAGE_STORE";
			String eventIdentificationCall = "SELECT * FROM \"" + fetchCall + "\"  WHERE IMAGE_ID = ?";
			Query query = em.createNativeQuery(eventIdentificationCall, ImageOutput.class);
			query.setParameter(1, guid);
			ImageOutput imo = (ImageOutput) query.getSingleResult();
			byte[] image = imo.getImageBinary();
			HttpHeaders httpHeaders = new HttpHeaders();
			httpHeaders.add("Content-Type", imo.getImageMime());
			httpHeaders.add("Cache-Control", "max-age=259200");
			em.getTransaction().commit();

			return new ResponseEntity(image, httpHeaders, HttpStatus.OK);

		} catch (Exception ex) {
			try {
				File file = new File(getClass().getClassLoader().getResource("default-image.png").getFile());
				HttpHeaders httpHeaders = new HttpHeaders();
				httpHeaders.add("Content-Type", "image/png");
				byte[] image = IOUtils.toByteArray(new FileInputStream(file));
				LOGGER.error("tenantName: " + ",Upload fetch failed : " + ex.getMessage());
				return new ResponseEntity(image, httpHeaders, HttpStatus.OK);
			} catch (Exception e) {
				HttpHeaders httpHeaders = new HttpHeaders();
				LOGGER.error("tenantName: " + ",Upload fetch failed : " + ex.getMessage());
				return new ResponseEntity(httpHeaders, HttpStatus.BAD_REQUEST);
			}
		}
	}
}

As above mentioned in snapshot that there are two method, first method is used to store the image as binary object into the database. Second method is used to fetch the image from database.

Along with the above class there is POJO class is set as response object to return the response of BLOB object in the byte [] array format, as shown below

public class ImageManagementServiceResponse {

	private byte[] image;
	private String level;
	private String guid;
	private Boolean success;	
	private Integer reasonType;	
	private String reasonDescription;	
	private Object data;
	
      // setter and getter method needs to be generated here
}

In the above code base, we have class, the service and the service Implementation class. In service class the upload image or files can be read and then in the implementation class, the actual business logic is mentioned to upload and retrieve of the images.

5. Entity class addition for the JPA implementations

As shown below the JPA class for persistence

@Entity
@Table(name="\"com.sap.sample::IMAGE_MANAGEMENT.IMAGE_STORE\"")
public class ImageStorage implements Serializable{

	private static final long serialVersionUID = 4829386985899147977L;

	@Id
	@Column(name="IMAGE_ID")
	private String imageId = null;

	@Lob
	@Column(name = "IMAGE_BINARY")
	private byte[] imageBinary = null;
	
	@Column(name = "IMAGE_MIME_TYPE")
	private String imageMimeType = null;

	public String getImageId() {
		return imageId;
	}

	public void setImageId(String imageId) {
		this.imageId = imageId;
	}

	public String getImageMimeType() {
		return imageMimeType;
	}

	public void setImageMimeType(String imageMimeType) {
		this.imageMimeType = imageMimeType;
	}

	public static long getSerialversionuid() {
		return serialVersionUID;
	}

	public byte[] getImageBinary() {
		return imageBinary;
	}

	public void setImageBinary(byte[] imageBinary) {
		this.imageBinary = imageBinary;
	}

This implementation will deal with any type of binary content, It can be doc, pdf etc. The Entity class needs to be added into the persistence.xml file. The annotation @Lob has to added for the column which mapped to byte [] columns as it bind with the binary content.

6. Database design

As shown above the IMAGE_BINARY fields stores the image object in the blob format. The above database field might change based on the requirement. In my case I have tried to show only for the image content save as blob object, it can be added for any number of fields and any type of content that can be stored as binary content.

7. Conclusion

This blog is about implementation of binary content and retrieval through Spring MVC from database, Of course there is a documentation and numerous materials about image processing or storing using spring MVC in the database, Here I have explained about the end to end integration from UI to back-end, along with the database binding mechanism. It’s an attempt for persisting binary object in db. With the above approach, we can implement how to store any image content in the form of binary or blob object into database.

Few of my other blog post refer below the links.

Blog Series:ODATA Protocol implementation for IOT Applications on SAP HCP

Binary content upload and download from HANA DB through Apache Olingo OData in SAP CF

CDS extension feature in HANA

Logging in HCP Cloud foundry with Java and Tomee using slf4j, logback, Jolokia

To report this post you need to login first.

2 Comments

You must be Logged on to comment or reply to a post.

  1. Fabian Lehmann

    Hi  Rajnish,

    you posting this blog in the SAP CP IoT CloudFoundry space, i think thats the wrong place for this.

    It´s possible to move the blog in the right one?

     

    br,

    Fabian

     

     

    (0) 

Leave a Reply