Method POST not supported Netflix Eureka and ZUUL - java

I am creating a Rest controller in JAVA . When I run the application locally , I am able to do POST operations. Then I create a JAR and then deploy it on a server . Plz note that I am using Netflix Eureka for service discovery and zuul as API gateway . The application starts running fine on server and it is registered in Eureka server as well . But when I use POST service , its giving me error : 405 Method Post not supported .
Controller class
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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 com.bp.budgetpulse.domain.FeedBackEmployeeDetails;
import com.bp.budgetpulse.service.FeedBackService;
#RestController
#RequestMapping(value = "/api/v1")
public class FeedBackController {
#SuppressWarnings("unused")
private final Logger logger = LoggerFactory.getLogger(FeedBackService.class);
#Autowired
private FeedBackService feedbackService;
/**
* This method to save the feedback details
*
* #param feedbackDetails
* #param userName
* #return response
*/
#RequestMapping(value = "/saveEmployeeFeedbackDetails", method = RequestMethod.POST)
public String saveEmployeeFeedbackDetails(#RequestBody FeedBackEmployeeDetails empFeedbackDetails) {
return feedbackService.saveEmployeeFeedbackDetails(empFeedbackDetails);
}
/**
*
* this method to get the feedback details
*
* #return feedback details
*/
#RequestMapping(value = "/getFeedBackDetails/{email}", method = RequestMethod.GET)
public FeedBackEmployeeDetails getFeedBackDetails(#PathVariable String email) {
return feedbackService.getFeedBackDetails(email);
}
}

POST method is supported in Netflix Eureka and ZUUL. Netflix Eureka and ZUUL do not impose any restriction on the API Methods. Here is a sample controller code that I have written that works without any issues in a Netflix Eureka and ZUUL environment:
import com.aj.gradingservice.model.Grade;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
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 java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
#RestController
#RequestMapping("/")
public class GradeController {
private static final Logger logger = LoggerFactory.getLogger(GradeController.class);
#RequestMapping(value = "ping", method = RequestMethod.GET)
public ResponseEntity<Map<String, String>> ping() {
Map<String, String> response = new HashMap<>();
response.put("message", "pong");
return new ResponseEntity<>(response, HttpStatus.OK);
}
#RequestMapping(value = "grades", method = RequestMethod.GET)
public ResponseEntity<List<Grade>> getGrades() {
logger.info("In GradeController.getGrades(), fetching list of grades");
List<Grade> grades = new ArrayList<>();
grades.add(new Grade(1, "P001", "A+"));
grades.add(new Grade(2, "C001", "A"));
grades.add(new Grade(3, "M001", "B+"));
return new ResponseEntity<>(grades, HttpStatus.OK);
}
#RequestMapping(value = "grade", method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE,produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Grade> createGrade(#RequestBody Grade grade) {
logger.info("Request received is: " + grade );
Grade gradeCreated = new Grade(grade.getId(),grade.getStudentId(),grade.getGrade());
return new ResponseEntity<>(gradeCreated, HttpStatus.OK);
}
}
I have written a blog post with the detailed explanation of setting up a Netflix Eureka and Zuul environment and there is end to end working code in GitHub. Please check: http://softwaredevelopercentral.blogspot.com/2018/02/spring-cloud-eureka-and-zuul.html

Related

PostMapping annotation causes a whitelabel error page in SpringBoot

