java JAX-RS实现rest风格的webservice

JAX-RS (Java API for XML-Restful Web Services) 介绍

JAX-RS 是基于Servlet构建的。

描述请求处理的过程:

client request----->JAX-RS servlet----->JAX-RS application (e.g., predictions3)

Tomcat/Jetty中部署 JAX-RS 的web.xml 如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
   
   
    <!--prediction3-->
    <!--对请求进行拦截,并转发给JAX-RS 应用-->
    <servlet>
        <servlet-name>Jersey Web Application</servlet-name>
        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Jersey Web Application</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    <!--prediction3  Over-->
</web-app>

用来配置 JAX-RS servlet "拦截"  请求 然后 将这个请求 dispatches(转发) 到 jax-rs 应用中。
是否将应用打包成 WAR文件

打包 : 将所有用到的jar(库)放到 WAR文件中。
 有点是没有版本问题困扰(可能某个jar文件需要特定版本,而war文件已经将所有的jar打包了,所以可以发送给任何人,而无需在配置依赖就可以直接放到tomcat下运行),缺点是文件体积就变大了
不打包:则需要将jar(库)都放到TOMCAT_HOME/lib  ,然后重启tomcat。
优点是多个应用可以共享jar库
JAX-RS实现
 RI表示jersey, 是Metro project的部分,见: https://jersey.java.net (version 2.x).
   RESTful路由

 由  Rails framework 所倡导并流行, 现在被广泛的模仿。
  不同http请求操作
        // GET /predictions         /* Read all predictions */
public void doGet(...)
        // POST /predictions        /* Create a new prediction for data in the HTTP request body */
public void doPost(...)
        // GET /predictions/27      /* Read prediction with id = 27 */
public void doGet(...)
        // DELETE /predictions/27   /* Delete prediction with id = 27 */
public void doDelete(...)
 在如JAX-RS 和 Restlet等框架中,  REST-style routes 可以通过注解(Annotation)来指定
注解可以指定Http的动作,即响应的http请求类型(e.g., GET) 和 名词,即客户端请求的url地址(e.g., URIs such as /predictions)
注解也可以指定响应的 MIME type  (e.g., application/json versus text/xml)

@Produces({MediaType.APPLICATION_JSON})  /* a JAX-RS example */
public Response getJson()
注解可以指定一个正则表达式来验证参数
   下面是伪代码的示例(JAX-RS实例中的很短):
        GET /predictions/{id: [0-9]+}     ###id必须是整数,如  12
 JAX-RS 来构建 predictions3 service 的代码组成

Prediction.java:
被注解的javaBean类,使其可以自动生成xml
 @XmlElement 注解 被放在 属性的getter方法上,如: who, what, id 三个属性的getter方法
 重写toString() 以支持对 get请求 做出 text/plain类型的响应
PredictionsList.java:
 被注解的javaBean类,同时也是作为主要的工具类。
     ##  @XmlElement 注解 被添加到getPredictions() 方法上,用于自动生成xml。
     ##  thread-safe(线程安全)
使用  java.util.concurrent.CopyOnWriteArrayList存储 predictions
使用线程安全的AtomicInteger  确保每一个Prediction实例对象都有唯一的id。
     ##  重写toString() 以支持  生成  text/plain(纯文本) 的predictions列表
 PredictionsRS.java:
大量的使用@GET, @Path 和@Produces 注解来表示JAX-RS service中的  REST-style 的资源
支持 RESTful 路由风格的所有的CRUD(增删查改)操作。
默认生成xml,也可以是 JSON 和纯文本来响应 GET 请求。支持GET 来获取prediction列表或单个prediction记录
 RestfulPrediction.java:
通过继承 JAX-RS 中的 javax.ws.rs.core.Application类,并重写getClasses() 来注册这个PredictionRS资源到JAX-RS的上下文(context)中
 注意JAX-RS中的 "拦截器" servlet  “拦截”与PredictionRS 资源相关的请求。
JAX-RS 的注解

下面是JAX-RS中比较重要的注解类:

Table 1. JAX-RS annotations

