简体   繁体   English

从Android / Java将Base64上传到RoR Carrierwave

[英]Base64 upload from Android/Java to RoR Carrierwave

I added the solution from use base64 image with Carrierwave in an effort to upload an image from a java class. 我添加了将Base64图像与Carrierwave结合使用的解决方案,以尝试从Java类上传图像。 This is now what my FileUploader class looks like -- and I believe to be where the problem is: 这就是我的FileUploader类的样子-我认为问题出在哪里:

# 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

The picture model: 图片型号:

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

Right now when the Post call is made the file path that is saved in the db is nil -- but everything else is saved. 现在,在进行Post调用时,保存在数据库中的文件路径为nil,但其他所有内容均已保存。 Here is the java/android class: 这是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);
    }

}

Does anyone have any ideas? 有人有什么想法吗? I've been stuck on this all day. 我整天都被困住了。 I think because I don't know much about Ruby I am either (1) malforming the request; 我想是因为我对Ruby不太了解,所以我要么(1)错误地处理了请求; or (2) I implemented the base64 image with Carrierwave incorrectly. 或(2)我用Carrierwave错误地实现了base64映像。

Finally solved the problem! 终于解决了问题! I hope this answer helps out others who are trying to solve this problem as there is no good resource for it. 我希望这个答案可以帮助其他尝试解决此问题的人,因为没有足够的资源。 This was surprising as I figured others would have wanted to do the same. 令我惊讶的是,我发现其他人也想这样做。 My original changes to the Carrierwave initialize file appear to have been a dead end. 我对Carrierwave初始化文件的原始更改似乎已死胡同。

What it came down to was creating that uploaded image object in the controller and then injecting it back into the params. 最终的结果是在控制器中创建了上载的图像对象,然后将其注入到参数中。

For this specific example, we are taking a base64 file (which I assume you have, as JSON doesn't support embeded files) and saving it as a temp file in the system then we are creating that UploadedFile object and finally reinjecting it into the params. 对于此特定示例,我们将获取一个base64文件(我假设您具有,因为JSON不支持嵌入文件),并将其另存为系统中的临时文件,然后创建该UploadedFile对象,最后将其重新注入到参数。

What my json/params looks like: 我的json / params看起来像什么:

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

Here is what my controller looks like now: 这是我的控制器现在的样子:

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

The only thing left to do at this point is to delete the tempfile, which I believe can be done with tempfile.delete 此时唯一要做的就是删除tempfile,我相信可以使用tempfile.delete来完成。

I hope this helps with your question! 希望这对您的问题有所帮助! I spent all day looking for a solution yesterday, and everything I have seen is a dead end. 昨天我整天都在寻找解决方案,而我所看到的一切都是死胡同。 This, however, works on my test cases. 但是,这适用于我的测试用例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM