Spring Boot controller to catch all unconfigured routes - spring

I am trying to catch all unconfigured routes once all other controllers have been checked and no route matches.
My controller is as below:
#Controller
public class ForwardController {
#RequestMapping(value = "/**/{[path:[^\\.]*}")
public String redirect() {
return "forward:/";
}
}
But this does not match : http://localhost:8080/abc/def
May I request some guidance on this?
My goal is to not have to handle /error and catch unconfigured routes which otherwise would lead to /error
I fixed this using:
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/**/{path:[^\\.]+}").setViewName("forward:/");
}
The only issue now is that images are not rendering.

Not sure about this. Just referring to:
Spring catch all route for index.html
could you try adding this:
/{spring:\\w+}
to make the above:
#RequestMapping(value = "/{spring:\\w+}")

Related

How to get a respose from a localhost url exactly http://localhost:8888/

I have two projects setting up Springboot in it, now, I am going to run these two springboot on eclipse, I set up the port 8888 for projectB.
Here is my projectB controller with RequestMapping.
#RequestMapping(value = "test", method = RequestMethod.GET)
public #ResponseBody String test() {
return "testtesttest";
}
I need to call a url from jquery method that url is to read the respose from a controller in projectB.
how can I call this url ??
I tried "http://localhost:8888/test" and "http://127.0.0.1:8888/test"
but I did not get anything from the response.
The error shows up as :
please give me the solution for this
very appreciated.
Add below code in your application's main class. This configures your web mvc cors mapping to allow request from " * "
#SpringBootApplication
public class Application {
#Configuration
public class MyConfiguration {
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
logger.info("Added CORS config");
registry.addMapping("/**").allowedOrigins("*").maxAge(3600);
}
};
}
}
}

How to test an existing camel route?

I'm trying to test an existing Camel route, but it's proving much more difficult than I anticipated. Most of the documentation that I've seen online seems to create a new route in the test, and then test that. How can I test a route that I have already created?
For simplicity, I have created the simplest route that I can think of, but I can't for the life of me figure out how to use that route in a test.
Here's the route:
#Component
public class TestRouteBuilder extends RouteBuilder{
#Override
public void configure() throws Exception {
from("direct:testStart")
.log("Log triggered.")
.to("direct:testEnd");
}
}
How can I use this route in a test?
I'm using Camel with Spring Boot, so my first thought was to inject the route into the test, but that didn't seem to work.
Any help appreciated, thanks.
This can be achieved in multiple ways.. Here is one way:
context.getRouteDefinitions().get(0).adviceWith(context, new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
weaveAddLast().to("mock:result");
}
});
You can also use CamelTestSupport:
#Override
public String isMockEndpoints() {
// override this method and return the pattern for which endpoints to mock.
// use * to indicate all
return "*";
}

Spring catch all route for index.html

