org.springframework.http.server.reactive.AbstractServerHttpResponse#org.springframework.web.reactive.HandlerResult源码实例Demo

下面列出了org.springframework.http.server.reactive.AbstractServerHttpResponse#org.springframework.web.reactive.HandlerResult 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。

@Override
public boolean supports(HandlerResult result) {
	if (hasModelAnnotation(result.getReturnTypeSource())) {
		return true;
	}

	Class<?> type = result.getReturnType().toClass();
	ReactiveAdapter adapter = getAdapter(result);
	if (adapter != null) {
		if (adapter.isNoValue()) {
			return true;
		}
		type = result.getReturnType().getGeneric().toClass();
	}

	return (CharSequence.class.isAssignableFrom(type) || Rendering.class.isAssignableFrom(type) ||
			Model.class.isAssignableFrom(type) || Map.class.isAssignableFrom(type) ||
			void.class.equals(type) || View.class.isAssignableFrom(type) ||
			!BeanUtils.isSimpleProperty(type));
}
 
@Test
public void handleReturnValueETagAndLastModified() throws Exception {
	String eTag = "\"deadb33f8badf00d\"";

	Instant currentTime = Instant.now().truncatedTo(ChronoUnit.SECONDS);
	Instant oneMinAgo = currentTime.minusSeconds(60);

	MockServerWebExchange exchange = MockServerWebExchange.from(get("/path")
			.ifNoneMatch(eTag)
			.ifModifiedSince(currentTime.toEpochMilli())
			);

	ResponseEntity<String> entity = ok().eTag(eTag).lastModified(oneMinAgo.toEpochMilli()).body("body");
	MethodParameter returnType = on(TestController.class).resolveReturnType(entity(String.class));
	HandlerResult result = handlerResult(entity, returnType);
	this.resultHandler.handleResult(exchange, result).block(Duration.ofSeconds(5));

	assertConditionalResponse(exchange, HttpStatus.NOT_MODIFIED, null, eTag, oneMinAgo);
}
 
/**
 * Invoke the method for the given exchange.
 * @param exchange the current exchange
 * @param bindingContext the binding context to use
 * @param providedArgs optional list of argument values to match by type
 * @return a Mono with a {@link HandlerResult}.
 * @throws ServerErrorException if method argument resolution or method invocation fails
 */
@Nullable
public HandlerResult invokeForHandlerResult(ServerWebExchange exchange,
		BindingContext bindingContext, Object... providedArgs) {

	MonoProcessor<HandlerResult> processor = MonoProcessor.create();
	this.delegate.invoke(exchange, bindingContext, providedArgs).subscribeWith(processor);

	if (processor.isTerminated()) {
		Throwable ex = processor.getError();
		if (ex != null) {
			throw (ex instanceof ServerErrorException ? (ServerErrorException) ex :
					new ServerErrorException("Failed to invoke: " + getShortLogMessage(), getMethod(), ex));
		}
		return processor.peek();
	}
	else {
		// Should never happen...
		throw new IllegalStateException(
				"SyncInvocableHandlerMethod should have completed synchronously.");
	}
}
 
private void testDefaultViewName(Object returnValue, MethodParameter returnType) {
	this.bindingContext.getModel().addAttribute("id", "123");
	HandlerResult result = new HandlerResult(new Object(), returnValue, returnType, this.bindingContext);
	ViewResolutionResultHandler handler = resultHandler(new TestViewResolver("account"));

	MockServerWebExchange exchange = MockServerWebExchange.from(get("/account"));
	handler.handleResult(exchange, result).block(Duration.ofMillis(5000));
	assertResponseBody(exchange, "account: {id=123}");

	exchange = MockServerWebExchange.from(get("/account/"));
	handler.handleResult(exchange, result).block(Duration.ofMillis(5000));
	assertResponseBody(exchange, "account: {id=123}");

	exchange = MockServerWebExchange.from(get("/account.123"));
	handler.handleResult(exchange, result).block(Duration.ofMillis(5000));
	assertResponseBody(exchange, "account: {id=123}");
}
 
