热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

javarestful接口开发_SpringBootrestfulapi接口设计,全局JOSN格式交互

SpringBootrestfulapi接口设计以及统一响应JSON格式包含所有错误的JSON,统一异常不使用切面RESTfulAPI最佳实践作为一个java后端开发

SpringBoot restful api接口设计以及统一响应JSON格式 包含所有错误的JSON,统一异常不使用切面

RESTful API 最佳实践作为一个 java后端开发人员,前后端分离的时代,我更专注于后端的开发;专业的人做专业的事

前后端分离,也需要前后端人员相互联调,为了更好的交互,统一一个设计规范;

1、Http的常用请求方法MethodGET 一搬用于获取数据

POST 用于提交数据

PUT 用于修改数据

DELETE 用于删除数据

2、Restful api 常用的几个注解@RestController 一般用于Controoler类上

@ResponseBody 用了这个 RestController 就没有必要 ResponseBody

@GetMapping 方法上

@PostMapping 方法上

@PutMapping 方法上

@DeleteMapping 方法上

比如一个Controller 的简单增删改查 四个接口

@RestController

@RequestMapping("/oftenReciver")

public class OftenReciverController extends BaseController {

@Autowired

IOftenReciverService thisService;

@Autowired

AppAuthTokenHandler tokenHandler;

@GetMapping

public R list()

{

return success(thisService.findList(page(new OrderBy(OrderBy.Direction.DESC,"rec.update_time")), tokenHandler.getAppUserId()));

}

@PostMapping

public R insertSave(OftenReciver entity){

return result(thisService.save(entity));

}

@PutMapping

public R editSave(OftenReciver entity){

return result(thisService.updateById(entity));

}

@GetMapping("/selectById/{id}")

public R selectById(@PathVariable("id") String id){

return success(thisService.getById(id));

}

@DeleteMapping("remove/{ids}")

public R delete(@PathVariable("id") List ids)

{

return result(thisService.removeByIds(ids));

}

}

这就是简单的 restful 风格的api了,但是restful风格的api,还不够,我们前后端分离开发的,都要统一一个规范,也就是数据格式,为了更方便的前后端的数据对接,减少前后端干架的可能性

3、设计固定数据JSON格式:

所以 我们得设计一个固定的数据格式:比如这个样的

JSON 格式:

{

code:0,

msg:'操作成功',

data:null

}

{

code:1,

msg:'系统异常',

data:null

}

{

code:2,

msg:'参数绑定失败',

data:null

}

{

code:404,

msg:'路径不存在',

data:null

}

{

code:401,

msg:'用户未登陆',

data:null

}

........

那么我们定义一个类做封装

R.java:

@Data

public class R

{

private static final int SUCCESS_CODE = 0;

private static final int ERROR_CODE = 1;

private static final String SUCCESS_R = "操作成功!";

private static final String ERROR_R = "操作失败!";

private int code;

private String msg;

private Object data;

public R() {}

public static R success()

{

R r = new R();

r.setCode(SUCCESS_CODE);

r.setMsg(SUCCESS_R);

return r;

}

public static R success(Object data)

{

R r = new R();

r.setCode(SUCCESS_CODE);

r.setMsg(SUCCESS_R);

r.setData(data);

return r;

}

public static R success(String msg)

{

R r = new R();

r.setCode(SUCCESS_CODE);

r.setMsg(msg);

return r;

}

// public static R error()

// {

// R r = new R();

// r.setCode(ERROR_CODE);

// r.setMsg(ERROR_R);

// return r;

// }

public static R error(Error error, String tip)

{

if (StringUtils.isNotBlank(tip) || StringUtils.isNotNull(tip))

{

tip = "," + tip;

}

else

{

tip = "";

}

return error(error.getCode(), error.getErrMsg() + tip);

}

public static R error(Error error)

{

return error(error, null);

}

public static R error(int code, String msg)

{

R r = new R();

r.setCode(code);

r.setMsg(msg);

return r;

}

}

4、定义错误枚举

为了更加规范接口,我又定义了一个错误的枚举,主要是为了统一错误类型,让前端更好做判断

长这样的 Error.java:

public enum Error

