Spring Rest Controller POST request doesn't work - java

I have a rest controller:
#RestController
#RequestMapping("/query")
public class QueryController {
#Autowired
private QueryService queryService;
#RequestMapping(value = "/select", method = RequestMethod.POST)
public #ResponseBody QueryResultDTO executeQuery(#RequestBody QueryDTO queryDTO) {
try {
QueryResultDTO queryResultDTO = queryService.executeQuery("select * from employees");
queryResultDTO.setSuccessful(true);
return queryResultDTO;
} catch (SQLException e) {
QueryResultDTO queryResultDTO = new QueryResultDTO();
queryResultDTO.setSuccessful(false);
queryResultDTO.setErrorMessage(e.getMessage());
return queryResultDTO;
}
}
}
and I try to send POST request from AngularJS controller:
app.controller("AppCtrl",function($scope,$http) {
var app = this;
$scope.execute= function () {
$http({
url: '../query/select',
method: "POST",
data: { 'message' : $scope.queryText }
})
.then(function(response) {
$scope.queryResult = response.data;
console.log($scope.queryResult);
console.log($scope.queryText)
},
function(response) {
console.log(response);
});
}
});
but It doesn't work. My executeQuery function in Spring Controller isn't even called.
But when I change RequestMethod to GET it works correctly.
#RestController
#RequestMapping("/query")
public class QueryController {
#Autowired
private QueryService queryService;
#RequestMapping(value = "/select", method = RequestMethod.GET)
public #ResponseBody QueryResultDTO executeQuery() {
try {
QueryResultDTO queryResultDTO = queryService.executeQuery("INSERT INTO employee VALUES (7,'dupa')");
queryResultDTO.setSuccessful(true);
return queryResultDTO;
} catch (SQLException e) {
QueryResultDTO queryResultDTO = new QueryResultDTO();
queryResultDTO.setSuccessful(false);
queryResultDTO.setErrorMessage(e.getMessage());
return queryResultDTO;
}
}
}
and in Angular controller:
app.controller("AppCtrl",function($scope,$http) {
var app = this;
$scope.execute= function () {
$http({
url: '../query/select',
method: "GET",
data: { 'message' : $scope.queryText }
})
.then(function(response) {
$scope.queryResult = response.data;
console.log($scope.queryResult);
console.log($scope.queryText)
},
function(response) {
console.log(response);
});
}
});
My main problem is that I'd like to send some data to my Spring controller and then send JSON in response to my Angular controller. Whith GET method response works perfectly, but when I use POST the controller method isn't even called.
Edit:
My QueryDTO class is simple:
public class QueryDTO {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
And some logs with DEBUG level:
2016-06-06 09:28:23.697 DEBUG 7504 --- [nio-8090-exec-2] o.s.web.servlet.DispatcherServlet : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
2016-06-06 09:28:23.698 DEBUG 7504 --- [nio-8090-exec-2] o.s.web.servlet.DispatcherServlet : Successfully completed request

Try adding the consumes=MediaType.APPLICATION_JSON_VALUE in your method.
#Transactional
#RequestMapping(value = "/userlogincheck", method = RequestMethod.POST, consumes=MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody void userLoginCheck(#RequestBody UserImpl user, HttpServletRequest request, HttpServletResponse response) throws JSONException, IOException {
JSONObject json = new JSONObject();
try {
String email=user.getEmail();
Long userId=user.getId();
User loginData = accountService.userLoginCheck(email,userId);
if(loginData==null)
{
json.put("status", "FAILURE");
json.put("message", "user does not exist");
json.put("nextPage", "signIn");
}
else
{
json.put("status", "SUCCESS");
json.put("nextPage", updateState);
}
}
catch(Exception e) {
logger.info(e.getMessage());
}
response.setContentType("application/json;charset=UTF-8");
logger.info("response======" + json.toString());
PrintWriter out = response.getWriter();
out.write(json.toString());
}

