我正在尝试创建电影数据库Web应用程序。每部电影应有一张海报图像。我不知道如何使用Spring Data REST将图像正确地提供给前端。
Movie.java
import lombok.AccessLevel;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.io.File;
import java.sql.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@Data
@Entity
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Movie {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String director;
private Date releaseDate;
private File posterFile;
@ManyToMany
@JoinTable(
name = "MOVIE_GENRES",
joinColumns = @JoinColumn(name = "MOVIE_ID"),
inverseJoinColumns = @JoinColumn(name = "GENRE_ID"))
private Set<Genre> genres = new HashSet<>();
@OneToMany
@MapKeyColumn(name = "ACTOR_ROLE")
private Map<String, Actor> cast = new HashMap<>();
public Movie(String title) {
this.title = title;
}
public void addActor(String role, Actor actor) {
cast.put(role, actor);
}
public void removeActor(String role) {
cast.remove(role);
}
public void addGenre(Genre genre) {
genres.add(genre);
}
public void removeGenre(Genre genre) {
genres.remove(genre);
}
}
我不能在电影bean中使用字节数组,因为它太大而无法保存在数据库中。我可以存储File对象,Path对象或包含路径的String:
private File posterFile;
问题在于,它将保存诸如"C:\user\documents\project\backend\images\posterxyz.png"
之类的本地路径。
当我尝试在前端使用此路径作为img-src时,出现错误“不允许加载本地资源”。我的意思是,这听起来像是一种愚蠢的方式。我只是不知道正确的方法是什么。
这是电影资料库。 我在后端使用Spring Data REST,它以超媒体应用程序语言格式生成JSON。
MovieRepository.java
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
@RepositoryRestResource(collectionResourceRel = "movies", path = "movies")
public interface MovieRepository extends PagingAndSortingRepository<Movie, Long> {
}
答案 0 :(得分:1)
我会
一个
通过在字段中添加posterFile
批注来防止@JsonIgnore
属性被序列化。
@JsonIgnore
private File posterFile;
您还可以通过Jackson混合类来执行此操作,以避免使用Json处理指令“污染”您的实体,但是您需要自己进行研究。
两个
向资源表示形式添加自定义链接,该链接将允许客户端按需获取图像数据。例如/movies/21/poster
有关如何将自定义链接添加到资源的详细信息,请参见此处:
Spring Data Rest Custom Links on Resource
专门用于创建到Spring MVC控制器的链接:
https://stackoverflow.com/a/24791083/1356423
三个
创建一个标准的Spring MVC控制器,该控制器绑定到您的自定义链接指向的路径,该路径将读取文件数据并流式传输响应。
例如
@Controller
public MoviePosterController{
@GetMapping(path="/movies/{movieId}/poster")
//https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#core.web for auto resolution of path var to domain Object
public @ResponseBody byte[] getPoster(@PathVariable("movieId") Movie movie, HttpServletResponse response){
File file = movie.getPosterFile();
//stream the bytes of the file
// see https://www.baeldung.com/spring-controller-return-image-file
// see https://www.baeldung.com/spring-mvc-image-media-data
}
}
答案 1 :(得分:1)
Spring Data / REST实际上不可能做到这一点,因为它专注于结构化数据。即大部分是表格和关联。是的,您可以按照其他答案中的说明进行操作,但是还有一个名为Spring Content的相关项目可以解决这个问题。
Spring Content提供与Spring Data / REST相同的编程范例,仅适用于非结构化数据。因此,使用此项目,您可以将一个或多个“内容”对象与Spring Data实体相关联,并通过HTTP管理它们,就像您的Spring Data实体一样。
添加到您的项目非常简单,如下所示:
pom.xml(也提供启动启动器)
<!-- Java API -->
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-jpa</artifactId>
<version>0.9.0</version>
</dependency>
<!-- REST API -->
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-rest</artifactId>
<version>0.9.0</version>
</dependency>
配置
@Configuration
@EnableJpaStores
@Import("org.springframework.content.rest.config.RestConfiguration.class")
public class ContentConfig {
// schema management (assuming mysql)
//
@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;
}
}
要关联内容,请将Spring Content批注添加到Movie实体。
Movie.java
@Entity
public class Movie {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
.. existing fields...
// private File posterFile; no longer required
@ContentId
private String contentId;
@ContentLength
private long contentLength = 0L;
// if you have rest endpoints
@MimeType
private String mimeType = "text/plain";
}
创建“商店”:
MoviePosterContentStore.java
@StoreRestResource(path="moviePosters")
public interface MoviePosterContentStore extends ContentStore<Movie, String> {
}
这就是在/moviePosters
上创建REST端点所需的全部。当您的应用程序启动时,Spring Content将查看Spring Content JPA,查看您的依赖项,查看您的MoviePosterContentStore
接口,并为JPA注入该接口的实现。它还将看到Spring Content REST依赖项,并注入一个@Controller
实现,该实现将HTTP请求转发到MoviePosterContentStore。这省去了您必须自己实现的任何事情,我认为这是您的追求。
所以...
要使用注入的REST API管理内容:
curl -X POST /moviePosters/{movieId}
-F file=@/path/to/poster.jpg
会将图像存储为数据库(作为BLOB) 并将其与ID为movieId
的电影实体相关联。
curl /moviePosters/{movieId} -H "Accept: image/jpeg"
将再次获取它,依此类推...支持所有CRUD方法和视频流以及BTW!
有两个入门指南here。 JPA的参考指南为here。还有一个教程视频here。编码位大约从1/2开始。
另外几点:
-如果您使用的是Spring Boot Starters,那么大多数情况下就不需要@Configuration。
-就像Spring Data是一个抽象一样,Spring Content也是如此,因此您不仅限于将海报图像作为BLOB存储在数据库中。您可以将它们存储在文件系统或S3之类的云存储或Spring Content支持的任何其他存储中。
HTH