HttpServer

1.Socket编程

1)创建服务器+指定端口 ServerSocket(int port) 创建绑定到特定端口的服务器套接字。

2)接收客户端连接 阻塞式

3)发送数据+接收数据

package com.yijiuju.learn.server;

import com.yijiuju.learn.util.CloseUtil;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/*
 * 创建服务器并启动
 * 请求并相应
 * 加入多线程
 * */
public class Server {
    private ServerSocket server;
    private boolean isShutDown = false;
    public static void main(String[] args) {
        Server server = new Server();
        server.star();
    }

    /*
    * 默认启动方法
    * */
    public  void star() {
        star(8888);
    }
    /*
    * 指定端口的启动方法
    * */
    public  void star(int port) {
        try {
            //1.创建服务器端,并指定端口
            server = new ServerSocket(port);
            //2.接收多个客户端连接,启用多线程
            this.receive();
        } catch (IOException e) {
            stop();
        }
    }
    /*
    * 接收客户端
    * */
    private void receive() {
        try {
            while (!isShutDown) {
                //接收客户端连接,获取套接字 阻塞式 
                Socket client =server.accept();
                //启用多线程将请求和响应独立,实现发送和接收数据的独立
                new Thread(new Dispatcher(client)).start();
            }
        } catch (IOException e) {
            isShutDown=true;
        }
    }
    /*
    * 停止服务
    * */
    public void stop() {
        isShutDown = true;
        CloseUtil.closeAll(server);
    }
}

2.html

格式



3.HTTP协议


1)HTTP请求报文



封装请求

package com.yijiuju.learn.server;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.*;

/*
* 封装请求
* */
public class Request {
    //请求方式
          private String method;
    //请求资源
         private String url;
    //请求参数
         private Map<String, List<String>> parameterMapValues;
    //内部
         private static final String CRLF = "\r\n";
    private InputStream is;
    private String requestInfo;

    public Request() {
        method = "";
        url = "";
        parameterMapValues = new HashMap<>();
    }

    public Request(InputStream is) {
        this();
        this.is = is;
        byte[] data = new byte[20480];
        try {
            int len = is.read(data);
            requestInfo = new String(data, 0, len);
        } catch (IOException e) {
            return;
        }

         //分析请求信息
        parseRequestInfo();
    }

    /*
     * 分析请求信息
     * */
    private void parseRequestInfo() {
        if (null == requestInfo || (requestInfo = requestInfo.trim()).equals("")) {
            return;
        }

        /*
        * ==========================
        * 从信息的首行分解出:请求方式 请求路径 请求参数(get可能存在)
        * :GET /index.html?uname=123&pwd=456 HTTP/1.1
        * 如果是POST方式,请求参数可能在最后正文中
        *
        * ==========================
        * */

        String paramSring = "";//接收请求参数
                 //1.获取请求方式
                   String firstLine = requestInfo.substring(0, requestInfo.indexOf(CRLF));
        int idx= firstLine.indexOf("/");
        this.method = firstLine.substring(0, idx).trim();
        String urlStr = firstLine.substring(idx,firstLine.indexOf("HTTP/"));
        if (this.method.equalsIgnoreCase("POST")) {
            this.url = urlStr;
            paramSring = requestInfo.substring(requestInfo.lastIndexOf(CRLF)).trim();
        } else if (this.method.equalsIgnoreCase("GET")) {
            if (urlStr.contains("?")) { //是否参数
                                      String[] urlArray = urlStr.split("\\?");
                this.url = urlArray[0];
                paramSring = urlArray[1];//接收请求参数
            } else {
                this.url = urlStr;
            }
        }

        //2.将请求参数封装到Map                  //不存在请求参数
                  if (paramSring.equals("")) {
            return;
        }
        parseParams(paramSring);

    }

