德國計畫撥款22億美元支持電動汽車 擴建充電站

據德國《時代週報》報導,德國聯邦經濟事務和能源部長西格瑪爾•加布里爾(Sigmar Gabriel)擬撥款20億歐元(約合21.8億美元)鼓勵更多消費者購買電動汽車。

《時代週報》稱,購買電動車將獲得聯邦政府的補貼,西格瑪爾還計畫擴建電動車充電站,並鼓勵聯邦政府機關人員使用電動汽車。然而該報導未進一步提供關於補貼的具體資訊。

德國聯邦政府計畫到2020年實現電動車保有量達百萬輛的目標。德國車企中,寶馬、梅賽德斯-賓士以及大眾旗下都已經生產了電動車,奧迪和保時捷也在計畫之中。

據悉,2014年德國電動車銷量約為1.9萬輛。到2014年年底,該國僅擁有2400個充電站和100個快速充電點。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

南極洲溫度創新高 攝氏18.2度跟台北一樣暖

摘錄自2020年2月9日聯合新聞網報導

紐約時報報導,世界上最冷、風勢最強也最乾燥的大陸南極洲,6日出現有紀錄以來最高溫,阿根廷在南極半島北端的艾斯伯蘭薩研究站測到攝氏18.2度高溫,打破2015年3月24日的最高溫紀錄攝氏17.5度,凸顯全球暖化的趨勢。

艾斯伯蘭薩目前處於夏季,6日出現攝氏18.2度,根據美國國家氣象局的資料,與洛杉磯當天出現的攝氏18度相當。根據中央氣象局的資料,這與位於中央氣象局內的台北測站當天上午8點到9點之間的溫度相當,6日當天上午8點是17.4度,9點是19.5度。

艾斯伯蘭薩從1961年起記錄氣溫。根據世界氣象組織的資料,南極洲的溫度通常不會這麼高,海岸地帶約是攝氏零下10度,內陸海拔較高處通常是攝氏零下60度。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

寒潮來襲,電動車撐不住?材料改良或為解方

北極震盪下,中國、台灣面臨數十年難得一見的低溫,連深圳與台北的平地都下起冰霰。這樣的天氣暴露出電動車的一大缺點──由於鋰電池在低溫環境下放電量不穩,因此電動車的續航力也大受挑戰。

根據美國AAA Automotive Research Center所做的研究,同一輛電動車在攝氏24度左右的溫度下可行駛約168公里,但在攝氏-6.7度左右時,行駛距離大幅縮減到只剩約69公里。而美國能源部及環保署的資料也載示,同樣在攝氏-6.7度的環境下,汽油車續航力會下降12%,但電動車會降低34%。

EnergyTrend鋰電池/電動車研究指出,同樣的問題也會發生在手機、平板等攜帶裝置上,主要的原因是鋰電池長時間處於寒冷環境下時,因化學反應不正常,會使放電電流變少,導致可用容量降低。若是攜帶式裝置,可將裝置帶在身上「保暖」,但電動車可不能如法炮製。

電動車近兩年來展望長紅,不只有Tesla、Faraday Future等新公司出現,保時捷、BMW、Audi、Nissan、Toyota、Ford、福斯汽車等國際車廠也紛紛推出電動車款,且銷售量持續攀升。尤其在霾害嚴重的中國,已正式將電動車列為重點發展項目。但在氣候的限制下,如何解決鋰電池的續航力降低問題,就成為一大議題。

從材料面、系統面解決

EnergyTrend調研團隊指出,中國雖然大力推動電動車,但仍以華中以南地區為推行主力,原因正在於東北、華北等地氣候太過嚴寒,不利於鋰電池與電動車行駛,不只電池容量會降低,汽車也會有無法發動的問題。

要解決此一問題,主要分成材料改良與系統改良。在材料方面,可改用更耐嚴寒氣候的電池材料;在系統方面,則又分成耐低溫零件以及低溫系統的使用。分析師指出,目前已有廠商針對電動車耐寒的議題提出相關技術。

以台灣電動機車Gogoro為例,Gogoro設計有高溫預防模式與低溫保護模式,在低溫狀況下,低溫保護模式啟用並使動力輸出降低,但騎乘一段時間後電池溫度就能慢慢回到正常。

目前相關技術仍在發展當中,但隨著電動車市場擴大,這將成為不得不跨越的一大難題。

(照片來源:Wikepedia)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

怎麼把CAT客戶端的RootMessageId記錄到每條日誌中?

什麼是RootMessageId?

為了理解RootMessageId先簡單介紹一下CAT的數據結構設計。CAT客戶端會將所有消息都封裝為一個完整的消息樹(MessageTree),消息樹可能包括Transaction、Event、Heartbeat、Metric等類型的消息。具體如下:

  • Transaction:適合記錄跨越系統邊界的程序訪問行為,比如遠程調用,數據庫調用,也適合執行時間較長的業務邏輯監控,Transaction用來記錄一段代碼的執行時間和次數
  • Event:用來記錄一件事發生的次數,比如記錄系統異常,它和transaction相比缺少了時間的統計,開銷比transaction要小
  • Heartbeat:表示程序內定期產生的統計信息, 如CPU利用率, 內存利用率, 連接池狀態, 系統負載等
  • Metric:用於記錄業務指標、指標可能包含對一個指標記錄次數、記錄平均值、記錄總和,業務指標最低統計粒度為1分鐘

歡迎關注微信公眾號:萬貓學社,每周一分享Java技術乾貨。

其中,Transaction類型的消息可作為消息樹節點,而其他消息只可作為消息樹的恭弘=叶 恭弘子節點,也就是Transaction是一個可嵌套的遞歸結構。比如:

消息樹的每一節點都有一個屬性messageId,用來唯一表示節點本身,其構成為:{domain}-{ip}-{timestamp}-{自增index}。另外還有兩個屬性,分別是parentMessageId, rootMessageId。parentMessageId表示父節點的messageId;rootMessageId則表示整個消息樹的根節點的messageId。這兩個屬性在之後CAT的調用鏈分析與分佈式調用鏈分析中發揮了關鍵作用。