Annotation Description
@ApplicationPath(your_application_path) 这个注解是放在你的Application类上的。设置整个应用的路径
@PATH(your_path) 这个类是放在你的javabean类上的。设置路径为  基本URL+/your_path。这个基本URL是基于你应用的路径和web.xml中servlet的URL pattern的。
@POST 用在方法上,表示这个方法会响应HTTP POST请求
@GET 用在方法上,表示这个方法会响应HTTP GET请求
@PUT 用在方法上,表示这个方法会响应HTTP PUT请求
@DELETE 用在方法上,表示这个方法会响应HTTP DELETE 请求
@Produces(MediaType.TEXT_PLAIN[, more-types]) 用在方法上,表示这个方法会返回何种类的响应。例如,如果指定为 ("text/plain") ,则返回纯文本的响应。也可指定 "application/xml" or "application/json"等其他类型。
@Consumes(type[, more-types]) 用在方法上,表示这个方法接收含有特定MIME type的http请求
@PathParam 用在方法上,从URL中获取值注入为该方法的一个参数。例如,/predictions/1 ,则我们就可以通过这个注解,将1获取到,然后作为这个方法的参数,相当方便。
实例:

项目目录结构:

使用maven管理依赖

因为用到的库较多,而库又要依赖其他库,所以建议使用maven来管理,pom.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>groupId</groupId>
    <artifactId>JAX-RS_For_RestfulService</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.json</groupId>
            <artifactId>json</artifactId>
            <version>20151123</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-bundle</artifactId>
            <version>1.19.1</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-server</artifactId>
            <version>1.19</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-core</artifactId>
            <version>1.19</version>
        </dependency>
        <dependency>
            <groupId>asm</groupId>
            <artifactId>asm</artifactId>
            <version>3.3.1</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.7</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.7.4</version>
        </dependency>
    </dependencies>
   
</project>

predictions.db:

存放记录的文本文件
被读取的文本文件,一条记录一行,每行的内容都有"!"分隔为两部分。

Cornelius Tillman!Managed holistic contingency will grow killer action-items.
Conner Kulas!Vision-oriented zero administration time-frame will generate back-end interfaces.
Loraine Ryan!Triple-buffered scalable function will productize visionary infomediaries.
Patricia Zulauf!Reactive radical knowledge base will aggregate extensible vortals.
River Wiza!Face to face client-server pricing structure will whiteboard robust communities.
Jarred Wehner!Future-proofed 5th generation protocol will strategize web-enabled networks.
Emily Roob!Cross-group fresh-thinking encoding will reinvent dot-com systems.
Elvis Ernser!Customizable assymetric database will visualize virtual action-items.
Kathryn Hilpert!User-centric non-volatile open architecture will iterate world-class vortals.
Tanner Dietrich!Enhanced zero tolerance system engine will evolve turn-key deliverables.
Linnie Funk!Distributed dynamic moratorium will iterate magnetic e-commerce.
Emery Ward!Synergistic demand-driven functionalities will visualize compelling vortals.
Craig Leuschke!Robust intermediate extranet will facilitate best-of-breed synergies.
Shayna Lehner!Digitized optimal conglomeration will exploit proactive relationships.
Hollis McCullough!Universal fault-tolerant architecture will synthesize bleeding-edge channels.
Mina Hayes!Cloned assymetric intranet will enable innovative functionalities.
River Friesen!Decentralized 24/7 hub will target robust web-readiness.
Carmel Becker!Synergistic disintermediate policy will expedite back-end experiences.
Bartholome Walsh!Triple-buffered didactic emulation will visualize integrated channels.
Russel Robel!Configurable intangible alliance will scale sexy ROI.
Charlene Mertz!Triple-buffered neutral collaboration will incubate B2B deliverables.
Letitia Pacocha!User-centric multi-state success will transform proactive convergence.
Lottie Marks!Open-source multi-tasking time-frame will monetize rich partnerships.
Kaden Crona!Optional static definition will unleash dynamic e-tailers.
Everardo Lind!De-engineered systematic emulation will deploy out-of-the-box partnerships.
Lilyan Thompson!Synergistic 24/7 website will transition 24/7 methodologies.
Alessia O'Connell!Reactive value-added middleware will engineer next-generation partnerships.
Reymundo Champlin!Self-enabling reciprocal synergy will generate seamless portals.
Immanuel Bergstrom!Assimilated intermediate superstructure will drive vertical methodologies.
Dahlia Robel!Proactive demand-driven open architecture will innovate impactful networks.
Deven Blanda!Balanced clear-thinking utilisation will expedite collaborative initiatives.
Hiram Gulgowski!Versatile tangible application will maximize rich e-business.

javabean类,使用如:

@XmlRootElement(name = "prediction")
 @XmlElement
等注解来指定生成的xml元素。

package predictions3;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
 * Created by AlexY on 2016/6/30.
 */
