parent
9a9166622e
commit
e4c62cc029
|
@ -157,9 +157,10 @@ import org.springframework.core.annotation.AliasFor;
|
|||
*
|
||||
* <p>The following return types are supported for handler methods:
|
||||
* <ul>
|
||||
* <li>{@code ModelAndView} object (from Servlet MVC),
|
||||
* with the model implicitly enriched with command objects and the results
|
||||
* of {@link ModelAttribute @ModelAttribute} annotated reference data accessor methods.
|
||||
* <li>{@link org.springframework.web.servlet.ModelAndView} object (Spring MVC only),
|
||||
* providing a view, model attributes, and optionally a response status.
|
||||
* <li>{@link org.springframework.web.reactive.result.view.Rendering} object (Spring WebFlux only),
|
||||
* providing a view, model attributes, and optionally a response status.
|
||||
* <li>{@link org.springframework.ui.Model Model} object, with the view name implicitly
|
||||
* determined through a {@link org.springframework.web.servlet.RequestToViewNameTranslator}
|
||||
* and the model implicitly enriched with command objects and the results
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.web.reactive.result.view;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link Rendering}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
*/
|
||||
class DefaultRendering implements Rendering {
|
||||
|
||||
private static final HttpHeaders EMPTY_HEADERS = HttpHeaders.readOnlyHttpHeaders(new HttpHeaders());
|
||||
|
||||
|
||||
private final Object view;
|
||||
|
||||
private final Map<String, Object> model;
|
||||
|
||||
private final HttpStatus status;
|
||||
|
||||
private final HttpHeaders headers;
|
||||
|
||||
|
||||
DefaultRendering(Object view, Model model, HttpStatus status, HttpHeaders headers) {
|
||||
this.view = view;
|
||||
this.model = (model != null ? model.asMap() : Collections.emptyMap());
|
||||
this.status = status;
|
||||
this.headers = headers != null ? headers : EMPTY_HEADERS;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Optional<Object> view() {
|
||||
return Optional.ofNullable(this.view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> modelAttributes() {
|
||||
return this.model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<HttpStatus> status() {
|
||||
return Optional.ofNullable(this.status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders headers() {
|
||||
return this.headers;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Rendering[view=" + this.view + ", modelAttributes=" + this.model +
|
||||
", status=" + this.status + ", headers=" + this.headers + "]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.web.reactive.result.view;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.ui.ExtendedModelMap;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link Rendering.RedirectBuilder}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
*/
|
||||
class DefaultRenderingBuilder implements Rendering.RedirectBuilder {
|
||||
|
||||
private final Object view;
|
||||
|
||||
private Model model;
|
||||
|
||||
private HttpStatus status;
|
||||
|
||||
private HttpHeaders headers;
|
||||
|
||||
|
||||
DefaultRenderingBuilder(Object view) {
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DefaultRenderingBuilder modelAttribute(String name, Object value) {
|
||||
initModel();
|
||||
this.model.addAttribute(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void initModel() {
|
||||
if (this.model == null) {
|
||||
this.model = new ExtendedModelMap();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultRenderingBuilder modelAttribute(Object value) {
|
||||
initModel();
|
||||
this.model.addAttribute(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultRenderingBuilder modelAttributes(Object... values) {
|
||||
initModel();
|
||||
this.model.addAllAttributes(Arrays.asList(values));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultRenderingBuilder model(Map<String, ?> map) {
|
||||
initModel();
|
||||
this.model.addAllAttributes(map);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultRenderingBuilder status(HttpStatus status) {
|
||||
this.status = status;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultRenderingBuilder header(String headerName, String... headerValues) {
|
||||
initHeaders();
|
||||
this.headers.put(headerName, Arrays.asList(headerValues));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultRenderingBuilder headers(HttpHeaders headers) {
|
||||
initHeaders();
|
||||
this.headers.putAll(headers);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void initHeaders() {
|
||||
if (this.headers == null) {
|
||||
this.headers = new HttpHeaders();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rendering.RedirectBuilder contextRelative(boolean contextRelative) {
|
||||
getRedirectView().setContextRelative(contextRelative);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rendering.RedirectBuilder propagateQuery(boolean propagate) {
|
||||
getRedirectView().setPropagateQuery(propagate);
|
||||
return this;
|
||||
}
|
||||
|
||||
private RedirectView getRedirectView() {
|
||||
Assert.isInstanceOf(RedirectView.class, this.view);
|
||||
return (RedirectView) this.view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rendering build() {
|
||||
return new DefaultRendering(this.view, this.model, this.status, this.headers);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.web.reactive.result.view;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
|
||||
/**
|
||||
* Public API for HTML rendering. Supported as a return value in Spring WebFlux
|
||||
* controllers. Comparable to the use of {@code ModelAndView} as a return value
|
||||
* in Spring MVC controllers.
|
||||
*
|
||||
* <p>Controllers typically return a {@link String} view name and rely on the
|
||||
* "implicit" model which can also be injected into the controller method.
|
||||
* Or controllers may return model attribute(s) and rely on a default view name
|
||||
* being selected based on the request path.
|
||||
*
|
||||
* <p>{@link Rendering} can be used to combine a view name with model attributes,
|
||||
* set the HTTP status or headers, and for other more advanced options around
|
||||
* redirect scenarios.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
*/
|
||||
public interface Rendering {
|
||||
|
||||
/**
|
||||
* Return the selected {@link String} view name or {@link View} object.
|
||||
*/
|
||||
Optional<Object> view();
|
||||
|
||||
/**
|
||||
* Return attributes to add to the model.
|
||||
*/
|
||||
Map<String, Object> modelAttributes();
|
||||
|
||||
/**
|
||||
* Return the HTTP status to set the response to.
|
||||
*/
|
||||
Optional<HttpStatus> status();
|
||||
|
||||
/**
|
||||
* Return headers to add to the response.
|
||||
*/
|
||||
HttpHeaders headers();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new builder for response rendering based on the given view name.
|
||||
* @param name the view name to be resolved to a {@link View}
|
||||
* @return the builder
|
||||
*/
|
||||
static Builder<?> view(String name) {
|
||||
return new DefaultRenderingBuilder(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new builder for a redirect through a {@link RedirectView}.
|
||||
* @param url the redirect URL
|
||||
* @return the builder
|
||||
*/
|
||||
static RedirectBuilder redirectTo(String url) {
|
||||
return new DefaultRenderingBuilder(new RedirectView(url));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Defines a builder for {@link Rendering}.
|
||||
*/
|
||||
interface Builder<B extends Builder<B>> {
|
||||
|
||||
/**
|
||||
* Add the given model attribute with the supplied name.
|
||||
* @see Model#addAttribute(String, Object)
|
||||
*/
|
||||
B modelAttribute(String name, Object value);
|
||||
|
||||
/**
|
||||
* Add an attribute to the model using a
|
||||
* {@link org.springframework.core.Conventions#getVariableName generated name}.
|
||||
* @see Model#addAttribute(Object)
|
||||
*/
|
||||
B modelAttribute(Object value);
|
||||
|
||||
/**
|
||||
* Add all given attributes to the model using
|
||||
* {@link org.springframework.core.Conventions#getVariableName generated names}.
|
||||
* @see Model#addAllAttributes(Collection)
|
||||
*/
|
||||
B modelAttributes(Object... values);
|
||||
|
||||
/**
|
||||
* Add the given attributes to the model.
|
||||
* @see Model#addAllAttributes(Map)
|
||||
*/
|
||||
B model(Map<String, ?> map);
|
||||
|
||||
/**
|
||||
* Specify the status to use for the response.
|
||||
*/
|
||||
B status(HttpStatus status);
|
||||
|
||||
/**
|
||||
* Specify a header to add to the response.
|
||||
*/
|
||||
B header(String headerName, String... headerValues);
|
||||
|
||||
/**
|
||||
* Specify headers to add to the response.
|
||||
*/
|
||||
B headers(HttpHeaders headers);
|
||||
|
||||
/**
|
||||
* Builder the {@link Rendering} instance.
|
||||
*/
|
||||
Rendering build();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extends {@link Builder} with extra options for redirect scenarios.
|
||||
*/
|
||||
interface RedirectBuilder extends Builder<RedirectBuilder> {
|
||||
|
||||
/**
|
||||
* Whether to the provided redirect URL should be prepended with the
|
||||
* application context path (if any).
|
||||
* <p>By default this is set to {@code true}.
|
||||
*
|
||||
* @see RedirectView#setContextRelative(boolean)
|
||||
*/
|
||||
RedirectBuilder contextRelative(boolean contextRelative);
|
||||
|
||||
/**
|
||||
* Whether to append the query string of the current URL to the target
|
||||
* redirect URL or not.
|
||||
* <p>By default this is set to {@code false}.
|
||||
*
|
||||
* @see RedirectView#setPropagateQuery(boolean)
|
||||
*/
|
||||
RedirectBuilder propagateQuery(boolean propagate);
|
||||
}
|
||||
|
||||
}
|
|
@ -159,7 +159,7 @@ public class ViewResolutionResultHandler extends HandlerResultHandlerSupport
|
|||
}
|
||||
return (CharSequence.class.isAssignableFrom(type) || View.class.isAssignableFrom(type) ||
|
||||
Model.class.isAssignableFrom(type) || Map.class.isAssignableFrom(type) ||
|
||||
!BeanUtils.isSimpleProperty(type));
|
||||
Rendering.class.isAssignableFrom(type) || !BeanUtils.isSimpleProperty(type));
|
||||
}
|
||||
|
||||
private boolean hasModelAnnotation(MethodParameter parameter) {
|
||||
|
@ -224,6 +224,15 @@ public class ViewResolutionResultHandler extends HandlerResultHandlerSupport
|
|||
else if (CharSequence.class.isAssignableFrom(clazz) && !hasModelAnnotation(parameter)) {
|
||||
viewsMono = resolveViews(returnValue.toString(), locale);
|
||||
}
|
||||
else if (Rendering.class.isAssignableFrom(clazz)) {
|
||||
Rendering render = (Rendering) returnValue;
|
||||
render.status().ifPresent(exchange.getResponse()::setStatusCode);
|
||||
exchange.getResponse().getHeaders().putAll(render.headers());
|
||||
model.addAllAttributes(render.modelAttributes());
|
||||
Object view = render.view().orElse(getDefaultViewName(exchange));
|
||||
viewsMono = (view instanceof String ? resolveViews((String) view, locale) :
|
||||
Mono.just(Collections.singletonList((View) view)));
|
||||
}
|
||||
else {
|
||||
String name = getNameForReturnValue(clazz, parameter);
|
||||
model.addAttribute(name, returnValue);
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.web.reactive.result.view;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.ui.ExtendedModelMap;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DefaultRenderingBuilder}.
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class DefaultRenderingBuilderTests {
|
||||
|
||||
|
||||
@Test
|
||||
public void defaultValues() {
|
||||
Rendering rendering = Rendering.view("abc").build();
|
||||
|
||||
assertEquals("abc", rendering.view().orElse(null));
|
||||
assertEquals(Collections.emptyMap(), rendering.modelAttributes());
|
||||
assertNull(rendering.status().orElse(null));
|
||||
assertEquals(0, rendering.headers().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultValuesForRedirect() throws Exception {
|
||||
Rendering rendering = Rendering.redirectTo("abc").build();
|
||||
|
||||
Object view = rendering.view().orElse(null);
|
||||
assertEquals(RedirectView.class, view.getClass());
|
||||
assertEquals("abc", ((RedirectView) view).getUrl());
|
||||
assertTrue(((RedirectView) view).isContextRelative());
|
||||
assertFalse(((RedirectView) view).isPropagateQuery());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void viewName() {
|
||||
Rendering rendering = Rendering.view("foo").build();
|
||||
assertEquals("foo", rendering.view().orElse(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void modelAttribute() throws Exception {
|
||||
Foo foo = new Foo();
|
||||
Rendering rendering = Rendering.view("foo").modelAttribute(foo).build();
|
||||
|
||||
assertEquals(Collections.singletonMap("foo", foo), rendering.modelAttributes());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void modelAttributes() throws Exception {
|
||||
Foo foo = new Foo();
|
||||
Bar bar = new Bar();
|
||||
Rendering rendering = Rendering.view("foo").modelAttributes(foo, bar).build();
|
||||
|
||||
Map<String, Object> map = new LinkedHashMap<>(2);
|
||||
map.put("foo", foo);
|
||||
map.put("bar", bar);
|
||||
assertEquals(map, rendering.modelAttributes());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void model() throws Exception {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
map.put("foo", new Foo());
|
||||
map.put("bar", new Bar());
|
||||
Rendering rendering = Rendering.view("foo").model(map).build();
|
||||
|
||||
assertEquals(map, rendering.modelAttributes());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void header() throws Exception {
|
||||
Rendering rendering = Rendering.view("foo").header("foo", "bar").build();
|
||||
|
||||
assertEquals(1, rendering.headers().size());
|
||||
assertEquals(Collections.singletonList("bar"), rendering.headers().get("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpHeaders() throws Exception {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("foo", "bar");
|
||||
Rendering rendering = Rendering.view("foo").headers(headers).build();
|
||||
|
||||
assertEquals(headers, rendering.headers());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void redirectWithAbsoluteUrl() throws Exception {
|
||||
Rendering rendering = Rendering.redirectTo("foo").contextRelative(false).build();
|
||||
|
||||
Object view = rendering.view().orElse(null);
|
||||
assertEquals(RedirectView.class, view.getClass());
|
||||
assertFalse(((RedirectView) view).isContextRelative());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void redirectWithPropagateQuery() throws Exception {
|
||||
Rendering rendering = Rendering.redirectTo("foo").propagateQuery(true).build();
|
||||
|
||||
Object view = rendering.view().orElse(null);
|
||||
assertEquals(RedirectView.class, view.getClass());
|
||||
assertTrue(((RedirectView) view).isPropagateQuery());
|
||||
}
|
||||
|
||||
|
||||
private static class Foo {}
|
||||
|
||||
private static class Bar {}
|
||||
|
||||
}
|
|
@ -39,6 +39,7 @@ import org.springframework.core.Ordered;
|
|||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
|
||||
import org.springframework.core.io.buffer.support.DataBufferTestUtils;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.mock.http.server.reactive.test.MockServerWebExchange;
|
||||
|
@ -86,6 +87,8 @@ public class ViewResolutionResultHandlerTests {
|
|||
testSupports(on(TestController.class).resolveReturnType(Model.class));
|
||||
testSupports(on(TestController.class).resolveReturnType(Map.class));
|
||||
testSupports(on(TestController.class).resolveReturnType(TestBean.class));
|
||||
testSupports(on(TestController.class).resolveReturnType(Rendering.class));
|
||||
testSupports(on(TestController.class).resolveReturnType(Mono.class, Rendering.class));
|
||||
|
||||
testSupports(on(TestController.class).annotPresent(ModelAttribute.class).resolveReturnType());
|
||||
}
|
||||
|
@ -148,16 +151,22 @@ public class ViewResolutionResultHandlerTests {
|
|||
|
||||
returnType = on(TestController.class).resolveReturnType(TestBean.class);
|
||||
returnValue = new TestBean("Joe");
|
||||
String responseBody = "account: {" +
|
||||
"id=123, " +
|
||||
String responseBody = "account: {id=123, " +
|
||||
"org.springframework.validation.BindingResult.testBean=" +
|
||||
"org.springframework.validation.BeanPropertyBindingResult: 0 errors, " +
|
||||
"testBean=TestBean[name=Joe]" +
|
||||
"}";
|
||||
"testBean=TestBean[name=Joe]}";
|
||||
testHandle("/account", returnType, returnValue, responseBody, resolver);
|
||||
|
||||
returnType = on(TestController.class).annotPresent(ModelAttribute.class).resolveReturnType();
|
||||
testHandle("/account", returnType, 99L, "account: {id=123, num=99}", resolver);
|
||||
|
||||
returnType = on(TestController.class).resolveReturnType(Rendering.class);
|
||||
HttpStatus status = HttpStatus.UNPROCESSABLE_ENTITY;
|
||||
returnValue = Rendering.view("account").modelAttribute("a", "a1").status(status).header("h", "h1").build();
|
||||
String expected = "account: {a=a1, id=123}";
|
||||
ServerWebExchange exchange = testHandle("/path", returnType, returnValue, expected, resolver);
|
||||
assertEquals(status, exchange.getResponse().getStatusCode());
|
||||
assertEquals("h1", exchange.getResponse().getHeaders().getFirst("h"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -429,6 +438,14 @@ public class ViewResolutionResultHandlerTests {
|
|||
Long longAttribute() {
|
||||
return null;
|
||||
}
|
||||
|
||||
Rendering rendering() {
|
||||
return null;
|
||||
}
|
||||
|
||||
Mono<Rendering> monoRendering() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1408,8 +1408,10 @@ of `java.util.Optional` in those cases is equivalent to having `required=false`.
|
|||
==== Supported method return types
|
||||
The following are the supported return types:
|
||||
|
||||
* `ModelAndView` object, with the model implicitly enriched with command objects and
|
||||
the results of `@ModelAttribute` annotated reference data accessor methods.
|
||||
* `ModelAndView` object (Spring MVC), providing a view, model attributes, and
|
||||
optionally a response status.
|
||||
* `Rendering` object (Spring WebFlux), providing a view, model attributes, and
|
||||
optionally a response status.
|
||||
* `Model` object, with the view name implicitly determined through a
|
||||
`RequestToViewNameTranslator` and the model implicitly enriched with command objects
|
||||
and the results of `@ModelAttribute` annotated reference data accessor methods.
|
||||
|
|
Loading…
Reference in New Issue