1+ /*
2+ * =============================================================================
3+ *
4+ * Copyright (c) 2011-2018, The THYMELEAF team (http://www.thymeleaf.org)
5+ *
6+ * Licensed under the Apache License, Version 2.0 (the "License");
7+ * you may not use this file except in compliance with the License.
8+ * You may obtain a copy of the License at
9+ *
10+ * http://www.apache.org/licenses/LICENSE-2.0
11+ *
12+ * Unless required by applicable law or agreed to in writing, software
13+ * distributed under the License is distributed on an "AS IS" BASIS,
14+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+ * See the License for the specific language governing permissions and
16+ * limitations under the License.
17+ *
18+ * =============================================================================
19+ */
20+ package org .thymeleaf .spring6 .view ;
21+
22+ import java .util .Arrays ;
23+ import java .util .Collections ;
24+ import java .util .HashSet ;
25+ import java .util .Map ;
26+ import java .util .Set ;
27+
28+ import jakarta .servlet .http .HttpServletRequest ;
29+ import jakarta .servlet .http .HttpServletResponse ;
30+
31+ import org .slf4j .Logger ;
32+ import org .slf4j .LoggerFactory ;
33+ import org .springframework .util .StringUtils ;
34+ import org .springframework .webflow .context .servlet .AjaxHandler ;
35+ import org .thymeleaf .exceptions .ConfigurationException ;
36+
37+
38+ // Copied from thymeleaf-spring5.
39+ // Temporarily here until available in thymeleaf-spring6.
40+
41+
42+ /**
43+ * <p>
44+ * Subclass of {@link ThymeleafView} adding compatibility with AJAX events in
45+ * Spring JavaScript (part of Spring WebFlow). This allows this View implementation
46+ * to be able to return only <i>fragments</i> of the page.
47+ * </p>
48+ * <p>
49+ * These rendering of fragments is used, for example, in Spring WebFlow's <render>
50+ * instructions (though not only).
51+ * </p>
52+ * <p>
53+ * This view searches for a comma-separated list of <i>markup selectors</i> in a request
54+ * parameter called {@code fragments}.
55+ * </p>
56+ *
57+ * @author Daniel Fernández
58+ *
59+ * @since 3.0.3
60+ *
61+ */
62+ public class AjaxThymeleafView extends ThymeleafView implements AjaxEnabledView {
63+
64+ private static final Logger vlogger = LoggerFactory .getLogger (AjaxThymeleafView .class );
65+
66+ private static final String FRAGMENTS_PARAM = "fragments" ;
67+
68+
69+ private AjaxHandler ajaxHandler = null ;
70+
71+
72+
73+ public AjaxThymeleafView () {
74+ super ();
75+ }
76+
77+
78+
79+ public AjaxHandler getAjaxHandler () {
80+ return this .ajaxHandler ;
81+ }
82+
83+
84+ public void setAjaxHandler (final AjaxHandler ajaxHandler ) {
85+ this .ajaxHandler = ajaxHandler ;
86+ }
87+
88+
89+
90+
91+ @ Override
92+ public void render (final Map <String , ?> model , final HttpServletRequest request , final HttpServletResponse response )
93+ throws Exception {
94+
95+
96+ final AjaxHandler templateAjaxHandler = getAjaxHandler ();
97+
98+ if (templateAjaxHandler == null ) {
99+ throw new ConfigurationException ("[THYMELEAF] AJAX Handler set into " +
100+ AjaxThymeleafView .class .getSimpleName () + " instance for template " +
101+ getTemplateName () + " is null." );
102+ }
103+
104+ if (templateAjaxHandler .isAjaxRequest (request , response )) {
105+
106+ final Set <String > fragmentsToRender = getRenderFragments (model , request , response );
107+ if (fragmentsToRender == null || fragmentsToRender .size () == 0 ) {
108+ vlogger .warn ("[THYMELEAF] An Ajax request was detected, but no fragments were specified to be re-rendered. "
109+ + "Falling back to full page render. This can cause unpredictable results when processing "
110+ + "the ajax response on the client." );
111+ super .render (model , request , response );
112+ return ;
113+ }
114+
115+ super .renderFragment (fragmentsToRender , model , request , response );
116+
117+ } else {
118+
119+ super .render (model , request , response );
120+
121+ }
122+
123+ }
124+
125+
126+
127+
128+ @ SuppressWarnings ({ "rawtypes" , "unused" })
129+ protected Set <String > getRenderFragments (
130+ final Map model , final HttpServletRequest request , final HttpServletResponse response ) {
131+ final String fragmentsParam = request .getParameter (FRAGMENTS_PARAM );
132+ final String [] renderFragments = StringUtils .commaDelimitedListToStringArray (fragmentsParam );
133+ if (renderFragments .length == 0 ) {
134+ return null ;
135+ }
136+ if (renderFragments .length == 1 ) {
137+ return Collections .singleton (renderFragments [0 ]);
138+ }
139+ return new HashSet <String >(Arrays .asList (renderFragments ));
140+ }
141+
142+
143+
144+ }
0 commit comments