简单web服务器

回忆socket

创建客服端(在httpClient_1包下)

  1. public class Client {
       public static void main(String[] args) {
           //1.创建socket对象
           Socket client=null;

           DataOutputStream dos = null;
           DataInputStream dis =null;
           try {
               client = new Socket("localhost", 8888);
               //2.获取输出流请求
               dos = new DataOutputStream(client.getOutputStream());
               dos.writeUTF("我是客服端:服务器你好!");
               //3.获取输出流响应
               dis = new DataInputStream(client.getInputStream());
               System.out.println(dis.readUTF());
          } catch (IOException e) {
               e.printStackTrace();
          } finally {
               //4.关闭流
               IOClose.closeAll(dis,dos,client);
          }


      }

创建IOClose类

  1. public class IOClose {
       //关闭全部的工具类
       public static void closeAll(Closeable...c){
           for (Closeable closeable : c) {
               if (closeable!=null){
                   try {
                       closeable.close();
                  } catch (IOException e) {
                       e.printStackTrace();
                  }
              }
          }

创建服务端(在httpserver_1包下)

  1. package com.feng.server;

    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;

    public class Server {
       public static void main(String[] args) {
           //1.创建ServerSocket对象
           ServerSocket server = null;
           Socket client =null;
           DataInputStream dis =null;
           DataOutputStream dos =null;
           try {
               server = new ServerSocket(8888);
               //2.监听是否有客服端发送请求
               client = server.accept();
               //3.获取Socket对象
               //4.获取输入流 ->得到客服端的请求
               dis = new DataInputStream(client.getInputStream());
               System.out.println(dis.readUTF());
               //5.获取输出流 ->给客服端响应结果
               dos = new DataOutputStream(client.getOutputStream());
               dos.writeUTF("客服端你好,我是服务器,我接受到了你的信息");
          } catch (IOException e) {
               e.printStackTrace();
          } finally {
               IOClose.closeAll(dos,dis,client,server);
          }

同样创建IOClose

在CS结构server(2)

  1. package com.feng.server;

    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;

    public class Server2 {
       public static void main(String[] args) {
           //1.创建ServerSocket对象
           ServerSocket server = null;
           Socket client =null;

           BufferedReader br = null;
           try {
               server = new ServerSocket(8888);
               //2.监听是否有客服端发送请求
               client = server.accept();
               //获取来自浏览器的请求信息
               br = new BufferedReader(new InputStreamReader(client.getInputStream(), "utf-8"));
               String str=null;
               while ((str=br.readLine()).length()>0) {
                   System.out.println(str);
              }
          } catch (IOException e) {
               e.printStackTrace();
          } finally {
               IOClose.closeAll(br,client,server);
          }
      }
    }

创建HTML

  1. <!DOCTYPE html>
    <html lang="en">
    <head>
       <meta charset="UTF-8">
       <title>javaWeb</title>
    </head>
    <body>
       <h1>HelloWorld</h1>
       <form action="http://localhost:8888/index.html" method="post">
           <p>用户名:<input type="text" id="uname" name="username"></p>
           <p>密码:<input type="password" id="pwd" name="password"></p>
           <p><input type="submit" value="登入"/></p>
       </form>
    </body>
    </html>

创建server3

获取来自浏览器的请求信息

  1. //获取来自浏览器的请求信息
    is = client.getInputStream();
    byte[] buf = new byte[20480];
    int len = is.read(buf);
    System.out.println(new String(buf,0,len));

对web浏览器做出响应

添加参数

  1. String CRLF="\r\n";
    String BLANK=" ";
    InputStream is = null;
  1. /**对web浏览器做出响应*/
    StringBuilder sb = new StringBuilder();
    StringBuilder sbContent = new StringBuilder(); //响应的文本
    sbContent.append("<html><head><title>响应结果</title></head>");
    sbContent.append("<body>登入成功</body></html>");

    //1拼接响应头
    sb.append("HTTP/1.1").append(BLANK).append(200).append(BLANK).append("OK");
    sb.append(CRLF);
    sb.append("Content-Type: text/html;charset=UTF-8");
    sb.append(CRLF);
    sb.append("Content-Length:").append(sbContent.toString().getBytes().length).append(CRLF);
    sb.append(CRLF);//带表响应头与响应正文部分之间的换行
    sb.append(sbContent);
    //2通过输出流
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream(),"UTF-8"));
    bw.write(sb.toString());
    bw.flush();
    bw.close();

整合server3

  1. public class Server3 {
       public static void main(String[] args) {
           //1.创建ServerSocket对象
           ServerSocket server = null;
           Socket client =null;
           String CRLF="\r\n";
           String BLANK=" ";
           InputStream is = null;
           try {
               server = new ServerSocket(8888);
               //2.监听是否有客服端发送请求
               client = server.accept();
               //获取来自浏览器的请求信息
               is = client.getInputStream();
               byte[] buf = new byte[20480];
               int len = is.read(buf);
               System.out.println(new String(buf,0,len));
               /**对web浏览器做出响应*/
               StringBuilder sb = new StringBuilder();
               StringBuilder sbContent = new StringBuilder(); //响应的文本
               sbContent.append("<html><head><title>响应结果</title></head>");
               sbContent.append("<body>登入成功</body></html>");

               //1拼接响应头
               sb.append("HTTP/1.1").append(BLANK).append(200).append(BLANK).append("OK");
               sb.append(CRLF);
               sb.append("Content-Type: text/html;charset=UTF-8");
               sb.append(CRLF);
               sb.append("Content-Length:").append(sbContent.toString().getBytes().length).append(CRLF);
               sb.append(CRLF);//带表响应头与响应正文部分之间的换行
               sb.append(sbContent);
               //2通过输出流
               BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream(),"UTF-8"));
               bw.write(sb.toString());
               bw.flush();
               bw.close();
          } catch (IOException e) {
               e.printStackTrace();
          } finally {
               //6.关闭流
               IOClose.closeAll(is,client,server);
          }


      }
    }

手写服务器 整体架构,编写XML文件

创建Request,Response,Server,WebApp(在server包下)

创建Servlet,LoginServlet(在servlet包下)

创建IOCloseUtil(在util包下)

创建web.xml(在WEB_INFO包下)

  1. <?xml version="1.0" encoding="UTF-8"?>
    <web-app >
       <servlet>
           <servlet-name>login</servlet-name>
           <servlet-class>com.feng.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>

    </web-app>

创建Entity,Mapping,ServletContext,WebDom4j,创建IOClose在util包下

配置解析XML文件

补充实体类

  1. package com.feng.server;

    public class Entity {  //servlet-name或每一个servlet-name所对应得实体类
       private String name;
       private String clazz;

       public Entity() {
      }

       public Entity(String name, String clazz) {
           this.name = name;
           this.clazz = clazz;
      }

       public String getName() {
           return name;
      }

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

       public String getClazz() {
           return clazz;
      }

       public void setClazz(String clazz) {
           this.clazz = clazz;
      }
    }

补充Mapping类

  1. package com.feng.server;

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

    public class Mapping { //映射关系,多个路径可以访问资源
       private String name; //servlet-name
       private List<String> urlPattern;//url-pattern

       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;
      }

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

       public Mapping(String name, List<String> urlPattern) {
           this.name = name;
           this.urlPattern = urlPattern;
      }
    }

