문제

Java에서는 웹 앱이 전쟁에 묶여 있습니다. 기본적으로 많은 서블릿 컨테이너는 전쟁 이름을 응용 프로그램의 컨텍스트 이름으로 사용합니다.

따라서 myapp.war가 배치됩니다 http://example.com/myapp.

문제는 WebApp이 "루트"를 "루트"또는 간단히 "/"로 간주하는 반면 HTML은 응용 프로그램의 루트를 "/myApp"로 간주한다는 것입니다.

Servlet API와 JSP에는이를 관리하는 데 도움이되는 시설이 있습니다. 예를 들어, 서블릿에서 : response.sendredirect ( "/myPage.jsp")를 사용하면 컨테이너가 컨텍스트를 선불로 만들고 URL을 만듭니다. http://example.com/myapp/mypage.jsp".

그러나 HTML의 IMG 태그로는 그렇게 할 수 없습니다. 당신이한다면u003Cimg src="/myimage.gif"/> 당신이 정말로 원했던 것은 "/myapp/myimage.gif"이기 때문에 404를 얻을 것입니다.

많은 프레임 워크에는 컨텍스트를 인식하는 JSP 태그가 있으며 JSP 내에서 올바른 URL을 만드는 방법이 다릅니다 (특히 우아하게는 없음).

코더가 "App Relative"URL을 사용할 때와 절대 URL을 사용하는시기를 벗어나는 것은 중요한 문제입니다.

마지막으로, 즉시 URL을 생성 해야하는 JavaScript 코드와 CSS 내에 내장 된 URL (배경 이미지 등) 문제가 있습니다.

다른 사람들 이이 문제를 완화하고 작업하기 위해 어떤 기술을 사용하는지 궁금합니다. 많은 사람들이 단순히 서버 루트 또는 사용중인 컨텍스트에 대해 간단히 펀트하고 하드 코드를 사용합니다. 나는 이미 그 대답을 알고 있습니다. 그것은 내가 찾고있는 것이 아닙니다.

너 뭐하니?

도움이 되었습니까?

해결책

URL을 생성하기 위해 JSTL을 사용할 수 있습니다.

예를 들어, <c:url value="/images/header.jpg" /> 컨텍스트 루트를 접두사합니다.

CSS의 경우 일반적으로 나에게는 문제가되지 않습니다.

다음과 같은 웹 루트 구조가 있습니다.

/CSS
/이미지

CSS 파일에서는 상대 URL (../images/header.jpg)을 사용하면 컨텍스트 루트를 알 필요가 없습니다.

JavaScript의 경우, 나에게 효과가있는 것은 다음과 같은 페이지 헤더에 일반적인 JavaScript를 포함하는 것입니다.

<script type="text/javascript">
var CONTEXT_ROOT = '<%= request.getContextPath() %>';
</script>

그런 다음 모든 스크립트에서 컨텍스트 루트를 사용할 수 있습니다 (또는 경로를 빌드 할 함수를 정의 할 수 있습니다. 좀 더 유연 할 수 있음).

분명히 이것은 모든 것이 JSP 및 JSTL 사용에 달려 있지만, 페이스 렛과 함께 JSF를 사용하고 관련된 기술은 비슷합니다. 유일한 차이는 컨텍스트 루트를 다른 방식으로 얻는 것입니다.

다른 팁

HTML 페이지의 경우 HTML을 설정했습니다 <base> 꼬리표. 모든 상대 링크 (즉, 체계 또는 /)는 그것에 대해 상대적으로 될 것입니다. 즉시 그것을 잡을 수있는 깨끗한 방법이 없습니다. HttpServletRequest, 우리는 여기서 JSTL의 도움이 필요하지 않습니다.

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<c:set var="req" value="${pageContext.request}" />
<c:set var="url">${req.requestURL}</c:set>
<c:set var="uri">${req.requestURI}</c:set>

<!DOCTYPE html>
<html lang="en">
  <head>
    <base href="${fn:substring(url, 0, fn:length(url) - fn:length(uri))}${req.contextPath}/" />
    <link rel="stylesheet" href="css/default.css">
    <script src="js/default.js"></script>
  </head>
  <body>
    <img src="img/logo.png" />
    <a href="other.jsp">link</a>
  </body>
