1616
1717package org .springframework .boot .autoconfigure .web ;
1818
19+ import java .util .concurrent .TimeUnit ;
20+ import java .util .function .BiFunction ;
21+ import java .util .function .Supplier ;
22+
23+ import javax .annotation .PostConstruct ;
24+
1925import org .springframework .boot .context .properties .ConfigurationProperties ;
26+ import org .springframework .boot .context .properties .NestedConfigurationProperty ;
27+ import org .springframework .http .CacheControl ;
28+ import org .springframework .util .Assert ;
2029
2130/**
2231 * Properties used to configure resource handling.
2534 * @author Brian Clozel
2635 * @author Dave Syer
2736 * @author Venil Noronha
37+ * @author Kristine Jetzke
2838 * @since 1.1.0
2939 */
3040@ ConfigurationProperties (prefix = "spring.resources" , ignoreUnknownFields = false )
3141public class ResourceProperties {
3242
3343 private static final String [] CLASSPATH_RESOURCE_LOCATIONS = {
3444 "classpath:/META-INF/resources/" , "classpath:/resources/" ,
35- "classpath:/static/" , "classpath:/public/" };
45+ "classpath:/static/" , "classpath:/public/" };
3646
3747 /**
3848 * Locations of static resources. Defaults to classpath:[/META-INF/resources/,
@@ -41,10 +51,17 @@ public class ResourceProperties {
4151 private String [] staticLocations = CLASSPATH_RESOURCE_LOCATIONS ;
4252
4353 /**
44- * Cache period for the resources served by the resource handler, in seconds.
54+ * Cache period for the resources served by the resource handler, in seconds. Either
55+ * {@link #cachePeriod} or {@link #cacheControl} can be set.
4556 */
4657 private Integer cachePeriod ;
4758
59+ /**
60+ * Cache control headers. Either {@link #cachePeriod} or {@link #cacheControl} can be set.
61+ */
62+ @ NestedConfigurationProperty
63+ private CacheControlProperties cacheControl ;
64+
4865 /**
4966 * Enable default resource handling.
5067 */
@@ -77,6 +94,15 @@ public void setCachePeriod(Integer cachePeriod) {
7794 this .cachePeriod = cachePeriod ;
7895 }
7996
97+ public CacheControlProperties getCacheControl () {
98+ return this .cacheControl ;
99+ }
100+
101+ public void setCacheControl (CacheControlProperties cacheControl ) {
102+ this .cacheControl = cacheControl ;
103+ }
104+
105+
80106 public boolean isAddMappings () {
81107 return this .addMappings ;
82108 }
@@ -89,6 +115,36 @@ public Chain getChain() {
89115 return this .chain ;
90116 }
91117
118+ public CacheControl createCacheControl () {
119+ if (this .cachePeriod != null ) {
120+ return CacheControl .maxAge (this .cachePeriod , TimeUnit .SECONDS );
121+ }
122+ if (this .cacheControl != null ) {
123+ return this .cacheControl .transformToHttpSpringCacheControl ();
124+ }
125+ return null ;
126+ }
127+
128+ @ PostConstruct
129+ public void checkIncompatibleCacheOptions () {
130+ Assert .state (this .cachePeriod == null || this .cacheControl == null ,
131+ "Only one of cache-period or cache-control may be set." );
132+ if (this .cacheControl != null ) {
133+ if (this .cacheControl .getMaxAge () != null ) {
134+ Assert .state (!Boolean .TRUE .equals (this .cacheControl .getNoCache ()), "no-cache may not be set if max-age is set." );
135+ Assert .state (!Boolean .TRUE .equals (this .cacheControl .getNoStore ()), "no-store may not be set if max-age is set." );
136+ }
137+ if (this .cacheControl .getNoCache () != null ) {
138+ Assert .state (this .cacheControl .getMaxAge () == null , "max-age may not be set if no-cache is set." );
139+ Assert .state (!Boolean .TRUE .equals (this .cacheControl .getNoStore ()), "no-store may not be set if no-cache is set." );
140+ }
141+ if (this .cacheControl .getNoStore () != null ) {
142+ Assert .state (this .cacheControl .getMaxAge () == null , "max-age may not be set if no-store is set." );
143+ Assert .state (!Boolean .TRUE .equals (this .cacheControl .getNoCache ()), "no-cache may not be set if no-store is set." );
144+ }
145+ }
146+ }
147+
92148 /**
93149 * Configuration for the Spring Resource Handling chain.
94150 */
@@ -121,8 +177,9 @@ public static class Chain {
121177 /**
122178 * Return whether the resource chain is enabled. Return {@code null} if no
123179 * specific settings are present.
124- * @return whether the resource chain is enabled or {@code null} if no specified
125- * settings are present.
180+ *
181+ * @return whether the resource chain is enabled or {@code null} if no specified settings are
182+ * present.
126183 */
127184 public Boolean getEnabled () {
128185 return getEnabled (getStrategy ().getFixed ().isEnabled (),
@@ -200,7 +257,7 @@ public static class Content {
200257 /**
201258 * Comma-separated list of patterns to apply to the Version Strategy.
202259 */
203- private String [] paths = new String [] { "/**" };
260+ private String [] paths = new String []{ "/**" };
204261
205262 public boolean isEnabled () {
206263 return this .enabled ;
@@ -233,7 +290,7 @@ public static class Fixed {
233290 /**
234291 * Comma-separated list of patterns to apply to the Version Strategy.
235292 */
236- private String [] paths = new String [] { "/**" };
293+ private String [] paths = new String []{ "/**" };
237294
238295 /**
239296 * Version string to use for the Version Strategy.
@@ -266,4 +323,183 @@ public void setVersion(String version) {
266323
267324 }
268325
326+ /**
327+ * Configuration for the Cache Control header.
328+ */
329+
330+ public static class CacheControlProperties {
331+
332+ private Long maxAge ;
333+
334+ private Boolean noCache ;
335+
336+ private Boolean noStore ;
337+
338+ private Boolean mustRevalidate ;
339+
340+ private Boolean noTransform ;
341+
342+ private Boolean cachePublic ;
343+
344+ private Boolean cachePrivate ;
345+
346+ private Boolean proxyRevalidate ;
347+
348+ private Long staleWhileRevalidate ;
349+
350+ private Long staleIfError ;
351+
352+ private Long sMaxAge ;
353+
354+ public Long getMaxAge () {
355+ return this .maxAge ;
356+ }
357+
358+ public void setMaxAge (Long maxAge ) {
359+ this .maxAge = maxAge ;
360+ }
361+
362+ public Boolean getNoCache () {
363+ return this .noCache ;
364+ }
365+
366+ public void setNoCache (Boolean noCache ) {
367+ this .noCache = noCache ;
368+ }
369+
370+ public Boolean getNoStore () {
371+ return this .noStore ;
372+ }
373+
374+ public void setNoStore (Boolean noStore ) {
375+ this .noStore = noStore ;
376+ }
377+
378+ public Boolean getMustRevalidate () {
379+ return this .mustRevalidate ;
380+ }
381+
382+ public void setMustRevalidate (Boolean mustRevalidate ) {
383+ this .mustRevalidate = mustRevalidate ;
384+ }
385+
386+ public Boolean getNoTransform () {
387+ return this .noTransform ;
388+ }
389+
390+ public void setNoTransform (Boolean noTransform ) {
391+ this .noTransform = noTransform ;
392+ }
393+
394+ public Boolean getCachePublic () {
395+ return this .cachePublic ;
396+ }
397+
398+ public void setCachePublic (Boolean cachePublic ) {
399+ this .cachePublic = cachePublic ;
400+ }
401+
402+ public Boolean getCachePrivate () {
403+ return this .cachePrivate ;
404+ }
405+
406+ public void setCachePrivate (Boolean cachePrivate ) {
407+ this .cachePrivate = cachePrivate ;
408+ }
409+
410+ public Boolean getProxyRevalidate () {
411+ return this .proxyRevalidate ;
412+ }
413+
414+ public void setProxyRevalidate (Boolean proxyRevalidate ) {
415+ this .proxyRevalidate = proxyRevalidate ;
416+ }
417+
418+ public Long getStaleWhileRevalidate () {
419+ return this .staleWhileRevalidate ;
420+ }
421+
422+ public void setStaleWhileRevalidate (Long staleWhileRevalidate ) {
423+ this .staleWhileRevalidate = staleWhileRevalidate ;
424+ }
425+
426+ public Long getStaleIfError () {
427+ return this .staleIfError ;
428+ }
429+
430+ public void setStaleIfError (Long staleIfError ) {
431+ this .staleIfError = staleIfError ;
432+ }
433+
434+ public Long getsMaxAge () {
435+ return this .sMaxAge ;
436+ }
437+
438+ public void setsMaxAge (Long sMaxAge ) {
439+ this .sMaxAge = sMaxAge ;
440+ }
441+
442+ CacheControl transformToHttpSpringCacheControl () {
443+ CacheControl httpSpringCacheControl = initCacheControl ();
444+ httpSpringCacheControl = setFlags (httpSpringCacheControl );
445+ httpSpringCacheControl = setTimes (httpSpringCacheControl );
446+ return httpSpringCacheControl ;
447+ }
448+
449+ private CacheControl initCacheControl () {
450+ if (this .maxAge != null ) {
451+ return CacheControl .maxAge (this .maxAge , TimeUnit .SECONDS );
452+ }
453+ if (Boolean .TRUE .equals (this .noCache )) {
454+ return CacheControl .noCache ();
455+ }
456+ if (Boolean .TRUE .equals (this .noStore )) {
457+ return CacheControl .noStore ();
458+ }
459+ return CacheControl .empty ();
460+ }
461+
462+ private CacheControl setFlags (CacheControl cacheControl ) {
463+ cacheControl = setBoolean (this .mustRevalidate , cacheControl ::mustRevalidate ,
464+ cacheControl );
465+ cacheControl = setBoolean (this .noTransform , cacheControl ::noTransform ,
466+ cacheControl );
467+ cacheControl = setBoolean (this .cachePublic , cacheControl ::cachePublic ,
468+ cacheControl );
469+ cacheControl = setBoolean (this .cachePrivate , cacheControl ::cachePrivate ,
470+ cacheControl );
471+ cacheControl = setBoolean (this .proxyRevalidate , cacheControl ::proxyRevalidate ,
472+ cacheControl );
473+ return cacheControl ;
474+ }
475+
476+ private static CacheControl setBoolean (Boolean value ,
477+ Supplier <CacheControl > setter , CacheControl cacheControl ) {
478+ if (Boolean .TRUE .equals (value )) {
479+ return setter .get ();
480+ }
481+ return cacheControl ;
482+ }
483+
484+ private CacheControl setTimes (CacheControl cacheControl ) {
485+ cacheControl = setLong (this .staleWhileRevalidate ,
486+ cacheControl ::staleWhileRevalidate , cacheControl );
487+ cacheControl = setLong (this .staleIfError , cacheControl ::staleIfError ,
488+ cacheControl );
489+ cacheControl = setLong (this .sMaxAge , cacheControl ::sMaxAge , cacheControl );
490+ return cacheControl ;
491+ }
492+
493+ private static CacheControl setLong (Long value ,
494+ BiFunction <Long , TimeUnit , CacheControl > setter ,
495+ CacheControl cacheControl ) {
496+ if (value != null ) {
497+ return setter .apply (value , TimeUnit .SECONDS );
498+ }
499+ return cacheControl ;
500+ }
501+
502+ }
503+
504+
269505}
0 commit comments