@Test
public void contentNegotiation() {
	TestBean value = new TestBean("Joe");
	MethodParameter returnType = on(Handler.class).resolveReturnType(TestBean.class);
	HandlerResult handlerResult = new HandlerResult(new Object(), value, returnType, this.bindingContext);

	MockServerWebExchange exchange = MockServerWebExchange.from(get("/account").accept(APPLICATION_JSON));

	TestView defaultView = new TestView("jsonView", APPLICATION_JSON);

	resultHandler(Collections.singletonList(defaultView), new TestViewResolver("account"))
			.handleResult(exchange, handlerResult)
			.block(Duration.ofSeconds(5));

	assertEquals(APPLICATION_JSON, exchange.getResponse().getHeaders().getContentType());
	assertResponseBody(exchange, "jsonView: {" +
			"org.springframework.validation.BindingResult.testBean=" +
			"org.springframework.validation.BeanPropertyBindingResult: 0 errors, " +
			"testBean=TestBean[name=Joe]" +
			"}");
}
 
@Test  // SPR-15291
public void contentNegotiationWithRedirect() {
	HandlerResult handlerResult = new HandlerResult(new Object(), "redirect:/",
			on(Handler.class).annotNotPresent(ModelAttribute.class).resolveReturnType(String.class),
			this.bindingContext);

	UrlBasedViewResolver viewResolver = new UrlBasedViewResolver();
	viewResolver.setApplicationContext(new StaticApplicationContext());
	ViewResolutionResultHandler resultHandler = resultHandler(viewResolver);

	MockServerWebExchange exchange = MockServerWebExchange.from(get("/account").accept(APPLICATION_JSON));
	resultHandler.handleResult(exchange, handlerResult).block(Duration.ZERO);

	MockServerHttpResponse response = exchange.getResponse();
	assertEquals(303, response.getStatusCode().value());
	assertEquals("/", response.getHeaders().getLocation().toString());
}
 
@Test
public void handleReturnValueETagAndLastModified() throws Exception {
	String eTag = "\"deadb33f8badf00d\"";

	Instant currentTime = Instant.now().truncatedTo(ChronoUnit.SECONDS);
	Instant oneMinAgo = currentTime.minusSeconds(60);

	MockServerWebExchange exchange = MockServerWebExchange.from(get("/path")
			.ifNoneMatch(eTag)
			.ifModifiedSince(currentTime.toEpochMilli())
			);

	ResponseEntity<String> entity = ok().eTag(eTag).lastModified(oneMinAgo.toEpochMilli()).body("body");
	MethodParameter returnType = on(TestController.class).resolveReturnType(entity(String.class));
	HandlerResult result = handlerResult(entity, returnType);
	this.resultHandler.handleResult(exchange, result).block(Duration.ofSeconds(5));

	assertConditionalResponse(exchange, HttpStatus.NOT_MODIFIED, null, eTag, oneMinAgo);
}
 
@Test
public void handleReturnValueChangedETagAndLastModified() throws Exception {
	String etag = "\"deadb33f8badf00d\"";
	String newEtag = "\"changed-etag-value\"";

	Instant currentTime = Instant.now().truncatedTo(ChronoUnit.SECONDS);
	Instant oneMinAgo = currentTime.minusSeconds(60);

	MockServerWebExchange exchange = MockServerWebExchange.from(get("/path")
			.ifNoneMatch(etag)
			.ifModifiedSince(currentTime.toEpochMilli())
			);

	ResponseEntity<String> entity = ok().eTag(newEtag).lastModified(oneMinAgo.toEpochMilli()).body("body");
	MethodParameter returnType = on(TestController.class).resolveReturnType(entity(String.class));
	HandlerResult result = handlerResult(entity, returnType);
	this.resultHandler.handleResult(exchange, result).block(Duration.ofSeconds(5));

	assertConditionalResponse(exchange, HttpStatus.OK, "body", newEtag, oneMinAgo);
}
 