    private void parseParams(String paramString) {
        //分割 将字符串转成数组
                   StringTokenizer token = new StringTokenizer(paramString, "&");
        while (token.hasMoreElements()) {
            String keyValue = token.nextToken();
            String[] keyValues = keyValue.split("=");
            if (keyValues.length == 1) {
                keyValues = Arrays.copyOf(keyValues, 2);
                keyValues[1] =null;
            }

            String key = keyValues[0].trim();
            String value = (null==keyValues[1])?null:decode(keyValues[1].trim(),"utf-8");
            //转换成Map
            if (!parameterMapValues.containsKey(key)) {
                parameterMapValues.put(key, new ArrayList<>());
            }
            List<String> values = parameterMapValues.get(key);
            values.add(value);
        }
    }
    /*
     * 根据页面的name 获取对应的多个值
     *
     * */
    public String[] getParameterValues(String name) {
        List<String> values = null;
        if ((values = parameterMapValues.get(name)) == null) {
            return null;
        } else {
            return values.toArray(new String[0]);
        }

    }

    /*
     * 根据页面的name 获取对应的单个值
     *
     * */
    public String getParameter(String name) {
        String[] values = getParameterValues(name);
        if (null == values) {
            return null;
        }
        return values[0];
    }

    /*
    * 解决中文问题
    * */
    private String decode(String value, String code) {
        try {
            return URLDecoder.decode(value, code);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
}

2)HTTP响应报文


封装响应

package com.yijiuju.learn.server;

import com.yijiuju.learn.util.CloseUtil;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Date;

/*
* 封装响应信息
* */
public class Response {
    //两个常量
         private static final String CRLF = "\r\n";
    private static final String BLANK = " ";
    //正文
         private StringBuilder content;
    //存储头信息
         private StringBuilder headInfo;
    //存储正文长度
         private int len =0;
    //         private BufferedWriter bw;

    public Response() {
        headInfo = new StringBuilder();
        content = new StringBuilder();
        len =0;
    }

    public Response(OutputStream os) {
        this();
        bw = new BufferedWriter(new OutputStreamWriter(os));
    }

    public Response(Socket client) {
        this();
        try {
            bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
        } catch (IOException e) {
            headInfo = null;
        }
    }
    /*
     * 构建响应头
     * */
    private void createHeadInfo(int code) {
        //1)HTTP协议版本 状态码 描述
        headInfo.append("HTTP/1.1").append(BLANK).append(code).append(BLANK);
        switch (code) {
            case 200:
                headInfo.append("OK");
                break;
            case 404:
                headInfo.append("NOT found");
                break;
            case 500:
                headInfo.append("Server Error");
                break;
        }
        headInfo.append(CRLF);
        //2)响应头(Response Head)
        headInfo.append("Server:Apache Tomcat/6.0.12").append(CRLF);
        headInfo.append("Date:").append(new Date()).append(CRLF);
        headInfo.append("Content-type:text/html;charset=gbk:").append(CRLF);
        //正文长度 字节长度
                   headInfo.append("Content-Length:").append(len).append(CRLF);
        //正文之前
                  headInfo.append(CRLF);
    }

    /*
     * 构建正文
     * */
    public Response println(String info) {
        content.append(info).append(CRLF);
        len += (info+CRLF).getBytes().length;
        return this;
    }
    /*
    * 推送到客户端
    * */
    void pushToClient(int code) throws IOException {
        if (null == headInfo) {
            code = 500;
        }
        createHeadInfo(code);
        //头信息+分隔符
                   bw.append(headInfo.toString());
        //正文
                  bw.append(content.toString());
        bw.flush();
    }
    public void close() {
        CloseUtil.closeAll(bw);
    }
}

分发器:创建线程,实现请求与响应独立进行

package com.yijiuju.learn.server;

import com.yijiuju.learn.servlet.Servlet;
import com.yijiuju.learn.util.CloseUtil;

import java.io.IOException;
import java.net.Socket;

/*
* 一个请求与响应 就一个此对象
* */
public class Dispatcher implements Runnable {

    private Socket client;
    private Request req;
    private Response rep;
    private int code = 200;

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

