I'm using Spring Boot 1.3.* to build a contract first web service. I looked at the answer for the question at How to use WSDL with spring-boot? . This worked fine
#EnableWs
#Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
#Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/ws/*");
}
//http://localhost:8080/ws/services.wsdl --bean name is set to 'services'
#Bean(name = "services")
public Wsdl11Definition defaultWsdl11Definition() {
SimpleWsdl11Definition wsdl11Definition = new SimpleWsdl11Definition();
wsdl11Definition.setWsdl(new ClassPathResource("/schema/MyWsdl.wsdl")); //your wsdl location
return wsdl11Definition;
}
}
My wsdl is now located at http://localhost:8080/ws/services.wsdl . Problem is that the application that will be the consumer of this web service requires the wsdl url to be written as
http://localhost:8080/ws/services?wsdl
How can i achieve this?
To configure urlrewrite as a bean check this tuckey-url-rewrite-filter-java-class-configuration
This will forward in backend and user will not be notified. Ad this rule in your urlrewrite.xml
<rule>
<from>/ws/services?wsdl</from>
<to>/ws/services.wsdl</to>
</rule>
Related
I create the SOAP endpoint in my spring boot project
#EnableWs
#Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
#Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
return new ServletRegistrationBean(servlet, "/project/soap/*");
}
#Bean(name="CollaborationMessageService")
public Wsdl11Definition defaultWsdl11Definition() {
SimpleWsdl11Definition wsdl11Definition = new SimpleWsdl11Definition();
wsdl11Definition.setWsdl(new ClassPathResource("/META-INF/wsdl/oracle/CollaborationMessageService.wsdl"));
return wsdl11Definition;
}
}
The endpoint is accessible in using below URL:-
http://localhost:8080/project/soap/CollaborationMessageService.wsdl
I want endpoint URL to be like:-
http://localhost:8080/project/soap/CollaborationMessageService?wsdl
is there any possible way to make these changes?
I'm implementing SOAP WS services with Spring Boot.
To be able to filter requests based on the request URI, I want to provide different Endpoint implementation at different URI mappings.
To do so, I register both mapping with the servlet registration bean first:
#EnableWs
#Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
...
#Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/ws/*", "/special/*" );
}
and then I register my Endpoint for each mapping:
#Bean(name = "serviceA")
public DefaultWsdl11Definition caseDocumentWsdl11Definition(XsdSchema caseASchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("CaseAPort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace(CaseAEndpoint.NAMESPACE_URI);
wsdl11Definition.setSchema(caseASchema);
return wsdl11Definition;
}
#Bean(name = "serviceB")
public DefaultWsdl11Definition caseDocumentBkkWsdl11Definition(XsdSchema caseBSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("CaseBPort");
wsdl11Definition.setLocationUri("/special");
wsdl11Definition.setTargetNamespace(CaseBEndpoint.NAMESPACE_URI);
wsdl11Definition.setSchema(caseBSchema);
return wsdl11Definition;
}
Now, the undesired effect I see is that when I send a request with the payload for service A to the URI of service B, e.g. with curl:
curl --header "content-type: text/xml" -d #caseARequest.xml http://localhost:8081/special/
it is handled by CaseAEndpoint implementation even though that is not registered (with setLocationUri) to handle it.
Thus, the plan to use the request URI to filter requests nd secure the endpoints does not work.
Any hint on what I'm missing or I need to add?
(As a workaround I added check in the endpoint impl based on the request URI using ServletUriComponentsBuilder.fromCurrentRequestUri().toUriString().contains("special")) but that's not how it should be and not what the API suggests, right?
We are using the latest Spring Boot for a Spring app and using the latest Spring Integration for SFTP. I've been to the Spring Integration SFTP documentation site, and I took the Spring Boot Configuration as is:
#Bean
public SessionFactory<LsEntry> sftpSessionFactory() {
DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
factory.setHost("localhost");
factory.setPort(port);
factory.setUser("foo");
factory.setPassword("foo");
factory.setAllowUnknownKeys(true);
return new CachingSessionFactory<LsEntry>(factory);
}
#Bean
public SftpInboundFileSynchronizer sftpInboundFileSynchronizer() {
SftpInboundFileSynchronizer fileSynchronizer = new SftpInboundFileSynchronizer(sftpSessionFactory());
fileSynchronizer.setDeleteRemoteFiles(false);
fileSynchronizer.setRemoteDirectory("/");
fileSynchronizer.setFilter(new SftpSimplePatternFileListFilter("*.xml"));
return fileSynchronizer;
}
#Bean
#InboundChannelAdapter(channel = "sftpChannel")
public MessageSource<File> sftpMessageSource() {
SftpInboundFileSynchronizingMessageSource source =
new SftpInboundFileSynchronizingMessageSource(sftpInboundFileSynchronizer());
source.setLocalDirectory(new File("ftp-inbound"));
source.setAutoCreateLocalDirectory(true);
source.setLocalFilter(new AcceptOnceFileListFilter<File>());
return source;
}
#Bean
#ServiceActivator(inputChannel = "sftpChannel")
public MessageHandler handler() {
return new MessageHandler() {
#Override
public void handleMessage(Message<?> message) throws MessagingException {
System.out.println(message.getPayload());
}
};
}
Let me be clear, after cutting and pasting, there are some unit tests that run. However, when loading the application context there was an error message because the Polling wasn't there.
When I googled that error, other posts on StackOverflow said I also had to add to remove this error message when loading the application context.
#Bean(name = PollerMetadata.DEFAULT_POLLER)
public PollerMetadata defaultPoller() {
PollerMetadata pollerMetadata = new PollerMetadata();
pollerMetadata.setTrigger(new PeriodicTrigger(60));
return pollerMetadata;
}
When I added this code, THEN at least my build would work and the tests would run because the application context was now being loaded correctly.
Now I am looking for a code sample on how to make this work and move files? The Spring Integration SFTP examples on GitHub are ok, but not great ... far from it.
The Basic Spring Integration Example shows how to read files from an SFTP Server, if the data is configured with an application-context.xml file. Where is the example where a Spring Boot configuration is used, and then the code to read from that server, and the code for the test?
I understand that regardless of whether you use a Java class for Spring Boot configuration or an application-context.xml file ... the working code should work the same for autowired SFTP channels and some inbound channel adapter.
So here is the code, I am trying to make work:
#Component
#Profile("sftpInputFetch")
public class SFTPInputFetcher implements InputFetcher
{
// The PollableChannel seems fine
#Autowired
PollableChannel sftpChannel;
#Autowired
SourcePollingChannelAdapter sftpChannelAdapter;
#Override
public Stream<String> fetchLatest() throws FileNotFoundException
{
Stream<String> stream = null;
sftpChannelAdapter.start();
Message<?> received = sftpChannel.receive();
File file = (File)received.getPayload();
// get Stream<String> from file
return stream;
}
Currently, "sftpChannelAdapter.start();" is the part I am having trouble with.
This implementation does not find the "SourcePollingChannelAdapter" class.
If this was defined in the classic XML application context with an "id" then this code autowires just fine. With a Spring Boot configuration, it doesn't look like you can define an "id" for a bean.
This just stems from my lack of knowledge on how to convert from using a traditional application-context XML file WITH annotations in the code, to using a complete Spring Boot application context configuration file.
Any help with this is much appreciated. Thanks!
I don't understand the question; you said
I had to add ... to make it work
and then
Now I am looking for a code sample on how to make this work?
What is not working?
You can also use
#InboundChannelAdapter(value = "sftpChannel", poller = #Poller(fixedDelay = "5000"))
instead of adding a default poller definition.
We will fix the docs for the missing poller config.
EDIT
I just copied the code into a new boot app (with the poller config) and it works as expected.
#SpringBootApplication
public class SftpJavaApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(SftpJavaApplication.class).web(false).run(args);
}
#Bean
public SessionFactory<LsEntry> sftpSessionFactory() {
DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
factory.setHost("...");
factory.setPort(22);
factory.setUser("...");
factory.setPassword("...");
factory.setAllowUnknownKeys(true);
return new CachingSessionFactory<LsEntry>(factory);
}
#Bean
public SftpInboundFileSynchronizer sftpInboundFileSynchronizer() {
SftpInboundFileSynchronizer fileSynchronizer = new SftpInboundFileSynchronizer(sftpSessionFactory());
fileSynchronizer.setDeleteRemoteFiles(false);
fileSynchronizer.setRemoteDirectory("foo");
fileSynchronizer.setFilter(new SftpSimplePatternFileListFilter("*.txt"));
return fileSynchronizer;
}
#Bean
#InboundChannelAdapter(channel = "sftpChannel", poller = #Poller(fixedDelay = "5000"))
public MessageSource<File> sftpMessageSource() {
SftpInboundFileSynchronizingMessageSource source = new SftpInboundFileSynchronizingMessageSource(
sftpInboundFileSynchronizer());
source.setLocalDirectory(new File("ftp-inbound"));
source.setAutoCreateLocalDirectory(true);
source.setLocalFilter(new AcceptOnceFileListFilter<File>());
return source;
}
#Bean
#ServiceActivator(inputChannel = "sftpChannel")
public MessageHandler handler() {
return new MessageHandler() {
#Override
public void handleMessage(Message<?> message) throws MessagingException {
System.out.println(message.getPayload());
}
};
}
}
Result:
16:57:59.697 [task-scheduler-1] WARN com.jcraft.jsch - Permanently added '10.0.0.3' (RSA) to the list of known hosts.
ftp-inbound/bar.txt
ftp-inbound/baz.txt
I am using springboot + jersey for web restful implementation. Now I am going to integrate swagger into our application. I did following.
#Configuration
#EnableSwagger2
public class JerseyConfiguration extends ResourceConfig {
public JerseyConfiguration(){
register(HelloworldAPI.class);
configureSwagger();
}
private void configureSwagger() {
BeanConfig beanConfig = new BeanConfig();
beanConfig.setVersion("1.0.2");
beanConfig.setSchemes(new String[]{"http"});
beanConfig.setHost("localhost:8080");
beanConfig.setBasePath("/");
beanConfig.setResourcePackage("com.cooltoo.api");
beanConfig.setPrettyPrint(true);
beanConfig.setScan(true);
}
}
I added following dependences on build.gradle:
compile('io.springfox:springfox-swagger2:'+springfoxSwaggerVersion)
compile('io.springfox:springfox-petstore:'+springfoxSwaggerVersion)
compile('io.springfox:springfox-swagger-ui:'+springfoxSwaggerVersion)
compile('io.swagger:swagger-jersey2-jaxrs:1.5.8')
I was able to launch the web application but I wander which url is for swagger? I tried with http://localhost:8080, http://localhost:8080/swagger, and http://localhost:8080/swagger-ui.html. But none of them could be accessed.
I think #EnableSwagger2 annotation and springfox dependencies would work if the endpoints are implemented using Spring MVC instead of a JAX-RS implementation.
I blogged about this a few months ago, Microservices using Spring Boot, Jersey Swagger and Docker
Basically if you need to document your Jersey-implemented endpoints, you would need to:
1)
Make sure your Spring Boot app scans for components located in specific packages (ie com.asimio.jerseyexample.config) via:
#SpringBootApplication(
scanBasePackages = {
"com.asimio.jerseyexample.config", "com.asimio.jerseyexample.rest"
}
)
2) Jersey configuration class implementation:
package com.asimio.jerseyexample.config;
...
#Component
public class JerseyConfig extends ResourceConfig {
#Value("${spring.jersey.application-path:/}")
private String apiPath;
public JerseyConfig() {
// Register endpoints, providers, ...
this.registerEndpoints();
}
#PostConstruct
public void init() {
// Register components where DI is needed
this.configureSwagger();
}
private void registerEndpoints() {
this.register(HelloResource.class);
// Access through /<Jersey's servlet path>/application.wadl
this.register(WadlResource.class);
}
private void configureSwagger() {
// Available at localhost:port/swagger.json
this.register(ApiListingResource.class);
this.register(SwaggerSerializers.class);
BeanConfig config = new BeanConfig();
config.setConfigId("springboot-jersey-swagger-docker-example");
config.setTitle("Spring Boot + Jersey + Swagger + Docker Example");
config.setVersion("v1");
config.setContact("Orlando L Otero");
config.setSchemes(new String[] { "http", "https" });
config.setBasePath(this.apiPath);
config.setResourcePackage("com.asimio.jerseyexample.rest.v1");
config.setPrettyPrint(true);
config.setScan(true);
}
}
3) Resource implementation using JAX-RS (Jersey) and Swagger annotations:
package com.asimio.jerseyexample.rest.v1;
...
#Component
#Path("/")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#Api(value = "Hello resource", produces = "application/json")
public class HelloResource {
private static final Logger LOGGER = LoggerFactory.getLogger(HelloResource.class);
#GET
#Path("v1/hello/{name}")
#ApiOperation(value = "Gets a hello resource. Version 1 - (version in URL)", response = Hello.class)
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Hello resource found"),
#ApiResponse(code = 404, message = "Hello resource not found")
})
public Response getHelloVersionInUrl(#ApiParam #PathParam("name") String name) {
LOGGER.info("getHelloVersionInUrl() v1");
return this.getHello(name, "Version 1 - passed in URL");
}
...
}
4) Make sure your app's Spring Boot configuration file makes a distinction between Spring MVC (for actuator endpoints) and Jersey (for resources) endpoints:
application.yml
...
# Spring MVC dispatcher servlet path. Needs to be different than Jersey's to enable/disable Actuator endpoints access (/info, /health, ...)
server.servlet-path: /
# Jersey dispatcher servlet
spring.jersey.application-path: /api
...
Maybe you use rather old version of springfox, but now (for version 2.4.0) it must be configured very different from your code, see http://springfox.github.io/springfox/docs/current/
For example, I have the following springfox configuration:
#Configuration
#EnableSwagger2
class SwaggerConfig {
#Bean
Docket rsApi() {
new Docket(DocumentationType.SWAGGER_12)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage('com.test.service'))
.paths(PathSelectors.any())
.build()
.pathMapping('/')
.useDefaultResponseMessages(false)
}
private ApiInfo apiInfo() {
new ApiInfoBuilder()
.title('Test API')
.description('Test API')
.version('0.0.10.SNAPSHOT')
.termsOfServiceUrl('')
.contact('Test company')
.license('Public')
.licenseUrl('http://example.com/')
.build()
}
}
I learn create Web Service soap from guide Producing a SOAP web service
When I have jar file and run main method everything is ok. I change to war file run by mvn spring-boot:run is the same.
But next i have a problem and I wont resolve it without use xml configuration (if I can) only annotation or java code
I found many similar issue but none was help
e.g
https://stackoverflow.com/questions/21115205/spring-boot-with-spring-ws-soap-endpoint-not-accessable
http://stackoverflow.com/questions/26873168/spring-boot-webservice-from-wsdl-not-working
Deploy war on wildFly 8.2 after that show wsdl but nothing else.
I change
#ComponentScan
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
to
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(
SpringApplicationBuilder application) {
return application.sources(WebServiceConfig.class);
}
}
and deploy in wildFly 8.2 after that show wsdl but when put request in SoapUI
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:gs="http://spring.io/guides/gs-producing-web-service">
<soapenv:Header/>
<soapenv:Body>
<gs:getCountryRequest>
<gs:name>Spain</gs:name>
</gs:getCountryRequest>
</soapenv:Body>
</soapenv:Envelope>
get
WARN [org.springframework.ws.server.EndpointNotFound] (default task-7) No endpoint mapping found `for [SaajSoapMessage {http://spring.io/guides/gs-producing-web-service}getCountryRequest]`
and clear page in soapUI
I search similar issue e.g Endpoint not accessable
changed
#Bean
public ServletRegistrationBean dispatcherServlet(
ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/ws/*");
}
to
#Bean
public MessageDispatcherServlet dispatcherServlet() {
return new MessageDispatcherServlet();
}
is the same, but when I use
#Bean
public MessageDispatcherServlet dispatcherServlet() {
return new MessageDispatcherServlet(getContext());
}
private WebApplicationContext getContext() {
AnnotationConfigWebApplicationContext context = new
AnnotationConfigWebApplicationContext();
context.setConfigLocation(Application.class.getName());
return context;
}
get
Caused by: java.lang.NoSuchMethodError: org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.applicationContext(Lorg/springframework/context/ApplicationContext;)Lorg/springframework/http/converter/json/Jackson2ObjectMapperBuilder;
whole error log and whole eclipse project
Thanks M. Deinum for reply it's really helpful.
First I tried use only Application class but I couldn't run server. Error in log Caused by: java.lang.ClassNotFoundException: org.xnio.SslClientAuthMode next I found solution with create two classes WebServiceConfig and Application.After changing server started , wsdl showed for me it was good change, therefore thank you again.
This issue is caused spring-boot bug GitHub, now I moving whole code from WebServiceConfig to Application and using the newest compile spring-boot. After that WS work good.In pom Paste current Application class maybe someone will have the same problem.
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(
SpringApplicationBuilder application) {
return application.sources(Application.class);
}
#Bean
public ServletRegistrationBean dispatcherServlet(
ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/ws/*");
}
#Bean(name = "countries")
public DefaultWsdl11Definition defaultWsdl11Definition(
XsdSchema countriesSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("CountriesPort");
wsdl11Definition.setLocationUri("/ws/");
wsdl11Definition
.setTargetNamespace("http://spring.io/guides/gs-producing-web-service");
wsdl11Definition.setSchema(countriesSchema);
return wsdl11Definition;
}
#Bean
public XsdSchema countriesSchema() {
return new SimpleXsdSchema(new ClassPathResource("countries.xsd"));
}
private WebApplicationContext getContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.setConfigLocation(Application.class.getName());
return context;
}
}