I'am trying to create a simple controller with Spring Boot
Congifuration is:
#Configuration
#EnableWebMvc
#ComponentScan (basePackages = { "ru.spb.chat.controller" })
public class WebConfig implements WebMvcConfigurer {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver bean = new InternalResourceViewResolver();
bean.setPrefix("/WEB-INF/view/");
bean.setSuffix(".html");
return bean;
}
}
and for servlet:
public class MainWebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(final ServletContext sc) throws ServletException {
AnnotationConfigWebApplicationContext root =
new AnnotationConfigWebApplicationContext();
root.scan("ru.spb");
sc.addListener(new ContextLoaderListener(root));
ServletRegistration.Dynamic appServlet =
sc.addServlet("mvc", new DispatcherServlet(new GenericWebApplicationContext()));
appServlet.setLoadOnStartup(1);
appServlet.addMapping("/");
}
}
My controller.
#Controller
public class RootController {
#GetMapping ("/")
public String root() {
return "login";
}
}
But when I try to map on "/" it returns 404-ERROR
This is my project-structure:
Remove your WebConfig and remove your ServletInitializer and MainWebAppInitializer. (You can probably also remove the WebSocketConfig and use the auto-configuration from Spring Boot!).
Let your ChatApplication extend SpringBootServletInitializer and implement the configure method.
#SpringBootApplication
public class ChatApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(ChatApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(ChatApplication.class);
}
}
Then in your application.properties add
spring.mvc.view.prefix=/WEB-INF/view/
spring.mvc.view.suffix=.html
Now you are using the proper Spring Boot auto-configuration AND proper way of creating a WAR which is executable.
That being said, you generally don't want a WAR (only if you use JSP, which is discouraged with embedded containers).
Related
I am setting up a completely java based spring app with no xml config :
public class WebApp extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{WebMvcConfigurer.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
and
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { mypackages })
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/static-assets/");
}
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
where do I put this, which used to be in my web.xml ?
<session-config>
<!-- Disables URL-based sessions (no more 'jsessionid' in the URL using Tomcat) -->
<tracking-mode>COOKIE</tracking-mode>
</session-config>
you can do it as in below
public class WebConfig implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext)
throws ServletException {
HashSet<SessionTrackingMode> set = new HashSet<SessionTrackingMode>();
set.add(SessionTrackingMode.COOKIE);
servletContext.setSessionTrackingModes(set);
}
}
In a Spring Boot app, you can configure the mode using the application property server.session.tracking-modes.
In your application.properties add:
server.session.tracking-modes=cookie
Or if you use application.yml:
server:
session:
tracking-modes: 'cookie'
The Spring Boot autoconfiguration internally uses the same call to servletContext.setSessionTrackingModes which Bassem recommended in his answer.
UPDATE
In newer versions of Springboot, use
server.servlet.session.tracking-modes=cookie
Since 3.2.0.RC1 this is available in the AbstractSecurityWebApplicationInitializer like so:
public class WebSecutityInit extends AbstractSecurityWebApplicationInitializer {
#Override
protected Set<SessionTrackingMode> getSessionTrackingModes() {
return EnumSet.of(SessionTrackingMode.SSL);
}
}
As of spring boot 2.4.0 and later, the application property is renamed to server.servlet.session.tracking-modes.
So, in application.properties, need to add
server.servlet.session.tracking-modes="cookie"
If using application.yml, need to have
server:
servlet:
session:
tracking-modes: cookie
Another solution, that works for me, has been the code below inside the SecurityConfig class.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS) //No sessionId eppended
...
}
I have been trying out the Java Configuration feature of Spring Web Flow 2.4 by modifying an existing project from xml configuration to JavaConfig. The XML version works, but JavaConfig doesn't. Every time I try to start the flow with URL http://localhost:8080/sia_p219_ch08_spring_web_flow_order_pizza_customer_flow_complete/pizza , it returns 404. There are no exceptions. The console show no "no request mapping found for..." message. The webpage shows The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.
The project is hosted on github, the working XML version is here.
I think the problem is the request URL doesn't call the pizza flow (/WEB-INF/flows/pizza/pizza-flow.xml).
Here are some code snippets:
WebAppInitializer:
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RootConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class };
}
#Override
// map DispatcherServlet to /
protected String[] getServletMappings() {
return new String[] { "/" };
}
RootConfig:
#Configuration
#Import({WebFlowConfig.class})
public class RootConfig {}
WebFlowConfig:
#Configuration
#ComponentScan({"pizza"})
public class WebFlowConfig extends AbstractFlowConfiguration {
static{
System.out.println("WebFlowConfig loaded");
}
#Autowired
private WebConfig webMvcConfig;
#Bean
public FlowDefinitionRegistry flowRegistry() {
return
getFlowDefinitionRegistryBuilder(flowBuilderServices())
.setBasePath("/WEB-INF/flows")
.addFlowLocationPattern("/**/*-flow.xml")
.build();
}
#Bean
public FlowExecutor flowExecutor(){
return getFlowExecutorBuilder(flowRegistry()).build();
}
#Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder()
.setViewFactoryCreator(mvcViewFactoryCreator())
.setDevelopmentMode(true)
.build();
}
#Bean
public MvcViewFactoryCreator mvcViewFactoryCreator() {
MvcViewFactoryCreator factoryCreator = new MvcViewFactoryCreator();
factoryCreator.setViewResolvers(Collections.singletonList(this.webMvcConfig.viewResolver()));
factoryCreator.setUseSpringBeanBinding(true);
return factoryCreator;
}
}
WebConfig
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
static{
System.out.println("WebConfig loaded");
}
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/flows/");
resolver.setSuffix(".jsp");
return resolver;
}
// configure static content handling
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
The flow definition files and JSPs are fine and you can see them on github if you want.
Thanks a lot, any help is greatly appreciated.
What I've found so far that the configuration definitely lacks this part of configuration in WebFlowConfig (take a look at the documentation page for integration with Spring MVC for details):
#Bean
#Autowired
public FlowHandlerAdapter flowHandlerAdapter(FlowExecutor flowExecutor) {
FlowHandlerAdapter flowHandlerAdapter = new FlowHandlerAdapter();
flowHandlerAdapter.setFlowExecutor(flowExecutor);
return flowHandlerAdapter;
}
#Bean
#Autowired
public FlowHandlerMapping flowHandlerMapping(FlowDefinitionRegistry flowDefinitionRegistry) {
FlowHandlerMapping flowHandlerMapping = new FlowHandlerMapping();
flowHandlerMapping.setFlowRegistry(flowDefinitionRegistry);
flowHandlerMapping.setOrder(0);
return flowHandlerMapping;
}
Also remove mvcViewFactoryCreator definition and setViewFactoryCreator call from the flowBuilderServices bean definition as well. It works for me.
I've been googling for the last 2 days and still can't figure out why it wont expose the SOAP web service. It works when I run it locally using Tomcat and Spring Boot. In the jboss-deployment-structure, jpa, javaee-api and webservices has been excluded. Also, there are no exceptions in sysout or logs. Only the message specified further down (HTTP 405). Even checked through TRACE logs.
JBoss Version: 6.4.4 (or 6.4.0)
Spring Boot: 1.3.0
CXF: 3.0.4
Spring MVC: From Spring Boot parent
I get this message:
HTTP Status 405 - Request method 'POST' not supported.
When debugging, I placed a breakpoint in class: DispatcherServlet, which then in getHandlerAdapter returned HttpRequestHandlerAdapter. Further along, it calls the HttpRequestHandlerAdapter.handle which again calls handleRequest on a WebContentGenerator. This only supports GET or HEAD requests.
Any ideas?
Code:
#Configuration
public class DispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] {
ApplicationConfig.class
};
}
#Override
protected String[] getServletMappings() {
return new String[] {
"/*"
};
}
}
#Configuration
public class ApplicationServletInitializer extends SpringBootServletInitializer {
}
#Configuration
#EnableAutoConfiguration
#Import({
RepositoryConfig.class,
WebConfig.class,
WsProviderConfig.class
})
public class ApplicationConfig {
}
#Configuration
#EnableConfigurationProperties
public class WebConfig {
#Bean
public SelftestController selftestController() {
return new SelftestController();
}
}
#Configuration
public class WsProviderConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(WsProviderConfig.class);
#Autowired
private ApplicationContext context;
#Bean
ServletRegistrationBean messageDispatcherServlet() {
ServletRegistrationBean bean = new ServletRegistrationBean(new CXFServlet(), "/soap/*");
bean.setLoadOnStartup(1);
return bean;
}
#Bean(name = Bus.DEFAULT_BUS_ID)
Bus bus() {
SpringBus bus = new SpringBus();
bus.getFeatures().addAll(Arrays.asList(new WSAddressingFeature(), new LoggingFeature()));
return bus;
}
#Bean
PlayerServiceV1 defaultPlayerService() {
return new DefaultPlayerService();
}
#PostConstruct
void publishWebServices() {
LOGGER.info("Publishing WebServices");
DefaultPlayerService defaultPlayerService = context.getBean(DefaultPlayerService.class);
Bus bus = context.getBean(Bus.DEFAULT_BUS_ID, Bus.class);
EndpointImpl endpoint = new EndpointImpl(bus, defaultPlayerService);
endpoint.publish("/test/players");
}
}
Hello I'm trying to rewrite my old code to use Spring Boot.
I have one listener public class ExecutorListener implements ServletContextListener.
How can I register this listener for Spring Boot?
I've tried:
#SpringBootApplication
#ComponentScan
public class Application extends SpringBootServletInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
servletContext.addListener(new ExecutorListener());
}
}
But the contextInitialized method is not called.
You can try couple of things:
Register ExecutorListener as a #Bean explicitly:
#Bean
public ExecutorListener executorListener() {
return new ExecutorListener();
}
or
You can try it with explicitly creating ServletRegistrationBean:
#Bean
public DispatcherServlet dispatcherServlet() {
DispatcherServlet servlet=new DispatcherServlet();
servlet.getServletContext().addListener(new ExecutorListener());
return servlet;
}
#Bean
public ServletRegistrationBean dispatcherServletRegistration() {
ServletRegistrationBean registrationBean = new ServletRegistrationBean(dispatcherServlet(), "/rest/v1/*");
registrationBean
.setName(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);
return registrationBean;
}
If using an embedded container, there will soon be a third option if using SpringBoot 1.3.0+
Annotate your ServletContextListener implementation with #WebListener from servlet spec 3, then annotate one of your Spring #Configuration classes with the new #ServletComponentScan (and optionally tell it which packages to scan for filters, servlets and listeners).
Only available in 1.3.0+ at the moment though: http://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/web/servlet/ServletComponentScan.html
Docs:
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-embedded-container-servlets-filters-listeners
In case you prefer auto discovery using annotations only, make your ExecutorListener implement the ServletContextInitializer and e.g. annotate it with javax.annotation.ManagedBean. From there, just implement the onStartup method:
#ManagedBean
public final class ExecutorListener implements ServletContextInitializer {
...
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
...
}
}
Another way is to create a class implements ServletContextListener and add #WebListner to the top which will tell Springboot this is a ServletContextListener , then add #ServletComponentScan(basePackages = "xxx") in SpringBootApplication to actually register it into the container
#WebListener
public class MyListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
...
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
...
}
}
I'm having some problems adding spring security. It shows an error that says:No bean named 'springSecurityFilterChain' is defined
public class WebInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(App.class);
servletContext.addListener(new ContextLoaderListener(rootContext));
// security filter
servletContext.addFilter(
"springSecurityFilterChain",
new DelegatingFilterProxy("springSecurityFilterChain"))
.addMappingForUrlPatterns(null, false, "/*");
// Manage the lifecycle of the root application context
AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext();
webContext.register(WebConfig.class);
webContext.setServletContext(servletContext);
ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(webContext));
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
}
}
In the moment I add the security filter, it shows this error. I've been like crazy trying to resolve this with no success.
This is my WebSecurityConfigurerAdapter
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("tom").password("123456").roles("USER");
auth.inMemoryAuthentication().withUser("bill").password("123456").roles("ADMIN");
auth.inMemoryAuthentication().withUser("james").password("123456").roles("SUPERADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/signin").access("hasRole('ROLE_ADMIN')")
.and().formLogin();
}
}
WebConfig
#Configuration
#EnableWebMvc
#ComponentScan(value = {"com.hp.visitor.controller"})
#Import({ WebSecurityConfig.class })
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
UrlBasedViewResolver setupViewResolver(){
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setPrefix("/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("/static/");
}
}
I've been trying a lot, but it always shows an 503 error.
How can I fix it?
Try registering the security filter this way
FilterRegistration.Dynamic securityFilter = servletContext.addFilter("springSecurityFilterChain", DelegatingFilterProxy.class);
securityFilter.addMappingForUrlPatterns(null, false, "/*");
And add the #Import({WebSecurityConfig.class}) in the configuration class you declare as your rootContext in WebInitializer in your case is in App.java
You can simply create a class that extends from AbstractSecurityWebApplicationInitializer and it will automatically create/initialize the security filter chain for you. No code needed:
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {}
Also, if you're only just creating a single dispatcher servlet, you could consider simply extending your WebAppIntializer class from AbstractAnnotationConfigDispatcherServletInitializer:
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{WebSecurityConfig.class, App.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{
"/"
};
}
You do not actually need to add the security filter manually. You can extend AbstractSecurityWebApplicationInitializer, which will insert the filter. You do not need to add any additional code than what is in the example below:
package com.example.spring.security.config;
import org.springframework.core.annotation.Order;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
#Order(1)
public class SecurityWebAppInitializer extends AbstractSecurityWebApplicationInitializer {
}
I typically will have my Security App Initializer with #Order(1) and the standard Web App Initializer with #Order(2).
You also need to make sure that your component scan is setup correctly. I have had it pointing at a wrong package and I have gotten this error before.