<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.0">Jekyll</generator><link href="https://piruin.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://piruin.github.io/" rel="alternate" type="text/html" /><updated>2021-10-06T10:36:28+07:00</updated><id>https://piruin.github.io/feed.xml</id><title type="html">Blast Piruin Panichphol</title><subtitle>Piruin Panichphol or Blast is Software Engineer, Scrum Master, Technical Coach. This is Piruin's personal website.
</subtitle><author><name>Blast Piruin Panichphol</name></author><entry xml:lang="th"><title type="html">Implement Jersey security without web.xml</title><link href="https://piruin.github.io/blog/implement-jersey-security-without-config-xml/" rel="alternate" type="text/html" title="Implement Jersey security without web.xml" /><published>2016-11-02T00:00:00+07:00</published><updated>2016-11-02T00:00:00+07:00</updated><id>https://piruin.github.io/blog/implement-jersey-security-without-config-xml</id><content type="html" xml:base="https://piruin.github.io/blog/implement-jersey-security-without-config-xml/">&lt;p&gt;การจะ Implement Security ด้วย Annotation ตามมาตรฐาน JAX-RS 2.0 บน Jersey ใน Document บอกให้ทำ config ที่ web.xml
แต่เนื่องจากผมเป็นมือใหม่เรื่อง Java Web Server บอกเลยว่าใช้ web.xml ไม่เป็น ตัว api ที่ทำอยู่ตอนนี้ก็เป็น Jetty Embedded
และดูแล้วก็ไม่ใช่สไตล์เท่าไหร่ ชอบการ Config ด้วย code มากกว่า เลยทำให้ต้องวิธีเอง งงบัคตัวเองอยู่ตั้งนาน หุหุ&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;ยังคงมีแต่เรื่อง Api ให้เขียนเนื่องจาก Android มีคนทำแทนแล้ว ไล่ตัวเองมาทำ Api แทน&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;มาดูโจทย์กัน&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@Path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/resource&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Resource&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

   &lt;span class=&quot;nd&quot;&gt;@RoleAllow&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;nd&quot;&gt;@Path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(/&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Response&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;privateRes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(){&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
   &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

   &lt;span class=&quot;nd&quot;&gt;@PermitAll&lt;/span&gt;
   &lt;span class=&quot;nd&quot;&gt;@Path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(/&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Response&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;publicRes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(){&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
   &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;ผมต้องการให้ทุกคนเข้าถึง &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resource/public&lt;/code&gt; ได้ แต่ที่ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resource/private&lt;/code&gt; อยากให้เฉพาะ user
เท่านั้นที่เข้าได้ ด้วย Security Annotation&lt;/p&gt;

&lt;p&gt;สิ่งที่เราต้องทำคือ&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;เราต้องเปิดใช้งาน &lt;strong&gt;Security Annotation&lt;/strong&gt; ตามมาตรฐาน JAX-RS 2.0 ซะก่อน  เนื่องจาก Jersey
ไม่ได้เปิดใช้งาน Feature นี้โดย default เราต้องเปิดเองถึงจะใช้ annotation เช่น  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@PermitAll&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@DenyAll&lt;/code&gt;
และ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@RoleAllow&lt;/code&gt; ได้&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;implement &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecurityContext&lt;/code&gt; ของเราเอง ซึ่งจะเก็บข้อมูลเกี่ยวกับความปลอดภัย ได้แก่ User ที่ connect มาชื่ออะไร
บทบาทอะไร (Role) Connect มาแบบปลอดภัยหรอไม่ ในที่นี้ถ้าเราใช้ web.xml และ config เป็นเราก็จะได้ค่าพวกนี้มาเลย
แต่ถ้าเราไม่ใช้หละก็ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecurityContext&lt;/code&gt; จะไม่มีค่าอะไรพวกนี้เลย return false ตลอดการ&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;เปิดใช้-security-annotation&quot;&gt;เปิดใช้ Security Annotation&lt;/h2&gt;

&lt;p&gt;ด้วยการ register &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RolesAllowedDynamicFeature&lt;/code&gt; class ให้กับ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ResourceConfig&lt;/code&gt; ซะก่อน&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ResourceConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ApplicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;packages&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;com.awesome.api&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;JacksonFeature&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;RolesAllowedDynamicFeature&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;เมื่อเราทำการ Regis &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RolesAllowedDynamicFeature&lt;/code&gt;  จะเท่ากับว่าเราเปิดใช้งาน Security Annotation แล้ว
เมื่อมี Request เข้ามาที่ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/resource/private&lt;/code&gt; server จะทำการเรียก&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isUserRole(user)&lt;/code&gt; ของ SecurityContext
ถ้า Method นี้ return &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; ก็จะได้ข้อมูลไป  แต่ถ้าเป็น false จะเจอ 403 Fobidden แทน&lt;/p&gt;

&lt;p&gt;ซึ่งตอนนี้ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecurityContext&lt;/code&gt; ของเรายังไม่มีค่าอะไรดังนั้น Request อะไรเข้ามาก็เข้าถึงส่วนที่เป็น Private ไม่ได้แน่นอน&lt;/p&gt;

&lt;h2 id=&quot;implement-securitycontext&quot;&gt;Implement SecurityContext&lt;/h2&gt;

&lt;p&gt;เราต้องสร้าง Filter ที่ทำงานตรวจสอบข้อมูลเกี่ยวกับการยืยนยันตัวตนทุกครั้งเมื่อมี Request เข้ามาที่ api  เช่นตัวอย่างต่อไปนี้&lt;/p&gt;

&lt;h3 id=&quot;authentication-filter&quot;&gt;Authentication Filter&lt;/h3&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@Priority&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Provider&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AuthenticationFilter&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ContainerRequestFilter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ErrorMessage&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;UNAUTHORIZED&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ErrorMessage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;401&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;ชื่อ หรือ รหัสผ่านไม่ถูกต้อง&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ErrorMessage&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;FORBIDDEN&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ErrorMessage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;403&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;คุณไม่มีสิทธิเข้าใข้งาน&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ContainerRequestContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requestContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(!&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BasicAuthenticationInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;hasAuthorizeProperty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;requestContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//[1]&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;BasicAuthenticationInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;authenInfo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BasicAuthenticationInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;requestContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//[2]&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;UserDao&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;userDao&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;DBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ConfigurationDB&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getDatasource&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;onDemand&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;UserDao&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;userDao&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;authenInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getUsername&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;authenInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getPassword&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;FaarmisException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;401&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;UNAUTHORIZED&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isAllow&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;FaarmisException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;403&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;FORBIDDEN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
       &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;urlScheme&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requestContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getUriInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBaseUri&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getScheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//[3]&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;AuthenticationContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;authenticationContext&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AuthenticationContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;urlScheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;requestContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setSecurityContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;authenticationContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;//[4]&lt;/span&gt;
   &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;โค้ดนี้เป็นตัวอย่างให้พอเห็น Concept นะครับ  Copy ไปใช้เลยไม่ได้นะ&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;มาดูกันว่ามันทำอะไรบ้าง&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;ตรวจสอบก่อนว่ามีข้อมูลการยืนยันตัวตนเข้ามาหรือป่าว ในตัวอย่างนี้ใช้ Basic Authentication  ถ้าไม่มี filter หยุดทำงานเลย ซึ่งจะมีผลให้ SecurityContext
ไม่มีข้อมูลอะไร Request นั้นก็จะเข้าถึงได้แต่ endpoint ไปเป็น &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@PermitAll&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;เอาข้อมูลการยืนยันตัวตนไปลองหาในฐานข้อมูลดูว่าเจอไหม ถ้าไม่เจอก็ Return 401 ไปเลย หรือถ้าเจอแต่ไม่ใช่ user ที่เราอยากให้เข้าถึงได้เช่นเป็น Blacklist
เราก็ return 403 ไปแทน&lt;/li&gt;
  &lt;li&gt;ถ้าผ่านข้อ 2 มากได้ เราจะเอาข้อมูลที่ได้มาสร้าง &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecurityContext&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;ทำการ set ค่า &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecurityContext&lt;/code&gt; ให้กับ Request นั้น เพื่อใช้ตรวจสอบกับ Security Annotation ต่อไป&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;สังเกตุ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Priority(1)&lt;/code&gt; นะครับ เป็นจุดสำคัญมากๆ ถ้าไม่กำหนดไว้เป็นค่าต่ำๆ filter นี้อาจจะทำงานหลัง filter ของ Security Annotation
ซึ่งหมายความว่าตอนนั้นจะยังไม่มี &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecurityContex&lt;/code&gt; ทำให้การทำงานไม่เป็นอย่างที่ต้องการ  ส่วน &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Provider&lt;/code&gt; จะช่วย Register filter นี้เข้าไปใน
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ResourceConfig&lt;/code&gt; ที่เราทำไปก่อนหน้าอัติโนมัติเลย ถ้าหากอยู่ภายใต้ package ที่กำหนดไว้ใน resource Config&lt;/p&gt;

&lt;p&gt;ที่นี้มาดูการสร้าง &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecurityContext&lt;/code&gt; กัน&lt;/p&gt;

&lt;h3 id=&quot;security-context&quot;&gt;Security Context&lt;/h3&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AuthenticationContext&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SecurityContext&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;HTTPS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Principal&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;userPrincipal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;AuthenticationContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;userPrincipal&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getUsername&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;scheme&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Principal&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getUserPrincipal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;userPrincipal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;isUserInRole&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;equals&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;isSecure&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;startsWith&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;HTTPS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getAuthenticationScheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;BASIC_AUTH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;เราทำการสร้าง class ที่ implement interface &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecurityContext&lt;/code&gt; ซึ่งจะมีอยู่ 4 method ด้วยกันได้แก่&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getUserPrincipal()&lt;/code&gt; ให้เราทำการ implement interface &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Principal&lt;/code&gt; เพื่อคืนชื่อของ user
ที่ Request api เข้ามา ในตัวอย่างผมให้ใช้ค่าที่ได้จาก &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getUsername()&lt;/code&gt; ของ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;User&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isUserInRole(role)&lt;/code&gt; นี้หละจุดสำคัญของบทความนี้ ค่าที่ถูกส่งเข้ามาใน method นี้จะไปค่าที่เป็น
parameter ของ @RoleAllows ถ้าเรา return true  Request ก็จะไม่โดนแตะออก&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isSecure()&lt;/code&gt; อันนี้ implement ง่ายครับ เช็คแค่ว่าเป็น HTTPS รึเปล่าพอ&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getAuthenticationScheme()&lt;/code&gt; เรายืนยันตัวตนด้วยวิธีไหนก็ระบุไป เช่น BASIC OAUTH&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;เพียงเท่านี้เราก็จะใช้งาน Security Annotation ได้ 100% โดยไม่จำเป็นต้องใช้ Web.xml เลยครับ
นอกจากนั้นเรายังมี SecurityContext ไว้ใช้ประโยชน์เพิ่มเติมในภายหลังได้นะ ดูแล้วอีกคุ้มรึเปล่าน้าาา~
ถ้ามีอะไรแนะนำ อะไรผิด รู้วิธีที่ดีกว่านี้ หรือมีทางเลือกอื่นก็มาแชร์กันนะครับ&lt;/p&gt;</content><author><name>Blast Piruin Panichphol</name></author><category term="java" /><category term="Jersey" /><category term="Jetty" /><category term="RESTful" /><category term="jax-rs" /><summary type="html">การจะ Implement Security ด้วย Annotation ตามมาตรฐาน JAX-RS 2.0 บน Jersey ใน Document บอกให้ทำ config ที่ web.xml แต่เนื่องจากผมเป็นมือใหม่เรื่อง Java Web Server บอกเลยว่าใช้ web.xml ไม่เป็น ตัว api ที่ทำอยู่ตอนนี้ก็เป็น Jetty Embedded และดูแล้วก็ไม่ใช่สไตล์เท่าไหร่ ชอบการ Config ด้วย code มากกว่า เลยทำให้ต้องวิธีเอง งงบัคตัวเองอยู่ตั้งนาน หุหุ</summary></entry><entry><title type="html">สรุปผลการพยายามเอาชนะ Page Insight และ Web Page Test</title><link href="https://piruin.github.io/blog/how-to-win-google-page-insight/" rel="alternate" type="text/html" title="สรุปผลการพยายามเอาชนะ Page Insight และ Web Page Test" /><published>2016-10-24T00:00:00+07:00</published><updated>2016-10-24T00:00:00+07:00</updated><id>https://piruin.github.io/blog/how-to-win-google-page-insight</id><content type="html" xml:base="https://piruin.github.io/blog/how-to-win-google-page-insight/">&lt;p&gt;หลังจากที่เว็ปนี้เริ่มเป็นรูปเป็นร่าง ผมก็ตั้งใจว่าจะทำให้ Performance ดีๆด้วย เลยลองทดสอบกับ
Page Insight และ Web Page Test ดู ปรากฎว่าคะแนนไม่ค่อยน่าพอใจเท่าไหร่ ก็ปรับแก้ไปเรื่อยๆจนได้ระดับนึง
เลยบันทึกไว้ก่อนว่าทำไปบ้าง และควรทำอะไรต่อ&lt;/p&gt;

&lt;h2 id=&quot;cloudfare&quot;&gt;Cloudfare&lt;/h2&gt;
&lt;p&gt;มันช่วยได้เรื่อง Cache control ได้ดีเลย ไม่ต้องทำอะไรเองเลยครับ ของเค้าดีจริง แถมยังทำให้เว็ปเป็น
https แบบที่เราไม่ต้องเสียตังค์เลย (อะไรจะใจดีปานนั้น) น่าเสียได้ว่าลองเปิด Feature minify html, css และ js
แล้วไม่เป็นผลกับ Web ที่ Host บน Github Pages แฮะ ไม่รู้ทำอะไรผิดรึเปล่า แต่แค่นี้ก็รักแล้วหละ
ช่วยเพิ่มคะแนนให้ผมไปได้เยอะเลย&lt;/p&gt;

&lt;p&gt;แต่การต้องพึ่งพา Css Framework และ jQuery นี้หละปัญหา&lt;/p&gt;

&lt;h2 id=&quot;css&quot;&gt;CSS&lt;/h2&gt;
&lt;p&gt;การใช้ CSS ที่จะทำให้เว็ปประสิทธิภาพดีที่สุดคือการ Inline style
ใช่แล้วยัดไปใน tag style ภายใต้ช่วง head เลย
แต่ Bootstrap มันใหญ่มากเลยนะจะยัดเข้าไปใน Head จริงๆหรอ
นั้นหละครับปัญหา  CSS Framework ส่วนใหญ่มักเยอะเกินความต้องการของเรา&lt;/p&gt;

&lt;p&gt;วิธีแก้คือ&lt;/p&gt;

&lt;h3 id=&quot;1-โหลดแบบ-css-async&quot;&gt;1. โหลดแบบ CSS Async&lt;/h3&gt;

&lt;p&gt;วิธีนี้ช่วยให้ PageInsight และ WebPageTest ไม่ว่าเราเรื่อง block การแสดงผล
แต่แลกมาด้วย user จะเป็นหน้าเราแบบ Plainๆ ไม่มี style ก่อนแป๊บนึง
แต่จะเป็นเฉพาะที่เข้าเว็บเราครั้งแรก วิธีนี้ง่ายที่สุดและ&lt;/p&gt;

&lt;h3 id=&quot;2-inline-ccs-style-ทั้งหมด&quot;&gt;2. Inline CCS Style ทั้งหมด&lt;/h3&gt;

&lt;p&gt;ฝังสไคล์ทั้งหมดไปเลย วิธีนี้ User จะไม่เป็นช่วงที่เว็ปเราไม่สวยเลย
ไม่โดนว่าเรื่อง CSS ไป Block การแสดงผลเช่นกัน แต่ต้องระวังเรื่องขนาดของ Html
การจะยัดทั้ง Bootstrap เข้าไปใน &amp;lt;head&amp;gt; จะทำให้ทุกหน้าเว็ปช้าแทน&lt;/p&gt;

&lt;p&gt;ถ้าเลือกวิธีนี้เราจะคัดเฉพาะบางส่วนของ Framework เอาเฉพาะที่เราใช้
เพื่อให้มันเล็กพอที่จะเอาไปยัดแบบ inline หรือ
คุณอาจจะหา CSS Framework เจ้าใหม่ที่เล็กหน่อยมีเฉพาะสิ่งที่คุณใช้ มาแทนที่เลย&lt;/p&gt;

&lt;h3 id=&quot;3-inline-ส่วนหลัก-และโหลด-css-หลักแบบ-async&quot;&gt;3. Inline ส่วนหลัก และโหลด CSS หลักแบบ Async&lt;/h3&gt;

&lt;p&gt;คัดเฉพาะส่วนเล็กให้เว็ปไม่ดูน่าเกลียด ระหว่างรอ CSS ของจริงโหลด
ยังก็อย่าลืมลดขนาด CSS หลักให้เล็กที่สุดด้วยนะครับ ใช้แรงเยอะหน่อยได้ได้ผลดีนะ&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;ลองดูว่าแบบไหนจะเหมาะกับงาน และความขยันของคุณที่สุด&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;javascript&quot;&gt;JavaScript&lt;/h2&gt;

&lt;p&gt;ถ้าเป็นไปได้พยายามอย่าใช้เยอะ โดนเฉพาะกับเว็ป Blog ทั่วไป หรือถ้าจะใช้
ให้โหลดแบบ Async แต่ระวังปัญหาเรื่อง Dependency ของ JS เนื่องจาก
ส่วนใหญ่จะใช้ JQuery แต่มันใหญ่ถ้าเราโหลด Async แล้วมีอีก Script ที่จะเป็น
ต้องใช้ jQuery งานจะงอกทันที&lt;/p&gt;

&lt;h3 id=&quot;จำเป็นต้องใช้-js-จริงรึเปล่า&quot;&gt;จำเป็นต้องใช้ JS จริงรึเปล่า?&lt;/h3&gt;

&lt;p&gt;ตอบคำถามนี้ให้ได้ก่อน ค่อยทำอย่างอื่นๆ ถ้าคำตอบคือไม่จำเป็นก็สบายเลย ลบออกให้หมดโล้ด&lt;/p&gt;

&lt;h3 id=&quot;โหลด-async-ให้หมด&quot;&gt;โหลด Async ให้หมด&lt;/h3&gt;

&lt;p&gt;มี Snippet ที่ช่วยให้โหลด js แบบ Async โดยที่ยังทำงานตามลำดับอย่างถูกต้องได้อยู่ ลองหาดูครับ
จริงๆผมหาเจอแล้วแต่ผมไม่ได้ Save ไว้ ต้องไว้ขออภัยต่อตัวเองและผู้อ่านด้วย ใครหาเจอบอกด้วยนะ&lt;/p&gt;

&lt;h2 id=&quot;รูปภาพ&quot;&gt;รูปภาพ&lt;/h2&gt;
&lt;p&gt;ต่อเราลดขนาด Css Js ให้ตายเท่าไหร่ ยังมันก็ไม่เท่ากับการโหลดภาพ 1 ภาพเลยครับ ฉะนั้นอย่าลือว่า
การ Optimize ภาพเป็นสิ่งสำคัญมากๆๆๆ ควรใช้ภาพที่ Resolution เหมาะกับการใช้งานจริง ไม่ใช่ใหญ่เว่อร์เกินไป
และก็ Compress ใหได้ไฟล์ที่เล็กที่สุดโดยไม่ให้เสียลายละเอียดไป ลองใช้ Online Tool ง่ายๆอย่าง TinyPNG ดูก็ได้ครับ&lt;/p&gt;

&lt;p&gt;แต่ถ้าขี้เกียจแต่อยากได้ผลลัพธ์ที่ดี ทางออกที่ดีอีกทางคือใช้ Tool ที่สามารถช่วย Optimize เรื่องภาพทั้งหมดได้แบบ Automate
อย่าง Grunt หรือ Gulp ก็จะทำให้ชีวิตง่ายขึ้น (รวมไปถึง minify css js เลยนะ)&lt;/p&gt;

&lt;h2 id=&quot;สรุป&quot;&gt;สรุป&lt;/h2&gt;

&lt;p&gt;พยายามออกแบบเว็ปให้เรียบง่ายที่สุด จะลดงานคุณไปได้มาก
แต่ถ้าไม่ชอบเรียบเราต้องหาวิธีแก้กันต่อไป หรือจะไม่แก้ก็ได้นะ&lt;/p&gt;

&lt;p&gt;ยังไงซะ User ไม่เลือกเข้าเว็ปเราจากคะแนนที่ได้จาก Page Insight หรอก (แต่ Google เลือกมี่จะแนะนำคุณจากคะแนนนะ)&lt;/p&gt;</content><author><name>Blast Piruin Panichphol</name></author><category term="general" /><summary type="html">หลังจากที่เว็ปนี้เริ่มเป็นรูปเป็นร่าง ผมก็ตั้งใจว่าจะทำให้ Performance ดีๆด้วย เลยลองทดสอบกับ Page Insight และ Web Page Test ดู ปรากฎว่าคะแนนไม่ค่อยน่าพอใจเท่าไหร่ ก็ปรับแก้ไปเรื่อยๆจนได้ระดับนึง เลยบันทึกไว้ก่อนว่าทำไปบ้าง และควรทำอะไรต่อ</summary></entry><entry xml:lang="th"><title type="html">Tutorial RESTFul Service by Jersey and Jetty Embedding</title><link href="https://piruin.github.io/blog/jersey-jetty-tutorial/" rel="alternate" type="text/html" title="Tutorial RESTFul Service by Jersey and Jetty Embedding" /><published>2016-10-14T00:00:00+07:00</published><updated>2016-10-14T00:00:00+07:00</updated><id>https://piruin.github.io/blog/jersey-jetty-tutorial</id><content type="html" xml:base="https://piruin.github.io/blog/jersey-jetty-tutorial/">&lt;p&gt;วันนี้เราจะ setup RESTFul service ด้วยการใช้ Jersey และ Jetty แบบ Embedded กันแบบง่ายๆ โดย Service ของเราสามารถคืน POJO เป็น เป็น JSON อัพโนมัติด้วย Jackson ได้ด้วย&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Project นี้ผมใช้ Gradle เป็นตัว Build นะครับ ถ้าใช้ Maven ก็ลองเปลี่ยนดูครับ ต่างกันแค่ตรงประกาศ dependency&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;เริ่มต้นแบบ-basic&quot;&gt;เริ่มต้นแบบ Basic&lt;/h2&gt;

&lt;p&gt;เริ่มจากการกำหนด Dependency ใน &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build.gradle&lt;/code&gt; ให้เป็นตามนี้&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;dependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jettyVersion&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;9.3.12.v20160915&quot;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jerseyVersion&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;2.23.2&quot;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;compile&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;org.eclipse.jetty:jetty-server:$jettyVersion&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;compile&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;org.eclipse.jetty:jetty-servlet:$jettyVersion&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;compile&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;org.eclipse.jetty:jetty-http:$jettyVersion&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;compile&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;org.glassfish.jersey.containers:jersey-container-servlet-core:$jerseyVersion&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;compile&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;org.glassfish.jersey.containers:jersey-container-jetty-servlet:$jerseyVersion&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;หลังจากกำหนด Dependency และทำการ Sync Gradle ใหม่แล้ว  เราจะสามารถอ้างถึง Class ต่างๆของ Jetty และ Jersey ได้แล้ว&lt;/p&gt;

&lt;p&gt;ต่อไปเราจะทำการให้โปรแกรมของเรา start server เมื่อเราทำการ execute .jar&lt;/p&gt;

&lt;p&gt;ที่ Class หลักของเรา หรือก็คือ class ที่มี &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public void main(String[] args)&lt;/code&gt; เพิ่มโค้ดดังนี้&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Server&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Server&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2222&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;ServletContextHandler&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ServletContextHandler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/*&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;nc&quot;&gt;ServletHolder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jersey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ServletHolder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ServletContainer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;jersey&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setInitOrder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;jersey&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setInitParameter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;jersey.config.server.provider.classnames&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;SayHello&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getCanonicalName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;addServlet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jersey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/*&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;finnaly&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;destroy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;และเพิ่ม class ที่เป็นตัว Service จริงๆ ในที่นี้เราจะสร้าง &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SayHello.class&lt;/code&gt; มีหน้าตาดังนี้&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SayHello&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

     &lt;span class=&quot;nd&quot;&gt;@GET&lt;/span&gt;
     &lt;span class=&quot;nd&quot;&gt;@Path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/say&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;nd&quot;&gt;@Produces&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text/plain&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;say&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(){&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello&quot;&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;ที่นี้เราก็ Start server ของเราได้เลย ลองเปิด Browser แล้วเข้าไปที่ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;localhost:2222/say&lt;/code&gt; เราจะเจอขอความว่า &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hello&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&quot;มี-servlet-มากกว่า-1-class&quot;&gt;มี Servlet มากกว่า 1 class&lt;/h2&gt;
&lt;p&gt;ในชีวิตจริง Service ของเราต้องมีมากกว่า 1 class แน่นอน คงไม่มีใครเขียน Service จริงๆ ให้จบใน Class เดียวจริงไหม? หรือว่ามี?&lt;/p&gt;

&lt;p&gt;สิ่งที่เราต้องทำคือไปที่ Main Class ของเราแล้วแก้ให้เป็นดังต่อไปนี้&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Server&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Server&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2222&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;nc&quot;&gt;ServletHolder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jersey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ServletHolder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ServletContainer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;jersey&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setInitOrder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;jersey&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setInitParameter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;jersey.config.server.provider.classnames&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;, &quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;nc&quot;&gt;SayHello&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getCanonicalName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt;
              &lt;span class=&quot;nc&quot;&gt;Second&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getConicalName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt;
              &lt;span class=&quot;nc&quot;&gt;Third&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getConicalName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;nc&quot;&gt;ServletContextHandler&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ServletContextHandler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/*&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;addServlet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jersey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/*&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;finnaly&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;destroy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;สังเกตสิ่งที่เปลี่ยนแปลงในบรรทัดที่ 7-11 แทนที่เราจะส่งชื่อ class ไป class เดียว เราเอามันมาเชื่อมกันโดยขั้นด้วย &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;,&lt;/code&gt; แทน
ทีนี้จะมีเพิ่มกี่ class ก็ comma แล้วใส่เพิ่มไปเรื่อยๆได้เลย&lt;/p&gt;

&lt;h2 id=&quot;return-เป็น-json-ด้วย-jackson-media&quot;&gt;Return เป็น JSON ด้วย Jackson Media&lt;/h2&gt;
&lt;p&gt;ถ้าเราต้องการ Response แบบ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application/json&lt;/code&gt; จาก POJO เราก็ทำดังนี้&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;JsonResource&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

     &lt;span class=&quot;nd&quot;&gt;@GET&lt;/span&gt;
     &lt;span class=&quot;nd&quot;&gt;@Path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/josn&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;nd&quot;&gt;@Produces&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;application/json&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Entity&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fromPojo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(){&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Entity&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Say hi, Json&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

     &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Entity&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

          &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Entity&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;){&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;จริงๆเรื่องมันควรจบง่ายๆแค่นี้ แต่ถ้าเราลองเรียก Service นี้เราจะพบ Internal Server Error
ที่เป็นเช่นนี้ เป็นเพราะว่าเราจำเป็นต้อง Register Feature การแปลง POJO เป็น Json ให้ตัว Jersey รู้ก่อน ดังนี้&lt;/p&gt;

&lt;p&gt;ที่เพิ่ม Depdency &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jersey-media-json-jackson&lt;/code&gt; ที่ build.gradle&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;compile &quot;org.glassfish.jersey.media:jersey-media-json-jackson:$jerseyVersion&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;และที่ main ก่อน start server ต้องทำดังต่อไปนี้&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;ResourceConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ResourceConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;packages&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;your.package.name&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;JacksonFeature&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nc&quot;&gt;ServletHolder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jersey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ServletHolder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ServletContainer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;เพียงเท่านี้ เมื่อเข้าที่ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;localhost:2222/json&lt;/code&gt; ก็จะได้ Response เป็น JSON ตามที่เราต้องการแล้ว&lt;/p&gt;</content><author><name>Blast Piruin Panichphol</name></author><category term="java" /><category term="Jersey" /><category term="Jetty" /><category term="RESTful" /><summary type="html">วันนี้เราจะ setup RESTFul service ด้วยการใช้ Jersey และ Jetty แบบ Embedded กันแบบง่ายๆ โดย Service ของเราสามารถคืน POJO เป็น เป็น JSON อัพโนมัติด้วย Jackson ได้ด้วย</summary></entry><entry><title type="html">กำหนด Custom domain ให้กับ Web บน Github Pages</title><link href="https://piruin.github.io/blog/github-pages-custom-domain/" rel="alternate" type="text/html" title="กำหนด Custom domain ให้กับ Web บน Github Pages" /><published>2016-09-29T00:00:00+07:00</published><updated>2016-09-29T00:00:00+07:00</updated><id>https://piruin.github.io/blog/github-pages-custom-domain</id><content type="html" xml:base="https://piruin.github.io/blog/github-pages-custom-domain/">&lt;p&gt;หลังจากทำโครง Web บน Github Pages เริ่มเป็นรูปเป็นร่างแล้ว จะเข้าเว็ปผ่าน &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piruin.github.io&lt;/code&gt; ต่อไปก็รู้สึกมันไม่เท่สักเท่าไหร่ เลยตัดสินใจเช่า Domain &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piruin.me&lt;/code&gt; และลงมือทำ Custom Domain กันสักหน่อย&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;เรื่องนี้ใช้เวลาแป๊บเดียวและไม่ยากครับ แม้แต่มือใหม่เพิ่งมีเว็ปที่จดโดเมนเป็นของตัวเองครั้งแรกแบบผมยังทำได้ภายในครึ่งชั่วโมง&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;ลงมือซิครับ-รออะไร&quot;&gt;ลงมือซิครับ! รออะไร?&lt;/h2&gt;
&lt;p&gt;ค่าที่ใช้ในบทความนี้เป็นของจริงจากที่ผมทำเว็ปนี้เลย  ซึ่ง Requirement ของผมคือ สามารถเข้าผ่าน &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piruin.me&lt;/code&gt; เป็นหลัก แต่ถ้าพิมพ์ว่า &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;www.piruin.me&lt;/code&gt; เข้ามาก็ต้องเข้ามาที่ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piruin.me&lt;/code&gt; ได้เช่นกัน ไม่ใช่เจอหน้า 404&lt;/p&gt;

&lt;h3 id=&quot;github&quot;&gt;GitHub&lt;/h3&gt;
&lt;p&gt;ก่อนอื่นเราต้องบอก GitHub ก่อนว่าเราจะใช้ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Custom Domain&lt;/code&gt; แล้วนะ โดยทำตามนี้&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;เข้าไปที่ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setting&lt;/code&gt; ของ Project ของ Website ของเรา&lt;/li&gt;
  &lt;li&gt;ที่หัวข้อ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Custom Domain&lt;/code&gt; ใส่ชื่อโดเมนของเรา เช่น piruin.me แล้วกด &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;save&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;จากนั้น github จะทำ &lt;strong&gt;commit&lt;/strong&gt; ไฟล์ชื่อ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CNAME&lt;/code&gt; ให้เราโดยมีชื่อโดเมนที่เราใส่ไปให้โดยอัตโนมัติ เท่านี้เป็นอันเสร็จส่วนแรก&lt;/p&gt;

&lt;h3 id=&quot;ตั้งค่า-dns&quot;&gt;ตั้งค่า DNS&lt;/h3&gt;
&lt;p&gt;ต่อไปเราจะทำการบอกให้ DNS รู้ว่า ถ้ามีคนพิมพ์ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piruin.me&lt;/code&gt; ให้พาไปที่เครื่อง server เครื่องไหน Ip อะไร หรือถ้าพิมพ์ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;www.piruin.me&lt;/code&gt; จะให้ Reirect ไปไหน&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;เข้าไป Website ที่เราจดโดเมนไว้ เช่น GoDaddy Namecheap 9ล9&lt;/li&gt;
  &lt;li&gt;หาเมนูที่เกี่ยวกับการตั้งค่า DNS ของเจ้านั้น (ขั้นตอนนี้เป็นขั้นที่ยากที่สุดแล้ว)&lt;/li&gt;
  &lt;li&gt;ทำการเพิ่ม Record ทั้งหมด 3 อันดังนี้
    &lt;ul&gt;
      &lt;li&gt;ประเภท &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A&lt;/code&gt;, Host &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@&lt;/code&gt;, IP &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.30.252.153&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;ประเภท &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A&lt;/code&gt;, Host &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@&lt;/code&gt;, IP &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.30.252.154&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;ประเภท &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CNAME&lt;/code&gt;, Host &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;www&lt;/code&gt;, ใส่ domain เดิมของ github page ของเรา เช่น &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piruin.github.io&lt;/code&gt; สำหรับ website ของผม&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;กด &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Save&lt;/code&gt; ถ้ามีให้กด แล้วรอ&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
  &lt;p&gt;ถ้าอยากเห็นผลเร็วๆ ตอนเพิ่ม Record ให้กำหนดค่า TTL ให้มีค่าน้อยๆเข้าไว้&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;ผลลัพธ์&quot;&gt;ผลลัพธ์&lt;/h3&gt;
&lt;p&gt;หลังจากผ่านไป ไม่น่าจะเกินครึ่งชั่วโมง เราจะสามารถเข้า Website ของเราไปด้วย &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piruin.me&lt;/code&gt; หรือจะพิมพ์ว่า &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;www.piruin.me&lt;/code&gt; ก็ได้เช่น ซึ่งจะ Redirect ไปที่ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piruin.me&lt;/code&gt; แทน&lt;/p&gt;

&lt;h2 id=&quot;เราทำอะไรลงไป&quot;&gt;เราทำอะไรลงไป&lt;/h2&gt;
&lt;p&gt;ตอนที่เราเพิ่ม DNS Record ประเภท &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A&lt;/code&gt; เป็นการบอกว่า ถ้ามีคนพิพม์ Apex Name (piruin.me) ให้ชี้ไปที่ IP 192.30.252.153 หรือ .154 ซึ่งเป็น IP ของ Github Pages
ส่วนตอนที่เพิ่มประเภท &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CNAME&lt;/code&gt; เราใส่ host เป็น Subdomain (www) แล้วให้ชี้ไปที่ domain default ของ Github Pages เดิมของซึ่งตอนนี้ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CNAME&lt;/code&gt; ที่ Project ของเรากำหนดให้เป็น apex name ทำให้เมื่อพิมพ์ว่า &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;www.piruin.me&lt;/code&gt; จะถูก Redirect ไปที่ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piruin.me&lt;/code&gt; แทน&lt;/p&gt;

&lt;h2 id=&quot;ทิ้งท้าย&quot;&gt;ทิ้งท้าย&lt;/h2&gt;
&lt;p&gt;ถ้าเราอยากให้คนเข้า Web เราด้วย Subdomain &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;www.&lt;/code&gt; เป็นหลักแทนที่จะเป็น Apex Name หละ  คิดว่าจะต้องเปลี่ยนตรงไหนบ้างครับ?&lt;/p&gt;</content><author><name>Blast Piruin Panichphol</name></author><category term="jekyll" /><category term="github-pages" /><summary type="html">หลังจากทำโครง Web บน Github Pages เริ่มเป็นรูปเป็นร่างแล้ว จะเข้าเว็ปผ่าน piruin.github.io ต่อไปก็รู้สึกมันไม่เท่สักเท่าไหร่ เลยตัดสินใจเช่า Domain piruin.me และลงมือทำ Custom Domain กันสักหน่อย</summary></entry><entry><title type="html">Hello World - I’am Blast Piruin</title><link href="https://piruin.github.io/blog/hello-world/" rel="alternate" type="text/html" title="Hello World - I’am Blast Piruin" /><published>2016-09-04T00:00:00+07:00</published><updated>2016-09-04T00:00:00+07:00</updated><id>https://piruin.github.io/blog/hello-world</id><content type="html" xml:base="https://piruin.github.io/blog/hello-world/">&lt;h2 id=&quot;ในที่สุดผมก็ลงมือทำเว็ปสักที&quot;&gt;ในที่สุดผมก็ลงมือทำเว็ปสักที&lt;/h2&gt;
&lt;p&gt;จริงๆผมก็เคยพยายามจะทำมาหลายครั้งแล้วหละ แต่ไม่สำเร็จสักที เนื่องจาก Requirement ตัวเองค่อยข้างจะเยอะ เช่น ไม่จำเป็นต้องดู Server เอง, รองรับสองภาษา (ทำอย่างกะว่าจะขยันเขียนภาษาอังกฤษ), ถ้า Blog เขียนด้วย Markdown ได้ก็ยิ่งดี และที่สำคัญต้อง Customize หน้าตาให้ถูกใจได้ง่ายๆและไม่เสียตังค์(งกอ่ะ) ก็เคยไปลองใช้บริการจากเจ้าต่างๆ เช่น WordPress Postach.io หลายเจ้าอยู่เหมือนกัน ซึ่งก็ไม่มีเจ้าไหนผ่านทุกข้อ สุดท้ายเลยล้มเลิกไป กลับนั่งเขียน Android ต่อดีกว่า&lt;/p&gt;

&lt;p&gt;จนกระทั่งที่ทำงานมีโจทย์ว่าอยากได้ Website สำหรับ Product ที่ทำอยู่ แต่ไม่อยากดูแล Server เอง ผมเลยเสนอให้น้องๆที่ทำงานลองใช้ Github Pages ดู แต่ตัวเองก็ไม่เคยใช้เหมือนกัน แค่เคยอ่านผ่านๆว่ามันใช้คู้กับ Jekyll เพื่อทำ Blog ได้  เมื่อแนะนำเค้าไปแล้วก็ตัวเองก็ควรจะรู้เรื่องสักหน่อยหละมั้ง –” เลยกลับมานั่งศึกษาหลังเลิกงานดู ทำไปทำมาเพลินดี เลยตั้งโจทย์เป็นทำ Web Blog ของตัวเองพร้อมศึกษาวิธีใช้ทำ Web บน Github Pages ด้วย Jekyll ไปเลยซะเลย&lt;/p&gt;

&lt;h3 id=&quot;ทำ-backlog-แล้วจะได้งาน&quot;&gt;ทำ Backlog แล้วจะได้งาน&lt;/h3&gt;
&lt;p&gt;หลังจากมีโจทย์แต่ไม่มีกรอก บวกกับความไม่รู้เรื่องเกี่ยวกับการทำ Web ใดๆทั้งสิ้น (html css ก็พึ่งศึกษากันงานนี้หละ) พอศึกษาอะไร ก็มักจะมีเรื่องใหม่ที่ไม่รู้ให้ศึกษาต่อไปเรื่อยๆไม่จบสักที แค่เรื่อง favicon เล็กๆก็ดูจะไม่เล็กอย่างที่คิด จนกลายเป็นไม่ได้ลงมือเขียนซะที  เลยตัดสินใจเอาวิญญาณ Scrum Master เข้าสิงตัวเอง สั่งตัวเองทำ Backlog ซะ ค่อยทำให้ Focus เป็นส่วนๆแล้วผ่านมาจนโครงสร้างในเว็ปเริ่มเป็นรูปเป็นร่างแล้วมานั่งเขียนบทความนี้&lt;/p&gt;

&lt;h3 id=&quot;web-นี้แคร์เรื่องอะไรบ้าง&quot;&gt;Web นี้แคร์เรื่องอะไรบ้าง&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;W3C Markup Standard&lt;/strong&gt; เพื่อให้เว็บมีคุณภาพผ่านมาตรฐานตามสไตล์ Agile developer เลยต้องตรวจเสมอว่าใช้ Tag ถูกต้อง, ไม่มีเปิด Tag แล้วลืมปิด, ไม่มี Link ตาย เรื่องพวกนี้ตรวจด้วย CI ทั้งหมด&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Web Accessibility&lt;/strong&gt; เรื่องนี้ผมคิดว่าเป็นสิ่งที่ควรทำ และเท่าที่ศึกษาดูพบว่าถ้าเราทำโครงสร้างเว็บตามมาตรฐาน ก็จะผ่านเรื่องสำคัญๆในหัวข้อนี้อยู่แล้ว&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;UX&lt;/strong&gt; เพิ่งอ่านทบทวน Don’t Make Me Think จบก่อนเริ่มทำพอเลย ดังนั้น Web นี้หละที่ลองของ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;สรุปคือมันต้อง &lt;strong&gt;หน้าตาถูกใจ UXดี โครงสร้างได้มาตรฐาน&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;การเขียน-blog&quot;&gt;การเขียน Blog&lt;/h3&gt;
&lt;p&gt;เรื่องนี้ไม่แน่ใจว่าจะเขียนไปได้ถึงไหน คนอื่นจะอ่านรู้เรื่องรึเปล่าก็ไม่รู้ แต่จะพยายามเขียนบ่อยๆเผื่อจะเขียนดีขึ้น  เวลาจะ Note อะไรจากเมื่อก่อนที่เขียนลง Evernote อย่างเดียว จะก๊อปมาลงนี้ไปด้วย แต่ขี้เกียจทำเรื่องรูปแฮะ :(  เรื่องที่คิดว่าจะเขียนน่าจะเกี่ยวกับเรื่องดังต่อไปนี้&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Android อาชีพหลักของเราต้องเขียนบ้าง (ถ้าเขียนทันชาวบ้านเค้านะ)&lt;/li&gt;
  &lt;li&gt;Java&lt;/li&gt;
  &lt;li&gt;Agile Scrum&lt;/li&gt;
  &lt;li&gt;การออกแบบระบบ&lt;/li&gt;
  &lt;li&gt;Jekyll Github Pages&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;เขียนบทความนี้ทำไม&quot;&gt;เขียนบทความนี้ทำไม&lt;/h2&gt;
&lt;p&gt;เพราะว่าหลังจากบทความเสร็จนี้จะถือว่าเปิดตัว &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;piruin.me&lt;/code&gt; อย่างเป็นทางการ บทความ Dummy ทั้งหมดจะต้องเอาออก เลยจำเป็นบทดความไว้ซะหน่อย Website จะได้ไม่ว่างแค่นั้นหละ บาย&lt;/p&gt;</content><author><name>Blast Piruin Panichphol</name></author><category term="general" /><category term="ไร้สาระ" /><summary type="html">ในที่สุดผมก็ลงมือทำเว็ปสักที จริงๆผมก็เคยพยายามจะทำมาหลายครั้งแล้วหละ แต่ไม่สำเร็จสักที เนื่องจาก Requirement ตัวเองค่อยข้างจะเยอะ เช่น ไม่จำเป็นต้องดู Server เอง, รองรับสองภาษา (ทำอย่างกะว่าจะขยันเขียนภาษาอังกฤษ), ถ้า Blog เขียนด้วย Markdown ได้ก็ยิ่งดี และที่สำคัญต้อง Customize หน้าตาให้ถูกใจได้ง่ายๆและไม่เสียตังค์(งกอ่ะ) ก็เคยไปลองใช้บริการจากเจ้าต่างๆ เช่น WordPress Postach.io หลายเจ้าอยู่เหมือนกัน ซึ่งก็ไม่มีเจ้าไหนผ่านทุกข้อ สุดท้ายเลยล้มเลิกไป กลับนั่งเขียน Android ต่อดีกว่า</summary></entry></feed>