【编程规范】 后端API接口设计编写与文档编写参考

您所在的位置:网站首页 美术零基础入门教程视频大全下载免费 【编程规范】 后端API接口设计编写与文档编写参考

【编程规范】 后端API接口设计编写与文档编写参考

2024-07-10 11:35:51| 来源: 网络整理| 查看: 265

文章目录 0 统一规范0.1 理清业务流程0.2 定义前后端开发的接口规范0.3 定义接口文档 1 后端接口编写1.0 后端接口介绍1.0.1 接口交互1.0.2 返回格式1.0.3 CODE状态码1.0.4 Message(Msg)1.0.5 DATA 1.1 数据校验与异常处理1.1.1 参数校验设计1.1.2 全局异常处理1.1.3 自定义异常 1.2 数据统一响应1.2.1 自定义统一响应体1.2.2 响应码枚举1.2.3 全局处理响应数据 1.3 其他返回数据 2 接口设计参考2.1 接口设计原则2.1.1 数据有效性校验2.1.2 幂等设计2.1.3 数据加密2.1.4 时间戳机制 2.2 设计规范2.2.1 URL设计2.2.2 返回值设计2.2.3 非RESTful API需求2.2.4 字段命名规范 3 文档编写3.1 简单版本3.1.1 目录格式3.1.2 案例模板接口说明请求示例请求参数说明响应示例响应参数说明 3.2 复杂版本3.2.1 目录格式3.2.2 案例模板封面文档信息版本历史目录文档具体内容部分编写目的对接准备事项使用协议 + 规范报文规范加解密规范业务接口 附录 参考文档 在一个新型的web应用中,由于中台只负责数据的输送,不涉及具体业务,所以就需要搭建一个业务服务来组装业务数据,把 浏览器/客户端 和中台连接起来。业务服务将组装完的数据以统一的数据格式返回给客户端,这里就需要对业务服务后台接口进行统一设计。下面就来具体介绍一下如何设计和编写后端接口。

0 统一规范 0.1 理清业务流程

通过需求文档,描述清楚业务流程,定义好相关的设计规范。根据项目大小划分好前台和后台的功能需求,通过需求来得到对应的模块。

0.2 定义前后端开发的接口规范

一般前后端分离项目会拥有不同的数据格式,例如 json、url等。 这里要通过文档的形式同前后端一起确定好数据阐述的格式。

接口地址:不包含接口BASE地址。

请求方式: get、post、put、delete等。

请求参数:数据格式(默认json)、数据类型、是否必填、中文描述。

响应参数:类型、中文描述。

0.3 定义接口文档

这里的接口文档一般就是对应后台的实体,即RequestVo(调用后台接口访问的实体)和给往前端的ResponseVo(前台调用接口时前往的实体)。一般来说ResponseVo都会在后台做一个统一的处理为ResultVo。

对于ResultVo的规范需要在上一节中定义好,例如:错误码Code,错误描述msg,请求的url,以及实体泛型T。

需要注意的是,这里定义的接口文档实在彻底了解号数据流、业务流的基础之上完成的。

尽量采用自动化接口文档,可以做到在线测试,同步更新。 文档中应包含:接口BASE地址、接口版本、接口模块分类等。

有了这个接口文档之后(实质上就是定义实体的过程和对应的json),前后端的开发基本根据这个文档去开发。在实际的项目业务中,接口文档会产生版本的迭代,这个时候我们会需要将它放到版本管理器中,不论你用的是git亦或者是svn。

注:除了以上描述的,我们的项目中还有redis,mongoDB,elasticsearch等。这些都是在非常了解业务的状况和系统架构下去设计的。后台运用这些工具去完成接口功能的实现以及系统功能和性能的实现。

1 后端接口编写

主要是对RESTful接口设计做一个介绍。

1.0 后端接口介绍 1.0.1 接口交互

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

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

1.0.2 返回格式

在 0.2小节 中我们提到了会把ResponseVo 处理为一个统一的ResultVo。

