【问题标题】:spring-boot using multiple view resolvers from xml configuration not redirecting correctlyspring-boot 使用来自 xml 配置的多个视图解析器未正确重定向
【发布时间】:2016-11-28 23:45:17
【问题描述】:

我有一个使用 spring xml 的遗留应用程序,我正在迁移到 spring-boot。

应用程序启动,我得到了身份验证页面,映射在 applicationContext-login.xml 中。登录成功后,它应该加载 WEB-INF/client/home.jsp,但相反,它会尝试加载 /WEB-INF/auth/home.jsp,我得到 404。 在启动日志中,我看到它映射了所有路径。 为什么这些重定向会发生冲突,我可以做些什么来解决这个问题?它会因为多个包含视图解析器的 @ImportResource 遇到问题吗?

从安全 http 配置中提取:

    <s:http use-expressions="true" entry-point-ref="delegatingAuthenticationEntryPoint">
        <s:form-login login-page="/auth/login"
                      login-processing-url="/auth/j_spring_security_check"
                      authentication-failure-url="/auth/login-secure?loginFailed=true"
                      default-target-url="/auth/defaultEntry"/>
        <s:logout logout-url="/auth/logout" logout-success-url="/auth/logout-success" delete-cookies="jsessionid"/>
    </s:http>

它指向的控制器:

    @RequestMapping(value = "/defaultEntry", method = RequestMethod.GET)
    public String defaultEntry() {
        if (authentication.isAuthenticated()) {
              return "redirect:/client/home";
        } else {
            return "redirect:login";
        }
    }

应用程序在 xml 文件中配置了多个视图解析器:

  • 类路径*:/springContext/applicationContext-login.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:context="http://www.springframework.org/schema/context"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
                          http://www.springframework.org/schema/beans/spring-beans.xsd
                          http://www.springframework.org/schema/context
                          http://www.springframework.org/schema/context/spring-context.xsd
                          http://www.springframework.org/schema/mvc
                          http://www.springframework.org/schema/mvc/spring-mvc.xsd"
        default-init-method="init"
        default-destroy-method="destroy">
    
      <import resource="applicationContext-web-common.xml" />
    
      <!-- Static login resources -->
      <mvc:resources mapping="/css/**" location="/WEB-INF/auth/css/"/>
      <mvc:resources mapping="/assets/**" location="/WEB-INF/auth/assets/"/>
      <mvc:resources mapping="/js/**" location="/WEB-INF/auth/js/"/>
    
      <context:component-scan base-package="org.myCompany.auth" />
    
      <!-- view resolver for JSP -->
      <bean id="loginViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
          <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
          <property name="prefix" value="/WEB-INF/auth/"/>
          <property name="suffix" value=".jsp"/>
      </bean>
    
      <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
          <property name="defaultLocale" value="en_US"/>
      </bean>
    

  • 类路径*:/springContext/applicationContext-client.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:context="http://www.springframework.org/schema/context"
          xmlns:mvc="http://www.springframework.org/schema/mvc"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/context
                            http://www.springframework.org/schema/context/spring-context.xsd
                            http://www.springframework.org/schema/mvc
                            http://www.springframework.org/schema/mvc/spring-mvc.xsd"
          default-init-method="init"
          default-destroy-method="destroy">
    
        <import resource="applicationContext-web-common.xml" />
    
        <context:component-scan base-package="org.myCompany.client" />
    
        <!-- Static resources -->
        <mvc:resources mapping="/player/**" location="/WEB-INF/client/player/"/>
        <mvc:resources mapping="/css/**" location="/WEB-INF/client/css/"/>
        <mvc:resources mapping="/data/**" location="/WEB-INF/client/data/"/>
        <mvc:resources mapping="/js/**" location="/WEB-INF/client/js/"/>
        <mvc:resources mapping="/locales/**" location="/WEB-INF/client/locales/"/>
        <mvc:resources mapping="/media/**" location="/WEB-INF/client/media/"/>
        <mvc:resources mapping="/index.html" location="/WEB-INF/client/index.html"/>
        <mvc:resources mapping="/test.html" location="/WEB-INF/client/test.html"/>
        <mvc:resources mapping="/admin/**" location="/WEB-INF/client/admin/"/>
        <mvc:resources mapping="/documentation/**" location="/WEB-INF/client/documentation/"/>
    
    
        <bean id="clientViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
            <property name="prefix" value="/WEB-INF/client/"/>
            <property name="suffix" value=".jsp"/>
        </bean>
    
    
    </beans>
    

还有一些其他的遵循相同的配置模式。

