본문 바로가기

Java/Spring

[Spring] Stream 형태로 Response 응답 주기 (feat. MyBatis, Observer)

환경

Spring Version : 4.2 이상 MySQL + MyBatis

문서

Http Stream Return은 총 3가지가 있는듯하다. (Spring 4.2부터)

- ResponseBodyEmitter : https://docs.spring.io/autorepo/docs/spring-framework/4.3.5.RELEASE/javadoc-api/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitter.html
- SseEmitter : https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/mvc/method/annotation/SseEmitter.html
- StreamingResponseBody : https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/mvc/method/annotation/StreamingResponseBody.html

DB Query (XML) - Mysql은 fetchSize를 Interger Min 값으로 줌


	<select id="selectAll" resultType="String" parameterType="sampleParam" fetchSize="생략..">
		/* SampleMapper.selectAll*/
		SELECT sample.id
		FROM sample
	</select>

Mapper


public interface SampleMapper {
    void selectAll(SampleParam param, ResultHandler resultHandler);
}

Result Handler


@Slf4j
public class SampleResultHandler extends Observable implements ResultHandler {
	/**
	 * MyBatis에서 Stream으로 읽은 DB 데이터를 Observer에게 알린다.
	 *
	 * @param resultContext
	 */
	@Override
	public void handleResult(ResultContext resultContext) {
		super.setChanged();
		super.notifyObservers(resultContext.getResultObject());
	}
}

Service


	@Override
	public void findAll(SampleParam param, Observer observer) {
		SampleResultHandler resultHandler = new SampleResultHandler();
		resultHandler.addObserver(observer);
		sampleMapper.selectAll(param, resultHandler);
	}

Controller


	@GetMapping("/stream/list")
	public ResponseBodyEmitter getSamples(SampleParam param) {

		// timeout 10분
		final ResponseBodyEmitter emitter = new ResponseBodyEmitter(600000L);

		ExecutorService executorService = Executors.newSingleThreadExecutor();
		executorService.execute(() -> {
				sampleService.findAll(param, (observer, args) -> {
					try {
						emitter.send(args.toString() + "\n");
					} catch (IOException e) {
						log.error("### Stream 방식으로 목록을 전달하던 중 에러 발생", e);
					}
				});
			emitter.complete();
		});
		return emitter;
	}