配置dom4j

  1. package com.feng.server;

    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.Element;
    import org.dom4j.io.SAXReader;

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

    public class WebDom4j { //用于解析xml
       private List<Entity> entityList; //用于储存实体类,每一个实体类一个servlet-name对应一个servlet-class
       private List<Mapping> mappingList;//用于储存映射类,每一个servlet-name对应一个url-pattern
    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;
    }

    //构造方法
    public WebDom4j() {
       entityList = new ArrayList<Entity>();
       mappingList = new ArrayList<Mapping>();
    }

    //获取Document对象的方法
    public Document getDocument(){

       try {
           //创建SAXReader对象
           SAXReader reader = new SAXReader();
           //调用read方法
           return reader.read(new File("web/WEB-INF/web.xml"));
      } catch (DocumentException e) {
           e.printStackTrace();
      }
       return null;
    }
    //获取元素
    public void parse(Document doc) {
       //1获取根元素
       Element root = doc.getRootElement(); //web-app
       //2获取servlet子元素
       for (Iterator<Element> ite = root.elementIterator("servlet"); ite.hasNext();) {
           Element subElement = ite.next(); //得到每一个servlet
           //创建一个实体类
           Entity ent = new Entity(); //用于储存servlet-name与servlet-class
           for (Iterator<Element> subIte = subElement.elementIterator(); subIte.hasNext();) {
               Element ele = subIte.next(); //servlet-name与servlet-class都有可能
               if ("servlet-name".equals(ele.getName())) {
                   ent.setName(ele.getText());
              } else if ("servlet-class".equals(ele.getName())) {
                   ent.setClazz(ele.getText());
              }
          }
           entityList.add(ent);//放到集合中
      }
       //测试
      /* for (Entity entity : entityList) {
           System.out.println(entity.getName() + "\t" + entity.getClazz());
       }*/

       //解析servlet-mapping

       for (Iterator<Element> ite = root.elementIterator("servlet-mapping"); ite.hasNext();){
           Element subEle = ite.next();//得到每一个servlet-mapping
           //创建一个mapping对象
           Mapping map = new Mapping();
           //解析mapping下面每一个子元素
           for (Iterator<Element> subIte = subEle.elementIterator(); subIte.hasNext();){
               Element ele = subIte.next();//可能是name,也可能是url
               if ("servlet-name".equals(ele.getName())) {
                   map.setName(ele.getText());
              } else if ("url-pattern".equals(ele.getName())) {
                   //获取集合对象,调用集合对象的添加方法,添加元素
                   map.getUrlPattern().add(ele.getText());
              }
          }
           mappingList.add(map);

      }
       //测试
       /*for (Mapping m : mappingList) {
           System.out.println(m.getName());
           for (String s : m.getUrlPattern()) {
               System.out.println(s);
           }
       }*/
    }

    //用于测试
       public static void main(String[] args) {
           WebDom4j web = new WebDom4j();
           web.parse(web.getDocument());
      }
    }

