<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های zahratgz</title>
        <link>https://virgool.io/feed/@zaratgz</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-06-16 16:00:34</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/38329/avatar/wo28Kh.png?height=120&amp;width=120</url>
            <title>zahratgz</title>
            <link>https://virgool.io/@zaratgz</link>
        </image>

                    <item>
                <title>پلاگین SonarLint در Intellij</title>
                <link>https://virgool.io/@zaratgz/%D9%BE%D9%84%D8%A7%DA%AF%DB%8C%D9%86-sonarlint-%D8%AF%D8%B1-intellij-uew79oszq2ev</link>
                <description>در این سری می خوایم با یکی از پلاگین های خوب Intellij آشنا بشیم. برای بهبود کدهایی که می نویسم خیلی به ما کمک می کند،کد ها را آنالیز می کند و برای خوانایی بهتر راه حل جایگزین پیشنهاد می دهد، حتی نمونه مثال هم دارد تا بیشتر با منظورش آشنا بشیم .توضیح اولیه خوبی داخل این پست هست، می تونید بهش مراجعه کنید.  https://virgool.io/@alihanifi/%D8%A2%D8%B4%D9%86%D8%A7%DB%8C%DB%8C-%D8%A8%D8%A7-%D8%A7%D8%A8%D8%B2%D8%A7%D8%B1%D9%87%D8%A7%DB%8C-%D8%AA%D8%AD%D9%84%DB%8C%D9%84-%DA%A9%D9%8F%D8%AF-%D8%A7%D8%B3%D8%AA%D8%A7%D8%AA%DB%8C%DA%A9-qeecdwac6zpv در ابتدا برای نصب این پلاگین داخل Intellij  تنها کافیه وارد بخش  Settings شودید و در منو plugins، پلاگین SonalLint را جستجو کنید و دانلود کنید.بعد از نصببعد از نصب و ریست شدن یک تب با نام SonarLint  در کنار tab های دیگر قرار می گیرد. کافی ایست در کلاسی که در حال  کدنویسی هستید بر روی این tab کلیک کنید تا به شما issues های مختلف که در کد شما شناسایی کرده را نشان دهد.شامل چند سطح مختلف می باشد که با رنگ مشخص شده است. در 5 سطح مختلف  اگر کدهای شما از نظر این پلاگین خوب باشد با پیغام &quot; No Issues to display &quot; رو به رو می شوید. در غیر این صورت با انتخاب هر کدام توضیحات مختصری همراه با مثال برای درک بهتر را نشان می دهد. با هم چند نمونه را بررسی می کنیم: در نمونه Minor : پیشنهاد می کند در صورتی که در حال استفاده از  آرایه هستید و می خواهید خالی بودن آن را بررسی نمایید به جای این که مقدار size =0  را چک کنید از متد isEmpty استفاده نمایید.در نمونه Major: پیشنهاد می کند اگر چندتا شرط if پشت سر هم دارید مثل نمونه ای که خودش گفته برای خوانایی بهتر کد بهتره شرط ها رو با هم ادغام کنید.در نمونه Critical : در شکل بالا مشخص است خطاهای حیاتی را مطرح می کند مثلا در صورتی که  اگر متدی داشته باشید که داخلش تعداد شرط های زیادی گذاشته باشید و در واقع دچار پیچیدگی زیادی شده است، پیشنهاد می کند داخل متدهای کوچیک تر با نام های با معنی بگذاریم تا خوانایی متد های پیچیده هم بهتر شود.
در نمونه Info: برای مثال اطلاع می دهد که todo باقی مانده را بهتر است انجام دهید.بعد از نوشتن کدهاتون حتما به سراغ این تب برید و با بررسی issue های این پلاگین، موارد را برطرف کنید تا کد خواناتر و بهتر را داشته باشید.بهتون اطمینان می دم به مرور که استفاده می کنید دیگه در زمان کد نویسی، خودتون موارد را رعایت می کنید و issue ها به صورت چشم گیری کاهش پیدا می کنه.</description>
                <category>zahratgz</category>
                <author>zahratgz</author>
                <pubDate>Sun, 01 Sep 2024 11:07:10 +0330</pubDate>
            </item>
                    <item>
                <title>استفاده از mapstruct برای تبدیل object ها به یکدیگر</title>
                <link>https://virgool.io/wptips/%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-mapstruct-%D8%A8%D8%B1%D8%A7%DB%8C-%D8%AA%D8%A8%D8%AF%DB%8C%D9%84-object-%D9%87%D8%A7-%D8%A8%D9%87-%DB%8C%DA%A9%D8%AF%DB%8C%DA%AF%D8%B1-tdxoy1ajizto</link>
                <description>گاهی در پروژه ها لازم است در لایه های مختلف یک object به object دیگری تبدیل شود، نوشتن کد برای تبدیل شی های مختلف به هم کار سخت و خسته کننده است و احتمال خطا را نیز زیاد می کند، یکی از روش ها استفاده از MapStruct است که با استفاده از annotaion های موجود، تبدیل انواع objectها را با هم انجام می دهد. از متد های setter/getter که در شی های sourceو target قرار دارد کمک می گیرد. کد ایجاد شده خوانا نیز می باشد و یک جا این تبدیلات توسط MapStruct انجام می شود و ما در تمام پروژه به راحتی از آن استفاده می کنیم.کلاس های تبدیل map در زمان کامپایل اجرا می شوند و در زمان runtime هیچ کاری را انجام نمی دهند بنابراین سرعت بالایی داردبرای تبدیل شی ها در یک پروژه ی spring boot تنها کافی ایست مقادیر زیر را به pom فایل خودتون اضافه کنید:&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.mapstruct&lt;/groupId&gt;
        &lt;artifactId&gt;mapstruct&lt;/artifactId&gt;
        &lt;version&gt;1.3.1.Final&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;
...
&lt;build&gt;
    &lt;plugins&gt;
        &lt;plugin&gt;
            &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
            &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
            &lt;version&gt;3.5.1&lt;/version&gt;
            &lt;configuration&gt;
                &lt;source&gt;1.8&lt;/source&gt;
                &lt;target&gt;1.8&lt;/target&gt;
                &lt;annotationProcessorPaths&gt;
                    &lt;path&gt;
                        &lt;groupId&gt;org.mapstruct&lt;/groupId&gt;
                        &lt;artifactId&gt;mapstruct-processor&lt;/artifactId&gt;
                        &lt;version&gt;1.3.1.Final&lt;/version&gt;
                    &lt;/path&gt;
                &lt;/annotationProcessorPaths&gt;
            &lt;/configuration&gt;
        &lt;/plugin&gt;
    &lt;/plugins&gt;
