SpringBoot学习之Json数据交互

最近在弄监控主机项目,对javaweb又再努力学习。实际的项目场景中,先后分离几乎是因此项目的标配,全栈的时代的逐渐远去,后端负责业务逻辑处理,前端负责数据展现成了一种固定的开发模式。像thymeleaf这种东西无法实现先后端分离模板难学也只有写java的才用吧,仍是用js模板引擎接受json好。前端

1. Json报文

SpringBoot 默认会使用 Json 做为响应报文格式。首先,咱们建立一个 UserController 用于处理前端的 Web 请求。
定义一个简单的控制器,与一般返回 Url 的 Controller 不同的是,login() 使用了 @ResponseBody 注解,它表示此接口响应为纯数据,不带任何界面展现,能够得到标准Jsonjava

@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);    //返回的响应实体具体看下节
    }
}

对于上面的代码来讲,还能够作进一步的优化,因为全部的 Restful 接口都只是返回数据,因此咱们能够直接在类级别上添加 @ResponseBody 注解。而大多数状况下,@Controller 与 @ResponseBody 又会一块儿使用,因此咱们使用 @RestController 注解来替换掉它们,从而更加简洁地实现功能。web

2. 接口规范

对于每一家公司来讲,都会定义本身的数据规范,一个统一且标准的数据规范对于系统维护来讲是很是重要的,也在很在程度上提高了开发效率。正则表达式

2.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;
    }

    ...    
}

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

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.2 请求数据规范

响应报文格式咱们已经定义好了,那么请求数据咱们如何接收呢?
通常来讲,请求与响应会使用相同的报文形式。若是响应为Json,那么请求也建议使用Json。
为登陆请求添加输入参数,首先,须要咱们定义好用户实体User类,直接在映射方法login() 使用该实体进行参数接收,并将接收到的参数直接返回,1.节代码已实现。
调出Postman,填写正确的Url,选择POST方式发送请求,选择Body,将 Content-Type 设置成 application/json,填入 Json 格式的请求数据,点击 Send 便可获得以下结果。

数据接收很是成功,但在上面的响应报文中,存在着了一个很是严重的问题,那就是用户的密码也随同用户信息一块儿返回给了客户端,显然这并非一种正确的作法。
咱们须要对其进行一次过滤,因为 SpringBoot 默认使用 Jackson 做为 Json 序列化工具,若是想要过滤掉响应中的某些字段,只需在过滤字段对应的 get 方法上加上 @JsonIgnore 注解便可。
但这样又会引起另一个问题,那就是请求中的字段也被过滤掉了,对于这种问题,能够采用抽离请求参数模型的方式进行处理,即自定义一套参数接收的 Model,好比,接收用户登陆的会使用 ReqUser 来进行参数接收,这样使得请求参数模型与数据库映射实体彻底分离,在必定程度上提高了系统的安全性。替换成 Model 对象后(1.节的代码已经替换好了),咱们就能够在数据库映射实体 User 上增长 @JsonIgnore 注解忽略该字段的序列化,而不影响请求参数的输入。
安全

3. 参数校验

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

3.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 方法上添加相应的校验注解。效果以下:

3.2. 复杂参数校验

  • 正则表达式校验
    若是用户的登陆名为手机号,那么就须要对登陆名的格式作进一步的校验,下面使用正则表达式来校验手机号的合法性。
@NotBlank(message = "用户名不能为空")
@Pattern(
        regexp = "1(([38]\\d)|(5[^4&&\\d])|(4[579])|(7[0135678]))\\d{8}",
        message = "手机号格式不合法"
)
public String getUsername() {
    return username;
}
  • 自定义校验注解
    在系统使用过程当中,有不少地方须要对手机号的格式进行校验,如:注册、验证码发送等。
    但校验手机号的正则表达式又过于复杂,若是多处编写,一旦运营商增长某个号段,对程序的维护人员来讲就是一个噩耗。这时,可使用自定义校验注解来代替这些经常使用的校验。

手机号校验注解 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;
}

这样的话,若是由于某些不可抗拒因素致使校验规则的变更,只须要修改一处理便可,维护成本大大下降。

4. Xml 报文

大多数状况下,使用 Json 就能够知足咱们的需求了,但仍然存在某些特定的场景须要使用到 XML 形式的报文,如:微信公众号开发。不过不用担忧,切换成 XML 报文也只须要作轻微的改动,添加相关依赖以下:"com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.8.8"
而后就能够开始进行测试了,此处借助一个模拟 HTTP 请求工具(Postman)来协助咱们测试该接口:
在上面的测试范例里,咱们指定了 Accept 为 text/xml,这样 SpringBoot 就会返回 XML 形式的数据。

相关文章
相关标签/搜索