更新编写XML

  1. <?xml version="1.0" encoding="UTF-8"?>
    <web-app>
       <servlet>
           <servlet-name>login</servlet-name>
           <servlet-class>com.feng.servlet.LoginServlet</servlet-class>
       </servlet>
       <servlet-mapping>
           <servlet-name>login</servlet-name>
           <url-pattern>/log</url-pattern>
           <url-pattern>/login</url-pattern>
       </servlet-mapping>
       <servlet>
           <servlet-name>register</servlet-name>
           <servlet-class>com.feng.servlet.RegisterServlet</servlet-class>
       </servlet>
       <servlet-mapping>
           <servlet-name>register</servlet-name>
           <url-pattern>/reg</url-pattern>
           <url-pattern>/regis</url-pattern>
           <url-pattern>/register</url-pattern>
       </servlet-mapping>
     
    </web-app>

编写servletContext Servlet 上下文,容器用于存储映射关系

  1. package com.feng.server;

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

    /**
    *ServletContext 上下文 就是一个容器

    */
    public class ServletContext { //Entity与Mapping之间的映射关系
        private Map<String, String> servlet;//key是servlet-name(实体类中的name),值servlet-class,实体类中的值
        private Map<String, String> mapping;//key是url-pattern(Map中的每一个元素),值servlet-name,实体类中的name

    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;
    }

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

编写WebAPP 初始化程序数据

  1. package com.feng.server;

    import com.feng.servlet.Servlet;

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

    public class WebApp {  //应用程序
       private static ServletContext context;
       static {
           context = new ServletContext();
           //分别获取对应关系的Map集合
           Map<String, String> servlet = context.getServlet();
           Map<String, String> mapping = context.getMapping();
           //创建解析XML文件对象
           WebDom4jTest web = new WebDom4jTest();
           //解析xml
           web.parse(web.getDocument());
           //获取解析xml之后的List集合
           List<Entity> entityList = web.getEntityList();
           List<Mapping> mappingList = web.getMappingList();

           //将List集合储存到map集合中
           for (Entity entity : entityList) {
               servlet.put(entity.getName(),entity.getClazz());
          }
           //System.out.println(servlet);
           for (Mapping map : mappingList) {
               //遍历url-pattern的集合
               List<String> urlPattern = map.getUrlPattern();
               for (String s : urlPattern) {
                   mapping.put(s,map.getName());
              }
          }
           //System.out.println(mapping);
      }

       /*
       * 根据url创建不同的Servlet对象
       * */
       public static Servlet getServlet(String url){
           if (url ==null||url.trim().equals("")){
               return null;
          }
           try {
           //如果url正确
           //根据url的key获取servlet-name的值
           String servletName = context.getMapping().get(url);
           //根据servlet-name找到对应得servlet-class
           String servletClass = context.getServlet().get(servletName);
           //得到的是一个完整的包+类名的字符串

           //使用反射创建servlet对象
           Class<?> clazz = Class.forName(servletClass);
           Servlet servlet = (Servlet) clazz.newInstance();
           return servlet;
          } catch (ClassNotFoundException e) {
               e.printStackTrace();
          } catch (InstantiationException e) {
               e.printStackTrace();
          } catch (IllegalAccessException e) {
               e.printStackTrace();
          }
           return null;
      }
       public static void main(String[] args) {
           System.out.println(getServlet("/log"));
           System.out.println(getServlet("/login"));
      }
    }

