Subdomain routing in Spring Boot - java

Basically, what I'm trying to achieve is something like this
#GetMapping("domain.xyz")
public String getHomepage() {
[...]
return "homepage/main.html";
}
#GetMapping("something.domain.xyz")
public String getSubdomainHomepage() {
[...]
return "homepage/subdomain.html";
}
Both domain.xyz and something.domain.xyz are pointed to the same server and the Spring app then considers the subdomain when routing so I can have different content on the top level domain and different content on the subdomain(s)...
Is this possible to achieve with Spring Boot?

(Note: This is not 100% tested, but will probably work)
I'm assuming you are having an Nginx or Apache in front of your Spring Boot application.
With Nginx for example, you would use the proxy_pass directive and then set the "Host" header to your "something.domain.xyz" or "domain.xyz" when forwarding to your Spring Boot app.
You could therefore enhance your GetMappings to filter for the Host header values.
#GetMapping(value ="/", headers="Host=domain.xyz")
public String getHomepage() {
[...]
return "homepage/main.html";
}
#GetMapping(value ="/", headers="Host=something.domain.xyz")
public String getSubdomainHomepage() {
[...]
return "homepage/subdomain.html";
}

Related

How to create a Spring Boot Actuator endpoint that delegates all calls to a different port?

I'm using Spring Boot 2.7.5 and I want to create an actuator endpoint, that acts as a proxy, and forwards all requests to a different server, running on the same JVM instance, but on a different port (say 8082). Here's the gist of it:
#Component
#RestControllerEndpoint(id = "myEndpoint", enableByDefault = true)
public class MyEndpoint {
#RequestMapping("**")
public Object myEndpoint() {
// TODO Forward everything to port 8082
return ...
}
}
What do I need to do in order to achieve this?
Update 1:
The port (8082) is not available from the internet so I can't do a simple redirect.
Update 2:
I don't want to forward the request to a Spring Controller or Spring Bean. Port 8082 is a separate server started in the same process.
What if instead of a redirect (as suggested in other replies) your actuator would perform a call to localhost:8082 and return it's return it's response? You could also return a ResponseEntity instead of just an Object to cascade the HTTP codes of the performed request.
#Component
#RestControllerEndpoint(id = "myEndpoint", enableByDefault = true)
public class MyEndpoint {
private static final String TARGET_HOST = "localhost";
private static final int TARGET_PORT = 8082;
#RequestMapping("**")
public Object myEndpoint(HttpServletRequest originalRequest) {
Uri targetUri = UriComponentsBuilder.fromHttpRequest(originalRequest)
.host(TARGET_HOST)
.port(TARGET_PORT)
.build();
Object responseBody = /* code to perfom the call using your preferred HTTP client*/;
return responseBody;
}
}
Spring Boot Actuator endpoint that delegates all calls to a different port.
For different port use this in your application.properties file
management.server.port=8081
management.endpoints.web.exposure.include=*
This will expose all actuator endpoints on port 8081.
The official document describes :
Base path for Web endpoints. Relative to the servlet context path (server.servlet.context-path) or WebFlux base path (spring.webflux.base-path) when the management server is sharing the main server port. Relative to the management server base path (management.server.base-path) when a separate management server port (management.server.port) is configured.
You can configure the following
management:
server:
port: 8081
servlet:
context-path:
endpoints:
web:
base-path: /
path-mapping:
prometheus: metrics
exposure:
include: [ "prometheus" ]
Tip : This configuration must be different with the server.ports must be different.
For more details, please check appendix.application-properties.actuator

Spring Cloud Gateway as a gateway as well as web application

