06 February 2016

Spring-boot, MVC, Freemarker, dan Twitter-Bootstrap (Bag 1)

Pembaca yang budiman, meneruskan artikel sebelumnya tentang spring boot, mari kita lanjutkan latihan kita dengan menggunakan spring-boot dalam sebuah aplikasi web. Sebelumnya pada artikel yang lalu kita belum menggunakan salah satu fitur spring-boot yaitu embedded web server seperti jetty atau tomcat, sebab memang artikel yang lalu merupakan penerapan konsep sangat dasar penggunaan spring-boot. Kali ini kita akan menggunakan fitur tersebut dalam latihan kita.
Spring Framework merupakan sebuah framework yang populer dan banyak digunakan karena kemudahannya membuat sebuah aplikasi web dengan desain mvc (model, viewer, controller). Maka seharusnya akan menjadi lebih mudah juga bagi kita untuk membuat sebuah aplikasi web dengan design pattern MVC, dengan menggunakan spring framework ini. 
Langkah pertama yang akan kita lakukan adalah membuat sebuah aplikasi web yang bisa mengeluarkan output dengan format json sebagai service atau lebih dikenal dengan restful services. Dengan skenario ini diharapkan kita bisa memahami bagaimana struktur mvc pada sebuah aplikasi dengan menggunakan spring-boot. Langkah selanjutnya baru kita akan membungkus output tersebut dengan tampilan html dan styling halaman web yang lebih menarik.
Sebelum kita memulai, silahkan check-out dulu source code dari artikel sebelumnya di sini. Kita akan mengembangkan lebih lanjut source code sebelumya untuk lebih menghemat waktu. Untuk membuat sebuah aplikasi web dengan kerangka kerja (framework) menggunakan spring-boot, kita perlu menambahkan paket library ke dalam classpath development kita. Silahkan tambahkan baris-baris berikut ini dalam file pom.xml.
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>1.2.2.RELEASE</version>
</dependency>
Seperti yang sama-sama kita lihat baris-baris di atas, kita menambahkan paket library spring-boot-starter-web. Paket library tersebut adalah paket yang dibutuhkan untuk membuat sebuah aplikasi web dengan menggunakan spring framework. Dengan paket library tersebut kita sudah cukup untuk menjadikan aplikasi yang akan kita buat menjadi sebuah aplikasi web yang bisa berjalan di atas web server seperti tomcat, jetty, atau web server lainnya.
Langkah selanjutnya dari project kita kali ini, pada folder src/main/java pada source code tersebut, silahkan tambahkan package baru dengan nama controller dibawah packageorg.josescalia.blog.simple”, seperti gambar dibawah ini:
Pada package controller yang baru kita buat inilah nantinya kita akan menambahkan class controller yang berfungsi sebagai end-point url yang bisa kita panggil melalui browser pada saat aplikasi web kita sedang berjalan.
Kemudian buatlah sebuah class dalam package yang baru kita buat tadi dengan nama AuthorController, adapun isi dari class tersebut adalah sebagai berikut:
package org.josescalia.blog.simple.controller;

import org.josescalia.blog.simple.model.Author;
import org.josescalia.blog.simple.repository.AuthorRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;

/**
 * Created by josescalia on 03/02/16.
 */

@Controller
public class AuthorController {

    @Autowired
    public AuthorRepository authorRepository;