歡迎關注微信公眾號:萬貓學社,每周一分享Java技術乾貨。

為什麼在日誌中記錄?

根據RootMessageId可以追蹤某一個請求的整個分佈式調用鏈,結合每一條日誌快速定位耗費性能的癥結,做針對性的性能優化。更加方便地做性能優化,特別是TP95、TP99等指標。

遇到偶爾發生的bug,是最讓人頭疼的,只有先從日誌中找線索,但是在海量的日誌中找到出現bug的那一個請求是很困難的。有了上游API提供的RootMessageId,就可以快速過濾出那次請求的所有日誌, 更快速更方便地定位線上bug。

歡迎關注微信公眾號:萬貓學社,每周一分享Java技術乾貨。

在日誌的什麼地方記錄?

當然是每一句日誌上都記錄RootMessageId了。有的同學會說,這日誌也記錄的太多了。當發現線上問題無法定位時,你就會狠日誌太少了。其實記錄日誌不怕多,就怕不全。現在硬盤很便宜了,搞個幾T沒有問題,另外還可以設置日誌清理策略。

歡迎關注微信公眾號:萬貓學社,每周一分享Java技術乾貨。

怎麼記錄到日誌中?

前面說了那麼多,終於到了今天的壓軸大戲了。實現記錄到日誌有很多種方式,這裏使用的是MDC(Mapped Diagnostic Contexts)。顧名思義,其目的是為了便於我們診斷線上問題而出現的方法工具類,目前我們經常使用的logback和log4j都是支持的。

歡迎關注微信公眾號:萬貓學社,每周一分享Java技術乾貨。

只需要在每個請求的入口調用MDC.put方法,把rootMessageId賦值進去就可以了,是不是很簡單?示例代碼:

//在Filter里,從header里獲取上下文信息,包括messageId、parentMessageId、rootMessageId
CatContext catContext = new CatContext();
catContext.addProperty(Cat.Context.ROOT, request.getHeader(CatConstants.CAT_HTTP_HEADER_ROOT_MESSAGE_ID));
catContext.addProperty(Cat.Context.PARENT, request.getHeader(CatConstants.CAT_HTTP_HEADER_PARENT_MESSAGE_ID));
catContext.addProperty(Cat.Context.CHILD, request.getHeader(CatConstants.CAT_HTTP_HEADER_CHILD_MESSAGE_ID));
if (catContext.getProperty(Cat.Context.ROOT) == null) {
    //如果調用鏈的頂端,沒有上下文信息,需要生成上下文信息
    Cat.logRemoteCallClient(catContext);
} else {
    Cat.logRemoteCallServer(catContext);
}
MDC.put("traceId", catContext.getProperty(Cat.Context.ROOT));

如果你還不知道怎麼集成CAT調用鏈,可以看看之前的《》

然後,在設置日誌輸出格式的配置文件里增加[%X{traceId}]。

Logback的xml配置示例:

<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true">
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] [%X{traceId}] [%-5level] [%-40.36logger{40}:%-4.4line] - %msg%n</pattern>
        </layout>
    </appender>

    <root level="INFO">
        <appender-ref ref="CONSOLE" />
    </root>
</configuration>

log4j的properties配置示例:

log4j.rootCategory=INFO,stdout,info,error
log4j.rootLooger=warn,stdout,info,error
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%-5p] [%thread] [%X{traceId}]  method:%l - %m%n

歡迎關注微信公眾號:萬貓學社,每周一分享Java技術乾貨。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

[視頻演示].NET Core開發的iNeuOS物聯網平台,實現從設備&PLC、雲平台、移動APP數據鏈路閉環

目       錄

1.      概述… 1

2.      登陸信息… 2

3.      設備驅動… 3

4.      組態建模… 3

5.      手機APP. 5

6.      視頻演示… 6

1.   概述

此次我們團隊人員對iNeuOS進行了全面升級,主要升級內容包括:

(1)    設備容器增加設備驅動,包括:西門子(S7-200smart、S7-300、S7-400、S7-1200、S7-1500)、三菱(FxSerial)、MQTT協議等。

(2)    組態建模可以設置背景,作為開發大屏展示使用,背景可以為一個獨立的圖元信息。

(3)    組態建模可以按瀏覽器大小按比例縮放,以適應移動APP显示。

(4)    組態建模標題框和文本框可以設置背景和字體顏色。

(5)    組態建模文本框綁定數據點后,可以設置上下限值,以用於判斷,進行顏色報警显示。

(6)    組態建模文本框可以設置數據保留小數點位數。

(7)    組態建模可以自定義畫任意圖形,並且填充顏色等。

(8)    組態建模開發好的視圖,可以右鍵單擊數值文本框,查看數據曲線趨勢。

(9)    手機移動APP,組態建模開發的視圖,直接可以显示在手機APP上。

(10)進行其他優化。

2.   演示信息

在線演示:  (注:服務器比較慢,請耐心等待。用戶自已註冊用戶,體驗系統功能)

視頻演示:

驅動開發: (v2.1版本)

手機APP:

登陸界面,如下圖:

3.   設備驅動

   主要了主流的PLC驅動,包括:西門子(S7-200smart、S7-300、S7-400、S7-1200、S7-1500)、三菱(FxSerial)。增加了MQTT協議,MQTT協議基本與阿里雲IOT的alink協議保持一致,方便在私有雲建設過程中遷移。如下圖:

      iNeuKernel現在完全支持跨平台部署,至此iNeuOS的前台和後台全部支持跨平台。

4.   組態建模

   雲端組態建模改動和完善的地方比較多,主要依據用戶提出的建議進行了修改。

(1)增加編輯區域設置背景功能,主要用於開發數據大屏展示的效果,可以上傳多個背景圖元,並且作為一個獨立的圖元,隨時可以更換背景。

  (2)編輯數據的文本框,可以設置背景和字體顏色、報警運作、保留小數位數等,更具有交互感。

  (3)任意畫圖形,儘管我們提供了3500多個SVG圖元信息,但是難免缺少特殊領域的圖形,可以使用這個功能彌補。也可以畫大屏展示的特定區域形式。

  (4)組態建模開發完成后,可以右鍵單擊文本框,查看趨勢,以展示當前數據的曲線圖。