private void testDefaultViewName(Object returnValue, MethodParameter returnType) {
	this.bindingContext.getModel().addAttribute("id", "123");
	HandlerResult result = new HandlerResult(new Object(), returnValue, returnType, this.bindingContext);
	ViewResolutionResultHandler handler = resultHandler(new TestViewResolver("account"));

	MockServerWebExchange exchange = MockServerWebExchange.from(get("/account"));
	handler.handleResult(exchange, result).block(Duration.ofMillis(5000));
	assertResponseBody(exchange, "account: {id=123}");

	exchange = MockServerWebExchange.from(get("/account/"));
	handler.handleResult(exchange, result).block(Duration.ofMillis(5000));
	assertResponseBody(exchange, "account: {id=123}");

	exchange = MockServerWebExchange.from(get("/account.123"));
	handler.handleResult(exchange, result).block(Duration.ofMillis(5000));
	assertResponseBody(exchange, "account: {id=123}");
}
 
private void testHttpOptions(String requestURI, Set<HttpMethod> allowedMethods) {
	ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.options(requestURI));
	HandlerMethod handlerMethod = (HandlerMethod) this.handlerMapping.getHandler(exchange).block();

	BindingContext bindingContext = new BindingContext();
	InvocableHandlerMethod invocable = new InvocableHandlerMethod(handlerMethod);
	Mono<HandlerResult> mono = invocable.invoke(exchange, bindingContext);

	HandlerResult result = mono.block();
	assertNotNull(result);

	Object value = result.getReturnValue();
	assertNotNull(value);
	assertEquals(HttpHeaders.class, value.getClass());
	assertEquals(allowedMethods, ((HttpHeaders) value).getAllow());
}
 
@Test
public void illegalArgumentException() {
	this.resolvers.add(stubResolver(1));
	Method method = ResolvableMethod.on(TestController.class).mockCall(o -> o.singleArg(null)).method();
	Mono<HandlerResult> mono = invoke(new TestController(), method);

	try {
		mono.block();
		fail("Expected IllegalStateException");
	}
	catch (IllegalStateException ex) {
		assertNotNull("Exception not wrapped", ex.getCause());
		assertTrue(ex.getCause() instanceof IllegalArgumentException);
		assertTrue(ex.getMessage().contains("Controller ["));
		assertTrue(ex.getMessage().contains("Method ["));
		assertTrue(ex.getMessage().contains("with argument values:"));
		assertTrue(ex.getMessage().contains("[0] [type=java.lang.Integer] [value=1]"));
	}
}
 
@Test
public void handleReturnValueChangedETagAndLastModified() throws Exception {
	String etag = "\"deadb33f8badf00d\"";
	String newEtag = "\"changed-etag-value\"";

	Instant currentTime = Instant.now().truncatedTo(ChronoUnit.SECONDS);
	Instant oneMinAgo = currentTime.minusSeconds(60);

	MockServerWebExchange exchange = MockServerWebExchange.from(get("/path")
			.ifNoneMatch(etag)
			.ifModifiedSince(currentTime.toEpochMilli())
			);

	ResponseEntity<String> entity = ok().eTag(newEtag).lastModified(oneMinAgo.toEpochMilli()).body("body");
	MethodParameter returnType = on(TestController.class).resolveReturnType(entity(String.class));
	HandlerResult result = handlerResult(entity, returnType);
	this.resultHandler.handleResult(exchange, result).block(Duration.ofSeconds(5));

	assertConditionalResponse(exchange, HttpStatus.OK, "body", newEtag, oneMinAgo);
}
 
