spring read server name inside cors - java

I'm trying to allow cors from the same server, with port 3000.
As I don't know where my server is going to be deployed, I tried to access the server name as string than concat it with my desired port.
So here is my approach :
#SpringBootApplication
public class TestApplication {
#Autowired
private HttpServletRequest request;
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
#Bean
public WebMvcConfigurer corsConfigurer() {
System.out.println(request.getServerName());
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("/**")
.allowedOrigins(request.getServerName()+":3000");
}
};
}
}
I think these are the highlights of my error message :
Error creating bean with name 'corsConfigurer'
org.springframework.beans.BeanInstantiationException: Failed to instantiate
java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread?

A good practice is to specify the allowed origins in the application.properties file and read it in your WebConfig.class. That allows you to easy add your production address later.
application.yml
web:
allowedOrigins:
- "http://localhost:4200"
- "some other"
#Configuration
public class WebMvcConfig implements WebMvcConfigurer {
private final String[] allowedOrigins;
public WebMvcConfig(#Value("${web.allowedOrigins:}") String[] allowedOrigins) {
this.allowedOrigins = allowedOrigins;
}
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") //
.allowedMethods("*") //
.allowCredentials(true) //
.allowedOrigins(allowedOrigins);
}
}

just use localhost, no need to access server name

Related

spring websocket cannot establish connection

cannot establish connection to my websocket server by browser client.
configuration:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic/", "/queue/");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/greeting");
}
}
And controller:
#MessageMapping("/message")
#SendToUser("/queue/reply")
public String processMessageFromClient(#Payload String message, Principal principal) throws Exception {
String name = new Gson().fromJson(message, Map.class).get("name").toString();
System.out.println(name);
//messagingTemplate.convertAndSendToUser(principal.getName(), "/queue/reply", name);
return name;
}
I start server, and then open index.html in browser then make connect to ws://localhost:8080/greeting
and after that sending message to /app/message
but actually happens nothing. Browser inspector shows 404. What's wronng i do?
Here is the way that use to implement WebSocket in Spring. First, you should configure the Web socket message broker and register the stomp endpoint as below. Here I use setAllowedOrigins("*").withSockJS() to access this endpoint to any host.
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/greeting")
.setAllowedOrigins("*")
.withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app")
.enableSimpleBroker("/topic", "/queue/");
}
}
Then I create the controller as below.
#Controller
public class WebSocketController {
private final SimpMessagingTemplate template;
#Autowired
WebSocketController(SimpMessagingTemplate template){
this.template = template;
}
#MessageMapping("/queue/reply")
public void sendMessage(String message){
System.out.println(message);
this.template.convertAndSend("/topic", message);
}
}
Use #MessageMapping("/queue/reply") instead of #SendToUser("/queue/reply") as above.
From that Simple Messaging Template, I used convertAndSend() method to
asynchronous data communication with that message broker. If there is
any data comes to that message broker it will automatically send that
data using the above configured endpoint called /socket with SockJS
and Stomp.
You can refer this article to learn more about the Spring web socket.

Springboot Dynamically modify the ResourceHandlerRegistry mapping

