如何在Thymeleaf中显示模型中的字节数组

时间:2018-01-12 23:24:45

标签: spring-mvc thymeleaf

我想显示所有产品信息,但显示产品图片时出现问题。我从DB获取我的产品然后将它们添加到Model,但不知道为什么只有图像不显示。在HTML中它看起来像这样:

<div class="row">
    <div class="col-sm-3 my-2 d-flex align-content-stretch flex-wrap" th:each="product : ${products}">
        <div class="card">
            <img class="card-img-top" th:src="${product.image}">
            <div class="card-body">
                <h5 class="card-title" th:text="${product.name}">Product name</h5>
                <p class="card-text" th:text="${product.description}">Product summary</p>
                <p class="card-text" th:text="${product.cost}">Product summary</p>
            </div>
        </div>
    </div>
</div>

在控制器中我添加了所有这样的产品:

@GetMapping("/")
public String getHomePage(Model model) {
    model.addAttribute("products", productRepository.findAll());
    return "home";
}

产品型号如图所示:

@Entity
@Getter
public class Product extends BaseEntity {

    private String name;

    private String description;

    @OneToOne
    private Category category;

    private double cost;

    @Lob
    private byte[] image;

    public Product() {
        super();
    }

    public Product(String name, String description, Category category, double cost, byte[] image) {
        this();
        this.name = name;
        this.description = description;
        this.category = category;
        this.cost = cost;
        this.image = image;
    }
}

我的问题是我想一次显示多张图片。 顺便说一句,我知道findAll方法并不是一个好的选择,但它只适用于测试建议。后来我想实现分页,但首先如何显示一个字节数组图像?

2 个答案:

答案 0 :(得分:1)

使用 Spring Boot 并遇到同样的问题,我不相信使用 HttpServletResponse 在单独的请求中获取图像,因为我们已经检索了模型属性中包含的图像字节数组,我想知道:如何加载来自字节数组本身的图像

通过将图像字节数组转换为 base64 字符串并将其传递给 JavaScript 以填充图像预览元素找到了解决方案:

在 Java 中

添加一个额外的 String 属性表示图像的 base64 编码值:

private String imageBase64;

从数据库中获取对象后,添加一个额外的从图像字节数组转换为base64的步骤如下:

if(ArrayUtils.isNotEmpty(product.getImage())) {
    String imageBase64 = Base64.getEncoder().encodeToString(product.getImage());
    productDTO.setImageBase64(imageBase64);
}

在 JSP/HTML 中

添加一个额外的隐藏字段,包含图像的 base64 字符串

<input type="hidden" id="imageBase64" value="${product.imageBase64}" readonly></input>
<img id="imagePreview" src="#" alt="Background image" />

在 JavaScript 中

通过隐藏字段中的base64值设置图像内容

var imageBase64 = $('#imageBase64').val();
var imagePreview= document.getElementById('imagePreview');
if(imagePreview) {
    imagePreview.src = "data:image/png;base64," + imageBase64;
}

此外,还可以将图像存储为 Base64 字符串并摆脱自定义转换阶段...

答案 1 :(得分:0)

我正在回答这个老问题,希望能帮助有同样需求的人。

为了使用字节显示图像,您必须创建一个控制器操作来显示图像:

@GetMapping("/product/image/{id}")
public void showProductImage(@PathVariable String id
                               HttpServletResponse response) throws IOException {
response.setContentType("image/jpeg"); // Or whatever format you wanna use

Product product = productRepository.findById(id);

InputStream is = new ByteArrayInputStream(product.getImage());
IOUtils(is, response.getOutputStream());
}

因此,您只需使用以下命令即可显示图像:

<div class="row">
    <div class="col-sm-3 my-2 d-flex align-content-stretch flex-wrap" th:each="product : ${products}">
        <div class="card">
            <img class="card-img-top" th:src="@{'product/image/' + @{product.image}}">
            <div class="card-body">
                <h5 class="card-title" th:text="${product.name}">Product name</h5>
                <p class="card-text" th:text="${product.description}">Product summary</p>
                <p class="card-text" th:text="${product.cost}">Product summary</p>
            </div>
        </div>
    </div> 

PS:尽管图像属性使用字节,但最好还是使用包装字节。这将使您管理没有图像的情况(空)