I had the same issue and was able to fix it by adding CSRF token to my request (this is only an issue if you are using the WebSecurity). https://docs.spring.io/spring-security/site/docs/current/reference/html/csrf.html
This link describe the following steps:
1) Add the token to your header, with thymeleaf you do as follows (I think you can fetch the token from cookie as well):
<head>
<meta name="_csrf" th:content="${_csrf.token}"/>
.....
</head>
2) Change your request to include the CSRF token as follows (I am not familiar with angular but I guess you can set the header the same way as I did with Jquery):
var token = $("meta[name='_csrf']").attr("content");
$.ajax({
type: 'POST',
url: url,
data: JSON.stringify(newTodo),
headers: {
'X-CSRF-TOKEN': token
},
contentType: 'application/json',
dataType: 'json',
success: function(){
alert('callback ');
}
});

Related

Ajax request with type 'POST' not working, only with 'GET'

I'm trying to send and ajax post request to my springboot mvc controller, but with no success. I've looked a number of similar topics, tried the given solutions, but with no success at all.
If I change the request type to GET, it triggers the controller endpoint.
The endpoint function is not even being triggered in the controller. It is showing only the following error in browser console: jquery-3.4.1.js:9837 POST http://localhost:8080/rede-credenciada 500
I made the same request with postman and it gives the following error:
{
"timestamp": "2020-07-09T17:46:20.920+0000",
"status": 999,
"error": "None",
"message": "No message available"
}
Note: It only happens with POST request, if I change to GET, it works fine. The request is "listened" by the controller.
Here is my ajax request:
const json = {
idGrupoProcedimento: 0,
idTipoEspecialidade: $("#especialidade").val(),
uf: $("#estado").val(),
codCidade: $("#cidade").val()
}
const jsonString = JSON.stringify(json);
$.ajax({
url: "/rede-credenciada",
type: 'POST',
contentType: "application/json",
dataType: "application/json",
data: jsonString,
success: function(data){
console.log(data);
},
error: function(e) {
console.log(e.message);
}
});
Here, my endpoint:
#RequestMapping(value = "/rede-credenciada", method = RequestMethod.POST, consumes = "application/json")
#ResponseBody
public RedeCredenciadaResponse buscaRedeCredenciadaPorFiltro(#RequestBody RedeCredenciadaRequest request) {
... some logic
RedeCredenciadaResponse redeCredenciada = new RedeCredenciadaResponse();
redeCredenciada.setPessoasFisicas(pessoas);
redeCredenciada.setEmpresas(empresas);
return redeCredenciada;
}
And here is my wrapper class:
public class RedeCredenciadaRequest {
private int idGrupoProcedimento;
private int idTipoEspecialidade;
private String uf;
private String codCidade;
public int getIdGrupoProcedimento() {
return idGrupoProcedimento;
}
public void setIdGrupoProcedimento(int idGrupoProcedimento) {
this.idGrupoProcedimento = idGrupoProcedimento;
}
public int getIdTipoEspecialidade() {
return idTipoEspecialidade;
}
public void setIdTipoEspecialidade(int idTipoEspecialidade) {
this.idTipoEspecialidade = idTipoEspecialidade;
}
public String getUf() {
return uf;
}
public void setUf(String uf) {
this.uf = uf;
}
public String getCodCidade() {
return codCidade;
}
public void setCodCidade(String cidade) {
this.codCidade = cidade;
}
The error:
In your ajax request you are using dataType:'application/json', According to jQuery’s Ajax-Related Methods Description
// The type of data we expect back
dataType : "json",
Value of dataType shoud be json, or xml, or html, etc.

Angularjs http no response from Spring Boot

I'm trying to develop a small application to create index on local elasticsearch engine. I use angularjs on the front-end, and spring-boot on the back-end. It can create index successfully, however, when I want to retrive the response in the front-end, it keeps throwing me errors.
Below is my AngularJS api call:
app.service('ESIndexService', function($http) {
this.createESIndex = function(esindexObj) {
var settings = {
method: 'POST',
url: BASE_URL + "/ESIndex/createESIndex",
data: esindexObj
};
return $http(settings).then(function(response) {
console.log("response:"+response);
return response;
}, function(error) {
console.log("error:"+error);
return error;
});
};
});
Then this is my controller:
#CrossOrigin
#RestController
#RequestMapping(value = "ESIndex")
public class ESIndexController {
#RequestMapping(value = "createESIndex", method = RequestMethod.POST)
public #ResponseBody String createIndex(#RequestBody ESIndex esIndex) {
try {
Settings settings = Settings.builder()
.put("xpack.security.user", String.format("%s:%s", Constants.ES_UNAME, Constants.ES_PWD)).build();
TransportClient client = new PreBuiltXPackTransportClient(settings)
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(Constants.ES_HOST), Constants.ES_PORT));
CreateIndexResponse response = client.admin().indices().prepareCreate(esIndex.getName()).setSettings(Settings.builder()
.put("index.number_of_shards", esIndex.getNumberOfShards())
.put("index.number_of_replicas", esIndex.getNumberOfReplicas())).get();
client.close();
if(response.isAcknowledged() && response.isShardsAcked())
return Constants.SUCCESS;
else
return "Fail to create index!";
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}
}
}
I want to get the response status and data in AngularJS response. However, it keeps throwing me errors:
error:SyntaxError: Unexpected token i in JSON at position 0
I'm not using JSON.parse function, why it gives me error like this?
After adding responseType: 'text', still throwing same error, the chrome nextwork
It turns out I need to add "transformResponse: undefined", however, in another of my project, I never did this. What's the difference?
AngularJS:
this.newBlog = function(blogObj) {
var settings = {
method: 'POST',
url: baseUrl + "/blog/newBlog.do",
data: blogObj
}
return $http(settings).then(function(response) {
return response;
}, function(error) {
return error;
});
};
Java Controller:
#RequestMapping(value="newBlog.do", method=RequestMethod.POST)
public #ResponseBody String newBlog(#RequestBody Blog blog, HttpServletRequest request) {
User createdBy = (User) request.getSession().getAttribute("user");
if(createdBy == null)
return NO_SESSION_MSG;
else {
createdBy.setPwd(null);
blog.setCreatedAt(TQBUtilities.getCurrentTime());
blog.setLastUpdatedAt(TQBUtilities.getCurrentTime());
blog.setCreatedBy(createdBy);
return blogService.newBlog(blog);
}
}
Angular is automatically trying to parse the server response as JSON. Try adding this to your settings object
responseType: 'text'
So
var settings = {
method: 'POST',
url: BASE_URL + "/ESIndex/createESIndex",
data: esindexObj,
responseType: 'text'
};
#jheimbouch add "transformResponse: undefined" to http call, like below, works fine:
var settings = {
method: 'POST',
url: BASE_URL + "/ESIndex/createESIndex",
data: esindexObj,
transformResponse: undefined
};
However, why it is required in angularjs 1.6.2? When I was using AngularJS 1.4.8, I don't need to add transformResponse attributes.

