@Override public Mono<View> resolveViewName(String viewName, Locale locale) { if (!canHandle(viewName, locale)) { return Mono.empty(); } AbstractUrlBasedView urlBasedView; if (viewName.startsWith(REDIRECT_URL_PREFIX)) { String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length()); urlBasedView = this.redirectViewProvider.apply(redirectUrl); } else { urlBasedView = createView(viewName); } View view = applyLifecycleMethods(viewName, urlBasedView); try { return (urlBasedView.checkResourceExists(locale) ? Mono.just(view) : Mono.empty()); } catch (Exception ex) { return Mono.error(ex); } }
@Test public void viewNames() throws Exception { this.resolver.setViewClass(TestView.class); this.resolver.setViewNames("my*"); Mono<View> mono = this.resolver.resolveViewName("my-view", Locale.US); assertNotNull(mono.block()); mono = this.resolver.resolveViewName("not-my-view", Locale.US); assertNull(mono.block()); }
/** * Apply the containing {@link ApplicationContext}'s lifecycle methods * to the given {@link View} instance, if such a context is available. * @param viewName the name of the view * @param view the freshly created View instance, pre-configured with * {@link AbstractUrlBasedView}'s properties * @return the {@link View} instance to use (either the original one * or a decorated variant) * @see #getApplicationContext() * @see ApplicationContext#getAutowireCapableBeanFactory() * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#initializeBean */ protected View applyLifecycleMethods(String viewName, AbstractUrlBasedView view) { ApplicationContext context = getApplicationContext(); if (context != null) { Object initialized = context.getAutowireCapableBeanFactory().initializeBean(view, viewName); if (initialized instanceof View) { return (View) initialized; } } return view; }
/** * Creates a new View instance of the specified view class and configures it. * Does <i>not</i> perform any lookup for pre-defined View instances. * <p>Spring lifecycle methods as defined by the bean container do not have to * be called here: They will be automatically applied afterwards, provided * that an {@link #setApplicationContext ApplicationContext} is available. * @param viewName the name of the view to build * @return the View instance * @see #getViewClass() * @see #applyLifecycleMethods */ protected AbstractUrlBasedView createView(String viewName) { Class<?> viewClass = getViewClass(); Assert.state(viewClass != null, "No view class"); AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(viewClass); view.setSupportedMediaTypes(getSupportedMediaTypes()); view.setRequestContextAttribute(getRequestContextAttribute()); view.setDefaultCharset(getDefaultCharset()); view.setUrl(getPrefix() + viewName + getSuffix()); return view; }
@Before public void setup() { StaticApplicationContext context = new StaticApplicationContext(); context.refresh(); this.resolver = new UrlBasedViewResolver(); this.resolver.setApplicationContext(context); }
/** * Register a script template view resolver with an empty default view name prefix and suffix. * <p><strong>Note</strong> that you must also configure script templating by * adding a {@link ScriptTemplateConfigurer} bean. * @since 5.0.4 */ public UrlBasedViewResolverRegistration scriptTemplate() { if (!checkBeanOfType(ScriptTemplateConfigurer.class)) { throw new BeanInitializationException("In addition to a script template view resolver " + "there must also be a single ScriptTemplateConfig bean in this web application context " + "(or its parent): ScriptTemplateConfigurer is the usual implementation. " + "This bean may be given any name."); } ScriptRegistration registration = new ScriptRegistration(); UrlBasedViewResolver resolver = registration.getViewResolver(); if (this.applicationContext != null) { resolver.setApplicationContext(this.applicationContext); } this.viewResolvers.add(resolver); return registration; }
@Override public Mono<View> resolveViewName(String viewName, Locale locale) { if (!canHandle(viewName, locale)) { return Mono.empty(); } AbstractUrlBasedView urlBasedView; if (viewName.startsWith(REDIRECT_URL_PREFIX)) { String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length()); urlBasedView = this.redirectViewProvider.apply(redirectUrl); } else { urlBasedView = createUrlBasedView(viewName); } View view = applyLifecycleMethods(viewName, urlBasedView); try { return (urlBasedView.checkResourceExists(locale) ? Mono.just(view) : Mono.empty()); } catch (Exception ex) { return Mono.error(ex); } }
/** * Set the view names (or name patterns) that can be handled by this view * resolver. View names can contain simple wildcards such that 'my*', '*Report' * and '*Repo*' will all match the view name 'myReport'. * @see UrlBasedViewResolver#setViewNames */ public UrlBasedViewResolverRegistration viewNames(String... viewNames) { this.viewResolver.setViewNames(viewNames); return this; }
/** * Set the view class that should be used to create views. * @see UrlBasedViewResolver#setViewClass */ public UrlBasedViewResolverRegistration viewClass(Class<?> viewClass) { this.viewResolver.setViewClass(viewClass); return this; }
@Override protected AbstractUrlBasedView createView(String viewName) { MustacheView view = (MustacheView) super.createView(viewName); view.setCompiler(this.compiler); view.setCharset(this.charset); return view; }
/** * Creates a new View instance of the specified view class and configures it. * Does <i>not</i> perform any lookup for pre-defined View instances. * <p>Spring lifecycle methods as defined by the bean container do not have to * be called here; those will be applied by the {@code loadView} method * after this method returns. * <p>Subclasses will typically call {@code super.buildView(viewName)} * first, before setting further properties themselves. {@code loadView} * will then apply Spring lifecycle methods at the end of this process. * @param viewName the name of the view to build * @return the View instance */ protected AbstractUrlBasedView createUrlBasedView(String viewName) { AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass()); view.setSupportedMediaTypes(getSupportedMediaTypes()); view.setRequestContextAttribute(getRequestContextAttribute()); view.setDefaultCharset(getDefaultCharset()); view.setUrl(getPrefix() + viewName + getSuffix()); return view; }
@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()); }
/** * Register a {@code FreeMarkerViewResolver} with a ".ftl" suffix. * <p><strong>Note</strong> that you must also configure FreeMarker by * adding a {@link FreeMarkerConfigurer} bean. */ public UrlBasedViewResolverRegistration freeMarker() { if (!checkBeanOfType(FreeMarkerConfigurer.class)) { throw new BeanInitializationException("In addition to a FreeMarker view resolver " + "there must also be a single FreeMarkerConfig bean in this web application context " + "(or its parent): FreeMarkerConfigurer is the usual implementation. " + "This bean may be given any name."); } FreeMarkerRegistration registration = new FreeMarkerRegistration(); UrlBasedViewResolver resolver = registration.getViewResolver(); if (this.applicationContext != null) { resolver.setApplicationContext(this.applicationContext); } this.viewResolvers.add(resolver); return registration; }
/** * Set the view names (or name patterns) that can be handled by this view * resolver. View names can contain simple wildcards such that 'my*', '*Report' * and '*Repo*' will all match the view name 'myReport'. * @see UrlBasedViewResolver#setViewNames */ public UrlBasedViewResolverRegistration viewNames(String... viewNames) { this.viewResolver.setViewNames(viewNames); return this; }
/** * Set the view class that should be used to create views. * @see UrlBasedViewResolver#setViewClass */ public UrlBasedViewResolverRegistration viewClass(Class<?> viewClass) { this.viewResolver.setViewClass(viewClass); return this; }
@Override protected AbstractUrlBasedView createView(String viewName) { MustacheView view = (MustacheView) super.createView(viewName); view.setCompiler(this.compiler); view.setCharset(this.charset); return view; }
/** * Register a {@code FreeMarkerViewResolver} with a ".ftl" suffix. * <p><strong>Note</strong> that you must also configure FreeMarker by * adding a {@link FreeMarkerConfigurer} bean. */ public UrlBasedViewResolverRegistration freeMarker() { if (this.applicationContext != null && !hasBeanOfType(FreeMarkerConfigurer.class)) { throw new BeanInitializationException("In addition to a FreeMarker view resolver " + "there must also be a single FreeMarkerConfig bean in this web application context " + "(or its parent): FreeMarkerConfigurer is the usual implementation. " + "This bean may be given any name."); } FreeMarkerRegistration registration = new FreeMarkerRegistration(); UrlBasedViewResolver resolver = registration.getViewResolver(); resolver.setApplicationContext(this.applicationContext); this.viewResolvers.add(resolver); return registration; }
private View applyLifecycleMethods(String viewName, AbstractView view) { return (View) getApplicationContext().getAutowireCapableBeanFactory().initializeBean(view, viewName); }