I'm developing a spring backend for a react-based single page application where I'm using react-router for client-side routing.
Beside the index.html page the backend serves data on the path /api/**.
In order to serve my index.html from src/main/resources/public/index.html on the root path / of my application I added a resource handler
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/").addResourceLocations("/index.html");
}
What I want to is to serve the index.html page whenever no other route matches, e.g. when I call a path other than /api.
How do I configure such catch-all route in spring?
Since my react app could use the root as forward target this ended up working for me
#Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/{spring:\\w+}")
.setViewName("forward:/");
registry.addViewController("/**/{spring:\\w+}")
.setViewName("forward:/");
registry.addViewController("/{spring:\\w+}/**{spring:?!(\\.js|\\.css)$}")
.setViewName("forward:/");
}
}
To be honest I have no idea why it has to be exactly in this specific format to avoid infinite forwarding loop.
I have a Polymer-based PWA hosted inside of my Spring Boot app, along with static web resources like images, and a REST API under "/api/...". I want the client-side app to handle the URL routing for the PWA. Here's what I use:
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
/**
* Ensure client-side paths redirect to index.html because client handles routing. NOTE: Do NOT use #EnableWebMvc or it will break this.
*/
#Override
public void addViewControllers(ViewControllerRegistry registry) {
// Map "/"
registry.addViewController("/")
.setViewName("forward:/index.html");
// Map "/word", "/word/word", and "/word/word/word" - except for anything starting with "/api/..." or ending with
// a file extension like ".js" - to index.html. By doing this, the client receives and routes the url. It also
// allows client-side URLs to be bookmarked.
// Single directory level - no need to exclude "api"
registry.addViewController("/{x:[\\w\\-]+}")
.setViewName("forward:/index.html");
// Multi-level directory path, need to exclude "api" on the first part of the path
registry.addViewController("/{x:^(?!api$).*$}/**/{y:[\\w\\-]+}")
.setViewName("forward:/index.html");
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/webapp/");
}
}
This should work for Angular and React apps as well.
Avoid #EnableWebMvc
By default Spring-Boot serves static content in src/main/resources:
/META-INF/resources/
/resources/
/static/
/public/
Take a look at this and this;
Or keep #EnableWebMvc and override addViewControllers
Did you specify #EnableWebMvc ? Take a look a this: Java Spring Boot: How to map my app root (“/”) to index.html?
Either you remove #EnableWebMvc, or you can re-define addViewControllers:
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("forward:/index.html");
}
Or define a Controller to catch /
You may take a look a this spring-boot-reactjs sample project on github:
It does what you want using a Controller:
#Controller
public class HomeController {
#RequestMapping(value = "/")
public String index() {
return "index";
}
}
Its index.html is under src/main/resources/templates
I use react and react-router in my spring boot app, and it was as easy as creating a controller that has mapping to / and subtrees of my website like /users/**
Here is my solution
#Controller
public class SinglePageAppController {
#RequestMapping(value = {"/", "/users/**", "/campaigns/**"})
public String index() {
return "index";
}
}
Api calls aren't caught by this controller and resources are handled automatically.
Found an answer by looking at this question
#Bean
public EmbeddedServletContainerCustomizer notFoundCustomizer() {
return new EmbeddedServletContainerCustomizer() {
#Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/"));
}
};
}
Another solution (change/add/remove myurl1, myurl2, ... with your routes):
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
#Controller
public class SinglePageAppController {
/**
* If the user refreshes the page while on a React route, the request will come here.
* We need to tell it that there isn't any special page, just keep using React, by
* forwarding it back to the root.
*/
#RequestMapping({"/myurl1/**", "/myurl2/**"})
public String forward(HttpServletRequest httpServletRequest) {
return "forward:/";
}
}
Note: Using public String index() also works fine, but only if you use templates. And the use of WebMvcConfigurerAdapter is deprecated.
To answer your specific question which involves serving up the Single Page App (SPA) in all cases except the /api route here is what I did to modify Petri's answer.
I have a template named polymer that contains the index.html for my SPA. So the challenge became let's forward all routes except /api and /public-api to that view.
In my WebMvcConfigurerAdapter I override addViewControllers and used the regular expression: ^((?!/api/|/public-api/).)*$
In your case you want the regular expression: ^((?!/api/).)*$
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/{spring:^((?!/api/).)*$}").setViewName("polymer");
super.addViewControllers(registry);
}
This results in being able to hit http://localhost or http://localhost/community to serve up my SPA and all of the rest calls that the SPA makes being successfully routed to http://localhost/api/posts, http://localhost/public-api/posts, etc.
After lot of tries I've found the following solution as most simple one. It will basically bypass all the Spring handling which was so difficult to deal with.
#Component
public class StaticContentFilter implements Filter {
private List<String> fileExtensions = Arrays.asList("html", "js", "json", "csv", "css", "png", "svg", "eot", "ttf", "woff", "appcache", "jpg", "jpeg", "gif", "ico");
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
doFilter((HttpServletRequest) request, (HttpServletResponse) response, chain);
}
private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String path = request.getServletPath();
boolean isApi = path.startsWith("/api");
boolean isResourceFile = !isApi && fileExtensions.stream().anyMatch(path::contains);
if (isApi) {
chain.doFilter(request, response);
} else if (isResourceFile) {
resourceToResponse("static" + path, response);
} else {
resourceToResponse("static/index.html", response);
}
}
private void resourceToResponse(String resourcePath, HttpServletResponse response) throws IOException {
InputStream inputStream = Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream(resourcePath);
if (inputStream == null) {
response.sendError(NOT_FOUND.value(), NOT_FOUND.getReasonPhrase());
return;
}
inputStream.transferTo(response.getOutputStream());
}
}