5.   手機APP

    手機APP可以使數據離用戶最近,組態建模完成后,通過手機進行縮放显示。

      打開手機APP显示已經開發完成的視圖列表,選擇任意視圖,显示效果如下圖。

6.   視頻演示


如果你播放不了該視頻, 那是你的設備不支持該文件格式

參見:

《》

《》

《》

 物聯網&集成技術 QQ群:54256083 

 物聯網&集成合作 QQ群:727664080

 網站:

聯繫QQ:504547114

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

2019能源碳排放不再增長 IEA:見證能源轉型是現在進行式

環境資訊中心綜合外電;彭瑞祥 編譯

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

Spring Boot2 系列教程(二十三)理解 Spring Data Jpa

有很多讀者留言希望松哥能好好聊聊 Spring Data Jpa! 其實這個話題松哥以前零零散散的介紹過,在我的書里也有介紹過,但是在公眾號中還沒和大夥聊過,因此本文就和大家來仔細聊聊 Spring Data 和 Jpa!

本文大綱:

1. 故事的主角

1.1 Jpa

1.1.1 JPA 是什麼

  1. Java Persistence API:用於對象持久化的 API
  2. Java EE 5.0 平台標準的 ORM 規範,使得應用程序以統一的方式訪問持久層

1.1.2 JPA 和 Hibernate 的關係

  1. JPA 是 Hibernate 的一個抽象(就像 JDBC 和 JDBC 驅動的關係);
  2. JPA 是規範:JPA 本質上就是一種 ORM 規範,不是 ORM 框架,這是因為 JPA 並未提供 ORM 實現,它只是制訂了一些規範,提供了一些編程的 API 接口,但具體實現則由 ORM 廠商提供實現;
  3. Hibernate 是實現:Hibernate 除了作為 ORM 框架之外,它也是一種 JPA 實現
  4. 從功能上來說, JPA 是 Hibernate 功能的一個子集

1.1.3 JPA 的供應商

JPA 的目標之一是制定一個可以由很多供應商實現的 API,Hibernate 3.2+、TopLink 10.1+ 以及 OpenJPA 都提供了 JPA 的實現,Jpa 供應商有很多,常見的有如下四種:

  1. Hibernate:JPA 的始作俑者就是 Hibernate 的作者,Hibernate 從 3.2 開始兼容 JPA。
  2. OpenJPA:OpenJPA 是 Apache 組織提供的開源項目。
  3. TopLink:TopLink 以前需要收費,如今開源了。
  4. EclipseLink

1.1.4 JPA 的優勢

  1. 標準化: 提供相同的 API,這保證了基於 JPA 開發的企業應用能夠經過少量的修改就能夠在不同的 JPA 框架下運行。
  2. 簡單易用,集成方便: JPA 的主要目標之一就是提供更加簡單的編程模型,在 JPA 框架下創建實體和創建 Java 類一樣簡單,只需要使用 javax.persistence.Entity 進行註解;JPA 的框架和接口也都非常簡單。
  3. 可媲美JDBC的查詢能力: JPA的查詢語言是面向對象的,JPA 定義了獨特的JPQL,而且能夠支持批量更新和修改、JOIN、GROUP BY、HAVING 等通常只有 SQL 才能夠提供的高級查詢特性,甚至還能夠支持子查詢。
  4. 支持面向對象的高級特性: JPA 中能夠支持面向對象的高級特性,如類之間的繼承、多態和類之間的複雜關係,最大限度的使用面向對象的模型

1.1.5 JPA 包含的技術

  1. ORM 映射元數據:JPA 支持 XML 和 JDK 5.0 註解兩種元數據的形式,元數據描述對象和表之間的映射關係,框架據此將實體對象持久化到數據庫表中。
  2. JPA 的 API:用來操作實體對象,執行CRUD操作,框架在後台完成所有的事情,開發者從繁瑣的 JDBC 和 SQL 代碼中解脫出來。
  3. 查詢語言(JPQL):這是持久化操作中很重要的一個方面,通過面向對象而非面向數據庫的查詢語言查詢數據,避免程序和具體的 SQL 緊密耦合。

1.2 Spring Data

Spring Data 是 Spring 的一個子項目。用於簡化數據庫訪問,支持NoSQL 和 關係數據存儲。其主要目標是使數據庫的訪問變得方便快捷。Spring Data 具有如下特點:

  • SpringData 項目支持 NoSQL 存儲:
    1. MongoDB (文檔數據庫)
    2. Neo4j(圖形數據庫)
    3. Redis(鍵/值存儲)
    4. Hbase(列族數據庫)
  • SpringData 項目所支持的關係數據存儲技術:
    1. JDBC
    2. JPA
  • Spring Data Jpa 致力於減少數據訪問層 (DAO) 的開發量. 開發者唯一要做的,就是聲明持久層的接口,其他都交給 Spring Data JPA 來幫你完成
  • 框架怎麼可能代替開發者實現業務邏輯呢?比如:當有一個UserDao.findUserById() 這樣一個方法聲明,大致應該能判斷出這是根據給定條件的 ID 查詢出滿足條件的 User 對象。Spring Data JPA 做的便是規範方法的名字,根據符合規範的名字來確定方法需要實現什麼樣的邏輯。

2. 主角的故事

2.1 Jpa 的故事

為了讓大夥徹底把這兩個東西學會,這裏我就先來介紹單純的 Jpa 使用,然後我們再結合 Spring Data 來看 Jpa 如何使用。

整體步驟如下:

  • 1.使用 IntelliJ IDEA 創建項目,創建時選擇 JavaEE Persistence ,如下:
  • 2.創建成功后,添加依賴 jar,由於 Jpa 只是一個規範,因此我們說用 Jpa 實際上必然是用 Jpa 的某一種實現,那麼是哪一種實現呢?當然就是 Hibernate 了,所以添加的 jar,實際上來自 Hibernate,如下:
  • 3.添加實體類

接下來在項目中添加實體類,如下:

