小言_互联网的博客

如何优雅地写后端API接口

367人阅读  评论(0)

在移动互联网,分布式、微服务盛行的今天,现在项目绝大部分都采用的微服务框架,前后端分离方式。前后端的工作职责越来越明确,现在的前端都称之为大前端,技术栈以及生态圈都已经非常成熟;以前后端人员瞧不起前端人员,那现在后端人员要重新认识一下前端,前端已经很成体系了

1.接口交互

前端和后端进行交互,前端按照约定请求URL路径,并传入相关参数,后端服务器接收请求,进行业务处理,返回数据给前端。

针对URL路径的restful风格,以及传入参数的公共请求头的要求(如:app_version,api_version,device等),这里就不介绍了,小伙伴们可以自行去了解,也比较简单。

着重介绍一下后端服务器如何实现把数据返回给前端?

2.返回格式

后端返回给前端我们采用json格式


  
  1. {
  2. "success": boolean,
  3. "code": int,
  4. "data": object,
  5. "msg": string
  6. }
  • success是否成功

最简单的判断,前端直接取该值判断是否操作成功,成功为true,失败为false

  • code状态码

当一个操作会因为多种因素失败的情况下,每种失败的原因进行设置不同的状态码。可以按照业务区分,例如用户的错误状态码在101-199之间,系统的错误状态码在201-299之间,可以按照自己的业务进行设置,我们参考下http状态码:


  
  1. 200 - 请求成功
  2. 301 - 资源(网页等)被永久转移到其它URL
  3. 404 - 请求的资源(网页等)不存在
  4. 500 - 内部服务器错误
  • data数据

这里是具体要返回的数据,数据格式可以为数组、对象、字符串等格式

  • msg消息

这个字段相对理解比较简单,就是发生错误时,如何友好的进行提示。一般的设计是和code状态码一起设计。如登陆失败> code:203,msg:登陆失败,账号或者密码有误

2.1.返回样例

这就是一个操作成功返回的例子


  
  1. {
  2. "success": true,
  3. "code": 1,
  4. "data": { "k": "v"},
  5. "msg": "操作成功"
  6. }

3.实现

3.1.定义状态码枚举类


  
  1. package com.niu.demo.util;
  2. /**
  3. * @description: 状态吗设置
  4. * @author: nxq email: niuxiangqian163@163.com
  5. * @createDate: 2020/12/21 7:46 下午
  6. * @updateUser: nxq email: niuxiangqian163@163.com
  7. * @updateDate: 2020/12/21 7:46 下午
  8. * @updateRemark:
  9. * @version: 1.0
  10. **/
  11. public enum ResultCode {
  12. /* 通用状态码 成功与失败 */
  13. SUCCESS( 1, "ok"), FAILED(- 1, "操作失败"),
  14. /* 参数错误 101 - 199*/
  15. PARAM_IS_INVALID( 101, "参数无效"),
  16. PARAM_IS_BLANK( 101, "参数为空"),
  17. /* 用户错误 201 - 299 */
  18. USER_NOT_LOGIN( 201, "未登录"),
  19. USER_NOT_EXIST( 202, "用户不存在"),
  20. USER_LOGIN_ERROR( 203, "登陆失败,账号或者密码有误"),
  21. NOT_PERMISSION( 204, "无权限访问"),
  22. /* 业务错误 301 - 399*/
  23. DATA_NOT_FOUND( 301, "没有数据"),
  24. //.......更多
  25. ;
  26. private Integer code;
  27. private String msg;
  28. ResultCode(Integer code, String msg) {
  29. this.code=code;
  30. this.msg=msg;
  31. }
  32. public Integer getCode() {
  33. return code;
  34. }
  35. public String getMsg(){
  36. return msg;
  37. }
  38. }

