【问题标题】:How to display @Lob image from mysql database using spring mvc and jsp如何使用spring mvc和jsp从mysql数据库中显示@Lob图像
【发布时间】:2018-12-06 07:55:28
【问题描述】:

有到 github 的链接:https://github.com/Lukszn/ProjectProfile 我使用的是 Spring 4.3.7.RELEASE,MySQL Connector Java:5.1.39 和 hibrnate:5.2.9。最后 我有用户和他的帐户模型。在帐户中,我有@Lob accPicture 和一些字符串(+ get/set)。我正在尝试从 stackoverflow 和文档中获得很多答案来显示帐户图像,但没有成功。最后想想我在做什么:创建自己的 ImageController。我成功地将图像存储在数据库中,但是当我尝试在我的 jsp 中显示它时,它显示“HTTP 状态 400 - 客户端发送的请求在语法上不正确。” 首先,我向您展示我的用户模型:

@Entity
@Table(name = "users")
public class User implements Serializable{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(unique = true)
    @NotBlank
    @Size(min=4,max=20)
    private String login;

    @NotBlank
    private String password;

    @Column(unique = true)
    @Email
    @NotBlank
    private String email;

    private String permission;

    @OneToMany()
    private List<Account> accounts;


    public User(final String login, final String password, final String email) {
        Preconditions.checkArgument(!Strings.isNullOrEmpty(login));
        Preconditions.checkArgument(!Strings.isNullOrEmpty(password));
        Preconditions.checkArgument(!Strings.isNullOrEmpty(email));
        this.login = login;
        this.password = password;
        this.email = email;
    }

    public User() {
    }
}
+ get/set

账户模型:

@Entity
@Table(name = "accounts")
public class Account {


    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    private boolean ifBasicAccount;

    private String accTitle;

    private String accFirstName;

    private String accLastName;

    private String accBirthdate;

    private String accPhoneNumber;

    private String accEducation;

    private String accExperience;

    private String accAbilities;

    private String accInterests;

    private String accProjects;

    private String accDescription;

    @Lob
    private byte[] accPicture;


    @ManyToOne
    private User user;


    public Account() {
    }

   + get/set

下一个帐户控制人:

@Controller
public class AccountController {

    @Autowired
    AccountRepository accountRepository;

    @Autowired
    UserRepository userRepository;


    @RequestMapping(method = RequestMethod.GET, value ="addAccount")
    public String addAccount(Model model) {
        Account account = new Account();
        model.addAttribute("account", account);

        return "addAccount";
    }

    @RequestMapping(method = RequestMethod.POST, value ="addAccount")
    public String addAccount(@ModelAttribute Account account, HttpSession session) {
        User user = userRepository.findOne((Long) session.getAttribute("user_id"));
        account.setIfBasicAccount(false);
        account.setUser(user);
        accountRepository.save(account);
        return "redirect:/accounts";
    }

    @RequestMapping("/accounts")
    public String accountList(Model model, HttpSession ses) {
        long userId = (Long) ses.getAttribute("user_id");
        List<Account> accounts = accountRepository.findUserAccounts(userId);
        model.addAttribute("accounts", accounts);
        return "accounts";
    }

    @RequestMapping(value = "/edit/{id}", method = RequestMethod.GET)
    public String editAccountForm(Model model, @PathVariable long id) {
        Account account = accountRepository.findOne(id);
        model.addAttribute("account",account);
        return "editAccountForm";
    }

    @RequestMapping(value = "/edit/{id}", method = RequestMethod.POST)
    public String editAccount(@ModelAttribute Account account, @PathVariable long id) {
        Account accountToUpdate = accountRepository.findOne(id);
        accountToUpdate.setAccTitle(account.getAccTitle());
        accountToUpdate.setAccFirstName(account.getAccFirstName());
        accountToUpdate.setAccLastName(account.getAccLastName());
        accountToUpdate.setAccBirthdate(account.getAccBirthdate());
        accountToUpdate.setAccPhoneNumber(account.getAccPhoneNumber());
        accountToUpdate.setAccEducation(account.getAccEducation());
        accountToUpdate.setAccExperience(account.getAccExperience());
        accountToUpdate.setAccAbilities(account.getAccAbilities());
        accountToUpdate.setAccInterests(account.getAccInterests());
        accountToUpdate.setAccProjects(account.getAccProjects());
        accountToUpdate.setAccDescription(account.getAccDescription());
        accountRepository.save(accountToUpdate);
        return "redirect:/accounts";
    }