编写服务


  1. public class Server { //服务器,用于启动或停止服务
       private ServerSocket server;

       public static void main(String[] args) {
           Server server = new Server();//创建服务器
           server.start();
      }

       private void start() {
           this.start(8888);
      }

       public void start(int port){
           try {
               server = new ServerSocket(port);
               this.receive();//调用接受请求的方式
          } catch (IOException e) {
               e.printStackTrace();
          }
      }

       private void receive() {

           try {
             
                   //1监听
                   Socket client = server.accept();
                   //创建线程类
                   Dispatcher dis = new Dispatcher(client);
                   //创建代理线程
                   new Thread(dis).start();
               
               //获取用户的请求
               /**InputStream is = client.getInputStream();
               byte[] buf = new byte[20480];
               int len = is.read(buf);
               System.out.println(new String(buf, 0, len));*/
                //封装请求信息
               Request req = new Request(client.getInputStream());
               req.show();
             
          } catch (IOException e) {
               e.printStackTrace();
          }

      }
       public void stop(){

      }
    }

编写Request

  1. package com.feng.server;

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

    public class Request { //请求

       //输入流
       private InputStream is;
       private String requestInfo; //请求字符串,请求方式,请求路径,参数,协议,协议版本,请求正文。。
       private String method;//请求的方式
       private String url;//请求的路径

       public String getUrl() {
           return url;
      }

       /*
       * 输入框的name为key,值为value
       * */
       private Map<String, List<String>> parameterMapValues;//参数
       private static final String CRLF="\r\n";//换行
       private static final String BLANK =" ";//空格
       //构造方法,初始化属性
       public Request(){
           parameterMapValues=new HashMap<String, List<String>>();
           method="";
           url="";
           requestInfo="";
      }
       public Request(InputStream is){
           this();//调用本类无参构造方法
           this.is=is;

           try {
               byte[] buf = new byte[20480];
               int len = this.is.read(buf);
               requestInfo = new String(buf, 0, len);
          } catch (IOException e) {
               return;
          }
           //调用本类中的分解信息的方法
           this.parseRequestInfo();
      }
       //分解请求信息的方法
       /**
       * 请求方式
       * 请求路径
       * 请求的参数
       * */
       public void parseRequestInfo() {
           String paraString="";//用于存储请求参数
           //获取参数的第一行
           String firstLine = requestInfo.substring(0, requestInfo.indexOf(CRLF)).trim();//从0开始到第一个换行的位置
           //分解出请求方式
           int index = firstLine.indexOf("/");
           this.method = firstLine.substring(0, index).trim();
           //分解url ,get可能包含的参数,也可能不包含的参数post
           String urlString = firstLine.substring(index, firstLine.indexOf("HTTP/")).trim();
           //判断请求方式是GET或POST
           if ("get".equalsIgnoreCase(this.method)) {   //包含请求参数
               if (urlString.contains("?")){
                   String[] urlArray = urlString.split("\\?");
                   this.url=urlArray[0];
                   paraString=urlArray[1];
              }else {
                   this.url=urlString;
              }
          }else {//post不包含请求参数
               this.url=urlString;
               paraString=requestInfo.substring(requestInfo.lastIndexOf(CRLF)).trim();
            }
           if (paraString.equals("")){
               return;
          }
           //请求参数
           System.out.println(paraString);
         
      }
       //用于测试
       public void show(){
           System.out.println(this.url);
           System.out.println(this.method);
      }

     
    }

