How do I Combine REST and Websocket in Spring Boot? - spring

Where to put these blocks of code for websocket configuration in spring boot REST API? In a REST contoller?
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfiguration extends AbstractWebSocketMessageBrokerConfigurer{
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/socket")
.setAllowedOrigins("*")
.withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app")
.enableSimpleBroker("/chat");
}
}

It should remain in separate class which is under package that spring scanning, its a configuration class

This is not a controller, it is a configuration file, and it has to go with the configuration files. Along with filter configurations, security, servlet configurations...in short, where are the #Configuration, package *.*.configuration

Related

Why do I need the #Configuration annotation when using WebSocketMessageBrokerConfigurer?

I'm trying to learn websocket and follow the guide. It advises starting with:
#Configuration
#EnableWebSocketMessageBroker
public class MyConfiguration implements WebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/portfolio").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableStompBrokerRelay("/queue/", "/topic/");
registry.setApplicationDestinationPrefixes("/app/");
}
}
And I don't really understand the meaning of the annotation #Configuration.
As I understand it, the container finds information about the Bean in it, but if only #override is used in this class, then what does it do in this case?
#Configuration
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html
Indicates that a class declares one or more #Bean methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime...
#EnableWebSocketMessageBroker
Add this annotation to an #Configuration class to enable broker-backed messaging over WebSocket using a higher-level messaging sub-protocol...
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/socket/config/annotation/EnableWebSocketMessageBroker.html
That mean without #Configuration, #EnableWebSocketMessageBroker will be ignored by spring container. So WebSocket will not be enabled.

Make websocket (sockjs) work with spring4 running at GlassFish 3.1.2.2

I try to create websocket connection using sockjs on client and spring4 (with java config) on backend under GlassFish 3.1.2.2 but whatever I do it always fail with the following problem:
java.lang.IllegalArgumentException: Async support must be enabled on a servlet and for all filters involved in async request processing. This is done in Java code using the Servlet API or by adding "<async-supported>true</async-supported>" to servlet and filter declarations in web.xml. Also you must use a Servlet 3.0+ container
However it works correctly under Tomcat without any error.
Is there a way to make this work under GlassFish 3.1.2.2? Or should I rewrite Spring java config back to web.xml style? If yes, can somebody show me an example?
Thank you.
I already enabled websocket in http protocol configuration in GlassFish manager and set
dynamic.setAsyncSupported(true);
in the WebApplicationInitializer.
#Configuration
public class WebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(final ServletContext servletContext) throws ServletException {
final AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(IdCardReaderWebsocketApp.class);
ctx.setServletContext(servletContext);
final Dynamic dynamic = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
dynamic.setLoadOnStartup(2);
dynamic.addMapping("/sockjs/*");
dynamic.setAsyncSupported(true);
}
}
#Configuration
#ComponentScan("com.something.websocket.idcardreader.mock")
#EnableWebMvc
#Import({ IdCardReaderWebsocketConfig.class })
public class IdCardReaderWebsocketApp extends WebMvcConfigurerAdapter {
}
#Configuration
#EnableWebSocketMessageBroker
public class IdCardReaderWebsocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(final StompEndpointRegistry registry) {
registry.addEndpoint("/idCardReaderWebsocketMockEndpoint").setAllowedOrigins("*").withSockJS();
}
#Override
public void configureMessageBroker(final MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/mockApp");
registry.enableSimpleBroker("/idcard");
}
}
Ok, finally I fixed the issue. I had also web.xml file with an other filter. So I added
<async-supported>true</async-supported>
to that filter and problem solved. It still failes with ws:// protocol but at least it works with http when sockjs trying.

Spring boot 2.0 with swagger ui not working properly

I am trying to integrate Spring Boot 2.0 with swagger but not showing up end points.When I looked to developer console on network tab ,it says that I couldn't find "http://localhost:8080/swagger-resources/configuration/ui" and return 404.
We solved this problem by adding resource handler for swagger:
Example:
#Configuration
public class MvcConfiguration extends WebMvcConfigurationSupport {
#Value("${spring.application.name}")
private String applicationName;
//...irrelevant code here
#Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
If you have #EnableWebMvc or #WebMvcConfigurationSupport annotation anywhere in the project then remove these or add custom resource handlers to configure swagger-ui.
Here's some common solutions:
https://github.com/springfox/springfox/issues/2396#issuecomment-402150402

SpringBoot HandlerInterceptor not intercepting library endpoint

I have a SpringBoot app where I have implemented a HandlerInterceptor to log general information about API usage. I want it to also log requests to Spring Security's OAuth2 endpoint but it does not intercept the request.
#Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
// register the interceptor that will write API usage info to a file
registry.addInterceptor(new ServiceUsageInterceptor());
}
How can I configure the HandlerInterceptor to intercept all requests?
Thanks
This turned out to be unrelated to the interceptor. The usage was being written to a log file using a custom AccessLogValve in the embedded Tomcat. Updating the pattern seemed to resolve the issue.
#Override
public void customize(ConfigurableEmbeddedServletContainer container) {
TomcatEmbeddedServletContainerFactory factory = (TomcatEmbeddedServletContainerFactory) container;
CustomAccessLogValve accessLogValve = new CustomAccessLogValve();
accessLogValve.setEnabled(true);
// set pattern
accessLogValve.setPattern("timestamp=\"%t\" local_host=\"%v\" status=\"%s\" remote_host=\"%h\" client_id=\"%q\" uri=\"%r\" execution_time=\"%D\"");
factory.addContextValves(accessLogValve);
}
}

Spring Boot WebSockets unable to find the current user (principal)

After signing-in, the websockets cannot find the current user by session.getPrincipal() (it returns null).
Here is the Java code for WebSockets:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfiguration extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/queue", "/topic");
config.setApplicationDestinationPrefixes("/socket");
config.setUserDestinationPrefix("/user");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/app").withSockJS();
}
}
It seems like a Spring Boot bug - I am using 1.3.8 RELEASE. After refreshing the page, it gets the logged-in user properly.
And here is the front-end (subscription)
ngstomp.subscribeTo('/user/queue/message')
.callback(function(response) {
console.log('Test');
})
.withBodyInJson()
.connect();
I tried this solution: https://www.javacodegeeks.com/2014/11/spring-boot-based-websocket-application-and-capturing-http-session-id.html
But it's not working.
Please help me!
Why you required to have session.getPricncipal(). Spring provides Principal object to be injected automatically in your controller as following.
#MessageMapping("/message")
public String processMessageFromClient(#Payload String message, Principal principal) throws Exception {
messagingTemplate.convertAndSendToUser(principal.getName(), "/queue/reply", name);
return name;
}
Reference: Spring Boot Websocket Example

Resources