WedX - журнал о программировании и компьютерных науках

Исключение конфигурации Spring MVC без XML: для настройки обработки сервлета по умолчанию требуется ServletContext.

Я новичок в среде Spring, пробую конфигурацию Spring MVC без xml (без 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;
}
}

Мой ЛогинКонтроллер:

@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)`

Добавлен класс для инициализации моего db сразу после обновления моего контекста, например:

@Component
public class DbInitialiserOnStartUp implements ApplicationListener<ContextRefreshedEvent> {

@Autowired
private AccountService accountService;

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

  • Какая версия Джетти? 02.05.2015
  • Опубликуйте детали сообщения об ошибке (stacktrace, если он у вас есть) 02.05.2015
  • Jetty 9.2.4v20141103, обновлена ​​трассировка стека: 02.05.2015

Ответы:


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 в качестве контекста... поэтому измените его соответствующим образом. Пример проекта здесь на случай, если вы захотите взглянуть; и это очень, очень хорошая статья на эту тему от ребят из 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, когда вызываете этот метод. Я не мог исправить проблемы с базой данных, так как у меня нет вашей схемы... лучше использовать базу данных в памяти при выполнении Proof of Concepts. Попробуйте улучшить/исправить этот фрагмент кода, и все будет хорошо.

01.05.2015
  • Спасибо за быстрый ответ, Машенька! Я пробовал, но та же ошибка. Также попробовал это с источником из вашей ссылки (у меня нет 1.8, поэтому для сборки пришлось ориентироваться на 1.7), и это тоже не работает. Если хочешь, я могу заархивировать свой проект для тебя? 02.05.2015
  • ОК @KunalPatel ...поместите это на GitHub или что-то подобное ... давайте посмотрим и посмотрим, что не так 02.05.2015
  • @KunalPatel Я обновил ответ ... это должно быть просто исправить 02.05.2015
  • @machina - Да, это частично решает проблему, так как ошибка не возникает. Но этот статический метод InitialiseDummyData() инициализирует некоторые данные для меня в базе данных, поскольку я пытаюсь проверить материал входа в систему, и для этого он обращается к ApplicationContext. Не могли бы вы подсказать, как правильно получить доступ к context, чтобы он не рвало, как сейчас? Спасибо за помощь, очень признателен. :-) 02.05.2015
  • @KunalPatel переместите метод InitialiseDummyData в компонент Spring, пометьте его, например, как @Component, и внедрите службу или DAO, необходимые для доступа и хранения/извлечения данных. 03.05.2015
  • Спасибо большое за ваше направление! Наконец-то я сделал это, используя класс слушателя ContextRefreshedEvent. Это правильный способ сделать это? Попробовал то, что вы сказали, используя Bean, но не совсем понял. Однако было бы интересно узнать, как это было бы сделано так, как сказано выше. Я отмечаю ваше обновление как ответ, жаль, что я не могу сделать больше. :-) 05.05.2015
  • Новые материалы

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..

    ИИ в аэрокосмической отрасли
    Каждый полет – это шаг вперед к великой мечте. Чтобы это происходило в их собственном темпе, необходима команда астронавтов для погони за космосом и команда технического обслуживания..


    Для любых предложений по сайту: [email protected]