编写login.html

  1. <!DOCTYPE html>
    <html lang="en">
    <head>
       <meta charset="UTF-8">
       <title>登入</title>
    </head>
    <body>
       <form action="http://localhost:8888/log" method="post">
           <p>用户名:<input type="text" name="username" id="username"></p>
           <p>密码:<input type="password" name="pwd" id="password"></p>
           <p>
              爱好:<input type="checkbox" name="hobby" value="ball"/>足球
                    <input type="checkbox" name="hobby" value="read"/>读书
                   <input type="checkbox" name="hobby" value="paint"/>画画
           </p>
           <p><input type="submit" value="登入"></p>
       </form>
    </body>
    </html>

储存参数,处理中文

  1. /**
      *username = admin
       * pwd = 123
       * hobby =ball
       * hobby = paint
       * */
      public void parseParam(String prarString){
          String[] token = prarString.split("&");
          for (int i=0;i<token.length;i++){
              String keyValues = token[i];
              String[] keyValue = keyValues.split("=");//把=分割掉,得到K和V
              if (keyValue.length==1){   //username=
                  keyValue = Arrays.copyOf(keyValue, 2);
                  keyValue[1] = null;
              }
              //将表单中的元素的name与name对应的值储存到Map集合
              String key = keyValue[0].trim();
              String value = keyValue[1]==null?null:decode(keyValue[1].trim(),"utf-8");
              //放到集合中存储
              if (!parameterMapValues.containsKey(key)) {  //键不存在就创建
                  parameterMapValues.put(key,new ArrayList<String>());
              }
              List<String> values = parameterMapValues.get(key);
              values.add(value); //创建一个集合添加值
          }

      }
       //根剧表单元素的name获取多个值
       public String [] getParamterValues(String name) {
          //根据key获取value
           List<String> values = parameterMapValues.get(name);
           if (values == null ){
               return null;
          } else {
               return values.toArray(new String[0] );
          }
      }
       public String getParamter(String name){
          //调用本类中根据name获取单个值的方法
           String[] values = this.getParamterValues(name);
           if (values ==null){
               return null;
          } else {
               return values[0];
          }
      }
        //处理中文,因浏览器对中文进行了编码,进行解码
           private String decode(String value,String code){
               try {
                   return URLDecoder.decode(value,code);
              } catch (UnsupportedEncodingException e) {
                   e.printStackTrace();
              }
               return null;
          }
     

       public static void main(String[] args) {
           Request req = new Request();
           //调用分解参数的方法
           req.parseParam("username=中文加密&pwd=123&hobby=ball&hobby=read");
           System.out.println(req.parameterMapValues);

           //调用获取多个值的方法
           String[] str = req.getParamterValues("hobby");
           for (String string : str) {
               System.out.println(string);
          }
           //调用单个获取值的方法
           System.out.println(req.getParamter("pwd"));
      }

加到Server类中,测试响应

  1.  //封装请求信息
               Request req = new Request(client.getInputStream());
               //req.show();
               /**
                * 做出响应
                * */
               StringBuilder sb = new StringBuilder();
               sb.append("HTTP/1.1").append(" ").append(200).append(" ").append("OK").append("\r\n");
               sb.append("Content-Type:text/html;charset=utf-8").append("\r\n");
               //内容
               String str = "<html><head><title>响应结果</title></head><body>成功</body></html>";
               sb.append("Content-Length:"+str.getBytes("utf-8").length).append("\r\n");
               sb.append("\r\n");
               sb.append(str);

               //通过输出流发送出去
               BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream(),"utf-8"));
               bw.write(sb.toString());
               bw.flush();
               bw.close();