Spring RequestMapping with root path (/{custom})

Let's say my website name is: foo.com
When a user types foo.com, I want to show index.html.
When a user types foo.com/something, I want the server catches the request at the controller.
Here is what I did in the HomeController:
#Controller
public class HomeController {
#RequestMapping(value={"/"}, method=RequestMethod.GET)
public String getHome() {
return "index.html";
}
}
And, the CustomController should catch the request
#Controller
public class CustomController {
#RequestMapping(value={"/{custom}"}, method=RequestMethod.GET)
public String getCustom(#PathVariable String custom) {
// Do something here..
}
}
However, it throws an error: Circular view path [index.html]: would dispatch back to the current handler URL [/index.html] again. It's because the CustomController catches the GET request: foo.com/index.html after the HomeController returns the string: index.html.
I did some research like this:
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/assets"); // My asset
registry.addResourceHandler("index.html").addResourceLocations("file:/index.html");
} // It's not working
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("forward:/" + FileNames.INDEX);
} // This also not working
}
And changing the annotation from #Controller to #RestController in the CustomController is not an option.
Also, I don't have JSP files in the project - they are plain *.html files.
I am using Spring 1.3.3 release, so please help me out.
This solution works with ui-router (AngularJS library). Also, you have to change $resourceProvider setting:
// In your app module config
$resourceProvider.defaults.stripTrailingSlashes = false;
Then, in the Spring server codes, you can do this:
#RequestMapping(value = "/{custom:[^\\.]*}")
public String redirect(#PathVariable String custom) {
// Do something here...
return "forward:/";
}
Found the solution at this link: https://spring.io/blog/2015/05/13/modularizing-the-client-angular-js-and-spring-security-part-vii

How to checkin interceptor whether a controller triggered a redirect

In my Spring MVC project I added an interceptor class, to check, whether a redirect has been triggered.
Here is my controller-class:
#Controller
public class RedirectTesterController {
#RequestMapping (value="/page1")
public String showPage1(){
return "page1";
}
#RequestMapping (value="/submit1")
public String submitPage1(){
return "redirect:/page2";
}
#RequestMapping (value="/page2")
public String showPage2(){
return "page2";
}
}
So if I call e.g.
localhost:8080/MyContext/submit1
the method "submitPage1" is executed.
Now - the server tells the client, to call
localhost:8080/MyContext/page2
which is also working.
So - I want to step into that process, after method "submitPage1"has been executed.
In my mind there should be some order/command in the httpResponse, which I could ask.
To check that, I made a breakpoint in my interceptor class in the method: "postHandle" - bit since then, I have no idea how to continue.
I tried to read the outputStream - but doing so crashes my application. (leads to an exception --> outputStream has already been called..).
Isn't there an easy solution for that ?
Following example shows how to test if a view is a redirect:
#Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new HandlerInterceptorAdapter() {
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
if (modelAndView != null && StringUtils.startsWithIgnoreCase(modelAndView.getViewName(), "redirect:")) {
// handle redirect...
}
}
});
}
}
See: HandlerInterceptorAdapter, StringUtils
Spring MVC Documentation: Intercepting requests with a HandlerInterceptor

Resources