Spring MVC无XML配置异常:需要ServletContext来配置默认的servlet处理

时间:2015-05-01 19:28:32

标签: java hibernate spring-mvc jetty

我是Spring框架的新手,尝试使用Spring MVC xml-less(没有web.xml或mvc-dispatcher-servlet.xml)配置,因为这是项目所需要的。

当我尝试运行它时出现以下错误(使用Jetty Local,再次是项目要求)

以下是我替换web.xml的配置:

(还试图在没有运气的情况下延长AbstractAnnotationConfigDispatcherServletInitializer

public class WebConfig implements WebApplicationInitializer {
@Override
public void onStartup( ServletContext servletContext ) throws ServletException {
    WebApplicationContext rootContext = getContext(servletContext);
    servletContext.addListener(new ContextLoaderListener(rootContext));

    ServletRegistration.Dynamic dispatcher = servletContext.addServlet("mvc", new DispatcherServlet(rootContext));
    dispatcher.setLoadOnStartup(1);
    dispatcher.addMapping("/");
}

private AnnotationConfigWebApplicationContext getContext(ServletContext ctx) {
    AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
    //Tried various combination of un/commenting following options.
    context.register( MvcServletConfig.class );
    //context.setConfigLocation("com.xyz.myapp.configuration");
    context.setServletContext( ctx );
    //context.refresh();
    //context.scan( "com.xyz.someapp.*" );
    return context;
}
}

这是我的MVC / Servlet配置替换mvc-dispatcher-servlet.xml:

@EnableWebMvc
@Configuration
@ComponentScan(basePackages = {"com.xyz.myapp"})
public class MvcServletConfig extends WebMvcConfigurerAdapter {

public MvcServletConfig() { super(); }

@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
    configurer.enable();
}

@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/").setViewName("forward:/login.jsp");
}

@Bean
public ViewResolver viewResolver() {
    InternalResourceViewResolver bean = new InternalResourceViewResolver();

    bean.setViewClass(JstlView.class);
    bean.setPrefix("/WEB-INF/pages/");
    bean.setSuffix(".jsp");

    return bean;
}
}

这是我的AppConfig:

@Configuration
@ComponentScan(basePackages = {"com.xyz.myapp.*"})
@Import( { HibernateConfig.class } )
public class AppConfig {}

这是我的HibernateConfig,其中我有一个访问上下文的静态方法:

@Configuration
@EnableTransactionManagement
@ComponentScan( {"com.obsm.visensia.configuration"} )
@PropertySources( value ={@PropertySource("classpath:/application.properties")} )
public class HibernateConfig {
@Transactional
public static void InitialiseDummyData()
{
    AbstractApplicationContext context = new AnnotationConfigApplicationContext( AppConfig.class);
    AccountService accountService = (AccountService) context.getBean("accountService");
    if ( accountService != null )
    {
        Role admin = new AdminRole();
        Role serverAdmin = new ServerAdminRole();
        Role normal = new NormalRole();

        User adminUser = new User();
        adminUser.setFirstName( "Kunal" );
        adminUser.setLastName( "Patel" );
        adminUser.setSex( Sex.Male );
        adminUser.setUsername( "kp" );
        adminUser.setPassword( "kp" );
        adminUser.addRole( admin );


        accountService.addUser( adminUser );

        User serverAdminUser = new User();
        serverAdminUser.setFirstName( "Server" );
        serverAdminUser.setLastName( "Admin" );
        serverAdminUser.setSex( Sex.Male );
        serverAdminUser.setUsername( "serveradmin" );
        serverAdminUser.setPassword( "serveradmin" );
        serverAdminUser.addRole( serverAdmin );

        accountService.addUser( serverAdminUser );

        User normalUser = new User();
        normalUser.setFirstName( "Normal" );
        normalUser.setLastName( "User" );
        normalUser.setSex( Sex.Undefined );
        normalUser.setUsername( "normal" );
        normalUser.setPassword( "normal" );
        normalUser.addRole( normal );

        accountService.addUser( normalUser );

        context.close();
    }
}
@Autowired
private Environment environment;

@Bean
public LocalSessionFactoryBean sessionFactory()
{
    LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
    sessionFactory.setDataSource( dataSource() );
    sessionFactory.setPackagesToScan( new String[] { "com.obsm.visensia.model" } );
    sessionFactory.setHibernateProperties( hibernateProperties() );
    return sessionFactory;
}

@Bean
public DataSource dataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName( environment.getRequiredProperty( "jdbc.driverClassName" ) );
    dataSource.setUrl( environment.getRequiredProperty( "jdbc.url" ) );
    dataSource.setUsername( environment.getRequiredProperty( "jdbc.username" ) );
    dataSource.setPassword( environment.getRequiredProperty( "jdbc.password" ) );
    return dataSource;
}

private Properties hibernateProperties() {
    Properties properties = new Properties();
    properties.put( "hibernate.dialect", environment.getRequiredProperty( "hibernate.dialect" ) );
    properties.put( "hibernate.show_sql", environment.getRequiredProperty( "hibernate.show_sql" ) );
    properties.put( "hibernate.hbm2ddl.auto", environment.getRequiredProperty( "hibernate.hbm2ddl.auto" ) );
    properties.put( "hibernate.format_sql", environment.getRequiredProperty( "hibernate.format_sql" ) );
    return properties;
}

@Bean
@Autowired
public HibernateTransactionManager transactionManager ( SessionFactory sessFact )
{
    HibernateTransactionManager transactionManager = new HibernateTransactionManager();
    transactionManager.setSessionFactory( sessFact );
    return transactionManager;
}
}

我的LoginController:

@Controller
@RequestMapping("/")
public class LoginController {

    @Autowired
    private AccountService accountService;

    @RequestMapping(method = RequestMethod.GET)
    public String login(ModelMap model) {
        HibernateConfig.InitialiseDummyData();
        model.addAttribute( "user", new User() );
        return "login";
    }

    @RequestMapping(method = RequestMethod.POST)
    public String verifyUser(@ModelAttribute("user") User user, Model model)
    {
        if ( accountService.verifyUser( user.getUsername(), user.getPassword() ) ) {
            User usr = accountService.findUserByUsername( user.getUsername() );
            model.addAttribute( "message", "Welcome, " + usr.getFirstName() );
            return "hello";
        }
        else
            return "login";
    }
}

我的HelloController:

@Controller
@RequestMapping("/")//Doesn't work even if I change it to '/hello'
public class HelloController {
    @RequestMapping(method = RequestMethod.GET)
    public String printWelcome(ModelMap model) {
        model.addAttribute("message", "Hello world!");
        return "hello";
    }
}

请帮忙,我已经被困在这里3天了:'(

更新

Jetty 9.2.4v20141103,这是堆栈跟踪:

Jetty 9.2.4v20141103 and following is the stacktrace:
`java.lang.IllegalArgumentException: A ServletContext is required to configure default servlet handling
    at org.springframework.util.Assert.notNull(Assert.java:112)
    at org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer.<init>(DefaultServletHandlerConfigurer.java:54)
    at org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.defaultServletHandlerMapping(WebMvcConfigurationSupport.java:416)
    at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerBySpringCGLIB$$b833a897.CGLIB$defaultServletHandlerMapping$30(<generated>)
    at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerBySpringCGLIB$$b833a897$$FastClassBySpringCGLIB$$56ff08f3.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:312)
    at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerBySpringCGLIB$$b833a897.defaultServletHandlerMapping(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:166)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:590)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1113)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1008)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:505)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:725)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
    at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:84)
    at com.obsm.visensia.configuration.HibernateConfig.InitialiseDummyData(HibernateConfig.java:32)
    at com.obsm.visensia.controller.LoginController.login(LoginController.java:26)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:781)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:721)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:800)
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:587)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577)
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1125)
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1059)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
    at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:215)
    at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:110)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
    at org.eclipse.jetty.server.Server.handle(Server.java:497)
    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:310)
    at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:248)
    at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:540)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:620)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:540)
    at java.lang.Thread.run(Thread.java:722)`

在我的上下文刷新后立即添加了一个初始化我的数据库的类,如下所示:

@Component
public class DbInitialiserOnStartUp implements ApplicationListener<ContextRefreshedEvent> {

@Autowired
private AccountService accountService;

@Transactional
@Override
public void onApplicationEvent( ContextRefreshedEvent contextRefreshedEvent ) {
    if ( accountService != null )
    {
        //inserts etc...
    }
}
}

2 个答案:

答案 0 :(得分:1)

我测试了它并且工作正常...试试这个:

// You named it WebConfig
public class WebAppInitializer implements WebApplicationInitializer { // web.xml replacement
  @Override
  public void onStartup(ServletContext servletContext) throws ServletException {
    AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();

    // Here you need to change "io.shido.config" to your config location
    applicationContext.setConfigLocation("io.shido.config");

    ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher",
        new DispatcherServlet(applicationContext)); // Register and map the dispatcher servlet

    //servletContext.setInitParameter("spring.profiles.default", "development");
    servletContext.addListener(new ContextLoaderListener(applicationContext));
    //applicationContext.register(AppConfig.class); // Manage the lifecycle of the root application context
    dispatcher.setLoadOnStartup(1);
    dispatcher.addMapping("/web/*"); // ...and here also change the context
  }
}

注意我也使用/web作为我的上下文......所以相应地更改它。有一个示例项目here以防您想要查看;而且this是ZeroTurnaround人员关于这个主题的非常非常好的文章。

此外,我在Maven POM文件中:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-war-plugin</artifactId>
  <version>2.6</version>
  <configuration>
    <!--<packagingExcludes>WEB-INF/web.xml</packagingExcludes>-->
    <failOnMissingWebXml>false</failOnMissingWebXml>
  </configuration>
</plugin>

<强>更新

你的Spring配置工作正常(但你可以真正改进它);当您致电LoginController时,问题出在HibernateConfig.InitialiseDummyData();上。评论该行和一切都会没问题。

当您调用该方法时,您将启动另一个Spring上下文。我无法解决数据库的问题,因为我没有你的架构......在执行概念证明时更好地使用内存数据库。尝试改进/修复这段代码,你应该好好去。

答案 1 :(得分:0)

    reader.onload = function(event) {
        // This stores the image to scope
        fabric.Image.fromURL(event.target.result, function(img) {
          canvas.add(img);
        });
        scope.$apply();
    };