@Test  // SPR-15291
public void contentNegotiationWithRedirect() {
	HandlerResult handlerResult = new HandlerResult(new Object(), "redirect:/",
			on(Handler.class).annotNotPresent(ModelAttribute.class).resolveReturnType(String.class),
			this.bindingContext);

	UrlBasedViewResolver viewResolver = new UrlBasedViewResolver();
	viewResolver.setApplicationContext(new StaticApplicationContext());
	ViewResolutionResultHandler resultHandler = resultHandler(viewResolver);

	MockServerWebExchange exchange = MockServerWebExchange.from(get("/account").accept(APPLICATION_JSON));
	resultHandler.handleResult(exchange, handlerResult).block(Duration.ZERO);

	MockServerHttpResponse response = exchange.getResponse();
	assertEquals(303, response.getStatusCode().value());
	assertEquals("/", response.getHeaders().getLocation().toString());
}
 
@Override
public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
	HandlerFunction<?> handlerFunction = (HandlerFunction<?>) handler;
	ServerRequest request = exchange.getRequiredAttribute(RouterFunctions.REQUEST_ATTRIBUTE);
	return handlerFunction.handle(request)
			.map(response -> new HandlerResult(handlerFunction, response, HANDLER_FUNCTION_RETURN_TYPE));
}
 
@Test
public void exceptionInResolvingArg() {
	this.resolvers.add(stubResolver(Mono.error(new UnsupportedMediaTypeStatusException("boo"))));
	Method method = ResolvableMethod.on(TestController.class).mockCall(o -> o.singleArg(null)).method();
	Mono<HandlerResult> mono = invoke(new TestController(), method);

	try {
		mono.block();
		fail("Expected UnsupportedMediaTypeStatusException");
	}
	catch (UnsupportedMediaTypeStatusException ex) {
		assertThat(ex.getMessage(), is("415 UNSUPPORTED_MEDIA_TYPE \"boo\""));
	}
}
 
@Test
public void voidMonoMethodWithExchangeArg() {
	this.resolvers.add(stubResolver(this.exchange));
	Method method = ResolvableMethod.on(TestController.class).mockCall(c -> c.exchangeMonoVoid(exchange)).method();
	HandlerResult result = invokeForResult(new TestController(), method);

	assertNull("Expected no result (i.e. fully handled)", result);
	assertEquals("body", this.exchange.getResponse().getBodyAsString().block(Duration.ZERO));
}
 
@Test
public void unresolvedViewName() {
	String returnValue = "account";
	MethodParameter returnType = on(Handler.class).annotPresent(ModelAttribute.class).resolveReturnType(String.class);
	HandlerResult result = new HandlerResult(new Object(), returnValue, returnType, this.bindingContext);

	MockServerWebExchange exchange = MockServerWebExchange.from(get("/path"));
	Mono<Void> mono = resultHandler().handleResult(exchange, result);

	StepVerifier.create(mono)
			.expectNextCount(0)
			.expectErrorMessage("Could not resolve view with name 'path'.")
			.verify();
}
 
源代码18 项目: spring-analysis-note   文件: ModelInitializer.java
private Mono<Void> invokeModelAttributeMethods(BindingContext bindingContext,
		List<InvocableHandlerMethod> modelMethods, ServerWebExchange exchange) {

	List<Mono<HandlerResult>> resultList = new ArrayList<>();
	modelMethods.forEach(invocable -> resultList.add(invocable.invoke(exchange, bindingContext)));

	return Mono
			.zip(resultList, objectArray ->
					Arrays.stream(objectArray)
							.map(object -> handleResult(((HandlerResult) object), bindingContext))
							.collect(Collectors.toList()))
			.flatMap(Mono::when);
}
 
