控制器

时间:2018-04-10 13:51:27

标签: java spring spring-mvc spring-boot dwr

注意 这是以前标记的答案,但随着我对底层组件的理解有所改进,我看​​到我们的初始答案只是解决了空指针,但没有解决根本原因。目前的根本原因似乎是dispatchListener和附加到容器的dwrServlet上下文缺乏可见性。

更新解决方案仍然难以捉摸,但我决定在此时放弃DWR有几个原因:自上次更新DWR以来,它已经很久了,Spring和Jquery提供了合适的替代品并且最近维护,删除我们的DWR依赖项将简化我们的项目。 此问题仅在学术目的上保持开放。

强烈提及我研究这个时间的时间。怜悯。

我相信我的设置是正确的,但显然我错过了一些至关重要的事情,我认为现在是时候寻找第二眼。

问题摘要

通过通过DWR调用的控制器方法访问它们时,我的bean为null。

详细问题说明

使用Spring版本4.3.0.RELEASE和Direct Web Remoting(org.directwebremoting.dwr)版本3.0.2-RELEASE;

  • com.mytest.beans包中定义的给定bean,它只包含一个包含字符串的字段(beanName),

  • 使用@Bean表示法在SpringWebConfig中建立(使用Srping的所有Java表示法,不使用xml - 仅使用带有dwr的xml),

  • 并在com.mytest.controller中定义的控制器中使用@Autowired自动装配,该控制器注释为@RemoteProxy,名称为“SController”,

  • 注释@Controller和注释@RequestMapping,其值为“/ dwr / *”,其中包含一个注释为@RemoteMethod的方法,名为getBeanName,它调用自动装配的实例sbean.beanName

  • 为自动装配的实例抛出一个空例外。

尝试的事情

我在这个例子中消除了错误地实例化bean的可能性,这是@Autowired的一个已知问题。我还小心地确保bean被注释为@Component,这是bean无法出现的另一个可能原因。我将dwr上的加载顺序设置为2,以便首先加载应用程序上下文,希望确保正常工作,这样我就可以访问dwr index.html进行测试和调试。

我也尝试将以下行添加到AppInitializer中:

dwr.setInitParameter("classes","com.mytest.bean.SBean, com.mytest.controller.SController");

但这没有帮助。

此示例中省略的内容

这不是完整的项目。 pom,项目结构和一些.jsp被省略。在我的测试中,我的身份验证功能正常,如果我添加一个dwr @RemoteMethod注入会话然后请求它,则可以访问添加到HttpSession的adUser属性。由于那些东西在实时应用程序(从中派生示例)中工作,我在示例中省略了它们,因为我不怀疑问题在于工作组件。日志配置也可能不相关,省略。也就是说,如果除了以下部分之外还有其他任何想要查看的内容,请告诉我,我会更新此问题。

配置

在我的com.mytest.config包中,我有三个类:AppInitializer,RootConfig和SpringWebConfig。 RootConfig只是空的。

AppInitializer 如下。我正在使用自制的Active Directory身份验证模块,该模块在其他Spring应用程序中运行良好,因此也就是UserLoginServlet。

package com.mytest.config;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.request.RequestContextListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

public class AppInitializer implements WebApplicationInitializer {

    private Logger logger = LoggerFactory.getLogger(AppInitializer.class);

    public void onStartup(ServletContext container) throws ServletException {

        try {

            AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
            ctx.register(SpringWebConfig.class);
            ctx.setServletContext(container);
            container.addListener(new ContextLoaderListener(ctx));
            container.addListener(new RequestContextListener());
            logger.info("Created AnnotationConfigWebApplicationContext");

            ServletRegistration.Dynamic dispatcher = container.addServlet("spring-mvc-dispatcher", new DispatcherServlet(ctx));
            dispatcher.setLoadOnStartup(1);
            dispatcher.addMapping("/");
            logger.info("DispatcherServlet added to AnnotationConfigWebApplicationContext");

            ServletRegistration.Dynamic servlet = container.addServlet("login", new com.mycompany.ad.UserLoginServlet());

            servlet.setLoadOnStartup(1);
            servlet.addMapping("/login/*");
            logger.info("UserLoginServlet added to AnnotationConfigWebApplicationContext");

            ServletRegistration.Dynamic dwr = container.addServlet("dwr", new org.directwebremoting.servlet.DwrServlet());
            dwr.setInitParameter("debug", "true");
            dwr.setLoadOnStartup(2);
            dwr.addMapping("/dwr/*");
            logger.info("DWR Servlet Mapping Created");
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage(), e);
        }

    }

}

SpringWebConfig 的定义如下。

package com.mytest.config;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.directwebremoting.annotations.DataTransferObject;
import org.directwebremoting.annotations.GlobalFilter;
import org.directwebremoting.annotations.RemoteProxy;
import org.directwebremoting.extend.Configurator;
import org.directwebremoting.spring.DwrClassPathBeanDefinitionScanner;
import org.directwebremoting.spring.DwrController;
import org.directwebremoting.spring.DwrHandlerMapping;
import org.directwebremoting.spring.SpringConfigurator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.mytest"})
@PropertySource(value = { "classpath:application.properties" })
public class SpringWebConfig extends WebMvcConfigurerAdapter {

