I'm developing a portlet with Spring MVC Portlet and deployed in Liferay. My intention for this portlet is to show a tree with some important info. To achieve this goal i need to request the server json files with the info that fills the tree.
The jsp page itself loads ok. I added a link in order to test if i can get a valid json. I've been looking for help and documentation and i generate a friendly url in the jsp. But when i click the link to get the json, the server throws the following error:
12:07:40,767 ERROR [http-bio-8080-exec-5][render_portlet_jsp:154] org.springframework.web.portlet.NoHandlerFoundException: No matching handler method found for portlet request: mode 'view', phase 'ACTION_PHASE', parameters map['action' -> array<String>['showTree']]
at com.liferay.portlet.FilterChainImpl.doFilter(FilterChainImpl.java:70)
at com.liferay.portal.kernel.portlet.PortletFilterUtil.doFilter(PortletFilterUtil.java:48)
at com.liferay.portal.kernel.servlet.PortletServlet.service(PortletServlet.java:111)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:72)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilter.doFilter(InvokerFilter.java:73)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:684)
at org.apache.catalina.core.ApplicationDispatcher.doInclude(ApplicationDispatcher.java:593)
at org.apache.catalina.core.ApplicationDispatcher.include(ApplicationDispatcher.java:530)
at com.liferay.portlet.InvokerPortletImpl.invoke(InvokerPortletImpl.java:534)
at com.liferay.portlet.InvokerPortletImpl.invokeAction(InvokerPortletImpl.java:579)
at com.liferay.portlet.InvokerPortletImpl.processAction(InvokerPortletImpl.java:294)
at com.liferay.portal.action.LayoutAction.processPortletRequest(LayoutAction.java:944)
at com.liferay.portal.action.LayoutAction.processLayout(LayoutAction.java:688)
at com.liferay.portal.action.LayoutAction.execute(LayoutAction.java:249)
at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:431)
Maybe i forgot something important. I paste the relevant parts of my code:
home.jsp (rendered home page)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1-transitional.dtd">
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet"%>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<body>
<!-- Add a <div> element where the tree should appear: -->
<h1>Liferay Spring Portlet MVC - Tree</h1>
<p>The time on the server is ${serverTime}.</p>
<p>Date: <input type="text" id="datepicker" /></p>
<div id="tree"> </div>
<portlet:actionURL var="ajaxTreeURL">
<portlet:param name="action" value="showTree"/>
</portlet:actionURL>
<a href="<%= ajaxTreeURL.toString() %>" > Go </a>
</body>
</html>
HomeController.java (renders the page and handles the requests)
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
@Autowired
private ExperimentService experimentService;
/**
* Simply selects the home view to render by returning its name.
*/
@RenderMapping
public String home(Locale locale, Model model) {
logger.info("Welcome home! the client locale is "+ locale.toString());
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate);
experimentService.getExperiments();
return "home";
}
@RequestMapping(params= {"action=showTree"})
public void showTreeHandler(ResourceRequest request, ResourceResponse response, Model model) throws Exception {
OutputStream outStream = response.getPortletOutputStream();
StringBuffer buffer = new StringBuffer();
Map<String, String> testMap = new HashMap<String, String>();
testMap.put("foo", "bar");
String test = new JSONObject(testMap).toString();
buffer.append(test);
outStream.write(buffer.toString().getBytes());
}
} String home(Locale locale, Model model) {
logger.info("Welcome home! the client locale is "+ locale.toString());
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate);
experimentService.getExperiments();
return "home";
}
@RequestMapping(params= {"action=showTree"})
public void showTreeHandler(ResourceRequest request, ResourceResponse response, Model model) throws Exception {
OutputStream outStream = response.getPortletOutputStream();
StringBuffer buffer = new StringBuffer();
Map<String, String> testMap = new HashMap<String, String>();
testMap.put("foo", "bar");
String test = new JSONObject(testMap).toString();
buffer.append(test);
outStream.write(buffer.toString().getBytes());
}
}
I add some extra config files (portlet.xml):
<?xml version="1.0"?>
<portlet-app
version="2.0"
xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
>
<portlet>
<portlet-name>liferay-spring-mvc</portlet-name>
<display-name>Liferay Spring MVC Portlet</display-name>
<portlet-class>org.springframework.web.portlet.DispatcherPortlet</portlet-class>
<init-param>
<name>contextConfigLocation</name>
<value>/WEB-INF/spring/context-portlet.xml</value>
</init-param>
<init-param>
<name>viewRendererUrl</name>
<value>/mappingUrls</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
</supports>
<portlet-info>
<title>Liferay Spring MVC Portlet</title>
<short-title>Liferay Spring MVC Portlet</short-title>
<keywords>liferay spring mvc portlet</keywords>
</portlet-info>
<security-role-ref>
<role-name>administrator</role-name>
</security-role-ref>
<security-role-ref>
<role-name>guest</role-name>
</security-role-ref>
<security-role-ref>
<role-name>power-user</role-name>
</security-role-ref>
<security-role-ref>
<role-name>user</role-name>
</security-role-ref>
</portlet>
</portlet-app>
context-portlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<!-- Autodetect annotated controllers -->
<context:component-scan base-package="es.unican.meteo" />
<bean class="org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
Can somebody help me with this issue?
Use
<portlet:resourceURL var="ajaxTreeURL">
<portlet:param name="action" value="showTree"/>
</portlet:resourceURL>
instead of
<portlet:actionURL var="ajaxTreeURL">
<portlet:param name="action" value="showTree"/>
</portlet:actionURL>