    @RequestMapping(value = "/author/list", method = RequestMethod.GET)
    public @ResponseBody List<Author> getList(){
        return (List<Author>) authorRepository.findAll();
    }

}
Mari kita bahas kode-kode diatas, perhatikan bahwa pada deklarasi class AuthorController tersebut, kita memberikan sebuah anotasi @Controller, ini menandakan bahwa nantinya pada saat aplikasi web ini dijalankan spring-framework akan memberikan tanda (me-register) bahwa kelas ini masuk dalam kelas controller dimana nantinya setiap pemanggilan url pada browser akan dicari mapping-nya di dalam class ini.
Kemudian perhatikan baris berikutnya yaitu deklarasi variabel authorRepository yang merupakan tipe data AuthorRepository, pada variabel tersebut kita memberikan anotasi @Autowired yang berarti memerintahkan kepada spring framework untuk membuat sebuah object siap pakai dengan nama variabel authorRepository pada saat aplikasi web pertama kali dijalankan (singleton). Seperti yang sama-sama kita tahu bahwa tipe data AuthorRepository merupakan sebuah class yang berfungsi menghubungkan aplikasi dengan database atau disebut juga dengan class DAO (Data Access Object). Dengan menggunakan anotasi @Autowired, maka variabel yang di buat dengan tipe data AuthorRepository tidak perlu lagi di inisialiasi sebagai object baru pada kelas AuthorController ini. Disanalah kekuatan spring framework sebenarnya, instansiasi object baru dilakukan pada saat aplikasi web pertama kali dijalankan, sehingga object tersebut sudah ada sejak pertama kali aplikasi dijalankan web, dan dia hidup di dalam life-cycle thread aplikasi web tersebut.
Kemudian perhatikan baris selanjutnya yaitu fungsi getList(); fungsi getList ini memiliki sebuah kembalian berupa ArrayList dari object data Author, object data Author yang berupa ArrayList ini akan ditulis ke dalam stream response body http request dan nantinya akan bisa ditampilkan di atas browser dengan format json. Fungsi tersebut juga memiliki anotasi @RequestMapping, yang berarti jika ada request pada browser dengan url address /author/list, maka fungsi ini akan dijalankan.
Untuk langkah selanjutnya kita akan memodifikasi sebuah class yang pernah kita buat sebelumnya, class ini merupakan class konfigurasi agar context aplikasi dari aplikasi web kita ini bisa dikenali dan terpakai dalam seluruh thread aplikasi, class yang akan kita buat tersebut adalah class DatabaseConfig yang ada dalam package org.josescalia.blog.simple.config. Modifikasi class tersebut menjadi seperti dibawah ini:
package org.josescalia.blog.simple.config;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.Properties;

/**
 * Created by josescalia on 06/03/15.
 */

@Configuration
public class DatabaseConfig{
    static Logger logger = Logger.getLogger(DatabaseConfig.class.getName());
    @Value("${spring.datasource.driver}")
    private String databaseDriver;
    @Value("${spring.datasource.url}")
    private String databaseUrl;
    @Value("${spring.datasource.hbm2ddl}")
    private String hbm2Ddl;
    @Value("${spring.datasource.username}")
    private String databaseUser;
    @Value("${spring.datasource.password}")
    private String databasePassword;
    @Value("${spring.datasource.dialect}")
    private String hibernateDialect;

    @Scope(value = "singleton")
    public DataSource getDataSource() {
        System.out.println("Setting datasource");
        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setDriverClassName(databaseDriver);
        ds.setUrl(databaseUrl);
        ds.setUsername(databaseUser);
        ds.setPassword(databasePassword);
        return ds;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(getDataSource());
        em.setPackagesToScan("org.josescalia.blog.simple.model");
        //
        final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(additionalProperties());
        return em;
    }

    @Bean
    public PlatformTransactionManager transactionManager(final EntityManagerFactory emf) {
        final JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(emf);
        return transactionManager;
    }

    final Properties additionalProperties() {
        logger.info("additional properties invoked");
        final Properties hibernateProperties = new Properties();
        hibernateProperties.setProperty("hibernate.hbm2ddl.auto", hbm2Ddl);
        hibernateProperties.setProperty("hibernate.dialect", hibernateDialect);
        return hibernateProperties;
    }
}
Kemudian kita set pula attribut-attribut class konfigurasi ini di dalam file application.properties yang ada pada folder src/main/resources. Class konfigurasi yang kita buat diatas sangat erat kaitannya dengan file application.properties, jika kita perhatikan kode-kode dalam class konfigurasi tersebut, beberapa properti yang dipakai di dalamnya kita ambil nilainya (value) dari file application.properties, berbeda sedikit dengan tulisan sebelumnya, pada latihan ini kita tidak lagi menggunakan metode 'hard-code' untuk pembuatan class konfigurasi ini. Keuntungan yang paling utama dengan tidak menerapkan metode hard-code adalah jika nanti setting-an database kita berubah, maka kita tidak perlu lagi mengkompilasi source-code kita menjadi binary kembali, tapi cukup dengan merubah nilai-nilai pada file application.properties tersebut. 
Untuk langkah selanjutnya, kita akan membuat class utama dari aplikasi web kita ini. Class yang akan kita buat ini hampir sama dengan class yang pernah kita buat sebagai class utama pada tutorial sebelumnya, hanya saja class ini kita buat bukan sebagai trigger mekanisme unit-test, melainkan sebagai class yang bisa kita eksekusi langsung sehingga aplikasi web kita bisa berjalan sesuai dengan harapan. Buatlah sebuah class dengan nama SpringApps dan letakkan dalam package org.josescalia.blog.simple sejajar dengan package model, repository, config, dan controller. Seperti gambar berikut ini:
Adapun isi dari class ini adalah sebagai berikut:
package org.josescalia.blog.simple;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.orm.jpa.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.stereotype.Component;
import java.io.IOException;

