Проблема с конвертацией потока данных BYTEA в таблицу Postgres в Docker контейнере(+ Spring)
При попытке мой локально рабочий Spring Boot + Postgres проект развернуть через Docker-Compose получаю ошибку во время попыток загрузить какой-либо документ в БД.
Имею сущность файла с такими полями
@Entity
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@EntityListeners(AuditingEntityListener.class)
@ToString(exclude = { "data" })
public class FileEntity implements BaseEntity, Authorable, Available {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String filename;
private String filetype;
@Lob
@Column(columnDefinition = "BYTEA")
private byte[] data;
@ManyToOne(fetch = FetchType.EAGER)
@JsonProperty("author")
@JoinColumn(name = "author_id")
private User author;
@JsonProperty(value = "public_file_entity", defaultValue = "false")
private Boolean publicEntity = false;
@JsonProperty(value = "available_for")
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(
name = "file_entity_user_access",
joinColumns = @JoinColumn(name = "id_file_entity"),
inverseJoinColumns = @JoinColumn(name = "id_user",
foreignKey = @ForeignKey(name = "fk_file_entity_user",
foreignKeyDefinition = "FOREIGN KEY (id_user) REFERENCES users(id_user) ON DELETE CASCADE"))
)
@JsonIgnore
private Set<User> availableFor = new HashSet<>();
@CreatedDate
@Column(updatable = false)
private LocalDate creationDate;
@LastModifiedDate
@Column(insertable = false)
private LocalDate updateDate;
}
Ниже мой контроллер, сервисный слой
@PostMapping("/upload")
public FileEntity uploadFile(
@RequestParam("file") MultipartFile file,
@RequestPart("params") String paramsJson
) throws IOException
{
ObjectMapper objectMapper = new ObjectMapper();
FileEntityUpdateDTO paramsDTO = objectMapper.readValue(paramsJson, FileEntityUpdateDTO.class);
log.info("получили файл с параметрами {}", file.getOriginalFilename());
log.info("получили дто с параметрами {}", paramsDTO.toString());
return fileService.storeFile(file, paramsDTO);
}
@Override
public FileEntity storeFile(MultipartFile file, FileEntityUpdateDTO paramsDTO) throws IOException {
FileEntity fileEntity = new FileEntity();
fileEntity.setFilename(file.getOriginalFilename());
fileEntity.setFiletype(file.getContentType());
fileEntity.setData(file.getBytes());
fileEntity.setAuthor(userUtils.getCurrentUser());
if (paramsDTO != null && paramsDTO.getPublicEntity()) {
fileEntity.setPublicEntity(true);
}
if (paramsDTO != null && paramsDTO.getAvailableFor() != null && !paramsDTO.getAvailableFor().isEmpty()) {
fileEntity.setAvailableFor(mappingFromDtoToEntity(paramsDTO.getAvailableFor()));
}
log.info("сейчас в сущности файла есть поле с данными файла типа {}", fileEntity.getData().getClass().getSimpleName());
return fileRepository.save(fileEntity);
}
private Set<User> mappingFromDtoToEntity(Set<Long> userIds) {
if (userIds == null || userIds.isEmpty()) {
return new HashSet<>();
}
return new HashSet<>(userRepository.findAllById(userIds));
}
Конфигурация docker-compose.yml
и application.properties
version: "3.9"
volumes:
document_accounting:
services:
document_accounting_db:
image: postgres
restart: always
environment:
- POSTGRES_USER=ivan
- POSTGRES_PASSWORD=password
- POSTGRES_DB=document_accounting_db
volumes:
- document_accounting:/var/lib/postgresql/data
ports:
- "127.0.0.1:5432:5432"
app:
restart: always
build: .
ports:
- "8080:8080"
depends_on:
- document_accounting_db
environment:
SPRING_DATASOURCE_URL: 'jdbc:postgresql://document_accounting_db:5432/document_accounting_db'
JAVA_OPTS: '-Xmx512m'
____________________________________________________________________
spring.application.name=DocumentAccounting2
spring.jpa.defer-datasource-initialization=true
spring.jpa.show-sql=true
spring.sql.init.mode=always
document_accounting.jwtCookieName=springAuthDemoToken
document_accounting.jwtSecret=0C659Ajwvt95MkZFzrg57TQi5AiHINzC5QINtsYemOeO2ZFQlm
document_accounting.jwtExpirationMs=86400000
spring.thymeleaf.prefix=classpath:/templates/
spring.web.resources.static-locations=classpath:/static/, classpath:/static/html/, classpath:/static/html/files
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML5
#logging.level.root=TRACE
logging.level.org.springframework = DEBUG
logging.file.path=logs/
logging.file.name=logs/application.log
logging.logback.rollingpolicy.max-file-size=10MB
logging.logback.rollingpolicy.max-history=1000
spring.output.ansi.enabled=always
spring.servlet.multipart.max-file-size=50MB
spring.servlet.multipart.max-request-size=50MB
spring.profiles.default=development
#data for start in docker-compose
spring.datasource.url=jdbc:postgresql://localhost:5432/document_accounting_db
spring.datasource.username=ivan
spring.datasource.password=password
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update
Получаю при загрузке файлов на этот ендпоинт такую портянку
documentaccounting2-app-1 | 2024-07-24T19:19:51.027Z DEBUG 1 --- [DocumentAccounting2] [io-8080-exec-10] o.s.d.auditing.AuditingHandlerSupport : Touched FileEntity(id=null, filename=3b68b19a-5634-4bf6-b738-2bf1dfb8f4eb_photo_2024-06-13_10-40-58.jpg, filetype=image/jpeg, author=User(idUser=1, username=admin, [email protected], password=$2a$10$J.hrsOXCPwUQul3E2.Wxsu9MCjjTj2FaQywfXP9Wf6GDMfa/9aQEu, name=Ivan, lastName=null, photo=null, roles=[Role(idRole=1, name=ROLE_ADMIN, creationDate=null, updateDate=null), Role(idRole=3, name=ROLE_USER, creationDate=null, updateDate=null)], creationDate=null, updateDate=null), publicEntity=false, availableFor=[], creationDate=2024-07-24, updateDate=2024-07-24) - Last modification at 2024-07-24T19:19:51.020311885 by unknown
documentaccounting2-app-1 | Hibernate: insert into file_entity (author_id,creation_date,data,filename,filetype,public_entity) values (?,?,?,?,?,?) returning id
documentaccounting2-app-1 | 2024-07-24T19:19:51.059Z WARN 1 --- [DocumentAccounting2] [io-8080-exec-10] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 0, SQLState: 42804
documentaccounting2-app-1 | 2024-07-24T19:19:51.059Z ERROR 1 --- [DocumentAccounting2] [io-8080-exec-10] o.h.engine.jdbc.spi.SqlExceptionHelper : ERROR: column "data" is of type bytea but expression is of type bigint
documentaccounting2-app-1 | Hint: You will need to rewrite or cast the expression.
documentaccounting2-app-1 | Position: 102
documentaccounting2-app-1 | 2024-07-24T19:19:51.062Z DEBUG 1 --- [DocumentAccounting2] [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager : Initiating transaction rollback
documentaccounting2-app-1 | 2024-07-24T19:19:51.063Z DEBUG 1 --- [DocumentAccounting2] [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager : Rolling back JPA transaction on EntityManager [SessionImpl(394680422<open>)]
documentaccounting2-app-1 | 2024-07-24T19:19:51.064Z DEBUG 1 --- [DocumentAccounting2] [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager : Not closing pre-bound JPA EntityManager after transaction
documentaccounting2-app-1 | 2024-07-24T19:19:51.066Z DEBUG 1 --- [DocumentAccounting2] [io-8080-exec-10] .m.m.a.ExceptionHandlerExceptionResolver : Using @ExceptionHandler com.ivan_degtev.documentaccounting2.handlers.GlobalControllerExceptionHandler#handleDataAccessException(DataAccessException)
documentaccounting2-app-1 | 2024-07-24T19:19:51.076Z DEBUG 1 --- [DocumentAccounting2] [io-8080-exec-10] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Using 'application/problem+json', given [*/*] and supported [application/problem+json]
documentaccounting2-app-1 | 2024-07-24T19:19:51.080Z DEBUG 1 --- [DocumentAccounting2] [io-8080-exec-10] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Writing [ProblemDetail[type='about:blank', title='Internal Server Error', status=500, detail='Server error, p (truncated)...]
documentaccounting2-app-1 | 2024-07-24T19:19:51.081Z DEBUG 1 --- [DocumentAccounting2] [io-8080-exec-10] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.dao.InvalidDataAccessResourceUsageException: could not execute statement [ERROR: column "data" is of type bytea but expression is of type bigint<EOL> Hint: You will need to rewrite or cast the expression.<EOL> Position: 102] [insert into file_entity (author_id,creation_date,data,filename,filetype,public_entity) values (?,?,?,?,?,?) returning id]; SQL [insert into file_entity (author_id,creation_date,data,filename,filetype,public_entity) values (?,?,?,?,?,?) returning id]]
documentaccounting2-app-1 | 2024-07-24T19:19:51.081Z DEBUG 1 --- [DocumentAccounting2] [io-8080-exec-10] o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptor
documentaccounting2-app-1 | 2024-07-24T19:19:51.081Z DEBUG 1 --- [DocumentAccounting2] [io-8080-exec-10] o.s.web.servlet.DispatcherServlet : Completed 500 INTERNAL_SERVER_ERROR
Мое непониманию ухудшается тем, что локально все отрабатывает прекрасно.
Имею локальный Postgres 16.3, пробовал в docker-compose.yml прописать это изображение image: postgres:16.3
- проблема осталась.
Логирование сущности файла на предмет типа данных дало такой результат перед отправкой в базу
documentaccounting2-app-1 | 2024-07-24T19:44:08.415Z INFO 1 --- [DocumentAccounting2] [io-8080-exec-10] c.i.d.service.impl.FileServiceImpl : сейчас в сущности файла есть поле с данными файла типа byte[]
Пока не понимаю в чем тут дело. Прошу помочь)
Ответы (1 шт):
Я решил эту проблему просто, но без понимания. Где-то на стеке видел совет, что нужно убрать аннотацию @Lob
из поля сущности, и оставить только @Column(columnDefinition = "BYTEA")
.
Это я и сделал, в докере заработало, но появилась новая проблема, о ней в другом вопросе.