RESTful HttpServlet 示例

RESTful 的核心就是制定客戶端與服務器交互的統一接口,HttpServlet 基於 HTTP ,可以使用 doXXX 方法來定義CRUD方法。

下面這個栗子,使用了HttpServlet 來實現 RESTful 風格的設計,用doGet 定義查詢接口,用doPost 定義新建接口,用 doPut 定義更新接口,用doDelete 定義刪除接口。Resource representation 格式使用 JSON .

  1. domain ,一個類,Prediction,who predicts what .
package com.cherry.example.domain;

import java.io.Serializable;

public class Prediction implements Serializable, Comparable<Prediction> {

    private String who; // person
    private String what; // his/her prediction
    private int id; // identifier used as lookup key

    public Prediction() {
    }

    public void setWho(String who) {
        this.who = who;
    }

    public String getWho() {
        return this.who;
    }

    public void setWhat(String what) {
        this.what = what;
    }

    public String getWhat() {
        return this.what;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getId() {
        return this.id;
    }

    public int compareTo(Prediction other) {
        return this.id - other.id;
    }
}
  1. repository ,不用數據庫,就用一個Map簡單表述
package com.cherry.example.repository;

import java.beans.XMLEncoder;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;

import javax.servlet.ServletContext;

import com.cherry.example.domain.Prediction;

public class Predictions {

    private ConcurrentMap<Integer, Prediction> predictions;
    private ServletContext sctx;
    private AtomicInteger mapKey;

    public Predictions() {
        predictions = new ConcurrentHashMap<Integer, Prediction>();
        mapKey = new AtomicInteger();
    }

    public void setServletContext(ServletContext sctx) {
        this.sctx = sctx;
    }

    public ServletContext getServletContext() {
        return this.sctx;
    }

    public void setMap(ConcurrentMap<String, Prediction> predictions) {
        // no-op for now
    }

    public ConcurrentMap<Integer, Prediction> getMap() {
        // Has the ServletContext been set?
        if (getServletContext() == null)
            return null;
        // Has the data been read already?
        if (predictions.size() < 1)
            populate();
        return this.predictions;
    }   

    public int addPrediction(Prediction p) {
        int id = mapKey.incrementAndGet();
        p.setId(id);
        predictions.put(id, p);
        return id;
    }   

    private void populate() {
        String filename = "/WEB-INF/data/predictions.db";
        InputStream in = sctx.getResourceAsStream(filename);
        // Read the data into the array of Predictions.
        if (in != null) {
            try {
                InputStreamReader isr = new InputStreamReader(in);
                BufferedReader reader = new BufferedReader(isr);

                String record = null;
                while ((record = reader.readLine()) != null) {
                    String[] parts = record.split("!");
                    Prediction p = new Prediction();
                    p.setWho(parts[0]);
                    p.setWhat(parts[1]);
                    addPrediction(p);
                }
            } catch (IOException e) {
            }
        }
    }

}
  1. web ,一個 Servlet ,定義了CRUD接口
package com.cherry.example.web;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.concurrent.ConcurrentMap;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.ws.http.HTTPException;

import com.cherry.example.domain.Prediction;
import com.cherry.example.repository.Predictions;
import com.google.gson.Gson;

@WebServlet(urlPatterns = "/predictions")
public class PredictionsServlet extends HttpServlet {

    private Predictions predictions; // backend bean

    // Executed when servlet is first loaded into container.
    // Create a Predictions object and set its servletContext
    // property so that the object can do I/O.
    @Override
    public void init() {
        predictions = new Predictions();
        predictions.setServletContext(this.getServletContext());
    }

    // GET /predictions
    // GET /predictions?id=1
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) {

        String result = null;
        Gson gson = new Gson();
        String param = request.getParameter("id");
        Integer key = (param == null) ? null : new Integer(param.trim());
        // If no query string, assume client wants the full list.
        if (key == null) {
            ConcurrentMap<Integer, Prediction> map = predictions.getMap();
            // Sort the map's values for readability.
            Object[] list = map.values().toArray();
            Arrays.sort(list);
            result = gson.toJson(list);
        }
        // Otherwise, return the specified Prediction.
        else {
            Prediction pred = predictions.getMap().get(key);
            if (pred == null) { // no such Prediction
                String msg = key + " does not map to a prediction.\n";
                result = gson.toJson(msg);
            } else { // requested Prediction found
                result = gson.toJson(pred);
            }
        }
        // response
        sendResponse(response, result);
    }