编写Response

  1. package com.feng.server;
    import com.feng.util.IOCloseUtil;
    import java.io.*;

    public class Response { //响应
       private StringBuilder headInfo;  //响应头
       private StringBuilder content; //响应内容
       private int length; //响应内容的长度

       //流
       private BufferedWriter bw;

       //两个常量,换行和空格
       private static final String CRLF="\r\n";  //换行
       private static final String BLANK=" ";  //空格

       //构造方法
       public Response() {
           headInfo= new StringBuilder();
           content = new StringBuilder();
      }
       //带构造方法

       public Response(OutputStream os) {
           this();//调用本类的无参构造方法
           try {
               bw = new BufferedWriter(new OutputStreamWriter(os,"utf-8"));
          } catch (UnsupportedEncodingException e) {
               e.printStackTrace();
          }
      }
       //构造正文部分
       public Response print(String info){
           content.append(info);
           try {
               length+= info.getBytes("utf-8").length;
          } catch (UnsupportedEncodingException e) {
               e.printStackTrace();
          }
           return this;
      }
       public Response printLn(String info){
           content.append(info).append(CRLF);
           try {
               length+=(info+CRLF).getBytes("utf-8").length;
          } catch (UnsupportedEncodingException e) {
               e.printStackTrace();
          }
           return this;
      }

       //构造响应头
       private void createHeadInfo(int code){
           headInfo.append("HTTP/1.1").append(BLANK).append(code).append(BLANK);
           switch (code){
               case 200:
                   headInfo.append("OK");
                   break;
               case 500:
                   headInfo.append("SERVER ERROR");
               default:
                   headInfo.append("NOT FOUND");
                   break;
          }
           headInfo.append(CRLF);
           headInfo.append("Content-Type:text/html;charset=utf-8").append(CRLF);
           headInfo.append("Content-Length:"+length).append(CRLF);
           headInfo.append(CRLF);
      }

       /**
        * 推送到客户机的浏览器
        * */
       public void pushToClient(int code){
           if (headInfo==null){
               code=500;
          }
           //调用本类中的构造响应头
           this.createHeadInfo(code);
           try {
               bw.write(headInfo.toString());
               bw.write(content.toString());
               bw.flush();
               this.close();
          } catch (IOException e) {
               e.printStackTrace();
          }

      }

       public void close() {
           IOCloseUtil.closeAll(bw);
      }
    }

然后再把Server里面做出响应那段代码注释掉

  1. package com.feng.server;

    import com.feng.servlet.Servlet;
    import com.feng.util.IOCloseUtil;

    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStreamWriter;
    import java.net.ServerSocket;
    import java.net.Socket;

    public class Server { //服务器,用于启动或停止服务
       private ServerSocket server;
     
       public static void main(String[] args) {
           Server server = new Server();//创建服务器
           server.start();
      }

       private void start() {
           this.start(8888);
      }

       public void start(int port){
           try {
               server = new ServerSocket(port);
               this.receive();//调用接受请求的方式
          } catch (IOException e) {
                e.printStackTrace();
          }
      }

       private void receive() {

           try {
               //1监听
               Socket client = server.accept();
               //创建线程类
               Dispatcher dis = new Dispatcher(client);
               //创建代理线程
               new Thread(dis).start();
               
               //获取用户的请求
              /* InputStream is = client.getInputStream();
               byte[] buf = new byte[20480];
               int len = is.read(buf);
               System.out.println(new String(buf, 0, len));*/
              //封装请求信息
               Request req = new Request(client.getInputStream());
               //req.show();
               /**
                * 做出响应
                * */
               /*StringBuilder sb = new StringBuilder();
               sb.append("HTTP/1.1").append(" ").append(200).append(" ").append("OK").append("\r\n");
               sb.append("Content-Type:text/html;charset=utf-8").append("\r\n");
               //内容
               String str = "<html><head><title>响应结果</title></head><body>成功</body></html>";
               sb.append("Content-Length:"+str.getBytes("utf-8").length).append("\r\n");
               sb.append("\r\n");
               sb.append(str);

               //通过输出流发送出去
               BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream(),"utf-8"));
               bw.write(sb.toString());
               bw.flush();
               bw.close();*/
               Response rep = new Response(client.getOutputStream());
               Servlet servlet = WebApp.getServlet(req.getUrl());
               int code=200;
               if (servlet ==null){
                   code=404;
              }
               //调用Servlet中的服务方法
               try {
                   servlet.service(req,rep);
              } catch (Exception e) {
                   e.printStackTrace();
              }
               rep.pushToClient(code);
               IOCloseUtil.closeAll(client);  //单线程已被删除
          } catch (IOException e) {
               e.printStackTrace();
          }

      }
       public void stop(){

      }
    }

封装Response

编写servlet

  1. public abstract class Servlet { //是所有请求servlet的父类
       public void service(Request req, Response rep) throws Exception {
           this.deGet(req,rep);
           this.doPost(req,rep);
      }

       public abstract void deGet(Request req, Response rep) throws Exception;
       public abstract void doPost(Request req, Response rep) throws Exception;

    }

