2012-03-24 28 views
7

Tôi đã thêm giải pháp từ use base64 image with Carrierwave trong nỗ lực tải lên hình ảnh từ lớp java. Điều này bây giờ là những gì lớp FileUploader của tôi trông như thế - và tôi tin là nơi mà vấn đề là:Tải lên Base64 từ Android/Java tới RoR Carrierwave

# encoding: utf-8 

class FileUploader < CarrierWave::Uploader::Base 

    # Include RMagick or MiniMagick support: 
    include CarrierWave::RMagick 
    # include CarrierWave::MiniMagick 

    # Choose what kind of storage to use for this uploader: 
    storage :file 
    # storage :fog 

    #START FROM BASE64 POST LINKED ABOVE 
    class FilelessIO < StringIO 
    attr_accessor :original_filename 
    attr_accessor :content_type 
    end 

    before :cache, :convert_base64 

    def convert_base64(file) 
    if file.respond_to?(:original_filename) && 
     file.original_filename.match(/^base64:/) 
     fname = file.original_filename.gsub(/^base64:/, '') 
     ctype = file.content_type 
     decoded = Base64.decode64(file.read) 
     file.file.tempfile.close! 
     decoded = FilelessIO.new(decoded) 
     decoded.original_filename = fname 
     decoded.content_type = ctype 
     file.__send__ :file=, decoded 
    end 
    file 
    end 
#END FROM POST LINKED ABOVE 


    # Override the directory where uploaded files will be stored. 
    # This is a sensible default for uploaders that are meant to be mounted: 
    def store_dir 
    "uploads/#{model.class.to_s.underscore}/#{model.user_id}" 
    end 

    # Provide a default URL as a default if there hasn't been a file uploaded: 
    # def default_url 
    # "/images/fallback/" + [version_name, "default.png"].compact.join('_') 
    # end 

    # Process files as they are uploaded: 
    # process :scale => [200, 300] 
    # 
    # def scale(width, height) 
    # # do something 
    # end 

    # Create different versions of your uploaded files: 
    version :thumb do 
     process :resize_to_fit => [200, 300] 
    end 

    version :web do 
     process :resize_to_fit => [1000, 1000] 
    end 

    # Add a white list of extensions which are allowed to be uploaded. 
    # For images you might use something like this: 
    def extension_white_list 
    %w(jpg jpeg gif png) 
    end 

    # Override the filename of the uploaded files: 
    # Avoid using model.id or version_name here, see uploader/store.rb for details. 
    def filename 
    if original_filename 
    Time.new.to_i.to_s+"_"+original_filename 
    end 
    end 

end 

Mô hình ảnh:

class Picture < ActiveRecord::Base 

    belongs_to :user 
    belongs_to :folders 

    attr_accessible :user_id, :picture_name, :picture_description, 
    :folder_id, :picture_path, :file_save 

    mount_uploader :picture_path, FileUploader 

    before_save :update_pictures_attributes 

    def update_pictures_attributes 
     self.file_size = picture_path.file.size 
    end 

end 

Ngay bây giờ khi cuộc gọi bài viết được thực hiện các đường dẫn tập tin được lưu trong db là nil - nhưng mọi thứ khác được lưu. Đây là lớp java/android:

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

import org.apache.http.client.*; 
import org.apache.http.client.entity.*; 
import org.apache.http.client.methods.*; 
import org.apache.http.entity.StringEntity; 
import org.apache.http.impl.client.*; 
import org.apache.http.message.*; 
import org.apache.commons.io.FileUtils; 
import org.json.*; 
import android.util.Base64; 
import android.util.Log; 

public class Uploader { 

    private String url; 
    private String fileName; 

    public Uploader(String url, String fileName){ 
     this.url = url; 
     this.fileName = fileName; 
    } 

    public Boolean upload() throws JSONException, ClientProtocolException, IOException { 
     Boolean success = true; 
     JSONObject jsonObject = constructPictureJson(); 
      DefaultHttpClient httpClient = new DefaultHttpClient(); 

      ResponseHandler <String> responseHandler = new BasicResponseHandler(); 
      HttpPost postMethod = new HttpPost(url); 
      postMethod.setEntity(new StringEntity(jsonObject.toString())); 
      postMethod.setHeader("Accept", "application/json"); 
      postMethod.setHeader("Content-type", "application/json"); 
      postMethod.setHeader("Data-type", "json"); 
      try{ 
      httpClient.execute(postMethod, responseHandler); 
      } catch (org.apache.http.client.HttpResponseException error){ 
       Log.d("Uploader Class Error", "Error code: "+error.getStatusCode()); 
       Log.d("Uploader Class Error", "Error message: "+error.getMessage()); 
       success = false; 
      } 
      //Log.d("server resposne", response); 
      return success; 
    } 