&lt;/build&gt;در ابتدا برای تبدیلات به یک اینترفیس نیاز داریم(متد های موجود در این اینترفیس شی های مختلف را به هم تبدیل می کند) @Mapper  را بالا سر آن قرار می دهیم. در زمان کامپایل خودش پیاده سازی مربوطه را بر اساس متد های نوشته شده ایجاد می کند.@Mapper
public interface CustomerDtoMapper {}در صورتی که بخواهید مقدار null بودن را نیز چک کند تا اگر فیلدی مقدارش Null است را در object نهایی set نکند کافی ایست nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS را در بالا سر اینترفیس که جزی از @Mapper می باشد قرار دهید.نکته:در ورژن های قدیمی که در داخل یک شی متغییر لیستی وجود داشت در زمان تبدیل لیست به هم ، دچار خطای NullpointerException می شد چون کدی که ایجاد می کرد شبیه کد زیر بود(فرض کنید در شی countryOutput متغییری با نام OtherLanguagesList با دیتاتایپ لیستی داریم و مقدار getOtherLanguagesList به دلیل null بودن دچار خطا می گردید)countryOutput.getOtherLanguagesList().addAll( list )بنابراین برای برطرف نمودن این خطا کافی بود در بخش Mapper مقدار زیر را وراد نمایید. کد پیاده سازی شده تغییر می کند .collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERREDدر صورتی که نام متغییر ها در هر دو طرف یکسان باشد دیگر در اینترفیس ایجاد شده نیازی نیست نظیر به نظیر اعلام کنیم کدام فیلد با کدام فیلد باید مقدار دهی شود و خودش این تبدیل را به صورت پیش فرض انجام می دهد. اما اگر نام ها متفاوت باشد باید با @Mapping در بالا سر متد مربوطه نظیر به نظیر اعلام کنیم کدام فیلد را با کدام فیلد map کند .حتی می توانید چند object متفاوت را به یک object تبدیل کنید.@Mappings({
        @Mapping( target = &amp;quotforename&amp;quot,source = &amp;quotcustomer.firstName&amp;quot),
        @Mapping(target = &amp;quotsurname&amp;quot,source = &amp;quotcustomer.lastName&amp;quot),
        @Mapping( target = &amp;quotstreet&amp;quot,source = &amp;quotaddress.street&amp;quot),
        @Mapping(target = &amp;quotpostalCode&amp;quot,source = &amp;quotaddress.postalCode&amp;quot),
        @Mapping(target = &amp;quotcounty&amp;quot,source = &amp;quotaddress.county&amp;quot)
})
DeliveryAddress from(Customer customer, Address address);در صورتی که بخواهید در زمان map کردن عملیات خاصی را انجام دهید می توانید با تعریف یک متد و پیاده سازی آن در اینترفیس و معرفی آن با qualifiedByName استفاده کنید. مثلا در اینجا برای تبدیل تاریخ رشته با جداکننده(1399/01/20) به عددی(13990120)@Mappings({
        @Mapping(source = &amp;quotbirthDate&amp;quot, target = &amp;quotbirthDate&amp;quot,
                qualifiedByName = &amp;quotconvertToNumberDate&amp;quot),
        @Mapping(target = &amp;quotstartDt&amp;quot, source = &amp;quotcustomerDto.customerStartDt&amp;quot,
                dateFormat = &amp;quotdd-MM-yyyy HH:mm:ss&amp;quot)
})
Customer fromCustomerDoToCustomer(CustomerDto customerDto);@Named(&amp;quotconvertToNumberDate&amp;quot)
default Integer removeSlashFromDate(String dateStr) {
    return Integer.parseInt(dateStr.replaceAll(&amp;quot/&amp;quot, &amp;quot&amp;quot));
}حتی از dateFormat و numberFormat نیز می توانید در زمان تبدیلات استفاده کنید. در مثال بالا برای تاریخ نیز از dateFormat استفاده کردیم.برای تبدیل enum به String  و بالعکس خودش مقدارها را تبدیل می کند :    1.
if ( customer.getCustomerType() != null ) {
    customerDto.customerType( customer.getCustomerType().name() );
}
2.
if ( customerDto.getCustomerType() != null ) {
    customer.customerType( Enum.valueOf( CustomerType.class, customerDto.getCustomerType() ) );
}ویژگی ignore :اگر در برابر پارامتری قرار دهیم یعنی در زمان تبدیل این متغییر را در نظر نگیرد.همچنین می خواهیم در زمان تبدیل مقدار شناسه با کمک کلاس  UUID برای ما ایجاد کند ، تنها کافی است برای شناسایی کلاس در زمان پیاده سازی متدها  نام کلاس را در بخش Mapper با import وارد نمایید. و بخش کد مورد نظر را نیز در بخش Mapping متغییر مورد نظر با expression بیان کنیم.@Mapper(imports = UUID.class)
public interface CustomerDtoMapper{

@Mapping(target=&amp;quotcustomerId&amp;quot,expression=&amp;quotjava( UUID.randomUUID().toString() )&amp;quot)
Customer fromCustomerDoToCustomer(CustomerDto customerDto)
}برای این که این اینترفیس توسط spring ایجاد شود در داخل Mapper بالا سر اینترفیس می توانیم از مقدار  “spring” در componentModel  استفاده کنیم.@Mapper(componentModel = &amp;quotspring&amp;quot)
public interface CustomerDtoMapper {} 
                                                    ............................................
@Autowired
private CustomerDtoMapper  mapper;راه حل دیگر برای دسترسی به متد ها :CustomerDtoMapper customerDtoMapper = Mappers.getMapper(CustomerDtoMapper.class);Customer customer =customerDtoMapper .fromCustomerDoToCustomer(dto);نمونه کد</description>
                <category>zahratgz</category>
                <author>zahratgz</author>
                <pubDate>Sun, 19 Apr 2020 17:16:30 +0430</pubDate>
            </item>
                    <item>
                <title>ایجاد زمانبندی در برنامه های جاوا</title>
                <link>https://virgool.io/fboard/%D8%A7%DB%8C%D8%AC%D8%A7%D8%AF-%D8%B2%D9%85%D8%A7%D9%86-%D8%A8%D9%86%D8%AF%DB%8C-%D8%AF%D8%B1-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D9%87%D8%A7%DB%8C-%D8%AC%D8%A7%D9%88%D8%A7-i4j9hwxa2gmh</link>
                <description>گاهی وقت ها، عملیات سیستم را در زمان هایی که تعداد درخواست ها به سیستم کم است(ممکن است در بازه ای از زمان دچار کمبود منابع باشیم) یا قرار است در یک بازه زمانی مشخص عملیات ثابت و تکراری، انجام شود از زمانبندی(scheduling) استفاده می کنیم.در Spring boot برای فعال سازی زمانبندی(scheduling) نیازی نیست وابستگی خاصی را اعمال نماییم. تنها کافی ایست بالاسر متد main از انوتیشن EnableScheduling@ استفاده نماییم تا کانتینر spring هر متدی که انوتیشن Scheduled@ را دارد را شناسایی کند.نکته: در صورتی که بخواهید امکان فعال و غیرفعال سازی زمان بندی را داشته باشید تنها کافی از انوتیشن ConditionalOnProperty@ در بالاسر کلاس مربوطه استفاده نمایید.@ConditionalOnProperty(name = &amp;quotspring.enable.scheduling&amp;quot)