private void invokeBinderMethod(
		WebExchangeDataBinder dataBinder, ServerWebExchange exchange, SyncInvocableHandlerMethod binderMethod) {

	HandlerResult result = binderMethod.invokeForHandlerResult(exchange, this.binderMethodContext, dataBinder);
	if (result != null && result.getReturnValue() != null) {
		throw new IllegalStateException(
				"@InitBinder methods must not return a value (should be void): " + binderMethod);
	}
	// Should not happen (no Model argument resolution) ...
	if (!this.binderMethodContext.getModel().asMap().isEmpty()) {
		throw new IllegalStateException(
				"@InitBinder methods are not allowed to add model attributes: " + binderMethod);
	}
}
 
@Test
public void handleResponseEntityWithNullBody() throws Exception {
	Object returnValue = Mono.just(notFound().build());
	MethodParameter type = on(TestController.class).resolveReturnType(Mono.class, entity(String.class));
	HandlerResult result = handlerResult(returnValue, type);
	MockServerWebExchange exchange = MockServerWebExchange.from(get("/path"));
	this.resultHandler.handleResult(exchange, result).block(Duration.ofSeconds(5));

	assertEquals(HttpStatus.NOT_FOUND, exchange.getResponse().getStatusCode());
	assertResponseBodyIsEmpty(exchange);
}
 
@Override
public boolean supports(HandlerResult result) {
	MethodParameter returnType = result.getReturnTypeSource();
	Class<?> containingClass = returnType.getContainingClass();
	return (AnnotatedElementUtils.hasAnnotation(containingClass, ResponseBody.class) ||
			returnType.hasMethodAnnotation(ResponseBody.class));
}
 
private Mono<HandlerResult> handleException(Throwable exception, HandlerMethod handlerMethod,
		BindingContext bindingContext, ServerWebExchange exchange) {

	Assert.state(this.methodResolver != null, "Not initialized");

	// Success and error responses may use different content types
	exchange.getAttributes().remove(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
	if (!exchange.getResponse().isCommitted()) {
		exchange.getResponse().getHeaders().remove(HttpHeaders.CONTENT_TYPE);
	}

	InvocableHandlerMethod invocable = this.methodResolver.getExceptionHandlerMethod(exception, handlerMethod);
	if (invocable != null) {
		try {
			if (logger.isDebugEnabled()) {
				logger.debug(exchange.getLogPrefix() + "Using @ExceptionHandler " + invocable);
			}
			bindingContext.getModel().asMap().clear();
			Throwable cause = exception.getCause();
			if (cause != null) {
				return invocable.invoke(exchange, bindingContext, exception, cause, handlerMethod);
			}
			else {
				return invocable.invoke(exchange, bindingContext, exception, handlerMethod);
			}
		}
		catch (Throwable invocationEx) {
			if (logger.isWarnEnabled()) {
				logger.warn(exchange.getLogPrefix() + "Failure in @ExceptionHandler " + invocable, invocationEx);
			}
		}
	}
	return Mono.error(exception);
}
 
@Test
public void checkNotModified() {
	MockServerHttpRequest request = MockServerHttpRequest.get("/").ifModifiedSince(10 * 1000 * 1000).build();
	ServerWebExchange exchange = MockServerWebExchange.from(request);
	this.resolvers.add(stubResolver(exchange));
	Method method = ResolvableMethod.on(TestController.class).mockCall(c -> c.notModified(exchange)).method();
	HandlerResult result = invokeForResult(new TestController(), method);

	assertNull("Expected no result (i.e. fully handled)", result);
}
 
@Test // SPR-17082
public void handleResponseEntityWithExistingResponseHeaders() throws Exception {
	ResponseEntity<Void> value = ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).build();
	MethodParameter returnType = on(TestController.class).resolveReturnType(entity(Void.class));
	HandlerResult result = handlerResult(value, returnType);
	MockServerWebExchange exchange = MockServerWebExchange.from(get("/path"));
	exchange.getResponse().getHeaders().setContentType(MediaType.TEXT_PLAIN);
	this.resultHandler.handleResult(exchange, result).block(Duration.ofSeconds(5));

	assertEquals(HttpStatus.OK, exchange.getResponse().getStatusCode());
	assertEquals(1, exchange.getResponse().getHeaders().size());
	assertEquals(MediaType.APPLICATION_JSON, exchange.getResponse().getHeaders().getContentType());
	assertResponseBodyIsEmpty(exchange);
}
 
