Android: Call to Spring MVC Restful WebService - java

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 ?

Related

Angular and Spring boot -> POST Request response 403

I have a problem with Spring boot and Angular. I make a POST request which works on POSTMAN and locally but which gives me a 403 in production on tomcat with apache as reverse proxy. But it's working when I am with the embedded tomcat.
I have to try everything soon.
All the solutions I've seen say to disable CSFR but I have no authentication to access my webservice and therefore no spring-security dependency.
I tried anyway but the problem is still there. And in some cases it required me to log in which I don't want to do
import ch.megahertz.swissqrbillsgeneratorapi.properties.FileStorageProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
#SpringBootApplication(scanBasePackages = {"ch.megahertz.swissqrbillsgeneratorapi.*"})
#EnableConfigurationProperties({
FileStorageProperties.class
})
public class SwissQrBillsGeneratorApiApplication extends SpringBootServletInitializer {
static Logger logger = LoggerFactory.getLogger(SwissQrBillsGeneratorApiApplication.class);
public static void main(String[] args) {
logger.info("Run application");
SpringApplication.run(SwissQrBillsGeneratorApiApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SwissQrBillsGeneratorApiApplication.class);
}
}
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
public class WebMvcConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("*")
.allowedHeaders("*")
.allowedOrigins("*")
.allowCredentials(false)
.maxAge(-1);
}
}
import ch.megahertz.swissqrbillsgeneratorapi.payload.Invoice;
import ch.megahertz.swissqrbillsgeneratorapi.service.CRMService;
import ch.megahertz.swissqrbillsgeneratorapi.service.FileStorageService;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
//#CrossOrigin(origins = {"https://swissqrbillsgenerator.megahertz.ch/","http://localhost:4200/"})
#Slf4j
#RestController
public class ApiController {
private static final Logger logger = LoggerFactory.getLogger(ApiController.class);
#Autowired
private FileStorageService fileStorageService;
#Autowired
private CRMService crmService;
#GetMapping
public String generateQRBills() {
log.info("Enter in GeT API");
return "Get ok";
}
#PostMapping("/generate")
public ResponseEntity<Resource> uploadFile(#RequestParam("file") MultipartFile file) throws IOException {
System.out.println("Enter in generate API");
logger.info("Enter in generate API");
log.info("Enter in generate POST API");
String fileName = fileStorageService.storeFile(file);
String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
.path("/downloadFile/")
.path(fileName)
.toUriString();
Invoice facture = crmService.getFactureInfo(fileName);
File fileWithQR = fileStorageService.addQrToFile(fileName, facture);
Resource resource = new UrlResource(fileWithQR.toURI());
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_TYPE,Files.probeContentType(resource.getFile().toPath()))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName+ "\"")
.body(resource);
}
}
Do you have any idea?
If Postman is returning the query, then the problem is probably in the Angular front end. I believe I was getting a 403 error when I tried to send a String from my backend, it had to be wrapped in an object and unwrapped by Angular to be a string in Angular.

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
}

Java EE - Return 415 status

I'm creating an WEB Api with Java and Jersey and now i get 415 status code on a POST request to my API.
The request made by Postman with the Header Content-type application/json
These images show my request
And that is my code.
package api;
import java.sql.SQLException;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import DAO.TransactionDAO;
import DAO.UsersDAO;
import Entity.Transaction;
import Entity.Users;
#Path("/users")
public class UsersController {
private UsersDAO dao;
private static final String CHARSET = ";charset=UTF-8";
#PostConstruct
private void init(){
this.dao = new UsersDAO();
}
#POST
#Path("/add")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.TEXT_PLAIN)
public int insert(Users user){
try{
return this.dao.add(user);
}
catch(Exception e){
e.toString();
return 0;
}
}
}
I found the error. My model didn't have an empty constructor. I just create it and work.

Method POST not supported Netflix Eureka and ZUUL

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

Spring restTemplate execute( ) POST large files and obtain a response

This took me quite a while to work out so I wanted to share it. Most information came from SO and I wanted to consolidate into this one place.
My requirements are to upload files using a RESTFul POST. Due to possibly large files I wanted to stream the files. I obviously want to be able to read the response.
I planned to use Jersey as the REST Server and Spring's RestTemplate as the client (and for testing).
The problem I faced was streaming POSTs and receiving a response. How can I do that? (Rhetorical question - I answer this!)
It's unnecessary to go through all these hoops with a RequestCallback. Simply use a PathResource.
PathResource pathResource = new PathResource(theTestFilePath);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(pathResource), String.class);
Spring will use a ResourceHttpMessageConverter to serialize the file identified by the given Path to the request body. Internally, the Spring 4.x implementation uses a buffer size of 4096 bytes (which is also what IOUtils#copy(..) uses).
Obviously, you can provide the response type you want. The example above expects the response body as a String. With a ResponseEntity, you can access all the response headers with
HttpHeaders responseHeaders = response.getHeaders();
I am using SpringBoot 1.2.4.RELEASE with Jersey being pulled in by:
compile("org.springframework.boot:spring-boot-starter-jersey")
I created the project with the brilliant Spring Starter Project (Spring Tool Suite > New or you can do through a website I believe and no doubt IntelliJ has this capability also). And chose 'Jersey (JAX-RS)' option. In the gradle build.gradle I also added the dependency:
compile('commons-io:commons-io:2.4')
I wrote this server side code.
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
import org.me.fileStore.service.FileStoreService;
#RestController
#Path("/filestore")
public class FileStoreRestService {
private static Logger logger = LoggerFactory.getLogger(FileStoreRestService.class);
#Autowired
private FileStoreService fileStoreService;
#POST
#Path("upload")
#Consumes(MediaType.APPLICATION_OCTET_STREAM)
#Produces(MediaType.APPLICATION_JSON)
public Response Upload(InputStream stream) throws IOException, URISyntaxException { //
String location = fileStoreService.upload(stream); // relative path
URI loc = new URI(location);
Response response = Response.created(loc).build();
System.out.println("POST - response: " + response + ", :" + response.getHeaders());
return response;
}
Where i had most troubles was in getting a Response with a location.
Firstly I had to handle streaming large files. I followed https://stackoverflow.com/a/15785322/1019307 as you can see in the test below. I was NOT obtaining a Response no matter what I tried with the HttpMessageConverterExtractor as per that post:
final HttpMessageConverterExtractor<String> responseExtractor =
new HttpMessageConverterExtractor<String>(String.class, restTemplate.getMessageConverters());
After finding https://stackoverflow.com/a/6006147/1019307 I wrote:
private static class ResponseFromHeadersExtractor implements ResponseExtractor<ClientHttpResponse> {
#Override
public ClientHttpResponse extractData(ClientHttpResponse response) {
System.out.println("StringFromHeadersExtractor - response headers: " + response.getHeaders());
return response;
}
}
This gave me this test:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.TestRestTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.client.RequestCallback;
import org.springframework.web.client.ResponseExtractor;
import org.springframework.web.client.RestTemplate;
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = FileStoreApplication.class)
#WebAppConfiguration
#IntegrationTest("server.port:9000")
public class FileStoreRestServiceTest {
private static Logger logger = LoggerFactory.getLogger(FileStoreRestServiceTest.class);
protected final Log logger2 = LogFactory.getLog(getClass());
String base = "http://localhost:9000/filestore";
private RestTemplate restTemplate = new TestRestTemplate();
#Test
public void testMyMethodExecute() throws IOException {
String content = "This is file contents\nWith another line.\n";
Path theTestFilePath = TestingUtils.getTempPath(content);
InputStream inputStream = Files.newInputStream(theTestFilePath);
String url = base + "/upload";
final RequestCallback requestCallback = new RequestCallback() {
#Override
public void doWithRequest(final ClientHttpRequest request) throws IOException {
request.getHeaders().setContentType(MediaType.APPLICATION_OCTET_STREAM);
IOUtils.copy(inputStream, request.getBody());
}
};
final RestTemplate restTemplate = new RestTemplate();
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setBufferRequestBody(false);
restTemplate.setRequestFactory(requestFactory);
ClientHttpResponse response = restTemplate.execute(url, HttpMethod.POST, requestCallback,
new ResponseFromHeadersExtractor());
URI location = response.getHeaders().getLocation();
System.out.println("Location: " + location);
Assert.assertNotNull(location);
Assert.assertNotEquals(0, location.getPath().length());
}
private static class ResponseFromHeadersExtractor implements ResponseExtractor<ClientHttpResponse> {
#Override
public ClientHttpResponse extractData(ClientHttpResponse response) {
System.out.println("StringFromHeadersExtractor - response headers: " + response.getHeaders());
return response;
}
}
I need to refactor much in that test out into some services.

Categories

Resources