{

操作失败(-1, "操作失败"),

系统异常(1, "系统异常"),

参数为空异常(2, "参数为空异常"),

参数异常(14, "参数异常"),

参数绑定异常(3, "参数绑定异常"),

文件上传异常(4, "文件上传异常"),

请求方式错误(5, "请求方式不支持"),

请求路径异常(6, "请检查url是否正确"),

权限异常(7, "权限不足"),

未登陆异常(9, "尚未登陆"),

微信接口异常(10, "微信接口异常"),

数据解析异常(11, "数据解析异常"),

Http接口响应异常(12, "数据解析异常"),

请求凭证有误(13, "请求凭证有误");

private int code;

private String errMsg;

public int getCode()

{

return code;

}

public void setCode(int code)

{

this.code = code;

}

public String getErrMsg()

{

return errMsg;

}

public void setErrMsg(String errMsg)

{

this.errMsg = errMsg;

}

Error(int code, String errMsg)

{

this.code = code;

this.errMsg = errMsg;

}

}

这样子 在controller 就能 固定的响应 错误的类型以及我们设定好的 code与类型对应了

例如这样子的:

@PostMapping("/takePro")

public R takePro(@RequestParam("commodityId") Integer id)

{

Commodity commodity = thisService.getById(id);

isNull(Error.参数异常);

int code = 0;

if (StringUtils.isNull(commodity.getTakeCode()))

{

code = (int) ((Math.random() * 9 + 1) * 1000);

commodity.setTakeCode(code);

commodity.setTakeUserId(getCurrentUserId());

thisService.updateById(commodity);

}else {

return error(Error.操作失败,"已被领取");

}

return success(getMap(Constanst.TAKE_CODE, code));

}

5、自定义全局异常 响应统一格式数据

GlobalExceptionHandler.java:

/**

*

*

*

*

* @author 永健

* @since 2019-05-23 19:32

*/

@RestControllerAdvice

public class GlobalExceptionHandler extends BaseException

{

private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

/**

* 参数绑定错误

*/

@ExceptionHandler(MissingServletRequestParameterException.class)

public R handleRRException(MissingServletRequestParameterException e)

{

return R.error(Error.参数绑定异常,"参数绑定失败,请求参数异常");

}

/**

* GET,POST 等方法

*/

@ExceptionHandler(HttpRequestMethodNotSupportedException.class)

public R handleRRException(HttpRequestMethodNotSupportedException e)

{

return R.error(Error.请求方式错误,"请求方式不对,换个姿势再来!@_@ ,试试 /GET/POST/PUT...");

}

/**

* 处理自定义异常

*/

@ExceptionHandler(MyException.class)

public R handleRRException(MyException e)

{

return R.error(e.getCode(), e.getMsg());

}

/**

* 处理自定义异常

*/

@ExceptionHandler(Exception.class)

public R handleException(Exception e)

{

e.printStackTrace();

return R.error(Error.系统异常,"服务器错误");

}

@ExceptionHandler(NoHandlerFoundException.class)

public R handlerNoFoundException(Exception e)

{

e.printStackTrace();

logger.error(e.getMessage(), e);

return R.error(Error.请求路径异常, "路径不存在,请检查路径是否正确");

}

@ExceptionHandler(DataIntegrityViolationException.class)

public R handleDuplicateKeyException(DataIntegrityViolationException e)

{

e.printStackTrace();

logger.error(e.getMessage(), e);

return R.error(Error.系统异常,"操作数据库出现异常:字段重复、有外键关联等");

}

/**

* 权限异常

*/

@ExceptionHandler({UnauthorizedException.class, AuthorizationException.class})

public R unauthorizedException(UnauthorizedException e)

{

e.printStackTrace();

logger.error(e.getMessage(), e);

return R.error(Error.权限异常);

}

}

这货我们也统一用封装的`R.java来处理` 这样子 自定义异常 以及所有的异常都能 统一拦截处理响应了

6、自定义异常类封装

`MyException.java`:

/**

*

*

*

*

* @author 永健

* @since 2019-05-23 19:32

*/

public class MyException extends RuntimeException

{

private static final long serialVersionUID = 1L;

private String msg;

private Error error;

private int code = 1;

public MyException(Error error)

{

super(error.getErrMsg());

this.code = error.getCode();

this.msg = error.getErrMsg();

}

public MyException(Error error, String msg)

{

super(msg);

this.code = error.getCode();

this.msg = error.getErrMsg() + "," + msg;

}

public String getMsg()

{

return msg;

}

public MyException setMsg(String msg)

{

this.msg = msg;

return this;

}

public int getCode()

{

return code;

}

public MyException setCode(int code)

{

this.code = code;

return this;

}

public Error getError()

{

return error;

}

public void setError(Error error)

{

this.code = error.getCode();

this.msg = error.getErrMsg();

this.error = error;

}

}

自定义异常类,的参数 也只限定 自定义的Error.java 这样子自定义的异常抛出 ,在GlobalExceptionHandler.java中处理,转换成 R.java的数据格式,这样子就达到了统一处理了,其它的异常都可以在这里拦截

7、404 异常配置

