SpringBoot Json数据交互

一、Json报文

SpringBoot默认会使用Json作为响应报文格式。

首先,我们创建一个UserController用于处理前端的Web请求。定义一个简单的控制器,与通常返回URL的Controller不一样的是,login()使用了@ResponseBody注解,它表示此接口响应为纯数据,不带任何界面展示,可以获得标准Json。

// 等同于SpringMVC @Controller 可以返回字符串跳转至jsp等页面
@Controller
@RequestMapping("/user")
public class UserController {

  @RequestMapping("/login")
  @ResponseBody
  public RespEntity login(@RequestBody ReqUser reqUser) {
    
    // 使用reqUser模型来接受,而不用User,实现接收数据和实体的解耦和
    User user = new User();
    if (reqUser != null) {
      user.setName(reqUser.getName());
      user.setPassword(reqUser.getPassword());
    }
    // 返回的响应实体具体看下节
    return new RespEntity(RespCode.SUCCESS, user);
  }

}

【注】

使用@Controller注解,在对应的方法上,视图解析器可以解析return的jsp、html页面,并且跳转到相应页面。

若返回json等内容到页面,则需要加@ResponseBody注解。

对于上面的代码来说,还可以做进一步的优化,由于所有的Restful接口都只是返回数据,所以我们可以直接在类级别上添加 @ResponseBody注解。而大多数情况下,@Controller与@ResponseBody又会一起使用,所以我们使用@RestController注解来替换掉它们,从而更加简洁地实现功能。

二、接口规范

对于每一家公司来说,都会定义自己的数据规范,一个统一且标准的数据规范对于系统维护来说是非常重要的,也在很在程度上提升了开发效率。

1. 响应报文规范

接口响应至少需要告诉使用方三项信息:状态码、描述、数据。其中,数据不是每个接口必须的,如果只是一个简单修改的动作,可能就没有必须返回数据了。

下面我们定义一个RespEntity类来封装我们的响应报文model:

public class RespEntity {

  private int code;
  private String msg;
  private Object data;

  public RespEntity(RespCode respCode) {
    this.code = respCode.getCode();
    this.msg = respCode.getMsg();
  }

  public RespEntity(RespCode respCode, Object data) {
    this(respCode);
    this.data = data;
  }

  ...

}

同时,定义一个枚举类来维护我们的状态码:

public enum RespCode {

  SUCCESS(0, "请求成功"),
  WARN(-1, "网络异常,请稍后重试");

  private int code;
  private String msg;

  RespCode(int code, String msg) {
    this.msg = msg;
  }

  public int getCode() {
    return code;
  }

  public String getMsg() {
    return msg;
  }

}

这样,我们的响应数据规范已基本建立。

2. 请求数据规范

响应报文格式我们已经定义好了,那么请求数据我们如何接收呢?

一般来说,请求与响应会使用相同的报文形式。如果响应为Json,那么请求也建议使用Json。

为登录请求添加输入参数,首先,需要我们定义好用户实体User类,直接在映射方法login()使用该实体进行参数接收,并将接收到的参数直接返回。

填写正确的URL,选择POST方式发送请求,选择Body,将Content-Type设置成application/json,填入Json格式的请求数据,点击Send即可得到如下结果。

数据接收非常成功,但在上面的响应报文中,存在着了一个非常严重的问题,那就是用户的密码也随同用户信息一起返回给了客户端,显然这并不是一种正确的做法。

我们需要对其进行一次过滤,由于SpringBoot默认使用Jackson作为Json序列化工具,如果想要过滤掉响应中的某些字段,只需在过滤字段对应的get方法上加上@JsonIgnore注解即可。

但这样又会引发另外一个问题,那就是请求中的字段也被过滤掉了,对于这种问题,可以采用抽离请求参数模型的方式进行处理,即自定义一套参数接收的Model。比如,接收用户登录的会使用ReqUser来进行参数接收,这样使得请求参数模型与数据库映射实体完全分离,在一定程度上提升了系统的安全性。替换成Model对象后,我们就可以在数据库映射实体User上增加@JsonIgnore注解忽略该字段的序列化,而不影响请求参数的输入。

三、参数校验

出于系统健壮性的考虑,我们需要对所有的参数进行必要性校验,如:登录请求时,如果没有用户名,程序应该立即驳回该请求。上面请求参数模型(Model)的抽象也使得我们对数据校验更加方便,当然主要还是依赖于SpringBoot的Validate功能的强大支持。

1. 简单参数校验

对于登录接口来说,用户名与密码都是必须的,那么我们现在为其添加上对应的参数校验,无需if-else判断,简单的几个注解就可以帮助我们完成所有的工作。

public class LoginController {

  @RequestMapping("/login")
  @ResponseBody
  public RespEntity login(@RequestBody @Valid ReqUser reqUser) {

  }

}
public class ReqUser {

  @NotBlank(message = "用户名不能为空")
  public String getName() {
    return name;
  }

  @NotBlank(message = "密码不能为空")
  public String getPassword() {
    return password;
  }

  ...

}

我们为请求参数的Model对象ReqUser加上了@Valid注解,并在Model类中对需要校验字段的get方法上添加相应的校验注解。效果如下:

2. 复杂参数校验

(1)正则表达式校验

如果用户的登录名为手机号,那么就需要对登录名的格式做进一步的校验,下面使用正则表达式来校验手机号的合法性。

@NotBlank(message = "用户名不能为空")
@Pattern(
    regexp = "1(([38]\\d)|(5[^4&&\\d])|(4[579])|(7[0135678]))\\d{8}",
    message = "手机号格式不合法"
)
public String getUsername() {
  return username;
}

(2)自定义校验注解

在系统使用过程中,有很多地方需要对手机号的格式进行校验,如:注册、验证码发送等。但校验手机号的正则表达式又过于复杂,如果多处编写,一旦运营商增加某个号段,对程序的维护人员来说就是一个噩耗。这时,可以使用自定义校验注解来代替这些常用的校验。

手机号校验注解Phone:

@Constraint(validatedBy = PhoneValidator.class)
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public interface Phone {

  String message() default "手机号格式不合法";

  Class<?>[] groups() default {};

  Class<? extends Payload>[] payload() default {};

}

手机号校验实现类PhoneValidator:

public class PhoneValidator implements ConstraintValidator<Phone, String> {

  private Pattern pattern = Pattern.compile("1(([38]\\d)|(5[^4&&\\d])|(4[579])|(7[0135678]))\\d{8}");

  @Override
  public void initialize(Phone phone) {
    
  }

  @Override
  public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
    return pattern.matcher(value).matches();
  }
  
}

Model上的使用:

@Phone
public String getUsername() {
  return username;
}

这样的话,如果因为某些不可抗拒因素导致校验规则的变动,只需要修改一处理即可,维护成本大大降低。

四、Xml报文

大多数情况下,使用Json就可以满足我们的需求了,但仍然存在某些特定的场景需要使用到XML形式的报文,如:微信公众号开发。不过不用担心,切换成XML报文也只需要做轻微的改动,添加相关依赖如下:"com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.8.8",然后就可以开始进行测试了,此处借助一个模拟HTTP请求工具(Postman)来协助我们测试该接口:

在上面的测试范例里,我们指定了Accept为text/xml,这样SpringBoot就会返回XML形式的数据。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值