I have a spring cloud gateway application and what I want is like if there are two routes then on one route it should redirect to some external application but for other route it should forward the request to same app with a particular url.
-id: my_local_route
predicates:
- Path="/services/local"
uri: "/mylocal/services/local" //can we do something like that
Please note I want to create my rest services in same app as in spring cloud gateway. I understand it is not correct approach but for my knowledge I wanted to know whether it is possible or not.
If you have some rest APIs within your spring-cloud-gateway project, you don't need to explicitly put the routes for it.
So suppose you have following rest api in gateway project
#RestController
#RequestMapping("test")
class Controller{
#GetMapping("hello")
public String hello(){
return "hello";
}
}
and for external-url, you want to send some traffic to let's say https://httpbin.org. So in gateway application.yml could look something like this:
spring:
cloud:
gateway:
routes:
- id: httpbin-route
uri: https://httpbin.org
predicates:
- Path=/status/**
With this request like
http://localhost:8080/test/hello will be resolved by your rest controller
http://localhost:8080/status/200 will be redirected to httpbin site
If for some reason you have the same root path for both cases, the controller will have precedence.
If you have the same endpoint in gateway predicates and controller, by default controller will take precedence over predicates, if you want predicates to take precedence over controller, just create a BeanPostProcessor to adjust the order:
#Component
public class RequestMappingHandlerMappingBeanPostProcessor implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof RequestMappingHandlerMapping) {
((RequestMappingHandlerMapping) bean).setOrder(2); // After RoutePredicateHandlerMapping
}
return bean;
}
}

How to configure hot reload in Jhipster?

I am using Jhipster(Angular + Springboot) Application for my existing project.
I managed to create a controller(app.resource) manually apart from the ones already generated by jhiptser(using .jh file) for achieving a file download functionality.
So, when we start the server we usually initiate two servers i.e gradlew and npm start. The second runs on port 9000 which eventually supports hot reload functionality.(front-end development)
So the problem is, I am able to access those endpoints from the server running on standard 8000 port. However, from the port which is a proxy(9000), the method is returning 404.
I tried to clean build the application several times.
NOTE: The #RequestMapping value on the new controller is different then those present already.
Does this have to do something with spring security?
Thanks in advance.
Here is the previous controller:
#RestController
#RequestMapping("/api")
public class FGAppDiagramResource {
#GetMapping(value = "/fg-app-diagram-downloadFile")
public void getImage(String fileName,String folderName, HttpServletResponse
response){
// Some Code
}
}
Here is my New controller:
#RestController
#RequestMapping("/fileDownload")
public class DownloadFileController {
private final Logger log =
LoggerFactory.getLogger(DownloadFileController.class);
public DownloadFileController() {
super();
}
#Autowired
private ApplicationProperties applicationProperties;
#GetMapping(value = "/fg-app-diagram-downloadFile/{fileName}/{folderName}")
public void getImage(#PathVariable String fileName,#PathVariable String folderName, HttpServletResponse response) {
// Some Code
}
}
Your new controller does not use /api so you must add your endpoint URL /fileDownload to proxy configuration of webpack dev server in webpack/webpack.dev.js
proxy: [{
context: [
/* jhipster-needle-add-entity-to-webpack - JHipster will add entity api paths here */
'/api',
'/fileDownload',
You may want to use /api/fileDownload to avoid changing proxy configuration and also because /api is useful for many other aspects like security and also using HTML5 URL routing strategy in Angular to get rid of # in client routes (see https://github.com/jhipster/generator-jhipster/pull/9098).
/api and /management are namespaces to avoid route conflicts, so it is usually wise to use them for your new endpoints.

Configure Spring Boot for SPA frontend

I have application where whole frontend part is laying in resource. I would like to separate things apart. And have separate server for UI, provided by gulp, for example.
So that I assume that my server should return index.html for all requests that are rendered by client side.
Eg: I have 'user/:id' rout that is managing by angular routing and doesn't need server for anything. How can I configure so that server will not reload or redirect me to anywhere?
My security config is following(don't know if it responsible for such things):
public class Application extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**").authorizeRequests().antMatchers("/", "/login**", "/webjars/**", "/app/**", "/app.js")
.permitAll().anyRequest().authenticated().and().exceptionHandling()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/")).and().logout()
.logoutSuccessUrl("/").permitAll().and().csrf()
.csrfTokenRepository(csrfTokenRepository()).and()
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class)
.addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);
}
For routing, according to this guide at Using "Natural" Routes (specifically here), you have to add a controller that does the following:
#Controller
public class RouteController {
#RequestMapping(value = "/{path:[^\\.]*}")
public String redirect() {
return "forward:/";
}
}
Then using Spring Boot, the index.html loads at /, and resources can be loaded; routes are handled by Angular.
EpicPandaForce has a great answer, and I wanted to expand on it. The following endpoint will allow matching on nested routes as well. If you wanted to have an admin section, you can configure it to return a different index.html.
#Controller
class PageController {
#GetMapping("/**/{path:[^\\.]*}")
fun forward(request: HttpServletRequest): String? {
if(request.requestURI.startsWith("/admin")) {
return "forward:/admin/index.html"
}
return "forward:/index.html"
}
}
This RequestMapping (or #GetMapping) works by excluding any request that contains a period (i.e. "index.html").
If you are using Angular with Spring Data Rest, I think that the most straightforward way to do it is using angular hash location strategy.
Just putting this in the providers array in your app module:
{ provide: LocationStrategy, useClass: HashLocationStrategy }
and, obviously, import it.

SpringMVC check server is UP or DOWN

How can I check if my server is UP or DOWN in SpringMVC or just simple in JAVA?
I want a simple function how receiving a URL as a parameter and return just one boolean variable TRUE or FALSE which represents a SERVER.
#RestController
public class HealthCheckController {
#RequestMapping("/healthcheck")
public Greeting greeting() {
return "up";
}
}
When you have to check if the server is up just send get request to /healthcheck. If it returns "up", you're OK.
If you use Spring Boot, you can take a look at actuator. It allows this functionality out of the box plus some other stuff like datasource checking and so on

Categories

Resources