Building Web Apps with Spring 3.0 – Meeting notes
This presentation and notes are from the May 2009 Java User group meeting in Twin Cities. You can view the details and download the code from http://www.intertech.com/UserGroups/JUGPresentation.aspx?TopicID=135 It was an excellent presentation. Bob has discussed about new cool features in Spring 3 and how it simplifies the Spring MVC development. These presentation slides are created by him and all rights lies with him.
- DispatcherServlet is the central servlet handling requests
- See slide 7. The request handling takes place in the following order
- HTTP Request is first handled by Dispatcher Servlet
- DispatcherServlet refers HandlerMapping find the controller which will handle the request
- DispatcherServlet sends the request to the Controller. Controller returns view and/or model.
- DispatcherServlet refers to ViewResolver to determine the view page based on logical view name
- View is rendered
- Controller hierarchy is deprecated in Spring 3.Just annotation is enough. No need to implement life-cycle methods
- Flexible method arguments. Flexible return types.
-
Annotations like
@RequestParam
@ModelAttribute
@RequestMapping
@SessionAttribute
@InitBinder
and WebBindingInitializer - Convention verses configuration
- ControllerClassNameHandlerMapping
- Model and ModelMap
- Rest Support
Stateless, cacheable, scalable, communication protocol
HTTP Methods – GET, POST, PUT(Idempotent), DELETE(Idempotent), HEAD, OPTIONS - Spring 3.0 has REST support
How to configure JCaptcha with your Spring App
Update: 03/17/2009: This code example uses JCaptcha 1.0-RC6 . The latest version released on 02/04/2009 is JCaptcha 1.0. If you use JCaptcha 1.0 then you might have to make some changes to the code given in this example.
This is how I setup JCaptcha in my application. Following code snippet is for the test page I have created to test the JCaptcha and Spring integration
1) First create a controller which will generate a new Captcha for each session based on session id
package com.example.web.controller;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.Map;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import com.octo.captcha.service.CaptchaServiceException;
import com.octo.captcha.service.image.ImageCaptchaService;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import com.example.domain.LoginCommand;
import com.example.logger.LoginLogger;
public class CaptchaController extends LoginBaseController {
public CaptchaController(){
setCommandClass(LoginCommand.class);
}
@Override
protected ModelAndView showForm(HttpServletRequest request, HttpServletResponse response, BindException errors,
Map controlModel) throws Exception {
byte[] captchaChallengeAsJpeg = null;
// the output stream to render the captcha image as jpeg into
ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
try {
// get the session id that will identify the generated captcha.
//the same id must be used to validate the response, the session id is a good candidate!
String captchaId = request.getSession().getId();
LoginLogger.debug(this, "Captcha ID which gave the image::" + captchaId);
// call the ImageCaptchaService getChallenge method
BufferedImage challenge = ((ImageCaptchaService)getCaptchaService()).getImageChallengeForID(captchaId, request.getLocale());
// a jpeg encoder
JPEGImageEncoder jpegEncoder =
JPEGCodec.createJPEGEncoder(jpegOutputStream);
jpegEncoder.encode(challenge);
} catch (IllegalArgumentException e) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return null;
} catch (CaptchaServiceException e) {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return null;
}
captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
// flush it in the response
response.setHeader("Cache-Control", "no-store");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
//response.setContentType("image/jpeg");
// response.getOutputStream().write(jpegOutputStream);
ServletOutputStream responseOutputStream =
response.getOutputStream();
responseOutputStream.write(captchaChallengeAsJpeg);
responseOutputStream.flush();
responseOutputStream.close();
return null;
}
}
Please note that your implementation can vary. The only thing you want is a simple Servlet which will execute the code in showForm method above. In my case I am relying on Spring framework to execute this code because in the JSP where you show Captcha image I have written something like this
<img id=”captchaImage” src=”http://localhost:8080/LoginApplication/captcha.htm”>. In my application the URL captcha.htm is wired to this controller. But you can choose to have a simple servlet mapped instead of a Spring Controller.
2) Make the following entries in your Spring config files to configure JCaptcha
<!-- Captcha Related Mappings -->
<bean id="captchaController"
class="com.example.web.controller.CaptchaController">
<property name="captchaService" ref="captchaService" />
</bean>
<bean id="imageEngine" class="com.octo.captcha.engine.GenericCaptchaEngine">
<constructor-arg index="0">
<list>
<ref bean="CaptchaFactory"/>
</list>
</constructor-arg>
</bean>
<bean id="CaptchaFactory" class="com.octo.captcha.image.gimpy.GimpyFactory" >
<constructor-arg><ref bean="wordgen"/></constructor-arg>
<constructor-arg><ref bean="wordtoimage"/></constructor-arg>
</bean>
<bean id="wordgen" class= "com.octo.captcha.component.word.wordgenerator.DictionaryWordGenerator" >
<constructor-arg><ref bean="filedict"/></constructor-arg>
</bean>
<bean id="filedict" class="com.octo.captcha.component.word.FileDictionary" >
<constructor-arg index="0"><value>toddlist</value></constructor-arg>
</bean>
<bean id="wordtoimage" class="com.octo.captcha.component.image.wordtoimage.ComposedWordToImage" >
<constructor-arg index="0"><ref bean="fontGenRandom"/></constructor-arg>
<constructor-arg index="1"><ref bean="backGenUni"/></constructor-arg>
<constructor-arg index="2"><ref bean="simpleWhitePaster"/></constructor-arg>
</bean>
<bean id="fontGenRandom" class="com.octo.captcha.component.image.fontgenerator.RandomFontGenerator" >
<constructor-arg index="0"><value>40</value></constructor-arg>
<constructor-arg index="1"><value>50</value></constructor-arg>
<constructor-arg index="2">
<list>
<ref bean="fontArial"/>
</list>
</constructor-arg>
</bean>
<bean id="fontArial" class="java.awt.Font" >
<constructor-arg index="0"><value>Arial</value></constructor-arg>
<constructor-arg index="1"><value>0</value></constructor-arg>
<constructor-arg index="2"><value>10</value></constructor-arg>
</bean>
<bean id="backGenUni" class="com.octo.captcha.component.image.backgroundgenerator.UniColorBackgroundGenerator" >
<constructor-arg index="0"><value>300</value></constructor-arg>
<constructor-arg index="1"><value>100</value></constructor-arg>
</bean>
<bean id="simpleWhitePaster" class="com.octo.captcha.component.image.textpaster.SimpleTextPaster" >
<constructor-arg type="java.lang.Integer" index="0">
<value>3</value>
</constructor-arg>
<constructor-arg type="java.lang.Integer" index="1">
<value>5</value>
</constructor-arg>
<constructor-arg type="java.awt.Color" index="2">
<ref bean="colorBlack"/>
</constructor-arg>
</bean>
<bean id="colorGreen" class="java.awt.Color" >
<constructor-arg index="0"><value>0</value></constructor-arg>
<constructor-arg index="1"><value>255</value></constructor-arg>
<constructor-arg index="2"><value>0</value></constructor-arg>
</bean>
<bean id="colorBlack" class="java.awt.Color" >
<constructor-arg index="0"><value>0</value></constructor-arg>
<constructor-arg index="1"><value>0</value></constructor-arg>
<constructor-arg index="2"><value>0</value></constructor-arg>
</bean>
<bean id="captchaService" class="com.octo.captcha.service.multitype.GenericManageableCaptchaService">
<constructor-arg index="0"><ref bean="imageEngine"/></constructor-arg>
<constructor-arg index="1"><value>180</value></constructor-arg>
<constructor-arg index="2"><value>180000</value></constructor-arg>
</bean>
For test purpose I have used a Simple Text Captcha.
3) To test create a command,controller and JSP like this
public class LoginCommand implements Serializable {
private String verificationTextForForgotPass;
//getter and setter methods
}
package com.example.web.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import com.octo.captcha.service.CaptchaServiceException;
import com.example.domain.LoginCommand;
public class CaptchaDemoController extends LoginBaseController {
private CaptchaService captchaService;
//Getter and setter for captchaService
public CaptchaDemoController() {
setCommandClass(LoginCommand.class);
}
@Override
protected Object formBackingObject(HttpServletRequest request) throws Exception {
LoginCommand command = new LoginCommand();
return command;
}
@Override
protected ModelAndView processFormSubmission(HttpServletRequest request, HttpServletResponse response,
Object command, BindException errors) throws Exception {
boolean isResponseCorrect = false;
String sessionId = request.getSession().getId();
//retrieve the response
String verificationText = ((LoginCommand) command).getVerificationTextForForgotPass();
// Call the Service method
try {
isResponseCorrect = getCaptchaService().validateResponseForID(sessionId, verificationText);
}
catch (CaptchaServiceException e) {
//should not happen, may be thrown if the id is not valid
}
//You can do whatever you want to based on the response
response.getWriter().write(String.valueOf(isResponseCorrect));
return null;
}
}
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <head> <title>Captcha Demo</title> </head> <form:form action="captchaDemo.htm"> <img id="captchaImage" src="http://localhost:8080/LoginApplication/captcha.htm"> Enter the text here <form:input id="verificationTextForgPassDiv" path="verificationTextForForgotPass" cssErrorClass="errorField"/> <input type="submit" name="Submit" value="Submit"/> </form:form>
As you can see the JSP will just show one Captcha Image and a text box where you can enter the Image text. The controller will verify the entered text and display true or false based on the result. You can implement your logic here for the Captcha verification result.
4) Finally make the following entries in your corresponding spring config file
<beans>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/captchaDemo.htm">captchaDemoController</prop>
<prop key="/captcha.htm">captchaController</prop>
</props>
</property>
</bean>
</beans>
<bean id="captchaDemoView" parent="baseView"> <property name="url" value="/WEB-INF/jsp/captchaDemo.jsp"/> </bean>
<bean id="captchaDemoController" class="com.example.web.controller.CaptchaDemoController">
<property name="formView" value="captchaDemoView"/>
<property name="successView" value="captchaDemoView"></property>
<property name="captchaService" ref="captchaService" />
</bean>
Oops I forgot to mention, you should have JCaptcha jars in your classpath for this example to work ![]()
I have written this post using the working code I have. I might have missed some configuration in this post. Let me know if you get any error. I will update the post.
MyEclipse Hibernate Spring tutorial – Managing Hibernate transaction in Spring
Spring transaction management, Hibernate transaction management in Spring
There was a problem/defect in the MyEclipse tutorial on Hibernate Spring. It was not a major problem. The tutorial demonstrates the Spring and Hibernate functionality pretty well. The only problem was that the code does seems to work properly. Because of absence of proper transaction management in code the data was not getting persisted in the database. Because of the caching in Hibernate it seems to the user that the data is being written to the database and then read back.
There are two solutions to the problem. One is to write the transaction management code in the java class itself. Another is to manage transaction via Spring’s transaction management. The second solution makes more sense because it shows of the Spring’s capability of managing transaction in Hibernate. You can see both the solutions here.
I am writing the Spring’s configuration for Hibernate transaction management again.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="configLocation" value="file:src/hibernate.cfg.xml"> </property> </bean> <bean id="userDAOTarget" class="com.myeclipse.hibernatespring.UserDAO"> <property name="sessionFactory"> <ref bean="sessionFactory" /> </property> </bean> <bean id="userDAOService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager" ref="transactionManager"/> <property name="transactionAttributes"> <props> <prop key="add*">PROPAGATION_REQUIRED</prop> <prop key="update*">PROPAGATION_REQUIRED</prop> <prop key="delete*">PROPAGATION_REQUIRED</prop> </props> </property> <property name="target"><ref local="persistenceLayer"/></property> </bean> <bean id="persistenceLayer" class="com.myeclipse.hibernatespring.PersistenceLayer" abstract="false" singleton="true" lazy-init="default" autowire="default" dependency-check="default"> <property name="userDAO"> <ref bean="userDAOTarget" /> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory"><ref bean="sessionFactory"/></property> </bean> </beans>
-
Archives
- October 2009 (2)
- September 2009 (3)
- August 2009 (2)
- July 2009 (1)
- June 2009 (2)
- May 2009 (3)
- April 2009 (8)
- February 2009 (2)
- December 2008 (1)
- November 2008 (3)
- October 2008 (1)
- January 2008 (8)
-
Categories
-
RSS
Entries RSS
Comments RSS