    @RequestMapping("/delete")
    public String deleteAccount(Model model) {
        return "deleteAccount";
    }

    @RequestMapping("/read/{id}")
    public String read(@PathVariable long id) {
        return accountRepository.findOne(id).toString();
    }

    @RequestMapping("/delete/{id}")
    public String delete(@PathVariable long id) {
        Account account = accountRepository.findOne(id);
        accountRepository.delete(account);
        return "redirect:/accounts";
    }
}

最后一个ImageController:

@Controller
@RequestMapping("/user")
public class ImageController {

    private AccountRepository accountRepository;

    @RequestMapping(value = "/accounts", method = RequestMethod.GET)
    public void showImage(@RequestParam("id") Long id, HttpServletResponse response, HttpServletRequest request)
            throws ServletException, IOException {

        Account account = accountRepository.getOne(id);
        response.setContentType("image/jpeg, image/jpg, image/png, image/gif");
        response.getOutputStream().write(account.getAccPicture());

        response.getOutputStream().close();
    }
}

我的 .jsp 显示帐户:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %>
    <%@ taglib prefix = "fmt" uri = "http://java.sun.com/jsp/jstl/fmt" %>
     <%@ page isELIgnored="false" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ include file="/WEB-INF/parts/header.jsp" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<div align="center">
<table class="table table-striped">
<h1>Accounts:</h1>
<c:forEach items="${accounts}" var="account" begin="0" varStatus="theCount">

    <tr>
        <td>${theCount.index+1}</td>
        <td><b>Nazwa: </b>${account.accTitle}</td>
        <td><b>Opis: </b>${account.accDescription}</td>
        <td><img src="/ProjectProfile/user/accounts?id=${account.id}"/></td>
        <td><a style="width: 180px;height: 20px;" href="./edit/${account.id}" class="badge badge-primary">Show/Edit</a></td>
        <td><a style="width: 180px;height: 20px;" href="./delete/${account.id}" class="badge badge-danger">Delete</a></td>
    </tr>
</c:forEach>
</table>

     <a href="<c:url value="/addAccount"/>">Add Account</a>

</body>
</html>

也许我需要使用 Base64Encoder,但我不知道怎么做? .... 我使用 pom.xml 和 AppConfig 进行配置。请看看这个项目,也许有人可以帮忙?

【问题讨论】:

  • 在询问异常时,请始终发布异常的准确和完整的堆栈跟踪。还要告诉我们哪个请求导致了这个异常的发生。不相关,但图像具有 一种 内容类型,而不是 4 种不同的内容类型。
  • 好的,现在我看到 NullPointerException: SEVERE: Servlet.service() for servlet [dispatcher] 在路径 [/ProjectProfile] 的上下文中抛出异常 [请求处理失败;嵌套异常是 java.lang.NullPointerException],根本原因是 java.lang.NullPointerException at pl.lukszn.ProjectProfile.controllers.ImageController.showImage(ImageController.java:27) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)跨度>
  • 那么,看看 ImageController 的第 27 行有什么可能为空。我们这里没有行号。
  • 账户 account = accountRepository.getOne(id);
  • 所以 accountRepository 为空。这是很正常的,因为您没有使用构造函数或使用 Autowired 注释正确注入它。

标签: java mysql spring-mvc jsp blob


【解决方案1】:
<img id="photo" src="data:image/png;base64,${PHOTOYOUNEED}" />

在负责将图片发送到html的控制器中:

(...)
    String photoencodeBase64 = modelX.getStringPhoto();
    modelAndView.addObject("PHOTOYOUNEED", photoencodeBase64 );

我也在模型中使用这个方法将byte[]转换为base64中的字符串:

public static String convertBinImageToString(byte[] binImage) {
    if(binImage!=null && binImage.length>0) {
        return Base64.getEncoder().encodeToString(binImage);
    }
    else
        return "";
}

我在模型内部的 getStringPhoto() getter 中调用它。

