写一个Restful接口很简单,但是要写出一个健壮而优雅的接口并不容易,通常一个接口包含输入请求参数、输出响应消息及接口中的异常输出。通过对输入请求参数在入口处统一校验,可以及早发现数据的问题,规范统一的响应输出和异常信息使你的Restful接口变得更优雅。
一、使用validation对输入参数进行校验
如果接口的输入信息不在入口处进行校验,我们就需要在业务层写上很多的判断逻辑,比如下面这种写法:
@Override
public void addMovie(Movie movie) {
if (StringUtils.isEmpty(movie.getName())) {
throw new BusinessException("电影名称不能为空");
}
if (movie.getDuration() == null) {
throw new BusinessException("电影时长不能为空");
}
if (StringUtils.isEmpty(movie.getDescription())){
throw new BusinessException("电影描述不能为空");
}
if (CollectionUtils.isEmpty(movie.getActors())) {
throw new BusinessException("演员不能为空");
}
//业务代码
}
从上面的代码可以看出业务代码还没有开始写,已经写了一堆的逻辑判断,看起来很不优雅,使用java和spring 的validation可以让我们只关注业务逻辑二不用去担心数据是否规范的问题。
- 在maven的pom文件中引入validation
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>${validation-api.version}</version>
</dependency>
- 编写 entity类
使用@NotEmpty和@NotNull等注解标注需要进行校验的字段
@Getter
@Setter
public class Movie {
private String id;
@NotEmpty(message = "Movie name cannot be empty")
private String name;
@NotNull(message = "电影时长不能为空")
private Integer duration;
@NotNull(message = "演员不能为空")
@NotEmpty(message = "演员不能为空")
private List<@Valid Actor> actors;
@NotEmpty(message = "电影描述不能为空")
private String description;
}
3.编写controller
controller上需要加上@Validated注解标注,在接口中需要校验的参数前面加上@Valid 注解,Movie前面的@Valid表示实体Movie会使用validation进行校验
@Validated
@RestController
@RequestMapping(value = "/movies")
public class MovieController {
@PostMapping
public ResponseResult addMovie(@RequestBody @Valid Movie movie) {
movieService.addMovie(movie);
System.out.println("test");
System.out.println(movie);
return ResponseResult.success();
}
}
4.编写业务代码
```java
@Override
public void addMovie(Movie movie) {
//业务代码
movieDao.save(movie);
}
二、使用统一的输出格式
1.定义响应消息体ResponseResult
code响应状态码,message 状态码描述,data响应的数据
```java
@Getter
@Setter
public class ResponseResult<T> {
/**
* 状态码
*/
int code;
/**
* 状态码描述
*/
String message;
/**
* 返回的数据
*/
T data;
private ResponseResult() {
this(200,"success");
}
private ResponseResult(int code,String message) {
this.code=code;
this.message=message;
}
private ResponseResult(ResponseMessage responseMessage) {
this.code= responseMessage.getCode();
this.message= responseMessage.getMessage();
}
private ResponseResult(int code,String message,T data) {
this.code=code;
this.message=message;
this.data=data;
}
private ResponseResult (ResponseMessage responseMessage, T data) {
this.code= responseMessage.getCode();
this.message= responseMessage.getMessage();
this.data=data;
}
public static ResponseResult success() {
return new ResponseResult();
}
public static <T> ResponseResult success(T data) {
return success(ResponseMessage.SUCCESS.getCode(),"success",data);
}
public static ResponseResult success(int code,String message) {
return success(code,message,null);
}
public static ResponseResult success(ResponseMessage responseMessage) {
return success(responseMessage.getCode(),responseMessage.getMessage(),null);
}
public static <T> ResponseResult success(ResponseMessage responseMessage,T data) {
return success(responseMessage.getCode(),responseMessage.getMessage(),data);
}
public static <T> ResponseResult success(int code,String message,T data) {
return new ResponseResult(code,message,data);
}
public static ResponseResult fail() {
return fail(ResponseMessage.FAIL.getCode(),ResponseMessage.FAIL.getMessage());
}
public static ResponseResult fail(int code,String message) {
return fail(code,message,null);
}
public static ResponseResult fail(ResponseMessage responseMessage) {
return fail(responseMessage.getCode(),responseMessage.getMessage(),null);
}
public static <T> ResponseResult fail(ResponseMessage responseMessage, T data) {
return fail(responseMessage.getCode(),responseMessage.getMessage(),data);
}
public static <T> ResponseResult fail(int code,String message,T data) {
return new ResponseResult(code,message,data);
}
}
2.定义状态码枚举
@Getter
public enum StatusCode {
/**
* 操作成功
*/
SUCCESS(200,"success"),
/**
* 新增成功
*/
ADD_SUCCESS(204,"success"),
/**
* 操作失败
*/
FAIL(-1,"fail"),
/**
* 资源不存在
*/
NOT_FOUND(404,"resource not found"),
/**
* 没有权限访问
*/
NOT_AUTH(401,"没有权限访问"),
/**
* 未知错误
*/
ERROR(500,"未知错误");
private int code;
private String message;
private StatusCode(int code, String message) {
this.code=code;
this.message=message;
}
}
三、使用@ControllerAdvice拦截异常,统一输出异常信息
1.自定义异常类BusinessException
@Getter
public class BusinessException extends RuntimeException {
private String message;
private Throwable throwable;
public BusinessException(String message) {
this(message,null);
}
public BusinessException(String message,Throwable throwable) {
super(message,throwable);
}
}
2.定义异常拦截类
程序中抛出的所有异常都会被拦截然后统一输出,避免输出不友好的异常提示信息。
@RestControllerAdvice
@ControllerAdvice
public class GlobalExceptionHandler {
/**
*
*/
@ExceptionHandler(Exception.class)
public ResponseResult handleException(Exception e) {
ResponseResult result=ResponseResult.fail(500,e.getMessage());
return result;
}
/**
* 拦截业务异常
*/
@ExceptionHandler(BusinessException.class)
public ResponseResult handleBusinessException(BusinessException e) {
return ResponseResult.fail(500,e.getMessage());
}
/**
* 拦截参数校验异常
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseResult handleMethodArgumentNotValidException(MethodArgumentNotValidException methodArgumentNotValidException) {
StringBuilder errorMessage=new StringBuilder();
List<ObjectError> objectErrors=methodArgumentNotValidException.getBindingResult().getAllErrors();
if (!CollectionUtils.isEmpty(objectErrors)) {
for (int i = 0; i < objectErrors.size(); i++) {
if (i == 0) {
errorMessage.append(objectErrors.get(i).getDefaultMessage());
} else {
errorMessage.append(",");
errorMessage.append(objectErrors.get(i).getDefaultMessage());
}
}
}else {
errorMessage.append("MethodArgumentNotValidException occured.");
}
return ResponseResult.fail(400,errorMessage.toString());
}
/**
* 拦截自定义约束异常
*/
@ExceptionHandler(ConstraintViolationException.class)
public ResponseResult handle(ConstraintViolationException constraintViolationException) {
Set<ConstraintViolation<?>> violations = constraintViolationException.getConstraintViolations();
String errorMessage = "";
if (!violations.isEmpty()) {
StringBuilder builder = new StringBuilder();
violations.forEach(violation -> builder.append(" " + violation.getMessage()));
errorMessage = builder.toString();
} else {
errorMessage = "ConstraintViolationException occured.";
}
return ResponseResult.fail(400,errorMessage);
}
}
五、使用postman测试,查看validation是否生效
转载:https://blog.csdn.net/tangyajun_168/article/details/105444944
查看评论