Spring MVC Internationalization


http://www.mkyong.com/spring-mvc/spring-mvc-internationalization-example/

http://stackoverflow.com/questions/5004652/spring-mvc-jsp-how-to-create-multilanguage-combo-with-country-list

http://stackoverflow.com/questions/6610510/spring-3-how-to-handle-multilanguage-url-with-same-content

Advertisements

Spring JNDI Datasource and Development Datasource


<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
		<property name="jndiName" value="com/dev/sss" />
		<property name="defaultObject" ref="developmentDataSource" />
	</bean>

	<!-- fall back datasource if JNDI look up of main datasource fails -->
	<bean id="developmentDataSource" class="org.apache.commons.dbcp.BasicDataSource"
		destroy-method="close">

		<property name="driverClassName" value="${jdbc.driverClassName}" />
		<property name="url" value="${jdbc.url}" />
		<property name="username" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />

		<property name="initialSize">
			<value>10</value>
		</property>
		<property name="maxActive">
			<value>0</value>
		</property>
		<property name="maxWait">
			<value>5000</value>
		</property>

	</bean>

Configure Log4j in Spring


Di mana kita harus menyimpan log output aplikasi kita? Tentunya kita ingin menggunakan lokasi yang dinamis sesuai dengan lokasi deployment. Misalnya, di Windows kita mungkin mendeploy aplikasi kita di

C:\Program Files\Apache Tomcat\webapps\aplikasi-saya

Sedangkan di Linux, kita mendeploy aplikasi di

/opt/apache-tomcat/webapps/aplikasi-saya

Dengan kemungkinan seperti di atas, bagaimana kita harus menulis konfigurasi log4j?
Mudah, bila kita menggunakan Spring MVC.

Kita bisa menggunakan Log4jConfigListener yang disediakan Spring. Class ini memungkinkan kita menggunakan variabel di konfigurasi log4j kita. Kita mendaftarkan class ini di dalam web.xml, sebelum ContextLoaderListener, seperti ini

    <listener>
        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
    </listener>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

Dengan adanya Log4jConfigListener ini, kita bisa menyebutkan lokasi konfigurasi log4j seperti ini :

    <context-param>
        <param-name>log4jConfigLocation</param-name>
        <param-value>classpath:artivisi-log4j.properties</param-value>
    </context-param>

Isi artivisi-log4j.properties terlihat seperti ini :

# Konfigurasi kategori
log4j.rootLogger=INFO,fileout

# File output
log4j.appender.fileout=org.apache.log4j.DailyRollingFileAppender
log4j.appender.fileout.file=${webapp.root.path}/WEB-INF/logs/application.log
log4j.appender.fileout.datePattern='.'yyyy-MM-dd
log4j.appender.fileout.layout=org.apache.log4j.PatternLayout
log4j.appender.fileout.layout.conversionPattern=%d [%t] %p (%F:%L) ­ %m%n

Perhatikan konfigurasi log4j.appender.fileout.file. Kita menggunakan variabel ${webapp.root.path} yang akan diisi dengan nilai lokasi deployment aplikasi web kita. Variabel ${webapp.root.path} ini didefinisikan dalam web.xml sebagai berikut :

<context-param>
        <param-name>webAppRootKey</param-name>
        <param-value>webapp.root.path</param-value>
</context-param>

Dengan konfigurasi ini, kita dapat meletakkan log output kita di

C:\Program Files\Apache Tomcat\webapps\aplikasi-saya\WEB-INF\logs\application.log

bila kita mendeploy di Windows, dan di

/opt/apache-tomcat/webapps/aplikasi-saya/WEB-INF/logs/application.log

bila kita deploy di Linux.

Konfigurasi di atas bisa disederhanakan lagi bila kita mengikuti nilai default yang disediakan Spring, yaitu cukup seperti ini dalam web.xml :

 

<listener>
        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
    </listener>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

