Java 控制器中的Spring WebMVCConfigureAdapter、WebApplicationInitializer和DWR空bean
注意这之前被标记为已回答,但随着我对底层组件的理解有所提高,我发现我们最初的回答只是针对空指针,而没有针对根本原因。目前的根本原因似乎是dispatchListener和附加到容器的dwrServlet上的上下文都不可见 更新解决方案仍然难以捉摸,但我现在决定放弃DWR,原因有几个:DWR的上次更新已经很久了,Spring和Jquery提供了合适的替代方案,并且是最近维护的,删除我们的DWR依赖项将简化我们的项目。这个问题目前仅限于学术目的 必须提到我花了多少时间研究这个。发发慈悲吧 我相信我的设置是正确的,但很明显我错过了一些关键的东西,我认为是时候寻找第二双眼睛了 问题摘要 当通过DWR调用的控制器方法访问我的bean时,它们是空的 详细问题描述 使用SpringVersion4.3.0.RELEASE和directwebremoting(org.directwebremoting.dwr)Version3.0.2-RELEASEJava 控制器中的Spring WebMVCConfigureAdapter、WebApplicationInitializer和DWR空bean,java,spring,spring-mvc,spring-boot,dwr,Java,Spring,Spring Mvc,Spring Boot,Dwr,注意这之前被标记为已回答,但随着我对底层组件的理解有所提高,我发现我们最初的回答只是针对空指针,而没有针对根本原因。目前的根本原因似乎是dispatchListener和附加到容器的dwrServlet上的上下文都不可见 更新解决方案仍然难以捉摸,但我现在决定放弃DWR,原因有几个:DWR的上次更新已经很久了,Spring和Jquery提供了合适的替代方案,并且是最近维护的,删除我们的DWR依赖项将简化我们的项目。这个问题目前仅限于学术目的 必须提到我花了多少时间研究这个。发发慈悲吧 我相信我的
- 包com.mytest.beans中定义的给定bean,它只包含一个包含字符串的字段(beanName)
- 在SpringWebConfig中使用@Bean表示法建立(使用所有Java表示法进行Srping,没有xml-仅使用xml和dwr)
- 并在com.mytest.controller中定义的控制器中使用@autowired进行自动连接,该控制器被注释为@RemoteProxy,名称为“scocontroller”
- 注释@Controller和注释@RequestMapping的值为“/dwr/*”,其中包含一个名为getBeanName的方法注释@RemoteMethod,该方法调用自动连线实例sbean.beanName
- 为自动连线实例引发null异常
dwr.setInitParameter("classes","com.mytest.bean.SBean, com.mytest.controller.SController");
但这没有帮助
本例中省略的内容
这不是完整的项目。省略了pom、项目结构和一些.jsp。在我的测试中,我的身份验证功能正常,如果我添加一个dwr@RemoteMethod来注入会话并请求它,那么可以访问添加到HttpSession的adUser属性。由于这些东西在live app(示例就是从中派生出来的)中起作用,我在示例中省略了它们,因为我不怀疑问题出在工作组件上。日志记录配置也可能不相关,因此被省略。这就是说,如果有什么你想看到除了以下部分,请让我知道,我会更新这个问题
配置
在我的包com.mytest.config中,我有三个类:AppInitializer、RootConfig和SpringWebConfig。RootConfig只是空的
AppInitializer如下所示。我使用的是一个home brew 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
}
}
斯比恩阶级
dwr.xml文件
如目前所示,考虑到Angelo的初始注释,dwr在/dwr处运行,dwr/index.html正在工作。Spring也在工作,因此只需点击/getBeanName现在就会返回“Sean”,而不是像以前那样尝试重定向到/Sean。但是,从自动生成的dwr测试页面执行测试调用仍然会产生一个错误,指示在访问sBean的控制器中的行处出现null
感谢您花时间审阅此内容。当然,我们非常感谢您协助解决此问题 正如我告诉您的,重点是您使用的是DWR Servlet,而不是spring Servlet。为了解决第一个问题,您必须使用DWR提供的spring支持,正如您在本链接中看到的那样 关于第二个问题(404错误),我认为这与以下事实有关:自从您删除了dwr servlet之后,您现在只有
/dwr/Sean
路径。
尝试使用/dwr/Sean
而不是dwr/dwr/Sean
路径
Angelo我看到的是您正在使用DWRServlet。在这种情况下,您没有使用SpringServlet,SpringContext也没有直接注入到这个servlet中。尝试在这里看一看感谢@Angelo的建议,我注释掉了DWR Servlet,在dispatcher上的全局映射之前添加了/DWR/*映射,并在控制器方法声明中添加了@RequestMapping(“getBeanName”),现在如果我调用mytest/DWR/DWR/getBeanName,它将返回404 DWR/DWR/Sean not found,这表明空指针问题已经解决,但我还有一些其他问题需要用标准Spring dispatcher解决。请随意添加一个我可以接受的答案。我还没有放弃让servlet共存并共享一个上下文,但一个可行但我不喜欢的解决方法是让DWR入口点不尝试连接到自动连线bean,而是向Spring控制器发出Web请求。就HTTP流量而言,它使每个DWR调用增加了一倍,但只增加了一半
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!";
}
}
}
package com.mytest.bean;
import org.springframework.stereotype.Component;
@Component
public class SBean {
public String beanName="Sean";
}
<!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>