手寫服務器httpserver_封裝分發器_多請求處理_多態_反射JAVA202-204

來源:http://www.bjsxt.com/
一、S02E202_01手寫服務器httpserver_封裝分發器

<html>
    <head>
        <title>第一個表單</title>
    </head>
    <body>
        <pre>
            method:請求方式 get/post
                get:默認方式,數據量小,安全性不高
                post:量大,安全性相對高
            action:請求的服務器路徑
            id:編號,前端(用戶的瀏覽器)區分唯一性,js中使用
            name:名稱,後端(服務器)區分唯一性,獲取值
            只要提交數據給後臺,必須存在name
        </pre>
        <form method="post" action="http://localhost:8888/index.html">
            用戶名:<input type="text" name="uname" id="name"/>
            密碼:<input type="password" name="pwd" id="pass"/>
            興趣:<input type="checkbox" name="fav" value="0"/>籃球
            <input type="checkbox" name="fav" value="1"/>足球
            <input type="checkbox" name="fav" value="2"/>乒乓球
            <input type="submit" value="登錄">
        </form>
    </body>
</html>
package com.test.server;

public class Servlet {
    public void service(Request req,Response rep){
        rep.println("<html><head><title>HTTP響應示例</title>");
        rep.println("</head><body>");
        rep.println("歡迎:").println(req.getParameterValue("uname")).println("回來");
        rep.println("</body></html>");
    }
}
package com.test.server;

import java.io.IOException;
import java.net.Socket;
/**
 * 一個請求與響應,就一個對象
 */
public class Dispatcher implements Runnable{
    private Socket client;
    private Request req;
    private Response rep;
    private int code = 200;

    Dispatcher(Socket client){
        this.client = client;
        try {
            req = new Request(client.getInputStream());
            rep = new Response(client.getOutputStream());
        } catch (IOException e) {
            //e.printStackTrace();
            code = 500;
            try {
                rep.pushToClient(code);
            } catch (IOException e1) {
                //e1.printStackTrace();
            }
            return;
        }
    }