/**
 * Created by josescalia on 03/02/16.
 */

@Configuration
@ComponentScan(basePackages = {"org.josescalia.blog.simple"})
@EntityScan(basePackages = "org.josescalia.blog.simple.model")
@EnableJpaRepositories(basePackages = {"org.josescalia.blog.simple.repository"})
@EnableAutoConfiguration
@Component
public class SpringApps {
    public static void main(String[] args) throws IOException {
        SpringApplication application = new SpringApplication(SpringApps.class);
        application.run(args);
    }
}
Sampai disini aplikasi web yang menghasilkan output sebagai restful service kita sudah selesai. Sebelum kita menjalankan aplikasi web kita ini, kita harus menambahkan sebuah maven plugin ke dalam file pom.xml kita terlebih dahulu, plugin ini adalah plugin yang memungkinkan aplikasi kita bisa dijalankan dengan menggunakan perintah maven. Tambahkan baris-baris berikut ini dalam file pom.xml:
<profiles>
    <profile>
        <id>default</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>exec-maven-plugin</artifactId>
                    <version>1.2.1</version>
                    <executions>
                        <execution>
                            <goals>
                                <goal>java</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <mainClass>org.josescalia.blog.simple.SpringApps</mainClass>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>
Kemudian jalankan perintah maven seperti dibawah ini:
mvn clean install exec:java -DskipTests -Pdefault
Kemudian setelah tidak ada error ketika menjalankan perintah maven tersebut, bukalah browser kesayangan anda dan ketikkan url berikut ini pada browser http://localhost:8080/author/lists, bagaimana hasilnya?, saya seperti gambar dibawah ini, bagaimana dengan anda?
Nah artinya aplikasi web kita dengan spring-boot sudah berjalan, tapi tidak ada datanya?, tentu saja tidak ada datanya, kan memang belum kita isi datanya, silahkan anda isi datanya dalam database mysql anda. Jika saya mengiisikan seluruh data yang ada pada database saya, maka hasilnya tentu akan seperti gambar dibawah ini:



Sebagai catatan, url-url yang bisa kita panggil dalam browser tersebut adalah url-url yang kita definisikan di dalam controller, baik AuthorController maupun BookController. Spring web application context akan secara langsung mengarahkan request http tersebut ke fungsi-fungsi yang ada dalam controller berdasarkan anotasi @RequestMapping yang sudah kita buat sebelumnya. Dan output dituliskan dalam halaman web berupa format json karena kembalian dari fungsi-fungsi yang kita buat dalam controller memiliki anotasi @ResponseBody.
Eksekusi maven yang kita lakukan tadi juga membuat spring-boot mengenali bahwa aplikasi yang dijalankan merupakan aplikasi web, sehingga secara default, spring-boot akan menggunakan embedded tomcat untuk menjalankan aplikasi tersebut. Banyak hal lagi yang bisa kita pelajari ketika aplikasi web ini berjalan, clue dari saya adalah perhatikan log console dari spring-boot aplikasi web yang sudah kita eksekusi menggunakan maven tadi.

Sampai disini kita hentikan sejenak tutorial ini, untuk memberikan waktu agar kita bisa memahami lebih dalam langkah-langkah tutorial ini. Pada tulisan selanjutnya kita akan meneruskan kembali aplikasi web ini dengan melibatkan freemarker dan bootstrap sebagai template halaman aplikasi web-nya. Source-code yang bisa di checkout mungkin nanti akan saya sediakan dalam tulisan bagian ke 2 dari tutorial ini.
Semoga bermanfaat

Depok, 7 Februai 2016

Josescalia

No comments: