AngularJs form post data giving null values in my spring controller - javascript

Hello all i am trying to post a form using angular but i am getting null values in my spring controller.Also in my console i see null values for the sysout.Moreover i get an error alert even though i see bull is printed on my console.
My JS Controller
angular.module('ngMailChimp', ['ngAria', 'ngMessages', 'ngAnimate'])
.controller('SignUpController', function ($scope, $http) {
$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded; charset=utf-8";
var ctrl = this,
newCustomer = { firstName:'',lastName:'',email:'',streetName:'',aptName:'',cityName:'',stateName:'',countryName:'', zipName:'', userName:'',password:'' };
var signup = function () {
if( ctrl.signupForm.$valid) {
ctrl.showSubmittedPrompt = true;
var formData = {
'firstName' : $scope.ctrl.newCustomer.firstName,
'lastName' : $scope.ctrl.newCustomer.lastName,
'email' : $scope.ctrl.newCustomer.email,
'streetName' : $scope.ctrl.newCustomer.streetName,
'aptName' : $scope.ctrl.newCustomer.aptName,
'cityName' : $scope.ctrl.newCustomer.cityName,
'stateName' : $scope.ctrl.newCustomer.stateName,
'countryName' : $scope.ctrl.newCustomer.countryName,
'zipName' : $scope.ctrl.newCustomer.zipName,
'userName' : $scope.ctrl.newCustomer.userName,
'password' : $scope.ctrl.newCustomer.password
};
var response = $http.post('http://localhost:8080/Weber/user/save', JSON.stringify(formData));
response.success(function(data, status, headers, config) {
$scope.list.push(data);
});
response.error(function(data, status, headers, config) {
alert( "Exception details: " + JSON.stringify({data: data}));
});
}
};
My Spring controller
#RestController
#RequestMapping(value = "/user")
public class UserRegistrationControllerImpl implements UserRegistrationController {
#Autowired
UserRegistrationDao userDao;
#RequestMapping(value = "/save", method = RequestMethod.POST)
public String saveUser(UserRegistration userReg) {
System.out.println(userReg.getFirstName()+" "+userReg.getLastName());
userDao.registerUser(userReg);
return "success";
}
Please help me out
Thank you
mark.

There is no mapper specified for converting JSON to Java object.
Use Jackson(dore, databind, annotations) if you want the JSON to be converted to object of UserRegistration.
Check this out: Convert nested java objects to Jackson JSON
Need to add below in dispatcher-servlet. This is for mapping the JSON to Java objects:
<beans:bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<beans:property name="messageConverters">
<beans:list>
<beans:ref bean="jsonMessageConverter" />
</beans:list>
</beans:property>
</beans:bean>
<!-- Configure bean to convert JSON to POJO and vice versa -->
<beans:bean id="jsonMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
</beans:bean>
EDIT 1:
Is the method in controller something like this?
#RequestMapping(value = "/save", method = RequestMethod.POST, headers = "Accept=application/json")
public String saveUser(#RequestBody UserRegistration userReg) {
System.out.println(userReg.getFirstName()+" "+userReg.getLastName());
userDao.registerUser(userReg);
return "success";
}
Use above if you are not responding back to the webpage with a result to be consumed. If you want something to be returned from this method and displayed in the webpage or consumed elsewhere, the declaration of method would change to:
public #ResponseBody String saveUser(#RequestBody UserRegistration userReg)
EDIT 2:
$scope.post = function() {
$scope.data = null;
$http({
method : 'POST',
url : 'save',
params : {
firstName : $scope.ctrl.newCustomer.firstName,
lastName : $scope.ctrl.newCustomer.lastName,
email : $scope.ctrl.newCustomer.email,
streetName : $scope.ctrl.newCustomer.streetName,
aptName : $scope.ctrl.newCustomer.aptName,
cityName : $scope.ctrl.newCustomer.cityName,
stateName : $scope.ctrl.newCustomer.stateName,
countryName : $scope.ctrl.newCustomer.countryName,
zipName : $scope.ctrl.newCustomer.zipName,
userName : $scope.ctrl.newCustomer.userName,
password : $scope.ctrl.newCustomer.password
}
}).success(function(data, status, headers, config) {
$scope.list.push(data);
}).error(function(data, status, headers, config) {
alert("Exception");
});
};

Try add #RequestBody in the method arguments:
#RequestMapping(value = "/save", method = RequestMethod.POST)
public String saveUser(#RequestBody UserRegistration userReg) {
System.out.println(userReg.getFirstName()+" "+userReg.getLastName());
userDao.registerUser(userReg);
return "success";
}

Related

AngularJs $http.get: Sending array of objects as params

I am having issues with finding the correct way to send an array of objects to my API using AngularJS.
FrontEnd Code
function getPrices(articles) {
return $http.get('http://someurl/api/prices/getprices', { params: { articles: articles } }).then(function (res) {
// do something with prices
}, function (err) {
// handle error
});
}
Articles are of the type
var oneArticle = {
code: 'someCode',
quantity: 1,
stockUnit: 'piece'
}
Api code
[VersionedRoute("getprices")]
[HttpGet]
public IHttpActionResult GetPrices([FromUri]List<Article> articles) {
// do something with input
}
Article class
public class Article {
public string Code {get;set;}
public int Quantity {get;set;}
public string StockUnit {get;set;}
}
Some questions:
1) Why do I not receive any data on my API. Articles is always null
2) Is this the right approach?
Thanks
EDIT 1:
Using a post option I receive following data in my request but I still don't know how to handle it on the API.
I finally got it working.
#Tomo: Thanks for the effort
#Naimad: My apologies, you were right from the beginning.
Here is the working solution:
Frontend:
function getPrices(articles) {
return $http.get('http://someurl/api/prices/getprices', articles).then(function (res) {
// do something with prices
}, function (err) {
// handle error
});
}
Backend
[VersionedRoute("getprices")]
[HttpPost]
public IHttpActionResult GetPrices([FromBody]List<Article> articles) {
// do something with code
}
.controller('LoginController', ['$scope', '$http', function ($scope, $http) {
function getPrices(articles) {
$http.get('http://someurl/api/prices/getprices')
.success(function (data) {
articles: data
}
}
}])
Have u tried
return $http({
url: '/api/SomeCtrl/GetPrices',
method: 'POST',
data: JSON.stringify({ Article : articles }),
headers: { 'Content-Type': 'application/json' }
});
and
public IHttpActionResult GetPrices([FromUri]Article articles) {
or
[HttpPost]
public void GetPrices(Article articles)
where instead of void you put whatever you are returning
?

org.springframework.web.HttpRequestMethodNotSupportedException

Need help with the exception getting whilst posting data to server, although GET method works fine within the same REST Resource. Code is given below; Early attention appreciated.
REST Endpoint
#RestController
#RequestMapping("/trading-api")
public class MemberMessageResource {
private final Logger log = LoggerFactory.getLogger(MemberMessageResource.class);
#Inject
MemberMessageService service;
#RequestMapping(value = "/messages/reply/", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<MemMessage> replyMemeberMessage(#RequestBody MemMessage msg)
throws URISyntaxException {
log.info("REST Request to reply a message : {" + msg.toString() + " }");
MemMessage result = msg;
return new ResponseEntity<MemMessage>(result, HttpStatus.OK);
}
}
MessageService.js
'use strict';
angular.module('nkApp').factory(
'messagesService',
[
'$http',
'$q',
function($http, $q) {
var REST_SERVICE_URI = '/trading-api/messages/';
var factory = {
replyMemeberMessage : replyMemeberMessage
};
return factory;
function replyMemeberMessage(message) {
console.log('Replying Message : ', message);
var deferred = $q.defer();
$http.post(REST_SERVICE_URI + "reply/" + message)
.then(
function (response) {
deferred.resolve(response.data);
},
function(errResponse){
console.error('Error while Replying Message');
deferred.reject(errResponse);
}
);
return deferred.promise;
}
} ]);
Console Error
2017-03-10 23:49:21.515 WARN 11764 --- [nio-8080-exec-8] o.s.web.servlet.PageNotFound : Request method 'POST' not supported
Browser Error
{"timestamp":1489189761519,"status":405,"error":"Method Not Allowed","exception":"org.springframework.web.HttpRequestMethodNotSupportedException","message":"Request method 'POST' not supported","path":"/trading-api/messages/reply/[object%20Object]"}
Your message object should not be part of your url, it should be your request body. Instead of adding to the url string, just pass it as the data argument in your angular javascript function:
$http.post(REST_SERVICE_URI + "reply/", message)

AngularJS and Go POST Request Method Not Allowed

Im currently working on a sample project and Im using Go and AngularJS I am new at this. I encountered a 405 Error Method Not Allowed after executing this codes.
sample.js
var app = angular.module('sample', []);
app.controller('sampleCtrl', function($scope, $http){
$scope.submit = function(){
//variables
$scope.firstName = document.getElementById('firstName').value;
$scope.middleName = document.getElementById('middleName').value;
$scope.lastName = document.getElementById('lastName').value;
$scope.age = document.getElementById('age').value;
$http({
method: 'POST',
url: baseUrl +'/sample',
headers: {'Content-Type': 'application/json'},
data: {
"firstName" : $scope.firstName,
"middleName" : $scope.middleName,
"lastName" : $scope.lastName,
"age" : $scope.age
}
}).then(function successCallback(response){
alert('Success');
});
}
});
sample.go
package controllers
import (
"github.com/astaxie/beego"
"net/http"
"fmt"
"encoding/json"
)
type SampleController struct {
beego.Controller
}
func (this *SampleController) Get(){
this.TplName = "sample/sample.html"
this.Render()
}
type Entry struct {
FirstName string
MiddleName string
LastName string
Age int
}
func (this *SampleController) Submit(rw http.ResponseWriter, req *http.Request){
decoder := json.NewDecoder(req.Body)
var data Entry
err := decoder.Decode(&data)
if err != nil {
fmt.Println("JSON Empty")
}else{
var firstName = data.FirstName
//var middle = data.MiddleName
//var lastName = data.LastName
//var age = data.Age
fmt.Println(firstName)
}
}
routers.go
package routers
import (
"test/controllers"
"github.com/astaxie/beego"
)
func init() {
beego.Router("/", &controllers.MainController{})
beego.Router("/sample", &controllers.SampleController{}) beego.Router("/sample/Submit",&controllers.SampleController{},"post:Submit")
}
Thanks for the help in advance.
Remove baseUrl and make sure url:"sample".
Maybe you can do this
console.log(baseUrl);
Check that baseUrl contains #;
I am not a Go developer, but looking at the error code it seems like you are making POST request, but have only defined routes for GET.
In router u have defined "/sample" as GET but you made an ajax call for POST method, its search's in the router for /sample it will find this
beego.Router("/sample", &controllers.SampleController{})
which redirects to SampleController but there it doesn't find any POST method definition so 405 method not found.
Try adding in samplecontroller
func (this *SampleController) Post(){
...// your code goes here
}
or add
beego.Router("/sample", &controllers.SampleController{"post:Sample"})
and add a Function Sample in samplecontroller just as you did for Submit

SyntaxError: Unexpected token S, AngularJS, Spring

I'm making a simple establishment of registration that must have data and a logo. In tests could transmit the file and the data separately but when trying to send them together the following error occurs:
SyntaxError: Unexpected token S
at Object.parse (native)
at qc (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js:14:245)
at Zb (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js:76:423)
at https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js:77:283
at r (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js:7:302)
at Zc (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js:77:265)
at c (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js:78:414)
at https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js:112:113
at n.$get.n.$eval (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js:126:15)
at n.$get.n.$digest (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js:123:106)
The Angular Controller
angular.module('EntregaJaApp').controller('EstabelecimentoController', ['$scope', '$http','Upload', function($scope, $http,Upload){
$scope.salvar = function(){
Upload.upload({
url: 'http://localhost:8080/site-web/gerencial/estabelecimento/salvar',
file: $scope.picFile[0],
method: 'POST',
headers: {'Content-Type': 'multipart/form-data'}, // only for html5
data: {'estabelecimento': $scope.estabelecimento}
});
}}
The Spring Controller
#Controller
#RequestMapping("/gerencial/estabelecimento")
public class EstabelecimentoController {
#Autowired
private EstabelecimentoService estabelecimentoService;
#RequestMapping(value = "/salvar", method = RequestMethod.POST)
public ResponseEntity<?> salvar(Estabelecimento estabelecimento,#RequestParam(value="file", required=false) MultipartFile file){
try {
byte[] bytes;
if (!file.isEmpty()) {
bytes = file.getBytes();
//store file in storage
}
System.out.println(String.format("receive %s from %s", file.getOriginalFilename(), estabelecimento.getNome()));
estabelecimentoService.salvar(estabelecimento);
return new ResponseEntity<>(MensagensGerais.SUCESSO_SALVAR,HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>((StringUtil.eVazia(e.getMessage()) ? MensagensGerais.ERRO_CONSULTAR : e.getMessage()),HttpStatus.BAD_REQUEST);
}
}
}
did you missed the return type annotation? Like
#RequestMapping(value = "/salvar", method = RequestMethod.POST)
#Produces(MediaType.APPLICATION_JSON)
public ResponseEntity<?> salvar(Estabelecimento estabelecimento,#RequestParam(value="file", required=false) MultipartFile file){...}
Assuming that the request specifies an Accept Header "application/json", it seems that the Strings are not correctly serialized (by Spring?). Angular versions prior to 1.3.x seem to have been generous, but now an exception is thrown when the response is not correct JSON. I have added the following response transformer to my app:
$httpProvider.defaults.transformResponse.unshift(function(data, headersGetter, status){
var contentType = headersGetter('Content-Type');
if(angular.isString(contentType) && contentType.startsWith('application/json')){
try {
angular.fromJson(data);
} catch(e){
var mod = '"'+data+'"';
try {
angular.fromJson(mod);
return mod;
}
catch(e){
return data;
}
}
return data;
}
else{
return data;
}
});
It transforms a JS string to a JSON string object by wrapping it in additional ".

Where exactly to put the antiforgeryToken

I have a layout page that has a form with AntiForgeryToken
using (Html.BeginForm(action, "Account", new { ReturnUrl = returnUrl }, FormMethod.Post, new { Id = "xcrf-form" }))
This generates a hidden field
<input name="__RequestVerificationToken" type="hidden" value="p43bTJU6xjctQ-ETI7T0e_0lJX4UsbTz_IUjQjWddsu29Nx_UE5rcdOONiDhFcdjan88ngBe5_ZQbHTBieB2vVXgNJGNmfQpOm5ATPbifYE1">
In my angular view (that is loaded in a div in the layout page, I do this
<form class="form" role="form" ng-submit="postReview()">
And my code for postReview() is as follows
$scope.postReview = function () {
var token = $('[name=__RequestVerificationToken]').val();
var config = {
headers: {
"Content-Type": "multipart/form-data",
// the following when uncommented does not work either
//'RequestVerificationToken' : token
//"X-XSRF-TOKEN" : token
}
}
// tried the following, since my other MVC controllers (non-angular) send the token as part of form data, this did not work though
$scope.reviewModel.__RequestVerificationToken = token;
// the following was mentioned in some link I found, this does not work either
$http.defaults.headers.common['__RequestVerificationToken'] = token;
$http.post('/Review/Create', $scope.reviewModel, config)
.then(function (result) {
// Success
alert(result.data);
}, function (error) {
// Failure
alert("Failed");
});
}
My MVC Create method is as follows
[HttpPost]
[ValidateAntiForgeryToken]
[AllowAnonymous]
public ActionResult Create([Bind(Include = "Id,CommentText,Vote")] ReviewModel reviewModel)
{
if (User.Identity.IsAuthenticated == false)
{
// I am doing this instead of [Authorize] because I dont want 302, which browser handles and I cant do client re-direction
return new HttpStatusCodeResult(HttpStatusCode.Forbidden);
}
// just for experimenting I have not yet added it to db, and simply returning
return new JsonResult {Data = reviewModel, JsonRequestBehavior = JsonRequestBehavior.AllowGet};
}
So no matter where I put the token, no matter what I use for 'Content-Type' (I tried application-json and www-form-urlencoded) I always get the error "The required anti-forgery form field "__RequestVerificationToken" is not present."
I even tried naming __RequestVerificationToken and RequestVerificationToken
Why does my server not find the damn token?
I also looked at couple of links that ask you to implement your own AntiForgeryToeknVerifyAttrbute and verify the token that is sent as cookieToken:formToken, I have not tried that but why I am not able to get it working whereas this works for the MVC controllers (non-angular posts)
Yes. By default, MVC Framework will check for Request.Form["__RequestVerificationToken"].
Checking the MVC source code
public AntiForgeryToken GetFormToken(HttpContextBase httpContext)
{
string value = httpContext.Request.Form[_config.FormFieldName];
if (String.IsNullOrEmpty(value))
{
// did not exist
return null;
}
return _serializer.Deserialize(value);
}
You need to create your own filter to check it from Request.Header
Code Snippet from Phil Haack's Article - MVC 3
private class JsonAntiForgeryHttpContextWrapper : HttpContextWrapper {
readonly HttpRequestBase _request;
public JsonAntiForgeryHttpContextWrapper(HttpContext httpContext)
: base(httpContext) {
_request = new JsonAntiForgeryHttpRequestWrapper(httpContext.Request);
}
public override HttpRequestBase Request {
get {
return _request;
}
}
}
private class JsonAntiForgeryHttpRequestWrapper : HttpRequestWrapper {
readonly NameValueCollection _form;
public JsonAntiForgeryHttpRequestWrapper(HttpRequest request)
: base(request) {
_form = new NameValueCollection(request.Form);
if (request.Headers["__RequestVerificationToken"] != null) {
_form["__RequestVerificationToken"]
= request.Headers["__RequestVerificationToken"];
}
}
public override NameValueCollection Form {
get {
return _form;
}
}
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class,
AllowMultiple = false, Inherited = true)]
public class ValidateJsonAntiForgeryTokenAttribute :
FilterAttribute, IAuthorizationFilter {
public void OnAuthorization(AuthorizationContext filterContext) {
if (filterContext == null) {
throw new ArgumentNullException("filterContext");
}
var httpContext = new JsonAntiForgeryHttpContextWrapper(HttpContext.Current);
AntiForgery.Validate(httpContext, Salt ?? string.Empty);
}
public string Salt {
get;
set;
}
// The private context classes go here
}
Check out here for MVC 4 implementation, to avoid salt issue
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class,
AllowMultiple = false, Inherited = true)]
public sealed class ValidateJsonAntiForgeryTokenAttribute
: FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
var httpContext = filterContext.HttpContext;
var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName];
AntiForgery.Validate(cookie != null ? cookie.Value : null,
httpContext.Request.Headers["__RequestVerificationToken"]);
}
}
I had the same problem. Turned out that I don't need to set antiforgery token anywhere explicitly in my angular js code. The MVC controller expects this token value to be delivered from 1. the form field, 2. cookie. The filter equates and is happy when they match.
When we submit the form, hidden field for the anti forgery token automatically supplies its value. Cookie is automatically set by the browser. So as I said, we don't need to do anything explicitly.
The problem really is request's content-type. By default it goes as as application/json and therefore the a.f. token value (or rather any form data) is not received.
Following worked for me:
// create the controller
var RegisterController = function ($scope, $http) {
$scope.onSubmit = function (e) {
// suppress default form submission
e.preventDefault();
var form = $("#registerform");
if (form.valid()) {
var url = form.attr('action');
var data = form.serialize();
var config = {
headers: {
'Content-type':'application/x-www-form-urlencoded',
}
};
$http.post(url, data, config).success(function (data) {
alert(data);
}).error(function(reason) {
alert(reason);
});
}
};
};
As Murali suggested I guess I need to put the toekn in the form itself, so I tried putting the token as part of form data and I needed to encode the form data as explained in https://stackoverflow.com/a/14868725/2475810
This approach does not require any additional code on server side, also we do not need to create and join cookie and form token. Just by form-encoding the data and including token as one of the fields as explained in the answer above we can get it rolling.
You should perform the HTTP request in this way:
$http({
url: '/Review/Create',
data: "__RequestVerificationToken=" + token + "&param1=1&param2=2",
method: 'POST',
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'application/json, text/javascript, */*; q=0.01',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
}).success(function(result) {
alert(result.data);
}).error(function(error) {
alert("Failed");
});

Categories

Resources