mirror of
https://gitee.com/dcren/initializr.git
synced 2025-05-04 20:58:03 +08:00
Improve resources caching
Update controllers to add an ETag information so that meta-data is cached on the client. Also enables the compression for json, css and html resources. Closes gh-165
This commit is contained in:
parent
89330da312
commit
5fb8c84e5e
@ -6,6 +6,12 @@ info:
|
|||||||
spring-boot:
|
spring-boot:
|
||||||
version: 1.3.0.RELEASE
|
version: 1.3.0.RELEASE
|
||||||
|
|
||||||
|
server:
|
||||||
|
compression:
|
||||||
|
enabled: true
|
||||||
|
mime-types: application/json,text/css,text/html
|
||||||
|
min-response-size: 2048
|
||||||
|
|
||||||
initializr:
|
initializr:
|
||||||
env:
|
env:
|
||||||
boms:
|
boms:
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package io.spring.initializr.web
|
package io.spring.initializr.web
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
import groovy.util.logging.Slf4j
|
import groovy.util.logging.Slf4j
|
||||||
import io.spring.initializr.generator.CommandLineHelpGenerator
|
import io.spring.initializr.generator.CommandLineHelpGenerator
|
||||||
import io.spring.initializr.mapper.InitializrMetadataJsonMapper
|
import io.spring.initializr.mapper.InitializrMetadataJsonMapper
|
||||||
@ -27,11 +30,13 @@ import io.spring.initializr.generator.ProjectRequest
|
|||||||
import io.spring.initializr.metadata.InitializrMetadata
|
import io.spring.initializr.metadata.InitializrMetadata
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.http.CacheControl
|
||||||
import org.springframework.http.HttpHeaders
|
import org.springframework.http.HttpHeaders
|
||||||
import org.springframework.http.HttpStatus
|
import org.springframework.http.HttpStatus
|
||||||
import org.springframework.http.MediaType
|
import org.springframework.http.MediaType
|
||||||
import org.springframework.http.ResponseEntity
|
import org.springframework.http.ResponseEntity
|
||||||
import org.springframework.stereotype.Controller
|
import org.springframework.stereotype.Controller
|
||||||
|
import org.springframework.util.DigestUtils
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute
|
import org.springframework.web.bind.annotation.ModelAttribute
|
||||||
import org.springframework.web.bind.annotation.RequestHeader
|
import org.springframework.web.bind.annotation.RequestHeader
|
||||||
import org.springframework.web.bind.annotation.RequestMapping
|
import org.springframework.web.bind.annotation.RequestMapping
|
||||||
@ -86,16 +91,20 @@ class MainController extends AbstractInitializrController {
|
|||||||
def builder = ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN)
|
def builder = ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN)
|
||||||
if (userAgent) {
|
if (userAgent) {
|
||||||
if (userAgent.startsWith(WebConfig.CURL_USER_AGENT_PREFIX)) {
|
if (userAgent.startsWith(WebConfig.CURL_USER_AGENT_PREFIX)) {
|
||||||
return builder.body(commandLineHelpGenerator.generateCurlCapabilities(metadata, appUrl))
|
def content = commandLineHelpGenerator.generateCurlCapabilities(metadata, appUrl)
|
||||||
|
return builder.eTag(createUniqueId(content)).body(content)
|
||||||
}
|
}
|
||||||
if (userAgent.startsWith(WebConfig.HTTPIE_USER_AGENT_PREFIX)) {
|
if (userAgent.startsWith(WebConfig.HTTPIE_USER_AGENT_PREFIX)) {
|
||||||
return builder.body(commandLineHelpGenerator.generateHttpieCapabilities(metadata, appUrl))
|
def content = commandLineHelpGenerator.generateHttpieCapabilities(metadata, appUrl)
|
||||||
|
return builder.eTag(createUniqueId(content)).body(content)
|
||||||
}
|
}
|
||||||
if (userAgent.startsWith(WebConfig.SPRING_BOOT_CLI_AGENT_PREFIX)) {
|
if (userAgent.startsWith(WebConfig.SPRING_BOOT_CLI_AGENT_PREFIX)) {
|
||||||
return builder.body(commandLineHelpGenerator.generateSpringBootCliCapabilities(metadata, appUrl))
|
def content = commandLineHelpGenerator.generateSpringBootCliCapabilities(metadata, appUrl)
|
||||||
|
return builder.eTag(createUniqueId(content)).body(content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
builder.body(commandLineHelpGenerator.generateGenericCapabilities(metadata, appUrl))
|
def content = commandLineHelpGenerator.generateGenericCapabilities(metadata, appUrl)
|
||||||
|
builder.eTag(createUniqueId(content)).body(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/", produces = ["application/hal+json"])
|
@RequestMapping(value = "/", produces = ["application/hal+json"])
|
||||||
@ -120,7 +129,8 @@ class MainController extends AbstractInitializrController {
|
|||||||
private ResponseEntity<String> serviceCapabilitiesFor(InitializrMetadataVersion version, MediaType contentType) {
|
private ResponseEntity<String> serviceCapabilitiesFor(InitializrMetadataVersion version, MediaType contentType) {
|
||||||
String appUrl = generateAppUrl()
|
String appUrl = generateAppUrl()
|
||||||
def content = getJsonMapper(version).write(metadataProvider.get(), appUrl)
|
def content = getJsonMapper(version).write(metadataProvider.get(), appUrl)
|
||||||
return ResponseEntity.ok().contentType(contentType).body(content)
|
return ResponseEntity.ok().contentType(contentType).eTag(createUniqueId(content))
|
||||||
|
.cacheControl(CacheControl.maxAge(7, TimeUnit.DAYS)).body(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InitializrMetadataJsonMapper getJsonMapper(InitializrMetadataVersion version) {
|
private static InitializrMetadataJsonMapper getJsonMapper(InitializrMetadataVersion version) {
|
||||||
@ -220,4 +230,10 @@ class MainController extends AbstractInitializrController {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String createUniqueId(String content) {
|
||||||
|
StringBuilder builder = new StringBuilder()
|
||||||
|
DigestUtils.appendMd5DigestAsHex(content.getBytes(StandardCharsets.UTF_8), builder)
|
||||||
|
builder.toString()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package io.spring.initializr.web
|
package io.spring.initializr.web
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
|
|
||||||
import groovy.json.JsonBuilder
|
import groovy.json.JsonBuilder
|
||||||
import io.spring.initializr.metadata.Dependency
|
import io.spring.initializr.metadata.Dependency
|
||||||
import io.spring.initializr.metadata.InitializrMetadataProvider
|
import io.spring.initializr.metadata.InitializrMetadataProvider
|
||||||
@ -23,6 +25,9 @@ import io.spring.initializr.util.Version
|
|||||||
import io.spring.initializr.util.VersionRange
|
import io.spring.initializr.util.VersionRange
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.http.MediaType
|
||||||
|
import org.springframework.http.ResponseEntity
|
||||||
|
import org.springframework.util.DigestUtils
|
||||||
import org.springframework.web.bind.annotation.RequestMapping
|
import org.springframework.web.bind.annotation.RequestMapping
|
||||||
import org.springframework.web.bind.annotation.RequestParam
|
import org.springframework.web.bind.annotation.RequestParam
|
||||||
import org.springframework.web.bind.annotation.RestController
|
import org.springframework.web.bind.annotation.RestController
|
||||||
@ -40,7 +45,7 @@ class UiController {
|
|||||||
protected InitializrMetadataProvider metadataProvider
|
protected InitializrMetadataProvider metadataProvider
|
||||||
|
|
||||||
@RequestMapping(value = "/ui/dependencies", produces = ["application/json"])
|
@RequestMapping(value = "/ui/dependencies", produces = ["application/json"])
|
||||||
String dependencies(@RequestParam(required = false) String version) {
|
ResponseEntity<String> dependencies(@RequestParam(required = false) String version) {
|
||||||
def dependencyGroups = metadataProvider.get().dependencies.content
|
def dependencyGroups = metadataProvider.get().dependencies.content
|
||||||
def content = []
|
def content = []
|
||||||
Version v = version ? Version.parse(version) : null
|
Version v = version ? Version.parse(version) : null
|
||||||
@ -55,7 +60,9 @@ class UiController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writeDependencies(content)
|
def json = writeDependencies(content)
|
||||||
|
ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).
|
||||||
|
eTag(createUniqueId(json)).body(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String writeDependencies(List<DependencyItem> items) {
|
private static String writeDependencies(List<DependencyItem> items) {
|
||||||
@ -96,4 +103,10 @@ class UiController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String createUniqueId(String content) {
|
||||||
|
StringBuilder builder = new StringBuilder()
|
||||||
|
DigestUtils.appendMd5DigestAsHex(content.getBytes(StandardCharsets.UTF_8), builder)
|
||||||
|
builder.toString()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import org.junit.Ignore
|
|||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.skyscreamer.jsonassert.JSONCompareMode
|
import org.skyscreamer.jsonassert.JSONCompareMode
|
||||||
|
|
||||||
|
import org.springframework.http.HttpHeaders
|
||||||
import org.springframework.http.HttpStatus
|
import org.springframework.http.HttpStatus
|
||||||
import org.springframework.http.MediaType
|
import org.springframework.http.MediaType
|
||||||
import org.springframework.http.ResponseEntity
|
import org.springframework.http.ResponseEntity
|
||||||
@ -32,6 +33,7 @@ import org.springframework.web.client.HttpClientErrorException
|
|||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.allOf
|
import static org.hamcrest.CoreMatchers.allOf
|
||||||
import static org.hamcrest.CoreMatchers.containsString
|
import static org.hamcrest.CoreMatchers.containsString
|
||||||
|
import static org.hamcrest.CoreMatchers.nullValue
|
||||||
import static org.hamcrest.core.IsNot.not
|
import static org.hamcrest.core.IsNot.not
|
||||||
import static org.junit.Assert.assertEquals
|
import static org.junit.Assert.assertEquals
|
||||||
import static org.junit.Assert.assertFalse
|
import static org.junit.Assert.assertFalse
|
||||||
@ -169,6 +171,7 @@ class MainControllerIntegrationTests extends AbstractInitializrControllerIntegra
|
|||||||
@Test
|
@Test
|
||||||
void metadataWithCurrentAcceptHeader() {
|
void metadataWithCurrentAcceptHeader() {
|
||||||
ResponseEntity<String> response = invokeHome(null, 'application/vnd.initializr.v2.1+json')
|
ResponseEntity<String> response = invokeHome(null, 'application/vnd.initializr.v2.1+json')
|
||||||
|
assertThat(response.getHeaders().getFirst(HttpHeaders.ETAG), not(nullValue()))
|
||||||
validateContentType(response, CURRENT_METADATA_MEDIA_TYPE)
|
validateContentType(response, CURRENT_METADATA_MEDIA_TYPE)
|
||||||
validateCurrentMetadata(new JSONObject(response.body))
|
validateCurrentMetadata(new JSONObject(response.body))
|
||||||
}
|
}
|
||||||
@ -184,6 +187,7 @@ class MainControllerIntegrationTests extends AbstractInitializrControllerIntegra
|
|||||||
@Test
|
@Test
|
||||||
void metadataWithHalAcceptHeader() {
|
void metadataWithHalAcceptHeader() {
|
||||||
ResponseEntity<String> response = invokeHome(null, 'application/hal+json')
|
ResponseEntity<String> response = invokeHome(null, 'application/hal+json')
|
||||||
|
assertThat(response.getHeaders().getFirst(HttpHeaders.ETAG), not(nullValue()))
|
||||||
validateContentType(response, MainController.HAL_JSON_CONTENT_TYPE)
|
validateContentType(response, MainController.HAL_JSON_CONTENT_TYPE)
|
||||||
validateCurrentMetadata(new JSONObject(response.body))
|
validateCurrentMetadata(new JSONObject(response.body))
|
||||||
}
|
}
|
||||||
@ -283,6 +287,7 @@ class MainControllerIntegrationTests extends AbstractInitializrControllerIntegra
|
|||||||
|
|
||||||
private void validateCurlHelpContent(ResponseEntity<String> response) {
|
private void validateCurlHelpContent(ResponseEntity<String> response) {
|
||||||
validateContentType(response, MediaType.TEXT_PLAIN)
|
validateContentType(response, MediaType.TEXT_PLAIN)
|
||||||
|
assertThat(response.getHeaders().getFirst(HttpHeaders.ETAG), not(nullValue()))
|
||||||
assertThat(response.body, allOf(
|
assertThat(response.body, allOf(
|
||||||
containsString("Spring Initializr"),
|
containsString("Spring Initializr"),
|
||||||
containsString('Examples:'),
|
containsString('Examples:'),
|
||||||
@ -291,6 +296,7 @@ class MainControllerIntegrationTests extends AbstractInitializrControllerIntegra
|
|||||||
|
|
||||||
private void validateHttpIeHelpContent(ResponseEntity<String> response) {
|
private void validateHttpIeHelpContent(ResponseEntity<String> response) {
|
||||||
validateContentType(response, MediaType.TEXT_PLAIN)
|
validateContentType(response, MediaType.TEXT_PLAIN)
|
||||||
|
assertThat(response.getHeaders().getFirst(HttpHeaders.ETAG), not(nullValue()))
|
||||||
assertThat(response.body, allOf(
|
assertThat(response.body, allOf(
|
||||||
containsString("Spring Initializr"),
|
containsString("Spring Initializr"),
|
||||||
containsString('Examples:'),
|
containsString('Examples:'),
|
||||||
@ -300,6 +306,7 @@ class MainControllerIntegrationTests extends AbstractInitializrControllerIntegra
|
|||||||
|
|
||||||
private void validateGenericHelpContent(ResponseEntity<String> response) {
|
private void validateGenericHelpContent(ResponseEntity<String> response) {
|
||||||
validateContentType(response, MediaType.TEXT_PLAIN)
|
validateContentType(response, MediaType.TEXT_PLAIN)
|
||||||
|
assertThat(response.getHeaders().getFirst(HttpHeaders.ETAG), not(nullValue()))
|
||||||
assertThat(response.body, allOf(
|
assertThat(response.body, allOf(
|
||||||
containsString("Spring Initializr"),
|
containsString("Spring Initializr"),
|
||||||
not(containsString('Examples:')),
|
not(containsString('Examples:')),
|
||||||
@ -308,6 +315,7 @@ class MainControllerIntegrationTests extends AbstractInitializrControllerIntegra
|
|||||||
|
|
||||||
private void validateSpringBootHelpContent(ResponseEntity<String> response) {
|
private void validateSpringBootHelpContent(ResponseEntity<String> response) {
|
||||||
validateContentType(response, MediaType.TEXT_PLAIN)
|
validateContentType(response, MediaType.TEXT_PLAIN)
|
||||||
|
assertThat(response.getHeaders().getFirst(HttpHeaders.ETAG), not(nullValue()))
|
||||||
assertThat(response.body, allOf(
|
assertThat(response.body, allOf(
|
||||||
containsString("Service capabilities"),
|
containsString("Service capabilities"),
|
||||||
containsString("Supported dependencies"),
|
containsString("Supported dependencies"),
|
||||||
|
Loading…
Reference in New Issue
Block a user