I'm using Spring Boot to make a REST Api for my Vue application. This is my route handler:
#RestController
public class RootController {
#CrossOrigin
#GetMapping("/")
public String index() {
return "Hello from server";
}
}
Whenever I use axios to make a request to my API it responds with:
How can I fix this?
Basically, you need to specify the origin with the #CrossOrigin annotation, that lets the spring app know which all origins are allowed to make request to those rest api's.
In your case, you can try replacing #CrossOrigin with #CrossOrigin(origins = "http://localhost:8080") assuming your client application is hosted at port 8080.
Also, you can try #CrossOrigin(origins = "", allowedHeaders = "") which would allow every origin and all headers.
#CrossOrigin
#RestController
public class RootController {
#GetMapping("/")
public String index() {
return "Hello from server";
}
}
I would highly recommend that you go to this Spring.io article that covers in-depth what you are asking for!
For the meantime, you can go and create a #Bean that would configure CORS for your application (Consider converting the code into Java syntax, I've just copied it from a kotlin project I'm working on):
#Bean
fun corsFilter(): CorsWebFilter {
val corsConfig = CorsConfiguration()
corsConfig.allowedOrigins = Arrays.asList("*")
corsConfig.maxAge = 8000L
corsConfig.addAllowedMethod("PUT")
corsConfig.addAllowedMethod("GET")
corsConfig.addAllowedMethod("POST")
corsConfig.addAllowedHeader("Origin")
corsConfig.addAllowedHeader("Content-Type")
corsConfig.addAllowedHeader("Accept")
val source = UrlBasedCorsConfigurationSource()
source.registerCorsConfiguration("/**", corsConfig)
return CorsWebFilter(source)
}
Related
I'm setting up the controller to match all routes and return the built production React. While doing that I couldn't do GET APIs from http://localhost:8080/api/ (Return the blank screen of React) when the POST method works fine. Any suggestion on how to make React match all routes except "/api", please?
My Controller Code
#Controller
public class ClientForwardController {
#GetMapping(value = "/**/{path:[^\\.]*}")
public String forward() {
return "forward:/";
}
}
I have found a solution to this question.
I've added SwaggerController.java controller
#Controller
#RequestMapping("/docs")
public class SwaggerController {
#GetMapping
public String index() {
return "redirect:/swagger-ui/index.html";
}
}
The point is to override the
"/**" matching in the previous controller I wrote above in the question.
And with the API endpoints ("/api"), I had a mistake to put GetMapping("/") for that controller so it has to write ("/api/something/something/") to match [I wrote "/api/something/something"]. So all the problems were fixed.
I'm trying to write REST server, using this video example (careful, russian speech).
In the example, when lecturer writes #RequestMapping above controller class, class becomes in use. But in my case, controller class "is never used", and when I started tomcat server with my controller and going on page http://localhost:8000/app/remind/get , I get this error: No mapping for GET /app/remind/get
This is my controller code:
#Controller
#RequestMapping("/reminder")
public class ReminderController {
#RequestMapping(value = "/get", method = RequestMethod.GET)
#ResponseBody
public String getReminder(){
return "my reminder";
}
}
And this is my WebConfig.java
#Configuration
#EnableWebMvc
#ComponentScan("com.fillooow.remindme.server")
public class WebConfig extends WebMvcConfigurerAdapter {
}
So, can you explain, why my class "is never used" and what am I missing?
EDIT
My problem was wrong context in configuration file ("/" instead of "/app")
Suggestion: try #GetMapping; be sure you're using the correct URL:
#Controller
#RequestMapping("/reminder")
public class ReminderController {
#GetMapping(value = "/get")
#ResponseBody
public String getReminder(){
return "my reminder";
}
}
... and ...
http://localhost:8000/app/reminder/get
ALSO: I'm not sure about your context root ("app") or your port ("8000" vs. "8080").
POSSIBLE ALTERNATIVE:
http://localhost:8080/reminder/get
ADDITIONAL SUGGESTION: Enable debugging
logging.level.org.springframework=DEBUG
Try the endpoint like as below
http://localhost:8000/reminder/get
I created a RestController which look like this :
#RestController
public class GreetingController {
#RequestMapping(value = "/greetings", method = RequestMethod.GET)
public Mono<Greeting> greeting(HttpServletRequest request) {
return Mono.just(new Greeting("Hello..." + request.toString()));
}
}
Unfortunately when I try to hit the "greetings" endpoint I get an exception :
java.lang.IllegalStateException: No resolver for argument [0] of type
[org.apache.catalina.servlet4preview.http.HttpServletRequest]
I am using
compile('org.springframework.boot.experimental:spring-boot-starter-web-reactive')
How to fix this ?
Link to full stack-trace. Link to build.gradle
----------EDIT----------
Using the interface. Now getting :
java.lang.IllegalStateException: No resolver for argument [0] of type
[javax.servlet.http.HttpServletRequest] on method (rest is same)
You should never use the Servlet API in a Spring Reactive Web application. This is not supported and this is making your app container-dependent, whereas Spring Web Reactive can work with non-Servlet runtimes such as Netty.
Instead you should use the HTTP API provided by Spring; here's your code sample with a few changes:
import org.springframework.http.server.reactive.ServletServerHttpRequest;
#RestController
public class GreetingController {
#GetMapping("/greetings")
public Mono<Greeting> greeting(ServerHttpRequest request) {
return Mono.just(new Greeting("Hello..." + request.getURI().toString()));
}
}
You can inject either ServerWebExchange or directly ServerHttpRequest / ServerHttpResponse.
I went deep into the call hierarchy and found that there is this class
InvocableHandlerMethod, in package org.springframework.web.reactive.result.method
, which has :
private List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
There is a resolveArguments() method in this class, which is called to "resolve the arguments". Unfortunately there is no resolver for
javax.servlet.http.HttpServletRequest in this list.
There is however a ServerWebExchangeArgumentResolver which is able to resolve ServletServerHttpRequest, from this I can extract the HttpServletRequest. Yeaaa....
So the endpoint looks like :
#RequestMapping(value = "/greetings", method = RequestMethod.GET)
public Mono<Greeting> greeting(ServletServerHttpRequest servletServerHttpRequest) {
HttpServletRequest httpServletRequest = servletServerHttpRequest.getServletRequest();
.
.
.
}
It is important that the ServletServerHttpRequest be from the package org.springframework.http.server.reactive
I have the following class
#RestController
#RequestMapping("/bets")
#CrossOrigin
public class BetRestController {
#Autowired
private BetController betController;
#ResponseBody
#RequestMapping(method=RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public BetResource betOnGame(#RequestBody #Valid BetResource betResource) {
return BetTranslator.from(betController.betOnGame(BetTranslator.from(betResource)));
}
#ResponseBody
#RequestMapping(method = RequestMethod.GET)
public List<BetResource> getAllBets() {
return betController.getAllBets().stream().map(BetTranslator::from).collect(Collectors.toList());
}
}
The problem is that when I try to access the POST method I am getting:
XMLHttpRequest cannot load http://localhost:8080/bets. Origin http://localhost:3000 is not allowed by Access-Control-Allow-Origin.
but GET method works.
What I have wrong in my configuration or maybe there is a bug in #CrossOrigin annotation processing?!
If I understand your problem correctly, it is possible to specify CORS origin on one specific method.
Sprint Boot documentation : https://spring.io/guides/gs/rest-service-cors/
Enabling CORS
Controller method CORS configuration
So that the RESTful web service will include CORS access control
headers in its response, you just have to add a #CrossOrigin
annotation to the handler method:
Here's the example from Spring boot website :
#CrossOrigin(origins = "http://localhost:9000")
#RequestMapping("/greeting")
public #ResponseBody Greeting greeting(#RequestParam(required=false, defaultValue="World") String name) {
System.out.println("==== in greeting ====");
return new Greeting(counter.incrementAndGet(), String.format(template, name));
}
I'm trying to implement a controller method similar to how is documented in the latest Gosling release train of Spring Data that supports QueryDsl. I've implemented the controller as shown in the example in the docs at http://docs.spring.io/spring-data/jpa/docs/1.9.0.RELEASE/reference/html/#core.web.type-safe. Everything compiles and when I start the application (using Spring Boot 1.2.5.RELEASE), everything starts fine.
However, when I try to call my rest endpoint, I always get the following exception:
org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.mysema.query.types.Predicate]: Specified class is an interface
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:101)
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.createAttribute(ModelAttributeMethodProcessor.java:137)
at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.createAttribute(ServletModelAttributeMethodProcessor.java:80)
My guess is that the QuerydslPredicateArgumentResolver is not being applied to the request, and thus the exception. But I see that the QuerydslPredicateArgumentResolver is registered as a bean when I query the Spring Boot manage endpoint /manage/beans. I have also ensured that #EnableSpringDataWebSupport is on my #Configuration class to no effect.
I have the controller annotated with #BasePathAwareController, since I'm using this with Spring Data REST and I want the methods to be under a similar path as the ones that Spring Data REST exposes. I also tried using #RepositoryRestController, but that didn't seem to matter. However, when using #RestController and putting it under a path that was different then the base path that Spring Data REST is using, things worked. So the question is, should it work?
The entire controller right now is:
#RestController
#RequestMapping(value = "/query")
public class AvailController
{
private final AvailRepository repo;
#Autowired
public AvailController(AvailRepository repository)
{
this.repo = repository;
}
#RequestMapping(value = "/avails", method = GET)
public #ResponseBody Page<Avail> getAvails(Model model,
#QuerydslPredicate(root = Avail.class) Predicate predicate,
Pageable pageable,
#RequestParam MultiValueMap<String, String> parameters)
{
return repo.findAll(predicate, pageable);
}
}
I had the same problem with instantiation of Predicate. In the example:
#Controller
#RequiredArgsConstructor(onConstructor = #__(#Autowired) )
class UserController {
private final UserRepository repository;
#RequestMapping(value = "/", method = RequestMethod.GET)
String index(Model model, //
#QuerydslPredicate(root = User.class) Predicate predicate, //
#PageableDefault(sort = { "lastname", "firstname" }) Pageable pageable, //
#RequestParam MultiValueMap<String, String> parameters) {
(...)
(https://github.com/spring-projects/spring-data-examples/blob/master/web/querydsl/src/main/java/example/users/web/UserController.java#L42 ) is using just #Controller and I was using #RepositoryRestController, that seems to be the reason. #RestController also works for me.
I created https://jira.spring.io/browse/DATAREST-838
I also had this issue when trying to implement a custom controller that mimics the returned value as Spring Data REST. I wanted to inject QuerydslPredicate to the controller method and got the annoying 'BeanInstantiationException'.
I found a work around for this by adding the following configuration file to my application:
#Configuration
#Order(Ordered.HIGHEST_PRECEDENCE )
public class MvcConfig extends WebMvcConfigurerAdapter {
#Autowired
#Qualifier("repositoryExporterHandlerAdapter")
RequestMappingHandlerAdapter repositoryExporterHandlerAdapter;
#Override
public void addArgumentResolvers(
List<HandlerMethodArgumentResolver> argumentResolvers) {
List<HandlerMethodArgumentResolver> customArgumentResolvers = repositoryExporterHandlerAdapter.getCustomArgumentResolvers();
argumentResolvers.addAll(customArgumentResolvers);
}
}
See here for reference: https://jira.spring.io/browse/DATAREST-657