3.2.创建返回结果类


  
  1. package com.niu.demo.util.core;
  2. import com.niu.demo.util.ResultCode;
  3. import java.io.Serializable;
  4. /**
  5. * @description: 响应类
  6. * @author: nxq email: niuxiangqian163@163.com
  7. * @createDate: 2020/12/21 7:37 下午
  8. * @updateUser: nxq email: niuxiangqian163@163.com
  9. * @updateDate: 2020/12/21 7:37 下午
  10. * @updateRemark:
  11. * @version: 1.0
  12. **/
  13. public class R<T> implements Serializable {
  14. private static final long serialVersionUID = 1L;
  15. private int code; //状态码
  16. private boolean success; //是否成功
  17. private String msg; //提示信息
  18. private T data; //数据
  19. public static <T> R<T> ok() {
  20. return restResult( null, ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg());
  21. }
  22. public static <T> R<T> ok(T data) {
  23. return restResult(data, ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg());
  24. }
  25. public static <T> R<T> ok(T data, String msg) {
  26. return restResult(data, ResultCode.SUCCESS.getCode(), msg);
  27. }
  28. public static <T> R<T> failed() {
  29. return restResult( null, ResultCode.FAILED.getCode(), ResultCode.FAILED.getMsg());
  30. }
  31. public static <T> R<T> failed(String msg) {
  32. return restResult( null, ResultCode.FAILED.getCode(), msg);
  33. }
  34. public static <T> R<T> failed(ResultCode resultCode) {
  35. return restResult( null, resultCode.getCode(), resultCode.getMsg());
  36. }
  37. public static <T> R<T> failed(Integer code,String msg) {
  38. return restResult( null, code, msg);
  39. }
  40. public static <T> R<T> failed(T data) {
  41. return restResult(data, ResultCode.FAILED.getCode(), ResultCode.SUCCESS.getMsg());
  42. }
  43. public static <T> R<T> failed(T data, String msg) {
  44. return restResult(data, ResultCode.FAILED.getCode(), msg);
  45. }
  46. public int getCode() {
  47. return code;
  48. }
  49. public void setCode(int code) {
  50. this.code = code;
  51. }
  52. public boolean isSuccess() {
  53. return success;
  54. }
  55. public void setSuccess(boolean success) {
  56. this.success = success;
  57. }
  58. public String getMsg() {
  59. return msg;
  60. }
  61. public void setMsg(String msg) {
  62. this.msg = msg;
  63. }
  64. public T getData() {
  65. return data;
  66. }
  67. public void setData(T data) {
  68. this.data = data;
  69. }
  70. private static <T> R<T> restResult(T data, int code, String msg) {
  71. R<T> apiResult = new R<>();
  72. apiResult.setCode(code);
  73. apiResult.setSuccess(code == 1);
  74. apiResult.setData(data);
  75. apiResult.setMsg(msg);
  76. return apiResult;
  77. }
  78. }

3.3.在控制器中使用


  
  1. @RequestMapping
  2. @RestController
  3. public class DemoController {
  4. @GetMapping("/test1")
  5. public R<Object> test1(){
  6. return R.ok();
  7. }
  8. @GetMapping("/test2")
  9. public R<String> test2(){
  10. return R.ok( "uuid");
  11. }
  12. @GetMapping("/test3")
  13. public R<List<String>> test3(){
  14. List<String> list = new ArrayList<>();
  15. return R.ok(list);
  16. }
  17. @GetMapping("/test4")
  18. public R<Object> test4(){
  19. return R.failed();
  20. }
  21. @GetMapping("/test5")
  22. public R<Object> test5(){
  23. return R.failed( "暂时不能进行修改");
  24. }
  25. @GetMapping("/test6")
  26. public R<Object> test6(){
  27. return R.failed(ResultCode.USER_LOGIN_ERROR);
  28. }
  29. @GetMapping("/test7")
  30. public R<Object> test7(){
  31. return R.failed( 500, "内部错误,请联系管理员");
  32. }
  33. }

4.补充

这个方案还有没有别的优化空间,当然是有的。例如:每个接口都要返回下R这个类,其实最主要的数据还是R的data数据对象,可以优化一下只返回数据对象,在拦截器里再包装一下数据对象。

如果大家有更好的方式可以在评论区交流一下

 


转载:https://blog.csdn.net/qq_41389354/article/details/111589086
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场