reST (reStructuredText) Question

My angular frontend App can not send PUT request to my backend REST app

I have two web apps running on a single tomcat instance. One of them is Spring MVC Rest app which has basic structure, a rest controller, a service layer and DAO layer which is interacting with postgresql .
Below you can see my RestController

package com.hizir.acil.main.controller;


import com.hizir.acil.main.model.Donor;
import com.hizir.acil.main.service.DonorService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;
import org.joda.time.*;

import javax.validation.Valid;

import java.util.List;


/**
* Created by TTTDEMIRCI on 12/29/2015.
*/


@RestController
@RequestMapping("/")
public class AppController {

@Autowired
DonorService donorService;

@Autowired
MessageSource messageSource;

/*
* This method will list all existing Donors in for JSP .
*/

@RequestMapping(value = { "/", "/listAllDonors" }, method = RequestMethod.GET)
public String listDonors(ModelMap model) {

List<Donor> donors = donorService.findAllDonors();
model.addAttribute("donors", donors);
return "alldonors";
}
/*
* This method will list all existing Donors in json format.
*/
@RequestMapping(value = { "/listjson" }, method = RequestMethod.GET, produces = "application/json")
public ResponseEntity<List<Donor>> listDonors() {
List<Donor> donors = donorService.findAllDonors();
if (donors.isEmpty()) {
return new ResponseEntity<List<Donor>>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<List<Donor>>(donors, HttpStatus.OK);
}

/*
* This method will provide the medium to add a new donor.
*/
@RequestMapping(value = { "/new" }, method = RequestMethod.GET)
public String newDonor(ModelMap model) {
Donor donor = new Donor();
model.addAttribute("donor", donor);
model.addAttribute("edit", false);
return "registration";
}



//-------------------Create a Donor--------------------------------------------------------

@RequestMapping(value = "/listjson", method = RequestMethod.POST)
public ResponseEntity<Void> createUser(@RequestBody Donor donor, UriComponentsBuilder ucBuilder) {
System.out.println("Creating Donor " + donor.getName());

// if (donorService.isUserExist(user)) {
// System.out.println("A User with name " + user.getUsername() + " already exist");
// return new ResponseEntity<Void>(HttpStatus.CONFLICT);
// }

donor.setCreationDate(new LocalDate());
donorService.saveDonor(donor);


System.out.println("donor created.............."+donor.getId());
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ucBuilder.path("/listjson/{id}").buildAndExpand(donor.getId()).toUri());
return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
}


//------------------- Update a donor --------------------------------------------------------


@RequestMapping( method = RequestMethod.PUT)
public ResponseEntity<Donor> updateUser(@PathVariable("id") int id, @RequestBody Donor donor) {
System.out.println("Updating donor " + id);

Donor currentDonor = donorService.findById(id);

// if (currentUser==null) {
// System.out.println("User with id " + id + " not found");
// return new ResponseEntity<User>(HttpStatus.NOT_FOUND);
// }

currentDonor.setName(donor.getName());
currentDonor.setSurname(donor.getSurname());
currentDonor.setBloodType(donor.getBloodType());

donorService.updateDonor(currentDonor);
return new ResponseEntity<Donor>(currentDonor, HttpStatus.OK);
}


/*
* This method will be called on form submission, handling POST request for
* saving donor in database. It also validates the user input
*/
@RequestMapping(value = { "/new" }, method = RequestMethod.POST)
public String saveDonor(@Valid Donor donor, BindingResult result,
ModelMap model) {

if (result.hasErrors()) {
return "registration";
}


donorService.saveDonor(donor);

model.addAttribute("success", "Donor " + donor.getName() + " registered successfully");
return "success";
}


/*
* This method will provide the medium to update an existing Donor.
*/
@RequestMapping(value = { "/edit-{id}-donor" }, method = RequestMethod.GET)
public String editDonor(@PathVariable int id, ModelMap model) {
Donor donor= donorService.findById(id);
model.addAttribute("donor", donor);
model.addAttribute("edit", true);
return "registration";
}

/*
* This method will be called on form submission, handling POST request for
* updating donor in database. It also validates the user input
*/
@RequestMapping(value = { "/edit-{id}-donor" }, method = RequestMethod.POST)
public String updateDonor(@Valid Donor donor, BindingResult result,
ModelMap model, @PathVariable int id) {

if (result.hasErrors()) {
return "registration";
}

// if(!service.isEmployeeSsnUnique(employee.getId(), employee.getSsn())){
// FieldError ssnError =new FieldError("employee","ssn",messageSource.getMessage("non.unique.ssn", new String[]{employee.getSsn()}, Locale.getDefault()));
// result.addError(ssnError);
// return "registration";
// }

donorService.updateDonor(donor);

model.addAttribute("success", "Donor " + donor.getName() + " updated successfully");
return "success";
}


/*
* This method will delete a donor by it's id value.
*/
@RequestMapping(value = { "/delete-{id}-donor" }, method = RequestMethod.GET)
public String deleteDonorById(@PathVariable int id) {
donorService.deleteDonorById(id);
return "redirect:/listAllDonors";
}

}


As you can see there are several request mappings. Listing donors and creating donor is working fine with frontend app and I can create new donor and list them. But when I try to update any request is not accessing this rest controller method.
Below is my angular service of frontedn app.

App.factory('User', [
'$resource',
function($resource) {
return $resource(
'http://localhost:8080/HizirAcilBackendApp/listjson/:id', {id: '@id'}, {
update : {
method : 'PUT'
}
},
{
stripTrailingSlashes: false
});
} ]);


and below is my angular controller

/**
*
*/
'use strict';

App.controller('UserController', ['$scope', 'User', function($scope, User) {
var self = this;
self.user= new User();

self.users=[];

self.fetchAllUsers = function(){
self.users = User.query();

};

self.createUser = function(){
self.user.$save(function(){
self.fetchAllUsers();
});
};

self.updateUser = function(){
self.user.$update(function(){
self.fetchAllUsers();
});
};

self.deleteUser = function(identity){
var user = User.get({id:identity}, function() {
user.$delete(function(){
console.log('Deleting user with id ', identity);
self.fetchAllUsers();
});
});
};

self.fetchAllUsers();

self.submit = function() {
if(self.user.id==null){
console.log('Saving New User', self.user);
self.createUser();
}else{
console.log('Upddating user with id ', self.user.id);
self.updateUser();
console.log('User updated with id ', self.user.id);
}
self.reset();
};

self.edit = function(id){
console.log('id to be edited', id);
for(var i = 0; i < self.users.length; i++){
if(self.users[i].id === id) {
self.user = angular.copy(self.users[i]);
break;
}
}
};

self.remove = function(id){
console.log('id to be deleted', id);
if(self.user.id === id) {//If it is the one shown on screen, reset screen
self.reset();
}
self.deleteUser(id);
};


self.reset = function(){
self.user= new User();
$scope.myForm.$setPristine(); //reset Form
};

}]);


I am trying to learn Angular,rest and spring all in one place and I think I have made a good progress but I stuck with this PUT request problem.
Any help and comment would be appreciated.
Regards
Turkmen

Answer

Looks like your RequestMapping is wrong, you did not specify a path there :

@RequestMapping( method = RequestMethod.PUT)

You need to set a apth and add {id} so spring can map it as @PathVariable

@RequestMapping(value = "/listjson/{id}", method = RequestMethod.POST)