Java REST API returns 附有图像但不会显示在 Angular 前端的对象

Java REST API returns object with image attached but will not display in Angular Front End

我有一个 API,其中 returns 一个 Product 对象附加了一个 ImageModel,它是存储在 MYSQL 数据库中的图像 table。我知道这可能很简单,但在过去的 36 个小时里,我一直在努力弄清楚这里发生了什么!

所以我想基本上在我创建的电子商务网站上展示产品以及产品图片。 API returns 产品和图像数据正确,但是前端不会显示图像,只显示产品数据。

这是 API 的回复:

响应列表中的每个对象都包含相同的内容,当然只是填充了不同的产品数据。现在,据我所知,我应该能够将 imageModel 数据传递给 javascripts filereader 以将其转换为图像,但它似乎不起作用。

这是代码:

    getProductsByCategory(obj) {

    let request ={
      "cat_id":obj.id
    }

   this.http.postRequestWithToken('api/product/getProductsByCategory',request).subscribe(data=>{
      this.productsList = data
      console.log('Prod List = ', this.productsList);
      if(this.productsList.length == 0){
        alert("No Product is found..");
      }

      this.productsList.forEach(product => {
            const reader = new FileReader();
            reader.readAsDataURL(product.imageModel);
            reader.onloadend = () => {
            product.images = reader.result;
         }
      });
   },error=>{
     alert("Error in login "+error);
   })
  }

productsList是控制台显示的数据,每次调用API时肯定存在。然后我遍历 productList 数据并尝试使用 readDataAsUrl 读取图像数据,然后给出错误:

我的目标是在 HTML 中简单地显示图像和产品数据,如下所示:

<div id="myTabContent" class="tab-content">
          <div role="tabpanel" class="tab-pane fade active in" id="home" aria-labelledby="home-tab">
            <div   class="agile_ecommerce_tabs">
              <div  *ngFor="let data of productsList" class="col-md-4 agile_ecommerce_tab_left">
                <div class="hs-wrapper">
                  <img src="***{{data.image}}***" alt=" " class="img-responsive" />
                  <div class="w3_hs_bottom">
                    <ul>
                      <li>
                        <a href="#" data-toggle="modal" data-target="#myModal"><span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span></a>
                      </li>
                    </ul>
                  </div>
                </div>
                <!-- <h5><a href="single.html">{{data.name}}</a></h5> -->
                <h5><a style="cursor:pointer;" (click)="product_btn(data.id)">{{data.name}}</a></h5>

                <div class="simpleCart_shelfItem">
                  <p>
                    <span>{{data.price}}</span> <i class="item_price">£ {{data.price}}</i>
                  </p>
                    <button (click)="addCart(data)" type="submit" class="w3ls-cart">Add to cart</button>
                </div>
              </div>
              <div class="clearfix"> </div>
            </div>
          </div>

注意这行: <img src="***{{data.image}}***" alt=" " class="img-responsive" /> 显然行不通,但如果可能的话我想这样做,这样每个产品都会与其正确的图像相匹配。

我参考了各种不同的帖子来尝试帮助我实现这一目标,例如:

我也尝试编写一个方法,然后将其传递到之前显示的循环中,但再次无法正常工作:

createImageFromBlob(image: Blob) {
    let reader = new FileReader();
    reader.addEventListener("load", () => {
    this.imageToShow = reader.result;
    }, false);

   if (image) {
      reader.readAsDataURL(image);
   }
}

我一直在兜圈子,似乎没有任何效果!我猜我错过了一些非常简单的东西。如果有人有任何想法,将不胜感激!感谢您的宝贵时间!


编辑 2


所以,我已经使用提供的答案清理了 url,并且在咨询了这个 我现在在控制台或我的终端中没有错误(这更烦人哈哈)

更新:

我现在遍历所有 productList 并清理图像并将其添加回 productList 作为 imageUpdate,如下所示:

    getProductsByCategory(obj) {
    let request ={
      "cat_id":obj.id
    }

   this.http.postRequestWithToken('api/product/getProductsByCategory',request).subscribe(data=>{
      this.productsList = data
      console.log('Prod List = ', this.productsList);

      if(this.productsList.length == 0){
        alert("No Product is found..");
      }

      this.productsList.forEach(product => {
        const sanitizedImage = this.sanitizer.bypassSecurityTrustUrl(`data:${product.imageModel.type};base64,${product.imageModel.picByte}`);
        product.imageUpdate = sanitizedImage;
      });

      this.productsList.forEach(element => {
        console.log('Final Updated Elements', element);
      });

   },error=>{
     alert("Error in login "+error);
   })
  }

这成功更新了 productList 如下:

然后我不得不将 html 修改为:

<img [src]="data.imageUpdate" alt=" " class="img-responsive" />

使用绑定语法。

然而,在网站上,图像仍然不显示:(

我不知道为什么会这样!!

您的 picByte 是一个 base64 编码的字符串。您可以简单地将此字符串传递给图像标签,如

<img src="data:image/jpg;base64,R0lGODdhEAAQAMwAAPj7+FmhUYjNfGuxYYDJdYTIeanOpT+DOTuANXi/bGOrWj6CONzv2sPjv2CmV1unU4zPgI/Sg6DJnJ3ImTh8Mtbs00aNP1CZSGy0YqLEn47RgXW8amasW7XWsmmvX2iuXiwAAAAAEAAQAAAFVyAgjmRpnihqGCkpDQPbGkNUOFk6DZqgHCNGg2T4QAQBoIiRSAwBE4VA4FACKgkB5NGReASFZEmxsQ0whPDi9BiACYQAInXhwOUtgCUQoORFCGt/g4QAIQA7" />

(此示例显示一个支票。)

你只需要构建这个 src 字符串,它应该看起来像

<img src="data:{{product.imageModel.type}};base64,{{product.imageModel.picByte}}" alt=" " class="img-responsive" />

(我在此处将您的 data iteratee 更改为 product 以避免混淆)


编辑:

您可能需要清理 url。在这种情况下,您需要映射您收到的产品并添加以下内容 属性:

constructor(private sanitizer: DomSanitizer) { }


const sanitizedImage = this.sanitizer.bypassSecurityTrustUrl(`data:${product.imageModel.type};base64,${product.imageModel.picByte}`);

好的,我想通了。事实证明这是一个比我最初尝试实施的解决方案简单得多的解决方案。我将 API 端点修改为 return a byte[] 并生成 MediaType.IMAGE_JPEG_VALUE 直接将图像作为浏览器可以正确显示的资源。这是代码:

@GetMapping(value = "/getImage/{imageId}", produces = MediaType.IMAGE_JPEG_VALUE)
    public byte[] getImage(@PathVariable("imageId") String imageId) throws IOException {
        final Optional<ImageModel> retrievedImage = imageRepository.findById(Long.valueOf(imageId));

        ImageModel img = new ImageModel(retrievedImage.get().getName(), retrievedImage.get().getType(),
                decompressBytes(retrievedImage.get().getPicByte()));
        
        return img.getPicByte();
    }

此方法基本上是从数据库中 returns byte[]。从前端我现在可以调用端点资源并且它 return 是预期的图像:

 <img src="{{baseUrl}}/api/product/getImage/{{data.imageModel.id}}" alt=" " class="img-responsive" />