POST request returns 415 error

I'm trying to call a POST request (using Jersey APi for REST) from an HTML form using AngularJS v 1.5.8.
I have an HTML form with a submit button that calls a REST serivce:
<body ng-app="myApp" ng-controller="loginController">
......
<form name="myForm" nonvalidate ng-submit="login()">
......
<div
class="col-md-4 col-md-offset-4 col-sm-4 col-sm-offset-3 col-xs-6 col-xs-offset-3">
<button type="submit" class="btn btn-default" ng-submit="login()">Submit</button>
</div>
</form>
This is my loginController script:
var app = angular.module ("myApp", []);
app.controller("loginController", function($scope, $http){
$scope.username = "";
$scope.password = "";
$scope.login = function() {
var transform = function(data) {
return $.param(data);
}
$http(
{
url : 'http://localhost:8080/RestServices/services/user/add',
method : 'POST',
headers : {
'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8'
},
transformRequest : function(data) {
return $.param(data);
},
data: { name: $scope.username,
password: $scope.password }
}).success(function(response, status) {
$scope.data = response; //Assign data received to $scope.data
}
)
}
}
)
And here is my simple REST post service:
#Path("user")
public class UserResource {
private TreeMap<Integer, User> userMap = new TreeMap<Integer, User>();
#POST
#Path("add")
#Consumes({MediaType.APPLICATION_JSON})
public Response addUser(User user) {
int id = userMap.size();
user.setId(id);
userMap.put(id, user);
ObjectMapper mapper = new ObjectMapper();
String jsonString = "";
try {
jsonString = mapper.writeValueAsString(user);
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
jsonString = null;
}
return Response.ok().entity(jsonString).build();
}
}
The POST request is called but returns a 415 error: the server refused this request because the request entity is in a format not supported by the requested resource for the requested method.
The problem is with the format that the REST API is expecting i.e. JSON.
So try with application/json and specifying charset won't be required:
headers: {
'Content-Type' : 'application/json'
}
function loginController($scope, $http) {
$scope.username = "";
$scope.password = "";
$scope.login = function () {
$http({
method: 'POST',
url: 'user/add',
data: {
username: $scope.username,
password: $scope.password
}
}).success(function (data, status, headers, config) {
$scope.result =data.username;
alert($scope.result);
}).error(function (data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
}
}

how to call spring controller in jquery ajax success method

I have created a spring controller and a jsp page. In jsp page I am using jquery ajax call to hit the controller. Now, this controller returns a json response as string. Now on based of json response in success method, I want to call a next controller call which will return a ModelAndView jsp page. How can I do this. Below is my code:
JSP Jquery ajax call:
$(document).ready(function(){
$("#submitButton").click(function(e){
var formData = getFormData();
if(formData!=false){
$.ajax({
type: 'POST',
'url': 'http://localhost:8080/Test_ReportingUI/fieldMappingNext.htm',
data: {jsonData: JSON.stringify(formData)},
dataType: 'json',
success: function(response){
try{
var strResponse=jQuery.parseJSON(response);
}catch(err){}
if(response.status=='ok')
{
alert ("okokokokokokokokok");
//I am successfully reaching till here.
//But in case of this alert box I want to call a
//controller which will return ModelAndView and
//should open a corresponding ModelAndView jsp page.
//something like:
/*
$.ajax({
type: 'GET',
'url': 'http://localhost:8080/Test_ReportingUI/abcxyz.htm',
)};
*/
}
else
{
alert("ERROR!!");
}
},
timeout: 10000,
error: function(xhr, status, err){
if(response.status=='timeout')
{
alert('Request time has been out','');
}
console.log(status,err);
}
}); }
});
});
Controller class methods:
#RequestMapping (value="fieldMappingNext.htm", method=RequestMethod.POST)
#ResponseBody String addFieldMappingNext(#RequestParam String jsonData)
{
String customerID =null;
String objectID = null;
String syncFieldName = null;
String optMapping = null;
JSONObject jsonResponse = new JSONObject();
try{
JSONObject requestedJSONObject = new JSONObject(jsonData);
customerID = requestedJSONObject.getString("customerID");
objectID = requestedJSONObject.getString("objectID");
syncFieldName = requestedJSONObject.getString("syncFieldName");
optMapping = requestedJSONObject.getString("optMapping");
}catch(Exception exex){
exex.printStackTrace();
}
if(optMapping.equalsIgnoreCase("direct")){
long metadataID=rwCustomerService.getMetaDataID(customerID,objectID);
List<RWFieldDetail> list=rwCustomerService.getFieldDetailNames(metadataID);
request.setAttribute("customerID", customerID);
request.setAttribute("objectID", objectID);
request.setAttribute("optMapping", optMapping);
request.setAttribute("syncFieldName", syncFieldName);
request.setAttribute("fieldNames", list);
try {
jsonResponse.put("status", "ok");
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return jsonResponse.toString();
}
Second Controller method that I want to call from jquery success method:
#RequestMapping (value="abcxyz.htm", method=RequestMethod.GET)
ModelAndView fieldMapping(){
ModelAndView modelAndView=new ModelAndView("FieldMappingMainScreenNext");
return modelAndView;
}
How do I do this.
Since the second handler method returns ModelAndView, you should redirect from the success callback:
...
success: function(response) {
window.location.replace(response.url);
}
...
In your Java code you can use something like:
Map<String, String> map = new HashMap<String, String>();
if(condition1){
map.put("url","url1.html");
}
if(condition2){
map.put("url","url2.html");
}
Convert it to a JSON string and revert it back. Afterwards, in the jquery portion you'll get the response:
success:function(jsonStr){
var obj = JSON.parse(jsonStr);
var url = obj.url;
}
That is how you can get the url. If you want to load an other page or create an ajax call then you can do it.

Spring MVC and AngularJS #RequestMapping

I have built an application with Spring-boot and AngularJS with the REST End Point application. I got a little stuck with #RequesMapping in Spring Controller I've made. The problem is, I have the example url:
"localhost:8080/foo/bar/api/cardGenerated/0102".
'01' is first parameter and '02' is second parameter. How can I mapped into #RequestMapping Spring controller to get a url above.
Here's my controller :
#RestController
#RequestMapping("/api")
public class CardGeneratedResource {
#RequestMapping(value = "/cardGenerated/{branchCode}{cardType}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<CardGenerated> get(#PathVariable("branchCode") String branchCode,
#PathVariable("cardType") String cardType,
HttpServletResponse response) {
log.debug("REST request to get CardGenerated : " + branchCode + " and " + cardType);
CardGenerated cardGenerated = cardGeneratedRepository.
findTopByBranchCodeAndCardTypeOrderByCardNumberDesc(branchCode, cardType);
if (cardGenerated == null) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(cardGenerated, HttpStatus.OK);
}
}
so this is my AngularJS $resource:
'use strict';
angular.module('itmApp')
.factory('CardGenerated', function ($resource) {
return $resource('api/cardGenerated/:branchCode:cardType', {}, {
'query': { method: 'GET', isArray: true},
'get': {
method: 'GET',
transformResponse: function (data) {
data = angular.fromJson(data);
return data;
}
}
});
});
I always got 'Failed to load resource: the server responded with a status of 404 (Not Found)'.
Here you are missing / .
You have two path variable here.so default url is
localhost:8080/foo/bar/api/cardGenerated/FIRST_PATH_VARIABLE/SECOND_PATH_VARIABLE
branchCode (First path variabel)
cardType (Second path variable)
#RequestMapping(value = "/cardGenerated/{branchCode}/{cardType}"
And in frontend side too the same mistake while registering factory definition.
api/cardGenerated/:branchCode/:cardType'
All method is like
#RestController
#RequestMapping("/api")
public class CardGeneratedResource {
#RequestMapping(value = "/cardGenerated/{branchCode}/{cardType}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<CardGenerated> get(#PathVariable("branchCode") String branchCode,
#PathVariable("cardType") String cardType,
HttpServletResponse response) {
log.debug("REST request to get CardGenerated : " + branchCode + " and " + cardType);
CardGenerated cardGenerated = cardGeneratedRepository.
findTopByBranchCodeAndCardTypeOrderByCardNumberDesc(branchCode, cardType);
if (cardGenerated == null) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(cardGenerated, HttpStatus.OK);
}
}
and angular factory is like
'use strict';
angular.module('itmApp')
.factory('CardGenerated', function ($resource) {
return $resource('api/cardGenerated/:branchCode/:cardType', {}, {
'query': { method: 'GET', isArray: true},
'get': {
method: 'GET',
transformResponse: function (data) {
data = angular.fromJson(data);
return data;
}
}
});
});
NOTE: First try with any rest client or postman and make sure backend api is working properly also angular side check parameters are being passed correctly.

Categories

Resources