编写LoginServlet

  1. public class LoginServlet extends Servlet {
       @Override
       public void deGet(Request req, Response rep) throws Exception {
           //获取请求参数
           String name = req.getParamter("username");
           String pwd = req.getParamter("pwd");

           if (this.login(name,pwd)) {
               //调用响应中的构建内容的方法
               rep.printLn(name+"登入成功");
          }else {
               rep.printLn(name+"登录失败,对不起,账号和密码不准确");
          }
      }
       private boolean login(String name,String pwd){
           if ("admin".equals(name)&&"123".equals(pwd)) {
               return true;
          }
           return false;
      }

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

      }
    }

封装分发器,实现多线程

  1. package com.feng.server;

    import com.feng.servlet.Servlet;
    import com.feng.util.IOCloseUtil;

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

    /**
    * 一个请求与响应就是一个Dispatcher
    *
    * @author asus
    * */
    public class Dispatcher implements Runnable {
       private Request req;
       private Response rep;
       private Socket client;
       private int code =200;//状态码

       //构造方法初始化属性

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

      }

       @Override
       public void run() {
           //根据不同的url创建指定的servlet对象
           Servlet servlet = WebApp.getServlet(req.getUrl());
           if (servlet==null){
               this.code=404;
          }else {
               //调用响应的servlet中service方法
               try {
                   servlet.service(req,rep);
              } catch (Exception e) {
                   this.code=500;
              }
          }
           //将有响应的结果推送到客户端的浏览器
           rep.pushToClient(code);
           IOCloseUtil.closeAll(client);
      }
    }

实现多线程

  1. package com.feng.server;

    import com.feng.servlet.Servlet;
    import com.feng.util.IOCloseUtil;

    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStreamWriter;
    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.start();
      }

       private void start() {
           this.start(8888);
      }

       public void start(int port){
           try {
               server = new ServerSocket(port);
               this.receive();//调用接受请求的方式
          } catch (IOException e) {
               isShutDown=true;
          }
      }

       private void receive() {

           try {
               while (!isShutDown){
                   //1监听
                   Socket client = server.accept();
                   //创建线程类
                   Dispatcher dis = new Dispatcher(client);
                   //创建代理线程
                   new Thread(dis).start();
              }
             
          } catch (IOException e) {
               e.printStackTrace();
          }

      }
       public void stop(){
    isShutDown=true;
    IOCloseUtil.closeAll(server);
      }
    }

可能会出现空指针异常

缺少favicon映射类,在xml里面配置

  1. <?xml version="1.0" encoding="UTF-8"?>
    <web-app>
       <servlet>
           <servlet-name>login</servlet-name>
           <servlet-class>com.feng.servlet.LoginServlet</servlet-class>
       </servlet>
       <servlet-mapping>
           <servlet-name>login</servlet-name>
           <url-pattern>/log</url-pattern>
           <url-pattern>/login</url-pattern>
       </servlet-mapping>
       <servlet>
           <servlet-name>register</servlet-name>
           <servlet-class>com.feng.servlet.RegisterServlet</servlet-class>
       </servlet>
       <servlet-mapping>
           <servlet-name>register</servlet-name>
           <url-pattern>/reg</url-pattern>
           <url-pattern>/regis</url-pattern>
           <url-pattern>/register</url-pattern>
       </servlet-mapping>
       <servlet>
           <servlet-name>favicon</servlet-name>
           <servlet-class>com.feng.servlet.FaviconServlet</servlet-class>
       </servlet>
       <servlet-mapping>
           <servlet-name>favicon</servlet-name>
           <url-pattern>/favicon.ico</url-pattern>
       </servlet-mapping>

    </web-app>

添加FaviconServlet

  1. package com.feng.servlet;

    import com.feng.server.Request;
    import com.feng.server.Response;

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

      }

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

      }
    }