Kemudian memberi nama file konfigurasi logger kita log4j.properties yang berada di top level dalam classpath, dan berisi seperti ini :

# Konfigurasi kategori
log4j.rootLogger=INFO,fileout

# File output
log4j.appender.fileout=org.apache.log4j.DailyRollingFileAppender
log4j.appender.fileout.file=${webapp.root}/WEB-INF/logs/application.log
log4j.appender.fileout.datePattern='.'yyyy-MM-dd
log4j.appender.fileout.layout=org.apache.log4j.PatternLayout
log4j.appender.fileout.layout.conversionPattern=%d [%t] %p (%F:%L) ­ %m%n

Nilai variabel ${webapp.root} secara default akan diisi dengan lokasi deployment tanpa harus mengkonfigurasi webAppRootKey

http://endy.artivisi.com/blog/java/log4j-spring-mvc/

Spring Decorator


Kemarin kita sudah membuat aplikasi sederhana yang memiliki tampilan list dan form. Tapi ada satu hal penting yang belum ada, yaitu header, footer, dan menu navigasi.

Ada beberapa cara untuk memasang header dan footer tanpa duplikasi kode. Cara paling sederhana tentunya dengan menggunakan include di setiap halaman. Contohnya kira-kira seperti ini.
personlist.html

#parse("header.html")

<table border="0" cellpadding="2" cellspacing="2">
	<tr>
		<th>Name</th>
		<th>Email</th>
		<th> </th>
	</tr>
	#foreach($person in $personList)
	<tr>
		<td>$person.Name</td>
		<td>$person.Email</td>
		<td><a href="personform?person_id=$person.Id">edit</a> | <a
			href="persondetail?person_id=$person.Id">view</a></td>
	</tr>
	#end
</table>

#parse("footer.html")

header.html

berisi kira-kira seperti ini

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>:: List of All Person ::</title>
  </head>

  <body>

dan
footer.html

</body>
</html>

Saya sendiri kurang suka dengan pendekatan seperti ini, karena:

* kita terpaksa membuat halaman html yang tidak lengkap. Di header.html tidak ada tutup body dan di footer.html tidak ada tag pembuka body.
* perintah include untuk header dan footer akan diulangi di setiap halaman.

Ada cara yang lebih baik, yaitu menggunakan decorator.

Pustaka decorator di Java cukup banyak, antara lain:

* SiteMesh
* Tiles
* Facelets

Tiles tadinya adalah decorator khusus untuk framework Struts. Tapi seiring dengan populernya penggunaan decorator, maka Tiles direfactor sehingga dapat berdiri sendiri tanpa Struts. Saat artikel ini ditulis, baik Tiles maupun penerusnya Tiles 2 cuma bisa digunakan untuk JSP. Jadi tidak bisa kita terapkan untuk aplikasi kita yang menggunakan Velocity.

Facelets bukan hanya sekedar decorator. Dia adalah teknologi templating untuk JSF. Jadi posisinya kurang lebih mirip dengan Velocity, yaitu template engine. Decorator hanyalah salah satu fitur tambahan Facelets. Sayangnya Facelets hanya bisa digunakan untuk JSF.

Sitemesh adalah decorator independen. Tidak terikat dengan framework apa-apa. Dia juga mendukung JSP, Freemarker, dan Velocity. Kita akan menggunakan SiteMesh pada artikel ini.

SiteMesh bekerja secara transparan. Pada saat membuat halaman aplikasi, kita bisa langsung coding seperti biasa. Tidak ada perubahan kode HTML di dalam template Velocity. Ketika dideploy, SiteMesh akan mencegat semua respon yang dikirim appserver ke browser dan menambahkan header dan footer.

Sebagai contoh,
personlist.html

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>:: List of All Person ::</title>
</head>
<body>