@Entity(name = "t_book")
public class Book {
    private Long id;
    private String name;
    private String author;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long getId() {
        return id;
    }
    // 省略其他getter/setter
}

首先 @Entity 註解表示這是一個實體類,那麼在項目啟動時會自動針對該類生成一張表,默認的表名為類名,@Entity 註解的 name 屬性表示自定義生成的表名。@Id 註解表示這個字段是一個 id,@GeneratedValue 註解表示主鍵的自增長策略,對於類中的其他屬性,默認都會根據屬性名在表中生成相應的字段,字段名和屬性名相同,如果開發者想要對字段進行定製,可以使用 @Column 註解,去配置字段的名稱,長度,是否為空等等。

  • 4.創建 persistence.xml 文件

JPA 規範要求在類路徑的 META-INF 目錄下放置 persistence.xml,文件的名稱是固定的

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
    <persistence-unit name="NewPersistenceUnit" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <class>org.javaboy.Book</class>
        <properties>
            <property name="hibernate.connection.url"
                      value="jdbc:mysql:///jpa01?useUnicode=true&amp;characterEncoding=UTF-8"/>
            <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
            <property name="hibernate.connection.username" value="root"/>
            <property name="hibernate.connection.password" value="123"/>
            <property name="hibernate.archive.autodetection" value="class"/>
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="true"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
        </properties>
    </persistence-unit>
</persistence>

注意:

  1. persistence-unit 的 name 屬性用於定義持久化單元的名字, 必填。
  2. transaction-type:指定 JPA 的事務處理策略。RESOURCE_LOCAL:默認值,數據庫級別的事務,只能針對一種數據庫,不支持分佈式事務。如果需要支持分佈式事務,使用JTA:transaction-type=”JTA”
  3. class 節點表示顯式的列出實體類
  4. properties 中的配置分為兩部分:數據庫連接信息以及Hibernate信息
  • 5.執行持久化操作
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("NewPersistenceUnit");
EntityManager manager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = manager.getTransaction();
transaction.begin();
Book book = new Book();
book.setAuthor("羅貫中");
book.setName("三國演義");
manager.persist(book);
transaction.commit();
manager.close();
entityManagerFactory.close();

這裏首先根據配置文件創建出來一個 EntityManagerFactory ,然後再根據 EntityManagerFactory 的實例創建出來一個 EntityManager ,然後再開啟事務,調用 EntityManager 中的 persist 方法執行一次持久化操作,最後提交事務,執行完這些操作后,數據庫中舊多出來一個 t_book 表,並且表中有一條數據。

2.1.1 關於 JPQL

  1. JPQL 語言,即 Java Persistence Query Language 的簡稱。JPQL 是一種和 SQL 非常類似的中間性和對象化查詢語言,它最終會被編譯成針對不同底層數據庫的 SQL 查詢,從而屏蔽不同數據庫的差異。JPQL語言的語句可以是 select 語句、update 語句或 delete 語句,它們都通過 Query 接口封裝執行。
  2. Query接口封裝了執行數據庫查詢的相關方法。調用 EntityManager 的 createQuery、create NamedQuery 及 createNativeQuery 方法可以獲得查詢對象,進而可調用 Query 接口的相關方法來執行查詢操作。
  3. Query接口的主要方法如下:
  • int executeUpdate(); | 用於執行update或delete語句。
  • List getResultList(); | 用於執行select語句並返回結果集實體列表。
  • Object getSingleResult(); | 用於執行只返回單個結果實體的select語句。
  • Query setFirstResult(int startPosition); | 用於設置從哪個實體記錄開始返回查詢結果。
  • Query setMaxResults(int maxResult); | 用於設置返回結果實體的最大數。與setFirstResult結合使用可實現分頁查詢。
  • Query setFlushMode(FlushModeType flushMode); | 設置查詢對象的Flush模式。參數可以取2個枚舉值:FlushModeType.AUTO 為自動更新數據庫記錄,FlushMode Type.COMMIT 為直到提交事務時才更新數據庫記錄。
  • setHint(String hintName, Object value); | 設置與查詢對象相關的特定供應商參數或提示信息。參數名及其取值需要參考特定 JPA 實現庫提供商的文檔。如果第二個參數無效將拋出IllegalArgumentException異常。
  • setParameter(int position, Object value); | 為查詢語句的指定位置參數賦值。Position 指定參數序號,value 為賦給參數的值。
  • setParameter(int position, Date d, TemporalType type); | 為查詢語句的指定位置參數賦 Date 值。Position 指定參數序號,value 為賦給參數的值,temporalType 取 TemporalType 的枚舉常量,包括 DATE、TIME 及 TIMESTAMP 三個,,用於將 Java 的 Date 型值臨時轉換為數據庫支持的日期時間類型(java.sql.Date、java.sql.Time及java.sql.Timestamp)。
  • setParameter(int position, Calendar c, TemporalType type); | 為查詢語句的指定位置參數賦 Calenda r值。position 指定參數序號,value 為賦給參數的值,temporalType 的含義及取捨同前。
  • setParameter(String name, Object value); | 為查詢語句的指定名稱參數賦值。
  • setParameter(String name, Date d, TemporalType type); | 為查詢語句的指定名稱參數賦 Date 值,用法同前。
  • setParameter(String name, Calendar c, TemporalType type); | 為查詢語句的指定名稱參數設置Calendar值。name為參數名,其它同前。該方法調用時如果參數位置或參數名不正確,或者所賦的參數值類型不匹配,將拋出 IllegalArgumentException 異常。

2.1.2 JPQL 舉例

和在 SQL 中一樣,JPQL 中的 select 語句用於執行查詢。其語法可表示為:

select_clause form_clause [where_clause] [groupby_clause] [having_clause] [orderby_clause]

其中:

  1. from 子句是查詢語句的必選子句。
  2. select 用來指定查詢返回的結果實體或實體的某些屬性。
  3. from 子句聲明查詢源實體類,並指定標識符變量(相當於SQL表的別名)。
  4. 如果不希望返回重複實體,可使用關鍵字 distinct 修飾。select、from 都是 JPQL 的關鍵字,通常全大寫或全小寫,建議不要大小寫混用。

