Java笔记-13 http服务器

文章目录

  • 反射入门
  • XML解析
    • 解析简单的xml文件
    • 解析webxml
  • html
  • http协议
  • 获取请求协议
  • 返回响应协议
  • 封装的响应

反射入门

  • 把java类中的各种结构(方法、属性、构造器、类名)映射成一个个的Java对象,利用反射技术可以对一个类进行剖析。框架设计常用反射
  • 可以通过字符串的方式或得类,创建对象
  • 获得Class对象Class.forName(“包名.类名”),
  • 使用无参构造器创建对象 (Iphone) classObj.getConstructor().newInstance();
package server.basic;

import java.lang.reflect.InvocationTargetException;

public class TestReflection {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        //获取Class对象 三种方式
        // 1 对象.getClass
        Iphone r = new Iphone();
        Class classObj = r.getClass();
        System.out.println(classObj);

        //2 类.class
        classObj = Iphone.class;

        //3 Class.forName("包名.类名")
        classObj = Class.forName("server.basic.Iphone");

        //解析Class对象
        //1 创建对象,java9不推荐
        Iphone t = (Iphone) classObj.newInstance();
        //2 创建对象的另一种方式,使用构造器,无参数构造器和带参数构造器
        Iphone iphone7 = (Iphone) classObj.getConstructor().newInstance();
        System.out.println(iphone7);
        iphone7 = (Iphone) classObj.getConstructor(double.class).newInstance(1000);
        System.out.println(iphone7);

    }
}

class Iphone{
    double price;
    public Iphone(){
    }
    public Iphone(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Price is "+price;
    }
}

XML解析

  • 可扩展标记语言
  • 解析方式SAX流解析、DOM文档解析树。

解析简单的xml文件

  • SAX解析示例,一个xml有person的标签,分别有name和age两个字段。将person作为类的对象放到容器中
  • xml示例文件
<?xml version="1.0" encoding="UTF-8" ?>
<persons>
    <person>
      <name>至尊宝</name>
      <age>9000</age>
   </person>
   <person>
      <name>白晶晶</name>
      <age>7000</age>
   </person>
</persons>
  • SAX解析
package server.basic;

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

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class TestXml1 {
    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        //1 获取解析工厂
        SAXParserFactory factory = SAXParserFactory.newInstance();
        //2 从解析工厂获取解析器
        SAXParser parse = factory.newSAXParser();
        //3 编写处理器

        //4 加载文档Document注册处理器
        PersonHandler handler = new PersonHandler();
        //5 解析server/basic/p.xml
        String xmlPath = "src/main/java/server/basic/p.xml";
        FileInputStream fis = new FileInputStream(xmlPath);
        parse.parse(fis,handler);

        List<Person> persons = handler.getPersons();
        for(Person p:persons){
            System.out.println(p.getName()+"--->"+p.getAge());
        }
    }
}

class PersonHandler extends DefaultHandler{
    private List<Person> persons; //多个Person的容器
    private Person person;
    private String tag; //当前操作的标签
    @Override  //开始解析xml文档
    public void startDocument() throws SAXException {
        System.out.println("开始解析");
        persons = new ArrayList<Person>(); //初始化容器
    }

    @Override  //开始解析元素,qName是标签名称
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        System.out.println(qName+"解析开始");
        if(null != qName){  //保存tag
            tag = qName;
            if(tag.equals("person")){  //如果是person标签就创建person对象
                person = new Person();
            }
        }
    }

    @Override //读取内容
    public void characters(char[] ch, int start, int length) throws SAXException {
        String str = new String(ch,start,length).trim();
//        if(str.length()>0) {
//            System.out.println("内容为----->" + str.trim());
//        }else {
//            System.out.println("内容为空---");
//        }
        if(tag != null) {
            if (tag.equals("name")) {
                person.setName(str);
            } else if (tag.equals("age")) {
                person.setAge(Integer.valueOf(str));
            }
        }
    }

    @Override //结束解析元素
    public void endElement(String uri, String localName, String qName) throws SAXException {
        System.out.println(qName+"解析结束");
        if(qName != null){
            if(qName.equals("person")){  //如果再次碰到person标签就添加到容器中
                persons.add(person);
            }
        }
        tag = null; //解析完成为了防止后一个标签的空格的影响,将tag赋值为null
    }

    @Override //结束解析文档
    public void endDocument() throws SAXException {
        System.out.println("解析结束");;
    }

    //获取存数据的容器
    public List<Person> getPersons() {
        return persons;
    }
}


class Person{
    private String name;
    private int age;

    public Person(){
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

解析webxml

  • 根据不同的pattern找到对应的类.servlet-mapping的url-pattern为网址的后缀,根据这个找到servlet-name,再根据servlet-name找到servlet下的servlet-class标签里的包.类名,再利用反射根据这个类创建对象,执行相应的操作
  • web.xml文件
  
 <web-app>
     <servlet>
        <servlet-name>loginservlet-name>
        <servlet-class>server.basic2.LoginServletservlet-class>
     servlet>
     <servlet>
        <servlet-name>regservlet-name>
        <servlet-class>server.basic2.RegisterServletservlet-class>
     servlet>

    <servlet-mapping>
        <servlet-name>loginservlet-name>
        <url-pattern>/loginurl-pattern>
        <url-pattern>/gurl-pattern>
    servlet-mapping>
    <servlet-mapping>
        <servlet-name>regservlet-name>
        <url-pattern>/regurl-pattern>
    servlet-mapping>
web-app>
  • Entity.java。对应servlet
package server.basic2;

/**
 *      
 *         login
 *         com.sxt.server.basic.servlet.LoginServlet
 *      
 */
public class Entity {
    private String name;
    private String clz;
    public Entity(){
    }

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

  • Mapping.java对应xml中的servlet-mapping,pattern可能有多个,因此pattern放到集合中
package server.basic2;

import java.util.HashSet;
import java.util.Set;

public class Mapping {
    private String name;
    private Set<String> patterns;
    public Mapping(){
        patterns = new HashSet<>();
    }

    public String getName() {
        return name;
    }

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

    public Set<String> getPatterns() {
        return patterns;
    }

    public void setPatterns(Set<String> patterns) {
        this.patterns = patterns;
    }

    public void addPattern(String pattern){
        this.patterns.add(pattern);
    }
}
  • TestXml2.java负责解析xml并完成响应,主要
package server.basic2;

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

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class TestXml2 {
    public static void main(String[] args) throws Exception {
        //1 获取解析工厂
        SAXParserFactory factory = SAXParserFactory.newInstance();
        //2 从解析工厂获取解析器
        SAXParser parse = factory.newSAXParser();
        //3 编写处理器

        //4 加载文档Document注册处理器
        WebHandler handler = new WebHandler();
        //5 解析server/basic/p.xml
        String xmlPath = "src/main/java/server/basic2/web.xml";
        FileInputStream fis = new FileInputStream(xmlPath);
        parse.parse(fis,handler);

        List<Entity> entities  = handler.getEntities();
        List<Mapping> mappings = handler.getMappings();
        //打印内容
        for(Entity p:entities){
            System.out.println(p.getName()+"--->"+p.getClz());
            //login--->server.basic2.LoginServlet
            //reg--->server.basic2.RegisterServlet
        }

        for(Mapping m:mappings){
            System.out.println(m.getName()+"--->"+m.getPatterns());
            //login--->[/login, /g]
            //reg--->[/reg]
        }
        //下面开始操作
        //获取映射关系
        WebContent web = new WebContent(entities,mappings);
        //模拟输入,假设输入了/login /g或者 /reg
        String className = web.getClz("/reg");
        System.out.println(className);
        //利用反射获取到类
        Class clz = Class.forName(className);
        //实例化,使用接口类型
        Serverlet servlet = (Serverlet)clz.getConstructor().newInstance();
        //提供服务
        servlet.service();
    }
}

class WebHandler extends DefaultHandler{
    private List<Entity> entities = new ArrayList<>();; //多个Person的容器
    private List<Mapping> mappings = new ArrayList<>(); //多个Person的容器

    private Entity entity;
    private Mapping mapping;
    private String tag; //当前操作的标签
    private boolean isMapping = false; //操作serverlet还是mapping

    @Override  //开始解析元素,qName是标签名称
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        System.out.println(qName+"解析开始");
        if(null != qName){  //保存tag
            tag = qName;
            if(tag.equals("servlet")){  //如果是servlet标签就创建eneity对象
                entity = new Entity();
                isMapping = false;
            }else if(tag.equals("servlet-mapping")){
                mapping = new Mapping();
                isMapping = true;
            }
        }
    }

    @Override //读取内容
    public void characters(char[] ch, int start, int length) throws SAXException {
        String str = new String(ch,start,length).trim();
//        if(str.length()>0) {
//            System.out.println("内容为----->" + str.trim());
//        }else {
//            System.out.println("内容为空---");
//        }
        if(tag != null) {
            if (isMapping) { //操作mapping
                if(tag.equals("servlet-name")){
                    mapping.setName(str);
                }else if(tag.equals("url-pattern")){
                    mapping.addPattern(str);
                }
            } else { //操作servlet
                if(tag.equals("servlet-name")){
                    entity.setName(str);
                }else if(tag.equals("servlet-class")){
                    entity.setClz(str);
                }
            }
        }
    }

    @Override //结束解析元素
    public void endElement(String uri, String localName, String qName) throws SAXException {
        System.out.println(qName+"解析结束");
        if(qName != null){
            if(qName.equals("servlet")){  //如果再次碰到person标签就添加到容器中
                entities.add(entity);
            }else if(qName.equals("servlet-mapping")){
                mappings.add(mapping);
            }
        }
        tag = null; //解析完成为了防止后一个标签的空格的影响,将tag赋值为null
    }


    //生成getter方法
    public List<Entity> getEntities() {
        return entities;
    }

    public List<Mapping> getMappings() {
        return mappings;
    }
}
  • Serverlet.java接口,xml中的类servlet-class对应的接口
package server.basic2;

public interface Serverlet {
    void service();
}
  • 两个实现类,servlet-class的两个类
  • LoginServlet.java
package server.basic2;

public class LoginServlet implements Serverlet {
    @Override
    public void service() {
        System.out.println("登录");
    }
}
  • RegisterServlet
package server.basic2;

public class RegisterServlet implements Serverlet {
    @Override
    public void service() {
        System.out.println("注册");
    }
}

html

  • 超文本标记语言,浏览器用
<html>
	<head>
		<title>第一个html登录title>
	head>
	<body>
		<h1>表单的使用h1>
		<pre>
				post:提交 ,基于http协议不同    量大   请求参数url不可见 安全<br/>
				get:  默认,获取,基于http协议不同  量小  请求参数url可见 不安全<br/>
				action: 请求web服务器的资源   URL<br/>
				name:作为后端使用,区分唯一: 请求服务器,必须存在,数据不能提交<br/>
				id: 作为前端使用,区分唯一<br/>
		pre>
		<form method="get" action="http://localhost:8888/index.html">
						用户名:<input type="text" name="uname"  id="uname"/>
						密码:<input type="password" name="pwd"  id="pwd"/>
						<input type="submit" value="登录"/>
		form>
	body>
html>

http协议

  • https://www.runoob.com/http/http-intro.html

获取请求协议

  • 获取get或post的请求协议
package server.myserver;

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

/**
 * 浏览器输入http://locolhost:8889
 * 端口号,接收
 */
public class Server01 {
    ServerSocket serverSocket;
    public static void main(String[] args) throws IOException {
        Server01 server = new Server01();
        server.start();

    }
    //启动服务
    public void start() throws IOException {
        serverSocket = new ServerSocket(8889);
        receive();
    }
    //接受
    public void receive() throws IOException {
        Socket client = serverSocket.accept();
        System.out.println("一个客户端建立了连接");
        //获取请求协议,get方式可以通过浏览器直接访问,get/post方式通过运行login.html访问
        InputStream is = client.getInputStream();
        byte[] data = new byte[1024*1024];
        int len = is.read(data); //一次性读取存入data
        String requestinfo = new String(data,0,len);
        System.out.println(requestinfo);

    }

    //停止服务
    public void stop(){

    }
}
  • get的请求协议
GET /index.html?uname=123&paswrd=10000 HTTP/1.1
Host: localhost:8889
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3314.0 Safari/537.36 SE 2.X MetaSr 1.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: _ga=GA1.1.1809456532.1578749380
  • post的请求协议,数据在最后空白行后面
POST /index.html HTTP/1.1
Host: localhost:8889
Connection: keep-alive
Content-Length: 19
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: null
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3706.400 SLBrowser/10.0.3974.400
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: _ga=GA1.1.2136018396.1577101129

uname=fda&pwd=34567

返回响应协议

  • 主要处理responseInfo,包括响应行,响应头和正文。正文前面空一行。

BufferedWriter bw =new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
bw.write(responseInfo.toString());
bw.flush();

package server.myserver;

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

/**
 * 返回响应协议
 * 浏览器输入http://locolhost:8889/index.html?uname=werg&passwd=2344
 * 创建ServerSocket,建立连接获取Socket,通过输入流获取请求协议
 */
public class Server02 {
    ServerSocket serverSocket;
    public static void main(String[] args) throws IOException {
        Server02 server = new Server02();
        server.start();

    }
    //启动服务
    public void start() throws IOException {
        serverSocket = new ServerSocket(8889);
        receive();
    }
    //接受
    public void receive() throws IOException {
        Socket client = serverSocket.accept();
        System.out.println("一个客户端建立了连接");
        //获取请求协议,get方式可以通过浏览器直接访问,get/post方式通过运行login.html访问
        InputStream is = client.getInputStream();
        byte[] data = new byte[1024*1024];
        int len = is.read(data); //一次性读取存入data
        String requestinfo = new String(data,0,len);
        System.out.println(requestinfo);

        //返回响应信息
        //1 响应行
        //2 响应头,最后一行是空行
        //3 正文
        StringBuilder content =new StringBuilder();
        content.append("");
        content.append("");
        content.append(""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        content<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"服务器响应成功"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        content<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"");
        content.append("");
        content.append("");
        content.append("中国必胜,武汉必胜。。。。");
        content.append("");
        content.append("");
        int size = content.toString().getBytes().length; //必须获取字节长度
        StringBuilder responseInfo =new StringBuilder();
        String blank =" ";
        String CRLF = "\r\n";
        //返回
        //1、响应行: HTTP/1.1 200 OK
        responseInfo.append("HTTP/1.1").append(blank);
        responseInfo.append(200).append(blank);
        responseInfo.append("OK").append(CRLF);
        //2、响应头(最后一行存在空行):
			/*
			 Date:Mon,31Dec209904:25:57GMT
			Server:shsxt Server/0.0.1;charset=GBK
			Content-type:text/html
			Content-length:39725426
			 */
        responseInfo.append("Date:").append(new Date()).append(CRLF);
        responseInfo.append("Server:").append("myserver Server/0.0.1;charset=GBK").append(CRLF);
        responseInfo.append("Content-type:text/html").append(CRLF);
        responseInfo.append("Content-length:").append(size).append(CRLF);
        responseInfo.append(CRLF);
        //3、正文
        responseInfo.append(content.toString());

        //写出到客户端
        BufferedWriter bw =new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
        bw.write(responseInfo.toString());
        bw.flush();

    }

    //停止服务
    public void stop(){

    }
}

封装的响应

  • 将响应头放到一个类中,直接传递响应代码和相应内容,进行响应。使用时只关注内容和状态码
  • Response.java
package server.myserver;

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 BufferedWriter bw;
    //正文
    private StringBuilder content;
    //协议头
    private StringBuilder headInfo;
    private int len; //正文的字节长度
    private final String BLANK = " ";
    private final String CRLF = "\r\n";
    private Response(){  //这个构造器私有,只能自己调用
        content = new StringBuilder();
        headInfo = new StringBuilder();
        len = 0;
    }

    public Response(Socket client) throws IOException {
        this();
        bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
    }

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

    //构建头信息,包括响应行和响应头
    private void createHeadInfo(int code){
        //1 响应行
        headInfo.append("HTTP/1.1").append(BLANK);
        headInfo.append(code).append(BLANK);
        switch (code){
            case 200:
                headInfo.append("OK").append(CRLF);
                break;
            case 404:
                headInfo.append("NOT FOUND").append(CRLF);
                break;
            case 505:
                headInfo.append("SERVER ERROR").append(CRLF);
                break;
        }
        //2 响应头,最后是个空行
        headInfo.append("Date:").append(new Date()).append(CRLF);
        headInfo.append("Server:").append("shsxt Server/0.0.1;charset=GBK").append(CRLF);
        headInfo.append("Content-type:text/html").append(CRLF);
        headInfo.append("Content-length:").append(len).append(CRLF);
        headInfo.append(CRLF);
    }

    //动态添加 3内容,返回对象本身,可以链式调用
    public Response print(String info){
        content.append(info);
        len+=info.getBytes().length;
        return this;
    }
    public Response println(String info){
        content.append(info).append(CRLF);
        len+=(info+CRLF).getBytes().length;
        return this;
    }

    // 推送信息,返回到浏览器,
    public void pushToBrowser(int code) throws IOException {
        if(null == headInfo){
            code = 505;
        }
        createHeadInfo(code);
        bw.append(headInfo);
        bw.append(content);
        bw.flush();
    }
}
  • 使用
package server.myserver;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
 * 封装响应协议
 * 浏览器输入http://locolhost:8889/index.html?uname=werg&passwd=2344
 * 创建ServerSocket,建立连接获取Socket,通过输入流获取请求协议
 */
public class Server03 {
    ServerSocket serverSocket;
    public static void main(String[] args) throws IOException {
        Server03 server = new Server03();
        server.start();

    }
    //启动服务
    public void start() throws IOException {
        serverSocket = new ServerSocket(8889);
        receive();
    }
    //接受
    public void receive() throws IOException {
        Socket client = serverSocket.accept();
        System.out.println("一个客户端建立了连接");

        //返回响应信息
        Response response = new Response(client);

        response.print("");
        response.print("");
        response.print(""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        response<span class="token punctuation">.</span><span class="token function">print</span><span class="token punctuation">(</span><span class="token string">"服务器响应成功"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        response<span class="token punctuation">.</span><span class="token function">print</span><span class="token punctuation">(</span><span class="token string">"");
        response.print("");
        response.print("");
        response.print("中国必胜,武汉必胜。。。。");
        response.print("");
        response.print("");

        response.pushToBrowser(200);

    }

    //停止服务
    public void stop(){

    }
}

你可能感兴趣的:(Java从入门到住院)