정적 리소스 서빙 및 빌드 프로세스 개선:
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
cd build/libs
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'
}
}
+2 -1
View File
@@ -96,8 +96,9 @@ pipeline {
sha256sum "$f" > "$f.sha256"
md5sum "$f" > "$f.md5"
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)
}
// 정적 리소스만 별도 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 {
doLast {
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} 로 매핑한다.
* 내용이 바뀌면 URL 이 바뀌므로 강제 새로고침 없이 브라우저 캐시가 무효화된다. Thymeleaf 의
* {@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) {
// 캐싱 ON(prod) 이면 브라우저에 1일 캐시를, OFF(dev/local) 면 no-store 를 내려보낸다.
// no-store 는 브라우저가 아예 저장하지 않으므로 강제 새로고침 없이 sass/JS 변경이 바로 보인다.
CacheControl cacheControl = isResourceCachingEnabled()
? CacheControl.maxAge(1, TimeUnit.DAYS)
: CacheControl.noStore();
boolean versioningOn = isResourceVersioningEnabled();
CacheControl cacheControl;
if (!isResourceCachingEnabled()) {
// no-store: 브라우저가 아예 저장하지 않으므로 강제 새로고침 없이 sass/JS 변경이 바로 보인다(dev/local).
cacheControl = CacheControl.noStore();
} else if (versioningOn) {
cacheControl = CacheControl.maxAge(1, TimeUnit.DAYS);
} else {
cacheControl = CacheControl.noCache();
}
ResourceChainRegistration chain = registry.addResourceHandler(pattern)
.addResourceLocations(locations)
.setCacheControl(cacheControl)
.resourceChain(isResourceCachingEnabled());
if (isResourceVersioningEnabled()) {
if (versioningOn) {
chain.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
}
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() {
if (environment.acceptsProfiles(Profiles.of("prod"))) {
return true;
}
return resourceVersioningEnabled;
}
+6 -4
View File
@@ -9,9 +9,11 @@ spring:
cachecontrol:
max-age: 86400
public: true
# 정적자원 콘텐츠 해시 버전닝은 PortalConfigWebDispatcherServlet 가 prod 프로파일에서
# 항상 ON 으로 수행한다(app.resource-versioning.enabled 토글 무시).
# 해시 URL + 장기 캐시(max-age 86400)로 배포 시 자동 캐시 무효화.
# 정적자원 콘텐츠 해시 버전닝: OHS 가 정적 리소스(css/js/img 등)를 직접 서빙하는 구조에서
# 해시 URL(main-<hash>.css)이 OHS 디스크의 무해시 원본과 어긋나 404 위험이 있어 OFF 로 전환했다
# (아래 app.resource-versioning.enabled: false, PortalConfigWebDispatcherServlet 참고).
# 캐시 무효화는 대신 no-cache(매 요청 If-Modified-Since 조건부 재검증)로 보장한다.
# 배경: djb-obsidian-docs/3000-테스트/15-Static리소스분리
jpa:
properties:
hibernate:
@@ -28,7 +30,7 @@ spring:
app:
resource-versioning:
enabled: true
enabled: false
resource-caching:
enabled: true