Java 使用SpringMVC管理REST响应
我正在使用Spring创建一个RESTAPI。目前,我使用此结构提供文件资源管理器服务: FileModel.javaJava 使用SpringMVC管理REST响应,java,spring,rest,spring-mvc,exception,Java,Spring,Rest,Spring Mvc,Exception,我正在使用Spring创建一个RESTAPI。目前,我使用此结构提供文件资源管理器服务: FileModel.java package hello; public class FileModel { private String name; private Long lastUpdate; private Long size; /** * Void Constructor */
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);
}
}
文件管理器
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);
}
}
或者这个
[
{
"name": "apache-tomcat-8.0.26-windows-x64.zip",
"lastUpdate": 1441282759343,
"size": 10470002
},
{
"name": "desktop.ini",
"lastUpdate": 1441357976196,
"size": 282
}
]
由于我必须通过其他java或matlab代码来管理此web服务,因此我需要一个自定义响应,例如状态、错误、异常、消息、正文,这样我就可以检查状态代码,并在出现错误或更少的情况下取消识别。
春天有没有一种建筑方法
谢谢
更新:我创建了两个响应类,一个用于ErrorResponse,另一个用于具有不同数量响应的响应。然后我用
@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);
}
在ErrorResponseBuilder中,创建了以下方法:
/**
* 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());
}
在HttpStatusManager中,我实现了以下功能:
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();
}
因此,从控制器开始,使用这条简单的线
@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);
}
@RequestMapping(value=“/files”,method=RequestMethod.GET)
公共响应getAllFiles(@RequestParam(value=“path”,defaultValue=“/home”)字符串路径)引发ResourceNotFoundException{
收集结果;
结果=file.getAllFiles(路径);
返回新响应(HttpStatus.OK.value(),结果);
}
你觉得怎么样?你可以使用
javax.ws.rs.core.Response
这个API很好。但就个人而言,我宁愿创建一个自定义类来处理此类响应
当然,您需要附加到项目f.e.Jackson JSON API
,以便构建返回对象的方法。您还必须在spring配置文件中配置messageConverters
更新
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;
}
}
用法示例
@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;
}
这只是一个一般的想法,你可以随意改变它。有两种方法可以实现这一点:
- 捕获异常并返回描述异常详细信息的POJO,如下所示:
其中,@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"); } }
表示将转换为JSON的POJOExceptionTo
- 使用
处理相同的功能。 例如:@ExceptionHandler
@ControllerAdvice
和@ExceptionHandler
在我的rest服务中实现全局错误处理机制
全局错误处理程序代码:
@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;
}
}
@ControllerAdvice
公共类WSControllerAdvice{
私有静态记录器=Logger.getLogger(SearchControllerAdvice.class);
@ExceptionHandler(Exception.class)
public@ResponseBody WSResponse errorHandler(异常e){
WSResponse=新的WSResponse();
logger.error(“发生异常”+e.getMessage());
response.setResponseStatus(WSResponseCode.UNHANDLED_异常);
响应。设置计数(0);
response.getErrors().add(“未处理的搜索错误:+e.getMessage());
返回响应;
}
}
通用响应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<>();
}
公共类WSResponse{
私有字符串响应状态;
私人长计数;
私人长途电话;
私人T结果;
私有列表错误=新建ArrayList();
私有字符串nextPageMark;
私有列表facets=newarraylist();
}
吸气剂设定器已移除
无论是否发生异常,您都有一个与此结构保持一致的响应格式。这不是Spring的东西,但我想它可能适合您的需要:javax.ws.rs.core.response。它已经存在,称为HTTP。在第一种情况下,在后200种情况下,您的http代码将是404。基本上,400或500范围内的某个值表示一个错误…我的想法是使用一个新类,例如ResponeBulder,它有以下字段:status、error、exception、message、body。然后,如果我有一个错误,在一个构造函数的主体中使用null,如果我有一个状态码,在另一个字段中使用null。这是个好主意吗?如何从我的异常中检索状态代码、错误和异常?这是一个非常好的主意(也建议使用生成器模式)。如果我正确理解您的问题,如果您正在调用某个方法,并且在处理异常时会发生,为什么不使用try-catch块呢?您可以轻松地从catch块中的exception对象中提取错误消息、异常类等,然后将其设置为您的ResponeBuilder对象。就错误代码而言,您可以自己分配它们。您可以创建一个类似int-getExceptionCode(Exception e)的方法,并根据异常类型返回正确的代码。你可能需要区分十几种不同的代码,我得试试。主体是字符串变量吗?使用构建器模式而不是一个包含两个方法()的类(一个包含http,另一个包含http和异常)是否有用?我一完成就向您推荐Builder模式将是一个不错的选择,因为它非常优雅,在您的情况下,您可以设置可变的字段数(例如,如果没有发生异常,您不会设置所有错误字段,如果出现异常,您也不会设置正文)。对于一种身体元素,它实际上取决于你的需要。如果您的服务只返回一件事(XML、单值,…),则字符串可能就足够了。但如果您有更复杂的响应,您也可以为body创建一个自定义类。我如何使用它?因此,在web服务器中,毫无例外地,我必须设置空值?如果您成功地处理了请求,那么您的
errors
数组将为空。
@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");
}
}
@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;
}
}
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<>();
}