หน้าเว็บ

วันอังคารที่ 4 มิถุนายน พ.ศ. 2556

การ config Maven (Maven Profile) เพื่อให้รองรับกับการพัฒนา Application ใน Environment ที่แตกต่างกัน : java

        ในบางครั้งการพัฒนา application เราอาจต้องใช้ environment ที่ไม่เหมือนกัน  เช่น   environment  development, environment test   หรือ environment production  ซึ่งแต่ละ environment ก็จะมีค่า config ที่แตกต่างกันออกไป  นั่นก็แสดงว่า  ในการ run application แต่ละที  เราก็ต้องมานั่งไล่แก้ config ทั้งหมดก่อน  ก่อนที่จะเอาไป run ในแต่ละ environment  ซึ่งถ้ามี config อยู่ซัก 10 20 ที่  ก็คงเหนื่อยกันน่าดูครับ  เพราะต้องแก้ไปแก้มาทุกครั้ง  อย่างนี้ไม่ดีแน่ครับ  เรามาหาตัวช่วยไล่แก้ config ให้เราโดยอัตโนมัติกันดีกว่า  นั่นก็คือ  การ config maven profile ครับ  ให้แบ่งออกเป็น profile development, profile test และ profile production  ซึ่งแต่ละ profile ก็จะมี config ของใครของมันอยู่  เวลา run application เราก็แค่เลือก ว่าจะใช้ profile ไหน  เราก็จะได้ config ของ profile นั้นมาใช้งานครับ  ทีนี้ก็สบายแมวไปอีกอย่างล่ะ ^___^  เรามาเริ่มลงมือทำกันดีกว่าครับ

ที่ maven project 

หมายเหตุ :   สำหรับคนที่ไม่รู้จัก maven หรือไม่เคยใช้  ลองอ่านที่ tutorial ของผมดูก่อนน่ะครับ เผื่อจะเข้าใจบ้าง  เพราะทั้ง tutorial ผมใช้ maven ทั้งหมดครับ http://na5cent.blogspot.com/p/tutorials.html


การ config maven profile เราจะ config กันที่ pom.xml ครับ

ที่ pom.xml ภายใต้ root element(<project/>)  ให้เพิ่ม element profiles ลงไปครับ  ดังนี้

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    ....
    ....
    ....

    <dependencies>
        ....
        ....
        ....
    </dependencies>

    <profiles>
        ....
        <!-- เราจะ config profile ไว้ในนี้ครับ -->
        ....
    </profiles>
    
    
    <build>
    ....
    ....
    ....
จากนั้นก็ config profile ลงไป (ผมมั่ว url username password น่ะครับ จำลองให้ต่างกันเฉยๆ อาจจะไม่ค่อยสมจริงเท่าไหร่ครับ)
    <profiles>
        <profile>
            <id>Development</id>
            <properties>
                <db.connectionURL>jdbc:oracle:thin:@127.0.0.1:1521:DEV</db.connectionURL>
                <db.username>HR</db.username>
                <db.password>HR</db.password>
            </properties>
        </profile>
        <profile>
            <id>Test</id>
            <properties>
                <db.connectionURL>jdbc:oracle:thin:@192.168.10.25:1508:TEST</db.connectionURL>
                <db.username>admin</db.username>
                <db.password>W_1r5Ad_tyu</db.password>
            </properties>
        </profile>
        <profile>
            <id>Production</id>
            <properties>
                <db.connectionURL>jdbc:oracle:thin:@192.168.10.23:1357:PRODUCTION</db.connectionURL>
                <db.username>protocolX</db.username>
                <db.password>Etd_@FDu+D2r30=</db.password>
            </properties>
        </profile>
    </profiles>
        จาก code จะมี profile อยู่ทั้งหมด 3 profile ครับ
คือ Development, Test และ Production  ที่จริงเราจะตั้งเป็นกี่ profile ก็ได้  แล้วก็จะใช้ชื่อว่าอะไรก็ได้ด้วยครับ  แค่ใส่ไว้ใน <id>ProfileName</id>  ก็พอ

        ต่อมาคือ <properties> อันนี้เป็น standard tag ของ maven  ที่เอาไว้ define  properties ของเราเองครับ  ซึ่งภายใน <properties> นั้น  เราจะ define ชื่อ tag ว่าอะไรก็ได้  เช่นผม define เป็น
<db.connectionURL>
<db.username>
<db.password>

        ตัวนี้แหล่ะครับคือ config ที่เราจะเอาไปแทน  เมื่อเราเลือกใช้ profile นั้นๆ

ต่อมาคือการ filter เพื่อแทนค่า config
        การ filter  จะมีส่วนที่ config ต่างกันอยู่ 2 ที่ครับ (เพราะมี resource 2 แบบ) คือ
1. java resources (resources ที่อยู่ใน class path)
2. web resources (html, css, javascript, config web app) ในกรณีที่เป็น web application