在 JPQL 中,查詢所有實體的 JPQL 查詢語句很簡單,如下:

select o from Order o

或

select o from Order as o

這裏關鍵字 as 可以省去,標識符變量的命名規範與 Java 標識符相同,且區分大小寫,調用 EntityManager 的 createQuery() 方法可創建查詢對象,接着調用 Query 接口的 getResultList() 方法就可獲得查詢結果集,如下:

Query query = entityManager.createQuery( "select o from Order o"); 
List orders = query.getResultList();
Iterator iterator = orders.iterator();
while(iterator.hasNext() ) {
  // 處理Order
}

其他方法的與此類似,這裏不再贅述。

2.2 Spring Data 的故事

在 Spring Boot 中,Spring Data Jpa 官方封裝了太多東西了,導致很多人用的時候不知道底層到底是怎麼配置的,本文就和大夥來看看在手工的 Spring 環境下,Spring Data Jpa 要怎麼配置,配置完成后,用法和 Spring Boot 中的用法是一致的。

2.2.1 基本環境搭建

首先創建一個普通的 Maven 工程,並添加如下依賴:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-oxm</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.27</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>5.2.12.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-jpamodelgen</artifactId>
        <version>5.2.12.Final</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.0.29</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>1.11.3.RELEASE</version>
    </dependency>
</dependencies>

這裏除了 Jpa 的依賴之外,就是 Spring Data Jpa 的依賴了。

接下來創建一個 User 實體類,創建方式參考 Jpa 中實體類的創建方式,這裏不再贅述。

接下來在 resources 目錄下創建一個 applicationContext.xml 文件,並配置Spring 和 Jpa,如下:

<context:property-placeholder location="classpath:db.properties"/>
<context:component-scan base-package="org.javaboy"/>
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
    <property name="driverClassName" value="${db.driver}"/>
    <property name="url" value="${db.url}"/>
    <property name="username" value="${db.username}"/>
    <property name="password" value="${db.password}"/>
</bean>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
    <property name="dataSource" ref="dataSource"/>
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
    </property>
    <property name="packagesToScan" value="org.javaboy.model"/>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.format_sql">true</prop>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQL57Dialect</prop>
        </props>
    </property>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 配置jpa -->
<jpa:repositories base-package="org.javaboy.dao"
                  entity-manager-factory-ref="entityManagerFactory"/>

這裏和 Jpa 相關的配置主要是三個:

  • 一個是 entityManagerFactory
  • 一個是 Jpa 的事務
  • 一個是配置 dao 的位置

配置完成后,就可以在 org.javaboy.dao 包下創建相應的 Repository 了,如下:

public interface UserDao extends Repository<User, Long> {
    User getUserById(Long id);
}

getUserById 表示根據 id 去查詢 User 對象,只要我們的方法名稱符合類似的規範,就不需要寫 SQL,具體的規範一會來說。好了,接下來,創建 Service 和 Controller 來調用這個方法,如下:

@Service
@Transactional
public class UserService {
    @Resource
    UserDao userDao;

    public User getUserById(Long id) {
        return userDao.getUserById(id);
    }
}
public void test1() {
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserService userService = ctx.getBean(UserService.class);
    User user = userService.getUserById(1L);
    System.out.println(user);
}

這樣,就可以查詢到 id 為 1 的用戶了。

2.2.2 Repository

上文我們自定義的 UserDao 實現了 Repository 接口,這個 Repository 接口是什麼來頭呢?

首先來看 Repository 的一個繼承關係圖:

可以看到,實現類不少。那麼到底如何理解 Repository 呢?

  1. Repository 接口是 Spring Data 的一個核心接口,它不提供任何方法,開發者需要在自己定義的接口中聲明需要的方法 public interface Repository<T, ID extends Serializable> { }
  2. 若我們定義的接口繼承了 Repository, 則該接口會被 IOC 容器識別為一個 Repository Bean,進而納入到 IOC 容器中,進而可以在該接口中定義滿足一定規範的方法。
  3. Spring Data可以讓我們只定義接口,只要遵循 Spring Data 的規範,就無需寫實現類。
  4. 與繼承 Repository 等價的一種方式,就是在持久層接口上使用 @RepositoryDefinition 註解,併為其指定 domainClass 和 idClass 屬性。像下面這樣:
@RepositoryDefinition(domainClass = User.class, idClass = Long.class)
public interface UserDao
{
    User findById(Long id);
    List<User> findAll();
}

基礎的 Repository 提供了最基本的數據訪問功能,其幾個子接口則擴展了一些功能,它的幾個常用的實現類如下:

  • CrudRepository: 繼承 Repository,實現了一組 CRUD 相關的方法
  • PagingAndSortingRepository: 繼承 CrudRepository,實現了一組分頁排序相關的方法
  • JpaRepository: 繼承 PagingAndSortingRepository,實現一組 JPA 規範相關的方法
  • 自定義的 XxxxRepository 需要繼承 JpaRepository,這樣的 XxxxRepository 接口就具備了通用的數據訪問控制層的能力。
  • JpaSpecificationExecutor: 不屬於Repository 體系,實現一組 JPA Criteria 查詢相關的方法

2.2.3 方法定義規範

2.2.3.1 簡單條件查詢

  • 按照 Spring Data 的規範,查詢方法以 find | read | get 開頭
  • 涉及條件查詢時,條件的屬性用條件關鍵字連接,要注意的是:條件屬性以首字母大寫

例如:定義一個 Entity 實體類:

class User{ 
   private String firstName; 
   private String lastName; 
}

使用 And 條件連接時,條件的屬性名稱與個數要與參數的位置與個數一一對應,如下:

findByLastNameAndFirstName(String lastName,String firstName);
  • 支持屬性的級聯查詢. 若當前類有符合條件的屬性, 則優先使用, 而不使用級聯屬性. 若需要使用級聯屬性, 則屬性之間使用 _ 進行連接.

查詢舉例:

  • 按照 id 查詢
User getUserById(Long id);
User getById(Long id);
  • 查詢所有年齡小於 90 歲的人
