将文件上载到Jhipster中的目录

时间:2017-02-11 14:59:02

标签: angularjs file-upload spring-boot jhipster

我正在尝试使用jhipster 4.0.0和angularjs构建的应用程序中构建文件上传器的后端和前端部分。 我该怎么办? Jhipster实际上是在使用实体构建器创建blob类型列,但将图像存储在数据库中并不是一个坏主意吗?

那么,我该如何构建该文件上传器?

1 个答案:

答案 0 :(得分:0)

如果您不想将文件/图像作为blob保存到数据库,您可以考虑的另一个选项是创建单独的文件上传/检索服务(我们使用的是MongoDB gridFs,因为我们正在处理大型文件保存/更新实体时,仅发送成功上载文件的文件ID(或文件路径)。

您可以使用ng-file-upload来帮助管理,请注意以下代码使用的是angularJS版本1.

<form name="editForm" role="form" novalidate ng-submit="save(userUploadedFile)" show-validation>
    <div class="form-group">
                <div ng-show="entity.image == null">
                    <label class="control-label" for="field_file">Image</label>
                    <input type="file" ngf-select ng-model="userUploadedFile" name="file" id="field_file" 
                        ngf-max-size="8MB" ng-disabled="disableFile" ngf-change="upload($files)"  ngf-accept="'image/*'"/>
                    <button type="button" ng-click="removeUserUploadedFile()" ng-show="userUploadedFile">Remove</button>
                </div>
                <div ng-show="editForm.file.$invalid">
                    <p class="help-block" ng-show="editForm.file.$error.maxSize">Error! Image exceeds 8MB file limit</p>
                </div>
                <my-server-file file-id="entity.image" on-delete="onRemoveServerFile()"/>

        </div>
        <!-- include submit button etc -->

</form>

my-server-file指令:

angular.module('myApp')
    .directive('myServerFile', function(UrlService, FileService, $log) {
        return {
            restrict: 'E',
            scope: {
                fileId: "=fileId",
                callbackOnDelete: "&onDelete"
                    },
            template :  "<div ng-if='fileId'>" +
                "<a ng-if='fileId' ng-href='{{serverFilePath}}' target='_blank' download='{{fileName}}'>{{fileName}}</a>" +
                "<button type='button' ng-click='deleteServerFile()' ng-show='fileId'>Remove</button>" +
                "</div>",
            controller: ['$scope', 
                         function($scope) {

                            $scope.getFile = function(fileId) {
                                if(fileId){
                                    $scope.serverFilePath = UrlService.getContextPath() + '/api/file/' + fileId;
                                    FileService.getFileMetaData(fileId).then(function(file){
                                        $scope.fileName = file.name;
                                    });
                                }
                            }

                            $scope.deleteServerFile = function(){
                                FileService.deleteFile($scope.fileId).then(function() {
                                    $scope.callbackOnDelete();
                                });
                            }
                         }
                     ],
                     link: function(scope, iElement, iAttrs, ctrl) {
                         scope.$watch('fileId', function(value) {
                             scope.getFile(value);
                         })
                     }
        }
    })

您的控制器需要在保存之前上传文件。

'use strict';

angular.module('myApp').controller('myAppController',
    ['$scope', '$stateParams', '$uibModalInstance', 'entity', 'UrlService', 'Upload', '$timeout', 'MyEntity'
        function($scope, $stateParams, $uibModalInstance, entity, UrlService, Upload, $timeout, MyEntity) {

        $scope.entity = entity;
        $scope.load = function(id) {
            MyEntity.get({id : id}, function(result) {
                $scope.entity = result;
            });
        };

        $scope.onRemoveServerFile = function() {
            //Need to remove the file reference from the entity.
            $scope.entity.image = null;
            if($scope.entity.id){
                MyEntity.update($scope.entity);
            }
        }

        $scope.removeUserUploadedFile = function() {
            $scope.userUploadedFile = null;
        }

        var uploadFile = function(file){
            file.upload = Upload.upload({
                url: UrlService.getContextPath() + '/api/file',            
                file: file
              });

              file.upload.then(function (response) {
                $timeout(function () {
                  file.result = response.data;
                  $scope.entity.image = file.result.fileId;
                  saveEntity();
                });
              }, function (response) {
                if (response.status > 0)
                  $scope.errorMsg = response.status + ': ' + response.data;
              }, function (evt) {
                // Math.min is to fix IE which reports 200% sometimes
                file.progress = Math.min(100, parseInt(100.0 * evt.loaded / evt.total));
              });
        }

        var onSaveSuccess = function (result) {
            $scope.isSaving = false;
            $scope.$emit('myApp:entityUpdate', result);
            $uibModalInstance.close(result);
        };

        var onSaveError = function (result) {
            $scope.isSaving = false;
        };

        var saveEntity = function() {
            $scope.isSaving = true;
            if ($scope.entity.id != null) {
                MyEntity.update($scope.entity, onSaveSuccess, onSaveError);
            } else {
                MyEntity.save($scope.entity, onSaveSuccess, onSaveError);
            }
        };

        $scope.save = function (file) {
            if(file != null){
                uploadFile(file);
            }
            else {
                saveEntity();
            }
        };
}]);

但这确实会带来一些缺点,当你删除实体时,你需要单独删除文件。

创建一个简单的FileSerivce以与后端进行交互。

angular.module('myApp')
    .factory('FileService', function ($http) {
        return {
            getFile: function(fileId) {
                return $http.get('api/file/' + fileId).then(function (response) {
                    return response.data;
                });
            },
            getFileMetaData: function(fileId) {
                return $http.get('api/file/' + fileId + '/metaData').then(function (response) {
                    return response.data;
                });
            },
            deleteFile: function(fileId) {
                return $http.delete('api/file/' + fileId);
            }
        }
    });

最后你的REST控制器,这里我们委托GridFs的自定义包装器,但你可以将它保存到文件系统并返回完整路径作为id。

@RestController
@RequestMapping("/api/file")
public class FileController {

    private final Logger log = LoggerFactory.getLogger(FileController.class);

    @Inject
    private GridFsService gridFsService;

    @RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public Map<String, String> upload(@RequestParam("file") MultipartFile file)
            throws IOException {
        GridFSFile storeFile = null;
        if (!file.isEmpty()) {
            storeFile = gridFsService.storeFile(file);
        }
        Map<String, String> map = new HashMap<>();
        map.put("fileId", storeFile.getId().toString());
        return map;
    }

    @RequestMapping(value="/{fileId}", method = RequestMethod.GET)
    @ResponseBody
    public ResponseEntity<InputStreamResource> getFile(
            @PathVariable String fileId) throws IOException {

        return gridFsService.getFile(fileId).map(f -> new ResponseEntity<> (
                new InputStreamResource(f.getInputStream()),
                HeaderUtil.createFileContentLengthAndContentTypeHeaders(f.getLength(), f.getContentType()),
                HttpStatus.OK
                )).orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));


    }

    @RequestMapping(value="/{fileId}/metaData", 
            method = RequestMethod.GET, 
            produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public ResponseEntity<Map<String, String>> getFileMetaData(
            @PathVariable String fileId) throws IOException {

        Optional<GridFSDBFile> optFile = gridFsService.getFile(fileId);
        if(!optFile.isPresent()){
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }

        GridFSDBFile file = optFile.get();

        Map<String, String> map = new HashMap<>();
        map.put("name", file.getFilename());
        map.put("contentType", file.getContentType());
        map.put("size", String.valueOf(FileUtils.byteCountToDisplaySize(file.getLength())));

        return ResponseEntity.ok()
                .body(map);

    }

    @RequestMapping(value="/{fileId}", method = RequestMethod.DELETE)
    public void deleteFile(
            @PathVariable String fileId) throws IOException {
        log.debug("REST request to delete File : {}", fileId);
        gridFsService.deleteFile(fileId);
    }

}