tag:blogger.com,1999:blog-50971008015815435282024-03-18T17:13:35.879+08:00krams::"freely you receive, freely you give"Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.comBlogger166125tag:blogger.com,1999:blog-5097100801581543528.post-7335402518718409232013-04-05T04:04:00.000+08:002013-04-05T04:05:18.676+08:00Book Review: Spring Security 3.1I haven't written any tutorials for my blog since December because of a new job I just got in Chicago. And today I won't be sharing any new tutorials as well. But don't despair because I will be sharing my review of another Spring book: <b>Spring Security 3.1</b> by <i>Robert Winch</i> and <i>Peter Mularien</i> and published by <i>Packt Publishing</i>. You can find the book at <a href="http://www.packtpub.com/spring-security-3-1/book">http://www.packtpub.com/spring-security-3-1/book</a> for $25.49. <br />
<br />
<a href="http://dgdsbygo8mp3h.cloudfront.net/sites/default/files/imagecache/productview_larger/8260OS_Spring%20Security%203.1.jpg" imageanchor="1" ><img border="0" src="http://dgdsbygo8mp3h.cloudfront.net/sites/default/files/imagecache/productview_larger/8260OS_Spring%20Security%203.1.jpg" style="float:left; margin-right: 15px"/></a> It may sound that I'm selling, but I'm not. I'm actually promoting this book because it's a great reference that will help all developers regardless of expertise. In addition, the book is written by Robert, the project lead for Spring Security and by Peter, the author of the Spring Security 3 book. That means you're getting your information from the source and experts!<br />
<br />
<b>What's good about this book?</b><br />
The book is fully packed with information regarding various aspects of Spring Security and integration steps with different scenarios, such as:<br />
<br />
<br />
<ul><li>Basic Spring Security configuration</li>
<li>OpenID integration</li>
<li>Access Control List (ACL)</li>
<li>JDBC-based configuration</li>
<li>Remember-me services</li>
<li>LDAP-based authentication</li>
<li>Single Sign-on services</li>
<li>JSF and GWT integration</li>
<li>and many more</li>
</ul><br />
I like how the introduction starts with a fictitious company and enumerates the reasons why you may need to secure an unsecured application. There's an index that shows how to load the sample projects in STS and configure Tomcat along with SSL. If you have read the previous <i>Spring Security 3</i> book, you might find the contents somewhat similar. <br />
<br />
For me the most interesting chapters are <i>Chapter 3: Custom Authentication</i> and <i>Chapter 10: Fine-grained Access Control</i> because both chapters provide information on how to adapt Spring Security to match any project requirements.<br />
<br />
<b>What's bad about this book?</b><br />
I believe the glaring problem of this book is it doesn't describe a whole project in any of its chapters. Mostly the chapters are focus on each aspect of Spring Security. They are detailed, but it's hard to see the overview or the general outlook of the chapter. Maybe because I'm used to the way I present my blog, and I prefer to have a full project laid out. Then describe each section part-by-part. Though there are samples in the book, but it's up to the reader to comprehend the whole project. But overall, this book is a great reference. Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com235tag:blogger.com,1999:blog-5097100801581543528.post-49878629810153814292012-12-10T21:33:00.003+08:002012-12-21T10:21:03.496+08:00Spring Social with JavaConfig (Part 1)In this tutorial, we will create an application that can post messages and retrieve profile information from Facebook and Twitter. We will use <i>Spring Social</i> to implement these features. To secure our application we will use Spring Security, and to manage our views, we will use Thymeleaf.<br />
<br />
<h2 class="explanation" style="padding-left:5px;">Table of Contents</h2><div class="explanation">Click on a link to jump to that section:<br />
<ol><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-1.html">Functional Specs</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-2.html">Generate OAuth keys</a></li>
<ul><li style="margin:0; padding: 0">Facebook</li>
<li style="margin:0; padding: 0">Twitter</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-3.html">Spring Social configuration</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-4.html">Spring Security configuration</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-5.html">JavaConfig</a></li>
<ul><li style="margin:0; padding: 0">ApplicationInitializer.java</li>
<li style="margin:0; padding: 0">ApplicationContext.java</li>
<li style="margin:0; padding: 0">DataConfig.java</li>
<li style="margin:0; padding: 0">ThymeleafConfig.java</li>
<li style="margin:0; padding: 0">spring.properties</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-6.html">View with Thymeleaf</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-7.html">Layers</a></li>
<ul><li style="margin:0; padding: 0">Domain</li>
<li style="margin:0; padding: 0">Repository</li>
<li style="margin:0; padding: 0">Service</li>
<li style="margin:0; padding: 0">Controller</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-8.html">Running the application</a></li>
<ul><li style="margin:0; padding: 0">Clone from GitHub</li>
<li style="margin:0; padding: 0">Create the Database</li>
<li style="margin:0; padding: 0">Run with Maven and Tomcat 7</li>
<li style="margin:0; padding: 0">Run with Maven and Jetty 8</li>
<li style="margin:0; padding: 0">Import to Eclipse</li>
<li style="margin:0; padding: 0">Validate with W3C</li>
</ul></ol></div><br />
<h2 class="explanation" style="padding-left:5px;">Dependencies</h2><div class="explanation">These are the main Maven dependencies:<br />
<ul><li style="margin:0; padding: 0">Spring 3.2.0.RELEASE</li>
<li style="margin:0; padding: 0">Spring Data JPA 1.2.0.RELEASE</li>
<li style="margin:0; padding: 0">Spring Security 3.1.3.RELEASE</li>
<li style="margin:0; padding: 0">Thymeleaf 2.0.14</li>
<li style="margin:0; padding: 0">Hibernate 3.6.3.Final</li>
<li style="margin:0; padding: 0">See <a href="https://github.com/krams915/spring-social-javaconfig/blob/master/pom.xml">pom.xml</a> for full details</li>
</ul></div><br />
<h2 class="explanation" style="padding-left:5px;">Required Tools</h2><div class="explanation">These are the minimum required tools:<br />
<ul><li style="margin:0; padding: 0">Git</li>
<li style="margin:0; padding: 0">Maven 3.0.4</li>
<li style="margin:0; padding: 0">MySQL</li>
<li style="margin:0; padding: 0">Eclipse IDE or SpringSource Tool Suite (STS)</li>
</ul></div><br />
<h2 class="explanation" style="padding-left:5px;">GitHub Repository</h2><div class="explanation">There are two versions of the application: a JavaConfig-based and an XML config-based app. Both versions are identical in their feature set.<br />
<ul><li style="margin:0; padding: 0"><a href="https://github.com/krams915/spring-social-javaconfig">spring-social-javaconfig</a></li>
<li style="margin:0; padding: 0"><a href="https://github.com/krams915/spring-social-xmlconfig">spring-social-xmlconfig</a></li>
</ul></div><br />
<h1>Functional Specs</h1><hr/>Our application's requirements are the following:<br />
<ul><li style="margin:0; padding: 0">Post to Facebook and Twitter</li>
<li style="margin:0; padding: 0">Retrieve profile information from Facebook and Twitter</li>
<li style="margin:0; padding: 0">Secure the application</li>
<li style="margin:0; padding: 0">Allow login and creation of new users</li>
<li style="margin:0; padding: 0">Create a page for managing users</li>
</ul><br />
Here's our <i>Use Case</i> diagrams:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://yuml.me/diagram/scruffy;/usecase/%5BUser%5D-(Post%20to%20Facebook),%20%5BUser%5D-(Post%20to%20Twitter),%20%5BUser%5D-(Retrieve%20info%20from%20Facebook),%20%5BUser%5D-(Retrieve%20info%20from%20Twitter),%20%5BUser%5D-(Sign%20in),%20%5BUser%5D-(Sign%20up).png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="643" width="437" src="http://yuml.me/diagram/scruffy;/usecase/%5BUser%5D-(Post%20to%20Facebook),%20%5BUser%5D-(Post%20to%20Twitter),%20%5BUser%5D-(Retrieve%20info%20from%20Facebook),%20%5BUser%5D-(Retrieve%20info%20from%20Twitter),%20%5BUser%5D-(Sign%20in),%20%5BUser%5D-(Sign%20up).png" /></a></div><br />
<pre style="display: none;">[User]-(Post to Facebook)
[User]-(Post to Twitter)
[User]-(Retrieve info from Facebook)
[User]-(Retrieve info from Twitter)
[User]-(Sign in)
[User]-(Sign up)
//http://yuml.me/
</pre><br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://yuml.me/diagram/scruffy;/usecase/%5BAdmin%5D-(Edit%20users),%20%5BAdmin%5D-(Delete%20users),%20%5BAdmin%5D-(Add%20users).png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="301" width="384" src="http://yuml.me/diagram/scruffy;/usecase/%5BAdmin%5D-(Edit%20users),%20%5BAdmin%5D-(Delete%20users),%20%5BAdmin%5D-(Add%20users).png" /></a></div><br />
<pre style="display: none;">[Admin]-(Edit users)
[Admin]-(Delete users)
[Admin]-(Add users)
//http://yuml.me/
</pre><br />
<h2>Screenshots</h2><hr/>Before we proceed, let's preview some screenshots of our application:<br />
<br />
<p style="text-align:center; font-size: 16px">Sign in page</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-t0a3Zvz-UEoMp0TGh5noez3vogm3yL_mom0O_DhIg5iBn3cXtPWl11-Ej-wfOOzujGSpyOUrUDQXSnRXV2zn2eQPqq_8N_H46QxoA3K4cQN20_4IpnTM8EWxMl5gILOnKmKB7E2KCsJ0/s1600/Screen+shot+2012-12-08+at+12.14.41+PM.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="329" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-t0a3Zvz-UEoMp0TGh5noez3vogm3yL_mom0O_DhIg5iBn3cXtPWl11-Ej-wfOOzujGSpyOUrUDQXSnRXV2zn2eQPqq_8N_H46QxoA3K4cQN20_4IpnTM8EWxMl5gILOnKmKB7E2KCsJ0/s400/Screen+shot+2012-12-08+at+12.14.41+PM.png" /></a></div><br />
<p style="text-align:center; font-size: 16px">Sign up</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7kFCNMBtHFlBzmijuYgcgYugoIs3mB3yaKmFB7pkpkJ_mpOlxWbHTF_gAO2u13qDt4D5ZeIed0QoXIvEBvihNFjbBxwXVy2CGTwt0zInG7PtUyt1O78iDhuIgyTAZ7Fe4UUsWahwUHeLG/s1600/Screen+shot+2012-12-08+at+12.38.09+PM.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="329" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7kFCNMBtHFlBzmijuYgcgYugoIs3mB3yaKmFB7pkpkJ_mpOlxWbHTF_gAO2u13qDt4D5ZeIed0QoXIvEBvihNFjbBxwXVy2CGTwt0zInG7PtUyt1O78iDhuIgyTAZ7Fe4UUsWahwUHeLG/s400/Screen+shot+2012-12-08+at+12.38.09+PM.png" /></a></div><br />
<p style="text-align:center; font-size: 16px">Facebook Profile</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjduMdGXV5rEDAkCE1sbxpmWHRrq7AFaBDjpVY3oP0OYWLrhbVIedovMbzqqMZ-d_Xu-2TWEblBRNRrwmPXTY0mia08xkUMTFXCgKy6vJK9s_dKaPxRQ_qcTfl-W1RuWVUgJiBFZIcwzW36/s1600/Screen+shot+2012-12-08+at+12.28.22+PM.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="324" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjduMdGXV5rEDAkCE1sbxpmWHRrq7AFaBDjpVY3oP0OYWLrhbVIedovMbzqqMZ-d_Xu-2TWEblBRNRrwmPXTY0mia08xkUMTFXCgKy6vJK9s_dKaPxRQ_qcTfl-W1RuWVUgJiBFZIcwzW36/s400/Screen+shot+2012-12-08+at+12.28.22+PM.png" /></a></div><br />
<p style="text-align:center; font-size: 16px">Twitter Profile</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxur7qAqdKh-YtHqp0J0iiElUjy149vKlj19bbw5DgQLrpcmVETwTe7HIIhkyDLePqobaiWFoBey6rxQghZD1QJNFaIgVvHe_9ADjYjyJf4hVyqzLl8sKl3QpqGxadVw_6qjUmKOPAupL0/s1600/Screen+shot+2012-12-08+at+12.31.07+PM.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="324" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxur7qAqdKh-YtHqp0J0iiElUjy149vKlj19bbw5DgQLrpcmVETwTe7HIIhkyDLePqobaiWFoBey6rxQghZD1QJNFaIgVvHe_9ADjYjyJf4hVyqzLl8sKl3QpqGxadVw_6qjUmKOPAupL0/s400/Screen+shot+2012-12-08+at+12.31.07+PM.png" /></a></div><br />
<p style="text-align:center; font-size: 16px">Manage Users</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhilUk381DpFUK3Fl7u9G8zZvMPoLNAgaNNK0OaFq4dudjeDJ3eUUakRi7yPBj9BhIwkA11ev7M8rMVPxZla5vZPhojA81Mk0EtdLKkyJMTiimr_Py11mY6tVvjQmp5w5bsKhp7C_jls1cm/s1600/Screen+shot+2012-12-08+at+12.34.13+PM.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="324" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhilUk381DpFUK3Fl7u9G8zZvMPoLNAgaNNK0OaFq4dudjeDJ3eUUakRi7yPBj9BhIwkA11ev7M8rMVPxZla5vZPhojA81Mk0EtdLKkyJMTiimr_Py11mY6tVvjQmp5w5bsKhp7C_jls1cm/s400/Screen+shot+2012-12-08+at+12.34.13+PM.png" /></a></div><br />
<p style="text-align:center; font-size: 16px">Post to Facebook</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnPLHCP7Ry0syM2f8HH1fJXPruXNOyzI0tWZcnNDBdfjRYfV3YLIkXkmvasu1huoX9qJjp1JnahkA6KzGrqhjgP8Y_GVn6lz1giJW5ZRmCf2apN7AQ163IZTXpB8kMLD2npa9rdLCEXBWa/s1600/Screen+shot+2012-12-08+at+12.35.31+PM.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="324" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnPLHCP7Ry0syM2f8HH1fJXPruXNOyzI0tWZcnNDBdfjRYfV3YLIkXkmvasu1huoX9qJjp1JnahkA6KzGrqhjgP8Y_GVn6lz1giJW5ZRmCf2apN7AQ163IZTXpB8kMLD2npa9rdLCEXBWa/s400/Screen+shot+2012-12-08+at+12.35.31+PM.png" /></a></div><br />
<p style="text-align:center; font-size: 16px">Tweet to Tweeter</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTGZltv9rZdMGEXPvSExFXcuAfEMo0VLi0nT_JHGzzf202qFlAFoWAyQUwG1hGMZev4bE_WwtQxIPYNysFBUGrgeGW8ZzRSLKN5oaa6MeTOtlfDHtaPsIHJObYpaFpLPIEjAUAupUmWItT/s1600/Screen+shot+2012-12-08+at+12.37.03+PM.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="325" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTGZltv9rZdMGEXPvSExFXcuAfEMo0VLi0nT_JHGzzf202qFlAFoWAyQUwG1hGMZev4bE_WwtQxIPYNysFBUGrgeGW8ZzRSLKN5oaa6MeTOtlfDHtaPsIHJObYpaFpLPIEjAUAupUmWItT/s400/Screen+shot+2012-12-08+at+12.37.03+PM.png" /></a></div><br />
<p style="text-align:center; font-size: 16px">Connect to Social Site</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUZFEqouUN1QFNM79U5LWO-CbUuSfF14koi1qdY653t7zhMgIwXXD5KWyFHdVQtbxApcAvz0tK2IE852sfBy9RXKSrZx6DN2i_5vI4sQGTTLu37x828X7K4Ag5Lo4jQJIWUID5LwJDprbh/s1600/Screen+shot+2012-12-08+at+12.41.17+PM.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="329" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUZFEqouUN1QFNM79U5LWO-CbUuSfF14koi1qdY653t7zhMgIwXXD5KWyFHdVQtbxApcAvz0tK2IE852sfBy9RXKSrZx6DN2i_5vI4sQGTTLu37x828X7K4Ag5Lo4jQJIWUID5LwJDprbh/s400/Screen+shot+2012-12-08+at+12.41.17+PM.png" /></a></div><br />
<p style="text-align:center; font-size: 16px">Connected to Social Site</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgD7KjrEAOBj6pwkifh8GKYzkPaeM2_WhCrryKmwJbhMysq9EtlUuwZbQ26n85JjM3uASsDUCA05NL3obUy96gS5YbUO8PGDaTHROQN5WdNS18JJq5yiyJL5tu_eHCygFZoDfTovOOXxfUc/s1600/Screen+shot+2012-12-08+at+12.41.46+PM.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="329" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgD7KjrEAOBj6pwkifh8GKYzkPaeM2_WhCrryKmwJbhMysq9EtlUuwZbQ26n85JjM3uASsDUCA05NL3obUy96gS5YbUO8PGDaTHROQN5WdNS18JJq5yiyJL5tu_eHCygFZoDfTovOOXxfUc/s400/Screen+shot+2012-12-08+at+12.41.46+PM.png" /></a></div><br />
<br />
<h1>Next</h1>In the next section, we will show how to generate the OAuth secret keys for Facebook and Twitter. Click <a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-2.html">here</a> to proceed.<br />
Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com152tag:blogger.com,1999:blog-5097100801581543528.post-17794060815016263282012-12-10T21:33:00.002+08:002012-12-10T22:27:08.856+08:00Spring Social with JavaConfig (Part 2)<h1>Review</h1>In the previous section, we have discussed the functional requirements of our application. In this section we will study how to generate OAuth keys for Facebook and Twitter. These are required so that <i>Spring Social</i> can communicate with these social media sites.<br />
<br />
<h2 class="explanation" style="padding-left:5px;">Table of Contents</h2><div class="explanation">Click on a link to jump to that section:<br />
<ol><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-1.html">Functional Specs</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-2.html">Generate OAuth keys</a></li>
<ul><li style="margin:0; padding: 0">Facebook</li>
<li style="margin:0; padding: 0">Twitter</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-3.html">Spring Social configuration</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-4.html">Spring Security configuration</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-5.html">JavaConfig</a></li>
<ul><li style="margin:0; padding: 0">ApplicationInitializer.java</li>
<li style="margin:0; padding: 0">ApplicationContext.java</li>
<li style="margin:0; padding: 0">DataConfig.java</li>
<li style="margin:0; padding: 0">ThymeleafConfig.java</li>
<li style="margin:0; padding: 0">spring.properties</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-6.html">View with Thymeleaf</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-7.html">Layers</a></li>
<ul><li style="margin:0; padding: 0">Domain</li>
<li style="margin:0; padding: 0">Repository</li>
<li style="margin:0; padding: 0">Service</li>
<li style="margin:0; padding: 0">Controller</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-8.html">Running the application</a></li>
<ul><li style="margin:0; padding: 0">Clone from GitHub</li>
<li style="margin:0; padding: 0">Create the Database</li>
<li style="margin:0; padding: 0">Run with Maven and Tomcat 7</li>
<li style="margin:0; padding: 0">Run with Maven and Jetty 8</li>
<li style="margin:0; padding: 0">Import to Eclipse</li>
<li style="margin:0; padding: 0">Validate with W3C</li>
</ul></ol></div><br />
<h1>Generate OAuth keys</h1><h2>Facebook</h2>To generate a Facebook secret key, you need to sign-up for a Facebook account first. Once you have an account, follow these steps:<br />
<ol><li>Open a browser</li>
<li>Visit https://developers.facebook.com/apps</li>
<li>Click on <b>Create New App</b></li>
<li>Fill-in the <b>App Name</b></li>
<li>You will be redirected to the <b>Basic</b> settings page</li>
<li>Now copy the <b>App ID</b> value. This is your client ID</li>
<li>Then copy the <b>App Secret</b> value. This is your client secret</li>
</ol><br />
<b>Note:</b> The values need to be stored in the <i>spring.properties</i> file (see Part 5).<br />
<br />
On my sample app, here's the <b>Basic</b> settings page. I've purposely changed the <b>App ID</b> and <b>App Secret</b> values:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiytS5vio49-gITlq1MOkLhpJ2UHvGsmTdRgsITARCPDRRQko0-a_x18YuIdjmjUFBbt5cKkhfQx8akrf2Ddfg2sReqVaVypCwKVyi-v_DyQ00zwyKmlIDv4aN34Sms2tkqoVn3D2neVs9I/s1600/Screen+shot+2012-12-09+at+6.17.38+PM.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="107" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiytS5vio49-gITlq1MOkLhpJ2UHvGsmTdRgsITARCPDRRQko0-a_x18YuIdjmjUFBbt5cKkhfQx8akrf2Ddfg2sReqVaVypCwKVyi-v_DyQ00zwyKmlIDv4aN34Sms2tkqoVn3D2neVs9I/s400/Screen+shot+2012-12-09+at+6.17.38+PM.png" /></a></div><br />
<h2>Twitter</h2>To generate a Twitter secret key, you need to sign-up for a Twitter account first. Once you have an account, follow these steps:<br />
<ol><li>Open a browser</li>
<li>Visit https://dev.twitter.com/</li>
<li>Visit the <b>My applications</b> page at https://dev.twitter.com/apps</li>
<li>Click on <b>Create a new application</b></li>
<li>Fill-in the <b>Name</b></li>
<li>Fill-in the <b>Description</b></li>
<li>Fill-in the <b>Website</b> (You will need to invent a fictitious URL)</li>
<li>You will be redirected to the <b>Details</b> tab of your new application</li>
<li>Now copy the <b>Consumer key</b> value. This is your client ID</li>
<li>Then copy the <b>Consumer secret</b> value. This is your client secret</li>
</ol><br />
<b>Note:</b> The values need to be stored in the <i>spring.properties</i> file (see Part 5).<br />
<br />
On my sample app, here's the <b>Details</b> tab. I've purposely changed the <b>Consumer key</b> and <b>Consumer secret</b> values:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmMlzWnJtLchbcv7-2oc1ixStouAJrfoeU1ax3tCR7l0UTZFIz6GWi76Qs-gyUy0M_tuw7-npU9cZFaNrCv6zdtMSPMQ6tbjoyzYwSd7kg1Bzfb1wErbLF5f-412T05W3LggqWGYe9GfXg/s1600/Screen+shot+2012-12-09+at+6.27.36+PM.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="126" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmMlzWnJtLchbcv7-2oc1ixStouAJrfoeU1ax3tCR7l0UTZFIz6GWi76Qs-gyUy0M_tuw7-npU9cZFaNrCv6zdtMSPMQ6tbjoyzYwSd7kg1Bzfb1wErbLF5f-412T05W3LggqWGYe9GfXg/s400/Screen+shot+2012-12-09+at+6.27.36+PM.png" /></a></div><br />
<br />
<h1>Next</h1>In the next section, we will setup the Spring Social-related configuration through JavaConfig. Click <a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-3.html">here</a> to proceed.Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com95tag:blogger.com,1999:blog-5097100801581543528.post-3932762005104694932012-12-10T21:33:00.001+08:002012-12-10T22:30:28.985+08:00Spring Social with JavaConfig (Part 3)<h1>Review</h1>In the previous section, we have shown the steps on how to generate and retrieve the OAuth secret keys from Facebook and Twitter. In this section we will setup the Spring Social configuration settings through JavaConfig. <br />
<br />
<h2 class="explanation" style="padding-left:5px;">Table of Contents</h2><div class="explanation">Click on a link to jump to that section:<br />
<ol><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-1.html">Functional Specs</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-2.html">Generate OAuth keys</a></li>
<ul><li style="margin:0; padding: 0">Facebook</li>
<li style="margin:0; padding: 0">Twitter</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-3.html">Spring Social configuration</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-4.html">Spring Security configuration</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-5.html">JavaConfig</a></li>
<ul><li style="margin:0; padding: 0">ApplicationInitializer.java</li>
<li style="margin:0; padding: 0">ApplicationContext.java</li>
<li style="margin:0; padding: 0">DataConfig.java</li>
<li style="margin:0; padding: 0">ThymeleafConfig.java</li>
<li style="margin:0; padding: 0">spring.properties</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-6.html">View with Thymeleaf</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-7.html">Layers</a></li>
<ul><li style="margin:0; padding: 0">Domain</li>
<li style="margin:0; padding: 0">Repository</li>
<li style="margin:0; padding: 0">Service</li>
<li style="margin:0; padding: 0">Controller</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-8.html">Running the application</a></li>
<ul><li style="margin:0; padding: 0">Clone from GitHub</li>
<li style="margin:0; padding: 0">Create the Database</li>
<li style="margin:0; padding: 0">Run with Maven and Tomcat 7</li>
<li style="margin:0; padding: 0">Run with Maven and Jetty 8</li>
<li style="margin:0; padding: 0">Import to Eclipse</li>
<li style="margin:0; padding: 0">Validate with W3C</li>
</ul></ol></div><br />
<h1>Spring Social configuration</h1><br />
<h2 class="explanation" style="padding-left:5px;">What is Spring Social?</h2><blockquote class="explanation">Spring Social is an extension of the Spring Framework that allows you to connect your applications with Software-as-a-Service (SaaS) providers such as Facebook and Twitter.<br />
<br />
Features:<br />
<ul><li>An extensible service provider framework that greatly simplifies the process of connecting local user accounts to hosted provider accounts.</li>
<li>A connect controller that handles the authorization flow between your Java/Spring web application, a service provider, and your users.</li>
<li>Java bindings to popular service provider APIs such as Facebook, Twitter, LinkedIn, TripIt, and GitHub.</li>
<li>A sign-in controller that enables users to authenticate with your application by signing in through a service provider.</li>
</ul>Source: <a href="http://www.springsource.org/spring-social">http://www.springsource.org/spring-social</a></blockquote><br />
Here's our <i>Spring Social</i> configuration:<br />
<br />
<b>SocialConfig.java</b><br />
<script src="https://gist.github.com/4238818.js?file=SocialConfig.java"></script><br />
<br />
Let me explain the contents of this configuration:<br />
<br />
<ul><li>We have autowired the environment properties and the datasource</li>
<li>We have declared a <i>ConnectionFactoryLocator</i> which allows us to register connections to Facebook and Twitter. Notice how we passed the OAuth secret IDs and secret keys to the locator</li>
<li>We've declared a <i>TextEncryptor</i> for encrypting strings. This is required by Spring Social's <i>JdbcUsersConnectionRepository</i></li>
<li><i>JdbcUsersConnectionRepository</i> is used for persisting connections to a database through JDBC</li>
<li><i>ConnectionRepository</i> allows a specific user to save and retrieve connections. We need to use this in conjunction with <b>Spring Security</b> because it provides us ready-made authenticated users. Notice how we assigned the current authenticated user</li>
<li><i>ConnectController</i> is a controller for managing the connection flow to social media sites</li>
<li><i>HiddenHttpMethodFilter</i> is required by Spring Social so that users can disconnect from social media sites. The filter needs to be declared in the web.xml or ApplicationInitializer</li>
</ul><br />
<b>Note:</b> If you need an in-depth explanation of each classes, please see the official Spring Social docs<br />
<br />
<h1>Next</h1>In the next section, we will focus on Spring Security-related configuration. Click <a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-4.html">here</a> to proceed.Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com13tag:blogger.com,1999:blog-5097100801581543528.post-20732372670376907932012-12-10T21:33:00.000+08:002012-12-10T22:31:42.489+08:00Spring Social with JavaConfig (Part 4)<h1>Review</h1>In the previous section, we have discussed the Spring Social-related configuration. In this section we will focus on Spring Security for securing our application.<br />
<br />
<h2 class="explanation" style="padding-left:5px;">Table of Contents</h2><div class="explanation">Click on a link to jump to that section:<br />
<ol><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-1.html">Functional Specs</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-2.html">Generate OAuth keys</a></li>
<ul><li style="margin:0; padding: 0">Facebook</li>
<li style="margin:0; padding: 0">Twitter</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-3.html">Spring Social configuration</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-4.html">Spring Security configuration</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-5.html">JavaConfig</a></li>
<ul><li style="margin:0; padding: 0">ApplicationInitializer.java</li>
<li style="margin:0; padding: 0">ApplicationContext.java</li>
<li style="margin:0; padding: 0">DataConfig.java</li>
<li style="margin:0; padding: 0">ThymeleafConfig.java</li>
<li style="margin:0; padding: 0">spring.properties</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-6.html">View with Thymeleaf</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-7.html">Layers</a></li>
<ul><li style="margin:0; padding: 0">Domain</li>
<li style="margin:0; padding: 0">Repository</li>
<li style="margin:0; padding: 0">Service</li>
<li style="margin:0; padding: 0">Controller</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-8.html">Running the application</a></li>
<ul><li style="margin:0; padding: 0">Clone from GitHub</li>
<li style="margin:0; padding: 0">Create the Database</li>
<li style="margin:0; padding: 0">Run with Maven and Tomcat 7</li>
<li style="margin:0; padding: 0">Run with Maven and Jetty 8</li>
<li style="margin:0; padding: 0">Import to Eclipse</li>
<li style="margin:0; padding: 0">Validate with W3C</li>
</ul></ol></div><br />
<h1>Spring Security</h1><br />
<h2 class="explanation" style="padding-left:5px;">What is Spring Security?</h2><blockquote class="explanation">Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications.<br />
<br />
Spring Security is one of the most mature and widely used Spring projects. Founded in 2003 and actively maintained by SpringSource since, today it is used to secure numerous demanding environments including government agencies, military applications and central banks. It is released under an Apache 2.0 license so you can confidently use it in your projects.<br />
<br />
Source: <a href="http://www.springsource.org/spring-security">http://www.springsource.org/spring-security</a></blockquote><br />
Here's our <i>Spring Security</i> configuration:<br />
<br />
<b>SecurityConfig.java</b><br />
<script src="https://gist.github.com/4238842.js?file=SecurityConfig.java"></script><br />
First, we declare a <i>DelegatingFilterProxy</i> bean using JavaConfig. This allows Spring Security to intercept requests to our application and verify if the required authentication and authorization are met. This bean needs to be registered in the web.xml (or ApplicationInitializer) as a filter (see next section).<br />
<br />
Second, we declare the usual XML-based configuration. This allows us to define the intercept-url patterns. Why are we not using JavaConfig here? Because the XML-based configuration is simpler, less-verbose, and easier:<br />
<br />
<b>spring-security.xml</b><br />
<script src="https://gist.github.com/4238849.js?file=spring-security.xml"></script><br />
<br />
For an in-depth explanation of this configuration, please see my tutorial on <a href="http://krams915.blogspot.com/2012/01/spring-security-31-implement_5023.html">Spring Security 3.1 - Implement UserDetailsService with Spring Data JPA</a><br />
<br />
<h1>Next</h1>In the next section, we will study the remaining JavaConfig-based configuration. Click <a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-5.html">here</a> to proceed.Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com8tag:blogger.com,1999:blog-5097100801581543528.post-43708187510943617402012-12-10T21:32:00.004+08:002012-12-10T22:38:31.432+08:00Spring Social with JavaConfig (Part 5)<h1>Review</h1>In the previous section, we have discussed the Spring Security-related configurations. In this section we will discuss the remaining configuration of our application.<br />
<br />
<h2 class="explanation" style="padding-left:5px;">Table of Contents</h2><div class="explanation">Click on a link to jump to that section:<br />
<ol><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-1.html">Functional Specs</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-2.html">Generate OAuth keys</a></li>
<ul><li style="margin:0; padding: 0">Facebook</li>
<li style="margin:0; padding: 0">Twitter</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-3.html">Spring Social configuration</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-4.html">Spring Security configuration</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-5.html">JavaConfig</a></li>
<ul><li style="margin:0; padding: 0">ApplicationInitializer.java</li>
<li style="margin:0; padding: 0">ApplicationContext.java</li>
<li style="margin:0; padding: 0">DataConfig.java</li>
<li style="margin:0; padding: 0">ThymeleafConfig.java</li>
<li style="margin:0; padding: 0">spring.properties</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-6.html">View with Thymeleaf</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-7.html">Layers</a></li>
<ul><li style="margin:0; padding: 0">Domain</li>
<li style="margin:0; padding: 0">Repository</li>
<li style="margin:0; padding: 0">Service</li>
<li style="margin:0; padding: 0">Controller</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-8.html">Running the application</a></li>
<ul><li style="margin:0; padding: 0">Clone from GitHub</li>
<li style="margin:0; padding: 0">Create the Database</li>
<li style="margin:0; padding: 0">Run with Maven and Tomcat 7</li>
<li style="margin:0; padding: 0">Run with Maven and Jetty 8</li>
<li style="margin:0; padding: 0">Import to Eclipse</li>
<li style="margin:0; padding: 0">Validate with W3C</li>
</ul></ol></div><br />
<h1>JavaConfig</h1>As stated in the introduction, we will be using JavaConfig-based configuration instead of the usual XML config. However, I don't want to alienate our readers who are used to XML. As a result, I've decided to provide both implementations. However, our focus here is still on JavaConfig.<br />
<br />
<span style="color: red; font-weight: bold">Note:</span> With JavaConfig, we can now omit the ubiquitous web.xml. But in order to that, we need to run a Servlet 3.0 web container. For this tutorial, I have tested the application with Tomcat 7.0.30 (Maven plugin), 7.0.33 (standalone Tomcat), and Jetty 8.1.5.v20120716 (Maven plugin).<br />
<br />
<b>ApplicationInitializer.java</b><br />
<hr/>The ApplicationInitializer.java is the equivalent of <i>web.xml</i>. Here's where we declare the <i>DispatcherServlet</i> and also we've registered two filters: one for Spring Security and another for Spring Social.<br />
<br />
<script src="https://gist.github.com/4238821.js?file=ApplicationInitializer.java"></script><br />
<br />
Here's the equivalent XML configuration:<br />
<br />
<script src="https://gist.github.com/4250880.js?file=web.xml"></script><br />
<br />
<b>ApplicationContext.java</b><br />
<hr/>The ApplicationContext.java contains our main configuration. It's responsible for loading other configurations, either as JavaConfig or XML config.<br />
<br />
<script src="https://gist.github.com/4238826.js?file=ApplicationContext.java"></script><br />
<br />
Let's describe each annotation:<br />
<ul><li><code class="code-custom ui-corner-top ui-corner-bottom">@Configuration </code><br />
- Marks a class as a JavaConfig<br />
</li>
<li><code class="code-custom ui-corner-top ui-corner-bottom">@ComponentScan(basePackages = {"org.krams"}) </code><br />
- Configures scanning of Spring components<br />
<br />
This is equivalent in XML as:<br />
<script src="https://gist.github.com/4187720.js?file=context-annotation-config.xml"></script><br />
</li>
<li><code class="code-custom ui-corner-top ui-corner-bottom">@EnableWebMvc <br />
</code><br />
- Activates Spring's MVC support<br />
<br />
This is equivalent in XML as:<br />
<script src="https://gist.github.com/4187728.js?file=mvc-annotation-driven.xml"></script><br />
</li>
<li><code class="code-custom ui-corner-top ui-corner-bottom">@Import({DataConfig.class, ThymeleafConfig.class, SocialConfig.class, SecurityConfig.class}) </code><br />
- This allows us to import JavaConfig-based config. Notice we have imported four configuration classes<br />
</li>
<li><code class="code-custom ui-corner-top ui-corner-bottom">@ImportResource("classpath:trace-context.xml") </code><br />
- This allows us to import XML-based config files. (As a side note why can't we just declare this as a JavaConfig? It turns out there's no direct translation for the trace-context.xml, so we'll have to import it as XML).<br />
<br />
This is equivalent in XML as:<br />
<script src="https://gist.github.com/4187734.js?file=import-resource.xml"></script><br />
</li>
<li><code class="code-custom ui-corner-top ui-corner-bottom">@PropertySource("classpath:spring.properties") </code><br />
- This allows us to import property files<br />
</li>
<li><code class="code-custom ui-corner-top ui-corner-bottom">@Bean </code><br />
- Declares a Spring bean<br />
</li>
</ul><br />
Here's the equivalent XML configuration:<br />
<br />
<script src="https://gist.github.com/4250887.js?file=applicationContext.xml"></script><br />
<br />
<b>DataConfig.java</b><br />
<hr/>The DataConfig.java contains our Spring Data configuration. This is where we declare our data source, transaction manager, and JPA entity manager.<br />
<br />
<script src="https://gist.github.com/4238836.js?file=DataConfig.java"></script><br />
<br />
Here's the equivalent XML configuration:<br />
<br />
<script src="https://gist.github.com/4250892.js?file=spring-data.xml"></script><br />
<br />
<b>ThymeleafConfig.java</b><br />
<hr/>The ThymeleafConfig.java contains our Thymeleaf configuration. This is where we declare our Thymeleaf view resolver.<br />
<br />
<script src="https://gist.github.com/4238840.js?file=ThymeleafConfig.java"></script><br />
We've declared some special settings on our Thymeleaf configuration:<br />
<pre class="code-custom">// Declare virtual paths
resolver.addTemplateAlias("connect/facebookConnect","facebook/connect");
resolver.addTemplateAlias("connect/twitterConnect","twitter/connect");
resolver.addTemplateAlias("connect/facebookConnected","facebook/connected");
resolver.addTemplateAlias("connect/twitterConnected","facebook/connected");
// Disable cache for testing purposes
resolver.setCacheable(false);
</pre><br />
These allows to redirect virtual path requests to specific templates within our application. We need to do this because the <i>ConnectController</i> from Spring Social has its own built-in controller path requests. And we need to redirect the resulting views that matches our template path. <br />
<br />
For example, when connecting to Facebook, <i>ConnectController</i> will use the <i>connect/facebookConnect</i> path and you are required to provide a view. Using the <i>addTemplateAlias()</i> method, we can provide a custom view, in this case, the view points to the directory in the <i>WEB-INF/templates/facebook/connect</i>.<br />
<br />
Also, we've disabled the caching feature so that we can easily update and test our html pages.<br />
<br />
Here's the equivalent XML configuration:<br />
<br />
<script src="https://gist.github.com/4250896.js?file=spring-servlet.xml"></script><br />
<b>SecurityConfig.java</b><br />
<hr/>The SecurityConfig.java contains a single bean <i>DelegatingFilterProxy</i>. This is required for Spring Security.<br />
<br />
<script src="https://gist.github.com/4238842.js?file=SecurityConfig.java"></script><br />
<br />
<b>spring.properties</b><br />
<hr/>spring.properties contains the property settings of our application. You need to declare your Facebook and Twitter OAuth settings here. Here's also where you declare your database.<br />
<br />
<script src="https://gist.github.com/4238853.js?file=spring.properties"></script><br />
<b>messages_en.properties</b><br />
<hr/>This is for internationalization of messages. The default language is English. If you need to provide custom language, create a new properties file and replace the values according to the language you've chosen. Please see the Spring documentation for more info on internationalization.<br />
<br />
<script src="https://gist.github.com/4238856.js?file=messages_en.properties"></script><br />
<br />
<h1>Next</h1>In the next section, we will discuss the Domain, Service, Controller, and View layers. Click <a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-6.html">here</a> to proceed.Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com10tag:blogger.com,1999:blog-5097100801581543528.post-5604972765634023082012-12-10T21:32:00.003+08:002012-12-10T21:38:53.534+08:00Spring Social with JavaConfig (Part 6)<h1>Review</h1>In the previous section, we have discussed the remaining JavaConfig configurations. In this section, we will discuss the View layer along with Thymeleaf.<br />
<br />
<h2 class="explanation" style="padding-left:5px;">Table of Contents</h2><div class="explanation">Click on a link to jump to that section:<br />
<ol><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-1.html">Functional Specs</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-2.html">Generate OAuth keys</a></li>
<ul><li style="margin:0; padding: 0">Facebook</li>
<li style="margin:0; padding: 0">Twitter</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-3.html">Spring Social configuration</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-4.html">Spring Security configuration</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-5.html">JavaConfig</a></li>
<ul><li style="margin:0; padding: 0">ApplicationInitializer.java</li>
<li style="margin:0; padding: 0">ApplicationContext.java</li>
<li style="margin:0; padding: 0">DataConfig.java</li>
<li style="margin:0; padding: 0">ThymeleafConfig.java</li>
<li style="margin:0; padding: 0">spring.properties</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-6.html">View with Thymeleaf</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-7.html">Layers</a></li>
<ul><li style="margin:0; padding: 0">Domain</li>
<li style="margin:0; padding: 0">Repository</li>
<li style="margin:0; padding: 0">Service</li>
<li style="margin:0; padding: 0">Controller</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-8.html">Running the application</a></li>
<ul><li style="margin:0; padding: 0">Clone from GitHub</li>
<li style="margin:0; padding: 0">Create the Database</li>
<li style="margin:0; padding: 0">Run with Maven and Tomcat 7</li>
<li style="margin:0; padding: 0">Run with Maven and Jetty 8</li>
<li style="margin:0; padding: 0">Import to Eclipse</li>
<li style="margin:0; padding: 0">Validate with W3C</li>
</ul></ol></div><br />
<h1>View with Thymeleaf</h1><hr/>The goal of this section is not to teach you everything about Thymeleaf but to point out the important sections. If you need a full Thymeleaf documentation, please see the official docs. <br />
<br />
<h2 class="explanation" style="padding-left:5px;">What is Thymeleaf?</h2><blockquote class="explanation">Thymeleaf is a Java library. It is an XML / XHTML / HTML5 template engine (extensible to other formats) that can work both in web and non-web environments. It is better suited for serving XHTML/HTML5 at the view layer of web applications, but it can process any XML file even in offline environments.<br />
<br />
It provides an optional module for integration with Spring MVC, so that you can use it as a complete substitute of JSP in your applications made with this technology, even with HTML5.<br />
<br />
The main goal of Thymeleaf is to provide an elegant and well-formed way of creating templates. Its Standard and SpringStandard dialects allow you to create powerful natural templates, that can be correctly displayed by browsers and therefore work also as static prototypes. You can also extend Thymeleaf by developing your own dialects.<br />
<br />
Source: <a href="http://www.thymeleaf.org/">Thymeleaf.org</a><br />
</blockquote><br />
Since we have numerous html pages with duplicate setup, I will focus on the ones that are most instructive.<br />
<br />
<b>Facebook profile.html</b><br />
This displays our Facebook profile information.<br />
<br />
<script src="https://gist.github.com/4238864.js?file=profile.html"></script><br />
<br />
<b>Let's discuss the important attributes</b><br />
<ul><li>The <b>#</b> means to resolve the attribute from the messages bundle</li>
<li>The <b>$</b> means to resolve the attribute from the model</li>
<li>The <b>#</b> and <b>$</b> can be combined together so that messages can be dynamically generated from the model and internationalized from the messages bundle</li>
<li><i>th:href</i> attribute<br />
<pre class="code-custom"><link rel="stylesheet" href="../../../resources/css/style.css" th:href="@{/resources/css/style.css}" />
</pre>Declares a resource relative to the context of the app. When testing the html mockup, the <i>th:href</i> attribute is ignored by the browser. When running the app, Thymeleaf's preprocessor will ignore the value of the href attribute and use the value in the <i>th:ref</i> attribute.<br />
</li>
<li><i>th:text</i> attribute<br />
<pre class="code-custom"><title th:text="#{'profile.title.' + ${source}}">Title</title>
</pre>Declares the usual title element. When testing the html mockup, the <i>th:text</i> attribute is ignored by the browser. When running the app, Thymeleaf's preprocessor will ignore the value of the title and use the value in the <i>th:text</i> attribute. <br />
<br />
This is a common attribute. So pay attention to this one.<br />
</li>
<li><i>th:include</i> attribute<br />
<pre class="code-custom"><div th:include="include :: menu"></div>
</pre>Includes an html fragment. The fragment is declared in the <i>include.html</i><br />
</li>
<li><i>th:src</i> attribute<br />
<pre class="code-custom"><img src="#" th:src="@{'http://graph.facebook.com/' + ${profileInfo.id}} + '/picture'" alt="profile image"/>
</pre>Declares an image element. The attribute <i>th:src</i> is similar with the <i>th:href</i> behavior. <br />
<br />
The value of <i>th:src</i> contains two parts: <i>'http://graph.facebook.com/'</i> which is a literal string and <i>${profileInfo.id}</i> is a model attribute. The value is sent by our Spring controller (see below):<br />
<br />
<script src="https://gist.github.com/4248183.js?file=FacebookController.java"></script><br />
</li>
<li><i>th:if</i> attribute<br />
<pre class="code-custom"><dd th:if="${#strings.isEmpty(profileInfo.email)}" th:text="'no email listed'">john@email.com</dd>
</pre>A conditional expression. This states "if the profileInfo.email attribute is empty, print out 'no email listed', but if it's not empty, then print out the value.<br />
</li>
</ul><br />
<span style="color: red; font-weight: bold">Note:</span> To see the remaining html pages, please visit the Github repository. I've omitted them here because most of the Thymeleaf tags we've discussed here are also the same ones we've used on those pages.<br />
<br />
<b>login.html</b><br />
This is the login page. We've shown it here because this is used by Spring Security for rendering the login page.<br />
<br />
<script src="https://gist.github.com/4248205.js?file=login.html"></script><br />
<br />
For more info, please see <a href="http://krams915.blogspot.com/2012/01/spring-security-31-implement_5023.html">Spring Security 3.1 - Implement UserDetailsService with Spring Data JPA</a> tutorial.<br />
<br />
<h1>Next</h1>In the next section, we will focus on the Domain, Repository, Service, and Controller classes Click <a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-7.html">here</a> to proceed.Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com11tag:blogger.com,1999:blog-5097100801581543528.post-52822762005064018552012-12-10T21:32:00.001+08:002012-12-10T22:40:03.312+08:00Spring Social with JavaConfig (Part 7)<h1>Review</h1>In the previous section, we have discussed the View layer along with Thymeleaf. In this section, we will focus on the Domain, Repository, Service, and Controller classes.<br />
<br />
<h2 class="explanation" style="padding-left:5px;">Table of Contents</h2><div class="explanation">Click on a link to jump to that section:<br />
<ol><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-1.html">Functional Specs</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-2.html">Generate OAuth keys</a></li>
<ul><li style="margin:0; padding: 0">Facebook</li>
<li style="margin:0; padding: 0">Twitter</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-3.html">Spring Social configuration</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-4.html">Spring Security configuration</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-5.html">JavaConfig</a></li>
<ul><li style="margin:0; padding: 0">ApplicationInitializer.java</li>
<li style="margin:0; padding: 0">ApplicationContext.java</li>
<li style="margin:0; padding: 0">DataConfig.java</li>
<li style="margin:0; padding: 0">ThymeleafConfig.java</li>
<li style="margin:0; padding: 0">spring.properties</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-6.html">View with Thymeleaf</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-7.html">Layers</a></li>
<ul><li style="margin:0; padding: 0">Domain</li>
<li style="margin:0; padding: 0">Repository</li>
<li style="margin:0; padding: 0">Service</li>
<li style="margin:0; padding: 0">Controller</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-8.html">Running the application</a></li>
<ul><li style="margin:0; padding: 0">Clone from GitHub</li>
<li style="margin:0; padding: 0">Create the Database</li>
<li style="margin:0; padding: 0">Run with Maven and Tomcat 7</li>
<li style="margin:0; padding: 0">Run with Maven and Jetty 8</li>
<li style="margin:0; padding: 0">Import to Eclipse</li>
<li style="margin:0; padding: 0">Validate with W3C</li>
</ul></ol></div><br />
<h1>Layers</h1><h2>Domain</h2><hr/>Our domain layer consists of two simple classes: <i>User.java</i> and <i>Role.java</i>. By annotating these classes with <i>@Entity</i> we're declaring these classes as JPA entities and consequently will be persisted to a database.<br />
<br />
The User class contains the following properties: first name, last name, username, role, and password. For the Role class, we only have two values: an admin and a regular user.<br />
<br />
<script src="https://gist.github.com/4248267.js?file=User.java"></script><br />
<br />
<script src="https://gist.github.com/4248270.js?file=Role.java"></script><br />
<br />
Although this is not part of the domain layer, we've included the <b>UserDto</b> here. This DTO is used for transferring user information to the view layer.<br />
<br />
<script src="https://gist.github.com/4248274.js?file=UserDto.java"></script><br />
<br />
<h2>Controller</h2><hr/>We have five controllers:<br />
<ul><li><i>AccessController</i> is responsible for managing login and signup requests</li>
<li><i>FacebookController</i> is responsible for handling Facebook requests</li>
<li><i>TwitterController</i> is responsible for handling Twitter requests</li>
<li><i>UserController</i> is responsible for handling User CRUD operations</li>
<li><i>MediatorController</i> simply handles call to the root page</li>
</ul><br />
<b>AccessController.java</b><br />
<script src="https://gist.github.com/4248245.js?file=AccessController.java"></script><br />
<br />
<b>FacebookController.java</b><br />
<script src="https://gist.github.com/4248249.js?file=FacebookController.java"></script><br />
<br />
<b>MediatorController.java</b><br />
<script src="https://gist.github.com/4248253.js?file=MediatorController.java"></script><br />
<br />
<b>TwitterController.java</b><br />
<script src="https://gist.github.com/4248257.js?file=TwitterController.java"></script><br />
<br />
<b>UserController.java</b><br />
<script src="https://gist.github.com/4248260.js?file=UserController.java"></script><br />
<br />
<h2>Repository</h2><hr/>We have a simple repository. There's nothing much to explain here.<br />
<br />
<b>UserRepository.java</b><br />
<script src="https://gist.github.com/4248271.js?file=UserRepository.java"></script><br />
<br />
<h2>Service</h2><hr/>We have two services:<br />
<ul><li><i>UserService</i> is used for handling user-related CRUD operations</li>
<li><i>RepositoryBasedUserDetailsService</i> is used for retrieving user details for authentication purposes</li>
</ul><br />
<b>UserService.java</b><br />
<script src="https://gist.github.com/4248278.js?file=UserService.java"></script><br />
<br />
<b>RepositoryBasedUserDetailsService.java</b><br />
<script src="https://gist.github.com/4248280.js?file=RepositoryBasedUserDetailsService.java"></script><br />
<h1>Next</h1>In the next section, we will study how to build and run our application. We will use Maven, Tomcat, and Jetty to run the app. We'll also study how to import the project in Eclipse. Click <a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-8.html">here</a> to proceed.Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com10tag:blogger.com,1999:blog-5097100801581543528.post-28893940152917698422012-12-10T21:32:00.000+08:002012-12-21T10:20:08.151+08:00Spring Social with JavaConfig (Part 8)<h1>Review</h1><hr/>In the previous section, we have discussed the Domain, Repository, Service, Controller layers. In this section, we will build and run our sample application. We will verify if our application is able to communicate with Facebook and Twitter. We will also show how to import the project in Eclipse.<br />
<br />
<br />
<h2 class="explanation" style="padding-left:5px;">Table of Contents</h2><div class="explanation">Click on a link to jump to that section:<br />
<ol><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-1.html">Functional Specs</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-2.html">Generate OAuth keys</a></li>
<ul><li style="margin:0; padding: 0">Facebook</li>
<li style="margin:0; padding: 0">Twitter</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-3.html">Spring Social configuration</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-4.html">Spring Security configuration</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-5.html">JavaConfig</a></li>
<ul><li style="margin:0; padding: 0">ApplicationInitializer.java</li>
<li style="margin:0; padding: 0">ApplicationContext.java</li>
<li style="margin:0; padding: 0">DataConfig.java</li>
<li style="margin:0; padding: 0">ThymeleafConfig.java</li>
<li style="margin:0; padding: 0">spring.properties</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-6.html">View with Thymeleaf</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-7.html">Layers</a></li>
<ul><li style="margin:0; padding: 0">Domain</li>
<li style="margin:0; padding: 0">Repository</li>
<li style="margin:0; padding: 0">Service</li>
<li style="margin:0; padding: 0">Controller</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-social-with-javaconfig-part-8.html">Running the application</a></li>
<ul><li style="margin:0; padding: 0">Clone from GitHub</li>
<li style="margin:0; padding: 0">Create the Database</li>
<li style="margin:0; padding: 0">Run with Maven and Tomcat 7</li>
<li style="margin:0; padding: 0">Run with Maven and Jetty 8</li>
<li style="margin:0; padding: 0">Import to Eclipse</li>
<li style="margin:0; padding: 0">Validate with W3C</li>
</ul></ol></div><br />
<h1>Running the Application</h1><hr/><h2>Clone from GitHub</h2>To clone from GitHub, follow these instructions:<br />
<ol><li>Open a Git terminal</li>
<li>Enter the following command:<br />
<div class="code-custom"><pre>git clone https://github.com/krams915/spring-social-javaconfig.git</pre></div>This will clone the JavaConfig-based application. <br />
<br />
If you prefer the XML-based version,<br />
<div class="code-custom"><pre>git clone https://github.com/krams915/spring-social-xmlconfig.git</pre></div><br />
<h2 class="explanation" style="padding-left:5px;">Remember:</h2><div class="explanation">There are two versions of our application: a JavaConfig-based and an XML config-based app. Both versions are identical in their feature set.<br />
<ul><li style="margin:0; padding: 0"><a href="https://github.com/krams915/spring-social-javaconfig">spring-social-javaconfig</a></li>
<li style="margin:0; padding: 0"><a href="https://github.com/krams915/spring-social-xmlconfig">spring-social-xmlconfig</a></li>
</ul></div></ol><h2>Create the Database</h2><ol><li>Run MySQL</li>
<li>Create a new database:<br />
<div class="code-custom"><pre>spring_social_tutorial</pre></div></li>
<li>Import the following SQL files:<br />
<div class="code-custom"><pre>spring_social_tutorial.sql
JdbcUsersConnectionRepository.sql
</pre></div><br />
These files can be found at the <i>src/main/resources</i> path<br />
</li>
</ol><h2>Run with Maven and Tomcat 7</h2>Ensure Maven is installed first, and you have created the MySQL database <ol><li>Open a terminal</li>
<li>Browse to the directory where you've cloned the project</li>
<li>Enter the following command:<br />
<div class="code-custom"><pre>mvn tomcat7:run</pre></div></li>
<li>You should see the following output:<br />
<pre>[INFO] Scanning for projects...
[INFO]
[INFO] -------------------------------------------------------------
[INFO] Building spring-social-tutorial Maven Webapp 0.0.1-SNAPSHOT
[INFO] -------------------------------------------------------------
[INFO]
[INFO] >>> tomcat7-maven-plugin:2.0:run (default-cli) @ spring-social-tutorial >>>
...
...
...
Dec 10, 2012 9:50:56 AM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-bio-8080"]
Dec 10, 2012 9:50:56 AM org.apache.catalina.core.StandardService startInternal
INFO: Starting service Tomcat
Dec 10, 2012 9:50:56 AM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/7.0.30
Dec 10, 2012 9:51:07 AM org.apache.catalina.core.ApplicationContext log
INFO: Spring WebApplicationInitializers detected on classpath: [org.krams.config.ApplicationInitializer@73b8cdd5]
Dec 10, 2012 9:51:08 AM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring root WebApplicationContext
Dec 10, 2012 9:51:18 AM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring FrameworkServlet 'dispatcher'
Dec 10, 2012 9:51:18 AM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-8080"]
</pre></li>
<li>Open a browser</li>
<li>Visit the entry page:<br />
<div class="code-custom"><pre>http://localhost:8080/spring-social-tutorial</pre></div></li>
<li>The primary admin credentials are the following:<br />
<div class="code-custom"><pre>username: john
password: admin</pre></div><br />
You can create a new account but by default it doesn't have any admin powers.<br />
</li>
</ol><h2>Run with Maven and Jetty 8</h2>Ensure Maven is installed first, and you have created the MySQL database. <ol><li>Open a terminal</li>
<li>Browse to the directory where you've cloned the project</li>
<li>Enter the following command:<br />
<div class="code-custom"><pre>mvn jetty:run</pre></div></li>
<li>You should see the following output:<br />
<pre>[INFO] Scanning for projects...
[INFO]
[INFO] -------------------------------------------------------------
[INFO] Building spring-social-tutorial Maven Webapp 0.0.1-SNAPSHOT
[INFO] -------------------------------------------------------------
[INFO]
[INFO] >>> jetty-maven-plugin:8.1.5.v20120716:run (default-cli) @ spring-social-tutorial >>>
...
...
...
2012-12-10 09:53:55.980:INFO:/spring-social-tutorial:Initializing Spring FrameworkServlet 'dispatcher'
2012-12-10 09:53:56.140:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:8080
[INFO] Started Jetty Server
</pre></li>
<li>Open a browser</li>
<li>Visit the entry page:<br />
<div class="code-custom"><pre>http://localhost:8080/spring-social-tutorial</pre></div></li>
<li>The primary admin credentials are the following:<br />
<div class="code-custom"><pre>username: john
password: admin</pre></div><br />
You can create a new account but by default it doesn't have any admin powers.<br />
</li>
</ol><h2>Import to Eclipse</h2>Ensure Maven is installed first <ol><li>Open a terminal</li>
<li>Enter the following command:<br />
<div class="code-custom"><pre>mvn eclipse:eclipse -Dwtpversion=2.0</pre></div></li>
<li>You should see the following output:<br />
<pre>[INFO] Scanning for projects...
[INFO]
[INFO] -------------------------------------------------------------
[INFO] Building spring-social-tutorial Maven Webapp 0.0.1-SNAPSHOT
[INFO] -------------------------------------------------------------
[INFO]
[INFO] >>> maven-eclipse-plugin:2.9:eclipse (default-cli) @ spring-social-tutorial >>>
...
...
...
[INFO] -------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] -------------------------------------------------------------
[INFO] Total time: 9.532s
[INFO] Finished at: Mon Dec 10 09:55:31 PHT 2012
[INFO] Final Memory: 17M/81M
[INFO] -------------------------------------------------------------
</pre><br />
This command will add the following files to your project: <br />
<pre>.classpath
.project
.settings
target</pre>You may have to enable "show hidden files" in your file explorer to view them.<br />
</li>
<li>Run Eclipse and import the application as Maven project</li>
</ol><h2>Validate with W3C Markup Validation Service</h2>One of the promises of using Thymeleaf is it produces valid HTML pages. Let's test that out using W3C validation service. <ol><li>Run the application</li>
<li>Open a browser</li>
<li>Visit the following URLs and validate them all:<br />
<div class="code-custom"><pre>http://localhost:8080/spring-social-tutorial/
http://localhost:8080/spring-social-tutorial/login
http://localhost:8080/spring-social-tutorial/users
http://localhost:8080/spring-social-tutorial/fb/profile
http://localhost:8080/spring-social-tutorial/tw/profile
http://localhost:8080/spring-social-tutorial/fb/post
http://localhost:8080/spring-social-tutorial/tw/post</pre></div></li>
<li>View the HTML source (right-click or go to menu)</li>
<li>Copy the HTML source</li>
<li>Open W3C Markup Validation Service at http://validator.w3.org/#validate_by_input</li>
<li>Paste the HTML source and wait for the validation result<br />
<br />
You should see a similar output:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUKtiZ5wurEnny1FLarQi_ZhGNc4VTboK0mWQAWK1XojC-QhtjK3r7tDdCZnQjat9qdDefUqybnd4V9Cbh_ALjr-qdR7QmaJKHvomIKtYKTNxe8-qQeOVAOwWGdZFhn8fMtHdyy1yktZr8/s1600/Screen+shot+2012-12-10+at+9.58.52+AM.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="193" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUKtiZ5wurEnny1FLarQi_ZhGNc4VTboK0mWQAWK1XojC-QhtjK3r7tDdCZnQjat9qdDefUqybnd4V9Cbh_ALjr-qdR7QmaJKHvomIKtYKTNxe8-qQeOVAOwWGdZFhn8fMtHdyy1yktZr8/s400/Screen+shot+2012-12-10+at+9.58.52+AM.png" /></a></div></li>
</ol><h1>Conclusion</h1><hr/><p>We've have completed our Spring Social-based application using JavaConfig. We're able to post and retrieve profile information from Facebook and Twitter. To provide authentication and security we've added Spring Security. For managing the view layer, we've integrated Thymeleaf as our template engine. As a bonus, we've also provided an XML-based application. </p><p>I hope you've enjoyed this tutorial. Don't forget to check my other tutorials at the <a href="http://krams915.blogspot.com/p/tutorials.html">Tutorials</a> section.</p><h2 class="explanation" style="padding-left:5px;">Revision History</h2><div class="explanation"><table style="width=100%; text-align: left;"><thead> <th style="width:100px">Revision</th> <th style="width:120px">Date</th> <th>Description</th> </thead> <tbody>
<tr> <td>1</td> <td>Dec 10 2012</td> <td>Uploaded tutorial and GitHub repositories</td> </tr>
<tr> <td>2</td> <td>Dec 21 2012</td> <td>Update to Spring 3.2.0.RELEASE</td> </tr>
</tbody> </table></div>Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com30tag:blogger.com,1999:blog-5097100801581543528.post-81679092423837627952012-12-02T18:56:00.004+08:002012-12-12T22:43:27.423+08:00Spring and Thymeleaf with JavaConfig (Part 1)In this tutorial, we will create a CRUD application based on Spring MVC 3.x and Spring Data JPA. We will utilize JavaConfig instead of XML to configure our application. For the view layer, we will use <i>Thymeleaf</i> as our template engine instead of JSP to process our html pages. <br />
<br />
<h2 class="explanation" style="padding-left:5px;">Table of Contents</h2><div class="explanation">Click on a link to jump to that section:<br />
<ol><li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig.html">Functional Specs</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_2.html">Creating the View</a></li>
<ul><li style="margin:0; padding: 0">HTML Mockup</li>
<li style="margin:0; padding: 0">Thymeleaf Integration</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_8540.html">JavaConfig</a></li>
<ul><li style="margin:0; padding: 0">ApplicationContext.java</li>
<li style="margin:0; padding: 0">SpringDataConfig.java</li>
<li style="margin:0; padding: 0">ThymeleafConfig.java</li>
<li style="margin:0; padding: 0">ApplicationInitializer.java</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_4044.html">Layers</a></li>
<ul><li style="margin:0; padding: 0">Domain</li>
<li style="margin:0; padding: 0">Service</li>
<li style="margin:0; padding: 0">Controller</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_4000.html">Running the application</a></li>
<ul><li style="margin:0; padding: 0">Clone from GitHub</li>
<li style="margin:0; padding: 0">Create the Database</li>
<li style="margin:0; padding: 0">Run with Maven and Tomcat 7</li>
<li style="margin:0; padding: 0">Run with Maven and Jetty 8</li>
<li style="margin:0; padding: 0">Import to Eclipse</li>
<li style="margin:0; padding: 0">Validate with W3C</li>
</ul></ol></div><br />
<h2 class="explanation" style="padding-left:5px;">Dependencies</h2><div class="explanation">These are the main Maven dependencies:<br />
<ul><li style="margin:0; padding: 0">Spring 3.2.0.RC1</li>
<li style="margin:0; padding: 0">Spring Data JPA 1.2.0.RELEASE</li>
<li style="margin:0; padding: 0">Thymeleaf 2.0.14</li>
<li style="margin:0; padding: 0">Hibernate 3.6.3.Final</li>
<li style="margin:0; padding: 0">See <a href="https://github.com/krams915/spring-thymeleaf-javaconfig/blob/master/pom.xml">pom.xml</a> for full details</li>
</ul></div><br />
<h2 class="explanation" style="padding-left:5px;">Required Tools</h2><div class="explanation">These are the minimum required tools:<br />
<ul><li style="margin:0; padding: 0">Git</li>
<li style="margin:0; padding: 0">Maven 3.0.4</li>
<li style="margin:0; padding: 0">MySQL</li>
<li style="margin:0; padding: 0">Eclipse IDE or SpringSource Tool Suite (STS)</li>
</ul></div><br />
<h2 class="explanation" style="padding-left:5px;">GitHub Repository</h2><div class="explanation">There are two versions of the application: a JavaConfig-based and an XML config-based app. Both versions are identical in their feature set.<br />
<ul><li style="margin:0; padding: 0"><a href="https://github.com/krams915/spring-thymeleaf-javaconfig">spring-thymeleaf-javaconfig</a></li>
<li style="margin:0; padding: 0"><a href="https://github.com/krams915/spring-thymeleaf-xmlconfig">spring-thymeleaf-xmlconfig</a></li>
</ul></div><br />
<h1>Functional Specs</h1><hr/>Our application's requirements are quite straightforward:<br />
<ul><li style="margin:0; padding: 0">Create a simple form to manage user information</li>
<li style="margin:0; padding: 0">Provide the following fields: first name, last name, username, role</li>
<li style="margin:0; padding: 0">Username must be unique</li>
<li style="margin:0; padding: 0">Provide CRUD operations</li>
<li style="margin:0; padding: 0">Provide table to view all users</li>
</ul><br />
Here's our <i>Use Case</i> diagram:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://yuml.me/diagram/scruffy;/usecase/%5BUser%5D-(Add),%20%5BUser%5D-(View),%20%5BUser%5D-(Update),%20%5BUser%5D-(Delete).png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="392" width="312" src="http://yuml.me/diagram/scruffy;/usecase/%5BUser%5D-(Add),%20%5BUser%5D-(View),%20%5BUser%5D-(Update),%20%5BUser%5D-(Delete).png" /></a></div><br />
<pre style="display: none;">[User]-(Add)
[User]-(View)
[User]-(Update)
[User]-(Delete)
//http://yuml.me/
</pre><br />
Here's a screenshot of our working application:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSDEbt0kL1f_hfVgRWDAlabCdfPwDSFxUl9KWnpFbU1ZEK2rskttjIjot-5DfFgRacawH9TbF2_lM1hVs2T0s-nGv0-qGQ6k8YIZtYvTWb67r1Gom9gJbKycJ78JvGmhsu8Uwoi76F4tI_/s1600/Screen+shot+2012-12-02+at+9.45.07+AM.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="378" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSDEbt0kL1f_hfVgRWDAlabCdfPwDSFxUl9KWnpFbU1ZEK2rskttjIjot-5DfFgRacawH9TbF2_lM1hVs2T0s-nGv0-qGQ6k8YIZtYvTWb67r1Gom9gJbKycJ78JvGmhsu8Uwoi76F4tI_/s400/Screen+shot+2012-12-02+at+9.45.07+AM.png" /></a></div><br />
<h1>Next</h1>In the next section, we will focus on the view layer. We'll start writing the HTML mockup template; then we'll integrate it with Thymeleaf. Click <a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_2.html">here</a> to proceed.Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com41tag:blogger.com,1999:blog-5097100801581543528.post-70618059173577772542012-12-02T18:56:00.003+08:002012-12-12T22:43:37.653+08:00Spring and Thymeleaf with JavaConfig (Part 2)<h1>Review</h1><hr/>In the previous section, we have read the functional specs of the application. In this section, we will focus on the view layer, create an HTML mockup, and integrate our mockup with Thymeleaf.<br />
<br />
<h2 class="explanation" style="padding-left:5px;">Table of Contents</h2><div class="explanation">Click on a link to jump to that section:<br />
<ol><li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig.html">Functional Specs</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_2.html">Creating the View</a></li>
<ul><li style="margin:0; padding: 0">HTML Mockup</li>
<li style="margin:0; padding: 0">Thymeleaf Integration</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_8540.html">JavaConfig</a></li>
<ul><li style="margin:0; padding: 0">ApplicationContext.java</li>
<li style="margin:0; padding: 0">SpringDataConfig.java</li>
<li style="margin:0; padding: 0">ThymeleafConfig.java</li>
<li style="margin:0; padding: 0">ApplicationInitializer.java</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_4044.html">Layers</a></li>
<ul><li style="margin:0; padding: 0">Domain</li>
<li style="margin:0; padding: 0">Service</li>
<li style="margin:0; padding: 0">Controller</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_4000.html">Running the application</a></li>
<ul><li style="margin:0; padding: 0">Clone from GitHub</li>
<li style="margin:0; padding: 0">Create the Database</li>
<li style="margin:0; padding: 0">Run with Maven and Tomcat 7</li>
<li style="margin:0; padding: 0">Run with Maven and Jetty 8</li>
<li style="margin:0; padding: 0">Import to Eclipse</li>
<li style="margin:0; padding: 0">Validate with W3C</li>
</ul></ol></div><br />
<h1>Creating the View</h1><hr/>In designing our application we'll start with the view layer because we can. Thanks to <i>Thymeleaf</i> creating HTML mockups is easy. Thymeleaf allows us to use these mockups as our HTML templates without any aesthetic changes. In addition, it passes <a href="http://validator.w3.org/">W3C Markup Validation Service</a> with flying colors.<br />
<br />
<h2 class="explanation" style="padding-left:5px;">What is Thymeleaf?</h2><blockquote class="explanation">Thymeleaf is a Java library. It is an XML / XHTML / HTML5 template engine (extensible to other formats) that can work both in web and non-web environments. It is better suited for serving XHTML/HTML5 at the view layer of web applications, but it can process any XML file even in offline environments.<br />
<br />
It provides an optional module for integration with Spring MVC, so that you can use it as a complete substitute of JSP in your applications made with this technology, even with HTML5.<br />
<br />
The main goal of Thymeleaf is to provide an elegant and well-formed way of creating templates. Its Standard and SpringStandard dialects allow you to create powerful natural templates, that can be correctly displayed by browsers and therefore work also as static prototypes. You can also extend Thymeleaf by developing your own dialects.<br />
<br />
Source: <a href="http://www.thymeleaf.org/">Thymeleaf.org</a><br />
</blockquote><br />
<h2>HTML Mockup</h2><hr/>Let's create our HTML mockup. You can see the final mockup below:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5HSGjeIhev2IIc5yU7gz9A1MIbeNLFCl9dB3q9fmr9UAfXBpFm4S6LpajxU6_dxe_9IjGH1P_gqIrftEg_eBoxN1BWQFhE_e2Of8cyqCMKeN38W8thsVmdmJswoGF8eXTAZDm3KyFGc5j/s1600/Screen+shot+2012-12-02+at+9.41.19+AM.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="264" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5HSGjeIhev2IIc5yU7gz9A1MIbeNLFCl9dB3q9fmr9UAfXBpFm4S6LpajxU6_dxe_9IjGH1P_gqIrftEg_eBoxN1BWQFhE_e2Of8cyqCMKeN38W8thsVmdmJswoGF8eXTAZDm3KyFGc5j/s400/Screen+shot+2012-12-02+at+9.41.19+AM.png" /></a></div><br />
First, we create a new HTML page. Note that this is a very simple HTML document that validates with <a href="http://validator.w3.org/">W3C Markup Validation Service</a>.<br />
<br />
<script src="https://gist.github.com/4187445.js?file=users.html"></script><br />
<br />
Next, we create an external CSS file. Because I'm not really a designer, I have scoured the web for a simple but elegant table style. I found one from <a href="http://coding.smashingmagazine.com/2008/08/13/top-10-css-table-designs/">Top 10 CSS Table Designs</a>.<br />
<br />
<script src="https://gist.github.com/4187352.js?file=styles.css"></script><br />
<br />
Then, open a browser and test the HTML mockup. You should see something similar to the following image:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5HSGjeIhev2IIc5yU7gz9A1MIbeNLFCl9dB3q9fmr9UAfXBpFm4S6LpajxU6_dxe_9IjGH1P_gqIrftEg_eBoxN1BWQFhE_e2Of8cyqCMKeN38W8thsVmdmJswoGF8eXTAZDm3KyFGc5j/s1600/Screen+shot+2012-12-02+at+9.41.19+AM.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="264" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5HSGjeIhev2IIc5yU7gz9A1MIbeNLFCl9dB3q9fmr9UAfXBpFm4S6LpajxU6_dxe_9IjGH1P_gqIrftEg_eBoxN1BWQFhE_e2Of8cyqCMKeN38W8thsVmdmJswoGF8eXTAZDm3KyFGc5j/s400/Screen+shot+2012-12-02+at+9.41.19+AM.png" /></a></div><br />
<br />
<h2>Thymeleaf Integration</h2><hr/>It's time to integrate Thymeleaf with our HTML mockup template. To integrate Thymeleaf we'll use its attribute-based template engine. Browsers will normally ignore unknown HTML attributes, so it won't affect our mockups.<br />
<br />
Before we proceed, let me provide you a short description of the specific Thymeleaf attributes we'll be using:<br />
<br />
<b>The important attributes</b><br />
<ul><li>The <b>#</b> means to resolve the attribute from the messages bundle</li>
<li>The <b>$</b> means to resolve the attribute from the model</li>
<li>The <b>#</b> and <b>$</b> can be combined together so that messages can be dynamically generated from the model and internationalized from the messages bundle</li>
<li><code class="code-custom ui-corner-top ui-corner-bottom">th:fragment="header" </code><br />
<br />
This allows us to include template fragments from other templates. For example, we can reuse them in footers, headers, and menus. For this tutorial, we won't be reusing the header, but I've added it anyway for future tutorials.<br />
</li>
<li><code class="code-custom ui-corner-top ui-corner-bottom">th:each="u : ${users} </code><br />
<br />
This allows us to loop a list of records. This is equivalent to Java's for-loop construct.<br />
</li>
<li><code class="code-custom ui-corner-top ui-corner-bottom">th:text="${u.id}" </code><br />
<br />
This allows to dynamically set the label of an element.<br />
</li>
<li><code class="code-custom ui-corner-top ui-corner-bottom">th:href="@{/users/delete(id=${u.id})}"> </code><br />
<br />
This allows us to define a dynamic URL.<br />
</li>
<li><code class="code-custom ui-corner-top ui-corner-bottom">th:field="*{id}" </code><br />
<br />
This allows us to define the field where an input's field will be attached to.<br />
</li>
<li><code class="code-custom ui-corner-top ui-corner-bottom">th:remove="all" </code><br />
<br />
This allows us to setup mockup data. Thymeleaf will automatically remove any element contained within this attribute.<br />
</li>
</ul><br />
Let's now apply these attributes. Here's our updated HTML mockup template:<br />
<br />
<b>users.html</b><br />
<script src="https://gist.github.com/4186466.js?file=users.html"></script><br />
<h2>Internationalization</h2><hr/>The <i>th:text</i> attribute allows us to externalize text and with the support of Spring's <i>MessageSource</i>, we are able to parameterize and provide internationalization support.<br />
<br />
<h2 class="explanation" style="padding-left:5px;">What is MessageSource?</h2><blockquote class="explanation">Strategy interface for resolving messages, with support for the parameterization and internationalization of such messages.<br />
<br />
Spring provides two out-of-the-box implementations for production:<br />
<ul><li>ResourceBundleMessageSource, built on top of the standard ResourceBundle</li>
<li>ReloadableResourceBundleMessageSource, being able to reload message definitions without restarting the VM</li>
</ul><br />
Source: <a href="http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/context/MessageSource.html">Spring 3 Docs: MessageSource</a><br />
</blockquote><br />
Notice the <b>th:text</b> attributes. Some of them refer to a dot notation object. Where does <i>Thymeleaf</i> retrieve this information?<br />
<br />
The information is retrieved from the messages_en.properties resource bundle:<br />
<br />
<script src="https://gist.github.com/4188133.js?file=messages_en.properties"></script><br />
We've declared that in the ApplicationContext.java configuration (see next section):<br />
<br />
<script src="https://gist.github.com/4188140.js?file=ApplicationContext.java"></script><br />
<br />
<h2>The Data transfer object (DTO)</h2><hr/>In order for our html page to display data from the Controller, we need to pass a Model attribute. The model attribute is represented by the <i>UserDto</i>. <br />
<br />
<script src="https://gist.github.com/4268110.js"></script><br />
<br />
The fields we declared on the users.html form is based from the fields of the <i>UserDto</i>:<br />
<br />
<script src="https://gist.github.com/4268161.js"></script><br />
<br />
Notice the form has a form-backing object declared named <i>commanduser</i>. Using Thymeleaf's attribute <i>th:object</i>, we're able to declare this form-backing object.<br />
<br />
This object passed from the <i>UserController</i>.<br />
<br />
<script src="https://gist.github.com/4268228.js"></script><br />
<br />
<h1>Next</h1>In the next section, we will focus on the configuration layer. We'll study how to declare a JavaConfig-based configuration. We'll also provide an XML-based configuration for comparison purposes. Click <a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_8540.html">here</a> to proceed.Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com2tag:blogger.com,1999:blog-5097100801581543528.post-51045210949065101792012-12-02T18:56:00.002+08:002012-12-12T22:43:47.649+08:00Spring and Thymeleaf with JavaConfig (Part 3)<h1>Review</h1><hr/>In the previous section, we focused on the view layer and created an HTML mockup template. In this section, we will focus on configuration and declare them using JavaConfig. We will also provide an XML-based config.<br />
<br />
<h2 class="explanation" style="padding-left:5px;">Table of Contents</h2><div class="explanation">Click on a link to jump to that section:<br />
<ol><li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig.html">Functional Specs</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_2.html">Creating the View</a></li>
<ul><li style="margin:0; padding: 0">HTML Mockup</li>
<li style="margin:0; padding: 0">Thymeleaf Integration</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_8540.html">JavaConfig</a></li>
<ul><li style="margin:0; padding: 0">ApplicationContext.java</li>
<li style="margin:0; padding: 0">SpringDataConfig.java</li>
<li style="margin:0; padding: 0">ThymeleafConfig.java</li>
<li style="margin:0; padding: 0">ApplicationInitializer.java</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_4044.html">Layers</a></li>
<ul><li style="margin:0; padding: 0">Domain</li>
<li style="margin:0; padding: 0">Service</li>
<li style="margin:0; padding: 0">Controller</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_4000.html">Running the application</a></li>
<ul><li style="margin:0; padding: 0">Clone from GitHub</li>
<li style="margin:0; padding: 0">Create the Database</li>
<li style="margin:0; padding: 0">Run with Maven and Tomcat 7</li>
<li style="margin:0; padding: 0">Run with Maven and Jetty 8</li>
<li style="margin:0; padding: 0">Import to Eclipse</li>
<li style="margin:0; padding: 0">Validate with W3C</li>
</ul></ol></div><br />
<h1>JavaConfig</h1><hr/>As stated in the introduction, we will be using JavaConfig-based configuration instead of the usual XML config. However, I don't want to alienate our readers who are used to XML. As a result, I've decided to provide both implementations. However, our focus here is still on JavaConfig.<br />
<br />
<b style="color:red">Note:</b> With JavaConfig, we can now omit the ubiquitous <i>web.xml</i>. But in order to that, we need to run a Servlet 3.0 web container. For this tutorial, I have tested the application with Tomcat 7.0.30 (Maven plugin), 7.0.33 (standalone Tomcat), and Jetty 8.1.5.v20120716 (Maven plugin). <br />
<br />
<h2>ApplicationContext.java</h2><hr/>The ApplicationContext.java contains our main configuration. It's responsible for loading other configurations, either as JavaConfig or XML config.<br />
<br />
<script src="https://gist.github.com/4186483.js?file=ApplicationContext.java"></script><br />
<br />
Let's describe each annotation:<br />
<ul><li><code class="code-custom ui-corner-top ui-corner-bottom">@Configuration </code><br />
- Marks a class as a JavaConfig<br />
</li>
<li><code class="code-custom ui-corner-top ui-corner-bottom">@ComponentScan(basePackages = {"org.krams"}) </code><br />
- Configures scanning of Spring components<br />
<br />
This is equivalent in XML as:<br />
<script src="https://gist.github.com/4187720.js?file=context-annotation-config.xml"></script><br />
</li>
<li><code class="code-custom ui-corner-top ui-corner-bottom">@EnableWebMvc <br />
</code><br />
- Activates Spring's MVC support<br />
<br />
This is equivalent in XML as:<br />
<script src="https://gist.github.com/4187728.js?file=mvc-annotation-driven.xml"></script><br />
</li>
<li><code class="code-custom ui-corner-top ui-corner-bottom">@Import({SpringDataConfig.class, ThymeleafConfig.class}) </code><br />
- This allows us to import JavaConfig-based config. Notice we are importing two external configuration classes: SpringDataConfig and ThymeleafConfig<br />
</li>
<li><code class="code-custom ui-corner-top ui-corner-bottom">@ImportResource("classpath:trace-context.xml") </code><br />
- This allows us to import XML-based config files. (As a side note why can't we just declare this as a JavaConfig? It turns out there's no direct translation for the trace-context.xml, so we'll have to import it as XML).<br />
<br />
This is equivalent in XML as:<br />
<script src="https://gist.github.com/4187734.js?file=import-resource.xml"></script><br />
</li>
<li><code class="code-custom ui-corner-top ui-corner-bottom">@PropertySource("classpath:spring.properties") </code><br />
- This allows us to import property files<br />
</li>
<li><code class="code-custom ui-corner-top ui-corner-bottom">@Bean </code><br />
- Declares a Spring bean<br />
</li>
</ul><br />
Here's the equivalent XML configuration:<br />
<br />
<script src="https://gist.github.com/4187691.js?file=applicationContext.xml"></script><br />
<br />
<h2>SpringDataConfig.java</h2><hr/>The SpringDataConfig.java contains our Spring Data configuration. This is where we declare our data source, transaction manager, and JPA entity manager.<br />
<br />
<script src="https://gist.github.com/4186488.js?file=SpringDataConfig.java"></script><br />
<br />
Here's the equivalent XML configuration:<br />
<br />
<script src="https://gist.github.com/4187741.js?file=spring-data.xml"></script><br />
<br />
<h2>ThymeleafConfig.java</h2><hr/>The ThymeleafConfig.java contains our Thymeleaf configuration. This is where we declare our Thymeleaf view resolver.<br />
<br />
<script src="https://gist.github.com/4186491.js?file=ThymeleafConfig.java"></script><br />
<br />
Here's the equivalent XML configuration:<br />
<br />
<script src="https://gist.github.com/4187743.js?file=spring-thymeleaf.xml"></script><br />
<br />
<h2>ApplicationInitializer.java</h2><hr/>The ApplicationInitializer.java is the equivalent of <i>web.xml</i>. Here's where we declare the <i>DispatcherServlet</i>.<br />
<br />
<script src="https://gist.github.com/4186486.js?file=ApplicationInitializer.java"></script><br />
<br />
Here's the equivalent XML configuration:<br />
<br />
<script src="https://gist.github.com/4187745.js?file=web.xml"></script><br />
<br />
<h1>Next</h1>In the next section, we will focus on the remaining layers of our Java application. We'll study the Domain, Repository, Service, and Controller layers. Click <a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_4044.html">here</a> to proceed.Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com3tag:blogger.com,1999:blog-5097100801581543528.post-66924093427963311092012-12-02T18:56:00.001+08:002012-12-12T22:43:59.939+08:00Spring and Thymeleaf with JavaConfig (Part 4)<h1>Review</h1><hr/>In the previous section, we declared our configuration using JavaConfig and compared it side-by-side with an XML-based configuration. In this section, we will discuss the remaining layers of our application.<br />
<br />
<h2 class="explanation" style="padding-left:5px;">Table of Contents</h2><div class="explanation">Click on a link to jump to that section:<br />
<ol><li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig.html">Functional Specs</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_2.html">Creating the View</a></li>
<ul><li style="margin:0; padding: 0">HTML Mockup</li>
<li style="margin:0; padding: 0">Thymeleaf Integration</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_8540.html">JavaConfig</a></li>
<ul><li style="margin:0; padding: 0">ApplicationContext.java</li>
<li style="margin:0; padding: 0">SpringDataConfig.java</li>
<li style="margin:0; padding: 0">ThymeleafConfig.java</li>
<li style="margin:0; padding: 0">ApplicationInitializer.java</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_4044.html">Layers</a></li>
<ul><li style="margin:0; padding: 0">Domain</li>
<li style="margin:0; padding: 0">Service</li>
<li style="margin:0; padding: 0">Controller</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_4000.html">Running the application</a></li>
<ul><li style="margin:0; padding: 0">Clone from GitHub</li>
<li style="margin:0; padding: 0">Create the Database</li>
<li style="margin:0; padding: 0">Run with Maven and Tomcat 7</li>
<li style="margin:0; padding: 0">Run with Maven and Jetty 8</li>
<li style="margin:0; padding: 0">Import to Eclipse</li>
<li style="margin:0; padding: 0">Validate with W3C</li>
</ul></ol></div><br />
<h1>Layers</h1><hr/>Here we'll discuss the Domain, Repository, Service and Controller layers.<br />
<br />
<h2>Domain</h2>Our domain layer consists of two simple classes: <i>User.java</i> and <i>Role.java</i>. If you'd been following my previous tutorials, you will notice that these are the same domain classes we'd been using before. Both classes had been annotated with <i>@Entity</i> which means these are JPA entities and will be persisted to a database.<br />
<br />
These classes represent a user with the following properties: first name, last name, username, role, and password (we're not actively using the password field). <br />
<br />
For role, we only have two values: an admin or a regular user.<br />
<br />
<b>User.java</b><br />
<script src="https://gist.github.com/4186508.js?file=User.java"></script><br />
<br />
<b>Role.java</b><br />
<script src="https://gist.github.com/4186515.js?file=Role.java"></script><br />
<br />
<h2>Controller</h2>Our controller is a standard controller providing CRUD requests. The most important lines here are the following:<br />
<br />
<div class="code-custom ui-corner-top ui-corner-bottom">// Create<br />
model.addAttribute("users", UserMapper.map(users));<br />
model.addAttribute("commanduser", new UserDto());<br />
model.addAttribute("usertype", "new");<br />
</div><br />
<div class="code-custom ui-corner-top ui-corner-bottom">// Update<br />
model.addAttribute("users", UserMapper.map(users));<br />
model.addAttribute("commanduser", UserMapper.map(repository.findOne(id)));<br />
model.addAttribute("usertype", "update");<br />
</div><br />
These lines adds three attributes to the model: <br />
<ul><li><i>users</i> - contains all users</li>
<li><i>commanduser</i> - the form backing object or the command object of the form</li>
<li><i>usertype</i> - an attribute to determine if the request is a new user or existing user<br />
</ul><b>UserController.java</b> <script src="https://gist.github.com/4186502.js?file=UserController.java"></script> <h2>Repository</h2>We have created two repositories: <i>UserRepository</i> and <i>RoleRepository</i>(not shown). We will be using <i>UserRepository</i> as our primary data access object. Notice we have declared a custom method <i>findByUsername</i> but beyond that, this repository is pretty much standard. <b>UserRepository.java</b> <script src="https://gist.github.com/4186518.js?file=UserRepository.java"></script> <h2>Service</h2>Our service layer basically delegates to the repository. It provides an extra logic to filter out duplicate usernames. <b>UserService.java</b> <script src="https://gist.github.com/4186523.js?file=UserService.java"></script> <h1>Next</h1>In the next section, we will study how to build and run our application. We will be using Maven, Tomcat, and Jetty to run the app. We'll also study how to import the project in Eclipse. Click <a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_4000.html">here</a> to proceed.Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com1tag:blogger.com,1999:blog-5097100801581543528.post-28998820486766120532012-12-02T18:56:00.000+08:002012-12-12T22:44:47.407+08:00Spring and Thymeleaf with JavaConfig (Part 5)<h1>Review</h1><hr/>In the previous section, we have discussed the Domain, Repository, Service, and Controller classes. In this section, we will build and run our app. We will also study how to import the project in Eclipse.<br />
<br />
<h2 class="explanation" style="padding-left:5px;">Table of Contents</h2><div class="explanation">Click on a link to jump to that section:<br />
<ol><li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig.html">Functional Specs</a></li>
<li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_2.html">Creating the View</a></li>
<ul><li style="margin:0; padding: 0">HTML Mockup</li>
<li style="margin:0; padding: 0">Thymeleaf Integration</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_8540.html">JavaConfig</a></li>
<ul><li style="margin:0; padding: 0">ApplicationContext.java</li>
<li style="margin:0; padding: 0">SpringDataConfig.java</li>
<li style="margin:0; padding: 0">ThymeleafConfig.java</li>
<li style="margin:0; padding: 0">ApplicationInitializer.java</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_4044.html">Layers</a></li>
<ul><li style="margin:0; padding: 0">Domain</li>
<li style="margin:0; padding: 0">Service</li>
<li style="margin:0; padding: 0">Controller</li>
</ul><li><a href="http://krams915.blogspot.com/2012/12/spring-and-thymeleaf-with-javaconfig_4000.html">Running the application</a></li>
<ul><li style="margin:0; padding: 0">Clone from GitHub</li>
<li style="margin:0; padding: 0">Create the Database</li>
<li style="margin:0; padding: 0">Run with Maven and Tomcat 7</li>
<li style="margin:0; padding: 0">Run with Maven and Jetty 8</li>
<li style="margin:0; padding: 0">Import to Eclipse</li>
<li style="margin:0; padding: 0">Validate with W3C</li>
</ul></ol></div><br />
<h1>Running the Application</h1><hr/><h2>Clone from GitHub</h2>To clone from GitHub, follow these instructions:<br />
<ol><li>Open a Git terminal</li>
<li>Enter the following command:<br />
<div class="code-custom"><pre>git clone https://github.com/krams915/spring-thymeleaf-javaconfig.git</pre></div>This will clone the JavaConfig-based application. <br />
<br />
If you prefer the XML-based version,<br />
<div class="code-custom"><pre>git clone https://github.com/krams915/spring-thymeleaf-xmlconfig.git</pre></div><br />
<h2 class="explanation" style="padding-left:5px;">Remember:</h2><div class="explanation">There are two versions of the application: a JavaConfig-based and an XML config-based app. Both versions are identical in their feature set.<br />
<ul><li style="margin:0; padding: 0"><a href="https://github.com/krams915/spring-thymeleaf-javaconfig">spring-thymeleaf-javaconfig</a></li>
<li style="margin:0; padding: 0"><a href="https://github.com/krams915/spring-thymeleaf-xmlconfig">spring-thymeleaf-xmlconfig</a></li>
</ul></div></ol><h2>Create the Database</h2><ol><li>Run MySQL</li>
<li>Create a new database:<br />
<div class="code-custom"><pre>spring_thymeleaf_tutorial</pre></div></li>
<li>Import the <i>spring_thymeleaf_tutorial.sql</i> from the <i>src/main/resources path</i></li>
</li>
</ol><h2>Run with Maven and Tomcat 7</h2>Ensure Maven is installed first, and you have created the MySQL database <ol><li>Open a terminal</li>
<li>Browse to the directory where you've cloned the project</li>
<li>Enter the following command:<br />
<div class="code-custom"><pre>mvn tomcat7:run</pre></div></li>
<li>You should see the following output:<br />
<pre>[INFO] Scanning for projects...
[INFO]
[INFO] -------------------------------------------------------------
[INFO] Building spring-thymeleaf-tutorial Maven Webapp 0.0.1-SNAPSHOT
[INFO] -------------------------------------------------------------
[INFO]
[INFO] >>> tomcat7-maven-plugin:2.0:run (default-cli) @ spring-thymeleaf-tutorial >>>
...
...
...
Dec 2, 2012 5:38:31 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-bio-8080"]
Dec 2, 2012 5:38:31 PM org.apache.catalina.core.StandardService startInternal
INFO: Starting service Tomcat
Dec 2, 2012 5:38:31 PM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/7.0.30
Dec 2, 2012 5:38:42 PM org.apache.catalina.core.ApplicationContext log
INFO: Spring WebApplicationInitializers detected on classpath: [org.krams.config.ApplicationInitializer@1cc33893]
Dec 2, 2012 5:38:43 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring root WebApplicationContext
Dec 2, 2012 5:38:52 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring FrameworkServlet 'dispatcher'
Dec 2, 2012 5:38:52 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-8080"]
</pre></li>
<li>Open a browser</li>
<li>Visit the following URL:<br />
<div class="code-custom"><pre>http://localhost:8080/spring-thymeleaf-tutorial/users</pre></div></li>
</ol><h2>Run with Maven and Jetty 8</h2>Ensure Maven is installed first, and you have created the MySQL database. <ol><li>Open a terminal</li>
<li>Browse to the directory where you've cloned the project</li>
<li>Enter the following command:<br />
<div class="code-custom"><pre>mvn jetty:run</pre></div></li>
<li>You should see the following output:<br />
<pre>[INFO] Scanning for projects...
[INFO]
[INFO] -------------------------------------------------------------
[INFO] Building spring-thymeleaf-tutorial Maven Webapp 0.0.1-SNAPSHOT
[INFO] -------------------------------------------------------------
[INFO]
[INFO] >>> jetty-maven-plugin:8.1.5.v20120716:run (default-cli) @ spring-thymeleaf-tutorial >>>
...
...
...
2012-12-02 17:42:56.556:INFO:/spring-thymeleaf-tutorial:Initializing Spring FrameworkServlet 'dispatcher'
2012-12-02 17:42:56.760:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:8080
[INFO] Started Jetty Server
</pre></li>
<li>Open a browser</li>
<li>Visit the following URL:<br />
<div class="code-custom"><pre>http://localhost:8080/spring-thymeleaf-tutorial/users</pre></div></li>
</ol><h2>Import to Eclipse</h2>Ensure Maven is installed first <ol><li>Open a terminal</li>
<li>Enter the following command:<br />
<div class="code-custom"><pre>mvn eclipse:eclipse -Dwtpversion=2.0</pre></div></li>
<li>You should see the following output:<br />
<pre>[INFO] Scanning for projects...
[INFO]
[INFO] -------------------------------------------------------------
[INFO] Building spring-thymeleaf-tutorial Maven Webapp 0.0.1-SNAPSHOT
[INFO] -------------------------------------------------------------
[INFO]
[INFO] >>> maven-eclipse-plugin:2.9:eclipse (default-cli) @ spring-thymeleaf-tutorial >>>
...
...
...
[INFO] -------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] -------------------------------------------------------------
[INFO] Total time: 9.356s
[INFO] Finished at: Sun Dec 02 17:46:43 PHT 2012
[INFO] Final Memory: 15M/81M
[INFO] -------------------------------------------------------------
</pre><br />
This command will add the following files to your project: <br />
<pre>.classpath
.project
.settings
target</pre>You may have to enable "show hidden files" in your file explorer to view them.<br />
</li>
<li>Run Eclipse and import the application as Maven project</li>
</ol><h2>Validate with W3C Markup Validation Service</h2>One of the promises of Thymeleaf is it produces valid HTML pages. Let's test that out using W3C validation service. <ol><li>Run the application</li>
<li>Open a browser</li>
<li>Visit the following URL:<br />
<div class="code-custom"><pre>http://localhost:8080/spring-thymeleaf-tutorial/users</pre></div></li>
<li>View the HTML source (right-click or go to menu)</li>
<li>Copy the HTML source</li>
<li>Open W3C Markup Validation Service at http://validator.w3.org/#validate_by_input</li>
<li>Paste the HTML source and wait for the validation result<br />
<br />
You should see a similar output:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYLJcTESDPubnINnB8PIR5mH1BWgRlH6ZMow75PG0VFiPmOWAketJ8QTcPuXNnizS-a32fmbCxnKquw4BLEFBD87iZEc-G72AEA4RTM3zM2Pk94orX3NbG2URddNJtt9HxYawGS1OU5-Zh/s1600/Screen+shot+2012-12-02+at+7.03.01+PM.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="201" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYLJcTESDPubnINnB8PIR5mH1BWgRlH6ZMow75PG0VFiPmOWAketJ8QTcPuXNnizS-a32fmbCxnKquw4BLEFBD87iZEc-G72AEA4RTM3zM2Pk94orX3NbG2URddNJtt9HxYawGS1OU5-Zh/s400/Screen+shot+2012-12-02+at+7.03.01+PM.png" /></a></div></li>
</ol><h1>Conclusion</h1><hr/><p>We've have completed our Spring MVC application with Thymeleaf as our template engine . We've studied how to convert our HTML mockup into a Thymeleaf template that validates with W3C validator service. We've also discussed how to create a JavaConfig-based application. As a bonus, we've also provided an XML-based application. </p><p>I hope you've enjoyed this tutorial. Don't forget to check my other tutorials at the <a href="http://krams915.blogspot.com/p/tutorials.html">Tutorials</a> section.</p><h2 class="explanation" style="padding-left:5px;">Revision History</h2><div class="explanation"><table style="width=100%; text-align: left;"><thead> <th style="width:100px">Revision</th> <th style="width:120px">Date</th> <th>Description</th> </thead> <tbody>
<tr> <td>1</td> <td>Dec 2 2012</td> <td>Uploaded tutorial and GitHub repositories</td> </tr>
<tr> <td>2</td> <td>Dec 3 2012</td> <td>Updated table of contents</td> </tr>
<tr> <td>3</td> <td>Dec 12 2012</td> <td>Updated Part 2</td> </tr>
</tbody> </table></div>Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com16tag:blogger.com,1999:blog-5097100801581543528.post-41444220914900678452012-11-26T19:56:00.001+08:002012-11-28T17:58:45.718+08:00Book Review: Spring DataI'm currently reviewing the book <b>Spring Data</b> from Packt Publishing. You can find the book at <a href="http://www.packtpub.com/spring-data/book">http://www.packtpub.com/spring-data/book</a>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://cdn3.cf.packtpub.com/sites/default/files/imagecache/productview_larger/9045OS_Spring%20Data%20Standard%20Guide_Mini.jpg" imageanchor="1" style="clear:left; float:left;margin-right:1em; margin-bottom:1em"><img border="0" height="213" width="175" src="http://cdn3.cf.packtpub.com/sites/default/files/imagecache/productview_larger/9045OS_Spring%20Data%20Standard%20Guide_Mini.jpg" /></a></div><b>Overview</b><br />
This book is about <a href="http://www.springsource.org/spring-data/jpa">Spring Data JPA</a> and <a href="http://www.springsource.org/spring-data/redis">Spring Data Redis</a><br />
<br />
<ul><li>Implement JPA repositories with lesser code</li>
<li>Includes functional sample projects that demonstrate the described concepts in action and help you start experimenting right away</li>
<li>Provides step-by-step instructions and a lot of code examples that are easy to follow and help you to get started from page one</li>
</ul><br />
<br />
<b>Full review</b><br />
My initial impression of this book is that it's too short and lacks full coverage because it only focuses on Spring Data JPA and Spring Data Redis. We all know how big the Spring Data umbrella projects are. But it turns out this is the strength of the book. By focusing on a subset of Spring Data umbrella projects, it's able to focus better on what matters most.<br />
<br />
As I read the book, I slowly realized that this book is a gem. If you need a solid understanding of Spring Data JPA, read this book. It tells you step-by-step all the possible query technologies, usage patterns, and their pros and cons. The book gradually prepares the reader to the value of Spring Data. <br />
<br />
The Spring Data JPA coverage is quite extensive. It teaches you how to download and install the necessary libraries. Configuration is based on programmatic configuration instead of the usual XML configuration files. I think this is good but also bad. It would be great if the book offers sample configuration both in XML and Java-based config. Since most users are familiar with XML configuration, translating from Java-based config would require extra effort to comprehend for most Spring users. Anyway, that's a minor weakness that we can live-up with. <br />
<br />
The book is successful in demonstrating how to provide CRUD support through Spring Data JPA and how to implement your own custom repository. There are various way to perform queries in Spring Data JPA, and I think the book has managed to cover all of them, including QueryDSL.<br />
<br />
The book's coverage on Spring Data Redis is extensive. It covers installation and configuration, connector types, Redis data structures, and of course, Spring Data support for Redis. The book teaches how to save relational data and perform CRUD operations in a NoSQL manner. It also covers messaging and caching support with Redis. Overall it's a pleasant read. It's interesting how the book has smoothly transitioned from Spring Data JPA to Redis.<br />
<br />
Overall, Spring Data from Packt Publishing is a solid book that I recommend to everyone to read. Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com14tag:blogger.com,1999:blog-5097100801581543528.post-42160098806445088522012-11-20T13:49:00.002+08:002012-11-20T19:42:16.751+08:00Spring MVC 3.2 with Spring Data Rest (Part 1)In this tutorial, we will update an existing Spring MVC app to Spring MVC 3.2 and add RESTful endpoints using <i>Spring Data Rest</i>. The goal is to demonstrate how we can implement <i>HATEOAS</i> methodology using Spring.<br />
<br />
Before we start, please take some time to review our existing application: <a href="http://krams915.blogspot.com/2012/01/spring-mvc-31-jqgrid-and-spring-data_1887.html">Spring MVC 3.1, jqGrid, and Spring Data JPA Integration Guide</a>. If all you need is a pure Spring Data Rest application, please visit the official <a href="https://github.com/SpringSource/spring-data-rest-webmvc">Spring Data Rest starter web application</a>.<br />
<br />
<div class="explanation"><h2>Table of Contents</h2><a href="http://krams915.blogspot.com/2012/11/spring-mvc-32-with-spring-data-rest.html">Part 1: Configuration</a><br />
<ul><li style="margin:0; padding: 0">Update the <i>pom.xml</i></li>
<li style="margin:0; padding: 0">Update the <i>web.xml</i></li>
<li style="margin:0; padding: 0">Spring Configurations</li>
<li style="margin:0; padding: 0">Repositories</li>
</ul><a href="http://krams915.blogspot.com/2012/11/spring-mvc-32-with-spring-data-rest_20.html">Part 2: Running the application</a><br />
</div><br />
<div class="explanation"><h2>Dependencies</h2><ul style="margin-top: 0px; padding-top: 0px"><li style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; ">Spring core 3.2.0.RC1</li>
<li style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; ">Spring Data Rest 1.0.0.RC3</li>
<li style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; ">Spring Data JPA 1.1.0.RELEASE</li>
<li style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; ">jQuery 1.6.4</li>
<li style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; ">jqGrid 4.3.1</li>
<li style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; ">See <a href="https://github.com/krams915/spring-data-rest-tutorial/blob/master/pom.xml">pom.xml</a> for details</li>
</ul></div><b><br />
Github</b><br />
To access the source code, please visit the project's Github repository (<a href="https://github.com/krams915/spring-data-rest-tutorial">click here</a>)<br />
<br />
<h1>Update the pom.xml</h1>Here are the changes that we need to do:<br />
<ul><li>Update the Spring core version</li>
<li>Update the Spring Data JPA version</li>
<li>Add Spring Data Rest dependency</li>
</ul><br />
<script src="https://gist.github.com/4109760.js?file=pom.xml"></script><br />
<br />
Note: I also added the <i>profiles</i> section at the end of the pom.xml, so that we can expose the repositories in a clean manner.<br />
<br />
<h1>Update the web.xml</h1>Here are the changes that we need to do:<br />
<ul><li>Update the <i>web-app</i> version to 2.5 (optional)</li>
<li>Update the <i>display-name</i> (optional)</li>
<li>Add Spring Data Rest servlet</li>
</ul><br />
<script src="https://gist.github.com/4109790.js?file=web.xml"></script><br />
<br />
<h1>Spring Configurations</h1>We need to do three tasks:<br />
<ul><li>Update the database name</li>
<li>Create a spring-data-rest.xml</li>
<li>Update the applicationContext.xml</li>
</ul><br />
<h2>Update the database name</h2>Open the <i>spring.properties</i> under WEB-INF folder, and update it as follows:<br />
<script src="https://gist.github.com/4109800.js?file=spring.properties"></script><br />
<br />
In the original application, the declared database name is <i>spring_jqgrid_tutorial</i>, let's update it to <i>spring_data_rest_tutorial</i> (though this is really not needed).<br />
<br />
<h2>Create a spring-data-rest.xml</h2><script src="https://gist.github.com/4109840.js?file=spring-data-rest.xml"></script><br />
<br />
<h2>Update the applicationContext.xml</h2>There's not much update here. We just need to import the <i>spring-data-rest.xml</i> as follows:<br />
<script src="https://gist.github.com/4109845.js?file=applicationContext.xml"></script><br />
<br />
<h1>Repositories</h1>We need to do two tasks:<br />
<ul><li>Update <i>UserRepository</i></li>
<li>Create a new repository <i>RoleRepository</i></li>
</ul><br />
The only update here is the addition of the annotation <i>@Param</i> to the <i>UserRepository</i>. This is required so that we can expose the parameters in the search queries.<br />
<script src="https://gist.github.com/4109820.js?file=UserRepository.java"></script><br />
<br />
We need to create a new repository for the <i>Role</i> domain so that we can expose it as RESTful endpoint:<br />
<script src="https://gist.github.com/4116138.js?file=RoleRepository.java"></script><br />
<br />
<h1>Next</h1>In the next section, we will build and run the application and test our RESTful endpoints. <a href="http://krams915.blogspot.com/2012/11/spring-mvc-32-with-spring-data-rest_20.html">Click here to proceed</a>.Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com10tag:blogger.com,1999:blog-5097100801581543528.post-35931153477035966942012-11-20T13:49:00.001+08:002012-11-20T19:53:18.344+08:00Spring MVC 3.2 with Spring Data Rest (Part 2)<h1>Review</h1>In the previous section, we have updated our app's configuration, so that our repositories are exposed as RESTful endpoints. We've also applied the <i>HATEOAS</i> methodology which "serves to decouple client and server in a way that allows the server to evolve functionality independently" (Wikipedia). In this section, we will build and run the application using Maven, demonstrate how to import the project in Eclipse, and run a series of manual tests to examine the RESTful endpoints.<br />
<br />
<div class="explanation"><h2>Table of Contents</h2><a href="http://krams915.blogspot.com/2012/11/spring-mvc-32-with-spring-data-rest.html">Part 1: Configuration</a><br />
<ul><li style="margin:0; padding: 0">Update the <i>pom.xml</i></li>
<li style="margin:0; padding: 0">Update the <i>web.xml</i></li>
<li style="margin:0; padding: 0">Update Spring configurations</li>
<li style="margin:0; padding: 0">Update the repositories</li>
</ul><a href="http://krams915.blogspot.com/2012/11/spring-mvc-32-with-spring-data-rest_20.html">Part 2: Running the application</a><br />
</div><br />
<blockquote class="explanation"><b>What is HATEOAS?</b><br />
<br />
HATEOAS, an abbreviation for Hypermedia as the Engine of Application State, is a constraint of the REST application architecture that distinguishes it from most other network application architectures. The principle is that a client interacts with a network application entirely through hypermedia provided dynamically by application servers. A REST client needs no prior knowledge about how to interact with any particular application or server beyond a generic understanding of hypermedia. Contrast this with e.g. a service-oriented architecture (SOA), where clients and servers interact through a fixed interface shared through documentation or an interface description language (IDL).<br />
<br />
The HATEOAS constraint serves to decouple client and server in a way that allows the server to evolve functionality independently.<br />
<br />
<i>Source</i>: http://en.wikipedia.org/wiki/HATEOAS<br />
</blockquote><br />
<br />
<h1>Running the Application</h1><h2>Access the source code</h2>To download the source code, please visit the project's Github repository (<a href="https://github.com/krams915/spring-data-rest-tutorial">click here</a>)<br />
<br />
<h2>Preparing the data source</h2><ol><li>Run MySQL (install one if you don't have one yet)</li>
<li>Create a new database:<br />
<div class="code-custom"><pre>spring_data_rest_tutorial</pre></div></li>
<li>Import the following file which is included in the source code under the <b>src/main/resources</b> folder:<br />
<div class="code-custom"><pre>spring_data_rest_tutorial.sql</pre></div></li>
</ol><br />
<h2>Building with Maven</h2><ol><li>Ensure Maven is installed</li>
<li>Open a command window (Windows) or a terminal (Linux/Mac)</li>
<li>Run the following command:<br />
<div class="code-custom"><pre>mvn tomcat:run</pre></div></li>
<li>You should see the following output:<br />
<pre>[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'tomcat'.
[INFO]
[INFO] --------------------------------------------------------------
[INFO] Building spring-data-rest-tutorial Maven Webapp 0.0.1-SNAPSHOT
[INFO] --------------------------------------------------------------
[INFO]
[INFO] Preparing tomcat:run
[INFO] [apt:process {execution: default}]
[INFO] [resources:resources {execution: default-resources}]
[INFO] [tomcat:run {execution: default-cli}]
[INFO] Running war on http://localhost:8080/spring-data-rest-tutorial
Nov 20, 2012 8:01:45 PM org.apache.catalina.startup.Embedded start
INFO: Starting tomcat server
Nov 20, 2012 8:01:45 PM org.apache.catalina.core.StandardEngine start
INFO: Starting Servlet Engine: Apache Tomcat/6.0.29
Nov 20, 2012 8:01:46 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring root WebApplicationContext
Nov 20, 2012 8:02:01 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring FrameworkServlet 'rest-exporter'
Nov 20, 2012 8:02:03 PM org.apache.coyote.http11.Http11Protocol init
INFO: Initializing Coyote HTTP/1.1 on http-8080
Nov 20, 2012 8:02:03 PM org.apache.coyote.http11.Http11Protocol start
INFO: Starting Coyote HTTP/1.1 on http-8080
</pre></li>
<span style="color:red; font-weight: bold">Note:</span> <span style="color:red">If the project will not build due to missing repositories, please enable the repositories section in the pom.xml!</span> </ol><br />
<h2>Access the grid page</h2>This displays a grid that allows us to experiment with the data visually. <br />
<ol><li>Follow the steps with Building with Maven</li>
<li>Open a browser</li>
<li>Enter the following URL (8080 is the default port for Tomcat):<br />
<div class="code-custom"><pre>http://localhost:8080/spring-data-rest-tutorial/</pre></div></li>
</ol><br />
<h2>Access the RESTful entry endpoint</h2>We've declared entry endpoint in <i>spring-data-rest.xml</i> and <i>web.xml</i> files.<br />
<ol><li>Follow the steps with Building with Maven</li>
<li>Open a browser</li>
<li>Enter the following URL:<br />
<div class="code-custom"><pre>http://localhost:8080/spring-data-rest-tutorial/api/</pre></div><br />
This gives the following result:<br />
<div class="code-custom"><pre>{
"links" : [ {
"rel" : "role",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/role"
}, {
"rel" : "user",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user"
} ],
"content" : [ ]
}
</pre></div></li>
</ol><br />
<br />
<h2>Access the User endpoint</h2><ol><li>Enter the following URL:<br />
<div class="code-custom"><pre>http://localhost:8080/spring-data-rest-tutorial/api/user</pre></div><br />
This gives the following result:<br />
<div class="code-custom"><pre>{
"links" : [ {
"rel" : "user.search",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/search"
} ],
"content" : [ {
"links" : [ {
"rel" : "self",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/1"
}, {
"rel" : "user.User.role",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/1/role"
} ],
"lastName" : "Smith",
"username" : "john",
"firstName" : "John",
"password" : "21232f297a57a5a743894a0e4a801fc3"
}, {
"links" : [ {
"rel" : "self",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/2"
}, {
"rel" : "user.User.role",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/2/role"
} ],
"lastName" : "Adams",
"username" : "jane",
"firstName" : "Jane",
"password" : "ee11cbb19052e40b07aac0ca060c23ee"
},
... (TRUNCATED)
... (TRUNCATED)
... (TRUNCATED)
{
"links" : [ {
"rel" : "self",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/13"
}, {
"rel" : "user.User.role",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/13/role"
} ],
"lastName" : "Zeigler",
"username" : "edward",
"firstName" : "Edward",
"password" : "mncmksk"
} ],
"page" : {
"size" : 20,
"totalElements" : 13,
"totalPages" : 1,
"number" : 1
}
}
</pre></div></li>
</ol><br />
<br />
<h2>Access the User endpoint with a limit</h2><ol><li>Enter the following URL:<br />
<div class="code-custom"><pre>http://localhost:8080/spring-data-rest-tutorial/api/user?limit=2</pre></div><br />
This gives the following result:<br />
<div class="code-custom"><pre>{
"links" : [ {
"rel" : "user.next",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user?page=2&limit=2"
}, {
"rel" : "user.search",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/search"
} ],
"content" : [ {
"links" : [ {
"rel" : "self",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/1"
}, {
"rel" : "user.User.role",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/1/role"
} ],
"lastName" : "Smith",
"username" : "john",
"firstName" : "John",
"password" : "21232f297a57a5a743894a0e4a801fc3"
}, {
"links" : [ {
"rel" : "self",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/2"
}, {
"rel" : "user.User.role",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/2/role"
} ],
"lastName" : "Adams",
"username" : "jane",
"firstName" : "Jane",
"password" : "ee11cbb19052e40b07aac0ca060c23ee"
} ],
"page" : {
"size" : 2,
"totalElements" : 12,
"totalPages" : 6,
"number" : 1
}
}
</pre></div><br />
Notice the result also provided the endpoint for search and each person's record.<br />
</li>
</ol><br />
<h2>Let's do a search</h2><ol><li>Open a browser</li>
<li>Enter the following URL:<br />
<div class="code-custom"><pre>http://localhost:8080/spring-data-rest-tutorial/api/user/search</pre></div><br />
This gives the following result:<br />
<div class="code-custom"><pre>{
"links" : [ {
"rel" : "user.findByFirstNameLike",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/search/findByFirstNameLike"
}, {
"rel" : "user.findByUsernameLike",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/search/findByUsernameLike"
}, {
"rel" : "user.findByFirstNameLikeAndLastNameLike",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/search/findByFirstNameLikeAndLastNameLike"
}, {
"rel" : "user.findByUsername",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/search/findByUsername"
}, {
"rel" : "user.findByLastNameLike",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/search/findByLastNameLike"
}, {
"rel" : "user.findByRole",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/search/findByRole"
} ],
"content" : [ ]
}
</pre></div><br />
This exposes all the queries we declared in the <i>UserRepository</i> interface.<br />
</li>
<li>Let's try searching by username.</li>
<li>Enter the following URL:<br />
<div class="code-custom"><pre>http://localhost:8080/spring-data-rest-tutorial/api/user/search/findByUsername?username=john</pre></div><br />
This gives the following result:<br />
<div class="code-custom"><pre>{
"links" : [ ],
"content" : [ {
"links" : [ {
"rel" : "self",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/1"
}, {
"rel" : "user.User.role",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/1/role"
} ],
"lastName" : "Smith",
"username" : "john",
"firstName" : "John",
"password" : "21232f297a57a5a743894a0e4a801fc3"
} ]
}
</pre></div><br />
</li>
</ol><br />
<br />
<h2>Delete a record</h2>You are required to have <a href="http://curl.haxx.se/">curl </a>installed.<br />
<ol><li>Open a command line.</li>
<li>Enter the following command:<br />
<div class="code-custom"><pre>curl -v -X DELETE http://localhost:8080/spring-data-rest-tutorial/api/user/3</pre></div><br />
This gives the following output:<br />
<div class="code-custom"><pre>* About to connect() to localhost port 8080 (#0)
* Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 8080 (#0)
> DELETE /spring-data-rest-tutorial/api/user/3 HTTP/1.1
> User-Agent: curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7 OpenSSL/0.9.8r zlib/1.2.3
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 204 No Content
< Server: Apache-Coyote/1.1
< Date: Mon, 19 Nov 2012 14:32:05 GMT
<
* Connection #0 to host localhost left intact
* Closing connection #0
</pre>
</div>If you check the records, notice that User with id 3 has been deleted.
</li>
</ol><h2>Add a record</h2>You are required to have <a href="http://curl.haxx.se/">curl </a>installed.
<ol><li>Open a command line.</li>
<li>Enter the following command:<br />
<div class="code-custom"><pre>curl -v -d '{"username":"homer", "firstName":"Homer", "lastName":"Simpson", "password":"12345678"}' -H "Content-Type: application/json" http://localhost:8080/spring-data-rest-tutorial/api/user</pre><br />
Under Windows use the following command instead:<br />
<pre>curl -v -d "{\"username\":\"homer\", \"firstName\":\"Homer\", \"lastName\":\"Simpson\", \"password\":\"12345678\"}" -H "Content-Type: application/json" http://localhost:8080/spring-data-rest-tutorial/api/user
</pre></div><br />
This adds a <i>User</i> record and gives the following output:<br />
<div class="code-custom"><pre>* About to connect() to localhost port 8080 (#0)
* Trying 127.0.0.1... connected
> POST /spring-data-rest-tutorial/api/user HTTP/1.1
> User-Agent: curl/7.22.0 (i386-pc-win32) libcurl/7.22.0 OpenSSL/1.0.0e zlib/1.2
.5
> Host: localhost:8080
> Accept: */*
> Content-Type: application/json
> Content-Length: 86
>
* upload completely sent off: 86out of 86 bytes
< HTTP/1.1 201 Created
< Server: Apache-Coyote/1.1
< Location: http://localhost:8080/spring-data-rest-tutorial/api/user/14
< Content-Type: application/octet-stream
< Content-Length: 0
< Date: Tue, 20 Nov 2012 04:58:56 GMT
<
* Connection #0 to host localhost left intact
* Closing connection #0
</pre>
</div></li>
<li>However, a <i>Role</i> has not been associated with this <i>User</i> record. We have to manually create and associate one. Open a command line.</li>
<li>Enter the following command:<br />
<div class="code-custom"><pre>curl -v -d '{"role":"1","user": {"rel": "user","href": "http://localhost:8080/spring-data-rest-tutorial/api/user/14"}}' -H "Content-Type: application/json" http://localhost:8080/spring-data-rest-tutorial/api/role</pre><br />
Under Windows use the following command instead:<br />
<pre>curl -v -d "{\"role\":\"1\",\"user\": {\"rel\": \"user\",\"href\": \"http://localhost:8080/spring-data-rest-tutorial/api/user/14\"}}" -H "Content-Type: application/json" http://localhost:8080/spring-data-rest-tutorial/api/role
</pre></div><br />
This adds a <i>Role</i> record and gives the following output:<br />
<div class="code-custom"><pre>* About to connect() to localhost port 8080 (#0)
* Trying 127.0.0.1... connected
> POST /spring-data-rest-tutorial/api/role HTTP/1.1
> User-Agent: curl/7.22.0 (i386-pc-win32) libcurl/7.22.0 OpenSSL/1.0.0e zlib/1.2
.5
> Host: localhost:8080
> Accept: */*
> Content-Type: application/json
> Content-Length: 106
>
* upload completely sent off: 106out of 106 bytes
< HTTP/1.1 201 Created
< Server: Apache-Coyote/1.1
< Location: http://localhost:8080/spring-data-rest-tutorial/api/role/14
< Content-Type: application/octet-stream
< Content-Length: 0
< Date: Tue, 20 Nov 2012 04:59:57 GMT
<
* Connection #0 to host localhost left intact
* Closing connection #0
</pre>
</div></li>
<li>Examine the output and we should see the new record:<br />
<div class="code-custom"><pre>http://localhost:8080/spring-data-rest-tutorial/api/user/14
{
"links" : [ {
"rel" : "self",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/14"
}, {
"rel" : "user.User.role",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/14/role"
} ],
"lastName" : "Simpson",
"username" : "homer",
"firstName" : "Homer",
"password" : "12345678"
}
http://localhost:8080/spring-data-rest-tutorial/api/user/14/role
{
"links" : [ {
"rel" : "self",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/role/14"
}, {
"rel" : "role.Role.user",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/role/14/user"
}, {
"rel" : "user.User.role",
"href" : "http://localhost:8080/spring-data-rest-tutorial/api/user/14/role"
} ],
"role" : 1
}
</pre></div></li>
<li>Examine the grid and we shall see the new record as well:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEio40vAV6iskNHlLYuBsJs720_egq-hhyJ5dVdQvx5s_skqvCEDm5jl2V7lrBTitNK-kJxfIQz-UTXG_CWk7PKCubOCApr27tgp7R_j-PG5o-GwI2ptT1nr6p2O19yAg7HoxsfmjwueEgqG/s1600/MWSnap077.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="223" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEio40vAV6iskNHlLYuBsJs720_egq-hhyJ5dVdQvx5s_skqvCEDm5jl2V7lrBTitNK-kJxfIQz-UTXG_CWk7PKCubOCApr27tgp7R_j-PG5o-GwI2ptT1nr6p2O19yAg7HoxsfmjwueEgqG/s400/MWSnap077.png" /></a></div><br />
</li>
</ol><b>Note</b>: You can do more with Spring Data Rest. I suggest reading the docs further for more info.
<h2>Import the project in Eclipse</h2><ol><li>Ensure Maven is installed</li>
<li>Open a command window (Windows) or a terminal (Linux/Mac)</li>
<li>Run the following command:<br />
<div class="code-custom"><pre>mvn eclipse:eclipse -Dwtpversion=2.0</pre></div></li>
<li>You should see the following output:<br />
<pre>[INFO] Scanning for projects...
[INFO]
[INFO] --------------------------------------------------
[INFO] Building spring-data-rest-tutorial Maven Webapp 0.0.1-SNAPSHOT
[INFO] ---------------------------------------------------
[INFO]
[INFO] Adding support for WTP version 2.0.
[INFO]
[INFO] --------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] --------------------------------------------------
</pre>This command will add the following files to your project: <br />
<pre>.classpath
.project
.settings
target</pre>You may have to enable "show hidden files" in your file explorer to view them<br />
</li>
<li>Open Eclipse and import the project</li>
</ol><h1>Conclusion</h1><p>That's it! We've have successfully updated our Spring MVC application and exposed our repositories as RESTful endpoints using Spring Data Rest. We've also demonstrated how to access our application using pure hyperlinks with <i>HATEOAS</i> methodology.</p><p>I hope you've enjoyed this tutorial. Don't forget to check my other tutorials at the <a href="http://krams915.blogspot.com/p/tutorials.html">Tutorials</a> section.</p><div class="explanation"><h2>Revision History</h2><hr/><table style="width=100%; text-align: left;"><thead> <th style="width:100px">Revision</th> <th style="width:120px">Date</th> <th>Description</th> </thead> <tbody>
<tr> <td>1</td> <td>Nov 20 2012</td> <td>Uploaded tutorial and Github repository</td> </tr>
</tbody> </table></div>Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com8tag:blogger.com,1999:blog-5097100801581543528.post-51842499133246434752012-08-02T23:19:00.000+08:002012-08-12T18:27:35.417+08:00Copy-maven-plugin UpdatesThis will be a short post.<br />
<br />
I have received a couple of complaints regarding the <i><a href="http://evgeny-goldin.com/wiki/Copy-maven-plugin">copy-maven-plugin</a></i> that I use for copying resources (see the sample poms from my projects). Initially I thought it was just a Maven issue, but it turns out the author has changed the plugin totally (including the repository). <br />
<br />
In order to continue using this excellent plugin, you need to update your copy-maven-plugin declaration in the project's <i>pom.xml</i><br />
<br />
<script src="https://gist.github.com/3237854.js?file=pom.xml"></script><br />
<br />
<blockquote class="explanation"><b>What is Copy-maven-plugin?</b><br />
<br />
Most build scripts or applications operate with lots and lots of archives: big, small, huge, "*.zip", and "*.tar.gz". Their content comes from various resources: files, directories, Maven dependencies and other archives, sometimes downloaded from HTTP or FTP. The resulting archives may need to become Maven artifacts and occasionally uploaded back to FTP or SCP.<br />
<br />
Eventually, when one needs to perform above operations, the result is usually a messy POM with quite a few plugin configurations and Ant snippets. "copy-maven-plugin" solves this issue and provides an elegant solution for all above tasks. It allows you to easily perform and configure the following operations:<br />
<br />
<ol><li>Copy files, directories and Maven dependencies.</li>
<li>Filter and replace text files as they're copied.</li>
<li>Pack, update, and unpack archives, zip entries and Maven dependencies.</li>
<li>Attach archives created as Maven artifacts or deploy them directly to Maven repository manager.</li>
<li>Download and upload archives from and to HTTP, SCP, and FTP.</li>
<li>Use Groovy "extension points" for text replaces, files filtering and post-processing.</li>
</ol><br />
See <a href="http://evgeny-goldin.com/wiki/Copy-maven-plugin">copy-maven-plugin</a> for reference<br />
</blockquote><br />
<h2>Updates as of August 12, 2012 6:21pm</h2><br />
Apparently, there are still problems with the latest <b>copy-maven-plugin</b> from goldin. Here are the problems:<br />
<br />
<ul><li>Latest plugin version uses Maven 3. All of my projects are built on Maven 2. By default, it should be compatible with Maven 3. However, the <i>copy-maven-plugin</i> has some issues working on Maven 2's structure if run on Maven 3.<br />
<li>Older version of the <i>copy-maven-plugin</i> no longer exists in its old repository. If it doesn't exist, then you won't be able to retrieve it</li><br />
</ul>
And because of these, I've decided to resort to the more standard, though less flexible <i>maven-resources-plugin</i>.
You should replace all instances of the goldin plugin (see the pom.xml) with the following:
<script src="https://gist.github.com/3331074.js?file=pom.xml"></script>
<br />
Thank you.<br />
Krams<br />
<br />Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com6tag:blogger.com,1999:blog-5097100801581543528.post-84515561462419238242012-07-08T19:35:00.001+08:002012-07-08T19:35:38.855+08:00Email with Attachments via Spring and SendGrid (Part 5)<h1>Review</h1>We have just completed our application. In the previous sections, we have discussed the functional specs, created the Java classes, declared the configuration files, and wrote the HTML form. In this section, we will build and run the application using Maven, and show how to import the project in Eclipse.<br />
<br />
<div class="explanation"><h2>Table of Contents</h2><a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and.html">Part 1: Introduction and Functional Specs</a><br />
<a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_08.html">Part 2: Java classes</a><br />
<a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_6269.html">Part 3: XML configuration</a><br />
<a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_197.html">Part 4: HTML form</a><br />
<a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_5148.html">Part 5: Running the Application</a><br />
</div><br />
<h1>Running the Application</h1><h2>Access the source code</h2>To download the source code, please visit the project's Github repository (<a href="https://github.com/krams915/spring-emailupload-tutorial/tree/master/spring-emailupload-tutorial">click here</a>)<br />
<br />
<h2>Building with Maven</h2><ol><li>Ensure Maven is installed</li>
<li>Open a command window (Windows) or a terminal (Linux/Mac)</li>
<li>Run the following command:<br />
<div class="code-custom"><pre>mvn tomcat:run</pre></div></li>
<li>You should see the following output:<br />
<pre>[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'tomcat'.
[INFO] artifact org.codehaus.mojo:tomcat-maven-plugin: checking for updates from central
[INFO] artifact org.codehaus.mojo:tomcat-maven-plugin: checking for updates from snapshots
[INFO] ------------------------------------------
[INFO] Building spring-emailupload-tutorial Maven Webapp
[INFO] task-segment: [tomcat:run]
[INFO] ------------------------------------------
[INFO] Preparing tomcat:run
[INFO] [apt:process {execution: default}]
[INFO] [resources:resources {execution: default-resources}]
[INFO] [tomcat:run {execution: default-cli}]
[INFO] Running war on http://localhost:8080/spring-emailupload-tutorial
Jul 8, 2012 7:22:24 PM org.apache.catalina.startup.Embedded start
INFO: Starting tomcat server
Jul 8, 2012 7:22:25 PM org.apache.catalina.core.StandardEngine start
INFO: Starting Servlet Engine: Apache Tomcat/6.0.29
Jul 8, 2012 7:22:25 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring root WebApplicationContext
Jul 8, 2012 7:22:27 PM org.apache.coyote.http11.Http11Protocol init
INFO: Initializing Coyote HTTP/1.1 on http-8080
Jul 8, 2012 7:22:27 PM org.apache.coyote.http11.Http11Protocol start
INFO: Starting Coyote HTTP/1.1 on http-8080
</pre></li>
<span style="color:red; font-weight: bold">Note:</span> <span style="color:red">If the project will not build due to missing repositories, please enable the repositories section in the pom.xml!</span> </ol><br />
<h2>Access the Entry page</h2><ol><li>Follow the steps with Building with Maven</li>
<li>Open a browser</li>
<li>Enter the following URL (8080 is the default port for Tomcat):<br />
<div class="code-custom"><pre>http://localhost:8080/spring-emailupload-tutorial/email</pre></div></li>
</ol><br />
<h2>Compose a message</h2><ol><li>Fill-in the To fields</li>
<li>Fill-in the Cc field</li>
<li>Fill-in the From fields</li>
<li>Fill-in the Subject field</li>
<li>Fill-in the Message field</li>
</ol><br />
<br />
<h2>Attach a file</h2><ol><li>Click on "Add a file"</li>
<li>Browse for a file and add it. Check the logs and you should see something similar to the following:<br />
<pre class="code-custom ui-corner-top ui-corner-bottom">[DEBUG] [http-8080-4 07:29:06] (TraceInterceptor.java:writeToLog:21) Entering EmailController.upload(org.springframework.web.multipart.commons.CommonsMultipartFile@1b7a72b)
[DEBUG] [http-8080-4 07:29:06] (EmailController.java:upload:49) Dummy1.jpg - 15009
[DEBUG] [http-8080-4 07:29:06] (TraceInterceptor.java:writeToLog:21) Leaving EmailController.upload(): [UploadedFile [name=Dummy1.jpg, size=15009, url=null, thumbnail_url=null, delete_url=null, delete_type=null]]
</pre></li>
</ol><br />
<h2>Attach multiple files</h2><ol><li>Click on "Add another file"</li>
<li>Browse for files and add them. Check the logs and you should see something similar to the following:<br />
<pre class="code-custom ui-corner-top ui-corner-bottom">[DEBUG] [http-8080-4 07:29:43] (TraceInterceptor.java:writeToLog:21) Entering EmailController.upload(org.springframework.web.multipart.commons.CommonsMultipartFile@ba2b6b)
[DEBUG] [http-8080-4 07:29:43] (EmailController.java:upload:49) Dummy2.jpg - 30364
[DEBUG] [http-8080-4 07:29:43] (TraceInterceptor.java:writeToLog:21) Leaving EmailController.upload(): [UploadedFile [name=Dummy2.jpg, size=30364, url=null, thumbnail_url=null, delete_url=null, delete_type=null]]
[DEBUG] [http-8080-2 07:29:43] (TraceInterceptor.java:writeToLog:21) Entering EmailController.upload(org.springframework.web.multipart.commons.CommonsMultipartFile@788a7b)
[DEBUG] [http-8080-2 07:29:43] (EmailController.java:upload:49) Dummy3.jpg - 17677
[DEBUG] [http-8080-2 07:29:43] (TraceInterceptor.java:writeToLog:21) Leaving EmailController.upload(): [UploadedFile [name=Dummy3.jpg, size=17677, url=null, thumbnail_url=null, delete_url=null, delete_type=null]]
</pre></li>
</ol><br />
<h2>Send the email</h2><ol><li>Click on "Send" to send the email. Check the logs and you should see something similar to the following:<br />
<pre class="code-custom ui-corner-top ui-corner-bottom">[DEBUG] [http-8080-1 07:32:09] (TraceInterceptor.java:writeToLog:21) Entering EmailController.send(Message [senderName=, senderEmail=krams915@yahoo.com, ccEmail=, subject=Test, body=Test, receiverName=, receiverEmail=flamark_915@yahoo.com, filename=Dummy1.jpg,Dummy2.jpg,Dummy3.jpg])
[DEBUG] [http-8080-1 07:32:09] (TraceInterceptor.java:writeToLog:21) Entering SendGridEmailService.send(Message [senderName=, senderEmail=krams915@yahoo.com, ccEmail=, subject=Test, body=Test, receiverName=, receiverEmail=flamark_915@yahoo.com, filename=Dummy1.jpg,Dummy2.jpg,Dummy3.jpg])
[DEBUG] [http-8080-1 07:32:20] (TraceInterceptor.java:writeToLog:21) Leaving SendGridEmailService.send(): StatusResponse [success=true, message=Message sent, ]
[DEBUG] [http-8080-1 07:32:20] (TraceInterceptor.java:writeToLog:21) Leaving EmailController.send(): StatusResponse [success=true, message=Message sent, ]
</pre></li>
<li>Also check your email account for the actual email message</li>
</ol><br />
<div class="explanation"><h2>Note: </h2>When adding a file via the "Add a file" link, the file is automatically uploaded to the backend. The backend responds with an object containing the filename (and other file details). When you click on the "Upload" button, the form data is sent along with the filename. The file itself is never uploaded in this second step because it's already in the server!<br />
</div><br />
<h2>Import the project in Eclipse</h2><ol><li>Ensure Maven is installed</li>
<li>Open a command window (Windows) or a terminal (Linux/Mac)</li>
<li>Run the following command:<br />
<div class="code-custom"><pre>mvn eclipse:eclipse -Dwtpversion=2.0</pre></div></li>
<li>You should see the following output:<br />
<pre>[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'eclipse'.
[INFO] org.apache.maven.plugins: checking for updates from central
[INFO] org.apache.maven.plugins: checking for updates from snapshots
[INFO] org.codehaus.mojo: checking for updates from central
[INFO] org.codehaus.mojo: checking for updates from snapshots
[INFO] artifact org.apache.maven.plugins:maven-eclipse-plugin: checking for updates from central
[INFO] artifact org.apache.maven.plugins:maven-eclipse-plugin: checking for updates from snapshots
[INFO] -----------------------------------------
[INFO] Building spring-emailupload-tutorial Maven Webapp
[INFO] task-segment: [eclipse:eclipse]
[INFO] -----------------------------------------
[INFO] Preparing eclipse:eclipse
[INFO] No goals needed for project - skipping
[INFO] [eclipse:eclipse {execution: default-cli}]
[INFO] Adding support for WTP version 2.0.
[INFO] -----------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] -----------------------------------------
</pre>This command will add the following files to your project: <br />
<pre>.classpath
.project
.settings
target</pre>You may have to enable "show hidden files" in your file explorer to view them<br />
</li>
<li>Open Eclipse and import the project</li>
</ol><br />
<h1>Conclusion</h1>That's it! We've have successfully completed our email application with Spring, SendGrid, and jQuery-File-Upload. We've also learned how to setup an HTML form for attaching multiple files.<br />
<br />
I hope you've enjoyed this tutorial. Don't forget to check my other tutorials at the <a href="http://krams915.blogspot.com/p/tutorials.html">Tutorials</a> section.<br />
<br />
<div class="explanation"><h2>Revision History</h2><hr/><table style="width=100%; text-align: left;"><thead> <th style="width:100px">Revision</th> <th style="width:120px">Date</th> <th>Description</th> </thead> <tbody>
<tr> <td>1</td> <td>July 8 2012</td> <td>Uploaded tutorial</td> </tr>
</tbody> </table></div>Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com9tag:blogger.com,1999:blog-5097100801581543528.post-31123762808676549742012-07-08T19:35:00.000+08:002012-07-08T19:35:58.214+08:00Email with Attachments via Spring and SendGrid (Part 4)<h1>Review</h1>In the previous section, we have declared and written the necessary configuration files. In this section, we will write the HTML form and JavaScript code for composing and sending emails with attachments. <br />
<br />
<div class="explanation"><h2>Table of Contents</h2><a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and.html">Part 1: Introduction and Functional Specs</a><br />
<a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_08.html">Part 2: Java classes</a><br />
<a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_6269.html">Part 3: XML configuration</a><br />
<a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_197.html">Part 4: HTML form</a><br />
<a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_5148.html">Part 5: Running the Application</a><br />
</div><br />
<h1>jQuery-File-Upload</h1>To achieve a seamless AJAX-like file upload experience, we will rely on blueimp's jQuery plugin <i>jQuery-File-Upload</i> for managing attachments.<br />
<br />
<div class="explanation"><b>What is jQuery-File-Upload?</b><br />
<br />
File Upload widget with multiple file selection, drag&drop support, progress bars and preview images for jQuery. Supports cross-domain, chunked and resumable file uploads and client-side image resizing. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.<br />
<br />
Source: https://github.com/blueimp/jQuery-File-Upload<br />
</div><br />
To view a demo of this plugin, please visit the following resources:<br />
<ul><li><a href="http://blueimp.github.com/jQuery-File-Upload/">Demo File Upload</a></li>
<li><a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Setup">How to setup the plugin on your website</a></li>
<li><a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Basic-plugin">How to use only the basic plugin (minimal setup guide).</a></li>
</ul><br />
For our purposes, we will follow the <i>minimal setup guide</i>, so that we can create our custom UI and eliminate extraneous steps.<br />
<br />
<div class="explanation"><b>Warning!</b><br />
Make sure to test the plugin on different browsers because some browsers behave in unexpected ways. In my opinion, Chrome and Firefox are the best browsers for development.</div><br />
<h1>Email Form</h1>Here's our email form again:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEvJ_mzl1W9-LFXrsf7EsTL7PHphd-nsoVdpLsplV1M5o5jSY-qzn_g_YR5euQqQplnQRTlLkTi7qhEwPS79bp8xllhdqJF_bmgf8INi4-f58tYoiQqB6nrzObpy3EXsIZ3hsJ_2jm1vFd/s1600/email-form.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="396" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEvJ_mzl1W9-LFXrsf7EsTL7PHphd-nsoVdpLsplV1M5o5jSY-qzn_g_YR5euQqQplnQRTlLkTi7qhEwPS79bp8xllhdqJF_bmgf8INi4-f58tYoiQqB6nrzObpy3EXsIZ3hsJ_2jm1vFd/s400/email-form.png" /></a></div><br />
And here's the full source:<br />
<br />
<script src="https://gist.github.com/3070526.js?file=form.jsp"></script><br />
<br />
<h1>Explanation</h1>Let's dissect and examine this lengthy source code. We're basically declaring the following:<br />
<br />
<ul><li>Endpoint Urls</li>
<li>Import Scripts</li>
<li>Initialization Function</li>
<li>File Display Function</li>
<li>File List Function</li>
<li>Dialog Function</li>
<li>Clear Function</li>
</ul><br />
<b>Endpoint Urls</b><br />
We've declared two global urls: <i>sendUrl</i> and <i>uploadUrl</i>. These are the endpoints for sending messages and uploading files respectively.<br />
<br />
<script src="https://gist.github.com/3070552.js?file=snippet.jsp"></script><br />
<br />
<b>Import Scripts</b><br />
Based on the <i>jQuery-File-Upload</i> <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Basic-plugin">basic plugin guide</a>, we need to import the following scripts: <i>jquery.ui.widget.js</i>, <i>jquery.iframe-transport.js</i>, and <i>jquery.fileupload.js</i>. The <i>util.js</i> contains a method for posting JSON objects. The remaining scripts are for the jQuery framework itself.<br />
<br />
<script src="https://gist.github.com/2952981.js?file=snippet.jsp"></script><br />
<br />
<b>Initialization Function</b><br />
This function contains the following initialization steps:<br />
<ul><li>Beautify buttons</li>
<li>Attach submit function</li>
<li>Attach clear function</li>
<li>Attach file upload function</li>
<li>Initialize filelist data</li>
</ul><br />
<script src="https://gist.github.com/3070556.js?file=snippet.jsp"></script><br />
<br />
<b>File Display Function</b><br />
This is used for formatting filenames. The output is similar to the following: <i>filename (256.50K)</i><br />
<br />
<script src="https://gist.github.com/2952993.js?file=snippet.jsp"></script><br />
<br />
<b>File List Function</b><br />
This is used to retrieved the list of filenames. The output is comma-delimited, which is similar to the following: <i>filename1.jpg,filename2.doc,filename3.txt</i><br />
<br />
<script src="https://gist.github.com/2952997.js?file=snippet.jsp"></script><br />
<br />
<b>Dialog Function</b><br />
This is a helper function for displaying dialog boxes.<br />
<br />
<script src="https://gist.github.com/2952999.js?file=snippet.jsp"></script><br />
<br />
<b>Clear Function</b><br />
This clears the form of its contents.<br />
<br />
<script src="https://gist.github.com/3070557.js?file=snippet.jsp"></script><br />
<br />
<b>Form</b><br />
This is the form itself. Notice we've set the file input's opacity to zero to hide it and make it work under Safari and Opera (try removing the opacity and hide the file input via <i>display:none</i> to see an unwanted effect).<br />
<br />
<script src="https://gist.github.com/3070561.js?file=snippet.jsp"></script><br />
<br />
By setting the file input's opacity to 0, we have successfully hidden the input. But how do we access it now? Notice the "Add a file" link? We've attached a click trigger function on that link to fire up the file input. If we removed the opacity, here's what we will see:<br />
<br />
<i>Chrome 19.0.1084.56</i><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiIkMl8LCJmkWdynhtd2N7nYLHJ0mP8MUjmRjSnx5NHRQgMF4c-wAw46rbpKM1fZ99ZWWxF_tp4tbLub3URuR9kR5Kjx7igx3sW4iMix7HOjK59dENo9_VRjPakhFh450pli9YIJRnLRkW/s1600/MWSnap074.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="157" width="289" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiIkMl8LCJmkWdynhtd2N7nYLHJ0mP8MUjmRjSnx5NHRQgMF4c-wAw46rbpKM1fZ99ZWWxF_tp4tbLub3URuR9kR5Kjx7igx3sW4iMix7HOjK59dENo9_VRjPakhFh450pli9YIJRnLRkW/s400/MWSnap074.png" /></a><br />
<br />
<i>Firefox 9.0.1</i><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQy9Kfe6LfONkq2V7v0jxIhi76soTtgl2p7_Q3FfkFEe6lffDqqyy2g4GQub8fWCMR6hTUp9a_fXep8ceGg6kHUA4xHwmWKxnCs_6TpGeKZ0NOeo62H96P5tPzMkTQ02FKSuskgq1XUr1Z/s1600/MWSnap075.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="155" width="318" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQy9Kfe6LfONkq2V7v0jxIhi76soTtgl2p7_Q3FfkFEe6lffDqqyy2g4GQub8fWCMR6hTUp9a_fXep8ceGg6kHUA4xHwmWKxnCs_6TpGeKZ0NOeo62H96P5tPzMkTQ02FKSuskgq1XUr1Z/s400/MWSnap075.png" /></a><br />
<br />
<i>Internet Explorer 9.0.8112.16421</i><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7EiJwEnkKN9hJz0RGEt7VcdsukvqBbdlqoYD4nMGDKQzVQMmWlrXYQ6-Q5YJmNiYAAv3dLH3A89-o_QDn9uQI4G_F8qXaOUGJGad_l_KBWAQk9dhW0PcT92gd0cyL_jPUTN-71x2rFE-F/s1600/MWSnap076.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="145" width="293" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7EiJwEnkKN9hJz0RGEt7VcdsukvqBbdlqoYD4nMGDKQzVQMmWlrXYQ6-Q5YJmNiYAAv3dLH3A89-o_QDn9uQI4G_F8qXaOUGJGad_l_KBWAQk9dhW0PcT92gd0cyL_jPUTN-71x2rFE-F/s400/MWSnap076.png" /></a><br />
<br />
<h1>Browser Bugs</h1>Even though the <i>jQuery-File-Upload</i> plugin has great cross-browser support, some browsers still behave erratically. Here's what I've discovered so far:<br />
<br />
<i>Internet Explorer 9.0.8112.16421</i><br />
<ul><li>Does not upload file</li>
<li>Does not upload message</li>
</ul><br />
<i>Opera 11.60</i><br />
<ul><li>Attach link does not work if file input has display:none</li>
<li>To make it work, set the opacity instead</li>
</ul><br />
<i>Safari 5.1.2</i><br />
<ul><li>Attach link does not work if file input has display:none</li>
<li>To make it work, set the opacity instead</li>
</ul><br />
<h1>Next</h1>We have just written and discussed the Html form for sending emails with attachments. In the next section, we will build and run the application using Maven, and show how to import the project in Eclipse. <a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_5148.html">Click here to proceed.</a>Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com1tag:blogger.com,1999:blog-5097100801581543528.post-59818409177055630422012-07-08T19:34:00.004+08:002012-07-08T19:36:15.917+08:00Email with Attachments via Spring and SendGrid (Part 3)<h1>Review</h1>In the previous section, we have discussed and implemented the Java classes. In this section, we will start writing the configuration files.<br />
<br />
<div class="explanation"><h2>Table of Contents</h2><a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and.html">Part 1: Introduction and Functional Specs</a><br />
<a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_08.html">Part 2: Java classes</a><br />
<a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_6269.html">Part 3: XML configuration</a><br />
<a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_197.html">Part 4: HTML form</a><br />
<a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_5148.html">Part 5: Running the Application</a><br />
</div><br />
<h1>Configuration</h1>Here are the important configuration files that needs to be declared:<br />
<ul><li>spring.properties</li>
<li>applicationContext.xml</li>
<li>spring-servlet.xml</li>
<li>web.xml</li>
</ul><br />
<b>spring.properties</b> <br />
This contains your <i>SendGrid</i> user and key credentials to access the Web API. This is equivalent to your SendGrid's username and password. This file also contains a temporary directory location for saving file uploads.<br />
<script src="https://gist.github.com/3070439.js?file=spring.properties"></script><br />
<br />
<b>applicationContext.xml</b><br />
In order for file uploads to work, make sure to declare a <i>MultipartResolver</i> bean<br />
<script src="https://gist.github.com/3070470.js?file=applicationContext.xml"></script><br />
<br />
<b>spring-servlet.xml</b><br />
<script src="https://gist.github.com/2944431.js?file=spring-servlet.xml"></script><br />
<br />
<b>web.xml</b><br />
<script src="https://gist.github.com/3070473.js?file=web.xml"></script><br />
<br />
<h1>Next</h1>We have just completed declaring the required configuration files. In the next section, we will write the HTML form and demonstrate how to use <i>jQuery-File-Upload</i> for uploading files via jQuery. <a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_197.html">Click here to proceed.</a>Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com4tag:blogger.com,1999:blog-5097100801581543528.post-12378494088185048102012-07-08T19:34:00.002+08:002012-07-08T19:36:33.066+08:00Email with Attachments via Spring and SendGrid (Part 2)<h1>Review</h1>In the previous section, we have laid down the functional specs and took a preview of the application. In this section, we will write and discuss the Java classes and the project's structure.<br />
<br />
<div class="explanation"><h2>Table of Contents</h2><a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and.html">Part 1: Introduction and Functional Specs</a><br />
<a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_08.html">Part 2: Java classes</a><br />
<a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_6269.html">Part 3: XML configuration</a><br />
<a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_197.html">Part 4: HTML form</a><br />
<a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_5148.html">Part 5: Running the Application</a><br />
</div><br />
<h1>Project Structure</h1>Our application is a Maven project which means it follows the Maven convention for web applications.<br />
<br />
Here's a preview of our project's structure:<br />
<table><tr> <td style="vertical-align: top"><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-xY3-A6gwx5JeUUetEpjbbbH8HfsYA6S9Px1vNcQHrpXXGh6TMiPWZOLuSPQwHeQfUzGRxOzjSJTBYQUQVazmf-7h0xeB8ypVxB1udUDp4YquMrQUGopNQqE2RaA7Cc2ZyAQdDs1Ny_J7/s1600/project1.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="395" width="261" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-xY3-A6gwx5JeUUetEpjbbbH8HfsYA6S9Px1vNcQHrpXXGh6TMiPWZOLuSPQwHeQfUzGRxOzjSJTBYQUQVazmf-7h0xeB8ypVxB1udUDp4YquMrQUGopNQqE2RaA7Cc2ZyAQdDs1Ny_J7/s400/project1.png" /></a></div></td> <td style="vertical-align: top"><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqKnHxp9RiwnQB8ykJXjh12Xx_hTbJCtk0NMhElt6p00vDu_vVnN-Vb7fd31HWtlXMtj9XgWJNShP3pFgkTj5RSzLO1fOmGV6bMam4oh7728oQ2OQ67apgeoRDL9yO4ua695V9xXKaB0Ym/s1600/project2.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="349" width="265" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqKnHxp9RiwnQB8ykJXjh12Xx_hTbJCtk0NMhElt6p00vDu_vVnN-Vb7fd31HWtlXMtj9XgWJNShP3pFgkTj5RSzLO1fOmGV6bMam4oh7728oQ2OQ67apgeoRDL9yO4ua695V9xXKaB0Ym/s400/project2.png" /></a></div></td> </tr>
</table><br />
<h1>Domain Layer</h1>The domain layer contains a <i>Message</i> class that represents an email message and n <i>UploadedFile</i> class that represents a file upload.<br />
<br />
<script src="https://gist.github.com/3070360.js?file=Message.java"></script><br />
<script src="https://gist.github.com/3070372.js?file=UploadedFile.java"></script><br />
<br />
<h1>Controller Layer</h1>The controller layer contains a simple controller <i>EmailController</i> that serves a form for composing and sending emails. It has two main methods: <i>send</i> for sending emails and <i>upload</i> for uploading files.<br />
<br />
Whenever a file is attached and uploaded, it is saved first to a temporary location which can be retrieved later via its filename. When the <i>send</i> method is triggered, it basically pulls out the file from the temporary location based on the filename.<br />
<script src="https://gist.github.com/3070375.js?file=EmailController.java"></script><br />
<br />
<h1>Service Layer</h1>The service layer contains the email service. We have a simple interface <i>EmailService</i> for sending messages. <br />
<script src="https://gist.github.com/2944419.js?file=EmailService.java"></script><br />
<br />
The actual implementation <i>SendGridEmailService</i> relies on <i>RestTemplate</i> to send the email message via HTTP.<br />
<script src="https://gist.github.com/3070383.js?file=SendGridEmailService.java"></script><br />
<br />
How did we manage to produce this code? Basically this is a translation of SendGrid's API using Spring <i>RestTemplate</i>. The specific SendGrid API we're using is the <b>Mail</b> module, which is under the Web API. Please see http://docs.sendgrid.com/documentation/api/web-api/mail/#send for the complete documentation.<br />
<br />
To test the Mail module, you can either use your browser or CURL (if you're familiar with it).<br />
<br />
Browser-based test:<br />
<pre class="code-custom ui-corner-top ui-corner-bottom">https://sendgrid.com/api/mail.send.xml?api_user=youremail@domain.com&api_key=secureSecret&to=destination@example.com&toname=Destination&subject=Example%20Subject&text=testingtextbody&from=info@domain.com
</pre><br />
CURL-based test:<br />
<pre class="code-custom ui-corner-top ui-corner-bottom">curl -d 'to=destination@example.com&toname=Destination&subject=Example Subject&text=testingtextbody&from=info@domain.com&api_user=sendgridUsername&api_key=sendgridPassword' https://sendgrid.com/api/mail.send.json
</pre><br />
<h1>Utility Layer</h1>This layer contains helper classes and interfaces. Here we've extracted the required SendGrid parameters when sending emails via HTTP.<br />
<script src="https://gist.github.com/2944432.js?file=SendGridParameter.java"></script><br />
<br />
<h1>Next</h1>We've just completed discussing and writing our Java classes. In the next section, we will declare the required configuration files. <a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_6269.html">Click here to proceed.</a><br />Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com3tag:blogger.com,1999:blog-5097100801581543528.post-5106429483086382512012-07-08T19:34:00.001+08:002012-07-08T19:41:45.975+08:00Email with Attachments via Spring and SendGrid (Part 1)<h1>Introduction</h1>In this article, we will study how to send emails and include attachments using Spring as our Java framework, SendGrid as our email service, and jQuery-File-Upload as our jQuery plugin. This article is the culmination of my previous articles about email and file upload (see below)<br />
<br />
<ul style="margin-top: 0px; padding-top: 0px;"><li style="margin-bottom: 0px; margin-top: 0px; padding-bottom: 0px; padding-top: 0px;"><a href="http://krams915.blogspot.com/2012/06/email-with-spring-and-sendgrid-part-1.html">Email with Spring and SendGrid tutorial</a></li>
<li style="margin-bottom: 0px; margin-top: 0px; padding-bottom: 0px; padding-top: 0px;"><a href="http://krams915.blogspot.com/2012/06/file-upload-with-spring-and-jquery-part_2793.html">File Upload with Spring and jQuery tutorial</a></li>
</ul><br />
I advise my readers to read those articles first before reading this guide to understand how to send email with SendGrid and how to upload files with jQuery.<br />
<br />
<div class="explanation"><h2>Table of Contents</h2><a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and.html">Part 1: Introduction and Functional Specs</a><br />
<a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_08.html">Part 2: Java classes</a><br />
<a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_6269.html">Part 3: XML configuration</a><br />
<a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_197.html">Part 4: HTML form</a><br />
<a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_5148.html">Part 5: Running the Application</a><br />
</div><br />
<div class="explanation"><h2>Dependencies</h2><ul style="margin-top: 0px; padding-top: 0px;"><li style="margin-bottom: 0px; margin-top: 0px; padding-bottom: 0px; padding-top: 0px;">Spring core 3.1.0.RELEASE</li>
<li style="margin-bottom: 0px; margin-top: 0px; padding-bottom: 0px; padding-top: 0px;"><a href="http://www.sendgrid.com/">SendGrid account (you're required to sign-up first)</a></li>
<li style="margin-bottom: 0px; margin-top: 0px; padding-bottom: 0px; padding-top: 0px;"><a href="https://github.com/blueimp/jQuery-File-Upload">jQuery-File-Upload</a></li>
<li style="margin-bottom: 0px; margin-top: 0px; padding-bottom: 0px; padding-top: 0px;">See <a href="https://github.com/krams915/spring-emailupload-tutorial/blob/master/spring-emailupload-tutorial/pom.xml">pom.xml</a> for details</li>
</ul></div><b><br />
Github</b><br />
To access the source code, please visit the project's Github repository (<a href="https://github.com/krams915/spring-emailupload-tutorial/tree/master/spring-emailupload-tutorial">click here</a>)<br />
<br />
<h1>Functional Specs</h1>Let's define our application's requirements:<br />
<ul><li>Create a simple form where users can compose and send emails</li>
<li>Emails do not need to be persisted in a database</li>
<li>Users can attach multiple files</li>
<li>Send email via HTTP instead of SMTP to avoid firewall issues</li>
</ul><br />
Here's our <i>Use Case</i> diagram:<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRuprjiXAomPxKazg6ePGdwOVR-3V2rUQtI8LhhjUDOfF-r_tvEctl0X-x9-VEucd0XwVSNtcQtDWajS35izuJP-Ceki4hrbf6P-DbwT7RSenFsuuaEDUarBxsa9AIPr6ROE-8ce7LpOrD/s1600/usecase.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="301" width="339" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRuprjiXAomPxKazg6ePGdwOVR-3V2rUQtI8LhhjUDOfF-r_tvEctl0X-x9-VEucd0XwVSNtcQtDWajS35izuJP-Ceki4hrbf6P-DbwT7RSenFsuuaEDUarBxsa9AIPr6ROE-8ce7LpOrD/s400/usecase.png" /></a></div><br />
<pre style="display: none;">[User]-(Compose)
[User]-(Attach)
[User]-(Send)
</pre><br />
<blockquote class="explanation"><b>What is SendGrid?</b><br />
<br />
SendGrid's cloud-based email infrastructure relieves businesses of the cost and complexity of maintaining custom email systems. SendGrid provides reliable delivery, scalability and real-time analytics along with flexible API's that make custom integration a breeze.<br />
<br />
Source: http://www.sendgrid.com</blockquote><br />
<h1>Screenshots</h1>Let's preview how our application will look like after it has been completed. This is also a good way to clarify further our application's specs<br />
<br />
<b>Compose email form</b><br />
This is the entry page where users can compose and send emails.<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEja5Nx6WhrQwNpjkAHWgRhYrMU3pXEYBCqd8DcvBB287c9P7Ve1wru2rNhhOp8j9OOqlZh7gGxoc4bctn-M1GdBCczaIMOIZTSHU9RwuRcjMzOjzkbB39Jz2-EMJZ49j_HPxhCvoul1RjZf/s1600/compose-email-form.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="399" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEja5Nx6WhrQwNpjkAHWgRhYrMU3pXEYBCqd8DcvBB287c9P7Ve1wru2rNhhOp8j9OOqlZh7gGxoc4bctn-M1GdBCczaIMOIZTSHU9RwuRcjMzOjzkbB39Jz2-EMJZ49j_HPxhCvoul1RjZf/s400/compose-email-form.png" /></a></div><br />
<b>Email with attachments</b><br />
Notice we can attach multiple files and display their file sizes<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwNEgtEnV6wNIFXOmjIg5M7ch2saDBIPJqhSPBNwexf0xrP80Wqpqqt-m-OuBT6NKbjHDv3imBD2zy3Z9Li3Loi69cvVbvbve3YfITZDfBgNP3bg0kfSi_5iWZVhc4UTqeQm5sCF9Gj0oC/s1600/compose-email-with-attachments.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="400" width="365" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwNEgtEnV6wNIFXOmjIg5M7ch2saDBIPJqhSPBNwexf0xrP80Wqpqqt-m-OuBT6NKbjHDv3imBD2zy3Z9Li3Loi69cvVbvbve3YfITZDfBgNP3bg0kfSi_5iWZVhc4UTqeQm5sCF9Gj0oC/s400/compose-email-with-attachments.png" /></a></div><br />
<b>Success alert</b><br />
After clicking "Send", the email message is sent. An alert is shown to confirm the action.<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdzmoMLFJq5Rl7W3ECxLpEsFm1oa5Q4uorvbN-Ggh3Ie00JTYP7P9W4Hnyrv1OHFg2ox3hFlERSQfbjGKA95b6C4SUbSaSesueBi7tOysPpnG-XWOCM0S-5eo9nyCs31K-LDlaSV-4gHOj/s1600/success-alert.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="400" width="366" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdzmoMLFJq5Rl7W3ECxLpEsFm1oa5Q4uorvbN-Ggh3Ie00JTYP7P9W4Hnyrv1OHFg2ox3hFlERSQfbjGKA95b6C4SUbSaSesueBi7tOysPpnG-XWOCM0S-5eo9nyCs31K-LDlaSV-4gHOj/s400/success-alert.png" /></a></div><br />
<b>Reset alert</b><br />
When user clicks on "Reset", the contents of the fields are cleared. An alert is shown to confirm the action.<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg27O3d59SA9lPnsd4Hi86WBjNV9kig5nHYaGU05m7ZHqym-laKZeOIPyQma3YdZgqyOKMm_50TQPBy-2li1KPSIKcQedW5_J4ksND1IZF2-r7ZEtcRuxxcpk5ubJOrVeGzj2FCIs3HUBFp/s1600/MWSnap076.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="215" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg27O3d59SA9lPnsd4Hi86WBjNV9kig5nHYaGU05m7ZHqym-laKZeOIPyQma3YdZgqyOKMm_50TQPBy-2li1KPSIKcQedW5_J4ksND1IZF2-r7ZEtcRuxxcpk5ubJOrVeGzj2FCIs3HUBFp/s400/MWSnap076.png" /></a></div><br />
<b>Sample emails</b><br />
This is the sample email received from Gmail:<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSUF9vCoOpPLF8us22gcxHMRtZPHQQk-BbvwjIb8gPowsZ_29db7rV6XLdgd55J8os2us6h1F29CRgEGPAQIYmCrn9lKAULrLXyaZ-z9RDefNMHH8TtY_URuhfewOaOCrlqBsEIoNKoLfO/s1600/gmail-sample.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="312" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSUF9vCoOpPLF8us22gcxHMRtZPHQQk-BbvwjIb8gPowsZ_29db7rV6XLdgd55J8os2us6h1F29CRgEGPAQIYmCrn9lKAULrLXyaZ-z9RDefNMHH8TtY_URuhfewOaOCrlqBsEIoNKoLfO/s400/gmail-sample.png" /></a></div><br />
This is the sample email received from Yahoo:<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhX_J9hjVsqsKFnQJ0gi6si6SnkMbJ00unEGwXy5IdPuk04Fhl3xC-_UfP5Pp3nO76k9mfbA0GnaOLAFKXoA_w7cqvhXTTSbpizHst_FOtsSjDW3Aqr_xspE9lZDkLzw4HftCmehfnuUBNc/s1600/yahoo-sample.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="323" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhX_J9hjVsqsKFnQJ0gi6si6SnkMbJ00unEGwXy5IdPuk04Fhl3xC-_UfP5Pp3nO76k9mfbA0GnaOLAFKXoA_w7cqvhXTTSbpizHst_FOtsSjDW3Aqr_xspE9lZDkLzw4HftCmehfnuUBNc/s400/yahoo-sample.png" /></a></div><br />
<h1>Next</h1>In the next section, we will start writing the Java classes, discuss the jQuery-File-Upload process, and the SendGrid API for sending attachments. <a href="http://krams915.blogspot.com/2012/07/email-with-attachments-via-spring-and_08.html">Click here to proceed.</a>Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com5tag:blogger.com,1999:blog-5097100801581543528.post-61025315156714458382012-06-20T15:33:00.004+08:002012-06-27T16:30:26.352+08:00File Upload with Spring and jQuery (Part 1)<h1>Introduction</h1>In this article, we will study how to do file uploads with Spring and jQuery. We will learn how to attach multiple files and use the jQuery-File-Upload plugin to provide a seamless file upload experience.<br />
<br />
<div class="explanation"><h2>Table of Contents</h2><a href="http://krams915.blogspot.com/2012/06/file-upload-with-spring-and-jquery-part_2793.html">Part 1: Introduction and Functional Specs</a><br />
<a href="http://krams915.blogspot.com/2012/06/file-upload-with-spring-and-jquery-part_1223.html">Part 2: Java classes</a><br />
<a href="http://krams915.blogspot.com/2012/06/file-upload-with-spring-and-jquery-part_7172.html">Part 3: XML configuration</a><br />
<a href="http://krams915.blogspot.com/2012/06/file-upload-with-spring-and-jquery-part_20.html">Part 4: HTML form</a><br />
<a href="http://krams915.blogspot.com/2012/06/file-upload-with-spring-and-jquery-part.html">Part 5: Running the Application</a><br />
</div><br />
<div class="explanation"><h2>Dependencies</h2><ul style="margin-top: 0px; padding-top: 0px;"><li style="margin-bottom: 0px; margin-top: 0px; padding-bottom: 0px; padding-top: 0px;">Spring core 3.1.0.RELEASE</li>
<li style="margin-bottom: 0px; margin-top: 0px; padding-bottom: 0px; padding-top: 0px;"><a href="https://github.com/blueimp/jQuery-File-Upload">jQuery-File-Upload</a></li>
<li style="margin-bottom: 0px; margin-top: 0px; padding-bottom: 0px; padding-top: 0px;">See <a href="https://github.com/krams915/spring-fileupload-tutorial/blob/master/spring-fileupload-tutorial/pom.xml">pom.xml</a> for details</li>
</ul></div><b><br />
Github</b><br />
To access the source code, please visit the project's Github repository (<a href="https://github.com/krams915/spring-fileupload-tutorial/tree/master/spring-fileupload-tutorial">click here</a>)<br />
<br />
<h1>Functional Specs</h1>Let's define our application's requirements:<br />
<ul><li>Create a simple form where users can upload multiple files</li>
<li>Users should be able to add an owner name and description for each upload</li>
<li>Provide an AJAX-like experience</li>
</ul><br />
Here's our <i>Use Case</i> diagram:<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9eoMn-PHEqRwnUonRWtqiq313lXs9WNyze-J-efWxKmIA_KtWuTJukkgkZL-eGn4tTISKzlyghUZTbQPXgNWRZiD2wke0n_4g_QZ95Zifu8NmNuGraPps3f0amPNF8nzpvhZ5kSsyuTFz/s1600/887d5742.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="221" width="328" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9eoMn-PHEqRwnUonRWtqiq313lXs9WNyze-J-efWxKmIA_KtWuTJukkgkZL-eGn4tTISKzlyghUZTbQPXgNWRZiD2wke0n_4g_QZ95Zifu8NmNuGraPps3f0amPNF8nzpvhZ5kSsyuTFz/s400/887d5742.png" /></a><br />
<br />
<pre style="display: none;">[User]-(Add files)
[User]-(Upload)
</pre><br />
<b>File Upload Strategy</b><br />
To achieve an AJAX-like experience we have to resort to a different strategy when uploading and sending form data. Instead of sending all form data in one go, we will upload the file separately (behind the scenes without user intervention).<br />
<br />
Here are the steps:<br />
<ol><li>User fills-in the form's text inputs, i.e owner and description</li>
<li>User clicks on "Add a file" link. Browsers for a file and attaches it</li>
<li>Behind the scene, the form uploads the file to the server. The server saves the file and returns the file details, i.e filename and file size</li>
<li>User clicks on "Upload" button. The form does a POST action to send the form data. But it never sends the file itself. Instead it sends the filename that was saved by the server. The user is tricked into thinking that the file hasn't been uploaded yet.</li>
</ol><br />
<h1>Screenshots</h1>Let's preview how our application will look like after it has been completed. This is also a good way to clarify further our application's specs<br />
<br />
This is the entry page where users can upload files. Users are allowed to attach multiple files.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitnrnvWHkQI-2K4rq5uexypCDCl29K0RELdjUaccNFppxyHAc_mCDLajTxyDNWXf2zbxgH8A1iUUH2JzbqMrzyTa1HSPbl05BfFNS8QDp8ArSKvuVUrQM7HAlgKbF-up9AdQHJZfsUXp-H/s1600/MWSnap069.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="294" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitnrnvWHkQI-2K4rq5uexypCDCl29K0RELdjUaccNFppxyHAc_mCDLajTxyDNWXf2zbxgH8A1iUUH2JzbqMrzyTa1HSPbl05BfFNS8QDp8ArSKvuVUrQM7HAlgKbF-up9AdQHJZfsUXp-H/s400/MWSnap069.png" /></a><br />
<span>Upload Form</span></div><br />
When attaching multiple files, this is the expected output.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQnein91ABPT6OIicnBL4BmBpYnqE0AviXDo3X6crr2PmYglxj5M8MWp4r72SX4KGc82h9Ctuah2taayKyOzCFlCQLN5ZMfnUAcs27E_eMd-9prsw3Xmtm7gt1xOw6y_jlIhgh4PCqOhvl/s1600/MWSnap070.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="334" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQnein91ABPT6OIicnBL4BmBpYnqE0AviXDo3X6crr2PmYglxj5M8MWp4r72SX4KGc82h9Ctuah2taayKyOzCFlCQLN5ZMfnUAcs27E_eMd-9prsw3Xmtm7gt1xOw6y_jlIhgh4PCqOhvl/s400/MWSnap070.png" /></a><br />
<span>Multiple files attachment</span></div><br />
This alert shows whenever files have been successfully uploaded.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivlXplKG5lZCknZNEpt1OFwtexE0Po8B_DDTYKF3zEGM7iIokwA_eIuUjqBRPMuQcV3rpi-EAtjvSwhFx82ucsgJnDvkgJyBA_gIPKyDXXZpFbnOvHyiPfZF_xJURzDAuDFiXI_PTaDGOa/s1600/MWSnap071.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="193" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivlXplKG5lZCknZNEpt1OFwtexE0Po8B_DDTYKF3zEGM7iIokwA_eIuUjqBRPMuQcV3rpi-EAtjvSwhFx82ucsgJnDvkgJyBA_gIPKyDXXZpFbnOvHyiPfZF_xJURzDAuDFiXI_PTaDGOa/s400/MWSnap071.png" /></a><br />
<span>Successful upload alert</span></div><br />
This alerts shows whenever files have failed to be uploaded.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkD7lYgdZZ5e9Li03VcoKpGh-f9aN5z-Fz4sc07NNJ86ZIlIVb2CK7VKKR3y8rU5oIs3jeO4lj9A9g1K3Tq-K-Xv40Eeh0ZtBojLFGi4LNrI0NyUUvrI1NoSWZbY2NAcyYy9weR5H82ZEP/s1600/MWSnap072.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="193" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkD7lYgdZZ5e9Li03VcoKpGh-f9aN5z-Fz4sc07NNJ86ZIlIVb2CK7VKKR3y8rU5oIs3jeO4lj9A9g1K3Tq-K-Xv40Eeh0ZtBojLFGi4LNrI0NyUUvrI1NoSWZbY2NAcyYy9weR5H82ZEP/s400/MWSnap072.png" /></a><br />
<span>Form fields cleared alert</span></div><br />
<h1>Next</h1>In the next section, we will start writing the Java classes. <a href="http://krams915.blogspot.com/2012/06/file-upload-with-spring-and-jquery-part_1223.html">Click here to proceed.</a>Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com9tag:blogger.com,1999:blog-5097100801581543528.post-14951064463998478232012-06-20T15:33:00.003+08:002012-06-21T16:45:51.340+08:00File Upload with Spring and jQuery (Part 2)<h1>Review</h1>In the previous section, we have laid down the functional specs of the application. In this section, we will start writing the Java classes and discuss the project's structure.<br />
<br />
<div class="explanation"><h2>Table of Contents</h2><a href="http://krams915.blogspot.com/2012/06/file-upload-with-spring-and-jquery-part_2793.html">Part 1: Introduction and Functional Specs</a><br />
<a href="http://krams915.blogspot.com/2012/06/file-upload-with-spring-and-jquery-part_1223.html">Part 2: Java classes</a><br />
<a href="http://krams915.blogspot.com/2012/06/file-upload-with-spring-and-jquery-part_7172.html">Part 3: XML configuration</a><br />
<a href="http://krams915.blogspot.com/2012/06/file-upload-with-spring-and-jquery-part_20.html">Part 4: HTML form</a><br />
<a href="http://krams915.blogspot.com/2012/06/file-upload-with-spring-and-jquery-part.html">Part 5: Running the Application</a><br />
</div><br />
<h1>Project Structure</h1>Our application is a Maven project which means our project follows the Maven structure.<br />
<br />
Here's a preview of our project's structure:<br />
<table><tr> <td style="vertical-align: top"><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-K88CDKBj8xRZTC0emXhbatqEfJltgK8S8dp7v6wk4rQzaxL9zsbAPSKT3dsco3zLFLKdVMX7d1jXiDWgyYCo4h-5Ief2Y59zQhYWqSMUjNmi8YsW93P7gtngd4_NFQaq-g-t4SCSA4LB/s1600/MWSnap069.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="234" width="218" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-K88CDKBj8xRZTC0emXhbatqEfJltgK8S8dp7v6wk4rQzaxL9zsbAPSKT3dsco3zLFLKdVMX7d1jXiDWgyYCo4h-5Ief2Y59zQhYWqSMUjNmi8YsW93P7gtngd4_NFQaq-g-t4SCSA4LB/s400/MWSnap069.png" /></a><br />
</td> <td style="vertical-align: top"><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_VjOtxB5RCLL0-y1UFjCu4gdowzUBATUxwLe7kmSmriyCYQGPj4k_AqLt9Vkf2cFCo3rNqCoOKL7Hw-BApfQFj7Usc-8ukRAxmou-O-5J2knsWh9kRjfYY995bTNk6Aw-yvGirTvCNdg8/s1600/MWSnap070.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="382" width="298" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_VjOtxB5RCLL0-y1UFjCu4gdowzUBATUxwLe7kmSmriyCYQGPj4k_AqLt9Vkf2cFCo3rNqCoOKL7Hw-BApfQFj7Usc-8ukRAxmou-O-5J2knsWh9kRjfYY995bTNk6Aw-yvGirTvCNdg8/s400/MWSnap070.png" /></a><br />
</td> </tr>
</table><br />
<h1>Domain Layer</h1>The domain layer contains a <i>Message</i> class that is used as a container to hold file details.<br />
<br />
<b>Message.java</b><br />
<script src="https://gist.github.com/2953108.js?file=Message.java"></script><br />
<br />
The domain layer also contains an <i>UploadedFile</i> class which is used for sending file information after it has been processed by the controller.<br />
<br />
<b>UploadedFile.java</b><br />
<script src="https://gist.github.com/2953111.js?file=UploadedFile.java"></script><br />
<br />
<h1>Controller Layer</h1>The controller layer contains a simple controller that serves a form for uploading files. There are two important endpoints here:<br />
<ul><li>/message - processes the file descriptions</li>
<li>/file - receives the files themselves</li>
</ul><br />
To simplify this tutorial, we're not persisting the messages and files in a database or to the disk.<br />
<br />
<b>UploadController.java</b><br />
<script src="https://gist.github.com/2953105.js?file=UploadController.java"></script><br />
<br />
<h1>Others</h1><i>StatusResponse </i>is used to determine the status of a request, and includes an error message if any.<br />
<br />
<b>StatusResponse.java</b><br />
<script src="https://gist.github.com/2953115.js?file=StatusResponse.java"></script><br />
<br />
<h1>Next</h1>We've completed writing our Java classes. In the next section, we will start writing the configuration files. <a href="http://krams915.blogspot.com/2012/06/file-upload-with-spring-and-jquery-part_7172.html">Click here to proceed.</a>Mark Serranohttp://www.blogger.com/profile/07683739886053674459noreply@blogger.com9