`1.application.yml 配置:`

spring:

mvc:

### 让mvc直接抛出异常,在全局异常类,捕获404 异常的类 NoHandlerFoundException.class

throw-exception-if-no-handler-found: true

### 关闭资源映射

resources:

add-mappings: false

在全局异常类,捕获404 异常的类 NoHandlerFoundException.class,然后写上我们异常的数据,这样子前端更简洁明了了。

8、写一个BaseControoler 来放置一些 常用的函数

public abstract class BaseController

{

/**

* 返回成功

*/

protected R success()

{

return R.success();

}

/**

* 返回失败消息

*/

protected R error(Error error)

{

return R.error(error);

}

protected R error()

{

return R.error(Error.操作失败);

}

/**

* 返回失败消息

*/

protected R error(Error error, String msg)

{

return R.error(error, msg);

}

/**

* 返回成功消息

*/

protected R successMsg(String message)

{

return R.success(message);

}

/**

* 返回成功消息

*/

protected R success(Object data)

{

return R.success(data);

}

/**

* 根据修改搜影响的行数返回结果

*/

protected R result(boolean flag)

{

return flag == true ? success() : error(Error.操作失败);

}

protected R result(boolean flag, String msg)

{

return flag == true ? successMsg(msg) : error(Error.操作失败);

}

protected R result(int row)

{

return row > 0 ? success() : error(Error.操作失败);

}

protected R result(int row, String msg)

{

return row > 0 ? successMsg(msg) : error(Error.操作失败);

}

/**

* 分页数据 默认使用更新时间降序

*/

protected Page page(OrderBy orderBy)

{

return getPage(orderBy);

}

protected Page page(OrderBy orderBy, int current, int size)

{

Page page = getPage(orderBy);

page.setSize(size);

page.setCurrent(current);

return page;

}

/**

* 自定义分页数据 默认使用更新时间降序

*/

protected Page page()

{

return getPage(new OrderBy(OrderBy.Direction.DESC, "update_time"));

}

/**

*

* 自定义分页条件

*/

private Page getPage(OrderBy orderBy)

{

Integer size = ServletUtils.getParamInteger("size");

if (size != null && size == -1)

{

size = Integer.MAX_VALUE;

}

Integer pageNum = ServletUtils.getParamInteger("current");

Page page &#61; new Page<>(pageNum &#61;&#61; null ? 0 : pageNum, size &#61;&#61; null ? 15 : size);

if (orderBy.getDirection().isAscending())

{

page.setAsc(orderBy.getColumns());

}

else

{

page.setDesc(orderBy.getColumns());

}

return page;

}

/**

*

* 设置查询参数

*/

protected Wrapper setParams(T t)

{

return new QueryWrapper().lambda().setEntity(t);

}

protected void out(String str, HttpServletResponse response)

{

ServletOutputStream outputStream &#61; null;

try

{

outputStream &#61; response.getOutputStream();

outputStream.write(str.getBytes());

outputStream.flush();

}

catch (IOException e)

{

e.printStackTrace();

}

finally

{

try

{

if (outputStream !&#61; null)

{

outputStream.close();

}

}

catch (IOException e)

{

e.printStackTrace();

}

}

}

protected Map getMap()

{

return new HashMap(8);

}

protected Map getMap(Object key, Object val)

{

Map map &#61; new HashMap(8);

map.put(key, val);

return map;

}

protected AppAuthTokenHandler tokenHandler(){

return BeanTool.getInstance(AppAuthTokenHandler.class);

}

protected User getCurrentUser(){

return tokenHandler().getUser();

}

protected Integer getCurrentUserId(){

return tokenHandler().getUserId();

}

}

比如 我们的 Mybastis-plus 的分页封装可以放在这里用&#xff0c;

map 的获取&#xff0c;当前登陆的用户信息 等等

**这样子 我们可以不使用切面也一样可以捕获所有的异常哦**



推荐阅读
  • 深入解析 Vue 中的 Axios 请求库
    本文深入探讨了 Vue 中的 Axios 请求库,详细解析了其核心功能与使用方法。Axios 是一个基于 Promise 的 HTTP 客户端,支持浏览器和 Node.js 环境。文章首先介绍了 Axios 的基本概念,随后通过具体示例展示了如何在 Vue 项目中集成和使用 Axios 进行数据请求。无论你是初学者还是有经验的开发者,本文都能为你解决 Vue.js 相关问题提供有价值的参考。 ... [详细]
  • DVWA学习笔记系列:深入理解CSRF攻击机制
    DVWA学习笔记系列:深入理解CSRF攻击机制 ... [详细]
  • 优化后的标题:深入探讨网关安全:将微服务升级为OAuth2资源服务器的最佳实践
    本文深入探讨了如何将微服务升级为OAuth2资源服务器,以订单服务为例,详细介绍了在POM文件中添加 `spring-cloud-starter-oauth2` 依赖,并配置Spring Security以实现对微服务的保护。通过这一过程,不仅增强了系统的安全性,还提高了资源访问的可控性和灵活性。文章还讨论了最佳实践,包括如何配置OAuth2客户端和资源服务器,以及如何处理常见的安全问题和错误。 ... [详细]
  • 在 Kubernetes 中,Pod 的调度通常由集群的自动调度策略决定,这些策略主要关注资源充足性和负载均衡。然而,在某些场景下,用户可能需要更精细地控制 Pod 的调度行为,例如将特定的服务(如 GitLab)部署到特定节点上,以提高性能或满足特定需求。本文深入解析了 Kubernetes 的亲和性调度机制,并探讨了多种优化策略,帮助用户实现更高效、更灵活的资源管理。 ... [详细]
  • 使用cpphttplib构建HTTP服务器以处理带有查询参数的URL请求 ... [详细]
  • 本文将介绍如何在混合开发(Hybrid)应用中实现Native与HTML5的交互,包括基本概念、学习目标以及具体的实现步骤。 ... [详细]
  • 本文将带你快速了解 SpringMVC 框架的基本使用方法,通过实现一个简单的 Controller 并在浏览器中访问,展示 SpringMVC 的强大与简便。 ... [详细]
  • 在PHP中实现腾讯云接口签名,以完成人脸核身功能的对接与签名配置时,需要注意将文档中的POST请求改为GET请求。具体步骤包括:使用你的`secretKey`生成签名字符串`$srcStr`,格式为`GET faceid.tencentcloudapi.com?`,确保参数正确拼接,避免因请求方法错误导致的签名问题。此外,还需关注API的其他参数要求,确保请求的完整性和安全性。 ... [详细]
  • REST与RPC:选择哪种API架构风格?
    在探讨REST与RPC这两种API架构风格的选择时,本文首先介绍了RPC(远程过程调用)的概念。RPC允许客户端通过网络调用远程服务器上的函数或方法,从而实现分布式系统的功能调用。相比之下,REST(Representational State Transfer)则基于资源的交互模型,通过HTTP协议进行数据传输和操作。本文将详细分析两种架构风格的特点、适用场景及其优缺点,帮助开发者根据具体需求做出合适的选择。 ... [详细]
  • 微信平台通过盛派SDK(sdk.weixin.senparc.com)允许服务号和订阅号使用appId和token读取关注用户的个人信息。然而,这一过程需严格遵守隐私保护和数据安全的相关规定,确保用户数据的安全性和隐私性。 ... [详细]
  • 本文详细解析了微信服务端示例类的功能与应用。其中,`ClientResponseHandler` 类主要用于处理微信支付所需的响应数据,而 `TenpayHttpClient` 则是对 HTTP 请求(包括 GET 和 POST 方法)进行了封装,以便在内部调用时更加便捷和高效。这些工具类在实际开发中起到了关键作用,开发者无需深入了解其底层实现细节,即可轻松集成微信支付功能。 ... [详细]
  • 理解和应用HTTP请求中的转发与重定向机制
    在HTTP请求处理过程中,客户端发送请求(通常简称为req),服务器进行相应处理后返回响应(通常简称为res)。理解和应用客户端的转发与重定向机制是前端开发的重要内容。这两种机制在Web开发中具有关键作用,能够有效管理和优化用户请求的处理流程。转发机制允许服务器内部将请求传递给另一个资源,而重定向则指示客户端向新的URL发起新的请求,从而实现页面跳转或资源更新。掌握这些技术有助于提升应用的性能和用户体验。 ... [详细]
  • FastDFS Nginx 扩展模块的源代码解析与技术剖析
    FastDFS Nginx 扩展模块的源代码解析与技术剖析 ... [详细]
  • 如何在 Angular 4 中实现跨域调用百度人脸识别 API? ... [详细]
  • C#微信开发入门教程第二篇:新手快速上手指南,含详细视频讲解
    在距离上次课程一个多星期后,我们终于带来了第二讲的内容。虽然原计划是一周一次更新,但由于工作繁忙有所延迟。近期在交流群中发现,一些初学者已经能够熟练调用微信接口,但对微信公众平台的消息接收处理机制还不够了解。因此,本次课程将详细介绍如何高效处理微信公众平台的消息接收,并提供详细的视频讲解,帮助大家快速上手。 ... [详细]
author-avatar
小小号号--
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有