List<User> findByAgeLessThan(Long age);
  • 查詢所有姓趙的人
List<User> findByUsernameStartingWith(String u);
  • 查詢所有姓趙的、並且 id 大於 50 的人
List<User> findByUsernameStartingWithAndIdGreaterThan(String name, Long id);
  • 查詢所有姓名中包含”上”字的人
List<User> findByUsernameContaining(String name);
  • 查詢所有姓趙的或者年齡大於 90 歲的
List<User> findByUsernameStartingWithOrAgeGreaterThan(String name, Long age);
  • 查詢所有角色為 1 的用戶
List<User> findByRole_Id(Long id);

2.2.3.2 支持的關鍵字

支持的查詢關鍵字如下圖:

2.2.3.3 查詢方法流程解析

為什麼寫上方法名,JPA就知道你想幹嘛了呢?假如創建如下的查詢:findByUserDepUuid(),框架在解析該方法時,首先剔除 findBy,然後對剩下的屬性進行解析,假設查詢實體為Doc:

  1. 先判斷 userDepUuid (根據 POJO 規範,首字母變為小寫)是否為查詢實體的一個屬性,如果是,則表示根據該屬性進行查詢;如果沒有該屬性,繼續第二步;
  2. 從右往左截取第一個大寫字母開頭的字符串(此處為 Uuid),然後檢查剩下的字符串是否為查詢實體的一個屬性,如果是,則表示根據該屬性進行查詢;如果沒有該屬性,則重複第二步,繼續從右往左截取;最後假設 user 為查詢實體的一個屬性;
  3. 接着處理剩下部分(DepUuid),先判斷 user 所對應的類型是否有depUuid屬性,如果有,則表示該方法最終是根據 “ Doc.user.depUuid” 的取值進行查詢;否則繼續按照步驟 2 的規則從右往左截取,最終表示根據 “Doc.user.dep.uuid” 的值進行查詢。
  4. 可能會存在一種特殊情況,比如 Doc 包含一個 user 的屬性,也有一個 userDep 屬性,此時會存在混淆。可以明確在屬性之間加上 “_” 以顯式表達意圖,比如 “findByUser_DepUuid()” 或者 “findByUserDep_uuid()”
  5. 還有一些特殊的參數:例如分頁或排序的參數:
Page<UserModel> findByName(String name, Pageable pageable);
List<UserModel> findByName(String name, Sort sort);

2.2.3.4 @Query 註解

有的時候,這裏提供的查詢關鍵字並不能滿足我們的查詢需求,這個時候就可以使用 @Query 關鍵字,來自定義查詢 SQL,例如查詢 Id 最大的 User:

@Query("select u from t_user u where id=(select max(id) from t_user)")
User getMaxIdUser();

如果查詢有參數的話,參數有兩種不同的傳遞方式,

  • 利用下標索引傳參,索引參數如下所示,索引值從1開始,查詢中 ”?X” 個數需要與方法定義的參數個數相一致,並且順序也要一致:
@Query("select u from t_user u where id>?1 and username like ?2")
List<User> selectUserByParam(Long id, String name);
  • 命名參數(推薦):這種方式可以定義好參數名,賦值時採用@Param(“參數名”),而不用管順序:
@Query("select u from t_user u where id>:id and username like :name")
List<User> selectUserByParam2(@Param("name") String name, @Param("id") Long id);

查詢時候,也可以是使用原生的 SQL 查詢,如下:

@Query(value = "select * from t_user",nativeQuery = true)
List<User> selectAll();

2.2.3.5 @Modifying 註解

涉及到數據修改操作,可以使用 @Modifying 註解,@Query 與 @Modifying 這兩個 annotation 一起聲明,可定義個性化更新操作,例如涉及某些字段更新時最為常用,示例如下:

@Modifying
@Query("update t_user set age=:age where id>:id")
int updateUserById(@Param("age") Long age, @Param("id") Long id);

注意:

  1. 可以通過自定義的 JPQL 完成 UPDATE 和 DELETE 操作. 注意: JPQL 不支持使用 INSERT
  2. 方法的返回值應該是 int,表示更新語句所影響的行數
  3. 在調用的地方必須加事務,沒有事務不能正常執行
  4. 默認情況下, Spring Data 的每個方法上有事務, 但都是一個只讀事務. 他們不能完成修改操作

說到這裏,再來順便說說 Spring Data 中的事務問題:

  1. Spring Data 提供了默認的事務處理方式,即所有的查詢均聲明為只讀事務。
  2. 對於自定義的方法,如需改變 Spring Data 提供的事務默認方式,可以在方法上添加 @Transactional 註解。
  3. 進行多個 Repository 操作時,也應該使它們在同一個事務中處理,按照分層架構的思想,這部分屬於業務邏輯層,因此,需要在Service 層實現對多個 Repository 的調用,並在相應的方法上聲明事務。

好了,關於Spring Data Jpa 本文就先說這麼多。

關注公眾號【江南一點雨】,專註於 Spring Boot+微服務以及前後端分離等全棧技術,定期視頻教程分享,關注后回復 Java ,領取松哥為你精心準備的 Java 乾貨!

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

※台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”

※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※小三通海運與一般國際貿易有何不同?

※小三通快遞通關作業有哪些?

德國龐巴迪研發出200-400千瓦無線充電系統 未來將引入中國市場

龐巴迪2009年開始研發無線充電系統PRIMOVE,於2013年將該系統成功應用在純電動巴士無線充電中。截至2015年底已在德國曼海姆、柏林、布勞恩斯魏克市開通了商業運行線路,累計運行里程已超過12.5萬公里。目前,龐巴迪已研發生產出200-400千瓦無線充電系統PRIMOVE。未來,龐巴迪將把這個無線充電技術引入中國市場。

目前,中國電動巴士使用的無線充電系統是單組30千瓦或使用兩組並聯達到60千瓦充電功率。龐巴迪的這套大功率無線充電系統的充電速度遠遠超過了目前中國純電動巴士廣泛使用的80千瓦有線充電系統,使得無線充電不僅可以在城市微循環線路中使用,也同樣適應於骨幹公交線路 (例如BRT) 以及有軌電車等軌道交通。

