使用Jersey创建RESTful风格的WebService
2016-03-03 17:51
447 查看
什么是RESTful架构
每一个URI代表一种资源客户端和服务端之间传递这种资源的某种表现层(“资源”具体呈现出来的形式叫做它的“表现层”。)
对于资源的具体操作,由HTTP动词表示。客户端通过HTTP动词(GET,POST,PUT,DELETE)对服务端资源进行操作,实现表现层状态转换
JAX-RS annotations
Annotation | Description |
---|---|
@PATH(your_path) | Sets the path to base URL + /your_path. The base URL is based on your application name, the servlet and the URL pattern from the web.xml configuration file. |
@POST | Indicates that the following method will answer to an HTTP POST request. |
@GET | Indicates that the following method will answer to an HTTP GET request. |
@PUT | Indicates that the following method will answer to an HTTP PUT request. |
@DELETE | Indicates that the following method will answer to an HTTP DELETE request. |
@Produces(MediaType.TEXT_PLAIN[, more-types]) | @Produces defines which MIME type is delivered by a method annotated with @GET. In the example text (“text/plain”) is produced. Other examples would be “application/xml” or “application/json”. |
@Consumes(type[, more-types]) | @Consumes defines which MIME type is consumed by this method. |
@PathParam | Used to inject values from the URL into a method parameter. This way you inject, for example, the ID of a resource into the method to get the correct object. |
@DefaultValue | 设置@QueryParam参数的默认值,如: @DefaultValue(“2”) @QueryParam(“step”) int step |
@Context | 解释上下文参数 |
服务端:
//'启动服务器 public class Test { //服务器路径 public static final String BASE_URI="http://localhost:8080/myapp"; final static ResourceConfig rc = new ResourceConfig().packages("com.chm.test"); public static HttpServer startServer() { HttpServer server = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);//URI.create(BASE_URI), rc return server; } public static void main(String[] args) throws Exception { // final HttpServer server = startServer(); // final HashMap<String, String> initParams = new HashMap<String, String>(); // // initParams.put("jersey.config.server.provider.packages", "com.chm.test");//packages定义了Jersey寻找服务类的位置。 它必须指向定义的资源类。 System.out.println("Starting grizzly..."); // HttpServer server = GrizzlyWebContainerFactory.create(BASE_URI, initParams); HttpServer server = startServer(); System.out.println(String.format("jersey app started" )); System.in.read(); server.shutdown(); System.exit(0); } } //资源类 @Path("/user") public class User { // @GET //// @Path("/{id}") //// @Produces(MediaType.TEXT_PLAIN) // @Produces(MediaType.APPLICATION_JSON) // public String sayHello(@Context HttpServletRequest request) // { // String age = request.getHeader("contentType"); // System.out.println(age); // Map<String, String> map = new HashMap<String, String>(); //// System.out.println("hello"); // map.put("aa", "zhangsan"); // map.put("bb", "lisi"); // String str = "{\"name\":\"zhangsan\",\"age\":24}"; //// System.out.println(id); // return str; // } @GET public String get(@Context UriInfo ui) { MultivaluedMap<String, String> queryParams = ui.getQueryParameters(); List<String> age = queryParams.get("age"); System.out.println(age); MultivaluedMap<String, String> pathParams = ui.getPathParameters(); return "success"; } @PUT @Path("{chm}") @Produces(MediaType.TEXT_PLAIN) public String update(@PathParam("chm") String name, String hello) { System.out.println(hello); System.out.println(name); return "put invoke"; } @POST @Path("f") public String postFile(final File file) { String result = ""; try { BufferedReader br = new BufferedReader(new FileReader(file)); return result = br.readLine(); }catch(Exception ex) { ex.printStackTrace(); } return result; } } //客户端 public class ClientTest { public static void main(String[] args) { // HttpServer server = Test.startServer(); //可以有多个过滤器 final Client client = ClientBuilder.newClient(); // client.register(Filter.class); // WebTarget target = client.target(Test.BASE_URI); // Entity<String> entity = Entity.entity("secrety", MediaType.TEXT_PLAIN); // Response resp = target.path("/user?age=26;addr=ah").request().get();// // System.out.println(resp.getStatus()); // resp.readEntity(String.class); // System.out.println(resp.hasEntity()); // String str = resp.readEntity(String.class); // System.out.println(str); // Form form = new Form(); // form.param("x", "y"); WebTarget target = client.target("http://localhost:8080/jersey/rest/hello"); Entity<String> entity = Entity.entity("<MyBean><anyString>Hello World!</anyString><anyNumber>42</anyNumber></MyBean>", MediaType.TEXT_HTML_TYPE); Response resp = target.request().post(entity); resp.close(); // target.path("/hello/charming").request().put(entity, String.class); // String path = System.getProperty("user.dir")+"/src/test.txt"; // System.out.println(path); // File f = new File(path); // Entity<File> e = Entity.entity(f, MediaType.TEXT_PLAIN_TYPE); // String str1 = target.path("/user/f").request().post(e, String.class); // System.out.println(str1); // } }
资源的生命周期
如下所示的例子import javax.inject.Singleton; @Path("/item") public class ItemResource { @Path("content") public Class<ItemContentSingletonResource> getItemContentResource() { return ItemContentSingletonResource.class; } } @Singleton public class ItemContentSingletonResource { // this class is managed in the singleton life cycle }
JAX-RS resources are managed in per-request scope by default which means that new resource is created for each request. In this example the javax.inject.Singleton annotation says that the resource will be managed as singleton and not in request scope. The sub-resource locator method returns a class which means that the runtime will managed the resource instance and its life-cycle. If the method would return instance instead, the Singleton annotation would have no effect and the returned instance would be used.
我们来看看 Resource scopes
scope | Annotation | Annotation full class name | Description |
---|---|---|---|
Request scope | @RequestScoped (or none) | org.glassfish.jersey.process.internal.RequestScoped | Default lifecycle (applied when no annotation is present). In this scope the resource instance is created for each new request and used for processing of this request. If the resource is used more than one time in the request processing, always the same instance will be used. This can happen when a resource is a sub resource is returned more times during the matching. In this situation only on instance will server the requests. |
Per-lookup scope | @PerLookup | org.glassfish.hk2.api.PerLookup | In this scope the resource instance is created every time it is needed for the processing even it handles the same request. |
Singleton | @Singleton | javax.inject.Singleton | In this scope there is only one instance per jax-rs application. Singleton resource can be either annotated with @Singleton and its class can be registered using the instance of Application. You can also create singletons by registering singleton instances into Application. |
典型的设计误区
URI包含动词。“资源”是一种实体,应该是名词。URI不应该有动词,动词放在HTTP协议中。URI中加入版本号。
例如
http://www.example.com/app/1.0/foo
http://www.example.com/app/1.1/foo
http://www.example.com/app/2.0/foo
不同的版本可以理解为同一种资源的不同表现形式,所以应该用同一个URI,版本号可以在HTTP请求头信息中的Accept字段中区分:
Accept: vnd.example-com.foo+json; version=1.0
Accept: vnd.example-com.foo+json; version=1.1
Accept: vnd.example-com.foo+json; version=2.0
相关文章推荐
- UEFI 模式ghost win10
- 《编程精粹》书摘与读书笔记总结
- 在现场更新文件的流程------运维日志27
- 使用Entity Framework时要注意的一些性能问题
- JavaScript全讲-架构原则透析
- iOS之键盘处理
- 转自知乎 《Unicode 和 UTF-8 有何区别?》
- (16)集合操作
- mysql 日志
- linux如何开启oracle自动备份的脚本
- mysql root 忘记密码 破解
- 白话windows之 会话、工作站、桌面、窗口之间的关系
- 我是如何使用Android反编译软件的?
- iOS导航栏 修改系统返回按钮
- sizeof运算符来获取各种数据类型在内存中所占字节数--gyy整理
- PHP实现登录,注册,密码修改
- springmvc学习笔记(一)之简介
- (15)字典操作
- python qrcode 库的使用
- 检查form表单数据是否发生变化