I would like to call a repository saveAll method in a WebFilter class, but when I return with a body populated ServerResponse the saveAll doesn't save anything in the DB. Returning without a body, the data is saved in the DB.
Here are the sources that i use.
Router with handlers:
@Configuration
@Slf4j
public class ResponseBodyRouter {
@Bean
public RouterFunction<ServerResponse> responseBodyRoute() {
return route()
.GET("/with-response-body", this::withResponseBodyHandler)
.GET("/without-response-body", this::withoutResponseBodyHandler)
.build();
}
private Mono<ServerResponse> withResponseBodyHandler(ServerRequest req) {
return ServerResponse
.ok()
.bodyValue("Body\n");
}
private Mono<ServerResponse> withoutResponseBodyHandler(ServerRequest req) {
return ServerResponse
.ok()
.build();
}
}
Webfilter:
@Component
@Order(Ordered.LOWEST_PRECEDENCE)
@Slf4j
public class LogWebFilter implements WebFilter {
@Autowired
private UserOperationLogRepository userOperationLogRepository;
@NonNull
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
return chain
.filter(exchange)
.then(logMessage(exchange));
}
public Mono<Void> logMessage(ServerWebExchange exchange) {
return Mono.deferContextual(ctx -> {
var list = new ArrayList<UserOperationLog>();
var userOperationLog = new UserOperationLog();
userOperationLog.setAction((short) 1);
userOperationLog.setPayload("payload");
userOperationLog.setResource("Client");
userOperationLog.setRowId(1L);
userOperationLog.setCreatedAt(OffsetDateTime.now());
userOperationLog.setUserId(1L);
list.add(userOperationLog);
return userOperationLogRepository.saveAll(list)
.log()
.collectList()
.then();
});
}
}
The bean:
@Data
@Table("user_operation_log")
public class UserOperationLog implements Persistable {
@Id
@Column("user_operation_log_id")
protected Long id;
@Column("user_id")
protected Long userId;
@Column("action")
protected Short action;
@Column("resource")
protected String resource;
@Column("row_id")
protected Long rowId;
@Column("payload")
protected String payload;
@Column("error")
protected String error;
@Column("created_at")
protected OffsetDateTime createdAt;
@Override
public boolean isNew() {
return true;
}
}
Reactive stream signal logs without response body:
onSubscribe(FluxUsingWhen.UsingWhenSubscriber)
request(unbounded)
onNext(UserOperationLog(id=102, userId=1, action=1, resource=Client, rowId=1, payload=payload, error=null, createdAt=2024-04-05T12:20:07.990301862+02:00))
onComplete()
Reactive stream signal logs with response body:
onSubscribe(FluxUsingWhen.UsingWhenSubscriber)
request(unbounded)
cancel()
I have tried replacing the repository.saveAll with Mono.just(), which worked as expected.
I have overcome this problem with a different approach using the beforeCommit
function in the WebFilter:
@Component
@Order(Ordered.LOWEST_PRECEDENCE)
@Slf4j
public class LogWebFilter implements WebFilter {
@Autowired
private UserOperationLogRepository userOperationLogRepository;
@NonNull
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
exchange.getResponse().beforeCommit(() -> Mono.deferContextual(ctx -> {
var list = new ArrayList<UserOperationLog>();
var userOperationLog = new UserOperationLog();
userOperationLog.setAction((short) 1);
userOperationLog.setPayload("payload");
userOperationLog.setResource("Client");
userOperationLog.setRowId(1L);
userOperationLog.setCreatedAt(OffsetDateTime.now());
userOperationLog.setUserId(1L);
list.add(userOperationLog);
return userOperationLogRepository.saveAll(list).collectList().then();
}));
return chain
.filter(exchange);
}
}