这个ResultVo大致由4个部分组成,分别 是接口请求地址(url)、接口请求方式(get/post)、请求数据(request)、响应数据(response)。

在前端的眼中,拿到的数据就会长这样,也就是我们所理解的返回格式。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iPfV1rRu-1662523338889)(C:\Users\Hasee\AppData\Roaming\Typora\typora-user-images\image-20220906214352990.png)]

1.0.3 CODE状态码

一般来说没有明确的规范要求,具体是看开发时需要什么就添加什么。

例如,我们要提示前端用户权限不足,那么我们返回的状态码就可以定义为 403 ;如果我们要告诉前端的数据参数异常,我们就可以把返回的状态码定义成 102 。具体的状态码细节可以参考http请求返回的状态码。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V9VfIYYH-1662523338892)(C:\Users\Hasee\AppData\Roaming\Typora\typora-user-images\image-20220906215237691.png)]

分类区间分类描述1**100~199信息,服务器收到请求,需要请求者继续执行操作2**200~299成功,操作被成功接收并处理3**300~399重定向,需要进一步的操作以完成请求4**400~499客户端错误,请求包含语法错误或无法完成请求5**500~599服务器错误,服务器在处理请求的过程中发生了错误

具体可以参考这篇文章:HTTP状态码有哪些分类?

同样我们可以这么设计:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AMuiZ7de-1662523338893)(C:\Users\Hasee\AppData\Roaming\Typora\typora-user-images\image-20220906215907754.png)]

这样设计的好处是可以把错误类型归类到某个区间内,如果区间不够,可以设计成4位数。 这样前端开发人员在得到返回值后,根据状态码就可以知道,大概什么错误,再根据msg相关的信息描述,可以快速定位。

1.0.4 Message(Msg)

这个字段相对理解比较简单,就是发生错误时,如何友好的进行提示。一般的设计是和code状态码一起设计。

1.0.5 DATA

返回数据体,json格式,根据不同的业务又不同的json体。一般来说返回给前端时会结合msg、code一起返回。

1.1 数据校验与异常处理 1.1.1 参数校验设计

我们先来看一段数据校验的代码:

