วันพฤหัสบดีที่ 6 พฤษภาคม พ.ศ. 2553

java spring framework 3 quickstart

ในส่วนนี้จะเป็นการทบทวนเล็ก ๆ เนื่องจากห่างไปสักพัก กับ java spring framework
สำหรับผู้ที่ยังไม่มีประสพการณ์แนะนำอ่าน Servlet, JSP ก่อนเลยนะเพราะต่อยอดมาครับ

ขั้นแรกก็คงมิพ้น file
project/WebContent/WEB-INF/web.xml


    TestJsp
    
        contextConfigLocationclasspath:conf/applicationContext.xml
    
        org.springframework.web.context.ContextLoaderListener
    
    
        dispatcher
        org.springframework.web.servlet.DispatcherServlet
        
            contextConfigLocationclasspath:conf/dispatcher-servlet.xml
        2
    
    
        dispatcher
        *.do
    
    
        30
    
    
        redirect.jsp
    


ส่วนต่อมา ในการกำหนด การชี้ไปยัง page ต่าง ๆ ใช้ annotation เข้าไป scan หา
project/src/conf/dispatcher-servlet.xml


  
    

    
      
    

    
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    



ส่วนต่อมา ในการกำหนด service ในที่นี้เราใช้ annotation ทำให้ เขียน xml น้องลงไปเยอะ
project/src/conf/applicationContext.xml



    <context:annotation-config/>
    <context:component-scan base-package="spring.anno"/>



เริ่มแรกเรามาลอง service กันเลยดีกว่า เพื่อทดสอบ config
project/src/spring/anno/Iface.java
package spring.anno;

public interface Iface {
    public String getData(String str);
}

project/src/spring/anno/IfaceImpl.java
package spring.anno;

import org.springframework.stereotype.Service;

@Service
public class IfaceImpl implements Iface{

    @Override
    public String getData(String str) {
        System.out.println("have call IfaceImpl.getData() : " + str);
        return str;
    }
}

ต่อมาก็สร้างตัว test เลย กรณีนี้ใช้ eclipse เข้าช่วย ดังนั้น อาจต้องแก้ junit เป็น v4 ก่อน และ load ในส่วน library spring test เพิ่มมา
project/src/spring/anno/test/IfaceTest.java
package spring.anno.test;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import spring.anno.Iface;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:/conf/applicationContext.xml"})
public class IfaceTest {
 
 private Iface iface;

 @Autowired
 public void setIface(Iface iface) {
  this.iface = iface;
 }

 @Before
 public void setUp() throws Exception {
  System.out.println("setUp");
 }

 @After
 public void tearDown() throws Exception {
  System.out.println("tearDown");
 }

 @Test
 public void testGetData() {
  System.out.println("testGetData");
  this.iface.getData("test 123 d^^");
 }
}

ถ้ามิมีสิ่งใดผิดพลาดจะเป็นประมาณนี้
6 พ.ค. 2553 9:18:56 org.springframework.test.context.TestContextManager retrieveTestExecutionListeners
INFO: @TestExecutionListeners is not present for class [class spring.anno.test.IfaceTest]: using defaults.
6 พ.ค. 2553 9:18:56 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [conf/applicationContext.xml]
6 พ.ค. 2553 9:18:57 org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.GenericApplicationContext@fd13b5: startup date [Thu May 06 09:18:57 ICT 2010]; root of context hierarchy
6 พ.ค. 2553 9:18:57 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1b3f8f6: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,ifaceImpl,ifacePage]; root of factory hierarchy
setUp
testGetData
have call IfaceImpl.getData() : test 123 d^^
tearDown
6 พ.ค. 2553 9:18:57 org.springframework.context.support.AbstractApplicationContext doClose
INFO: Closing org.springframework.context.support.GenericApplicationContext@fd13b5: startup date [Thu May 06 09:18:57 ICT 2010]; root of context hierarchy
6 พ.ค. 2553 9:18:57 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry destroySingletons
INFO: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1b3f8f6: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,ifaceImpl,ifacePage]; root of factory hierarchy

หลังจากนั้นเราก็มาเริ่มสร้าง controller กับเลยดีกว่า
project/src/spring/anno/web/IfacePage.java
package spring.anno.web;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import spring.anno.Iface;

@Controller
public class IfacePage {
    