I've a spring boot web application that can serve files from a static file location in server.
I've specified the location in properties file and using it to configure the ResourceHandlerRegistry.
#SpringBootApplication
public class MyWebApplication {
#Value("${targetdirectory}")
private String targetDirectory;
#Bean
WebMvcConfigurer configurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
targetDirectory = StringUtils.appendIfMissing(targetDirectory, "/", "/");
targetDirectory = StringUtils.prependIfMissing(targetDirectory, "file:/", "file:/");
registry.addResourceHandler("/resourcetarget/**").addResourceLocations(targetDirectory);
}
};
}
public static void main(String[] args) {
SpringApplication.run(MyWebApplication.class, args);
}
}
Everything works as expected. Now I have to dynamically set the resource location based on user input.
After the application is loaded, the user triggers an HTTP post request where he can specify the directory by which can be used as the resource location.
So after that any requests to the /resourcetarget/** should be mapped to the directory which the user specified. Following is the controller I have.
#RestController
#RequestMapping(value = "api/locations", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public class MyController {
#PostMapping
public ResponseEntity<Object> handleLocationSet(#RequestBody LocationDTO locationDto) {
String newFileLocation = locationDto.getLocation();
// How do I update the ResourceHandlerRegistry mapping for /resourcetarget/**
// with the new location received here?
return ResponseEntity.ok();
}
}
How can I update the mapping for this dynamic location for a static resource url. Please help

Spring boot application does not start when ActiveMQ failover transport fails

I want my Spring Boot application to start regardless if it can connect to JMS or not. I have this minimal example:
#SpringBootApplication
#EnableJms
public class JmsActivemqFailoverApplication {
public static void main(String[] args) {
SpringApplication.run(JmsActivemqFailoverApplication.class, args);
}
#Component
public static class JmsReceiver {
#JmsListener(destination = "inbox")
public void receive(Message message) {
System.out.println("Received <" + message + ">");
}
}
#RestController
public static class HelloWorldController {
#GetMapping("/")
public String helloWorld() {
return "Hello world";
}
}
}
when application.properties contains:
spring.activemq.broker-url=tcp://non-existing-broker:61616
I can get response from helloWorld endpoint. When I change property to:
spring.activemq.broker-url=failover:(tcp://non-existing-broker:61616)
Application keeps trying to connect to broker and I can not get response from my REST endpoint.
Please advice, how can I have application running without waiting for ActiveMQ Failover transport to succeed.
Example code available at https://github.com/madoxas/jms-activemq-failover
One way to achieve this is:
Disable automatic JMS container startup with property spring.jms.listener.auto-startup=false
Start JMS container after application has started:
#Component
public class JmsStarter implements ApplicationRunner {
private final JmsListenerEndpointRegistry jmsRegistry;
public JmsStarter(JmsListenerEndpointRegistry jmsRegistry) {
this.jmsRegistry = jmsRegistry;
}
#Override
public void run(ApplicationArguments args) {
for (MessageListenerContainer listenerContainer : jmsRegistry.getListenerContainers()) {
listenerContainer.start();
}
}
}

Launch spring WebSocket programmatically

After some time I got my WebSocket running with this config:
#Configuration
//#EnableWebSocket
public class WebSocketServerConfig implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(), "/var").setAllowedOrigins("*");
}
#Bean
public WebSocketHandler myHandler() {
return new WebsocketServer();
}
}
But I'm unable to find a way to launch this WebSocket from my code.
Is there a way to launch this WebSocket later in my program?
I found this document but it does not provide a way to implement a startWebSocket() function or something similar.
The document you linked shows an example, where it returns an instance of EchoWebSocketHandler.
You could accept connections and implement your own logic for afterConnectionEstablished or handleMessage using some internal status to determine whether you should accept requests, i.e.
#Configuration
#EnableWebSocket
public class MyConfiguration implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(echoWebSocketHandler(), "/echo").withSockJS();
}
#Bean
public WebSocketHandler echoWebSocketHandler() {
//FooWebSocketHandler implements your specific logic
return new FooWebSocketHandler();
}
}
public class FooWebSocketHandler extends AbstractWebSocketHandler {
private boolean enabled;
...
public void handleMessage(WebSocketSession session,
WebSocketMessage<?> message)
throws Exception {
if (enabled) {//work
} else {
//disabled, i.e. throw exception or send data according to your api
}
}
}

Aspect does not get triggered in the context of listening for a RabbitMQ message

The FailedMessageAspect.afterMethod() below gets called successfully during RabbitConsumerMain.main() below. However, it doesn't get called when it's used in the context of listening for a RabbitMQ message - when MessageHandlerImpl.handleMesasge() receives a message from a RabbitMQ queue. Any idea why?
FailedMessageAspect.java
#Aspect
#Component
public class FailedMessageAspect {
#AfterReturning("execution(* com..MessageHandlerImpl.testAspect(..))")
private void afterMethod() {
System.out.println("aspect foo");
}
}
MessageHandlerImpl.java
#Component
public class MessageHandlerImpl implements MessageHandler {
#Override
public void testAspect() {
System.out.println("handler foo");
}
#Override
public void handleMessage(String message) {
// handleMessage is called successfully when message is received
testAspect();
// FailedMessageAspect.afterMethod() does not get called
}
}
RabbitConsumerMain.java
#Controller
#SpringBootApplication
public class RabbitConsumerMain implements CommandLineRunner {
#Autowired
private MessageHandler messageHandler;
public static void main(String[] args) throws Exception {
SpringApplication.run(RabbitConsumerMain.class, args);
}
#Override
public void run(String... args) {
messageHandler.testAspect();
//FailedMessageSpect.afterMethod() gets called right here
}
}
ConsumerConfiguration.java
#Configuration
public class ConsumerConfiguration {
#Autowired #Lazy
private MessageHandler messageHandler;
//other standard AMQP configs
#Bean
public MessageListenerContainer messageListenerContainer() {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory());
container.setQueues(workQueue());
MessageListenerAdapter adapter = new MessageListenerAdapter(messageHandler, new Jackson2JsonMessageConverter());
container.setMessageListener(adapter);
return container;
}
}
You don't show all your configuration but, just to be clear, Spring AOP does not advise internal method calls such as handleMessage calling testAspect() within the same class instance.
You need to use AspectJ for that; otherwise, all methods you advise must be public methods invoked via bean definitions, so Spring can invoke the method via a proxy. Internal calls within a bean are never advised.
See the reference manual for a complete explanation.

Categories

Resources