public String addUser(User user) { if (user.getId() == null || user.getAccount() == null || user.getPassword() == null ) { return "对象或者对象字段不能为空"; } if (StringUtils.isEmpty(user.getAccount()) || StringUtils.isEmpty(user.getPassword())) { return "不能输入空字符串"; } // 参数校验完毕后这里就写上业务逻辑 return "success"; }

是不是感觉比较熟悉,在最开始不熟悉开发的时候,都会这么写过。虽然我们阅读这段代码对参数的校验是没有问题的,而且排版也还看得过去。但是每个接口都这么写显然会看的比较繁琐。而且还没到业务处理,参数校验的代码就这么多了,显然会让人头大。

在我们引入的依赖 spring-boot-starter-web 中包含了 Validator ,它可以非常方便的定制校验规则,并自动完成校验。只需要在需要校验的字段加上对应的注解即可,message后面填校验失败后的信息。

@NotNull(message = "xxx") @Size(min=*, max=*, message = "xxx") //下面这个注解适用于邮箱验证 @Email(message="xxx")

校验规则和错误提示信息配置完毕后,接下来只需要在接口中需要校验的参数上加上@Valid 注解,并添加BindResult参数即可方便完成验证。

BindResult作用:如果有参数校验失败,会将错误信息封装成对象组装在BindingResult里

当然,每个接口中都添加BindResult显然会比较繁琐,我们完全可以把BindResult去掉

例如:

@RestController public class UserController { @Autowired private UserService userService; @RequestMapping("user") public String addUser(@RequestBody @Valid User user,) { return userService.addUser(user); } } 1.1.2 全局异常处理

如果我们接口向上一节那么写,就会发现这样就把所有的问题都响应到前端了,解决这个问题的办法就是使用全局异常处理。

由于参数校验会自动引发异常,我们就不用再去手动捕捉异常进行处理,这个时候我们就可以用spring boot全局异常处理。

首先,我们需要新建一个ExceptionControllerAdvice类,在这个类上加上**@ControllerAdvice或@RestControllerAdvice注解**,这个类就配置成全局处理类了。(这个根据你的Controller层用的是@Controller还是@RestController来决定)

然后在类中新建方法,在方法上加上**@ExceptionHandler注解**并指定你想处理的异常类型,接着在方法内编写对该异常的操作逻辑,就完成了对该异常的全局处理。

例如:

@RestControllerAdvice public class ExceptionControllerAdvice { @ExceptionHandler(MethodArgumentNotValidException.class) public String MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) { // 从异常对象中拿到ObjectError对象 ObjectError objectError = e.getBindingResult().getAllErrors().get(0); // 然后提取错误提示信息进行返回 return objectError.getDefaultMessage(); } } 1.1.3 自定义异常

我们在 1.0.1小节 中了解了返回格式的写法,我们自定义异常也可以参考这一小节来编写。

@Getter //只要getter方法,无需setter public class APIException extends RuntimeException { private int code; private String msg; public APIException() { this(1001, "接口错误"); } public APIException(String msg) { this(1001, msg); } public APIException(int code, String msg) { super(msg); this.code = code; this.msg = msg; } }

当然,我们也需要在全局异常类中添加上我们对自定义异常的处理。

@ExceptionHandler(APIException.class) public String APIExceptionHandler(APIException e) { return e.getMsg(); }

这样就对异常的处理就比较规范了,当然还可以添加对Exception的处理,这样无论发生什么异常我们都能屏蔽掉然后响应数据给前端,不过建议最后项目上线时这样做,能够屏蔽掉错误信息暴露给前端,在开发中为了方便调试还是不要这样做。

1.2 数据统一响应

在上一大节中,我们对全局异常处理和自定义异常已经处理完毕,但是当我们抛出自定义异常的时候,全局异常处理只响应了异常中的错误信息msg给前端,并没有将错误代码code返回。这里就要说到数据统一响应了。

我们尽管对参数校验方式和异常处理方式做好了规范,但是对响应数据没有做好规范。

1.2.1 自定义统一响应体

统一数据响应第一步肯定要做的就是我们自己自定义一个响应体类,无论后台是运行正常还是发生异常,响应给前端的数据格式是不变的。

可以参考我们自定义异常类,也来一个响应信息代码code和响应信息说明msg。

@JsonInclude(JsonInclude.Include.NON_NULL) public class ResultVo { /** * 状态码 */ private Integer code; /** * 提示信息,如果有错误时,前端可以获取该字段进行提示 */ private String msg; /** * 查询到的结果数据, */ private T data; public ResponseResult(Integer code, String msg) { this.code = code; this.msg =msg; } public ResponseResult(Integer code, T data) { this.code = code; this.data = data; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg =msg; } public T getData() { return data; } public void setData(T data) { this.data = data; } public ResultVo(Integer code, String msg, T data) { this.code = code; this.msg =msg; this.data = data; } }

然后我们修改全局异常处理的返回值:

@ExceptionHandler(APIException.class) public ResultVO APIExceptionHandler(APIException e) { // 注意哦,这里返回类型是自定义响应体 return new ResultVO(e.getCode(), "响应失败", e.getMsg()); } @ExceptionHandler(MethodArgumentNotValidException.class) public ResultVO MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) { ObjectError objectError = e.getBindingResult().getAllErrors().get(0); // 注意哦,这里返回类型是自定义响应体 return new ResultVO(1001, "参数校验失败", objectError.getDefaultMessage()); }

通过上面的操作,我们将状态码和响应说明还有错误提示数据都返给了前端,并且是所有异常都会返回相同的格式。

这样无论是正确响应还是发生异常,响应数据的格式都是统一的。

数据格式规范好了,不过响应码code和响应信息msg还没有规范。所以,必须要将响应码和响应信息给规范起来。

1.2.2 响应码枚举

要规范响应体中的响应码和响应信息我们使用枚举是最好的。Java中自带了枚举类型,我们可以依据枚举类型创建一个响应码枚举类。

@Getter public enum ResultCode { private int code; private String msg; ResultCode(int code, String msg) { this.code = code; this.msg = msg; } //这里的状态码依据项目实际情况自行定义,不必照搬 SUCCESS(1000, "操作成功"), FAILED(1001, "响应失败"), VALIDATE_FAILED(1002, "参数校验失败"), ERROR(5000, "未知错误"); }

我们还要把状态码和信息就会一一对应,这样比较好维护。

这里要修改响应体的构造方法,让其只准接受响应码枚举来设置响应码和响应信息。

public ResultVO(T data) { //这里的SUCCESS依据自己定义的ResultCode来替换 this(ResultCode.SUCCESS, data); } public ResultVO(ResultCode resultCode, T data) { this.code = resultCode.getCode(); this.msg = resultCode.getMsg(); this.data = data; }

同时我们还应当对全局异常处理的响应码设置方式进行修改:

@ExceptionHandler(APIException.class) public ResultVO APIExceptionHandler(APIException e) { // 注意哦,这里传递的响应码枚举 return new ResultVO(ResultCode.FAILED, e.getMsg()); } @ExceptionHandler(MethodArgumentNotValidException.class) public ResultVO MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) { ObjectError objectError = e.getBindingResult().getAllErrors().get(0); // 注意哦,这里传递的响应码枚举 return new ResultVO(ResultCode.VALIDATE_FAILED, objectError.getDefaultMessage()); } 1.2.3 全局处理响应数据

既然我们对响应数据做了处理,也对异常做了统一返回响应体,我们可以用一个全局处理来把省略掉用响应体包装接口返回数据。

我们同样是像全局异常处理一样,定义一个全局处理类 ResponseControllerAdvice 继承 ResponseBodyAdvice 接口并重写其中的方法。

// 注意,这里要加上需要扫描的包,即项目的controller包 @RestControllerAdvice(basePackages = {"xxx"}) public class ResponseControllerAdvice implements ResponseBodyAdvice { @Override public boolean supports(MethodParameter returnType, Class aClass) { // 如果接口返回的类型本身就是ResultVO那就没有必要进行额外的操作,返回false return !returnType.getGenericParameterType().equals(ResultVO.class); } @Override public Object beforeBodyWrite(Object data, MethodParameter returnType, MediaType mediaType, Class aClass, ServerHttpRequest request, ServerHttpResponse response) { // String类型不能直接包装,所以要进行些特别的处理 if (returnType.getGenericParameterType().equals(String.class)) { ObjectMapper objectMapper = new ObjectMapper(); try { // 将数据包装在ResultVO里后,再转换为json字符串响应给前端 return objectMapper.writeValueAsString(new ResultVO(data)); } catch (JsonProcessingException e) { throw new APIException("返回String类型错误"); } } // 将原本的数据包装在ResultVO里 return new ResultVO(data); } }

重写的这两个方法是用来在controller将数据进行返回前进行增强操作,supports方法要返回为true才会执行beforeBodyWrite方法,所以如果有些情况不需要进行增强操作可以在supports方法里进行判断。

对返回数据进行真正的操作还是在beforeBodyWrite方法中,我们可以直接在该方法里包装数据,这样就不需要每个接口都进行数据包装了,省去了很多麻烦。

这样尽管我们没有在接口中包装数据,但返回给前端的依然是经过包装后的数据。

1.3 其他返回数据

在上一节中,我们得到了一个统一响应体ResultVo,里面具有code、msg、data。

如果返回给前端的数据,要求给出分页信息,那么ResponsePages类中,还需要有Page类,其中至少包括当前页数,每页显示条数和总条数信息。分页使用github的pagehelper工具类来完成。

http返回对象示例: { code: code, msg: msg, pageInfo: { // 分页信息 curPage: 1, pageLimit: 10, page: 1, total: 10 } data: {data} }

很多时候我们往往需要多种返回数据,例如添加返回分页信息,我们可以灵活的根据业务需求修改ResultVo,但是切记不要在项目进行到中段时再反复修改,一定要在项目开始时就确立,这就是接口开发文档存在的意义。

2 接口设计参考 2.1 接口设计原则

参考面向对象原则,接口设计也有六大原则,分别是单一职责原则、里氏替换原则、依赖倒置原则、接口隔离原则、迪米特法则、开闭原则。

接下来介绍一些其他的设计原则。

2.1.1 数据有效性校验

常规性校验:包括必填字段,长度检测。格式校验等。

鉴权校验:当前请求必须符合权限等。

业务校验:根据实际业务而定,比如订单金额不能小于0等等。

作用:在接口层做用户鉴权校验和参数校验,比如做ID基础校验,id"id":"20201219", "name":"21.59", "age":"ftp_1002" ... }, ] 复制代码 请求参数说明 字段名字段说明字段类型是否必填字段1说明字段1的作用varchar(50)是字段2说明字段2的作用int是字段3说明字段3的作用decimal是 响应示例

成功响应编码:

{ "code: "200", "message": "请求成功", "data": 返回数据,格式自定 } 复制代码

失败响应编码:

{ "code: "200", "message": "请求成功", "data": 返回数据,格式自定 } 复制代码 响应参数说明 接口返回码接口返回描述200成功400请求参数异常401授权失败500系统异常 3.2 复杂版本

由于不同的公司有不同的文档格式要求,此处只列举一个仅供参考的案例。

3.2.1 目录格式 + 封面 + 接口文档名称 + 接口版本号 + 版权说明 + 文档信息 + 标题 | 创建时间 | 打印时间 | 文件名 | 存放目录 | 所有者 | 作用 + 小题:版权声明 + 版本历史(重点1) + \| 版本号 \| 日期 \| 修改者 \| 描述 \| + \| v1.0.0 \| xxx \| xxx \| xxx | + 目录 + 结构清晰 + 有条理 + 能快速定位需要的信息(后文会介绍) + 文档具体内容部分 + 编写目的 + 对接准备事项 + 测试联调 + 上线 + 使用协议 + 规范 + 报文规范 + 请求报文规范 + 响应报文规范 + 接口描述 + 报文规范 + 请求报文 + 响应报文 + 公共报文头 + 接口码说明 + 业务接口 + 查询接口 + 加解密规范 + 原则 + 令牌信息 + 加密规范 + 解密规范 + 业务接口 + 具体接口1: + 说明 + 规范码(查表) + 使用方式 + 请求字段 + 响应字段 + 案例 + 具体接口2.... ........ + 附录 + 参考资料1 + 参考资料2 + 其他..... 复制代码 3.2.2 案例模板 封面

封面还是比较重要的,毕竟是打开文档的第一眼内容,下面用阿里的文档作为参考,可以看到封面一般是如下内容:

公司名称 文档名称 版本号

在这里插入图片描述

文档信息

文档信息主要记录这份文件的产生日期以及具体的创建打印日期等。

文档名内容标题xxx文档创建日期20xx-xx-xx打印日期20xx-xx-xx文件名文档的全名存放目录文件位置所有者某某公司作者xxx

版权声明:(现在这个时代版权是极其重要的)

xxxx所有,不得三方借阅、出让、出版

版本历史

版本历史是很重要的,每次改动都需要有详细的记录,这样才能保证文档的干净和有效,同时可以方便review的时候,对于文档的修订者进行文档审查。

版本号日期概述修订者1.0.020xx-xx-xx创建xxx1.0.120xx-xx-xx修改文档第一小节内容xxx1.0.220xx-xx-xx修订文档第四小节的错误描述,更新文档说明xxx 目录

好的文档一定有好的目录,只要按照一定的规范和格式写出来的文档,一般看上去都是十分舒服的。还是用阿里的开发手册做参考

在这里插入图片描述

文档具体内容部分

这一部分发挥的自由空间就比较大了,不同的业务不同的公司不同的需求不同的人都能写出万千种格式的文档,所以这里也是给一个样例做参考使用。是否有实用价值因人而异。

为了不让整个目录树太长,这里没有做标题说明=-=

编写目的

需要解决什么问题,为什么要这份文档,这份文档有什么参考价值?

对接准备事项

接口方可以提供什么内容,接口方需要对接方的那些内容,以及提供的其他信息,比如需要对接方提供 系统应用id,系统唯一标识。向对接方提供密钥等等

​ 1. 测试联调:分配测试的密钥,测试环境的账户和密码以及其他信息

​ 2. 上线:上线之后需要做什么事情,如:替换生产url,替换生产环境账户密码,替换密钥为生产密钥等等

使用协议 + 规范

可以是本次对接使用的算法,通信协议,可以是术语说明或者和业务相关的其他说明,以及对接的要求都可以,发挥空间很大,自由设计。

报文规范

报文规范是接口对接的核心部分,因为对接大部分的时间基本都是花在接口参数调试和请求调试等。所以报文规范算是非常重要的内容。具体内容可以参考简单版本的接口描述,也可以使用目录格式进行对应的描述

+ 请求报文:主要为请求的Body,以及请求的header内容,一般都是Json的格式,并且要求UTF8编码 + 响应报文:返回的格式和内容,也是需要协商的部分 + 公共报文头:一般需要重复使用的参数可以作为公共报文头,但是不是所有的公共报文头都是必选,存在可选的参数 + 接口码说明:描述接口的注意事项,以及那些字段参数需要重点关注,主要为提示信息 + 业务接口:一般表示业务的返回结果,比如统一2000作为报文的成功响应码,其他所有码都是存在对应的接口码表进行设计。 + 查询接口:如何才算是表示查询成功,比如一个还钱的接口当中可能是受理中,拒绝或者处理完成,等查询接口的信息描述 复制代码 加解密规范

也是比较重要的部分,也是比较花时间的地方,需要大量调试来打通接口的地方,存在以下的几个要点。

原则:接口存在一些简单的原则,比如`非对称加密`,`数字签名`,`时间戳判断有效性`,具体按照接口的原则自由设置 令牌信息:描述令牌是如何生成的,是比较重要的部分,一般由对接双方沟通完成,最好多以案例和代码辅助解释 加密规范:描述接口数据的加密过程,比较重要的内容信息,最好多以案例和代码辅助解释 解密规范:就是解释接口要如何解密,比如需要拿到服务端给过来的配对公钥才能解密,再比如使用签名+参数进行对照加密验证签名是否正确等。

加解密规范参考:

一般的加密方式,一般情况下做到下面这种形式基本可以屏蔽大部分的攻击:

1. 按照map的key进行字典排序,同时加入`timetamp`值校验核对时间 2. 把参数按照一些特殊形式拼接为`key=value&key=value`的形式,末尾带入时间戳或者其他的一些信息,比如应用Id等核实身份的内容 3. 把这一串按照**AES加密**,然后按照**BASE64编码**,生成一个编码串 4. 把BASE64编码进行**MD5加密**,加密完成之后,得到固定长度的MD5字符串 5. 按照md5串+上面的string在进行一次md5加密,生成签名,那么这个签名基本上就唯一的 业务接口

这里基本可以照抄简单接口模板,因为接口描述每个人的描述不同,下面给出一些基本上涉及的点,另外,到了这一步就尽量用案例辅助,因为案例可以帮助接口阅读者更快速的上手和理解,注意这一部分的内容:实用性大于理论性。

具体接口:

1. 说明 2. 规范码(查表) 3. 使用方式 4. 请求字段 5. 响应字段 6. 案例 附录

可能这部分和说明书一样基本没人看,所以不做过多的解释,附录不必写的很详细的,这里可以随意施展。

参考文档

1.CSDN_如何设计和编写标准的后端接口 2.开源博客_API 接口规范 3.CSDN_什么是接口文档,如何写接口,有什么规范?



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