public class ScheduleEnabling {}و مقدار true/false بودن را از طریق فایل application.properties در اختیار برنامه قرار دهید.spring.enable.scheduling = trueبرای اجرای یک متد در زمان مشخص/یا زمان های متعدد، باید از انوتیشن Scheduled@ در بالاسر متد مربوطه استفاده نمایید، که به صورت کلی 4 نوع ورودی fixedDelay،fixedRate،initialDelay و cronرا دارد.( امکان ورودی داده به صورت عددی و رشته را نیز دارد.)نوع 1:fixedRateدر این مدل بیان می شودکه حتما در زمان مشخص متد اجرا شود، بر اساس این که مقدار fixedRate یا fixedRateString را انتخاب کرده باشید امکان ورود مددت زمان تکرار با عدد یا رشته را دارید.می تونیم مقدار را در فایل application.properties نیز قرار دهیم.مقدار عددی fixedRate باید بر اساس میلی ثانیه باشد برای مثال برای 1 ثانیه باید مقدار 1000 را وارد نمایید. در fixedRateString  نیز با فرمت خاص زیر می توانیم مقدار تکرار را بیان کنیم. در مثال زیر گفته شده هر 2 ثانیه متد رو اجرا کنه.(پیش فرض PT برای بیان استاندارد ISO-8601)sample.schedule.string = PT2Sیکی از معایب fixedRate این است که منتظر اتمام اجرای قبلی نمی مونه و دقیقا در زمان تعیین شده دوباره اجرا می شود و امکان داره در برنامه هایی که چندین متد زمانبندی شده دارد دچار مشکل شود.نوع 2:fixedDelayخیلی شبیه قبلی کار می کند با این تفاوت که منتظر می ماند تا کار قبلی انجام شود و بعد زمان بندی جدید رو شروع می کند.نوع 3:initialDelayبرای زمانی است که بخواهیم اجرای اول را در زمان متفاوتی انجام دهیم و بعد با fixed rate/fixed Delay تکرار های بعدی را مشخص کنیم.(اولین اجرا با تاخیر 1 ثانیه ای انجام می شود، سپس سایر اجرا ها هر 2 ثانیه)@Scheduled(initialDelay = 1000, fixedRateString = &amp;quot${sample.schedule.string}&amp;quot) public void scheduleTaskWithInitialDelay() throws InterruptedException {     task1(); }نوع 4 :cronممکن است شرایطی پیش بیاید که اجرای متد به فواصل زمانی خاصی نیاز داشته باشد. مثلا هر هفته یا آخر هر ماه یا ... .در این موارد بهتر است از عبارات cron  استفاده نمایید. ترتیب قرار گیری مقادیر به صورت زیر است.مقدار سال اجباری نمی باشد ولی سایر فیلد ها باید پر شود.&lt;second&gt; &lt;minute&gt; &lt;hour&gt; &lt;day-of-month&gt; &lt;month&gt; &lt;day-of-week&gt; &lt;year&gt;مقادیر مجازی که می توانید استفاده نمایید:برای مثال عبارت : 2019 ? * * 12 0 0  یعنی  در سال 2019 هر ماه و در هر روز ساعت 12 اجرا شود.کارکتر های خاصی که در ستون آخر شکل بالا(یا تصویر زیر)قرار دارد را می توان به جای مقادیر عددی نیز گذاشت. که برای تعیین زمان بندی بهتر و حالات متخلف بسیار مناسب است.ستاره که به مفهوم تمام ساعات یا دقیقه می باشد.اما اگر بخواهید زمان بندی در ساعات خاصی اجرا شود(برای مثال ساعات فرد یا زوج) تنها کافی ایست ساعت های مورد نظر خود را با کاما ( , )از هم جدا کنید مانند:   * * * 5,7,9 5 زمان بندی شما در ساعات 5:5 - 7:5 - 9:5 انجام می شود.اگر بخواهید زمان بندی شما در ساعاتی پشت هم انجام شود کافی ایست از - بین ساعات استفاده کنید مانند: * * * 9-5 5 زمان بندی شما سر ساعات 5:5 6:5 7:5 8:5 9:5 انجام می گردد.حتی شما می توانید از چند کارکتر نیز بر اساس نیاز خودتان استفاده کنید و زمان بندی مورد نظر خود را بنویسید:  * * * 9/2-5 5  مقدار 2/ یعنی سر ساعت دوم: 5:5 7:5 9:5یکی از پارامترهایی که با cron می آید مقدار zone است که تعین کننده این است که اجرای متد براساس زمان چه کشوری باشد.(تمام مقادیر مجاز برای time zone)@Scheduled(cron=&amp;quot0 0 12 * * ? 2019&amp;quot, zone=&amp;quotEurope/Paris&amp;quot) 
public void doSomething() {     // Something}البته مثل موارد قبلی نیز، می توانیم مقدار عبارت cron را داخل فایل application.properties قرار دهیم و بخوانیم.سایت های مختلفی وجود دارد که به صورت آنلاین مقدار cron شما را محاسبه یا  زمان های بعدی اجرا را به شما نشان می دهد. مانند: Cron maker یا cron tabنمونه کد </description>
                <category>zahratgz</category>
                <author>zahratgz</author>
                <pubDate>Tue, 10 Mar 2020 13:53:03 +0330</pubDate>
            </item>
                    <item>
                <title>Activiti  با Spring boot</title>
                <link>https://virgool.io/@zaratgz/apache-activiti-%D8%A8%D8%A7-spring-boot-qadhijc63aav</link>
                <description>برای شروع به کار، به plugin های activiti نیاز داریم. پست زیر نحوه ی اضافه نمودن این plugin ها به inteliji  را توضیح می دهد. http://vrgl.ir/WJL6m جهت شروع به کار dependency زیر را در فایل pom اضافه می کنیم.&lt;dependency&gt;
    &lt;groupId&gt;org.activiti&lt;/groupId&gt;
    &lt;artifactId&gt;activiti-spring-boot-starter&lt;/artifactId&gt;
    &lt;version&gt;7.0.0.Beta1&lt;/version&gt;
&lt;/dependency&gt;در این آموزش مدل های Script Task،Service Task  را مورد بررسی قرار می دهیم.نکته :تمام فایل های bpmn را در مسیر زیر قرار دهید:(Springboot به صورت پیش فرض در این مسیر به دنبال فایل های با پسوند bpmn می گردد)src/main/resources/processesکامپوننت Script Task:یکی از کامپوننت های bpmn، با نام Script Task است که دو نوع Groovy، javascript را پشتیبانی می کند.و نوع آن را در بخش script format تعیین می کنیم.برای هر فایل bpmnای یک شناسه idقرار می دهیم که یکتا باشد و بعدا در کد با objectای، از جنس org.activiti.engine.RuntimeService می گوییم کدوم process اجرا شود.نمونه مانند شکل زیر یک flow، با نقاط شروع و پایان و کامپوننت Script task قرار دهید. نوع فرمت را javascript انتخاب نمایید. برای این فایل، ما شناسه را مقدار &quot;js-script-task-process&quot; تعریف کرده ایم.برای اجرا این task یک کلاس کنترلر ایجاد کردم که با ارسال درخواست، مقدار عبارت در script بالا را در console نمایش می دهد.@RestController
@RequestMapping(&amp;quot/activiti&amp;quot)
public class ScriptTaskController {

    @Autowired
    private RuntimeService runtimeService;

    @GetMapping(&amp;quotscript-task/js&amp;quot)
    public String jsScriptTask() {
        runtimeService.startProcessInstanceByKey(&amp;quotjs-script-task-process&amp;quot);
        return &amp;quotcheck the console log...&amp;quot
    }
}نمونه groovy:اضافه نمودن وابستگی زیر به pom فایل:&lt;dependency&gt;
    &lt;groupId&gt;org.codehaus.groovy&lt;/groupId&gt;
    &lt;artifactId&gt;groovy-all&lt;/artifactId&gt;
    &lt;version&gt;2.4.17&lt;/version&gt;
&lt;/dependency&gt;یک فایل جدید با پسوند bpmn، در مسیر مربوطه ایجاد می کنیم.flow مانند زیر با شناسه &quot;groovy-script-task-process&quot; ایجاد می کنیم و نوع فرمت را groovy انتخاب می کنیم......
@Autowired
private RuntimeService runtimeService;

@GetMapping(&amp;quotscript-task/groovy&amp;quot)
public String groovyScriptTask() {
    runtimeService.startProcessInstanceByKey(&amp;quotgroovy-script-task-process&amp;quot);
    return &amp;quotcheck the console log...&amp;quot
}
.....
کامپوننت ServiceTask:برای اجرای متدهای جاوایی در activiti، از service task استفاده می کنیم. در اینجا دو مورد Delegate و Expression مورد بررسی قرار می دهیم.نمونه Delegate :یک کلاس ایجاد کنید و اینترفیس JavaDelegate را پیاده سازی کنید. عملیاتی که قرار است task شما انجام دهد را در متد execute پیاده سازی نمایید.public class JavaDelegateService implements JavaDelegate {

    @Override
    public void execute(DelegateExecution execution) {
        System.out.println(&amp;quotJava Delegate Service Task executed successfully.&amp;quot);
        System.out.println(&amp;quotAnd the Sum of 2 + 2= &amp;quot + (2 + 2));
    }
}در فایل bpmn که ایجاد نمودید، کلاس مربوطه را معرفی نمایید.نمونه Expression :با ELexpresion نام کلاس و متد مربوطه را به task می دهیم.public class MethodExpressionService {

    public void myService() {
        System.out.println(&amp;quotMethod Expression Service Task executed successfully.&amp;quot);
        System.out.println(&amp;quotAnd the Multiply of 12 * 2= &amp;quot + (12 * 2));
    }
}جهت تست هر دو Service task ها:@RestController
@RequestMapping(&amp;quotactiviti&amp;quot)
public class ServiceTaskController {

    @Autowired
    private RuntimeService runtimeService;

    @GetMapping(&amp;quotservice/delegate&amp;quot)
    public String startTheDelegateProcess() {
        runtimeService.startProcessInstanceByKey(&amp;quotjava-delegate-service-task-process&amp;quot);
        return &amp;quotCheck the console log...&amp;quot
    }

    @GetMapping(&amp;quotservice/expression&amp;quot)
    public String startTheExpressionProcess() {
        runtimeService.startProcessInstanceByKey(&amp;quotmethod-expression-service-task-process&amp;quot);
        return &amp;quotCheck the console log...&amp;quot
    }
}به صورت پیش فرض از دیتابیس h2 برای مدیریت process id,task id و ... استفاده می کند. در صورت نیاز می توانید اطلاعات دیتابیس خودتون مانند اوراکل را نیز در application.properties قرار دهید.در نمونه کد زیر، برای تست پروژه به security نیاز دارد که در  application.propertiesمقادیر user-pass را قرار داده ام.سورس پروژه</description>
                <category>zahratgz</category>
                <author>zahratgz</author>
                <pubDate>Wed, 12 Feb 2020 20:06:36 +0330</pubDate>
            </item>
                    <item>
                <title>استفاده از Projections در  Spring Data JPA</title>
                <link>https://virgool.io/@zaratgz/%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-projections-%D8%AF%D8%B1-spring-data-jpa-vq5fieqeyogh</link>
                <description>دونوع پیاده سازی Interface-base  و class-base دارد، که در اینجا ما به نوع interface-base می پردازیم. یه شمای کلی به صورت زیر:داستان چیه:یک جدول داریم به اسم درخواست ها، درون این جدول کلی فیلد و روابط با جداول دیگر است. زمانی که برای واکشی اطلاعات از دیتابیس از Jpa استفاده می کنیم ، به صورت معمول کلاس entity رو به عنوان Object برگشتی در اینترفیس repository (مانند زیر) قرار می دیم.@Repository 
public interface PsmRequestRepository       
  extends    MiddleRepository&lt;PsmRequestChangesEnt, Long&gt; { 
PsmRequestChangesEnt  findByShebaName(String shebaName);
  }در نتیجه بعد از فراخوانی این متد، تمام فیلد ها و روابطی که در entity تعریف کردیم مقداردهی و برگردانده می شود.ولی بعضی وقتی ها لازم نیست که در زمان fetch کردن داده ها، کل فیلد های entity و تمام روابطی که ساختیم رو برگردونیم و ما بر اساس نیازمون (سرویس هامون) تنها یک سری فیلد ها را می خواهیم. برای مثال در بالا بر اساس فیلد ReqType فقط برخی از فیلد ها پر می شود ، گاهی فقط فیلد های مربوط به آدرس(MainStreet,SubStreet ,...)، گاهی فیلدهای مربوط به شماره و گاهی هم فیلدهای مربوط به  اطلاعات صنف و صنف تکمیلی(GILD_POM_GULD_ID وGILD_POM_GLGR_ID کلید خارجی به دو جدول دیگر) در این زمان یکی از روش ها استفاده از Interface projections.فیلد TERM_POM_TRMN_ID یک کلید خارجی به جدول ترمینال است که پدر جدول درخواست ها می باشد با مقادیر شناسه- کد و .... . یک interface پدر تعریف کردم که اطلاعات پدر رو داخلش گذاشتم: ویژگی اینترفیس باید چی باشه؟ هر فیلدی را که می خواهیم jpa برای ما از دیتابیس برگردونه رو داخل اینترفیس قرار می دهیم ولی متد های getter آن ها را.(دقیقا باید هم نام متغییر های تعریف شده در کلاس entity اصلی باشد تا به درستی توسط Jpa پر شود)public interface RequestData {
    Long getId();
    Long getTerminalNo();
    String getStoreName();
}یه اینترفیس دیگه ام ایجاد کردم برای حالتی که نیاز به برگردوندن فیلد های آدرس از جدول درخواست ها دارم:این ایترفیس فیلد های اینترفیس پدر رو نیز بر می گردونه چون از اینترفیس پدر extends کردیم:public interface AddressOnly 
        extends RequestData{
    
    String getPreNum();
    String getPhone();
    String getMainStreet();
    String getSubStreet();
    String getAlley();
    String getPostCode();
    String getFloorAndUnit();
    String getPlaque();
    String getDesc();
//------------------------------------------------------------------------------
 @Value(&amp;quot#{target.preNum+ &#039; &#039; + target.phone}&amp;quot) 
String getPhoneNumber() ;
//یا :
default String getPhoneNumber() {
    return getPreNum().concat(getPhone());
}
}می توانیم از ترکیب متغییر های مختلف نیز متغییر جدید ایجاد کنیم که دو مدلش در بالا ذکر شده است. (getPhoneNumber وقتی پر می شود مقدار فیلد های پیش شماره و شماره را به هم وصل می کند و فیلد جدید شماره تلفن را برای ما ایجاد می کند، برای مواردی چون نام و نام خانوادگی که اطلاعات رو در دو ستون جدا ذخیره می کنید خیلی به درد می خوره)نمونه فراخوانی خروجی اینترفیس در repository مربوطه :-من در این مورد محدود کردم که تنها اینترفیسی ها که از جنس RequestData هستند را قبول کند @Repository
public interface PsmRequestRepository
        extends    MiddleRepository&lt;PsmRequestChangesEnt, Long&gt; {

&lt;RW extends RequestData&gt; RW  findByStatusAndShebaName(StatusEnum status, String shebaName, Class&lt;RW&gt; type);
...
}
نحوه ی فراخوانی متد :public AddressOnly findByStatusAndShebaName( StatusEnum status,String shebaName) throws FrameworkException {
    return reqService.findByStatusAndShebaName(status, shebaName, AddressOnly.class);
}نمایش خروجی :ورودی وضعیت و شماره شبا، خروجی تنها فیلد های آدرس مربوط به آن درخواست ، نه کل فیلد ها :@GetMapping(value = &amp;quot/req/{shebaName}&amp;quot,
        produces = &amp;quotapplication/json;charset=UTF-8&amp;quot)
public AddressOnly reqLoadByShebaName(@PathVariable Long shebaName)
        throws FrameworkException {
    return addressService.findByStatusAndShebaName(code, StatusEnum.INSTALLED);
}نکته: حتی می تونیم در یک اینترفیس یک اینترفیس دیگه هم قرار دهیم. در زیر متغیرPsmGuildEnt ،یک Object از کلاس صنف است که ما فقط می خواهیم در زمان fetch کردن داده ها، اطلاعات فیلد های کد و عنوان صنف را بر گرداند.public interface StoreName_GuildOnly extends RequestData {

    GuildOnly getPsmGuildEnt();

    interface GuildOnly{
         Long getCode();
        String getTitle();
    }
}</description>
                <category>zahratgz</category>
                <author>zahratgz</author>
                <pubDate>Tue, 28 Jan 2020 09:38:30 +0330</pubDate>
            </item>
                    <item>
                <title>ایجاد فایل های bpmn در Inteliji</title>
                <link>https://virgool.io/@zaratgz/%D8%A7%DB%8C%D8%AC%D8%A7%D8%AF-%D9%81%D8%A7%DB%8C%D9%84-%D9%87%D8%A7%DB%8C-bpmn-%D8%AF%D8%B1-inteliji-mkzy8lx3rq0h</link>
                <description>برای این که  Inteliji فایل های bpmn را بشناسد و بتوانیم با آن ها کار کنیم، نیاز است که pluginهای ، مربوط به BPM را نصب کنیم.actiBPM - Yaoqiang BPMN Editor - JBoss jBPMدر صورت نصب پلاگین های بالا برای ایجاد فایل به راحتی بر روی پوشه ای که می خواهید فایل ایجاد شود کلیک راست کنید و BPMN File را کلیک کنید. با فعال بودن پلاگین ها فایل ها به صورت زیر نمایش داده می شوند .
به راحتی در بخش editor می توانید موارد مورد نیاز را مقدار دهی کنید.اما اگر پلاگین ها را نصب نکند، باز هم می توانید فایل BPMN را ایجاد نمایید .ولی ظاهر آن کمی متفاوت است:در صورت عدم نصب پلاگین، بار اول برای ایجاد فایل هایی با پسوند .bpmn صفحه ی زیر برای شما نمایش داده می شود: با انتخاب xml بیان می کنید که این فایل نیز جز دسته ی فایل های xml است.در صورتی که به اشتباه این صفحه را بستید یا گزینه ی open matching ... را کلیک  کردید می توانید در بخش setting نیز نوع type را اضافه  نمایید . در زیر مجموعه ی xml با دکمه ی به علاوه فرمت جدید را اضافه کنید:برای نمایش دیاگرام ها نیز  بر روی فایل کلیک راست کنید و show BPMN Designer را کلیلک کنید.</description>
                <category>zahratgz</category>
                <author>zahratgz</author>
                <pubDate>Tue, 21 Jan 2020 15:05:04 +0330</pubDate>
            </item>
                    <item>
                <title>کار با Spring boot و drools -بخش2</title>
                <link>https://virgool.io/@zaratgz/%DA%A9%D8%A7%D8%B1-%D8%A8%D8%A7-spring-boot-%D9%88-drools-%D8%A8%D8%AE%D8%B42-iuuonkv4wrx6</link>
                <description>کار با Spring boot و drools -بخش 1ابتدا چند نمونه از شرط هایی که می توانیم در بخش when فایل های قوانین قرار دهیم را با هم می بینیم. شرط های مختلف را با کاما از هم جدا می کنیم. در شرط ها امکان اضافه نمودن fact های مختلف نیز هست.هر زمان که شی CartItem ساخته شد و مقدار فیلد cartStatus (که یک enum است) برابر PROCESSED بود و مقدار فیلد qty در شی  CartItem نیز از مقدار فیلد availableQty در fact محصول( product) بیشتر بود وارد بخش then شود .when
   $cartItem : CartItem(cartStatus != CartStatus.PROCESSED, qty &gt; product.getAvailableQty())
then..امکان فراخوانی متدی از یک fact که خروجی اش مقدار true/false باشد نیز مانند بالا وجود دارد.when
   $cartItem : CartItem(cartStatus != CartStatus.PROCESSED, 
   product.isRequiresRegisteration(),  !cart.customer.isRegistered(product))
 then...  

when  
   $cartItem : CartItem(cartStatus != CartStatus.PROCESSED, cart.customer.isNew()) 
then ...امکان بررسی مقدار type های string با == و pattern.when
$cartItem : CartItem(cartStatus != CartStatus.PROCESSED, cart.customer.coupon == &#039;DISC01&#039;)
then...

when    
   Product(code != 0 &amp;&amp; code not matches &amp;quot^[0-9]{6}$&amp;quot) 
then..زمانیکه شرطی دارید که ممکن است در تعداد زیادی قانون لحاظ شود،کافی ایست یک قانون تعریف کنید و در سایر قوانین از آن استفاده نمایید.در مثال زیر ما تمام افرادی که در دپارتمان it قرار دارند و مدیر هستند را می خواهیم. ابتدا یک کلاس ITManager تعریف می کنیم که یک فیلد از جنس Employee دارد.public class ITManager {private Employee emp;public ITManager(Employee emp){this.emp=emp;}
//getter and setter
}تعریف قانون: درصورتی که کارمند مدیر بود و در بخش it نیز قرار داشت به Rule Engine  اضافه می کنیم. rule &amp;quotIT Manager Inference&amp;quot
when    $dept: Department(name==&amp;quotIT&amp;quot);    $emp: Employee(dept == $dept,manager==true);then
   insert(new ITManager($emp));
endنحوه ی استفاده از قانون تعریف شده در سایر قوانین:rule &amp;quotgive Manager Laptop&amp;quot
when
   $emp: Employee();
   $itManager: ITManager(emp == $emp);
then
   $emp.setMessage(&amp;quotGive Laptop&amp;quot);
   System.out.println($emp.getName()+ &amp;quot: &amp;quot+$emp.getDept().getName()+ 
   &amp;quot:&amp;quot+$emp.getMessage());
endاگر شرط ITManager درست باشد وارد then شده و متن مورد نظر را چاپ می کند.نکته:در فایل قوانین نیز مثل کلاس های جاوایی امکان اضافه نمودن comment را نیز دارید.comment های یک خطی با #  یا  // ، و چند خطی نیز با /*..*/.جدول تصمیم گیری:Decision Tablesاکسل بالا شامل بخش های مختلف زیر است.بخش RuleSet :مسیری در پروژه است که فایل اکسل قوانین در آن قرار دارد.باید اولین مقدار در فایل اکسل باشد.بخش Sequential:مقدار true,false را می گیرد اگر True  باشد قوانین را بر اساس بالاترین اولویت تا پایین اجرا میکند. اجباری نمی باشد.بخش Import: تمام جاوا کلاس های مورد نیاز و با کاما از هم جدا می شوند.بخشVariables: متغیر های global در این بخش تعریف می شود.بخشFunctions: می تواند یک یا چند Functions بر اساس بیزینس قوانین داشته باشد.بخش Notes: توضیح کلی در مورد هدف و کار اکسلستون های  CONDITION و  ACTION : دراولین ردیف این ستون یک reference به  factهامون قرار می دهیم و در ردیف های بعدی با کمک آن reference به value هاشون(متغییرهاشون) دسترسی داریم. در اکسل بالا اگر سن مشتری برابر 1 بود میزان تخفیف 15 درصد در نظر گرفته می شود، در غیر این صورت 25 درصد.مراحل ایجاد پروژه در Springboot:وابستگی های مورد نیاز برای ساخت پروژه  را در pom فایل اضافه می کنیم:(در صورتیکه می خواهید از جداول تصمیم گیری استفاده نمایید drools-decisiontables را اضافه نمایید.)&lt;dependency&gt;
    &lt;groupId&gt;org.kie&lt;/groupId&gt;
    &lt;artifactId&gt;kie-ci&lt;/artifactId&gt;
    &lt;version&gt;7.31.0.Final&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
    &lt;groupId&gt;org.drools&lt;/groupId&gt;
    &lt;artifactId&gt;drools-decisiontables&lt;/artifactId&gt;
    &lt;version&gt;7.1.0.Beta1&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
    &lt;groupId&gt;org.drools&lt;/groupId&gt;
    &lt;artifactId&gt;drools-core&lt;/artifactId&gt;
    &lt;version&gt;7.31.0.Final&lt;/version&gt;
&lt;/dependency&gt;کلاس محصول به همراه enum مورد نیاز:public class Product {

    private String type;
    private int code;
    private int discount;
//getter/setter/ constructor
......
}
public enum  TypeEnum {
    DIAMOND(&amp;quotdiamond&amp;quot), GOLD(&amp;quotgold&amp;quot);
.....
}خواندن فایل های قوانین که مسیرش را در زیر مشخص کرده ایم و ساخت containerایجاد session  مورد نظر و فعال(fire) کردن تمام قوانین موجود در container.دو نوع session  وجود دارد: Stateless Sessionو Stateful Session که متانسب با نیاز و نوع پروژه از آن ها استفاده می کنیم . در صورت استفاده از Stateful Session باید حتما متد dispose را صدا کنیم تا فضای گرفته شده را آزاد کند مانند زیر:تست پروژه: با ایجاد یک کلاس کنترلر، بر اساس ورودی ها امکان اجرا شدن حداقل یک قانون وجود دارد.فایل قانون در زیر مسیر :src/main/resources/rules(حتی امکان throw کردن خطا را نیز داریم)package rules

import com.isc.mcb.model.Product
import com.isc.mcb.model.TypeEnum
import com.isc.mcb.NumberFormatException

rule &amp;quotOffer for Diamond&amp;quot
   when
      $productObject: Product(TypeEnum.DIAMOND.type.equals(type))
   then
      $productObject.setDiscount(15);
   end

rule &amp;quotOffer for Gold&amp;quot
   when
      $productObject: Product(TypeEnum.GOLD.type.equals(type))
   then
      $productObject.setDiscount(25);
   end

rule &amp;quotCodeValidation&amp;quot
   when
      Product(code != 0 &amp;&amp; code not matches &amp;quot^[0-9]{6}$&amp;quot)
   then
      throw new NumberFormatException(&amp;quotInvalid Product Code. Must be a valid 6 digits number.&amp;quot);
endبر اساس این که fact ها نوعش چی باشد، درصد آن مشخص می شود و اگر طول کد محصول بیشتر از 6 رقم باشد خطا برگردانده می شود.نمونه کدبرای دیدن مثال های بیشتر در فایل قوانین نیز  به آدرس example سر بزنید.</description>
                <category>zahratgz</category>
                <author>zahratgz</author>
                <pubDate>Sun, 19 Jan 2020 14:31:33 +0330</pubDate>
            </item>
                    <item>
                <title>کار با Spring boot و drools -بخش1</title>
                <link>https://virgool.io/@zaratgz/%DA%A9%D8%A7%D8%B1-%D8%A8%D8%A7-spring-boot-%D9%88-drools-%D8%A8%D8%AE%D8%B41-cq7vpifxjdqy</link>
                <description>یک Business Rule Management System یا به اختصار BRMS است. فریم ورک open source و جاوایی.این فریم ورک بیشتر زمانی استفاده می شود که مسئله، پروسه و منطق های خیلی پیچیده و پویا داشته باشید و گاهی در زمان اجرا برنامه ها بخواهید منطق ها و قوانین را تغییر دهید، بدون این که مجبور باشید کدها را تغییر دهید. حتی این تغییر می توتند توسط افراد غیر برنامه نویس هم انجام شود.(بهترین بخشش همینه) در واقع با تفکیک منطق برنامه از داده‌ها و سایر قسمت‌های پروژه کار می کند.داخل خودش یه Rule Engine (موتورهای قوانین کسب‌وکار) دارد که یکی از وظایفش، مدیریت و نظارت بر روی fact هاست. بهتره از Drools زمانی استفاده بشود که قوانین مدام در حال تغییر هستند و if-then زیادی در پروژه ها وجود دارد. ما تو Rule Engine می گویم که چه کاری رو انجام بده (What to Do) نه این که چه طوری انجامش بده (How to do it)این Rule Engine به دو صورت عمل می کند:روش استدلال پیش رو Forward Chaining ،که از داده ها شروع می کند و به نتیجه می رسد. یعنی با درنظر گرفتن داده های مربوط به موضوع مورد سوال، از if(اگر) ها شروع کرده و به نتایج یاthen(پس) های مناسب می رسد. به عبارت دیگر در Forward Chaining از مقدمات به نتایج می رسیم، روش دوم Backward Chaining است که از نتایج شروع می کند و برای نتایج مشخص به دنبال شرایط اولیه مناسب می گردد. به عبارت دیگر نقطه شروع then(پس) ها هستند و از آن ها به if(اگر) ها دست می یابد. روش اول استنتاج را روش مبتنی بر داده و روش دوم را روش مبتنی بر هدف می گویند.کلا برای کار با drools  دو مرحله رو باید طی کنیم:1. تعریف قوانین که هم می تواند داخل فایلی با پسوند  .drl بر اساس syntax تعریف شده اش باشد(یکم دانستن مفاهیم برنامه نویسی لازمه ) و یا داخل فایل اکسل .xls با tempalte مخصوصش، که اصطلاحا decision table یا جدول تصمیم گیری می گویند.(نیاز به دانش برنامه نویسی رو به صفر می رسونه و هر فردی با این کمک جدول تصمیم گیری می تونه به راحتی قوانین رو اضافه یا تغییر بده.)2. ایجاد فضای کاری و ساخت session مورد نظر و بعد اضافه کردن fact ها( که همون object های جاوا)و اجرای تمام قوانین.معادل مفاهیمکلا در صورتی که شرط برقرار بود، چه کاری انجام شود.When    
    &lt;Condition is true&gt; 
Then  
     &lt;Take desired Action&gt;بررسی فایل drl  :package rules;

import com.isc.mcb.model.Product;
import com.isc.mcb.model.TypeEnum;
import com.isc.mcb.NumberFormatException;

global String hName;
function String fTest(){....}

rule &amp;quotvalidate holiday&amp;quot
dialect &amp;quotmvel&amp;quot
salience 5
when
      $h1 : Holiday( month == &amp;quotjuly&amp;quot )
then
      System.out.println($h1.name + &amp;quot:&amp;quot + $h1.month);
end
لغتPackage :تمام فایل های قوانین باید با package شروع شوند.(مسیر ذخیره شده فایل در پروژه است که باید در زیر پوشه resource باشد) قوانین پکیج ها در جاوا، برای rules ها (فای های قوانین)نیز صادق است. لغت Import : تمام Object های جاوایی که می خواهیم در Rules داشته باشیم را باید import کنیم. به این Object ها در فایل قوانین، fact گفته می شود. Fact/objectها باید قوانین pojo کلاس ها را داشته باشند.(شامل متد های setter/getter )لغت globals : در فایل های قوانین می توانیم متغیرهای globals نیز تعریف کنیم تا در همه ی قوانین تعریف شده در فایل، قابل دسترس باشد. این متغیر ها اجباری نیستند.(در فایل قوانین بیش از یک قانون نیز می توان تعریف کرد)عبارت functions : در صورتی که عملیاتی داریم که ممکن است در بیشتر قوانین اجرا شود بهتر است یک functions تعریف کنیم و در قوانین مختلف فراخوانی ایش کنیم.این بخش نیز اجباری نمی باشد.عبارت Rule Definition:شامل نام قانون، شرط و نتیجه آن می باشد. نام دیگر بخش when  ، را  LHS یا(left hand side) و بخش thenنیز RHSیا (right hand side)  می گویند.در بخش then می توان از کلمات update و insert و retract نیز استفاده کرد. update (تغییر مقدار fact، باعث می شود rules engine از تغییر fact اگاه شود و امکان دارد سایر قوانینی که قبلا اجرا شده اند را نیز دوباره اجرا کند و باعث یه حلقه ی بی نهایت شود چون خود قانون update نیز دوباره اجرا می شود. بنابراین از no-loop در این قانون استفاده می شود تا جلوی حلقه ی بی نهایت را بگیرد. )، Insert (ایجاد یک factجدید در sessionجاری Rule Engine ) و Retract  (اگر شرط خاصی در قانون صادق باشد و شما نخواهید بر روی fact جاری کار خاصی انجام دهید می توانید fact رو از Rule Engine پس بگیرید (retract) )لغت Dialect: تنها دو مقدار java و mvel را قبول می کند و به صورت پیش فرض بر روی جاوا قرار دارد. نوشتن کدهای جاوایی تنها در بخش then امکان پذیر است. امکان دسترسی به متد های set,get نیز به دلیل وجود همین لغت است.لغت Salience(اولویت بندی): ممکن است در فایل قوانین چندتا شرط قانون برای یکfact معتبر باشد در این حالت قانون ها به چه ترتیبی اجرا می شوند؟ در حالت کلی قوانین به صورت خودسرانه اجرا می شوند و هیچ ترتیبی ندارند، اما اگر ما بخواهیم بر اساس ترتیب خاصی اجرا شوند باید از Salience استفاده کنیم. Salience اعداد مثبت و منفی می گیرد. درواقع اعداد اولویت ها هستند بالاترین شماره یعنی بالاترین اولویت. به صورت پیش فرض مقدار Salience صفر است. در صورتی که چند قانون مقدار Salience یکسانی داشته باشند تنها می توانیم بگوییم باهم اجرا می شوند ولی ترتیب آنها مشخص نیست .تعریف متغیر: بهتر است در زمان تعریف متغیر از $ استفاده کنیم. اجباری وجود ندارد ولی باعث تمایز بین متغییر های کلاس جاوا و متغیر های قوانین می شود، در واقع خوانایی رو بالاتر می برد.عبارت activation-group(گروه بندی):جزء لغت های ذخیره شده فایل قوانین است و می تواند شامل یک قانون یا چند قانون باشد. قوانینی که در داخل گروه activation قرار دارند شبیه &quot;if..else if..else&quot; در زبان جاوا هستند بنابراین تنها یکی از این قوانین اجرا خواهد شد.(بالاتریت اولویت یا Salience اجرا می شود)در این پست به بررسی مفاهیم ، syntax و لغات رزرو شده در فایل های قوانین .drl پرداختیم. در پست بعدی ساختار جدول تصمیم گیری را بررسی می کنیم و با spring boot یک مثال ساده را پیاده سازی می کنیم.منابع هم از کلی سایت های مختلف(چه فارسی چه انگلیسی) بخش-2</description>
                <category>zahratgz</category>
                <author>zahratgz</author>
                <pubDate>Wed, 08 Jan 2020 21:42:01 +0330</pubDate>
            </item>
                    <item>
                <title>ایجاد یک Shortcut جدید در Adf</title>
                <link>https://virgool.io/@zaratgz/%D8%A7%DB%8C%D8%AC%D8%A7%D8%AF-%DB%8C%DA%A9-shortcut-%D8%AC%D8%AF%DB%8C%D8%AF-%D8%AF%D8%B1-adf-sjr32i2bdxqg</link>
                <description> در زمان نوشتن یک برنامه جاوایی کد هایی وجود دارد که بیش از اندازه تکرار می شود.مثلfor, while, try و ..  که برای چنین کد هایی خود  adf و بیشتر idea های برنامه نویسی به صورت پیش فرض Shortcut های مخصوص به خودشون را دارند و اگر شما نیز کد هایی دارید که به دفعات در برنامه یا برنامه های شما قراره تکرار شود می توانید با روش زیر آن ها را به Shortcut های adf اضافه کنید.به مسیر Tools&gt;Preference برید و از زیر منوی Code Editorبر روی Code Templates کلیک کنید تا صفحه ی زیر باز شود.در این بخش بیشتر دستورات پایه ای مورد نیاز در بخش های مختلف adf مثل صفحات Jsf,Jsp و ... وجود دارد. شما می توانید در بخش جستجو، دستورات مورد نظر را پیدا کنید. توضیحات دستور، کلید میان بر،کد دستور، متغییر های مورد نیاز و ..را ببینید.برای دسترسی به این کد ها، تنها کافی است Shortcutدستور مورد نظر را در صفحه ی خود بنویسید سپس با  Ctrl+Enter به کد دستور دسترسی داشته باشید.حالا بریم سراغ اضافه کردن دستور جدید، روی دکمه به علاوه سبز رنگ کلیک کنید تا یه سطر جدید تو Code Templates اضافه شه.می خوام برای ایجاد تاریخ سیستم یه Shortcut ایجاد کنم.برای تعریف متغییر حتما قبل و بعد از اسم متغییر از علامت $ استفاده کنید.در بخش import نیز کلاسی که ممکنه بعد از اضافه شدن کد شما نیاز باشه import بشه رو تعریف کنید.کار تموم شد. حالا در هر جایی از کلاس های جاوایی تون که به این کد نیاز داردی فقط کافی  shortcut مربوطه را وارد کنید سپس با Ctrl+Enter به کل کد، دسترسی داشته باشید.(shortcut من لغت date ه)</description>
                <category>zahratgz</category>
                <author>zahratgz</author>
                <pubDate>Mon, 06 Jan 2020 19:38:16 +0330</pubDate>
            </item>
                    <item>
                <title>ایجاد annotation سفارشی در Aop</title>
                <link>https://virgool.io/@zaratgz/%D8%A7%DB%8C%D8%AC%D8%A7%D8%AF-annotation-%D8%B3%D9%81%D8%A7%D8%B1%D8%B4%DB%8C-%D8%AF%D8%B1-aop-zffotneq4imy</link>
                <description>گاهی لازم می شه داخل پروژه بعد یا قبل از انجام یک سری متد ها، عملیات خاصی مانند Logگیری یا احراز هویت انجام شود که مفهوم (aop (aspect-oriented programming به میان می آید.با فرض این که مفاهیم اولیه aop و cross-cutting concern را می دانیم ، می خواهیم یه annotation سفارشی برای پروژه ی خودمون بسازیم و بگیم هر متدی که بالا سر خودش این annotation را  صدا کرده یکسری عملیات خاص مثل log را انجام دهد. این کار از تکرار کد های شبیه به هم در ماژول های مختلف کم می کنه هم چنین در صورت تغییر در این بخش لازم نیست کل کد ها رو تغییر دهیم.اول از همه باید وابستگی های مورد نظر را به پروژه اضافه کنیم.  &lt;parent&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
         &lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;
         &lt;version&gt;1.5.2.RELEASE&lt;/version&gt;
    &lt;/parent&gt;&lt;dependencies&gt;    &lt;dependency&gt;
       &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
       &lt;artifactId&gt;spring-boot-starter-aop&lt;/artifactId&gt;
    &lt;/dependency&gt;&lt;/dependencies&gt;کافیه یه annotation مانند زیر بسازیم .@target: تعیین می کنه که annotation تعریف شده ما در کجا ها معتبر و مناسب است. ( در مثال زیر در صورتی که بالاسر کلاس یا متغیر ها استفاده شود، کامپایلر خطا می گیرد )@Retention هم تعیین می کنه که annotation تعریف شده از کجا برای jvm قابل دسترس باشد.@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SystemAspect {}حالا که annotation رو ساختیم کافیه یه کلاس aspect ایجاد کنیم که عملیاتی که قرار است هر دفعه اعمال شود را داخل آن پیاده سازی کنیم. @Aspect
@Component
public class ExampleAspect {

@After(&amp;quot@annotation(SystemAspect)&amp;quot) 
public void logExecutionTime(JoinPoint joinPoint) 
 throws Throwable { 
 ....
       }

}بر اساس پیاده سازی بالا، متد logExecutionTime، بعد از اجرای متد هایی که از@SystemAspect استفاده کرده اند فراخوانی می شود .ما تو بدنه ی این متد عملیاتی چون ذخیره در db یا ... را می توانیم انجام دهیم و مقدار متغییر  joinPoint نیز  یکسری اطلاعات مانند نام متد، نام کلاس و ...که باعث شده این aspect  اجرا شود را در اختیار ما می گذارد .@After(&amp;quot@annotation(SystemAspect)&amp;quot)
public void logExecutionTime(JoinPoint joinPoint)
        throws Throwable {

    MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
    String actualClassName = methodSignature.getDeclaringTypeName();
    String methodName = methodSignature.getName();
    String returnTypeName =methodSignature .getReturnType().getName();
    Object[] paramValues=joinPoint.getArgs();
}
مثال زیر نحوه ی استفاده از annoation است. اگر همه چیز درست پیش رفته باشه یه آیکون تقریبا صورتی رنگ در کنار متد قرار می گیرد که اگر بر روی این آیکون بزنید شما رو به متد مربوطه که قرار است بعد از این متد اجرا شود می برد.(متد logExecutionTime بالا)در  annotation که بالا تعریف شد، از هیچ value استفاده نشده و مثل یه marker عمل می کنه، ولی  ما میتونیم value های متفاوتی تعریف کنیم و در زمان log گیری از اون ها استفاده کنیم .@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SystemAspect {
    boolean localOnly() default false;
    boolean admin() default true;
}هم می تونیم در بالاسر متدی که این annotation رو صدا کردیم مقادیر admin و localOnly را مقدار دهی کنیم یا از همان مقادیر پیش فرض شان استفاده کنیم.@SystemAspect(admin = false)
public void testAspect(){...}نحوه ی گرفتن مقدار این annotation ها در کلاس aspect هم مانند زیر است.@After(&amp;quot@annotation(SystemAspect)&amp;quot)
 public void logExecutionTime(JoinPoint joinPoint)   
       throws Throwable {   
          MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();     
          SystemAspect annotation = methodSignature.getMethod()
          .getAnnotation(SystemAspect.class);

        if (annotation.admin()) {
               ......   
                    }
       }منبع:https://niels.nu/blog/2017/spring-boot-aop.htmlhttps://www.baeldung.com/spring-aop-annotation</description>
                <category>zahratgz</category>
                <author>zahratgz</author>
                <pubDate>Sat, 04 Jan 2020 14:27:38 +0330</pubDate>
            </item>
                    <item>
                <title>حذف فایل های به اشتباه ذخیره شده در گیت</title>
                <link>https://virgool.io/@zaratgz/%D8%AD%D8%B0%D9%81-%D9%81%D8%A7%DB%8C%D9%84-%D9%87%D8%A7%DB%8C-%D8%A8%D9%87-%D8%A7%D8%B4%D8%AA%D8%A8%D8%A7%D9%87-%D8%B0%D8%AE%DB%8C%D8%B1%D9%87-%D8%B4%D8%AF%D9%87-%D8%AF%D8%B1-%DA%AF%DB%8C%D8%AA-ixgml6wpe9tp</link>
                <description>ممکنه برای هر کسی پیش بیاد که به اشتباه فایلی را داخل گیت add کرده باشد، مانند فایل هایی که تو پوشه target ساخته می شود و از اون تاریخ به بعد، حتی با تغییر فایل gitignore. نیز هنوزم گیت تغییرات اون فایل را دنبال می کند. برای این که دیگه تغییرات سمت repository گیت نرود از دو تا دستور زیر استفاده می کنید.ساختار کلی دستور برای حذف فایلgit rm --cached [filenames]برای مثال:1. پاک کردن یک فایل :git rm --cached bin/Foo.class2.حذف تمام فایل های داخل یک پوشه :git rm --cached target/\*از دستور git status برای مشاهده وضعیت جاری پروژه استفاده می کنیم.بعد فایلی (idea/misc.xml)که به اشتباه قبلا فرستاده اید به گیت را با دستور بالا وارد کنید و enter رو بزنید. دستور commit و یه متن مناسب فایل از repository گیت حذف شد و از این به بعد دیگه توسط گیت trace نمی شه.</description>
                <category>zahratgz</category>
                <author>zahratgz</author>
                <pubDate>Mon, 30 Dec 2019 16:27:35 +0330</pubDate>
            </item>
                    <item>
                <title>کار با Spring boot و Redis -بخش 2</title>
                <link>https://virgool.io/@zaratgz/%DA%A9%D8%A7%D8%B1-%D8%A8%D8%A7-spring-boot-%D9%88-redis-%D8%A8%D8%AE%D8%B4-2-kfce74kovs5e</link>
                <description>کار با Spring boot و Redis-بخش 1در ابتدا به pom فایل پروژه dependency های زیر را اضافه کنید.&lt;dependencies&gt;
	&lt;dependency&gt;
		&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
		&lt;artifactId&gt;spring-boot-starter-data-redis&lt;/artifactId&gt;
	&lt;/dependency&gt;
	&lt;dependency&gt;
		&lt;groupId&gt;redis.clients&lt;/groupId&gt;
		&lt;artifactId&gt;jedis&lt;/artifactId&gt;
	&lt;/dependency&gt;
	&lt;dependency&gt;
		&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
		&lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
	&lt;/dependency&gt;
       &lt;dependency&gt;
               &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
               &lt;artifactId&gt;spring-boot-starter-cache&lt;/artifactId&gt;
       &lt;/dependency&gt;
       &lt;dependency&gt;
             &lt;groupId&gt;redis.clients&lt;/groupId&gt;
             &lt;artifactId&gt;jedis&lt;/artifactId&gt;
             &lt;version&gt;2.9.0&lt;/version&gt;
       &lt;/dependency&gt;
&lt;/dependencies&gt;یک کلاس config باید ایجاد کنیم و دوتا bean به نام های  JedisConnectionFactory  و  RedisTemplate را به spring معرفی کنیم.@Configuration
public class BeanConfig {

 @Bean
  RedisConnectionFactory connectionFactory() {
    RedisStandaloneConfiguration redisStandaloneConfiguration =
            new RedisStandaloneConfiguration(&amp;quotlocalhost&amp;quot, 6379);

   return new JedisConnectionFactory(redisStandaloneConfiguration);
}
    @Bean
public RedisTemplate&lt;String, Object&gt; redisTemplate() {
    RedisTemplate&lt;String, Object&gt; redisTemplate = new RedisTemplate&lt;&gt;();
    redisTemplate.setConnectionFactory(connectionFactory());
    redisTemplate.setKeySerializer(new StringRedisSerializer());
    redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    return redisTemplate;
}
}می تونید اطلاعات مثل پورت و ip و .. را نیز از طریق فایل application.properties نیز به پروژه اضافه کنید.spring.redis.host=127.0.0.1 
spring.redis.password=password
spring.redis.port=6379حتی اطلاعاتی چون connection pool مانند زیر :spring.cache.type=redisspring.redis.timeout=60000
spring.redis.jedis.pool.max-idle=100
spring.redis.jedis.pool.min-idle=2
spring.redis.jedis.pool.max-active=200بریم سر وقت عملیات crud  با restTemplate بدون ذخیره سازی در دیتابیس:عملیات crud رو بر روی objectای به نام Account با اطلاعات زیر اعمال می کنیم، حتما باید Serializable  را implements کرده باشید.public class Account
        implements Serializable {

    private Long id;
    private Double balance;
    
    public Account() {  }
    
    public Account(Long id, Double balance) {
        this.id = id;
        this.balance = balance;
    }

    public Long getId() {  return id;   }

    public void setId(Long id) {   this.id = id;    }

    public Double getBalance() {   return balance;   }

    public void setBalance(Double balance) { this.balance = balance;   }

    @Override
    public String toString() {
        return &amp;quotAccount{&amp;quot +
                &amp;quotid=&amp;quot + id +
                &amp;quot, balance=&amp;quot + balance +
                &#039;}&#039;;
    }
}سپس یک کلاس repository می سازیم و دو تا object های RedisTemplate و HashOperations را از طریق سازندش مقدار دهی می کنیم و تمام متد های مورد نیاز برای عملیات crud را ایجاد می کنیم.@Repositorypublic class RedisAccountRepository { private static final String KEY = &quot;ACCOUNT&quot;; private HashOperations hashOperations; private RedisTemplate&lt;String, Object&gt; redisTemplate; public RedisAccountRepository(RedisTemplate redisTemplate){ this.redisTemplate = redisTemplate; this.hashOperations = this.redisTemplate.opsForHash();    } public void save(Account account){ hashOperations.put(KEY, account.getId().toString(), account); }  public void update(Account account){        save(account);    } public void delete(String id){ hashOperations.delete(KEY, id);    } public Account findById(String id){ return (Account) hashOperations.get(KEY, id);    } public List findAll(){ return hashOperations.values(KEY); } }حتما key که تعریف می کنید static  و final باشد.هر 3 متد ذخیره که با hashOperations انجام می شود (put , putIfAbsent , putAll)  نیاز به 3 متغیر ورودی دارند.void put(H key, HK hashKey, HV value);مقدار key باید یکتا باشد .برای ویرایش کافی است از همان شیوه ی ذخیره استفاده کنید چون در صورتی که در زمان ذخیره بر اساس key , hashkey رکورد را پیدا کند، مقدار value جدید را جایگزین قبلی می کند.در صورتی که نیاز باشد چند object را باهم از cache بخوانید می توانید از متد multiGet استفاده کنید:public Map&lt;String, List&lt;Account&gt;&gt; multiGetAccount(List&lt;String&gt; accountIds){
    
    Map&lt;String, List&lt;Account&gt;&gt; accountMap = new HashMap&lt;&gt;();
    List&lt;Object&gt; accounts = hashOperations.multiGet(KEY, accountIds);
    
    for (int i = 0; i &lt; accountIds.size(); i++) {
        accountMap.put(accountIds.get(i), (List&lt;Account&gt;) accounts.get(i));
    }
    return accountMap;
}
با یک کلاس کنترلر می تونید تمام موارد را باهم داشته باشد و یکجا تست کنید.@RestController
@RequestMapping(path = &amp;quot/redisRepository&amp;quot)
public class RedisRepositoryController {

    @Autowired
    private RedisAccountRepository repository;

    @GetMapping(value = &amp;quot/getAll&amp;quot,produces = MediaType.APPLICATION_JSON_VALUE)
    public List&lt;Account&gt; getAllAccount() {
      return repository.findAll();
    }

    @PostMapping(value = &amp;quot/save&amp;quot,consumes = MediaType.APPLICATION_JSON_VALUE,
            produces = MediaType.APPLICATION_JSON_VALUE)
    public void save(@RequestBody Account account) {
        repository.save(account);
    }

    @PostMapping(value = &amp;quot/update&amp;quot,consumes = MediaType.APPLICATION_JSON_VALUE,
            produces = MediaType.APPLICATION_JSON_VALUE)
    public void update(@RequestBody Account account) {
        repository.update(account);
    }

    @GetMapping( &amp;quot/deleteById/{id}&amp;quot)
    public void deleteById(@PathVariable String id) {
        repository.delete(id);
    }

    @GetMapping(value = &amp;quot/getById/{id}&amp;quot,produces = MediaType.APPLICATION_JSON_VALUE)
    public Account findById(@PathVariable String id) {
        return repository.findById(id);
    }
    
}
می تونید dependency های مربوط به سویگر و کلاس config اش رو هم به پروژه تون اضافه کنید و به کمک سویگر عملیات crud بر روی redis رو تست کنید.&lt;dependency&gt;
   &lt;groupId&gt;io.springfox&lt;/groupId&gt;
   &lt;artifactId&gt;springfox-swagger2&lt;/artifactId&gt;
   &lt;version&gt;2.9.2&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
   &lt;groupId&gt;io.springfox&lt;/groupId&gt;
   &lt;artifactId&gt;springfox-swagger-ui&lt;/artifactId&gt;
   &lt;version&gt;2.9.2&lt;/version&gt;
&lt;/dependency&gt;کلاس config مربوط به سویگر:@Configuration@EnableSwagger2public class SwaggerConfig {    @Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2)                .select()                .apis(RequestHandlerSelectors.any())                .paths(PathSelectors.any())                .build();    }}سویگر با آدرس زیر بر اساس پورتی که پروژه با آن بالا است قابل دسترس می باشد:http://localhost:8082/swagger-ui.htmدر صورتی که بخواهید اطلاعات را از دیتابیس بخوانید و عملیات cache را نیز انجام دهید، باید dependency زیر را به pom فایل اضافه کنید.&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-data-jpa&lt;/artifactId&gt;
&lt;/dependency&gt; از @Cacheable بالاسر متد می توان استفاده کرد. در صورتی که در cache بر اساس value , key مقدار وجود داشته باشد دیگر متد اجرا نمی شود و اطلاعات را از cache می خواند در غیر این صورت متد اجرا شده و اطلاعات از دیتابیس فراخوانی می شود. حتما باید @EnableCaching را در کنار @SpringBootApplication در بالاسر کلاس main خود قرار دهید.@Cacheable(value = &amp;quotAccountCache&amp;quot, key=&amp;quot#id&amp;quot)
public Account getAccount(String id) {
    System.out.println(&amp;quotIn getAccount cache Component..&amp;quot);
    return  accountRepository.findOne(Long.valueOf(id));
}از @CacheEvict در بالا سر متدهایی که بر روی اطلاعات تاثیر می ذارند مانند ویرایش - ذخیره و حذف استفاده کنید تا اخرین تغییرات را در سمت cache نیز داشته باشید.@Caching(evict = {
        @CacheEvict(value=&amp;quotAccountCache&amp;quot, allEntries=true)})
public void saveOrUpdate(Account account) {
    System.out.println(&amp;quotIn addAccount cache component..&amp;quot);
    redisAccountRepository.save(account);
}کدپروژه</description>
                <category>zahratgz</category>
                <author>zahratgz</author>
                <pubDate>Mon, 16 Dec 2019 15:17:30 +0330</pubDate>
            </item>
                    <item>
                <title>کار با Spring boot و Redis -بخش 1</title>
                <link>https://virgool.io/@zaratgz/%DA%A9%D8%A7%D8%B1-%D8%A8%D8%A7-spring-boot-%D9%88-redis-%D8%A8%D8%AE%D8%B4-1-tlrsbxvpfis2</link>
                <description>برای ایجاد یک پروژه crudساده در spring boot با redis، اول از همه باید redis را بر روی سیستم عامل نصب کنیم .راه های مختلفی برای نصب بر روی سیستم عامل های ویندوز و لینوکس وجود دارد که می تونید به سایت redis سری بزنید یا در صورتی که سیستم عامل ویندوز دارید می تونید از آدرس Redis-x64-3.2.100.zip فایل مربوط به آخرین نسخه را دانلود کنید و در مسیر دلخواه سیستم خودتان آن را Extract کنید.در مسیر دو پوشه با نام های  32bit و  64bit خواهید داشت که متناسب با نوع سیستم عامل تون وارد یکی از پوشه ها شوید.برای شروع کار سرور redis تنها کافی است بر روی فایل redis-server.exe کلیک کنید تا سرور بالا بیاد و منتظر اتصال client باشد.(اطلاعات مثل پورت و Ip نیز در پنجره سرور قابل مشاهده است - پورت پیش فرض 6379)برای تست این که سرور به درستی کار می کند فایل redis-cli.exe را به عنوان client اجرا کنید .بلافاصله بعد از این که فایل redis-cli.exe را اجرا کردید در پنجره ی سرور پیغام اتصال یک client چاپ می شود، که نشاندهنده ی اتصال درست بین سرور و کلاینت می باشد.حالا با دوتا command ساده عملیات ذخیره و بازیابی را که به صورت key-value می باشد در redis انجام می دیم.ذخیره داده با دستور:set &amp;quotname&amp;quot &amp;quottest redis&amp;quot
سپس Enter را بزنید تا پیغام ok چاپ شود.فراخوانی داده با دستور:redis 127.0.0.1:6379&gt; get &amp;quotname&amp;quot

&amp;quottest redis&amp;quotنصب Redis بر روی سیستم عمال ویندوز تموم شد .کار با Spring boot و Redis-بخش 2</description>
                <category>zahratgz</category>
                <author>zahratgz</author>
                <pubDate>Mon, 16 Dec 2019 14:13:12 +0330</pubDate>
            </item>
            </channel>
</rss>