2014年3月5日 星期三

spring4 + hibernate4 Java sample code

java code基本上我看跟3是一樣的XD...
就是那個hibernate currentSession怪怪的QQ...

就照基本的spring分吧~
不過偶省掉了一個有些版本在寫的interface/implement...

我通常使用非特定的物件來處理~
因為return資料的型態為json格式, 在Java上不用定死的Bean物件~
轉而利用List, Map來組成~
好處是不用處理特定的型態~ Json物件裡面還是有要分String/int/...bala
取用也要放對才有正確的型態~
不過用基礎物件的話~ 只要放好Integer/Double/String....etc...balabala...
甚至於null, 裡面若還是List/Map 多層也都會正確轉換~
要注意的大概是Date型態~ 自動轉換會變成非常複雜的js Date物件~
所以我大多是在轉入Map時~ 用SimpleDateFormat先轉成需要的字串格式就可以了~

spring協助處理了一些uri pattern的問題~
不過也會因為他包過~ 造成有時候不知道發生了什麼事~
碰過的幾項注意事項大概就是

1. uri pattern的結尾不要輸入有點"."的資料~
bad pattern: /aaa/{num}
因為spring會自己把"."後面的資料切掉~ 對數字來說~ 數字就錯了!!...ex: 11.993 --> 11
避免方式大概就是在會有點的資料多一個/, 或是不要以他為最後一個參數
call use: http://xxxxxxx/aaa/11.993/
或是改pattern為 /aaa/{num}/input

2.  pattern變數有空白
bad pattern: /aaa/{emp ty}/input
空白有時候很小~ 很容易沒看到XD...然後他就莫名的GG了

3. pattern和底下的變數名稱不一樣
copy 來copy去的時候~ 挺容易發生的...

4. 不同method使用到重覆的pattern
這個應該很好理解~ 命名規則最好一開始就能先有個規則~ 以免剛好跟共同開發的人~ 心有靈兮一點通後就打架了...

5. 中文轉碼問題...
因為web server本身就可以設定編碼(若不設定會看local/OS地區, 或你安裝的那一包...有時候外在主機環境~ 是不能改web server設定的~ 就只能從程式動)... 而filiter也可以設定... spring也會有小聰明...連Broswer都很貼心的幫你轉(FF/Chrome會, 老IE不會....)
為了可以write once..run anywhere....別人好心幫你搬家完後也不會出事 ...
最保險的還是前後端講好~ 前端先encodeURIComponent~
這樣子永遠不會被誰多轉一次

sample code
-----------------------------------
Controller
----------------------------------

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.apache.log4j.Logger;

import java.util.*;

@Controller
public class SampleController {

    @Autowired
    SampleService theService;

    @RequestMapping(value={"/test/list"}, method = RequestMethod.GET)
    public @ResponseBody List fn1(Model model){
        return theService.test1();
    }
}

-------------------------------------------
Service
-------------------------------------------
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Component
public class SampleService {

    @Autowired
    SampleDao dao = null;


    public List test1()  {
        return dao.test1();
    }
}

-----------------------------------------
Dao
----------------------------------------
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Component;
import org.apache.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.SQLQuery;
import org.hibernate.type.StringType;
import org.hibernate.type.TimestampType;
import org.hibernate.type.IntegerType;

import java.util.*;
import java.text.SimpleDateFormat;
import com.iisi.commons.DBQuickUtils;

@Repository
public class SampleDao {

    Logger logg = Logger.getLogger(this.getClass());

    @Autowired
    SessionFactory sessionFactory;

     SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private Session curSession()  {
        Session ses = sessionFactory.getCurrentSession();
        return ses;
    }

    public List test1()  {

        String sql = "select * from test_table";
        SQLQuery qry = curSession().createSQLQuery(sql);
        qry = qry.addScalar("id", IntegerType.INSTANCE).addScalar("name", StringType.INSTANCE)
                 .addScalar("utime", TimestampType.INSTANCE);

        List lst = qry.list();

        List re = hibernateResultToMap(lst, sf, new String[]{"ID", "NAME", "TIME"});

        return re;
    }
}

spring4 + hibernate4 簡易設定

為了配合公司部門績效~ 老是要搞那些framework...
但是他就是肥滋滋的...只有越來越胖...搞得看起來很複雜~ 好像很厲害的樣子...
但是在偶低眼裡還是不如jdbc...

就又先做個簡單的版本設定吧~
因該案子要做的部分很簡單~ 只要撈DB/中介以REST提供的服務就好~
沒有網頁~沒有SOAP~\(^_^)/~

lib配置就不提囉~ 反正有少放的話~ 會一直有ClassNotFound來煩~ 應該就會知道~