【讨论】:

  • 什么都没有改变,也许我做错了什么...添加到帐户模型:私人字符串字符串照片;和他的吸气剂: public String getStringPhoto() { return convertBinImageToString(accPicture); },接下来改变ImageController:@RequestMapping(value = "/accounts", method = RequestMethod.GET) public void showImage(@RequestParam("id") long id, Model model) { Account account = accountRepository.findById(id);字符串 photoencodeBase64 = account.getStringPhoto(); model.addAttribute("accPicture", photoencodeBase64); }.... 和 jsp ...base64,${account.accImage}" />
  • 发帖时能不能使用“code sample {}”获取模型、控制器和jsp的主代码?另外,错误信息是什么?您也可以使用“代码示例{}”将它放在这里吗?谢谢! :D
  • 我为您的评论添加新答案
【解决方案2】:

好的,Eunito,让我们看看...更改了 Account.java(model):

@Entity
@Table(name = "accounts")
public class Account {


    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    private boolean ifBasicAccount;

    private String accTitle;

    private String accFirstName;

    private String accLastName;

    private String accBirthdate;

    private String accPhoneNumber;

    private String accEducation;

    private String accExperience;

    private String accAbilities;

    private String accInterests;

    private String accProjects;

    private String accDescription;

    @Lob
    private byte[] accPicture;

    private String stringPhoto;





    @ManyToOne
    private User user;


