I’m using Spring MVC in a project. I wanted to create a session scoped bean that I could reference directly from my JSP. In this case, it was a bean for holding status or error messages for display in the UI. It would keep a queue of messages, and would clear them when displayed.
The interface for my MessageUtil class was simple, with an addMessage method for adding a message to the queue, and a getFlashMessages method that gets all messages as a list and clears the internal queue.
The implementation could be equally simple. Mine has a touch more code in order to pull the actual message text from a resource bundle, but the class definition is very simple
public class MessageUtilImpl implements MessageUtil, Serializable
{
// implementation here
}
In my spring context configuration file, I defined the bean as follows:
<bean id="messageUtil" class="mypackage.MessageUtilImpl" scope="session">
<aop:scoped-proxy proxy-target-class="false"/>
<property name="messageSource" ref="messageSource" />
</bean>
Where the messageSource contains the bundle for messages. The real ticket here is the aop:scoped-proxy configuration.
Since I wanted to inject this message utility class into my Spring MVC controllers (which are of a greater scope than session scope) it was puking at me. Adding aop:scope-proxy configuration to the bean definition (which apparently isn’t available yet as an annotation, which is why I had to configure in xml instead) allows Spring to use AOP to inject the session bean into the controller for the thread that is processing the request, tying my messageUtil to the one that has been constructed for the current session.
One item of note is the proxy-target-class attribute. If you set it to false, then spring aop will use a java interface based proxy. This means that your bean must have an interface and an implementation, and that everywhere you use the bean, you must reference it via the interface and NOT the implementation. Well… DUH. If you have an interface and an impl, and you are referencing the impl, then what can I say? If you set that value to true, then spring aop will use cglib (which now must be on your build path, probably runtime path) to proxy the implementation class, meaning you don’t need to have an interface and implementation, you can simple have a class. I didn’t want to need cglib, so I chose interface based proxy.
With that magic done, now all I had to do was reference my messageUtil bean in the jsps so I could call the getFlashMessages() method and display them.
Now, I’m no JSP guru. I’ve spent the last 3 years in JSF land. I’m sure I could wire this up to get the messages via ajax and do something super awesome… but I didn’t. I’m using the Pines Notify jQuery plugin to show a simple growl-type message.
<script type="text/javascript" >
<c:forEach var="flashMessage" items="${sessionScope['scopedTarget.messageUtil'].flashMessages}" >
$.pnotify( {
pnotify_title: "${flashMessage.title}",
pnotify_text: "${flashMessage.message}",
pnotify_type: "${flashMessage.severity}",
pnotify_shadow: true
})
</c:forEach>
</script>
Besides the aop:scoped-proxy, the thing that took the longest to figure out was how to get the stinking spring session bean. You can see that I’m accessing it like this
${sessionScope['scopedTarget.messageUtil'].flashMessages}
The answer is the ‘scopedTarget’ prefix to the bean name. Since it uses a dot in the name, you can’t use sessionScope.scopedTarget.messageUtil, so the way it’s referenced above is the only way I know how to do it. It took surprisingly long for me to find it.
I’m sure as soon as I publish this, someone will find a reference to it in the official spring documentation, but Adobe Reader didn’t find it in the 799 page Spring Documentation PDF I have.
That’s it for this one. Have fun with spring session scoped beans and jsp el.