浅谈Spring Boot 开发REST接口最佳实践
本文介绍了spring boot 开发rest接口最佳实践,分享给大家,具体如下:
http动词与sql命令对应
get
从服务器获取资源,可一个或者多个,对应sql命令中的select get /users 获取服务器上的所有的用户信息 get /users/id 获取指定id的用户信息
post
在服务器上创建一个新资源,对应sql命令中的create post /users 创建一个新的用户
put
在服务器上更新一个资源,客户端提供改变后的完整资源,对应sql命令中的update put /users/id 更新指定id的用户的全部信息
delete
从服务器上删除一个资源,对应sql命令中的delete delete /users/id 删除指定id的用户信息
patch
在服务器更新一个资源的部分属性,对应sql命令中的update patch /users/id 更新指定id的用户的某个属性
url中的约定
url中名词使用复数形式
url中的名称是使用单数还是使用复数的问题,争议由来已久。url中的名词一般对应数据库中的表,表中存储的是同类数据, 在实践中我是强制使用复数形式 ,看上去更舒服些。
/users /users/1 /roles /roles/1
至于一些不规则的、不可数的名词就见仁见智吧。
/heroes /heroes/1 /people /people/1 /foots /foots/1 /feet /feet/1
版本
讲版本号加入到url中以应对不兼容的和破坏性的更改。发布新api时,客户端可以自如的迁移到新api,不会因调用完全不同的新api而陷入窘境。使用直观的“v”前缀来表示后面的数字是版本号,不需要次级版本号,不应该频繁的发布api版本。
/edu/v1/users /edu/v1/roles
对可选的、复杂的参数使用查询字符串
为了让url更小、更简洁,为资源设置一个基本url,讲可选的、复杂的参数用查询字符串表示。
/edu/v1/users?enabled=1&roleid=1
提供分页信息
一次性返回数据库中的所有的资源不是一个好主意,因此需要提供分页机制。通常使用数据库中众所周知的参数offset和limit
/edu/v1/users?enabled=1&offset=1&limit=15
如果客户端没有传递这些参数,则应使用默认值,通常offset=0,limit=10。
非资源请求使用动词
有时api调用并不涉及资源,在这种情况下,服务器执行一个操作病将结果返回给客户端。
/edu/v1/calc?p=100
考虑特定资源和跨资源搜索
提供对特定止缘的搜索很容易,只需要使用相应的资源集合,并将搜索字符串附加到查询参数中即可。
/edu/v1/users?username=李庆海
如果需要对所有资源提供全局搜索,则需要使用其他方法。
/edu/v1/search?key=李庆海
响应结果
使用小驼峰命名法作为属性标识符
通常,restful web服务将被javascript编写的客户端使用。客户端会将json响应转换为javascript对象,然后调用其属性。因此,最好遵循javascript代码通用规范。
person.year_of_birth // 不推荐,违反javascript代码通用规范 person.yearofbirth // 不推荐,javascript构造方法命名 person.yearofbirth // 推荐
提供分页信息
返回结果比较多时,应提供分页信息。
{ "page": 0, "size": 10, "total": 3465, "obj": [ ] }
spring mvc开发rest接口
常用注解
@restcontroller
@restcontroller是@responsebody和@controller的组合注解。
@requestmapping
此注解即可以作用在控制器的某个方法上,也可以作用在此控制器类上。当控制器在类级别上添加@requestmapping注解时,这个注解会应用到控制器的所有处理器方法上。处理器方法上的@requestmapping注解会对类级别上的@requestmapping的声明进行补充。
@postmapping
组合注解,是@requestmapping(method =requestmethod.post)的缩写。
@putmapping
组合注解,是@requestmapping(method = requestmethod.put)的缩写。
@patchmapping
组合注解,是@requestmapping(method = requestmethod.patch)的缩写。
@deletemapping
组合注解,是@requestmapping(method = requestmethod.delete)的缩写。
@getmapping
组合注解,是@requestmapping(method = requestmethod.get)的缩写。
@pathvariable
获取url中的数据。
@requestparam
获取请求参数的值。
rest接口及swagger 编写api文档示例
关于swagger的使用可参考spring boot 项目中使用swagger2 。方法体中的代码不重要,重要的是方法的签名以及与http动词的映射。
import java.util.date; import javax.persistence.entitynotfoundexception; import org.springframework.beans.factory.annotation.autowired; import org.springframework.data.domain.page; import org.springframework.web.bind.annotation.getmapping; import org.springframework.web.bind.annotation.patchmapping; import org.springframework.web.bind.annotation.pathvariable; import org.springframework.web.bind.annotation.postmapping; import org.springframework.web.bind.annotation.requestbody; import org.springframework.web.bind.annotation.requestmapping; import org.springframework.web.bind.annotation.requestparam; import org.springframework.web.bind.annotation.restcontroller; import cn.com.infcn.jianshu.service.userservice; import cn.com.infcn.jianshu.exception.bizexception; import cn.com.infcn.jianshu.exception.loginnameorpassworderrorexception; import cn.com.infcn.jianshu.exception.resourceexistsexception; import cn.com.infcn.jianshu.model.user; import cn.com.infcn.jianshu.util.jsonresult; import io.swagger.annotations.api; import io.swagger.annotations.apioperation; import io.swagger.annotations.apiparam; /** * 系统用户controller * * @author 李庆海 * */ @api(value = "系统用户接口", tags = "系统管理") @restcontroller @requestmapping("/v3/edu/users") public class usercontroller { @autowired private userservice userservice; /** * 添加用户,注册 * * @param loginname * 登录账号 * @param username * 用户名称 * @param password * 登录密码 * @param roleid * 用户角色 * @return * @throws resourceexistsexception */ @apioperation(value = "添加用户") @postmapping("/") public jsonresult create( @apiparam(name = "loginname", value = "登录账号", required = true) @requestparam(required = true) @requestbody string loginname, @apiparam(name = "username", value = "用户名称", required = true) @requestparam(required = true) @requestbody string username, @apiparam(name = "password", value = "登录密码", required = true) @requestparam(required = true) @requestbody string password, @apiparam(name = "roleid", value = "用户角色编号", required = true) @requestparam(required = true) @requestbody string roleid) throws resourceexistsexception { boolean exists = this.userservice.exists(loginname); if (exists) { throw new resourceexistsexception(loginname); } user user = userservice.create(loginname, password, username, roleid); return jsonresult.success(user); } /** * 用户凭借登录账号和登录密码进行登录 * * @param loginname * 登录账号 * @param password * 登录密码 * @throws entitynotfoundexception */ @apioperation(value = "根据用户编号查询用户信息") @getmapping("/login") public jsonresult login( @apiparam(name = "loginname", value = "登录账号", required = true) @requestparam(required = true) string loginname, @apiparam(name = "password", value = "登录密码", required = true) @requestparam(required = true) string password) throws loginnameorpassworderrorexception { user user = this.userservice.login(loginname, password); if (null == user) { throw new loginnameorpassworderrorexception(); } return jsonresult.success(user); } /** * 根据用户编号查询用户信息 * * @param id * 用户编号 * @throws entitynotfoundexception */ @apioperation(value = "根据用户编号查询用户信息") @getmapping("/{id}") public jsonresult read( @apiparam(name = "id", value = "用户编号,主键", required = true) @pathvariable(required = true) string id) throws entitynotfoundexception { user user = this.userservice.getone(id); return jsonresult.success(user); } /** * 账户注销,不删除用户的数据 * * @param userid * 用户编号 * @return */ @apioperation(value = "注销账户") @patchmapping("/{id}") public jsonresult cancel( @apiparam(name = "id", value = "用户编号,主键", required = true) @pathvariable(required = true) string id) throws entitynotfoundexception { this.userservice.cancel(id); return jsonresult.success(); } /** * 重置密码 * * @param id * 用户编号 * @param password * 新登录密码 * @return */ @apioperation(value = "重置密码") @patchmapping("/") public jsonresult updatepassword( @apiparam(name = "id", value = "用户编号,主键", required = true) @requestparam(required = true) string id, @apiparam(name = "password", value = "新登录密码", required = true) @requestparam(required = true) string password) { this.userservice.updatepassword(id, password); return jsonresult.success(); } /** * 多条件组合查询 * * @param username * 用户名称 * @param roleid * 用户角色 * @param start * 开始日期 * @param end * 结束日期 * @param page * 分页,从0开始 * @param size * 每页的行数,默认10 * @return * @throws bizexception */ @apioperation(value = "用户信息查询") @getmapping("/") public jsonresult query( @apiparam(name = "username", value = "用户名称,查询关键词", required = false) @requestparam(required = false) string username, @apiparam(name = "roleid", value = "用户角色编号", required = false) @requestparam(required = false) string roleid, @apiparam(name = "start", value = "用户角色编号", required = false) @requestparam(required = false) date start, @apiparam(name = "end", value = "用户角色编号", required = false) @requestparam(required = false) date end, @apiparam(name = "page", value = "分页,第几页,从1开始", defaultvalue = "1", required = true) @requestparam(defaultvalue = "1", required = true) int page, @apiparam(name = "size", value = "每页的行数,正整数", defaultvalue = "10", required = true) @requestparam(defaultvalue = "10", required = true) int size) throws bizexception { page<user> datas = this.userservice.finddatas(username, roleid, start, end, page, size); if (null == datas || null == datas.getcontent() || datas.getcontent().isempty()) { throw new bizexception("用户不存在"); } return jsonresult.success(datas); } }
swagger2接口文档效果图
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。