`
liyanboss
  • 浏览: 140278 次
  • 性别: Icon_minigender_1
  • 来自: 厦门
社区版块
存档分类
最新评论
收藏列表
标题 标签 来源
Stored Function to generate Sequences https://www.percona.com/blog/2008/04/02/stored-function-to-generate-sequences/
delimiter //
create function seq(seq_name char (20)) returns int
begin
 update seq set val=last_insert_id(val+1) where name=seq_name;
 return last_insert_id();
end
//
delimiter ;
CREATE TABLE `seq` (
  `name` varchar(20) NOT NULL,
  `val` int(10) unsigned NOT NULL,
  PRIMARY KEY  (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
insert into seq values('one',100);
insert into seq values('two',1000);
Multipart form upload on Android multipart form upload on android Multipart form upload on Android
Multipart form upload on Android
Android 1.5 includes Apache HttpClient 4 for the purposes of making HTTP requests. Unfortunately HttpClient 4 (or the version included with Android anyway) doesn’t appear to support multipart form uploads.

As it happens writing a solution from scratch (at the HTTP layer that is) is pretty straight forward. The main challenge is understanding how the POST request should be structured. Once you know that it’s simply a matter of putting all the pieces together.

The connection is managed using the java.net.HttpURLConnection class. There’s a few properties that need to set on the connection to ensure it can be written to and read from,

HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
A special header informs the server that this will be a multipart form submission.

conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=xxxxxxxxxx");
The “boundry” can be any string. In this example it’s xxxxxxxxxx. It’s used in the body of the request to seperate each field being submitted.

Next comes the main body of the request. Each field being submitted follows the same pattern. For example, to submit a text file called “helloworld.txt” with the contents “Hello World” and using the boundry string xxxxxxxxxx here’s what the request would look like,

--xxxxxxxxxx
Content-Disposition: form-data; name="filetoupload"; filename="helloworld.txt"
Content-Type: text/plain

Hello World
--xxxxxxxxxx--
The final -- is important. It tells the server it’s the end of the submission.

Here’s a full method that’s used to upload a file to a URL. It can optionally take a username and password which is used to perform BASIC authentication.

    public static void put(String targetURL, File file, String username, String password) throws Exception {

        String BOUNDRY = "==================================";
        HttpURLConnection conn = null;

        try {

            // These strings are sent in the request body. They provide information about the file being uploaded
            String contentDisposition = "Content-Disposition: form-data; name=\"userfile\"; filename=\"" + file.getName() + "\"";
            String contentType = "Content-Type: application/octet-stream";

            // This is the standard format for a multipart request
            StringBuffer requestBody = new StringBuffer();
            requestBody.append("--");
            requestBody.append(BOUNDRY);
            requestBody.append('\n');
            requestBody.append(contentDisposition);
            requestBody.append('\n');
            requestBody.append(contentType);
            requestBody.append('\n');
            requestBody.append('\n');
            requestBody.append(new String(Util.getBytesFromFile(file)));
            requestBody.append("--");
            requestBody.append(BOUNDRY);
            requestBody.append("--");

            // Make a connect to the server
            URL url = new URL(targetURL);
            conn = (HttpURLConnection) url.openConnection();

            // Put the authentication details in the request
            if (username != null) {
                String usernamePassword = username + ":" + password;
                String encodedUsernamePassword = Base64.encodeBytes(usernamePassword.getBytes());
                conn.setRequestProperty ("Authorization", "Basic " + encodedUsernamePassword);
            }

            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDRY);

            // Send the body
            DataOutputStream dataOS = new DataOutputStream(conn.getOutputStream());
            dataOS.writeBytes(requestBody.toString());
            dataOS.flush();
            dataOS.close();

            // Ensure we got the HTTP 200 response code
            int responseCode = conn.getResponseCode();
            if (responseCode != 200) {
                throw new Exception(String.format("Received the response code %d from the URL %s", responseCode, url));
            }

            // Read the response
            InputStream is = conn.getInputStream();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] bytes = new byte[1024];
            int bytesRead;
            while((bytesRead = is.read(bytes)) != -1) {
                baos.write(bytes, 0, bytesRead);
            }
            byte[] bytesReceived = baos.toByteArray();
            baos.close();

            is.close();
            String response = new String(bytesReceived);

            // TODO: Do something here to handle the 'response' string

        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }

    }
There’s nothing in this code particular to Android so it will work in any java application.
使用HttpURLConnection发送Post/Get请求 httpurlconnection 使用HttpURLConnection发送Post/Get请求
  HTTP规范定义中最常用的请求类型就是Get和Post。当你在浏览器里输入任意一个网址按回车,浏览器即已经在执行Get请求了;当你回复了某条微博时,这时可能就执行了一次Post请求。简单的来说,Get就是向服务器发送索取数据的一种请求,不会影响资源的状态;Post是向服务器提交数据的一种请求,可能创建或更新服务器上的资源。

        访问服务器链接时,需要以链接地址为参数构造生成一个java.net.URL实例。URL由网络协议、主机名、端口、信息路径、引用等组成统一资源定位符,它是指向互联网“资源”的指针。资源可以是简单的文件或目录,也可以是对更为复杂的对象的引用,例如对数据库或搜索引擎的查询。

        URL的示例代码如下:

1
URL url = new URL("http://www.devdiv.com:80/res/index.html#chapter1");

        在上面的示例URL中,使用的协议为HTTP超文本传输协议;主机名为www.devdiv.com;端口为80,端口值不是必须要求的,当未指定端口号时则使用协议默认的端口;信息路径为"res/index.html";引用内容则是由"#"指示的"chapter1",表示在检索到指定的资源后,程序需要使用文档中附加有"chapter1"的标记部分。

        生成URL实例后,执行url.openConnection()方法可以获取HttpURLConnection对象。如果URL的协议属于以下包或其子包之一的公共、专用URLConnection子类:java.lang、java.io、java.util、java.net,则返回的连接将为该子类的类型。例如,对于HTTP,将返回HttpURLConnection,对于JAR,将返回JarURLConnection。代码如下:

1
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();

        通过代码获取的HttpURLConnection默认是进行Get请求,数据只读不提交。要使用Post方式提交数据,应提前设置好各项参数,代码如下:

1
httpConn.setDoInput(true);
2
httpConn.setDoOutput(true);
3
 
4
// 此方法在正式链接之前设置才有效。
5
httpConn.setRequestMethod("POST");
6
httpConn.setUseCaches(false);
7
// 正式创建链接
8
httpConn.connect();

        setDoInput(boolean)参数值为true决定着当前链接可以进行数据读取,反之则不允许读取操作;setDoOutput(boolean)参数值为true时决定着当前链接可以进行数据提交工作,反之则不允许。setRequestMethod("POST")将当前HTTP请求方式设置为"POST",并在最后执行setUseCaches(boolean)取消了用户缓存。以上所有的工作都必须在正式创建链接之前进行。

        Post方式提交数据,需要用到数据输出流。当执行httpConn.connect()后,即可执行httpConn.getOutputStream()获取数据流从而进行数据写操作,为将数据提交到服务器作准备。代码如下:

1
DataOutputStream dos = new DataOutputStream(httpConn.getOutputStream());
2
 
3
String postContent = URLEncoder.encode("channel", "UTF-8") + "=" + URLEncoder.encode("Devdiv", "UTF-8") + "&" + URLEncoder.encode("author", "UTF-8") + "=" + URLEncoder.encode("Sodino", "UTF-8") ;
4
 
5
dos.write(postContent.getBytes());
6
dos.flush();
7
// 执行完dos.close()后,POST请求结束
8
dos.close();

        数据是以<Key,Value>形式提交的,为保证数据的准确性,当数据是英文字母、数字时,原样发送;如果是空格则转换为"+",如果涉及到中文或其它字符,则通过URLEncoder.encode()进行BASE 64标准转码,得出"%XX"格式的加工数据,其中"X"为该符号以16进制表示的ASCII码。

        为保持数据的合法,本文所提交的内容虽皆为英文字符,但仍一致使用URLEncoder进行转码。当<Key,Value>数量不止一组时,组与组之间用"&"进行分隔。执行DataOutputStream.write(byte[])可以将所要提交的内容由输出流写入内存缓冲区中,在关闭输出流之前,执行一次flush()刷新操作,强制将可能未输出的数据及时写入内存缓冲区。

        对于同一个HttpURLConnection实例,只有执行完Post请求后,才允许Get请求进行,否则以Get请求进行的任何动作都将直接导致未执行的Post操作失败。

        从服务器上获取数据,同理,需要数据输入流,并循环读取所有数据后,方可加工出用户想要获取的信息。代码如下:

01
// 开始GET数据
02
String encoding = httpConn.getContentEncoding();
03
is = httpConn.getInputStream();
04
int read = -1;
05
baos = new ByteArrayOutputStream();
06
while ((read = is.read()) != -1) {
07
        baos.write(read);
08
}
09
byte[] data = baos.toByteArray();
10
baos.close();
11
 
12
String content = null;
13
if (encoding != null) {
14
        content = new String(data, encoding);
15
} else {
16
        content = new String(data);
17
}


        读取过程中使用了ByteArrayOutputStream作为字节数据的缓冲流。当InputStream.read()返回值为-1表示数据已经全部读取完毕后,再将ByteArrayOutputStream中的缓冲数据由baos.toByteArray()一次性生成byte[],并根据一开始由httpConn.getContentEncoding()获取的字符编码类型,将byte[]构造成新的String。最后,所有的输入流、输出流都应该执行close()操作。

        在读取数据之前,可以获取当前链接的返回值、返回数据长度等等信息。在单纯的读取数据中,正常的返回值RespondCode等于HTTP_OK,需要链接跳转的返回值HTTP_MOVED_PERM/ HTTP_MOVED_TEMP,如果访问资源不存在,则返回值HTTP_NOT_FOUND。代码如下:

01
// 获取代码返回值
02
int respondCode = httpConn.getResponseCode()
03
// 获取返回内容类型
04
String type = httpConn.getContentType();
05
// 获取返回内容的字符编码
06
String encoding = httpConn.getContentEncoding();
07
// 获取返回内容长度,单位字节
08
int length = httpConn.getContentLength();
09
// 获取头信息的Key
10
String key = httpConn.getHeaderField(idx);
11
// 获取完整的头信息Map
12
Map<String, List<String>> map = httpConn.getHeaderFields();

        以上为完整的Post/Get请求过程。

        有时在简单的需求驱使下,服务器开发人员出于便捷性考虑,也会将Post请求方式交由Get请求方式替代实现。以同样需要向服务器发送两组<Key,Value>数据为需求,可以将此两组数据组合到url中,代码如下:

1
URL url = new URL("http://www.devdiv.com:80/res/index.html?channel=Devdiv&author=sodino");

        在完整的链接后,以"?"分隔url和传输数据,将<Key,Value>数据用"="组合成字符串后缀。然后依上面介绍的步骤向服务器发起请求,亦可读取正确的数据。同理,<Key,Value>在使用"="组合成字符串之前,仍需使用URLEncoder进行转码以保证数据的准确性。

        对于Post/Get所能发送的<Key,Value>的数据量大小,HTTP 1.1中并没有具体的限制,在实际运行中与程序运行环境及服务器部署设置有关。

        以上介绍了Post/Get的基本使用方法,由此可看出,由于Post方式将请求的数据放置在HTTP请求的正文内,它的安全性要比Get请求的安全性要高。比如:通过Get发送数据,用户名和密码信息都将会出现在URL上,在设置了浏览器缓存的情况下会被记录导致泄漏。所以在涉及到用户个人隐私的数据时,强烈推荐在将数据加密后使用Post方式提交至服务器。
JDK中的URLConnection参数详解 jdk中的urlconnection参数详解 JDK中的URLConnection参数详解
JDK中的URLConnection参数详解

针对JDK中的URLConnection连接Servlet的问题,网上有虽然有所涉及,但是只是说明了某一个或几个问题,是以FAQ的方式来解决的,而且比较零散,现在对这个类的使用就本人在项目中的使用经验做如下总结: 
1:> URL请求的类别: 
分为二类,GET与POST请求。二者的区别在于: 
     a:) get请求可以获取静态页面,也可以把参数放在URL字串后面,传递给servlet, 
     b:) post与get的不同之处在于post的参数不是放在URL字串里面,而是放在http请求的正文内。 
2:> URLConnection的对象问题: 
URLConnection的对象,如下代码示例: 

// 下面的index.jsp由<servlet-mapping>映射到 
// 一个Servlet(com.quantanetwork.getClientDataServlet) 
// 该Servlet的注意点下边会提到 
URL url = new URL("http://localhost:8080/TestHttpURLConnectionPro/index.jsp"); 

URLConnection rulConnection = url.openConnection();// 此处的urlConnection对象实际上是根据URL的 
          // 请求协议(此处是http)生成的URLConnection类 
          // 的子类HttpURLConnection,故此处最好将其转化 
          // 为HttpURLConnection类型的对象,以便用到 
          // HttpURLConnection更多的API.如下: 

HttpURLConnection httpUrlConnection = (HttpURLConnection) rulConnection; 


3:> HttpURLConnection对象参数问题 
// 设置是否向httpUrlConnection输出,因为这个是post请求,参数要放在 
// http正文内,因此需要设为true, 默认情况下是false; 
httpUrlConnection.setDoOutput(true); 

// 设置是否从httpUrlConnection读入,默认情况下是true; 
httpUrlConnection.setDoInput(true); 

// Post 请求不能使用缓存 
httpUrlConnection.setUseCaches(false); 

// 设定传送的内容类型是可序列化的java对象 
// (如果不设此项,在传送序列化对象时,当WEB服务默认的不是这种类型时可能抛java.io.EOFException) 
httpUrlConnection.setRequestProperty("Content-type", "application/x-java-serialized-object"); 

// 设定请求的方法为"POST",默认是GET 
httpUrlConnection.setRequestMethod("POST"); 

// 连接,从上述第2条中url.openConnection()至此的配置必须要在connect之前完成, 
        httpUrlConnection.connect(); 


4:>  HttpURLConnection连接问题: 

// 此处getOutputStream会隐含的进行connect(即:如同调用上面的connect()方法, 
// 所以在开发中不调用上述的connect()也可以)。 
OutputStream outStrm = httpUrlConnection.getOutputStream(); 



5:> HttpURLConnection写数据与发送数据问题: 
// 现在通过输出流对象构建对象输出流对象,以实现输出可序列化的对象。 
ObjectOutputStream objOutputStrm = new ObjectOutputStream(outStrm); 

// 向对象输出流写出数据,这些数据将存到内存缓冲区中 
objOutputStrm.writeObject(new String("我是测试数据")); 

// 刷新对象输出流,将任何字节都写入潜在的流中(些处为ObjectOutputStream) 
objOutputStm.flush(); 

// 关闭流对象。此时,不能再向对象输出流写入任何数据,先前写入的数据存在于内存缓冲区中, 
// 在调用下边的getInputStream()函数时才把准备好的http请求正式发送到服务器 
objOutputStm.close(); 

// 调用HttpURLConnection连接对象的getInputStream()函数, 
// 将内存缓冲区中封装好的完整的HTTP请求电文发送到服务端。 
InputStream inStrm = httpConn.getInputStream(); // <===注意,实际发送请求的代码段就在这里 

// 上边的httpConn.getInputStream()方法已调用,本次HTTP请求已结束,下边向对象输出流的输出已无意义, 
// 既使对象输出流没有调用close()方法,下边的操作也不会向对象输出流写入任何数据. 
// 因此,要重新发送数据时需要重新创建连接、重新设参数、重新创建流对象、重新写数据、 
// 重新发送数据(至于是否不用重新这些操作需要再研究) 
objOutputStm.writeObject(new String("")); 
httpConn.getInputStream(); 



总结:a:) HttpURLConnection的connect()函数,实际上只是建立了一个与服务器的tcp连接,并没有实际发送http请求。 
    无论是post还是get,http请求实际上直到HttpURLConnection的getInputStream()这个函数里面才正式发送出去。 
       b:) 在用POST方式发送URL请求时,URL请求参数的设定顺序是重中之重, 
    对connection对象的一切配置(那一堆set函数) 
    都必须要在connect()函数执行之前完成。而对outputStream的写操作,又必须要在inputStream的读操作之前。 
    这些顺序实际上是由http请求的格式决定的。 
    如果inputStream读操作在outputStream的写操作之前,会抛出例外: 
    java.net.ProtocolException: Cannot write output after reading input....... 
       
       c:) http请求实际上由两部分组成, 
    一个是http头,所有关于此次http请求的配置都在http头里面定义, 
           一个是正文content。 
    connect()函数会根据HttpURLConnection对象的配置值生成http头部信息,因此在调用connect函数之前, 
    就必须把所有的配置准备好。 
       d:) 在http头后面紧跟着的是http请求的正文,正文的内容是通过outputStream流写入的, 
    实际上outputStream不是一个网络流,充其量是个字符串流,往里面写入的东西不会立即发送到网络, 
    而是存在于内存缓冲区中,待outputStream流关闭时,根据输入的内容生成http正文。 
    至此,http请求的东西已经全部准备就绪。在getInputStream()函数调用的时候,就会把准备好的http请求 
    正式发送到服务器了,然后返回一个输入流,用于读取服务器对于此次http请求的返回信息。由于http 
    请求在getInputStream的时候已经发送出去了(包括http头和正文),因此在getInputStream()函数 
    之后对connection对象进行设置(对http头的信息进行修改)或者写入outputStream(对正文进行修改) 
    都是没有意义的了,执行这些操作会导致异常的发生。 

6:> Servlet端的开发注意点: 
a:) 对于客户端发送的POST类型的HTTP请求,Servlet必须实现doPost方法,而不能用doGet方法。 
b:) 用HttpServletRequest的getInputStream()方法取得InputStream的对象,比如: 
     InputStream inStream = httpRequest.getInputStream(); 
     现在调用inStream.available()(该方法用于“返回此输入流下一个方法调用可以不受阻塞地 
     从此输入流读取(或跳过)的估计字节数”)时,永远都反回0。试图使用此方法的返回值分配缓冲区, 
     以保存此流所有数据的做法是不正确的。那么,现在的解决办法是 
     Servlet这一端用如下实现: 
     InputStream inStream = httpRequest.getInputStream(); 
     ObjectInputStream objInStream = new ObjectInputStream(inStream); 
     Object obj = objInStream.readObject(); 
     // 做后续的处理 
     // 。。。。。。 
     // 。。。 。。。 
     而客户端,无论是否发送实际数据都要写入一个对象(那怕这个对象不用),如: 
     ObjectOutputStream objOutputStrm = new ObjectOutputStream(outStrm); 
     objOutputStrm.writeObject(new String("")); // 这里发送一个空数据 
     // 甚至可以发一个null对象,服务端取到后再做判断处理。 
     objOutputStrm.writeObject(null); 
     objOutputStrm.flush(); 
     objOutputStrm.close(); 

注意:上述在创建对象输出流ObjectOutputStream时,如果将从HttpServletRequest取得的输入流 
      (即:new ObjectOutputStream(outStrm)中的outStrm)包装在BufferedOutputStream流里面, 
      则必须有objOutputStrm.flush();这一句,以便将流信息刷入缓冲输出流.如下: 
      ObjectOutputStream objOutputStrm = new ObjectOutputStream(new BufferedOutputStream(outStrm)); 
      objOutputStrm.writeObject(null); 
      objOutputStrm.flush(); // <======此处必须要有. 
      objOutputStrm.close(); 



HttpURLConnection是基于HTTP协议的,其底层通过socket通信实现。如果不设置超时(timeout),在网络异常的情况下,可能会导致程序僵死而不继续往下执行。可以通过以下两个语句来设置相应的超时:
System.setProperty("sun.net.client.defaultConnectTimeout", 超时毫秒数字符串);
System.setProperty("sun.net.client.defaultReadTimeout", 超时毫秒数字符串);

其中: sun.net.client.defaultConnectTimeout:连接主机的超时时间(单位:毫秒)
sun.net.client.defaultReadTimeout:从主机读取数据的超时时间(单位:毫秒)

例如:
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");
System.setProperty("sun.net.client.defaultReadTime

Java中可以使用HttpURLConnection来请求WEB资源。
HttpURLConnection对象不能直接构造,需要通过URL.openConnection()来获得HttpURLConnection对象,示例代码如下:

String szUrl = "http://www.ee2ee.com/";
URL url = new URL(szUrl);
HttpURLConnection urlCon = (HttpURLConnection)url.openConnection(); 
 

HttpURLConnection是基于HTTP协议的,其底层通过socket通信实现。如果不设置超时(timeout),在网络异常的情况下,可能会导致程序僵死而不继续往下执行。可以通过以下两个语句来设置相应的超时:
System.setProperty("sun.net.client.defaultConnectTimeout", 超时毫秒数字符串);
System.setProperty("sun.net.client.defaultReadTimeout", 超时毫秒数字符串);

其中: sun.net.client.defaultConnectTimeout:连接主机的超时时间(单位:毫秒)
sun.net.client.defaultReadTimeout:从主机读取数据的超时时间(单位:毫秒)

例如:
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");
System.setProperty("sun.net.client.defaultReadTimeout", "30000");

JDK 1.5以前的版本,只能通过设置这两个系统属性来控制网络超时。在1.5中,还可以使用HttpURLConnection的父类URLConnection的以下两个方法:
setConnectTimeout:设置连接主机超时(单位:毫秒)
setReadTimeout:设置从主机读取数据超时(单位:毫秒)

例如:

HttpURLConnection urlCon = (HttpURLConnection)url.openConnection();
urlCon.setConnectTimeout(30000);
urlCon.setReadTimeout(30000); 
 

需要注意的是,笔者在JDK1.4.2环境下,发现在设置了defaultReadTimeout的情况下,如果发生网络超时,HttpURLConnection会自动重新提交一次请求,出现一次请求调用,请求服务器两次的问题(Trouble)。我认为这是JDK1.4.2的一个bug。在JDK1.5.0中,此问题已得到解决,不存在自动重发现象。out", "30000");
Global site tag (gtag.js) - Google Analytics