    // POST /predictions
    // HTTP body should contain two keys, one for the predictor ("who") and
    // another for the prediction ("what").
    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) {
        String who = request.getParameter("who");
        String what = request.getParameter("what");
        // Are the data to create a new prediction present?
        if (who == null || what == null)
            throw new HTTPException(HttpServletResponse.SC_BAD_REQUEST);
        // Create a Prediction.
        Prediction p = new Prediction();
        p.setWho(who);
        p.setWhat(what);
        // Save the ID of the newly created Prediction.
        int id = predictions.addPrediction(p);
        // Generate the confirmation message.
        String msg = "Prediction " + id + " created.\n";
        sendResponse(response, msg);
    }

    // PUT /predictions
    // HTTP body should contain at least two keys: the prediction's id
    // and either who or what.
    @Override
    public void doPut(HttpServletRequest request, HttpServletResponse response) {
        /*
         * A workaround is necessary for a PUT request because neither Tomcat nor Jetty
         * generates a workable parameter map for this HTTP verb.
         */
        String key = null;
        String rest = null;
        boolean who = false;
        /* Let the hack begin. */
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
            String data = br.readLine();
            /*
             * To simplify the hack, assume that the PUT request has exactly two parameters:
             * the id and either who or what. Assume, further, that the id comes first. From
             * the client side, a hash character # separates the id and the who/what, e.g.,
             * id=33#who=Homer Allision
             */
            String[] args = data.split("#"); // id in args[0], rest in args[1]
            String[] parts1 = args[0].split("="); // id = parts1[1]
            key = parts1[1];
            String[] parts2 = args[1].split("="); // parts2[0] is key
            if (parts2[0].contains("who"))
                who = true;
            rest = parts2[1];
        } catch (Exception e) {
            throw new HTTPException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
        // If no key, then the request is ill formed.
        if (key == null)
            throw new HTTPException(HttpServletResponse.SC_BAD_REQUEST);
        // Look up the specified prediction.
        Prediction p = predictions.getMap().get(new Integer(key.trim()));
        if (p == null) { // not found?
            String msg = key + " does not map to a Prediction.\n";
            sendResponse(response, msg);
        } else { // found
            if (rest == null) {
                throw new HTTPException(HttpServletResponse.SC_BAD_REQUEST);
            }
            // Do the editing.
            else {
                if (who)
                    p.setWho(rest);
                else
                    p.setWhat(rest);
                String msg = "Prediction " + key + " has been edited.\n";
                sendResponse(response, msg);
            }
        }
    }

    // DELETE /predictions?id=1
    @Override
    public void doDelete(HttpServletRequest request, HttpServletResponse response) {
        String param = request.getParameter("id");
        Integer key = (param == null) ? null : new Integer(param.trim());
        // Only one Prediction can be deleted at a time.
        if (key == null)
            throw new HTTPException(HttpServletResponse.SC_BAD_REQUEST);
        try {
            predictions.getMap().remove(key);
            String msg = "Prediction " + key + " removed.\n";
            sendResponse(response, msg);
        } catch (Exception e) {
            throw new HTTPException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    // Method Not Allowed
    @Override
    public void doTrace(HttpServletRequest request, HttpServletResponse response) {
        throw new HTTPException(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
    }

    @Override
    public void doHead(HttpServletRequest request, HttpServletResponse response) {
        throw new HTTPException(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
    }

    @Override
    public void doOptions(HttpServletRequest request, HttpServletResponse response) {
        throw new HTTPException(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
    }

    // Send the response payload to the client.
    private void sendResponse(HttpServletResponse response, String payload) {
        try {
            OutputStream out = response.getOutputStream();
            out.write(payload.getBytes());
            out.flush();
        } catch (Exception e) {
            throw new HTTPException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章