java nio手动实现简单的http服务器

   需求分析

   最近在学习HTTP协议,还是希望动手去做一做,所以就自己实现了一个http服务器,主要功能是将http请求封装httpRequest,通过解析web.xml,用不同的handler处理不同的uri,然后再将封装好的httpResponse还原成http响应返回浏览器。

  代码已经成功上传至  GitHub 

   如果对你学习JavaNIO有帮助的话,记得给个star哦!

https://github.com/hansiming/HttpServerByJavaNIO

 

  代码

  使用java nio实现监听,完成服务器监听线程

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上下文抽象类设计

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,成功!

 

 posted on 2016-07-16 15:22  韩思明  阅读(6246)  评论(11编辑  收藏  举报