这篇文章主要给大家介绍了关于SpringBoot项目实战之数据交互篇的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
前言
SpringBoot非常适合Web应用开发,使用它我们可以轻松地构建一个Web服务。在对Spring Boot的介绍中,我们用它实现了一个非常简单的界面并输出Hello World!让我们模拟一个真实的场景来学习SpringBoot应用开发。
1. 数据格式
在实际项目场景中,前后分离几乎是项目的标配,全栈时代逐渐远去。后端负责业务逻辑处理,前端负责数据展示,已经成为固定的开发模式。一般来说,后端提供的数据接口可能有Json和XML两种数据形式。用哪个往往会和公司的工程师文化有关。
1.1. Json 报文
对于SpringBoot,它将默认使用Json作为响应消息格式。让我们用一个简单的例子来测试它:
首先,我们创建一个UserController来处理前端Web请求。
@Controller@RequestMapping("/sys/user")public class UserController { @RequestMapping("login") @ResponseBody public Maplt;String, Stringgt; login() { Maplt;String, Stringgt; hashMap = new HashMaplt;gt;(); hashMap.put("msg", "登录成功"); return hashMap; }}
这个例子相信大多数用过SpringMVC的人都会很熟悉。定义一个简单的控制器和等效的映射不同于通常返回Url的控制器。这里我们使用@ResponseBody注释,表示这个接口响应是纯数据,没有任何接口显示。有关请求的相应地址,请参见以下输出:
显然,我们得到了想要的结果,一个标准的Json字符串,是不是很简单?
对于上面的代码,还可以进一步优化。由于所有Restful接口只返回数据,我们可以直接在类级别添加@ResponseBody注释。大多数情况下,@Controller和@ResponseBody会再次一起使用,所以我们使用@RestController注释来替换它们,从而更简洁地实现功能。
@RestController@RequestMapping("/sys/user")public class UserController { @RequestMapping("login") public Maplt;String, Stringgt; login() { Maplt;String, Stringgt; hashMap = new HashMaplt;gt;(); hashMap.put("msg", "登录成功"); return hashMap; }}
1.2. Xml 报文
在大多数情况下,Json可以满足我们的需求,但是还有一些特定的场景需要使用XML消息,比如微信微信官方账号开发。不过,不用担心,切换到XML message只需要稍加改动。按如下方式添加相关依赖项:
"com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.8.8"
然后就可以开始测试了。这里用一个模拟的HTTP请求工具(Postman)来帮助我们测试接口,如何使用就不多说了。我们就上图展示一下吧:
在上面的测试示例中,我们将Accept指定为text/xml,因此SpringBoot将以xml形式返回数据。
2. 接口规范
每个公司都会定义自己的数据规范。一个统一标准的数据规范对于系统维护非常重要,也大大提高了开发效率。
2.1. 响应报文规范
一般来说,接口响应至少需要告诉用户三条信息:状态码、描述和数据。其中,数据并不是每个接口都需要的。如果只是简单的修改,可能不需要返回数据。让我们定义一个结果类来封装我们的响应消息。
public class Result { private int code; private String msg; private Object data; public Result(ResultCode resultCode, Object data) { this(resultCode); this.data = data; } public Result(ResultCode resultCode) { this.code = resultCode.getCode(); this.msg = resultCode.getMsg(); } ...}
同时,定义一个枚举类来维护我们的状态代码:
public enum ResultCode { SUCCESS(0, "请求成功"), WARN(-1, "网络异常,请稍后重试"); private int code; private String msg; ResultCode(int code, String msg) { this.msg = msg; } public int getCode() { return code; } public String getMsg() { return msg; }}
这样,我们的响应数据规范就基本建立起来了。将上面代码中返回的Map修改为return Result,按照指定的规范返回数据,结果如下。
2.2. 请求数据规范
我们已经定义了响应消息格式,那么我们如何接收请求数据呢?一般来说,请求和响应会使用相同的消息形式,即如果响应是Json,请求也建议Json。如果您想在上面的登录请求中添加输入参数,您需要完成以下步骤:
首先,我们定义用户实体:
public class User { private String username; private String password; ...}
然后,在映射方法中直接使用实体来接收参数,并且直接返回所接收的参数:
@RestController@RequestMapping("/sys/user")public class UserController { @RequestMapping("login") public Result login(@RequestBody User loginUser) { return new Result(ResultCode.SUCCESS, loginUser); }}
打电话给我们的邮递员,填写正确的Url,选择Post发送请求,选择Body,设置Content-Type为application/json,填写json格式的请求数据,点击Send得到如下结果。
数据接收成功,但是在上面的响应消息中,出现了一个非常严重的问题,就是将用户的密码和用户信息一起返回给了客户端,这显然不是一个正确的做法。我们需要过滤一次。因为SpringBoot默认使用Jackson作为Json序列化工具,所以如果想过滤掉响应中的一些字段,只需要在过滤掉的字段对应的get方法中添加@JsonIgnore注释即可。但是,这会导致另一个问题,即请求中的字段被过滤掉了。对于这个问题,我们可以使用分离请求参数模型的方法,即定义一组参数接收模型。比如接收用户在登录时会使用UserModel接收参数,使得请求参数模型与数据库映射实体完全分离,在一定程度上提高了系统的安全性。
@RequestMapping("login")public Result login(@RequestBody UserModel userModel) { User user = new User(); user.setUsername(userModel.getUsername()); user.setPassword(userModel.getPassword()); return new Result(ResultCode.SUCCESS, user);}
用模型对象替换后,我们可以给数据库映射实体用户添加@JsonIgnore注释,在不影响请求参数输入的情况下忽略这个字段的序列化。
3. 参数校验
为了系统的健壮性,一般来说,我们需要检查所有参数的必要性。例如,如果登录请求中没有用户名,程序应该立即拒绝该请求。上述请求参数模型的抽象也使得我们对数据的验证更加方便。当然,这主要依赖于SpringBoot的Validate功能的强大支持。
3.1. 简单参数校验
对于登录界面,用户名和密码都是需要的,所以我们现在为它增加了相应的参数验证,不需要if-else判断,简单的几条注释就可以帮助我们完成所有的工作。
@RequestMapping("login")public Result login(@RequestBody @Valid UserModel userModel) { ...}---public class UserModel { private String username; private String password; @NotBlank(message = "用户名不能为空") public String getUsername() { return username; } @NotBlank(message = "密码不能为空") public String getPassword() { return password; } ...}
在上面的例子中,我们向请求参数的模型对象添加了@Valid注释,并向需要检查模型类中的字段的get方法添加了相应的check注释。效果如下:
3.2. 复杂参数校验
3.2.1. 正则表达式校验
如果用户的登录名是手机号,则需要进一步检查登录名的格式。这里用正则表达式来检查手机号的合法性。
@NotBlank(message = "用户名不能为空")@Pattern( regexp = "1(([38]\\d)|(5[^4amp;amp;\\d])|(4[579])|(7[0135678]))\\d{8}", message = "手机号格式不合法")public String getUsername() { return username;}
3.2.2. 自定义校验注解
在使用系统的过程中,有很多地方需要检查手机号码的格式,比如注册、验证码发送等。但是,检查手机号码的正则表达式太复杂了。如果写在很多地方,一旦运营商增加了某个号段,对于程序的维护者来说就是一个坏消息。此时,您可以使用自定义检查注释来代替这些常见的检查。
手机号码验证实现类PhoneValidator:
public class PhoneValidator implements ConstraintValidatorlt;Phone, Stringgt; { private Pattern pattern = Pattern.compile("1(([38]\\d)|(5[^4amp;amp;\\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(); }}
手机号码验证标注电话:
@Constraint(validatedBy = PhoneValidator.class)@Target({ElementType.METHOD, ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Phone { String message() default "手机号格式不合法"; Classlt;gt;[] groups() default {}; Classlt; extends Payloadgt;[] payload() default {};}
在模型上使用:
@Phonepublic String getUsername() { return username;}
这样,如果由于一些不可抗拒的因素导致校验规则改变,只需要修改一次,维护成本大大降低。
项目Github地址:https://github.com/qchery/funda
总结
关于SpringBoot项目实际数据交互的这篇文章到此为止。关于SpringBoot数据交互的更多信息
精彩评论