JAX-RS 从傻逼到牛逼 2:开发一个简单的服务

标签: jax rs 傻逼 | 发表时间:2011-09-20 17:22 | 作者:蜀山兆孨龘 时金魁
出处:http://www.blogjava.net/

JAX-RS 使用注解进行配置,所以用它开发 REST 风格的服务非常简单。楼主在本文用一个小例子来说明 JAX-RS 的基本用法。


假设楼主要开发一个小电影服务,客户端可以通过请求 URI 对电影进行 CRUD 操作。为简明起见,这儿不使用数据库,只在内存中模拟。先用一个非常简单的 Movie 类,在后续的文章中根据情况逐步扩充:

        public class Movie {
            private int id;
            private String title;
            // 此处省略若干行
        }
    

嗯,就是一个很普通的 JavaBean,实际项目中可以根据需要加上 @Entity 等注解。接下来看看如何编写 JAX-RS 服务。


一个 JAX-RS 服务就是一个使用了 JAX-RS 注解来将 HTTP 请求绑定到方法的 Java 类,一共支持两种类型:单请求对象或单例对象。单请求对象意味着每来一个请求,就创建一个服务对象,在请求结束时销毁。单例对象则意味着只有一个服务对象处理所有的请求,从而可以在多个请求间维持服务状态。JAX-RS 服务可通过继承 javax.ws.rs.core.Application 来定义,其中的 getClasses 方法返回单请求对象的类型,getSingletons 方法返回单例对象的类型。这两个方法是可选的。在 Java EE 6 环境中,如果这两个方法都返回 null 或者空集合,那么应用程序中的所有 JAX-RS 都将被部署。这时可以用 CDI 的 @javax.inject.Singleton 或者 EJB 的 @javax.ejb.Singleton 注解来指定单例对象。

如果电影服务的上下文根路径为 http://localhost/ms,而楼主希望将服务部署到 http://localhost/ms/rest 下面,只需要写一个类:

        @ApplicationPath("rest")
        public class RestApplication extends Application {
        }
    

@ApplicationPath 注解指定所有服务的相对基址,如果为空字符串,则直接使用上下文根路径。另一种配置方式是在 web.xml 文件中进行声明,那是为了使 JAX-RS 能在 Servlet 容器(例如 Tomcat)中运行,此处略过。这项配置必不可少,否则无法部署服务。