</html>

그러나 이것은 결국 경고입니다 : 앵커 ( #identifier URL)도 기본 경로와 관련이 있습니다. 당신이 그들 중 하나가 있으면, 당신은 대신 요청 URL (URI)과 관련하여 그것을 만들고 싶습니다. 그래서,

<a href="#identifier">jump</a>

에게

<a href="${uri}#identifier">jump</a>

JS에서는 액세스 할 수 있습니다 <base> 상대 URL을 절대 URL로 변환 할 때마다 DOM의 요소.

var base = document.getElementsByTagName("base")[0].href;

또는 jQuery를하는 경우

var base = $("base").attr("href");

CSS에서 이미지 URL은 스타일 시트 자체의 URL과 관련이 있습니다. 따라서 스타일 시트 자체와 관련하여 일부 폴더에 이미지를 삭제하십시오. 예를 들어

/css/style.css
/css/images/foo.png

다음과 같이 참조하십시오

background-image: url('images/foo.png');

CSS 폴더와 같은 수준의 일부 폴더에서 이미지를 삭제하려면

/css/style.css
/images/foo.png

그런 다음 사용하십시오 ../ 공통 상위 폴더로 이동합니다

background-image: url('../images/foo.png');

또한보십시오:

나는 동의한다 지각. 필터에주의를 기울였으며 프로젝트에 직면하여 솔루션을 찾았습니다. urlrewritefilter. 다음과 같은 간단한 구성 :

<rule>
    <from>^.+/resources/(.*)$</from>
    <to>/resources/$1</to>
</rule>

* /리소스 경로 /리소스 패스 (컨텍스트 경로 접두사 포함)에 대한 모든 요청을 전달하는 데 도움이됩니다. 그래서 나는 단순히 내 모든 것을 넣을 수 있습니다 이미지 그리고 CSS 아래에 파일 자원 배경 이미지 및 기타 케이스에 대한 내 스타일에서 상대 URL을 계속 사용하고 계속 사용하십시오.

Servlet API와 JSP에는이를 관리하는 데 도움이되는 시설이 있습니다. 예를 들어, 서블릿에서 : response.sendredirect ( "/myPage.jsp")를 사용하면 컨테이너가 컨텍스트를 선불로 만들고 URL을 만듭니다. http://example.com/myapp/mypage.jsp".

아, 어쩌면 아마 아닐 수도 있습니다 - 그것은 당신의 컨테이너와 서블릿 사양에 따라 다릅니다!

에서 Servlet 2.3 : 새로운 기능 노출:

마지막으로, 전문가 그룹의 긴 토론 후, Servlet API 2.3은 한 번 명확히했으며 Res.SendRedirect ( "/index.html")에서 발생하는 모든 일에 대해 뿌리가 아닌 컨텍스트 내에서 서비스를 실행하도록 요청합니다. 문제는 Servlet API 2.2에는 "/index.html"과 같은 불완전한 경로가 서블릿 컨테이너에 의해 전체 경로로 번역되지만 컨텍스트 경로가 어떻게 처리되는지는 말하지 않는다는 것입니다. 통화를하는 서블릿이 경로 "/contextPath"에서 컨텍스트에있는 경우, ridirect uri가 컨테이너 루트를 기준으로 번역해야합니다 (http : // 서버 : port/index.html) 또는 컨텍스트 루트 (http : // 서버 : port/contextpath/index.html)? 최대 이식성을 위해서는 동작을 정의하는 것이 필수적입니다. 긴 토론 후, 전문가들은 컨테이너 루트를 기준으로 번역하기로 결정했습니다. 컨텍스트 상대를 원하는 사람들의 경우 getContextPath ()에서 URI로 출력을 선불로 전환 할 수 있습니다.

아니요, 2.3의 경로가 있습니다 ~ 아니다 컨텍스트 경로를 포함하도록 자동 번역.

나는 사용했다 도우미 수업 IMG 태그 등을 생성하려면이 헬퍼 클래스는 접두사 경로 응용 프로그램의 컨텍스트 경로와 함께. (이것은 효과가 있지만 정말 마음에 들지 않습니다. 누군가 더 나은 대안이 있다면 말씀 해주십시오.)

CSS 파일 등의 경로의 경우 an을 사용합니다 개미 빌드 스크립트 이는 Production Environment의 Site.css 용 Site.Production.css를 사용하여 개발 환경의 Site.Development.css를 사용합니다.

또는 때때로 나는 ANT 스크립트를 사용합니다 @token @대체 다른 환경에 대한 적절한 데이터가있는 토큰. 이 경우 @ contextpath @ token은 올바른 컨텍스트 경로로 대체됩니다.

한 가지 옵션은 가능할 때마다 "Flat"응용 프로그램 구조 및 상대 URL을 사용하는 것입니다.

"Flat"이라는 의미는 응용 프로그램 루트 아래에 하위 디렉토리가 없으며 "이미지/"로 정적 컨텐츠에 대한 디렉토리가 거의 없음을 의미합니다. 모든 JSP, ACTION URL, 서블릿은 루트 바로 아래로 이동합니다.

이것은 문제를 완전히 해결하지는 않지만 크게 단순화합니다.

Vilmantas는 여기에서 올바른 단어를 말했습니다 : 상대 URL.

IMG에서해야 할 일은 사용하는 것뿐입니다.

<img src="myimage.gif"/>

대신에

<img src="/myimage.gif"/>

그리고 그것은 앱 컨텍스트와 관련이 있습니다 (브라우저가 가야 할 URL을 해석하고 있기 때문에).

특별한 경우를 제외하고는 절대 URL을 사용하지 않는 것이 좋습니다. 항상. 절대 URL은 언제에 좋습니다 다른 웹 앱 WebApp의 무언가를 가리키고 있습니다. 내부적으로 - 하나의 리소스가 동일한 맥락에서 두 번째 리소스를 가리키는 경우 자원은 사는 곳을 알아야하므로 두 번째 리소스에 대한 상대 경로를 표현할 수 있어야합니다.

물론, 모듈 식 구성 요소를 작성하는 모듈 식 구성 요소를 작성할 수 있습니다. 예를 들어:

/myapp/user/email.jsp:
Email: <a href="../sendmail.jsp">${user.email}</a>

/myapp/browse/profile.jsp:
<jsp:include page="../user/email.jsp" />

/myapp/home.jsp:
<jsp:include page="../user/email.jsp" />

그래서 어떻게합니까? email.jsp 상대적인 경로를 알고 있습니다 sendmail.jsp? 분명히 링크가 끊어 질 것입니다 /myapp/browse/profile.jsp 아니면 부서 질 것입니다 /myapp/home.jsp . 답은 모든 URL을 동일한 플랫 필레 패스 공간에 보관합니다. 즉, 모든 URL은 이후에 슬래시가 없어야합니다. /myapp/ .

URL과 컨텐츠를 생성하는 실제 파일 사이에 어떤 종류의 매핑이있는 한 이는 쉽게 달성하기가 쉽습니다. (예 : 봄에는 Dispatcherservlet을 사용하여 URL을 JSP 파일 또는보기에 매핑하십시오.)

특별한 경우가 있습니다. 예를 들어 JavaScript로 브라우저 측 응용 프로그램을 작성하는 경우 플랫 Filepath 공간을 유지하기가 더 어려워집니다. 이 경우, 또는 다른 특별한 경우 또는 개인 취향이있는 경우 사용하는 것은 실제로 큰 문제가 아닙니다. <%= request.getContextPath() %> 절대 경로를 만들기 위해.

request.getContextPath ()를 사용하여 특정 컨텍스트에 대해 하드 코딩되지 않은 절대 URL을 구축 할 수 있습니다. 이전 답변에서 알 수 있듯이 JavaScript의 경우 JSP 상단 (또는 바람직하게는 템플릿에서)에 변수를 설정하고 문맥으로 접두사를 설정합니다.

CSS 파일을 동적으로 생성하지 않으면 CSS 이미지 교체에는 효과가 없습니다. 이는 다른 문제를 일으킬 수 있습니다. 그러나 이미지와 관련하여 CSS 파일이 어디에 있는지 알고 있으므로 상대 URL을 사용하여 벗어날 수 있습니다.

어떤 이유로, 나는 상대 URL을 처리하는 데 어려움을 겪었고 컨텍스트에 설정된 JavaScript 변수가있는 표현식을 사용하는 것으로 되돌아 가야했습니다. 방금 IE 이미지 교체품을 자신의 파일로 나누고 IE 매크로를 사용하여 올바른 파일을 가져 왔습니다. 어쨌든 투명한 PNG를 다루기 위해 이미 그렇게해야했기 때문에 큰 문제는 아닙니다. 예쁘지는 않지만 작동합니다.

이러한 기술의 대부분을 사용했습니다 (XSLT 아키텍처 저장).

문제의 핵심 (및 합의)은 잠재적으로 여러 디렉토리가있는 사이트가 있다고 생각합니다.

디렉토리 깊이 (더 나은 용어 부족)가 일정하다면 CSS와 같은 것의 상대 URL에 의존 할 수 있습니다.

마음에, 레이아웃이 완전히 평평 할 필요는 없으며 일관성이 있습니다.

예를 들어, /css, /js, /common, /admin, /user와 같은 계층 구조를 수행했습니다. 적절한 디렉토리에 적절한 페이지와 리소스를 넣습니다. 이와 같은 구조를 갖는 것은 컨테이너 기반 인증과 매우 잘 작동합니다.

나는 또한 *.css와 *.js를 JSP 서블릿에 매핑하고 동적으로 만들어서 즉시 만들 수 있도록 동적으로 만들었습니다.

나는 내가 놓친 다른 것이 있기를 바랐다.

나는 아니요 다음은 우아한 문제라고 주장합니다. 사실, 가시적으로는 (가장 가능성이 높은) 성능이 인기를 감안할 때이 문제를 추천하지 않을 것입니다.

웹 앱의 JSP는 엄격하게 XML 원시 데이터입니다. 그런 다음이 원시 데이터를 XSL (서버 측)으로 전송하여 올바른 CSS 태그를 적용하고 XHTML을 뱉어 냈습니다.

웹 사이트의 다른 구성 요소에 대해 가지고있는 여러 XSL 파일에 의해 상속되는 단일 Template.xsl이 있습니다. 우리의 경로는 모두 paths.xml이라는 XSL 파일로 정의되었습니다.

<?xml version="1.0" encoding="UTF-8"?>
<paths>
    <path name="account" parent="home">Account/</path>
    <path name="css">css/</path>
    <path name="home">servlet/</path>
    <path name="icons" parent="images">icons/</path>
    <path name="images">images/</path>
    <path name="js">js/</path>
</paths>

내부 링크는 다음과 같이 XML에 있습니다.

<ilink name="link to icons" type="icons">link to icons</ilink>

이것은 XSL에 의해 처리됩니다.

<xsl:template match="ilink">
    <xsl:variable name="temp">
        <xsl:value-of select="$rootpath" />
        <xsl:call-template name="paths">
            <xsl:with-param name="path-name"><xsl:value-of select="@type" /></xsl:with-param>
        </xsl:call-template>
        <xsl:value-of select="@file" />
    </xsl:variable>
        <a href="{$temp}" title="{@name}" ><xsl:value-of select="." /></a>
</xsl:template>

$rootPath 각 파일에 전달되었습니다 ${applicationScope.contextPath} JSP/Java 파일로 하드 코딩하는 대신 XML을 사용하는 아이디어는 우리가 다시 컴파일하기를 원하지 않았다는 것입니다.

다시 말하지만, 솔루션은 전혀 좋은 솔루션이 아닙니다 ... 그러나 우리는 그것을 한 번 사용했습니다!

편집하다: 실제로, 우리의 문제의 복잡성은 전체보기에 JSP를 사용할 수 없었기 때문에 발생했습니다. 왜 누군가가 사용하지 않겠습니까? ${applicationScope.contextPath} 컨텍스트 경로를 검색하려면? 그때 우리를 위해 잘 작동했습니다.

처음부터 사이트를 만들 때 @will과 함께 측면 - 일관되고 예측 가능한 URL 구조를 목표로하여 상대 참조를 고수 할 수 있습니다.

그러나 원래 사이트 루트 바로 아래에서 작동하도록 구축 된 사이트를 업데이트하는 경우 (간단한 JSP 사이트에서는 매우 일반적) 공식적입니다. 자바 ee 포장 (컨텍스트 루트는 루트 아래의 경로가 될 때).

그것은 많은 코드 변경을 의미 할 수 있습니다.

코드 변경을 피하거나 연기하고 싶지만 여전히 올바른 컨텍스트 루트 참조를 확인하려면 테스트 한 기술은 서블릿 필터를 사용하는 것입니다. 필터는 아무것도 변경하지 않고 기존 ProEJCT로 떨어질 수 있으며 (web.xml 제외) 아웃 바운드 HTML의 URL 참조를 올바른 경로로 재구성하고 리디렉션이 올바르게 참조되도록합니다.

예제 사이트 및 유용한 코드를 여기에서 사용할 수 있습니다. EnforceContextrootfilter-1.0-src.zip NB : 실제 매핑 규칙은 Servlet 클래스에서 Regex로 구현되며 꽤 일반적인 캐치를 제공하지만 특정 상황에 대해 수정해야 할 수도 있습니다.

btw, 나는 다루기 위해 약간 다른 질문을했다 기존 코드베이스를 "/"에서 뿌리가 아닌 컨텍스트-경로로 마이그레이션

나는 내 핵심 JavaScript 라이브러리의 일부로 속성을 작성하는 경향이 있습니다. 나는 그것이 완벽하다고 생각하지 않지만 그것이 내가 달성 한 최고라고 생각합니다.

먼저, 항상 사용할 수있는 앱 코어의 일부인 모듈이 있습니다.

(function (APP) {
  var ctx;
  APP.setContext = function (val) {
    // protect rogue JS from setting the context.
    if (ctx) {
      return;
    }
    val = val || val.trim();
    // Don't allow a double slash for a context.
    if (val.charAt(0) === '/' && val.charAt(1) === '/') {
      return;
    }
    // Context must both start and end in /.
    if (val.length === 0 || val === '/') {
      val = '/';
    } else {
      if (val.charAt(0) !== '/') {
        val = '/' + val;
      }
      if (val.slice(-1) !== '/') {
        val += '/';
      }
    }
    ctx = val;
  };
  APP.getContext = function () {
    return ctx || '/';
  };
  APP.getUrl = function (val) {
    if (val && val.length > 0) {
      return APP.getContext() + (val.charAt(0) === '/' ? val.substring(1) : val);
    }
    return APP.getContext();
  };
})(window.APP = window.APP || {});

그런 다음 항상 다음이 포함 된 공통 헤더와 함께 Apache 타일을 사용합니다.

<script type="text/javascript">
  APP.setContext('${pageContext.request['contextPath']}');
  // If preferred use JSTL cor, but it must be available and declared.
  //APP.setContext('<c:url value='/'/>');
</script>

이제 사용할 수있는 컨텍스트를 초기화했습니다 getUrl(path) 컨텍스트 내에서 주어진 입력 문자열에 대한 절대 경로를 반환 할 어디에서나 (JS 파일 또는 JSP/HTML 내).

다음은 의도적으로 동일합니다. getUrl 상대 경로는 처음에 컨텍스트를 알 필요가 없으므로 항상 절대 경로를 반환합니다.

var path = APP.getUrl("/some/path");
var path2 = APP.getUrl("some/path");

가장 좋은 방법은 다음과 같습니다. 컨텍스트 리디렉션 필터 필터는 프리 매칭 확장 지점에 적용해야하므로 주석 @prematching을 사용해야합니다.

이 인터페이스를 구현하는 필터는 jax-rs 런타임에 의해 @provider와 주석을 달아야합니다. 컨테이너 요청 필터 인스턴스를 발견하고 특정 리소스 방법에 동적으로 바인딩 할 수 있습니다.

샘플 코드로 설명 :

http://writeulearn.com/java-filters/

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top