一. 概念 rest
全称 (Resource) REpresentational State Transfer (表现层状态转移)
rest 描述的是 client 到 server的一种交互形式
Resource 资源 代表了数据
REpresentational 资源的表现形式 如json xml text...
State 状态
State Transfer 状态转变化 主要通过 http 的一系列操作实现
二. 概念 restful
restful 是API的一种设计风格,这个风格里面规定资源的操作CRUD(create, reach, update, delete)通过Http方法 post get put
delete 来实现:
rest | http | des |
---|---|---|
create | post | 添加 |
reach | get | 获取 |
update | put | 更新 |
delete | delete | 删除 |
在restful 里面 万物皆资源,那要操作这些资源,怎么对这些资源进行定位呢? 答: 通过url.
通常情况下 我们写url 如下
method | api | des |
---|---|---|
get | api/getUser | 获取用户 |
post | api/addUser | 添加用户 |
post | api/updateUser | 更新用户信息 |
post | api/deleteUser | 删除用户 |
这是不符合restful 风格的, rest 不建议在url 中使用动词如表格中的get/add...来表述你的意图
那符合rest的url是什么样子的呢
method | api | des |
---|---|---|
get | api/user | 获取用户 |
post | api/user | 添加用户 |
put | api/user | 更新用户信息 |
delete | api/user | 删除用户 |
通俗点来讲就是 通过url就可以知道你想要的资源 通过http method就可以知道你想要的操作 通过http status 就可以知到操作的结果,并约束get 的操作不能改变资源的状态
推荐使用名词复数来定义所有资源
api/users 代替 api/user
使用子资源来表达资源间的关系
example: id 为12的用户下的所有订单
api/users/12/orders
HATEOAS 约束
HATEOAS(Hypermedia as the engine of application state) 一种比较复杂的约束,我们通常的做法是和服务器端约定好接口的定义,然后接口连接hardcode在本地 需要的时候调用,这种方式使客户端和服务器端的耦合加重,如果服务器端修改了接口定义,那么客户端也要跟着修改,在 HATEOAS 资源的uri都是动态的所以当接口定义发生改变时 客户端并不需要做任何的修改。
example: 请求用户列表
{
"users": [
{
"id": "23",
"name": "Stefan Jauker",
"links": [
{
"rel": "self",
"href": "/api/v1/users/23"
}
]
}
]
}
Tips:
可以参考git接口定义
https://developer.github.com/v3/git/commits/
HATEOAS说明
https://en.wikipedia.org/wiki/HATEOAS
Http 状态码说明
https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
从上到下 我们已经涵盖了Rest 的四种成熟度, 下面我们来看一下什么是Rest 的成熟度模型
1.第一个层次(Level 0)的 Web 服务只是使用 HTTP 作为传输方式,实际上只是远程方法调用(RPC)的一种具体形式。SOAP 和 XML-RPC 都属于此类。
Tips: RPC SOAP REST 对比
https://www.cnblogs.com/bellkosmos/p/5213491.html
2.第二个层次(Level 1)的 Web 服务引入了资源的概念。每个资源有对应的标识符和表达。
3.第三个层次(Level 2)的 Web 服务使用不同的 HTTP 方法来进行不同的操作,并且使用 HTTP 状态码来表示不同的结果。如 HTTP GET 方法来获取资源,HTTP DELETE 方法来删除资源。
4.第四个层次(Level 3)的 Web 服务使用 HATEOAS。在资源的表达中包含了链接信息。客户端可以根据链接来发现可以执行的动作。
talk is cheap show me the code
---------------------------------我是漂亮的分割线-----------------------------
下面篇文章介绍怎样使用jersey 实现restful api
遵循rest 风格的框架辣么多 为啥用jersey 呢?
为啥要用jersey?
因为简单呀 哇哈哈哈。。。。
首先附上 restful api 设计指南
http://www.ruanyifeng.com/blog/2014/05/restful_api.html
首先介绍几个annotation:
@GET @POST @PUT @ DELETE Http method
@Path 标识路径url
@Consumes 要求输入的数据类型 MediaType (application/json ...)
@Produces 接口返回的数据类型 MediaType (同上)
@PathParam 路径参数: /user /{param}
@QueryParam get请求url 参数 /user?id=12
@FormParam 表单参数
以上是常用的几个注解, 下面开始讲实际操作
准备好原料 eclipse/ tomcat /jersey libs
一 新建web项目
不会的找度娘
二 将lib是里面的jar 包全部复制到 web-info lib & ext下, 对就是那么暴力 。。。
image.png三 新建package
例如 com.demo.api
全局配置
@ApplicationPath("/rest")
public class RestResourceConfig extends ResourceConfig {
public RestResourceConfig() {
packages("com.rest.demo.resource");
register(UserRest.class);
}
}
或者通过 web.xml 中配置
如果是基于web 3.0 新建的项目的话 是没有web.xml 的, 那么你需要新建一个web.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>HiJersey</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>Way REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.demo.api</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Way REST Service</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
新建类
@Path("/manager")
public class ManagerResource {
}
这样就简单的暴露了 一个resource
ps: @path 不是必须的, /不是必须的
下面我们来实现一个简单的get service
@GET
public String sayHi() {
return "hi jersey";
}
run on server 打开浏览器访问
http://localhost:8080/HiJersey/rest/manager
可以看到结果
image.png很简单有木有
下面我们来实现稍微复杂一点的api
1.get 请求 带路径参数和查询参数
@GET
@Path("/user/{id}")
@Produces(MediaType.APPLICATION_JSON)
public User getUser(@PathParam("id") String id, @QueryParam("name") String name) {
User user = new User(id, 18, name);
return user;
}
注意 这边返回的是一个自定义类 那需要在User 类上注释@XmlRootElement 如下
@XmlRootElement
public class User implements Serializable{
}
同样可以返回 List & Map 类型的数据
- post 请求 接收对象参数
@POST
@Path("user")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public User addUser(User user) {
return user;
}
- post 接收表单数据
@POST
@Path("login")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON)
public User login(MultivaluedMap<String, String> formParams) {
User user = new User();
user.setName(formParams.getFirst("name").toString());
user.setPassword(formParams.getFirst("password").toString());
return user;
}
@Path("login2")
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public User login(@FormParam("name") String name, @FormParam("password") String password) {
User user = new User();
user.setName(name);
user.setPassword(password);
return user;
}
put delete 方式传参和返回数据同上
- 文件上传
@POST
@Path("file")
@Consumes({MediaType.MULTIPART_FORM_DATA})
@Produces({MediaType.APPLICATION_JSON})
public List<String> upload(@Context HttpServletRequest request, @Context HttpServletResponse response) {
String path = "D:"+File.separator+"imgs" + File.separator;
return FileUtil.upload(path, request);
}
第二种方式 so easy
@POST
@Path("file2")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public String upload2(
@FormDataParam("file") InputStream input,
@FormDataParam("file") FormDataContentDisposition d) {
FileUtil.saveFile(input, "D:"+File.separator+"imgs" + File.separator+d.getFileName());
return d.getFileName();
}
注意这种方式需要配置 xml 并且需要加入multipart 和 mimepull包
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
</init-param>
*注意: form 要设置成enctype='multipart/form-data'
5.获取所有路径参数 和查询参数
@GET
@Path("{version}")
public String get(@Context UriInfo ui) {
MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
MultivaluedMap<String, String> pathPatams = ui.getPathParameters();
for(String key : queryParams.keySet()) {
System.out.println(key +" " + queryParams.getFirst(key));
}
for(String key : pathPatams.keySet()) {
System.out.println(key +" " + pathPatams.getFirst(key));
}
return "success";
}
以上就是jersey 的最基础的用法 over
网友评论