I previously showed how to create a Liferay Spring MVC Freemarker portlets. But what if you want to use both Freemarker and JSP in the same portlet? Is it possible? If you are using Spring 3.0 or higher, it certainly is. And it's actually very simple and easy to do. I'm going to show you how to create Liferay Spring MVC Freemarker and JSP portlets in a moment.
But first. When would you need to do this? I really haven't found any use for this when creating a brand new portlet on my own. However, I have found this useful in multiple cases. If somebody delivers JSP-files for a project you are working on, and you really want to do your own work in Freemarker, since Freemarker is superior to JSP, this gives you a solution without very much added effort. This method is also great when upgrading your portlets from JSP to Freemarker. It allows you to gradually upgrade rather than do everything in a single big bang. And if you aren't really sure if you should be upgrading your portlets or not, I highly recommend reading 10 reasons to replace your JSPs with Freemarker templates on the Stack Hunter blog. Finally, if you are extending a legacy portlet that uses JSP, and you really don't feel like mucking about with JSP any more, this method comes to the rescue.
Now, before you continue, Liferay has an issue with Spring MVC Freemarker portlets resulting in a nullpointer exception in FreeMarkerView.getTemplate(). If you don't already know how to handle this, please read my post I linked to in the first paragraph before continuing.
Spring 3.0 added support for multiple view resolvers by giving them priorities. Using multiple ordered view resolvers is as simple as adding both resolvers, just as you would if you were adding theme as singletons in addition to giving them a priority. View resolvers with a lower priority number resolve before resolvers with a higher priority number.
Contemplate this code:
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"> <property name="templateLoaderPath" value="/WEB-INF/freemarker/"/> </bean> <bean id="viewResolver" class="is.brendan.liferay.web.freemarker.ExtendedFreemarkerViewResolver"> <property name="cache" value="true"/> <property name="prefix" value=""/> <property name="suffix" value=".ftl"/> <property name="exposeSpringMacroHelpers" value="true"/> <property name="freemarkerConfigurer" ref="freemarkerConfig"/> <property name="order" value="0" /> </bean> <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView" /> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> <property name="order" value="1" /> </bean>
Now, if you return the "myview" in your Spring MVC @RenderMapping mapped method, Spring will first investigate the /WEB-INF/freemarker/ folder looking for a file named myview.ftl. If that file does not exist, Spring will move on and investigate the /WEB-INF/jsp/ folder looking for a file named myview.jsp. Naturally, if neither of the files exists, your portlet will crash and burn.