我正在尝试使用jhipster 4.0.0和angularjs构建的应用程序中构建文件上传器的后端和前端部分。 我该怎么办? Jhipster实际上是在使用实体构建器创建blob类型列,但将图像存储在数据库中并不是一个坏主意吗?
那么,我该如何构建该文件上传器?
答案 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);
}
}