简体   繁体   中英

GET request processed by wrong DispatcherServlet (spring, tiles2, thymeleaf)

I decided to move my authorization functionality to another controller, however this caused some issues for me. Mainly, my callback controller cannot forward the GET request to the appropriate dispatcher servlet

DispatcherServlet with name 'Auth' processing GET request for [/user/username] (this should be 'Dashboard' dispatcher servlet)

My view layer is making use of spring, tiles 2, and thymeleaf integration. I have found this comment on stackoverflow, which shed some light on my situation. https://stackoverflow.com/a/13406096/2276284

"Secondly, when using Spring + Tiles, and returning some JSP in your tiles definition, it is treated as an internal forward request, and handled by the same servlet as the original request."

I found this stackoverflow comment as well, but it did not work for me. https://stackoverflow.com/a/17232532/2276284 Suggesting returning a new ModelAndView, or using the HttpServletResponse to redirect.

How can I successfully redirect to another controller/view?

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" 
                             id="pue" version="3.1">
    <!-- webapp properties -->
    <display-name>PUE</display-name>
    <description>Personal User Engagement for Instagram</description>

    <!-- session listener -->
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>

    <!-- root context -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/app-context.xml</param-value>
    </context-param>

    <!-- spring security filter -->
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- custom redirect filter -->
    <filter>
        <filter-name>pueUsernameAuthFilter</filter-name>
        <filter-class>abnd.pue.auth.service.impl.PUEUsernameAuthFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>pueUsernameAuthFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- servlet config -->
    <servlet>
        <servlet-name>Auth</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring/servlets/auth-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet>
        <servlet-name>IgOauth</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring/servlets/igoauth-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet>
        <servlet-name>Dashboard</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring/servlets/dashboard-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- servlet mapping config -->

    <servlet-mapping>
        <servlet-name>Auth</servlet-name>
        <url-pattern>/logout</url-pattern>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>IgOauth</servlet-name>
        <url-pattern>/ig/oauth/callback</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>Dashboard</servlet-name>
        <url-pattern>/user/{username}</url-pattern>
        <url-pattern>/user/{username}/profile</url-pattern>
        <url-pattern>/user/{username}/assets</url-pattern>
    </servlet-mapping>

    <!-- mime types -->
    <mime-mapping>
        <extension>ico</extension>
        <mime-type>image/x-icon</mime-type>
    </mime-mapping>
</web-app>

spring-thymeleaf-tiles.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- thymeleaf view resolvers with tiles integration -->
    <bean id="tilesConfigurer" class="org.thymeleaf.extras.tiles2.spring4.web.configurer.ThymeleafTilesConfigurer">
        <property name="definitions">
            <list>
                <value>/WEB-INF/tiles/tiles.xml</value>
            </list>
        </property>
    </bean>

    <!-- template resolver -->
    <bean id="templateResolver" class="org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver">
        <property name="prefix" value="/WEB-INF/tiles/" />
        <property name="suffix" value=".html" />
        <property name="templateMode" value="HTML5" />
        <property name="characterEncoding" value="utf-8" />
        <property name="cacheable" value="false" />
    </bean>

    <!-- template engine -->
    <bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
        <property name="templateResolver" ref="templateResolver" />
        <property name="additionalDialects">
            <set>
                <bean id="tilesDialect" class="org.thymeleaf.extras.tiles2.dialect.TilesDialect" />
            </set>
        </property>
    </bean>

    <!-- tiles view resolver -->
    <bean id="tilesViewResolver" class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
        <property name="viewClass" value="org.thymeleaf.extras.tiles2.spring4.web.view.ThymeleafTilesView" />
        <property name="templateEngine" ref="templateEngine" />
        <property name="characterEncoding" value="utf-8" />
        <property name="order" value="1" />
    </bean>

</beans>

IgOauthController

package abnd.pue.ig.controller;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import abnd.pue.ig.service.intf.IgOauthService;

@Controller
public class IgOauthController {  
    @Autowired
    private IgOauthService igOauthService;

    private static final Logger logger = LoggerFactory.getLogger(IgOauthController.class);

    /**
     * 
     * @param request
     * @return String
     * @throws IOException
     */
    @RequestMapping(value="/ig/oauth/callback")
    public ModelAndView igCallback(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws IOException {
        // get code parameter
        String code = request.getParameter("code");
        // attempt to get user name from callback
        String username = igOauthService.processCallbackRequest(request, session, code);

        // if username isn't empty redirect to user page
        if (!username.isEmpty()) {
            logger.info("username set: " + username);
            return new ModelAndView ("redirect:/user/" + username);
        }

        logger.info("no username set");

        // otherwise return to index TODO error display
        return new ModelAndView("redirect:/");
    }

}

Alright, thanks for the help guys. So, the issue was that I could not redirect my view away from the default DispatcherServlet. I was also using invalid url patterns in my web.xml, while trying to create dynamic urls.

The answer was restructuring the wiring of my servlet paths, and changing the default servlet from Auth, to Dashboard. I also implemented UrlRewriteFilter to redirect all traffic from root context ("/") to "/login"

Here are the affected changes.

web.xml

<!-- servlet mapping config -->
<servlet-mapping>
    <servlet-name>Auth</servlet-name>
    <url-pattern>/login</url-pattern>
    <url-pattern>/logout</url-pattern>
</servlet-mapping>

<servlet-mapping>
    <servlet-name>IgOauth</servlet-name>
    <url-pattern>/ig/oauth/callback</url-pattern>
</servlet-mapping>

<servlet-mapping>
    <servlet-name>Dashboard</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

IgOauthController

@Controller
@RequestMapping(value = "/ig/oauth")
public class IgOauthController {  
    @Autowired
    private IgOauthService igOauthService;

    private static final Logger logger = LoggerFactory.getLogger(IgOauthController.class);

    /**
     * 
     * @param request
     * @return String
     * @throws IOException
     */
    @RequestMapping(value="/callback")
    public void igCallback(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws IOException {
        // get code parameter
        String code = request.getParameter("code");
        // attempt to get user name from callback
        String username = igOauthService.processCallbackRequest(request, session, code);

        // if username isn't empty redirect to user page
        if (!username.isEmpty()) {
            logger.info("username set: " + username);
            response.sendRedirect("/" + username + "/dashboard");
            return;
        }

        logger.info("no username set");

        // otherwise return to index TODO error display
        response.sendRedirect("/login");
        return;
    }

}

DashboardController

@Controller
@RequestMapping(value = "/{username}")
public class DashboardController {

    @RequestMapping(value = "/dashboard", method=RequestMethod.GET)
    public ModelAndView userDashboard() throws InstagramException {
        ...
    }

    @RequestMapping(value = "/profile", method=RequestMethod.GET) 
    public ModelAndView userProfile() throws InstagramException {
        ...
    }

    @RequestMapping(value = "/assets", method=RequestMethod.GET) 
    public ModelAndView userAssets() throws InstagramException {
        ...
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM