PIXNET Logo登入

互聯網 - 大數據

跳到主文

本部落格為互聯網熱門頭條訊息管理中心

部落格全站分類:生活綜合

  • 相簿
  • 部落格
  • 留言
  • 名片
  • 3月 07 週二 201721:17
  • 程序員該用哪種姿勢來理財


Source: http://www.cnblogs.com/ityouknow/p/5772248.html
其實一直想寫一篇文章名字都想好了,叫做“程序員該不該理財?”。后來想了想,該不該這個就不用想了,必須要理財!那么市面上那么多理財的方式對于我們屌絲的程序員該如何選擇呢?其實我也是那種土的掉咋的那種類型,以前幾乎沒有想過神馬理財的,一來呢畢業的時候工資全都不夠花的還理個毛線,二來總是感覺理財好像都是有錢人搞的東西;后來偶然進入了互聯網金融行業,呆了幾年,慢慢也接觸了很多理財方式,但也還是一個門外漢,此文就是和大家一起聊聊我們程序員該如何去理財?算是拋磚引玉,歡迎拍磚。
純潔的微笑原創 轉載請注明出處 http://www.cnblogs.com/ityouknow/p/5772248.html
我的理財經歷
先聊聊我的理財經歷,我的理財大概也是從畢業三年之后才慢慢開始的,對了也就是從余額寶開始,后來在第三方支付、互聯網金融公司工作,對理財的種類了解慢慢多了起來,互聯網金融也就是P2P或者金融公司產品各種變種(其實也是債權類產品的進一步封裝),有活期產品、封閉期的固定收益產品(日、月、年類的固定收益);買了股票(先是A股,后來美股),在了解了基金(指數基金、債券基金、股票基金等等),后來也看了黃金和期貨(了解較少)、保險接觸最少。
一路慢慢走來,理財的這種想法和認識也是在不斷的發展變化,不認識、不了解、不認同的一些偏見也在慢慢的消失,可以以更理性的角度去看待投資理財的這件事情,理財真的是我們每一個人都應該好好的學習的事情,如何讓你辛辛苦苦的積蓄可以跑贏通貨膨脹,不隨著時間推移我們的資產不斷縮水;但是在工作中常常發現我們的程序員對于理財目前來講大多都還是比較保守,常常是全部都銀行或者全部寶寶類產品,更有激進者全都投入股市,有一年損失十幾萬的。下面分幾個階段來聊聊我對理財的幾個認識:
寶寶時代
說起了理財或者第三方支付,總是不能避開一家偉大的公司-支付寶,支付寶一直在引領、教育著我們這一代人對于理財的認識;我的理財起點就是從余額寶開始的,清晰的記得13年6月余額寶出來的時候,大家都感覺到稀奇或者不了解(當時仍然有很多人認為還是把錢放到銀行保險,哪怕余額寶也是!),記得當初剛開始余額寶轉進去了100元,每天看著它給帶來的幾分錢收益都很滿足,然后就一發不扣收拾,幾乎是前腳收到發工資的短信,下一分鐘錢就同步到了余額寶里面,曾經有一段時間中國鬧錢荒,導致余額寶的最高收益高達6.76;
不過后來由于這塊的蛋糕臺大了,各大銀行也都著急出了很多的政策來限制:第一步,開限額,導致大額資金無法進入;第二步,自己干,很多銀行自己也推出了資金的貨幣基金理財產品和余額寶來競爭,理財通也橫空出世,理財通搞了一個同卡進出的理念比較好,很大程度上對資金安全起了很大的作用。
互聯網金融
2014年算是互聯網金融的元年,其實互聯網金融在很早的時候就被引入了國內,之前一直是不溫不火的發展著,突然到了2014年隨著資本的大量進入催化了互聯網金融的大發展。現在的互聯網金融主要分為大的兩個部分:p2p和眾籌,p2p在中國發展進行非常多的變種,現在主要的產品有活期債權、封裝成月或者年的理財產品,然后后面去打包,從債權方面又分為,企業和個人。我也是在2014年由于工作原因接觸到了p2p,小做嘗試了之后,發現完爆余額寶,幾乎又是全部積蓄投入到p2p里面,當初算了一筆賬,按照年化12的標的來計算的話,投入10萬,一年的收益就是1.2萬,投資1000萬,那么每年不用工作就是120萬!,輕輕松松的年收入破百萬!對了沒有一點稅!!
那時候各家平臺又是送蘋果手機、又是送電腦的各種活動玩的不亦樂乎,后來到了15年跑路了很多平臺,慢慢的才把很大的一部分撤了出來。眾籌也是在中國玩出了很多的花樣,主要還是分為產品眾籌和股權眾籌,產品眾籌主要是以高科技產品為主,但是現在很多新品發布會也搞上去了;股權眾籌也就是拿出自己的錢去投資一些比較看好的小公司來占一部分原始股權,一般股權眾籌都有一定的門檻,沒有資金百萬級別以上基本上不用參與了,風險也非常大不是咱這小市民可以玩的。
股票
我是在第一次股災快結束的時候進入的,15年股市正火爆的時候公司有很多的同事整天都在關注著股票,什么過了3000點了,這回進去就是炮灰了,然后大盤到了4000點,有同事又說,人民日報都刊登了文章,4000點只是一個起點,好吧,他們最后的結局都是什么,我就不說了大家也猜的到,那時候我們部門幾乎有一半的程序員多多少少都在在A股開了戶,活動的時候也是在討論著各種的股票。
到了6月份以后我突然有了點時間,也就特別好奇股市為啥有這么大的吸引力,也試探性的在網上開了戶,在網上找了費率最便宜的那種,好多同事都是在模擬炒股的軟件上面模擬的先玩上一段時候再進入市場,但是我覺得模擬因為沒有真正的資金在上面,感覺不到任何的刺激。于是乎剛開始搞了1000元的資金去試探。清楚的記得買的第一只股票是“蘇寧云商”,然后迫不及待的每天看著它漲了還是跌了樂此不疲,買了沒有多久“蘇寧云商”就停牌了,發公告說阿里投資,重大利好!好多人都說股市新手的運氣都會比較好,先給你一點甜頭,讓你先陷進去,然后慢慢在和你玩,后來“蘇寧云商”開盤后連續三個漲停,賺了幾百塊錢。
我立刻對股市產生了極大的興趣,大家是不是又準備看一個A股小散被收割的故事:) 于是乎,追漲殺跌、專門看股票技術指標(成交量、KDJ、MACD ...)、請教一些玩股票的朋友推薦股票,分析股票。專門組建了一個討論組,把喜歡炒股的幾個IT的朋友都拉進去,大家討論每天的行情,那是一個熱鬧!慢慢的發現很多科技股票買不了才發現創業板是需要專門去線下開通,好吧,迫不及待就去開通了創業板。短短的6個月買了很多股票,樂視、掌趣科技、東方財富、衛寧健康、華裔兄弟、萬達院線、信息發展。。。。。多到我也不清楚到底買了多少,全部短線交易!資金也從最初的1000一直增加到最高50000,經歷了股災2.0、3.0,也經歷了創業板最低的1800點、10月份的超級大反彈、今年的熔斷。認識的兩個朋友中,有一個在牛市的時候曾經一周每天盈利1萬(這樣還有什么心情上班),有一個在股災中還么賠多少但是熔斷沒有躲過去,搭進去近一年的工資。
作為一個IT男,中國最優秀的互聯網幾乎都在美國上市,所以就一直了解如何去買美股,那時候“宜人貸”剛上納斯達克破發了,"lending club 簡稱LC" 也跌到12美元左右,覺得是個機會。剛好積木出了一款產品叫做積木股票,就迫不及待的注冊、開通海外匯款。進去之后就買了LC ,結果LC沒多久就跌到8美元、7、6 ...。失望之極,剛退出沒多久LC又出黑天鵝時間 ,直接從7左右跌到最低3.44美元!美股由于沒有漲跌幅度的限制比A股要刺激很多,經常看到某一個股票一天漲40%、50%,但跌的時候也一樣經常一下子一半市值就沒了,我在美股的虧損幾乎都來自LC。宜人貸是讓我非常震撼的一只股票,因為從開盤一直跌到3美元左右,然后開始上升到現在達30美元左右,沒有抓住非常可惜。現在手里拿的都是一些中概念股,京東、58、獵豹等。
基金
一個人的精力總是有限,整天看股票真的很累還影響工作、有時候甚至影響心情還不一定賺錢。如何想讓牛逼的人來替我們理財,這時候也就慢慢的了解到了基金,特別是在關注了微信公共賬號的“股社區”學了很多的知識,目前也是剛剛了解一些。基金我了解主要是這幾種:債卷基金,主要是買國家的債卷或者國企類型的公司債卷為主,風險度比較低,收益率也偏低一些,我目前就是定投的這類;股票基金,也就是找一個牛逼的基金經理幫我們炒股,盈利了大家分錢這種模式,風險也很高,也比較依賴于基金經理的個人水平。大盤類的基金,比如ETF300 之類,就是買主板最牛逼的股票各買一點,只要大盤漲,我們收益就會漲,大盤跌,我們就會虧損這種,短期看收益很難確定,長期來看肯定收益為正;也有一部分混合基金就是股票和債卷都買一些。
黃金
2016年初的時候,各種報道黃金跌破1000美元就是底部,那時候是1100美元左右吧,感覺差不多了,就買了交通銀行黃金延期(T+D)買了不到一萬元,沒幾天虧損了一點就出來了沒有堅持,如果堅持到現在那也賺了一些;有時候你想到和做到完全是兩種情形。現在如果想投資黃金的話,直接買螞蟻聚寶的“存金寶”,關鍵方便快捷。
我的投資經驗與教訓
結合我這三年多的投資理財教訓,談一些對投資的看法。
銀行存款
一直流行著一句話,窮人往銀行里面存錢,富人從銀行中貸款,可以很大程度上反應中國情況。如果你把積蓄都放到銀行里面躺著,結合通貨膨脹來講,你就是在虧錢!而且銀行的服務超級爛,辦業務超級慢,因此建議銀行卡里面一分錢也不要放!
寶寶類產品
可以把平時需要緊急用的錢和零花的錢都可以放到這里面,既可以享受一定的收益性,也可以靈活的存取、消費,建議以大平臺余額寶、理財通為主,其它類的謹慎選擇。
互聯網金融
平臺真的重要! 平臺真的重要!! 平臺真的重要!!! 重要的事情說三遍,如果選擇不好平臺就是0和1的事情,投資的平臺跑路了就一分錢都沒有了,筆者就投資了一個跑路的公司e租寶和一個在跑路之前投資過的公司。我們經常說,你貪戀的是人家的利息 ,人家貪戀的是你的本金。 但回過頭來看其實大多數跑路的公司都是騙子公司,幾乎沒有什么正經的互聯網金融公司,只是打著互聯網金融的旗號來行騙而已。P2P真的風險很高嗎,其實筆者看來只要選擇好平臺,應該還是非常好的一種理財方式。那怎么選擇平臺呢,盡量選擇評級靠前、國企或者上市公司背景的企業。
股市和基金
股市是一個學問很深的東西,有人窮盡一生也不能領悟,主要看性格、價值觀、人性的把握。大家要以我為戒,禁忌追漲殺跌、頻繁買賣,要堅持價值投資,持續持用,追求長遠的收益。股市也是一個風險度很高的投資,大家需要根據自己的風險偏好來選擇投資,也可以適當的選擇合適的基金產品來投資,一般股票配置比率應該和年齡成反比,越年輕就可以多占比你投資的一部分,最重要的是不要讓股票影響了我們正常的生活和工作!一直想找一個既可以買A股、港股和美股的產品,一直沒有發現很可惜。對于股市,要敬畏它、尊重它、理解它。
比如程序員來講最酷的方法就是用 Python 寫一些程序進行量化交易或者分析股票相關內容,我這里也給大家推薦一個:股票分析(一):常見的技術指標雪球
黃金和保險
和平時期買股票,戰亂期間買黃金,這個要看每個的理解了,我了解也不是很多;保險是我了解最少的一部分了,總感覺我們這么年輕考慮保險干啥呢,但是這種保險的意識也需要慢慢的養成。
買房
好多人評論說沒有提到買房,是因為對于這個買房還真不太懂,但我感覺拐點也快到了,一線城市的房價很難說,但是三四線投資房產的必要性真的不太大了,而且買房建議一定買核心地段或者位置環境偏好的小區,貴一點不要緊,方便以后轉手。
資產配置
我目前的資金配置是,寶寶類產品1/4、p2p投資1/4、a股+美股3/8、基金1/8;大家可以根據各自風險承受度來選擇自己的資產配比。
最后
理財是我們每一個人必須要關注的事情,那怕我們現在并沒有多少錢,經常看到一個廣告說,投資是你人生最后的一個事業,隨著年齡的增長投資理財對我們越來越重要。投資也是一件謹慎、嚴肅的事情畢竟關系著我們辛苦賺的血汗錢。
最后的最后
對于我們,投資自己更重要!
投資有風險,理財需謹慎 !
好多人私信想一起交流,我就建了一個QQ群,有興趣的入群交流:308719523 暗號:程序員
(繼續閱讀...)
文章標籤

AutoPoster 發表在 痞客邦 留言(0) 人氣(1)

  • 個人分類:生活學習
▲top
  • 3月 07 週二 201721:17
  • spring boot(四):thymeleaf使用詳解


Source: http://www.cnblogs.com/ityouknow/p/5833560.html
在上篇文章springboot(二):web綜合開發中簡單介紹了一下thymeleaf,這篇文章將更加全面詳細的介紹thymeleaf的使用。thymeleaf 是新一代的模板引擎,在spring4.0中推薦使用thymeleaf來做前端模版引擎。
thymeleaf介紹
簡單說, Thymeleaf 是一個跟 Velocity、FreeMarker 類似的模板引擎,它可以完全替代 JSP 。相較與其他的模板引擎,它有如下三個極吸引人的特點:
  • 1.Thymeleaf 在有網絡和無網絡的環境下皆可運行,即它可以讓美工在瀏覽器查看頁面的靜態效果,也可以讓程序員在服務器查看帶數據的動態頁面效果。這是由于它支持 html 原型,然后在 html 標簽里增加額外的屬性來達到模板+數據的展示方式。瀏覽器解釋 html 時會忽略未定義的標簽屬性,所以 thymeleaf 的模板可以靜態地運行;當有數據返回到頁面時,Thymeleaf 標簽會動態地替換掉靜態內容,使頁面動態顯示。


  • 2.Thymeleaf 開箱即用的特性。它提供標準和spring標準兩種方言,可以直接套用模板實現JSTL、 OGNL表達式效果,避免每天套模板、該jstl、改標簽的困擾。同時開發人員也可以擴展和創建自定義的方言。


  • 3.Thymeleaf 提供spring標準方言和一個與 SpringMVC 完美集成的可選模塊,可以快速的實現表單綁定、屬性編輯器、國際化等功能。


  • 標準表達式語法
    它們分為四類:
  • 1.變量表達式

  • 2.選擇或星號表達式

  • 3.文字國際化表達式

  • 4.URL表達式

  • 變量表達式
    變量表達式即OGNL表達式或Spring EL表達式(在Spring術語中也叫model attributes)。如下所示:
    ${session.user.name}
    它們將以HTML標簽的一個屬性來表示:
    <span th:text="${book.author.name}"> 
    <li th:each="book : ${books}">

    選擇(星號)表達式
    選擇表達式很像變量表達式,不過它們用一個預先選擇的對象來代替上下文變量容器(map)來執行,如下:
    *{customer.name}
    被指定的object由th:object屬性定義:
     <div th:object="${book}"> 
    ...
    <span th:text="*{title}">...</span>
    ...
    </div>

    文字國際化表達式
    文字國際化表達式允許我們從一個外部文件獲取區域文字信息(.properties),用Key索引Value,還可以提供一組參數(可選).
     #{main.title} 
    #{message.entrycreated(${entryId})}

    可以在模板文件中找到這樣的表達式代碼:
     <table> 
    ...
    <th th:text="#{header.address.city}">...</th>
    <th th:text="#{header.address.country}">...</th>
    ...
    </table>

    URL表達式
    URL表達式指的是把一個有用的上下文或回話信息添加到URL,這個過程經常被叫做URL重寫。
    @{/order/list}
    URL還可以設置參數:
    @{/order/details(id=${orderId})}
    相對路徑:
    @{../documents/report}
    讓我們看這些表達式:
     <form th:action="@{/createOrder}"> 
    <a href="main.html" th:href="@{/main}">

    變量表達式和星號表達有什么區別嗎?
    如果不考慮上下文的情況下,兩者沒有區別;星號語法評估在選定對象上表達,而不是整個上下文
    什么是選定對象?就是父標簽的值,如下:
     <div th:object="${session.user}">
    <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
    <p>Surname: <span th:text="*{lastName}">Pepper</span>.</p>
    <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
    </div>

    這是完全等價于:
     <div th:object="${session.user}">
    <p>Name: <span th:text="${session.user.firstName}">Sebastian</span>.</p>
    <p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p>
    <p>Nationality: <span th:text="${session.user.nationality}">Saturn</span>.</p>
    </div>

    當然,美元符號和星號語法可以混合使用:
     <div th:object="${session.user}">
    <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
    <p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p>
    <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
    </div>

    表達式支持的語法
    字面(Literals)
  • 文本文字(Text literals): 'one text', 'Another one!',…

  • 數字文本(Number literals): 0, 34, 3.0, 12.3,…

  • 布爾文本(Boolean literals): true, false

  • 空(Null literal): null

  • 文字標記(Literal tokens): one, sometext, main,…

  • 文本操作(Text operations)
  • 字符串連接(String concatenation): +

  • 文本替換(Literal substitutions): |The name is ${name}|

  • 算術運算(Arithmetic operations)
  • 二元運算符(Binary operators): +, -, *, /, %

  • 減號(單目運算符)Minus sign (unary operator): -

  • 布爾操作(Boolean operations)
  • 二元運算符(Binary operators):and, or

  • 布爾否定(一元運算符)Boolean negation (unary operator):!, not

  • 比較和等價(Comparisons and equality)
  • 比較(Comparators): >, <, >=, <= (gt, lt, ge, le)

  • 等值運算符(Equality operators):==, != (eq, ne)

  • 條件運算符(Conditional operators)
  • If-then: (if) ? (then)

  • If-then-else: (if) ? (then) : (else)

  • Default: (value) ?: (defaultvalue)

  • 所有這些特征可以被組合并嵌套:
    'User is of type ' + (${user.isAdmin()} ? 'Administrator' : (${user.type} ?: 'Unknown'))

    常用th標簽都有那些?


    關鍵字
    功能介紹
    案例




    th:id
    替換id
    <input th:id="'xxx' + ${collect.id}"/>


    th:text
    文本替換
    <p th:text="${collect.description}">description</p>


    th:utext
    支持html的文本替換
    <p th:utext="${htmlcontent}">conten</p>


    th:object
    替換對象
    <div th:object="${session.user}">


    th:value
    屬性賦值
    <input th:value="${user.name}" />


    th:with
    變量賦值運算
    <div th:with="isEven=${prodStat.count}%2==0"></div>


    th:style
    設置樣式
    th:style="'display:' + @{(${sitrue} ? 'none' : 'inline-block')} + ''"


    th:onclick
    點擊事件
    th:onclick="'getCollect()'"


    th:each
    屬性賦值
    tr th:each="user,userStat:${users}">


    th:if
    判斷條件
    <a th:if="${userId == collect.userId}" >


    th:unless
    和th:if判斷相反
    <a th:href="@{/login}" th:unless=${session.user != null}>Login</a>


    th:href
    鏈接地址
    <a th:href="@{/login}" th:unless=${session.user != null}>Login</a> />


    th:switch
    多路選擇 配合th:case 使用
    <div th:switch="${user.role}">


    th:case
    th:switch的一個分支
    <p th:case="'admin'">User is an administrator</p>


    th:fragment
    布局標簽,定義一個代碼片段,方便其它地方引用
    <div th:fragment="alert">


    th:include
    布局標簽,替換內容到引入的文件
    <head th:include="layout :: htmlhead" th:with="title='xx'"></head> />


    th:replace
    布局標簽,替換整個標簽到引入的文件
    <div th:replace="fragments/header :: title"></div>


    th:selected
    selected選擇框 選中
    th:selected="(${xxx.id} == ${configObj.dd})"


    th:src
    圖片類地址引入
    <img class="img-responsive" alt="App Logo" th:src="@{/img/logo.png}" />


    th:inline
    定義js腳本可以使用變量
    <script type="text/javascript" th:inline="javascript">


    th:action
    表單提交的地址
    <form action="subscribe.html" th:action="@{/subscribe}">


    th:remove
    刪除某個屬性
    <tr th:remove="all"> 1.all:刪除包含標簽和所有的孩子。2.body:不包含標記刪除,但刪除其所有的孩子。3.tag:包含標記的刪除,但不刪除它的孩子。4.all-but-first:刪除所有包含標簽的孩子,除了第一個。5.none:什么也不做。這個值是有用的動態評估。


    th:attr
    設置標簽屬性,多個屬性可以用逗號分隔
    比如 th:attr="src=@{/image/aa.jpg},title=#{logo}",此標簽不太優雅,一般用的比較少。


    還有非常多的標簽,這里只列出最常用的幾個,由于一個標簽內可以包含多個th:x屬性,其生效的優先級順序為:
    include,each,if/unless/switch/case,with,attr/attrprepend/attrappend,value/href,src ,etc,text/utext,fragment,remove。
    幾種常用的使用方法
    1、賦值、字符串拼接
     <p th:text="${collect.description}">description</p>
    <span th:text="'Welcome to our application, ' + ${user.name} + '!'">

    字符串拼接還有另外一種簡潔的寫法
    <span th:text="|Welcome to our application, ${user.name}!|">

    2、條件判斷 If/Unless
    Thymeleaf中使用th:if和th:unless屬性進行條件判斷,下面的例子中,<a>標簽只有在th:if中條件成立時才顯示:
    <a th:if="${myself=='yes'}" > </i> </a>
    <a th:unless=${session.user != null} th:href="@{/login}" >Login</a>

    th:unless于th:if恰好相反,只有表達式中的條件不成立,才會顯示其內容。
    也可以使用 (if) ? (then) : (else) 這種語法來判斷顯示的內容
    3、for 循環
     <tr th:each="collect,iterStat : ${collects}"> 
    <th scope="row" th:text="${collect.id}">1</th>
    <td >
    <img th:src="${collect.webLogo}"/>
    </td>
    <td th:text="${collect.url}">Mark</td>
    <td th:text="${collect.title}">Otto</td>
    <td th:text="${collect.description}">@mdo</td>
    <td th:text="${terStat.index}">index</td>
    </tr>

    iterStat稱作狀態變量,屬性有:
  • index:當前迭代對象的index(從0開始計算)

  • count: 當前迭代對象的index(從1開始計算)

  • size:被迭代對象的大小

  • current:當前迭代變量

  • even/odd:布爾值,當前循環是否是偶數/奇數(從0開始計算)

  • first:布爾值,當前循環是否是第一個

  • last:布爾值,當前循環是否是最后一個

  • 4、URL
    URL在Web應用模板中占據著十分重要的地位,需要特別注意的是Thymeleaf對于URL的處理是通過語法@{...}來處理的。
    如果需要Thymeleaf對URL進行渲染,那么務必使用th:href,th:src等屬性,下面是一個例子
    <!-- Will produce 'http://localhost:8080/standard/unread' (plus rewriting) -->
    <a th:href="@{/standard/{type}(type=${type})}">view</a>
    <!-- Will produce '/gtvg/order/3/details' (plus rewriting) -->
    <a href="details.html" th:href="@{/order/{orderId}/details(orderId=${o.id})}">view</a>

    設置背景
    <div th:style="'background:url(' + @{/<path-to-image>} + ');'"></div>

    根據屬性值改變背景
     <div class="media-object resource-card-image" th:style="'background:url(' + @{(${collect.webLogo}=='' ? 'img/favicon.png' : ${collect.webLogo})} + ')'" ></div>

    幾點說明:
  • 上例中URL最后的(orderId=${o.id}) 表示將括號內的內容作為URL參數處理,該語法避免使用字符串拼接,大大提高了可讀性

  • @{...}表達式中可以通過{orderId}訪問Context中的orderId變量

  • @{/order}是Context相關的相對路徑,在渲染時會自動添加上當前Web應用的Context名字,假設context名字為app,那么結果應該是/app/order

  • 5、內聯js
    內聯文本:[[...]]內聯文本的表示方式,使用時,必須先用th:inline="text/javascript/none"激活,th:inline可以在父級標簽內使用,甚至作為body的標簽。內聯文本盡管比th:text的代碼少,不利于原型顯示。
    <script th:inline="javascript">
    /*<![CDATA[*/
    ...
    var username = /*[[${sesion.user.name}]]*/ 'Sebastian';
    var size = /*[[${size}]]*/ 0;
    ...
    /*]]>*/
    </script>

    js附加代碼:
    /*[+
    var msg = 'This is a working application';
    +]*/

    js移除代碼:
    /*[- */
    var msg = 'This is a non-working template';
    /* -]*/

    6、內嵌變量
    為了模板更加易用,Thymeleaf還提供了一系列Utility對象(內置于Context中),可以通過#直接訪問:
  • dates : java.util.Date的功能方法類。

  • calendars : 類似#dates,面向java.util.Calendar

  • numbers : 格式化數字的功能方法類

  • strings : 字符串對象的功能類,contains,startWiths,prepending/appending等等。

  • objects: 對objects的功能類操作。

  • bools: 對布爾值求值的功能方法。

  • arrays:對數組的功能類方法。

  • lists: 對lists功能類方法

  • sets

  • maps
    ...

  • 下面用一段代碼來舉例一些常用的方法:
    dates
    /*
    * Format date with the specified pattern
    * Also works with arrays, lists or sets
    */
    ${#dates.format(date, 'dd/MMM/yyyy HH:mm')}
    ${#dates.arrayFormat(datesArray, 'dd/MMM/yyyy HH:mm')}
    ${#dates.listFormat(datesList, 'dd/MMM/yyyy HH:mm')}
    ${#dates.setFormat(datesSet, 'dd/MMM/yyyy HH:mm')}
    /*
    * Create a date (java.util.Date) object for the current date and time
    */
    ${#dates.createNow()}
    /*
    * Create a date (java.util.Date) object for the current date (time set to 00:00)
    */
    ${#dates.createToday()}

    strings
    /*
    * Check whether a String is empty (or null). Performs a trim() operation before check
    * Also works with arrays, lists or sets
    */
    ${#strings.isEmpty(name)}
    ${#strings.arrayIsEmpty(nameArr)}
    ${#strings.listIsEmpty(nameList)}
    ${#strings.setIsEmpty(nameSet)}
    /*
    * Check whether a String starts or ends with a fragment
    * Also works with arrays, lists or sets
    */
    ${#strings.startsWith(name,'Don')} // also array*, list* and set*
    ${#strings.endsWith(name,endingFragment)} // also array*, list* and set*
    /*
    * Compute length
    * Also works with arrays, lists or sets
    */
    ${#strings.length(str)}
    /*
    * Null-safe comparison and concatenation
    */
    ${#strings.equals(str)}
    ${#strings.equalsIgnoreCase(str)}
    ${#strings.concat(str)}
    ${#strings.concatReplaceNulls(str)}
    /*
    * Random
    */
    ${#strings.randomAlphanumeric(count)}

    使用thymeleaf布局
    使用thymeleaf布局非常的方便
    定義代碼片段
    <footer th:fragment="copy"> 
    &copy; 2016
    </footer>

    在頁面任何地方引入:
    <body> 
    <div th:include="footer :: copy"></div>
    <div th:replace="footer :: copy"></div>
    </body>

    th:include 和 th:replace區別,include只是加載,replace是替換
    返回的HTML如下:
    <body> 
    <div> &copy; 2016 </div>
    <footer>&copy; 2016 </footer>
    </body>

    下面是一個常用的后臺頁面布局,將整個頁面分為頭部,尾部、菜單欄、隱藏欄,點擊菜單只改變content區域的頁面
    <body class="layout-fixed">
    <div th:fragment="navbar" class="wrapper" role="navigation">
    <div th:replace="fragments/header :: header">Header</div>
    <div th:replace="fragments/left :: left">left</div>
    <div th:replace="fragments/sidebar :: sidebar">sidebar</div>
    <div layout:fragment="content" id="content" ></div>
    <div th:replace="fragments/footer :: footer">footer</div>
    </div>
    </body>

    任何頁面想使用這樣的布局值只需要替換中見的 content模塊即可
     <html xmlns:th="http://www.thymeleaf.org" layout:decorator="layout">
    <body>
    <section layout:fragment="content">
    ...

    也可以在引用模版的時候傳參
    <head th:include="layout :: htmlhead" th:with="title='Hello'"></head>

    layout 是文件地址,如果有文件夾可以這樣寫 fileName/layout:htmlhead
    htmlhead 是指定義的代碼片段 如 th:fragment="copy"
    源碼案例
    這里有一個開源項目幾乎使用了這里介紹的所有標簽和布局,大家可以參考:
    cloudfavorites
    參考
    thymeleaf官方指南
    新一代Java模板引擎Thymeleaf
    Thymeleaf基本知識
    thymeleaf總結文章
    Thymeleaf 模板的使用
    thymeleaf 學習筆記


    作者:純潔的微笑
    出處:http://www.ityouknow.com/
    版權所有,歡迎保留原文鏈接進行轉載:)
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(4,363)

    • 個人分類:生活學習
    ▲top
    • 3月 07 週二 201721:17
    • spring boot(五):spring data jpa的使用


    Source: http://www.cnblogs.com/ityouknow/p/5891443.html
    在上篇文章springboot(二):web綜合開發中簡單介紹了一下spring data jpa的基礎性使用,這篇文章將更加全面的介紹spring data jpa 常見用法以及注意事項
    使用spring data jpa 開發時,發現國內對spring boot jpa全面介紹的文章比較少案例也比較零碎,因此寫文章總結一下。本人也正在翻譯Spring Data JPA 參考指南,有興趣的同學歡迎聯系我,一起加入翻譯中!
    spring data jpa介紹
    首先了解JPA是什么?
    JPA(Java Persistence API)是Sun官方提出的Java持久化規范。它為Java開發人員提供了一種對象/關聯映射工具來管理Java應用中的關系數據。他的出現主要是為了簡化現有的持久化開發工作和整合ORM技術,結束現在Hibernate,TopLink,JDO等ORM框架各自為營的局面。值得注意的是,JPA是在充分吸收了現有Hibernate,TopLink,JDO等ORM框架的基礎上發展而來的,具有易于使用,伸縮性強等優點。從目前的開發社區的反應上看,JPA受到了極大的支持和贊揚,其中就包括了Spring與EJB3.0的開發團隊。

    注意:JPA是一套規范,不是一套產品,那么像Hibernate,TopLink,JDO他們是一套產品,如果說這些產品實現了這個JPA規范,那么我們就可以叫他們為JPA的實現產品。


    spring data jpa
    Spring Data JPA 是 Spring 基于 ORM 框架、JPA 規范的基礎上封裝的一套JPA應用框架,可使開發者用極簡的代碼即可實現對數據的訪問和操作。它提供了包括增刪改查等在內的常用功能,且易于擴展!學習并使用 Spring Data JPA 可以極大提高開發效率!

    spring data jpa讓我們解脫了DAO層的操作,基本上所有CRUD都可以依賴于它來實現


    基本查詢
    基本查詢也分為兩種,一種是spring data默認已經實現,一種是根據查詢的方法來自動解析成SQL。
    預先生成方法
    spring data jpa 默認預先生成了一些基本的CURD的方法,例如:增、刪、改等等
    1 繼承JpaRepository
    public interface UserRepository extends JpaRepository<User, Long> {
    }

    2 使用默認方法
    @Test
    public void testBaseQuery() throws Exception {
    User user=new User();
    userRepository.findAll();
    userRepository.findOne(1l);
    userRepository.save(user);
    userRepository.delete(user);
    userRepository.count();
    userRepository.exists(1l);
    // ...
    }

    就不解釋了根據方法名就看出意思來
    自定義簡單查詢
    自定義的簡單查詢就是根據方法名來自動生成SQL,主要的語法是findXXBy,readAXXBy,queryXXBy,countXXBy, getXXBy后面跟屬性名稱:
    User findByUserName(String userName);

    也使用一些加一些關鍵字And、 Or
    User findByUserNameOrEmail(String username, String email);

    修改、刪除、統計也是類似語法
    Long deleteById(Long id);
    Long countByUserName(String userName)

    基本上SQL體系中的關鍵詞都可以使用,例如:LIKE、 IgnoreCase、 OrderBy。
    List<User> findByEmailLike(String email);
    User findByUserNameIgnoreCase(String userName);
    List<User> findByUserNameOrderByEmailDesc(String email);

    具體的關鍵字,使用方法和生產成SQL如下表所示


    Keyword
    Sample
    JPQL snippet




    And
    findByLastnameAndFirstname
    … where x.lastname = ?1 and x.firstname = ?2


    Or
    findByLastnameOrFirstname
    … where x.lastname = ?1 or x.firstname = ?2


    Is,Equals
    findByFirstnameIs,findByFirstnameEquals
    … where x.firstname = ?1


    Between
    findByStartDateBetween
    … where x.startDate between ?1 and ?2


    LessThan
    findByAgeLessThan
    … where x.age < ?1


    LessThanEqual
    findByAgeLessThanEqual
    … where x.age ⇐ ?1


    GreaterThan
    findByAgeGreaterThan
    … where x.age > ?1


    GreaterThanEqual
    findByAgeGreaterThanEqual
    … where x.age >= ?1


    After
    findByStartDateAfter
    … where x.startDate > ?1


    Before
    findByStartDateBefore
    … where x.startDate < ?1


    IsNull
    findByAgeIsNull
    … where x.age is null


    IsNotNull,NotNull
    findByAge(Is)NotNull
    … where x.age not null


    Like
    findByFirstnameLike
    … where x.firstname like ?1


    NotLike
    findByFirstnameNotLike
    … where x.firstname not like ?1


    StartingWith
    findByFirstnameStartingWith
    … where x.firstname like ?1 (parameter bound with appended %)


    EndingWith
    findByFirstnameEndingWith
    … where x.firstname like ?1 (parameter bound with prepended %)


    Containing
    findByFirstnameContaining
    … where x.firstname like ?1 (parameter bound wrapped in %)


    OrderBy
    findByAgeOrderByLastnameDesc
    … where x.age = ?1 order by x.lastname desc


    Not
    findByLastnameNot
    … where x.lastname <> ?1


    In
    findByAgeIn(Collection ages)
    … where x.age in ?1


    NotIn
    findByAgeNotIn(Collection age)
    … where x.age not in ?1


    TRUE
    findByActiveTrue()
    … where x.active = true


    FALSE
    findByActiveFalse()
    … where x.active = false


    IgnoreCase
    findByFirstnameIgnoreCase
    … where UPPER(x.firstame) = UPPER(?1)


    復雜查詢
    在實際的開發中我們需要用到分頁、刪選、連表等查詢的時候就需要特殊的方法或者自定義SQL
    分頁查詢
    分頁查詢在實際使用中非常普遍了,spring data jpa已經幫我們實現了分頁的功能,在查詢的方法中,需要傳入參數Pageable
    ,當查詢中有多個參數的時候Pageable建議做為最后一個參數傳入
    Page<User> findALL(Pageable pageable);
    Page<User> findByUserName(String userName,Pageable pageable);

    Pageable 是spring封裝的分頁實現類,使用的時候需要傳入頁數、每頁條數和排序規則
    @Test
    public void testPageQuery() throws Exception {
    int page=1,size=10;
    Sort sort = new Sort(Direction.DESC, "id");
    Pageable pageable = new PageRequest(page, size, sort);
    userRepository.findALL(pageable);
    userRepository.findByUserName("testName", pageable);
    }

    限制查詢
    有時候我們只需要查詢前N個元素,或者支取前一個實體。
    ser findFirstByOrderByLastnameAsc();
    User findTopByOrderByAgeDesc();
    Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);
    List<User> findFirst10ByLastname(String lastname, Sort sort);
    List<User> findTop10ByLastname(String lastname, Pageable pageable);

    自定義SQL查詢
    其實Spring data 覺大部分的SQL都可以根據方法名定義的方式來實現,但是由于某些原因我們想使用自定義的SQL來查詢,spring data也是完美支持的;在SQL的查詢方法上面使用@Query注解,如涉及到刪除和修改在需要加上@Modifying.也可以根據需要添加 @Transactional 對事物的支持,查詢超時的設置等
    @Modifying
    @Query("update User u set u.userName = ?1 where c.id = ?2")
    int modifyByIdAndUserId(String userName, Long id);
    @Transactional
    @Modifying
    @Query("delete from User where id = ?1")
    void deleteByUserId(Long id);
    @Transactional(timeout = 10)
    @Query("select u from User u where u.emailAddress = ?1")
    User findByEmailAddress(String emailAddress);

    多表查詢
    多表查詢在spring data jpa中有兩種實現方式,第一種是利用hibernate的級聯查詢來實現,第二種是創建一個結果集的接口來接收連表查詢后的結果,這里主要第二種方式。
    首先需要定義一個結果集的接口類。
    public interface HotelSummary {
    City getCity();
    String getName();
    Double getAverageRating();
    default Integer getAverageRatingRounded() {
    return getAverageRating() == null ? null : (int) Math.round(getAverageRating());
    }
    }

    查詢的方法返回類型設置為新創建的接口
    @Query("select h.city as city, h.name as name, avg(r.rating) as averageRating "
    - "from Hotel h left outer join h.reviews r where h.city = ?1 group by h")
    Page<HotelSummary> findByCity(City city, Pageable pageable);
    @Query("select h.name as name, avg(r.rating) as averageRating "
    - "from Hotel h left outer join h.reviews r group by h")
    Page<HotelSummary> findByCity(Pageable pageable);

    使用
    Page<HotelSummary> hotels = this.hotelRepository.findByCity(new PageRequest(0, 10, Direction.ASC, "name"));
    for(HotelSummary summay:hotels){
    System.out.println("Name" +summay.getName());
    }

    在運行中Spring會給接口(HotelSummary)自動生產一個代理類來接收返回的結果,代碼匯總使用getXX的形式來獲取


    多數據源的支持
    同源數據庫的多源支持
    日常項目中因為使用的分布式開發模式,不同的服務有不同的數據源,常常需要在一個項目中使用多個數據源,因此需要配置sping data jpa對多數據源的使用,一般分一下為三步:
  • 1 配置多數據源

  • 2 不同源的實體類放入不同包路徑

  • 3 聲明不同的包路徑下使用不同的數據源、事務支持

  • 這里有一篇文章寫的很清楚:Spring Boot多數據源配置與使用
    異構數據庫多源支持
    比如我們的項目中,即需要對mysql的支持,也需要對mongodb的查詢等。
    實體類聲明@Entity 關系型數據庫支持類型、聲明@Document 為mongodb支持類型,不同的數據源使用不同的實體就可以了
    interface PersonRepository extends Repository<Person, Long> {
    …
    }
    @Entity
    public class Person {
    …
    }
    interface UserRepository extends Repository<User, Long> {
    …
    }
    @Document
    public class User {
    …
    }

    但是,如果User用戶既使用mysql也使用mongodb呢,也可以做混合使用
    interface JpaPersonRepository extends Repository<Person, Long> {
    …
    }
    interface MongoDBPersonRepository extends Repository<Person, Long> {
    …
    }
    @Entity
    @Document
    public class Person {
    …
    }

    也可以通過對不同的包路徑進行聲明,比如A包路徑下使用mysql,B包路徑下使用mongoDB
    @EnableJpaRepositories(basePackages = "com.neo.repositories.jpa")
    @EnableMongoRepositories(basePackages = "com.neo.repositories.mongo")
    interface Configuration { }

    其它
    使用枚舉
    使用枚舉的時候,我們希望數據庫中存儲的是枚舉對應的String類型,而不是枚舉的索引值,需要在屬性上面添加@Enumerated(EnumType.STRING) 注解
    @Enumerated(EnumType.STRING) 
    @Column(nullable = true)
    private UserType type;

    不需要和數據庫映射的屬性
    正常情況下我們在實體類上加入注解@Entity,就會讓實體類和表相關連如果其中某個屬性我們不需要和數據庫來關聯只是在展示的時候做計算,只需要加上@Transient屬性既可。
    @Transient
    private String userName;

    源碼案例
    這里有一個開源項目幾乎使用了這里介紹的所有標簽和布局,大家可以參考:
    cloudfavorites
    參考
    Spring Data JPA - Reference Documentation
    Spring Data JPA——參考文檔 中文版


    作者:純潔的微笑
    出處:http://www.ityouknow.com/
    版權所有,歡迎保留原文鏈接進行轉載:)
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(92)

    • 個人分類:生活學習
    ▲top
    • 3月 07 週二 201721:17
    • spring boot 實戰:我們的第一款開源軟件

    Source: http://www.cnblogs.com/ityouknow/p/5909460.html
    在信息爆炸時代,如何避免持續性信息過剩,使自己變得專注而不是被紛繁的信息所累?每天會看到各種各樣的新聞,各種新潮的技術層出不窮,如何篩選出自己所關心的?
    各位看官會想,我們是來看開源軟件的,你給我扯什么信息干嘛,別著急,聽我慢慢道來。
     
    背景
    瀏覽器收藏夾應該是我們在收藏文章、網站的第一個利器,平時遇到喜歡的網站或者文章很方便的收藏到收藏夾中;很快我們的收藏夾就滿了,于是就像我這樣,創建文件夾來分組兩層、三層都有:
    favorites_chrome
    有的也會借助百度首頁導航這樣的一些功能來整理自己收藏的網站,以前我記得QQ還有一款產品叫做網絡收藏夾,用過一段時間,后來QQ也把這款產品給淘汰了;也嘗試了去用印象筆記、有道筆記這些產品,這些產品都偏向收藏一些具體的文章或者自己整理的日志信息方面。
    當瀏覽器收藏夾收藏的網站或者文章在一百份以內的時候收藏和查找問題都不是特別大。當收藏大于1000份的時候,去查找自己收藏的內容絕對是個體力活,另外還有一些文章我僅僅只是暫時保存下來,準備隨后找時間看看就行,也需要收藏、整理、刪除的時候就很麻煩。
     
    產品介紹
    于是在這樣的背景下,我就想著需要做這么一款產品,可以方便隨時隨地的收藏我喜歡的文章或者網站,方便整理,我日后需要的時候非常方便的去檢索,另外如果可以的話,我是否可以分享我自己收藏的文章或者網站,同時也可以看看大牛們或者是同行都收藏了什么文章我是否感興趣,于是就開發了這么一款產品:云收藏
    核心功能點:
  • 收藏、分類、檢索文章

  • 導出、導出(包活從瀏覽器中)

  • 可以點贊、分享、討論

  • 注冊、登錄、個人賬戶

  • 臨時收藏、查看別人收藏

  • 其它…

  • 放產品一些截圖:
    主頁
    favorites_chrome

    注冊
    favorites_chrome

    首頁
    favorites_chrome

    收藏
    favorites_chrome

     
     
    技術點
    這段時間我們團隊主要在學習spring boot,這個開源項目也就成了我們的練習新技術的一個非常好的產品,主要的技術都是和spring boot相關,可以參考我以前文章構建微服務:spring boot系列文章
     
    網頁端
    網頁端收藏夾主頁
    收藏快捷圖標
    這個是收藏的最關鍵一步,一段js代碼,拖入到瀏覽器的收藏夾,每次點擊收藏的時候負責讀取網站的title、描述、網址等信息,并且提交到收藏的頁面
    前端
    前端頁面由Angle - Bootstrap Admin theme這套主題改造而來;模版引擎使用了thymeleaf,可以參考這篇文章:springboot(四):thymeleaf使用詳解
    持久層
    數據庫主要使用了 Spring data jpa模版來實現,可以參考這篇文章:springbooot(五):spring data jpa的使用
    session
    session使用持久化技術來保存登錄狀態,登錄一次保持需要會話30天,主要是依賴redis來實現,參考:springboot(三):Spring boot中Redis的使用
    其它
    使用grade做為項目的構建工具、使用了一點webjars、vuejs、Jsoup、Scheduled …
     
    客戶端
    客戶端技術使用react native來開發安卓和IOS的app,目前還在開發中,完成之后也會開源出來。
     
    未來計劃做的內容
    這個開源產品暫時只是開源了我們web端產品,安卓端、IOS端內容的開發還在進行中。
    未來我們還會持續的來完善這些產品,做一些有意思的小功能,以下可能是我們近期準備要做的
  • 可以自定義個人收藏頁面

  • 無登錄可以查看熱門收藏內容

  • 首頁展示熱門收藏家

  • 小紙條

  • 智能推薦

  • 其它…

  • 大家有什么更好玩想法,也可以在建議給我們
     
    產品主頁
    產品地址
    源碼地址
     


    作者:純潔的微笑
    出處:http://www.ityouknow.com/
    版權所有,歡迎保留原文鏈接進行轉載:)

     
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(4)

    • 個人分類:生活學習
    ▲top
    • 3月 07 週二 201721:17
    • linux定時備份mysql并同步到其它服務器


    Source: http://www.cnblogs.com/ityouknow/p/5923489.html
    數據在任何一家公司里面都是最核心的資產,定期備份則是為了保證數據庫出現問題的時候能夠及時回滾到最近的備份點,將損失縮小到最小
    這篇文章將會兩部分來說明:1、mysql的定期備份;2、同步到其它服務器
    mysql 備份
    備份還原某個數據庫
    備份還原
    # 導出數據庫
    /usr/bin/mysqldump -u root -ppwd database > database20160929.sql
    # 導入數據庫
    mysql -u root -p database < database20160929.sql

    備份到壓縮文件從壓縮文件導入
    #備份到壓縮文件
    /usr/bin/mysqldump -u root -ppwd database | gzip > database20160929.sql.gz
    #從壓縮文件導入
    gzip < database20160929.sql.gz | mysql -u root -p database

    crontab定時備份
    1、創建備份目錄
    # root 用戶,創建備份目錄
    mkdir -p /bak/mysqlbak
    cd /bak/mysqldata

    2、編寫運行腳本
    vi /usr/sbin/bakmysql.sh
    腳本代碼:
    #!/bin/bash
    # Name:bakmysql.sh
    # This is a ShellScript For Auto DB Backup and Delete old Backup
    #
    backupdir=/bak/mysqlbak
    time=` date +%Y%m%d%H `
    mysql_bin_dir/mysqldump -u root -ppwd database | gzip > $backupdir/database$time.sql.gz
    #
    find $backupdir -name "name_*.sql.gz" -type f -mtime +7 -exec rm {} ; > /dev/null 2>&1
    #

    腳本說明:
  • backupdir mysql備份地址

  • root mysql用戶名

  • pwd mysql密碼

  • database 數據庫名

  • mysql_bin_dir mysql的bin路徑;

  • time=` date +%Y%m%d%H `也可以寫為time="$(date +"%Y%m%d$H")"其中`符號是TAB鍵上面的符號,不是ENTER左邊的'符號,還有date后要有一個空格。

  • type f 表示查找普通類型的文件,f表示普通文件。

  • mtime +7 按照文件的更改時間來查找文件,+5表示文件更改時間距現在7天以前;如果是 -mmin +5 表示文件更改時間距現在5分鐘以前。

  • exec rm {} \ 表示執行一段shell命令,exec選項后面跟隨著所要執行的命令或腳本,然后是一對兒{},一個空格和一個\,最后是一個分號。

  • /dev/null 2>&1 把標準出錯重定向到標準輸出,然后扔到/DEV/NULL下面去。通俗的說,就是把所有標準輸出和標準出錯都扔到垃圾桶里面;其中的& 表示讓該命令在后臺執行。

  • 3、為腳本添加執行權限
    # chmod +x /usr/sbin/bakmysql.sh
    4、設置crontab定時執行
    vi /etc/crontab
    #在最后一行中加入:
    00 3 * * * root /usr/sbin/bakmysql.sh
    #表示每天3點00分執行備份

    注:crontab配置文件格式如下:
    分 時 日 月 周  命令


    5、重啟crontab
    /etc/rc.d/init.d/crond restart
    這樣就完了定時備份并清理前7天的備份數據
    同步到其它服務器
    這里使用Linux同步文件工具rsync+inotify來進行文件的同步
    rsync
    rsync是類unix系統下的數據鏡像備份工具——remote sync。一款快速增量備份工具 Remote Sync,遠程同步 支持本地復制,或者與其他SSH、rsync主機同步
    用法
    rsync src dest
    這是最簡單的用法,表示同步src,dest文件。(即,執行之后,dest的文件與src的相同,以src的為準)
    常用選項

    • -a: 等價于-rlptgoD,歸檔式

    • -r: 遞歸

    • -l: 復制軟件鏈接

    • -p: 保留權限信息

    • -t: 將src的修改時間,同步到dest

    • -g: 同步組信息(group)

    • -o: 同步擁有者信息(own)

    • -D: 保持字符與塊設備文件

    • -z: 啟用壓縮傳輸

    • -–delete:如果src沒有此文件,那么dest也不能有,即在dest刪除src里沒有的文件。(如果你使用這個選項,就必須搭配-r選項一起)


    ## 將本地/bak/mysqlbak/文件同步到 遠程服務器 /bak/mysql/bak 目錄下面 排除 mysqlbak/index目錄 通過ssh端口
    rsync -vzacu /bak/mysqlbak/ root@192.168.53.86:/bak/mysqlbak --exclude "mysqlbak/index" -e "ssh -p 22"
    # 將遠程目錄 /bak/mysqlbak下的文件同步到本地 /bak/mysqlbak/目錄下
    rsync -vzrtopg --progress --delete root@192.168.53.85:/bak/mysqlbak /bak

    啟用rsync服務器端同步遠程文件
    rsycn的服務端為服務器的文件接收端,rsycn的客戶端為服務器的文件推動端。
    rsycn的服務端/文件接收端配置
    服務端需要開啟rsyncd服務
    添加配置文件rsyncd.conf
    vi /etc/rsyncd.conf
    #以下是全局配置
    log file = /var/log/rsyncd.log
    pid file = /var/run/rsyncd.pid
    lock file = /var/lock/rsyncd
    [mysqlbak] #模塊名,在源服務器指定這個名字
    comment = sync rsync/home #描述信息
    path = /bak/mysqlbak #備份目錄
    use chroot=no #不使用chroot,不用root權限
    read only = no #設置本地備份目錄為讀寫權限
    uid=root
    gid=root
    max connections=10 #客戶端最大連接數
    auth users = root #指定數據同步用戶
    secrets file = /etc/rsyncd.pass #指定數據同步用戶信息文件
    hosts allow=192.168.53.0/85 #允許連接的客戶端
    ignore errors = yes #忽略出現I/O錯誤
    timeout = 600

    創建認證文件
    vi /etc/rsyncd.pass
    ##代碼
    root:root #格式是用戶名:密碼
    #屬主要有權限讀這個文件,否則會報沒權限
    chmod 600 /etc/rsyncd.pass

    修改/etc/xinetd.d/rsync文件,disable 改為 no
    service rsync
    {
    disable = no
    socket_type = stream
    wait = no
    user = root
    server = /usr/bin/rsync
    server_args = --daemon
    log_on_failure += USERID
    }

    啟動服務端
    rsync --daemon --config=/etc/rsyncd.conf
    rsycn的客戶端/文件發送端配置
    客戶端配置簡單 只需要配置密碼既可
    vi /etc/rsync_client.pwd
    ##代碼
    root #只需要填寫rsync服務的密碼
    #屬主要有權限讀這個文件,否則會報沒權限
    chmod 600 /etc/rsync_client.pwd

    客戶端同步測試
    /usr/bin/rsync -auvrtzopgP --progress --password-file=/etc/rsync_client.pwd /bak/mysqlbak/ root@192.168.53.86::mysqlbak

    rsync只是一次性同步,如果需要實時同步就需要引入另一個工具了


    inotify
    Inotify 是一種強大的、細粒度的、異步的文件系統事件監控機制,linux內核從2.6.13起,加入了Inotify支持,通過Inotify可以監控文件系統中添加、刪除,修改、移動等各種細微事件,利用這個內核接口,第三方軟件就可以監控文件系統下文件的各種變化情況,而inotify-tools就是這樣的一個第三方軟件。

    Inotify只需要要按照部署在同步的客戶端,當監控的文件有變化觸動 rsync腳本來同步


    安裝
    yum install inotify-tools
    配置監控的文件路徑
    vi /etc/inotify_exclude.lst
    #代碼
    /bak/mysqlbak #監控目錄
    @/bak/log #排除監控目錄

    rsync排除監控文件目錄
    vi /etc/rsyncd.d/rsync_exclude.lst
    #代碼
    src/*.html*
    src/js/
    src/2014/20140[1-9]/

    客戶端同步到遠程的腳本rsync.sh
    #rsync auto sync script with inotify
    #variables
    current_date=$(date +%Y%m%d_%H%M%S)
    source_path=/bak/mysqlbak/
    log_file=/var/log/rsync_client.log
    #rsync
    rsync_server=192.168.53.86
    rsync_user=root
    rsync_pwd=/etc/rsync_client.pwd
    rsync_module=mysqlbak
    INOTIFY_EXCLUDE='(.*/*\.log|.*/*\.swp)$|^/tmp/src/mail/(2014|20.*/.*che.*)'
    RSYNC_EXCLUDE='/bak/rsync_exclude.lst'
    #rsync client pwd check
    if [ ! -e ${rsync_pwd} ];then
    echo -e "rsync client passwod file ${rsync_pwd} does not exist!"
    exit 0
    fi
    #inotify_function
    inotify_fun(){
    /usr/bin/inotifywait -mrq --timefmt '%Y/%m/%d-%H:%M:%S' --format '%T %w %f' \
    --exclude ${INOTIFY_EXCLUDE} -e modify,delete,create,move,attrib ${source_path} \
    | while read file
    do
    /usr/bin/rsync -auvrtzopgP --exclude-from=${RSYNC_EXCLUDE} --progress --bwlimit=200 --password-file=${rsync_pwd} ${source_path} ${rsync_user}@${rsync_server}::${rsync_module}
    done
    }
    #inotify log
    inotify_fun >> ${log_file} 2>&1 &

    給腳本執行權限,執行后就可以了
    chmod 777 rsync.sh
    ./rsync.sh

    參考:
    Linux下同步工具inotify+rsync使用詳解


    作者:純潔的微笑
    出處:http://www.ityouknow.com/
    版權所有,歡迎保留原文鏈接進行轉載 :)
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(5)

    • 個人分類:生活學習
    ▲top
    • 3月 07 週二 201721:17
    • python3爬取1024圖片

    list
    Source: http://www.cnblogs.com/ityouknow/p/6013074.html
    這兩年python特別火,火到博客園現在也是隔三差五的出現一些python的文章。各種開源軟件、各種爬蟲算法紛紛開路,作為互聯網行業的IT狗自然看的我也是心癢癢,于是趁著這個霧霾橫行的周末瞅了兩眼,作為一名老司機覺得還是應該以練帶學,1024在程序員界這么流行的網站,當然拿來先練一練。
    python自稱是以自然語言的視角來編程,特點是開發快,語言簡潔,沒那么多技巧,大名鼎鼎的豆瓣、youtube都是使用python開發的網站,看來python在大規模使用這個方面來講應該沒有啥子問題;python也不是沒有缺點在性能方面就Java、C++等老前輩還是沒得比的,另外python和nodejs一樣只能使用CPU單核,也是性能方面影響是因素之一。但python在特定領域表現突出,特別是腳本、爬蟲、科學算法等。

    好了,還是說正事如何爬取1024網站的圖片


    分析
    列表頁面
    首先進入1024的導航網站,隨便點擊一個地址進入選擇圖片區或者在網站地址后面添加thread0806.php?fid=16&search=&page=,這就是1024網站的圖片區,這個爬蟲就是主要抓取這個區域的所有圖片,使用瀏覽器debug分析一下這個頁面發現基本都是列表頁,格式如下:
    在地址欄http://xxxxxx.biz/thread0806.php?fid=16&search=&page=后面拼1、2、3等于就是訪問圖片區第一頁、第二頁、第三頁的列表頁。根據這些列表頁就可以爬出具體的每一個圖片頁的地址,類似上圖的地址:htm_data/16/1611/2114702.html 在地址的前面拼接上主站地址就是具體的圖片頁了。所以根據以上的分析:通過循環地址欄找到不同的列表頁在根據列表頁找到具體的圖片頁

    地址欄->圖片列表->圖片頁地址


    獲取列表頁圖片地址代碼如下:
    import urllib.request,socket,re,sys,os
    baseUrl='http://xxxx.biz/'
    def getContant(Weburl):
    Webheader= {'Upgrade-Insecure-Requests':'1',
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.103 Safari/537.36',}
    req = urllib.request.Request(url = Weburl,headers=Webheader)
    respose = urllib.request.urlopen(req)
    _contant = respose.read()
    respose.close()
    return str(_contant)
    def getUrl(URL):
    pageIndex = 1
    for i in range(1,int(pageIndex)+1):
    Weburl = URL + str(i)
    contant = getContant(Weburl)
    comp = re.compile(r'<a href="htm_data.{0,30}html" target="_blank" id=""><font color=g')
    urlList1 = comp.findall(contant)
    comp = re.compile(r'a href="(.*?)"')
    urlList2 = comp.findall(str(urlList1))
    urlList = []
    for url1 in urlList2:
    url2 = baseUrl+url1
    urlList.append(url2)
    return urlList
    URL = baseUrl+'thread0806.php?fid=16&search=&page='
    UrlList = getUrl(URL)
    print(UrlList)

    在這個地址后面拼接1到N就是不同的列表頁


    圖片頁面
    利用瀏覽器debug一下頁面,圖片基本上都是外鏈地址,以http或者https開頭以jpg、png、gif結尾,寫個正則表達式匹配這些地址,然后交給程序下載就OK了。
    頁面代碼如下:
    在下載過程中遇到了幾個問題,就是有的頁面會報403禁止訪問等,應該是網站加了一些防止爬蟲的手段,網上找了下加上header參數來模擬瀏覽器訪問就解決了;
    下載單個頁面代碼如下:
    import urllib.request,socket,re,sys,os
    #定義文件保存路徑
    targetPath = "D:\\temp\\1024\\1"
    def openUrl(url):
    headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) ' 'Chrome/51.0.2704.63 Safari/537.36'
    }
    req = urllib.request.Request(url=url, headers=headers)
    res = urllib.request.urlopen(req)
    data = res.read()
    downImg(data)
    def downImg(data):
    for link,t in set(re.findall(r'([http|https]:[^\s]*?(jpg|png|gif))', str(data))):
    if link.startswith('s'):
    link='http'+link
    else:
    link='htt'+link
    print(link)
    try:
    opener=urllib.request.build_opener()
    opener.addheaders=[('User-Agent','Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1941.0 Safari/537.36')]
    urllib.request.install_opener(opener)
    urllib.request.urlretrieve(link,saveFile(link))
    except:
    print('失敗')
    def saveFile(path):
    #檢測當前路徑的有效性
    if not os.path.isdir(targetPath):
    os.mkdir(targetPath)
    #設置每個圖片的路徑
    pos = path.rindex('/')
    t = os.path.join(targetPath,path[pos+1:])
    return t
    url = "http://xxxx.biz/htm_data/16/1611/2115193.html"
    openUrl(url)

    批量爬取
    批量爬取有兩個工作要做,第一for循環目標內的所有列表頁,第二為了避免重復爬取,需要給每個頁面建立唯一的文件夾,下次爬取的時候如果存在直接跳過。最后在理一下所有的爬取步驟:

    循環地址欄->找出圖片頁列表->圖片頁分析找出圖片地址->為圖片頁建立唯一的文件夾->開始下載頁面圖片


    完整的代碼如下:
    import urllib.request,socket,re,sys,os
    baseUrl='http://xxxx.biz/'
    targetPath = "D:\\temp\\1024\\"
    def getContant(Weburl):
    Webheader= {'Upgrade-Insecure-Requests':'1',
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.103 Safari/537.36',}
    req = urllib.request.Request(url = Weburl,headers=Webheader)
    respose = urllib.request.urlopen(req)
    _contant = respose.read()
    respose.close()
    return str(_contant)
    def getUrl(URL):
    pageIndex = 1
    for i in range(1,int(pageIndex)+1):
    Weburl = URL + str(i)
    contant = getContant(Weburl)
    comp = re.compile(r'<a href="htm_data.{0,30}html" target="_blank" id=""><font color=g')
    urlList1 = comp.findall(contant)
    comp = re.compile(r'a href="(.*?)"')
    urlList2 = comp.findall(str(urlList1))
    urlList = []
    for url1 in urlList2:
    url2 = baseUrl+url1
    urlList.append(url2)
    return urlList
    def openUrl(url):
    headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) ' 'Chrome/51.0.2704.63 Safari/537.36'
    }
    filePath=targetPath+url[-12:-5]
    #檢測當前路徑的有效性
    if not os.path.isdir(filePath):
    os.mkdir(filePath)
    req = urllib.request.Request(url=url, headers=headers)
    res = urllib.request.urlopen(req)
    data = res.read()
    downImg(data,filePath)
    else:
    print("已經下載過的地址跳過:"+url)
    print("filePath "+filePath)
    def downImg(data,filePath):
    for link,t in set(re.findall(r'([http|https]:[^\s]*?(jpg|png|gif))', str(data))):
    if link.startswith('s'):
    link='http'+link
    else:
    link='htt'+link
    print(link)
    try:
    opener=urllib.request.build_opener()
    opener.addheaders=[('User-Agent','Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1941.0 Safari/537.36')]
    urllib.request.install_opener(opener)
    urllib.request.urlretrieve(link,saveFile(link,filePath))
    except:
    print('失敗')
    def saveFile(path,filePath):
    #設置每個圖片的路徑
    pos = path.rindex('/')
    t = os.path.join(filePath,path[pos+1:])
    return t
    def openPage(UrlList):
    for pageUlr in UrlList:
    try:
    print('正在下載地址:'+pageUlr)
    openUrl(pageUlr)
    except:
    print('地址:'+pageUlr+'下載失敗')
    URL = baseUrl+'thread0806.php?fid=16&search=&page='
    for num in range(0,20):#0-20頁
    print("#######################################")
    print("##########總目錄下載地址###############")
    print(URL+str(num))
    print("#######################################")
    print("#######################################")
    UrlList = getUrl(URL+str(num))
    openPage(UrlList)

    最后的爬取結果:

    源代碼地址:python-crawler
    具體地址和源代碼在一起


    其它
    關于python2和python3的爭論,網站爭論比較大python3不兼容pyhton2,很多第三方的類庫暫時還沒有支持python3等等,但是對于我們新手來說,肯定是往前看果斷python3.
    代碼比較冗余幾個地方還沒有寫好,還在慢慢學習中,目前只是搞的可以跑起來。還有幾個問題沒有解決,下載一段時間后會莫名其妙的斷掉目前還么找到原因,后期看是否可以加上多線程來爬取可能會快一點,大家有什么更好的建議也可以提出來。
    參考:
    爬取豆瓣首頁圖片
    使用Python爬取1024上的圖片


    作者:純潔的微笑
    出處:http://www.ityouknow.com/
    版權所有,歡迎保留原文鏈接進行轉載:)
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(17)

    • 個人分類:生活學習
    ▲top
    • 3月 07 週二 201721:17
    • spring boot(六):如何優雅的使用mybatis


    Source: http://www.cnblogs.com/ityouknow/p/6037431.html



    這兩天啟動了一個新項目因為項目組成員一直都使用的是mybatis,雖然個人比較喜歡jpa這種極簡的模式,但是為了項目保持統一性技術選型還是定了 mybatis。到網上找了一下關于spring boot和mybatis組合的相關資料,各種各樣的形式都有,看的人心累,結合了mybatis的官方demo和文檔終于找到了最簡的兩種模式,花了一天時間總結后分享出來。


    orm框架的本質是簡化編程中操作數據庫的編碼,發展到現在基本上就剩兩家了,一個是宣稱可以不用寫一句SQL的hibernate,一個是可以靈活調試動態sql的mybatis,兩者各有特點,在企業級系統開發中可以根據需求靈活使用。發現一個有趣的現象:傳統企業大都喜歡使用hibernate,互聯網行業通常使用mybatis。


    hibernate特點就是所有的sql都用Java代碼來生成,不用跳出程序去寫(看)sql,有著編程的完整性,發展到最頂端就是spring data jpa這種模式了,基本上根據方法名就可以生成對應的sql了,有不太了解的可以看我的上篇文章springboot(五):spring data jpa的使用。


    mybatis初期使用比較麻煩,需要各種配置文件、實體類、dao層映射關聯、還有一大推其它配置。當然mybatis也發現了這種弊端,初期開發了generator可以根據表結果自動生產實體類、配置文件和dao層代碼,可以減輕一部分開發量;后期也進行了大量的優化可以使用注解了,自動管理dao層和配置文件等,發展到最頂端就是今天要講的這種模式了,mybatis-spring-boot-starter就是springboot+mybatis可以完全注解不用配置文件,也可以簡單配置輕松上手。



    現在想想spring boot 就是牛逼呀,任何東西只要關聯到spring boot都是化繁為簡。



    mybatis-spring-boot-starter


    官方說明:MyBatis Spring-Boot-Starter will help you use MyBatis with Spring Boot
    其實就是myBatis看spring boot這么火熱也開發出一套解決方案來湊湊熱鬧,但這一湊確實解決了很多問題,使用起來確實順暢了許多。mybatis-spring-boot-starter主要有兩種解決方案,一種是使用注解解決一切問題,一種是簡化后的老傳統。


    當然任何模式都需要首先引入mybatis-spring-boot-starter的pom文件,現在最新版本是1.1.1(剛好快到雙11了 :))



    <dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.1.1</version>
    </dependency>


    好了下來分別介紹兩種開發模式


    無配置文件注解版


    就是一切使用注解搞定。


    1 添加相關maven文件



    <dependencies>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.1.1</version>
    </dependency>
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional>
    </dependency>
    </dependencies>


    完整的pom包這里就不貼了,大家直接看源碼


    2、application.properties 添加相關配置



    mybatis.type-aliases-package=com.neo.entity
    spring.datasource.driverClassName = com.mysql.jdbc.Driver
    spring.datasource.url = jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf-8
    spring.datasource.username = root
    spring.datasource.password = root


    springboot會自動加載spring.datasource.*相關配置,數據源就會自動注入到sqlSessionFactory中,sqlSessionFactory會自動注入到Mapper中,對了你一切都不用管了,直接拿起來使用就行了。


    在啟動類中添加對mapper包掃描@MapperScan



    @SpringBootApplication
    @MapperScan("com.neo.mapper")
    public class Application {
    public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
    }
    }


    或者直接在Mapper類上面添加注解@Mapper,建議使用上面那種,不然每個mapper加個注解也挺麻煩的


    3、開發Mapper


    第三步是最關鍵的一塊,sql生產都在這里



    public interface UserMapper {
    @Select("SELECT * FROM users")
    @Results({
    @Result(property = "userSex", column = "user_sex", javaType = UserSexEnum.class),
    @Result(property = "nickName", column = "nick_name")
    })
    List<UserEntity> getAll();
    @Select("SELECT * FROM users WHERE id = #{id}")
    @Results({
    @Result(property = "userSex", column = "user_sex", javaType = UserSexEnum.class),
    @Result(property = "nickName", column = "nick_name")
    })
    UserEntity getOne(Long id);
    @Insert("INSERT INTO users(userName,passWord,user_sex) VALUES(#{userName}, #{passWord}, #{userSex})")
    void insert(UserEntity user);
    @Update("UPDATE users SET userName=#{userName},nick_name=#{nickName} WHERE id =#{id}")
    void update(UserEntity user);
    @Delete("DELETE FROM users WHERE id =#{id}")
    void delete(Long id);
    }


    為了更接近生產我特地將user_sex、nick_name兩個屬性在數據庫加了下劃線和實體類屬性名不一致,另外user_sex使用了枚舉




    • @Select 是查詢類的注解,所有的查詢均使用這個

    • @Result 修飾返回的結果集,關聯實體類屬性和數據庫字段一一對應,如果實體類屬性和數據庫屬性名保持一致,就不需要這個屬性來修飾。

    • @Insert 插入數據庫使用,直接傳入實體類會自動解析屬性到對應的值

    • @Update 負責修改,也可以直接傳入對象

    • @delete 負責刪除



    了解更多屬性參考這里



    注意,使用#符號和$符號的不同:




    // This example creates a prepared statement, something like select * from teacher where name = ?;
    @Select("Select * from teacher where name = #{name}")
    Teacher selectTeachForGivenName(@Param("name") String name);
    // This example creates n inlined statement, something like select * from teacher where name = 'someName';
    @Select("Select * from teacher where name = '${name}'")
    Teacher selectTeachForGivenName(@Param("name") String name);


    4、使用


    上面三步就基本完成了相關dao層開發,使用的時候當作普通的類注入進入就可以了



    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class UserMapperTest {
    @Autowired
    private UserMapper UserMapper;
    @Test
    public void testInsert() throws Exception {
    UserMapper.insert(new UserEntity("aa", "a123456", UserSexEnum.MAN));
    UserMapper.insert(new UserEntity("bb", "b123456", UserSexEnum.WOMAN));
    UserMapper.insert(new UserEntity("cc", "b123456", UserSexEnum.WOMAN));
    Assert.assertEquals(3, UserMapper.getAll().size());
    }
    @Test
    public void testQuery() throws Exception {
    List<UserEntity> users = UserMapper.getAll();
    System.out.println(users.toString());
    }
    @Test
    public void testUpdate() throws Exception {
    UserEntity user = UserMapper.getOne(3l);
    System.out.println(user.toString());
    user.setNickName("neo");
    UserMapper.update(user);
    Assert.assertTrue(("neo".equals(UserMapper.getOne(3l).getNickName())));
    }
    }


    源碼中controler層有完整的增刪改查,這里就不貼了
    源碼在這里spring-boot-mybatis-annotation


    極簡xml版本


    極簡xml版本保持映射文件的老傳統,優化主要體現在不需要實現dao的是實現層,系統會自動根據方法名在映射文件中找對應的sql.


    1、配置


    pom文件和上個版本一樣,只是application.properties新增以下配置



    mybatis.config-locations=classpath:mybatis/mybatis-config.xml
    mybatis.mapper-locations=classpath:mybatis/mapper/*.xml


    指定了mybatis基礎配置文件和實體類映射文件的地址


    mybatis-config.xml 配置



    <configuration>
    <typeAliases>
    <typeAlias alias="Integer" type="java.lang.Integer" />
    <typeAlias alias="Long" type="java.lang.Long" />
    <typeAlias alias="HashMap" type="java.util.HashMap" />
    <typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap" />
    <typeAlias alias="ArrayList" type="java.util.ArrayList" />
    <typeAlias alias="LinkedList" type="java.util.LinkedList" />
    </typeAliases>
    </configuration>


    這里也可以添加一些mybatis基礎的配置


    2、添加User的映射文件



    <mapper namespace="com.neo.mapper.UserMapper" >
    <resultMap id="BaseResultMap" type="com.neo.entity.UserEntity" >
    <id column="id" property="id" jdbcType="BIGINT" />
    <result column="userName" property="userName" jdbcType="VARCHAR" />
    <result column="passWord" property="passWord" jdbcType="VARCHAR" />
    <result column="user_sex" property="userSex" javaType="com.neo.enums.UserSexEnum"/>
    <result column="nick_name" property="nickName" jdbcType="VARCHAR" />
    </resultMap>
    <sql id="Base_Column_List" >
    id, userName, passWord, user_sex, nick_name
    </sql>
    <select id="getAll" resultMap="BaseResultMap" >
    SELECT
    <include refid="Base_Column_List" />
    FROM users
    </select>
    <select id="getOne" parameterType="java.lang.Long" resultMap="BaseResultMap" >
    SELECT
    <include refid="Base_Column_List" />
    FROM users
    WHERE id = #{id}
    </select>
    <insert id="insert" parameterType="com.neo.entity.UserEntity" >
    INSERT INTO
    users
    (userName,passWord,user_sex)
    VALUES
    (#{userName}, #{passWord}, #{userSex})
    </insert>
    <update id="update" parameterType="com.neo.entity.UserEntity" >
    UPDATE
    users
    SET
    <if test="userName != null">userName = #{userName},</if>
    <if test="passWord != null">passWord = #{passWord},</if>
    nick_name = #{nickName}
    WHERE
    id = #{id}
    </update>
    <delete id="delete" parameterType="java.lang.Long" >
    DELETE FROM
    users
    WHERE
    id =#{id}
    </delete>
    </mapper>


    其實就是把上個版本中mapper的sql搬到了這里的xml中了


    3、編寫Dao層的代碼



    public interface UserMapper {
    List<UserEntity> getAll();
    UserEntity getOne(Long id);
    void insert(UserEntity user);
    void update(UserEntity user);
    void delete(Long id);
    }


    對比上一步這里全部只剩了接口方法


    4、使用


    使用和上個版本沒有任何區別,大家就看代碼吧


    xml配置版本


    如何選擇


    兩種模式各有特點,注解版適合簡單快速的模式,其實像現在流行的這種微服務模式,一個微服務就會對應一個自已的數據庫,多表連接查詢的需求會大大的降低,會越來越適合這種模式。


    老傳統模式比適合大型項目,可以靈活的動態生成SQL,方便調整SQL,也有痛痛快快,洋洋灑灑的寫SQL的感覺。


    完整代碼地址




    作者:純潔的微笑
    出處:http://www.ityouknow.com/
    版權所有,歡迎保留原文鏈接進行轉載:)



    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(6)

    • 個人分類:生活學習
    ▲top
    • 3月 07 週二 201721:17
    • 六年程序生涯

    Source: http://www.cnblogs.com/ityouknow/p/6084208.html



    工作六年對一個程序員意味什么?在職位上:高級開發工程師?架構師?技術經理?or ... ?在能力上:各種編碼無壓力?核心代碼無壓力?平臺架構無壓力? or ... fuck?看著這些問號都心累。那么,六年你迷惘了嗎?又走到了那個十字路口?


    六對我來講總是一個特殊的數字,六年中一直想對自己的程序員生涯做一個回顧,總是有各種的借口飄然而過就到了幾天。畢業六年,大學同學們基本上都走在了不同的路線,也走進了完全不同的生活,能在六年沖出來的現在也都小有了名氣,為什么相同的學校相同的專業卻走向了不同的方向呢,且聽我慢慢道來。



    每個人程序員的經歷都是一個故事



     


    如何入坑


    在XX的培訓班上有一次我對大家這樣介紹:我來自一個二流的本科院校中的一個三流專業,學校本來就是師范類的院校,自然不是特別受歡迎,我們是師范學校里面的非師范專業,而且是學校剛開的專業掛在數學系更加非主流,專業就是:信息與計算科學。我聽說有的學校這個專業是計算機系的,不知準確信息。但基本上都是學數學的,帶著學習一點計算機,當初報考這個專業也是因為這個名字,看起來很有科技含量,多少農村孩子都是這樣報考專業的!!!


     


    大學生活


    一般大家回顧都要說說大學生活,我的大學一年一句話來總結,大一基本上都是在網吧度過的,大二基本上都是在籃球場度過的,大三基本上都和女朋友一起過的,大四基本上都在找工作中度過,導致我走向編程這條道路的經歷基本上都在大四了。放一張當時大學的圖片,當然現在都已經發生了很大的變化。


    dx


    有幾個原因導致了我最后選擇去培訓機構培訓Java編碼,第一、對計算機比較感興趣,大學數學課程基本沒聽過,都是考試應付,但對相關計算機課程很感興趣,但學的太淺了,我不討厭數學,但是讓我想到學這么多微積分、線性代數...畢業后有個鳥用,就泄氣了,沒有一點動力。第二、真的不好找工作,專業幾乎沒有對口,同學干啥都有,有的走向了培訓、當了教師,有的做了文員、公務員、銀行職員,有的做了交警、還有公安,但最讓我驚奇的是有一個當了律師,太驚訝了,我感覺比編程可困難多了,基本上都是各自找自己的出路。第三、大三暑假那會參加了數學建模競賽,在小組中我負責編程的部分,那時候用的MATLAB和C語言,隨著不斷的練習和使用更加驗證了對軟件的熱情和理解,也只是覺得軟件應該是一個朝陽行業,慢慢的去了解了入行的標準,找工作的過程中慢慢試著去接觸了一些培訓機構,但是看到1w左右的培訓費用,我猶豫了,那時候的1w對我來講太重了。


    大四那年冬天,印象很深刻,跑遍了省會城市大小招聘會場,不是簡歷都過不了,就是么消息;最后到應聘上幾家公司,但是和自己想象中差距太遠,一個是培訓機構當老師,沒去;一個是做管培生,去了,我靠基本上跟傳銷一樣,什么管培生就是賣軟件,記得應該叫“紅利軟件”,就是跑到各個交易所里面去找大爺大媽,聊天要電話,讓聽講座最后引導買軟件,一套軟件大概是3000左右,可以提成10%;早上7點上班,各種活動游戲,8:30出發,9點左右到交易所各種找人,看著眼睛發光的大媽大爺就是目標客戶。下午5點左右回來,各種培訓,然后開始根據話術打電話晚上10點回家,我們學校一共去了8個人吧,最后留下了一個我們都想到不到一個人,我們班一個文文弱弱的小女生,學習很好的那種,一干就是兩年,真是人不可貌相呀,堅持了兩周我就撤了。


     


    南下深圳


    為什么了去了深圳?幾個原因,我老大(初中很好的朋友,初中畢業后當兵,然后南下深圳)在這里,萬一不行還有一個投奔的地方。深圳應該是當時印象中南方比較發達的城市,希望可以見見世面,找找工作,對了那年還是非典,疫苗剛出來,只給大四的學生先用,那天還發著低燒,也沒管直接就打了。小馬是我們班的一個同學,關系比較好,聽我說要去深圳,特別激動說,強哥咱倆一起去闖天下去 :),因為小馬家境還不錯,沒有吃過太多的苦,從小都沒出過省,還是有點擔心,但是看著小馬這么激動,恰好我也有一個伴,就欣然接受了。后來我先去的,看了情況還行,就打了電話叫了小馬一起過來。那時候從西安到深圳為了省錢買了硬座,應該是做了將近30個小時左右吧,吃了N多筒的泡面終于到了深圳,南方人的普通話真是聽不懂呀。對了,小馬最終做了一名人民警察,這就是另外的故事了。


    因為我先去的深圳,就先去了深圳人才大市場,當然了各種受挫。等小馬來了以后我們就先進了龍崗的比亞迪工廠,我們分在了不同的車間,小馬比較幸運去了電池車間,就是流水線,我分到了紙箱車間,大家可能平時覺得紙箱子沒有啥,但是在沒有成品之前,邊緣幾乎都跟刀子一樣,沒幾天從手到胳膊全部是傷,但最重要的是我和我們車間的老大搞不到一起,整天吵架,有一次差點干了起來,那個車間老大后面瞬間站了兩個人,那次之后起我就出來了。


    聽了老大的建議,我又去了龍華的富士康,有一個朋友接我,對我說那邊大學生應聘一人還發一個電腦而且是做辦公室的(車間里面的人都羨慕做辦公室的,畢竟不用賣苦力;在廠里面一般工服有三種顏色:藍領,就是普工或者技工身份進廠的;紅領,就是質檢,專門檢查質量的,大部分從藍領升上去;白領,一般就是大學生了做文職或者管理),我沒去,我還是以普工的身份進的富士康,我不信我干不下去,最后又分到了觀瀾的一個小分廠里面做物流,對了就是富士康當時有名的第一跳,就在那個廠區。廠里面不像大家現在洋氣的說996什么的,幾乎沒有假期,什么周末更別提了,早8點晚8點,半月白班,半月夜班。富士康在深圳還是福利比較好的一個工廠,包吃住用藥等。


    這個圖網上找的,有點像當初那個屌絲的年華 dx


    在工廠的這段經歷讓我明白了,我必須要依靠一個技能來養活自己。這個技能就是搞軟件!


     


    培訓班


    根據之前的了解我大概選了兩家培訓機構,一家就是野馬XXX,另外一家就是XX內培訓機構,價格都差不多,但野馬有教師,X內是視頻教學,當時感覺不能接受,不太靠譜。本來都拿著錢去野馬那邊交錢了,在付款的時候,財務說可以減免了一百元,跟我一直溝通的那位說政策搞錯了,肯定不是這個。就因為這個原因,我感覺他們不夠嚴謹,我說那我就先不報名了,然后就去了隔壁的X內看看,結果他們正在上課就讓我試聽了一下,里面全是大四的學生,我坐在后排聽了一上午,雖然感覺還是跟不上,但是有那種建模學習的那種氛圍,我就定了X內。后來我在X內都上課兩周了,野馬打電話說給我特殊減免3千元讓我過去,最后沒去,但是感覺水分真大。


    其實X內當在西安的培訓還挺扎實的,還考了sun的證書,其實也么啥用。開始從跟不上,到處請教別人,到慢慢的理解,寫各種小游戲,到最后也有學員來問我問題。那時候周六、周天可以免費在培訓機構學習,我幾乎周末都在哪里,畢業答辯的前兩天才回去,然后又過來,畢業典禮沒有去,畢業體檢舍友這個幫我測血壓,那個幫忙測體重,畢業證書、學位證書舍友幫忙領。我的大四幾乎和學校都沒有關系。在X內認識了好幾個朋友,工作到現在都聯系著,有的去了華為,有的在外包,還有的搞了小公司。


    培訓機構承諾免費介紹工作,那時候的培訓好像也沒有讓大家偽造什么工作經驗,學校什么的,一般情況下只要你不是很爛,基本上都能找到工作。X內推薦了幾家公司,自己也投了簡歷記得最后收到了2個或者3個offer,也記不得都有什么公司了,最后選擇了去李嘉誠兒子的一家公司就是電訊盈科,這個公司那時候剛來西安,還算不錯的公司,主要是電信方面的研發,可惜我再這公司也才呆了不到一個月。


     


    工作西安


    剛入這行還是比較周折,也差點進去了另一個方向,所幸最后走向了正軌。程序員都是第一年的工作不是特別好找,過了第一年后,后面就比較輕松了。剛進電訊盈科的時候我的心里狀態還是沒有調整過來,感覺還是在大學的那種狀態,進去之后是淘汰制,一個月內培訓oracle,兩周淘汰一次人。其實我感覺自己太不會表現了或者其它吧,最終一個月底的時候我也被淘汰了,打電話給我姐說的時候,我姐說,關鍵人家一共20多個人就淘汰了2個人!其中就有你!對了培訓的錢,借我姐夫的。我感覺很憋屈,但我還是不認可,我是最差的。但最終我還是需要面對再找工作的問題。


    網上海投了N份簡歷,電話不多,面試了幾家公司后,也收到了幾份Offer一個小公司不交社保,1800;有一家外包華為2100正規繳納社保,我去了華為外包。關于薪資我給大家說兩個笑話:1、我當初培訓的時候一個學員給我說,有一個朋友從這里出來后,第一份工作2000,跳槽后4000,再跳槽后6000,我們一群人心里都默默的崇拜著,想著這肯定都是大牛級別的人物;2、我畢業第一份工作預期是2000左右,然后我就幻想著以后每年能漲1000元我就滿足了,到了30歲我就能拿快8000了,現在真到30了才發現現在的畢業生起步價也是這個數。


     


    第一份工作


    那時候我也在網上看了很多外包公司的種種不是,但我的選擇不是很多,不管怎么樣畢業了就不能再往家里要錢了,總得先掙錢吧。華為外包有一個變態的特點為了保密,不允許帶U盤、手機等各種存儲、通訊設備,上班后基本就和外界失聯了。那時候是做無線上網卡的客戶端,就是那時候往電腦一插就可以上網那種。每個人進來會分配一個師傅來帶,比較幸運我來的時候分給了一個比較好的師傅,性格、態度,以及他工作的方式其實最后也都影響了我。


    我們應該在研發二部,大概分了三個部門,大巴組,小巴組和定制組。定制組:就是不用寫代碼的那種,華為開發了一些工具通過工具可以改變客戶端軟件的logo,模塊功能等,華為的軟件真是遍布全球到處的客戶都有,阿拉伯、非洲各種語言大部分的需求都是基本可以工具搞定;小巴組,就是需要改一些代碼,但是工作量又不是特別多的那種;大巴組就是需要改動需要1月以上的需求。我當時分在了小巴組,大概有十幾個人,其中也有很多碩士畢業的也被忽悠進來。最原始的代碼都是印度阿三寫的,我們都是在上面做二次開發,剛進去看了一個類代碼有上萬多行驚呆了,但是代碼確實寫的非常正規。沒有什么架構文檔給我們,但改動基本都是外層的皮膚了或者小按鈕之類的。


    加班非常多,但比較開心的是加班有工資,而且是按照國家標準來的,平時加班1.5倍,周六天2倍,假期三倍。這是我工作到現在最正規的加班制度了,工資只有2100,但通過加班可以拿到3000左右,加到2點都是很正常的事情,特別喜歡假期加班可以拿三倍工資,華為在西安包了N多大樓,當時在軟件園三期,班車上百輛開出去還是挺壯觀的。華為的中午休息文化,確實好,中午吃完飯熄燈大家都睡覺,中午趟在哪里睡一個小時,下午工作質量明顯提高N倍。


    我剛進去的時候客戶端有兩種一種是Java寫的,一種是QT(C++的封裝),慢慢的Java版本的都淘汰了,全部上線了QT。我從小巴慢慢開發了大巴需求,但到最后沒有Java版本的需求了,全部用QT。Java組的大家都各種轉型,有的去了另外一個js控制的項目組,我選擇了留下來搞QT,開始學習C++,因為有C語言的底子,倒也不難慢慢的可以開始搞QT版本的小巴需求,但是最后我就糾結了,我以后到底是往Java方向發展呢,還是C++呢。后來終于想通了,我花了那么多錢培訓java這樣太虧了 ,于是選擇了離職。那時候華為方的領導其實對我也特別好,還專門給了我兩周時間不用上班去參加華為Java的培訓,大家都帶著華為的白牌子,我帶著外包的黃色牌子,培訓老師問了我好幾次我是那個部門的,但最后我還是撤了。


    放一張我們小巴組出游的照片
    dx



    第一份工作促成我從學生到職場的轉變。



     


    第二份工作


    當時面試有意向的公司大概是兩家,一家是做GIS系統關于地理信息的公司,另外一家是XX系統,主要是做思科代理,給思科做各種軟件或者給思科的硬件去做集成方案的各種軟件。我選擇了后者,沒有別的原因,后面這家工資給的高,我就這么實在。


    剛進公司其實比較緊張,因為半年沒有做Java了,每天各種學習,各種加班最后發現其實還可以,雖然半年沒有搞了但問題也不大,公司用的是hibernate和Struts基本上都是以前用過的框架。第一個項目是,smart meeting智能會議,就是大公司預定會議的一套系統,大部分的工作都在前端,那段時間讓我對js有很了很大的了解,因為預定會議的系統界面都是各種拖拽。第二個項目大概就是vozimate,就是給思科的IP話機上面做應用,就是通過電話可以查詢股票了、天氣預報了等等,我們的這些信息都是通過爬蟲抓取第三方的,過一段時間就需要調整一下爬蟲策略。第一次讓我對硬件和軟件交互有了理解,思科的IP話機當時還是蠻先進的視頻通話,各種會議都是沒有問題。


    最重要的一個項目也是我幾乎入職一直在搞的項目就是UC manager,就是通過思科的電話打完短途、長途、漫游、國際漫游、轉接、會議等等,凡是和打電話相關都會有,其實就是相當于聯通或者移動公司話費的計費系統,當然還有路線最優路由,統計等各種功能非常多,剛開始做一些小功能,到負責一個模塊,到最后整個系統都是我來負責,直到我離職的最后一天,我都在做這個項目的最后一版計費優化。正因為這個項目到北京面試的時候得到了一個高薪的機會,這個下面再講。


    其實在這個公司里面,項目中規中矩,代碼也是主流的框架和技術,一年多的時間穩扎穩打讓我對大項項目框架和設計有了很多的認識,特別是爬蟲什么的讓我非常興奮。那時候中午我經常看博客園的新聞,整天都是互聯網公司怎么怎么了,但是西安基本沒有一家正正經經的互聯網公司,于是就有了去北京想法,剛好jerry也有這樣的想法13年過年后,大家紛紛提離職,準備去帝都呼吸新鮮的霧霾。


    記得是11年十一過后入職的,當天一起入職了四名同事,我什么要強調這個呢,因為這四個同事到現在為止,都成了我職場后關系最好的四個好基友,其中有一個女孩,但我們仍然這樣認為。jerry、波仔和鴿子,我們四個各有特點,jerry就是那種極客精神,喜歡各種硬件、軟件,做了好幾個網站,創業幾次,目前創業中;波仔,天生搞笑天王,唱歌天王,在生活中帶來無限的樂趣,跟他在一起永遠是歡笑不斷;鴿子,是女漢子或者是逍遙著,天生喜歡流浪、喝酒,拉薩、云南、日本、臺灣、英國各處流浪,永遠給人一種激情滿滿的感覺。


    我們甚至創建了自己的戶外組織Flyever,有自己的官網,甚至印了自己的隊旗,logo和口號:自由 夢想!每月組織去排山,腐敗、各種活動。發工資了說今天活動一下吧,十幾個人就去吃飯喝酒,晚上通宵唱歌;世界末日了說去慶祝下吧,這兩天心情不好,去活動一下吧!找各種借口去腐敗,爬了很多山,喝了數不清多少瓶的9度。這是曾經的官網www.flyever.cn


    放一張我們當時一個活動策劃的截圖
    fly


    在放幾張我們去過的地方


    青海湖的太陽
    fly


    蘆葦蕩
    fly


     


    北上帝都


    來到北京的時候,我身上只剩了3000快錢,1000多在分鐘寺(現在已經拆遷)租了個公寓,買了些日常用品后就剩1千多了,我專門挑互聯網公司來投簡歷,大概頭了100份左右,找了10家去面試,一周內面試完拿到了5份offer,其中有一家給的特別高就是因為我以前做了UCmanager這個項目,他們公司剛好給愛立信做項目,缺少這樣項目經驗的人,我猶豫了很久,畢竟工資給的很高,但最后還是放棄了,進了一家第三方支付公司。


     


    第三方支付公司


    選擇第三方支付公司的時候,其實我還不是特別了解這個行業,只是覺得支付應該是比較不錯的。這家公司也是我現在公司的母公司,剛入職的時候感覺周圍一大片全都是大牛!公司還管飯,感覺特別好,沒過了幾天,就被同事拉進了一個XX山炮群,又開啟了胡吃海喝的時代,經常私下我們幾個組織著去AA聚餐,各種吹牛,各種燒烤啤酒也別有一番風味,混熟了之后,才發現和我一樣大家都是屌絲,有一次部門聚餐的時候,部門經理說,大家都舉下手看看大家都是那個省的,結果幾乎每個省都是一兩個這種,看著來自五湖四海的同事在一起工作,也是一番景象。


    剛來公司做的是,第三方支付的前置接入系統,當時公司每天交易額剛剛上億,服務壓力非常大,每天各種報警,我們就輔助從前置開始跟蹤,慢慢的對業務有了了解,后來也寫了專門的壓測程序來跑。再后來開始負責公司官網的改版,收銀臺改版,到后來開始了解J8583,銀行接入平臺 慢慢的才對第三方支付有了一個整體的了解,13年底的時候慢慢的興起了很多p2p,很多公司在做對接平臺,那時候大家都不懂什么是p2p,我們也不懂,也是一邊學習一邊搞,項目持續做了很久,我帶了兩三個人來做后端。最后這個項目也沒有做起來,因為我們還是不了解p2p公司到底需要什么,自己琢磨的東西還是不太靠譜。


    14初的時候總監,偷偷告訴我要封閉去做一個關于金融的項目,想讓我參加,沒想到正是這個項目對我的職場有如此大的影響,所以說關鍵時候的選擇非常的重要。緊接著沒過幾天,就開了幾個車拉著我們去了四星級酒店開始封閉開發,后來方案定了使用PHP開發之后,我又撤了回來做平臺接口層的開發。大約過了一個月項目基本完成了,大家回來后項目組因為一個老總出走,帶走了一個團隊,剩下的開發幾乎都走光了,那時候其實我也找好了工作,新的公司待遇和環境都不錯,領導找我談話,想讓我負責這個項目。我對領導說我先考慮一下,等我休假回來后給回復。那段時間太累了加了很多班,請了好幾天假去了青海湖大玩了幾天,朋友都建議我去新的公司,后來我考慮一下還是選擇了留下。


    hkrt


     


    互聯網金融


    那個封閉的項目就是互聯網金融,那時候互聯網金融已經慢慢熱了起來,14年我們上線的時候應該是最后的一波熱潮了。直到今天我們公司在行業的排名都在20-60之間來回。


    14年初的時候大家搞的p2p都是網頁版,app端有幾個公司有,但都很基礎,當時公司人力有限,就面臨一個選擇先做APP還是網站的問題,其實APP的問題主要是通道的問題,當時快捷支付應用到P2P公司還是非常難的。最后領導還是拍板先上APP,大家就集中人力先做APP,最后證明這是個正確的選擇,現在監控我們公司的交易,幾乎百分之80來自APP,第一次感覺移動互聯網的浪潮就是這樣來的。


    系統剛投產的那段時間,交易量火爆,最夸張的時候1000萬的標的幾秒鐘就滿了,雖然現在平臺也是這樣。但當時對我們來講還是蠻震驚的。在交易量火爆的情況下,系統出現了各種問題,首先是秒殺的時候控制不住并發,有時候會出現超賣的現象,最后各種優化,通過memcahed鎖解決了這個問題,緊接著服務器又因為流量太大扛不住了,于是又上線lvs做負載。期間各種問題不斷,那段時間我幾乎晚上11點之前沒有回過家,每次我走的時候老婆還在睡覺,回來的時候她又睡著了,周末也是各種加班,總感覺自己見不到太陽,持續了很久,但是成長也是非常的大。


    因為我們的前端是PHP寫的我又逼著自己學習了PHP,從開始能看懂,到最后可以寫一點。公司慢慢上線了官網,又增加了小網頁(H5),各種分布式系統改造。做各種活動,和滴滴打車做活動、和河貍家做活動、和攜程做活動等等,有一次一天注冊了X千個用戶,驚呆了,發現羊毛黨來了,又是各種限制。在后來慢慢的有黑客盯上了我們,各種騷擾,DDOS攻擊,SQL注入等等。反正是能遇到的問題我們基本都遇到了,每一次問題之后,我們系統就又健壯了一些。


    再后來要做大數據分析,我們又開始啟動golang+monggodb這套方案來做大數據,剛開始也很困難,但是大家對新技術的這種渴望戰勝了一切;再后來上線了dubbo做SOA服務治理,到現在啟動spring boot+cloud。我們的系統也從第一代平臺開始到現在第四代平臺更換中,對這四代平臺做一個簡單的介紹: 第一代平臺,主要是集中式,以快速上線為目的;第二代平臺主要是分布式改造,緩解各服務壓力;第三代平臺主要做服務端SOA治理,后臺統一賬戶中心;第四代微服務化改造,已達到灰度上線、動態部署集中管理的目的。


    我也從負責Java端,到負責整個技術團隊,慢慢的在領導的信任下測試交給了我,再后來分公司獨立后將運維也交給了我,于是成了整個分公司的技術負責人。這就是我的故事。未來仍然有更多的挑戰,感謝我們團隊的兄弟姐妹,感謝工作中遇到的所有同事和領導。


    我特別喜歡一句話在這里分享給大家:



    我的代碼曾運行在幾千萬用戶的機器上,作為一個程序員,還有什么比這更讓人滿足的呢?如果有,那就是讓這個用戶數量再擴大 10 倍。



    zxjr


    路漫漫,歡迎大家在博文下面回復自己個人的經歷,以共勉!




    作者:純潔的微笑
    出處:http://www.ityouknow.com/
    碼字很辛苦,轉載請注明出處 :)



    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(4)

    • 個人分類:生活學習
    ▲top
    • 3月 07 週二 201721:16
    • spring boot(七):springboot+mybatis多數據源最簡解決方案


    Source: http://www.cnblogs.com/ityouknow/p/6102399.html
    說起多數據源,一般都來解決那些問題呢,主從模式或者業務比較復雜需要連接不同的分庫來支持業務。我們項目是后者的模式,網上找了很多,大都是根據jpa來做多數據源解決方案,要不就是老的spring多數據源解決方案,還有的是利用aop動態切換,感覺有點小復雜,其實我只是想找一個簡單的多數據支持而已,折騰了兩個小時整理出來,供大家參考。

    廢話不多說直接上代碼吧


    配置文件
    pom包就不貼了比較簡單該依賴的就依賴,主要是數據庫這邊的配置:
    mybatis.config-locations=classpath:mybatis/mybatis-config.xml
    spring.datasource.test1.driverClassName = com.mysql.jdbc.Driver
    spring.datasource.test1.url = jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf-8
    spring.datasource.test1.username = root
    spring.datasource.test1.password = root
    spring.datasource.test2.driverClassName = com.mysql.jdbc.Driver
    spring.datasource.test2.url = jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf-8
    spring.datasource.test2.username = root
    spring.datasource.test2.password = root

    一個test1庫和一個test2庫,其中test1位主庫,在使用的過程中必須制定主庫,不然會報錯。
    數據源配置
    @Configuration
    @MapperScan(basePackages = "com.neo.mapper.test1", sqlSessionTemplateRef = "test1SqlSessionTemplate")
    public class DataSource1Config {
    @Bean(name = "test1DataSource")
    @ConfigurationProperties(prefix = "spring.datasource.test1")
    @Primary
    public DataSource testDataSource() {
    return DataSourceBuilder.create().build();
    }
    @Bean(name = "test1SqlSessionFactory")
    @Primary
    public SqlSessionFactory testSqlSessionFactory(@Qualifier("test1DataSource") DataSource dataSource) throws Exception {
    SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
    bean.setDataSource(dataSource);
    bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mybatis/mapper/test1/*.xml"));
    return bean.getObject();
    }
    @Bean(name = "test1TransactionManager")
    @Primary
    public DataSourceTransactionManager testTransactionManager(@Qualifier("test1DataSource") DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
    }
    @Bean(name = "test1SqlSessionTemplate")
    @Primary
    public SqlSessionTemplate testSqlSessionTemplate(@Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
    return new SqlSessionTemplate(sqlSessionFactory);
    }
    }

    最關鍵的地方就是這塊了,一層一層注入,先創建DataSource,在創建SqlSessionFactory在創建事務,最后包裝到SqlSessionTemplate中。其中需要制定分庫的mapper文件地址,以及分庫到層代碼
    @MapperScan(basePackages = "com.neo.mapper.test1", sqlSessionTemplateRef = "test1SqlSessionTemplate")

    這塊的注解就是指明了掃描dao層,并且給dao層注入指定的SqlSessionTemplate。所有@Bean都需要按照命名指定正確。
    dao層和xml層
    dao層和xml需要按照庫來分在不同的目錄,比如:test1庫dao層在com.neo.mapper.test1包下,test2庫在com.neo.mapper.test1
    public interface User1Mapper {
    List<UserEntity> getAll();
    UserEntity getOne(Long id);
    void insert(UserEntity user);
    void update(UserEntity user);
    void delete(Long id);
    }

    xml層
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    <mapper namespace="com.neo.mapper.test1.User1Mapper" >
    <resultMap id="BaseResultMap" type="com.neo.entity.UserEntity" >
    <id column="id" property="id" jdbcType="BIGINT" />
    <result column="userName" property="userName" jdbcType="VARCHAR" />
    <result column="passWord" property="passWord" jdbcType="VARCHAR" />
    <result column="user_sex" property="userSex" javaType="com.neo.enums.UserSexEnum"/>
    <result column="nick_name" property="nickName" jdbcType="VARCHAR" />
    </resultMap>
    <sql id="Base_Column_List" >
    id, userName, passWord, user_sex, nick_name
    </sql>
    <select id="getAll" resultMap="BaseResultMap" >
    SELECT
    <include refid="Base_Column_List" />
    FROM users
    </select>
    <select id="getOne" parameterType="java.lang.Long" resultMap="BaseResultMap" >
    SELECT
    <include refid="Base_Column_List" />
    FROM users
    WHERE id = #{id}
    </select>
    <insert id="insert" parameterType="com.neo.entity.UserEntity" >
    INSERT INTO
    users
    (userName,passWord,user_sex)
    VALUES
    (#{userName}, #{passWord}, #{userSex})
    </insert>
    <update id="update" parameterType="com.neo.entity.UserEntity" >
    UPDATE
    users
    SET
    <if test="userName != null">userName = #{userName},</if>
    <if test="passWord != null">passWord = #{passWord},</if>
    nick_name = #{nickName}
    WHERE
    id = #{id}
    </update>
    <delete id="delete" parameterType="java.lang.Long" >
    DELETE FROM
    users
    WHERE
    id =#{id}
    </delete>
    </mapper>

    測試
    測試可以使用SpringBootTest,也可以放到Controller中,這里只貼Controller層的使用
    @RestController
    public class UserController {
    @Autowired
    private User1Mapper user1Mapper;
    @Autowired
    private User2Mapper user2Mapper;
    @RequestMapping("/getUsers")
    public List<UserEntity> getUsers() {
    List<UserEntity> users=user1Mapper.getAll();
    return users;
    }
    @RequestMapping("/getUser")
    public UserEntity getUser(Long id) {
    UserEntity user=user2Mapper.getOne(id);
    return user;
    }
    @RequestMapping("/add")
    public void save(UserEntity user) {
    user2Mapper.insert(user);
    }
    @RequestMapping(value="update")
    public void update(UserEntity user) {
    user2Mapper.update(user);
    }
    @RequestMapping(value="/delete/{id}")
    public void delete(@PathVariable("id") Long id) {
    user1Mapper.delete(id);
    }
    }

    最后源碼地址在這里spring-boot-mybatis-mulidatasource


    作者:純潔的微笑
    出處:http://www.ityouknow.com/
    版權所有,歡迎保留原文鏈接進行轉載:)
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(1)

    • 個人分類:生活學習
    ▲top
    • 3月 07 週二 201721:16
    • springboot(八):RabbitMQ詳解


    Source: http://www.cnblogs.com/ityouknow/p/6120544.html
    RabbitMQ 即一個消息隊列,主要是用來實現應用程序的異步和解耦,同時也能起到消息緩沖,消息分發的作用。
    消息中間件在互聯網公司的使用中越來越多,剛才還看到新聞阿里將RocketMQ捐獻給了apache,當然了今天的主角還是講RabbitMQ。消息中間件最主要的作用是解耦,中間件最標準的用法是生產者生產消息傳送到隊列,消費者從隊列中拿取消息并處理,生產者不用關心是誰來消費,消費者不用關心誰在生產消息,從而達到解耦的目的。在分布式的系統中,消息隊列也會被用在很多其它的方面,比如:分布式事務的支持,RPC的調用等等。
    以前一直使用的是ActiveMQ,在實際的生產使用中也出現了一些小問題,在網絡查閱了很多的資料后,決定嘗試使用RabbitMQ來替換ActiveMQ,RabbitMQ的高可用性、高性能、靈活性等一些特點吸引了我們,查閱了一些資料整理出此文。
    RabbitMQ介紹
    RabbitMQ是實現AMQP(高級消息隊列協議)的消息中間件的一種,最初起源于金融系統,用于在分布式系統中存儲轉發消息,在易用性、擴展性、高可用性等方面表現不俗。RabbitMQ主要是為了實現系統之間的雙向解耦而實現的。當生產者大量產生數據時,消費者無法快速消費,那么需要一個中間層。保存這個數據。
    AMQP,即Advanced Message Queuing Protocol,高級消息隊列協議,是應用層協議的一個開放標準,為面向消息的中間件設計。消息中間件主要用于組件之間的解耦,消息的發送者無需知道消息使用者的存在,反之亦然。AMQP的主要特征是面向消息、隊列、路由(包括點對點和發布/訂閱)、可靠性、安全。
    RabbitMQ是一個開源的AMQP實現,服務器端用Erlang語言編寫,支持多種客戶端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系統中存儲轉發消息,在易用性、擴展性、高可用性等方面表現不俗。
    相關概念
    通常我們談到隊列服務, 會有三個概念: 發消息者、隊列、收消息者,RabbitMQ 在這個基本概念之上, 多做了一層抽象, 在發消息者和 隊列之間, 加入了交換器 (Exchange). 這樣發消息者和隊列就沒有直接聯系, 轉而變成發消息者把消息給交換器, 交換器根據調度策略再把消息再給隊列。
  • 左側 P 代表 生產者,也就是往 RabbitMQ 發消息的程序。

  • 中間即是 RabbitMQ,其中包括了 交換機 和 隊列。

  • 右側 C 代表 消費者,也就是往 RabbitMQ 拿消息的程序。

  • 那么,其中比較重要的概念有 4 個,分別為:虛擬主機,交換機,隊列,和綁定。
  • 虛擬主機:一個虛擬主機持有一組交換機、隊列和綁定。為什么需要多個虛擬主機呢?很簡單,RabbitMQ當中,用戶只能在虛擬主機的粒度進行權限控制。 因此,如果需要禁止A組訪問B組的交換機/隊列/綁定,必須為A和B分別創建一個虛擬主機。每一個RabbitMQ服務器都有一個默認的虛擬主機“/”。

  • 交換機:Exchange 用于轉發消息,但是它不會做存儲 ,如果沒有 Queue bind 到 Exchange 的話,它會直接丟棄掉 Producer 發送過來的消息。
    這里有一個比較重要的概念:路由鍵 。消息到交換機的時候,交互機會轉發到對應的隊列中,那么究竟轉發到哪個隊列,就要根據該路由鍵。

  • 綁定:也就是交換機需要和隊列相綁定,這其中如上圖所示,是多對多的關系。

  • 交換機(Exchange)
    交換機的功能主要是接收消息并且轉發到綁定的隊列,交換機不存儲消息,在啟用ack模式后,交換機找不到隊列會返回錯誤。交換機有四種類型:Direct, topic, Headers and Fanout
  • Direct:direct 類型的行為是"先匹配, 再投送". 即在綁定時設定一個 routing_key, 消息的routing_key 匹配時, 才會被交換器投送到綁定的隊列中去.

  • Topic:按規則轉發消息(最靈活)

  • Headers:設置header attribute參數類型的交換機

  • Fanout:轉發消息到所有綁定隊列

  • Direct Exchange
    Direct Exchange是RabbitMQ默認的交換機模式,也是最簡單的模式,根據key全文匹配去尋找隊列。
    第一個 X - Q1 就有一個 binding key,名字為 orange; X - Q2 就有 2 個 binding key,名字為 black 和 green。當消息中的 路由鍵 和 這個 binding key 對應上的時候,那么就知道了該消息去到哪一個隊列中。
    Ps:為什么 X 到 Q2 要有 black,green,2個 binding key呢,一個不就行了嗎? - 這個主要是因為可能又有 Q3,而Q3只接受 black 的信息,而Q2不僅接受black 的信息,還接受 green 的信息。
    Topic Exchange
    Topic Exchange 轉發消息主要是根據通配符。 在這種交換機下,隊列和交換機的綁定會定義一種路由模式,那么,通配符就要在這種路由模式和路由鍵之間匹配后交換機才能轉發消息。
    在這種交換機模式下:
  • 路由鍵必須是一串字符,用句號(.) 隔開,比如說 agreements.us,或者 agreements.eu.stockholm 等。

  • 路由模式必須包含一個 星號(*),主要用于匹配路由鍵指定位置的一個單詞,比如說,一個路由模式是這樣子:agreements..b.*,那么就只能匹配路由鍵是這樣子的:第一個單詞是 agreements,第四個單詞是 b。 井號(#)就表示相當于一個或者多個單詞,例如一個匹配模式是agreements.eu.berlin.#,那么,以agreements.eu.berlin開頭的路由鍵都是可以的。

  • 具體代碼發送的時候還是一樣,第一個參數表示交換機,第二個參數表示routing key,第三個參數即消息。如下:
    rabbitTemplate.convertAndSend("testTopicExchange","key1.a.c.key2", " this is RabbitMQ!");

    topic 和 direct 類似, 只是匹配上支持了"模式", 在"點分"的 routing_key 形式中, 可以使用兩個通配符:
  • *表示一個詞.

  • #表示零個或多個詞.

  • Headers Exchange
    headers 也是根據規則匹配, 相較于 direct 和 topic 固定地使用 routing_key , headers 則是一個自定義匹配規則的類型.
    在隊列與交換器綁定時, 會設定一組鍵值對規則, 消息中也包括一組鍵值對( headers 屬性), 當這些鍵值對有一對, 或全部匹配時, 消息被投送到對應隊列.
    Fanout Exchange
    Fanout Exchange 消息廣播的模式,不管路由鍵或者是路由模式,會把消息發給綁定給它的全部隊列,如果配置了routing_key會被忽略。
    springboot集成RabbitMQ
    springboot集成RabbitMQ非常簡單,如果只是簡單的使用配置非常少,springboot提供了spring-boot-starter-amqp項目對消息各種支持。
    簡單使用
    1、配置pom包,主要是添加spring-boot-starter-amqp的支持
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>

    2、配置文件
    配置rabbitmq的安裝地址、端口以及賬戶信息
    spring.application.name=spirng-boot-rabbitmq
    spring.rabbitmq.host=192.168.0.86
    spring.rabbitmq.port=5672
    spring.rabbitmq.username=admin
    spring.rabbitmq.password=123456

    3、隊列配置
    @Configuration
    public class RabbitConfig {
    @Bean
    public Queue Queue() {
    return new Queue("hello");
    }
    }

    3、發送者
    rabbitTemplate是springboot 提供的默認實現
    public class HelloSender {
    @Autowired
    private AmqpTemplate rabbitTemplate;
    public void send() {
    String context = "hello " + new Date();
    System.out.println("Sender : " + context);
    this.rabbitTemplate.convertAndSend("hello", context);
    }
    }

    4、接收者
    @Component
    @RabbitListener(queues = "hello")
    public class HelloReceiver {
    @RabbitHandler
    public void process(String hello) {
    System.out.println("Receiver : " + hello);
    }
    }

    5、測試
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class RabbitMqHelloTest {
    @Autowired
    private HelloSender helloSender;
    @Test
    public void hello() throws Exception {
    helloSender.send();
    }
    }

    注意,發送者和接收者的queue name必須一致,不然不能接收


    多對多使用
    一個發送者,N個接收者或者N個發送者和N個接收者會出現什么情況呢?
    一對多發送
    對上面的代碼進行了小改造,接收端注冊了兩個Receiver,Receiver1和Receiver2,發送端加入參數計數,接收端打印接收到的參數,下面是測試代碼,發送一百條消息,來觀察兩個接收端的執行效果
    @Test
    public void oneToMany() throws Exception {
    for (int i=0;i<100;i++){
    neoSender.send(i);
    }
    }

    結果如下:
    Receiver 1: spirng boot neo queue ****** 11
    Receiver 2: spirng boot neo queue ****** 12
    Receiver 2: spirng boot neo queue ****** 14
    Receiver 1: spirng boot neo queue ****** 13
    Receiver 2: spirng boot neo queue ****** 15
    Receiver 1: spirng boot neo queue ****** 16
    Receiver 1: spirng boot neo queue ****** 18
    Receiver 2: spirng boot neo queue ****** 17
    Receiver 2: spirng boot neo queue ****** 19
    Receiver 1: spirng boot neo queue ****** 20

    根據返回結果得到以下結論

    一個發送者,N個接受者,經過測試會均勻的將消息發送到N個接收者中


    多對多發送
    復制了一份發送者,加入標記,在一百個循環中相互交替發送
    @Test
    public void manyToMany() throws Exception {
    for (int i=0;i<100;i++){
    neoSender.send(i);
    neoSender2.send(i);
    }
    }

    結果如下:
    Receiver 1: spirng boot neo queue ****** 20
    Receiver 2: spirng boot neo queue ****** 20
    Receiver 1: spirng boot neo queue ****** 21
    Receiver 2: spirng boot neo queue ****** 21
    Receiver 1: spirng boot neo queue ****** 22
    Receiver 2: spirng boot neo queue ****** 22
    Receiver 1: spirng boot neo queue ****** 23
    Receiver 2: spirng boot neo queue ****** 23
    Receiver 1: spirng boot neo queue ****** 24
    Receiver 2: spirng boot neo queue ****** 24
    Receiver 1: spirng boot neo queue ****** 25
    Receiver 2: spirng boot neo queue ****** 25

    結論:和一對多一樣,接收端仍然會均勻接收到消息


    高級使用
    對象的支持
    springboot以及完美的支持對象的發送和接收,不需要格外的配置。
    //發送者
    public void send(User user) {
    System.out.println("Sender object: " + user.toString());
    this.rabbitTemplate.convertAndSend("object", user);
    }
    ...
    //接受者
    @RabbitHandler
    public void process(User user) {
    System.out.println("Receiver object : " + user);
    }

    結果如下:
    Sender object: User{name='neo', pass='123456'}
    Receiver object : User{name='neo', pass='123456'}

    Topic Exchange
    topic 是RabbitMQ中最靈活的一種方式,可以根據routing_key自由的綁定不同的隊列
    首先對topic規則配置,這里使用兩個隊列來測試
    @Configuration
    public class TopicRabbitConfig {
    final static String message = "topic.message";
    final static String messages = "topic.messages";
    @Bean
    public Queue queueMessage() {
    return new Queue(TopicRabbitConfig.message);
    }
    @Bean
    public Queue queueMessages() {
    return new Queue(TopicRabbitConfig.messages);
    }
    @Bean
    TopicExchange exchange() {
    return new TopicExchange("exchange");
    }
    @Bean
    Binding bindingExchangeMessage(Queue queueMessage, TopicExchange exchange) {
    return BindingBuilder.bind(queueMessage).to(exchange).with("topic.message");
    }
    @Bean
    Binding bindingExchangeMessages(Queue queueMessages, TopicExchange exchange) {
    return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#");
    }
    }

    使用queueMessages同時匹配兩個隊列,queueMessage只匹配"topic.message"隊列
    public void send1() {
    String context = "hi, i am message 1";
    System.out.println("Sender : " + context);
    this.rabbitTemplate.convertAndSend("exchange", "topic.message", context);
    }
    public void send2() {
    String context = "hi, i am messages 2";
    System.out.println("Sender : " + context);
    this.rabbitTemplate.convertAndSend("exchange", "topic.messages", context);
    }

    發送send1會匹配到topic.#和topic.message 兩個Receiver都可以收到消息,發送send2只有topic.#可以匹配所有只有Receiver2監聽到消息
    Fanout Exchange
    Fanout 就是我們熟悉的廣播模式或者訂閱模式,給Fanout交換機發送消息,綁定了這個交換機的所有隊列都收到這個消息。
    Fanout 相關配置
    @Configuration
    public class FanoutRabbitConfig {
    @Bean
    public Queue AMessage() {
    return new Queue("fanout.A");
    }
    @Bean
    public Queue BMessage() {
    return new Queue("fanout.B");
    }
    @Bean
    public Queue CMessage() {
    return new Queue("fanout.C");
    }
    @Bean
    FanoutExchange fanoutExchange() {
    return new FanoutExchange("fanoutExchange");
    }
    @Bean
    Binding bindingExchangeA(Queue AMessage,FanoutExchange fanoutExchange) {
    return BindingBuilder.bind(AMessage).to(fanoutExchange);
    }
    @Bean
    Binding bindingExchangeB(Queue BMessage, FanoutExchange fanoutExchange) {
    return BindingBuilder.bind(BMessage).to(fanoutExchange);
    }
    @Bean
    Binding bindingExchangeC(Queue CMessage, FanoutExchange fanoutExchange) {
    return BindingBuilder.bind(CMessage).to(fanoutExchange);
    }
    }

    這里使用了A、B、C三個隊列綁定到Fanout交換機上面,發送端的routing_key寫任何字符都會被忽略:
    public void send() {
    String context = "hi, fanout msg ";
    System.out.println("Sender : " + context);
    this.rabbitTemplate.convertAndSend("fanoutExchange","", context);
    }

    結果如下:
    Sender : hi, fanout msg 
    ...
    fanout Receiver B: hi, fanout msg
    fanout Receiver A : hi, fanout msg
    fanout Receiver C: hi, fanout msg

    結果說明,綁定到fanout交換機上面的隊列都收到了消息
    上面所有的例子,代碼在這里
    參考
    RabbitMQ 使用參考
    RabbitMQ:Spring 集成 RabbitMQ 與其概念,消息持久化,ACK機制


    作者:純潔的微笑
    出處:http://www.ityouknow.com/
    版權所有,歡迎保留原文鏈接進行轉載:)
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(10)

    • 個人分類:生活學習
    ▲top
    «1...226227228230»

    pop-under

    參觀人氣

    • 本日人氣:
    • 累積人氣:

    線上人數

    Marquee

    最新文章

    • 文章列表
    • jvm系列(四):jvm調優-命令大全(jps jstat jmap jhat jstack jinfo)
    • spring boot(一):入門篇
    • jvm系列(一):java類的加載機制
    • jvm系列(三):java GC算法 垃圾收集器
    • spring boot 實戰:我們的第一款開源軟件
    • jvm系列(六):jvm調優-從eclipse開始
    • 混合應用技術選型
    • jvm系列(二):JVM內存結構
    • spring boot(五):spring data jpa的使用

    熱門文章

    • (1,762)jQuery之前端國際化jQuery.i18n.properties
    • (630)技術筆記:Indy控件發送郵件
    • (513)linux下安裝sqlite3
    • (501)學習筆記: Delphi之線程類TThread
    • (242)VC單選按鈕控件(Radio Button)用法(轉)
    • (149)Android AppBar
    • (103)單條件和多條件查詢
    • (50)淺談config文件的使用
    • (26)Tomcat shutdown執行后無法退出進程問題排查及解決
    • (22)基于 Asp.Net的 Comet 技術解析

    文章分類

    • 生活學習 (2,296)
    • 未分類文章 (1)

    最新留言

    • [20/04/24] 我是女生想約炮 有男生願意給我溫暖的嗎?我賴是woyou58 於文章「(1)從底層設計,探討插件式GIS框架的...」留言:
      我叫黎兒女生最近內心掙扎著要不要約炮我的line:woy...

    文章搜尋

    文章精選

    誰來我家

    Live Traffic Feed