//指定生成的xml的根元素
@XmlRootElement(name = "prediction")
public class Prediction implements Comparable<Prediction> {
    private String who;  // 人
    private String what; //他的prediction
    private int id; //作为搜索的key
    @XmlElement
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    @XmlElement
    public String getWhat() {
        return what;
    }
    public void setWhat(String what) {
        this.what = what;
    }
    @XmlElement
    public String getWho() {
        return who;
    }
    public void setWho(String who) {
        this.who = who;
    }
    @Override
    public int compareTo(Prediction o) {
        return this.id - o.id;
    }
//    重写toString方法,这样可以直接以纯文本输出(text/plain)
    @Override
    public String toString() {
        return String.format("%2d:",id)+who+"==>"+what+ "\n";
    }
}

PredictionsList :

javabean类,返回整个Predicliton的列表

package predictions3;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by AlexY on 2016/6/30.
 */

@XmlRootElement(name = "predictionList")
public class PredictionsList {

    private List<Prediction> preds;
    private AtomicInteger predId;

    public PredictionsList() {

//        为了线程安全
        preds = new CopyOnWriteArrayList<>();
        predId = new AtomicInteger();

    }

    //有个name属性,可以用来修改xml中的元素的名字,(默认值就是程序从getter方法获取的)
    @XmlElement
    //指定封装这个xml元素的元素,就是在外面在套一层标签
    @XmlElementWrapper(name = "predictions")
    public List<Prediction> getPredictions() {
        return preds;
    }

    public void setPredictions(List<Prediction> preds) {
        this.preds = preds;
    }

 

    @Override
    public String toString() {

//         TODO: 2016/6/30 可以用stringbuffer优化
        String s = "";
        for (Prediction p : preds){
            s += p.toString();

        }

        return s;
    }

    public Prediction find(int id){
        Prediction pred = null;

//        从list中搜索
//          注意:因为现在list还很短,所以可以使用线性查找,
//          如果当list变成一个很大的有序列表,则最好用 二分查找

        for ( Prediction p : preds){

            if (p.getId() == id){
                pred = p;

                break;
            }

        }

        return pred;

    }

    public int add(String who,String what){

        int id = predId.incrementAndGet();
        Prediction p = new Prediction();

        p.setWho(who);
        p.setWhat(what);
        p.setId(id);

        preds.add(p);

        return id;

    }

PredictionsRS:

对http请求进行响应,返回对应的类型的请求。
是最重要的一个类。

package predictions3;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.ServletContext;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
 * Created by AlexY on 2016/6/30.
 */
@Path("/")
public class PredictionsRS {
    @Context
    private ServletContext sctx;  //依赖注入
    private static PredictionsList plist; // 在populate()方法中设置
    public PredictionsRS() {
    }
    @GET
    @Path("/xml")
    @Produces({MediaType.APPLICATION_XML})
    public Response getXml() {
        checkContext();
        return Response.ok(plist, "application/xml").build();
    }
    @GET
    @Path("/xml/{id:\\d+}")
    @Produces({MediaType.APPLICATION_XML}) //也可以直接用"application/xml"
    public Response getXml(@PathParam("id") int id) {
        checkContext();
        return toRequestedType(id, "application/xml");
    }
    @GET
    @Produces({MediaType.APPLICATION_JSON})
    @Path("/json")
    public Response getJson() {
        checkContext();
        return Response.ok(toJson(plist), "application/json").build();
    }
    @GET
    @Produces({MediaType.APPLICATION_JSON})
    @Path("/json/{id:\\d+}")
    public Response getJson(@PathParam("id") int id) {
        checkContext();
        return toRequestedType(id, "application/json");
    }
    @GET
    @Path("/plain")
    @Produces({MediaType.TEXT_PLAIN})
    public String getPlain() {
        checkContext();
        return plist.toString();
    }
//    创建新的记录
    @POST
    @Produces({MediaType.TEXT_PLAIN})
    @Path("/create")
    public Response create(@FormParam("who") String who, @FormParam("what") String what) {
        checkContext();
        String msg = null;
//        who和what两个字段都必须有
        if (null == who || null == what) {
            msg = "Property 'who' or 'what' is missing.\n";
            return Response.status(Response.Status.BAD_REQUEST).
                    entity(msg).
                    type(MediaType.TEXT_PLAIN)
                    .build();
        }
//        创建新的Prediction,并返回它的id
        int id = addPrediction(who,what);
        msg = "Prediction " + id + " created: (who = " + who + " what = " + what + ").\n";
        return Response.ok(msg, "text/plain").build();
    }
    @PUT
    @Produces({MediaType.TEXT_PLAIN})
    @Path("/update")
    public Response update(@FormParam("id") int id, @FormParam("who") String who, @FormParam("what") String what){
        checkContext();
        String msg = null;
        if ( null == who && null == what){
            msg = "Neither who nor what is given: nothing to edit.\n";
        }
        // 这里id为int ,所以默认肯定是0,我们PredictionsList中没有0的索引
        Prediction p = plist.find(id);
        if ( null == p){
            msg = "There is no prediction with ID " + id + "\n";
        }
//        如果有错误消息,则返回
        if ( null != msg){
            return Response.status(Response.Status.BAD_REQUEST).entity(msg).type(MediaType.TEXT_PLAIN).build();
        }
//        更新记录
        if ( null != who){
            p.setWho(who);
        }
        if ( null != what){
            p.setWhat(what);
        }
        msg = "Prediction " + id + " has been updated.\n";
        return Response.ok(msg,"text/plain").build();
    }
    @DELETE
    @Produces({MediaType.TEXT_PLAIN})
    @Path("/delete/{id:\\d+}")
    public Response delete(@PathParam("id") int id){
        checkContext();
        String msg = null;
        Prediction p = plist.find(id);
        if (null == p){
            msg = "There is no prediction with ID " + id + ". Cannot delete.\n";
            return Response.status(Response.Status.BAD_REQUEST).entity(msg).type(MediaType.TEXT_PLAIN).build();
        }
//        查找到记录,并删除
        plist.getPredictions().remove(p);
        msg = "Prediction " + id + " deleted.\n";
        return Response.ok(msg, "text/plain").build();
    }
//    生成Http error 响应 或  指定type的 Ok响应(即 http code 200)
    private Response toRequestedType(int id, String type) {
        Prediction pred = plist.find(id);
        if (null == pred) {
            String msg = id + " is a bad ID.\n";
            return Response.status(Response.Status.BAD_REQUEST).
                    entity(msg).
                    type(MediaType.TEXT_PLAIN).
                    build();
        } else if (type.contains("json")) {
            return Response.ok(toJson(pred), type).build();
        } else {
            return Response.ok(pred, type).build();
        }
    }
//  工具方法,检查plist是否为null,如果为null,则调用populate()方法,
// 从predictions.db中读取记录
    private void checkContext() {
        if (plist == null) {
            populate();
        }
    }
    //    从文件中读取记录到PredictionsList中
    private void populate() {
        plist = new PredictionsList();
        String filename = "WEB-INF/data/predictions.db";
        InputStream in = sctx.getResourceAsStream(filename);
        if ( null != in){
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            String record = null;
            try {
                while (null != (record = reader.readLine())) {
                    System.out.println("record:"+record);
                    String[] parts = record.split("!");
                    addPrediction(parts[0], parts[1]);
                }
            } catch (IOException e) {
                throw new RuntimeException("I/O failed!");
            }
        }
    }
//    添加一个新的prediction到list中
    private int addPrediction(String who, String what) {
        int id = plist.add(who, what);
        return id;
    }
//    将Prediction转换为 json文档
    private String toJson(Prediction prediction){
        String json = "If you see this, there's a problem.";
        if ( null != prediction){
//             使用Gson库
//            Gson gson = new Gson();
//            json =  gson.toJson(prediction).toString();
            try {
//                使用jackson库
                json = new ObjectMapper().writeValueAsString(prediction);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
        return json;
    }
//    将PredictionsList转换为 json文档
    private String toJson(PredictionsList plist) {
        String json = "If you see this, there's a problem.";
        try {
            json = new ObjectMapper().writeValueAsString(plist);
        }
        catch(Exception e) { }
        return json;
    }
}

RestfulPrediction :
继承了Application类,
通过@ApplicationPath 注解指定整个应用的路径。

//指定资源的url路由
@ApplicationPath("/resourcesP")
public class RestfulPrediction extends Application {
    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> set = new HashSet<>();
//        将资源类的class文件添加进去
        set.add(PredictionsRS.class);
        return set;
    }
}

测试:
http://localhost:8080/resourcesP/xml

时间: 2024-09-22 05:44:30

java JAX-RS实现rest风格的webservice的相关文章

rest风格的webservice的好处是什么啊?????

问题描述 rest风格的webservice有什么好处啊?它和直接web的http请求返回json有什么区别啊?求大神!!!!! 解决方案 解决方案二:使用RestfulWebService实现:结构清晰.符合标准.强化扩展.缓存机制.完全操作.安全操作.无状态性:另外Rest一个很到的特性是同一资源多种描述:配置文件中,可实现客户端不同的访问机制,得到不同的结果格式和内容.如uri/.../?frmat=json返回json格式数据;uri/.../?frmat=xml返回xml格式数据解决方

Java版仿QQ验证码风格图片验证码_java

本文为大家分享了Java版仿QQ验证码风格图片验证码,具体内容如下  功能包括:自定义图片尺寸和字符长度,随机背景颜色和字符颜色,随机字符偏移角度,字符平滑边缘,干扰线,噪点,背景扭曲. 本来想做字符扭曲的,不知道怎的先生成文字再扭曲就报错了,先就这样吧,希望有高手能帮助修正一下. 需要说明的是之所以有几分像QQ的验证码感觉是因为这个Algerian字体,如果系统没有的话需要自行安装,百度搜字体名能下载到,丢系统Fonts文件夹就行. 效果图: package hh.com.util; impo

优秀Java程序员的编程风格

今天突发奇想,对编码习惯和编程风格很感兴趣,于是乎,找了一下关于编程风格(Java篇)的资料,希望对爱好编码或者开始学习编码的同学有帮助! 来自<The Elements of Java Style>-<Java编程风格>一书,值得一读的书籍,会让你在细节上节省很多时间,合作之间更加愉快! 好处不多说了,但是有几个原则如下: 1.保持原有风格 2.坚持最小惊奇原则 3.第一次就做对 4.记录所有非规范行为 格式规范: 1.缩进嵌套的代码:在每个代码块和嵌套中加入缩进,缩进代码,加强

springMVC spring3.1 hibernate4 cxf整合发布restful风格的webservice

问题描述 现在的问题是通过controller访问service是正常的,用cxf发布的webservice  就不访问不了service,报错:org.apache.cxf.interceptor.Fault: No Session found for current threadat org.apache.cxf.service.invoker.AbstractInvoker.createFault(AbstractInvoker.java:162)at org.apache.cxf.ser

Java编程中使用XFire框架调用WebService程序接口_java