很好很强大,现在开始编写电影服务类 MovieService,先看看声明和初始化:

        @Singleton
        @Path("movie")
        public class MovieService {
            private AtomicInteger ai;
            private ConcurrentMap<Integer, Movie> movieMap;

            @PostConstruct
            private void init() {
                ai = new AtomicInteger();
                movieMap = new ConcurrentHashMap<>();
                int id = ai.getAndIncrement();
                movieMap.put(id, new Movie().setId(id).setTitle("Avatar"));
            }
    

因为楼主只需要一个“内存数据库”,所以用单例对象即可,此处使用 CDI 的 @javax.inject.Singleton 来声明单例。@Path 声明了一个服务,它指示 MovieService 负责处理发送到 http://localhost/ms/rest/movie 的请求。路径的拼接方式非常直观。init 方法带有 @PostConstruct 注解,因此将在 MovieService 构造完成后立即调用,它向 movieMap 中存入了一个 ID 为 0 的 Movie 对象。为简化代码,Movie 的设置方法都返回 this,有点伪造构建者模式的味道。


接下来看看如何处理 HTTP 请求。

GET

GET 请求用于获取一个资源。在本例中用来获取一部电影的信息:

        @GET
        @Path("{id}")
        @Produces(MediaType.APPLICATION_JSON)
        public Movie find(@PathParam("id") int id) {
            Movie movie = movieMap.get(id);
            if (movie != null) {
                return movie;
            } else {
                throw new WebApplicationException(Response.Status.NOT_FOUND);
            }
        }
    

该方法标注了 @GET,表示用来处理向 http://localhost/ms/rest/movie/{id} 发送的 GET 请求。@Path 再次用来绑定路径,注意其参数 {id},它带有花括号,对应 URI 的最后一段,也正好和方法参数 id@PathParam 的值相对应。这种参数还有很多高级用法,以后再介绍。@Produces 注解指定输出格式为 JSON。JAX-RS 内置了很多格式,详见 MediaType 的文档。如果找到了相应 ID 的对象,则将其返回,JAX-RS 会自动加上响应码 200 OK;否则抛出异常,错误码为 404 Not Found。

例如,通过浏览器访问 http://localhost/ms/rest/movie/0,得到的结果为 {"@id":"0","@title":"Avatar"}。

POST

POST 请求用于创建一个资源。在本例中用来创建一部电影:

        @POST
        @Consumes(MediaType.APPLICATION_JSON)
        public Response create(Movie movie) {
            int id = ai.getAndIncrement();
            movieMap.put(id, movie.setId(id));
            return Response.created(URI.create(String.valueOf(id))).build();
        }
    

由于没有 @Path 注解,所以 POST 请求的目标就直接是 http://localhost/ms/rest/movie。Consumes@Produces 相反,表示接受的数据类型,此处 JAX-RS 会自动把 JSON 数据转换为 Movie 对象。返回的响应码为 201 Created,并且带有所创建资源的 URI。

例如,向 http://localhost/ms/rest/movie 发送 POST 请求,正文为 {"@title": "007"},则可以从 FireBug 的网络监控中看到返回的响应码,以及头部中 Location 的值为 http://localhost:8080/rest/service/movie/1。多次发送该 POST 请求,将会创建多个资源,以保证 POST 不是幂等的。

PUT

PUT 请求用于创建或更新一个资源。与 POST 不同,PUT 请求要指定某个特定资源的地址。在本例中用来更新一部电影的信息:

        @PUT
        @Path("{id}")
        @Consumes(MediaType.APPLICATION_JSON)
        public Response update(@PathParam("id") int id, Movie movie) {
            movie.setId(id);
            if (movieMap.replace(id, movie) != null) {
                return Response.ok().build();
            } else {
                throw new WebApplicationException(Response.Status.NOT_FOUND);
            }
        }
    

更新成功就返回 200 OK,否则返回 404 Not Found。这儿先把 movie 对象的 ID 强制改为 URI 所指定的,以免出现不一致。也可以根据需求,将不一致作为异常处理,给客户端返回一个错误码。

顺便啰嗦一句,反正代码在自己手中,楼主也可以把 PUT 搞成非幂等的,例如将 PUT 当成 POST 来处理,就像以前把 GET 和 POST 一视同仁那样。不过咱既然在搞 JAX-RS,就还是要沾染一点 REST 风格,严格遵守 HTTP 才是。

DELETE

DELETE 请求用于删除一个资源。在本例中用来删除一部电影:

        @DELETE
        @Path("{id}")
        public Response delete(@PathParam("id") int id) {
            if (movieMap.remove(id) != null) {
                return Response.ok().build();
            } else {
                throw new WebApplicationException(Response.Status.NOT_FOUND);
            }
        }
    

没什么特别的,该说的前面都说了。

HEAD 和 OPTIONS 请求就忽略吧,用得不太多,也同样挺简单的。


JAX-RS 服务的部署和部署常规 Web 程序一样,打包成 war 文件就可以了。最后赞一下 NetBeans 可以为 REST 风格的服务自动生成测试页面,很好用,虽然在 Firefox 下页面显示不正常(对此我已经提了一个 bug),但 IE 是可以的。



蜀山兆孨龘 2011-09-20 17:22 发表评论

相关 [jax rs 傻逼] 推荐:

JAX-RS 从傻逼到牛叉 5:资源的动态定位

- - BlogJava-首页技术区
目前我们的电影服务只提供了对电影信息的访问服务,现在我们要再增加两项级服务,分别用来访问导演和演员信息. 加上原先的电信信息服务,我们把 URI 统一放到. /ms/rest/service/ 的子路径下. 最先想到的方法就是为这三个 URI 分别写 JAX-RS 服务:. // 此处省略若干行 } @Singleton @Path("service/director") public class DirectorService {.

JAX-RS 从傻逼到牛逼 2:开发一个简单的服务

- 时金魁 - BlogJava-首页技术区
JAX-RS 使用注解进行配置,所以用它开发 REST 风格的服务非常简单. 楼主在本文用一个小例子来说明 JAX-RS 的基本用法. 假设楼主要开发一个小电影服务,客户端可以通过请求 URI 对电影进行 CRUD 操作. 为简明起见,这儿不使用数据库,只在内存中模拟. 先用一个非常简单的 Movie 类,在后续的文章中根据情况逐步扩充:.

WebService之JAX-WS、CXF、Spring3.0+

- - 博客园_首页
          面对工作的需要,web服务这一块一直都在身边转悠着. 既然工作中需要这些,作为程序员就应该去了解和学习. 下面主要简述采用CXF+Spring+JAX-WS来发布WebService服务,以及创建客户端调用服务.          1、先了解关于WebService的相关概念以及一些专有名词的解释:.

mongodb利用rs,实现ha和备份

- - CSDN博客推荐文章
mongodb最简单的部署方式,是单节点部署. 国庆前找了台8核,48G RAM的server,在100+并发的压力下跑了一个星期,也没有发现数据丢失和server负载过大的情况. 但是单节点部署还是有一些问题,第一是无法做HA,如果该mongod down掉,或者部署的server down掉,应用就无法工作;第二是不利于备份,因为在备份的时候,会给mongod额外的负担,有可能影响业务;第三是无法做读写分离.

利用JAX-WS开发Web服务

- - CSDN博客推荐文章
利用JAX-WS开发Web服务.        Web服务是一种经由HTTP与其他软件进行通信的软件. Java最激动人心的一个特性是用于XML Web服务的Java API(JAX-WS). JAX-WS是一组Java类和包,他可以创建对Web服务发出请求的客户端,以及接受这些请求的服务.        JAX-WS支持使用简单对象访问协议(SimpleObject Access Protocol,SOAP)和表述性状态转移(Representational State Transfer,REST)实现的Web服务.

傻逼兮兮才有未来

- So - 牛博国际
      曾几何时中国还有个女子足球,当男足四处卖淫的时候,女足似乎还行. 当时女足有个孙庆梅,踢得不错,那时候日本刚刚有女子足球,孙庆梅在松下队踢过一阵,帮松下拿了全日本冠军.      当时的《足球报》采访过孙红梅,她对日本女球员的评论是傻逼兮兮,只会“加油干”,连赢了球就不要再加油了都不知道,言下之意很看不起对这种一根筋的加油干.

牛逼和傻逼的区别就是一个把妹

- Linker Lin - 微博段子
牛逼和傻逼的区别就是一个把妹睡觉听说iPhone出新的了就买,另一个熬夜看发布会但是新品出了却没钱买. 原文地址:http://www.tduanzi.com/tweets/14893.html.

二十多年来,无论我做什么,都有一堆傻逼说我“不务正业”。一定程度上,这反应了中国人最令人作呕的一面:他们总是替你决定什么是你的“正业”。——@罗永浩

- 梁振华 - 饭否 | 饭友经典语录
二十多年来,无论我做什么,都有一堆傻逼说我“不务正业”. 一定程度上,这反应了中国人最令人作呕的一面:他们总是替你决定什么是你的“正业”.