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();
}
Related
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.
when i click button client side date format is working fine but server side date format is different
how to solve this problem?
[HttpPost]
public ActionResult CheckAvailabilityValue(MainModel check)
{
try
{
Get_Location();
//if (ModelState.IsValid)
//{
locationInformation checking = new locationInformation();
bool suc = checking.CheckAvailability(check);
if (suc == false)
{
return Json(new { success = true, message = "Checked successfully" }, JsonRequestBehavior.AllowGet);
}
else if (suc == true)
{
return Json(new { False = true, message = "Checked successfully" }, JsonRequestBehavior.AllowGet);
}
//}
}
catch
{
return View();
}
return View();
}
MainModel Class:
public class CheckingDetails
{
[Key]
public int BookingID { get; set; }
public int LocationID { get; set; }
public int FacilityID { get; set; }
public int VenueID { get; set; }
public int CapacityID { get; set; }
public DateTime BookedFromDate { get; set; }
public DateTime BookedToDate { get; set; }
public string FromTime { get; set; }
public string ToTime { get; set; }
}
Below i attached screen shot
public bool CheckAvailability(MainModel check)
{
bool flag = false;
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["venue"].ConnectionString))
{
SqlCommand cmd = new SqlCommand("spCheckAvailability", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#BookedFromDate", Convert.ToDateTime(check.CheckMasters.BookedFromDate));
cmd.Parameters.AddWithValue("#BookedToDate", Convert.ToDateTime(check.CheckMasters.BookedToDate));
cmd.Parameters.AddWithValue("#FromTime", check.CheckMasters.FromTime);
cmd.Parameters.AddWithValue("#ToTime", check.CheckMasters.ToTime);
con.Open();
flag = Convert.ToBoolean(cmd.ExecuteScalar());
return flag;
}
}
I have some angular code that asks for user name input:
playCtrl.js
var myApp = angular.module('myApp');
/*
* CONTROLLERS METHOD
*/
myApp.controller('PlayController', ['$scope', '$http', function($scope, $http) {
var REQUEST_SERVICE_URI = '/Project2/play.do';
//var REQUEST_SERVICE_URI = 'http://13.59.197.145:8085/Project2/#/play';
var playerObject = {} // create playerObject
$scope.message = "Let's play!";
$scope.message2 = "Please enter your name";
$scope.user = {
userid: '',
username: '',
roleId: '',
statusId: ''
};
$scope.register = function() {
playerObject = $scope.user; // adding user to a playerObject
console.log('playerObject.name: ' + playerObject.name);
//console.log('playerObject: ' + $scope.user.name);
console.log("REGISTER BUTTON WAS CLICKED");
$http.post(REQUEST_SERVICE_URI, playerObject).
then(function(playerObject) {
alert("SUCCESS");
//$scope.user = data;
});
}
}])
Then I have my SpringController.java that's trying to get this user object:
#RestController
public class SpringController {
// has to accept
#RequestMapping(headers="Accept=application/json", value="/play.do", method = RequestMethod.POST)
public String registerUser(Users user, BindingResult bindingResult, ModelMap modelMap, HttpSession session){
Register r = new Register();
System.out.println("TRYING TO CREATE A USER: " + user);
if(r.createUser(user.getUsername())){
session.setAttribute("username", user.getUsername());
session.setAttribute("role", user.getRole());
session.setAttribute("status", user.getStatus());
System.out.println("Created user: " + user.getUsername());
return "lobby";
}else{
return "login";
}
}
My console DOES print out everything in the angularjs perfectly fine, and it also prints "TRYING TO CREATE A USER: " + user from the java side, however it shoes that all everything is null: TRYING TO CREATE A USER: Users [userid=0, username=null, roleId=null, statusId=null]
(my user create implementation only needs a username, all others can be null)
Here's my web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/beans.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>SpringDispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/beans.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringDispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
Here's the error I get from the console:
javax.validation.ConstraintViolationException: Validation failed for classes
[com.revature.bean.Users] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
ConstraintViolationImpl{interpolatedMessage='Username cannot be empty(1-20 characters)', propertyPath=username, rootBeanClass=class com.revature.bean.Users, messageTemplate='Username cannot be empty(1-20 characters)'}
Users.java :
package com.revature.bean;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.validation.constraints.Size;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.stereotype.Component;
#Component
#Entity
#Table(name = "Users")
#Cache(usage = CacheConcurrencyStrategy.READ_ONLY, region = "myAwesomeCache")
public class Users {
#Id
#Column(name = "U_Id")
#SequenceGenerator(name = "UID_SEQ", sequenceName = "UID_SEQ")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "UID_SEQ")
private int userid;
#NotEmpty(message="Username cannot be empty(1-20 characters)")
#Size(min=1,max=20)
#Column(name = "Username")
private String username;
public Users() {
super();
}
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "Role_ID")
private Roles role;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "Status_ID")
private Status status;
public Users(int userid, String username, Roles roleId, Status statusId) {
super();
this.userid = userid;
this.username = username;
this.role = roleId;
this.status = statusId;
}
public Users(String username, Roles roleId, Status statusId) {
super();
this.username = username;
this.role = roleId;
this.status = statusId;
}
public int getUserid() {
return userid;
}
public void setUserid(int userid) {
this.userid = userid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Status getStatusId() {
return status;
}
public void setStatusId(Status status) {
this.status = status;
}
public Roles getRole() {
return role;
}
public void setRole(Roles role) {
this.role = role;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
#Override
public String toString() {
return "Users [userid=" + userid + ", username=" + username + ", roleId=" + role + ", statusId=" + status
+ "]";
}
}
How would I go about sending the object properly?
I just figured it out: I had to add #RequestBody within the () of my SpringController method, and change the input from Object to String type:
public String registerUser(#RequestBody String username, BindingResult bindingResult, ModelMap modelMap, HttpSession session)
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.