I'm providing a soap webservice with java-first approach, thus using CXF for this. To make it publishing with spring-boot, I have the following dispatcher servlet:
#Bean
public ServletRegistrationBean dispatcherServletRegistration() {
ServletRegistrationBean registration = new ServletRegistrationBean(new CXFServlet(), "/services/*");
registration.setName(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);
return registration;
}
This works fine, but I now want to offer a REST service aside. The rest service should NOT be published by cxf, but by the default spring mapping:
#RestConstroller
#RequestMapping("/rest/content")
public class MyServiceRest extends SpringBeanAutowiringSupport {
}
The result of this:
localhost:8080/app-name/rest/content results in HTTP 404.
localhost:8080/app-name/services/rest/content shows a spring message "No service was found."
So, somehow the latter is inside the context of the CXFServlet, and the REST service is not found.
What do I have to change to make this setup work?
By the way: when I remove the ServletRegistrationBean, the rest service works as expected. But that's not an option as I have to offer the soap service alongside.
Your bean named dispatcherServletRegistration is replacing Spring Boot's default DispatcherServlet so your left with just a CXFServlet and no DispatcherServlet in your application.
Update your bean to register the CXFServlet to something like this:
#Bean
public ServletRegistrationBean cxfServletRegistration() {
return new ServletRegistrationBean(new CXFServlet(), "/services/*");
}
Related
I have a Spring Boot Rest application where I need to allow CORS requests.
Requests use the common path <host>:<port>/api/... and so far I only have two resources:
package my.controllers;
#RestController
#RequestMapping(path="/", produces="application/json")
public class DataController {
#GetMapping("/")
public ApiResponse<Map<String, Object>> getValues() {
// ...
}
#GetMapping("/sub")
public ApiResponse<String> getValuesSub() {
// ...
}
Here are two example requests from the Javascript client running at http://localhost:3000/:
fetch('http://localhost:2001/api/').then(/* ... */);
fetch('http://localhost:2001/api/sub')).then(/* ... */);
If I add the #CrossOrigin(origins = "*") annotation to the controller, CORS requests work fine; if I replace it implementing WebMvcConfigurer.addCorsMappings() though:
#ComponentScan(basePackages={ "my.controllers" })
#Configuration
public class WebappConfig implements WebMvcConfigurer {
// ...
#Override
public void addCorsMappings(CorsRegistry registry) {
LogManager.getLogger(getClass()).info("CORS settings");
registry.addMapping("/api/**").allowedOrigins("*").maxAge(3600);
}
CORS requests fail, and I get (in Firefox, Chrome shows a similar error message):
CORS header 'Access-Control-Allow-Origin' missing
I see the log entry, so the method is surely invoked.
I've seen other questions mentioning Spring Security or Spring Data (I use none), so here's my dependencies list in case I'm missing something:
spring-boot-starter-web
spring-boot-starter-tomcat
spring-boot-starter-log4j2
spring-boot-configuration-processor
commons-lang3
commons-beanutils
What's the right way to set CORS settings to the whole application, without using the #CrossOrigin annotation on each controller?
UPDATE
I'm initializing a Rest servlet like this:
#Bean
public ServletRegistrationBean<DispatcherServlet> registerDispatcherServlet(DispatcherServlet servlet) {
ServletRegistrationBean<DispatcherServlet> registration = new ServletRegistrationBean<>(servlet);
servlet.setContextConfigLocation("");
registration.addUrlMappings("/api/*");
registration.setLoadOnStartup(1);
return registration;
}
The logs says:
Servlet dispatcherServlet mapped to [/api/*]
Servlet dispatcherServlet mapped to [/]
Servlet dispatcherServlet was not registered (possibly already registered?)
Could it be that the given Cors settings are going to the mentioned unregistered servlet?
I got it working by replacing "/api/**" with "/**" in the call to addMapping() when configuring the CORS registry:
#Override
public void addCorsMappings(CorsRegistry registry) {
LogManager.getLogger(getClass()).info("CORS things!");
registry.addMapping("/**").allowedOrigins("*").maxAge(3600);
}
Though I'm puzzled about why this is the setting that makes it work, and what would I have to do if I need to expose several independent Rest paths, i.e.:
http:/host:port/public-api (from all over the Internet)
http:/host:port/reserved-api (from well known hosts)
http:/host:port/admin-api (same host only)
I'm working on migrating some applications from Spring to Spring Boot. Some of the applications provide SOAP web services on the root url of the application (/), which is fine with a Spring application. But on Spring Boot, this causes some issues, since setting up a servlet to listen on / will overwrite the default dispatcher-servlet, causing for instance the actuator endpoint to be overwritten. Still, I do not want to change the url to my wsdl, since this will lead to updating all the clients of the service.
Is there a way to have Spring Boot supply a JAX-WS/CXF Web Service on /, without overwriting the default servlet? Is there a way to have the default servlet supply the web service, without the need of an extra CXFServlet?
Managed to access the wsdl at least, by exposing the CXFServlet as a filter, rather than a servlet:
#Bean
public Endpoint endpoint(final SpringBus springBus, final MyServiceImpl myService) {
final EndpointImpl endpoint = new EndpointImpl(springBus, myService);
endpoint.publish("/MyService");
return endpoint;
}
#Bean
public SpringBus springBus() {
return new SpringBus();
}
#Bean
public FilterRegistrationBean<CXFServlet> cxfServletFilter(final SpringBus springBus) {
final CXFServlet cxfServlet = new CXFServlet();
cxfServlet.setBus(springBus);
final FilterRegistrationBean<CXFServlet> filterRegistrationBean = new FilterRegistrationBean<>(cxfServlet);
filterRegistrationBean.setOrder(2);
return filterRegistrationBean;
}
I also removed cxf-spring-boot-starter-jaxws from my pom.xml.
Any feedback on this solution is appreciated.
Set Context path differently for both Webservice and Rest
I have an application which contains both implementation of Webservices and Rest services and I am looking for an solution to set context path for both Webservices and Rest services differently using yml/properties file
How to configure servlet dispatcher to work properly?
I would like to have:
localhost:8080/ws/* - webservice
localhost:8080/web/* - MVC components
servlet:
context-path: "/ws"
It sets globally for both webservices and rest services , How to make it independent to each other with out programming?
Using Spring Boot (with Spring Starter Web) you could achive what are you asking for with the annotation #RequestMapping.
You could put #RequestMapping(value="/ws") on the class declaration of every rest controller and #RequestMapping(value="/web") for web controllers.
For both rest and web controller than you could use other annotations to specify method path, i.e #GetMapping(value="/methodPath").
#Controller
#RequestMapping(value="/web")
public class WebController{
#GetMapping(value="/method")
public String method(){
...
}
}
#RestController
#RequestMapping(value="/ws")
public class RestController{
#GetMapping(value="method")
public String method(){
...
}
}
I have a spring boot application that uses the spring boot starter web. This creates a running Tomcat instance and sets up the http server running on a port. Within my camel route, I want to use this http server as the component for http requests, but I can't figure out how to utilize it. I see many many examples of configuring a jetty instance and consuming from it, but then wouldn't I in effect have two http servers running? I only want to have one. I assume the http server is already autowired up since I can consume from it with other spring code (such as a RestController) and I can see it started in my spring boot logs as well.
#Component
public class ExampleRoute extends RouteBuilder
{
#Override
public void configure() throws Exception
{
//#formatter:off
from( <want to take in an http request here> )
.log( LoggingLevel.INFO, log, "Hello World!" );
//#formatter:on
}
}
There is an example here: https://github.com/camelinaction/camelinaction2/tree/master/chapter7/springboot-camel
You can to register a ServletRegistrationBean that setup the Camel Servlet with Spring Boot.
#Bean
ServletRegistrationBean camelServlet() {
// use a #Bean to register the Camel servlet which we need to do
// because we want to use the camel-servlet component for the Camel REST service
ServletRegistrationBean mapping = new ServletRegistrationBean();
mapping.setName("CamelServlet");
mapping.setLoadOnStartup(1);
// CamelHttpTransportServlet is the name of the Camel servlet to use
mapping.setServlet(new CamelHttpTransportServlet());
mapping.addUrlMappings("/camel/*");
return mapping;
}
However for Camel 2.19 we plan on make this simpler and OOTB: https://issues.apache.org/jira/browse/CAMEL-10416
And then you can do
from("servlet:foo")
.to("bean:foo");
Where the HTTP url to call that Camel route will be http:localhost:8080/camel/foo
So I am developing a REST API in an application that uses both Spring and Wicket at the same time.
If I annotate #RequestMapping(value="/exchange") at my Spring #Controller annotated class (the one that is acting as a webserver), how do I have to configure Wicket to "recognize" http://myserver.com/myapp/exchange or http://myserver.com/myapp/exchange/onemethod as a valid URL so I don't get a 404 ERROR when I try to call the webservice from a client?
Use the JAX-RS #Path annotation:
#Path("exchange")
#Component
public class ExchangeService {
#POST
#Path("onemethod")
public void oneMethod(...) {
...
}
}