為了將這項技術產業化並推向市場,擁有專利技術的地埋式初級線圈預製模組已經經過了長達一年的一百萬次的13噸軸重碾壓試驗,以此保證模組至少20年的使用壽命。該系統所有電力電子設備全部採取地埋的特點,使城市核心區充電基礎設施零占地成為可能。所有電力電子設備達到最高防護等級IP68,並採用德國專業的排水箱體設計,即使在暴雨情況下依然保證安全運行,成為這套無線充電系統的優勢所在。

獨特的線圈設計將電磁場定向傳輸,使巴士車內幾乎檢測不到電磁場,車外電磁場強度也只有國際標準ICNIRP2010 的四分之一。目前,PRIMOVE無線充電技術處於國際電動車用無線充電標準IEC61980中的最大功率等級。
 

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”

※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※小三通海運與一般國際貿易有何不同?

※小三通快遞通關作業有哪些?

為什麼 HTTPS 比 HTTP 安全

HTTP(超文本傳輸協議)是目前互聯網應用最廣泛的協議,伴隨着人們網絡安全意識的加強,HTTPS 被越來越多地採納。不論是訪問一些購物網站,或是登錄一些博客、論壇等,我們都被 HTTPS 保護着,甚至 Google Chrome、Firefox 等主流瀏覽器已經將所有基於 HTTP 的站點都標記為不安全。

為什麼 HTTPS 比 HTTP 安全?在回答這個問題之前,首先我們得了解 HTTP 和 HTTPS 是什麼。

HTTP 和 HTTPS 的訪問過程

從互聯網發展至今,HTTP 一直擔任互聯網傳輸信息的標準協議。傳輸的信息可以是互聯網內計算機之間的文檔,文件,圖像,視頻等。

HTTP 請求過程中,客戶端與服務器之間沒有任何身份確認的過程,數據全部明文傳輸,“裸奔”在互聯網上,所以很容易遭到黑客的攻擊。

從上圖中可以看到,客戶端發出的請求很容易被黑客截獲,如果此時黑客冒充服務器,則其可返回任意信息給客戶端,而不被客戶端察覺,所以我們經常會聽到一詞“劫持”。

而 HTTPS 實際上是帶有 SSL 的 HTTP(HTTP + SSL=HTTPS)。當您在瀏覽器的地址欄中看到 HTTPS 時,這就意味着與該網站的所有通信都將被加密,整個訪問過程更加安全。

為什麼 HTTPS 比 HTTP 安全

HTTPS 的安全性往往體現在三個方面:

  • 服務器身份驗證,通過服務器身份驗證,用戶可以明確當前它正在與對應的服務器進行通信。

  • 數據機密性,其他方無法理解發送的數據內容,因為提交的數據是加密的。

  • 數據完整性,傳輸會攜帶 Message Authentication Code(MAC)用於驗證,因此傳輸的數據不會被另一方更改。
    可以舉個例子來比較下。一個 HTTP 請求,其組成則是多個遵循 HTTP 協議的文本行,例如下面的 GET 請求:

GET /helloupyun.txt HTTP/1.1

User-Agent: curl/7.73.0 libcurl/7.73.0 OpenSSL/1.1.l zlib/1.2.11

Host: www.upyun.com

Accept-Language: en

請求會以明文的形式直接發送,既然是明文的形式,對於協議命令和語法有基本了解的人,只要監控了請求發送的過程,就能獲取並讀懂請求的意義。因此用 HTTP 的方式發送密碼一類的數據時,安全性極低。

相對的,HTTPS 使用了 SSL(或 TLS)來加密 HTTP 請求和響應,因此在上面的示例中,監控請求的人將會看到一串隨機的数字,而不是可讀性的文本。

GsERHg9YDMpYk0VVDiRvw1H5miNieJeJ/FNUjgH0BmVAWII6+T4MnDwmCMZUI/orxP3HGwYCSIvyzS3MpmmSe4iaWKCOHH==

其中加密過程採用的 SSL(安全套接字層)這一標準的安全技術,涵蓋了非對稱密鑰和對稱密鑰。

對稱加密
對稱加密是指加密與解密使用同一個密鑰的加密算法。

目前常見的加密算法有:DES、AES、IDEA 等

非對稱加密
非對稱加密使用的是兩個密鑰,公鑰與私鑰,我們會使用公鑰對網站賬號密碼等數據進行加密,再用私鑰對數據進行解密。這個公鑰會發給查看網站的所有人,而私鑰是只有網站服務器自己擁有的。

目前常見非對稱加密算法:RSA,DSA,DH 等。

而常用的套件,例如 ChaCha20-Poly1305 加密套件就使用了這兩種算法,其中 Chacha20 是指對稱加密算法,而Poly1305 是指身份認證算法。

參考 RFC 文檔,我們可以了解 ChaCha20 提供了 256 位的加密強度,這作為對稱加密算法來保障 HTTPS 安全性是足夠了。

而 Poly1305 作為身份認證算法提供身份驗證,可以防止攻擊者在 TLS 握手過程中,將虛假信息插入到安全的數據流中,Poly1305 算法提供了大約 100 位的安全性加密強度,足以阻止這類攻擊。

總的來看,HTTPS 相比 HTTP ,它作為一種加密手段不僅加密了數據,還給了網站一張安全可信賴的身份證。

聊聊 HTTPS 的一些優缺點

整體來看 HTTPS 有以下五個優點:

  • 最大限度地提高 Web 上數據和事務的安全性;

  • 加密用戶敏感或者機密信息;

  • 提高搜索引擎中的排名

  • 避免在瀏覽器中出現“不安全”的提示;

  • 提升用戶對網站的信賴。

相對的,缺點也是必不可少的:

  • HTTPS 協議在握手階段耗時相對較大,會影響頁面整體加載速度;

  • 在瀏覽器和服務器上會更多的 CPU 周期來加密/解密數據;

  • SSL 證書一般都需要支付一定費用來獲取,並且費用往往不低;

  • 並不是絕對意義上的安全,在網站遭受攻擊,服務器被劫持時,HTTPS 基本起不到任何安全防護作用。

