@ -17,7 +17,6 @@
package org.springframework.web.reactive.result.view ;
package org.springframework.web.reactive.result.view ;
import java.util.Collection ;
import java.util.Collection ;
import java.util.List ;
import java.util.Map ;
import java.util.Map ;
import java.util.function.Consumer ;
import java.util.function.Consumer ;
@ -32,13 +31,16 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert ;
import org.springframework.util.Assert ;
/ * *
/ * *
* Public API for HTML rendering of a collection of fragments each with a view
* Public API to render HTML fragments . A fragment is a portion of an HTML page .
* and independent model . For use with frontends technologies such as
* Normally HTML is rendered with a single model and view . This API allows
* using multiple model and view pairs , one for each HTML fragment .
*
* < p > For use with frontends technologies such as
* < a href = "https://htmx.org/" > htmx < / a > where multiple page fragments may be
* < a href = "https://htmx.org/" > htmx < / a > where multiple page fragments may be
* rendered in one response . Supported as a return value from Spring WebFlux
* rendered in one response .
* controller methods .
*
*
* < p > For full page rendering with a single model and view , use { @link Rendering } .
* < p > Supported as a return value from annotated controller methods .
* For full page rendering with a single model and view , use { @link Rendering } .
*
*
* @author Rossen Stoyanchev
* @author Rossen Stoyanchev
* @since 6 . 2
* @since 6 . 2
@ -63,59 +65,107 @@ public interface FragmentsRendering {
/ * *
/ * *
* Create a builder and add a fragment with a view name and a model .
* Create a builder with one HTML fragment , also inheriting attributes from
* the shared model for the request .
* @param viewName the name of the view for the fragment
* @param viewName the name of the view for the fragment
* @param model attributes for the fragment in addition to model
* attributes inherited from the model for the request
* @return this builder
* @return this builder
* @since 6 . 2 . 13
* /
* /
static Builder with ( String viewName , Map < String , Object > model ) {
static Builder fragment ( String viewName ) {
return withCollection ( List . of ( Fragment . create ( viewName , model ) ) ) ;
return new DefaultFragmentsRenderingBuilder ( ) . fragment ( viewName ) ;
}
}
/ * *
/ * *
* Variant of { @link # with ( String , Map ) } with a view name only , but also
* Create a builder with one HTML fragment .
* inheriting model attributes from the shared model for the request .
* @param viewName the view name for the fragment
* @param viewName the name of the view for the fragment
* @param model attributes for the fragment , in addition to attributes from the
* shared model for the request
* @return this builder
* @return this builder
* @since 6 . 2 . 13
* /
* /
static Builder with ( String viewName ) {
static Builder fragment ( String viewName , Map < String , Object > model ) {
return withCollection ( List . of ( Fragment . create ( viewName ) ) ) ;
return new DefaultFragmentsRenderingBuilder ( ) . fragment ( viewName , model ) ;
}
}
/ * *
/ * *
* Variant of { @link # with ( String , Map ) } with a collection of fragments .
* Create a builder with multiple HTML fragments .
* @param fragments the fragments to add ; each fragment also inherits model
* @param fragments the fragments to add ; each fragment also inherits
* attributes from the shared model for the request
* attributes from the shared model for the request
* @return the created builder
* @return the created builder
* @since 6 . 2 . 13
* /
* /
static Builder withCollection ( Collection < Fragment > fragments ) {
static Builder fragments ( Collection < Fragment > fragments ) {
return new DefaultFragmentsRenderingBuilder ( fragments ) ;
return new DefaultFragmentsRenderingBuilder ( ) . fragments ( fragments ) ;
}
}
/ * *
/ * *
* Variant of { @link # with ( String , Map ) } with a { @link Publisher } of fragments .
* Create a builder with a { @link Publisher } of fragments .
* @param fragmentsPublisher the fragments to add ; each fragment also
* @param fragmentsPublisher the fragments to add ; each fragment also
* inherits model attributes from the shared model for the request
* inherits model attributes from the shared model for the request
* @return the created builder
* @return the created builder
* @since 6 . 2 . 13
* /
* /
static < P extends Publisher < Fragment > > Builder with Publisher( P fragmentsPublisher ) {
static < P extends Publisher < Fragment > > Builder fragments Publisher( P fragmentsPublisher ) {
return new DefaultFragmentsRenderingBuilder ( fragmentsPublisher ) ;
return new DefaultFragmentsRenderingBuilder ( fragmentsPublisher ) ;
}
}
/ * *
/ * *
* Variant of { @link # with Publisher( Publisher ) } that allows using any
* Variant of { @link # fragments Publisher( Publisher ) } that allows using any
* producer that can be resolved to { @link Publisher } via
* producer that can be resolved to { @link Publisher } via
* { @link ReactiveAdapterRegistry } .
* { @link ReactiveAdapterRegistry } .
* @since 6 . 2 . 13
* /
* /
static Builder withProducer ( Object fragmentsProducer ) {
static Builder fragmentsProducer ( Object fragmentsProducer ) {
return new DefaultFragmentsRenderingBuilder ( adaptProducer ( fragmentsProducer ) ) ;
ReactiveAdapter adapter = ReactiveAdapterRegistry . getSharedInstance ( ) . getAdapter ( fragmentsProducer . getClass ( ) ) ;
Assert . isTrue ( adapter ! = null , "Unknown producer " + fragmentsProducer . getClass ( ) ) ;
Publisher < Fragment > publisher = adapter . toPublisher ( fragmentsProducer ) ;
return fragmentsPublisher ( publisher ) ;
}
}
private static Publisher < Fragment > adaptProducer ( Object producer ) {
ReactiveAdapter adapter = ReactiveAdapterRegistry . getSharedInstance ( ) . getAdapter ( producer . getClass ( ) ) ;
/ * *
Assert . isTrue ( adapter ! = null , "Unknown producer " + producer . getClass ( ) ) ;
* The same as { @link # fragment ( String , Map ) } .
return adapter . toPublisher ( producer ) ;
* @deprecated in favor of { @link # fragment ( String , Map ) }
* /
@Deprecated ( since = "6.2.13" , forRemoval = true )
static Builder with ( String viewName , Map < String , Object > model ) {
return fragment ( viewName , model ) ;
}
/ * *
* The same as { @link # fragments ( Collection ) } .
* @deprecated in favor of { @link # fragments ( Collection ) }
* /
@Deprecated ( since = "6.2.13" , forRemoval = true )
static Builder with ( String viewName ) {
return fragment ( viewName ) ;
}
/ * *
* The same as { @link # fragments ( Collection ) } .
* @deprecated in favor of { @link # fragments ( Collection ) }
* /
@Deprecated ( since = "6.2.13" , forRemoval = true )
static Builder withCollection ( Collection < Fragment > fragments ) {
return fragments ( fragments ) ;
}
/ * *
* The same as { @link # fragmentsPublisher ( Publisher ) } .
* @deprecated in favor of { @link # fragmentsPublisher ( Publisher ) }
* /
@Deprecated ( since = "6.2.13" , forRemoval = true )
static < P extends Publisher < Fragment > > Builder withPublisher ( P fragmentsPublisher ) {
return fragmentsPublisher ( fragmentsPublisher ) ;
}
/ * *
* The same as { @link # fragmentsProducer ( Object ) } .
* @deprecated in favor of { @link # fragmentsProducer ( Object ) }
* /
@Deprecated ( since = "6.2.13" , forRemoval = true )
static Builder withProducer ( Object fragmentsProducer ) {
return fragmentsProducer ( fragmentsProducer ) ;
}
}
@ -148,30 +198,39 @@ public interface FragmentsRendering {
Builder headers ( Consumer < HttpHeaders > headersConsumer ) ;
Builder headers ( Consumer < HttpHeaders > headersConsumer ) ;
/ * *
/ * *
* Add a fragment with a view name and a model .
* Add an HTML fragment .
* @param viewName the name of the view for the fragment
* @param viewName the view name for the fragment
* @param model attributes for the fragment in addition to model
* @param model fragment attributes in addition to attributes from the
* attribute s in herited f rom th e model for the request
* sha red model for the request
* @return this builder
* @return this builder
* /
* /
Builder fragment ( String viewName , Map < String , Object > model ) ;
Builder fragment ( String viewName , Map < String , Object > model ) ;
/ * *
/ * *
* Variant of { @link # fragment ( String , Map ) } with a view name only , where
* Add an HTML fragment . The fragment will use attributes from the shared
* the fragment model also inherits model attributes from the shared
* model for the request .
* model for the request .
* @param viewName the name of the view for the fragment
* @param viewName the view name for the fragment
* @return this builder
* @return this builder
* /
* /
Builder fragment ( String viewName ) ;
Builder fragment ( String viewName ) ;
/ * *
/ * *
* Variant of { @link # fragment ( String , Map ) } with a { @link Fragment } .
* Add an HTML fragment .
* @param fragment the fragment to add
* @param fragment the fragment to add ; the fragment also inherits
* attributes from the shared model for the request
* @return this builder
* @return this builder
* /
* /
Builder fragment ( Fragment fragment ) ;
Builder fragment ( Fragment fragment ) ;
/ * *
* Add HTML fragments .
* @param fragments the fragments to add ; each fragment also inherits
* attributes from the shared model for the request
* @return this builder
* @since 6 . 2 . 13
* /
Builder fragments ( Collection < Fragment > fragments ) ;
/ * *
/ * *
* Build the { @link FragmentsRendering } instance .
* Build the { @link FragmentsRendering } instance .
* /
* /