diff --git a/application/src/main/java/org/thingsboard/server/controller/ImageController.java b/application/src/main/java/org/thingsboard/server/controller/ImageController.java index a027e77b2e..1a1b4e3b46 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ImageController.java +++ b/application/src/main/java/org/thingsboard/server/controller/ImageController.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import io.swagger.annotations.ApiParam; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.ByteArrayResource; import org.springframework.http.CacheControl; import org.springframework.http.HttpHeaders; @@ -55,6 +56,7 @@ import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; import java.time.Duration; +import java.util.concurrent.TimeUnit; import java.util.function.Supplier; import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; @@ -73,6 +75,10 @@ public class ImageController extends BaseController { private final ImageService imageService; private final TbImageService tbImageService; + @Value("${cache.image.systemImagesBrowserTtlInMinutes:0}") + private int systemImagesBrowserTtlInMinutes; + @Value("${cache.image.tenantImagesBrowserTtlInMinutes:0}") + private int tenantImagesBrowserTtlInMinutes; private static final String IMAGE_URL = "/api/images/{type}/{key}"; private static final String SYSTEM_IMAGE = "system"; @@ -194,14 +200,20 @@ public class ImageController extends BaseController { data = imageService.getImageData(tenantId, imageInfo.getId()); } tbImageService.putETag(cacheKey, descriptor.getEtag()); - return ResponseEntity.ok() + var result = ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + fileName) .header("x-filename", fileName) - .contentLength(data.length) .header("Content-Type", descriptor.getMediaType()) - .cacheControl(CacheControl.noCache()) - .eTag(descriptor.getEtag()) - .body(new ByteArrayResource(data)); + .contentLength(data.length) + .eTag(descriptor.getEtag()); + if (systemImagesBrowserTtlInMinutes > 0 && imageInfo.getTenantId().isSysTenantId()) { + result.cacheControl(CacheControl.maxAge(systemImagesBrowserTtlInMinutes, TimeUnit.MINUTES)); + } else if (tenantImagesBrowserTtlInMinutes > 0 && !imageInfo.getTenantId().isSysTenantId()) { + result.cacheControl(CacheControl.maxAge(tenantImagesBrowserTtlInMinutes, TimeUnit.MINUTES)); + } else { + result.cacheControl(CacheControl.noCache()); + } + return result.body(new ByteArrayResource(data)); } private TbResourceInfo checkImageInfo(String imageType, String key, Operation operation) throws ThingsboardException { diff --git a/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbImageService.java b/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbImageService.java index 4b70814e26..0820965544 100644 --- a/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbImageService.java +++ b/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbImageService.java @@ -41,8 +41,8 @@ public class DefaultTbImageService extends AbstractTbEntityService implements Tb private final Cache cache; public DefaultTbImageService(ImageService imageService, - @Value("${cache.imageETags.timeToLiveInMinutes:120}") int cacheTtl, - @Value("${cache.imageETags.maxSize:200000}") int cacheMaxSize) { + @Value("${cache.image.etag.timeToLiveInMinutes:120}") int cacheTtl, + @Value("${cache.image.etag.maxSize:200000}") int cacheMaxSize) { this.imageService = imageService; this.cache = Caffeine.newBuilder() .expireAfterAccess(cacheTtl, TimeUnit.MINUTES) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 9e59db76e8..6dde5de957 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -586,9 +586,12 @@ cache: entityLimits: timeToLiveInMinutes: "${CACHE_SPECS_ENTITY_LIMITS_TTL:5}" # Entity limits cache TTL maxSize: "${CACHE_SPECS_ENTITY_LIMITS_MAX_SIZE:100000}" # 0 means the cache is disabled - imageETags: - timeToLiveInMinutes: "${CACHE_SPECS_IMAGE_ETAGS_TTL:44640}" # Image ETags cache TTL - maxSize: "${CACHE_SPECS_IMAGE_ETAGS_MAX_SIZE:1000000}" # 0 means the cache is disabled + image: + etag: + timeToLiveInMinutes: "${CACHE_SPECS_IMAGE_ETAGS_TTL:44640}" # Image ETags cache TTL + maxSize: "${CACHE_SPECS_IMAGE_ETAGS_MAX_SIZE:1000000}" # 0 means the cache is disabled + systemImagesBrowserTtlInMinutes: "${CACHE_SPECS_IMAGE_SYSTEM_BROWSER_TTL:0}" # Browser cache TTL for system images in minutes. 0 means the cache is disabled + tenantImagesBrowserTtlInMinutes: "${CACHE_SPECS_IMAGE_TENANT_BROWSER_TTL:0}" # Browser cache TTL for tenant images in minutes. 0 means the cache is disabled # Spring data parameters spring.data.redis.repositories.enabled: false # Disable this because it is not required.