    @Override
    public void run() {
        try {
            Servlet serv = WebApp.getServlet(req.getUrl());
            if (null == serv) {
                this.code = 404; //找不到资源
            } else {
                serv.service(req,rep);
            }

            rep.pushToClient(code); //推送到客户端
        }catch (Exception e) {
            this.code = 500;
        }
        try {
            rep.pushToClient(500);
        } catch (IOException e) {
            e.printStackTrace();
        }
        CloseUtil.closeAll(client);
    }
}

创建Servlet,用来处理不同的请求对应不同的响应

package com.yijiuju.learn.servlet;

import com.yijiuju.learn.server.Request;
import com.yijiuju.learn.server.Response;

/**
 * Created by heyuying on 18-6-7
 */

/*
* 抽象为一个父类
* */
public abstract class Servlet {
    public void service(Request req, Response rep) throws Exception {
        this.doGet(req,rep);
        this.doPost(req,rep);
    }
    protected abstract void doGet(Request req, Response rep) throws Exception;
    protected abstract void doPost(Request req, Response rep) throws Exception;
}
注册的响应,继承Servlet

package com.yijiuju.learn.servlet;

import com.yijiuju.learn.server.Request;
import com.yijiuju.learn.server.Response;

public class RegisterServlet extends Servlet {
    @Override
    public void doGet(Request req, Response rep) throws Exception {

    }

    @Override
    public void doPost(Request req, Response rep) throws Exception {
        rep.println("<html><head>");
        rep.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">");
        rep.println("<title>返回注册</title>");
        rep.println("</head><body>");
        rep.println("你的用户名为:" + req.getParameter("uname"));
        rep.println("</body></html>");
    }
}

登录的响应,继承Servlet

package com.yijiuju.learn.servlet;

import com.yijiuju.learn.server.Request;
import com.yijiuju.learn.server.Response;

public class LoginServlet extends Servlet {
    @Override
    public void doGet(Request req, Response rep) throws Exception {
        String name = req.getParameter("uname");
        String pwd = req.getParameter("pwd");
        if (login(name, pwd)) {
            rep.println("<html><head>");
            rep.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">");
            rep.println("<title>登录</title>");
            rep.println("</head><body>");
            rep.println("登录成功");
            rep.println("</body></html>");
        } else {
            rep.println("<html><head>");
            rep.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">");
            rep.println("<title>登录</title>");
            rep.println("</head><body>");
            rep.println("登录失败");
            rep.println("</body></html>");
        }
    }

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

    }

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

4.反射

创建ServletContext,用来存储映射关系 

package com.yijiuju.learn.server;

import java.util.HashMap;
import java.util.Map;
/*
* Servlet上下文
* */
public class ServletContext {

    //为每个servlet取个别名
    //login --> com.yijiuju.learn.servlet.LoginServlet
    private Map<String, String> servlet;
    //url --> login
    //  /log -->login
    //  login-->login
    private Map<String, String> mapping;


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

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

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

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

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

5.XML解析

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
    <servlet>
        <servlet-name>login</servlet-name>
        <servlet-class>com.yijiuju.learn.servlet.LoginServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>login</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>login</servlet-name>
        <url-pattern>/log</url-pattern>
    </servlet-mapping>