private ServerWebExchange testHandle(String path, MethodParameter returnType, Object returnValue,
		String responseBody, ViewResolver... resolvers) {

	Model model = this.bindingContext.getModel();
	model.asMap().clear();
	model.addAttribute("id", "123");
	HandlerResult result = new HandlerResult(new Object(), returnValue, returnType, this.bindingContext);
	MockServerWebExchange exchange = MockServerWebExchange.from(get(path));
	resultHandler(resolvers).handleResult(exchange, result).block(Duration.ofSeconds(5));
	assertResponseBody(exchange, responseBody);
	return exchange;
}
 
@Test
public void resolveProvidedArgFirst() {
	this.resolvers.add(stubResolver("value1"));
	Method method = ResolvableMethod.on(TestController.class).mockCall(o -> o.singleArg(null)).method();
	Mono<HandlerResult> mono = invoke(new TestController(), method, "value2");

	assertHandlerResultValue(mono, "success:value2");
}
 
@Test
public void httpHeaders() throws Exception {
	HttpHeaders headers = new HttpHeaders();
	headers.setAllow(new LinkedHashSet<>(Arrays.asList(HttpMethod.GET, HttpMethod.POST, HttpMethod.OPTIONS)));
	MethodParameter returnType = on(TestController.class).resolveReturnType(entity(Void.class));
	HandlerResult result = handlerResult(headers, returnType);
	MockServerWebExchange exchange = MockServerWebExchange.from(get("/path"));
	this.resultHandler.handleResult(exchange, result).block(Duration.ofSeconds(5));

	assertEquals(HttpStatus.OK, exchange.getResponse().getStatusCode());
	assertEquals(1, exchange.getResponse().getHeaders().size());
	assertEquals("GET,POST,OPTIONS", exchange.getResponse().getHeaders().getFirst("Allow"));
	assertResponseBodyIsEmpty(exchange);
}
 
private HandlerResult handle(RequestMappingHandlerAdapter adapter,
		Object controller, String methodName) throws Exception {

	Method method = controller.getClass().getMethod(methodName);
	HandlerMethod handlerMethod = new HandlerMethod(controller, method);
	return adapter.handle(this.exchange, handlerMethod).block(Duration.ZERO);
}
 
@Test
public void handleResponseEntityWithNullBody() throws Exception {
	Object returnValue = Mono.just(notFound().build());
	MethodParameter type = on(TestController.class).resolveReturnType(Mono.class, entity(String.class));
	HandlerResult result = handlerResult(returnValue, type);
	MockServerWebExchange exchange = MockServerWebExchange.from(get("/path"));
	this.resultHandler.handleResult(exchange, result).block(Duration.ofSeconds(5));

	assertEquals(HttpStatus.NOT_FOUND, exchange.getResponse().getStatusCode());
	assertResponseBodyIsEmpty(exchange);
}
 
@Test
public void handleReturnValueEtag() throws Exception {
	String etagValue = "\"deadb33f8badf00d\"";
	MockServerWebExchange exchange = MockServerWebExchange.from(get("/path").ifNoneMatch(etagValue));

	ResponseEntity<String> entity = ok().eTag(etagValue).body("body");
	MethodParameter returnType = on(TestController.class).resolveReturnType(entity(String.class));
	HandlerResult result = handlerResult(entity, returnType);
	this.resultHandler.handleResult(exchange, result).block(Duration.ofSeconds(5));

	assertConditionalResponse(exchange, HttpStatus.NOT_MODIFIED, null, etagValue, Instant.MIN);
}