每个程序员都能写出简介优雅的restful接口validation(springboot)
背景
最近在开发的时候贼烦,本来是想写一个非常简洁而优雅的restful风格的代码的,controller层本来是想超级简单,可是奈何,一个接口包含输入请求参数总是需要我们去效验的。
@PostMapping("/saveIntuitiveLike")
@AdminValidable(validType = 2)
@ApiOperation(value = "直观像模块-新建直观像", notes = "", httpMethod = "POST")
public Response<?> saveIntuitiveLike(HttpServletRequest request, HttpServletResponse response,
@ApiParam(value = "直观像模块-新建直观像") @RequestBody List<SaveIntuitiveLikeNodeReq> reqList) throws Exception {
String adminName = this.getCurrentAdminName(request);
logger.info("直观像模块-新建直观像:saveIntuitiveLike,adminName is {} req is {}", adminName, JsonUtil.tranObjToStr(reqList));
//参数
if (!UtilEmpty.isNullorEmpty(reqList)) {
reqList.forEach(x->{
try {
checkIntuitiveLike(x);
} catch (OkyaException e) {
logger.info("直观像模块-新建直观像:saveIntuitiveLike error msg is ", JsonUtil.tranObjToStr(e));
e.printStackTrace();
}
});
}
intuitiveLikeBusiness.saveIntuitiveLike(reqList);
return Response.ok("创建成功");
}
public void checkIntuitiveLike(SaveIntuitiveLikeNodeReq req) throws OkyaException {
if (UtilEmpty.isNullorEmpty(req)) {
try {
throw new OkyaException("IntuitiveLikeBusiness", "checkPara", API_RESULT.PARA_CAN_NOT_EMPTY);
} catch (OkyaException e) {
e.printStackTrace();
}
}
boolean b = paramCheck( req.getAnswerJudgeTime(), req.getAnswerLists(), req.getAnswerShowTime(),
req.getAnswerTime(), req.getIntuitiveShowTime(), req.getIntuitiveType(), req.getLessonUnique());
if (!b) {
throw new OkyaException("IntuitiveLikeBusiness", "checkPara", API_RESULT.PARA_CAN_NOT_EMPTY);
}
}
然而效验就是归效验,这样写代码是简单了,然并卵,可是前段并不知道具体是哪个参数是空的呀,这就很蛋疼了。所以呢 老是会存在到底哪个参数不能非空呀。所以我们就的在swagger上标明到底哪个参数是否是要非空,可是要是哪天需求改了呢,参数就很有可能忘记修改
这个痛点一直伴随了我这苦逼的程序员很久,终于曙光到来,发现validation能够非常好的处理这个问题,废话不多说,我们直接来个Demo展现一下风采吧。
pom文件引入依赖包
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
编写DTO类
@Data
@ApiModel
public class UserSaveReq implements Serializable {
@NotEmpty(message = "用户名字不能为空")
@ApiModelProperty(value = "姓名")
private String user;
@ApiModelProperty(value = "手机号码")
@NotBlank(message = "手机号不能为空")
private String phone;
}
编写controller层
@PostMapping("/saveUser")
public String saveUser(HttpServletRequest request, HttpServletResponse response,
@ApiParam(value = "查询订单列表") @RequestBody @Valid UserSaveReq req){
UserModel userModel = new UserModel();
BeanUtils.copyProperties(req,userModel);
userService.save(userModel);
return "添加成功";
}
记得这里必须要加上@Valid注解
测试一波
接口返回400,在defaultMessage上返回了我们刚才在Dto上配置的message内容,这样展示是 好像是有点不太友好,没关系我们使用@ControllerAdvice拦截异常
首先我们封装下Response输出格式
package com.evan;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;/**
- 请求响应结果
- @author EvanYang
* @param
*/
@ApiModel(description = “返回对象”)
@Data
public class Response{
public final static String CODE_OK = “200”;
public final static String MSG_OK = “ok”;
public final static String CODE_ERROR = “5000”;
public final static String MSG_ERROR = “error”;
@ApiModelProperty(value = “返回码,200为成功,其他为失败”, required = true)
private String resultCode;
@ApiModelProperty(value = “返回码描述”, required = true)
private String resultMsg;
@ApiModelProperty(value = “结果签名”, required = true)
private String sign;
@ApiModelProperty(value = “详细数据”, required = false)
private T data;public Response() {
resultCode = CODE_OK;
resultMsg = MSG_OK;
}
public Response(String resultCode, String resultMsg) {
this.resultCode = resultCode;
this.resultMsg = resultMsg;
}
/**
- 成功结果
* - @param data
- @param
@return
*/
public staticResponse ok(T data, String sign) {
Responseresponse = new Response<>();
response.setData(data);
response.setSign(sign);
return response;
}/**
- 成功结果
* - @param data
- @param
- @return
*/
public staticResponse ok(T data) {
Responseresponse = new Response<>();
response.setData(data);
return response;
}
/**
* 失败结果
*
* @param data
* @param <T>
* @return
*/
public static <T> Response<T> error(T data) {
Response<T> response = new Response<>();
response.setData(data);
return error(CODE_ERROR, MSG_ERROR, data);
}
/**
* 失败结果
*
* @param code
* @param msg
* @param data
* @param <T>
* @return
*/
public static <T> Response<T> error(String code, String msg, T data) {
Response<T> response = new Response<>(code, msg);
response.setData(data);
return response;
}
/**
* 失败结果
*
* @param data
* @param <T>
* @return
*/
public static <T> Response<T> error(Exception exception, T data) {
return errorException(exception, data);
}
/**
* 失败结果
* @param data
* @param <T>
* @return
*/
public static <T> Response<T> errorException(Exception exception, T data) {
Response<T> response = new Response<>();
response.setData(data);
response.setResultMsg(exception.getMessage());
return response;
}
}
自定义异常类BusinessException
package com.evan.except;
/**
- @author evanYang
- @version 1.0
@date 04/11/2020 10:49
*/
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);
}
}
定义异常拦截类 程序中抛出的所有异常都会被拦截然后统一输出,避免输出不友好的异常提示信息。
package com.evan.except;
import com.evan.Response;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;/**
- @author evanYang
- @version 1.0
@date 04/11/2020 10:50
*/
@ControllerAdvice
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public Response<?> handleException(Exception e) {return Response.error( e.getMessage());
}
/**
拦截业务异常
*/
@ExceptionHandler(BusinessException.class)
public Response<?> handleBusinessException(BusinessException e) {
return Response.error( e.getMessage());
}/**
拦截参数校验异常
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public Response<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException methodArgumentNotValidException) {
StringBuilder errorMessage=new StringBuilder();
ListobjectErrors=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 Response.error(“400”, errorMessage.toString(),null);
}/**
- 拦截自定义约束异常
*/
@ExceptionHandler(ConstraintViolationException.class)
public Response<?> handle(ConstraintViolationException constraintViolationException) {
Set> violations = constraintViolationException.getConstraintViolations();
String errorMessage = “”;
if (!violations.isEmpty()) {
} else {StringBuilder builder = new StringBuilder();
violations.forEach(violation -> builder.append(" " + violation.getMessage()));
errorMessage = builder.toString();
}errorMessage = "ConstraintViolationException occured.";
return Response.error(“400”, errorMessage,null);
}
}
这会我们再来看看我们的返回信息
最后文末附上GitHUb上的工程地址:GitHub项目链接
还没有评论,来说两句吧...