我正在加载Application.java中的资源

    @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
    //@EnableWebMvc
    @ComponentScan({"org.myCompany"})
    @ImportResource({"classpath*:/springContext/applicationContext-controllers.xml",
            "classpath*:/springContext/applicationContext-rest.xml",
            "classpath*:/springContext/applicationContext-login.xml",
            "classpath*:/springContext/applicationContext-client.xml",
            "classpath*:/springContext/applicationContext-admin.xml",
            "classpath*:/springContext/applicationContext-logging.xml",
            "classpath*:/springContext/applicationContext-web-common.xml"
    })
    public class Application extends SpringBootServletInitializer {

        public static void main(String[] args) throws UnknownHostException {
            SpringApplication app = new SpringApplication(Application.class);
            ApplicationContext ctx = app.run(args);
            Environment env = ctx.getEnvironment();

            logger.info(String.format("\n----------------------------------------------------------\n\t" +
                            "Application '%s' is running! Access URLs:\n\t" +
                            "Local: \t\thttp://localhost:%s\n\t" +
                            "External: \thttp://%s:%s\n----------------------------------------------------------",
                    env.getProperty("spring.application.name"),
                    env.getProperty("server.port"),
                    InetAddress.getLocalHost().getHostAddress(),
                    env.getProperty("server.port")));
        }

        @Bean
        public ServletRegistrationBean restDispatcher() {
            ServletRegistrationBean registration = new ServletRegistrationBean(new DispatcherServlet(),
                    "/rest/*", "/websocket/*");
            registration.setName("rest-dispatcher");
            registration.setLoadOnStartup(2);
            Map<String, String> params = new HashMap<>();
            params.put("contextConfigLocation", "classpath*:springContext/applicationContext-rest.xml");
            registration.setInitParameters(params);
            return registration;
        }

        @Bean
        public ServletRegistrationBean authDispatcher() {
            ServletRegistrationBean registration = new ServletRegistrationBean(new DispatcherServlet(), "/auth/*");
            registration.setName("auth-dispatcher");
            registration.setLoadOnStartup(2);
            Map<String, String> params = new HashMap<>();
            params.put("contextConfigLocation", "classpath*:springContext/applicationContext-login.xml");
            registration.setInitParameters(params);
            return registration;
        }

        @Bean
        public ServletRegistrationBean clientDispatcher() {
            ServletRegistrationBean registration = new ServletRegistrationBean(new DispatcherServlet(), "/client/*");
            registration.setName("client-dispatcher");
            registration.setLoadOnStartup(2);
            Map<String, String> params = new HashMap<>();
            params.put("contextConfigLocation", "classpath*:springContext/applicationContext-client.xml");
            registration.setInitParameters(params);
            return registration;
        }

    //... other servlets registration, filters registration

    }

【问题讨论】:

    标签: xml spring jsp spring-mvc spring-boot


    【解决方案1】:

    您正在从登录屏幕返回redirect:/client/home,这将由您的 loginViewResolver 处理:

    <bean id="loginViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
          <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
          <property name="prefix" value="/WEB-INF/auth/"/>
          <property name="suffix" value=".jsp"/>
      </bean>
    

    clientViewResolver 不会被调用,因为在视图解析器上没有指定顺序。您可以使用 order 属性设置顺序。,

    【讨论】:

    • 但是为什么在 spring mvc 应用程序上一切正常?
    • 如果你不指定一个顺序,它会在两者上都采用默认顺序——这意味着哪个先出现是不可预测的,因此可能会也可能不会。
    • 将订单 1 添加到客户端,将订单 2 添加到登录。现在我只得到请求 URL:localhost:8000/client/home 请求方法:GET 状态代码:404 Not Found
    • 你正在重定向到redirect:/client/home,并且视图解析器也有前缀WEB-INF/client,所以它会被解析为WEB-INF/client/client/home.jsp。另请注意,您将面临使用 2 个解析器的问题 - 如果一个找不到 jsp,它不会将控制权传递给第二个。您只需要 1,因为两者都是相同的类型,只是前缀不同。
    • 我知道拥有多个视图解析器并不理想,但我无法重构整个应用程序。我只需要一种方法来使用 spring-boot 来运行它以用于开发目的,同时不影响生产构建流程。重定向仍然不起作用。关于如何使其工作的任何建议?
    【解决方案2】:

    我可以假设,这是由 Spring Security 配置引起的,并且不依赖于 View Resolvers。看起来成功登录后用户被重定向到他之前尝试访问的页面,它可能不是/defaultEntry。尝试如下编辑您的 Spring Security http 配置:

    <s:http use-expressions="true" entry-point-aref="delegatingAuthenticationEntryPoint">
        <s:form-login login-page="/auth/login"
                      login-processing-url="/auth/j_spring_security_check"
                      authentication-failure-url="/auth/login-secure?loginFailed=true"
                      default-target-url="/auth/defaultEntry"
                      always-use-default-target="true"/>
        <s:logout logout-url="/auth/logout" logout-success-url="/auth/logout-success" delete-cookies="jsessionid"/>
    </s:http>
    

    如果有帮助 - 您将获得进一步查看的线索。

    另外,看看这个StackOverFlow answer

    【讨论】:

      【解决方案3】:

      您定义的调度程序 servlet 配置存在问题

        <bean id="clientViewResolve" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/client/"/>
        <property name="suffix" value=".jsp"/>
      

      使用该配置,它可能会解析为 /WEB-INF/client/client/*.jsp

      最好使用单个视图解析器,而不是复杂地使用两个视图解析器。

      【讨论】:

        猜你喜欢
        • 2011-07-20
        • 2020-09-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-10
        • 2018-03-10
        • 1970-01-01
        相关资源
        最近更新 更多