    <servlet>
        <servlet-name>reg</servlet-name>
        <servlet-class>com.yijiuju.learn.servlet.RegisterServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>reg</servlet-name>
        <url-pattern>/reg</url-pattern>
    </servlet-mapping>

</web-app>

webApp用来将解析XML文件,将url-->login-->到loginServlet类的全限定名,做成映射关系

package com.yijiuju.learn.server;

import com.yijiuju.learn.servlet.Servlet;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.util.List;
import java.util.Map;


public class WebApp {
    private static ServletContext context;
    static {

        //1.获取解析工厂
                   SAXParserFactory factory = SAXParserFactory.newInstance();
        //2.获取解析器
                  SAXParser sax = null;
        try {
            sax = factory.newSAXParser();
            //指定XML+处理器
                            WebHandler handler = new WebHandler();
            sax.parse(Thread.currentThread().
                    getContextClassLoader().
                    getResourceAsStream("WEB-INF/web"), handler); //java包下的相对路径

                           //list转成Map
            context = new ServletContext();
            // <url-pattern> <servlet-name>
            Map<String, String> mapping = context.getMapping();
            for (Mapping map : handler.getMappingList()) {
                List<String> urls = map.getUrlPattern();
                for (String url : urls) {
                    mapping.put(url, map.getName());
                }
            }

            context.getServlet();
             //<servlet-name>   <servlet-class>
            Map<String, String> servlet = context.getServlet();
            for (Entity entity : handler.getEntityList()) {
                servlet.put(entity.getName(), entity.getClz());
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    //url--->login-->类的全限定名com.yijiuju.learn.servlet.LoginServlet,通过反射-->LoginServlet
    public static Servlet getServlet(String url) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        if (null == url || (url = url.trim()).equals("")) {
            return null;
        }
        //根据字符串(完整路径)创建对象
        String name = context.getServlet().get(context.getMapping().get(url));
        return (Servlet) Class.forName(name).newInstance(); //确保空构造存在
    }
}

处理器

package com.yijiuju.learn.server;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import java.util.ArrayList;
import java.util.List;

public class WebHandler extends DefaultHandler {
    private List<Entity> entityList;
    private List<Mapping> mappingList;
    private Entity entity;
    private Mapping mapping;
    private String beginTag;
    private boolean isMap;

    public List<Entity> getEntityList() {
        return entityList;
    }

    public void setEntityList(List<Entity> entityList) {
        this.entityList = entityList;
    }

    public List<Mapping> getMappingList() {
        return mappingList;
    }

    public void setMappingList(List<Mapping> mappingList) {
        this.mappingList = mappingList;
    }

    @Override
    public void startDocument() throws SAXException {
       //文档解析开始
        entityList = new ArrayList<>();
        mappingList = new ArrayList<>();
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        //开始元素
        if (null != qName) {
            beginTag = qName;
            if (qName.equals("servlet")) {
                isMap = false;
                entity = new Entity();

            } else if (qName.equals("servlet-mapping")) {
                isMap = true;
                mapping = new Mapping();
            }
        }
    }
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        //处理内容
        if (null != beginTag) {
            String str = new String(ch, start, length);
            if (isMap) {
                if (beginTag.equals("servlet-name")) {
                    mapping.setName(str);
                } else if (beginTag.equals("url-pattern")) {
                    mapping.getUrlPattern().add(str);
                }

            } else {
                if (beginTag.equals("servlet-name")) {
                    entity.setName(str);
                } else if (beginTag.equals("servlet-class")) {
                    entity.setClz(str);

                }

            }

        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        //结束元素
        if (null != qName) {
            if (qName.equals("servlet")) {
                entityList.add(entity);

            } else if (qName.equals("servlet-mapping")) {
                mappingList.add(mapping);
            }
        }

        beginTag = null;
    }

    @Override
    public void endDocument() throws SAXException {
        //文档解析结束
    }

}

package com.yijiuju.learn.server;

/*
   <servlet>
        <servlet-name>login</servlet-name>
        <servlet-class>cn.hyy.test.net.httpServer.server4.LoginServlet</servlet-class>
    </servlet>

* */
public class Entity {
    private String name;
    private String clz;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getClz() {
        return clz;
    }

    public void setClz(String clz) {
        this.clz = clz;
    }
}
package com.yijiuju.learn.server;

import java.util.ArrayList;
import java.util.List;

/*
*  <servlet-mapping>
        <servlet-name>login</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>login</servlet-name>
        <url-pattern>/log</url-pattern>
    </servlet-mapping>

    一对多
* */
public class Mapping {

    private String name;
    private List<String> urlPattern;

    public Mapping() {
        urlPattern = new ArrayList<>();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<String> getUrlPattern() {
        return urlPattern;
    }

    public void setUrlPattern(List<String> urlPattern) {
        this.urlPattern = urlPattern;
    }
}

package com.yijiuju.learn.util;

import java.io.Closeable;
import java.io.IOException;

/*
* 关闭流的方法
* */
public class CloseUtil {

    public static void closeAll(Closeable...io) {
        for (Closeable temp : io) {
            if (null != temp) {
                try {
                    temp.close();
                } catch (IOException e) {
                    //e.printStackTrace();

                }
            }
        }

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值