    @Override
    public void run() {
        Servlet serv = new Servlet();
        serv.service(req, rep);
        try {
            rep.pushToClient(code);//推送到客戶端
        } catch (IOException e) {
            //e.printStackTrace();
            try {
                rep.pushToClient(500);
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }

        try {
            client.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
package com.test.server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
 * 創建服務器,並啓動
 * 1、請求
 * 2、響應
 */
public class ServerForResAndReq2 {
    private ServerSocket server;
    private boolean isShutDown = false;

    public static void main(String[] args) {
        ServerForResAndReq2 server = new ServerForResAndReq2();
        server.start();
    }
    /**
     * 啓動方法
     */
    public void start(){        
        start(8888);
    }
    /**
     * 指定端口的啓動方法
     */
    public void start(int port){        
        try {
            server = new ServerSocket(port);
            this.receive();
        } catch (IOException e) {
            //e.printStackTrace();
            stop();
        }
    }
    /**
     * 接收客戶端
     */
    private void receive(){
        try {
            //請求及響應
            while(!isShutDown){
                new Thread(new Dispatcher(server.accept())).start();
            }
        } catch (IOException e) {
            //e.printStackTrace();
            stop();
        }
    }
    /**
     * 停止服務器
     */
    public void stop(){
        isShutDown = true;
        try {
            server.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

二、S02E203_01手寫服務器httpserver_多請求處理_多態

package com.test.server2;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
 * 創建服務器,並啓動
 * 1、請求
 * 2、響應
 */
public class Server {
    private ServerSocket server;
    private boolean isShutDown = false;

    public static void main(String[] args) {
        Server server = new Server();
        server.start();
    }
    /**
     * 啓動方法
     */
    public void start(){        
        start(8888);
    }
    /**
     * 指定端口的啓動方法
     */
    public void start(int port){        
        try {
            server = new ServerSocket(port);
            this.receive();
        } catch (IOException e) {
            //e.printStackTrace();
            stop();
        }
    }
    /**
     * 接收客戶端
     */
    private void receive(){
        try {
            //請求及響應
            while(!isShutDown){
                new Thread(new Dispatcher(server.accept())).start();
            }
        } catch (IOException e) {
            //e.printStackTrace();
            stop();
        }
    }
    /**
     * 停止服務器
     */
    public void stop(){
        isShutDown = true;
        try {
            if(!(null==server)){
                server.close();
            }
        } catch (IOException e) {
            //e.printStackTrace();
        }
    }
}
package com.test.server2;

import java.io.IOException;
import java.net.Socket;
/**
 * 一個請求與響應,就一個對象
 */
public class Dispatcher implements Runnable{
    private Socket client;
    private Request req;
    private Response rep;
    private int code = 200;

    Dispatcher(Socket client){
        this.client = client;
        try {
            req = new Request(client.getInputStream());
            rep = new Response(client.getOutputStream());
        } catch (IOException e) {
            //e.printStackTrace();
            code = 500;
            try {
                rep.pushToClient(code);
            } catch (IOException e1) {
                //e1.printStackTrace();
            }
            return;
        }
    }

    @Override
    public void run() {
        try {
            Servlet serv = WebApp.getServlet(req.getUrl());
            if(null==serv){
                this.code = 404;//找不到處理
            }else{
                serv.service(req, rep);
            }
            rep.pushToClient(code);//推送到客戶端
        } catch (Exception e) {
            //e.printStackTrace();
            this.code = 500;
            try {
                rep.pushToClient(code);
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
        try {
            client.close();
        } catch (IOException e) {
            //e.printStackTrace();
        }
    }
}
package com.test.server2;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
/**
 * 封裝request
 */
public class Request {
    //請求方式
    private String method;
    //請求資源
    private String url;
    //請求參數
    private Map<String,List<String>> parameterMapValues;

    //內部
    public static final String CRLF = "\r\n";
    private InputStream is;
    private String requestInfo;

    public Request(){
        method = "";
        url = "";
        parameterMapValues = new HashMap<String,List<String>>();
        requestInfo = "";
    }
    public Request(InputStream is){
        this();
        this.is = is;
        try {
            byte[] data = new byte[204800];
            int len = is.read(data);
            requestInfo = new String(data,0,len);
        } catch (IOException e) {
            return;
        }
        //分析請求信息
        parseRequestInfo();
    }

    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    /**
     * 分析請求信息
     */
    private void parseRequestInfo(){
        if((null==requestInfo) || (requestInfo=requestInfo.trim()).equals("")){
            return;
        }

        /**
         * ====================================
         * 從信息的首行分解出:請求方式  請求路徑  請求參數(get可能存在)
         *   如:GET /index.html?uname=intputUname&pwd=inputPassword HTTP/1.1
         * 
         * 如果爲post方式,請求參數可能在最後正文中
         * ====================================
         */
        String paramString = "";//接收請求參數
        int positionCRLF = 0;

        positionCRLF = requestInfo.indexOf(CRLF);
        if (positionCRLF == -1){
            return;
        }
        //1、獲取請求方式
        String firstLine = requestInfo.substring(0,requestInfo.indexOf(CRLF));
        int idx = requestInfo.indexOf("/");// /的位置
        this.method = firstLine.substring(0,idx).trim();
        String urlStr = firstLine.substring(idx,firstLine.indexOf("HTTP/")).trim();
        if(this.method.equalsIgnoreCase("post")){//post方式
            this.url = urlStr;
            paramString = requestInfo.substring(requestInfo.lastIndexOf(CRLF)).trim();
        }else if(this.method.equalsIgnoreCase("get")){//get方式
            if(urlStr.contains("?")){
                String[] urlArray = urlStr.split("\\?");
                this.url = urlArray[0];
                paramString = urlArray[1];//接收請求參數
            }else{
                this.url = urlStr;
            }
        }

        //2、將請求參數封裝到Map中
        parseParams(paramString);
    }
    /**
     * 將請求參數封裝到Map中
     * @param paramString
     */
    private void parseParams(String paramString){
        //分割,將字符串轉成數組
        StringTokenizer token = new StringTokenizer(paramString,"&");
        while(token.hasMoreTokens()){
            String keyValue = token.nextToken();
            String[] keyValues = keyValue.split("=");
            if(keyValues.length == 1){
                keyValues = Arrays.copyOf(keyValues, 2);
                keyValues[1] = null;
            }

            String key = keyValues[0].trim();
            String value = null==keyValues[1]?null:decode(keyValues[1].trim(),"gbk");
            //分揀,轉換成Map
            if(!parameterMapValues.containsKey(key)){
                parameterMapValues.put(key, new ArrayList<String>());
            }

            List<String> values = parameterMapValues.get(key);
            values.add(value);
        }
    }
    /**
     * 解決中文
     * @param value
     * @param code
     * @return
     */
    private String decode(String value,String code){
        try {
            return java.net.URLDecoder.decode(value, code);
        } catch (UnsupportedEncodingException e) {
            //e.printStackTrace();
        }
        return null;
    }
    /**
     * 根據頁面的name獲取對應的多個值
     */
    public String[] getParameterValues(String name){
        List<String> values = null;
        if( (values=parameterMapValues.get(name))==null ){
            return null;
        }else{
            return values.toArray(new String[0]);
        }
    }
    /**
     * 根據頁面的name獲取對應的單個值
     */
    public String getParameterValue(String name){
        String[] values = getParameterValues(name);
        if(null==values){
            return null;
        }
        return values[0];
    }
}
package com.test.server2;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Date;
/**
 * 封裝響應信息
 */
public class Response {
    //兩個常量
    public static final String CRLF = "\r\n";
    public static final String BLANK = " ";
    //流
    private BufferedWriter bw;
    //正文
    private StringBuilder content;
    //存儲頭信息
    private StringBuilder headInfo;
    //存儲正文長度
    private int len = 0;

    public Response(){
        headInfo = new StringBuilder();
        content = new StringBuilder();
        len = 0;
    }
    public Response(OutputStream os){
        this();
        bw = new BufferedWriter(new OutputStreamWriter(os));
    }
    public Response(Socket client){
        this();
        try {
            bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
        } catch (IOException e) {
            headInfo = null;
        }
    }
    /**
     * 構建正文
     */
    public Response print(String info){
        content.append(info);
        len += (info + CRLF).getBytes().length;
        return this;
    }
    /**
     * 構建正文+回車
     */
    public Response println(String info){
        content.append(info).append(CRLF);
        len += (info + CRLF).getBytes().length;
        return this;
    }

    /**
     * 構建響應頭
     */
    private void createHeadInfo(int code){
        //1)HTTP協議版本、狀態代碼、描述
        headInfo.append("HTTP/1.1").append(BLANK).append(code).append(BLANK);
        switch(code){
            case 200:
                headInfo.append("OK");
                break;
            case 404:
                headInfo.append("NOT FOUND");
                break;
            case 500:
                headInfo.append("Server Error");
                break;
        }
        headInfo.append(CRLF);
        //2)響應頭(Response Head)
        headInfo.append("Server:test Server/0.0.1").append(CRLF);
        headInfo.append("Date:").append(new Date()).append(CRLF);
        headInfo.append("Content-type:text/html;charset=GBK").append(CRLF);
        //正文長度:字節長度
        headInfo.append("Content-Length:").append(len).append(CRLF);
        headInfo.append(CRLF);
    }

    /**
     * 推送到客戶端
     * @throws IOException 
     */
    void pushToClient(int code) throws IOException{
        if(null==headInfo){
            code = 500;
        }
        createHeadInfo(code);
        //頭信息+分割符
        bw.append(headInfo.toString());
        //正文
        bw.append(content.toString());
        bw.flush();
        bw.close();
    }
}
package com.test.server2;

import java.util.Map;

public class WebApp {
    private static ServletContext contxt;
    static{
        contxt = new ServletContext();

        Map<String,String> mapping = contxt.getMapping();
        mapping.put("/login", "login");
        mapping.put("/log", "login");
        mapping.put("/reg", "register");

        Map<String,Servlet> servlet = contxt.getServlet();
        servlet.put("login", new LoginServlet());
        servlet.put("register", new RegisterServlet());     
    }

    public static Servlet getServlet(String url){
        if(null==url || (url=url.trim()).equals("")){
            return null;
        }
        return contxt.getServlet().get(contxt.getMapping().get(url));
    }
}
package com.test.server2;
/**
 * 抽象爲一個父類
 */
public abstract class Servlet {
    public void service(Request req,Response rep) throws Exception{
        this.doGet(req,rep);
        this.doPost(req,rep);
    }

    public abstract void doGet(Request req,Response rep) throws Exception;
    public abstract void doPost(Request req,Response rep) throws Exception;
}
package com.test.server2;

import java.util.HashMap;
import java.util.Map;
/**
 * 上下文
 */
public class ServletContext {
    //爲每一個servlet取別名
    // login-->LoginServlet
    private Map<String,Servlet> servlet;
    // url-->login
    //  /log-->login
    //  /login-->login
    private Map<String,String> mapping;

    public ServletContext() { 
        servlet = new HashMap<String,Servlet>();
        mapping = new HashMap<String,String>();
    }

    public Map<String, Servlet> getServlet() {
        return servlet;
    }

    public void setServlet(Map<String, Servlet> servlet) {
        this.servlet = servlet;
    }

    public Map<String, String> getMapping() {
        return mapping;
    }

    public void setMapping(Map<String, String> mapping) {
        this.mapping = mapping;
    }
}
package com.test.server2;

public class LoginServlet extends Servlet{

    @Override
    public void doGet(Request req,Response rep) throws Exception {
        String name = req.getParameterValue("uname");
        String pwd = req.getParameterValue("pwd");
        if(login(name, pwd)){
            rep.println("登錄成功");
        }else{
            rep.println("登錄失敗");
        }
    }

    public boolean login(String name,String pwd){
        return name.equals("test") && pwd.equals("12346");
    }

    @Override
    public void doPost(Request req,Response rep) throws Exception {

    }
}
package com.test.server2;

public class RegisterServlet extends Servlet{

    @Override
    public void doGet(Request req, Response rep) throws Exception {

    }

    @Override
    public void doPost(Request req, Response rep) throws Exception {
        rep.println("<html><head><title>返回註冊</title>");
        rep.println("</head><body>");
        rep.println("你的用戶名爲:" + req.getParameterValue("uname"));
        rep.println("</body></html>");
    }
}

三、S02E204_01手寫服務器httpserver_多請求處理_反射
反射

**以下代碼關鍵性修改:**
Map<String,Servlet>改爲Map<String,String>
package com.test.server2;

import java.util.HashMap;
import java.util.Map;
/**
 * 上下文
 */
public class ServletContext {
    //爲每一個servlet取別名
    // login-->com.test.server2.LoginServlet
    private Map<String,String> servlet;
    // url-->login
    //  /log-->login
    //  /login-->login
    private Map<String,String> mapping;

    public ServletContext() { 
        servlet = new HashMap<String,String>();
        mapping = new HashMap<String,String>();
    }

    public Map<String, String> getServlet() {
        return servlet;
    }

    public void setServlet(Map<String, String> servlet) {
        this.servlet = servlet;
    }

    public Map<String, String> getMapping() {
        return mapping;
    }

    public void setMapping(Map<String, String> mapping) {
        this.mapping = mapping;
    }
}
**以下代碼關鍵性修改:**
//return contxt.getServlet().get(contxt.getMapping().get(url));
//根據字符串(完整路徑)創建對象
String name = contxt.getServlet().get(contxt.getMapping().get(url));
return (Servlet)Class.forName(name).newInstance();//確保空構造存在
package com.test.server2;

import java.util.Map;

public class WebApp {
    private static ServletContext contxt;
    static{
        contxt = new ServletContext();

        Map<String,String> mapping = contxt.getMapping();
        mapping.put("/login", "login");
        mapping.put("/log", "login");
        mapping.put("/reg", "register");

        Map<String,String> servlet = contxt.getServlet();
        servlet.put("login", "com.test.server2.LoginServlet");
        servlet.put("register", "com.test.server2.RegisterServlet");        
    }

    public static Servlet getServlet(String url) throws InstantiationException, IllegalAccessException, ClassNotFoundException{
        if(null==url || (url=url.trim()).equals("")){
            return null;
        }
        //return contxt.getServlet().get(contxt.getMapping().get(url));

        //根據字符串(完整路徑)創建對象
        String name = contxt.getServlet().get(contxt.getMapping().get(url));
        return (Servlet)Class.forName(name).newInstance();//確保空構造存在
    }
}
發佈了4 篇原創文章 · 獲贊 7 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章