Kotlin Stream Image from Database

Many web applications allow users to store images for later. For example, you may want to allow users to upload a profile picture that gets displayed later on in the application. This post demonstrates how to upload an image to a web application and store the image in a database. Then we will see how to display that image in a browser.

PersistedImage

The key to storing an image in a database is to use @Lob annotation in JPA and make the datatype as a byte array. Here is an example class that stores byte array in the database.

@Entity
data class PersistedImage(@field: Id @field: GeneratedValue var id : Long = 0,
                          //The bytes field needs to be marked as @Lob for Large Object Binary
                          @field: Lob var bytes : ByteArray? = null,
                          var mime : String = ""){

    fun toStreamingURI() : String {
        //We need to encode the byte array into a base64 String for the browser
        val base64 = DatatypeConverter.printBase64Binary(bytes)

        //Now just return a data string. The Browser will know what to do with it
        return "data:$mime;base64,$base64"
    }

Kotlin has a ByteArray class. In Java you would use byte []. The effect is the same either way. When persistence provider scans this class, it will store the byte array as a Lob in the database. Nevertheless it’s not enough to simply store an image in the database. At some point in time, the user will most likely wish to see the image. That’s there the toStreamingURI() method comes in handy.

The first line uses DatatypeConverter to convert the byte array to a base64 string. Then we can append that string to “data:[mime];base64,[base 64]”. In our example, we use Kotlin’s String template feature to build such a String. We start with the data: followed by the mime (such as /img/png). Then we can add the base64 string created by DatatypeConverter. This string can get added to the src attribute of the html img tag as shown in the screen shot below.

base64string
The browser knows how to display this string as an image.

File Uploads

It’s worth while to discuss how files are upload in Spring. Spring has a MultipartFile class that can get mapped to the a file upload input tag in the form. Here is how it looks in the HTML code.
fileuploadform
There are a couple of things that are critical for this to work. First, we have to set our applications.properties file to allow large file uploads.

spring.http.multipart.max-file-size=25MB
spring.http.multipart.max-request-size=25MB

Next our form tag has to set the enctype attribute to “multipart/form-data”. Finally we have to keep track of the name attribute on our input tag so that we can map it to the server code. In our example, our input tag has it’s name attribute set to “image”.

On the server end, we use this code get an instance of MultipartFile.

@RequestMapping(method = arrayOf(RequestMethod.POST))
    fun doPost(
            //Grab the uploaded image from the form
            @RequestPart("image") multiPartFile : MultipartFile,
               model : Model) : String {
        //Save the image file
        imageService.save(multiPartFile.toPersistedImage())
        model.addAttribute("images", imageService.loadAll())
        return "index"
    }

We annotate the multipartFile parameter with @RequestPart and pass to the annotation the same name attribute that we set on our input tag. At this point, the container will inject an instance of MultipartFile that represents the file that the user uploaded to the server. The MultipartFile class has two attributes that are critical to our purposes. First it has a byte array property that represents the bytes of the uploaded file and it has the file’s MIME.

We can use Kotlin’s extension functions to add a toPersistedImage() method on MutlipartFile.

fun MultipartFile.toPersistedImage() = PersistedImage(bytes = this.bytes, mime = this.contentType)

This method simply returns an instance of PersisitedImage that can get stored in the database. At this point, we can easily store and retrieve the image from the database.

Application

The demonstration application is a regular Spring MVC application written in Kotlin. You can refer to this post on an explanation on how this works. Here is the Kotlin code followed by the HTML code.

Kotlin Code

package com.stonesoupprogramming.streamimage

import org.hibernate.SessionFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.stereotype.Controller
import org.springframework.stereotype.Repository
import org.springframework.stereotype.Service
import org.springframework.ui.Model
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.web.bind.annotation.RequestPart
import org.springframework.web.multipart.MultipartFile
import javax.persistence.*
import javax.transaction.Transactional
import javax.xml.bind.DatatypeConverter

@SpringBootApplication
class StreamImageDbApplication

fun main(args: Array) {
    SpringApplication.run(StreamImageDbApplication::class.java, *args)
}

@Entity
data class PersistedImage(@field: Id @field: GeneratedValue var id : Long = 0,
                          //The bytes field needs to be marked as @Lob for Large Object Binary
                          @field: Lob var bytes : ByteArray? = null,
                          var mime : String = ""){

    fun toStreamingURI() : String {
        //We need to encode the byte array into a base64 String for the browser
        val base64 = DatatypeConverter.printBase64Binary(bytes)

        //Now just return a data string. The Browser will know what to do with it
        return "data:$mime;base64,$base64"
    }
}

//This is a Kotlin extension function that turns a MultipartFile into a PersistedImage
fun MultipartFile.toPersistedImage() = PersistedImage(bytes = this.bytes, mime = this.contentType)

@Configuration
class DataConfig {

    @Bean
    fun sessionFactory(@Autowired entityManagerFactory: EntityManagerFactory) :
             SessionFactory = entityManagerFactory.unwrap(SessionFactory::class.java)
}

@Repository
class ImageRepository(@Autowired private val sessionFactory: SessionFactory){

    fun save(persistedImage: PersistedImage) {
        sessionFactory.currentSession.saveOrUpdate(persistedImage)
    }

    fun loadAll() = sessionFactory.currentSession.createCriteria(PersistedImage::class.java).list() as List
}

@Transactional
@Service
class ImageService(@Autowired private val imageRepository: ImageRepository){

    fun save(persistedImage: PersistedImage) {
        imageRepository.save(persistedImage)
    }

    fun loadAll() = imageRepository.loadAll()
}

@Controller
@RequestMapping("/")
class IndexController(@Autowired private val imageService: ImageService){

    @RequestMapping(method = arrayOf(RequestMethod.GET))
    fun doGet(model : Model) : String {
        model.addAttribute("images", imageService.loadAll())
        return "index"
    }

    @RequestMapping(method = arrayOf(RequestMethod.POST))
    fun doPost(
            //Grab the uploaded image from the form
            @RequestPart("image") multiPartFile : MultipartFile,
               model : Model) : String {
        //Save the image file
        imageService.save(multiPartFile.toPersistedImage())
        model.addAttribute("images", imageService.loadAll())
        return "index"
    }
}

application.properties

spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext
spring.datasource.driver-class-name=org.hsqldb.jdbcDriver

spring.http.multipart.max-file-size=25MB
spring.http.multipart.max-request-size=25MB

index.html

streamimage

Conclusion

Spring and Kotlin make it easy to embed images in a database and display those images in a browser. The main take away is to define a byte array property as a Lob on persisted image and then convert it to a base64 String when you wish to display it. Here are some screen shots of the working application.


You can get the source code for this project at my GitHub here or watch the video tutorial on YouTube.

Advertisement

One thought on “Kotlin Stream Image from Database”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: