以下的传参方式只针对post传参进行分析,put和delete的传参方式可以参考post请求,get请求的传参就是接在URL后面,下面几种方式接收参数对get请求来说都是一样的。
1、直接用属性接收参数
@RequestMapping("/ginseng")
public void login1(@RequestParam(value = "name" , required = false,defaultValue = "zhangsan",name = "name") String userName ,String passWord) {
log.info("传参结果" + userName + passWord);
}
@RequestMapping可以接收GET,POST,PUT,DELETE请求
1.1、@RequestParam的使用
value和name:这两个属性是针对传参的参数设置别名,这两个属性只要设置一个就行,效果是等效的。
required:传参的必须性,默认为true,必传,如果没有传这个参数就会报Required request parameter ‘name’ for method parameter type String is not present的错误
defaultValue:设置默认的值,设置默认值之后,required为false时不传参也不会报错
不使用@RequestParam注解:类似于passWord的传参,为非必传参数,默认值为null,参数名为属性名(passWord)
1.2、Post请求的传参方式
针对直接用属性来接收参数的情况GET请求只需注意传参的key和接收参数的别名保持一致即可
Post请求常见的传参方式接受 form-data和x-www-for-urlencoded的传参方式,注意传参的key和接收参数的别名保持一致。
2、用对象接受参数
package com.it520.bookkeepingweb.request;
import lombok.Data;
@Data
public class LoginRequest {
/**
* 用户名
*/
private String userName;
/**
* 密码
*/
private String passWord;
}
@RequestMapping("/ginseng")
public void login1(LoginRequest request) {
log.info("传参结果" + request.toString());
}
针对直接用属性来接收参数的情况GET请求只需注意传参的key和接收参数的别名保持一致即可
Post请求常见的传参方式接受 form-data和x-www-for-urlencoded的传参方式,注意传参的key和接收参数的别名保持一致。
3、@RequestBody对象接受参数
@RequestMapping("/ginseng")
public void login1(@RequestBody LoginRequest request) {
log.info("传参结果" + request.toString());
}
在接受参数的对象前面加上了@RequestBody的注解,就能够使POST请求的传参方式支持JSON格式的传参,这种方式也是POST请求最推荐的传参方式。
4、@Vaild数据校验
4.1、@Vaild的依赖
首先,我们在 Maven 配置中引入 @valid 的依赖:
如果你是 springboot 项目,那么可以不用引入了,已经引入了,他就存在于最核心的 web 开发包里面。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.5.RELEASE</version>
</dependency>
如果你不是 springboot 项目,那么引入下面依赖即可:
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.4.1.Final</version>
</dependency>
4.2、@Vaild的使用
第一步,在controller类接收参数的对象前面加上@Vaild的注解
@RequestMapping("/ginseng")
public void login1(@Valid LoginRequest request) {
log.info("传参结果" + request.toString());
}
第二步,在接收请求的类的属性上添加注解
package com.it520.bookkeepingweb.request;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
public class LoginRequest {
/**
* 用户名
*/
@NotNull(message = "用户名不能为null")
private String userName;
/**
* 密码
*/
private String passWord;
}
@Null
限制只能为null
@NotNull
限制必须不为null
@AssertFalse
限制必须为false
@AssertTrue
限制必须为true
@DecimalMax(value)
限制必须为一个不大于指定值的数字
@DecimalMin(value)
限制必须为一个不小于指定值的数字
@Digits(integer,fraction)
限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@Future
限制必须是一个将来的日期
@Max(value)
限制必须为一个不大于指定值的数字
@Min(value)
限制必须为一个不小于指定值的数字
@Past
限制必须是一个过去的日期
@Pattern(value)
限制必须符合指定的正则表达式
@Size(max,min)
限制字符长度必须在min到max之间
@Past
验证注解的元素值(日期类型)比当前时间早
@NotEmpty
验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@NotBlank
验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格
@Email
验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式
注意,不要错用了异常类型,比如在int上不可用@size
4.3、全局异常处理
全局异常处理能够对自定义的错误能够体现在返回结果中
第一步:自定义返回结果的封装类
package com.it520.bookkeepingweb.web.result;
import com.it520.bookkeepingcommon.constant.ErrorCodeEnum;
import lombok.Data;
@Data
public class BaseResult {
private Integer errorCode = 0;
private String errorMessage = "success";
private Object data;
public BaseResult() {
}
//自定义报错信息
public BaseResult (Integer errorCode , String errorMessage){
this.errorCode = errorCode;
this.errorMessage = errorMessage;
}
//从枚举中获取报错信息
public BaseResult (ErrorCodeEnum errorCodeEnum){
this.errorCode = errorCodeEnum.getErrorCode();
this.errorMessage = errorCodeEnum.getChErrorMessage();
}
public void packageErrorMessage(ErrorCodeEnum errorCodeEnum){
this.errorCode = errorCodeEnum.getErrorCode();
this.errorMessage = errorCodeEnum.getChErrorMessage();
}
}
自定义错误枚举
package com.it520.bookkeepingcommon.constant;
public enum ErrorCodeEnum {
ERRORCODE000(0 , "成功" ,"success"),
ERRORCODE001(1 , "登陆失败" ,"login fail"),
ERRORCODE002(2 , "参数异常" ,"ill param")
;
private final Integer errorCode;
private final String chErrorMessage;
private final String enErrorMessage;
ErrorCodeEnum(Integer errorCode, String errorChMessage, String errorZhMessage) {
this.errorCode = errorCode;
this.chErrorMessage = errorChMessage;
this.enErrorMessage = errorZhMessage;
}
public Integer getErrorCode() {
return errorCode;
}
public String getChErrorMessage() {
return chErrorMessage;
}
public String getEnErrorMessage() {
return enErrorMessage;
}
}
自定义异常处理器
package com.it520.bookkeepingweb.config;
import com.it520.bookkeepingcommon.constant.ErrorCodeEnum;
import com.it520.bookkeepingweb.web.result.BaseResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
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;
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 忽略参数异常处理器
*
* @param e 忽略参数异常
* @return ResponseResult
*/
@ExceptionHandler(value = MissingServletRequestParameterException.class)
public BaseResult parameterMissingExceptionHandler(MissingServletRequestParameterException e) {
log.error("", e);
return new BaseResult(ErrorCodeEnum.ERRORCODE002.getErrorCode(), "请求参数 " + e.getParameterName() + " 不能为空");
}
/**
* 缺少请求体异常处理器
*
* @param e 缺少请求体异常
* @return ResponseResult
*/
@ExceptionHandler(value = HttpMessageNotReadableException.class)
public BaseResult parameterBodyMissingExceptionHandler(HttpMessageNotReadableException e) {
log.error("", e);
return new BaseResult(ErrorCodeEnum.ERRORCODE002.getErrorCode(), "参数体不能为空");
}
/**
* 参数效验异常处理器
*
* @param e 参数验证异常
* @return BaseResult
*/
@ExceptionHandler(value =MethodArgumentNotValidException.class)
public BaseResult parameterExceptionHandler(MethodArgumentNotValidException e) {
log.error("", e);
// 获取异常信息
BindingResult exceptions = e.getBindingResult();
// 判断异常中是否有错误信息,如果存在就使用异常中的消息,否则使用默认消息
if (exceptions.hasErrors()) {
List<ObjectError> errors = exceptions.getAllErrors();
if (!errors.isEmpty()) {
// 这里列出了全部错误参数,按正常逻辑,只需要第一条错误即可
FieldError fieldError = (FieldError) errors.get(0);
return new BaseResult(ErrorCodeEnum.ERRORCODE002.getErrorCode(), fieldError.getDefaultMessage());
}
}
return new BaseResult(ErrorCodeEnum.ERRORCODE002);
}
/**
* 参数效验异常处理器
*
* @param e 参数验证异常
* @return BaseResult
*/
@ExceptionHandler(value =BindException.class)
public BaseResult bindExceptionHandler(BindException e) {
log.error("", e);
// 获取异常信息
StringBuilder errorMsg = new StringBuilder();
BindingResult exceptions = e.getBindingResult();
// 判断异常中是否有错误信息,如果存在就使用异常中的消息,否则使用默认消息
for (FieldError fieldError : exceptions.getFieldErrors()) {
errorMsg.append("参数:")
.append(fieldError.getField())
.append("错误:")
.append(fieldError.getDefaultMessage())
.append(" ");
}
return new BaseResult(ErrorCodeEnum.ERRORCODE002.getErrorCode() , errorMsg.toString());
}
/**
* 参数转换异常
*
* @param e 参数验证异常
* @return BaseResult
*/
@ExceptionHandler(value =ConstraintViolationException.class)
public BaseResult constraintViolationExceptionHandler(ConstraintViolationException e) {
log.error("", e);
// 获取异常信息
StringBuilder errorMessage = new StringBuilder();
Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
for (ConstraintViolation<?> constraintViolation : constraintViolations) {
errorMessage.append(constraintViolation.getMessageTemplate()).append("\\n");
}
return new BaseResult(ErrorCodeEnum.ERRORCODE002.getErrorCode() , String.valueOf(errorMessage));
}
/**
* 参数转换异常
*
* @param e 参数验证异常
* @return BaseResult
*/
@ExceptionHandler(value =ClassCastException.class)
public BaseResult classCastExceptionHandler(ClassCastException e) {
log.error("", e);
// 获取异常信息
String errorMessage = e.getMessage();
return new BaseResult(ErrorCodeEnum.ERRORCODE002.getErrorCode() , errorMessage);
}
}
异常处理器常见的三大异常
ConstraintViolationException:不符合验证规则时触发
BindException:使用form data方式调用接口,校验异常抛出 BindException
MethodArgumentNotValidException:使用 json 请求体调用接口,校验异常会抛出此错误
相对于其他的错误,可以从控制台报错的情况中对该错误进行处理,同时也可以使用Exception对其他不想处理的错误进行处理。
当在异常处理器中同时使用了Exception和ConstraintViolationException时,如果验证器触发了ConstraintViolationException,就只会执行ConstraintViolationException所在的处理方法,而不会调用Exception处理方法,所以异常处理器会优先处理已经有所指明的异常,只有在异常处理器中没有对该异常进行声明的情况下才会执行Exception所在的异常处理方法。
对这个有更深的了解可以参考这篇文章https://blog.csdn.net/qq_45515182/article/details/125766858
这篇文章对@Valid的使用以及异常处理做了很好的解答
java实现HTTP接口的各种传参方式的实现可以参考我的文章https://blog.csdn.net/m0_46616045/article/details/126130783