I'm new to Java and react web development and I'm having an issue with my postBody method. After sending a post request, the console prints the data posted from my frontend correctly, but it shows a whitelabel error page that says (type=Not Found, status=404) in localhost:8080/api and (type=Method Not Allowed, status=405) in localhost:8080/api/data. Below is the HelloController code.
package com.java.java.practice;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.MediaType;
import org.springframework.web.cors.CorsConfiguration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
#RestController
#RequestMapping("/api")
public class HelloController {
//this performes a post and get request
#CrossOrigin(origins = "http://localhost:3000/api")
#PostMapping(value="/n", consumes = MediaType.APPLICATION_JSON_VALUE)
public String postBody(#RequestBody String fullName) {
System.out.println(fullName);
return "Hello " + fullName; //returns response
}
}
Below is the main application
package com.java.java.practice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication
#ComponentScan(basePackages="com.java.java.practice")
public class PracticeApplication {
public static void main(String[] args) {
SpringApplication.run(PracticeApplication.class, args);
}
}
The weird thing is, when I replace my HelloController code with the one posted underneath, the whitelabel page goes away and shows text on the screen.
package com.java.java.practice;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.MediaType;
import org.springframework.web.cors.CorsConfiguration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
#RestController
public class HelloController {
//this performes a post and get request
#CrossOrigin(origins = "http://localhost:3000/api")
#RequestMapping("/api")
public String postBody() {
return "Hello"; //returns response
}
}
Any help would be much appreciated.
I can see a few issues as below,
When you try to call via a web browser it's always calling as HTTP GET. But in your RestController, there is no GET method. It only has a POST method. Try to use Postman or CURL to call post method instead of GET.
Your URL is wrong. Since you appending /n for the PostMapping annotation it should be (http://localhost:3000/api/n)
Only you want fullName as request body try to use PathVariable instead. No point to use RequestBody only for 1 parameter. Sample code as below.
#PostMapping(value="/{fullName}", consumes = MediaType.APPLICATION_JSON_VALUE)
public String postBody(#PathVariable String fullName) {
System.out.println(fullName);
return "Hello " + fullName; //returns response
}

After disabled Http GET method, how to unit test it?

So in my Spring controller, i have this route
#RequestMapping(value = "myroute", method = POST)
public String myRoute(HttpServletRequest) {
...
}
We use MockMvcBuilder to mock the POST calls.
MockHttpServletRequestBuilder post = post(myRouteUrl);
mockMvc.perform(post).andExpect(status().isOK());
Now if i just change post to get, the status back is still 200.
So how to verify GET method is failing ?
Using Java 1.8.
Thanks !
I got a HTTP error 405 when I tried the following. Is there something else missing from the example shown?
This is the controller class I used.
package demo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
#RestController
public class MyController {
#RequestMapping(value = "/myroute", method = GET)
public String myRoute(HttpServletRequest request) {
System.out.println("HERE");
return "good";
}
}
This is the test class I used.
package demo;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#ExtendWith(MockitoExtension.class)
#WebMvcTest(MyController.class)
class MyControllerTest {
#Autowired
private MockMvc mockMvc;
#Test
void myRoute() throws Exception {
MockHttpServletRequestBuilder post = post("/myroute");
mockMvc.perform(post).andExpect(status().isOk());
}
}
Error Message:
Error message = Request method 'POST' not supported
Headers = [Allow:"GET"]
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
Status expected:<200> but was:<405>
Expected :200
Actual :405

Send Multipart and JSON data in a Java Object - Spring Boot Rest

I have a java bean which has both multipart and String data. I am trying to pass it in a rest client call which takes this java bean input and processes it.
Below are my model class, controller and rest client.
On making a call from my rest client , I am getting this exception.
Exception in thread "main" org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter found for request type [com.techidiocy.models.NHPdfMergeRequest] and content type [multipart/form-data]
at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:810)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:594)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:557)
at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:384)
Model Class
import org.springframework.web.multipart.MultipartFile;
public class Candidate {
private String firstName;
private String lastName;
private MultipartFile resume;
//getters and setters
}
Controller Class
import org.springframework.beans.factory.annotation.Autowired;
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.multipart.MultipartFile;
#RestController
public class CandidateController {
#Autowired
private CandidateService candidateService;
#RequestMapping(method=RequestMethod.POST, path="/add")
public void add(#RequestBody Candidate request) {
// do some processing
String firstName = request.getFirstName();
String lastName = request.getLastName();
MultipartFile resume = request.getResume();
candidateService.add(firstName, lastName, resume);
}
}
Rest Client
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.client.RestTemplate;
public class CandidateClient {
public static void main(String[] args) throws IOException {
String serverURL = "http://localhost:8080/add";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
Candidate candidate = new Candidate();
candidate.setFirstName("John");
candidate.setLastName("Doe");
candidate.setResume(new MockMultipartFile("tmp.pdf", FileUtils.readFileToByteArray(new File("/home/john/resume/john.pdf"))));
HttpEntity<Candidate> httpEntity = new HttpEntity<Candidate>(candidate, headers);
RestTemplate client = new RestTemplate();
client.postForEntity(serverURL, httpEntity, Resource.class);
}
}
Note: I had also tried to set the header content type as json in rest client and then I am getting all the values as Null in the controller. headers.setContentType(MediaType.APPLICATION_JSON);
I had also searched over the internet for this kind of scenario but I am unable to find a solution for this.
I had also tried to pass all the parameters separately (not as part of java bean) then I am able to make it work.

