end0tknr's kipple - web写経開発

太宰府天満宮の狛犬って、妙にカワイイ

html5のFileAPIと spring bootで ドラッグ&ドロップなファイル・アップロード、ついでにAWS S3へも登録...

で、spring boot for java が、おおよそ分かってきた気がするので、 webアプリっぽい機能を一つ書いてみた。以下

html

<html lang="ja">
<body>

<table>
  <thead>
    <tr>
    <th style="width:120px;">ファイル</th>
    <td id="file_drop_zone" colspan="2" style="width:500px;">
  ここにファイルをドラッグ&ドロップして下さい
    </td>
    </tr>
  </thead>
  <tbody id="file_dropped_zone">
  </tbody>
  <tfoot>
    <tr>
    <td></td>
    <td colspan="2">
      <button type="button"
          onClick="doc_list.submit_docs()">登録実行</button></td>
    </tr>
  </tfoot>
</table>

<script id="tmpl_droped_file" type="text/x-jquery-tmpl">
<tr>
  <td><input type="hidden" class="fileContent" name="fileContent"></td>
  <td class="fileName"></td>
  <td class="fileSize"></td>
</tr>
</script>

<script src="/jquery/jquery-3.2.1.min.js"></script>
<script src="/jquery/jquery.tmpl.js"></script>
<script src="/jquery/jquery.json.js"></script>
<script src="/js/DocList.js"></script>
<script>
  $(document).ready(function(){  doc_list.init_page(); });
</script>
</body>
</html>

javascript

ドラッグ&ドロップでファイルを開き、 reader.readAsDataURL(file) によりBASE64 の文字列でサーバ側にPOSTしています。

(function() {

var DocList = function() {};

DocList.prototype = {
    init_page: function(){
        this.init_file_drop_zone();
    },

    init_file_drop_zone: function(){
        var this_obj = this;

        $('#file_drop_zone').on("dragover",function(evt){
            evt.stopPropagation();
            evt.preventDefault();
            evt.originalEvent.dataTransfer.dropEffect = 'copy';
        });
        $('#file_drop_zone').on("drop",function(evt){
            evt.stopPropagation();
            evt.preventDefault();
            var files = evt.originalEvent.dataTransfer.files;
            if(files.length != 1){
                alert('1ファイルのみドロップできます');
                return;
            }

            var drop_elm = evt.target;
            var file = files[0];
            var reader = new FileReader();
            
            reader.onload = (function(theFile) {
                return function(e){
                    file.content =  e.target.result;
                    this_obj.post_read_file(file, drop_elm);
                };
            })(file);
            
            reader.readAsDataURL(file); //BASE64でファイルを読込み
            // reader.readAsArrayBuffer(file);
            // reader.readAsBinaryString(file);
            // reader.readAsText(file);
        });
    },

    // FileAPIによる読込み結果をDOMに反映
    post_read_file: function(file, drop_elm){
        var list_tr = $('#tmpl_droped_file').tmpl();
        this.fill_in_droped_file_tr(list_tr, file );

        $('#file_dropped_zone').append( list_tr );
        //file.content
    },
    
    fill_in_droped_file_tr: function(tr, file ){
        $('.fileName',    tr).html(file.name);
        $('.fileSize',    tr).html(file.size/1000 +'KB');
        $('.fileContent', tr).val(file.content);
        return tr;
    },

    
    submit_docs: function(){
        var data = {
            teiCode: $('#tei_code').text(),
            fileNames : [],
            fileContents : []
        };

        $("#file_dropped_zone tr").each(function(){
            var upfile_name = $(".fileName", $(this)).text();
        // reader.readAsDataURL()では先頭に余計な文字列(MIME TYPE)が
        // 入るので、これを削除
            var upfile_content =$(".fileContent",$(this)).val().split(",")[1];
            if(upfile_name && upfile_content){
                data.fileNames.push(upfile_name);
                data.fileContents.push(upfile_content);
            }
        });

        var req_url = '/DocListRest/' + data.tei_code + '/upfiles';
        var this_obj = this;
        $.ajax({url: req_url,
                type: 'POST',
                data: data,
                success: function(ret_json,txt_status,xhr){
                    var ret_data = $.parseJSON( ret_json );
                    if (ret_data.result =='success'){
                        alert('SUCCESS');
                    } else {
                        alert('FAIL');
                    }
                },
                error: function(ret_json,txt_status,xhr){
                    alert('FAIL');
                }
               });
        
    },
};

window.doc_list = new DocList();
})();

サーバ側 (spring boot for java )

package jp.end0tknr.streamdoc.ctrl;

import java.util.List;
import java.util.Map;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Base64;
import java.util.HashMap;
import java.util.LinkedHashMap;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.ui.Model;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import jp.end0tknr.streamdoc.objmodel.ImageMagick;
import jp.end0tknr.streamdoc.objmodel.TeiDoc;


@RestController
public class DocListRest {
    private static final Logger logger =
            LoggerFactory.getLogger(DocListRest.class);
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    private static final String ACCESS_KEY   = "ないしょ";
    private static final String SECRET_KEY   = "ないしょ";
    
    @RequestMapping(value="/DocListRest/{teiCode}/upfiles")
    public HashMap<String, String> upfiles (
            @PathVariable String teiCode,
            @RequestParam("fileNames[]") List<String> fileNames,
            @RequestParam("fileContents[]") List<String> fileContents,
            Model model) {
        logger.info("start upfiles()");

        logger.info( Regions.AP_NORTHEAST_1.toString() );

        BasicAWSCredentials awsCreds =
                new BasicAWSCredentials(ACCESS_KEY, SECRET_KEY);
        
        AmazonS3 s3client =
                AmazonS3ClientBuilder.standard()
                .withRegion(Regions.AP_NORTHEAST_1)
                .withCredentials(new AWSStaticCredentialsProvider(awsCreds))
                .build();

        ImageMagick imageMagick = new ImageMagick();
        
        
        int i = 0; 
        for (String fileContent : fileContents ) {
            String fileName = fileNames.get(i);
            FileOutputStream newFile;
            
            String newFilePath = "c:/home/endo/tmp/"+fileName; 
            
            try {
                newFile = new FileOutputStream(newFilePath);
                newFile.write( Base64.getDecoder().decode(fileContent) );
                newFile.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            
            File file = new File(newFilePath);
            try {
                logger.info( "tmp/"+fileName );
                s3client.putObject(new PutObjectRequest(
                        "test-end0tknr",
                        "tmp/"+fileName, file));
            } catch (AmazonServiceException ase) {
                logger.error(ase.getMessage());
            } catch (AmazonClientException ace) {
                logger.error(ace.getMessage());
            } 
        
            imageMagick.convThumbnail(newFilePath);
            
            
            i++;
        }

        logger.info("done upfiles()");
        HashMap<String,String> retVals = new HashMap<String,String>();
        retVals.put("result","success");
        return retVals;
    }
}