转载

每日一博 | Java URL 自定义私有协议与 ContentHandler

URI, URL

URI,是uniform resource identifier,统一资源标识符,用来唯一的标识一个资源。而URL是uniform resource locator,统一资源定位器,它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。而URN,uniform resource name,统一资源命名,是通过名字来标识资源,比如mailto:java-net@java.sun.com。也就是说,URI是以一种抽象的,高层次概念定义统一资源标识,而URL和URN则是具体的资源标识的方式。URL和URN都是一种URI。

我们很多时候把URL认为是只与网络相关,但是确切的说,网络资源定位只是他的一个(资源定位工厂)子集。

一.序言一段

我们习惯了http

 URL url=new URL("http://www.apptest.com:8080/test/ios.php");

我们也要习惯

 "https", "ftp", "mailto", "telnet", "file", "ldap", "gopher",  "jdbc", "rmi", "jndi", "jar", "doc", "netdoc", "nfs", "verbatim", "finger", "daytime",   "systemresource"

当然,我们还要让URL习惯我们

 URL url=new URL("oschina://www.apptest.com:8080/test/ios.php");

如果不习惯,总会出现如下异常

java.net.MalformedURLException: unknown protocol

在Android浏览器使用Ajax时也会不支持没有定义的过的协议。

二.协议的自定义

协议:在编程的世界里,协议本身就是一套Input/ouput约束规则,因此,我们确切的协议应该围绕I/O展开的,所以,这里的协议可以称为I/O协议。

协议发起方:request

协议响应方:response

协议成立的条件是:request和reponse认可同一套协议,并按照协议约束进行通信。

三.自定义协议与URL

在java中,自定义协议一定需要用URL吗?

答案是否定的。

事实上,围绕I/O,我们的规则定义完全有我们本身掌握,并没有说离开URL地球不转了,Java要毁灭了。

为什么使用URL类来自定义协议?

答案是因为URL是一套成熟的协议通信处理框架。

这里说的自定义URL协议,实质上更多的是通过已有的规则进行扩充协议。

四.实战

我们知道,自定义协议需要Response 和Request,双方需要充理解对方的协议。这里为了方便起见,我们使用Http协议服务器来作为Response。

这里我们使用了Ngnix服务器+PHP+FastCGI来构建Reponse,部署代码如下

1.定义Response

<?php  $raw_post_data = file_get_contents('php://input', 'r');  echo "-------/$_POST------------------/n<br/>";  echo var_dump($_POST) . "/n";  echo "-------php://input-------------/n<br/>";  echo $raw_post_data . "/n<br/>";   $rs = json_encode($_SERVER);  file_put_contents('text.html',$rs);  echo '写入成功';

2.定义Request

2.1实现URLStreamHandlerFactory工厂,主要用来产生协议处理器

public class EchoURLStreamHandlerFactory implements URLStreamHandlerFactory {    public URLStreamHandler createURLStreamHandler(String protocol){      if(protocol.equals("echo") || protocol.equals("oschina"))      {        return new EchoURLStreamHandler();      }     return null;      }   }

2.2实现URLStreamHandler,主要作用是生成协议对应的连接器

public class EchoURLStreamHandler extends URLStreamHandler {   @Override  protected URLConnection openConnection(URL u) throws IOException {   return new EchoURLConnection(u);  }  }

2.3实现URLConnection,作用是协议通信规则的自定义,这里我们使用HTTP协议作为通信规则

public class EchoURLConnection extends URLConnection {    private Socket connection = null;    public final static int DEFAULT_PORT = 80;   public EchoURLConnection(URL url) {   super(url);     }    public void sendHeader() throws UnsupportedEncodingException, IOException  {     BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(getOutputStream(),             "UTF8"));    ;     wr.write("POST " + getURL().getPath() + " HTTP/1.1 /r/n");     wr.write("Host:www.java2000.net/r/n");     wr.write("Connection:keep-alive/r/n");     wr.write("Date:Fri, 22 Apr 2016 13:17:35 GMT/r/n");     wr.write("Vary:Accept-Encoding/r/n");     wr.write("Content-Type: application/x-www-form-urlencoded/r/n");     wr.write("/r/n/r/n"); // 以空行作为分割             wr.flush();  }   public synchronized InputStream getInputStream() throws IOException {   if (!connected)   {    connect();    sendHeader();   }      return connection.getInputStream();     }   public synchronized OutputStream getOutputStream() throws IOException {   if (!connected)   {    connect();        sendHeader();   }   return connection.getOutputStream();  }   public String getContentType() {   return "text/plain";  }   public synchronized void connect() throws IOException {   if (!connected) {    int port = url.getPort();    if (port < 0 || port > 65535)     port = DEFAULT_PORT;    this.connection = new Socket(url.getHost(), port);    this.connected = true;   }  }   public synchronized void disconnect() throws IOException {   if (connected) {    this.connection.close();    this.connected = false;   }  } }

在这里,协议定义已经完成。

我们测试代码如下

尝试连接  oschina://localhost:8080/test/ios.php

             //注册协议工厂      URL.setURLStreamHandlerFactory(new EchoURLStreamHandlerFactory());            URL url=new URL("oschina://localhost:8080/test/ios.php");      EchoURLConnection connection=(EchoURLConnection)url.openConnection();      connection.setDoOutput(true);      connection.setDoInput(true);         InputStream stream = connection.getInputStream();      int len = -1;      byte[] buf = new byte[1024];      while((len=stream.read(buf, 0, 1024))!=-1)      {              System.out.println(new String(buf, 0, len));      }

运行结果

每日一博 | Java URL 自定义私有协议与 ContentHandler

结果说明,协议确实定义成功了

五.自定义mineType解析器

java中提供了 ContentHandlerFactory,用来解析mineType

public class EchoContentHandlerFactory implements ContentHandlerFactory{     public ContentHandler createContentHandler(String mimetype){     if(mimetype.equals("text/html") || mimetype.equals("text/plain")){       return new EchoContentHandler();     }else{       return null;     }   } }
public class EchoContentHandler extends ContentHandler {    public Object getContent(URLConnection connection) throws IOException {   InputStream in = connection.getInputStream();   BufferedReader br = new BufferedReader(new InputStreamReader(in));   return br.readLine();  }   public Object getContent(URLConnection connection, Class[] classes) throws IOException {   InputStream in = connection.getInputStream();   for (int i = 0; i < classes.length; i++) {    if (classes[i] == InputStream.class)     return in;    else if (classes[i] == String.class)     return getContent(connection);   }   return null;  } }

用法很简单

  URLConnection.setContentHandlerFactory(new EchoContentHandlerFactory());
原文  http://my.oschina.net/ososchina/blog/664743?fromerr=ximWGNUZ
正文到此结束
Loading...