<table border="0" cellpadding="2" cellspacing="2">
	<tr>
		<th>Name</th>
		<th>Email</th>
		<th> </th>
	</tr>
	#foreach($person in $personList)
	<tr>
		<td>$person.Name</td>
		<td>$person.Email</td>
		<td><a href="personform?person_id=$person.Id">edit</a> | <a
			href="persondetail?person_id=$person.Id">view</a></td>
	</tr>
	#end
</table>

</body>
</html>

Seperti kita lihat, tidak ada kode khusus. Kodenya sama persis dengan artikel sebelumnya.

Ini adalah decoratornya, kita beri nama main.html.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

<link href="${base}/css/main.css" rel="stylesheet" type="text/css" />
<link href="${base}/css/layout.css" rel="stylesheet" type="text/css" />

<title>${title}</title>
</head>
<body>

<div id="header">
<h1>Hello Spring 2.5</h1>
<h2>Tutorial Spring 2.5 Annotation Configuration</h2>
</div>

<div id="top-bar">
<ul>
	<li>hola, endymuhardin</li>
	<li><a href="#">help</a></li>
	<li><a href="#">logout</a></li>
</ul>
</div>

<div id="menu-bar">
<ul>
	<li><a href="${base}/tutorial/personlist">manage person</a></li>
	<li><a href="#">generate report</a></li>
	<li><a href="#">prevent global warming</a></li>
</ul>
</div>

<div id="main">

<div id="sidebar">

<h1>Manage Person</h1>
<ul>
	<li><a href="${base}/tutorial/personform">add person</a></li>
	<li><a href="${base}/tutorial/personlist">list of person</a></li>
</ul>

</div>

<div id="content">

${body}

</div>

</div>

<div id="footer">

<div id="copyright">Copyright &copy; 2008 :: ArtiVisi Intermedia
::</div>

<div id="company-logo">Company Logo</div>

</div>
</body>
</html>

Ada beberapa tag khusus yang digunakan dalam decorator kita, yaitu

* ${base}
* ${title}
* ${body}

Ini adalah variabel yang disediakan SiteMesh untuk kita. ${base} adalah path menuju aplikasi web kita. Kita menggunakan ${base} untuk membuat URL yang lengkap. Variabel ini sangat berguna agar aplikasi kita bisa dideploy ke berbagai context.

Pada saat mendekorasi, SiteMesh akan membaca respon HTML yang dikeluarkan appserver dan mengambil isi tag title dan body, kemudian memasangnya di tempat kita menaruh tag ${title} dan ${body}. Setelah itu, barulah keseluruhan respon yang sudah didekorasi akan dikirim ke client.

Kita sudah punya halaman yang akan ditampilkan (personlist.html) dan decoratornya (main.html). Untuk menggabungkan keduanya, kita harus memasang SiteMesh sebagai Servlet Filter. Servlet Filter memiliki kemampuan untuk mencegat baik request maupun response. Kita mendaftarkan filter di web.xml. Berikut deklarasi filter SiteMesh berikut mappingnya.

<filter>
  <filter-name>sitemesh</filter-name>
  <filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
</filter>	

<filter-mapping>
  <filter-name>sitemesh</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

Selain itu, kita juga perlu memasang servlet SiteMesh. Servlet ini yang akan mencegat semua pemanggilan template velocity, yaitu semua file yang berakhiran *.html. Berikut adalah deklarasi servlet berikut mappingnya.

<servlet>
  <servlet-name>sitemesh-velocity</servlet-name>
  <servlet-class>com.opensymphony.module.sitemesh.velocity.VelocityDecoratorServlet</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>sitemesh-velocity</servlet-name>
  <url-pattern>*.html</url-pattern>
</servlet-mapping>

Selanjutnya, kita harus memberi tahu SiteMesh di mana kita meletakkan decorator dan URL apa saja yang ingin didekorasi. Biasanya kita punya beberapa decorator yang berbeda untuk (misalnya):

* halaman utama. Lengkap dengan menubar, header, dan footer
* halaman login. Tanpa menubar, header, dan footer
* tampilan siap print. Tanpa warna-warni.

