جاوا و تکنولوژی های آن

java programming language

در این وبلاگ به بررسی نکات موجود در جاوا و تکنولوژی های آن می پردازیم

طبقه بندی موضوعی


وجود فایل های استاتیک مانند css, js , images و ... در وب اجتناب ناپذیر است و باید برای ارائه کردن این محتوا (که نیازی به تغییر ندارند) و محتوای فایل عینا به درخواست کننده ارسال میشود باید مکانیزم ارائه، جدا از بحث داینامیک فایل های View داشته باشیم در ادامه به نحوه سرو کردن محتوای استاتیک در Spring MVC بصورت XML و تنطیمات کد Java میپردازیم 


قبل از شروع از نظر ساختاری باید در نظر داشته باشیم که فایل های استاتیک در یک مسیر خاص روی هارد نگهداری میشوند و برای راحتی و اصولی کار کردن بهتر است یک ساختار نظامندی را در نظر بگیریم مثلا فایل های image در زیر شاخه images قرار گیرند و ...




روش XML :

xml قدیمی ترین روش تنظیمات در Spring است که همچنان قابل استفاده است از آنجا که این روش طرفدار های خاص خودش را دارد اشاره کردن بهش خالی از لطف نیست
کافی است در یک خط با استفاده از تگ <mvc:resource> مشخص کنیم که کدام url به کدام ادرس روی حافظه باید اشاره کند :
<mvc:resources mapping="/resources/**" location="/resources/" />

فرض کنید در شاخه resources یک فایل با نام myCss.css وجود دارد که میخواهیم در Html آنرا بخوانیم :

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
    <link href="<c:url value="/resources/myCss.css" />" rel="stylesheet">
    <title>Home</title>
</head>
<body>
    <h1>Hello world!</h1>
</body>
</html>





روش Java Configuration :


در Spring 4.1 برای بهینه کردن و بالا بردن کارایی فایل های استاتیک در مرورگر ها که قابلیت ایجاد تنظیمات زنجیره ای و کش کردن روی مرورگر ها روش جدیدی معرفی شد 


PathResourceResolver :

همانطور که از نامش مشخص است ساده ترین نوع Resource Resolver ای که میتوانیم استفاده کنیم که یک url را با یک آدرس map میکند. این Resource Resolver پیش فرض است مگر نوع دیگری تعریف کنیم 

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry
      .addResourceHandler("/resources/**")
      .addResourceLocations("/resources/","/other-resources/")
      .setCachePeriod(3600)
      .resourceChain(true)
      .addResolver(new PathResourceResolver());
}

در این تنظیمات 3600 ثانیه فایل های در مرورگر cache میشوند و Resolver ای که مشخص کردیم از نوع PathResourceResolver است 


نوع دیگر :

