如何通过jQuery.ajax发送含String与Blob的对象至Spring REST并接收?
Got it, let's walk through this end-to-end—from sending the data with jQuery.ajax to receiving it in Spring, mapping to a custom model, and saving everything to the database. Here's how to make it work:
Since JSON doesn't natively support Blob types, we'll use FormData to package both the string and blob data. This is the most reliable way to send mixed data types via AJAX.
// Assume you have a string value and a Blob (e.g., from a file input) const textValue = "Hello from frontend!"; const fileBlob = document.getElementById("fileInput").files[0]; // This is a Blob // Create FormData and append your data const formData = new FormData(); formData.append("textContent", textValue); formData.append("fileBlob", fileBlob); // Send via jQuery.ajax $.ajax({ url: "/api/upload", type: "POST", data: formData, contentType: false, // Critical: Let browser set correct multipart boundary processData: false, // Critical: Prevent jQuery from converting FormData to string success: function(response) { console.log("Upload successful:", response); }, error: function(xhr) { console.error("Upload failed:", xhr.responseText); } });
Why contentType: false and processData: false? The browser automatically sets the correct multipart/form-data header with a boundary when using FormData, so we don't want jQuery overriding that. Disabling processData stops jQuery from trying to serialize the FormData object into a query string.
We'll create a model class to map the incoming FormData fields. Since Spring handles Blobs from multipart requests as MultipartFile, our model will include that type along with the string field.
import org.springframework.web.multipart.MultipartFile; import lombok.Data; // Use @Data from Lombok to auto-generate getters/setters (optional but convenient) @Data public class MyModel { private String textContent; // Matches the "textContent" key in FormData private MultipartFile fileBlob; // Matches the "fileBlob" key in FormData }
If you don't use Lombok, just add manual getter and setter methods for both fields—Spring needs these to bind the request data to the model.
By default, Spring uses @ModelAttribute to bind multipart/form-data requests to model objects, but if you specifically need to use @RequestBody, we need to add a custom message converter to handle multipart data with Jackson.
First, the controller:
import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api/upload") public class UploadController { private final MyDataService dataService; // Constructor injection (preferred over @Autowired) public UploadController(MyDataService dataService) { this.dataService = dataService; } @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity<String> uploadData(@RequestBody MyModel myModel) { try { dataService.saveToDatabase(myModel); return ResponseEntity.ok("Data saved successfully"); } catch (Exception e) { return ResponseEntity.internalServerError().body("Save failed: " + e.getMessage()); } } }
Next, configure the message converter to let Jackson parse multipart requests into your model:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.MultipartJackson2HttpMessageConverter; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import com.fasterxml.jackson.databind.ObjectMapper; @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void configureMessageConverters(java.util.List<org.springframework.http.converter.HttpMessageConverter<?>> converters) { converters.add(multipartJackson2HttpMessageConverter()); } @Bean public MultipartJackson2HttpMessageConverter multipartJackson2HttpMessageConverter() { MultipartJackson2HttpMessageConverter converter = new MultipartJackson2HttpMessageConverter(); converter.setObjectMapper(new ObjectMapper()); return converter; } }
Note: If you don't strictly need @RequestBody, using @ModelAttribute is simpler—just replace @RequestBody with @ModelAttribute in the controller method, and you can skip the message converter configuration.
First, define your JPA entity to map to the database table. We'll store the Blob as a byte[] (annotated with @Lob to mark it as a large object):
import jakarta.persistence.*; import lombok.Data; @Entity @Table(name = "uploaded_data") @Data public class MyDataEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String textContent; @Lob // Marks this as a BLOB type in the database private byte[] fileData; }
Then create a repository interface:
import org.springframework.data.jpa.repository.JpaRepository; public interface MyDataRepository extends JpaRepository<MyDataEntity, Long> { }
Finally, the service layer to handle converting the model to the entity and saving:
import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; @Service public class MyDataService { private final MyDataRepository repository; public MyDataService(MyDataRepository repository) { this.repository = repository; } public void saveToDatabase(MyModel myModel) throws IOException { MyDataEntity entity = new MyDataEntity(); entity.setTextContent(myModel.getTextContent()); // Convert MultipartFile to byte[] for database storage entity.setFileData(myModel.getFileBlob().getBytes()); repository.save(entity); } }
Key Notes
- Make sure the field names in
MyModelexactly match the keys you used inFormData.append()—Spring uses these names to bind the data. - If you're dealing with large Blobs, check your database's maximum BLOB size limit (e.g., MySQL's
max_allowed_packet). - Handle exceptions properly (like
IOExceptionwhen reading the MultipartFile) to avoid unhandled errors in your controller.
内容的提问来源于stack exchange,提问作者Flora

