Spring MVC #Pathvariable won't work - java

I have an interface and an implementation class:
Interface
#RequestMapping(value = CUSTOMER_PATH + "{id}", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON + CHARSET_UTF_8_ENCODING})
Response getCustomerDetails(#PathVariable(CONTACT_ID) String id);
Impl
#Override
public Response getCustomerDetails(String id) {
String methodname = "getCustomerDetails: ";
LOG.info(methodname + "Get Customer Details");
Response response;
System.out.println("******************id: " + id);
if (StringUtils.isEmpty(id)) {
response = Response.status(Status.BAD_REQUEST).entity(MockData.customerDetailsInvalid).build();
LOG.info(methodname + "Returning Customer's Details - Status: Invalid Request");
} else {
response = Response.status(Status.OK).entity(MockData.customerDetails).build();
LOG.info(methodname + "Returning Customer's Details - Status: OK");
}
return response;
}
The path ..../MockDataProvider-war/services/mock/customers/7 returns “invalid request”.
The value for id is printed out as null, even though it should be 7.
Anyone know why id is null?

Reason is #PathVariable(CONTACT_ID)
it should be #PathVariable String id this will work.

Fixed it by changing the Interface from:
Response getCustomerDetails(#PathVariable(CONTACT_ID) String id);
to:
Response getCustomerDetails(String id);
and the Impl from:
public Response getCustomerDetails(String id)
to
public Response getCustomerDetails(#PathVariable(CONTACT_ID) String id)

Related

Cannot redirect after facebook login using response entity in spring boot

Ok, so I am trying to achieve facebook authentication in my application but after success user is not redirected to homepage even though location header is set.
This is my current scenario.
Front-End call:
#GetMapping(value = "/login/facebook")
public String loginFacebook() {
String facebookLoginUrl = String.valueOf(this.restTemplate.getForEntity(this.serverApi + "/login/facebook",String.class).getHeaders().get("Location"));
facebookLoginUrl = facebookLoginUrl.substring(1,facebookLoginUrl.length()-1);
System.out.println(facebookLoginUrl);
return "redirect:" + facebookLoginUrl;
}
Back-End:
#RequestMapping(value = "/login/facebook", method = RequestMethod.GET)
public String startFacebookProcess() {
this.facebookConnectionFactory = new FacebookConnectionFactory(appId,appSecret);
OAuth2Operations operations = this.facebookConnectionFactory.getOAuthOperations();
OAuth2Parameters parameters = new OAuth2Parameters();
// promeni url-a za front-enda
parameters.setRedirectUri("http://localhost:8080/login/returnFromFacebook");
parameters.setScope(this.scope);
System.out.println("In startFacebookProcess");
String url = operations.buildAuthorizeUrl(parameters);
System.out.println(url);
return "redirect:" + url;
}
After that, the user is being redirected to the official facebook login page where he allows his details to be used.
Then he performs a GET request to my Front-End with his authorization code:
#GetMapping(value = "/login/returnFromFacebook")
public ResponseEntity getFacebookData(#RequestParam("code") String authorizationCode){
System.out.println(authorizationCode);
ResponseEntity response = this.restTemplate.getForEntity(this.serverApi +
"/login/returnFromFacebook?code=" + authorizationCode, ResponseEntity.class);
if(response.getStatusCode().is2xxSuccessful()){
return response;
}
return new ResponseEntity(HttpStatus.CONFLICT);
}
My Back-End is being called and I contact facebook to fetch the user data using his authorization code. Then I return a ResponseEntity which inherited all the HttpServletResponse headers and cookies.
#RequestMapping(value = "/login/returnFromFacebook", method = RequestMethod.GET)
public ResponseEntity getDataFromFacebook(#RequestParam("code") String authorizationCode,
HttpServletResponse response) throws IOException {
// leg 2
OAuth2Operations operations = this.facebookConnectionFactory.getOAuthOperations();
AccessGrant accessGrant = operations.exchangeForAccess(authorizationCode,
"http://localhost:8080/login/returnFromFacebook",null);
// leg 3
System.out.println("code: " + authorizationCode);
Connection<Facebook> connection = this.facebookConnectionFactory.createConnection(accessGrant);
User currentUser = connection.getApi().fetchObject("me", User.class,"email,first_name,last_name");
System.out.println("Email: " + currentUser.getEmail());
if(this.appUserDAO.findUserAccountByEmail(currentUser.getEmail()) == null){
Map<String, String> facebookDetailsMap = new LinkedHashMap<>();
facebookDetailsMap.put("email",currentUser.getEmail());
facebookDetailsMap.put("name",currentUser.getFirstName() + " " + currentUser.getLastName());
this.appUserDAO.saveFacebookAccount(facebookDetailsMap);
}
// Create JWT Token
String token = JWT.create()
.withSubject(currentUser.getEmail())
.withExpiresAt(new Date(System.currentTimeMillis() + JwtProperties.EXPIRATION_TIME))
.sign(HMAC512(JwtProperties.SECRET.getBytes()));
JwtAuthenticationFilter.setJwtCookie(response,token);
System.out.println(response.getStatus() + " " + response.getHeader("set-cookie"));
response.setHeader("Location", "http://localhost:8080/");
// HttpHeaders headers = new HttpHeaders();
// headers.add(index");
return new ResponseEntity<>(HttpStatus.CREATED);
}
This is the received response header in the browser. The cookies are set and everything but user is not being redirected to Location header. :
I tried to return a String "redirect:/" from GetFacebookData(Front-End) but the response cookies and headers are not being applied. I don't know why the Location header is not working.
I fixed it by returning the 'index' template if the back-end call was sucessful but also apply the cookie header into the original response (which was to the front-end) using HttpServletResponse (this is not possible with ResponseEntity btw). With HttpServletResponse you dont have to return it to the browser, it applies everything by default. With ResponseEntity you have to return ResponseEntity Object in order to apply headers. This is how the function looks like now:
#GetMapping(value = "/login/returnFromFacebook")
public String getFacebookData(#RequestParam("code") String authorizationCode, HttpServletResponse httpServletResponse) throws IOException {
System.out.println(authorizationCode);
ResponseEntity response = this.restTemplate.getForEntity(this.serverApi +
"/login/returnFromFacebook?code=" + authorizationCode, ResponseEntity.class);
System.out.println(response.getStatusCodeValue() + " " + response.getHeaders().get("Location"));
//set cookie for original request
String jwtCookieHeader = String.valueOf(response.getHeaders().get("set-cookie"));
jwtCookieHeader = jwtCookieHeader.substring(1,jwtCookieHeader.length()-1);
httpServletResponse.setHeader("set-cookie", jwtCookieHeader);
if(response.getStatusCode().is2xxSuccessful()){
return "redirect:/";
}
return String.valueOf(new ResponseEntity(HttpStatus.CONFLICT));
}

Spring Boot #RestController no respond

I'm starting with Spring and REST application. Currently, I'm developing one application on my own and I stuck.
The app is divided just like standard Spring Boot project. All of the controllers are contained in web package.
One of "standard" controller is responsible for handling HTTP request and returning an HTML website. I have added a REST controller which should respond to POST request from the first controller, but I receive a 404 error.
How it looks like in code?
#RestController
#RequestMapping("/users")
public class UserRestController {
#Autowired
private UserService userService;
#RequestMapping(value = "/user", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
public ResponseEntity<?> getUser(#RequestParam("userId") String userId, Errors errors) {
AjaxUser response = new AjaxUser();
if (errors.hasErrors()) {
response.message = errors.getAllErrors().stream().map(x -> x.getDefaultMessage()).collect(Collectors.joining(","));
return ResponseEntity.badRequest().body(response);
}
response.setUser(userService.getUserById(Integer.getInteger(userId).intValue()));
return ResponseEntity.ok(response);
}
private class AjaxUser {
private User user;
private String message;
public void setUser(User user) {
this.user = user;
}
public void setMessage(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
#Override
public String toString() {
return "User { id:" + user.getId() + ", Name: " + user.getName() + ", surname: " + user.getSurname() + "}";
}
}
}
From .js file I send a ajax query which should trigger a rest controller, here is the code:
function sendUserId(id) {
var user = {};
user["userId"] = id;
console.log("USER: ", user);
$.ajax({
type: "POST",
contentType: "application/json",
url: "/users/user",
data: JSON.stringify(user),
dataType: 'json',
cache: false,
timeout: 100000,
success: function (user) {
var json = "<h4>Ajax Response</h4><pre>"
+ JSON.stringify(user, null, 4) + "</pre>";
console.log("SUCCESS : ", user);
},
error: function (e) {
var json = "<h4>Ajax Response</h4><pre>"
+ e.responseText + "</pre>";
console.log("ERROR : ", e);
}
});
}
userId is taken from a html by jQuery, console.log show existing and right value.
Note: There exist a standard user #Controller which is responsible for displaying a user list, it works, problem appear during sending a user id to REST controller. It behaves just like the REST controller doesn't exist and browser return 404 status response. Btw, page use a Spring Secure to login and so on.
Could someone help?
BR Konrad
The controller is looking to have a request parameter that you are missing in the js requesting url
/users/user?userId=1
You can get a user by id like below:
#RequestMapping(value = "{id}", method = RequestMethod.GET)
public ResponseEntity<User> get(#PathVariable("id") int id) {
User user = userService.findById(id);
if (user == null) {
return new ResponseEntity<User>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<User>(user, HttpStatus.OK);
}
So your rest entry point is /users/userid, eg: /users/1
Found this from the post Spring MVC RESTFul Web Service CRUD Example
the problem based on function arguments, REST controller should take String argument and next parse it to JSON object, the response should be String too. Topic can be closed, thanks all to be involved.

Spring GET same URL but different parameter types

so I am creating a User API and I'm trying to call getUserByEmail() before login. My problem is that I get a Ambiguous handler methods mapped for HTTP path ERROR.
#RequestMapping(value = "/user/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<User> getUser(#PathVariable("id") int id) {
System.out.println("Fetching User with id " + id);
User user = userService.findById(id);
if (user == null) {
System.out.println("User with id " + id + " not found");
return new ResponseEntity<User>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<User>(user, HttpStatus.OK);
}
#RequestMapping(value = "/user/{email}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<User> getUserByEmail(#PathVariable("email") String email) {
System.out.println("Fetching User with email " + email);
User user = userService.findByEmail(email);
if (user == null) {
System.out.println("User with email " + email + " not found");
return new ResponseEntity<User>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<User>(user, HttpStatus.OK);
}
Here is the error response I get:
{"timestamp":1460226184275,"status":500,"error":"Internal Server Error","exception":"java.lang.IllegalStateException","message":"Ambiguous handler methods mapped for HTTP path 'http://localhost:8080/user/fr': {public org .springframework.http.ResponseEntity com.ffa.controllers.UserController.getUser(int), public org.springframework
.http.ResponseEntity com.ffa.controllers.UserController.getUserByEmail(java.lang.String)}","path":"/user
/fr"}
I know my problem has something to do with me having a GET that is the same but with different parameter types. Any help would be greatly appreciated!
Instead of PathVariables you can use RequestParams with two different URLs.
#RequestMapping(value = "/user", params="userID", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<User> getUser(#RequestParam("userID") int id) {
System.out.println("Fetching User with id " + id);
User user = userService.findById(id);
if (user == null) {
System.out.println("User with id " + id + " not found");
return new ResponseEntity<User>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<User>(user, HttpStatus.OK);
}
#RequestMapping(value = "/user", params="emailID, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE")
public ResponseEntity<User> getUserByEmail(#RequestParam("emailID") String email) {
System.out.println("Fetching User with email " + email);
User user = userService.findByEmail(email);
if (user == null) {
System.out.println("User with email " + email + " not found");
return new ResponseEntity<User>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<User>(user, HttpStatus.OK);
}
When you call /user?userID=123 it will invoke the first one and when you call /user?emailID=something#gamil.com it will invoke the second one. This is taken care by the params property which is passed in the #RequestMapping.

Angular post not passing payload to java spring via long poll

I am trying to pass variables using post in angular to java spring. The java post function is executed, but all of the parameters are null.
var CreditCard = $resource("http://:host::port/" + context + "/agent/creditCard",
{host: "localhost", port: 8080 },
{getTestPost2: {method:'POST', params:{charge:true, jsonPost:"1234"}}
});
var newCard = new CreditCard({number:'0123'});
newCard.name = "Mike Smith";
newCard.$save();
I checked the my network status shows 200 OK.
Request Payloadview source
{number:0123, name:Mike Smith}
name: "Mike Smith"
number: "0123"
Java
#RequestMapping(
value="/agent/creditCard",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody void getTestPost2(
#PathVariable String clientId,
#RequestParam(value="jsonPost", required=false) String jsonPost,
#RequestParam(value="charge", required=false) boolean charge,
#RequestParam(value="name", required=false) String name,
#RequestParam(value="number", required=false) String number
){
logger.debug("jsonPost " + jsonPost);
logger.debug("name " + name);
logger.debug("charge " + charge);
logger.debug("number " + number);
}
Output:
jsonPost null
name null
charge false
number null
Java
#RequestMapping(
value="/agent/creditCard",
method = RequestMethod.POST,
params = { "jsonPost", "charge", "name", "number"}
produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public #ResponseBody void getTestPost2(
#PathVariable String clientId,
#RequestParam(value="jsonPost", required=false) String jsonPost,
#RequestParam(value="charge", required=false) boolean charge,
#RequestParam(value="name", required=false) String name,
#RequestParam(value="number", required=false) String number
){
logger.debug("jsonPost " + jsonPost);
logger.debug("name " + name);
logger.debug("charge " + charge);
logger.debug("number " + number);
}
I add params and ResponseBody, you can try it.
You should write a CreditCard class to use as the parameter type. Annotate it with #RequestBody to let a HttpMessageConverter convert the JSON body to the required object.
#ResponseBody
#RequestMapping(
value="/agent/creditCard",
method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE)
public void postCreditCard(#RequestBody CreditCard creditCard) {
// process data...
}

post request with multiple parameters JSON and String on Jackson/Jersey JAVA

I've created a rest api using Jersey/Jackson and it works well. I want to adjust my POST methods to receive a string token in addition to the POJO they are receiving as JSON. I've adjusted one of my methods like so:
#POST
#Path("/user")
#Consumes(MediaType.APPLICATION_JSON)
public Response createObject(User o, String token) {
System.out.println("token: " + token);
String password = Tools.encryptPassword(o.getPassword());
o.setPassword(password);
String response = DAL.upsert(o);
return Response.status(201).entity(response).build();
}
I want to call that method, but for whatever reason token prints to null no matter what I try. Here is the client code I've written to send the post request:
public String update() {
try {
com.sun.jersey.api.client.Client daclient = com.sun.jersey.api.client.Client
.create();
WebResource webResource = daclient
.resource("http://localhost:8080/PhizzleAPI/rest/post/user");
User c = new User(id, client, permission, reseller, type, username,
password, name, email, active, createddate,
lastmodifieddate, token, tokentimestamp);
JSONObject j = new JSONObject(c);
ObjectMapper mapper = new ObjectMapper();
String request = mapper.writeValueAsString(c) + "&{''token'':,''"
+ "dog" + "''}";
System.out.println("request:" + request);
ClientResponse response = webResource.type("application/json")
.post(ClientResponse.class, request);
if (response.getStatus() != 201) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatus());
}
System.out.println("Output from Server .... \n");
String output = response.getEntity(String.class);
setId(UUID.fromString(output));
System.out.println("output:" + output);
return "" + output;
} catch (UniformInterfaceException e) {
return "failue: " + e.getMessage();
} catch (ClientHandlerException e) {
return "failue: " + e.getMessage();
} catch (Exception e) {
return "failure: " + e.getMessage();
}
}
Any help would be greatly appreciated.
This is not the way JAX-RS works. The body of your POST request will get marshaled to the first argument of your annotated resource method (in this case, into the User argument). You have a couple options to get around this:
Create a wrapper object containing both a User object and token. Send that back and forth between your client and server.
Specify the token as a query parameter on your URL and access it on the server side as a #QueryParam.
Add the token as a header parameter and access it on the server side as a #HeaderParam.
Example - Option 1
class UserTokenContainer implements Serializable {
private User user;
private String token;
// Constructors, getters/setters
}
Example - Option 2
Client:
WebResource webResource = client.
resource("http://localhost:8080/PhizzleAPI/rest/post/user?token=mytoken");
Server:
#POST
Path("/user")
#Consumes(MediaType.APPLICATION_JSON)
public Response createObject(#QueryParam("token") String token, User o) {
System.out.println("token: " + token);
// ...
}
Example - Option 3
Client:
ClientResponse response = webResource
.type("application/json")
.header("Token", token)
.post(ClientResponse.class, request);
Server:
#POST
Path("/user")
#Consumes(MediaType.APPLICATION_JSON)
public Response createObject(#HeaderParam("token") String token, User o) {
System.out.println("token: " + token);
// ...
}
In case you're using Jersey 1.x, best approach is to post multiple objects as #FormParam
At least two advantages:
You don't need to use a wrapper object to post multiple parameters
The parameters are sent within the body rather than in the url (as with #QueryParam and #PathParam)
Check this example:
Client: (pure Java):
public Response testPost(String param1, String param2) {
// Build the request string in this format:
// String request = "param1=1&param2=2";
String request = "param1=" + param1+ "&param2=" + param2;
WebClient client = WebClient.create(...);
return client.path(CONTROLLER_BASE_URI + "/test")
.post(request);
}
Server:
#Path("/test")
#POST
#Produces(MediaType.APPLICATION_JSON)
public void test(#FormParam("param1") String param1, #FormParam("param2") String param2) {
...
}

Categories