How do I call MitreID OIDC server?

I am using the Spring Boot MitreID OIDC application from here. This runs OK and I can login but there are no other options available to me:
I am trying to access it using simple-web-app. In simple-web-app I try to login using URI: http://localhost:8080/openid-connect-server-webapp/. This gives:
WARN : org.mitre.openid.connect.client.service.impl.DynamicServerConfigurationService -
Couldn't load configuration for http://localhost:8080/openid-connect-server-webapp/:
com.google.common.util.concurrent.UncheckedExecutionException:
org.springframework.web.client.HttpClientErrorException: 404
ERROR: org.mitre.openid.connect.client.OIDCAuthenticationFilter - No server
configuration found for issuer: http://localhost:8080/openid-connect-server-webapp/
EDIT: when I try http://localhost:8080 I get:
WARN : org.mitre.openid.connect.client.service.impl.WebfingerIssuerService - Webfinger
endpoint MUST use the https URI scheme, overriding by configuration
ERROR: org.mitre.openid.connect.client.OIDCAuthenticationFilter - No client
configuration found for issuer: http://localhost:8080/
Can anyone point me in the right direction?
FYI simple-web-app has only one java class:
package org.mitre.web;
import java.security.Principal;
import java.util.Locale;
import java.util.Set;
import javax.annotation.Resource;
import org.mitre.openid.connect.client.OIDCAuthenticationFilter;
import org.mitre.openid.connect.client.SubjectIssuerGrantedAuthority;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* Handles requests for the application home page.
*/
#Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
// filter reference so we can get class names and things like that.
#Autowired
private OIDCAuthenticationFilter filter;
#Resource(name = "namedAdmins")
private Set<SubjectIssuerGrantedAuthority> admins;
/**
* Simply selects the home view to render by returning its name.
*/
#RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model, Principal p) {
model.addAttribute("issuerServiceClass", filter.getIssuerService().getClass().getSimpleName());
model.addAttribute("serverConfigurationServiceClass", filter.getServerConfigurationService().getClass().getSimpleName());
model.addAttribute("clientConfigurationServiceClass", filter.getClientConfigurationService().getClass().getSimpleName());
model.addAttribute("authRequestOptionsServiceClass", filter.getAuthRequestOptionsService().getClass().getSimpleName());
model.addAttribute("authRequestUriBuilderClass", filter.getAuthRequestUrlBuilder().getClass().getSimpleName());
model.addAttribute("admins", admins);
return "home";
}
#RequestMapping("/user")
#PreAuthorize("hasRole('ROLE_USER')")
public String user(Principal p) {
return "user";
}
#RequestMapping("/open")
public String open(Principal p) {
return "open";
}
#RequestMapping("/admin")
#PreAuthorize("hasRole('ROLE_ADMIN')")
public String admin(Model model, Principal p) {
model.addAttribute("admins", admins);
return "admin";
}
#RequestMapping("/login")
public String login(Principal p) {
return "login";
}
}
MitreID is serving on root but sample app is calling on /openid-connect-server-webapp/
You'll want to change your sample app to point to the proper issuer....http://localhost:8080/ (maybe in the application.properties of your sample app?) Or your MitreID server is not configured properly (possibly for issuer property)
See http://localhost:8080/.well-known/openid-configuration for all the endpoints your sample app would hit

Android: Call to Spring MVC Restful WebService

I have a restful web service which is written by using spring. Now I want to call it from my android application.
Unfortunately I am familiar with retrofit.
This is one of my method in restful web service.
import com.example.service.RosterDetailService;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
#RestController
#RequestMapping(value = "/api/v1/roster")
public class RosterDetailManagement {
private final Logger logger = LoggerFactory.getLogger(RosterDetailManagement.class);
#Autowired
private RosterDetailService rosterDetailService;
#RequestMapping(value = "/details/getGuardRecords", method = RequestMethod.POST)
#ResponseBody
public List<Map<Object, Object>> getRosterDetailsByGuardEmailAndType(#RequestBody ObjectNode params) {
logger.info("-----------RosterDetailManagement, getRosterDetailsByGuardEmailAndType 1");
Map<Object, Object> response = new HashMap<>();
String guardEmail = params.get("guardEmail").asText();
String status = params.get("status").asText();
return rosterDetailService.getRosterDetailsByGuardEmailAndType(guardEmail, status);
}
}
Now I want detailed steps to call this restful web service in android.
Can anyone help me ?

Categories

Resources