Я новичок в среде 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...
}
}
}
InitialiseDummyData()инициализирует некоторые данные для меня в базе данных, поскольку я пытаюсь проверить материал входа в систему, и для этого он обращается кApplicationContext. Не могли бы вы подсказать, как правильно получить доступ кcontext, чтобы он не рвало, как сейчас? Спасибо за помощь, очень признателен. :-) 02.05.2015InitialiseDummyDataв компонент Spring, пометьте его, например, как@Component, и внедрите службу или DAO, необходимые для доступа и хранения/извлечения данных. 03.05.2015ContextRefreshedEvent. Это правильный способ сделать это? Попробовал то, что вы сказали, используя Bean, но не совсем понял. Однако было бы интересно узнать, как это было бы сделано так, как сказано выше. Я отмечаю ваше обновление как ответ, жаль, что я не могу сделать больше. :-) 05.05.2015