將 HTTP 升級成 HTTPS

如何將網站從 HTTP 升級成 HTTPS 呢?相比起常規的升級步驟,又拍雲提供一套更為簡潔明了的流程,從 SSL 證書的申購、管理到部署,三步即可完成。同時,又拍雲與國際頂級 CA 機構合作,證書類型豐富,操作流程簡單方便。

推薦閱讀

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

※台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”

※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※小三通海運與一般國際貿易有何不同?

※小三通快遞通關作業有哪些?

PHP讀取Excel內的圖片

今天接到了一個從Excel內讀取圖片的需求,在網上查找了一些資料,基本實現了自己的需求,不過由於查到的一些代碼比較久遠,裏面一些庫方法已經被移除不存在了,所以不能直接移植到自己的項目里,需要稍加改動一下。

這裏介紹一下分別使用phpspreadsheet和PHPExcel擴展庫來實現讀取Excel內圖片的功能:

PHPSpreadsheet

首先安裝phpspreadsheet,由於線上服務器PHP版本是PHP5.6,所以需要安裝兼容PHP5.6的版本,這裏安裝1.8.2版本

composer require phpoffice/phpspreadsheet=1.8.2

然後就可以在項目里使用了

use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\IOFactory;

$imageFilePath = './uploads/imgs/'; //圖片本地存儲的路徑
if (!file_exists($imageFilePath)) { //如果目錄不存在則遞歸創建
    mkdir($imageFilePath, 0777, true);
}

try {
    $inputFileName = './files/1.xlsx';  //包含圖片的Excel文件
    $objRead = IOFactory::createReader('Xlsx');
    $objSpreadsheet = $objRead->load($inputFileName);
    $objWorksheet = $objSpreadsheet->getSheet(0);
    $data = $objWorksheet->toArray();

    foreach ($objWorksheet->getDrawingCollection() as $drawing) {
        list($startColumn, $startRow) = Coordinate::coordinateFromString($drawing->getCoordinates());
        $imageFileName = $drawing->getCoordinates() . mt_rand(1000, 9999);

        switch ($drawing->getExtension()) {
            case 'jpg':
            case 'jpeg':
                $imageFileName .= '.jpg';
                $source = imagecreatefromjpeg($drawing->getPath());
                imagejpeg($source, $imageFilePath . $imageFileName);
                break;
            case 'gif':
                $imageFileName .= '.gif';
                $source = imagecreatefromgif($drawing->getPath());
                imagegif($source, $imageFilePath . $imageFileName);
                break;
            case 'png':
                $imageFileName .= '.png';
                $source = imagecreatefrompng($drawing->getPath());
                imagepng($source, $imageFilePath, $imageFileName);
                break;
        }
        $startColumn = ABC2decimal($startColumn);
        $data[$startRow-1][$startColumn] = $imageFilePath . $imageFileName;
    }
    dump($data);die();
} catch (\Exception $e) {
    throw $e;
}

public function ABC2decimal($abc)
{
    $ten = 0;
    $len = strlen($abc);
    for($i=1;$i<=$len;$i++){
        $char = substr($abc,0-$i,1);//反向獲取單個字符

        $int = ord($char);
        $ten += ($int-65)*pow(26,$i-1);
    }
    return $ten;
}

可以看到,圖片被讀取並存到了本地服務器中

PHPExcel

PHPExcel實現從Excel文件里讀取內容的方法和phpspreadsheet幾乎一樣,畢竟phpspreadsheet就是在PHPExcel基礎上寫的,不過PHPExcel由於已經被廢棄了,所以建議優先使用phpspreadsheet,如果原來項目里一直使用了PHPExcel也可以繼續使用PHPExcel的方法

use PHPExcel_IOFactory;
use PHPExcel_Cell;

try {
    $inputFileName = './files/1.xlsx';
    $inputFileType = PHPExcel_IOFactory::identify($inputFileName);
    $objReader = PHPExcel_IOFactory::createReader($inputFileType);
    $objPHPExcel = $objReader->load($inputFileName);
} catch (\Exception $e) {
    die('加載文件發生錯誤:"'.pathinfo($inputFileName,PATHINFO_BASENAME).'": '.$e->getMessage());
}

$sheet = $objPHPExcel->getSheet(0);
$data = $sheet->toArray(); //該方法讀取不到圖片,圖片需單獨處理
$imageFilePath = './uploads/imgs/'; //圖片本地存儲的路徑
if (!file_exists($imageFilePath)) {
    mkdir($imageFilePath, 0777, true);
}

//處理圖片
foreach ($sheet->getDrawingCollection() as $img) {
    list($startColumn, $startRow) = PHPExcel_Cell::coordinateFromString($img->getCoordinates()); //獲取圖片所在行和列
    $imageFileName = $img->getCoordinates() . mt_rand(1000, 9999);
    switch($img->getExtension()) {
        case 'jpg':
        case 'jpeg':
            $imageFileName .= '.jpeg';
            $source = imagecreatefromjpeg($img->getPath());
            imagejpeg($source, $imageFilePath.$imageFileName);
            break;
        case 'gif':
            $imageFileName .= '.gif';
            $source = imagecreatefromgif($img->getPath());
            imagejpeg($source, $imageFilePath.$imageFileName);
            break;
        case 'png':
            $imageFileName .= '.png';
            $source = imagecreatefrompng($img->getPath());
            imagejpeg($source, $imageFilePath.$imageFileName);
            break;
    }
    $startColumn = ABC2decimal($startColumn);
    $data[$startRow-1][$startColumn] = $imageFilePath . $imageFileName;

}
var_dump($data);

public function ABC2decimal($abc)
{
    $ten = 0;
    $len = strlen($abc);
    for($i=1;$i<=$len;$i++){
        $char = substr($abc,0-$i,1);//反向獲取單個字符

        $int = ord($char);
        $ten += ($int-65)*pow(26,$i-1);
    }
    return $ten;
}

參考文章:

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

※台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”

※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※小三通海運與一般國際貿易有何不同?

※小三通快遞通關作業有哪些?