計算機網絡(13)-----java nio手動實現簡單的http服務器

java nio手動實現簡單的http服務器

   需求分析

   最近在學習HTTP協議,仍是但願動手去作一作,因此就本身實現了一個http服務器,主要功能是將http請求封裝httpRequest,經過解析web.xml,用不一樣的handler處理不一樣的uri,而後再將封裝好的httpResponse還原成http響應返回瀏覽器。html

  代碼已經成功上傳至  GitHub java

   若是對你學習JavaNIO有幫助的話,記得給個star哦!git

https://github.com/hansiming/HttpServerByJavaNIOgithub

 

  代碼web

  使用java nio實現監聽,完成服務器監聽線程apache

package com.cszjo.com.http.server;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

import org.apache.log4j.Logger;

import com.cszjo.com.http.handler.HttpHandler;
import com.cszjo.com.http.utils.XMLUtil;

/**  
 * @Title:  Server.java   
 * @Description: 打開服務
 * @author: Han   
 * @date:   2016年7月12日 下午7:22:47  
 */  
public class Server implements Runnable {

    private boolean interrupted = false;
    
    private Logger logger = Logger.getLogger(Server.class);
    
    public Server(boolean interrupted) {
        this.interrupted = interrupted;
    }

    @Override
    public void run() {
        try {
            //打開一個選擇器
            Selector selector = Selector.open();
            //打開ServerSocketChannel通道
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            //獲得ServerSocket對象
            ServerSocket serverSocket = serverSocketChannel.socket();
            //ServerSocketChannel通道監聽server.xml中設置的端口
            String portStr = XMLUtil.getRootElement("server.xml").element("port").getText(); 
            serverSocket.setReuseAddress(true);  
            try {
                serverSocket.bind(new InetSocketAddress(Integer.parseInt(portStr)));
            } catch (Exception e) {
                logger.error("綁定端口失敗,請檢查server.xml中是否設置了port屬性");
                return;
            }
            logger.info("成功綁定端口" + portStr);
            //將通道設置爲非阻塞模式
            serverSocketChannel.configureBlocking(false);
            //將serverSocketChannel註冊給選擇器,並綁定ACCEPT事件
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            logger.info("服務器啓動成功");
            while(!interrupted) {
                //查詢就緒的通道數量
                int readyChannels = selector.select();
                //沒有就緒的則繼續進行循環
                if(readyChannels == 0)
                    continue;
                //得到就緒的selectionKey的set集合
                Set<SelectionKey> keys = selector.selectedKeys();
                //得到set集合的迭代器
                Iterator<SelectionKey> iterator = keys.iterator();
                while(iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    if(key.isAcceptable()) {
                        //該key有ACCEPT事件
                        //將監聽獲得的channel強轉爲ServerSocketChannel
                        ServerSocketChannel server = (ServerSocketChannel) key.channel();
                        //獲得接收到的SocketChannel
                        SocketChannel socketChannel = server.accept();
                        if(socketChannel != null) {
                            logger.info("收到了來自" + ((InetSocketAddress)socketChannel.getRemoteAddress()).getHostString()
                                    + "的請求");
                            //將socketChannel設置爲阻塞模式
                            socketChannel.configureBlocking(false);
                            //將socketChannel註冊到選擇器
                            socketChannel.register(selector, SelectionKey.OP_READ);
                        }
                    } else if (key.isReadable()) {
                        //該key有Read事件
                        SocketChannel socketChannel = (SocketChannel) key.channel();
                        String requestHeader = "";
                        //拿出通道中的Http頭請求
                        try {
                            requestHeader = receive(socketChannel);
                        } catch (Exception e) {
                            logger.error("讀取socketChannel出錯");
                            return;
                        }
                        //啓動線程處理該請求,if條件判斷一下,防止心跳包
                        if(requestHeader.length() > 0) {
                            logger.info("該請求的頭格式爲\r\n" + requestHeader);
                            logger.info("啓動了子線程..");
                            new Thread(new HttpHandler(requestHeader, key)).start();
                        }
                    } else if (key.isWritable()) {
                        //該key有Write事件
                        logger.info("有流寫出!");
                        SocketChannel socketChannel = (SocketChannel) key.channel();
                        socketChannel.shutdownInput();
                        socketChannel.close();
                    }
                    //從key集合中刪除key,這一步很重要,就是由於沒寫這句,Selector.select()方法一直返回的是0
                    //緣由分析多是不從集合中刪除,就不會回到I/O就緒事件中
                    iterator.remove();
                }
            }
        
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    private String receive(SocketChannel socketChannel) throws Exception {
        //聲明一個1024大小的緩衝區
        ByteBuffer buffer = ByteBuffer.allocate(1024);  
        byte[] bytes = null;  
        int size = 0;
        //定義一個字節數組輸出流
        ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
        //將socketChannel中的數據寫入到buffer中,此時的buffer爲寫模式,size爲寫了多少個字節
        while ((size = socketChannel.read(buffer)) > 0) {
            //將寫模式改成讀模式
            //The limit is set to the current position and then the position is set to zero.
            //將limit設置爲以前的position,而將position置爲0,更多java nio的知識會寫成博客的
            buffer.flip();
            bytes = new byte[size];
            //將Buffer寫入到字節數組中
            buffer.get(bytes);
            //將字節數組寫入到字節緩衝流中
            baos.write(bytes);
            //清空緩衝區
            buffer.clear();
        }
        //將流轉回字節數組
        bytes = baos.toByteArray();
        return new String(bytes);
    }
}

    實現MapHandler,解析web.xml,完成uri到對應handler的映射,該handler使用單例完成數組

package com.cszjo.com.http.handler;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.dom4j.Element;

import com.cszjo.com.http.utils.XMLUtil;

/**  
 * @Title:  HandlerMap.java   
 * @Description: HandlerMap(單例) 訪問路徑--->相應解決類
 * @author: Han   
 * @date:   2016年7月15日 下午4:52:29  
 */  
public class MapHandler {
    
    //訪問路徑對應控制類
    private static Map<String, Handler> handlerMap = new HashMap<>();
    
    private static MapHandler instance = null; 
    
    //將構造器私有化
    private MapHandler(){}
    
    //獲得HandlerMap對象實例
    public static MapHandler getContextMapInstance() {
        
        if(instance == null) {
            synchronized (MapHandler.class) {
                if(instance == null) {
                    instance = new MapHandler();
                    //獲得web.xml的根路徑
                    Element rootElement = XMLUtil.getRootElement("web.xml");
                    //獲得handler的集合
                    List<Element> handlers = XMLUtil.getElements(rootElement);
                    for (Element element : handlers) {
                        Element urlPattenEle = XMLUtil.getElement(element, "url-patten");
                        //獲得urlPatten(uri)
                        String urlPatten = XMLUtil.getElementText(urlPattenEle);
                        Element handlerClazzEle = XMLUtil.getElement(element, "handler-class");
                        //獲得handler 的class文件路徑
                        String clazzPath = XMLUtil.getElementText(handlerClazzEle);
                        Class<?> clazz = null;
                        try {
                            //經過反射獲得handler實例化對象,而後以鍵值對的形式存儲
                            clazz = Class.forName(clazzPath);
                            Handler handler = (Handler)clazz.newInstance();
                            instance.getHandlerMap().put(urlPatten, handler);
                            Logger.getLogger(MapHandler.class).info("成功添加Handler " + clazzPath);
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        } catch (InstantiationException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
            
        return instance;
    }
    
    public Map<String, Handler> getHandlerMap() {
        return handlerMap;
    }
}

  web.xml瀏覽器

<?xml version="1.0" encoding="UTF-8"?>
<server>
    <handler>
        <handler-class>com.cszjo.com.http.handler.impl.LogionHandler</handler-class>
        <url-patten>/login</url-patten>
    </handler>
</server>

  httpHandler,處理一次http請求,經過uri啓動不一樣的handler進行處理服務器

package com.cszjo.com.http.handler;

import java.nio.channels.SelectionKey;

import org.apache.log4j.Logger;

import com.cszjo.com.http.context.Context;
import com.cszjo.com.http.context.impl.HttpContext;
import com.cszjo.com.http.handler.impl.NotFoundHandler;

/**  
 * @Title:  HandlerHttp.java   
 * @Description: 處理一次Http請求 
 * @author: Han   
 * @date:   2016年7月15日 下午7:07:21  
 */  
public class HttpHandler implements Runnable {

    //就緒的I/O鍵
    private SelectionKey key;
    //上下文
    private Context context = new HttpContext();
    //http請求字符串
    private String requestHeader;
    //針對uri選擇不一樣的處理器
    private Handler handler;
    private Logger logger = Logger.getLogger(HttpHandler.class);
    
    public HttpHandler(String requestHeader, SelectionKey key) {
        this.key = key;
        this.requestHeader = requestHeader;
    }

    @Override
    public void run() {
        //初始化上下文
        context.setContext(requestHeader, key);
        //獲得uri
        String uri = context.getRequest().getUri();
        logger.info("獲得了uri " + uri);
        //獲得MapHandler集合(uri-->handler)
        handler = MapHandler.getContextMapInstance().getHandlerMap().get(uri);
        //找不到對應的handler
        if(handler == null) {
            //404Handler進行處理
            handler = new NotFoundHandler();
        }
        //初始化handler並執行
        handler.init(context);
    }
}

  Context上下文抽象類設計app

package com.cszjo.com.http.context;

import java.nio.channels.SelectionKey;

/**  
 * @Title:  Context.java   
 * @Description: Http上下文抽象類
 * @author: Han   
 * @date:   2016年7月16日 下午2:19:06  
 */  
public abstract class Context {
    
    protected Request request;
    protected Response response;
    
    /**
     * 設置當前鏈接的上下文
     * @param:  @return  
     * @return: Context
     * @Autor: Han
     */
    public abstract void setContext(String requestHeader, SelectionKey key);
    
    /**
     * 獲得Request
     * @param:  @return  
     * @return: Request
     * @Autor: Han
     */
    public Request getRequest() {
        return request;
    }
    
    /**
     * 獲得Response
     * @param:  @return  
     * @return: Response
     * @Autor: Han
     */
    public Response getResponse() {
        return response;
    }

}

  HttpContext的實現

package com.cszjo.com.http.context.impl;

import java.nio.channels.SelectionKey;

import com.cszjo.com.http.context.Context;
import com.cszjo.com.http.context.Request;
import com.cszjo.com.http.context.Response;

/**  
 * @Title:  HttpContext.java   
 * @Description: HttpContext http上下文
 * @author: Han   
 * @date:   2016年7月16日 下午2:20:00  
 */  
public class HttpContext extends Context {

    private Request request;
    private Response response;
    
    @Override
    public void setContext(String requestHeader, SelectionKey key) {
        
        //初始化request
        request = new HttpRequest(requestHeader);
        //初始化response
        response = new HttpResponse(key);
        setRequest();
        setResponse();
    }

    private void setRequest() {
        super.request = this.request;
    }

    private void setResponse() {
        super.response = this.response;
    }
}

  Request接口設計

package com.cszjo.com.http.context;

import java.util.Map;
import java.util.Set;

/**  
 * @Title:  Request.java   
 * @Description: 接口設計:Request接口
 * @author: Han   
 * @date:   2016年7月15日 下午9:21:45  
 */  
public interface Request {
    
    public static final String POST = "POST";
    
    public static final String GET = "GET";
    /**
     * 獲得參數
     * @param:  @return  
     * @return: Map<String,Object>
     * @Autor: Han
     */
    public Map<String, Object> getAttribute();
    
    /**
     * 獲得請求方式
     * @param:  @return  
     * @return: String
     * @Autor: Han
     */
    public String getMethod();
    
    /**
     * 獲得URI
     * @param:  @return  
     * @return: String
     * @Autor: Han
     */
    public String getUri();

    /**
     * 版本協議
     * @param:  @return  
     * @return: String
     * @Autor: Han
     */
    public String getProtocol();

    /**
     * 獲得請求頭Map
     * @param:  @return  
     * @return: String
     * @Autor: Han
     */
    public Map<String, Object> getHeaders();

    /**
     * 獲得請求頭參數集合
     * @param:  @return  
     * @return: String
     * @Autor: Han
     */
    public Set<String> getHeaderNames();

    /**
     * 根據請求頭名獲得對應的請求頭
     * @param:  @return  
     * @return: String
     * @Autor: Han
     */
    public Object getHeader(String key);
}

  HttpRequest實現

package com.cszjo.com.http.context.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import com.cszjo.com.http.context.Request;

/**  
 * @Title:  HttpRequest.java   
 * @Description: HTTP請求(還有不少方法能夠寫的)
 * @author: Han   
 * @date:   2016年7月15日 下午9:16:45  
 */  
public class HttpRequest implements Request {
    
    //參數
    private Map<String, Object> attribute = new HashMap<>();
    
    //請求頭(Request Header)
    private Map<String, Object> headers = new HashMap<>();
    
    //請求方法
    private String method;
    
    //uri
    private String uri;
    
    //協議版本
    private String protocol;
    
    public HttpRequest(String httpHeader) {
        init(httpHeader);
    }

    private void init(String httpHeader) {
        //將請求分行
        String[] headers = httpHeader.split("\r\n");
        //設置請求方式
        initMethod(headers[0]);
        //設置URI
        initURI(headers[0]);
        //設置版本協議
        initProtocol(headers[0]);
        //設置請求頭
        initRequestHeaders(headers);
    }

    /**
     * 設置請求方法
     * @param:  @param str  
     * @return: void
     * @Autor: Han
     */
    private void initMethod(String str) {
        method = str.substring(0, str.indexOf(" "));
    }
    
    /**
     * 設置request參數
     * @param:  @param attr  
     * @return: void
     * @Autor: Han
     */
    private void initAttribute(String attr) {
        String[] attrs = attr.split("&");
        for (String string : attrs) {
            String key = string.substring(0, string.indexOf("="));
            String value = string.substring(string.indexOf("=") + 1);
            attribute.put(key, value);
        }
    }

    /**
     * 設置uri
     * @param:  @param str  
     * @return: void
     * @Autor: Han
     */
    private void initURI(String str) {
        uri = str.substring(str.indexOf(" ") + 1, str.indexOf(" ", str.indexOf(" ") + 1));
        //若是是get方法,則後面跟着參數   /index?a=1&b=2
        if(method.toUpperCase().equals("GET")) {
            //有問號表示後面跟有參數
            if(uri.contains("?")) {
                 String attr = uri.substring(uri.indexOf("?") + 1, uri.length());
                uri = uri.substring(0, uri.indexOf("?"));
                initAttribute(attr);
            }
        }
    }
    
    /**
     * 初始化請求頭
     * @param:  @param strs  
     * @return: void
     * @Autor: Han
     */
    private void initRequestHeaders(String[] strs) {
        //去掉第一行
        for(int i = 1; i < strs.length; i++) {
            String key = strs[i].substring(0, strs[i].indexOf(":"));
            String value = strs[i].substring(strs[i].indexOf(":") + 1);
            headers.put(key, value);
        }
    }
    
    /**
     * 設置協議版本
     * @param:  @param str  
     * @return: void
     * @Autor: Han
     */
    private void initProtocol(String str) {
        protocol = str.substring(str.lastIndexOf(" ") + 1, str.length());
    }

    @Override
    public Map<String, Object> getAttribute() {
        return attribute;
    }

    @Override
    public String getMethod() {
        return method;
    }

    @Override
    public String getUri() {
        return uri;
    }

    @Override
    public String getProtocol() {
        return protocol;
    }

    @Override
    public Map<String, Object> getHeaders() {
        return headers;
    }

    @Override
    public Set<String> getHeaderNames() {
        return headers.keySet();
    }

    @Override
    public Object getHeader(String key) {
        return headers.get(key);
    }
}

  Response接口設計

package com.cszjo.com.http.context;

import java.nio.channels.SelectionKey;

import com.cszjo.com.http.utils.XMLUtil;

/**  
 * @Title:  Response.java   
 * @Description: 接口設計:response接口
 * @author: Han   
 * @date:   2016年7月16日 下午2:19:25  
 */  
public interface Response {
    
    //服務器名字
    public static final String SERVER_NAME = XMLUtil.getRootElement("server.xml").element("serverName").getText();
    
    public String getContentType();
    
    public int getStatuCode();
    
    public String getStatuCodeStr();
    
    public String getHtmlFile();
    
    public void setHtmlFile(String htmlFile);
    
    public SelectionKey getKey();
    
    public void setContentType(String contentType);
    
    public void setStatuCode(int statuCode);
    
    public void setStatuCodeStr(String statuCodeStr);
}

  httpResponse實現

package com.cszjo.com.http.context.impl;

import java.nio.channels.SelectionKey;

import com.cszjo.com.http.context.Response;

/**  
 * @Title:  HttpResponse.java   
 * @Description: http響應
 * @author: Han   
 * @date:   2016年7月16日 下午2:20:41  
 */  
public class HttpResponse implements Response {
    
    private SelectionKey key;
    //內容類型  defalut 爲text/html
    private String contentType = "text/html";
    //響應碼  defalut 爲200
    private int StatuCode = 200;
    private String statuCodeStr = "OK";
    private String htmlFile = "";

    public HttpResponse(SelectionKey key) {
        this.key = key;
    }

    @Override
    public String getContentType() {
        return contentType;
    }

    @Override
    public int getStatuCode() {
        return StatuCode;
    }

    @Override
    public SelectionKey getKey() {
        return key;
    }

    @Override
    public String getStatuCodeStr() {
        return statuCodeStr;
    }

    @Override
    public String getHtmlFile() {
        return htmlFile;
    }

    @Override
    public void setHtmlFile(String htmlFile) {
        this.htmlFile = htmlFile;
    }

    @Override
    public void setContentType(String contentType) {
        this.contentType = contentType;
    }

    @Override
    public void setStatuCode(int statuCode) {
        StatuCode = statuCode;
    }

    @Override
    public void setStatuCodeStr(String statuCodeStr) {
        this.statuCodeStr = statuCodeStr;
    }
}

  處理器Handler的接口設計

package com.cszjo.com.http.handler;

import com.cszjo.com.http.context.Context;

/**  
 * @Title:  Handler.java   
 * @Description: 接口設計:處理器Handler接口
 * @author: Han   
 * @date:   2016年7月12日 下午7:12:37  
 */  
public interface Handler {
    
    /**
     * 初始化handler
     * @param:  @param context  
     * @return: void
     * @Autor: Han
     */
    public void init(Context context);
    
    /**
     * handler service(service應該不是這樣作的... - -!)
     * @param:  @param context  
     * @return: void
     * @Autor: Han
     */
    public void service(Context context);
    
    /**
     * Get形式執行該方法
     * @param:  @param context  
     * @return: void
     * @Autor: Han
     */
    public void doGet(Context context);
    
    /**
     * POST形式執行該方法
     * @param:  @param context  
     * @return: void
     * @Autor: Han
     */
    public void doPost(Context context);
    
    /**
     * 銷燬Handler(並無銷燬... - -!)
     * @param:  @param context  
     * @return: void
     * @Autor: Han
     */
    public void destory(Context context);
}

  由於doGet或者doPost只會執行一個,因此中間在寫一個抽象類,具體的handler只須要重寫該抽象類的方法既可

package com.cszjo.com.http.handler.abs;

import com.cszjo.com.http.context.Context;
import com.cszjo.com.http.context.Request;
import com.cszjo.com.http.handler.Handler;
import com.cszjo.com.http.handler.ResponseHandler;

/**  
 * @Title:  AbstractHandler.java   
 * @Description: Handler抽象類
 * @author: Han   
 * @date:   2016年7月16日 下午2:11:57  
 */  
public class AbstractHandler implements Handler {
    
    protected Context context;
    
    @Override
    public void init(Context context) {
        this.context = context;
        this.service(context);
    }
    
    @Override
    public void service(Context context) {
        //經過請求方式選擇具體解決方法
        String method = context.getRequest().getMethod();
        if(method.equals(Request.GET)) {
            this.doGet(context);
        } else if (method.equals(Request.POST)) {
            this.doPost(context);
        }
        sendResponse(context);
    }

    @Override
    public void doGet(Context context) {
        
    }

    @Override
    public void doPost(Context context) {
        
    }

    @Override
    public void destory(Context context) {
        context = null;
    }

    /**
     * 經過上下文,返回封裝response響應
     * @param:  @param context  
     * @return: void
     * @Autor: Han
     */
    private void sendResponse(Context context) {
        new ResponseHandler().write(context);
    }
}

  Login Handler的實現

package com.cszjo.com.http.handler.impl;

import org.apache.log4j.Logger;

import com.cszjo.com.http.context.Context;
import com.cszjo.com.http.handler.abs.AbstractHandler;

/**  
 * @Title:  LogionHandler.java   
 * @Description: 解決login業務邏輯 
 * @author: Han   
 * @date:   2016年7月16日 下午2:08:18  
 */  
public class LogionHandler extends AbstractHandler{

    private Logger logger = Logger.getLogger(LogionHandler.class);
    
    @Override
    public void doGet(Context context) {
        logger.info("進入了handler--->LoginHandler");
        context.getResponse().setHtmlFile("login.html");
    }
}

  未找到請求的URI,因此返回404,該處理器處理404錯誤

package com.cszjo.com.http.handler.impl;

import org.apache.log4j.Logger;

import com.cszjo.com.http.context.Context;
import com.cszjo.com.http.context.Response;
import com.cszjo.com.http.handler.abs.AbstractHandler;

/**  
 * @Title:  NotFoundHandler.java   
 * @Description: 解決404NotFound響應
 * @author: Han   
 * @date:   2016年7月16日 下午2:08:44  
 */  
public class NotFoundHandler extends AbstractHandler {
    
    private Logger logger = Logger.getLogger(NotFoundHandler.class);
    private Response response;
    
    @Override
    public void doGet(Context context) {
        logger.info("進入了404Handler");
        response = context.getResponse();
        
        response.setStatuCode(404);
        response.setStatuCodeStr("Not Found");
        response.setHtmlFile("404.html");
    }
}

  封裝完http請求,下一步就須要還原response響應了

package com.cszjo.com.http.handler;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Date;

import org.apache.log4j.Logger;

import com.cszjo.com.http.context.Context;
import com.cszjo.com.http.context.Request;
import com.cszjo.com.http.context.Response;

/**  
 * @Title:  ResponseHandler.java   
 * @Description: 封裝response響應
 * @author: Han   
 * @date:   2016年7月16日 下午2:09:45  
 */  
public class ResponseHandler {
    
    private Request request;
    private Response response;
    private String protocol;
    private int statuCode;
    private String statuCodeStr;
    private ByteBuffer buffer;
    private String serverName;
    private String contentType;
    private SocketChannel channel;
    private Selector selector;
    private SelectionKey key;
    private Logger logger = Logger.getLogger(ResponseHandler.class);
    private BufferedReader reader;
    private String htmlFile;
    
    public void write(Context context) {
        //從context中獲得相應的參數
        request = context.getRequest();
        response = context.getResponse();
        buffer = ByteBuffer.allocate(1024);
        protocol = request.getProtocol();
        statuCode = response.getStatuCode();
        statuCodeStr = response.getStatuCodeStr();
        serverName = Response.SERVER_NAME;
        contentType = response.getContentType();
        key = response.getKey();
        selector = key.selector();
        channel = (SocketChannel)key.channel();
        htmlFile = response.getHtmlFile();
        
        //獲得響應正文內容
        String html = setHtml(context);
        
        StringBuilder sb = new StringBuilder();
        //狀態行
        sb.append(protocol + " " + statuCode + " " + statuCodeStr + "\r\n");
        //響應頭
        sb.append("Server: " + serverName + "\r\n");
        sb.append("Content-Type: " + contentType + "\r\n");
        sb.append("Date: " + new Date() + "\r\n");
        if(reader != null) {
            sb.append("Content-Length: " + html.getBytes().length + "\r\n");
        }

        //響應內容
        sb.append("\r\n");
        sb.append(html);
        
        buffer.put(sb.toString().getBytes());
        //從寫模式,切換到讀模式
        buffer.flip();
        try {
            logger.info("生成相應\r\n" + sb.toString());
            channel.register(selector, SelectionKey.OP_WRITE);
            channel.write(buffer);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private String setHtml(Context context) {
        StringBuilder html = null;
        if(htmlFile != null && htmlFile.length() > 0) {
            
            html = new StringBuilder();
            
            try {
                reader = new BufferedReader(new FileReader(new File(htmlFile)));
                String htmlStr;
                htmlStr = reader.readLine();
                while(htmlStr != null) {
                    html.append(htmlStr + "\r\n");
                    htmlStr = reader.readLine();
                }
                
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
        return html.toString();
    }
}

  程序啓動入口

package com.cszjo.com.http.server;

/**  
 * @Title:  Solution.java   
 * @Description: 啓動Web服務器入口
 * @author: Han   
 * @date:   2016年7月12日 下午7:11:15  
 */  
public class Solution {
    
    //啓動方法
    public static void main(String[] args) {
        new Thread(new Server(false)).start();
    }
}

  XMLUtils

package com.cszjo.com.http.utils;

import java.io.File;
import java.util.List;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**  
 * @Title:  XMLUtil.java   
 * @Description: 解決XML讀取問題 
 * @author: Han   
 * @date:   2016年7月15日 下午4:55:28  
 */  
public class XMLUtil {
    
    private static Logger logger = Logger.getLogger(XMLUtil.class);
    private static SAXReader reader = new SAXReader();
    
    /**
     * 獲得根節點
     * @param:  @param xmlPath
     * @param:  @return  
     * @return: Element
     * @Autor: Han
     */
    public static Element getRootElement(String xmlPath) {
        Document document = null;;
        try {
            document = reader.read(new File(xmlPath));
        } catch (DocumentException e) {
            logger.error("找不到指定的xml文件的路徑" + xmlPath + "!");
            return null;
        }
        return document.getRootElement();
    }
    
    /**
     * 獲得該節點下的子節點集合
     * @param:  @param element
     * @param:  @return  
     * @return: List<Element>
     * @Autor: Han
     */
    @SuppressWarnings("unchecked")
    public static List<Element> getElements(Element element) {
        return element.elements();
    }
    
    /**
     * 獲得該節點下指定的節點
     * @param:  @param name
     * @param:  @return  
     * @return: Element
     * @Autor: Han
     */
    public static Element getElement(Element element, String name) {
        Element childElement = element.element(name);
        if(childElement == null) {
            logger.error(element.getName() + "節點下沒有子節點" + name);
            return null;
        }
        return childElement;
    }
    
    /**
     * 獲得該節點的內容
     * @param:  @param element
     * @param:  @return  
     * @return: String
     * @Autor: Han
     */
    public static String getElementText(Element element) {
        return element.getText();
    }
}

  該項目須要用到的兩個包:log4j,dom4j

  其他配置文件和靜態文件

  log4j.properties

 ### \u8BBE\u7F6E###
log4j.rootLogger = debug,stdout,D,E

### \u8F93\u51FA\u4FE1\u606F\u5230\u63A7\u5236\u62AC ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

### \u8F93\u51FADEBUG \u7EA7\u522B\u4EE5\u4E0A\u7684\u65E5\u5FD7\u5230=E://logs/error.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = E://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG 
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

### \u8F93\u51FAERROR \u7EA7\u522B\u4EE5\u4E0A\u7684\u65E5\u5FD7\u5230=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =E://logs/error.log 
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR 
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

  server.xml

<?xml version="1.0" encoding="UTF-8"?>
<server>
    <port>8089</port>
    <serverName>Han`s Server</serverName>
    <!-- 默認編碼爲UTF-8 -->
    <charset>UTF-8</charset>
</server>

  login.html

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <meta name="Generator" content="EditPlus®">
  <meta name="Author" content="">
  <meta name="Keywords" content="">
  <meta name="Description" content="">
  <title>han登陸</title>
 </head>
 <body>
    用戶名:<input type="text" name="userName"><br/>
    密碼:<input type="text" name="userName"><br/>
 </body>
</html>

  404.html

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <meta name="Generator" content="EditPlus®">
  <meta name="Author" content="">
  <meta name="Keywords" content="">
  <meta name="Description" content="">
  <title>Document</title>
 </head>
 <body>
  <h1>404 NOT Found</h1>
  <strong style="color:red;">來自Han服務器</strong>
 </body>
</html>

測試

  啓動服務

  

  在瀏覽器中輸入http://localhost:8089/login以後

  

  

  瀏覽器顯示

  

  在瀏覽器中輸入http://localhost:8089/lo以後

  

  OK,成功!

相關文章
相關標籤/搜索