简体   繁体   中英

How to retrieve blob from server using JPA repository in spring

I've created spring application for CRUD. I can easily write into server data like string,Long,blob but When I try to retrieve it from server. I've encountered with difficulty which byte array from server gives in BigInteger from server. How I could get data in byte array instead of BigInteger?When I write in insert byte array this data which column is BLOB. Here is my code

Repository

public interface ArriveRepository extends JpaRepository<ArriveEntity,Long>
{ 
    @Query(value = "select arrive.time,air_lines.image,arrive.flight,arrive.destination_uzb," +
            "arrive.destination_eng,arrive.destination_rus,arrive.status,arrive.status_time " +
            "from arrive inner join air_lines on air_lines.id = arrive.airline_id where arrive.arrive_date = (:date1)",nativeQuery = true)
    List<Object[]> getForArriveTerminal(@Param("date1") LocalDate date1);
}

When I retrieve data from server I'm using this class

ArriveTerminalDto

public class ArriveTerminalDto {
   private String time;
   private BigInteger logo;
   private String flight;
   private String destinationUzb;
   private String destinationEng;
   private String destinationRus;
   private String status;
   private String statusTime;
  //getter setter}

Service class

  public List<ArriveTerminalDto> getToShow(LocalDate date1)
    {
        List<ArriveTerminalDto> list = new ArrayList<>();
        List<Object[]> list1 = arriveRepository.getForArriveTerminal(date1);
        for(Object[] objects: list1)
        {
            ArriveTerminalDto arriveTerminalDto = new ArriveTerminalDto();
            arriveTerminalDto.setTime((String)objects[0]);
            arriveTerminalDto.setLogo((BigInteger) objects[1]);
            arriveTerminalDto.setFlight((String) objects[2]);
            arriveTerminalDto.setDestinationUzb((String) objects[3]);
            arriveTerminalDto.setDestinationRus((String) objects[4]);
            arriveTerminalDto.setDestinationEng((String) objects[5]);
            arriveTerminalDto.setStatus((String) objects[6]);
            list.add(arriveTerminalDto);
        }
        return list;
    }

This code works but it didn't give me byte array from server. When I try to change BigInteger into byt[] array it gives me following errors from postman

{
    "timestamp": "2019-01-28T09:33:52.038+0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "java.math.BigInteger cannot be cast to [B",
    "path": "/arrive/terminal/date=2019-01-27"
}

Changed Object into ArriveTerminalDto but still it give error my following repo

public interface ArriveRepository extends JpaRepository<ArriveEntity,Long>
{

    @Query(value = "select arrive.time,air_lines.image,arrive.flight,arrive.destination_uzb," +
            "arrive.destination_eng,arrive.destination_rus,arrive.status,arrive.status_time " +
            "from arrive inner join air_lines on air_lines.id = arrive.airline_id where arrive.arrive_date = (:date1)",nativeQuery = true)
    List<ArriveTerminalDto> getForArriveTerminal(@Param("date1") LocalDate date1);
}

Try to change entity definition to handle byte[] directly, but suggest JPA to interpret it as Lob. You can do it with @Lob annotation:

public class ArriveTerminalDto {
    private String time;
    @Lob
    private byte[] logo;
    private String flight;
    private String destinationUzb;
    private String destinationEng;
    private String destinationRus;
    private String status;
    private String statusTime;
}

Laster, as @Clijsters suggested, you can change your repo to return List<ArriveTerminalDto> .

Why don't you take a look at the Spring Content community project. This project allows you to associate content with Spring Data entities. Think Spring Data but for Content, or unstructured data. This can also give you REST endpoints for the content as well, like Spring Data REST.

This approach will give you a clear abstraction for your content with implementations for many different types of storage. It is stream-based, rather than byte-based. Using byte[] won't work if you want to transfer very large files. Also getting databases to stream properly is very idiosyncratic. You probably don't want to figure all that out yourself when Spring Content already has.

This is pretty easy to add to your existing projects. I am not sure if you are using Spring Boot, or not. I'll give a non-spring boot example:

pom.xml

   <!-- Java API -->
   <dependency>
      <groupId>com.github.paulcwarren</groupId>
      <artifactId>spring-content-jpa</artifactId>
      <version>0.5.0</version>
   </dependency>
   <!-- REST API (if you want it) -->
   <dependency>
      <groupId>com.github.paulcwarren</groupId>
      <artifactId>spring-content-rest</artifactId>
      <version>0.5.0</version>
   </dependency>

Configuration

@Configuration
@EnableJpaStores
@Import("org.springframework.content.rest.config.RestConfiguration.class")
public class ContentConfig {

    // schema management
    // 
    @Value("/org/springframework/content/jpa/schema-drop-mysql.sql")
    private Resource dropContentTables;

    @Value("/org/springframework/content/jpa/schema-mysql.sql")
    private Resource createContentTables;

    @Bean
    DataSourceInitializer datasourceInitializer() {
        ResourceDatabasePopulator databasePopulator =
                new ResourceDatabasePopulator();

        databasePopulator.addScript(dropContentTables);
        databasePopulator.addScript(createContentTables);
        databasePopulator.setIgnoreFailedDrops(true);

        DataSourceInitializer initializer = new DataSourceInitializer();
        initializer.setDataSource(dataSource());
        initializer.setDatabasePopulator(databasePopulator);

        return initializer;
    }
}

To associate content, add Spring Content annotations to your account entity.

ArriveEntity.java

@Entity
public class ArriveEntity {

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

    .. existing fields...    


    @ContentId
    private String contentId;

    @ContentLength
    private long contentLength = 0L;

    // if you have rest endpoints
    @MimeType
    private String mimeType = "text/plain";
}

Create a "store":

ArrivEntityContentStore.java

@StoreRestResource(path="arriveEntityContent)
public interface ArrivEntityContentStore extends ContentStore<ArriveEntity, String> {
}

This is all you need to create REST endpoints @ /arriveEntityContent . When your application starts, Spring Content will look at your dependencies (seeing Spring Content JPA/REST), look at your ArrivEntityContentStore interface and inject an implementation of that interface for JPA. It will also inject a @Controller that forwards http requests to that implementation. This saves you having to implement any of this yourself which I think is what you are after.

So...

To access content with a Java API, auto-wire ArrivEntityContentStore and use it methods.

Or to access content with a REST API:

curl -X POST /arriveEntityContent/{arriveEntityId}

with a multipart/form-data request will store the image in the database and associate it with the account entity whose id is itemId .

curl /arriveEntityContent/{arriveEntityId}

will fetch it again and so on...supports full CRUD.

There are a couple of getting started guides here . The reference guide is here . And there is a tutorial video here . The coding bit starts about 1/2 way through.

HTH

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM