注意 这是以前标记的答案,但随着我对底层组件的理解有所改进,我看到我们的初始答案只是解决了空指针,但没有解决根本原因。目前的根本原因似乎是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中的行处为空。
谢谢您花在审核上的时间。解决此问题的协助当然非常感谢!
答案 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
路径
安吉洛