手写Javaweb服务器的更多相关文章

  1. JavaSE 手写 Web 服务器(二)

    原文地址:JavaSE 手写 Web 服务器(二) 博客地址:http://www.extlight.com 一.背景 在上一篇文章 <JavaSE 手写 Web 服务器(一)> 中介绍了 ...

  2. JavaSE 手写 Web 服务器(一)

    原文地址:JavaSE 手写 Web 服务器(一) 博客地址:http://www.extlight.com 一.背景 某日,在 Java 技术群中看到网友讨论 tomcat 容器相关内容,然后想到自 ...

  3. 黑马vue---40、结合Node手写JSONP服务器剖析JSONP原理

    黑马vue---40.结合Node手写JSONP服务器剖析JSONP原理 一.总结 一句话总结: 服务端可以返回js代码给script标签,那么标签会执行它,并且可带json字符串作为参数,这样就成功 ...

  4. 【项目】手写FTP服务器-C++实现FTP服务器

    X_FTP_server 手写FTP服务器-C++实现FTP服务器 项目Gitee链接:https://gitee.com/hsby/ftp_Server 简介 一个基于libevent的高并发FTP ...

  5. 手写Tomcat服务器

    预备知识 编写服务器用到的知识点 1) Socket 编程2) HTML3) HTTP 协议4) 反射5) XML 解析6) 服务器编写 Socket编程 https://www.cnblogs.co ...

  6. 利用html 5 websocket做个山寨版web聊天室(手写C#服务器)

    在之前的博客中提到过看到html5 的websocket后很感兴趣,终于可以摆脱长轮询(websocket之前的实现方式可以看看Developer Works上的一篇文章,有简单提到,同时也说了web ...

  7. MiniCat:手写Http服务器

    minicat 项目介绍 已实现http基础协议.参数接受.servlet.filter.cookie.多文件上传等.支持NIO. 一款轻量化Http服务器.支持bio.nio两种模式.归属Coody ...

  8. 手写网站服务器~用Python手动实现一个简单的服务器,不借助任何框架在浏览器中输出任意内容

    写在前面的一些P话: 在公司网站开发中,我们往往借助于Flask.Django等网站开发框架去提高网站开发效率.那么在面试后端开发工程师的时候,面试官可能就会问到网站开发的底层原理是什么? 我们不止仅 ...

  9. 自己手写http服务器 http响应信息的封装与测试

    package cn.edu.sss.httpServer; import java.io.BufferedWriter; import java.io.IOException; import jav ...

随机推荐

  1. Spring Boot 知识清单(一)SpringApplication

    爱生活,爱编码,微信搜一搜[架构技术专栏]关注这个喜欢分享的地方.本文 架构技术专栏 已收录,有各种JVM.多线程.源码视频.资料以及技术文章等你来拿. 一.概述 目前Spring Boot已经发展到 ...

  2. MySQL存储引擎入门介绍

    什么是MySQL? MySQL 是一种关系型数据库,在Java企业级开发中非常常用,因为 MySQL 是开源免费的,并且方便扩展.阿里巴巴数据库系统也大量用到了 MySQL,因此它的稳定性是有保障的. ...

  3. 【Django】将多个querysets拼接,使用djangorestframework序列化

    concern_set = models.Concern.objects.filter(user_id=1).values("concern_id") querysets = mo ...

  4. Centos-搜索文件或目录-find

    find 在指定的目录下查找指定的文件 相关选项 -type 指定文件类型 -name   指定文件名字,支持通配符 -gid   指定用户组ID -uid   指定用户ID -empty 查找长度为 ...

  5. PageObject课程培训记录

    前言 昨晚的培训课程讲了PO设计模式,对于PO模式我们需要去了解关于为什么要使用PO,而不使用PO是什么情况?什么是PO模式?PO怎么去使用? 第一,为什么要使用PO,而不使用PO是什么情况? 我们先 ...

  6. Python练习题 038:Project Euler 010:两百万以内所有素数之和

    本题来自 Project Euler 第10题:https://projecteuler.net/problem=10 # Project Euler: Problem 10: Summation o ...

  7. 13.深入k8s:Pod 水平自动扩缩HPA及其源码分析

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com 源码版本是1.19 Pod 水平自动扩缩 Pod 水平自动扩缩工作原理 Pod 水平自动 ...

  8. 【题解】[SDOI2015]星际战争

    \(\color{red}{Link}\) \(\text{Solution:}\) 观察到,如果一个时间\(T\)可以完成任务,则\(T+1\)这个时间也可以完成任务. 于是我们可以二分. 为了避免 ...

  9. 学习Jmeter,这一篇就够了

    Jmeter在软件测试中的常用功能,看完你应该就会了 1.Jmeter的下载安装 1.1  Jmeter的官方网址是:http://jmeter.apache.org/:下载最新的包到本地进行解压,路 ...

  10. node将js中的json对象生成到新的excel表中

    第一步  安装依赖包   npm install json2xls fs 第二步  创建node.js文件,文件内代码如下: var fs = require('fs'); var path = re ...