Исключение нулевого указателя - это индикатор того, что вы используете объект, не инициализируя его.
Например, ниже - класс ученика, который будет использовать его в нашем коде.
public class Student {
private int id;
public int getId() {
return this.id;
}
public setId(int newId) {
this.id = newId;
}
}
Приведенный ниже код дает вам исключение с нулевым указателем.
public class School {
Student obj_Student;
public School() {
try {
obj_Student.getId();
}
catch(Exception e) {
System.out.println("Null Pointer ");
}
}
}
Поскольку вы используете Obj_Student
, но вы забыли инициализировать его, как в правильном коде, показанном ниже:
public class School {
Student obj_Student;
public School() {
try {
obj_Student = new Student();
obj_Student.setId(12);
obj_Student.getId();
}
catch(Exception e) {
System.out.println("Null Pointer ");
}
}
}
Мне нравится RestClient. Это инкапсулирует net/http с замечательными функциями как многослойные данные формы:
require 'rest_client'
RestClient.post('http://localhost:3000/foo',
:name_of_file_param => File.new('/path/to/file'))
Это также поддерживает потоковую передачу.
gem install rest-client
запустят Вас.
curb
похож на отличное решение, но в случае, если оно не удовлетворяет Ваши потребности, Вы можете делать это с Net::HTTP
. Многослойное сообщение формы является просто тщательно-отформатированной-строкой с некоторыми дополнительными заголовками. Это походит на каждого Ruby программиста, который должен сделать, многослойные сообщения заканчивают тем, что писали свою собственную небольшую библиотеку для него, которая заставляет меня задаться вопросом, почему эта функциональность не встроена. Возможно, это... Так или иначе, для Вашего удовольствия чтения, я буду идти вперед и давать свое решение здесь. Этот код базируется прочь примеров, которые я нашел на нескольких блогах, но я сожалею, что не могу больше находить ссылки. Таким образом, я предполагаю, что просто должен взять весь кредит на меня...
модуль я записал для этого, содержит один общедоступный класс, для генерации данных формы и заголовков из хеша String
и File
объекты. Так, например, если бы Вы хотели отправить форму со строковым параметром, названным "заголовком" и параметром файла, названным "документом", Вы сделали бы следующее:
#prepare the query
data, headers = Multipart::Post.prepare_query("title" => my_string, "document" => my_file)
Тогда Вы просто делаете нормальное POST
с Net::HTTP
:
http = Net::HTTP.new(upload_uri.host, upload_uri.port)
res = http.start {|con| con.post(upload_uri.path, data, headers) }
Или однако еще Вы хотите сделать POST
. Дело в том, что Multipart
возвраты данные и заголовки, которые необходимо отправить. И вот именно! Простой, правильно? Вот код для Многослойного модуля (Вам нужно mime-types
драгоценный камень):
# Takes a hash of string and file parameters and returns a string of text
# formatted to be sent as a multipart form post.
#
# Author:: Cody Brimhall <mailto:brimhall@somuchwit.com>
# Created:: 22 Feb 2008
# License:: Distributed under the terms of the WTFPL (http://www.wtfpl.net/txt/copying/)
require 'rubygems'
require 'mime/types'
require 'cgi'
module Multipart
VERSION = "1.0.0"
# Formats a given hash as a multipart form post
# If a hash value responds to :string or :read messages, then it is
# interpreted as a file and processed accordingly; otherwise, it is assumed
# to be a string
class Post
# We have to pretend we're a web browser...
USERAGENT = "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/523.10.6 (KHTML, like Gecko) Version/3.0.4 Safari/523.10.6"
BOUNDARY = "0123456789ABLEWASIEREISAWELBA9876543210"
CONTENT_TYPE = "multipart/form-data; boundary=#{ BOUNDARY }"
HEADER = { "Content-Type" => CONTENT_TYPE, "User-Agent" => USERAGENT }
def self.prepare_query(params)
fp = []
params.each do |k, v|
# Are we trying to make a file parameter?
if v.respond_to?(:path) and v.respond_to?(:read) then
fp.push(FileParam.new(k, v.path, v.read))
# We must be trying to make a regular parameter
else
fp.push(StringParam.new(k, v))
end
end
# Assemble the request body using the special multipart format
query = fp.collect {|p| "--" + BOUNDARY + "\r\n" + p.to_multipart }.join("") + "--" + BOUNDARY + "--"
return query, HEADER
end
end
private
# Formats a basic string key/value pair for inclusion with a multipart post
class StringParam
attr_accessor :k, :v
def initialize(k, v)
@k = k
@v = v
end
def to_multipart
return "Content-Disposition: form-data; name=\"#{CGI::escape(k)}\"\r\n\r\n#{v}\r\n"
end
end
# Formats the contents of a file or string for inclusion with a multipart
# form post
class FileParam
attr_accessor :k, :filename, :content
def initialize(k, filename, content)
@k = k
@filename = filename
@content = content
end
def to_multipart
# If we can tell the possible mime-type from the filename, use the
# first in the list; otherwise, use "application/octet-stream"
mime_type = MIME::Types.type_for(filename)[0] || MIME::Types["application/octet-stream"][0]
return "Content-Disposition: form-data; name=\"#{CGI::escape(k)}\"; filename=\"#{ filename }\"\r\n" +
"Content-Type: #{ mime_type.simplified }\r\n\r\n#{ content }\r\n"
end
end
end
Вот мое решение после попытки других, доступных на этом сообщении, я использую его для загрузки фотографии на TwitPic:
def upload(photo)
`curl -F media=@#{photo.path} -F username=#{@username} -F password=#{@password} -F message='#{photo.title}' http://twitpic.com/api/uploadAndPost`
end
Хорошо, вот простой пример с помощью ограничения.
require 'yaml'
require 'curb'
# prepare post data
post_data = fields_hash.map { |k, v| Curl::PostField.content(k, v.to_s) }
post_data << Curl::PostField.file('file', '/path/to/file'),
# post
c = Curl::Easy.new('http://localhost:3000/foo')
c.multipart_form_post = true
c.http_post(post_data)
# print response
y [c.response_code, c.body_str]
Хорошо решение с NetHttp имеет недостаток, который является при регистрации больших файлов, это загружает целый файл в память сначала.
После игры немного с ним я предложил следующее решение:
class Multipart
def initialize( file_names )
@file_names = file_names
end
def post( to_url )
boundary = '----RubyMultipartClient' + rand(1000000).to_s + 'ZZZZZ'
parts = []
streams = []
@file_names.each do |param_name, filepath|
pos = filepath.rindex('/')
filename = filepath[pos + 1, filepath.length - pos]
parts << StringPart.new ( "--" + boundary + "\r\n" +
"Content-Disposition: form-data; name=\"" + param_name.to_s + "\"; filename=\"" + filename + "\"\r\n" +
"Content-Type: video/x-msvideo\r\n\r\n")
stream = File.open(filepath, "rb")
streams << stream
parts << StreamPart.new (stream, File.size(filepath))
end
parts << StringPart.new ( "\r\n--" + boundary + "--\r\n" )
post_stream = MultipartStream.new( parts )
url = URI.parse( to_url )
req = Net::HTTP::Post.new(url.path)
req.content_length = post_stream.size
req.content_type = 'multipart/form-data; boundary=' + boundary
req.body_stream = post_stream
res = Net::HTTP.new(url.host, url.port).start {|http| http.request(req) }
streams.each do |stream|
stream.close();
end
res
end
end
class StreamPart
def initialize( stream, size )
@stream, @size = stream, size
end
def size
@size
end
def read ( offset, how_much )
@stream.read ( how_much )
end
end
class StringPart
def initialize ( str )
@str = str
end
def size
@str.length
end
def read ( offset, how_much )
@str[offset, how_much]
end
end
class MultipartStream
def initialize( parts )
@parts = parts
@part_no = 0;
@part_offset = 0;
end
def size
total = 0
@parts.each do |part|
total += part.size
end
total
end
def read ( how_much )
if @part_no >= @parts.size
return nil;
end
how_much_current_part = @parts[@part_no].size - @part_offset
how_much_current_part = if how_much_current_part > how_much
how_much
else
how_much_current_part
end
how_much_next_part = how_much - how_much_current_part
current_part = @parts[@part_no].read(@part_offset, how_much_current_part )
if how_much_next_part > 0
@part_no += 1
@part_offset = 0
next_part = read ( how_much_next_part )
current_part + if next_part
next_part
else
''
end
else
@part_offset += how_much_current_part
current_part
end
end
end
У меня была та же проблема (должен отправить на jboss веб-сервер). Ограничение хорошо работает для меня, за исключением того, что оно заставило рубин отказывать (рубиновые 1.8.7 на человечности 8.10), когда я использую переменные сеанса в коде.
я рою в документы клиента отдыха, не мог найти признак многослойной поддержки. Я попробовал примеры клиента отдыха выше, но jboss сказал, что сообщение http не является многослойным.
также есть многоотраслевой пост Ника Сигера , чтобы добавить к длинному списку возможных решений.
restclient не работал у меня, пока я не отменил create_file_field в RestClient::Payload::Multipart.
Он создавал 'Content-Disposition: multipart/form-data' в каждой части, где должно быть 'Content-Disposition: form-data'.
http://www.ietf.org/rfc/rfc2388.txt
Мой форк здесь, если он вам нужен: git@github.com:kcrawford/rest-client.git
Я не могу сказать достаточно хороших слов о библиотеке многостраничных сообщений Ника Зигера.
Он добавляет поддержку многокомпонентной публикации непосредственно в Net :: HTTP, избавляя вас от необходимости вручную беспокоиться о границах или больших библиотеках, цели которых могут отличаться от ваших собственных.
Вот небольшой пример его использования из README :
require 'net/http/post/multipart'
url = URI.parse('http://www.example.com/upload')
File.open("./image.jpg") do |jpg|
req = Net::HTTP::Post::Multipart.new url.path,
"file" => UploadIO.new(jpg, "image/jpeg", "image.jpg")
res = Net::HTTP.start(url.host, url.port) do |http|
http.request(req)
end
end
Вы можете проверить библиотеку здесь: http://github.com/ nicksieger / multipart-post
или установите его с помощью:
$ sudo gem install multipart-post
Если вы подключаетесь через SSL, вам нужно установить соединение следующим образом:
n = Net::HTTP.new(url.host, url.port)
n.use_ssl = true
# for debugging dev server
#n.verify_mode = OpenSSL::SSL::VERIFY_NONE
res = n.start do |http|