I'm developing a WebSocket server application using spring.
Class PlayerHandler
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.io.IOException;
/**
* Created by kris on 11.07.16.
*/
public class PlayerHandler extends TextWebSocketHandler{
public PlayerHandler(){}
#Override
#AuthorizationRequired
public void handleTextMessage(WebSocketSession session, TextMessage tm) throws IOException {
session.sendMessage(tm);
}
}
I want user to be authorized with every incoming request by token, so I created a Aspect UserAuthorization
package com.berrigan.axevor.authorization;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class UserAuthorization {
#Around("#annotation(com.berrigan.axevor.authorization.AuthorizationRequired)")
public void authorize(ProceedingJoinPoint jp) throws Throwable{
System.out.println("\n\n\n\n\Works\n\n\n\n\n\n");
jp.proceed();
}
}
I added the #AuthorizationRequired annotation, which indicates methods in which users are going to be authorized. Unfortunately method authorize never get called. I've added following code to my main class to check if the bean get created.
UserAuthorization ua = ctx.getBean(UserAuthorization.class); // ApplicationContext
if(au == null) System.out.println("is null")
But I don't get such log.
My spring config
#EnableAutoConfiguration
#Configuration
#EnableAspectJAutoProxy
#Import({com.berrigan.axevor.websocket.WebSocketConfig.class})
#ComponentScan(basePackages = {"com.berrigan.axevor"})
public class Config {}
Annotation code:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface AuthorizationRequired{}
#Configuration
#EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer{
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry){
registry.addHandler(playerHandler(), "/game").setAllowedOrigins("*");
}
#Bean
public WebSocketHandler playerHandler(){
return new PlayerHandler();
}
}
Solution found, corrupted pom.xml file. After regenerating it, everything works like a charm
Related
I'm just trying use Camel Reactive Stream together with Spring Boot Reactor using the following code
package com.manning.camel.reactive;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.reactive.streams.api.CamelReactiveStreamsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
/**
* A simple Camel route that triggers from a timer and calls a bean and prints to system out.
* <p/>
* Use <tt>#Component</tt> to make Camel auto-detect this route when starting.
*/
#RestController
public class MySpringBootRouter extends RouteBuilder {
#Autowired
private ProducerTemplate template;
#Autowired
private CamelReactiveStreamsService crss;
#GetMapping
public Mono<String> sayHi() {
template.asyncSendBody("direct:works", "Hi");
//return Mono.from(crss.fromStream("greet", String.class));
return Mono.from(crss.fromStream("greet", String.class));
}
#Override
public void configure() {
from("direct:works")
.log("Fired")
.to("reactive-streams:greet");
}
}
After run the code
java.lang.IllegalStateException: The stream has no active subscriptions
After a long time, solved the error, as can be noticed the Router Class logic was changed a little
#Slf4j
#Service
#AllArgsConstructor
public class MyService {
final CamelContext context;
#PostConstruct
public void consumerData() {
var rCamel = CamelReactiveStreams.get(context);
var numbers = rCamel.fromStream("numbers", Integer.class);
Flux.from(numbers).subscribe(e -> log.info("{}", e));
}
}
#Component
#NoArgsConstructor
public class MyRouter extends RouteBuilder {
// Injects the Subscriber
#Autowired MyService service;
#Override
public void configure() {
//onException(ReactiveStreamsNoActiveSubscriptionsException.class)
// .continued(true);
from("timer://reactiveApp?fixedRate=true&period=2s")
.transform(method(Random.class, "nextInt(100)"))
//.log("${body}");
.to("direct:message");
from("direct:message")
//.log("${body}")
.to("reactive-streams:numbers");
}
}
I wrote a spring boot project.
It has three files.
Appconfig.java
package config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
#Configuration
#EnableWebMvc
#ComponentScan
(basePackages = {"controller"})
public class AppConfig {
}
ServletInitilizer.java
package config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class ServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[0];
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{AppConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
HelloController.java
package controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
public class HelloController {
#RequestMapping("hi")
#ResponseBody
public String hi() {
return "Hello, world.";
}
}
When I try to run it, it has error "No mapping found for HTTP request with URI [/SpringC1_01/] in DispatcherServlet with name 'dispatcher'".
Is this because server didn't find the controller or other reason? Thx.
Yes. i suspect two issues in the code.
#SpringBootApplication annotation is missing in AppConfig.
#RestController annotation is missing in HelloController.
Most of all you are missing a couple of things here.
Main class which contains public static void main and this class should be annotated with #SpringBootApplication
HelloController should be annotated with #RestController
At method level it should definitely point to some HTTP method in your case perhaprs it is Get mapping, so add #GetMapping annotation arround the method.
Move RequestMapping annotation from method level and add it to HelloController class.
Here are three simple components of a WebSocket server, created on Spring
Spring boot app:
package test.andrew;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Websocket server configuration file:
package test.andrew;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
#Configuration
#EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new SocketTextHandler(), "/name");
}
}
And a Socket text handler class:
package test.andrew;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.io.IOException;
#Component
public class SocketTextHandler extends TextWebSocketHandler {
#Override
public void handleTextMessage(WebSocketSession session, TextMessage message)
throws InterruptedException, IOException {
session.sendMessage(new TextMessage("Pong"));
}
#Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
session.sendMessage(new TextMessage("Connection established"));
}
}
My problem is that the server doesn't work as it works, for example, when using plain old javax.websocket
I cannot establish a connection through the Smart Websocket Client Chrome extension and as a result, cannot proceed with sending a message to a wss.
I would be grateful for your help or advice!
I solved this problem by modifying WebSocketConfig Class to:
package test.andrew;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
#Configuration
#EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new SocketTextHandler(), "/name").setAllowedOrigins("*");
}
}
Please note that .setAllowedOrigins("*") method is called. after allow origins, we can call this web socket url through chrome extension.
If you are using spring security then permit this url in spring security configuration file.
My intention is run the aspect before get message method in service. I don't want to use xml configuration, so I add (hopefully) necessary annotation. But, when I run my application, aspect doesen't work, and nothing happen. Can You explain me why?
Service
public interface Service {
void getMessage();
}
Service implementation
import org.springframework.stereotype.Component;
#Service
public class ServiceImpl implements Service {
public void getMessage() {
System.out.println("Hello world");
}
}
Aspect
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class LoggingAspect {
#Before("execution(* com.example.aop.Service.getMessage())")
public void logBefore(JoinPoint joinPoint) {
System.out.println("AOP is working!!!");
}
}
Run
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#SpringBootApplication
#EnableAspectJAutoProxy(proxyTargetClass=true)
#ComponentScan("com.example")
public class AopApplication {
public static void main(String[] args) {
final ConfigurableApplicationContext run = SpringApplication.run(AopApplication.class, args);
final Service bean = run.getBean(ServiceImpl.class);
bean.getMessage();
}
}
Output
Only Hello world
Probably, you have to add #Component annotation to LoggingAspect class.
I believe the pointcut expression syntax should be like this:
#Before("execution(void com.aop.service.Service+.getMessage(..))")
The + is used to apply the pointcut to subtypes (you can replace void with * too.
I am learning spring the from book the "Spring in Action fourth edition" by Craig Walls. I am trying to apply advice to the method declared by the interface and I am getting Exception. When I apply the same advice to the class which doesn't implement anything, everything works fine.
Spring version - 4.3.2
Help would be appreciated.
Exception:
Exception in thread "main"org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.fifczan.bean.UserService] is defined
Code:
Interface:
package com.fifczan.bean;
public interface Service {
void doTask();
}
Implementation:
package com.fifczan.bean;
import org.springframework.stereotype.Component;
#Component
public class UserService implements Service {
public void doTask() {
System.out.println("doing task");
}
}
Aspect:
package com.fifczan;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class UserAspect {
//If i change Service(interface) to UserService(implementation)
//in pointcut I am getting the same exception
#Before("execution(* com.fifczan.bean.Service.doTask(..))")
public void userAdvice(){
System.out.println("doing sth before method doTask");
}
}
Configuration:
package com.fifczan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#Configuration
#EnableAspectJAutoProxy
#ComponentScan
public class AspectJAutoProxyConfig {
}
main :
package com.fifczan;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.fifczan.bean.UserService;
public class AspectJAutoProxyTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AspectJAutoProxyConfig.class);
UserService userService= ctx.getBean(UserService.class);
userService.doTask();
}
}
You're asking for a bean of UserService, which is the concrete class, not the interface. Retrieve or inject a bean of type Service.