• 计算机网络(13)-----java nio手动实现简单的http服务器


    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("该请求的头格式为
    " + 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("
    ");
            //设置请求方式
            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 + "
    ");
            //响应头
            sb.append("Server: " + serverName + "
    ");
            sb.append("Content-Type: " + contentType + "
    ");
            sb.append("Date: " + new Date() + "
    ");
            if(reader != null) {
                sb.append("Content-Length: " + html.getBytes().length + "
    ");
            }
    
            //响应内容
            sb.append("
    ");
            sb.append(html);
            
            buffer.put(sb.toString().getBytes());
            //从写模式,切换到读模式
            buffer.flip();
            try {
                logger.info("生成相应
    " + 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 + "
    ");
                        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

     ### u8BBEu7F6E###
    log4j.rootLogger = debug,stdout,D,E
    
    ### u8F93u51FAu4FE1u606Fu5230u63A7u5236u62AC ###
    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
    
    ### u8F93u51FADEBUG u7EA7u522Bu4EE5u4E0Au7684u65E5u5FD7u5230=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
    
    ### u8F93u51FAERROR u7EA7u522Bu4EE5u4E0Au7684u65E5u5FD7u5230=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,成功!

  • 相关阅读:
    为网站设置自定义404错误页面
    iOS核心动画
    Java 匿名内部类的示例介绍
    理解SimpleExpandableListAdapter的构造函数
    Android 控件之Spinner
    ExpandableListView 和 ExpandableListActivity的使用及数据更新
    Android中 RatingBar评分条的使用
    IHttphandler之Url重写
    DOTA版设计模式——开篇
    IHttphandler之图片水印
  • 原文地址:https://www.cnblogs.com/a294098789/p/5676566.html
Copyright © 2020-2023  润新知