@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/js/**") 
                .addResourceLocations("/js/") 
                .setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS));
    }
}

* طبق استاندارد تعریف شده در RFC2616 حداکثر زمانی که میتوان برای فیلد Cache-Control در Header تعیین کرد 365 روز است 



EncodedResourceResolver : 

این Resource Resolver بر اساس فیلد Accept-Encoding هدر میتواند encoding خاصی مثل فشرده سازی را اعمال کند. برای صرفه جویی در پهنای باند محتوای ارسالی را  gzip کنیم (اگر مرورگر ساپورت کند که در هدر انرا ارسال کرده) و بعد ارسال کنیم.

برای استفاده کافی است در ادامه کد قبلی روی متغییر register و با استفاده از قابلیت chain یک Resource Resolver دیگر بدین صورت تعریف کنیم :

registry
  .addResourceHandler("/other-files/**")
  .addResourceLocations("file:/Users/Me/")
  .setCachePeriod(3600)
  .resourceChain(true)
  .addResolver(new EncodedResourceResolver());

EncodedResourceResolver   از gzip و br حمایت میکند



نحوه کارکرد زنجیره Resource Resolver ها :

اگر چندین Resource Resolver را در chain اضافه کرده بایم و چنانچه محتوای استاتیک توسط Resource Resolver پیدا نشود این عملیات به ResourceResolver بعدی منتقل میشود، تنهای Resource Resolver ای که نمی تواند عملیات انتقال به Resource Resolver بعدی را انجام دهد PathResourceResolver است برای همین باید همیشه در انتهای زنجیره قرار دهیم 


*اگر ما (resourceResolver(true نکنیم تنها PathResourceResolver در زنجیره خواهد بود

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry
      .addResourceHandler("/js/**")
      .addResourceLocations("/js/")
      .setCachePeriod(3600)
      .resourceChain(true)
      .addResolver(new GzipResourceResolver())
      .addResolver(new PathResourceResolver());
}



تنظیمات مهم امنیتی برای فایل های استاتیک :

اگر از Spring Security استفاده میکنیم لازم است تنظیماتی را برای اجازه دسترسی فایل های استاتیک ست کنیم :


<intercept-url pattern="/files/**" access="permitAll" />
<intercept-url pattern="/other-files/**/" access="permitAll" />
<intercept-url pattern="/resources/**" access="permitAll" />
<intercept-url pattern="/js/**" access="permitAll" />





اگر مدت زمان cache زیاد بود و ما ورژن جدیدی از فایل را تولید کرده باشیم که باید در مرورگر ها ست شود در این موقع چه راهکاری وجود دارد ؟


- فایل ها را همراه با Versioning ارائه دهیم مثلا اگر فایلی بنام foo.js وجود داشت آنرا به foo-6348593894856.js تغییر دهیم و موقعی که ورژنی جدید شد در Html نام فایل را عوض کنیم و فایل قبلی دیگر درخواستی برای آن وجود نخواهد داشت

- آدرس فایل را بکل عوض کنیم 


برای روش اول :

Spring میتواند توسط کلاس VersionResourceResolver روش versioning را با استفاده از تولید کد hash هر فایل و اضافه کردن آن به نام فایل همیشه آپدیت های بروز را برای مرورگر ارائه دهد :

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/js/**")
            .addResourceLocations("/js/")
            .setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS))
            .resourceChain(false)
            .addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
}


برای روش دوم :

در Spring با استفاده از کلاس ResourceUrlEncodingFilter و تگ url از JSTL آنرا ارائه دهیم 

ابتدا باید کلاس ResourceUrlEncodingFilter  را در web.xml ثبت کنیم :

<filter>
    <filter-name>resourceUrlEncodingFilter</filter-name>
    <filter-class>
        org.springframework.web.servlet.resource.ResourceUrlEncodingFilter
    </filter-class>
</filter>
<filter-mapping>
    <filter-name>resourceUrlEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

و برای کد در View از تگ url استفاده میکنیم :

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
.
.
.
<script type="text/javascript" src="<c:url value="/js/foo.js" />">

وقتی view بالا رندر شد تبدیل به این کد خواهد شد :

<script type="text/javascript" src="/js/foo-46944c7e3a9bd20cc30fdc085cae46f2.js">


*روش بالا برای مواردی که داخل فایل، فایل دیگری را import نکرده باشیم جواب میدهد ولی مثلا در CSS میتوانیم توسط import کردن یک css دیگر را در css جاری import کنیم در این شرایط چطور میتوان از روش های بالا استفاده کرد ؟ 

@import "another.css";

کافی است از کلاس CssLinkResourceTransformer  استفاده کنیم :

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/resources/**")
            .addResourceLocations("/resources/", "classpath:/other-resources/")
            .setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS))
            .resourceChain(false)
            .addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"))
            .addTransformer(new CssLinkResourceTransformer());
}

و در css تبدیل به چیزی شبیه به کد زیر خواهد شد :

@import "another-9556ab93ae179f87b178cfad96a6ab72.css";





نظرات  (۰)

هیچ نظری هنوز ثبت نشده است

ارسال نظر

ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی