[javascript学习指南]java JAX-RS实现rest风格的webservice

时间:2020-10-15  来源: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 如下:


         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">
   
   
   
   
   
        Jersey Web Application
        com.sun.jersey.spi.container.servlet.ServletContainer
        1
   

   
        Jersey Web Application
        /*
   

   


用来配置 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文件如下:


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">
    4.0.0
    groupId
    JAX-RS_For_RestfulService
    1.0-SNAPSHOT
   
       
           
                org.apache.maven.plugins
                maven-compiler-plugin
                2.3.2
               
                    1.7
                    1.7
               

           

       

   

   
       
            org.json
            json
            20151123
       

       
            com.sun.jersey
            jersey-bundle
            1.19.1
       

       
            com.sun.jersey
            jersey-server
            1.19
       

       
            com.sun.jersey
            jersey-core
            1.19
       

       
            asm
            asm
            3.3.1
       

       
            javax.servlet
            javax.servlet-api
            3.0.1
       

       
            com.google.code.gson
            gson
            2.7
       

       
            com.fasterxml.jackson.core
            jackson-databind
            2.7.4
       

   

   


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 {
    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 preds;
    private AtomicInteger predId;


    public PredictionsList() {

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

    }

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

    public void setPredictions(List 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> getClasses() {
        Set> set = new HashSet<>();
//        将资源类的class文件添加进去
        set.add(PredictionsRS.class);
        return set;
    }
}


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

[javascript学习指南]java JAX-RS实现rest风格的webservice

http://m.bbyears.com/asp/104764.html

推荐访问:java学习路线
相关阅读 猜你喜欢
本类排行 本类最新