You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AngularJS实现Blob文件编辑上传及Spring Boot文件存储方案咨询

解决从数据库获取、编辑并重新存储文件列表的问题

Hey, let's work through this together! The main problem right now is that your backend isn't returning key metadata for each file (like content type, filename, and a unique identifier). Without that, your frontend can't create proper Blobs for preview, and your backend won't know which existing file to replace when you upload updates. Here's a full, actionable solution:

一、First: Adjust Your Spring Boot Backend

First, you need to modify your backend to return file data along with metadata, not just raw byte arrays. Let's create a simple DTO to wrap this info:

public class FileDto {
    private Long id; // Unique ID from your DB to identify which file to update
    private String fileName;
    private String contentType;
    private byte[] content;

    // Add constructors, getters, and setters here
}

Update your /landownerDetails/{email} endpoint to return a List<FileDto> instead of a raw byte array. Now your frontend will get all the info it needs to handle each file correctly.

For the update endpoint (/user/landownerDetails/editProfile/{email}), set it up to accept:

  • The user's basic profile details
  • Updated files (either replacing existing ones via their ID, or new files)

You can use MultipartFile to handle uploaded files, and pass along the file IDs to map new files to existing database records. Here's a simplified example of the update controller:

@PostMapping("/user/landownerDetails/editProfile/{email}")
public ResponseEntity<?> updateLandOwnerProfile(
        @PathVariable String email,
        @RequestParam String fname,
        @RequestParam String lname,
        // Add all your other user profile fields here
        @RequestParam(value = "files", required = false) MultipartFile[] files,
        @RequestParam(value = "fileIds", required = false) Long[] fileIds) {

    // 1. Update the user's basic profile details first
    LandOwner landOwner = landOwnerRepository.findByEmail(email).orElseThrow();
    landOwner.setFname(fname);
    landOwner.setLname(lname);
    // Set other user fields...
    landOwnerRepository.save(landOwner);

    // 2. Handle file updates
    if (files != null && fileIds != null && files.length == fileIds.length) {
        for (int i = 0; i < files.length; i++) {
            MultipartFile uploadedFile = files[i];
            Long fileId = fileIds[i];

            if (fileId != null) {
                // Replace an existing file: find the record by ID and update it
                UserDocument existingDoc = userDocumentRepository.findById(fileId).orElseThrow();
                existingDoc.setContent(uploadedFile.getBytes());
                existingDoc.setFileName(uploadedFile.getOriginalFilename());
                existingDoc.setContentType(uploadedFile.getContentType());
                userDocumentRepository.save(existingDoc);
            } else {
                // Add a new file: create a new record linked to the user
                UserDocument newDoc = new UserDocument();
                newDoc.setContent(uploadedFile.getBytes());
                newDoc.setFileName(uploadedFile.getOriginalFilename());
                newDoc.setContentType(uploadedFile.getContentType());
                newDoc.setLandOwner(landOwner);
                userDocumentRepository.save(newDoc);
            }
        }
    }

    return ResponseEntity.ok(Map.of("status", true));
}

二、Now: Fix Your AngularJS Frontend

1. Process the Backend Response & Prepare Files for Display

In your landOwnerEditProfile controller, when you receive the userdocuments array, convert each entry to a usable object that includes the Blob, metadata, and a spot for new files:

serviceCalls.landOwnerEditProfile(sessionStorage.emailId)
.then((response)=>{
    console.log(response.data);
    let status = response.status;
    if(status===200){
        let landownerDetails = response.data;
        let landowner = landownerDetails.dayleasingusers;
        let userdocuments = landownerDetails.userdocuments;
        
        // Map the backend FileDto array to frontend-friendly objects
        $scope.files = userdocuments.map(doc => {
            // Create a Blob using the contentType from the backend
            const fileBlob = new Blob([doc.content], { type: doc.contentType });
            return {
                id: doc.id, // Keep the DB ID to identify which file to update
                fileName: doc.fileName,
                contentType: doc.contentType,
                blob: fileBlob,
                newFile: null // Will hold the user's selected replacement file
            };
        });

        // ... Your existing code to populate user profile fields ...
    }
})

2. Display Files & Add Edit/Replace Options

Add this HTML to render each file and let users replace them:

<div ng-repeat="file in files" class="file-item">
    <h4>{{file.fileName}}</h4>
    <!-- Preview based on file type -->
    <div class="file-preview">
        <img ng-if="file.contentType.startsWith('image/')" 
             ng-src="{{getBlobUrl(file.blob)}}" 
             alt="{{file.fileName}}" 
             style="max-width: 150px; max-height: 150px;">
        <object ng-if="file.contentType === 'application/pdf'"
                data="{{getBlobUrl(file.blob)}}"
                type="application/pdf"
                style="width: 200px; height: 250px;">
            Can't preview PDF - <a ng-href="{{getBlobUrl(file.blob)}}" download="{{file.fileName}}">Download</a>
        </object>
        <p ng-if="!file.contentType.startsWith('image/') && file.contentType !== 'application/pdf'">
            {{file.contentType}} file - <a ng-href="{{getBlobUrl(file.blob)}}" download="{{file.fileName}}">Download</a>
        </p>
    </div>
    <!-- Replace file input -->
    <input type="file" 
           ng-change="replaceFile(file, $event)" 
           class="mt-2"
           <!-- Remove accept if you want to allow changing file types -->
           accept="{{file.contentType}}">
</div>

Add these helper functions to your controller to handle Blob URLs and file replacement:

// Create a temporary URL for the Blob to render/ download
$scope.getBlobUrl = function(blob) {
    return URL.createObjectURL(blob);
};

// Handle when a user selects a new file to replace an existing one
$scope.replaceFile = function(file, event) {
    const selectedFile = event.target.files[0];
    if (selectedFile) {
        file.newFile = selectedFile;
        // Update the preview Blob with the new file
        file.blob = new Blob([selectedFile], { type: selectedFile.type });
    }
};

// Clean up Blob URLs when the controller is destroyed to avoid memory leaks
$scope.$on('$destroy', function() {
    $scope.files.forEach(file => {
        if (file.blob) {
            URL.revokeObjectURL(file.blob);
        }
    });
});

3. Update Your Upload Service to Send Modified Files

Modify your updateLandOwnerProfile service method to only send files that the user has modified, along with their IDs so the backend knows which records to update:

this.updateLandOwnerProfile = function(details, email) {
    var differed = $q.defer();
    $rootScope.config.headers.Authorization = sessionStorage.Authorization;
    var formdata = new FormData();

    // Add all user profile fields to FormData
    formdata.append("email", email);
    formdata.append("fname", details.user.fname);
    formdata.append("lname", details.user.lname);
    formdata.append("city", details.user.city);
    formdata.append("phone1", details.user.phone1);
    formdata.append("phone2", details.user.phone2);
    formdata.append("phone3", details.user.phone3);
    formdata.append("streetAddressLine1", details.user.streetAddressLine1);
    formdata.append("streetAddressLine2", details.user.streetAddressLine2);
    formdata.append("stripeApiKey", details.user.stripeApiKey);
    formdata.append("zipcode", details.user.zipcode);
    formdata.append("businessName", details.user.businessName);

    // Add only modified files (where newFile is not null)
    const modifiedFiles = details.files.filter(file => file.newFile !== null);
    modifiedFiles.forEach(file => {
        formdata.append("files", file.newFile);
        formdata.append("fileIds", file.id); // Send the original file ID
    });

    $http.post($rootScope.URL + "/user/landownerDetails/editProfile/"+email+"/", formdata, {
        transformRequest: angular.identity,
        headers: {
            "Content-Type": undefined,
            "Authorization": $rootScope.config.headers.Authorization
        }
    })
    .then(function(response) {
        if(!response.data.status){
            throw new Error("Details Not Updated");
        }
        console.log("Details updated success");
        differed.resolve(response);
    })
    .catch(function(response) {
        console.log("Update failed", response);
        differed.reject(response);
    });
    return differed.promise;
}

Key Things to Remember

  • Metadata is critical: Without sending the file ID, contentType, and filename between frontend and backend, you can't properly handle file previews or updates.
  • Clean up Blob URLs: Always revoke temporary Blob URLs when you're done with them to prevent memory leaks in the browser.
  • Only send changed files: No need to re-upload every file every time — just send the ones the user modified to save bandwidth.
  • Flexible file types: If you want to let users change the file type (e.g., replace a BMP with a PDF), just remove the accept attribute from the file input.

内容的提问来源于stack exchange,提问作者Sm Srikanth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:54:08