    public JSONObject constructPictureJson() throws JSONException, IOException{ 
     String userId = "1"; 
     String folderId = "1"; 
     String[] file = fileName.split("/"); 
     JSONObject pictureData = new JSONObject(); 
     pictureData.put("user_id", userId); 
     pictureData.put("folder_id", folderId); 
     pictureData.put("picture_name", "picture name"); 
     pictureData.put("picture_description", "1"); 
     pictureData.put("content_type", "jpg"); 
     pictureData.put("original_filename", "base64:"+file[file.length-1]); 
     pictureData.put("filename", file[file.length-1]); 
     pictureData.put("picture_path", encodePicture(fileName)); 

     return pictureData; 
    } 

    public String encodePicture(String fileName) throws IOException{ 
     File picture = new File(fileName); 
     return Base64.encodeToString(FileUtils.readFileToByteArray(picture), Base64.DEFAULT); 
    } 

} 

Có ai có ý tưởng nào không? Tôi đã bị mắc kẹt trên tất cả các ngày này. Tôi nghĩ bởi vì tôi không biết nhiều về Ruby Tôi hoặc là (1) làm sai lệch yêu cầu; hoặc (2) Tôi đã triển khai image base64 với Carrierwave không chính xác.

Trả lời

19

Cuối cùng đã giải quyết được sự cố! Tôi hy vọng câu trả lời này sẽ giúp những người khác đang cố gắng giải quyết vấn đề này vì không có nguồn lực tốt cho nó. Điều này thật đáng ngạc nhiên khi tôi nghĩ rằng những người khác sẽ muốn làm như vậy. Những thay đổi ban đầu của tôi đối với tệp khởi tạo Carrierwave dường như đã là một kết thúc chết.

Điều gì xảy ra khi tạo đối tượng hình ảnh được tải lên đó trong bộ điều khiển và sau đó tiêm nó trở lại vào các tham số. Đối với ví dụ cụ thể này, chúng tôi đang lấy một tệp base64 (mà tôi cho rằng bạn có, vì JSON không hỗ trợ tệp được nhúng) và lưu nó dưới dạng tệp tạm thời trong hệ thống, sau đó chúng tôi đang tạo đối tượng UploadedFile đó và cuối cùng reinjecting nó vào params.

gì json/my params trông giống như:

picture {:user_id => "1", :folder_id => 1, etc., :picture_path {:file => "base64 awesomeness", :original_filename => "my file name", :filename => "my file name"}} 

Đây là những gì điều khiển của tôi trông giống như bây giờ:

40  # POST /pictures 
41 # POST /pictures.json 
42 def create 
43 
44  #check if file is within picture_path 
45  if params[:picture][:picture_path]["file"] 
46   picture_path_params = params[:picture][:picture_path] 
47   #create a new tempfile named fileupload 
48   tempfile = Tempfile.new("fileupload") 
49   tempfile.binmode 
50   #get the file and decode it with base64 then write it to the tempfile 
51   tempfile.write(Base64.decode64(picture_path_params["file"])) 
52  
53   #create a new uploaded file 
54   uploaded_file = ActionDispatch::Http::UploadedFile.new(:tempfile => tempfile, :filename => picture_path_params["filename"], :original_filename => picture_path_params["original_filename"]) 
55  
56   #replace picture_path with the new uploaded file 
57   params[:picture][:picture_path] = uploaded_file 
58  
59  end 
60 
61  @picture = Picture.new(params[:picture]) 
62 
63  respond_to do |format| 
64  if @picture.save 
65   format.html { redirect_to @picture, notice: 'Picture was successfully created.' } 
66   format.json { render json: @picture, status: :created, location: @picture } 
67  else 
68   format.html { render action: "new" } 
69   format.json { render json: @picture.errors, status: :unprocessable_entity } 
70  end 
71  end 
72 end 

Điều duy nhất còn lại để làm vào thời điểm này là để xóa các tempfile, mà tôi tin rằng có thể được thực hiện với tempfile.delete

Tôi hy vọng điều này sẽ giúp với câu hỏi của bạn! Tôi đã dành cả ngày để tìm một giải pháp ngày hôm qua, và mọi thứ tôi đã thấy là một kết thúc chết. Điều này, tuy nhiên, hoạt động trên các trường hợp thử nghiệm của tôi.

+1

Điều này thật tuyệt vời! Cám ơn vì cái này. Tôi đã kết thúc việc đặt các tham số xử lý vào một 'before_filter: process_attached_file, chỉ:: create' gọi để giúp giữ cho phương thức create cleaner hơn. –

+3

Tôi đang cố gắng làm điều tương tự; bạn có thể đăng mã java cuối cùng cho ứng dụng Android của mình không? – scientiffic

+0

Bạn có nhớ chia sẻ triển khai cuối cùng của mình cho chức năng tải lên ở phía bên android không? Tôi đã làm một điều tương tự và tôi cũng đang sử dụng Rails nhưng tải lên thực sự là cực kỳ chậm - im giả định điều này là bởi vì tôi đang thử nghiệm trên webrick, nhưng tôi muốn được tò mò để xem nếu bạn thu nhỏ hình ảnh xuống hoặc giảm độ phân giải bằng mọi cách trước khi tải lên – Riptyde4

Các vấn đề liên quan