정적 리소스 서빙 및 빌드 프로세스 개선:
eapim-portal CI / build (push) Has been cancelled
eapim-portal Test / test (push) Has been cancelled

- OHS 환경 대응 정적자원 해시 버전닝 OFF 설정 반영
- eapim-portal-static.zip 생성 및 CI/CD 추가
- OHS 설정 샘플 가이드 추가
This commit is contained in:
Rinjae
2026-09-07 10:55:43 +09:00
parent 8118dba74d
commit 982187298c
6 changed files with 110 additions and 17 deletions
+2 -1
View File
@@ -74,8 +74,9 @@ pipeline {
set -eu set -eu
cd build/libs cd build/libs
sha256sum eapim-portal.war > eapim-portal.war.sha256 sha256sum eapim-portal.war > eapim-portal.war.sha256
sha256sum eapim-portal-static.zip > eapim-portal-static.zip.sha256
''' '''
archiveArtifacts artifacts: 'build/libs/eapim-portal.war,build/libs/eapim-portal.war.sha256', fingerprint: true archiveArtifacts artifacts: 'build/libs/eapim-portal.war,build/libs/eapim-portal.war.sha256,build/libs/eapim-portal-static.zip,build/libs/eapim-portal-static.zip.sha256', fingerprint: true
stash name: 'war', includes: 'build/libs/eapim-portal.war' stash name: 'war', includes: 'build/libs/eapim-portal.war'
} }
} }
+2 -1
View File
@@ -96,8 +96,9 @@ pipeline {
sha256sum "$f" > "$f.sha256" sha256sum "$f" > "$f.sha256"
md5sum "$f" > "$f.md5" md5sum "$f" > "$f.md5"
done done
sha256sum eapim-portal-static.zip > eapim-portal-static.zip.sha256
''' '''
archiveArtifacts artifacts: 'build/libs/eapim-portal.war,build/libs/eapim-portal-boot.war,build/libs/eapim-portal.war.sha1,build/libs/eapim-portal.war.sha256,build/libs/eapim-portal.war.md5,build/libs/eapim-portal-boot.war.sha1,build/libs/eapim-portal-boot.war.sha256,build/libs/eapim-portal-boot.war.md5', fingerprint: true archiveArtifacts artifacts: 'build/libs/eapim-portal.war,build/libs/eapim-portal-boot.war,build/libs/eapim-portal.war.sha1,build/libs/eapim-portal.war.sha256,build/libs/eapim-portal.war.md5,build/libs/eapim-portal-boot.war.sha1,build/libs/eapim-portal-boot.war.sha256,build/libs/eapim-portal-boot.war.md5,build/libs/eapim-portal-static.zip,build/libs/eapim-portal-static.zip.sha256', fingerprint: true
} }
} }
} }
+12
View File
@@ -315,6 +315,18 @@ war {
classpath = excludeLocalOnlyLibs(classpath) classpath = excludeLocalOnlyLibs(classpath)
} }
// 정적 리소스만 별도 zip (OHS 추가 배포용). war/bootWar 는 그대로 정적 리소스 포함 유지
// (WAS 단독 접속 인원 지원). sass/ 는 컴파일 소스이며 실제 서빙 경로에 없어 제외
// (PortalConfigWebDispatcherServlet#addResourceHandlers 기준).
task staticResourcesZip(type: Zip) {
archiveFileName = "eapim-portal-static.zip"
destinationDirectory = file("$buildDir/libs")
from('src/main/resources/static') {
exclude 'sass/**'
}
}
assemble.dependsOn staticResourcesZip
task printSourceSets { task printSourceSets {
doLast { doLast {
sourceSets.each { srcSet -> sourceSets.each { srcSet ->
+64
View File
@@ -0,0 +1,64 @@
## OHS Static Resource 설정 예시
```apacheconf
<VirtualHost *:443>
ServerName weblogic-djb.rinjae.kr
<IfModule ossl_module>
SSLEngine on
SSLVerifyClient None
SSLProtocol TLSv1.2 TLSv1.3
SSLHonorCipherOrder on
SSLCipherSuite TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
SSLWallet "${ORACLE_INSTANCE}/config/fmwconfig/components/${COMPONENT_TYPE}/instances/${COMPONENT_NAME}/keystores/default"
<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>
<Directory "${ORACLE_INSTANCE}/config/fmwconfig/components/${COMPONENT_TYPE}/instances/${COMPONENT_NAME}/cgi-bin">
SSLOptions +StdEnvVars
</Directory>
BrowserMatch "MSIE [2-5]" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=63072000; preload; includeSubDomains"
</IfModule>
</IfModule>
Alias /css /ohs/static/eapim-portal/css
Alias /js /ohs/static/eapim-portal/js
Alias /img /ohs/static/eapim-portal/img
Alias /images /ohs/static/eapim-portal/images
Alias /webfonts /ohs/static/eapim-portal/webfonts
Alias /font /ohs/static/eapim-portal/font
Alias /html /ohs/static/eapim-portal/html
Alias /plugins /ohs/static/eapim-portal/plugins
<Directory "/ohs/static/eapim-portal">
Require all granted
Options -Indexes
</Directory>
<LocationMatch "^/(css|js|img|images|webfonts|font|html|plugins)/">
Header set Cache-Control "no-cache"
</LocationMatch>
<IfModule weblogic_module>
<Location />
DirectoryIndex disabled
SetHandler weblogic-handler
WebLogicHost 172.30.1.100
WebLogicPort 39130
DynamicServerList OFF
ConnectTimeoutSecs 10
ConnectRetrySecs 2
WLProxySSL ON
</Location>
</IfModule>
</VirtualHost>
```
@@ -175,31 +175,44 @@ public class PortalConfigWebDispatcherServlet implements WebMvcConfigurer {
* {@code /css/main.css} 요청을 내용 해시가 포함된 {@code /css/main-<hash>.css} 로 매핑한다. * {@code /css/main.css} 요청을 내용 해시가 포함된 {@code /css/main-<hash>.css} 로 매핑한다.
* 내용이 바뀌면 URL 이 바뀌므로 강제 새로고침 없이 브라우저 캐시가 무효화된다. Thymeleaf 의 * 내용이 바뀌면 URL 이 바뀌므로 강제 새로고침 없이 브라우저 캐시가 무효화된다. Thymeleaf 의
* {@code @{/css/main.css}} 링크는 {@link #resourceUrlEncodingFilter()} 가 해시 URL 로 치환한다.</p> * {@code @{/css/main.css}} 링크는 {@link #resourceUrlEncodingFilter()} 가 해시 URL 로 치환한다.</p>
*
* <p>버전닝이 꺼져 있으면(prod 포함 — {@link #isResourceVersioningEnabled()} 참고) URL 이
* 고정이라 장기 {@code max-age} 캐시를 쓰면 배포 후에도 브라우저가 옛 내용을 계속 쓸 위험이 있다.
* 이 경우 {@code no-cache}(매 요청 {@code If-Modified-Since} 조건부 재검증, 변경 없으면 304)로
* 신선도를 보장한다 — OHS 가 정적 리소스를 직접 서빙해도 Apache 가 파일 mtime 기준으로 동일하게
* Last-Modified/조건부 GET 을 처리하므로 WAS 와 동작이 어긋나지 않는다
* (배경: djb-obsidian-docs/3000-테스트/15-Static리소스분리).</p>
*/ */
private void addStaticResourceHandler(ResourceHandlerRegistry registry, String pattern, String... locations) { private void addStaticResourceHandler(ResourceHandlerRegistry registry, String pattern, String... locations) {
// 캐싱 ON(prod) 이면 브라우저에 1일 캐시를, OFF(dev/local) 면 no-store 를 내려보낸다. boolean versioningOn = isResourceVersioningEnabled();
// no-store 는 브라우저가 아예 저장하지 않으므로 강제 새로고침 없이 sass/JS 변경이 바로 보인다. CacheControl cacheControl;
CacheControl cacheControl = isResourceCachingEnabled() if (!isResourceCachingEnabled()) {
? CacheControl.maxAge(1, TimeUnit.DAYS) // no-store: 브라우저가 아예 저장하지 않으므로 강제 새로고침 없이 sass/JS 변경이 바로 보인다(dev/local).
: CacheControl.noStore(); cacheControl = CacheControl.noStore();
} else if (versioningOn) {
cacheControl = CacheControl.maxAge(1, TimeUnit.DAYS);
} else {
cacheControl = CacheControl.noCache();
}
ResourceChainRegistration chain = registry.addResourceHandler(pattern) ResourceChainRegistration chain = registry.addResourceHandler(pattern)
.addResourceLocations(locations) .addResourceLocations(locations)
.setCacheControl(cacheControl) .setCacheControl(cacheControl)
.resourceChain(isResourceCachingEnabled()); .resourceChain(isResourceCachingEnabled());
if (isResourceVersioningEnabled()) { if (versioningOn) {
chain.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**")); chain.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
} }
chain.addResolver(new PathResourceResolver()); chain.addResolver(new PathResourceResolver());
} }
/** /**
* 정적자원 해시 버전닝 활성 여부. prod 프로파일은 토글과 무관하게 항상 ON, * 정적자원 해시 버전닝 활성 여부. {@code app.resource-versioning.enabled} 값을 그대로 따른다.
* 그 외 프로파일은 {@code app.resource-versioning.enabled} 값을 따른다. *
* <p>과거 prod 프로파일은 이 토글과 무관하게 항상 ON 이었으나, OHS 가 정적 리소스를 직접
* 서빙하는 구조로 바뀌면서 OFF 로 전환했다 — 해시가 붙은 URL(main-&lt;hash&gt;.css)이 OHS
* 디스크의 무해시 원본과 어긋나 404 가 날 수 있어서다(prod.yml 에서 명시적으로 false 설정).
* 대신 캐시 신선도는 {@link #addStaticResourceHandler} 의 no-cache 조건부 재검증으로 보장한다.</p>
*/ */
private boolean isResourceVersioningEnabled() { private boolean isResourceVersioningEnabled() {
if (environment.acceptsProfiles(Profiles.of("prod"))) {
return true;
}
return resourceVersioningEnabled; return resourceVersioningEnabled;
} }
+6 -4
View File
@@ -9,9 +9,11 @@ spring:
cachecontrol: cachecontrol:
max-age: 86400 max-age: 86400
public: true public: true
# 정적자원 콘텐츠 해시 버전닝은 PortalConfigWebDispatcherServlet 가 prod 프로파일에서 # 정적자원 콘텐츠 해시 버전닝: OHS 가 정적 리소스(css/js/img 등)를 직접 서빙하는 구조에서
# 항상 ON 으로 수행한다(app.resource-versioning.enabled 토글 무시). # 해시 URL(main-<hash>.css)이 OHS 디스크의 무해시 원본과 어긋나 404 위험이 있어 OFF 로 전환했다
# 해시 URL + 장기 캐시(max-age 86400)로 배포 시 자동 캐시 무효화. # (아래 app.resource-versioning.enabled: false, PortalConfigWebDispatcherServlet 참고).
# 캐시 무효화는 대신 no-cache(매 요청 If-Modified-Since 조건부 재검증)로 보장한다.
# 배경: djb-obsidian-docs/3000-테스트/15-Static리소스분리
jpa: jpa:
properties: properties:
hibernate: hibernate:
@@ -28,7 +30,7 @@ spring:
app: app:
resource-versioning: resource-versioning:
enabled: true enabled: false
resource-caching: resource-caching:
enabled: true enabled: true