 JAVA调用webservice,当你刚开始接触的时候你会觉得它是一个恶梦,特别是没有一个统一的标准实现,比起.net的那些几步就可以完成的webservice实现,我们看着JAVA的实现真是伤心啊.但就算是伤心,我们也还是要完成的.JAVA也不乏比较好的实现,如xfire,jersey,CXF. 这里我们就一起来看一下xfire的实现.  1)首先,当然是要下包啦,这个普通人都知道.http://xfire.codehaus.org/Download可以到这里去下,可以下all也可以下dis

java代码调用使用cxf搭建的webService服务传递对象

前边成功创建好一个cxf的webServcie服务,并带了一个无参数的方法.现在进一步尝试了使用带参数的方法,分别测了用String为参数和用自定义的对象为参数. 其中,使用String为参数时和不带参数的写法没有什么区别,调用时也就是很普通的调用.但是调用自定义对象为参数的方法时,实际数据并没有传递成功,于是在网上搜索一番后找到了解决办法,成功实现这一功能. 具体实现步骤大致如下: 1.在服务项目中添加一个自定义的类: package models; public class UserMode

webservice中如何实现服务端为JAVA而客户端为.net或者C

问题描述 比如WEBSERVICE用CXF实现用JAVA做的服务端,定义了一个服务端接口 , 提供给客户端调用(ITransPort.java)生成的WSDL地址为:http://localhost:8080/LifeEC/WebService/transPort?wsdl如果是客户端用JAVA调用就会很好实现,用WSDLTOJAVA方法生成客户端代码调用相关的方法但是如果客户端为 其他编程语言,如.NET, 是否也有相关CXF针对.NET的库文件来生成客户端代码,或者用其他方式来调用服务端的J

Java那些事儿 - JavaOne 2011、CDI和Google Dart语言

对于Java社区来说,9月和10月间最重要的事件是一年一度的JavaOne大会的召开.JavaOne 2011的 主题是"推动Java向前发展(Moving Java Forward)".从这个主题可以看出,Oracle正试图以领导者的身份带领Java社区来共同推动Java的发展.Java SE 7的发布,是这个过程中的一个重要里程碑.相对于上一次JavaOne会议来说,JavaOne 2011在社区中的评价比较不错,被认为是一次成功的会议.Oracle也更加重视社区在推动Java发展

Java RESTful Web Service实战(第2版)

Java核心技术系列 Java RESTful Web Service实战 (第2版) 韩陆 著 图书在版编目(CIP)数据 Java RESTful Web Service实战 / 韩陆著. -2版. -北京:机械工业出版社,2016.7 (Java核心技术系列) ISBN 978-7-111-54213-1 Ⅰ. J-   Ⅱ. 韩-   Ⅲ. JAVA语言-程序设计   Ⅳ. TP312 中国版本图书馆CIP数据核字(2016)第156331号 Java RESTful Web Servi