Sebagai contoh, kita cuma akan menggunakan satu decorator, yaitu main.html. Decorator ini berlaku untuk semua request. Berikut konfigurasinya.

<decorators defaultdir="/WEB-INF/decorators">
  <decorator name="default" page="main.html">
    <pattern>/*</pattern>
  </decorator>
</decorators>

File ini diletakkan di dalam folder WEB-INF, bersama-sama dengan web.xml.

Pada konfigurasi decorator tersebut, kita jelaskan bahwa semua request (/*) akan dicegat dan didekorasi dengan main.html yang ada di folder /WEB-INF/decorators.

Terakhir, kita lengkapi pustaka yang dibutuhkan. Jar yang dibutuhkan adalah:

* sitemesh.jar
* commons-digester.jar
* velocity-tools-view.jar

Perhatikan bahwa velocity-tools-view.jar ini sudah mengandung velocity-tools-generic.jar yang kita gunakan pada artikel sebelumnya. Jadi pastikan bahwa kita tidak lupa membuang velocity-tools-generic.jar.

Selesai sudah. Mudah bukan?

Contoh ini sudah dipublish di GoogleCode, Anda bisa mengunduh:

* keseluruhan project folder
* File *.war yang siap deploy
* File *.jar yang siap dijalankan secara standalone

Atau Anda juga bisa menggunakan Subversion untuk menarik keseluruhan project folder, dengan perintah:

svn export http://hello-spring-25.googlecode.com/svn/trunk/ hello-spring-25-read-only

Setelah project folder diperoleh, dibutuhkan database MySQL dengan konfigurasi sebagai berikut:

* nama database : belajar
* username : belajar
* password : java

Tabel T_PERSON yang digunakan pada contoh ini dapat dibuat dengan menggunakan script sql yang ada di folder src/sql/mysql-schema.sql.

Untuk menjalankan aplikasi ini, dibutuhkan Ant 1.7.0 dan Java 6. Cukup ketik ant run di konsol. Kemudian browse ke http://localhost:8080/

Selamat mencoba

LazyInitializationException: could not initialize proxy-the owning Session was closed


Solution 1

You have a classic case of LIE – Lazy Initialization error. This topic has been discussed so many times that I suggest to do a search on the forum and point to the hibernate documentation. Basically, you are using lazy relationships that require an open session (so the lazy loading can happen). Inside Spring you can use OpenSessionInViewFilter/Interceptor or the HibernateInterceptor to keep a Hibernate session open during a request or method calls.

Solution 2

@Entity

@Table(name=”gis_point”)

@org.hibernate.annotations.Proxy(lazy=false)

Entity {

}

http://forum.springsource.org/showthread.php?t=27993

http://www.myeclipseide.com/PNphpBB2-viewtopic-t-12830.html

http://stackoverflow.com/questions/345705/hibernate-lazyinitializationexception-could-not-initialize-proxy

autowiring properties value


<context:property-placeholder location="classpath*:*.properties" />

<bean id="clientPreferencesManager" class="pl.bildpresse.bildchat2.business.ClientPreferencesManager" >
    <property name="clientApiUrl" value="${clientapi.url}" />
</bean>
Spring 3.x
@Repository
public class RewardsTestDatabase {
    //property
    @Value("${jdbc.database.name}")
    public void setDatabaseName(String dbName) { ... }

    //expresion
    @Value("#{strategyBean.databaseKeyGenerator}")
    public void setKeyGenerator(KeyGenerator kg) { ... }
}


Spring 2.5
@Autowired
@Qualifier("${clientapi.url}")
public void setClientApiUrl(String clientApiUrl) {
    this.clientApiUrl = clientApiUrl;
}
@Repository
public class RewardsTestDatabase {

    @Value("#{systemProperties.databaseName}")
    public void setDatabaseName(String dbName) { ... }

    @Value("#{strategyBean.databaseKeyGenerator}")
    public void setKeyGenerator(KeyGenerator kg) { ... }
}