Spring MVC Portlet and Liferay: No matching handler method found for portlet request actionUrl

mannuk picture mannuk · Aug 29, 2013 · Viewed 9.3k times · Source

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?

Answer

Niranjan picture Niranjan · Aug 30, 2013

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>