How to exclude some endpoints from server.servlet.path configuration? - spring-boot

I have Spring Boot application with a single index.html page.
I need to have server.servlet.path=/api setting.
In order to get index.html I have to go localhost:8080/api/ becase of my setting described above.
I want to be able to get index.html by localhost:8080/ and any else endpoints by localhost:8080/api/**.
How can I do it?
Thanks

Once you configured server.servlet.path=/api, DispatcherServlet is going to handle only request matching URL Patterns /api/**.
One way to achieve your requirement is to use a plain Servlet.
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StreamUtils;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.Charset;
#WebServlet(urlPatterns = {"/"})
public class RootServlet extends HttpServlet {
#Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
ClassPathResource resource = new ClassPathResource("static/index.html");
String content = StreamUtils.copyToString(resource.getInputStream(), Charset.defaultCharset() );
resp.getWriter().write(content);
}
}
Now you can register the Servlet using #ServletComponentScan annotation. Assuming you put RootServlet in com.myapp.servlets package:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
#SpringBootApplication
#ServletComponentScan(basePackages = "com.myapp.servlets")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
For more info see https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-add-a-servlet-filter-or-listener

Related

/hello Not Found

I create a project using Spring Initializer.
I added a mapping for /hello:
package com.propfinancing.www;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
#RestController
#SpringBootApplication
public class PfWebApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(PfWebApplication.class, args);
}
#GetMapping("/hello")
public String hello(#RequestParam(value = "name", defaultValue = "World") String name) {
return String.format("Hello %s!", name);
}
}
I created a war file and uploaded that to my tomcat server.
When I go to the URL http://dev.propfinancing.com/www/hello
I get a 404 - Not Found page.
Any idea what went wrong?
I think I figured it out.
Apparently, Spring 5 does not work with tomcat 10:
https://github.com/spring-projects/spring-boot/issues/22414
I am going to install Tomcat 9 on my server and see if that works.

Spring not picking up RestController endpoint

I have my spring project setup as shown below, but I am getting a 404 on the /custom endpoint. All answers I've found similar to this problem highlighted that the controller layer needs to be in a package below the project layer however I have it set out like this so I'm unsure why Spring isn't recognising the endpoint.
package com.myproject.controller;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("custom")
public class CustomPathController {
#GetMapping
public ResponseEntity<Void> test() {
return new ResponseEntity<>(HttpStatus.OK);
}
}
package com.myproject;
import com.ryantenney.metrics.spring.config.annotation.EnableMetrics;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#EnableMetrics
#EnableJpaRepositories
#SpringBootApplication
public class MyProject {
public static void main(String[] args) {
SpringApplication.run(MyProject.class, args);
}
}
There must have been a port clash as a PC restart has fixed the issue

Error creating bean with name 'primeLocateCometDService' when spring boot 1.5.19 with CometD 3.0.9 and tomcat 8.5.37

I just upgrade a tomcat project to spring boot project with CometD. Here are two services classes named: PrimeLocateCometDService & AbstractRealtimeCometDPublishService
When I start the project, error occurred.
public AbstractRealtimeCometDPublishService(BayeuxServer bayeuxServer, String sessionName) {
this.bayeuxServer = bayeuxServer;
this.localSession = bayeuxServer.newLocalSession(sessionName);
this.localSession.handshake();
}
Handshake will throw nullpointerexception.
package com.citi.pf.realtime;
import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;
import org.cometd.annotation.AnnotationCometDServlet;
import org.cometd.bayeux.server.BayeuxServer;
import org.cometd.server.BayeuxServerImpl;
import org.cometd.server.transport.JSONPTransport;
import org.cometd.server.transport.JSONTransport;
import org.cometd.websocket.server.WebSocketTransport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration;
import org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.ImportResource;
import com.citi.pf.portal.lib.util.ENVUtils;
#SpringBootApplication
#ImportResource({
//webapp
"classpath:META-INF/realtime/pf-realtime-webapp-context.xml",
"classpath:WEB-INF/realtime/comet-config.xml",
"classpath:WEB-INF/realtime/webmvc-config.xml",
"classpath:pfGFIConfigSrvc.xml",
//core
"classpath:META-INF/realtime/pf-realtime-core-context.xml",
//security
"classpath:META-INF/realtime/pf-realtime-security-context.xml",
//prime-locate
"classpath:META-INF/realtime/prime-locate-integration-context.xml",
"classpath:META-INF/realtime/prime-locate-jndi-context.xml",
//prime-locate-cometd
"classpath:META-INF/realtime/prime-locate-cometd-integration-context.xml",
"classpath:META-INF/realtime/prime-locate-cometd-jndi-context.xml",
//prime-notification
"classpath:META-INF/realtime/prime-notification-cometd-integration-context.xml",
"classpath:META-INF/realtime/prime-notification-cometd-jndi-context.xml",
//prime-query
"classpath:META-INF/realtime/prime-query-integration-context.xml",
"classpath:META-INF/realtime/prime-query-jndi-context.xml",
//prime-wire
"classpath:META-INF/realtime/prime-wire-integration-context.xml",
"classpath:META-INF/realtime/prime-wire-jndi-context.xml"
})
#ServletComponentScan
#ComponentScan
#EnableAutoConfiguration(exclude= {
DataSourceAutoConfiguration.class,
JmsAutoConfiguration.class,
MongoAutoConfiguration.class,
MongoDataAutoConfiguration.class,
MultipartAutoConfiguration.class,
SecurityAutoConfiguration.class,
SecurityAutoConfiguration.class,
FallbackWebSecurityAutoConfiguration.class,
OAuth2AutoConfiguration.class})
public class PFRealtimeServicesApplication extends SpringBootServletInitializer implements ServletContextInitializer{
private static final Logger logger = LoggerFactory.getLogger(PFRealtimeServicesApplication.class);
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(PFRealtimeServicesApplication.class);
}
public static void main(String[] args) {
ENVUtils.registerEnvName("env");
ENVUtils.registerRunningSystem("REALTIME");
logger.info("Enter Realtime services application.");
SpringApplication.run(PFRealtimeServicesApplication.class,args);
}
#Override
public void onStartup(ServletContext servletContext) {
ServletRegistration.Dynamic cometdServlet = servletContext.addServlet("cometd", AnnotationCometDServlet.class);
cometdServlet.addMapping("/cometd/*");
cometdServlet.setAsyncSupported(true);
cometdServlet.setLoadOnStartup(1);
//cometdServlet.setInitParameter("PrimeLocateCometDService", PrimeLocateCometDService.class.getName());
//cometdServlet.setInitParameter("PrimeNotificationCometDService", PrimeNotificationCometDService.class.getName());
}
#Bean
protected ServletContextInitializer servletInitializer() {
return servletContext -> servletContext.setAttribute(BayeuxServer.ATTRIBUTE, bayeuxServer(servletContext));
}
#Bean
#DependsOn("servletInitializer")
protected BayeuxServer bayeuxServer(ServletContext servletContext) {
BayeuxServerImpl bean = new BayeuxServerImpl();
bean.setTransports(new WebSocketTransport(bean), new JSONTransport(bean), new JSONPTransport(bean));
servletContext.setAttribute(BayeuxServer.ATTRIBUTE, bean);
bean.setOption(ServletContext.class.getName(), servletContext);
bean.setOption("ws.cometdURLMapping", "/cometd/*");
return bean;
}
}
Hope the PrimeLocateCometDService Bean can be created successfully.
My project use Spring Boot 1.5.19 with CometD 3.0.9 and Tomcat 8.5.37.
(1) #ImportResource import all the xml files to the Application.java
(2) Remove (in xml file)
<bean id="websocketTransport" class="org.cometd.websocket.server.WebSocketTransport">
<constructor-arg ref="bayeux" />
</bean>
(3)Application extends SpringBootServletInitializer implements ServletContextInitializer
#Override
public void onStartup(ServletContext servletContext) {
ServletRegistration.Dynamic cometdServlet = servletContext.addServlet("cometd",
AnnotationCometDServlet.class);
cometdServlet.addMapping("/cometd/*");
cometdServlet.setAsyncSupported(true);
cometdServlet.setLoadOnStartup(1);
}
(4)pom.xml
Remove:
<dependency>
<groupId>org.cometd.java</groupId>
<artifactId>cometd-java-websocket-javax-server</artifactId>
<version>3.0.9</version>
</dependency>
Add:
<dependency>
<groupId>org.cometd.java</groupId>
<artifactId>cometd-java-websocket-javax-server</artifactId>
<version>3.0.9</version>
</dependency>
These are all I think will impact CometD with Spring Boot. Hope these will help someone.

Unable to fetch random port when server.port is 0

I need to fetch port number on which undertow was Started by my Sprint boot app. I have defined server.port=0 in application.properties. I cannot use fix port numbers like 8080.
package com.aggregate.application;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Properties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
#Configuration
#ComponentScan(basePackages = {"com.aggregate"})
#EnableAutoConfiguration
public class GServiceApplication extends SpringBootServletInitializer
implements ApplicationListener<ApplicationReadyEvent> {
#Autowired
private ApplicationContext applicationContext;
#Override
public void onApplicationEvent(ApplicationReadyEvent event) {
try {
String ip = InetAddress.getLocalHost().getHostAddress();
String port = applicationContext.getBean(Environment.class).getProperty("server.port");
System.out.printf("ip:port=" +ip+ ":"+port);
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws UnknownHostException
{
SpringApplication application = new SpringApplication(GServiceApplication.class);
Properties properties = new Properties();
properties.put("server.port", 0);
properties.put("server.address", InetAddress.getLocalHost().getHostAddress());
application.setDefaultProperties(properties);
application.run(args);
}
}
Undertow started:- o.s.b.w.e.u.UndertowServletWebServer : Undertow started on port(s) 55646 (http) with context path '' as printed in console
Expected result:- ip:port=xx.xx.x.1x1:55646
Actual result:- ip:port=xx.xx.x.1x1:0
Passing in the port number 0 is a trick that the Java core ServerSocket class can do. Undertow isn't aware of this; it just assumes that the port is always fixed. So there's no official API to read the port number that is actually used; but if you find the Undertow object, you can do:
// assuming you only have one:
ListenerInfo listenerInfo = undertow.getListenerInfo().iterator().next();
InetSocketAddress socketAddress = (InetSocketAddress) listenerInfo.getAddress();
URI uri = URI.create(listenerInfo.getProtcol() + "://" + socketAddress.getHostString() + ":" + socketAddress.getPort());
HTH

Debug Spring Boot application in VSC

I have one simple Spring boot app that runs normally in console.
But I can't debug it in VSC.
The code is:
package com.sample.service.sample;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
/**
* sample service
*
*/
#EnableDiscoveryClient
#SpringBootApplication
#EnableBinding(Source.class)
#EnableMongoRepositories(basePackages = "com.sample.service.sample.repositories")
public class ServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceApplication.class, args);
}
}
The exception is:
nested exception is java.lang.NoClassDefFoundError: org/objenesis/strategy/InstantiatorStrategy
What did I miss in VSC setting for Spring Boot?

Resources