    private Logger logger = LoggerFactory.getLogger(SpringWebConfig.class);

    @Bean
    public DwrController dwrController(ApplicationContext applicationContext){
        logger.info("Starting dwrController Bean");
        BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry)applicationContext.getAutowireCapableBeanFactory();
        Map<String,String> configParam = new HashMap<String, String>();


        logger.info("Configuring scanners for DWR Bean");

        ClassPathBeanDefinitionScanner scanner = new DwrClassPathBeanDefinitionScanner(beanDefinitionRegistry);
        scanner.addIncludeFilter(new AnnotationTypeFilter(RemoteProxy.class));
        scanner.addIncludeFilter(new AnnotationTypeFilter(DataTransferObject.class));
        scanner.addIncludeFilter(new AnnotationTypeFilter(GlobalFilter.class));
        scanner.scan("com.mytest.bean");


        logger.info("Instantiating DwrController instance");
        DwrController dwrController = new DwrController();
        dwrController.setDebug(true);
        dwrController.setConfigParams(configParam);

        logger.info("Setting up SpringConfigurator for dwrController");
        SpringConfigurator springConfigurator = new SpringConfigurator();
        List<Configurator> configurators = new ArrayList<Configurator>();
        configurators.add(springConfigurator);
        dwrController.setConfigurators(configurators);

        logger.info("dwrController ready.");
        return dwrController;
    }

    @Bean
    public BeanNameUrlHandlerMapping beanNameUrlHandlerMapping(){
        logger.info("Setting up beanNameUrlHandlerMapping");
        BeanNameUrlHandlerMapping beanNameUrlHandlerMapping = new BeanNameUrlHandlerMapping();
        logger.info("beanNameUrlHandlerMapping ready.");
        return beanNameUrlHandlerMapping;
    }

    @Bean
    public DwrHandlerMapping dwrHandlerMapping(DwrController dwrController){
        logger.info("Setting up dwrHandlerMapping");
        Map<String,DwrController> urlMap = new HashMap<String, DwrController>();
        urlMap.put("/dwr/**/*",dwrController);

        DwrHandlerMapping dwrHandlerMapping = new DwrHandlerMapping();
        dwrHandlerMapping.setAlwaysUseFullPath(true);
        dwrHandlerMapping.setUrlMap(urlMap);
        logger.info("dwrHandlerMappying ready.");
        return dwrHandlerMapping;
    }

    @Bean(name="sBean") 
    public SBean sBean() {
        logger.info("SBean starting");
        return new SBean();
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
        logger.info("DefaultServletHandlerConfigurer enabled");
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry){          
        // not using an interceptor
    }


}

这些是示例中最复杂的部分。为了便于说明,以下更简单的部分尽可能地备用。

SController 类:

package com.mytest.controller;

import javax.servlet.http.HttpSession;

import org.directwebremoting.annotations.RemoteMethod;
import org.directwebremoting.annotations.RemoteProxy;
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.bind.annotation.ResponseBody;

import com.mytest.bean.SBean;


@RemoteProxy(name="SController")
@Controller
@RequestMapping("/dwr/*")
public class SController {

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

    @Autowired
    SBean sbean;

    @RemoteMethod
    @RequestMapping("getBeanName")
    @ResponseBody public String getBeanName() {
        try {
            return sbean.beanName;
        }
        catch(Exception e) {
            logger.error(e.getLocalizedMessage(),e);
            return "Error!";
        }

    }
}

SBean

package com.mytest.bean;

import org.springframework.stereotype.Component;

@Component
public class SBean {
    public String beanName="Sean";
}

dwr.xml 文件

<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 3.0//EN" "dwr30.dtd">
<dwr>
  <allow>

    <create creator="new" javascript="SController" scope="script">
      <param name="class" value="com.mytest.controller.SController"/>
    </create>

  <convert converter="bean" match="java.lang.Throwable"/>
  <convert converter="bean" match="java.lang.StackTraceElement"/>

  <convert match="com.mytest.bean.SBean" converter="bean"/>

  </allow>
</dwr>

如图所示,考虑到Angelo的初始评论,dwr正在/ dwr运行,而dwr / index.html正在运行。 Spring也在工作,所以简单地点击/ getBeanName现在返回“Sean”而不是像之前那样尝试重定向到/ Sean。但是,从自动生成的dwr测试页面执行测试调用仍会产生错误,指示在访问sBean的Controller中的行处为空。

谢谢您花在审核上的时间。解决此问题的协助当然非常感谢!

1 个答案:

答案 0 :(得分:1)

正如我告诉你的那样,你使用的是DWR Servlet而不是spring servlet。为解决第一个问题,您必须使用DWR提供的弹簧支持,如您在此链接中所见http://directwebremoting.org/dwr/documentation/server/integration/spring.html

关于第二个问题(404错误),我认为这与您删除dwr servlet后现在只有/dwr/Sean路径的事实有关。 尝试使用/dwr/Sean而不是dwr/dwr/Sean路径

安吉洛