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

如何在Java REST客户端接收Angular传来的Blob数据

问题分析

你遇到的核心问题有两个:

  1. java.sql.Blob是抽象类,没有默认构造器,Jackson无法直接实例化它;
  2. 前端将Blob放入JSON payload发送时,浏览器会把Blob序列化成仅包含size和type的普通对象,根本没有传输实际的二进制PDF数据,这才是导致反序列化失败的根源,添加@JsonTypeInfo无法解决这个本质问题。

下面给出两种可行的解决方案,优先推荐第一种。


方案一:使用FormData传输(最推荐,标准文件上传方式)

FormData是浏览器专门用来传输文件和表单数据的格式,Spring对它的支持非常完善,完全避免JSON传输二进制的问题。

前端(Angular)修改

修改服务中的submitOrderedItems方法,用FormData分别封装Order对象(转成JSON字符串)和PDF Blob:

public submitOrderedItems(order: Order, pdf: Blob) {
  console.log("submitting ordered items");
  const url = "http://localhost:8080/orders/add";

  const formData = new FormData();
  // 将Order对象序列化为JSON字符串
  formData.append('order', JSON.stringify(order));
  // 添加PDF Blob,指定文件名和MIME类型
  formData.append('pdf', pdf, 'order_' + Date.now() + '.pdf');

  this.http.post(url, formData).subscribe(value => {});
  
  console.log("sended");
}

后端(Spring)修改

  1. 废弃OrderAndBlob类,控制器方法改用@RequestParam接收FormData中的参数:
@RestController
@RequestMapping("/orders")
@CrossOrigin(origins = "*", maxAge = 3600)
public class OrderController {
    @Autowired
    private ObjectMapper objectMapper; // 用于解析JSON字符串为Order对象
    @Autowired
    private OrderService orderService;

    @PostMapping("/add")
    @PreAuthorize("hasRole('USER')")
    public void addOrders(@RequestParam("order") String orderJson, 
                          @RequestParam("pdf") MultipartFile pdfFile) throws IOException, SQLException {
        // 将JSON字符串转为Order对象
        Order order = objectMapper.readValue(orderJson, Order.class);
        
        // 若需要将MultipartFile转为java.sql.Blob,可通过以下方式实现
        Blob pdfBlob = new SerialBlob(pdfFile.getBytes());
        System.out.println(pdfBlob);
        
        orderService.saveOrderAndLines(order);
        // 这里可以添加PDF Blob的持久化逻辑
    }
}

方案二:Base64编码传输(JSON兼容方式)

如果必须用JSON payload传输,可将Blob转为Base64字符串,后端接收后再解码为二进制数据并转为Blob。

前端(Angular)修改

  1. 在生成Blob后,通过FileReader将其转为Base64字符串:
confirmOrder(): void {
  let DATA: any = document.body;
  html2canvas(DATA).then((canvas) => {
    let fileWidth = 208;
    let fileHeight = (canvas.height * fileWidth) / canvas.width;
    let PDF = new jsPDF('p', 'mm', 'a4');
    let position = 0;
    PDF.addImage(canvas, 'PNG', 0, position, fileWidth, fileHeight);
    this.pdfBlob = PDF.output('blob');

    // 将Blob转为Base64字符串(去掉前缀,只保留编码部分)
    const reader = new FileReader();
    reader.onload = () => {
      const fullBase64 = reader.result as string;
      const pdfBase64 = fullBase64.split(',')[1];
      this.salesproductService.submitOrderedItems(this.order, pdfBase64);
      this.router.navigate(["/main"]);
    };
    reader.readAsDataURL(this.pdfBlob);
  });
}
  1. 修改服务方法,发送包含Order和Base64字符串的JSON payload:
public submitOrderedItems(order: Order, pdfBase64: string) {
  console.log("submitting ordered items");
  const url = "http://localhost:8080/orders/add";

  const payload = {
    order: order,
    pdfBase64: pdfBase64
  };

  this.http.post(url, payload).subscribe(value => {});
  
  console.log("sended");
}

后端(Spring)修改

  1. 修改OrderAndBlob类,改为接收Base64字符串,再提供转为Blob的方法:
public class OrderAndBlob {
    private Order order;
    private String pdfBase64;

    // Getter和Setter
    public Order getOrder() {
        return order;
    }

    public void setOrder(Order order) {
        this.order = order;
    }

    public String getPdfBase64() {
        return pdfBase64;
    }

    public void setPdfBase64(String pdfBase64) {
        this.pdfBase64 = pdfBase64;
    }

    // 将Base64字符串转为java.sql.Blob
    public Blob getPdfBlob() throws SQLException {
        byte[] pdfBytes = Base64.getDecoder().decode(pdfBase64);
        return new SerialBlob(pdfBytes);
    }
}
  1. 控制器方法保持@RequestBody,调用转换方法获取Blob:
@RestController
@RequestMapping("/orders")
@CrossOrigin(origins = "*", maxAge = 3600)
public class OrderController {
    @Autowired
    private OrderService orderService;

    @PostMapping("/add")
    @PreAuthorize("hasRole('USER')")
    public void addOrders(@RequestBody OrderAndBlob orderAndBlob) throws SQLException {
        Blob pdfBlob = orderAndBlob.getPdfBlob();
        System.out.println(pdfBlob);
        orderService.saveOrderAndLines(orderAndBlob.getOrder());
    }
}

内容的提问来源于stack exchange,提问作者Yannick Mussche

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 08:40:31