การ filter จะถูกกำหนดไว้ใน <build>  ซึ่ง java resource จะอยู่ใน <resources> และ web resource จะอยู่ใน <webResources>   ภายใต้ <plugin> อีกทีครับ    เรามาเข้าใจโครงสร้างกันก่อนดีกว่าครับ  ประมาณนี้

    <profiles>
        <profile>
            <id>Development</id>
            <properties>
                <db.connectionURL>jdbc:oracle:thin:@127.0.0.1:1521:DEV</db.connectionURL>
                <db.username>HR</db.username>
                <db.password>HR</db.password>
            </properties>
        </profile>
        <profile>
            <id>Test</id>
            <properties>
                <db.connectionURL>jdbc:oracle:thin:@192.168.10.25:1508:TEST</db.connectionURL>
                <db.username>admin</db.username>
                <db.password>W_1r5Ad_tyu</db.password>
            </properties>
        </profile>
        <profile>
            <id>Production</id>
            <properties>
                <db.connectionURL>jdbc:oracle:thin:@192.168.10.23:1357:PRODUCTION</db.connectionURL>
                <db.username>protocolX</db.username>
                <db.password>Etd_@FDu+D2r30=</db.password>
            </properties>
        </profile>
    </profiles>
    
    
    <build>
        
        <resources>
            ....
            <!-- java resources จะอยู่ตรงนี้ -->   
            ....
        </resources>
        
        <plugins>
            <plugin>
                ....
                ....
                ....
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.1.1</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>

                    <webResources>
                        ....
                        <!-- web resources จะอยู่ตรงนี้ -->   
                        ...  
                    </webResources>
                </configuration>
            </plugin>
            <plugin>
                ....
                ....
                ....
            </plugin>
        </plugins>
    </build>
หมายเหตุ : <resources> หรือ <webResources> ถ้าไม่มีก็ให้สร้างขึ้นมาเองครับ และตัว <webResources> ให้สร้างไว้ใน plugin ที่มี <artifactId>maven-war-plugin</artifactId> เท่านั้น plugin ตัวอื่นๆ ไม่ต้องไปสนใจครับ
ที่ <resources>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
                <includes>
                    <include>**/*.properties</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>false</filtering>
                <excludes>
                    <exclude>**/*.properties</exclude>
                </excludes>
            </resource>
        </resources>
ความหมายคือ ผมให้ filter java resources(src/main/resources) ทุกๆไฟล์ ที่เป็น file .properties ครับ

        ทีนี้จะข้อสังเกตอยู่ 2 อย่าง คือ <include>  กับ <exclude>  และ <filtering>true</filtering> กับ  <filtering>false</filtering> มันคืออะไร?
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
                <includes>
                    <include>**/*.properties</include>
                </includes>
            </resource>
คือ ให้ filter (เพราะ filtering เป็น true) ภายใต้ src/main/resources โดย filter(ไล่แทนค่า config) .properties ทั้งหมด
            <resource>
                <directory>src/main/resources</directory>
                <filtering>false</filtering>
                <excludes>
                    <exclude>**/*.properties</exclude>
                </excludes>
            </resource>
คือ ไม่ต้อง filter(เพราะ filtering เป็น false)  ภายใต้ src/main/resources  <exclude>**/*.properties</exclude> คือ  ไม่ต้องเอาไฟล์นี้มา

บางคนอ่านแล้วอาจจะงงๆ ครับ  แต่ว่ามันไม่ได้มีอะไรจริงๆ  มันแค่ทำ 2 step คือ
1. เลือกเฉพาะ file (.properties) ที่จะ filter กับ
2. เลือก file อื่นๆ(ยกเว้น .properties)  โดยไม่ต้อง filter

ความหมายมีแค่นี้ครับ

ที่ <webResources>
ทำคล้ายๆกันกับ resources ครับ  แค่เลือกว่า เราจะ filter ที่ file ไหน   ใน web resource เราจะเปลี่ยน path จาก src/main/resources ไปเป็น src/main/webapp  ดังนี้

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.1.1</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                    <webResources>
                        <resource>
                            <directory>src/main/webapp</directory>
                            <filtering>true</filtering>
                            <includes>
                                <include>**/*.jsp</include>
                            </includes>
                        </resource>
                        <resource>
                            <directory>src/main/webapp</directory>
                            <filtering>false</filtering>
                            <excludes>
                                <exclude>**/*.jsp</exclude>
                            </excludes>
                        </resource>
                    </webResources>
                </configuration>
            </plugin>
ลองสร้าง file ขึ้นมา test ดูครับ โดยผมวาง file ไว้ตาม ภาพน่ะครับ


ที่ database.properties
connectionUrl=${db.connectionURL}
username=${db.username}
password=${db.password}
ที่ index.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        connectionUrl=${db.connectionURL}<br/>
        username=${db.username}<br/>
        password=${db.password}
    </body>
</html>
ลอง เลือก profile แล้วก็ build profile แล้วก็ run ดูครับ (เลือก profile ตรง กรอบแดงๆ ที่ผมทำไว้)


สมมติผมเลือกเป็น Production Profile




config ต่างๆ  ก็จะถูกแทนค่าตาม profile ที่เราเลือกไว้ครับ

        ทีนี้เรามาตั้งคำถามต่อมาอีกว่า  แล้วถ้าเราต้องการ config ค่าที่เป็นค่า global ที่ทุกๆ profile จะใช้ได้เหมือนกัน  เราจะ config ไว้ที่ไหน?

คำตอบคือ  ไว้ใน <properties>  ภายใต้ root tag ครับ  ประมาณนี้
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.blogspot.na5cent</groupId>
    <artifactId>MavenFilterLearning</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>MavenFilterLearning</name>

    <properties>
        <project.author>redcrow</project.author> <!-- ****** -->
        <project.url>http://na5cent.blogspot.com/2013/06/config-maven-profile-environment-java.html&lt/project.url>
        <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    ....
    ....
    ....

        ทุกๆ profile จะใช้  config <project.author>redcrow</project.author> และ <project.url>http://na5cent.blogspot.com/2013/06/config-maven-profile-environment-java.html&lt/project.url> เดียวกันทั้งหมด

หวังว่าบทความนี้จะเป็นประโยชน์  สำหรับ developer ทุกคนน่ะครับ  ^____^

1 ความคิดเห็น: