Reputation: 3328
I'm using Spring to create a REST api. At the moment I use this structure to provide a file explorer service:
FileModel.java
package hello;
public class FileModel {
private String name;
private Long lastUpdate;
private Long size;
/**
* Void Constructor
*/
public FileModel() {
}
/**
* Parametrized constructor
* @param name
* @param created
* @param lastUpdate
* @param size
*/
public FileModel(String name, Long lastUpdate, Long size) {
super();
this.name = name;
this.lastUpdate = lastUpdate;
this.size = size;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the lastUpdate:A long value representing the time the file was last modified,
* measured in milliseconds since the epoch (00:00:00 GMT, January 1, 1970)
*/
public Long getLastUpdate() {
return lastUpdate;
}
/**
* @param lastUpdate the lastUpdate to set
*/
public void setLastUpdate(Long lastUpdate) {
this.lastUpdate = lastUpdate;
}
/**
* @return the size in bytes
*/
public Long getSize() {
return size;
}
/**
* @param size the size to set
*/
public void setSize(Long size) {
this.size = size;
}
}
FileServices.java
package hello;
import java.io.File;
import java.io.FileNotFoundException;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.util.ArrayList;
import org.springframework.stereotype.Service;
@Service
public class FileServices {
public ArrayList<FileModel> getAllFiles(String path) throws FileNotFoundException {
ArrayList<FileModel> files=new ArrayList<FileModel>();
File directory = new File(path);
if (directory.exists()){
//get all the files from a directory
File[] fList = directory.listFiles();
//check if list is null
for (File file : fList){
if (file.isFile()){
FileModel f=new FileModel(file.getName(),file.lastModified(),file.length());
files.add(f);
}
}
return files;
}
else throw new ResourceNotFoundException(path);
}
}
ResourceNotFoundException.java
package hello;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
private static final long serialVersionUID = 1L;
public ResourceNotFoundException(String path){
super("The specified path: "+ path +" doesn't exist");
}
}
FileManager
package hello;
import java.io.FileNotFoundException;
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class FileManager {
@Autowired
private FileServices file;
@RequestMapping(value = "/files", method = RequestMethod.GET)
public Collection<FileModel> getAllFiles(@RequestParam(value="path", defaultValue="/home") String path) throws FileNotFoundException {
return file.getAllFiles(path);
}
}
The response is either error message like this
> { "timestamp": 1442560477794, "status": 404, "error": "Not
> Found", "exception": "hello.ResourceNotFoundException", "message":
> "The specified path: /home doesn't exist", "path":
> "/MatlabLib/files" }
or this.
[
{
"name": "apache-tomcat-8.0.26-windows-x64.zip",
"lastUpdate": 1441282759343,
"size": 10470002
},
{
"name": "desktop.ini",
"lastUpdate": 1441357976196,
"size": 282
}
]
Given that I have to manage this web services through other java or matlab code, I need a custom response, for example with status, error, exception, message, body so I can check status code and undestand if there is an error or less. Is there in Spring a building method to do it?
Thanks
UPDATE: I created two response class, one for ErrorResponse and one for Response with different number of fied. Then I used
@ControllerAdvice
public class ErrorController {
/**
*
* @param e: exception thrown
* @return ErroreResponse
*/
@ExceptionHandler(Exception.class)
public @ResponseBody ErrorResponse errorHandler(Exception e){
//Make the exception by buildErrorResponse
return ErrorResponseBuilder.buildErrorResponse(e);
}
in the ErrorResponseBuilder made this method:
/**
* Build exception response beginning from exception
* @param e exception thrown
* @return ErrorResponse: response of an exception
*/
public static ErrorResponse buildErrorResponse(Exception e){
StringWriter errors = new StringWriter();
e.printStackTrace(new PrintWriter(errors));
return new ErrorResponse(HttpStatusManager.getHttpCode(e),e.getClass().getName(),e.getMessage(),errors.toString());
}
and in a HttpStatusManager I implemented this:
public HttpStatusManager() {
}
/**
* Add to this class all new exception associating a code error
* @param exception
* @return
*/
public static int getHttpCode(Exception exception){
if (exception instanceof ResourceNotFoundException);
return HttpStatus.NOT_FOUND.value();
}
so from the controlle use this simple line
@RequestMapping(value = "/files", method = RequestMethod.GET)
public Response<Collection<FileModel>> getAllFiles(@RequestParam(value="path", defaultValue="/home") String path) throws ResourceNotFoundException {
Collection<FileModel> result;
result = file.getAllFiles(path);
return new Response<Collection<FileModel>>(HttpStatus.OK.value(),result);
}
What do you think?
Upvotes: 1
Views: 3854
Reputation: 2119
You could use javax.ws.rs.core.Response
which has nice API. But personally, I would rather create a custom class to handle such responses.
Of course, you need to attach to your project f.e. Jackson JSON API
so you could build methods which returns objects. Also you have to configure messageConverters
in your spring configuration file.
UPDATE
public class Response {
private Object responseBody;
private String message;
private int responseCode;
public Response() {
responseCode = 200; //default HTTP 200 OK
}
public Object getResponseBody() {
return responseBody;
}
public void setResponseBody(Object responseBody) {
this.responseBody = responseBody;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getResponseCode() {
return responseCode;
}
public void setResponseCode(int responseCode) {
this.responseCode = responseCode;
}
}
Example of usage
@RequestMapping(value = "/files", method = RequestMethod.GET)
public Response getAllFiles(@RequestParam(value="path", defaultValue="/home") String path) {
Response response = new Response();
try {
Collection<FileModel> files = file.getAllFiles(path);
response.setResponseBody(files);
} catch (FileNotFoundException e) {
Utils.setErrMessage(response, e);
}
return response;
}
Your setErrMessage
function may look like this
public void setErrMessage(Response response, Exception e) {
if(e instanceof NullPointerException) {
response.setErrCode(400); //HTTP 400 Bad Request
}
else if(e instanceof FileNotFoundException || ...) {
response.setErrCode(500); //HTTP 500 Interval Server Error
}
...
response.setMessage(e.getMessage);
}
It's just a general idea, you can change it whatever you like.
Upvotes: 2
Reputation: 1575
I have a generic reponse DTO and I use Spring @ControllerAdvice
and @ExceptionHandler
to achieve a global error handling mechanism in my rest services.
Global Error Handler Code:
@ControllerAdvice
public class WSControllerAdvice {
private static Logger logger = Logger.getLogger(SearchControllerAdvice.class);
@ExceptionHandler(Exception.class)
public @ResponseBody WSResponse<String> errorHandler(Exception e){
WSResponse<String> response = new WSResponse<String>();
logger.error("Exception occured "+e.getMessage());
response.setResponseStatus(WSResponseCode.UNHANDLED_EXCEPTION);
response.setCount(0);
response.getErrors().add("Unhandled Search Error : " + e.getMessage());
return response;
}
}
Generic Response DTO
public class WSResponse<T> {
private String responseStatus;
private long count;
private long totalNumFound;
private T results ;
private List<String> errors = new ArrayList<>();
private String nextPageMark;
private List<Facet> facets = new ArrayList<>();
}
Getter Setter removed
You have a consistent response format with this structure in place,irrespective of the fact that an exception occurs or not.
Upvotes: 1
Reputation: 5786
There are two ways to achieve this:
Catch the exception and return a POJO that describes the exception details as follows:
@RequestMapping(value = "/files", method = RequestMethod.GET)
public Object getAllFiles(@RequestParam(value="path", defaultValue="/home") String path) throws FileNotFoundException {
try{
}catch(ResourceNotFoundException rnfEx){
return new ExceptionDTO("ERR-001","Resource not found");
}
}
where the ExceptionDTO
represents a POJO that would transform to JSON
Use @ExceptionHandler
to handle the same functionality.
Example : http://www.journaldev.com/2651/spring-mvc-exception-handling-exceptionhandler-controlleradvice-handlerexceptionresolver-json-response-example
Upvotes: 0