    public Account() {
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getAccTitle() {
        return accTitle;
    }

    public void setAccTitle(String accTitle) {
        this.accTitle = accTitle;
    }


    public String getAccFirstName() {
        return accFirstName;
    }

    public void setAccFirstName(String accFirstName) {
        this.accFirstName = accFirstName;
    }

    public String getAccLastName() {
        return accLastName;
    }

    public void setAccLastName(String accLastName) {
        this.accLastName = accLastName;
    }

    public String getAccBirthdate() {
        return accBirthdate;
    }

    public void setAccBirthdate(String accBirthdate) {
        this.accBirthdate = accBirthdate;
    }

    public String getAccPhoneNumber() {
        return accPhoneNumber;
    }

    public void setAccPhoneNumber(String accPhoneNumber) {
        this.accPhoneNumber = accPhoneNumber;
    }

    public String getAccEducation() {
        return accEducation;
    }

    public void setAccEducation(String accEducation) {
        this.accEducation = accEducation;
    }

    public String getAccExperience() {
        return accExperience;
    }

    public void setAccExperience(String accExperience) {
        this.accExperience = accExperience;
    }

    public String getAccAbilities() {
        return accAbilities;
    }

    public void setAccAbilities(String accAbilities) {
        this.accAbilities = accAbilities;
    }

    public String getAccInterests() {
        return accInterests;
    }

    public void setAccInterests(String accInterests) {
        this.accInterests = accInterests;
    }

    public String getAccProjects() {
        return accProjects;
    }

    public void setAccProjects(String accProjects) {
        this.accProjects = accProjects;
    }


    public String getAccDescription() {
        return accDescription;
    }

    public void setAccDescription(String accDescription) {
        this.accDescription = accDescription;
    }


    public byte[] getAccPicture() {
        return accPicture;
    }

    public void setAccPicture(byte[] accPicture) {
        this.accPicture = accPicture;
    }


    public String getStringPhoto() {
        return convertBinImageToString(accPicture);
    }

    public void setStringPhoto(String stringPhoto) {
        this.stringPhoto = stringPhoto;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public boolean isIfBasicAccount() {
        return ifBasicAccount;
    }

    public void setIfBasicAccount(boolean ifBasicAccount) {
        this.ifBasicAccount = ifBasicAccount;
    }

    public static String convertBinImageToString(byte[] accPicture) {
        if(accPicture!=null && accPicture.length>0) {
            return Base64.getEncoder().encodeToString(accPicture);
        }
        else
            return "";
    }

}

我有两个帐户控制器(一个仅用于显示图像-我不太确定这是一件好事,因为我有两个相同的 RequestMappings)。所以看看改变的 ImageController:

@Controller
@RequestMapping("/admin/user")
public class ImageController {

    @Autowired
    AccountRepository accountRepository;

    @RequestMapping(value = "/accounts", method = RequestMethod.GET)
    public void showImage(@RequestParam("id") long id, Model model) {

        Account account = accountRepository.findById(id);
        String photoencodeBase64 = account.getStringPhoto();
        model.addAttribute("accPicture", photoencodeBase64);

    }
}

和.jsp来显示图片:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %>
    <%@ taglib prefix = "fmt" uri = "http://java.sun.com/jsp/jstl/fmt" %>
     <%@ page isELIgnored="false" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ include file="/WEB-INF/parts/header.jsp" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<div align="center">
<table class="table table-striped">
<h1>Accounts:</h1>
<c:forEach items="${accounts}" var="account" begin="0" varStatus="theCount">

    <tr>
        <td>${theCount.index+1}</td>
        <td><b>Title: </b>${account.accTitle}</td>
        <td><b>Description: </b>${account.accDescription}</td>
        <td><b>Image: </b><img id="photo" src="data:image/png;base64,${account.accPicture}" /></td>
        <td><a style="width: 180px;height: 20px;" href="./edit/${account.id}" class="badge badge-primary">Show/Edit</a></td>
        <td><a style="width: 180px;height: 20px;" href="./delete/${account.id}" class="badge badge-danger">Delete</a></td>
    </tr>
</c:forEach>
</table>

     <a href="<c:url value="/addAccount"/>">Add Account</a>

</body>
</html>

所以会发生什么-当我添加新帐户时-> 写标题、名称等并从文件中添加图像我的浏览器显示HTTP Status 400 - The request sent by the client was syntactically incorrect.-> 我需要查看所有用户帐户。 在 STS 控制台中什么也没发生。在 MySQL 中也是如此。

【讨论】:

    【解决方案3】:

    为什么不使用Spring Content JPA?这可以提供用于管理与 jpa 实体关联的内容的存储服务和其余端点。

    pom.xml

       <!-- Java API -->
       <dependency>
          <groupId>com.github.paulcwarren</groupId>
          <artifactId>spring-content-jpa</artifactId>
          <version>0.1.0</version>
       </dependency>
       <!-- REST API -->
       <dependency>
          <groupId>com.github.paulcwarren</groupId>
          <artifactId>spring-content-rest</artifactId>
          <version>0.1.0</version>
       </dependency>
    

    配置

    @Configuration
    @EnableJpaStores
    @Import("org.springframework.content.rest.config.RestConfiguration.class")
    public class MysqlConfig {
    
        // schema management
        // 
        @Value("/org/springframework/content/jpa/schema-drop-mysql.sql")
        private Resource dropRepositoryTables;
    
        @Value("/org/springframework/content/jpa/schema-mysql.sql")
        private Resource dataRepositorySchema;
    
        @Bean
        DataSourceInitializer datasourceInitializer() {
            ResourceDatabasePopulator databasePopulator =
                    new ResourceDatabasePopulator();
    
            databasePopulator.addScript(dropReopsitoryTables);
            databasePopulator.addScript(dataReopsitorySchema);
            databasePopulator.setIgnoreFailedDrops(true);
    
            DataSourceInitializer initializer = new DataSourceInitializer();
            initializer.setDataSource(dataSource());
            initializer.setDatabasePopulator(databasePopulator);
    
            return initializer;
        }
    }
    

    要关联内容,请将 Spring Content 注释添加到您的帐户实体。

    帐户.java

    @Entity
    public class Account {
    
       // replace @Lob field with
    
       @ContentId
       private String contentId;
    
       @ContentLength
       private long contentLength = 0L;
    
       // if you have rest endpoints
       @MimeType
       private String mimeType = "text/plain";
    

    创建一个“商店”:

    AccountImagesStore.java

    @StoreRestResource(path="accountImages)
    public interface AccountImagesStore extends ContentStore<Account, String> {
    }
    

    这就是创建 REST 端点 @/accountImages 所需的全部内容。当您的应用程序启动时,Spring Content 将查看您的依赖项(查看 Spring Content JPA/REST),查看您的 AccountImagesStore 接口并为 JPA 注入该接口的实现。它还将注入一个@Controller,将http请求转发到该实现。这使您不必自己实施任何这些,我认为这就是您所追求的。

    所以...

    curl -X POST /accountImages/{account-id}

    使用 multipart/form-data 请求将图像存储在数据库中,并将其与 id 为 account-id 的帐户实体相关联。

    curl /accountImages/{account-id}

    将再次获取它等等...支持完整的 CRUD。

    所以你只需要在你的 JSP 中显示它就是一个图像标签:

    有一些入门指南here。参考指南是here。还有一个教程视频here。编码位从大约 1/2 处开始。

    HTH

    【讨论】:

    • 很高兴它有帮助。 Spring Content 有许多其他功能,例如演绎版和全文搜索。不知道它们是否有用,但以防万一。
    猜你喜欢
    • 2014-12-11
    • 2015-08-01
    • 1970-01-01
    • 2013-12-20
    • 1970-01-01
    • 2013-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多