Java 包装ResponseEntity ajax风格主体的最佳实践?
通过Java 包装ResponseEntity ajax风格主体的最佳实践?,java,spring-mvc,generics,Java,Spring Mvc,Generics,通过ResponseEntity我们可以直接控制HTTP响应;我们可以设置头、正文和HTTP响应代码。假设在客户端,我们有一个通用的AJAX数据服务,它需要三个响应状态条件:成功,失败,和错误——此状态将与HTTP状态代码分开评估,当然由$.AJAX负责。因此,ResponseEntity的主体需要某种类型的通用对象,可能类似于下面的内容,其中JsonResponse中的数据是客户端请求的任何数据;用户列表、任意数据的地图、任何内容(稍后将详细介绍): ResponseEntityFactory
ResponseEntity
我们可以直接控制HTTP响应;我们可以设置头、正文和HTTP响应代码。假设在客户端,我们有一个通用的AJAX数据服务,它需要三个响应状态条件:成功
,失败
,和错误
——此状态将与HTTP状态代码分开评估,当然由$.AJAX
负责。因此,ResponseEntity
的主体需要某种类型的通用对象,可能类似于下面的内容,其中JsonResponse
中的数据是客户端请求的任何数据;用户列表、任意数据的地图、任何内容(稍后将详细介绍):
ResponseEntityFactory.java
public class ResponseEntityFactory {
private enum ResponseStatus {
SUCCESS, FAIL, ERROR
}
public static ResponseEntity success (String message, Object data) {
return getResponseEntity(HttpStatus.OK, ResponseStatus.SUCCESS, message, data, null);
}
/* ADDITIONAL SUCCESS, FAIL, ERROR FACTORY METHODS */
private static ResponseEntity getResponseEntity(HttpStatus httpStatus, ResponseStatus responseStatus, String message, Object data, HttpHeaders headers) {
if (httpStatus == null) throw new IllegalArgumentException("HttpStatus cannot be null");
if (responseStatus == null) throw new IllegalArgumentException("ResponseStatus cannot be null");
JsonResponse jsonResponse = new JsonResponse(responseStatus, message, data);
return new ResponseEntity(jsonResponse, headers, httpStatus);
}
private static class JsonResponse {
private ResponseStatus status;
private String message;
private Object data;
public JsonResponse(ResponseStatus status, String message, Object data) {
if (status == null) throw new IllegalArgumentException("ResponseStatus cannot be null");
this.status = status;
this.message = message;
this.data = data;
}
public ResponseStatus getStatus() {
return status;
}
public void setStatus(ResponseStatus status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
}
@Controller
@RequestMapping(value = "/example")
public class ExampleController {
@Autowire
private UserService userService;
@RequestMapping(method = RequestMethod.GET)
public ResponseEntity getUsers() {
List<User> users = userService.getAllUsers();
return AjaxResponseFactory.success("Found users", userList);
}
@RequestMapping(value = "/active/{id}" method = RequestMethod.GET)
public ResponseEntity isUserActive(long userId) {
boolean = userService.isUserActive(userId);
return AjaxResponseFactory.success(null, boolean);
}
}
ExampleController.java
public class ResponseEntityFactory {
private enum ResponseStatus {
SUCCESS, FAIL, ERROR
}
public static ResponseEntity success (String message, Object data) {
return getResponseEntity(HttpStatus.OK, ResponseStatus.SUCCESS, message, data, null);
}
/* ADDITIONAL SUCCESS, FAIL, ERROR FACTORY METHODS */
private static ResponseEntity getResponseEntity(HttpStatus httpStatus, ResponseStatus responseStatus, String message, Object data, HttpHeaders headers) {
if (httpStatus == null) throw new IllegalArgumentException("HttpStatus cannot be null");
if (responseStatus == null) throw new IllegalArgumentException("ResponseStatus cannot be null");
JsonResponse jsonResponse = new JsonResponse(responseStatus, message, data);
return new ResponseEntity(jsonResponse, headers, httpStatus);
}
private static class JsonResponse {
private ResponseStatus status;
private String message;
private Object data;
public JsonResponse(ResponseStatus status, String message, Object data) {
if (status == null) throw new IllegalArgumentException("ResponseStatus cannot be null");
this.status = status;
this.message = message;
this.data = data;
}
public ResponseStatus getStatus() {
return status;
}
public void setStatus(ResponseStatus status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
}
@Controller
@RequestMapping(value = "/example")
public class ExampleController {
@Autowire
private UserService userService;
@RequestMapping(method = RequestMethod.GET)
public ResponseEntity getUsers() {
List<User> users = userService.getAllUsers();
return AjaxResponseFactory.success("Found users", userList);
}
@RequestMapping(value = "/active/{id}" method = RequestMethod.GET)
public ResponseEntity isUserActive(long userId) {
boolean = userService.isUserActive(userId);
return AjaxResponseFactory.success(null, boolean);
}
}
@控制器
@请求映射(value=“/example”)
公共类示例控制器{
@自动连线
私人用户服务;
@RequestMapping(method=RequestMethod.GET)
公共响应getUsers(){
List users=userService.getAllUsers();
返回ajaxsresponsefactory.success(“找到的用户”,userList);
}
@RequestMapping(value=“/active/{id}”method=RequestMethod.GET)
公共响应属性isUserActive(长用户ID){
boolean=userService.isUserActive(userId);
返回AjaxResponseFactory.success(null,布尔值);
}
}
ResponseEntityFactory
简化了控制器,但我对这个问题的全部关注集中在JsonResponse
中的数据
变量(类型为对象
)上。从我到目前为止所做的测试来看,一切都是正确序列化的:单个原语、简单的字符串列表或长的、更复杂的域对象。所以我的问题是,这样可以吗?还有别的选择吗?以某种方式使用泛型的机会
同样,主要目标是能够将HTTP响应代码与响应状态代码成功
、失败
、错误
分开评估-这本身就允许在响应服务器响应时具有更大的粒度。例如,fail
条件可能与http200ok
一起返回;HTTP请求成功,否则设置它是不合适的,但是有一个验证错误(可能是空用户名或其他),这不允许在服务器上执行操作。可以说,这些类型的场景在技术上属于400坏请求类型
,但我倾向于同意人们的观点,即即使使用最新的RFC400
定义,这些状态也应该与合法的错误请求相关联,而不是业务逻辑中的必然和任意问题
那么,如果我想在ResponseEntity
中使用JsonResponse
类型对象响应浏览器,那么确保数据
对象正确序列化的最佳方法是什么?我愿意接受任何建议或替代方案——与此无关,只是似乎是一种合理的方法。但我很想看看用泛型解决这个问题是否可行和/或更可取 返回不同数据类型的端点类似于meh。否则,为什么要使用泛型?http通信的另一端看不到它从responseEntityTanks获得的响应文本-我不确定我是否理解您关于不同数据类型的第一点。如果每个控制器都在使用EntityResponseFactory,上面的操作会这样做吗?和wrt泛型相比,我认为它可能是一种更好的方法,以列表的方式直接使用java.lang.Object,而不是列表类型,但我的理解可能会被误导;泛型知识有限,以及它们在UI中的使用方式。我想你的最后一点可能会回答我的问题,不管怎样,一切都是对象,那么这里的危害是什么呢?在大多数情况下,我会返回一个域或DTO对象列表,而不是字符串列表,因此对serializationwrt类型的关注增加了:当一个方法可以返回list
,下次某个DomainObject时。从$.ajax
使用API会很难看,因为没有固定的json模式。您可以使用ResponseEntity
来实现这一点。我想你不会想的对象与精确指定的对象:您最感兴趣的是查看方法返回的内容。像json文档自动生成器这样的一些工具可能也需要这样的功能。另一方面,序列化程序很少关心。因为即使使用泛型,例如列表
,它也必须检查具体的类型,看看是否必须进行特殊的序列化。啊,我认为我在控制器中使用getData()方法作为示例必然会造成混乱-我用一个更真实的示例更新了这个问题,说明我的控制器看起来如何。当然,对于每个适用的端点(/users,/admin等),我都会有一个控制器,每个控制器都有描述性的方法,而不是像getData()那样的方法。另外,对于JS端,每个端点都有一个对应的JS服务(user_service.JS、admin_service.JS),当然所有这些都使用更通用的数据服务来执行ajax调用。返回不同数据类型的端点有点像meh。否则,为什么要使用泛型?http通信的另一端看不到它从responseEntityTanks获得的响应文本-我不确定我是否理解您关于不同数据类型的第一点。如果每个控制器都在使用EntityResponseFactory,上面的操作会这样做吗?和wrt泛型相比,我认为它可能是一种更好的方法,以列表的方式直接使用java.lang.Object,而不是列表类型,但我的理解可能会被误导;限制