    private Iface iface;
    
    @Autowired
    public void setIface(Iface iface) {
        this.iface = iface;
    }
    
    public Iface getIface() {
        return iface;
    }

    @RequestMapping("/helloWorld.do")
    public ModelMap helloWorld() {
        System.out.println("request get http for helloWorld...");
        return new ModelMap();
    }
    
    @RequestMapping("/helloCat.do")
    public ModelMap helloCat() {
        System.out.println("request get http for helloCat...");
        String data = this.getIface().getData("request get http for helloCat...");
        ModelMap mm = new ModelMap();
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("data", data);
        List<Integer> l = new LinkedList<Integer>();
        for(int i=0; i<10; i++){
            l.add(i);
        }
        map.put("testloop", l);
        mm.addAllAttributes(map);
        return mm;
    }
}
และ template เพื่อแสดงผล ในหน้านี้ยังมิมีอะไร เอาง่าย ๆ ก่อน การเข้าถึง โดย
http://localhost:8080/proeject/helloWorld.do
project/WebContent/WEB-INF/jsp/helloWorld.jsp
<html>
    <head>
        <title>test helloWorld</title>
    </head>
    <body>
        data : helloWorld
    </body>
</html>
และ template เพื่อแสดงผล และทำการเีรียก service และ เริ่มผูกข้อมูลมายังหน้า page เอาง่าย ๆ อีกเช่นกัน การเข้าถึง โดย
http://localhost:8080/proeject/helloCat.do
project/WebContent/WEB-INF/jsp/helloCat.jsp
<html>
    <head>
        <title>test helloCat</title>
    </head>
    <body>
    data : helloCat
    <br />
    <% out.print(request.getAttribute("data")); %>
    <br />
    <table border="1">
    <%@page import="java.util.LinkedList"%>
    <%@page import="java.util.List"%>
    <%
    List<Integer> testloop = (List<Integer>)request.getAttribute("testloop");
    if( null == testloop){
        out.print("<tr><td>");
        out.print("data loop empty...");
        out.print("</td></tr>");
    }else{
        for(Integer i : testloop){
            out.print("<tr><td>");
            out.print(" test </td><td>" + i);
            out.print("</td></tr>");
        }
    }
%>
    </table>
    </body>
</html>
เพิ่มเติมในส่วน file redirect.jsp เพื่อเป็น default page site ซึ่งจะทำงานในกรณีที่เราใส่แค่
http://localhost:8080/proeject
(ซึ่งตอนนี้ยังคงไม่ได้ทำอะไรในตอนนี้ เอาไว้ต่อยอดในบทความถัด ๆ ไปครับ) project/WebContent/WEB-INF/redirect.jsp
<%--
Views should be stored under the WEB-INF folder so that
they are not accessible except through controller process.

This JSP is here to provide a redirect to the dispatcher
servlet but should be the only JSP outside of WEB-INF.
--%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<% response.sendRedirect("security/index.do"); %>

ข้อสำคัญอย่าลืม library ต่าง ๆ มาให้ครบ เพราะเราไม่ได้เขียนเองตั้งแต่ต้น เราพึ่งพา library ต่าง ๆ ของ spring และ อื่น ๆเป็นหลัก เขียนเองคงรอชาติเศษ ๆ หุหุ
ไม่แน่ใจว่าตกหล่นอะไรไปหรือเปล่า เพราะทำแล้วลองแล้ว ก็ลากมาแปะไว้ในนี้เลย ^^'
จับผิดได้แจ้งด้วยนะครับ
ขอบคุณครับ

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

Unknown กล่าวว่า...

ขอภาพประกอบด้วยได้ไหมครับ

Unknown กล่าวว่า...
ความคิดเห็นนี้ถูกผู้เขียนลบ
Unknown กล่าวว่า...

ต้องบอกว่า การ upload รูป เป็นเรื่องยากเนื่องจาก blogspot ไม่ support รูป อยู่แล้ว ส่วนจะไปฝากรูปแล้ว แปะ ก็เป็นเรื่องลำบากใจ เพราะส่วนใหญ่ ที่รับฝากรูป จะเก็บรูปให้เราไม่นาน ก็ลบทิ้ง จึงไม่ได้ใส่รูปไว้ ต้องขออภัยด้วยครับ