I'm following this tutorial to understand how webSocket works in Spring.
My controller class:
#Controller
public class TestController {
#MessageMapping("/chat")
#SendTo("/topic/messages")
public String greeting(String message) {
System.out.println("HelloWorld"); // <--- The code is executed
return "HelloWorld";
}
}
My WebSocket class:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat").setAllowedOriginPatterns("*").withSockJS();
}
}
My js client:
export function connect() {
var socket = new SockJS("http://192.168.1.63:5001/chat");
stompClient = Stomp.over(socket);
//stompClient.debug = null;
stompClient.connect({}, (frame) => {
console.log(frame);
stompClient.subscribe("/topic/messages", messageOutput => {
console.log(messageOutput); // <-- Nothing here!
});
});
}
export function disconnect() {
if (stompClient != null) {
stompClient.disconnect();
}
console.log("Disconnected");
}
export function sendMessage() {
stompClient.send(
"/app/chat",
{},
"this is only a test!"
);
}
what happens in Chrome Inspector: Chrome Inspector
So, it seems as the server side doesn't replay at client though the "greeting" method is invoked.
Related
I have to calls in my component. The secound depends on the result from the first call.At the first call, I set the value for my component variable "locked". The secound call should be executed when the result is true --> locked = true. But it will reach the code, before the first call is finished and the value is set. How can I wait with the execution of my code, until the call "getByUsernamer" is finished.
Here is my code:
export class LoginComponent implements OnInit {
errorMessage: string = "";
isLocked = false;
username: string | null = "";
constructor(
private authService: AuthService,
private cookieService: CookieService,
private router: Router,
private jwtTokenService: JwtTokenService,
private userService: UserService) {
}
ngOnInit(): void {
}
test() {
this.userService.getUserByUsername(this.username)?.subscribe(
{
next: response => {
let user: User = response;
this.isLocked = user.locked
}
}
);
if (!this.isLocked) {
this.router.navigate(['/home']).finally(
() => this.userService.setLastLogin(this.username).subscribe());
} else {
this.errorMessage = "The user is locked."
}
}
}
You can check the isLocked variable in the callback of the first call, so you are sure that you received the answer and the isLocked variable is set
export class LoginComponent implements OnInit {
errorMessage: string = "";
isLocked = false;
username: string | null = "";
constructor(
private authService: AuthService,
private cookieService: CookieService,
private router: Router,
private jwtTokenService: JwtTokenService,
private userService: UserService) {
}
ngOnInit(): void {
}
test() {
this.userService.getUserByUsername(this.username)?.subscribe(
{
next: response => {
let user: User = response;
this.isLocked = user.locked;
// Moved here the test so it happens only after
// the first request receive the answer
if (!this.isLocked) {
this.router.navigate(['/home']).finally(() => this.userService.setLastLogin(this.username).subscribe());
} else {
this.errorMessage = "The user is locked."
}
}
}
);
}
}
I have a small web app built using Spring, and the REST services are accessible from curl and postman. If I try to access them using the JavaScript hosted on my web app I get a 405 error. What could cause this?
I realize there are insecurities in the code, this is just a rushed class project so they are not important.
If I copy the JavaScript code and run it in the console of the browser it works.
User class
import org.springframework.data.annotation.Id;
public class User {
#Id
public String id;
private String username;
private String firstName;
private String lastName;
private String password;
private int zipCode;
private int jacketThreshold;
private int coatThreshold;
public User() {}
public User(String username)
{
this.username = username;
}
public User(String firstName, String lastName, String password) {
this.firstName = firstName;
this.lastName = lastName;
this.password = password;
}
public User(String username, String password, int zipCode) {
this.username = username;
this.password = password;
this.zipCode = zipCode;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getZipCode() {
return zipCode;
}
public void setZipCode(int zipCode) {
this.zipCode = zipCode;
}
public int getJacketThreshold() {
return jacketThreshold;
}
public void setJacketThreshold(int jacketThreshold) {
this.jacketThreshold = jacketThreshold;
}
public int getCoatThreshold() {
return coatThreshold;
}
public void setCoatThreshold(int coatThreshold) {
this.coatThreshold = coatThreshold;
}
#Override
public String toString() {
return String.format(
"User[id=%s, firstName='%s', lastName='%s']",
id, firstName, lastName);
}
}
UserController class
import org.springframework.web.bind.annotation.*;
#RestController
public class UserController {
private final UserRepository repository;
public UserController(UserRepository repository) {
this.repository = repository;
}
#CrossOrigin
#PostMapping("/newuser")
User newUser(#RequestBody User newUser)
{
return repository.save(newUser);
}
}
UserRepository
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
#RepositoryRestResource(collectionResourceRel = "users", path = "users")
public interface UserRepository extends MongoRepository<User, String> {
public User findByUsername(#Param("username") String username);
}
Application class
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class WtwApplication {
public static void main(String[] args) {
SpringApplication.run(WtwApplication.class, args);
}
}
JavaScript calling the REST service
var user = document.getElementById('uname');
var pass = document.getElementById('pass');
var zip = document.getElementById('zip');
const data = { username : user, password : pass};
fetch('http://localhost:8080/newuser', {
method: 'POST', // or 'PUT'
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data),
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
});
Error received
2020-12-04 22:52:34.071 WARN 17936 --- [nio-8080-exec-7] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported]
Cross origin must include your js hosted server address like
Ex - #CrossOrigin(origins="http://localhost:3000)
and add it after the #RestController
Check your js code.
If you look at your controller, it's declared #PostMapping. Make sure your js code is calling the same POST method.
Check if you are returning a #ResponseBody or a #ResponseStatus
To fix this simply add a #ResponseBody
#RequestMapping(value="/user", method = RequestMethod.POST)
public #ResponseBody String updateUser(#RequestBody User user){
return userService.updateUser(user).getId();
}
or a #ResponseStatus to your method.
#RequestMapping(value="/user", method = RequestMethod.POST)
#ResponseStatus(value=HttpStatus.OK)
public String updateUser(#RequestBody User user){
return userService.updateUser(user).getId();
}
Service get json-data from backend:
constructor(private http: Http) { };
getUsers(): Observable<any> {
return this.http.get('http://127.0.0.1:8000/app_todo2/users_list');
};
In the component, this data is processed:
ngOnInit() {
this.getAllUsersData();
}
private getAllUsersData(): void {
this.usersService.getUsers().subscribe(
data => {
this.allUsersData = JSON.parse(data.json());
console.log(this.allUsersData);
})
};
But i need processed this data in service. And i need get in component clear data:
private getAllUsersData(): void {
this.usersService.getUsers().subscribe(
data => {
this.allUsersData = data;
console.log(this.allUsersData);
})
};
please help me.
Map your data on service:
getUsers(): Observable<any> {
return this.http.get('http://127.0.0.1:8000/app_todo2/users_list')
.map(data => data.json());
}
then:
private getAllUsersData(): void {
this.usersService.getUsers().subscribe(
data => {
this.allUsersData = data;
console.log(this.allUsersData);
})
};
I have a simple MVC Get method as below to get a Customer Id from the Session
[HttpGet]
public string GetCustomerId()
{
return Session["CUSTOMERID"].ToString();
}
If I hit this URL directly in the browser
http://localhost/myApp/Home/GetCustomerId I can set a breakpoint int the method and it gets hit and I get the value returned.
However, I need to call the method from my Client code which is Angular 2 written in typescript. My Typescript method is as below - I cannot get it to hit the MVC Breakpoint even though I am logging the exact same URL as above to the console.
public getCustomerIdFromSession() {
console.log('get customer from session called');
let srv = this.environmentService.getCurrentEnvironment();
let httpOrHttps = '';
if (srv === AppSettings.ENV_LOCALHOST) {
httpOrHttps = AppSettings.URL_HTTP;
}
else {
httpOrHttps = AppSettings.URL_HTTPS;
}
let baseUrl = httpOrHttps + srv + AppSettings.URL_GET_CUST_FROM_SESSION;
console.log(baseUrl); //this logs - http://localhost/myApp/Home/GetCustomerId
return this.http.get(baseUrl)
.catch(this.handleError);
}
public handleError(error: Response) {
console.log("error");
return Observable.throw(error.json() || 'Server Error');
}
**UPDATE To include entire Typescript service
import { Injectable, Output, EventEmitter } from '#angular/core';
import { Http, Response, RequestOptions, Headers } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import { EnvironmentService } from '../common/environment.service';
import { AppSettings } from '../common/app-settings';
#Injectable()
export class SessionService {
#Output() public gSession: EventEmitter<any> = new EventEmitter();
private sessionTime: number = 1500000; // 25 minute
constructor(private http: Http, private environmentService: EnvironmentService) {
}
public setValue(isLoading: boolean): void {
this.gSession.emit(isLoading);
}
public getValue(): any {
return this.gSession;
}
public startSession(): void {
this.getCustomerIdFromSession();
let timeoutId = setTimeout(() => {
this.setValue(true);
}, this.sessionTime);
}
public getCustomerIdFromSession() {
console.log('get customer from session called');
let srv = this.environmentService.getCurrentEnvironment();
let httpOrHttps = '';
if (srv === AppSettings.ENV_LOCALHOST) {
httpOrHttps = AppSettings.URL_HTTP;
}
else {
httpOrHttps = AppSettings.URL_HTTPS;
}
let baseUrl = httpOrHttps + srv + AppSettings.URL_GET_CUST_FROM_SESSION;
console.log(baseUrl); //this logs - http://localhost/myApp/Home/GetCustomerId
return this.http.get(baseUrl)
.catch(this.handleError);
}
public handleError(error: Response) {
console.log("error");
return Observable.throw(error.json() || 'Server Error');
}
public extractData(res: Response) {
console.log("In extract method");
let body = res.json();
console.log(body);
if (body) {
return body.data || body;
} else {
return {};
}
}
}
You are not mapping the response.
return this.http
.get(baseUrl)
.map(this.extractData)
.catch(this.handleError);
private extractData(res: Response) {
let body = res.json();
if (body) {
return body.data || body;
} else {
return {};
}
}
You have to map the response and process it with json() if you know that will be a JSON or with text(). Usually will be JSON.
I took the liberty of adding a response handler such as extractData. You could just json() the response directly if you wanted.
I am building a chat app. I have a client (Ionic 2) talking to a server (Java). The client can receive messages successfully from the server (e.g. "Welcome to the chat!" is received when connecting), but when I try send a message to the server from the client, it does not get there (the DataListener<Message> is not being invoked on the "chat_message:send" event.).
Please any suggestions?
Server Code:
import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.Configuration;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.listener.ConnectListener;
import com.corundumstudio.socketio.listener.DataListener;
import com.corundumstudio.socketio.listener.DisconnectListener;
public class Server {
public static void main(String[] args) {
Configuration config = new Configuration();
config.setHostname("localhost");
config.setPort(3700);
final SocketIOServer server = new SocketIOServer(config);
server.addConnectListener(new ConnectListener() {
#Override
public void onConnect(SocketIOClient client) {
System.out.println("onConnected");
client.sendEvent("chat_message:message", new Message("Welcome to the chat!"));
}
});
server.addDisconnectListener(new DisconnectListener() {
#Override
public void onDisconnect(SocketIOClient client) {
System.out.println("onDisconnected");
}
});
server.addEventListener("chat_message:send", Message.class, new DataListener<Message>() {
#Override
public void onData(SocketIOClient client, Message data, AckRequest ackSender) throws Exception {
System.out.println("onSend: " + data.toString());
server.getBroadcastOperations().sendEvent("chat_message:message", data);
}
});
System.out.println("Starting server...");
server.start();
System.out.println("Server started");
}
}
and
public class Message {
private String message;
public Message(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
Client Code:
import { Component, NgZone } from '#angular/core';
import { Http } from "#angular/http";
import { MessageModel } from '../model/messageModel';
import { UtilityService } from '../utils/utilityService';
declare var io;
#Component({
templateUrl: 'build/pages/chat/chat.html',
providers: [UtilityService]
})
export class ChatPage {
private socketHost: string = "http://localhost:3700";
private messages: MessageModel[] = [];
private zone: NgZone = null;
private chatBox: string = null;
private socket: any = null;
private utilityService: UtilityService = null;
constructor(http: Http, utilityService: UtilityService) {
this.utilityService = utilityService;
this.setUpMessageService(http);
}
setUpMessageService(http: Http): void {
this.messages = [];
this.zone = new NgZone({ enableLongStackTrace: false });
let url = this.socketHost + "/fetch";
http.get(url).subscribe((success) => {
var data = success.json();
console.log(data);
for (var i = 0; i < data.length; i++) {
this.messages.push(data[i].message);
}
}, (error) => {
console.log(JSON.stringify(error));
});
this.chatBox = "";
this.socket = io(this.socketHost);
this.socket.on("chat_message:message", (messageModel: MessageModel) => {
this.zone.run(() => {
console.log('run: ' + messageModel);
this.messages.push(messageModel);
});
});
}
send(msg) {
if (msg && msg != "") {
let messageModel: MessageModel = new MessageModel();
messageModel.message = msg;
console.log(messageModel);
this.socket.emit("chat_message:send", messageModel);
}
this.chatBox = "";
}
}
and
import { Injectable } from "#angular/core";
#Injectable()
export class MessageModel {
public message: string = null;
}
If I send the message as a String and not a MessageModel from the client it works.