單純設定檔~
先從最基本的入口web.xml開始
1. 加入spring主設定檔(路徑要寫對)
2. 有用到DispatcherServlet處理uri pattern和response
3. 用到OpenSessionInViewFilter, 是因為不知道為啥~ open session有問題~ 查一查~ 好像是說在hibernate4, 搭配spring的實作調用不同了~ 在程式內若要直接取currentSession會有問題~ 但是我又不想在程式內用openSession...怕有人又給我忘了關...所以直接調用hibernate4的 filiter出來處理吧QQ/
(基本上~ 我認為會這樣是...政治問題XD...因為hibernate被JBoss買走~ spring是VMware體系...越來越不Open是可想而之的...不綁綁我家的server和機器怎麼賺錢!!?為了凸顯其他家開發上困難或是慢~ 好在sales時做個勝表...少一些其他支援也是正常...)

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring4/root-context.xml</param-value>
    </context-param>

    <!-- Sets the default profile to use in the absence of any profiles set
        at deployment time. -->
    <context-param>
        <param-name>spring.profile.default</param-name>
        <param-value>dev</param-value>
    </context-param>

    <!-- Creates the Spring Container shared by all Servlets and Filters -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- Handles requests into the application -->  
    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring4/servlet-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
  
    <filter>
          <filter-name>hibernateFilter</filter-name>
          <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
          <init-param>
             <param-name>sessionFactoryBeanName</param-name>
             <param-value>sessionFactory</param-value>       
          </init-param>    
       </filter>

    <filter-mapping>
        <filter-name>hibernateFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <security-constraint>
        <web-resource-collection>
            <url-pattern>/*</url-pattern>
            <http-method>PUT</http-method>
            <http-method>DELETE</http-method>
            <http-method>HEAD</http-method>
            <http-method>OPTIONS</http-method>
            <http-method>TRACE</http-method>
        </web-resource-collection>
        <auth-constraint></auth-constraint>
    </security-constraint>

接下來~
指向root-context, 我簡化為三個設定
server參數檔--> properties
掃component路徑檔 --> servlet-context
資料來源設定(hibernate) --> data
<!-- Turn on support for @Annotation-based configuration e.g. @Inject -->
    <context:annotation-config />

    <!-- Loads application properties -->
    <import resource="properties.xml" />
   
    <!-- Loads controller/component -->
    <import resource="servlet-context.xml" />
   
    <!-- Loads model(hibernate) -->
    <import resource="data.xml" />


component檔內容
直接給他上層就好~ 省得打一堆資料夾~
<context:component-scan base-package="xxx.yyy.zzz.web.**" />

data檔內容~
差別大概就是~hibernate4 的調用class不同~
另外spring4的使用xml schema也些許不同...不過應該google都能找到ok的範例
另外~ 我沒有使用bean OR mapping...我習慣使用jdbc的sql操作方式(hsql)...
能更彈性的增減物件屬性~ 以及下條件
(誰叫我老是碰到要用db內的function處理資料...hibernate碰到db function..都很難用...)
加上這次專案只有查詢需求~ 沒有新刪修這些transcation鳥事~ 就更不用管他啦^_^Y
<bean id="dataSource"
    class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName">
            <value>com.microsoft.sqlserver.jdbc.SQLServerDriver</value>           
        </property>
        <property name="url">           
            <value>jdbc:sqlserver://.......</value>
        </property>
        <property name="username">
            <value>oooo</value>
        </property>
        <property name="password">
            <value>xxxx</value>           
        </property>
        <property name="timeBetweenEvictionRunsMillis" value="300000" />
        <property name="numTestsPerEvictionRun" value="6" />
        <property name="minEvictableIdleTimeMillis" value="1800000" />
        <property name="initialSize" value="3" />
        <property name="maxActive" value="100" />
        <property name="maxIdle" value="10" />
        <property name="minIdle" value="1"/>
        <property name="maxWait" value="5000" />       
        <property name="poolPreparedStatements" value="true" />
        <property name="maxOpenPreparedStatements" value="100" />
    </bean>
   
     <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
       
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.use_sql_comments">true</prop>
                <prop key="hibernate.format_sql">false</prop>
                <prop key="hibernate.cache.use_second_level_cache">false</prop>               
            </props>
        </property>
    </bean>


servlet檔內容,
主要設定回傳為json格式ResponseBody
 <!-- messageConverters beans -->   
    <beans:bean id="stringHttpMessageConverter"
        class="org.springframework.http.converter.StringHttpMessageConverter">
    </beans:bean>

    <beans:bean id="mappingJacksonHttpMessageConverter"
        class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
    </beans:bean>   

    <!--
        AnnotationMethodHandlerAdapter messageConverters for @ResponseBody
    -->
    <beans:bean
        class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <beans:property name="messageConverters">
            <beans:list>
                <beans:ref bean="stringHttpMessageConverter" />
                <beans:ref bean="mappingJacksonHttpMessageConverter" />
            </beans:list>
        </beans:property>
    </beans:bean>

下篇再補java code的部分

centos 常用指令

總算快把上次做的備註都寫完了/灑小花....

最後再把有用到的centos指令做一些整理
當然google鳥哥還是最多最完整的^_<...

-------------------------------------------------------
用指令進行SFTP(scp)
因為悲慘的沒有UI又只能跳版, 所以只能用cmd進行檔案對傳...
scp 本機檔案 帳號@其他主機:檔案
ex:
scp hadoop-1.2.1.tar.gz XXX@xxx.xxx.xxx.xxx:/home/XXX/hadoop-1.2.1.tar.gz

當然如果是windows 和centos要對傳~
windows端只要裝filezilla client就好了^_^/

-------------------------------------------------------
yum安裝時若是卡住...
這次發生是在於防火牆卡了一半的通訊的協定~ 前面的列表清單拿取有過~
但是在安裝過程中~ 有些下不下來~ 然後安裝程序就一直卡著~ 也不timeout...麻煩
(後來確認是部分網路限制被檔~ 拜託機房"全開http, https, ftp"就OK了)
解除程序的做法...
先砍pid暫存檔, 再砍程序

###yum lock
cat /var/run/yum.pid
rm -f /var/run/yum.pid 20360

ps aux | grep yum
kill -9 21361

-----------------------------------------------------
尋找process(ps)
ex: 找java程序
ps aux | grep java

這行好像是像windows的程序的應用程式管理員~
就centos UI介面裡的程序(印象中~有點忘了)
ps -ef

----------------------------------------------------
找檔案(find)
find 指定路徑下 -name 名稱 -type 類型
類似windows的檔案搜詢~ 可以限定尋找file或是資料夾
要注意的是~ 找檔案有權限限制(我想至少要read)~
所以要是像偶用非root查根目錄, 就會被"權限不足"的字洗版Orz...
然後一眨眼洗完後...完全看不到~ 被找到的在那~ 囧a...
ex:
find / -name mapred -type d

----------------------------------------------------
防火牆設定...
現在要注意的是~iptables 指得是ipv4
不過新的OS現在都支援ipv6...是iptables6的樣子...
在service裡可以看到兩個~ 要注意囉...
要注意是否有要分開管理~
我習慣是關ipv6, 只用舊的...內網而已~誰管你用6...XD...
另外hadoop對於ipv6的支援也不知道做好了沒Orz...

vim /etc/sysconfig/iptables
service iptables restart

----------------------------------------------------
因為scp還要打密碼有點麻煩...
在server架起來之後~ 另外有一招是~  用wget...
用http拿資料囉~~

當然資料夾內容要壓一下~ 都到http可以access到的地方~
另一台wget收完再解壓縮...

##壓縮和解壓縮 folder
tar -zcvf XXX.tar.gz ooo
wget http://xxx.xxx.xxx.xxx/ooo.tar.gz
tar -xzf ooo.tar.gz ooo

如果單檔太大~ 純壓縮
###only tar 1 file
tar -czvf ooo_all_.tar.gz ooo_all.sql

因為rar居然無法包tar(但是會解喔~是那招QQ)...
只好特別去下載7z來用~囧rz...
不用zip的原因是~ 因為一_一a...centos沒有內建zip...
在server上能少一事是一事阿QQ
###unzip 7zip tar
tar -xv -f frog.08.tar

--------------------------------------------------
刪除整個資料夾含檔案
記得加-R...使用前要看清楚~ 並在身心健全下使用~~
偶永遠都記得以前發生過rm  /...之後大家就開心的聊天了...
(等MIS把備份倒回去...還好那邊有好好的做備份!!!!!)
###delete file without confirm(-f), -R -> all include sub dirs/files
rm -Rf xxxx

------------------------------------------------
看看server有沒有聽port...
通常用在確認服務是死的活的~
或是看有沒有人佔port
netstat -nap | grep 9000

------------------------------------------------
掛crontab
相當於windows的排程~ 差別crontab要用root設定~
另外...該死的...偶後來發現~crontab跑的環境與user登入時不同...
(path, env都不一樣)
造成python的程式怎麼都不會跑...被搞死...
google應該也會得到不少的泣訴~ 不幸的是~ 我的環境可能掛太多外掛lib...改成絕對路徑, 加PATH...偽裝成sh...都無法運作T__T...
(喵的~ 我只是一個小小小的Java工程師...為什麼還在那邊研究怎麼寫shell script....)
所以那一隻後來就只好改成AP定期batch的方式運作~
總之就是...我覺得python想成為主流語言~ 還有很~~~~~大的進步空間...

vim /etc/crontab

另外crontab有時候程序跑一跑也是會自己死掉但沒關掉的XD...
有次查的時候~ 突然想到做一下ps...結果抓到幾隻~ 看一下啟動日期~ 運作多久...
反正kill掉就好了...還有發現cron產出的pid還蠻"連號"的...XD應該不難判別...